X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Fssa.c;h=d58d814e11fb0685d48c275cc497a968b8ab034a;hb=0d40321933ac575314ab51efa3c62e8cf535a9d2;hp=12d862f94cc81088b56a02ab8a83b1cb5ce41685;hpb=3331634f37c395ea87d15a2f3338b2bc66a8470a;p=mono.git diff --git a/mono/mini/ssa.c b/mono/mini/ssa.c index 12d862f94cc..d58d814e11f 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) @@ -389,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)) @@ -414,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)) { @@ -436,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; @@ -475,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"); @@ -486,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); @@ -554,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; @@ -580,32 +580,20 @@ mono_ssa_remove (MonoCompile *cfg) } } - if (spec [MONO_INST_SRC1] != ' ') { - MonoInst *var = get_vreg_to_inst (cfg, ins->sreg1); - - 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; - } - } - } - - if (spec [MONO_INST_SRC2] != ' ') { - MonoInst *var = get_vreg_to_inst (cfg, ins->sreg2); + 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->sreg2, cfg->varinfo [vmv->reg]->dreg); - ins->sreg2 = 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; } } } - + mono_inst_set_src_registers (ins, sregs); } } @@ -634,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))) @@ -700,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)) { @@ -749,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) { @@ -763,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); - - r1 = 2; - arg0 = carray [ins->sreg1]; - if (arg0) - r1 = 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); + 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]); - r2 = 2; - arg1 = carray [ins->sreg2]; - if (arg1) - r2 = 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))) - 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 -> "); @@ -822,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)) - return 2; - else - return 0; - } - else if (spec [MONO_INST_SRC1] != ' ') { - /* Unop */ - if (r1 == 2) + if (num_sregs == 0) + return 2; + for (i = 0; i < num_sregs; ++i) { + if (rs [i] == 2) return 2; - else - return 0; } - else - return 2; + return 0; } static inline void @@ -977,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++) @@ -994,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; @@ -1064,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)) { @@ -1072,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) { @@ -1085,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; @@ -1103,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; @@ -1119,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 "); @@ -1140,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]); } @@ -1199,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) { @@ -1210,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)