Merge pull request #2736 from xmcclure/more-trampolines
[mono.git] / mono / mini / local-propagation.c
index e9403d0a31b3c3cb09cd76abec1d12a648032af8..2120fa08728e6c39a3863b4ab80ce95dc3c5b499 100644 (file)
@@ -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;
        }
@@ -178,22 +219,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 +430,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);
                                }
                        }