X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Fssa.c;h=023d2778009bebb9a1002239cba36ec82a2427ee;hb=549fddc4b4422c7fbe245b63cc6ca194b6f0bc08;hp=ac34bfd1b558f302ad97c108f67d96fe740eba96;hpb=0aedc3f6fb2194817c766659c50a7e7f4786672e;p=mono.git diff --git a/mono/mini/ssa.c b/mono/mini/ssa.c index ac34bfd1b55..023d2778009 100644 --- a/mono/mini/ssa.c +++ b/mono/mini/ssa.c @@ -1105,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]); } @@ -1350,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 */