X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Fssa.c;h=023d2778009bebb9a1002239cba36ec82a2427ee;hb=1cdf7fafbded32d4cf2beb14cf2bc4b7829ff926;hp=bee0f1b9002b877d5755350fef4d2780cdf33170;hpb=217ddc29c40bc8b11f8fbd4800e61db7f4f22bbf;p=mono.git diff --git a/mono/mini/ssa.c b/mono/mini/ssa.c index bee0f1b9002..023d2778009 100644 --- a/mono/mini/ssa.c +++ b/mono/mini/ssa.c @@ -5,7 +5,9 @@ * Dietmar Maurer (dietmar@ximian.com) * * (C) 2003 Ximian, Inc. + * Copyright 2011 Xamarin, Inc (http://www.xamarin.com) */ +#include #include #include #include @@ -14,6 +16,9 @@ #ifndef DISABLE_JIT #include "mini.h" +#ifdef HAVE_ALLOCA_H +#include +#endif #define USE_ORIGINAL_VARS #define CREATE_PRUNED_SSA @@ -126,6 +131,8 @@ op_phi_to_move (int opcode) return OP_FMOVE; case OP_VPHI: return OP_VMOVE; + case OP_XPHI: + return OP_XMOVE; default: g_assert_not_reached (); } @@ -172,6 +179,8 @@ mono_ssa_rename_vars (MonoCompile *cfg, int max_vars, MonoBasicBlock *bb, gboole /* First pass: Create new vars */ for (ins = bb->code; ins; ins = ins->next) { const char *spec = INS_INFO (ins->opcode); + int num_sregs; + int sregs [MONO_MAX_SRC_REGS]; #ifdef DEBUG_SSA printf ("\tProcessing "); mono_print_ins (ins); @@ -179,42 +188,27 @@ mono_ssa_rename_vars (MonoCompile *cfg, int max_vars, MonoBasicBlock *bb, gboole if (ins->opcode == OP_NOP) continue; - /* SREG1 */ - if (spec [MONO_INST_SRC1] != ' ') { - MonoInst *var = get_vreg_to_inst (cfg, ins->sreg1); - if (var && !(var->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))) { - int idx = var->inst_c0; - if (stack [idx]) { - if (var->opcode != OP_ARG) - g_assert (stack [idx]); - ins->sreg1 = stack [idx]->dreg; - record_use (cfg, stack [idx], bb, ins); - } - else - record_use (cfg, var, bb, ins); - } - else if (G_UNLIKELY (!var && lvreg_stack [ins->sreg1])) - ins->sreg1 = lvreg_stack [ins->sreg1]; - } - - /* SREG2 */ - if (spec [MONO_INST_SRC2] != ' ') { - MonoInst *var = get_vreg_to_inst (cfg, ins->sreg2); - if (var && !(var->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))) { - int idx = var->inst_c0; - if (stack [idx]) { - if (var->opcode != OP_ARG) - g_assert (stack [idx]); - - ins->sreg2 = stack [idx]->dreg; - record_use (cfg, stack [idx], bb, ins); + /* SREGs */ + num_sregs = mono_inst_get_src_registers (ins, sregs); + for (i = 0; i < num_sregs; ++i) { + if (spec [MONO_INST_SRC1 + i] != ' ') { + MonoInst *var = get_vreg_to_inst (cfg, sregs [i]); + if (var && !(var->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))) { + int idx = var->inst_c0; + if (stack [idx]) { + if (var->opcode != OP_ARG) + g_assert (stack [idx]); + sregs [i] = stack [idx]->dreg; + record_use (cfg, stack [idx], bb, ins); + } + else + record_use (cfg, var, bb, ins); } - else - record_use (cfg, var, bb, ins); + else if (G_UNLIKELY (!var && lvreg_stack [sregs [i]])) + sregs [i] = lvreg_stack [sregs [i]]; } - else if (G_UNLIKELY (!var && lvreg_stack [ins->sreg2])) - ins->sreg2 = lvreg_stack [ins->sreg2]; } + mono_inst_set_src_registers (ins, sregs); if (MONO_IS_STORE_MEMBASE (ins)) { MonoInst *var = get_vreg_to_inst (cfg, ins->dreg); @@ -275,7 +269,7 @@ mono_ssa_rename_vars (MonoCompile *cfg, int max_vars, MonoBasicBlock *bb, gboole } else if (G_UNLIKELY (!var && lvreg_defined [ins->dreg] && (ins->dreg >= MONO_MAX_IREGS))) { /* Perform renaming for local vregs */ - lvreg_stack [ins->dreg] = mono_alloc_preg (cfg); + lvreg_stack [ins->dreg] = vreg_is_ref (cfg, ins->dreg) ? mono_alloc_ireg_ref (cfg) : mono_alloc_preg (cfg); ins->dreg = lvreg_stack [ins->dreg]; } else @@ -347,8 +341,6 @@ mono_ssa_compute (MonoCompile *cfg) g_assert (!(cfg->comp_done & MONO_COMP_SSA)); - /* we dont support methods containing exception clauses */ - g_assert (mono_method_get_header (cfg->method)->num_clauses == 0); g_assert (!cfg->disable_ssa); if (cfg->verbose_level >= 4) @@ -370,7 +362,8 @@ mono_ssa_compute (MonoCompile *cfg) buf += bitsize; vinfo [i].idx = i; /* implicit reference at start */ - mono_bitset_set_fast (vinfo [i].def_in, 0); + if (cfg->varinfo [i]->opcode == OP_ARG) + mono_bitset_set_fast (vinfo [i].def_in, 0); } for (i = 0; i < cfg->num_bblocks; ++i) { @@ -388,8 +381,8 @@ mono_ssa_compute (MonoCompile *cfg) for (i = 0; i < cfg->num_varinfo; ++i) { MonoInst *var = cfg->varinfo [i]; -#if SIZEOF_VOID_P == 4 - if (var->type == STACK_I8) +#if SIZEOF_REGISTER == 4 + if (var->type == STACK_I8 && !COMPILE_LLVM (cfg)) continue; #endif if (var->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT)) @@ -413,7 +406,7 @@ mono_ssa_compute (MonoCompile *cfg) /* fixme: create pruned SSA? we would need liveness information for that */ - if (bb == cfg->bb_exit) + if (bb == cfg->bb_exit && !COMPILE_LLVM (cfg)) continue; if ((cfg->comp_done & MONO_COMP_LIVENESS) && !mono_bitset_test_fast (bb->live_in_set, i)) { @@ -435,11 +428,15 @@ mono_ssa_compute (MonoCompile *cfg) ins->opcode = OP_FPHI; break; case STACK_VTYPE: - ins->opcode = OP_VPHI; - ins->klass = var->klass; + ins->opcode = MONO_CLASS_IS_SIMD (cfg, var->klass) ? OP_XPHI : OP_VPHI; break; } + if (var->inst_vtype->byref) + ins->klass = mono_defaults.int_class; + else + ins->klass = var->klass; + ins->inst_phi_args = mono_mempool_alloc0 (cfg->mempool, sizeof (int) * (cfg->bblocks [idx]->in_count + 1)); ins->inst_phi_args [0] = cfg->bblocks [idx]->in_count; @@ -474,6 +471,8 @@ mono_ssa_compute (MonoCompile *cfg) mono_ssa_rename_vars (cfg, cfg->num_varinfo, cfg->bb_entry, originals, stack, lvreg_stack, lvreg_defined, stack_history, stack_history_size); g_free (stack_history); g_free (originals); + g_free (lvreg_stack); + g_free (lvreg_defined); if (cfg->verbose_level >= 4) printf ("\nEND COMPUTE SSA.\n\n"); @@ -485,7 +484,7 @@ void mono_ssa_remove (MonoCompile *cfg) { MonoInst *ins, *var, *move; - int i, j, first; + int bbindex, i, j, first; g_assert (cfg->comp_done & MONO_COMP_SSA); @@ -553,11 +552,13 @@ mono_ssa_remove (MonoCompile *cfg) * can coalesce them into the original variable. */ - for (i = 0; i < cfg->num_bblocks; ++i) { - MonoBasicBlock *bb = cfg->bblocks [i]; + for (bbindex = 0; bbindex < cfg->num_bblocks; ++bbindex) { + MonoBasicBlock *bb = cfg->bblocks [bbindex]; for (ins = bb->code; ins; ins = ins->next) { const char *spec = INS_INFO (ins->opcode); + int num_sregs; + int sregs [MONO_MAX_SRC_REGS]; if (ins->opcode == OP_NOP) continue; @@ -579,32 +580,20 @@ mono_ssa_remove (MonoCompile *cfg) } } - if (spec [MONO_INST_SRC1] != ' ') { - MonoInst *var = get_vreg_to_inst (cfg, ins->sreg1); + num_sregs = mono_inst_get_src_registers (ins, sregs); + for (i = 0; i < num_sregs; ++i) { + MonoInst *var = get_vreg_to_inst (cfg, sregs [i]); if (var) { MonoMethodVar *vmv = MONO_VARINFO (cfg, var->inst_c0); if ((vmv->reg != -1) && (vmv->idx != vmv->reg) && (MONO_VARINFO (cfg, vmv->reg)->reg != -1)) { - printf ("COALESCE: R%d -> R%d\n", ins->sreg1, cfg->varinfo [vmv->reg]->dreg); - ins->sreg1 = cfg->varinfo [vmv->reg]->dreg; + printf ("COALESCE: R%d -> R%d\n", sregs [i], cfg->varinfo [vmv->reg]->dreg); + sregs [i] = cfg->varinfo [vmv->reg]->dreg; } } } - - if (spec [MONO_INST_SRC2] != ' ') { - MonoInst *var = get_vreg_to_inst (cfg, ins->sreg2); - - if (var) { - MonoMethodVar *vmv = MONO_VARINFO (cfg, var->inst_c0); - - if ((vmv->reg != -1) && (vmv->idx != vmv->reg) && (MONO_VARINFO (cfg, vmv->reg)->reg != -1)) { - printf ("COALESCE: R%d -> R%d\n", ins->sreg2, cfg->varinfo [vmv->reg]->dreg); - ins->sreg2 = cfg->varinfo [vmv->reg]->dreg; - } - } - } - + mono_inst_set_src_registers (ins, sregs); } } @@ -633,24 +622,20 @@ mono_ssa_create_def_use (MonoCompile *cfg) for (ins = bb->code; ins; ins = ins->next) { const char *spec = INS_INFO (ins->opcode); MonoMethodVar *info; + int num_sregs; + int sregs [MONO_MAX_SRC_REGS]; if (ins->opcode == OP_NOP) continue; - /* SREG1 */ - if (spec [MONO_INST_SRC1] != ' ') { - MonoInst *var = get_vreg_to_inst (cfg, ins->sreg1); + /* SREGs */ + num_sregs = mono_inst_get_src_registers (ins, sregs); + for (i = 0; i < num_sregs; ++i) { + MonoInst *var = get_vreg_to_inst (cfg, sregs [i]); if (var && !(var->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))) record_use (cfg, var, bb, ins); } - /* SREG2 */ - if (spec [MONO_INST_SRC2] != ' ') { - MonoInst *var = get_vreg_to_inst (cfg, ins->sreg2); - if (var && !(var->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))) - record_use (cfg, var, bb, ins); - } - if (MONO_IS_STORE_MEMBASE (ins)) { MonoInst *var = get_vreg_to_inst (cfg, ins->dreg); if (var && !(var->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))) @@ -699,20 +684,24 @@ mono_ssa_copyprop (MonoCompile *cfg) /* Rewrite all uses of var to be uses of var2 */ int dreg = var->dreg; int sreg1 = var2->dreg; - const char *spec; l = info->uses; while (l) { MonoVarUsageInfo *u = (MonoVarUsageInfo*)l->data; MonoInst *ins = u->inst; GList *next = l->next; + int num_sregs; + int sregs [MONO_MAX_SRC_REGS]; - spec = INS_INFO (ins->opcode); - - if (spec [MONO_INST_SRC1] != ' ' && ins->sreg1 == dreg) { - ins->sreg1 = sreg1; - } else if (spec [MONO_INST_SRC2] != ' ' && ins->sreg2 == dreg) { - ins->sreg2 = sreg1; + num_sregs = mono_inst_get_src_registers (ins, sregs); + for (i = 0; i < num_sregs; ++i) { + if (sregs [i] == dreg) + break; + } + if (i < num_sregs) { + g_assert (sregs [i] == dreg); + sregs [i] = sreg1; + mono_inst_set_src_registers (ins, sregs); } else if (MONO_IS_STORE_MEMBASE (ins) && ins->dreg == dreg) { ins->dreg = sreg1; } else if (MONO_IS_PHI (ins)) { @@ -748,10 +737,13 @@ mono_ssa_copyprop (MonoCompile *cfg) static int evaluate_ins (MonoCompile *cfg, MonoInst *ins, MonoInst **res, MonoInst **carray) { - MonoInst *arg0, *arg1, *c0; - int r1, r2; - gboolean const_args = FALSE; + MonoInst *args [MONO_MAX_SRC_REGS]; + int rs [MONO_MAX_SRC_REGS]; + MonoInst *c0; + gboolean const_args = TRUE; const char *spec = INS_INFO (ins->opcode); + int num_sregs, i; + int sregs [MONO_MAX_SRC_REGS]; /* Short-circuit this */ if (ins->opcode == OP_ICONST) { @@ -762,52 +754,32 @@ evaluate_ins (MonoCompile *cfg, MonoInst *ins, MonoInst **res, MonoInst **carray if (ins->opcode == OP_NOP) return 2; - arg0 = NULL; - if (spec [MONO_INST_SRC1] != ' ') { - MonoInst *var = get_vreg_to_inst (cfg, ins->sreg1); + num_sregs = mono_inst_get_src_registers (ins, sregs); + for (i = 0; i < MONO_MAX_SRC_REGS; ++i) + args [i] = NULL; + for (i = 0; i < num_sregs; ++i) { + MonoInst *var = get_vreg_to_inst (cfg, sregs [i]); - r1 = 2; - arg0 = carray [ins->sreg1]; - if (arg0) - r1 = 1; + rs [i] = 2; + args [i] = carray [sregs [i]]; + if (args [i]) + rs [i] = 1; else if (var && !(var->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))) - r1 = MONO_VARINFO (cfg, var->inst_c0)->cpstate; - } else { - r1 = 2; - } - - arg1 = NULL; - if (spec [MONO_INST_SRC2] != ' ') { - MonoInst *var = get_vreg_to_inst (cfg, ins->sreg2); - - r2 = 2; - arg1 = carray [ins->sreg2]; - if (arg1) - r2 = 1; - else if (var && !(var->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))) - r2 = MONO_VARINFO (cfg, var->inst_c0)->cpstate; - } - else { - r2 = 0; + rs [i] = MONO_VARINFO (cfg, var->inst_c0)->cpstate; + if (rs [i] != 1) + const_args = FALSE; } c0 = NULL; - if ((spec [MONO_INST_SRC1] != ' ') && (spec [MONO_INST_SRC2] != ' ')) { - /* Binop */ - const_args = (r1 == 1) && (r2 == 1); - } - else if (spec [MONO_INST_SRC1] != ' ') { - /* Unop */ - const_args = (r1 == 1); - } - if (const_args) { + if (num_sregs > 0 && const_args) { + g_assert (num_sregs <= 2); if ((spec [MONO_INST_DEST] != ' ') && carray [ins->dreg]) { // Cached value *res = carray [ins->dreg]; return 1; } - c0 = mono_constant_fold_ins (cfg, ins, arg0, arg1, FALSE); + c0 = mono_constant_fold_ins (cfg, ins, args [0], args [1], FALSE); if (c0) { if (G_UNLIKELY (cfg->verbose_level > 1)) { printf ("\t cfold -> "); @@ -821,22 +793,13 @@ evaluate_ins (MonoCompile *cfg, MonoInst *ins, MonoInst **res, MonoInst **carray return 2; } - if ((spec [MONO_INST_SRC1] != ' ') && (spec [MONO_INST_SRC2] != ' ')) { - /* Binop */ - if ((r1 == 2) || (r2 == 2)) + if (num_sregs == 0) + return 2; + for (i = 0; i < num_sregs; ++i) { + if (rs [i] == 2) return 2; - else - return 0; } - else if (spec [MONO_INST_SRC1] != ' ') { - /* Unop */ - if (r1 == 2) - return 2; - else - return 0; - } - else - return 2; + return 0; } static inline void @@ -976,11 +939,11 @@ visit_inst (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins, GList **cvars, } } - if (ins->opcode == OP_JUMP_TABLE) { + if (MONO_IS_JUMP_TABLE (ins)) { int i; - MonoJumpInfoBBTable *table = ins->inst_p0; + MonoJumpInfoBBTable *table = MONO_JUMP_TABLE_FROM_INS (ins); - if (ins->next->opcode != OP_PADD) { + if (!ins->next || ins->next->opcode != OP_PADD) { /* The PADD was optimized away */ /* FIXME: handle this as well */ for (i = 0; i < table->table_size; i++) @@ -993,7 +956,7 @@ visit_inst (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins, GList **cvars, g_assert (ins->next->sreg1 == ins->dreg); if (carray [ins->next->sreg2]) { -#if SIZEOF_VOID_P == 8 +#if SIZEOF_REGISTER == 8 int idx = carray [ins->next->sreg2]->inst_c0 >> 3; #else int idx = carray [ins->next->sreg2]->inst_c0 >> 2; @@ -1063,6 +1026,7 @@ fold_ins (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins, MonoInst **carray { const char *spec = INS_INFO (ins->opcode); int opcode2; + int num_sregs = mono_inst_get_num_src_registers (ins); if ((ins->opcode != OP_NOP) && (ins->dreg != -1) && !MONO_IS_STORE_MEMBASE (ins)) { if (carray [ins->dreg] && (spec [MONO_INST_DEST] == 'i') && (ins->dreg >= MONO_MAX_IREGS)) { @@ -1071,9 +1035,8 @@ fold_ins (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins, MonoInst **carray g_assert (carray [ins->dreg]->opcode == OP_ICONST); ins->opcode = OP_ICONST; ins->inst_c0 = carray [ins->dreg]->inst_c0; - ins->sreg1 = ins->sreg2 = -1; - } - else if ((spec [MONO_INST_SRC2] != ' ') && carray [ins->sreg2]) { + MONO_INST_NULLIFY_SREGS (ins); + } else if (num_sregs == 2 && carray [ins->sreg2]) { /* Perform op->op_imm conversion */ opcode2 = mono_op_to_op_imm (ins->opcode); if (opcode2 != -1) { @@ -1084,13 +1047,15 @@ fold_ins (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins, MonoInst **carray if ((opcode2 == OP_VOIDCALL) || (opcode2 == OP_CALL) || (opcode2 == OP_LCALL) || (opcode2 == OP_FCALL)) ((MonoCallInst*)ins)->fptr = (gpointer)ins->inst_imm; } + } else { + /* FIXME: Handle 3 op insns */ } - if (ins->opcode == OP_JUMP_TABLE) { + if (MONO_IS_JUMP_TABLE (ins)) { int i; - MonoJumpInfoBBTable *table = ins->inst_p0; + MonoJumpInfoBBTable *table = MONO_JUMP_TABLE_FROM_INS (ins); - if (ins->next->opcode != OP_PADD) { + if (!ins->next || ins->next->opcode != OP_PADD) { /* The PADD was optimized away */ /* FIXME: handle this as well */ return; @@ -1102,7 +1067,7 @@ fold_ins (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins, MonoInst **carray if (carray [ins->next->sreg2]) { /* Convert to a simple branch */ -#if SIZEOF_VOID_P == 8 +#if SIZEOF_REGISTER == 8 int idx = carray [ins->next->sreg2]->inst_c0 >> 3; #else int idx = carray [ins->next->sreg2]->inst_c0 >> 2; @@ -1118,12 +1083,13 @@ fold_ins (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins, MonoInst **carray NULLIFY_INS (ins); NULLIFY_INS (ins->next); NULLIFY_INS (ins->next->next); - NULLIFY_INS (ins->next->next->next); + if (ins->next->next->next) + NULLIFY_INS (ins->next->next->next); return; } - if (ins->next->next->next->opcode != OP_BR_REG) { + if (!ins->next->next->next || ins->next->next->next->opcode != OP_BR_REG) { /* A one-way switch which got optimized away */ if (G_UNLIKELY (cfg->verbose_level > 1)) { printf ("\tNo cfold on "); @@ -1139,7 +1105,7 @@ fold_ins (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins, MonoInst **carray /* Unlink target bblocks */ for (i = 0; i < table->table_size; ++i) { - if (i != idx) { + if (table->table [i] != table->table [idx]) { remove_bb_from_phis (cfg, bb, table->table [i]); mono_unlink_bblock (cfg, bb, table->table [i]); } @@ -1198,6 +1164,15 @@ mono_ssa_cprop (MonoCompile *cfg) info->cpstate = 2; } + for (bb = cfg->bb_entry->next_bb; bb; bb = bb->next_bb) { + /* + * FIXME: This should be bb->flags & BB_FLAG_EXCEPTION_HANDLER, but + * that would still allow unreachable try's to be removed. + */ + if (bb->region) + add_cprop_bb (cfg, bb, &bblock_list); + } + cvars = NULL; while (bblock_list) { @@ -1209,11 +1184,13 @@ mono_ssa_cprop (MonoCompile *cfg) g_assert (bb->flags & BB_REACHABLE); - if (bb->out_count == 1) { - if (!(bb->out_bb [0]->flags & BB_REACHABLE)) { - bb->out_bb [0]->flags |= BB_REACHABLE; - bblock_list = g_list_prepend (bblock_list, bb->out_bb [0]); - } + /* + * Some bblocks are linked to 2 others even through they fall through to the + * next bblock. + */ + if (!(bb->last_ins && MONO_IS_BRANCH_OP (bb->last_ins))) { + for (i = 0; i < bb->out_count; ++i) + add_cprop_bb (cfg, bb->out_bb [i], &bblock_list); } if (cfg->verbose_level > 1) @@ -1373,4 +1350,117 @@ mono_ssa_strength_reduction (MonoCompile *cfg) } #endif +void +mono_ssa_loop_invariant_code_motion (MonoCompile *cfg) +{ + MonoBasicBlock *bb, *h, *idom; + MonoInst *ins, *n, *tins; + int i; + + g_assert (cfg->comp_done & MONO_COMP_SSA); + if (!(cfg->comp_done & MONO_COMP_LOOPS) || !(cfg->comp_done & MONO_COMP_SSA_DEF_USE)) + return; + + for (bb = cfg->bb_entry->next_bb; bb; bb = bb->next_bb) { + GList *lp = bb->loop_blocks; + + if (!lp) + continue; + h = (MonoBasicBlock *)lp->data; + if (bb != h) + continue; + MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) { + gboolean is_class_init = FALSE; + + /* + * Try to move instructions out of loop headers into the preceeding bblock. + */ + if (ins->opcode == OP_VOIDCALL) { + MonoCallInst *call = (MonoCallInst*)ins; + + if (call->fptr_is_patch) { + MonoJumpInfo *ji = (MonoJumpInfo*)call->fptr; + + if (ji->type == MONO_PATCH_INFO_CLASS_INIT) + is_class_init = TRUE; + } + } + if (ins->opcode == OP_LDLEN || ins->opcode == OP_STRLEN || ins->opcode == OP_CHECK_THIS || ins->opcode == OP_AOTCONST || is_class_init) { + gboolean skip; + int sreg; + + idom = h->idom; + /* + * h->nesting is needed to work around: + * http://llvm.org/bugs/show_bug.cgi?id=17868 + */ + if (!(idom && idom->last_ins && idom->last_ins->opcode == OP_BR && idom->last_ins->inst_target_bb == h && h->nesting == 1)) { + continue; + } + + /* + * Make sure there are no instructions with side effects before ins. + */ + skip = FALSE; + MONO_BB_FOR_EACH_INS (bb, tins) { + if (tins == ins) + break; + if (!MONO_INS_HAS_NO_SIDE_EFFECT (tins)) { + skip = TRUE; + break; + } + } + if (skip) { + /* + printf ("%s\n", mono_method_full_name (cfg->method, TRUE)); + mono_print_ins (tins); + */ + continue; + } + + /* Make sure we don't move the instruction before the def of its sreg */ + if (ins->opcode == OP_LDLEN || ins->opcode == OP_STRLEN || ins->opcode == OP_CHECK_THIS) + sreg = ins->sreg1; + else + sreg = -1; + if (sreg != -1) { + MonoInst *tins; + + skip = FALSE; + for (tins = ins->prev; tins; tins = tins->prev) { + const char *spec = INS_INFO (tins->opcode); + + if (tins->opcode == OP_MOVE && tins->dreg == sreg) { + sreg = tins->sreg1; + } if (spec [MONO_INST_DEST] != ' ' && tins->dreg == sreg) { + skip = TRUE; + break; + } + } + if (skip) + continue; + ins->sreg1 = sreg; + } + + if (cfg->verbose_level > 1) { + printf ("licm in BB%d on ", bb->block_num); + mono_print_ins (ins); + } + //{ static int count = 0; count ++; printf ("%d\n", count); } + MONO_REMOVE_INS (bb, ins); + mono_bblock_insert_before_ins (idom, idom->last_ins, ins); + if (ins->opcode == OP_LDLEN || ins->opcode == OP_STRLEN) + idom->has_array_access = TRUE; + } + } + } + + cfg->comp_done &= ~MONO_COMP_SSA_DEF_USE; + for (i = 0; i < cfg->num_varinfo; i++) { + MonoMethodVar *info = MONO_VARINFO (cfg, i); + info->def = NULL; + info->uses = NULL; + } +} + #endif /* DISABLE_JIT */