/* Visits the blocks in dominator tree order, recursively. */ static void optimize_bb(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshBB *bb) { MVMSpeshCallInfo arg_info; MVMint32 i; /* Look for instructions that are interesting to optimize. */ MVMSpeshIns *ins = bb->first_ins; while (ins) { switch (ins->info->opcode) { case MVM_OP_set: copy_facts(tc, g, ins->operands[0], ins->operands[1]); break; case MVM_OP_istrue: case MVM_OP_isfalse: optimize_istrue_isfalse(tc, g, bb, ins); break; case MVM_OP_if_i: case MVM_OP_unless_i: case MVM_OP_if_n: case MVM_OP_unless_n: case MVM_OP_if_o: case MVM_OP_unless_o: optimize_iffy(tc, g, ins, bb); break; case MVM_OP_prepargs: arg_info.cs = g->sf->body.cu->body.callsites[ins->operands[0].callsite_idx]; arg_info.prepargs_ins = ins; break; case MVM_OP_arg_i: case MVM_OP_arg_n: case MVM_OP_arg_s: case MVM_OP_arg_o: { MVMint16 idx = ins->operands[0].lit_i16; if (idx < MAX_ARGS_FOR_OPT) { arg_info.arg_is_const[idx] = 0; arg_info.arg_facts[idx] = MVM_spesh_get_facts(tc, g, ins->operands[1]); arg_info.arg_ins[idx] = ins; } break; } case MVM_OP_argconst_i: case MVM_OP_argconst_n: case MVM_OP_argconst_s: { MVMint16 idx = ins->operands[0].lit_i16; if (idx < MAX_ARGS_FOR_OPT) { arg_info.arg_is_const[idx] = 1; arg_info.arg_ins[idx] = ins; } break; } case MVM_OP_coerce_in: optimize_coerce(tc, g, bb, ins); break; case MVM_OP_invoke_v: optimize_call(tc, g, bb, ins, 0, &arg_info); break; case MVM_OP_invoke_i: case MVM_OP_invoke_n: case MVM_OP_invoke_s: case MVM_OP_invoke_o: optimize_call(tc, g, bb, ins, 1, &arg_info); break; case MVM_OP_islist: case MVM_OP_ishash: case MVM_OP_isint: case MVM_OP_isnum: case MVM_OP_isstr: optimize_is_reprid(tc, g, ins); break; case MVM_OP_findmeth: optimize_method_lookup(tc, g, ins); break; case MVM_OP_can: case MVM_OP_can_s: break; /* XXX This causes problems, Spesh: failed to fix up handlers (-1, 110, 110) */ /* optimize_can_op(tc, g, bb, ins); break; */ case MVM_OP_create: optimize_repr_op(tc, g, bb, ins, 1); break; case MVM_OP_isconcrete: optimize_isconcrete(tc, g, ins); break; case MVM_OP_istype: optimize_istype(tc, g, ins); break; case MVM_OP_bindattr_i: case MVM_OP_bindattr_n: case MVM_OP_bindattr_s: case MVM_OP_bindattr_o: case MVM_OP_bindattrs_i: case MVM_OP_bindattrs_n: case MVM_OP_bindattrs_s: case MVM_OP_bindattrs_o: optimize_repr_op(tc, g, bb, ins, 0); break; case MVM_OP_getattr_i: case MVM_OP_getattr_n: case MVM_OP_getattr_s: case MVM_OP_getattr_o: case MVM_OP_getattrs_i: case MVM_OP_getattrs_n: case MVM_OP_getattrs_s: case MVM_OP_getattrs_o: optimize_repr_op(tc, g, bb, ins, 1); break; case MVM_OP_box_i: case MVM_OP_box_n: case MVM_OP_box_s: optimize_repr_op(tc, g, bb, ins, 2); break; case MVM_OP_unbox_i: case MVM_OP_unbox_n: case MVM_OP_unbox_s: optimize_repr_op(tc, g, bb, ins, 1); break; case MVM_OP_elems: optimize_repr_op(tc, g, bb, ins, 1); break; case MVM_OP_hllize: optimize_hllize(tc, g, ins); break; case MVM_OP_decont: optimize_decont(tc, g, bb, ins); break; case MVM_OP_assertparamcheck: optimize_assertparamcheck(tc, g, bb, ins); break; case MVM_OP_getlexstatic_o: optimize_getlex_known(tc, g, bb, ins); break; case MVM_OP_getlexperinvtype_o: if (specialized_on_invocant(tc, g)) optimize_getlex_known(tc, g, bb, ins); break; case MVM_OP_sp_log: case MVM_OP_sp_osrfinalize: /* Left-over log instruction that didn't become a guard, or OSR * finalize instruction; just delete it. */ MVM_spesh_manipulate_delete_ins(tc, g, bb, ins); break; } ins = ins->next; } /* Visit children. */ for (i = 0; i < bb->num_children; i++) optimize_bb(tc, g, bb->children[i]); }
/* Drives the overall optimization work taking place on a spesh graph. */ void MVM_spesh_optimize(MVMThreadContext *tc, MVMSpeshGraph *g) { optimize_bb(tc, g, g->entry); eliminate_dead_ins(tc, g); eliminate_dead_bbs(tc, g); eliminate_unused_log_guards(tc, g); }
/* Does all known instruction optimizations */ void cuc_optimize (cuc_func * func) { int modified = 0; int first = 1; log ("Optimizing.\n"); do { modified = 0; clean_deps (func); if (cuc_debug >= 6) print_cuc_bb (func, "AFTER_CLEAN_DEPS"); if (optimize_cmovs (func)) { if (cuc_debug >= 6) print_cuc_bb (func, "AFTER_OPT_CMOVS"); modified = 1; } if (cuc_debug) cuc_check (func); if (optimize_tree (func)) { if (cuc_debug >= 6) print_cuc_bb (func, "AFTER_OPT_TREE1"); modified = 1; } if (remove_nops (func)) { if (cuc_debug >= 6) print_cuc_bb (func, "NO_NOPS"); modified = 1; } if (cuc_debug) cuc_check (func); if (remove_dead (func)) { if (cuc_debug >= 5) print_cuc_bb (func, "AFTER_DEAD"); modified = 1; } if (cuc_debug) cuc_check (func); if (cse (func)) { log ("Common subexpression elimination.\n"); if (cuc_debug >= 3) print_cuc_bb (func, "AFTER_CSE"); modified = 1; } if (first) { insert_conditional_facts (func); if (cuc_debug >= 3) print_cuc_bb (func, "AFTER_COND_FACT"); if (cuc_debug) cuc_check (func); first = 0; } if (optimize_bb (func)) { if (cuc_debug >= 5) print_cuc_bb (func, "AFTER_OPT_BB"); modified = 1; } if (cuc_debug) cuc_check (func); if (remove_nops (func)) { if (cuc_debug >= 6) print_cuc_bb (func, "NO_NOPS"); modified = 1; } if (remove_dead_bb (func)) { if (cuc_debug >= 5) print_cuc_bb (func, "AFTER_DEAD_BB"); modified = 1; } if (remove_trivial_regs (func)) { if (cuc_debug >= 2) print_cuc_bb (func, "AFTER_TRIVIAL"); modified = 1; } if (remove_nops (func)) { if (cuc_debug >= 6) print_cuc_bb (func, "NO_NOPS"); modified = 1; } add_memory_dep (func, func->memory_order); if (cuc_debug >= 7) print_cuc_bb (func, "AFTER_MEMORY_DEP"); add_data_dep (func); if (cuc_debug >= 8) print_cuc_bb (func, "AFTER_DATA_DEP"); if (schedule_memory (func, func->memory_order)) { if (cuc_debug >= 7) print_cuc_bb (func, "AFTER_SCHEDULE_MEM"); modified = 1; } } while (modified); set_io (func); #if 0 detect_max_values (func); if (cuc_debug >= 5) print_cuc_bb (func, "AFTER_MAX_VALUES"); #endif }