From 9d3604e57b80856794363f45ffd98bfe0d93c09a Mon Sep 17 00:00:00 2001 From: Vlad Brezae Date: Wed, 23 Dec 2015 17:01:40 +0200 Subject: [jit] Refactor strength reduction handling within mono_local_cprop --- mono/mini/local-propagation.c | 222 ++++++++++++++++++++++-------------------- 1 file changed, 116 insertions(+), 106 deletions(-) diff --git a/mono/mini/local-propagation.c b/mono/mini/local-propagation.c index aa2a934f556..145d8fbc28f 100644 --- a/mono/mini/local-propagation.c +++ b/mono/mini/local-propagation.c @@ -41,6 +41,119 @@ mono_bitset_mp_new_noinit (MonoMemPool *mp, guint32 max_size) return mono_bitset_mem_new (mem, max_size, MONO_BITSET_DONT_FREE); } +/* + * Replaces ins with optimized opcodes. + * Returns TRUE if additional vregs were allocated. + */ +static gboolean +mono_strength_reduction_ins (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins, const char **spec) +{ + gboolean allocated_vregs = FALSE; + + /* FIXME: Add long/float */ + switch (ins->opcode) { + case OP_MOVE: + case OP_XMOVE: + if (ins->dreg == ins->sreg1) { + MONO_DELETE_INS (bb, ins); + } + break; + case OP_ADD_IMM: + case OP_IADD_IMM: + case OP_SUB_IMM: + case OP_ISUB_IMM: +#if SIZEOF_REGISTER == 8 + case OP_LADD_IMM: + case OP_LSUB_IMM: +#endif + if (ins->inst_imm == 0) { + ins->opcode = OP_MOVE; + } + break; + case OP_MUL_IMM: + case OP_IMUL_IMM: +#if SIZEOF_REGISTER == 8 + case OP_LMUL_IMM: +#endif + if (ins->inst_imm == 0) { + ins->opcode = (ins->opcode == OP_LMUL_IMM) ? OP_I8CONST : OP_ICONST; + ins->inst_c0 = 0; + ins->sreg1 = -1; + } else if (ins->inst_imm == 1) { + ins->opcode = OP_MOVE; + } else if ((ins->opcode == OP_IMUL_IMM) && (ins->inst_imm == -1)) { + ins->opcode = OP_INEG; + } else if ((ins->opcode == OP_LMUL_IMM) && (ins->inst_imm == -1)) { + ins->opcode = OP_LNEG; + } else { + int power2 = mono_is_power_of_two (ins->inst_imm); + if (power2 >= 0) { + ins->opcode = (ins->opcode == OP_MUL_IMM) ? OP_SHL_IMM : ((ins->opcode == OP_LMUL_IMM) ? OP_LSHL_IMM : OP_ISHL_IMM); + ins->inst_imm = power2; + } + } + break; + case OP_IREM_UN_IMM: + case OP_IDIV_UN_IMM: { + int c = ins->inst_imm; + int power2 = mono_is_power_of_two (c); + + if (power2 >= 0) { + if (ins->opcode == OP_IREM_UN_IMM) { + ins->opcode = OP_IAND_IMM; + ins->sreg2 = -1; + ins->inst_imm = (1 << power2) - 1; + } else if (ins->opcode == OP_IDIV_UN_IMM) { + ins->opcode = OP_ISHR_UN_IMM; + ins->sreg2 = -1; + ins->inst_imm = power2; + } + } + break; + } + case OP_IDIV_IMM: { + int c = ins->inst_imm; + int power2 = mono_is_power_of_two (c); + MonoInst *tmp1, *tmp2, *tmp3, *tmp4; + + /* FIXME: Move this elsewhere cause its hard to implement it here */ + if (power2 == 1) { + int r1 = mono_alloc_ireg (cfg); + + NEW_BIALU_IMM (cfg, tmp1, OP_ISHR_UN_IMM, r1, ins->sreg1, 31); + mono_bblock_insert_after_ins (bb, ins, tmp1); + NEW_BIALU (cfg, tmp2, OP_IADD, r1, r1, ins->sreg1); + mono_bblock_insert_after_ins (bb, tmp1, tmp2); + NEW_BIALU_IMM (cfg, tmp3, OP_ISHR_IMM, ins->dreg, r1, 1); + mono_bblock_insert_after_ins (bb, tmp2, tmp3); + + NULLIFY_INS (ins); + allocated_vregs = TRUE; + } else if (power2 > 0 && power2 < 31) { + int r1 = mono_alloc_ireg (cfg); + + NEW_BIALU_IMM (cfg, tmp1, OP_ISHR_IMM, r1, ins->sreg1, 31); + mono_bblock_insert_after_ins (bb, ins, tmp1); + NEW_BIALU_IMM (cfg, tmp2, OP_ISHR_UN_IMM, r1, r1, (32 - power2)); + mono_bblock_insert_after_ins (bb, tmp1, tmp2); + NEW_BIALU (cfg, tmp3, OP_IADD, r1, r1, ins->sreg1); + mono_bblock_insert_after_ins (bb, tmp2, tmp3); + NEW_BIALU_IMM (cfg, tmp4, OP_ISHR_IMM, ins->dreg, r1, power2); + mono_bblock_insert_after_ins (bb, tmp3, tmp4); + + NULLIFY_INS (ins); + allocated_vregs = TRUE; + } + break; + } + default: + break; + } + + *spec = INS_INFO (ins->opcode); + return allocated_vregs; +} + /* * mono_local_cprop: * @@ -280,112 +393,9 @@ restart: } /* Do strength reduction here */ - /* FIXME: Add long/float */ - switch (ins->opcode) { - case OP_MOVE: - case OP_XMOVE: - if (ins->dreg == ins->sreg1) { - MONO_DELETE_INS (bb, ins); - spec = INS_INFO (ins->opcode); - } - break; - case OP_ADD_IMM: - case OP_IADD_IMM: - case OP_SUB_IMM: - case OP_ISUB_IMM: -#if SIZEOF_REGISTER == 8 - case OP_LADD_IMM: - case OP_LSUB_IMM: -#endif - if (ins->inst_imm == 0) { - ins->opcode = OP_MOVE; - spec = INS_INFO (ins->opcode); - } - break; - case OP_MUL_IMM: - case OP_IMUL_IMM: -#if SIZEOF_REGISTER == 8 - case OP_LMUL_IMM: -#endif - if (ins->inst_imm == 0) { - ins->opcode = (ins->opcode == OP_LMUL_IMM) ? OP_I8CONST : OP_ICONST; - ins->inst_c0 = 0; - ins->sreg1 = -1; - } else if (ins->inst_imm == 1) { - ins->opcode = OP_MOVE; - } else if ((ins->opcode == OP_IMUL_IMM) && (ins->inst_imm == -1)) { - ins->opcode = OP_INEG; - } else if ((ins->opcode == OP_LMUL_IMM) && (ins->inst_imm == -1)) { - ins->opcode = OP_LNEG; - } else { - int power2 = mono_is_power_of_two (ins->inst_imm); - if (power2 >= 0) { - ins->opcode = (ins->opcode == OP_MUL_IMM) ? OP_SHL_IMM : ((ins->opcode == OP_LMUL_IMM) ? OP_LSHL_IMM : OP_ISHL_IMM); - ins->inst_imm = power2; - } - } - spec = INS_INFO (ins->opcode); - break; - case OP_IREM_UN_IMM: - case OP_IDIV_UN_IMM: { - int c = ins->inst_imm; - int power2 = mono_is_power_of_two (c); - - if (power2 >= 0) { - if (ins->opcode == OP_IREM_UN_IMM) { - ins->opcode = OP_IAND_IMM; - ins->sreg2 = -1; - ins->inst_imm = (1 << power2) - 1; - } else if (ins->opcode == OP_IDIV_UN_IMM) { - ins->opcode = OP_ISHR_UN_IMM; - ins->sreg2 = -1; - ins->inst_imm = power2; - } - } - spec = INS_INFO (ins->opcode); - break; - } - case OP_IDIV_IMM: { - int c = ins->inst_imm; - int power2 = mono_is_power_of_two (c); - MonoInst *tmp1, *tmp2, *tmp3, *tmp4; - - /* FIXME: Move this elsewhere cause its hard to implement it here */ - if (power2 == 1) { - int r1 = mono_alloc_ireg (cfg); - - NEW_BIALU_IMM (cfg, tmp1, OP_ISHR_UN_IMM, r1, ins->sreg1, 31); - mono_bblock_insert_after_ins (bb, ins, tmp1); - NEW_BIALU (cfg, tmp2, OP_IADD, r1, r1, ins->sreg1); - mono_bblock_insert_after_ins (bb, tmp1, tmp2); - NEW_BIALU_IMM (cfg, tmp3, OP_ISHR_IMM, ins->dreg, r1, 1); - mono_bblock_insert_after_ins (bb, tmp2, tmp3); - - NULLIFY_INS (ins); - - // We allocated a new vreg, so need to restart - goto restart; - } else if (power2 > 0 && power2 < 31) { - int r1 = mono_alloc_ireg (cfg); - - NEW_BIALU_IMM (cfg, tmp1, OP_ISHR_IMM, r1, ins->sreg1, 31); - mono_bblock_insert_after_ins (bb, ins, tmp1); - NEW_BIALU_IMM (cfg, tmp2, OP_ISHR_UN_IMM, r1, r1, (32 - power2)); - mono_bblock_insert_after_ins (bb, tmp1, tmp2); - NEW_BIALU (cfg, tmp3, OP_IADD, r1, r1, ins->sreg1); - mono_bblock_insert_after_ins (bb, tmp2, tmp3); - NEW_BIALU_IMM (cfg, tmp4, OP_ISHR_IMM, ins->dreg, r1, power2); - mono_bblock_insert_after_ins (bb, tmp3, tmp4); - - NULLIFY_INS (ins); - - // We allocated a new vreg, so need to restart - goto restart; - } - break; - } - } - + if (mono_strength_reduction_ins (cfg, bb, ins, &spec)) + goto restart; + if (spec [MONO_INST_DEST] != ' ') { MonoInst *def = defs [ins->dreg]; -- cgit v1.2.3 From 137c0999cc8e1e9171c7703af9b013f2e43731f5 Mon Sep 17 00:00:00 2001 From: Vlad Brezae Date: Wed, 23 Dec 2015 17:38:50 +0200 Subject: [jit] Don't allocate memory for unused vreg cfg->next_vreg is not an allocated vreg --- mono/mini/local-propagation.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mono/mini/local-propagation.c b/mono/mini/local-propagation.c index 145d8fbc28f..0282810f862 100644 --- a/mono/mini/local-propagation.c +++ b/mono/mini/local-propagation.c @@ -171,8 +171,8 @@ mono_local_cprop (MonoCompile *cfg) restart: max = cfg->next_vreg; - defs = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * (cfg->next_vreg + 1)); - def_index = (gint32 *)mono_mempool_alloc (cfg->mempool, sizeof (guint32) * (cfg->next_vreg + 1)); + defs = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * cfg->next_vreg); + def_index = (gint32 *)mono_mempool_alloc (cfg->mempool, sizeof (guint32) * cfg->next_vreg); for (bb = cfg->bb_entry; bb; bb = bb->next_bb) { MonoInst *ins; -- cgit v1.2.3 From da562c22e2fe6100e465598ef2baa96081ea9b52 Mon Sep 17 00:00:00 2001 From: Vlad Brezae Date: Wed, 23 Dec 2015 18:43:54 +0200 Subject: [jit] We don't need to restart cprop if optimizations allocate new vregs Definitions for these new vregs cannot exist yet since we just created the instructions and they will be scanned next. Just resize the def arrays. --- mono/mini/local-propagation.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/mono/mini/local-propagation.c b/mono/mini/local-propagation.c index 0282810f862..eb5f21d7fff 100644 --- a/mono/mini/local-propagation.c +++ b/mono/mini/local-propagation.c @@ -167,8 +167,7 @@ mono_local_cprop (MonoCompile *cfg) gint32 *def_index; int max; int filter = FILTER_IL_SEQ_POINT; - -restart: + int initial_max_vregs = cfg->next_vreg; max = cfg->next_vreg; defs = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * cfg->next_vreg); @@ -393,8 +392,23 @@ restart: } /* Do strength reduction here */ - if (mono_strength_reduction_ins (cfg, bb, ins, &spec)) - goto restart; + if (mono_strength_reduction_ins (cfg, bb, ins, &spec) && max < cfg->next_vreg) { + MonoInst **defs_prev = defs; + gint32 *def_index_prev = def_index; + guint32 prev_max = max; + guint32 additional_vregs = cfg->next_vreg - initial_max_vregs; + + /* We have more vregs so we need to reallocate defs and def_index arrays */ + max = initial_max_vregs + additional_vregs * 2; + defs = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * max); + def_index = (gint32 *)mono_mempool_alloc (cfg->mempool, sizeof (guint32) * max); + + /* Keep the entries for the previous vregs, zero the rest */ + memcpy (defs, defs_prev, sizeof (MonoInst*) * prev_max); + memset (defs + prev_max, 0, sizeof (MonoInst*) * (max - prev_max)); + memcpy (def_index, def_index_prev, sizeof (guint32) * prev_max); + memset (def_index + prev_max, 0, sizeof (guint32) * (max - prev_max)); + } if (spec [MONO_INST_DEST] != ' ') { MonoInst *def = defs [ins->dreg]; -- cgit v1.2.3 From f60b11a873bdacc152a5dfeb063b2dd9a8650b8f Mon Sep 17 00:00:00 2001 From: Vlad Brezae Date: Fri, 15 Jan 2016 16:20:51 -0800 Subject: [jit] Simplify strength reduction code emitting when running cprop We allocate a temporary bb where we can emit the optimization of an instruction. After doing strength reduction, we verify if the bb has instructions, in which case we need to replace the original instruction with the optimized code. --- mono/mini/local-propagation.c | 55 ++++++++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 22 deletions(-) diff --git a/mono/mini/local-propagation.c b/mono/mini/local-propagation.c index eb5f21d7fff..e9403d0a31b 100644 --- a/mono/mini/local-propagation.c +++ b/mono/mini/local-propagation.c @@ -43,10 +43,15 @@ mono_bitset_mp_new_noinit (MonoMemPool *mp, guint32 max_size) /* * Replaces ins with optimized opcodes. + * + * We can emit to cbb the equivalent instructions which will be used as + * replacement for ins, or simply change the fields of ins. Spec needs to + * be updated if we silently change the opcode of ins. + * * Returns TRUE if additional vregs were allocated. */ static gboolean -mono_strength_reduction_ins (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins, const char **spec) +mono_strength_reduction_ins (MonoCompile *cfg, MonoInst *ins, const char **spec) { gboolean allocated_vregs = FALSE; @@ -55,7 +60,7 @@ mono_strength_reduction_ins (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins case OP_MOVE: case OP_XMOVE: if (ins->dreg == ins->sreg1) { - MONO_DELETE_INS (bb, ins); + NULLIFY_INS (ins); } break; case OP_ADD_IMM: @@ -114,34 +119,23 @@ mono_strength_reduction_ins (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins case OP_IDIV_IMM: { int c = ins->inst_imm; int power2 = mono_is_power_of_two (c); - MonoInst *tmp1, *tmp2, *tmp3, *tmp4; - /* FIXME: Move this elsewhere cause its hard to implement it here */ if (power2 == 1) { int r1 = mono_alloc_ireg (cfg); - NEW_BIALU_IMM (cfg, tmp1, OP_ISHR_UN_IMM, r1, ins->sreg1, 31); - mono_bblock_insert_after_ins (bb, ins, tmp1); - NEW_BIALU (cfg, tmp2, OP_IADD, r1, r1, ins->sreg1); - mono_bblock_insert_after_ins (bb, tmp1, tmp2); - NEW_BIALU_IMM (cfg, tmp3, OP_ISHR_IMM, ins->dreg, r1, 1); - mono_bblock_insert_after_ins (bb, tmp2, tmp3); + MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, r1, ins->sreg1, 31); + MONO_EMIT_NEW_BIALU (cfg, OP_IADD, r1, r1, ins->sreg1); + MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_IMM, ins->dreg, r1, 1); - NULLIFY_INS (ins); allocated_vregs = TRUE; } else if (power2 > 0 && power2 < 31) { int r1 = mono_alloc_ireg (cfg); - NEW_BIALU_IMM (cfg, tmp1, OP_ISHR_IMM, r1, ins->sreg1, 31); - mono_bblock_insert_after_ins (bb, ins, tmp1); - NEW_BIALU_IMM (cfg, tmp2, OP_ISHR_UN_IMM, r1, r1, (32 - power2)); - mono_bblock_insert_after_ins (bb, tmp1, tmp2); - NEW_BIALU (cfg, tmp3, OP_IADD, r1, r1, ins->sreg1); - mono_bblock_insert_after_ins (bb, tmp2, tmp3); - NEW_BIALU_IMM (cfg, tmp4, OP_ISHR_IMM, ins->dreg, r1, power2); - mono_bblock_insert_after_ins (bb, tmp3, tmp4); + MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_IMM, r1, ins->sreg1, 31); + MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, r1, r1, (32 - power2)); + MONO_EMIT_NEW_BIALU (cfg, OP_IADD, r1, r1, ins->sreg1); + MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_IMM, ins->dreg, r1, power2); - NULLIFY_INS (ins); allocated_vregs = TRUE; } break; @@ -162,7 +156,7 @@ mono_strength_reduction_ins (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins void mono_local_cprop (MonoCompile *cfg) { - MonoBasicBlock *bb; + MonoBasicBlock *bb, *bb_opt; MonoInst **defs; gint32 *def_index; int max; @@ -172,6 +166,7 @@ mono_local_cprop (MonoCompile *cfg) max = cfg->next_vreg; defs = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * cfg->next_vreg); def_index = (gint32 *)mono_mempool_alloc (cfg->mempool, sizeof (guint32) * cfg->next_vreg); + cfg->cbb = bb_opt = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock)); for (bb = cfg->bb_entry; bb; bb = bb->next_bb) { MonoInst *ins; @@ -391,8 +386,10 @@ mono_local_cprop (MonoCompile *cfg) } } + g_assert (cfg->cbb == bb_opt); + g_assert (!bb_opt->code); /* Do strength reduction here */ - if (mono_strength_reduction_ins (cfg, bb, ins, &spec) && max < cfg->next_vreg) { + if (mono_strength_reduction_ins (cfg, ins, &spec) && max < cfg->next_vreg) { MonoInst **defs_prev = defs; gint32 *def_index_prev = def_index; guint32 prev_max = max; @@ -410,6 +407,20 @@ mono_local_cprop (MonoCompile *cfg) memset (def_index + prev_max, 0, sizeof (guint32) * (max - prev_max)); } + if (cfg->cbb->code || (cfg->cbb != bb_opt)) { + MonoInst *saved_prev = ins->prev; + + /* If we have code in cbb, we need to replace ins with the decomposition */ + mono_replace_ins (cfg, bb, ins, &ins->prev, bb_opt, cfg->cbb); + bb_opt->code = bb_opt->last_ins = NULL; + bb_opt->in_count = bb_opt->out_count = 0; + cfg->cbb = bb_opt; + + /* ins is hanging, continue scanning the emitted code */ + ins = saved_prev; + continue; + } + if (spec [MONO_INST_DEST] != ' ') { MonoInst *def = defs [ins->dreg]; -- cgit v1.2.3 From dbd9b34fe30bb353817fd52cf54a5e3ab72ce993 Mon Sep 17 00:00:00 2001 From: Vlad Brezae Date: Wed, 23 Dec 2015 19:40:05 +0200 Subject: [jit] Move optimization to cprop in order to handle more cases Cprop can convert more binops to their _IMM counterpart, which would otherwise not be detected at method_to_ir time, allowing us to do strength reduction. --- mono/mini/decompose.c | 41 ----------------------------------------- mono/mini/local-propagation.c | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 41 deletions(-) diff --git a/mono/mini/decompose.c b/mono/mini/decompose.c index fa59554351b..7eb45ddaa2b 100644 --- a/mono/mini/decompose.c +++ b/mono/mini/decompose.c @@ -472,47 +472,6 @@ mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins) } 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); - - NULLIFY_INS (ins); - } -#endif - break; - } - default: emulate = TRUE; break; diff --git a/mono/mini/local-propagation.c b/mono/mini/local-propagation.c index e9403d0a31b..eb0749ecc11 100644 --- a/mono/mini/local-propagation.c +++ b/mono/mini/local-propagation.c @@ -140,6 +140,47 @@ 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; + } + default: break; } -- cgit v1.2.3