[jit] Simplify strength reduction code emitting when running cprop
authorVlad Brezae <brezaevlad@gmail.com>
Sat, 16 Jan 2016 00:20:51 +0000 (16:20 -0800)
committerVlad Brezae <brezaevlad@gmail.com>
Sat, 16 Jan 2016 01:19:27 +0000 (17:19 -0800)
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

index eb5f21d7fff06d1cc872cf48aa86c840fb6035ce..e9403d0a31b3c3cb09cd76abec1d12a648032af8 100644 (file)
@@ -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];