aboutsummaryrefslogtreecommitdiff
path: root/tcg/i386
diff options
context:
space:
mode:
Diffstat (limited to 'tcg/i386')
-rw-r--r--tcg/i386/tcg-target-con-set.h4
-rw-r--r--tcg/i386/tcg-target-con-str.h2
-rw-r--r--tcg/i386/tcg-target-has.h57
-rw-r--r--tcg/i386/tcg-target.c.inc1818
4 files changed, 1107 insertions, 774 deletions
diff --git a/tcg/i386/tcg-target-con-set.h b/tcg/i386/tcg-target-con-set.h
index 06e6521..458d69c 100644
--- a/tcg/i386/tcg-target-con-set.h
+++ b/tcg/i386/tcg-target-con-set.h
@@ -42,9 +42,10 @@ C_O1_I2(r, 0, reZ)
C_O1_I2(r, 0, ri)
C_O1_I2(r, 0, rI)
C_O1_I2(r, L, L)
+C_O1_I2(r, r, r)
C_O1_I2(r, r, re)
C_O1_I2(r, r, ri)
-C_O1_I2(r, r, rI)
+C_O1_I2(r, rO, re)
C_O1_I2(x, x, x)
C_N1_I2(r, r, r)
C_N1_I2(r, r, rW)
@@ -57,4 +58,3 @@ C_O2_I1(r, r, L)
C_O2_I2(a, d, a, r)
C_O2_I2(r, r, L, L)
C_O2_I3(a, d, 0, 1, r)
-C_N1_O1_I4(r, r, 0, 1, re, re)
diff --git a/tcg/i386/tcg-target-con-str.h b/tcg/i386/tcg-target-con-str.h
index 52142ab..dbedff1 100644
--- a/tcg/i386/tcg-target-con-str.h
+++ b/tcg/i386/tcg-target-con-str.h
@@ -20,7 +20,7 @@ REGS('r', ALL_GENERAL_REGS)
REGS('x', ALL_VECTOR_REGS)
REGS('q', ALL_BYTEL_REGS) /* regs that can be used as a byte operand */
REGS('L', ALL_GENERAL_REGS & ~SOFTMMU_RESERVE_REGS) /* qemu_ld/st */
-REGS('s', ALL_BYTEL_REGS & ~SOFTMMU_RESERVE_REGS) /* qemu_st8_i32 data */
+REGS('s', ALL_BYTEL_REGS & ~SOFTMMU_RESERVE_REGS) /* qemu_st MO_8 data */
/*
* Define constraint letters for constants:
diff --git a/tcg/i386/tcg-target-has.h b/tcg/i386/tcg-target-has.h
index 63768ff..42647fa 100644
--- a/tcg/i386/tcg-target-has.h
+++ b/tcg/i386/tcg-target-has.h
@@ -26,66 +26,9 @@
#define have_avx512vbmi2 ((cpuinfo & CPUINFO_AVX512VBMI2) && have_avx512vl)
/* optional instructions */
-#define TCG_TARGET_HAS_div2_i32 1
-#define TCG_TARGET_HAS_rot_i32 1
-#define TCG_TARGET_HAS_ext8s_i32 1
-#define TCG_TARGET_HAS_ext16s_i32 1
-#define TCG_TARGET_HAS_ext8u_i32 1
-#define TCG_TARGET_HAS_ext16u_i32 1
-#define TCG_TARGET_HAS_bswap16_i32 1
-#define TCG_TARGET_HAS_bswap32_i32 1
-#define TCG_TARGET_HAS_not_i32 1
-#define TCG_TARGET_HAS_andc_i32 have_bmi1
-#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_nor_i32 0
-#define TCG_TARGET_HAS_clz_i32 1
-#define TCG_TARGET_HAS_ctz_i32 1
-#define TCG_TARGET_HAS_ctpop_i32 have_popcnt
-#define TCG_TARGET_HAS_extract2_i32 1
-#define TCG_TARGET_HAS_negsetcond_i32 1
-#define TCG_TARGET_HAS_add2_i32 1
-#define TCG_TARGET_HAS_sub2_i32 1
-#define TCG_TARGET_HAS_mulu2_i32 1
-#define TCG_TARGET_HAS_muls2_i32 1
-#define TCG_TARGET_HAS_muluh_i32 0
-#define TCG_TARGET_HAS_mulsh_i32 0
-
#if TCG_TARGET_REG_BITS == 64
/* Keep 32-bit values zero-extended in a register. */
#define TCG_TARGET_HAS_extr_i64_i32 1
-#define TCG_TARGET_HAS_div2_i64 1
-#define TCG_TARGET_HAS_rot_i64 1
-#define TCG_TARGET_HAS_ext8s_i64 1
-#define TCG_TARGET_HAS_ext16s_i64 1
-#define TCG_TARGET_HAS_ext32s_i64 1
-#define TCG_TARGET_HAS_ext8u_i64 1
-#define TCG_TARGET_HAS_ext16u_i64 1
-#define TCG_TARGET_HAS_ext32u_i64 1
-#define TCG_TARGET_HAS_bswap16_i64 1
-#define TCG_TARGET_HAS_bswap32_i64 1
-#define TCG_TARGET_HAS_bswap64_i64 1
-#define TCG_TARGET_HAS_not_i64 1
-#define TCG_TARGET_HAS_andc_i64 have_bmi1
-#define TCG_TARGET_HAS_orc_i64 0
-#define TCG_TARGET_HAS_eqv_i64 0
-#define TCG_TARGET_HAS_nand_i64 0
-#define TCG_TARGET_HAS_nor_i64 0
-#define TCG_TARGET_HAS_clz_i64 1
-#define TCG_TARGET_HAS_ctz_i64 1
-#define TCG_TARGET_HAS_ctpop_i64 have_popcnt
-#define TCG_TARGET_HAS_extract2_i64 1
-#define TCG_TARGET_HAS_negsetcond_i64 1
-#define TCG_TARGET_HAS_add2_i64 1
-#define TCG_TARGET_HAS_sub2_i64 1
-#define TCG_TARGET_HAS_mulu2_i64 1
-#define TCG_TARGET_HAS_muls2_i64 1
-#define TCG_TARGET_HAS_muluh_i64 0
-#define TCG_TARGET_HAS_mulsh_i64 0
-#define TCG_TARGET_HAS_qemu_st8_i32 0
-#else
-#define TCG_TARGET_HAS_qemu_st8_i32 1
#endif
#define TCG_TARGET_HAS_qemu_ldst_i128 \
diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc
index 33d303a..09fce27 100644
--- a/tcg/i386/tcg-target.c.inc
+++ b/tcg/i386/tcg-target.c.inc
@@ -424,6 +424,7 @@ static bool tcg_target_const_match(int64_t val, int ct,
#define OPC_SHLX (0xf7 | P_EXT38 | P_DATA16)
#define OPC_SHRX (0xf7 | P_EXT38 | P_SIMDF2)
#define OPC_SHRD_Ib (0xac | P_EXT)
+#define OPC_STC (0xf9)
#define OPC_TESTB (0x84)
#define OPC_TESTL (0x85)
#define OPC_TZCNT (0xbc | P_EXT | P_SIMDF3)
@@ -1092,7 +1093,7 @@ static void tcg_out_movi_int(TCGContext *s, TCGType type,
{
tcg_target_long diff;
- if (arg == 0) {
+ if (arg == 0 && !s->carry_live) {
tgen_arithr(s, ARITH_XOR, ret, ret);
return;
}
@@ -1167,7 +1168,7 @@ static inline void tcg_out_pushi(TCGContext *s, tcg_target_long val)
}
}
-static inline void tcg_out_mb(TCGContext *s, TCGArg a0)
+static void tcg_out_mb(TCGContext *s, unsigned a0)
{
/* Given the strength of x86 memory ordering, we only need care for
store-load ordering. Experimentally, "lock orl $0,0(%esp)" is
@@ -1545,6 +1546,11 @@ static void tcg_out_jxx(TCGContext *s, int opc, TCGLabel *l, bool small)
}
}
+static void tcg_out_br(TCGContext *s, TCGLabel *l)
+{
+ tcg_out_jxx(s, JCC_JMP, l, 0);
+}
+
static int tcg_out_cmp(TCGContext *s, TCGCond cond, TCGArg arg1,
TCGArg arg2, int const_arg2, int rexw)
{
@@ -1642,47 +1648,78 @@ static void tcg_out_brcond(TCGContext *s, int rexw, TCGCond cond,
tcg_out_jxx(s, jcc, label, small);
}
-#if TCG_TARGET_REG_BITS == 32
-static void tcg_out_brcond2(TCGContext *s, const TCGArg *args,
- const int *const_args, bool small)
+static void tgen_brcond(TCGContext *s, TCGType type, TCGCond cond,
+ TCGReg arg1, TCGReg arg2, TCGLabel *label)
+{
+ int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
+ tcg_out_brcond(s, rexw, cond, arg1, arg2, false, label, false);
+}
+
+static void tgen_brcondi(TCGContext *s, TCGType type, TCGCond cond,
+ TCGReg arg1, tcg_target_long arg2, TCGLabel *label)
+{
+ int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
+ tcg_out_brcond(s, rexw, cond, arg1, arg2, true, label, false);
+}
+
+static const TCGOutOpBrcond outop_brcond = {
+ .base.static_constraint = C_O0_I2(r, reT),
+ .out_rr = tgen_brcond,
+ .out_ri = tgen_brcondi,
+};
+
+static void tcg_out_brcond2(TCGContext *s, TCGCond cond, TCGReg al,
+ TCGReg ah, TCGArg bl, bool blconst,
+ TCGArg bh, bool bhconst,
+ TCGLabel *label_this, bool small)
{
TCGLabel *label_next = gen_new_label();
- TCGLabel *label_this = arg_label(args[5]);
- TCGCond cond = args[4];
switch (cond) {
case TCG_COND_EQ:
case TCG_COND_TSTEQ:
tcg_out_brcond(s, 0, tcg_invert_cond(cond),
- args[0], args[2], const_args[2], label_next, 1);
- tcg_out_brcond(s, 0, cond, args[1], args[3], const_args[3],
- label_this, small);
+ al, bl, blconst, label_next, true);
+ tcg_out_brcond(s, 0, cond, ah, bh, bhconst, label_this, small);
break;
case TCG_COND_NE:
case TCG_COND_TSTNE:
- tcg_out_brcond(s, 0, cond, args[0], args[2], const_args[2],
- label_this, small);
- tcg_out_brcond(s, 0, cond, args[1], args[3], const_args[3],
- label_this, small);
+ tcg_out_brcond(s, 0, cond, al, bl, blconst, label_this, small);
+ tcg_out_brcond(s, 0, cond, ah, bh, bhconst, label_this, small);
break;
default:
- tcg_out_brcond(s, 0, tcg_high_cond(cond), args[1],
- args[3], const_args[3], label_this, small);
+ tcg_out_brcond(s, 0, tcg_high_cond(cond),
+ ah, bh, bhconst, label_this, small);
tcg_out_jxx(s, JCC_JNE, label_next, 1);
- tcg_out_brcond(s, 0, tcg_unsigned_cond(cond), args[0],
- args[2], const_args[2], label_this, small);
+ tcg_out_brcond(s, 0, tcg_unsigned_cond(cond),
+ al, bl, blconst, label_this, small);
break;
}
tcg_out_label(s, label_next);
}
+
+static void tgen_brcond2(TCGContext *s, TCGCond cond, TCGReg al,
+ TCGReg ah, TCGArg bl, bool blconst,
+ TCGArg bh, bool bhconst, TCGLabel *l)
+{
+ tcg_out_brcond2(s, cond, al, ah, bl, blconst, bh, bhconst, l, false);
+}
+
+#if TCG_TARGET_REG_BITS != 32
+__attribute__((unused))
#endif
+static const TCGOutOpBrcond2 outop_brcond2 = {
+ .base.static_constraint = C_O0_I4(r, r, ri, ri),
+ .out = tgen_brcond2,
+};
-static void tcg_out_setcond(TCGContext *s, int rexw, TCGCond cond,
- TCGArg dest, TCGArg arg1, TCGArg arg2,
- int const_arg2, bool neg)
+static void tcg_out_setcond(TCGContext *s, TCGType type, TCGCond cond,
+ TCGReg dest, TCGReg arg1, TCGArg arg2,
+ bool const_arg2, bool neg)
{
+ int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
int cmp_rexw = rexw;
bool inv = false;
bool cleared;
@@ -1757,7 +1794,7 @@ static void tcg_out_setcond(TCGContext *s, int rexw, TCGCond cond,
case TCG_COND_LT:
/* If arg2 is 0, extract the sign bit. */
if (const_arg2 && arg2 == 0) {
- tcg_out_mov(s, rexw ? TCG_TYPE_I64 : TCG_TYPE_I32, dest, arg1);
+ tcg_out_mov(s, type, dest, arg1);
if (inv) {
tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_NOT, dest);
}
@@ -1793,49 +1830,89 @@ static void tcg_out_setcond(TCGContext *s, int rexw, TCGCond cond,
}
}
-#if TCG_TARGET_REG_BITS == 32
-static void tcg_out_setcond2(TCGContext *s, const TCGArg *args,
- const int *const_args)
+static void tgen_setcond(TCGContext *s, TCGType type, TCGCond cond,
+ TCGReg dest, TCGReg arg1, TCGReg arg2)
+{
+ tcg_out_setcond(s, type, cond, dest, arg1, arg2, false, false);
+}
+
+static void tgen_setcondi(TCGContext *s, TCGType type, TCGCond cond,
+ TCGReg dest, TCGReg arg1, tcg_target_long arg2)
+{
+ tcg_out_setcond(s, type, cond, dest, arg1, arg2, true, false);
+}
+
+static const TCGOutOpSetcond outop_setcond = {
+ .base.static_constraint = C_O1_I2(q, r, reT),
+ .out_rrr = tgen_setcond,
+ .out_rri = tgen_setcondi,
+};
+
+static void tgen_negsetcond(TCGContext *s, TCGType type, TCGCond cond,
+ TCGReg dest, TCGReg arg1, TCGReg arg2)
+{
+ tcg_out_setcond(s, type, cond, dest, arg1, arg2, false, true);
+}
+
+static void tgen_negsetcondi(TCGContext *s, TCGType type, TCGCond cond,
+ TCGReg dest, TCGReg arg1, tcg_target_long arg2)
{
- TCGArg new_args[6];
- TCGLabel *label_true, *label_over;
+ tcg_out_setcond(s, type, cond, dest, arg1, arg2, true, true);
+}
+
+static const TCGOutOpSetcond outop_negsetcond = {
+ .base.static_constraint = C_O1_I2(q, r, reT),
+ .out_rrr = tgen_negsetcond,
+ .out_rri = tgen_negsetcondi,
+};
- memcpy(new_args, args+1, 5*sizeof(TCGArg));
+static void tgen_setcond2(TCGContext *s, TCGCond cond, TCGReg ret,
+ TCGReg al, TCGReg ah,
+ TCGArg bl, bool const_bl,
+ TCGArg bh, bool const_bh)
+{
+ TCGLabel *label_over = gen_new_label();
- if (args[0] == args[1] || args[0] == args[2]
- || (!const_args[3] && args[0] == args[3])
- || (!const_args[4] && args[0] == args[4])) {
- /* When the destination overlaps with one of the argument
- registers, don't do anything tricky. */
- label_true = gen_new_label();
- label_over = gen_new_label();
+ if (ret == al || ret == ah
+ || (!const_bl && ret == bl)
+ || (!const_bh && ret == bh)) {
+ /*
+ * When the destination overlaps with one of the argument
+ * registers, don't do anything tricky.
+ */
+ TCGLabel *label_true = gen_new_label();
- new_args[5] = label_arg(label_true);
- tcg_out_brcond2(s, new_args, const_args+1, 1);
+ tcg_out_brcond2(s, cond, al, ah, bl, const_bl,
+ bh, const_bh, label_true, true);
- tcg_out_movi(s, TCG_TYPE_I32, args[0], 0);
+ tcg_out_movi(s, TCG_TYPE_I32, ret, 0);
tcg_out_jxx(s, JCC_JMP, label_over, 1);
tcg_out_label(s, label_true);
- tcg_out_movi(s, TCG_TYPE_I32, args[0], 1);
- tcg_out_label(s, label_over);
+ tcg_out_movi(s, TCG_TYPE_I32, ret, 1);
} else {
- /* When the destination does not overlap one of the arguments,
- clear the destination first, jump if cond false, and emit an
- increment in the true case. This results in smaller code. */
-
- tcg_out_movi(s, TCG_TYPE_I32, args[0], 0);
+ /*
+ * When the destination does not overlap one of the arguments,
+ * clear the destination first, jump if cond false, and emit an
+ * increment in the true case. This results in smaller code.
+ */
+ tcg_out_movi(s, TCG_TYPE_I32, ret, 0);
- label_over = gen_new_label();
- new_args[4] = tcg_invert_cond(new_args[4]);
- new_args[5] = label_arg(label_over);
- tcg_out_brcond2(s, new_args, const_args+1, 1);
+ tcg_out_brcond2(s, tcg_invert_cond(cond), al, ah, bl, const_bl,
+ bh, const_bh, label_over, true);
- tgen_arithi(s, ARITH_ADD, args[0], 1, 0);
- tcg_out_label(s, label_over);
+ tgen_arithi(s, ARITH_ADD, ret, 1, 0);
}
+ tcg_out_label(s, label_over);
}
+
+#if TCG_TARGET_REG_BITS != 32
+__attribute__((unused))
#endif
+static const TCGOutOpSetcond2 outop_setcond2 = {
+ .base.static_constraint = C_O1_I4(r, r, r, ri, ri),
+ .out = tgen_setcond2,
+};
static void tcg_out_cmov(TCGContext *s, int jcc, int rexw,
TCGReg dest, TCGReg v1)
@@ -1843,57 +1920,20 @@ static void tcg_out_cmov(TCGContext *s, int jcc, int rexw,
tcg_out_modrm(s, OPC_CMOVCC | jcc | rexw, dest, v1);
}
-static void tcg_out_movcond(TCGContext *s, int rexw, TCGCond cond,
- TCGReg dest, TCGReg c1, TCGArg c2, int const_c2,
- TCGReg v1)
+static void tgen_movcond(TCGContext *s, TCGType type, TCGCond cond,
+ TCGReg dest, TCGReg c1, TCGArg c2, bool const_c2,
+ TCGArg vt, bool const_vt,
+ TCGArg vf, bool consf_vf)
{
+ int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
int jcc = tcg_out_cmp(s, cond, c1, c2, const_c2, rexw);
- tcg_out_cmov(s, jcc, rexw, dest, v1);
+ tcg_out_cmov(s, jcc, rexw, dest, vt);
}
-static void tcg_out_ctz(TCGContext *s, int rexw, TCGReg dest, TCGReg arg1,
- TCGArg arg2, bool const_a2)
-{
- if (have_bmi1) {
- tcg_out_modrm(s, OPC_TZCNT + rexw, dest, arg1);
- if (const_a2) {
- tcg_debug_assert(arg2 == (rexw ? 64 : 32));
- } else {
- tcg_debug_assert(dest != arg2);
- tcg_out_cmov(s, JCC_JB, rexw, dest, arg2);
- }
- } else {
- tcg_debug_assert(dest != arg2);
- tcg_out_modrm(s, OPC_BSF + rexw, dest, arg1);
- tcg_out_cmov(s, JCC_JE, rexw, dest, arg2);
- }
-}
-
-static void tcg_out_clz(TCGContext *s, int rexw, TCGReg dest, TCGReg arg1,
- TCGArg arg2, bool const_a2)
-{
- if (have_lzcnt) {
- tcg_out_modrm(s, OPC_LZCNT + rexw, dest, arg1);
- if (const_a2) {
- tcg_debug_assert(arg2 == (rexw ? 64 : 32));
- } else {
- tcg_debug_assert(dest != arg2);
- tcg_out_cmov(s, JCC_JB, rexw, dest, arg2);
- }
- } else {
- tcg_debug_assert(!const_a2);
- tcg_debug_assert(dest != arg1);
- tcg_debug_assert(dest != arg2);
-
- /* Recall that the output of BSR is the index not the count. */
- tcg_out_modrm(s, OPC_BSR + rexw, dest, arg1);
- tgen_arithi(s, ARITH_XOR + rexw, dest, rexw ? 63 : 31, 0);
-
- /* Since we have destroyed the flags from BSR, we have to re-test. */
- int jcc = tcg_out_cmp(s, TCG_COND_EQ, arg1, 0, 1, rexw);
- tcg_out_cmov(s, jcc, rexw, dest, arg2);
- }
-}
+static const TCGOutOpMovcond outop_movcond = {
+ .base.static_constraint = C_O1_I4(r, r, reT, r, 0),
+ .out = tgen_movcond,
+};
static void tcg_out_branch(TCGContext *s, int call, const tcg_insn_unit *dest)
{
@@ -2382,23 +2422,50 @@ static void tcg_out_qemu_ld_direct(TCGContext *s, TCGReg datalo, TCGReg datahi,
}
}
-static void tcg_out_qemu_ld(TCGContext *s, TCGReg datalo, TCGReg datahi,
- TCGReg addr, MemOpIdx oi, TCGType data_type)
+static void tgen_qemu_ld(TCGContext *s, TCGType type, TCGReg data,
+ TCGReg addr, MemOpIdx oi)
+{
+ TCGLabelQemuLdst *ldst;
+ HostAddress h;
+
+ ldst = prepare_host_addr(s, &h, addr, oi, true);
+ tcg_out_qemu_ld_direct(s, data, -1, h, type, get_memop(oi));
+
+ if (ldst) {
+ ldst->type = type;
+ ldst->datalo_reg = data;
+ ldst->datahi_reg = -1;
+ ldst->raddr = tcg_splitwx_to_rx(s->code_ptr);
+ }
+}
+
+static const TCGOutOpQemuLdSt outop_qemu_ld = {
+ .base.static_constraint = C_O1_I1(r, L),
+ .out = tgen_qemu_ld,
+};
+
+static void tgen_qemu_ld2(TCGContext *s, TCGType type, TCGReg datalo,
+ TCGReg datahi, TCGReg addr, MemOpIdx oi)
{
TCGLabelQemuLdst *ldst;
HostAddress h;
ldst = prepare_host_addr(s, &h, addr, oi, true);
- tcg_out_qemu_ld_direct(s, datalo, datahi, h, data_type, get_memop(oi));
+ tcg_out_qemu_ld_direct(s, datalo, datahi, h, type, get_memop(oi));
if (ldst) {
- ldst->type = data_type;
+ ldst->type = type;
ldst->datalo_reg = datalo;
ldst->datahi_reg = datahi;
ldst->raddr = tcg_splitwx_to_rx(s->code_ptr);
}
}
+static const TCGOutOpQemuLdSt2 outop_qemu_ld2 = {
+ .base.static_constraint = C_O2_I1(r, r, L),
+ .out = tgen_qemu_ld2,
+};
+
static void tcg_out_qemu_st_direct(TCGContext *s, TCGReg datalo, TCGReg datahi,
HostAddress h, MemOp memop)
{
@@ -2417,7 +2484,7 @@ static void tcg_out_qemu_st_direct(TCGContext *s, TCGReg datalo, TCGReg datahi,
switch (memop & MO_SIZE) {
case MO_8:
- /* This is handled with constraints on INDEX_op_qemu_st8_i32. */
+ /* This is handled with constraints in cset_qemu_st(). */
tcg_debug_assert(TCG_TARGET_REG_BITS == 64 || datalo < 4);
tcg_out_modrm_sib_offset(s, OPC_MOVB_EvGv + P_REXB_R + h.seg,
datalo, h.base, h.index, 0, h.ofs);
@@ -2509,8 +2576,38 @@ static void tcg_out_qemu_st_direct(TCGContext *s, TCGReg datalo, TCGReg datahi,
}
}
-static void tcg_out_qemu_st(TCGContext *s, TCGReg datalo, TCGReg datahi,
- TCGReg addr, MemOpIdx oi, TCGType data_type)
+static void tgen_qemu_st(TCGContext *s, TCGType type, TCGReg data,
+ TCGReg addr, MemOpIdx oi)
+{
+ TCGLabelQemuLdst *ldst;
+ HostAddress h;
+
+ ldst = prepare_host_addr(s, &h, addr, oi, false);
+ tcg_out_qemu_st_direct(s, data, -1, h, get_memop(oi));
+
+ if (ldst) {
+ ldst->type = type;
+ ldst->datalo_reg = data;
+ ldst->datahi_reg = -1;
+ ldst->raddr = tcg_splitwx_to_rx(s->code_ptr);
+ }
+}
+
+static TCGConstraintSetIndex cset_qemu_st(TCGType type, unsigned flags)
+{
+ return flags == MO_8 ? C_O0_I2(s, L) : C_O0_I2(L, L);
+}
+
+static const TCGOutOpQemuLdSt outop_qemu_st = {
+ .base.static_constraint =
+ TCG_TARGET_REG_BITS == 32 ? C_Dynamic : C_O0_I2(L, L),
+ .base.dynamic_constraint =
+ TCG_TARGET_REG_BITS == 32 ? cset_qemu_st : NULL,
+ .out = tgen_qemu_st,
+};
+
+static void tgen_qemu_st2(TCGContext *s, TCGType type, TCGReg datalo,
+ TCGReg datahi, TCGReg addr, MemOpIdx oi)
{
TCGLabelQemuLdst *ldst;
HostAddress h;
@@ -2519,13 +2616,18 @@ static void tcg_out_qemu_st(TCGContext *s, TCGReg datalo, TCGReg datahi,
tcg_out_qemu_st_direct(s, datalo, datahi, h, get_memop(oi));
if (ldst) {
- ldst->type = data_type;
+ ldst->type = type;
ldst->datalo_reg = datalo;
ldst->datahi_reg = datahi;
ldst->raddr = tcg_splitwx_to_rx(s->code_ptr);
}
}
+static const TCGOutOpQemuLdSt2 outop_qemu_st2 = {
+ .base.static_constraint = C_O0_I3(L, L, L),
+ .out = tgen_qemu_st2,
+};
+
static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0)
{
/* Reuse the zeroing that exists for goto_ptr. */
@@ -2553,6 +2655,12 @@ static void tcg_out_goto_tb(TCGContext *s, int which)
set_jmp_reset_offset(s, which);
}
+static void tcg_out_goto_ptr(TCGContext *s, TCGReg a0)
+{
+ /* Jump to the given host address (could be epilogue) */
+ tcg_out_modrm(s, OPC_GRP5, EXT5_JMPN_Ev, a0);
+}
+
void tb_target_set_jmp_target(const TranslationBlock *tb, int n,
uintptr_t jmp_rx, uintptr_t jmp_rw)
{
@@ -2562,480 +2670,938 @@ void tb_target_set_jmp_target(const TranslationBlock *tb, int n,
/* no need to flush icache explicitly */
}
-static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type,
- const TCGArg args[TCG_MAX_OP_ARGS],
- const int const_args[TCG_MAX_OP_ARGS])
+
+static void tgen_add(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
{
- TCGArg a0, a1, a2;
- int c, const_a2, vexop, rexw;
+ int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
-#if TCG_TARGET_REG_BITS == 64
-# define OP_32_64(x) \
- case glue(glue(INDEX_op_, x), _i64): \
- case glue(glue(INDEX_op_, x), _i32)
-#else
-# define OP_32_64(x) \
- case glue(glue(INDEX_op_, x), _i32)
-#endif
+ if (a0 == a1) {
+ tgen_arithr(s, ARITH_ADD + rexw, a0, a2);
+ } else if (a0 == a2) {
+ tgen_arithr(s, ARITH_ADD + rexw, a0, a1);
+ } else {
+ tcg_out_modrm_sib_offset(s, OPC_LEA + rexw, a0, a1, a2, 0, 0);
+ }
+}
- /* Hoist the loads of the most common arguments. */
- a0 = args[0];
- a1 = args[1];
- a2 = args[2];
- const_a2 = const_args[2];
- rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
+static void tgen_addi(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, tcg_target_long a2)
+{
+ int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
- switch (opc) {
- case INDEX_op_goto_ptr:
- /* jmp to the given host address (could be epilogue) */
- tcg_out_modrm(s, OPC_GRP5, EXT5_JMPN_Ev, a0);
- break;
- case INDEX_op_br:
- tcg_out_jxx(s, JCC_JMP, arg_label(a0), 0);
- break;
- OP_32_64(ld8u):
- /* Note that we can ignore REXW for the zero-extend to 64-bit. */
- tcg_out_modrm_offset(s, OPC_MOVZBL, a0, a1, a2);
- break;
- OP_32_64(ld8s):
- tcg_out_modrm_offset(s, OPC_MOVSBL + rexw, a0, a1, a2);
- break;
- OP_32_64(ld16u):
- /* Note that we can ignore REXW for the zero-extend to 64-bit. */
- tcg_out_modrm_offset(s, OPC_MOVZWL, a0, a1, a2);
- break;
- OP_32_64(ld16s):
- tcg_out_modrm_offset(s, OPC_MOVSWL + rexw, a0, a1, a2);
- break;
-#if TCG_TARGET_REG_BITS == 64
- case INDEX_op_ld32u_i64:
-#endif
- case INDEX_op_ld_i32:
- tcg_out_ld(s, TCG_TYPE_I32, a0, a1, a2);
- break;
+ if (a0 == a1) {
+ tgen_arithi(s, ARITH_ADD + rexw, a0, a2, false);
+ } else {
+ tcg_out_modrm_sib_offset(s, OPC_LEA + rexw, a0, a1, -1, 0, a2);
+ }
+}
+
+static const TCGOutOpBinary outop_add = {
+ .base.static_constraint = C_O1_I2(r, r, re),
+ .out_rrr = tgen_add,
+ .out_rri = tgen_addi,
+};
+
+static void tgen_addco(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
+ tgen_arithr(s, ARITH_ADD + rexw, a0, a2);
+}
+
+static void tgen_addco_imm(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, tcg_target_long a2)
+{
+ int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
+ tgen_arithi(s, ARITH_ADD + rexw, a0, a2, true);
+}
+
+static const TCGOutOpBinary outop_addco = {
+ .base.static_constraint = C_O1_I2(r, 0, re),
+ .out_rrr = tgen_addco,
+ .out_rri = tgen_addco_imm,
+};
+
+static void tgen_addcio(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
+ tgen_arithr(s, ARITH_ADC + rexw, a0, a2);
+}
+
+static void tgen_addcio_imm(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, tcg_target_long a2)
+{
+ int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
+ tgen_arithi(s, ARITH_ADC + rexw, a0, a2, true);
+}
+
+static const TCGOutOpBinary outop_addcio = {
+ .base.static_constraint = C_O1_I2(r, 0, re),
+ .out_rrr = tgen_addcio,
+ .out_rri = tgen_addcio_imm,
+};
+
+static void tgen_addci_rrr(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ /* Because "0O" is not a valid constraint, we must match ourselves. */
+ if (a0 == a2) {
+ tgen_addcio(s, type, a0, a0, a1);
+ } else {
+ tcg_out_mov(s, type, a0, a1);
+ tgen_addcio(s, type, a0, a0, a2);
+ }
+}
+
+static void tgen_addci_rri(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, tcg_target_long a2)
+{
+ tcg_out_mov(s, type, a0, a1);
+ tgen_addcio_imm(s, type, a0, a0, a2);
+}
+
+static void tgen_addci_rir(TCGContext *s, TCGType type,
+ TCGReg a0, tcg_target_long a1, TCGReg a2)
+{
+ tgen_addci_rri(s, type, a0, a2, a1);
+}
+
+static void tgen_addci_rii(TCGContext *s, TCGType type, TCGReg a0,
+ tcg_target_long a1, tcg_target_long a2)
+{
+ if (a2 == 0) {
+ /* Implement 0 + 0 + C with -(x - x - c). */
+ tgen_arithr(s, ARITH_SBB, a0, a0);
+ tcg_out_modrm(s, OPC_GRP3_Ev, EXT3_NEG, a0);
+ } else {
+ tcg_out_movi(s, type, a0, a2);
+ tgen_addcio_imm(s, type, a0, a0, a1);
+ }
+}
+
+static const TCGOutOpAddSubCarry outop_addci = {
+ .base.static_constraint = C_O1_I2(r, rO, re),
+ .out_rrr = tgen_addci_rrr,
+ .out_rri = tgen_addci_rri,
+ .out_rir = tgen_addci_rir,
+ .out_rii = tgen_addci_rii,
+};
+
+static void tcg_out_set_carry(TCGContext *s)
+{
+ tcg_out8(s, OPC_STC);
+}
+
+static void tgen_and(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
+ tgen_arithr(s, ARITH_AND + rexw, a0, a2);
+}
+
+static void tgen_andi(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, tcg_target_long a2)
+{
+ int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
+ tgen_arithi(s, ARITH_AND + rexw, a0, a2, false);
+}
+
+static const TCGOutOpBinary outop_and = {
+ .base.static_constraint = C_O1_I2(r, 0, reZ),
+ .out_rrr = tgen_and,
+ .out_rri = tgen_andi,
+};
+
+static void tgen_andc(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
+ tcg_out_vex_modrm(s, OPC_ANDN + rexw, a0, a2, a1);
+}
+
+static TCGConstraintSetIndex cset_andc(TCGType type, unsigned flags)
+{
+ return have_bmi1 ? C_O1_I2(r, r, r) : C_NotImplemented;
+}
+
+static const TCGOutOpBinary outop_andc = {
+ .base.static_constraint = C_Dynamic,
+ .base.dynamic_constraint = cset_andc,
+ .out_rrr = tgen_andc,
+};
+
+static void tgen_clz(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
+ int jcc;
+
+ if (have_lzcnt) {
+ tcg_out_modrm(s, OPC_LZCNT + rexw, a0, a1);
+ jcc = JCC_JB;
+ } else {
+ /* Recall that the output of BSR is the index not the count. */
+ tcg_out_modrm(s, OPC_BSR + rexw, a0, a1);
+ tgen_arithi(s, ARITH_XOR + rexw, a0, rexw ? 63 : 31, 0);
+
+ /* Since we have destroyed the flags from BSR, we have to re-test. */
+ jcc = tcg_out_cmp(s, TCG_COND_EQ, a1, 0, 1, rexw);
+ }
+ tcg_out_cmov(s, jcc, rexw, a0, a2);
+}
+
+static void tgen_clzi(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, tcg_target_long a2)
+{
+ int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
+ tcg_out_modrm(s, OPC_LZCNT + rexw, a0, a1);
+}
+
+static TCGConstraintSetIndex cset_clz(TCGType type, unsigned flags)
+{
+ return have_lzcnt ? C_N1_I2(r, r, rW) : C_N1_I2(r, r, r);
+}
+
+static const TCGOutOpBinary outop_clz = {
+ .base.static_constraint = C_Dynamic,
+ .base.dynamic_constraint = cset_clz,
+ .out_rrr = tgen_clz,
+ .out_rri = tgen_clzi,
+};
+
+static void tgen_ctpop(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1)
+{
+ int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
+ tcg_out_modrm(s, OPC_POPCNT + rexw, a0, a1);
+}
+
+static TCGConstraintSetIndex cset_ctpop(TCGType type, unsigned flags)
+{
+ return have_popcnt ? C_O1_I1(r, r) : C_NotImplemented;
+}
+
+static const TCGOutOpUnary outop_ctpop = {
+ .base.static_constraint = C_Dynamic,
+ .base.dynamic_constraint = cset_ctpop,
+ .out_rr = tgen_ctpop,
+};
+
+static void tgen_ctz(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
+ int jcc;
+
+ if (have_bmi1) {
+ tcg_out_modrm(s, OPC_TZCNT + rexw, a0, a1);
+ jcc = JCC_JB;
+ } else {
+ tcg_out_modrm(s, OPC_BSF + rexw, a0, a1);
+ jcc = JCC_JE;
+ }
+ tcg_out_cmov(s, jcc, rexw, a0, a2);
+}
+
+static void tgen_ctzi(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, tcg_target_long a2)
+{
+ int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
+ tcg_out_modrm(s, OPC_TZCNT + rexw, a0, a1);
+}
+
+static TCGConstraintSetIndex cset_ctz(TCGType type, unsigned flags)
+{
+ return have_bmi1 ? C_N1_I2(r, r, rW) : C_N1_I2(r, r, r);
+}
+
+static const TCGOutOpBinary outop_ctz = {
+ .base.static_constraint = C_Dynamic,
+ .base.dynamic_constraint = cset_ctz,
+ .out_rrr = tgen_ctz,
+ .out_rri = tgen_ctzi,
+};
+
+static const TCGOutOpBinary outop_divs = {
+ .base.static_constraint = C_NotImplemented,
+};
+
+static void tgen_divs2(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a4)
+{
+ int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
+ tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_IDIV, a4);
+}
+
+static const TCGOutOpDivRem outop_divs2 = {
+ .base.static_constraint = C_O2_I3(a, d, 0, 1, r),
+ .out_rr01r = tgen_divs2,
+};
+
+static const TCGOutOpBinary outop_divu = {
+ .base.static_constraint = C_NotImplemented,
+};
+
+static void tgen_divu2(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a4)
+{
+ int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
+ tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_DIV, a4);
+}
+
+static const TCGOutOpDivRem outop_divu2 = {
+ .base.static_constraint = C_O2_I3(a, d, 0, 1, r),
+ .out_rr01r = tgen_divu2,
+};
+
+static const TCGOutOpBinary outop_eqv = {
+ .base.static_constraint = C_NotImplemented,
+};
- OP_32_64(st8):
- if (const_args[0]) {
- tcg_out_modrm_offset(s, OPC_MOVB_EvIz, 0, a1, a2);
- tcg_out8(s, a0);
- } else {
- tcg_out_modrm_offset(s, OPC_MOVB_EvGv | P_REXB_R, a0, a1, a2);
- }
- break;
- OP_32_64(st16):
- if (const_args[0]) {
- tcg_out_modrm_offset(s, OPC_MOVL_EvIz | P_DATA16, 0, a1, a2);
- tcg_out16(s, a0);
- } else {
- tcg_out_modrm_offset(s, OPC_MOVL_EvGv | P_DATA16, a0, a1, a2);
- }
- break;
#if TCG_TARGET_REG_BITS == 64
- case INDEX_op_st32_i64:
-#endif
- case INDEX_op_st_i32:
- if (const_args[0]) {
- tcg_out_modrm_offset(s, OPC_MOVL_EvIz, 0, a1, a2);
- tcg_out32(s, a0);
- } else {
- tcg_out_st(s, TCG_TYPE_I32, a0, a1, a2);
- }
- break;
+static void tgen_extrh_i64_i32(TCGContext *s, TCGType t, TCGReg a0, TCGReg a1)
+{
+ tcg_out_shifti(s, SHIFT_SHR + P_REXW, a0, 32);
+}
- OP_32_64(add):
- /* For 3-operand addition, use LEA. */
- if (a0 != a1) {
- TCGArg c3 = 0;
- if (const_a2) {
- c3 = a2, a2 = -1;
- } else if (a0 == a2) {
- /* Watch out for dest = src + dest, since we've removed
- the matching constraint on the add. */
- tgen_arithr(s, ARITH_ADD + rexw, a0, a1);
- break;
- }
+static const TCGOutOpUnary outop_extrh_i64_i32 = {
+ .base.static_constraint = C_O1_I1(r, 0),
+ .out_rr = tgen_extrh_i64_i32,
+};
+#endif /* TCG_TARGET_REG_BITS == 64 */
- tcg_out_modrm_sib_offset(s, OPC_LEA + rexw, a0, a1, a2, 0, c3);
- break;
- }
- c = ARITH_ADD;
- goto gen_arith;
- OP_32_64(sub):
- c = ARITH_SUB;
- goto gen_arith;
- OP_32_64(and):
- c = ARITH_AND;
- goto gen_arith;
- OP_32_64(or):
- c = ARITH_OR;
- goto gen_arith;
- OP_32_64(xor):
- c = ARITH_XOR;
- goto gen_arith;
- gen_arith:
- if (const_a2) {
- tgen_arithi(s, c + rexw, a0, a2, 0);
- } else {
- tgen_arithr(s, c + rexw, a0, a2);
- }
- break;
+static void tgen_mul(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
+ tcg_out_modrm(s, OPC_IMUL_GvEv + rexw, a0, a2);
+}
- OP_32_64(andc):
- if (const_a2) {
- tcg_out_mov(s, rexw ? TCG_TYPE_I64 : TCG_TYPE_I32, a0, a1);
- tgen_arithi(s, ARITH_AND + rexw, a0, ~a2, 0);
- } else {
- tcg_out_vex_modrm(s, OPC_ANDN + rexw, a0, a2, a1);
- }
- break;
+static void tgen_muli(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, tcg_target_long a2)
+{
+ int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
- OP_32_64(mul):
- if (const_a2) {
- int32_t val;
- val = a2;
- if (val == (int8_t)val) {
- tcg_out_modrm(s, OPC_IMUL_GvEvIb + rexw, a0, a0);
- tcg_out8(s, val);
- } else {
- tcg_out_modrm(s, OPC_IMUL_GvEvIz + rexw, a0, a0);
- tcg_out32(s, val);
- }
- } else {
- tcg_out_modrm(s, OPC_IMUL_GvEv + rexw, a0, a2);
- }
- break;
+ if (a2 == (int8_t)a2) {
+ tcg_out_modrm(s, OPC_IMUL_GvEvIb + rexw, a0, a0);
+ tcg_out8(s, a2);
+ } else {
+ tcg_out_modrm(s, OPC_IMUL_GvEvIz + rexw, a0, a0);
+ tcg_out32(s, a2);
+ }
+}
- OP_32_64(div2):
- tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_IDIV, args[4]);
- break;
- OP_32_64(divu2):
- tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_DIV, args[4]);
- break;
+static const TCGOutOpBinary outop_mul = {
+ .base.static_constraint = C_O1_I2(r, 0, re),
+ .out_rrr = tgen_mul,
+ .out_rri = tgen_muli,
+};
- OP_32_64(shl):
- /* For small constant 3-operand shift, use LEA. */
- if (const_a2 && a0 != a1 && (a2 - 1) < 3) {
- if (a2 - 1 == 0) {
- /* shl $1,a1,a0 -> lea (a1,a1),a0 */
- tcg_out_modrm_sib_offset(s, OPC_LEA + rexw, a0, a1, a1, 0, 0);
- } else {
- /* shl $n,a1,a0 -> lea 0(,a1,n),a0 */
- tcg_out_modrm_sib_offset(s, OPC_LEA + rexw, a0, -1, a1, a2, 0);
- }
- break;
- }
- c = SHIFT_SHL;
- vexop = OPC_SHLX;
- goto gen_shift_maybe_vex;
- OP_32_64(shr):
- c = SHIFT_SHR;
- vexop = OPC_SHRX;
- goto gen_shift_maybe_vex;
- OP_32_64(sar):
- c = SHIFT_SAR;
- vexop = OPC_SARX;
- goto gen_shift_maybe_vex;
- OP_32_64(rotl):
- c = SHIFT_ROL;
- goto gen_shift;
- OP_32_64(rotr):
- c = SHIFT_ROR;
- goto gen_shift;
- gen_shift_maybe_vex:
- if (have_bmi2) {
- if (!const_a2) {
- tcg_out_vex_modrm(s, vexop + rexw, a0, a2, a1);
- break;
- }
- tcg_out_mov(s, rexw ? TCG_TYPE_I64 : TCG_TYPE_I32, a0, a1);
- }
- /* FALLTHRU */
- gen_shift:
- if (const_a2) {
- tcg_out_shifti(s, c + rexw, a0, a2);
- } else {
- tcg_out_modrm(s, OPC_SHIFT_cl + rexw, c, a0);
- }
- break;
+static void tgen_muls2(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2, TCGReg a3)
+{
+ int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
+ tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_IMUL, a3);
+}
- OP_32_64(ctz):
- tcg_out_ctz(s, rexw, args[0], args[1], args[2], const_args[2]);
- break;
- OP_32_64(clz):
- tcg_out_clz(s, rexw, args[0], args[1], args[2], const_args[2]);
- break;
- OP_32_64(ctpop):
- tcg_out_modrm(s, OPC_POPCNT + rexw, a0, a1);
- break;
+static const TCGOutOpMul2 outop_muls2 = {
+ .base.static_constraint = C_O2_I2(a, d, a, r),
+ .out_rrrr = tgen_muls2,
+};
- OP_32_64(brcond):
- tcg_out_brcond(s, rexw, a2, a0, a1, const_args[1],
- arg_label(args[3]), 0);
- break;
- OP_32_64(setcond):
- tcg_out_setcond(s, rexw, args[3], a0, a1, a2, const_a2, false);
- break;
- OP_32_64(negsetcond):
- tcg_out_setcond(s, rexw, args[3], a0, a1, a2, const_a2, true);
- break;
- OP_32_64(movcond):
- tcg_out_movcond(s, rexw, args[5], a0, a1, a2, const_a2, args[3]);
- break;
+static const TCGOutOpBinary outop_mulsh = {
+ .base.static_constraint = C_NotImplemented,
+};
- OP_32_64(bswap16):
- if (a2 & TCG_BSWAP_OS) {
- /* Output must be sign-extended. */
- if (rexw) {
- tcg_out_bswap64(s, a0);
- tcg_out_shifti(s, SHIFT_SAR + rexw, a0, 48);
- } else {
- tcg_out_bswap32(s, a0);
- tcg_out_shifti(s, SHIFT_SAR, a0, 16);
- }
- } else if ((a2 & (TCG_BSWAP_IZ | TCG_BSWAP_OZ)) == TCG_BSWAP_OZ) {
- /* Output must be zero-extended, but input isn't. */
- tcg_out_bswap32(s, a0);
- tcg_out_shifti(s, SHIFT_SHR, a0, 16);
- } else {
- tcg_out_rolw_8(s, a0);
- }
- break;
- OP_32_64(bswap32):
- tcg_out_bswap32(s, a0);
- if (rexw && (a2 & TCG_BSWAP_OS)) {
- tcg_out_ext32s(s, a0, a0);
- }
- break;
+static const TCGOutOpBinary outop_muluh = {
+ .base.static_constraint = C_NotImplemented,
+};
- OP_32_64(neg):
- tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_NEG, a0);
- break;
- OP_32_64(not):
- tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_NOT, a0);
- break;
+static void tgen_mulu2(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2, TCGReg a3)
+{
+ int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
+ tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_MUL, a3);
+}
- case INDEX_op_qemu_ld_i32:
- tcg_out_qemu_ld(s, a0, -1, a1, a2, TCG_TYPE_I32);
- break;
- case INDEX_op_qemu_ld_i64:
- if (TCG_TARGET_REG_BITS == 64) {
- tcg_out_qemu_ld(s, a0, -1, a1, a2, TCG_TYPE_I64);
- } else {
- tcg_out_qemu_ld(s, a0, a1, a2, args[3], TCG_TYPE_I64);
- }
- break;
- case INDEX_op_qemu_ld_i128:
- tcg_debug_assert(TCG_TARGET_REG_BITS == 64);
- tcg_out_qemu_ld(s, a0, a1, a2, args[3], TCG_TYPE_I128);
- break;
+static const TCGOutOpMul2 outop_mulu2 = {
+ .base.static_constraint = C_O2_I2(a, d, a, r),
+ .out_rrrr = tgen_mulu2,
+};
- case INDEX_op_qemu_st_i32:
- case INDEX_op_qemu_st8_i32:
- tcg_out_qemu_st(s, a0, -1, a1, a2, TCG_TYPE_I32);
- break;
- case INDEX_op_qemu_st_i64:
- if (TCG_TARGET_REG_BITS == 64) {
- tcg_out_qemu_st(s, a0, -1, a1, a2, TCG_TYPE_I64);
- } else {
- tcg_out_qemu_st(s, a0, a1, a2, args[3], TCG_TYPE_I64);
- }
- break;
- case INDEX_op_qemu_st_i128:
- tcg_debug_assert(TCG_TARGET_REG_BITS == 64);
- tcg_out_qemu_st(s, a0, a1, a2, args[3], TCG_TYPE_I128);
- break;
+static const TCGOutOpBinary outop_nand = {
+ .base.static_constraint = C_NotImplemented,
+};
- OP_32_64(mulu2):
- tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_MUL, args[3]);
- break;
- OP_32_64(muls2):
- tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_IMUL, args[3]);
- break;
- OP_32_64(add2):
- if (const_args[4]) {
- tgen_arithi(s, ARITH_ADD + rexw, a0, args[4], 1);
- } else {
- tgen_arithr(s, ARITH_ADD + rexw, a0, args[4]);
- }
- if (const_args[5]) {
- tgen_arithi(s, ARITH_ADC + rexw, a1, args[5], 1);
- } else {
- tgen_arithr(s, ARITH_ADC + rexw, a1, args[5]);
- }
- break;
- OP_32_64(sub2):
- if (const_args[4]) {
- tgen_arithi(s, ARITH_SUB + rexw, a0, args[4], 1);
- } else {
- tgen_arithr(s, ARITH_SUB + rexw, a0, args[4]);
- }
- if (const_args[5]) {
- tgen_arithi(s, ARITH_SBB + rexw, a1, args[5], 1);
+static const TCGOutOpBinary outop_nor = {
+ .base.static_constraint = C_NotImplemented,
+};
+
+static void tgen_or(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
+ tgen_arithr(s, ARITH_OR + rexw, a0, a2);
+}
+
+static void tgen_ori(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, tcg_target_long a2)
+{
+ int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
+ tgen_arithi(s, ARITH_OR + rexw, a0, a2, false);
+}
+
+static const TCGOutOpBinary outop_or = {
+ .base.static_constraint = C_O1_I2(r, 0, re),
+ .out_rrr = tgen_or,
+ .out_rri = tgen_ori,
+};
+
+static const TCGOutOpBinary outop_orc = {
+ .base.static_constraint = C_NotImplemented,
+};
+
+static const TCGOutOpBinary outop_rems = {
+ .base.static_constraint = C_NotImplemented,
+};
+
+static const TCGOutOpBinary outop_remu = {
+ .base.static_constraint = C_NotImplemented,
+};
+
+static void tgen_rotl(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
+ tcg_out_modrm(s, OPC_SHIFT_cl + rexw, SHIFT_ROL, a0);
+}
+
+static void tgen_rotli(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, tcg_target_long a2)
+{
+ int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
+ tcg_out_shifti(s, SHIFT_ROL + rexw, a0, a2);
+}
+
+static const TCGOutOpBinary outop_rotl = {
+ .base.static_constraint = C_O1_I2(r, 0, ci),
+ .out_rrr = tgen_rotl,
+ .out_rri = tgen_rotli,
+};
+
+static void tgen_rotr(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
+ tcg_out_modrm(s, OPC_SHIFT_cl + rexw, SHIFT_ROR, a0);
+}
+
+static void tgen_rotri(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, tcg_target_long a2)
+{
+ int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
+ tcg_out_shifti(s, SHIFT_ROR + rexw, a0, a2);
+}
+
+static const TCGOutOpBinary outop_rotr = {
+ .base.static_constraint = C_O1_I2(r, 0, ci),
+ .out_rrr = tgen_rotr,
+ .out_rri = tgen_rotri,
+};
+
+static TCGConstraintSetIndex cset_shift(TCGType type, unsigned flags)
+{
+ return have_bmi2 ? C_O1_I2(r, r, ri) : C_O1_I2(r, 0, ci);
+}
+
+static void tgen_sar(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
+ if (have_bmi2) {
+ tcg_out_vex_modrm(s, OPC_SARX + rexw, a0, a2, a1);
+ } else {
+ tcg_out_modrm(s, OPC_SHIFT_cl + rexw, SHIFT_SAR, a0);
+ }
+}
+
+static void tgen_sari(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, tcg_target_long a2)
+{
+ int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
+
+ tcg_out_mov(s, type, a0, a1);
+ tcg_out_shifti(s, SHIFT_SAR + rexw, a0, a2);
+}
+
+static const TCGOutOpBinary outop_sar = {
+ .base.static_constraint = C_Dynamic,
+ .base.dynamic_constraint = cset_shift,
+ .out_rrr = tgen_sar,
+ .out_rri = tgen_sari,
+};
+
+static void tgen_shl(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
+ if (have_bmi2) {
+ tcg_out_vex_modrm(s, OPC_SHLX + rexw, a0, a2, a1);
+ } else {
+ tcg_out_modrm(s, OPC_SHIFT_cl + rexw, SHIFT_SHL, a0);
+ }
+}
+
+static void tgen_shli(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, tcg_target_long a2)
+{
+ int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
+
+ /* For small constant 3-operand shift, use LEA. */
+ if (a0 != a1 && a2 >= 1 && a2 <= 3) {
+ if (a2 == 1) {
+ /* shl $1,a1,a0 -> lea (a1,a1),a0 */
+ tcg_out_modrm_sib_offset(s, OPC_LEA + rexw, a0, a1, a1, 0, 0);
} else {
- tgen_arithr(s, ARITH_SBB + rexw, a1, args[5]);
+ /* shl $n,a1,a0 -> lea 0(,a1,n),a0 */
+ tcg_out_modrm_sib_offset(s, OPC_LEA + rexw, a0, -1, a1, a2, 0);
}
- break;
+ return;
+ }
+ tcg_out_mov(s, type, a0, a1);
+ tcg_out_shifti(s, SHIFT_SHL + rexw, a0, a2);
+}
-#if TCG_TARGET_REG_BITS == 32
- case INDEX_op_brcond2_i32:
- tcg_out_brcond2(s, args, const_args, 0);
- break;
- case INDEX_op_setcond2_i32:
- tcg_out_setcond2(s, args, const_args);
- break;
-#else /* TCG_TARGET_REG_BITS == 64 */
- case INDEX_op_ld32s_i64:
- tcg_out_modrm_offset(s, OPC_MOVSLQ, a0, a1, a2);
- break;
- case INDEX_op_ld_i64:
- tcg_out_ld(s, TCG_TYPE_I64, a0, a1, a2);
- break;
- case INDEX_op_st_i64:
- if (const_args[0]) {
- tcg_out_modrm_offset(s, OPC_MOVL_EvIz | P_REXW, 0, a1, a2);
- tcg_out32(s, a0);
+static const TCGOutOpBinary outop_shl = {
+ .base.static_constraint = C_Dynamic,
+ .base.dynamic_constraint = cset_shift,
+ .out_rrr = tgen_shl,
+ .out_rri = tgen_shli,
+};
+
+static void tgen_shr(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
+ if (have_bmi2) {
+ tcg_out_vex_modrm(s, OPC_SHRX + rexw, a0, a2, a1);
+ } else {
+ tcg_out_modrm(s, OPC_SHIFT_cl + rexw, SHIFT_SHR, a0);
+ }
+}
+
+static void tgen_shri(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, tcg_target_long a2)
+{
+ int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
+
+ tcg_out_mov(s, type, a0, a1);
+ tcg_out_shifti(s, SHIFT_SHR + rexw, a0, a2);
+}
+
+static const TCGOutOpBinary outop_shr = {
+ .base.static_constraint = C_Dynamic,
+ .base.dynamic_constraint = cset_shift,
+ .out_rrr = tgen_shr,
+ .out_rri = tgen_shri,
+};
+
+static void tgen_sub(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
+ tgen_arithr(s, ARITH_SUB + rexw, a0, a2);
+}
+
+static const TCGOutOpSubtract outop_sub = {
+ .base.static_constraint = C_O1_I2(r, 0, r),
+ .out_rrr = tgen_sub,
+};
+
+static void tgen_subbo_rri(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, tcg_target_long a2)
+{
+ int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
+ tgen_arithi(s, ARITH_SUB + rexw, a0, a2, 1);
+}
+
+static const TCGOutOpAddSubCarry outop_subbo = {
+ .base.static_constraint = C_O1_I2(r, 0, re),
+ .out_rrr = tgen_sub,
+ .out_rri = tgen_subbo_rri,
+};
+
+static void tgen_subbio_rrr(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
+ tgen_arithr(s, ARITH_SBB + rexw, a0, a2);
+}
+
+static void tgen_subbio_rri(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, tcg_target_long a2)
+{
+ int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
+ tgen_arithi(s, ARITH_SBB + rexw, a0, a2, 1);
+}
+
+static const TCGOutOpAddSubCarry outop_subbio = {
+ .base.static_constraint = C_O1_I2(r, 0, re),
+ .out_rrr = tgen_subbio_rrr,
+ .out_rri = tgen_subbio_rri,
+};
+
+#define outop_subbi outop_subbio
+
+static void tcg_out_set_borrow(TCGContext *s)
+{
+ tcg_out8(s, OPC_STC);
+}
+
+static void tgen_xor(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
+ tgen_arithr(s, ARITH_XOR + rexw, a0, a2);
+}
+
+static void tgen_xori(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, tcg_target_long a2)
+{
+ int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
+ tgen_arithi(s, ARITH_XOR + rexw, a0, a2, false);
+}
+
+static const TCGOutOpBinary outop_xor = {
+ .base.static_constraint = C_O1_I2(r, 0, re),
+ .out_rrr = tgen_xor,
+ .out_rri = tgen_xori,
+};
+
+static void tgen_bswap16(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, unsigned flags)
+{
+ int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
+
+ if (flags & TCG_BSWAP_OS) {
+ /* Output must be sign-extended. */
+ if (rexw) {
+ tcg_out_bswap64(s, a0);
+ tcg_out_shifti(s, SHIFT_SAR + rexw, a0, 48);
} else {
- tcg_out_st(s, TCG_TYPE_I64, a0, a1, a2);
+ tcg_out_bswap32(s, a0);
+ tcg_out_shifti(s, SHIFT_SAR, a0, 16);
}
- break;
+ } else if ((flags & (TCG_BSWAP_IZ | TCG_BSWAP_OZ)) == TCG_BSWAP_OZ) {
+ /* Output must be zero-extended, but input isn't. */
+ tcg_out_bswap32(s, a0);
+ tcg_out_shifti(s, SHIFT_SHR, a0, 16);
+ } else {
+ tcg_out_rolw_8(s, a0);
+ }
+}
- case INDEX_op_bswap64_i64:
- tcg_out_bswap64(s, a0);
- break;
- case INDEX_op_extrh_i64_i32:
- tcg_out_shifti(s, SHIFT_SHR + P_REXW, a0, 32);
- break;
+static const TCGOutOpBswap outop_bswap16 = {
+ .base.static_constraint = C_O1_I1(r, 0),
+ .out_rr = tgen_bswap16,
+};
+
+static void tgen_bswap32(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, unsigned flags)
+{
+ tcg_out_bswap32(s, a0);
+ if (flags & TCG_BSWAP_OS) {
+ tcg_out_ext32s(s, a0, a0);
+ }
+}
+
+static const TCGOutOpBswap outop_bswap32 = {
+ .base.static_constraint = C_O1_I1(r, 0),
+ .out_rr = tgen_bswap32,
+};
+
+#if TCG_TARGET_REG_BITS == 64
+static void tgen_bswap64(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1)
+{
+ tcg_out_bswap64(s, a0);
+}
+
+static const TCGOutOpUnary outop_bswap64 = {
+ .base.static_constraint = C_O1_I1(r, 0),
+ .out_rr = tgen_bswap64,
+};
#endif
- OP_32_64(deposit):
- if (args[3] == 0 && args[4] == 8) {
- /* load bits 0..7 */
- if (const_a2) {
- tcg_out_opc(s, OPC_MOVB_Ib | P_REXB_RM | LOWREGMASK(a0),
- 0, a0, 0);
- tcg_out8(s, a2);
- } else {
- tcg_out_modrm(s, OPC_MOVB_EvGv | P_REXB_R | P_REXB_RM, a2, a0);
- }
- } else if (TCG_TARGET_REG_BITS == 32 && args[3] == 8 && args[4] == 8) {
- /* load bits 8..15 */
- if (const_a2) {
- tcg_out8(s, OPC_MOVB_Ib + a0 + 4);
- tcg_out8(s, a2);
- } else {
- tcg_out_modrm(s, OPC_MOVB_EvGv, a2, a0 + 4);
- }
- } else if (args[3] == 0 && args[4] == 16) {
- /* load bits 0..15 */
- if (const_a2) {
- tcg_out_opc(s, OPC_MOVL_Iv | P_DATA16 | LOWREGMASK(a0),
- 0, a0, 0);
- tcg_out16(s, a2);
- } else {
- tcg_out_modrm(s, OPC_MOVL_EvGv | P_DATA16, a2, a0);
- }
- } else {
- g_assert_not_reached();
- }
- break;
+static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1)
+{
+ int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
+ tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_NEG, a0);
+}
- case INDEX_op_extract_i64:
- if (a2 + args[3] == 32) {
- if (a2 == 0) {
- tcg_out_ext32u(s, a0, a1);
- break;
- }
- /* This is a 32-bit zero-extending right shift. */
- tcg_out_mov(s, TCG_TYPE_I32, a0, a1);
- tcg_out_shifti(s, SHIFT_SHR, a0, a2);
- break;
- }
- /* FALLTHRU */
- case INDEX_op_extract_i32:
- if (a2 == 0 && args[3] == 8) {
+static const TCGOutOpUnary outop_neg = {
+ .base.static_constraint = C_O1_I1(r, 0),
+ .out_rr = tgen_neg,
+};
+
+static void tgen_not(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1)
+{
+ int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
+ tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_NOT, a0);
+}
+
+static const TCGOutOpUnary outop_not = {
+ .base.static_constraint = C_O1_I1(r, 0),
+ .out_rr = tgen_not,
+};
+
+static void tgen_deposit(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1,
+ TCGReg a2, unsigned ofs, unsigned len)
+{
+ if (ofs == 0 && len == 8) {
+ tcg_out_modrm(s, OPC_MOVB_EvGv | P_REXB_R | P_REXB_RM, a2, a0);
+ } else if (ofs == 0 && len == 16) {
+ tcg_out_modrm(s, OPC_MOVL_EvGv | P_DATA16, a2, a0);
+ } else if (TCG_TARGET_REG_BITS == 32 && ofs == 8 && len == 8) {
+ tcg_out_modrm(s, OPC_MOVB_EvGv, a2, a0 + 4);
+ } else {
+ g_assert_not_reached();
+ }
+}
+
+static void tgen_depositi(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1,
+ tcg_target_long a2, unsigned ofs, unsigned len)
+{
+ if (ofs == 0 && len == 8) {
+ tcg_out_opc(s, OPC_MOVB_Ib | P_REXB_RM | LOWREGMASK(a0), 0, a0, 0);
+ tcg_out8(s, a2);
+ } else if (ofs == 0 && len == 16) {
+ tcg_out_opc(s, OPC_MOVL_Iv | P_DATA16 | LOWREGMASK(a0), 0, a0, 0);
+ tcg_out16(s, a2);
+ } else if (TCG_TARGET_REG_BITS == 32 && ofs == 8 && len == 8) {
+ tcg_out8(s, OPC_MOVB_Ib + a0 + 4);
+ tcg_out8(s, a2);
+ } else {
+ g_assert_not_reached();
+ }
+}
+
+static const TCGOutOpDeposit outop_deposit = {
+ .base.static_constraint = C_O1_I2(q, 0, qi),
+ .out_rrr = tgen_deposit,
+ .out_rri = tgen_depositi,
+};
+
+static void tgen_extract(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1,
+ unsigned ofs, unsigned len)
+{
+ if (ofs == 0) {
+ switch (len) {
+ case 8:
tcg_out_ext8u(s, a0, a1);
- } else if (a2 == 0 && args[3] == 16) {
+ return;
+ case 16:
tcg_out_ext16u(s, a0, a1);
- } else if (a2 == 8 && args[3] == 8) {
- /*
- * On the off-chance that we can use the high-byte registers.
- * Otherwise we emit the same ext16 + shift pattern that we
- * would have gotten from the normal tcg-op.c expansion.
- */
- if (a1 < 4 && a0 < 8) {
- tcg_out_modrm(s, OPC_MOVZBL, a0, a1 + 4);
- } else {
- tcg_out_ext16u(s, a0, a1);
- tcg_out_shifti(s, SHIFT_SHR, a0, 8);
- }
+ return;
+ case 32:
+ tcg_out_ext32u(s, a0, a1);
+ return;
+ }
+ } else if (TCG_TARGET_REG_BITS == 64 && ofs + len == 32) {
+ /* This is a 32-bit zero-extending right shift. */
+ tcg_out_mov(s, TCG_TYPE_I32, a0, a1);
+ tcg_out_shifti(s, SHIFT_SHR, a0, ofs);
+ return;
+ } else if (ofs == 8 && len == 8) {
+ /*
+ * On the off-chance that we can use the high-byte registers.
+ * Otherwise we emit the same ext16 + shift pattern that we
+ * would have gotten from the normal tcg-op.c expansion.
+ */
+ if (a1 < 4 && (TCG_TARGET_REG_BITS == 32 || a0 < 8)) {
+ tcg_out_modrm(s, OPC_MOVZBL, a0, a1 + 4);
} else {
- g_assert_not_reached();
+ tcg_out_ext16u(s, a0, a1);
+ tcg_out_shifti(s, SHIFT_SHR, a0, 8);
}
- break;
+ return;
+ }
+ g_assert_not_reached();
+}
+
+static const TCGOutOpExtract outop_extract = {
+ .base.static_constraint = C_O1_I1(r, r),
+ .out_rr = tgen_extract,
+};
- case INDEX_op_sextract_i64:
- if (a2 == 0 && args[3] == 8) {
- tcg_out_ext8s(s, TCG_TYPE_I64, a0, a1);
- } else if (a2 == 0 && args[3] == 16) {
- tcg_out_ext16s(s, TCG_TYPE_I64, a0, a1);
- } else if (a2 == 0 && args[3] == 32) {
+static void tgen_sextract(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1,
+ unsigned ofs, unsigned len)
+{
+ if (ofs == 0) {
+ switch (len) {
+ case 8:
+ tcg_out_ext8s(s, type, a0, a1);
+ return;
+ case 16:
+ tcg_out_ext16s(s, type, a0, a1);
+ return;
+ case 32:
tcg_out_ext32s(s, a0, a1);
- } else {
- g_assert_not_reached();
+ return;
}
- break;
-
- case INDEX_op_sextract_i32:
- if (a2 == 0 && args[3] == 8) {
- tcg_out_ext8s(s, TCG_TYPE_I32, a0, a1);
- } else if (a2 == 0 && args[3] == 16) {
- tcg_out_ext16s(s, TCG_TYPE_I32, a0, a1);
- } else if (a2 == 8 && args[3] == 8) {
- if (a1 < 4 && a0 < 8) {
- tcg_out_modrm(s, OPC_MOVSBL, a0, a1 + 4);
- } else {
- tcg_out_ext16s(s, TCG_TYPE_I32, a0, a1);
- tcg_out_shifti(s, SHIFT_SAR, a0, 8);
- }
+ } else if (ofs == 8 && len == 8) {
+ if (type == TCG_TYPE_I32 && a1 < 4 && a0 < 8) {
+ tcg_out_modrm(s, OPC_MOVSBL, a0, a1 + 4);
} else {
- g_assert_not_reached();
+ tcg_out_ext16s(s, type, a0, a1);
+ tgen_sari(s, type, a0, a0, 8);
}
- break;
+ return;
+ }
+ g_assert_not_reached();
+}
- OP_32_64(extract2):
- /* Note that SHRD outputs to the r/m operand. */
- tcg_out_modrm(s, OPC_SHRD_Ib + rexw, a2, a0);
- tcg_out8(s, args[3]);
- break;
+static const TCGOutOpExtract outop_sextract = {
+ .base.static_constraint = C_O1_I1(r, r),
+ .out_rr = tgen_sextract,
+};
- case INDEX_op_mb:
- tcg_out_mb(s, a0);
- break;
- case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */
- case INDEX_op_mov_i64:
- case INDEX_op_call: /* Always emitted via tcg_out_call. */
- case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */
- case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */
- case INDEX_op_ext8s_i32: /* Always emitted via tcg_reg_alloc_op. */
- case INDEX_op_ext8s_i64:
- case INDEX_op_ext8u_i32:
- case INDEX_op_ext8u_i64:
- case INDEX_op_ext16s_i32:
- case INDEX_op_ext16s_i64:
- case INDEX_op_ext16u_i32:
- case INDEX_op_ext16u_i64:
- case INDEX_op_ext32s_i64:
- case INDEX_op_ext32u_i64:
- case INDEX_op_ext_i32_i64:
- case INDEX_op_extu_i32_i64:
- case INDEX_op_extrl_i64_i32:
- default:
- g_assert_not_reached();
- }
+static void tgen_extract2(TCGContext *s, TCGType type, TCGReg a0,
+ TCGReg a1, TCGReg a2, unsigned shr)
+{
+ int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
+
+ /* Note that SHRD outputs to the r/m operand. */
+ tcg_out_modrm(s, OPC_SHRD_Ib + rexw, a2, a0);
+ tcg_out8(s, shr);
+}
-#undef OP_32_64
+static const TCGOutOpExtract2 outop_extract2 = {
+ .base.static_constraint = C_O1_I2(r, 0, r),
+ .out_rrr = tgen_extract2,
+};
+
+static void tgen_ld8u(TCGContext *s, TCGType type, TCGReg dest,
+ TCGReg base, ptrdiff_t offset)
+{
+ tcg_out_modrm_offset(s, OPC_MOVZBL, dest, base, offset);
+}
+
+static const TCGOutOpLoad outop_ld8u = {
+ .base.static_constraint = C_O1_I1(r, r),
+ .out = tgen_ld8u,
+};
+
+static void tgen_ld8s(TCGContext *s, TCGType type, TCGReg dest,
+ TCGReg base, ptrdiff_t offset)
+{
+ int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
+ tcg_out_modrm_offset(s, OPC_MOVSBL + rexw, dest, base, offset);
+}
+
+static const TCGOutOpLoad outop_ld8s = {
+ .base.static_constraint = C_O1_I1(r, r),
+ .out = tgen_ld8s,
+};
+
+static void tgen_ld16u(TCGContext *s, TCGType type, TCGReg dest,
+ TCGReg base, ptrdiff_t offset)
+{
+ tcg_out_modrm_offset(s, OPC_MOVZWL, dest, base, offset);
+}
+
+static const TCGOutOpLoad outop_ld16u = {
+ .base.static_constraint = C_O1_I1(r, r),
+ .out = tgen_ld16u,
+};
+
+static void tgen_ld16s(TCGContext *s, TCGType type, TCGReg dest,
+ TCGReg base, ptrdiff_t offset)
+{
+ int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
+ tcg_out_modrm_offset(s, OPC_MOVSWL + rexw, dest, base, offset);
}
+static const TCGOutOpLoad outop_ld16s = {
+ .base.static_constraint = C_O1_I1(r, r),
+ .out = tgen_ld16s,
+};
+
+#if TCG_TARGET_REG_BITS == 64
+static void tgen_ld32u(TCGContext *s, TCGType type, TCGReg dest,
+ TCGReg base, ptrdiff_t offset)
+{
+ tcg_out_modrm_offset(s, OPC_MOVL_GvEv, dest, base, offset);
+}
+
+static const TCGOutOpLoad outop_ld32u = {
+ .base.static_constraint = C_O1_I1(r, r),
+ .out = tgen_ld32u,
+};
+
+static void tgen_ld32s(TCGContext *s, TCGType type, TCGReg dest,
+ TCGReg base, ptrdiff_t offset)
+{
+ tcg_out_modrm_offset(s, OPC_MOVSLQ, dest, base, offset);
+}
+
+static const TCGOutOpLoad outop_ld32s = {
+ .base.static_constraint = C_O1_I1(r, r),
+ .out = tgen_ld32s,
+};
+#endif
+
+static void tgen_st8_r(TCGContext *s, TCGType type, TCGReg data,
+ TCGReg base, ptrdiff_t offset)
+{
+ tcg_out_modrm_offset(s, OPC_MOVB_EvGv | P_REXB_R, data, base, offset);
+}
+
+static void tgen_st8_i(TCGContext *s, TCGType type, tcg_target_long data,
+ TCGReg base, ptrdiff_t offset)
+{
+ tcg_out_modrm_offset(s, OPC_MOVB_EvIz, 0, base, offset);
+ tcg_out8(s, data);
+}
+
+static const TCGOutOpStore outop_st8 = {
+ .base.static_constraint = C_O0_I2(qi, r),
+ .out_r = tgen_st8_r,
+ .out_i = tgen_st8_i,
+};
+
+static void tgen_st16_r(TCGContext *s, TCGType type, TCGReg data,
+ TCGReg base, ptrdiff_t offset)
+{
+ tcg_out_modrm_offset(s, OPC_MOVL_EvGv | P_DATA16, data, base, offset);
+}
+
+static void tgen_st16_i(TCGContext *s, TCGType type, tcg_target_long data,
+ TCGReg base, ptrdiff_t offset)
+{
+ tcg_out_modrm_offset(s, OPC_MOVL_EvIz | P_DATA16, 0, base, offset);
+ tcg_out16(s, data);
+}
+
+static const TCGOutOpStore outop_st16 = {
+ .base.static_constraint = C_O0_I2(ri, r),
+ .out_r = tgen_st16_r,
+ .out_i = tgen_st16_i,
+};
+
+static void tgen_st_i(TCGContext *s, TCGType type, tcg_target_long data,
+ TCGReg base, ptrdiff_t offset)
+{
+ bool ok = tcg_out_sti(s, type, data, base, offset);
+ tcg_debug_assert(ok);
+}
+
+static const TCGOutOpStore outop_st = {
+ .base.static_constraint = C_O0_I2(re, r),
+ .out_r = tcg_out_st,
+ .out_i = tgen_st_i,
+};
+
static int const umin_insn[4] = {
OPC_PMINUB, OPC_PMINUW, OPC_PMINUD, OPC_VPMINUQ
};
@@ -3581,182 +4147,6 @@ static TCGConstraintSetIndex
tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags)
{
switch (op) {
- case INDEX_op_goto_ptr:
- return C_O0_I1(r);
-
- case INDEX_op_ld8u_i32:
- case INDEX_op_ld8u_i64:
- case INDEX_op_ld8s_i32:
- case INDEX_op_ld8s_i64:
- case INDEX_op_ld16u_i32:
- case INDEX_op_ld16u_i64:
- case INDEX_op_ld16s_i32:
- case INDEX_op_ld16s_i64:
- case INDEX_op_ld_i32:
- case INDEX_op_ld32u_i64:
- case INDEX_op_ld32s_i64:
- case INDEX_op_ld_i64:
- return C_O1_I1(r, r);
-
- case INDEX_op_st8_i32:
- case INDEX_op_st8_i64:
- return C_O0_I2(qi, r);
-
- case INDEX_op_st16_i32:
- case INDEX_op_st16_i64:
- case INDEX_op_st_i32:
- case INDEX_op_st32_i64:
- return C_O0_I2(ri, r);
-
- case INDEX_op_st_i64:
- return C_O0_I2(re, r);
-
- case INDEX_op_add_i32:
- case INDEX_op_add_i64:
- return C_O1_I2(r, r, re);
-
- case INDEX_op_sub_i32:
- case INDEX_op_sub_i64:
- case INDEX_op_mul_i32:
- case INDEX_op_mul_i64:
- case INDEX_op_or_i32:
- case INDEX_op_or_i64:
- case INDEX_op_xor_i32:
- case INDEX_op_xor_i64:
- return C_O1_I2(r, 0, re);
-
- case INDEX_op_and_i32:
- case INDEX_op_and_i64:
- return C_O1_I2(r, 0, reZ);
-
- case INDEX_op_andc_i32:
- case INDEX_op_andc_i64:
- return C_O1_I2(r, r, rI);
-
- case INDEX_op_shl_i32:
- case INDEX_op_shl_i64:
- case INDEX_op_shr_i32:
- case INDEX_op_shr_i64:
- case INDEX_op_sar_i32:
- case INDEX_op_sar_i64:
- return have_bmi2 ? C_O1_I2(r, r, ri) : C_O1_I2(r, 0, ci);
-
- case INDEX_op_rotl_i32:
- case INDEX_op_rotl_i64:
- case INDEX_op_rotr_i32:
- case INDEX_op_rotr_i64:
- return C_O1_I2(r, 0, ci);
-
- case INDEX_op_brcond_i32:
- case INDEX_op_brcond_i64:
- return C_O0_I2(r, reT);
-
- case INDEX_op_bswap16_i32:
- case INDEX_op_bswap16_i64:
- case INDEX_op_bswap32_i32:
- case INDEX_op_bswap32_i64:
- case INDEX_op_bswap64_i64:
- case INDEX_op_neg_i32:
- case INDEX_op_neg_i64:
- case INDEX_op_not_i32:
- case INDEX_op_not_i64:
- case INDEX_op_extrh_i64_i32:
- return C_O1_I1(r, 0);
-
- case INDEX_op_ext8s_i32:
- case INDEX_op_ext8s_i64:
- case INDEX_op_ext8u_i32:
- case INDEX_op_ext8u_i64:
- return C_O1_I1(r, q);
-
- case INDEX_op_ext16s_i32:
- case INDEX_op_ext16s_i64:
- case INDEX_op_ext16u_i32:
- case INDEX_op_ext16u_i64:
- case INDEX_op_ext32s_i64:
- case INDEX_op_ext32u_i64:
- case INDEX_op_ext_i32_i64:
- case INDEX_op_extu_i32_i64:
- case INDEX_op_extrl_i64_i32:
- case INDEX_op_extract_i32:
- case INDEX_op_extract_i64:
- case INDEX_op_sextract_i32:
- case INDEX_op_sextract_i64:
- case INDEX_op_ctpop_i32:
- case INDEX_op_ctpop_i64:
- return C_O1_I1(r, r);
-
- case INDEX_op_extract2_i32:
- case INDEX_op_extract2_i64:
- return C_O1_I2(r, 0, r);
-
- case INDEX_op_deposit_i32:
- case INDEX_op_deposit_i64:
- return C_O1_I2(q, 0, qi);
-
- case INDEX_op_setcond_i32:
- case INDEX_op_setcond_i64:
- case INDEX_op_negsetcond_i32:
- case INDEX_op_negsetcond_i64:
- return C_O1_I2(q, r, reT);
-
- case INDEX_op_movcond_i32:
- case INDEX_op_movcond_i64:
- return C_O1_I4(r, r, reT, r, 0);
-
- case INDEX_op_div2_i32:
- case INDEX_op_div2_i64:
- case INDEX_op_divu2_i32:
- case INDEX_op_divu2_i64:
- return C_O2_I3(a, d, 0, 1, r);
-
- case INDEX_op_mulu2_i32:
- case INDEX_op_mulu2_i64:
- case INDEX_op_muls2_i32:
- case INDEX_op_muls2_i64:
- return C_O2_I2(a, d, a, r);
-
- case INDEX_op_add2_i32:
- case INDEX_op_add2_i64:
- case INDEX_op_sub2_i32:
- case INDEX_op_sub2_i64:
- return C_N1_O1_I4(r, r, 0, 1, re, re);
-
- case INDEX_op_ctz_i32:
- case INDEX_op_ctz_i64:
- return have_bmi1 ? C_N1_I2(r, r, rW) : C_N1_I2(r, r, r);
-
- case INDEX_op_clz_i32:
- case INDEX_op_clz_i64:
- return have_lzcnt ? C_N1_I2(r, r, rW) : C_N1_I2(r, r, r);
-
- case INDEX_op_qemu_ld_i32:
- return C_O1_I1(r, L);
-
- case INDEX_op_qemu_st_i32:
- return C_O0_I2(L, L);
- case INDEX_op_qemu_st8_i32:
- return C_O0_I2(s, L);
-
- case INDEX_op_qemu_ld_i64:
- return TCG_TARGET_REG_BITS == 64 ? C_O1_I1(r, L) : C_O2_I1(r, r, L);
-
- case INDEX_op_qemu_st_i64:
- return TCG_TARGET_REG_BITS == 64 ? C_O0_I2(L, L) : C_O0_I3(L, L, L);
-
- case INDEX_op_qemu_ld_i128:
- tcg_debug_assert(TCG_TARGET_REG_BITS == 64);
- return C_O2_I1(r, r, L);
- case INDEX_op_qemu_st_i128:
- tcg_debug_assert(TCG_TARGET_REG_BITS == 64);
- return C_O0_I3(L, L, L);
-
- case INDEX_op_brcond2_i32:
- return C_O0_I4(r, r, ri, ri);
-
- case INDEX_op_setcond2_i32:
- return C_O1_I4(r, r, r, ri, ri);
-
case INDEX_op_ld_vec:
case INDEX_op_dupm_vec:
return C_O1_I1(x, r);