#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 */
#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
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
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:
/* 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;
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);
if (strstr (mtriple, "armv6")) {
v6_supported = TRUE;
}
+ if (strstr (mtriple, "armv7s")) {
+ v7s_supported = TRUE;
+ }
if (strstr (mtriple, "thumbv7s")) {
v7s_supported = TRUE;
thumb2_supported = TRUE;