summaryrefslogtreecommitdiffstats
path: root/qemu/tcg/mips
diff options
context:
space:
mode:
Diffstat (limited to 'qemu/tcg/mips')
-rw-r--r--qemu/tcg/mips/tcg-target.h11
-rw-r--r--qemu/tcg/mips/tcg-target.inc.c (renamed from qemu/tcg/mips/tcg-target.c)273
2 files changed, 179 insertions, 105 deletions
diff --git a/qemu/tcg/mips/tcg-target.h b/qemu/tcg/mips/tcg-target.h
index f5ba52cac..b1cda37b6 100644
--- a/qemu/tcg/mips/tcg-target.h
+++ b/qemu/tcg/mips/tcg-target.h
@@ -96,6 +96,13 @@ extern bool use_mips32_instructions;
extern bool use_mips32r2_instructions;
#endif
+/* MIPS32R6 instruction set detection */
+#if defined(__mips_isa_rev) && (__mips_isa_rev >= 6)
+#define use_mips32r6_instructions 1
+#else
+#define use_mips32r6_instructions 0
+#endif
+
/* optional instructions */
#define TCG_TARGET_HAS_div_i32 1
#define TCG_TARGET_HAS_rem_i32 1
@@ -105,8 +112,8 @@ extern bool use_mips32r2_instructions;
#define TCG_TARGET_HAS_orc_i32 0
#define TCG_TARGET_HAS_eqv_i32 0
#define TCG_TARGET_HAS_nand_i32 0
-#define TCG_TARGET_HAS_mulu2_i32 1
-#define TCG_TARGET_HAS_muls2_i32 1
+#define TCG_TARGET_HAS_mulu2_i32 (!use_mips32r6_instructions)
+#define TCG_TARGET_HAS_muls2_i32 (!use_mips32r6_instructions)
#define TCG_TARGET_HAS_muluh_i32 1
#define TCG_TARGET_HAS_mulsh_i32 1
diff --git a/qemu/tcg/mips/tcg-target.c b/qemu/tcg/mips/tcg-target.inc.c
index e97980df0..aaf881cfd 100644
--- a/qemu/tcg/mips/tcg-target.c
+++ b/qemu/tcg/mips/tcg-target.inc.c
@@ -35,7 +35,7 @@
#define LO_OFF (MIPS_BE * 4)
#define HI_OFF (4 - LO_OFF)
-#ifndef NDEBUG
+#ifdef CONFIG_DEBUG_TCG
static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
"zero",
"at",
@@ -76,7 +76,7 @@ static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
#define TCG_TMP1 TCG_REG_T9
/* check if we really need so many registers :P */
-static const TCGReg tcg_target_reg_alloc_order[] = {
+static const int tcg_target_reg_alloc_order[] = {
/* Call saved registers. */
TCG_REG_S0,
TCG_REG_S1,
@@ -127,7 +127,7 @@ static inline uint32_t reloc_pc16_val(tcg_insn_unit *pc, tcg_insn_unit *target)
{
/* Let the compiler perform the right-shift as part of the arithmetic. */
ptrdiff_t disp = target - (pc + 1);
- assert(disp == (int16_t)disp);
+ tcg_debug_assert(disp == (int16_t)disp);
return disp & 0xffff;
}
@@ -138,7 +138,7 @@ static inline void reloc_pc16(tcg_insn_unit *pc, tcg_insn_unit *target)
static inline uint32_t reloc_26_val(tcg_insn_unit *pc, tcg_insn_unit *target)
{
- assert((((uintptr_t)pc ^ (uintptr_t)target) & 0xf0000000) == 0);
+ tcg_debug_assert((((uintptr_t)pc ^ (uintptr_t)target) & 0xf0000000) == 0);
return ((uintptr_t)target >> 2) & 0x3ffffff;
}
@@ -150,8 +150,8 @@ static inline void reloc_26(tcg_insn_unit *pc, tcg_insn_unit *target)
static void patch_reloc(tcg_insn_unit *code_ptr, int type,
intptr_t value, intptr_t addend)
{
- assert(type == R_MIPS_PC16);
- assert(addend == 0);
+ tcg_debug_assert(type == R_MIPS_PC16);
+ tcg_debug_assert(addend == 0);
reloc_pc16(code_ptr, (tcg_insn_unit *)value);
}
@@ -288,16 +288,24 @@ typedef enum {
OPC_SRLV = OPC_SPECIAL | 0x06,
OPC_ROTRV = OPC_SPECIAL | (0x01 << 6) | 0x06,
OPC_SRAV = OPC_SPECIAL | 0x07,
- OPC_JR = OPC_SPECIAL | 0x08,
+ OPC_JR_R5 = OPC_SPECIAL | 0x08,
OPC_JALR = OPC_SPECIAL | 0x09,
OPC_MOVZ = OPC_SPECIAL | 0x0A,
OPC_MOVN = OPC_SPECIAL | 0x0B,
OPC_MFHI = OPC_SPECIAL | 0x10,
OPC_MFLO = OPC_SPECIAL | 0x12,
OPC_MULT = OPC_SPECIAL | 0x18,
+ OPC_MUL_R6 = OPC_SPECIAL | (0x02 << 6) | 0x18,
+ OPC_MUH = OPC_SPECIAL | (0x03 << 6) | 0x18,
OPC_MULTU = OPC_SPECIAL | 0x19,
+ OPC_MULU = OPC_SPECIAL | (0x02 << 6) | 0x19,
+ OPC_MUHU = OPC_SPECIAL | (0x03 << 6) | 0x19,
OPC_DIV = OPC_SPECIAL | 0x1A,
+ OPC_DIV_R6 = OPC_SPECIAL | (0x02 << 6) | 0x1A,
+ OPC_MOD = OPC_SPECIAL | (0x03 << 6) | 0x1A,
OPC_DIVU = OPC_SPECIAL | 0x1B,
+ OPC_DIVU_R6 = OPC_SPECIAL | (0x02 << 6) | 0x1B,
+ OPC_MODU = OPC_SPECIAL | (0x03 << 6) | 0x1B,
OPC_ADDU = OPC_SPECIAL | 0x21,
OPC_SUBU = OPC_SPECIAL | 0x23,
OPC_AND = OPC_SPECIAL | 0x24,
@@ -306,13 +314,15 @@ typedef enum {
OPC_NOR = OPC_SPECIAL | 0x27,
OPC_SLT = OPC_SPECIAL | 0x2A,
OPC_SLTU = OPC_SPECIAL | 0x2B,
+ OPC_SELEQZ = OPC_SPECIAL | 0x35,
+ OPC_SELNEZ = OPC_SPECIAL | 0x37,
OPC_REGIMM = 0x01 << 26,
OPC_BLTZ = OPC_REGIMM | (0x00 << 16),
OPC_BGEZ = OPC_REGIMM | (0x01 << 16),
OPC_SPECIAL2 = 0x1c << 26,
- OPC_MUL = OPC_SPECIAL2 | 0x002,
+ OPC_MUL_R5 = OPC_SPECIAL2 | 0x002,
OPC_SPECIAL3 = 0x1f << 26,
OPC_EXT = OPC_SPECIAL3 | 0x000,
@@ -320,6 +330,15 @@ typedef enum {
OPC_WSBH = OPC_SPECIAL3 | 0x0a0,
OPC_SEB = OPC_SPECIAL3 | 0x420,
OPC_SEH = OPC_SPECIAL3 | 0x620,
+
+ /* MIPS r6 doesn't have JR, JALR should be used instead */
+ OPC_JR = use_mips32r6_instructions ? OPC_JALR : OPC_JR_R5,
+
+ /*
+ * MIPS r6 replaces MUL with an alternative encoding which is
+ * backwards-compatible at the assembly level.
+ */
+ OPC_MUL = use_mips32r6_instructions ? OPC_MUL_R6 : OPC_MUL_R5,
} MIPSInsn;
/*
@@ -413,7 +432,7 @@ static bool tcg_out_opc_jmp(TCGContext *s, MIPSInsn opc, void *target)
if ((from ^ dest) & -(1 << 28)) {
return false;
}
- assert((dest & 3) == 0);
+ tcg_debug_assert((dest & 3) == 0);
inst = opc;
inst |= (dest >> 2) & 0x3ffffff;
@@ -567,6 +586,55 @@ static inline void tcg_out_addi(TCGContext *s, TCGReg reg, TCGArg val)
}
}
+static void tcg_out_addsub2(TCGContext *s, TCGReg rl, TCGReg rh, TCGReg al,
+ TCGReg ah, TCGArg bl, TCGArg bh, bool cbl,
+ bool cbh, bool is_sub)
+{
+ TCGReg th = TCG_TMP1;
+
+ /* If we have a negative constant such that negating it would
+ make the high part zero, we can (usually) eliminate one insn. */
+ if (cbl && cbh && bh == -1 && bl != 0) {
+ bl = -bl;
+ bh = 0;
+ is_sub = !is_sub;
+ }
+
+ /* By operating on the high part first, we get to use the final
+ carry operation to move back from the temporary. */
+ if (!cbh) {
+ tcg_out_opc_reg(s, (is_sub ? OPC_SUBU : OPC_ADDU), th, ah, bh);
+ } else if (bh != 0 || ah == rl) {
+ tcg_out_opc_imm(s, OPC_ADDIU, th, ah, (is_sub ? -bh : bh));
+ } else {
+ th = ah;
+ }
+
+ /* Note that tcg optimization should eliminate the bl == 0 case. */
+ if (is_sub) {
+ if (cbl) {
+ tcg_out_opc_imm(s, OPC_SLTIU, TCG_TMP0, al, bl);
+ tcg_out_opc_imm(s, OPC_ADDIU, rl, al, -bl);
+ } else {
+ tcg_out_opc_reg(s, OPC_SLTU, TCG_TMP0, al, bl);
+ tcg_out_opc_reg(s, OPC_SUBU, rl, al, bl);
+ }
+ tcg_out_opc_reg(s, OPC_SUBU, rh, th, TCG_TMP0);
+ } else {
+ if (cbl) {
+ tcg_out_opc_imm(s, OPC_ADDIU, rl, al, bl);
+ tcg_out_opc_imm(s, OPC_SLTIU, TCG_TMP0, rl, bl);
+ } else if (rl == al && rl == bl) {
+ tcg_out_opc_sa(s, OPC_SRL, TCG_TMP0, al, 31);
+ tcg_out_opc_reg(s, OPC_ADDU, rl, al, bl);
+ } else {
+ tcg_out_opc_reg(s, OPC_ADDU, rl, al, bl);
+ tcg_out_opc_reg(s, OPC_SLTU, TCG_TMP0, rl, (rl == bl ? al : bl));
+ }
+ tcg_out_opc_reg(s, OPC_ADDU, rh, th, TCG_TMP0);
+ }
+}
+
/* Bit 0 set if inversion required; bit 1 set if swapping required. */
#define MIPS_CMP_INV 1
#define MIPS_CMP_SWAP 2
@@ -739,9 +807,9 @@ static void tcg_out_setcond2(TCGContext *s, TCGCond cond, TCGReg ret,
TCGReg tmp0 = TCG_TMP0;
TCGReg tmp1 = ret;
- assert(ret != TCG_TMP0);
+ tcg_debug_assert(ret != TCG_TMP0);
if (ret == ah || ret == bh) {
- assert(ret != TCG_TMP1);
+ tcg_debug_assert(ret != TCG_TMP1);
tmp1 = TCG_TMP1;
}
@@ -792,13 +860,20 @@ static void tcg_out_brcond2(TCGContext *s, TCGCond cond, TCGReg al, TCGReg ah,
}
static void tcg_out_movcond(TCGContext *s, TCGCond cond, TCGReg ret,
- TCGReg c1, TCGReg c2, TCGReg v)
+ TCGReg c1, TCGReg c2, TCGReg v1, TCGReg v2)
{
- MIPSInsn m_opc = OPC_MOVN;
+ bool eqz = false;
+
+ /* If one of the values is zero, put it last to match SEL*Z instructions */
+ if (use_mips32r6_instructions && v1 == 0) {
+ v1 = v2;
+ v2 = 0;
+ cond = tcg_invert_cond(cond);
+ }
switch (cond) {
case TCG_COND_EQ:
- m_opc = OPC_MOVZ;
+ eqz = true;
/* FALLTHRU */
case TCG_COND_NE:
if (c2 != 0) {
@@ -811,14 +886,32 @@ static void tcg_out_movcond(TCGContext *s, TCGCond cond, TCGReg ret,
/* Minimize code size by preferring a compare not requiring INV. */
if (mips_cmp_map[cond] & MIPS_CMP_INV) {
cond = tcg_invert_cond(cond);
- m_opc = OPC_MOVZ;
+ eqz = true;
}
tcg_out_setcond(s, cond, TCG_TMP0, c1, c2);
c1 = TCG_TMP0;
break;
}
- tcg_out_opc_reg(s, m_opc, ret, v, c1);
+ if (use_mips32r6_instructions) {
+ MIPSInsn m_opc_t = eqz ? OPC_SELEQZ : OPC_SELNEZ;
+ MIPSInsn m_opc_f = eqz ? OPC_SELNEZ : OPC_SELEQZ;
+
+ if (v2 != 0) {
+ tcg_out_opc_reg(s, m_opc_f, TCG_TMP1, v2, c1);
+ }
+ tcg_out_opc_reg(s, m_opc_t, ret, v1, c1);
+ if (v2 != 0) {
+ tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_TMP1);
+ }
+ } else {
+ MIPSInsn m_opc = eqz ? OPC_MOVZ : OPC_MOVN;
+
+ tcg_out_opc_reg(s, m_opc, ret, v1, c1);
+
+ /* This should be guaranteed via constraints */
+ tcg_debug_assert(v2 == ret);
+ }
}
static void tcg_out_call_int(TCGContext *s, tcg_insn_unit *arg, bool tail)
@@ -934,9 +1027,11 @@ static int tcg_out_call_iarg_reg2(TCGContext *s, int i, TCGReg al, TCGReg ah)
/* Perform the tlb comparison operation. The complete host address is
placed in BASE. Clobbers AT, T0, A0. */
static void tcg_out_tlb_load(TCGContext *s, TCGReg base, TCGReg addrl,
- TCGReg addrh, int mem_index, TCGMemOp s_bits,
+ TCGReg addrh, TCGMemOpIdx oi,
tcg_insn_unit *label_ptr[2], bool is_load)
{
+ TCGMemOp s_bits = get_memop(oi) & MO_SIZE;
+ int mem_index = get_mmuidx(oi);
int cmp_off
= (is_load
? offsetof(CPUArchState, tlb_table[mem_index][0].addr_read)
@@ -962,30 +1057,34 @@ static void tcg_out_tlb_load(TCGContext *s, TCGReg base, TCGReg addrl,
add_off -= 0x7ff0;
}
- /* Load the tlb comparator. */
- if (TARGET_LONG_BITS == 64) {
- tcg_out_opc_imm(s, OPC_LW, TCG_TMP0, TCG_REG_A0, cmp_off + LO_OFF);
- tcg_out_opc_imm(s, OPC_LW, base, TCG_REG_A0, cmp_off + HI_OFF);
- } else {
- tcg_out_opc_imm(s, OPC_LW, TCG_TMP0, TCG_REG_A0, cmp_off);
- }
+ /* Load the (low half) tlb comparator. */
+ tcg_out_opc_imm(s, OPC_LW, TCG_TMP0, TCG_REG_A0,
+ cmp_off + (TARGET_LONG_BITS == 64 ? LO_OFF : 0));
/* Mask the page bits, keeping the alignment bits to compare against.
- In between, load the tlb addend for the fast path. */
+ In between on 32-bit targets, load the tlb addend for the fast path. */
tcg_out_movi(s, TCG_TYPE_I32, TCG_TMP1,
TARGET_PAGE_MASK | ((1 << s_bits) - 1));
- tcg_out_opc_imm(s, OPC_LW, TCG_REG_A0, TCG_REG_A0, add_off);
+ if (TARGET_LONG_BITS == 32) {
+ tcg_out_opc_imm(s, OPC_LW, TCG_REG_A0, TCG_REG_A0, add_off);
+ }
tcg_out_opc_reg(s, OPC_AND, TCG_TMP1, TCG_TMP1, addrl);
label_ptr[0] = s->code_ptr;
tcg_out_opc_br(s, OPC_BNE, TCG_TMP1, TCG_TMP0);
+ /* Load and test the high half tlb comparator. */
if (TARGET_LONG_BITS == 64) {
/* delay slot */
- tcg_out_nop(s);
+ tcg_out_opc_imm(s, OPC_LW, TCG_TMP0, TCG_REG_A0, cmp_off + HI_OFF);
+
+ /* Load the tlb addend for the fast path. We can't do it earlier with
+ 64-bit targets or we'll clobber a0 before reading the high half tlb
+ comparator. */
+ tcg_out_opc_imm(s, OPC_LW, TCG_REG_A0, TCG_REG_A0, add_off);
label_ptr[1] = s->code_ptr;
- tcg_out_opc_br(s, OPC_BNE, addrh, base);
+ tcg_out_opc_br(s, OPC_BNE, addrh, TCG_TMP0);
}
/* delay slot */
@@ -1156,8 +1255,6 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, bool is_64)
TCGMemOp opc;
#if defined(CONFIG_SOFTMMU)
tcg_insn_unit *label_ptr[2];
- int mem_index;
- TCGMemOp s_bits;
#endif
/* Note that we've eliminated V0 from the output registers,
so we won't overwrite the base register during loading. */
@@ -1171,21 +1268,17 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, bool is_64)
opc = get_memop(oi);
#if defined(CONFIG_SOFTMMU)
- mem_index = get_mmuidx(oi);
- s_bits = opc & MO_SIZE;
-
- tcg_out_tlb_load(s, base, addr_regl, addr_regh, mem_index,
- s_bits, label_ptr, 1);
+ tcg_out_tlb_load(s, base, addr_regl, addr_regh, oi, label_ptr, 1);
tcg_out_qemu_ld_direct(s, data_regl, data_regh, base, opc);
add_qemu_ldst_label(s, 1, oi, data_regl, data_regh, addr_regl, addr_regh,
s->code_ptr, label_ptr);
#else
- if (GUEST_BASE == 0 && data_regl != addr_regl) {
+ if (guest_base == 0 && data_regl != addr_regl) {
base = addr_regl;
- } else if (GUEST_BASE == (int16_t)GUEST_BASE) {
- tcg_out_opc_imm(s, OPC_ADDIU, base, addr_regl, GUEST_BASE);
+ } else if (guest_base == (int16_t)guest_base) {
+ tcg_out_opc_imm(s, OPC_ADDIU, base, addr_regl, guest_base);
} else {
- tcg_out_movi(s, TCG_TYPE_PTR, base, GUEST_BASE);
+ tcg_out_movi(s, TCG_TYPE_PTR, base, guest_base);
tcg_out_opc_reg(s, OPC_ADDU, base, base, addr_regl);
}
tcg_out_qemu_ld_direct(s, data_regl, data_regh, base, opc);
@@ -1233,55 +1326,6 @@ static void tcg_out_qemu_st_direct(TCGContext *s, TCGReg datalo, TCGReg datahi,
}
}
-static void tcg_out_addsub2(TCGContext *s, TCGReg rl, TCGReg rh, TCGReg al,
- TCGReg ah, TCGArg bl, TCGArg bh, bool cbl,
- bool cbh, bool is_sub)
-{
- TCGReg th = TCG_TMP1;
-
- /* If we have a negative constant such that negating it would
- make the high part zero, we can (usually) eliminate one insn. */
- if (cbl && cbh && bh == -1 && bl != 0) {
- bl = -bl;
- bh = 0;
- is_sub = !is_sub;
- }
-
- /* By operating on the high part first, we get to use the final
- carry operation to move back from the temporary. */
- if (!cbh) {
- tcg_out_opc_reg(s, (is_sub ? OPC_SUBU : OPC_ADDU), th, ah, bh);
- } else if (bh != 0 || ah == rl) {
- tcg_out_opc_imm(s, OPC_ADDIU, th, ah, (is_sub ? -bh : bh));
- } else {
- th = ah;
- }
-
- /* Note that tcg optimization should eliminate the bl == 0 case. */
- if (is_sub) {
- if (cbl) {
- tcg_out_opc_imm(s, OPC_SLTIU, TCG_TMP0, al, bl);
- tcg_out_opc_imm(s, OPC_ADDIU, rl, al, -bl);
- } else {
- tcg_out_opc_reg(s, OPC_SLTU, TCG_TMP0, al, bl);
- tcg_out_opc_reg(s, OPC_SUBU, rl, al, bl);
- }
- tcg_out_opc_reg(s, OPC_SUBU, rh, th, TCG_TMP0);
- } else {
- if (cbl) {
- tcg_out_opc_imm(s, OPC_ADDIU, rl, al, bl);
- tcg_out_opc_imm(s, OPC_SLTIU, TCG_TMP0, rl, bl);
- } else if (rl == al && rl == bl) {
- tcg_out_opc_sa(s, OPC_SRL, TCG_TMP0, al, 31);
- tcg_out_opc_reg(s, OPC_ADDU, rl, al, bl);
- } else {
- tcg_out_opc_reg(s, OPC_ADDU, rl, al, bl);
- tcg_out_opc_reg(s, OPC_SLTU, TCG_TMP0, rl, (rl == bl ? al : bl));
- }
- tcg_out_opc_reg(s, OPC_ADDU, rh, th, TCG_TMP0);
- }
-}
-
static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is_64)
{
TCGReg addr_regl, addr_regh __attribute__((unused));
@@ -1290,8 +1334,6 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is_64)
TCGMemOp opc;
#if defined(CONFIG_SOFTMMU)
tcg_insn_unit *label_ptr[2];
- int mem_index;
- TCGMemOp s_bits;
#endif
data_regl = *args++;
@@ -1302,26 +1344,22 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is_64)
opc = get_memop(oi);
#if defined(CONFIG_SOFTMMU)
- mem_index = get_mmuidx(oi);
- s_bits = opc & 3;
-
/* Note that we eliminated the helper's address argument,
so we can reuse that for the base. */
base = (TARGET_LONG_BITS == 32 ? TCG_REG_A1 : TCG_REG_A2);
- tcg_out_tlb_load(s, base, addr_regl, addr_regh, mem_index,
- s_bits, label_ptr, 0);
+ tcg_out_tlb_load(s, base, addr_regl, addr_regh, oi, label_ptr, 0);
tcg_out_qemu_st_direct(s, data_regl, data_regh, base, opc);
add_qemu_ldst_label(s, 0, oi, data_regl, data_regh, addr_regl, addr_regh,
s->code_ptr, label_ptr);
#else
- if (GUEST_BASE == 0) {
+ if (guest_base == 0) {
base = addr_regl;
} else {
base = TCG_REG_A0;
- if (GUEST_BASE == (int16_t)GUEST_BASE) {
- tcg_out_opc_imm(s, OPC_ADDIU, base, addr_regl, GUEST_BASE);
+ if (guest_base == (int16_t)guest_base) {
+ tcg_out_opc_imm(s, OPC_ADDIU, base, addr_regl, guest_base);
} else {
- tcg_out_movi(s, TCG_TYPE_PTR, base, GUEST_BASE);
+ tcg_out_movi(s, TCG_TYPE_PTR, base, guest_base);
tcg_out_opc_reg(s, OPC_ADDU, base, base, addr_regl);
}
}
@@ -1432,8 +1470,8 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
case INDEX_op_and_i32:
if (c2 && a2 != (uint16_t)a2) {
int msb = ctz32(~a2) - 1;
- assert(use_mips32r2_instructions);
- assert(is_p2m1(a2));
+ tcg_debug_assert(use_mips32r2_instructions);
+ tcg_debug_assert(is_p2m1(a2));
tcg_out_opc_bf(s, OPC_EXT, a0, a1, msb, 0);
break;
}
@@ -1451,21 +1489,45 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
i1 = OPC_MULT, i2 = OPC_MFLO;
goto do_hilo1;
case INDEX_op_mulsh_i32:
+ if (use_mips32r6_instructions) {
+ tcg_out_opc_reg(s, OPC_MUH, a0, a1, a2);
+ break;
+ }
i1 = OPC_MULT, i2 = OPC_MFHI;
goto do_hilo1;
case INDEX_op_muluh_i32:
+ if (use_mips32r6_instructions) {
+ tcg_out_opc_reg(s, OPC_MUHU, a0, a1, a2);
+ break;
+ }
i1 = OPC_MULTU, i2 = OPC_MFHI;
goto do_hilo1;
case INDEX_op_div_i32:
+ if (use_mips32r6_instructions) {
+ tcg_out_opc_reg(s, OPC_DIV_R6, a0, a1, a2);
+ break;
+ }
i1 = OPC_DIV, i2 = OPC_MFLO;
goto do_hilo1;
case INDEX_op_divu_i32:
+ if (use_mips32r6_instructions) {
+ tcg_out_opc_reg(s, OPC_DIVU_R6, a0, a1, a2);
+ break;
+ }
i1 = OPC_DIVU, i2 = OPC_MFLO;
goto do_hilo1;
case INDEX_op_rem_i32:
+ if (use_mips32r6_instructions) {
+ tcg_out_opc_reg(s, OPC_MOD, a0, a1, a2);
+ break;
+ }
i1 = OPC_DIV, i2 = OPC_MFHI;
goto do_hilo1;
case INDEX_op_remu_i32:
+ if (use_mips32r6_instructions) {
+ tcg_out_opc_reg(s, OPC_MODU, a0, a1, a2);
+ break;
+ }
i1 = OPC_DIVU, i2 = OPC_MFHI;
do_hilo1:
tcg_out_opc_reg(s, i1, 0, a1, a2);
@@ -1542,7 +1604,7 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
break;
case INDEX_op_movcond_i32:
- tcg_out_movcond(s, args[5], a0, a1, a2, args[3]);
+ tcg_out_movcond(s, args[5], a0, a1, a2, args[3], args[4]);
break;
case INDEX_op_setcond_i32:
@@ -1598,8 +1660,10 @@ static const TCGTargetOpDef mips_op_defs[] = {
{ INDEX_op_add_i32, { "r", "rZ", "rJ" } },
{ INDEX_op_mul_i32, { "r", "rZ", "rZ" } },
+#if !use_mips32r6_instructions
{ INDEX_op_muls2_i32, { "r", "r", "rZ", "rZ" } },
{ INDEX_op_mulu2_i32, { "r", "r", "rZ", "rZ" } },
+#endif
{ INDEX_op_mulsh_i32, { "r", "rZ", "rZ" } },
{ INDEX_op_muluh_i32, { "r", "rZ", "rZ" } },
{ INDEX_op_div_i32, { "r", "rZ", "rZ" } },
@@ -1629,7 +1693,11 @@ static const TCGTargetOpDef mips_op_defs[] = {
{ INDEX_op_deposit_i32, { "r", "0", "rZ" } },
{ INDEX_op_brcond_i32, { "rZ", "rZ" } },
+#if use_mips32r6_instructions
+ { INDEX_op_movcond_i32, { "r", "rZ", "rZ", "rZ", "rZ" } },
+#else
{ INDEX_op_movcond_i32, { "r", "rZ", "rZ", "rZ", "0" } },
+#endif
{ INDEX_op_setcond_i32, { "r", "rZ", "rZ" } },
{ INDEX_op_setcond2_i32, { "r", "rZ", "rZ", "rZ", "rZ" } },
@@ -1667,7 +1735,6 @@ static int tcg_target_callee_save_regs[] = {
/* The Linux kernel doesn't provide any information about the available
instruction set. Probe it using a signal handler. */
-#include <signal.h>
#ifndef use_movnz_instructions
bool use_movnz_instructions = false;