[jit] Refactor strength reduction handling within mono_local_cprop
authorVlad Brezae <brezaevlad@gmail.com>
Wed, 23 Dec 2015 15:01:40 +0000 (17:01 +0200)
committerVlad Brezae <brezaevlad@gmail.com>
Fri, 15 Jan 2016 22:37:47 +0000 (14:37 -0800)
mono/mini/local-propagation.c

index aa2a934f556215633115d9cce999a9b6361575d7..145d8fbc28f0c9d7b0ef9170be3a5830dfddaa4a 100644 (file)
@@ -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];