Merge pull request #1150 from ludovic-henry/pr17c-delegate-trampoline
[mono.git] / mono / mini / decompose.c
index e9536e9f5291970756ddec139cbdf78df2d270fa..07242d86138e0ce371119ddffa80e7d85e9861fe 100644 (file)
@@ -13,6 +13,7 @@
 #include "jit-icalls.h"
 
 #include <mono/metadata/gc-internal.h>
+#include <mono/metadata/abi-details.h>
 
 #ifndef DISABLE_JIT
 
@@ -476,6 +477,43 @@ mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins)
                break;
 #endif
 
+#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;
+               } 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_SHR_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_SHR_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);
+               }
+               break;
+       }
+
        default:
                emulate = TRUE;
                break;
@@ -1519,7 +1557,7 @@ mono_decompose_array_access_opts (MonoCompile *cfg)
                                switch (ins->opcode) {
                                case OP_LDLEN:
                                        NEW_LOAD_MEMBASE_FLAGS (cfg, dest, OP_LOADI4_MEMBASE, ins->dreg, ins->sreg1,
-                                                                                       G_STRUCT_OFFSET (MonoArray, max_length), ins->flags | MONO_INST_INVARIANT_LOAD);
+                                                                                       MONO_STRUCT_OFFSET (MonoArray, max_length), ins->flags | MONO_INST_INVARIANT_LOAD);
                                        MONO_ADD_INS (cfg->cbb, dest);
                                        break;
                                case OP_BOUNDS_CHECK:
@@ -1558,7 +1596,7 @@ mono_decompose_array_access_opts (MonoCompile *cfg)
                                        break;
                                case OP_STRLEN:
                                        MONO_EMIT_NEW_LOAD_MEMBASE_OP_FLAGS (cfg, OP_LOADI4_MEMBASE, ins->dreg,
-                                                                                                                ins->sreg1, G_STRUCT_OFFSET (MonoString, length), ins->flags | MONO_INST_INVARIANT_LOAD);
+                                                                                                                ins->sreg1, MONO_STRUCT_OFFSET (MonoString, length), ins->flags | MONO_INST_INVARIANT_LOAD);
                                        break;
                                default:
                                        break;