Enable hw division/remainder on mt in non-thumb mode as well.
authorZoltan Varga <vargaz@gmail.com>
Tue, 14 May 2013 16:27:32 +0000 (18:27 +0200)
committerZoltan Varga <vargaz@gmail.com>
Tue, 14 May 2013 16:27:32 +0000 (18:27 +0200)
mono/arch/arm/arm-codegen.h
mono/mini/cpu-arm.md
mono/mini/mini-arm.c

index 31c457507550b27fa67ca79ba78ef9b0a6af8bdb..d94653e4402926313bfd24305dcfe7470e7d6508 100644 (file)
@@ -1037,6 +1037,7 @@ typedef struct {
 #define ARM_INC(p, reg) ARM_ADD_REG_IMM8(p, reg, reg, 1)
 #define ARM_DEC(p, reg) ARM_SUB_REG_IMM8(p, reg, reg, 1)
 
+#define ARM_MLS(p, rd, rn, rm, ra) ARM_EMIT((p), (ARMCOND_AL << 28) | (0x6 << 20) | ((rd) << 16) | ((ra) << 12) | ((rm) << 8) | (0x9 << 4) | ((rn) << 0))
 
 /* ARM V5 */
 
@@ -1095,6 +1096,13 @@ typedef union {
 #define ARM_MCR(p, coproc, opc1, rt, crn, crm, opc2) \
        ARM_MCR_COND ((p), (coproc), (opc1), (rt), (crn), (crm), (opc2), ARMCOND_AL)
 
+/* ARMv7VE */
+#define ARM_SDIV_COND(p, rd, rn, rm, cond) ARM_EMIT (p, (((cond) << 28) | (0xe << 23) | (0x1 << 20) | ((rd) << 16) | (0xf << 12) | ((rm) << 8) | (0x0 << 5) | (0x1 << 4) | ((rn) << 0)))
+#define ARM_SDIV(p, rd, rn, rm) ARM_SDIV_COND ((p), (rd), (rn), (rm), ARMCOND_AL)
+
+#define ARM_UDIV_COND(p, rd, rn, rm, cond) ARM_EMIT (p, (((cond) << 28) | (0xe << 23) | (0x3 << 20) | ((rd) << 16) | (0xf << 12) | ((rm) << 8) | (0x0 << 5) | (0x1 << 4) | ((rn) << 0)))
+#define ARM_UDIV(p, rd, rn, rm) ARM_UDIV_COND ((p), (rd), (rn), (rm), ARMCOND_AL)
+
 #ifdef __cplusplus
 }
 #endif
index fc873899a61b7bda2fa9e0a2ce23af502b536896..0ff8a13f839d70f0fb2aa495dafc4b64ca3f0de5 100644 (file)
@@ -212,10 +212,10 @@ tls_get: len:8 dest:i clob:c
 int_add: dest:i src1:i src2:i len:4
 int_sub: dest:i src1:i src2:i len:4
 int_mul: dest:i src1:i src2:i len:4
-int_div: dest:i src1:i src2:i len:40
-int_div_un: dest:i src1:i src2:i len:16
-int_rem: dest:i src1:i src2:i len:48
-int_rem_un: dest:i src1:i src2:i len:24
+int_div: dest:i src1:i src2:i len:4
+int_div_un: dest:i src1:i src2:i len:4
+int_rem: dest:i src1:i src2:i len:8
+int_rem_un: dest:i src1:i src2:i len:8
 int_and: dest:i src1:i src2:i len:4
 int_or: dest:i src1:i src2:i len:4
 int_xor: dest:i src1:i src2:i len:4
index 295e45e5a015247ff176279fb51705497740a342..a092e077d174a1baf6d331b70035db6b68509da6 100644 (file)
@@ -891,7 +891,7 @@ mono_arch_cpu_enumerate_simd_versions (void)
 gboolean
 mono_arch_opcode_needs_emulation (MonoCompile *cfg, int opcode)
 {
-       if (COMPILE_LLVM (cfg) && v7s_supported) {
+       if (v7s_supported) {
                switch (opcode) {
                case OP_IDIV:
                case OP_IREM:
@@ -2947,6 +2947,16 @@ loop_start:
                                /* ARM sets the C flag to 1 if there was _no_ overflow */
                                ins->next->opcode = OP_COND_EXC_NC;
                        break;
+               case OP_IDIV_IMM:
+               case OP_IDIV_UN_IMM:
+               case OP_IREM_IMM:
+               case OP_IREM_UN_IMM:
+                       ADD_NEW_INS (cfg, temp, OP_ICONST);
+                       temp->inst_c0 = ins->inst_imm;
+                       temp->dreg = mono_alloc_ireg (cfg);
+                       ins->sreg2 = temp->dreg;
+                       ins->opcode = mono_op_imm_to_op (ins->opcode);
+                       break;
                case OP_LOCALLOC_IMM:
                        ADD_NEW_INS (cfg, temp, OP_ICONST);
                        temp->inst_c0 = ins->inst_imm;
@@ -4099,12 +4109,25 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        ARM_AND_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
                        break;
                case OP_IDIV:
+                       g_assert (v7s_supported);
+                       ARM_SDIV (code, ins->dreg, ins->sreg1, ins->sreg2);
+                       break;
                case OP_IDIV_UN:
-               case OP_DIV_IMM:
+                       g_assert (v7s_supported);
+                       ARM_UDIV (code, ins->dreg, ins->sreg1, ins->sreg2);
+                       break;
                case OP_IREM:
+                       g_assert (v7s_supported);
+                       ARM_SDIV (code, ARMREG_IP, ins->sreg1, ins->sreg2);
+                       ARM_MLS (code, ins->dreg, ARMREG_IP, ins->sreg2, ins->sreg1);
+                       break;
                case OP_IREM_UN:
+                       g_assert (v7s_supported);
+                       ARM_UDIV (code, ARMREG_IP, ins->sreg1, ins->sreg2);
+                       ARM_MLS (code, ins->dreg, ARMREG_IP, ins->sreg2, ins->sreg1);
+                       break;
+               case OP_DIV_IMM:
                case OP_REM_IMM:
-                       /* crappy ARM arch doesn't have a DIV instruction */
                        g_assert_not_reached ();
                case OP_IOR:
                        ARM_ORR_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
@@ -6482,6 +6505,9 @@ mono_arch_set_target (char *mtriple)
        if (strstr (mtriple, "armv6")) {
                v6_supported = TRUE;
        }
+       if (strstr (mtriple, "armv7s")) {
+               v7s_supported = TRUE;
+       }
        if (strstr (mtriple, "thumbv7s")) {
                v7s_supported = TRUE;
                thumb2_supported = TRUE;