aboutsummaryrefslogtreecommitdiff
path: root/tcg/i386
diff options
context:
space:
mode:
Diffstat (limited to 'tcg/i386')
-rw-r--r--tcg/i386/tcg-target-con-set.h2
-rw-r--r--tcg/i386/tcg-target-con-str.h1
-rw-r--r--tcg/i386/tcg-target.c.inc291
-rw-r--r--tcg/i386/tcg-target.h9
4 files changed, 190 insertions, 113 deletions
diff --git a/tcg/i386/tcg-target-con-set.h b/tcg/i386/tcg-target-con-set.h
index 5ea3a29..7d00a7d 100644
--- a/tcg/i386/tcg-target-con-set.h
+++ b/tcg/i386/tcg-target-con-set.h
@@ -33,7 +33,7 @@ C_O1_I1(r, q)
C_O1_I1(r, r)
C_O1_I1(x, r)
C_O1_I1(x, x)
-C_O1_I2(Q, 0, Q)
+C_O1_I2(q, 0, qi)
C_O1_I2(q, r, re)
C_O1_I2(r, 0, ci)
C_O1_I2(r, 0, r)
diff --git a/tcg/i386/tcg-target-con-str.h b/tcg/i386/tcg-target-con-str.h
index 24e6bcb..95a30e5 100644
--- a/tcg/i386/tcg-target-con-str.h
+++ b/tcg/i386/tcg-target-con-str.h
@@ -19,7 +19,6 @@ REGS('D', 1u << TCG_REG_EDI)
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('Q', ALL_BYTEH_REGS) /* regs with a second byte (e.g. %ah) */
REGS('L', ALL_GENERAL_REGS & ~SOFTMMU_RESERVE_REGS) /* qemu_ld/st */
REGS('s', ALL_BYTEL_REGS & ~SOFTMMU_RESERVE_REGS) /* qemu_st8_i32 data */
diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc
index a6b2eae..0c3d1e4 100644
--- a/tcg/i386/tcg-target.c.inc
+++ b/tcg/i386/tcg-target.c.inc
@@ -144,7 +144,6 @@ static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot)
# define TCG_REG_L1 TCG_REG_EDX
#endif
-#define ALL_BYTEH_REGS 0x0000000fu
#if TCG_TARGET_REG_BITS == 64
# define ALL_GENERAL_REGS 0x0000ffffu
# define ALL_VECTOR_REGS 0xffff0000u
@@ -152,7 +151,7 @@ static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot)
#else
# define ALL_GENERAL_REGS 0x000000ffu
# define ALL_VECTOR_REGS 0x00ff0000u
-# define ALL_BYTEL_REGS ALL_BYTEH_REGS
+# define ALL_BYTEL_REGS 0x0000000fu
#endif
#ifdef CONFIG_SOFTMMU
# define SOFTMMU_RESERVE_REGS ((1 << TCG_REG_L0) | (1 << TCG_REG_L1))
@@ -277,6 +276,7 @@ static bool tcg_target_const_match(int64_t val, TCGType type, int ct)
#define OPC_MOVL_GvEv (0x8b) /* loads, more or less */
#define OPC_MOVB_EvIz (0xc6)
#define OPC_MOVL_EvIz (0xc7)
+#define OPC_MOVB_Ib (0xb0)
#define OPC_MOVL_Iv (0xb8)
#define OPC_MOVBE_GyMy (0xf0 | P_EXT38)
#define OPC_MOVBE_MyGy (0xf1 | P_EXT38)
@@ -1436,99 +1436,89 @@ static void tcg_out_cmp(TCGContext *s, TCGArg arg1, TCGArg arg2,
}
}
-static void tcg_out_brcond32(TCGContext *s, TCGCond cond,
- TCGArg arg1, TCGArg arg2, int const_arg2,
- TCGLabel *label, int small)
+static void tcg_out_brcond(TCGContext *s, int rexw, TCGCond cond,
+ TCGArg arg1, TCGArg arg2, int const_arg2,
+ TCGLabel *label, bool small)
{
- tcg_out_cmp(s, arg1, arg2, const_arg2, 0);
+ tcg_out_cmp(s, arg1, arg2, const_arg2, rexw);
tcg_out_jxx(s, tcg_cond_to_jcc[cond], label, small);
}
-#if TCG_TARGET_REG_BITS == 64
-static void tcg_out_brcond64(TCGContext *s, TCGCond cond,
- TCGArg arg1, TCGArg arg2, int const_arg2,
- TCGLabel *label, int small)
-{
- tcg_out_cmp(s, arg1, arg2, const_arg2, P_REXW);
- tcg_out_jxx(s, tcg_cond_to_jcc[cond], label, small);
-}
-#else
-/* XXX: we implement it at the target level to avoid having to
- handle cross basic blocks temporaries */
+#if TCG_TARGET_REG_BITS == 32
static void tcg_out_brcond2(TCGContext *s, const TCGArg *args,
- const int *const_args, int small)
+ const int *const_args, bool small)
{
TCGLabel *label_next = gen_new_label();
TCGLabel *label_this = arg_label(args[5]);
switch(args[4]) {
case TCG_COND_EQ:
- tcg_out_brcond32(s, TCG_COND_NE, args[0], args[2], const_args[2],
- label_next, 1);
- tcg_out_brcond32(s, TCG_COND_EQ, args[1], args[3], const_args[3],
- label_this, small);
+ tcg_out_brcond(s, 0, TCG_COND_NE, args[0], args[2], const_args[2],
+ label_next, 1);
+ tcg_out_brcond(s, 0, TCG_COND_EQ, args[1], args[3], const_args[3],
+ label_this, small);
break;
case TCG_COND_NE:
- tcg_out_brcond32(s, TCG_COND_NE, args[0], args[2], const_args[2],
- label_this, small);
- tcg_out_brcond32(s, TCG_COND_NE, args[1], args[3], const_args[3],
- label_this, small);
+ tcg_out_brcond(s, 0, TCG_COND_NE, args[0], args[2], const_args[2],
+ label_this, small);
+ tcg_out_brcond(s, 0, TCG_COND_NE, args[1], args[3], const_args[3],
+ label_this, small);
break;
case TCG_COND_LT:
- tcg_out_brcond32(s, TCG_COND_LT, args[1], args[3], const_args[3],
- label_this, small);
+ tcg_out_brcond(s, 0, TCG_COND_LT, args[1], args[3], const_args[3],
+ label_this, small);
tcg_out_jxx(s, JCC_JNE, label_next, 1);
- tcg_out_brcond32(s, TCG_COND_LTU, args[0], args[2], const_args[2],
- label_this, small);
+ tcg_out_brcond(s, 0, TCG_COND_LTU, args[0], args[2], const_args[2],
+ label_this, small);
break;
case TCG_COND_LE:
- tcg_out_brcond32(s, TCG_COND_LT, args[1], args[3], const_args[3],
- label_this, small);
+ tcg_out_brcond(s, 0, TCG_COND_LT, args[1], args[3], const_args[3],
+ label_this, small);
tcg_out_jxx(s, JCC_JNE, label_next, 1);
- tcg_out_brcond32(s, TCG_COND_LEU, args[0], args[2], const_args[2],
- label_this, small);
+ tcg_out_brcond(s, 0, TCG_COND_LEU, args[0], args[2], const_args[2],
+ label_this, small);
break;
case TCG_COND_GT:
- tcg_out_brcond32(s, TCG_COND_GT, args[1], args[3], const_args[3],
- label_this, small);
+ tcg_out_brcond(s, 0, TCG_COND_GT, args[1], args[3], const_args[3],
+ label_this, small);
tcg_out_jxx(s, JCC_JNE, label_next, 1);
- tcg_out_brcond32(s, TCG_COND_GTU, args[0], args[2], const_args[2],
- label_this, small);
+ tcg_out_brcond(s, 0, TCG_COND_GTU, args[0], args[2], const_args[2],
+ label_this, small);
break;
case TCG_COND_GE:
- tcg_out_brcond32(s, TCG_COND_GT, args[1], args[3], const_args[3],
- label_this, small);
+ tcg_out_brcond(s, 0, TCG_COND_GT, args[1], args[3], const_args[3],
+ label_this, small);
tcg_out_jxx(s, JCC_JNE, label_next, 1);
- tcg_out_brcond32(s, TCG_COND_GEU, args[0], args[2], const_args[2],
- label_this, small);
+ tcg_out_brcond(s, 0, TCG_COND_GEU, args[0], args[2], const_args[2],
+ label_this, small);
break;
case TCG_COND_LTU:
- tcg_out_brcond32(s, TCG_COND_LTU, args[1], args[3], const_args[3],
- label_this, small);
+ tcg_out_brcond(s, 0, TCG_COND_LTU, args[1], args[3], const_args[3],
+ label_this, small);
tcg_out_jxx(s, JCC_JNE, label_next, 1);
- tcg_out_brcond32(s, TCG_COND_LTU, args[0], args[2], const_args[2],
- label_this, small);
+ tcg_out_brcond(s, 0, TCG_COND_LTU, args[0], args[2], const_args[2],
+ label_this, small);
break;
case TCG_COND_LEU:
- tcg_out_brcond32(s, TCG_COND_LTU, args[1], args[3], const_args[3],
- label_this, small);
+ tcg_out_brcond(s, 0, TCG_COND_LTU, args[1], args[3], const_args[3],
+ label_this, small);
tcg_out_jxx(s, JCC_JNE, label_next, 1);
- tcg_out_brcond32(s, TCG_COND_LEU, args[0], args[2], const_args[2],
- label_this, small);
+ tcg_out_brcond(s, 0, TCG_COND_LEU, args[0], args[2], const_args[2],
+ label_this, small);
break;
case TCG_COND_GTU:
- tcg_out_brcond32(s, TCG_COND_GTU, args[1], args[3], const_args[3],
- label_this, small);
+ tcg_out_brcond(s, 0, TCG_COND_GTU, args[1], args[3], const_args[3],
+ label_this, small);
tcg_out_jxx(s, JCC_JNE, label_next, 1);
- tcg_out_brcond32(s, TCG_COND_GTU, args[0], args[2], const_args[2],
- label_this, small);
+ tcg_out_brcond(s, 0, TCG_COND_GTU, args[0], args[2], const_args[2],
+ label_this, small);
break;
case TCG_COND_GEU:
- tcg_out_brcond32(s, TCG_COND_GTU, args[1], args[3], const_args[3],
- label_this, small);
+ tcg_out_brcond(s, 0, TCG_COND_GTU, args[1], args[3], const_args[3],
+ label_this, small);
tcg_out_jxx(s, JCC_JNE, label_next, 1);
- tcg_out_brcond32(s, TCG_COND_GEU, args[0], args[2], const_args[2],
- label_this, small);
+ tcg_out_brcond(s, 0, TCG_COND_GEU, args[0], args[2], const_args[2],
+ label_this, small);
break;
default:
g_assert_not_reached();
@@ -1537,23 +1527,107 @@ static void tcg_out_brcond2(TCGContext *s, const TCGArg *args,
}
#endif
-static void tcg_out_setcond32(TCGContext *s, TCGCond cond, TCGArg dest,
- TCGArg arg1, TCGArg arg2, int const_arg2)
+static void tcg_out_setcond(TCGContext *s, int rexw, TCGCond cond,
+ TCGArg dest, TCGArg arg1, TCGArg arg2,
+ int const_arg2, bool neg)
{
- tcg_out_cmp(s, arg1, arg2, const_arg2, 0);
- tcg_out_modrm(s, OPC_SETCC | tcg_cond_to_jcc[cond], 0, dest);
- tcg_out_ext8u(s, dest, dest);
-}
+ bool inv = false;
+ bool cleared;
-#if TCG_TARGET_REG_BITS == 64
-static void tcg_out_setcond64(TCGContext *s, TCGCond cond, TCGArg dest,
- TCGArg arg1, TCGArg arg2, int const_arg2)
-{
- tcg_out_cmp(s, arg1, arg2, const_arg2, P_REXW);
+ switch (cond) {
+ case TCG_COND_NE:
+ inv = true;
+ /* fall through */
+ case TCG_COND_EQ:
+ /* If arg2 is 0, convert to LTU/GEU vs 1. */
+ if (const_arg2 && arg2 == 0) {
+ arg2 = 1;
+ goto do_ltu;
+ }
+ break;
+
+ case TCG_COND_LEU:
+ inv = true;
+ /* fall through */
+ case TCG_COND_GTU:
+ /* If arg2 is a register, swap for LTU/GEU. */
+ if (!const_arg2) {
+ TCGReg t = arg1;
+ arg1 = arg2;
+ arg2 = t;
+ goto do_ltu;
+ }
+ break;
+
+ case TCG_COND_GEU:
+ inv = true;
+ /* fall through */
+ case TCG_COND_LTU:
+ do_ltu:
+ /*
+ * Relying on the carry bit, use SBB to produce -1 if LTU, 0 if GEU.
+ * We can then use NEG or INC to produce the desired result.
+ * This is always smaller than the SETCC expansion.
+ */
+ tcg_out_cmp(s, arg1, arg2, const_arg2, rexw);
+
+ /* X - X - C = -C = (C ? -1 : 0) */
+ tgen_arithr(s, ARITH_SBB + (neg ? rexw : 0), dest, dest);
+ if (inv && neg) {
+ /* ~(C ? -1 : 0) = (C ? 0 : -1) */
+ tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_NOT, dest);
+ } else if (inv) {
+ /* (C ? -1 : 0) + 1 = (C ? 0 : 1) */
+ tgen_arithi(s, ARITH_ADD, dest, 1, 0);
+ } else if (!neg) {
+ /* -(C ? -1 : 0) = (C ? 1 : 0) */
+ tcg_out_modrm(s, OPC_GRP3_Ev, EXT3_NEG, dest);
+ }
+ return;
+
+ case TCG_COND_GE:
+ inv = true;
+ /* fall through */
+ 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);
+ if (inv) {
+ tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_NOT, dest);
+ }
+ tcg_out_shifti(s, (neg ? SHIFT_SAR : SHIFT_SHR) + rexw,
+ dest, rexw ? 63 : 31);
+ return;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ /*
+ * If dest does not overlap the inputs, clearing it first is preferred.
+ * The XOR breaks any false dependency for the low-byte write to dest,
+ * and is also one byte smaller than MOVZBL.
+ */
+ cleared = false;
+ if (dest != arg1 && (const_arg2 || dest != arg2)) {
+ tgen_arithr(s, ARITH_XOR, dest, dest);
+ cleared = true;
+ }
+
+ tcg_out_cmp(s, arg1, arg2, const_arg2, rexw);
tcg_out_modrm(s, OPC_SETCC | tcg_cond_to_jcc[cond], 0, dest);
- tcg_out_ext8u(s, dest, dest);
+
+ if (!cleared) {
+ tcg_out_ext8u(s, dest, dest);
+ }
+ if (neg) {
+ tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_NEG, dest);
+ }
}
-#else
+
+#if TCG_TARGET_REG_BITS == 32
static void tcg_out_setcond2(TCGContext *s, const TCGArg *args,
const int *const_args)
{
@@ -1610,23 +1684,13 @@ static void tcg_out_cmov(TCGContext *s, TCGCond cond, int rexw,
}
}
-static void tcg_out_movcond32(TCGContext *s, TCGCond cond, TCGReg dest,
- TCGReg c1, TCGArg c2, int const_c2,
- TCGReg v1)
-{
- tcg_out_cmp(s, c1, c2, const_c2, 0);
- tcg_out_cmov(s, cond, 0, dest, v1);
-}
-
-#if TCG_TARGET_REG_BITS == 64
-static void tcg_out_movcond64(TCGContext *s, TCGCond cond, TCGReg dest,
- TCGReg c1, TCGArg c2, int const_c2,
- TCGReg v1)
+static void tcg_out_movcond(TCGContext *s, int rexw, TCGCond cond,
+ TCGReg dest, TCGReg c1, TCGArg c2, int const_c2,
+ TCGReg v1)
{
- tcg_out_cmp(s, c1, c2, const_c2, P_REXW);
- tcg_out_cmov(s, cond, P_REXW, dest, v1);
+ tcg_out_cmp(s, c1, c2, const_c2, rexw);
+ tcg_out_cmov(s, cond, rexw, dest, v1);
}
-#endif
static void tcg_out_ctz(TCGContext *s, int rexw, TCGReg dest, TCGReg arg1,
TCGArg arg2, bool const_a2)
@@ -2574,14 +2638,18 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
tcg_out_modrm(s, OPC_POPCNT + rexw, a0, a1);
break;
- case INDEX_op_brcond_i32:
- tcg_out_brcond32(s, a2, a0, a1, const_args[1], arg_label(args[3]), 0);
+ OP_32_64(brcond):
+ tcg_out_brcond(s, rexw, a2, a0, a1, const_args[1],
+ arg_label(args[3]), 0);
break;
- case INDEX_op_setcond_i32:
- tcg_out_setcond32(s, args[3], a0, a1, a2, const_a2);
+ OP_32_64(setcond):
+ tcg_out_setcond(s, rexw, args[3], a0, a1, a2, const_a2, false);
break;
- case INDEX_op_movcond_i32:
- tcg_out_movcond32(s, args[5], a0, a1, a2, const_a2, args[3]);
+ 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;
OP_32_64(bswap16):
@@ -2730,16 +2798,6 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
}
break;
- case INDEX_op_brcond_i64:
- tcg_out_brcond64(s, a2, a0, a1, const_args[1], arg_label(args[3]), 0);
- break;
- case INDEX_op_setcond_i64:
- tcg_out_setcond64(s, args[3], a0, a1, a2, const_a2);
- break;
- case INDEX_op_movcond_i64:
- tcg_out_movcond64(s, args[5], a0, a1, a2, const_a2, args[3]);
- break;
-
case INDEX_op_bswap64_i64:
tcg_out_bswap64(s, a0);
break;
@@ -2751,13 +2809,30 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
OP_32_64(deposit):
if (args[3] == 0 && args[4] == 8) {
/* load bits 0..7 */
- tcg_out_modrm(s, OPC_MOVB_EvGv | P_REXB_R | P_REXB_RM, a2, a0);
- } else if (args[3] == 8 && args[4] == 8) {
+ 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 */
- tcg_out_modrm(s, OPC_MOVB_EvGv, a2, a0 + 4);
+ 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 */
- tcg_out_modrm(s, OPC_MOVL_EvGv | P_DATA16, a2, a0);
+ 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();
}
@@ -3312,10 +3387,12 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op)
case INDEX_op_deposit_i32:
case INDEX_op_deposit_i64:
- return C_O1_I2(Q, 0, Q);
+ 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, re);
case INDEX_op_movcond_i32:
diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h
index 2a2e3ff..8417ea4 100644
--- a/tcg/i386/tcg-target.h
+++ b/tcg/i386/tcg-target.h
@@ -150,6 +150,7 @@ typedef enum {
#define TCG_TARGET_HAS_sextract_i32 1
#define TCG_TARGET_HAS_extract2_i32 1
#define TCG_TARGET_HAS_movcond_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
@@ -159,8 +160,7 @@ typedef enum {
#if TCG_TARGET_REG_BITS == 64
/* Keep 32-bit values zero-extended in a register. */
-#define TCG_TARGET_HAS_extrl_i64_i32 1
-#define TCG_TARGET_HAS_extrh_i64_i32 1
+#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
@@ -187,6 +187,7 @@ typedef enum {
#define TCG_TARGET_HAS_sextract_i64 0
#define TCG_TARGET_HAS_extract2_i64 1
#define TCG_TARGET_HAS_movcond_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
@@ -227,8 +228,8 @@ typedef enum {
#define TCG_TARGET_HAS_cmpsel_vec -1
#define TCG_TARGET_deposit_i32_valid(ofs, len) \
- (((ofs) == 0 && (len) == 8) || ((ofs) == 8 && (len) == 8) || \
- ((ofs) == 0 && (len) == 16))
+ (((ofs) == 0 && ((len) == 8 || (len) == 16)) || \
+ (TCG_TARGET_REG_BITS == 32 && (ofs) == 8 && (len) == 8))
#define TCG_TARGET_deposit_i64_valid TCG_TARGET_deposit_i32_valid
/* Check for the possibility of high-byte extraction and, for 64-bit,