[jit] Decompose long immediate shifts
authorVlad Brezae <brezaevlad@gmail.com>
Wed, 10 Feb 2016 09:55:17 +0000 (11:55 +0200)
committerVlad Brezae <brezaevlad@gmail.com>
Mon, 11 Apr 2016 16:21:32 +0000 (19:21 +0300)
We decompose them as part of the cprop pass to handle more immediates and to further propagate copies.

The native backend of some architectures (for example x86) may support long shifts with specialized instructions. Even there, this still makes immediate shifts 2 times faster because long ops are poorly handled by the jit.

On arm, where we were emulating, this makes long immediate shifts 3-5 times faster.

mono/mini/decompose.c
mono/mini/local-propagation.c

index 10c8c75e134d359dd829d023521131246a1f8f67..187bf138f1e0422e8de39d90e77e1a27d001b6d3 100644 (file)
@@ -932,6 +932,8 @@ mono_decompose_long_opts (MonoCompile *cfg)
                                MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
                                MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
                                break;
+#ifdef TARGET_POWERPC
+/* FIXME This is normally handled in cprop. Proper fix or remove if no longer needed. */
                        case OP_LSHR_UN_IMM:
                                if (tree->inst_c1 == 32) {
 
@@ -940,20 +942,12 @@ mono_decompose_long_opts (MonoCompile *cfg)
                                         * later apply the speedup to the left shift as well
                                         * See BUG# 57957.
                                         */
-                                       /* FIXME: Move this to the strength reduction pass */
                                        /* just move the upper half to the lower and zero the high word */
                                        MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
                                        MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
                                }
                                break;
-                       case OP_LSHL_IMM:
-                               if (tree->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 (tree->dreg), MONO_LVREG_LS (tree->sreg1));
-                                       MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_LS (tree->dreg), 0);
-                               }
-                               break;
-
+#endif
                        case OP_LCOMPARE: {
                                MonoInst *next = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
 
index 2120fa08728e6c39a3863b4ab80ce95dc3c5b499..dc159106eb01a32ef9fa71c427674ce5a2c3f651 100644 (file)
@@ -180,6 +180,69 @@ mono_strength_reduction_ins (MonoCompile *cfg, MonoInst *ins, const char **spec)
 #endif
                break;
        }
+#if SIZEOF_REGISTER == 4
+       case OP_LSHR_IMM: {
+               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 (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 (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;