Implement division/remainder in hardware when using armv7s+llvm+thumb.
authorZoltan Varga <vargaz@gmail.com>
Fri, 3 May 2013 17:50:16 +0000 (19:50 +0200)
committerZoltan Varga <vargaz@gmail.com>
Fri, 3 May 2013 17:50:16 +0000 (19:50 +0200)
mono/mini/decompose.c
mono/mini/mini-arm.c
mono/mini/mini-arm.h
mono/mini/mini.h

index b86678d4e2305694c31a6a5706e162f09f10af0e..c15502818fbd048bd473e1c25b3f31d497bb8688 100644 (file)
@@ -269,6 +269,7 @@ mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins)
        MonoInst *repl = NULL;
        int type = ins->type;
        int dreg = ins->dreg;
+       gboolean emulate = FALSE;
 
        /* FIXME: Instead of = NOP, don't emit the original ins at all */
 
@@ -410,18 +411,55 @@ mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins)
                cfg->exception_message = g_strdup_printf ("float conv.ovf.un opcodes not supported.");
                break;
 
-       default: {
-               MonoJitICallInfo *info;
+#if defined(MONO_ARCH_EMULATE_DIV) && defined(MONO_ARCH_HAVE_OPCODE_NEEDS_EMULATION)
+       case OP_IDIV:
+       case OP_IREM:
+       case OP_IDIV_UN:
+       case OP_IREM_UN:
+               if (!mono_arch_opcode_needs_emulation (cfg, ins->opcode)) {
+#ifdef MONO_ARCH_NEED_DIV_CHECK
+                       int reg1 = alloc_ireg (cfg);
+                       int reg2 = alloc_ireg (cfg);
+                       /* b == 0 */
+                       MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg2, 0);
+                       MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "DivideByZeroException");
+                       if (ins->opcode == OP_IDIV || ins->opcode == OP_IREM) {
+                               /* b == -1 && a == 0x80000000 */
+                               MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg2, -1);
+                               MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, reg1, -1);
+                               MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0x80000000);
+                               MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, reg2, -1);
+                               MONO_EMIT_NEW_BIALU (cfg, OP_IAND, reg1, reg1, reg2);
+                               MONO_EMIT_NEW_ICOMPARE_IMM (cfg, reg1, 1);
+                               MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "DivideByZeroException");
+                       }
+#endif
+                       MONO_EMIT_NEW_BIALU (cfg, ins->opcode, ins->dreg, ins->sreg1, ins->sreg2);
+                       ins->opcode = OP_NOP;
+               } else {
+                       emulate = TRUE;
+               }
+               break;
+#endif
+
+       default:
+               emulate = TRUE;
+               break;
+       }
+
+       if (emulate) {
+               MonoJitICallInfo *info = NULL;
 
 #if SIZEOF_REGISTER == 8
                if (decompose_long_opcode (cfg, ins, &repl))
-                       break;
+                       emulate = FALSE;
 #else
                if (COMPILE_LLVM (cfg) && decompose_long_opcode (cfg, ins, &repl))
-                       break;
+                       emulate = FALSE;
 #endif
 
-               info = mono_find_jit_opcode_emulation (ins->opcode);
+               if (emulate)
+                       info = mono_find_jit_opcode_emulation (ins->opcode);
                if (info) {
                        MonoInst **args;
                        MonoInst *call;
@@ -447,8 +485,6 @@ mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins)
 
                        NULLIFY_INS (ins);
                }
-               break;
-       }
        }
 
        if (ins->opcode == OP_NOP) {
index 99d84ec657d431df2bc3cfff5566109a69b06cd3..e4fb334c932987b2181a6e12a5ac754166aa642a 100644 (file)
@@ -91,7 +91,9 @@ static CRITICAL_SECTION mini_arch_mutex;
 static int v5_supported = 0;
 static int v6_supported = 0;
 static int v7_supported = 0;
+static int v7s_supported = 0;
 static int thumb_supported = 0;
+static int thumb2_supported = 0;
 /*
  * Whenever to use the ARM EABI
  */
@@ -898,6 +900,23 @@ mono_arch_cpu_enumerate_simd_versions (void)
 
 #ifndef DISABLE_JIT
 
+gboolean
+mono_arch_opcode_needs_emulation (MonoCompile *cfg, int opcode)
+{
+       if (COMPILE_LLVM (cfg) && v7s_supported && thumb2_supported) {
+               switch (opcode) {
+               case OP_IDIV:
+               case OP_IREM:
+               case OP_IDIV_UN:
+               case OP_IREM_UN:
+                       return FALSE;
+               default:
+                       break;
+               }
+       }
+       return TRUE;
+}
+
 static gboolean
 is_regsize_var (MonoGenericSharingContext *gsctx, MonoType *t) {
        if (t->byref)
@@ -6628,6 +6647,10 @@ mono_arch_set_target (char *mtriple)
        if (strstr (mtriple, "armv6")) {
                v6_supported = TRUE;
        }
+       if (strstr (mtriple, "thumbv7s")) {
+               v7s_supported = TRUE;
+               thumb2_supported = TRUE;
+       }
        if (strstr (mtriple, "darwin") || strstr (mtriple, "ios")) {
                v5_supported = TRUE;
                thumb_supported = TRUE;
index f8aae7b9ac229a399b073fec5aaceb378e89828f..4d0eb4525ced37850e36417d36c178edb3fbf6f6 100644 (file)
@@ -231,6 +231,7 @@ typedef struct MonoCompileArch {
 #define MONO_ARCH_HAVE_SETUP_RESUME_FROM_SIGNAL_HANDLER_CTX 1
 #define MONO_ARCH_GSHAREDVT_SUPPORTED 1
 #define MONO_ARCH_HAVE_GENERAL_RGCTX_LAZY_FETCH_TRAMPOLINE 1
+#define MONO_ARCH_HAVE_OPCODE_NEEDS_EMULATION 1
 
 #if defined(__native_client__)
 #undef MONO_ARCH_SOFT_DEBUG_SUPPORTED
index 5f64c2ef1b4b9901af828173441a27f7ab5ba590..ecac3e393a7c43082ec337e3a6b93f65fe40f8d3 100644 (file)
@@ -2188,6 +2188,7 @@ void      mono_arch_set_target                  (char *mtriple) MONO_INTERNAL;
 gboolean  mono_arch_gsharedvt_sig_supported     (MonoMethodSignature *sig) MONO_INTERNAL;
 gpointer  mono_arch_get_gsharedvt_trampoline    (MonoTrampInfo **info, gboolean aot) MONO_INTERNAL;
 gpointer  mono_arch_get_gsharedvt_call_info     (gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, MonoGenericSharingContext *gsctx, gboolean gsharedvt_in, gint32 vcall_offset, gboolean calli) MONO_INTERNAL;
+gboolean  mono_arch_opcode_needs_emulation      (MonoCompile *cfg, int opcode) MONO_INTERNAL;
 
 /* Soft Debug support */
 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED