X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Flocal-propagation.c;h=a35a7a39f21405c92b2b9602205116099f4b7852;hb=ccc6d60a3373f07ed1e7a0e82ec3dbc1b5aef26b;hp=e9403d0a31b3c3cb09cd76abec1d12a648032af8;hpb=f60b11a873bdacc152a5dfeb063b2dd9a8650b8f;p=mono.git diff --git a/mono/mini/local-propagation.c b/mono/mini/local-propagation.c index e9403d0a31b..a35a7a39f21 100644 --- a/mono/mini/local-propagation.c +++ b/mono/mini/local-propagation.c @@ -10,6 +10,7 @@ * * (C) 2006 Novell, Inc. http://www.novell.com * Copyright 2011 Xamarin, Inc (http://www.xamarin.com) + * Licensed under the MIT license. See LICENSE file in the project root for full license information. */ #include @@ -140,6 +141,116 @@ mono_strength_reduction_ins (MonoCompile *cfg, MonoInst *ins, const char **spec) } break; } +#if SIZEOF_REGISTER == 8 + case OP_LREM_IMM: +#endif + case OP_IREM_IMM: { + int power = mono_is_power_of_two (ins->inst_imm); + if (ins->inst_imm == 1) { + ins->opcode = OP_ICONST; + MONO_INST_NULLIFY_SREGS (ins); + ins->inst_c0 = 0; +#if __s390__ + } +#else + } else if ((ins->inst_imm > 0) && (ins->inst_imm < (1LL << 32)) && (power != -1)) { + gboolean is_long = ins->opcode == OP_LREM_IMM; + int compensator_reg = alloc_ireg (cfg); + int intermediate_reg; + + /* Based on gcc code */ + + /* Add compensation for negative numerators */ + + if (power > 1) { + intermediate_reg = compensator_reg; + MONO_EMIT_NEW_BIALU_IMM (cfg, is_long ? OP_LSHR_IMM : OP_ISHR_IMM, intermediate_reg, ins->sreg1, is_long ? 63 : 31); + } else { + intermediate_reg = ins->sreg1; + } + + MONO_EMIT_NEW_BIALU_IMM (cfg, is_long ? OP_LSHR_UN_IMM : OP_ISHR_UN_IMM, compensator_reg, intermediate_reg, (is_long ? 64 : 32) - power); + MONO_EMIT_NEW_BIALU (cfg, is_long ? OP_LADD : OP_IADD, ins->dreg, ins->sreg1, compensator_reg); + /* Compute remainder */ + MONO_EMIT_NEW_BIALU_IMM (cfg, is_long ? OP_LAND_IMM : OP_AND_IMM, ins->dreg, ins->dreg, (1 << power) - 1); + /* Remove compensation */ + MONO_EMIT_NEW_BIALU (cfg, is_long ? OP_LSUB : OP_ISUB, ins->dreg, ins->dreg, compensator_reg); + + allocated_vregs = TRUE; + } +#endif + break; + } +#if SIZEOF_REGISTER == 4 + case OP_LSHR_IMM: { + if (COMPILE_LLVM (cfg)) + break; + if (ins->inst_c1 == 32) { + MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (ins->dreg), MONO_LVREG_MS (ins->sreg1)); + MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_IMM, MONO_LVREG_MS (ins->dreg), MONO_LVREG_MS (ins->sreg1), 31); + } else if (ins->inst_c1 == 0) { + MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (ins->dreg), MONO_LVREG_LS (ins->sreg1)); + MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (ins->dreg), MONO_LVREG_MS (ins->sreg1)); + } else if (ins->inst_c1 > 32) { + MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_IMM, MONO_LVREG_LS (ins->dreg), MONO_LVREG_MS (ins->sreg1), ins->inst_c1 - 32); + MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_IMM, MONO_LVREG_MS (ins->dreg), MONO_LVREG_MS (ins->sreg1), 31); + } else { + guint32 tmpreg = alloc_ireg (cfg); + MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, tmpreg, MONO_LVREG_MS (ins->sreg1), 32 - ins->inst_c1); + MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_IMM, MONO_LVREG_MS (ins->dreg), MONO_LVREG_MS (ins->sreg1), ins->inst_c1); + MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, MONO_LVREG_LS (ins->dreg), MONO_LVREG_LS (ins->sreg1), ins->inst_c1); + MONO_EMIT_NEW_BIALU (cfg, OP_IOR, MONO_LVREG_LS (ins->dreg), MONO_LVREG_LS (ins->dreg), tmpreg); + allocated_vregs = TRUE; + } + break; + } + case OP_LSHR_UN_IMM: { + if (COMPILE_LLVM (cfg)) + break; + if (ins->inst_c1 == 32) { + MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (ins->dreg), MONO_LVREG_MS (ins->sreg1)); + MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (ins->dreg), 0); + } else if (ins->inst_c1 == 0) { + MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (ins->dreg), MONO_LVREG_LS (ins->sreg1)); + MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (ins->dreg), MONO_LVREG_MS (ins->sreg1)); + } else if (ins->inst_c1 > 32) { + MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, MONO_LVREG_LS (ins->dreg), MONO_LVREG_MS (ins->sreg1), ins->inst_c1 - 32); + MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (ins->dreg), 0); + } else { + guint32 tmpreg = alloc_ireg (cfg); + MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, tmpreg, MONO_LVREG_MS (ins->sreg1), 32 - ins->inst_c1); + MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, MONO_LVREG_MS (ins->dreg), MONO_LVREG_MS (ins->sreg1), ins->inst_c1); + MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, MONO_LVREG_LS (ins->dreg), MONO_LVREG_LS (ins->sreg1), ins->inst_c1); + MONO_EMIT_NEW_BIALU (cfg, OP_IOR, MONO_LVREG_LS (ins->dreg), MONO_LVREG_LS (ins->dreg), tmpreg); + allocated_vregs = TRUE; + } + break; + } + case OP_LSHL_IMM: { + if (COMPILE_LLVM (cfg)) + break; + if (ins->inst_c1 == 32) { + /* just move the lower half to the upper and zero the lower word */ + MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (ins->dreg), MONO_LVREG_LS (ins->sreg1)); + MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_LS (ins->dreg), 0); + } else if (ins->inst_c1 == 0) { + MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (ins->dreg), MONO_LVREG_LS (ins->sreg1)); + MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (ins->dreg), MONO_LVREG_MS (ins->sreg1)); + } else if (ins->inst_c1 > 32) { + MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, MONO_LVREG_MS (ins->dreg), MONO_LVREG_LS (ins->sreg1), ins->inst_c1 - 32); + MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_LS (ins->dreg), 0); + } else { + guint32 tmpreg = alloc_ireg (cfg); + MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, tmpreg, MONO_LVREG_LS (ins->sreg1), 32 - ins->inst_c1); + MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, MONO_LVREG_MS (ins->dreg), MONO_LVREG_MS (ins->sreg1), ins->inst_c1); + MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, MONO_LVREG_LS (ins->dreg), MONO_LVREG_LS (ins->sreg1), ins->inst_c1); + MONO_EMIT_NEW_BIALU (cfg, OP_IOR, MONO_LVREG_MS (ins->dreg), MONO_LVREG_MS (ins->dreg), tmpreg); + allocated_vregs = TRUE; + } + break; + } +#endif + default: break; } @@ -178,22 +289,28 @@ mono_local_cprop (MonoCompile *cfg) int sregs [MONO_MAX_SRC_REGS]; int num_sregs, i; - if ((ins->dreg != -1) && (ins->dreg < max)) { - defs [ins->dreg] = NULL; + if (ins->dreg != -1) { #if SIZEOF_REGISTER == 4 - defs [ins->dreg + 1] = NULL; + const char *spec = INS_INFO (ins->opcode); + if (spec [MONO_INST_DEST] == 'l') { + defs [ins->dreg + 1] = NULL; + defs [ins->dreg + 2] = NULL; + } #endif + defs [ins->dreg] = NULL; } num_sregs = mono_inst_get_src_registers (ins, sregs); for (i = 0; i < num_sregs; ++i) { int sreg = sregs [i]; - if (sreg < max) { - defs [sreg] = NULL; #if SIZEOF_REGISTER == 4 + const char *spec = INS_INFO (ins->opcode); + if (spec [MONO_INST_SRC1 + i] == 'l') { defs [sreg + 1] = NULL; -#endif + defs [sreg + 2] = NULL; } +#endif + defs [sreg] = NULL; } } @@ -383,6 +500,14 @@ mono_local_cprop (MonoCompile *cfg) (!defs [def->sreg1] || (def_index [def->sreg1] < def_index [sreg]))) { /* Avoid needless sign extension */ ins->sreg1 = def->sreg1; + } else if (ins->opcode == OP_COMPARE_IMM && def->opcode == OP_LDADDR && ins->inst_imm == 0) { + MonoInst dummy_arg1; + + memset (&dummy_arg1, 0, sizeof (MonoInst)); + dummy_arg1.opcode = OP_ICONST; + dummy_arg1.inst_c0 = 1; + + mono_constant_fold_ins (cfg, ins, &dummy_arg1, NULL, TRUE); } } @@ -430,13 +555,13 @@ mono_local_cprop (MonoCompile *cfg) ins->inst_destbasereg = def->sreg1; ins->inst_offset += def->inst_imm; } + + if (!MONO_IS_STORE_MEMBASE (ins) && !vreg_is_volatile (cfg, ins->dreg)) { + defs [ins->dreg] = ins; + def_index [ins->dreg] = ins_index; + } } - if ((spec [MONO_INST_DEST] != ' ') && !MONO_IS_STORE_MEMBASE (ins) && !vreg_is_volatile (cfg, ins->dreg)) { - defs [ins->dreg] = ins; - def_index [ins->dreg] = ins_index; - } - if (MONO_IS_CALL (ins)) last_call_index = ins_index;