mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge tag 'pull-tcg-20240205-2' of https://gitlab.com/rth7680/qemu into staging
tcg: Introduce TCG_COND_TST{EQ,NE}
target/alpha: Use TCG_COND_TST{EQ,NE}
target/m68k: Use TCG_COND_TST{EQ,NE} in gen_fcc_cond
target/sparc: Use TCG_COND_TSTEQ in gen_op_mulscc
target/s390x: Use TCG_COND_TSTNE for CC_OP_{TM,ICM}
target/s390x: Improve general case of disas_jcc
# -----BEGIN PGP SIGNATURE-----
#
# iQFRBAABCgA7FiEEekgeeIaLTbaoWgXAZN846K9+IV8FAmXBpTAdHHJpY2hhcmQu
# aGVuZGVyc29uQGxpbmFyby5vcmcACgkQZN846K9+IV/p6gf9HAasTSRECk2cvjW9
# /mcJy0AIaespnI50fG8fm48OoFl0847CdrsJycpZ1spw3W3Wb0cVbMbq/teNMjXZ
# 0SGQJFk9Baq7wMhW7VzhSzJ96pcorpQprp7XBMdheLXqpT4zsM/EuwEAepBk8RUG
# 3kCeo38dswXE681ZafZkd/8pPzII19sQK8eiMpceeYkBsbbep+DDcnE18Ee4kISS
# u0SbuslKVahxd86LKuzrcz0pNFcmFuR5jRP9hmbQ0MfeAn0Pxlndi+ayZNghfgPf
# 3hDjskiionFwxb/OoRj45BssTWfDiluWl7IUsHfegPXCQ2Y+woT5Vq6TVGZn0GqS
# c6RLQQ==
# =TMiE
# -----END PGP SIGNATURE-----
# gpg: Signature made Tue 06 Feb 2024 03:19:12 GMT
# gpg: using RSA key 7A481E78868B4DB6A85A05C064DF38E8AF7E215F
# gpg: issuer "richard.henderson@linaro.org"
# gpg: Good signature from "Richard Henderson <richard.henderson@linaro.org>" [full]
# Primary key fingerprint: 7A48 1E78 868B 4DB6 A85A 05C0 64DF 38E8 AF7E 215F
* tag 'pull-tcg-20240205-2' of https://gitlab.com/rth7680/qemu: (39 commits)
tcg/tci: Support TCG_COND_TST{EQ,NE}
tcg/s390x: Support TCG_COND_TST{EQ,NE}
tcg/s390x: Add TCG_CT_CONST_CMP
tcg/s390x: Split constraint A into J+U
tcg/ppc: Support TCG_COND_TST{EQ,NE}
tcg/ppc: Add TCG_CT_CONST_CMP
tcg/ppc: Tidy up tcg_target_const_match
tcg/ppc: Use cr0 in tcg_to_bc and tcg_to_isel
tcg/ppc: Sink tcg_to_bc usage into tcg_out_bc
tcg/sparc64: Support TCG_COND_TST{EQ,NE}
tcg/sparc64: Pass TCGCond to tcg_out_cmp
tcg/sparc64: Hoist read of tcg_cond_to_rcond
tcg/i386: Use TEST r,r to test 8/16/32 bits
tcg/i386: Improve TSTNE/TESTEQ vs powers of two
tcg/i386: Support TCG_COND_TST{EQ,NE}
tcg/i386: Move tcg_cond_to_jcc[] into tcg_out_cmp
tcg/i386: Pass x86 condition codes to tcg_out_cmov
tcg/arm: Support TCG_COND_TST{EQ,NE}
tcg/arm: Split out tcg_out_cmp()
tcg/aarch64: Generate CBNZ for TSTNE of UINT32_MAX
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
@@ -253,6 +253,8 @@ Jumps/Labels
|
||||
| ``TCG_COND_GEU /* unsigned */``
|
||||
| ``TCG_COND_LEU /* unsigned */``
|
||||
| ``TCG_COND_GTU /* unsigned */``
|
||||
| ``TCG_COND_TSTEQ /* t1 & t2 == 0 */``
|
||||
| ``TCG_COND_TSTNE /* t1 & t2 != 0 */``
|
||||
|
||||
Arithmetic
|
||||
----------
|
||||
|
||||
+53
-21
@@ -29,26 +29,34 @@
|
||||
* Conditions. Note that these are laid out for easy manipulation by
|
||||
* the functions below:
|
||||
* bit 0 is used for inverting;
|
||||
* bit 1 is signed,
|
||||
* bit 2 is unsigned,
|
||||
* bit 3 is used with bit 0 for swapping signed/unsigned.
|
||||
* bit 1 is used for conditions that need swapping (signed/unsigned).
|
||||
* bit 2 is used with bit 1 for swapping.
|
||||
* bit 3 is used for unsigned conditions.
|
||||
*/
|
||||
typedef enum {
|
||||
/* non-signed */
|
||||
TCG_COND_NEVER = 0 | 0 | 0 | 0,
|
||||
TCG_COND_ALWAYS = 0 | 0 | 0 | 1,
|
||||
|
||||
/* equality */
|
||||
TCG_COND_EQ = 8 | 0 | 0 | 0,
|
||||
TCG_COND_NE = 8 | 0 | 0 | 1,
|
||||
|
||||
/* "test" i.e. and then compare vs 0 */
|
||||
TCG_COND_TSTEQ = 8 | 4 | 0 | 0,
|
||||
TCG_COND_TSTNE = 8 | 4 | 0 | 1,
|
||||
|
||||
/* signed */
|
||||
TCG_COND_LT = 0 | 0 | 2 | 0,
|
||||
TCG_COND_GE = 0 | 0 | 2 | 1,
|
||||
TCG_COND_LE = 8 | 0 | 2 | 0,
|
||||
TCG_COND_GT = 8 | 0 | 2 | 1,
|
||||
TCG_COND_GT = 0 | 4 | 2 | 0,
|
||||
TCG_COND_LE = 0 | 4 | 2 | 1,
|
||||
|
||||
/* unsigned */
|
||||
TCG_COND_LTU = 0 | 4 | 0 | 0,
|
||||
TCG_COND_GEU = 0 | 4 | 0 | 1,
|
||||
TCG_COND_LEU = 8 | 4 | 0 | 0,
|
||||
TCG_COND_GTU = 8 | 4 | 0 | 1,
|
||||
TCG_COND_LTU = 8 | 0 | 2 | 0,
|
||||
TCG_COND_GEU = 8 | 0 | 2 | 1,
|
||||
TCG_COND_GTU = 8 | 4 | 2 | 0,
|
||||
TCG_COND_LEU = 8 | 4 | 2 | 1,
|
||||
} TCGCond;
|
||||
|
||||
/* Invert the sense of the comparison. */
|
||||
@@ -60,25 +68,49 @@ static inline TCGCond tcg_invert_cond(TCGCond c)
|
||||
/* Swap the operands in a comparison. */
|
||||
static inline TCGCond tcg_swap_cond(TCGCond c)
|
||||
{
|
||||
return c & 6 ? (TCGCond)(c ^ 9) : c;
|
||||
return (TCGCond)(c ^ ((c & 2) << 1));
|
||||
}
|
||||
|
||||
/* Create an "unsigned" version of a "signed" comparison. */
|
||||
static inline TCGCond tcg_unsigned_cond(TCGCond c)
|
||||
/* Must a comparison be considered signed? */
|
||||
static inline bool is_signed_cond(TCGCond c)
|
||||
{
|
||||
return c & 2 ? (TCGCond)(c ^ 6) : c;
|
||||
}
|
||||
|
||||
/* Create a "signed" version of an "unsigned" comparison. */
|
||||
static inline TCGCond tcg_signed_cond(TCGCond c)
|
||||
{
|
||||
return c & 4 ? (TCGCond)(c ^ 6) : c;
|
||||
return (c & (8 | 2)) == 2;
|
||||
}
|
||||
|
||||
/* Must a comparison be considered unsigned? */
|
||||
static inline bool is_unsigned_cond(TCGCond c)
|
||||
{
|
||||
return (c & 4) != 0;
|
||||
return (c & (8 | 2)) == (8 | 2);
|
||||
}
|
||||
|
||||
/* Must a comparison be considered a test? */
|
||||
static inline bool is_tst_cond(TCGCond c)
|
||||
{
|
||||
return (c | 1) == TCG_COND_TSTNE;
|
||||
}
|
||||
|
||||
/* Create an "unsigned" version of a "signed" comparison. */
|
||||
static inline TCGCond tcg_unsigned_cond(TCGCond c)
|
||||
{
|
||||
return is_signed_cond(c) ? (TCGCond)(c + 8) : c;
|
||||
}
|
||||
|
||||
/* Create a "signed" version of an "unsigned" comparison. */
|
||||
static inline TCGCond tcg_signed_cond(TCGCond c)
|
||||
{
|
||||
return is_unsigned_cond(c) ? (TCGCond)(c - 8) : c;
|
||||
}
|
||||
|
||||
/* Create the eq/ne version of a tsteq/tstne comparison. */
|
||||
static inline TCGCond tcg_tst_eqne_cond(TCGCond c)
|
||||
{
|
||||
return is_tst_cond(c) ? (TCGCond)(c - 4) : c;
|
||||
}
|
||||
|
||||
/* Create the lt/ge version of a tstne/tsteq comparison of the sign. */
|
||||
static inline TCGCond tcg_tst_ltge_cond(TCGCond c)
|
||||
{
|
||||
return is_tst_cond(c) ? (TCGCond)(c ^ 0xf) : c;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -92,7 +124,7 @@ static inline TCGCond tcg_high_cond(TCGCond c)
|
||||
case TCG_COND_LE:
|
||||
case TCG_COND_GEU:
|
||||
case TCG_COND_LEU:
|
||||
return (TCGCond)(c ^ 8);
|
||||
return (TCGCond)(c ^ (4 | 1));
|
||||
default:
|
||||
return c;
|
||||
}
|
||||
|
||||
+40
-54
@@ -453,13 +453,13 @@ static DisasJumpType gen_bdirect(DisasContext *ctx, int ra, int32_t disp)
|
||||
}
|
||||
|
||||
static DisasJumpType gen_bcond_internal(DisasContext *ctx, TCGCond cond,
|
||||
TCGv cmp, int32_t disp)
|
||||
TCGv cmp, uint64_t imm, int32_t disp)
|
||||
{
|
||||
uint64_t dest = ctx->base.pc_next + (disp << 2);
|
||||
TCGLabel *lab_true = gen_new_label();
|
||||
|
||||
if (use_goto_tb(ctx, dest)) {
|
||||
tcg_gen_brcondi_i64(cond, cmp, 0, lab_true);
|
||||
tcg_gen_brcondi_i64(cond, cmp, imm, lab_true);
|
||||
|
||||
tcg_gen_goto_tb(0);
|
||||
tcg_gen_movi_i64(cpu_pc, ctx->base.pc_next);
|
||||
@@ -472,81 +472,71 @@ static DisasJumpType gen_bcond_internal(DisasContext *ctx, TCGCond cond,
|
||||
|
||||
return DISAS_NORETURN;
|
||||
} else {
|
||||
TCGv_i64 z = load_zero(ctx);
|
||||
TCGv_i64 i = tcg_constant_i64(imm);
|
||||
TCGv_i64 d = tcg_constant_i64(dest);
|
||||
TCGv_i64 p = tcg_constant_i64(ctx->base.pc_next);
|
||||
|
||||
tcg_gen_movcond_i64(cond, cpu_pc, cmp, z, d, p);
|
||||
tcg_gen_movcond_i64(cond, cpu_pc, cmp, i, d, p);
|
||||
return DISAS_PC_UPDATED;
|
||||
}
|
||||
}
|
||||
|
||||
static DisasJumpType gen_bcond(DisasContext *ctx, TCGCond cond, int ra,
|
||||
int32_t disp, int mask)
|
||||
int32_t disp)
|
||||
{
|
||||
if (mask) {
|
||||
TCGv tmp = tcg_temp_new();
|
||||
DisasJumpType ret;
|
||||
|
||||
tcg_gen_andi_i64(tmp, load_gpr(ctx, ra), 1);
|
||||
ret = gen_bcond_internal(ctx, cond, tmp, disp);
|
||||
return ret;
|
||||
}
|
||||
return gen_bcond_internal(ctx, cond, load_gpr(ctx, ra), disp);
|
||||
return gen_bcond_internal(ctx, cond, load_gpr(ctx, ra),
|
||||
is_tst_cond(cond), disp);
|
||||
}
|
||||
|
||||
/* Fold -0.0 for comparison with COND. */
|
||||
|
||||
static void gen_fold_mzero(TCGCond cond, TCGv dest, TCGv src)
|
||||
static TCGv_i64 gen_fold_mzero(TCGCond *pcond, uint64_t *pimm, TCGv_i64 src)
|
||||
{
|
||||
uint64_t mzero = 1ull << 63;
|
||||
TCGv_i64 tmp;
|
||||
|
||||
switch (cond) {
|
||||
*pimm = 0;
|
||||
switch (*pcond) {
|
||||
case TCG_COND_LE:
|
||||
case TCG_COND_GT:
|
||||
/* For <= or >, the -0.0 value directly compares the way we want. */
|
||||
tcg_gen_mov_i64(dest, src);
|
||||
break;
|
||||
return src;
|
||||
|
||||
case TCG_COND_EQ:
|
||||
case TCG_COND_NE:
|
||||
/* For == or !=, we can simply mask off the sign bit and compare. */
|
||||
tcg_gen_andi_i64(dest, src, mzero - 1);
|
||||
break;
|
||||
/* For == or !=, we can compare without the sign bit. */
|
||||
*pcond = *pcond == TCG_COND_EQ ? TCG_COND_TSTEQ : TCG_COND_TSTNE;
|
||||
*pimm = INT64_MAX;
|
||||
return src;
|
||||
|
||||
case TCG_COND_GE:
|
||||
case TCG_COND_LT:
|
||||
/* For >= or <, map -0.0 to +0.0. */
|
||||
tcg_gen_movcond_i64(TCG_COND_NE, dest, src, tcg_constant_i64(mzero),
|
||||
src, tcg_constant_i64(0));
|
||||
break;
|
||||
tmp = tcg_temp_new_i64();
|
||||
tcg_gen_movcond_i64(TCG_COND_EQ, tmp,
|
||||
src, tcg_constant_i64(INT64_MIN),
|
||||
tcg_constant_i64(0), src);
|
||||
return tmp;
|
||||
|
||||
default:
|
||||
abort();
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
static DisasJumpType gen_fbcond(DisasContext *ctx, TCGCond cond, int ra,
|
||||
int32_t disp)
|
||||
{
|
||||
TCGv cmp_tmp = tcg_temp_new();
|
||||
DisasJumpType ret;
|
||||
|
||||
gen_fold_mzero(cond, cmp_tmp, load_fpr(ctx, ra));
|
||||
ret = gen_bcond_internal(ctx, cond, cmp_tmp, disp);
|
||||
return ret;
|
||||
uint64_t imm;
|
||||
TCGv_i64 tmp = gen_fold_mzero(&cond, &imm, load_fpr(ctx, ra));
|
||||
return gen_bcond_internal(ctx, cond, tmp, imm, disp);
|
||||
}
|
||||
|
||||
static void gen_fcmov(DisasContext *ctx, TCGCond cond, int ra, int rb, int rc)
|
||||
{
|
||||
TCGv_i64 va, vb, z;
|
||||
|
||||
z = load_zero(ctx);
|
||||
vb = load_fpr(ctx, rb);
|
||||
va = tcg_temp_new();
|
||||
gen_fold_mzero(cond, va, load_fpr(ctx, ra));
|
||||
|
||||
tcg_gen_movcond_i64(cond, dest_fpr(ctx, rc), va, z, vb, load_fpr(ctx, rc));
|
||||
uint64_t imm;
|
||||
TCGv_i64 tmp = gen_fold_mzero(&cond, &imm, load_fpr(ctx, ra));
|
||||
tcg_gen_movcond_i64(cond, dest_fpr(ctx, rc),
|
||||
tmp, tcg_constant_i64(imm),
|
||||
load_fpr(ctx, rb), load_fpr(ctx, rc));
|
||||
}
|
||||
|
||||
#define QUAL_RM_N 0x080 /* Round mode nearest even */
|
||||
@@ -1683,16 +1673,12 @@ static DisasJumpType translate_one(DisasContext *ctx, uint32_t insn)
|
||||
break;
|
||||
case 0x14:
|
||||
/* CMOVLBS */
|
||||
tmp = tcg_temp_new();
|
||||
tcg_gen_andi_i64(tmp, va, 1);
|
||||
tcg_gen_movcond_i64(TCG_COND_NE, vc, tmp, load_zero(ctx),
|
||||
tcg_gen_movcond_i64(TCG_COND_TSTNE, vc, va, tcg_constant_i64(1),
|
||||
vb, load_gpr(ctx, rc));
|
||||
break;
|
||||
case 0x16:
|
||||
/* CMOVLBC */
|
||||
tmp = tcg_temp_new();
|
||||
tcg_gen_andi_i64(tmp, va, 1);
|
||||
tcg_gen_movcond_i64(TCG_COND_EQ, vc, tmp, load_zero(ctx),
|
||||
tcg_gen_movcond_i64(TCG_COND_TSTEQ, vc, va, tcg_constant_i64(1),
|
||||
vb, load_gpr(ctx, rc));
|
||||
break;
|
||||
case 0x20:
|
||||
@@ -2827,35 +2813,35 @@ static DisasJumpType translate_one(DisasContext *ctx, uint32_t insn)
|
||||
break;
|
||||
case 0x38:
|
||||
/* BLBC */
|
||||
ret = gen_bcond(ctx, TCG_COND_EQ, ra, disp21, 1);
|
||||
ret = gen_bcond(ctx, TCG_COND_TSTEQ, ra, disp21);
|
||||
break;
|
||||
case 0x39:
|
||||
/* BEQ */
|
||||
ret = gen_bcond(ctx, TCG_COND_EQ, ra, disp21, 0);
|
||||
ret = gen_bcond(ctx, TCG_COND_EQ, ra, disp21);
|
||||
break;
|
||||
case 0x3A:
|
||||
/* BLT */
|
||||
ret = gen_bcond(ctx, TCG_COND_LT, ra, disp21, 0);
|
||||
ret = gen_bcond(ctx, TCG_COND_LT, ra, disp21);
|
||||
break;
|
||||
case 0x3B:
|
||||
/* BLE */
|
||||
ret = gen_bcond(ctx, TCG_COND_LE, ra, disp21, 0);
|
||||
ret = gen_bcond(ctx, TCG_COND_LE, ra, disp21);
|
||||
break;
|
||||
case 0x3C:
|
||||
/* BLBS */
|
||||
ret = gen_bcond(ctx, TCG_COND_NE, ra, disp21, 1);
|
||||
ret = gen_bcond(ctx, TCG_COND_TSTNE, ra, disp21);
|
||||
break;
|
||||
case 0x3D:
|
||||
/* BNE */
|
||||
ret = gen_bcond(ctx, TCG_COND_NE, ra, disp21, 0);
|
||||
ret = gen_bcond(ctx, TCG_COND_NE, ra, disp21);
|
||||
break;
|
||||
case 0x3E:
|
||||
/* BGE */
|
||||
ret = gen_bcond(ctx, TCG_COND_GE, ra, disp21, 0);
|
||||
ret = gen_bcond(ctx, TCG_COND_GE, ra, disp21);
|
||||
break;
|
||||
case 0x3F:
|
||||
/* BGT */
|
||||
ret = gen_bcond(ctx, TCG_COND_GT, ra, disp21, 0);
|
||||
ret = gen_bcond(ctx, TCG_COND_GT, ra, disp21);
|
||||
break;
|
||||
invalid_opc:
|
||||
ret = gen_invalid(ctx);
|
||||
|
||||
+33
-41
@@ -5129,46 +5129,44 @@ undef:
|
||||
static void gen_fcc_cond(DisasCompare *c, DisasContext *s, int cond)
|
||||
{
|
||||
TCGv fpsr;
|
||||
int imm = 0;
|
||||
|
||||
c->v2 = tcg_constant_i32(0);
|
||||
/* TODO: Raise BSUN exception. */
|
||||
fpsr = tcg_temp_new();
|
||||
gen_load_fcr(s, fpsr, M68K_FPSR);
|
||||
c->v1 = fpsr;
|
||||
|
||||
switch (cond) {
|
||||
case 0: /* False */
|
||||
case 16: /* Signaling False */
|
||||
c->v1 = c->v2;
|
||||
c->tcond = TCG_COND_NEVER;
|
||||
break;
|
||||
case 1: /* EQual Z */
|
||||
case 17: /* Signaling EQual Z */
|
||||
c->v1 = tcg_temp_new();
|
||||
tcg_gen_andi_i32(c->v1, fpsr, FPSR_CC_Z);
|
||||
c->tcond = TCG_COND_NE;
|
||||
imm = FPSR_CC_Z;
|
||||
c->tcond = TCG_COND_TSTNE;
|
||||
break;
|
||||
case 2: /* Ordered Greater Than !(A || Z || N) */
|
||||
case 18: /* Greater Than !(A || Z || N) */
|
||||
c->v1 = tcg_temp_new();
|
||||
tcg_gen_andi_i32(c->v1, fpsr,
|
||||
FPSR_CC_A | FPSR_CC_Z | FPSR_CC_N);
|
||||
c->tcond = TCG_COND_EQ;
|
||||
imm = FPSR_CC_A | FPSR_CC_Z | FPSR_CC_N;
|
||||
c->tcond = TCG_COND_TSTEQ;
|
||||
break;
|
||||
case 3: /* Ordered Greater than or Equal Z || !(A || N) */
|
||||
case 19: /* Greater than or Equal Z || !(A || N) */
|
||||
c->v1 = tcg_temp_new();
|
||||
tcg_gen_andi_i32(c->v1, fpsr, FPSR_CC_A);
|
||||
tcg_gen_shli_i32(c->v1, c->v1, ctz32(FPSR_CC_N) - ctz32(FPSR_CC_A));
|
||||
tcg_gen_andi_i32(fpsr, fpsr, FPSR_CC_Z | FPSR_CC_N);
|
||||
tcg_gen_or_i32(c->v1, c->v1, fpsr);
|
||||
tcg_gen_xori_i32(c->v1, c->v1, FPSR_CC_N);
|
||||
c->tcond = TCG_COND_NE;
|
||||
imm = FPSR_CC_Z | FPSR_CC_N;
|
||||
c->tcond = TCG_COND_TSTNE;
|
||||
break;
|
||||
case 4: /* Ordered Less Than !(!N || A || Z); */
|
||||
case 20: /* Less Than !(!N || A || Z); */
|
||||
c->v1 = tcg_temp_new();
|
||||
tcg_gen_xori_i32(c->v1, fpsr, FPSR_CC_N);
|
||||
tcg_gen_andi_i32(c->v1, c->v1, FPSR_CC_N | FPSR_CC_A | FPSR_CC_Z);
|
||||
c->tcond = TCG_COND_EQ;
|
||||
imm = FPSR_CC_N | FPSR_CC_A | FPSR_CC_Z;
|
||||
c->tcond = TCG_COND_TSTEQ;
|
||||
break;
|
||||
case 5: /* Ordered Less than or Equal Z || (N && !A) */
|
||||
case 21: /* Less than or Equal Z || (N && !A) */
|
||||
@@ -5176,49 +5174,45 @@ static void gen_fcc_cond(DisasCompare *c, DisasContext *s, int cond)
|
||||
tcg_gen_andi_i32(c->v1, fpsr, FPSR_CC_A);
|
||||
tcg_gen_shli_i32(c->v1, c->v1, ctz32(FPSR_CC_N) - ctz32(FPSR_CC_A));
|
||||
tcg_gen_andc_i32(c->v1, fpsr, c->v1);
|
||||
tcg_gen_andi_i32(c->v1, c->v1, FPSR_CC_Z | FPSR_CC_N);
|
||||
c->tcond = TCG_COND_NE;
|
||||
imm = FPSR_CC_Z | FPSR_CC_N;
|
||||
c->tcond = TCG_COND_TSTNE;
|
||||
break;
|
||||
case 6: /* Ordered Greater or Less than !(A || Z) */
|
||||
case 22: /* Greater or Less than !(A || Z) */
|
||||
c->v1 = tcg_temp_new();
|
||||
tcg_gen_andi_i32(c->v1, fpsr, FPSR_CC_A | FPSR_CC_Z);
|
||||
c->tcond = TCG_COND_EQ;
|
||||
imm = FPSR_CC_A | FPSR_CC_Z;
|
||||
c->tcond = TCG_COND_TSTEQ;
|
||||
break;
|
||||
case 7: /* Ordered !A */
|
||||
case 23: /* Greater, Less or Equal !A */
|
||||
c->v1 = tcg_temp_new();
|
||||
tcg_gen_andi_i32(c->v1, fpsr, FPSR_CC_A);
|
||||
c->tcond = TCG_COND_EQ;
|
||||
imm = FPSR_CC_A;
|
||||
c->tcond = TCG_COND_TSTEQ;
|
||||
break;
|
||||
case 8: /* Unordered A */
|
||||
case 24: /* Not Greater, Less or Equal A */
|
||||
c->v1 = tcg_temp_new();
|
||||
tcg_gen_andi_i32(c->v1, fpsr, FPSR_CC_A);
|
||||
c->tcond = TCG_COND_NE;
|
||||
imm = FPSR_CC_A;
|
||||
c->tcond = TCG_COND_TSTNE;
|
||||
break;
|
||||
case 9: /* Unordered or Equal A || Z */
|
||||
case 25: /* Not Greater or Less then A || Z */
|
||||
c->v1 = tcg_temp_new();
|
||||
tcg_gen_andi_i32(c->v1, fpsr, FPSR_CC_A | FPSR_CC_Z);
|
||||
c->tcond = TCG_COND_NE;
|
||||
imm = FPSR_CC_A | FPSR_CC_Z;
|
||||
c->tcond = TCG_COND_TSTNE;
|
||||
break;
|
||||
case 10: /* Unordered or Greater Than A || !(N || Z)) */
|
||||
case 26: /* Not Less or Equal A || !(N || Z)) */
|
||||
c->v1 = tcg_temp_new();
|
||||
tcg_gen_andi_i32(c->v1, fpsr, FPSR_CC_Z);
|
||||
tcg_gen_shli_i32(c->v1, c->v1, ctz32(FPSR_CC_N) - ctz32(FPSR_CC_Z));
|
||||
tcg_gen_andi_i32(fpsr, fpsr, FPSR_CC_A | FPSR_CC_N);
|
||||
tcg_gen_or_i32(c->v1, c->v1, fpsr);
|
||||
tcg_gen_xori_i32(c->v1, c->v1, FPSR_CC_N);
|
||||
c->tcond = TCG_COND_NE;
|
||||
imm = FPSR_CC_A | FPSR_CC_N;
|
||||
c->tcond = TCG_COND_TSTNE;
|
||||
break;
|
||||
case 11: /* Unordered or Greater or Equal A || Z || !N */
|
||||
case 27: /* Not Less Than A || Z || !N */
|
||||
c->v1 = tcg_temp_new();
|
||||
tcg_gen_andi_i32(c->v1, fpsr, FPSR_CC_A | FPSR_CC_Z | FPSR_CC_N);
|
||||
tcg_gen_xori_i32(c->v1, c->v1, FPSR_CC_N);
|
||||
c->tcond = TCG_COND_NE;
|
||||
tcg_gen_xori_i32(c->v1, fpsr, FPSR_CC_N);
|
||||
imm = FPSR_CC_A | FPSR_CC_Z | FPSR_CC_N;
|
||||
c->tcond = TCG_COND_TSTNE;
|
||||
break;
|
||||
case 12: /* Unordered or Less Than A || (N && !Z) */
|
||||
case 28: /* Not Greater than or Equal A || (N && !Z) */
|
||||
@@ -5226,27 +5220,25 @@ static void gen_fcc_cond(DisasCompare *c, DisasContext *s, int cond)
|
||||
tcg_gen_andi_i32(c->v1, fpsr, FPSR_CC_Z);
|
||||
tcg_gen_shli_i32(c->v1, c->v1, ctz32(FPSR_CC_N) - ctz32(FPSR_CC_Z));
|
||||
tcg_gen_andc_i32(c->v1, fpsr, c->v1);
|
||||
tcg_gen_andi_i32(c->v1, c->v1, FPSR_CC_A | FPSR_CC_N);
|
||||
c->tcond = TCG_COND_NE;
|
||||
imm = FPSR_CC_A | FPSR_CC_N;
|
||||
c->tcond = TCG_COND_TSTNE;
|
||||
break;
|
||||
case 13: /* Unordered or Less or Equal A || Z || N */
|
||||
case 29: /* Not Greater Than A || Z || N */
|
||||
c->v1 = tcg_temp_new();
|
||||
tcg_gen_andi_i32(c->v1, fpsr, FPSR_CC_A | FPSR_CC_Z | FPSR_CC_N);
|
||||
c->tcond = TCG_COND_NE;
|
||||
imm = FPSR_CC_A | FPSR_CC_Z | FPSR_CC_N;
|
||||
c->tcond = TCG_COND_TSTNE;
|
||||
break;
|
||||
case 14: /* Not Equal !Z */
|
||||
case 30: /* Signaling Not Equal !Z */
|
||||
c->v1 = tcg_temp_new();
|
||||
tcg_gen_andi_i32(c->v1, fpsr, FPSR_CC_Z);
|
||||
c->tcond = TCG_COND_EQ;
|
||||
imm = FPSR_CC_Z;
|
||||
c->tcond = TCG_COND_TSTEQ;
|
||||
break;
|
||||
case 15: /* True */
|
||||
case 31: /* Signaling True */
|
||||
c->v1 = c->v2;
|
||||
c->tcond = TCG_COND_ALWAYS;
|
||||
break;
|
||||
}
|
||||
c->v2 = tcg_constant_i32(imm);
|
||||
}
|
||||
|
||||
static void gen_fjmpcc(DisasContext *s, int cond, TCGLabel *l1)
|
||||
|
||||
@@ -754,10 +754,10 @@ static void disas_jcc(DisasContext *s, DisasCompare *c, uint32_t mask)
|
||||
case CC_OP_TM_64:
|
||||
switch (mask) {
|
||||
case 8:
|
||||
cond = TCG_COND_EQ;
|
||||
cond = TCG_COND_TSTEQ;
|
||||
break;
|
||||
case 4 | 2 | 1:
|
||||
cond = TCG_COND_NE;
|
||||
cond = TCG_COND_TSTNE;
|
||||
break;
|
||||
default:
|
||||
goto do_dynamic;
|
||||
@@ -768,11 +768,11 @@ static void disas_jcc(DisasContext *s, DisasCompare *c, uint32_t mask)
|
||||
case CC_OP_ICM:
|
||||
switch (mask) {
|
||||
case 8:
|
||||
cond = TCG_COND_EQ;
|
||||
cond = TCG_COND_TSTEQ;
|
||||
break;
|
||||
case 4 | 2 | 1:
|
||||
case 4 | 2:
|
||||
cond = TCG_COND_NE;
|
||||
cond = TCG_COND_TSTNE;
|
||||
break;
|
||||
default:
|
||||
goto do_dynamic;
|
||||
@@ -854,18 +854,14 @@ static void disas_jcc(DisasContext *s, DisasCompare *c, uint32_t mask)
|
||||
c->u.s64.a = cc_dst;
|
||||
c->u.s64.b = tcg_constant_i64(0);
|
||||
break;
|
||||
|
||||
case CC_OP_LTGT_64:
|
||||
case CC_OP_LTUGTU_64:
|
||||
c->u.s64.a = cc_src;
|
||||
c->u.s64.b = cc_dst;
|
||||
break;
|
||||
|
||||
case CC_OP_TM_32:
|
||||
case CC_OP_TM_64:
|
||||
case CC_OP_ICM:
|
||||
c->u.s64.a = tcg_temp_new_i64();
|
||||
c->u.s64.b = tcg_constant_i64(0);
|
||||
tcg_gen_and_i64(c->u.s64.a, cc_src, cc_dst);
|
||||
c->u.s64.a = cc_src;
|
||||
c->u.s64.b = cc_dst;
|
||||
break;
|
||||
|
||||
case CC_OP_ADDU:
|
||||
@@ -889,67 +885,45 @@ static void disas_jcc(DisasContext *s, DisasCompare *c, uint32_t mask)
|
||||
case CC_OP_STATIC:
|
||||
c->is_64 = false;
|
||||
c->u.s32.a = cc_op;
|
||||
switch (mask) {
|
||||
case 0x8 | 0x4 | 0x2: /* cc != 3 */
|
||||
cond = TCG_COND_NE;
|
||||
|
||||
/* Fold half of the cases using bit 3 to invert. */
|
||||
switch (mask & 8 ? mask ^ 0xf : mask) {
|
||||
case 0x1: /* cc == 3 */
|
||||
cond = TCG_COND_EQ;
|
||||
c->u.s32.b = tcg_constant_i32(3);
|
||||
break;
|
||||
case 0x8 | 0x4 | 0x1: /* cc != 2 */
|
||||
cond = TCG_COND_NE;
|
||||
c->u.s32.b = tcg_constant_i32(2);
|
||||
break;
|
||||
case 0x8 | 0x2 | 0x1: /* cc != 1 */
|
||||
cond = TCG_COND_NE;
|
||||
c->u.s32.b = tcg_constant_i32(1);
|
||||
break;
|
||||
case 0x8 | 0x2: /* cc == 0 || cc == 2 => (cc & 1) == 0 */
|
||||
cond = TCG_COND_EQ;
|
||||
c->u.s32.a = tcg_temp_new_i32();
|
||||
c->u.s32.b = tcg_constant_i32(0);
|
||||
tcg_gen_andi_i32(c->u.s32.a, cc_op, 1);
|
||||
break;
|
||||
case 0x8 | 0x4: /* cc < 2 */
|
||||
cond = TCG_COND_LTU;
|
||||
c->u.s32.b = tcg_constant_i32(2);
|
||||
break;
|
||||
case 0x8: /* cc == 0 */
|
||||
cond = TCG_COND_EQ;
|
||||
c->u.s32.b = tcg_constant_i32(0);
|
||||
break;
|
||||
case 0x4 | 0x2 | 0x1: /* cc != 0 */
|
||||
cond = TCG_COND_NE;
|
||||
c->u.s32.b = tcg_constant_i32(0);
|
||||
break;
|
||||
case 0x4 | 0x1: /* cc == 1 || cc == 3 => (cc & 1) != 0 */
|
||||
cond = TCG_COND_NE;
|
||||
c->u.s32.a = tcg_temp_new_i32();
|
||||
c->u.s32.b = tcg_constant_i32(0);
|
||||
tcg_gen_andi_i32(c->u.s32.a, cc_op, 1);
|
||||
break;
|
||||
case 0x4: /* cc == 1 */
|
||||
cond = TCG_COND_EQ;
|
||||
c->u.s32.b = tcg_constant_i32(1);
|
||||
break;
|
||||
case 0x2 | 0x1: /* cc > 1 */
|
||||
cond = TCG_COND_GTU;
|
||||
c->u.s32.b = tcg_constant_i32(1);
|
||||
break;
|
||||
case 0x2: /* cc == 2 */
|
||||
cond = TCG_COND_EQ;
|
||||
c->u.s32.b = tcg_constant_i32(2);
|
||||
break;
|
||||
case 0x1: /* cc == 3 */
|
||||
case 0x4: /* cc == 1 */
|
||||
cond = TCG_COND_EQ;
|
||||
c->u.s32.b = tcg_constant_i32(3);
|
||||
c->u.s32.b = tcg_constant_i32(1);
|
||||
break;
|
||||
case 0x2 | 0x1: /* cc == 2 || cc == 3 => cc > 1 */
|
||||
cond = TCG_COND_GTU;
|
||||
c->u.s32.b = tcg_constant_i32(1);
|
||||
break;
|
||||
case 0x4 | 0x1: /* cc == 1 || cc == 3 => (cc & 1) != 0 */
|
||||
cond = TCG_COND_TSTNE;
|
||||
c->u.s32.b = tcg_constant_i32(1);
|
||||
break;
|
||||
case 0x4 | 0x2: /* cc == 1 || cc == 2 => (cc - 1) <= 1 */
|
||||
cond = TCG_COND_LEU;
|
||||
c->u.s32.a = tcg_temp_new_i32();
|
||||
c->u.s32.b = tcg_constant_i32(1);
|
||||
tcg_gen_addi_i32(c->u.s32.a, cc_op, -1);
|
||||
break;
|
||||
case 0x4 | 0x2 | 0x1: /* cc != 0 */
|
||||
cond = TCG_COND_NE;
|
||||
c->u.s32.b = tcg_constant_i32(0);
|
||||
break;
|
||||
default:
|
||||
/* CC is masked by something else: (8 >> cc) & mask. */
|
||||
cond = TCG_COND_NE;
|
||||
c->u.s32.a = tcg_temp_new_i32();
|
||||
c->u.s32.b = tcg_constant_i32(0);
|
||||
tcg_gen_shr_i32(c->u.s32.a, tcg_constant_i32(8), cc_op);
|
||||
tcg_gen_andi_i32(c->u.s32.a, c->u.s32.a, mask);
|
||||
break;
|
||||
/* case 0: never, handled above. */
|
||||
g_assert_not_reached();
|
||||
}
|
||||
if (mask & 8) {
|
||||
cond = tcg_invert_cond(cond);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
@@ -488,6 +488,7 @@ static void gen_op_subccc(TCGv dst, TCGv src1, TCGv src2)
|
||||
static void gen_op_mulscc(TCGv dst, TCGv src1, TCGv src2)
|
||||
{
|
||||
TCGv zero = tcg_constant_tl(0);
|
||||
TCGv one = tcg_constant_tl(1);
|
||||
TCGv t_src1 = tcg_temp_new();
|
||||
TCGv t_src2 = tcg_temp_new();
|
||||
TCGv t0 = tcg_temp_new();
|
||||
@@ -499,8 +500,7 @@ static void gen_op_mulscc(TCGv dst, TCGv src1, TCGv src2)
|
||||
* if (!(env->y & 1))
|
||||
* src2 = 0;
|
||||
*/
|
||||
tcg_gen_andi_tl(t0, cpu_y, 0x1);
|
||||
tcg_gen_movcond_tl(TCG_COND_EQ, t_src2, t0, zero, zero, t_src2);
|
||||
tcg_gen_movcond_tl(TCG_COND_TSTEQ, t_src2, cpu_y, one, zero, t_src2);
|
||||
|
||||
/*
|
||||
* b2 = src1 & 1;
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
* tcg-target-con-str.h; the constraint combination is inclusive or.
|
||||
*/
|
||||
C_O0_I1(r)
|
||||
C_O0_I2(r, rA)
|
||||
C_O0_I2(r, rC)
|
||||
C_O0_I2(rZ, r)
|
||||
C_O0_I2(w, r)
|
||||
C_O0_I3(rZ, rZ, r)
|
||||
@@ -22,6 +22,7 @@ C_O1_I2(r, 0, rZ)
|
||||
C_O1_I2(r, r, r)
|
||||
C_O1_I2(r, r, rA)
|
||||
C_O1_I2(r, r, rAL)
|
||||
C_O1_I2(r, r, rC)
|
||||
C_O1_I2(r, r, ri)
|
||||
C_O1_I2(r, r, rL)
|
||||
C_O1_I2(r, rZ, rZ)
|
||||
@@ -31,6 +32,6 @@ C_O1_I2(w, w, wN)
|
||||
C_O1_I2(w, w, wO)
|
||||
C_O1_I2(w, w, wZ)
|
||||
C_O1_I3(w, w, w, w)
|
||||
C_O1_I4(r, r, rA, rZ, rZ)
|
||||
C_O1_I4(r, r, rC, rZ, rZ)
|
||||
C_O2_I1(r, r, r)
|
||||
C_O2_I4(r, r, rZ, rZ, rA, rMZ)
|
||||
|
||||
@@ -16,6 +16,7 @@ REGS('w', ALL_VECTOR_REGS)
|
||||
* CONST(letter, TCG_CT_CONST_* bit set)
|
||||
*/
|
||||
CONST('A', TCG_CT_CONST_AIMM)
|
||||
CONST('C', TCG_CT_CONST_CMP)
|
||||
CONST('L', TCG_CT_CONST_LIMM)
|
||||
CONST('M', TCG_CT_CONST_MONE)
|
||||
CONST('O', TCG_CT_CONST_ORRI)
|
||||
|
||||
+130
-36
@@ -105,6 +105,18 @@ static bool reloc_pc19(tcg_insn_unit *src_rw, const tcg_insn_unit *target)
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool reloc_pc14(tcg_insn_unit *src_rw, const tcg_insn_unit *target)
|
||||
{
|
||||
const tcg_insn_unit *src_rx = tcg_splitwx_to_rx(src_rw);
|
||||
ptrdiff_t offset = target - src_rx;
|
||||
|
||||
if (offset == sextract64(offset, 0, 14)) {
|
||||
*src_rw = deposit32(*src_rw, 5, 14, offset);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
|
||||
intptr_t value, intptr_t addend)
|
||||
{
|
||||
@@ -115,6 +127,8 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
|
||||
return reloc_pc26(code_ptr, (const tcg_insn_unit *)value);
|
||||
case R_AARCH64_CONDBR19:
|
||||
return reloc_pc19(code_ptr, (const tcg_insn_unit *)value);
|
||||
case R_AARCH64_TSTBR14:
|
||||
return reloc_pc14(code_ptr, (const tcg_insn_unit *)value);
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
@@ -126,6 +140,7 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
|
||||
#define TCG_CT_CONST_MONE 0x800
|
||||
#define TCG_CT_CONST_ORRI 0x1000
|
||||
#define TCG_CT_CONST_ANDI 0x2000
|
||||
#define TCG_CT_CONST_CMP 0x4000
|
||||
|
||||
#define ALL_GENERAL_REGS 0xffffffffu
|
||||
#define ALL_VECTOR_REGS 0xffffffff00000000ull
|
||||
@@ -270,7 +285,8 @@ static bool is_shimm1632(uint32_t v32, int *cmode, int *imm8)
|
||||
}
|
||||
}
|
||||
|
||||
static bool tcg_target_const_match(int64_t val, TCGType type, int ct, int vece)
|
||||
static bool tcg_target_const_match(int64_t val, int ct,
|
||||
TCGType type, TCGCond cond, int vece)
|
||||
{
|
||||
if (ct & TCG_CT_CONST) {
|
||||
return 1;
|
||||
@@ -278,6 +294,15 @@ static bool tcg_target_const_match(int64_t val, TCGType type, int ct, int vece)
|
||||
if (type == TCG_TYPE_I32) {
|
||||
val = (int32_t)val;
|
||||
}
|
||||
|
||||
if (ct & TCG_CT_CONST_CMP) {
|
||||
if (is_tst_cond(cond)) {
|
||||
ct |= TCG_CT_CONST_LIMM;
|
||||
} else {
|
||||
ct |= TCG_CT_CONST_AIMM;
|
||||
}
|
||||
}
|
||||
|
||||
if ((ct & TCG_CT_CONST_AIMM) && (is_aimm(val) || is_aimm(-val))) {
|
||||
return 1;
|
||||
}
|
||||
@@ -344,6 +369,9 @@ static const enum aarch64_cond_code tcg_cond_to_aarch64[] = {
|
||||
[TCG_COND_GTU] = COND_HI,
|
||||
[TCG_COND_GEU] = COND_HS,
|
||||
[TCG_COND_LEU] = COND_LS,
|
||||
/* bit test */
|
||||
[TCG_COND_TSTEQ] = COND_EQ,
|
||||
[TCG_COND_TSTNE] = COND_NE,
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
@@ -366,6 +394,10 @@ typedef enum {
|
||||
/* Conditional branch (immediate). */
|
||||
I3202_B_C = 0x54000000,
|
||||
|
||||
/* Test and branch (immediate). */
|
||||
I3205_TBZ = 0x36000000,
|
||||
I3205_TBNZ = 0x37000000,
|
||||
|
||||
/* Unconditional branch (immediate). */
|
||||
I3206_B = 0x14000000,
|
||||
I3206_BL = 0x94000000,
|
||||
@@ -646,6 +678,14 @@ static void tcg_out_insn_3202(TCGContext *s, AArch64Insn insn,
|
||||
tcg_out32(s, insn | tcg_cond_to_aarch64[c] | (imm19 & 0x7ffff) << 5);
|
||||
}
|
||||
|
||||
static void tcg_out_insn_3205(TCGContext *s, AArch64Insn insn,
|
||||
TCGReg rt, int imm6, int imm14)
|
||||
{
|
||||
insn |= (imm6 & 0x20) << (31 - 5);
|
||||
insn |= (imm6 & 0x1f) << 19;
|
||||
tcg_out32(s, insn | (imm14 & 0x3fff) << 5 | rt);
|
||||
}
|
||||
|
||||
static void tcg_out_insn_3206(TCGContext *s, AArch64Insn insn, int imm26)
|
||||
{
|
||||
tcg_out32(s, insn | (imm26 & 0x03ffffff));
|
||||
@@ -1341,19 +1381,26 @@ static inline void tcg_out_dep(TCGContext *s, TCGType ext, TCGReg rd,
|
||||
tcg_out_bfm(s, ext, rd, rn, a, b);
|
||||
}
|
||||
|
||||
static void tcg_out_cmp(TCGContext *s, TCGType ext, TCGReg a,
|
||||
static void tcg_out_cmp(TCGContext *s, TCGType ext, TCGCond cond, TCGReg a,
|
||||
tcg_target_long b, bool const_b)
|
||||
{
|
||||
if (const_b) {
|
||||
/* Using CMP or CMN aliases. */
|
||||
if (b >= 0) {
|
||||
tcg_out_insn(s, 3401, SUBSI, ext, TCG_REG_XZR, a, b);
|
||||
if (is_tst_cond(cond)) {
|
||||
if (!const_b) {
|
||||
tcg_out_insn(s, 3510, ANDS, ext, TCG_REG_XZR, a, b);
|
||||
} else {
|
||||
tcg_out_insn(s, 3401, ADDSI, ext, TCG_REG_XZR, a, -b);
|
||||
tcg_debug_assert(is_limm(b));
|
||||
tcg_out_logicali(s, I3404_ANDSI, 0, TCG_REG_XZR, a, b);
|
||||
}
|
||||
} else {
|
||||
/* Using CMP alias SUBS wzr, Wn, Wm */
|
||||
tcg_out_insn(s, 3502, SUBS, ext, TCG_REG_XZR, a, b);
|
||||
if (!const_b) {
|
||||
tcg_out_insn(s, 3502, SUBS, ext, TCG_REG_XZR, a, b);
|
||||
} else if (b >= 0) {
|
||||
tcg_debug_assert(is_aimm(b));
|
||||
tcg_out_insn(s, 3401, SUBSI, ext, TCG_REG_XZR, a, b);
|
||||
} else {
|
||||
tcg_debug_assert(is_aimm(-b));
|
||||
tcg_out_insn(s, 3401, ADDSI, ext, TCG_REG_XZR, a, -b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1394,30 +1441,75 @@ static inline void tcg_out_goto_label(TCGContext *s, TCGLabel *l)
|
||||
static void tcg_out_brcond(TCGContext *s, TCGType ext, TCGCond c, TCGArg a,
|
||||
TCGArg b, bool b_const, TCGLabel *l)
|
||||
{
|
||||
intptr_t offset;
|
||||
bool need_cmp;
|
||||
int tbit = -1;
|
||||
bool need_cmp = true;
|
||||
|
||||
if (b_const && b == 0 && (c == TCG_COND_EQ || c == TCG_COND_NE)) {
|
||||
need_cmp = false;
|
||||
} else {
|
||||
need_cmp = true;
|
||||
tcg_out_cmp(s, ext, a, b, b_const);
|
||||
}
|
||||
|
||||
if (!l->has_value) {
|
||||
tcg_out_reloc(s, s->code_ptr, R_AARCH64_CONDBR19, l, 0);
|
||||
offset = tcg_in32(s) >> 5;
|
||||
} else {
|
||||
offset = tcg_pcrel_diff(s, l->u.value_ptr) >> 2;
|
||||
tcg_debug_assert(offset == sextract64(offset, 0, 19));
|
||||
switch (c) {
|
||||
case TCG_COND_EQ:
|
||||
case TCG_COND_NE:
|
||||
/* cmp xN,0; b.ne L -> cbnz xN,L */
|
||||
if (b_const && b == 0) {
|
||||
need_cmp = false;
|
||||
}
|
||||
break;
|
||||
case TCG_COND_LT:
|
||||
case TCG_COND_GE:
|
||||
/* cmp xN,0; b.mi L -> tbnz xN,63,L */
|
||||
if (b_const && b == 0) {
|
||||
c = (c == TCG_COND_LT ? TCG_COND_TSTNE : TCG_COND_TSTEQ);
|
||||
tbit = ext ? 63 : 31;
|
||||
need_cmp = false;
|
||||
}
|
||||
break;
|
||||
case TCG_COND_TSTEQ:
|
||||
case TCG_COND_TSTNE:
|
||||
/* tst xN,0xffffffff; b.ne L -> cbnz wN,L */
|
||||
if (b_const && b == UINT32_MAX) {
|
||||
ext = TCG_TYPE_I32;
|
||||
need_cmp = false;
|
||||
break;
|
||||
}
|
||||
/* tst xN,1<<B; b.ne L -> tbnz xN,B,L */
|
||||
if (b_const && is_power_of_2(b)) {
|
||||
tbit = ctz64(b);
|
||||
need_cmp = false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (need_cmp) {
|
||||
tcg_out_insn(s, 3202, B_C, c, offset);
|
||||
} else if (c == TCG_COND_EQ) {
|
||||
tcg_out_insn(s, 3201, CBZ, ext, a, offset);
|
||||
tcg_out_cmp(s, ext, c, a, b, b_const);
|
||||
tcg_out_reloc(s, s->code_ptr, R_AARCH64_CONDBR19, l, 0);
|
||||
tcg_out_insn(s, 3202, B_C, c, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (tbit >= 0) {
|
||||
tcg_out_reloc(s, s->code_ptr, R_AARCH64_TSTBR14, l, 0);
|
||||
switch (c) {
|
||||
case TCG_COND_TSTEQ:
|
||||
tcg_out_insn(s, 3205, TBZ, a, tbit, 0);
|
||||
break;
|
||||
case TCG_COND_TSTNE:
|
||||
tcg_out_insn(s, 3205, TBNZ, a, tbit, 0);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
} else {
|
||||
tcg_out_insn(s, 3201, CBNZ, ext, a, offset);
|
||||
tcg_out_reloc(s, s->code_ptr, R_AARCH64_CONDBR19, l, 0);
|
||||
switch (c) {
|
||||
case TCG_COND_EQ:
|
||||
tcg_out_insn(s, 3201, CBZ, ext, a, 0);
|
||||
break;
|
||||
case TCG_COND_NE:
|
||||
tcg_out_insn(s, 3201, CBNZ, ext, a, 0);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1574,7 +1666,7 @@ static void tcg_out_cltz(TCGContext *s, TCGType ext, TCGReg d,
|
||||
} else {
|
||||
AArch64Insn sel = I3506_CSEL;
|
||||
|
||||
tcg_out_cmp(s, ext, a0, 0, 1);
|
||||
tcg_out_cmp(s, ext, TCG_COND_NE, a0, 0, 1);
|
||||
tcg_out_insn(s, 3507, CLZ, ext, TCG_REG_TMP0, a1);
|
||||
|
||||
if (const_b) {
|
||||
@@ -1719,7 +1811,7 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h,
|
||||
addr_adj, compare_mask);
|
||||
|
||||
/* Perform the address comparison. */
|
||||
tcg_out_cmp(s, addr_type, TCG_REG_TMP0, TCG_REG_TMP2, 0);
|
||||
tcg_out_cmp(s, addr_type, TCG_COND_NE, TCG_REG_TMP0, TCG_REG_TMP2, 0);
|
||||
|
||||
/* If not equal, we jump to the slow path. */
|
||||
ldst->label_ptr[0] = s->code_ptr;
|
||||
@@ -2275,7 +2367,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
|
||||
a2 = (int32_t)a2;
|
||||
/* FALLTHRU */
|
||||
case INDEX_op_setcond_i64:
|
||||
tcg_out_cmp(s, ext, a1, a2, c2);
|
||||
tcg_out_cmp(s, ext, args[3], a1, a2, c2);
|
||||
/* Use CSET alias of CSINC Wd, WZR, WZR, invert(cond). */
|
||||
tcg_out_insn(s, 3506, CSINC, TCG_TYPE_I32, a0, TCG_REG_XZR,
|
||||
TCG_REG_XZR, tcg_invert_cond(args[3]));
|
||||
@@ -2285,7 +2377,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
|
||||
a2 = (int32_t)a2;
|
||||
/* FALLTHRU */
|
||||
case INDEX_op_negsetcond_i64:
|
||||
tcg_out_cmp(s, ext, a1, a2, c2);
|
||||
tcg_out_cmp(s, ext, args[3], a1, a2, c2);
|
||||
/* Use CSETM alias of CSINV Wd, WZR, WZR, invert(cond). */
|
||||
tcg_out_insn(s, 3506, CSINV, ext, a0, TCG_REG_XZR,
|
||||
TCG_REG_XZR, tcg_invert_cond(args[3]));
|
||||
@@ -2295,7 +2387,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
|
||||
a2 = (int32_t)a2;
|
||||
/* FALLTHRU */
|
||||
case INDEX_op_movcond_i64:
|
||||
tcg_out_cmp(s, ext, a1, a2, c2);
|
||||
tcg_out_cmp(s, ext, args[5], a1, a2, c2);
|
||||
tcg_out_insn(s, 3506, CSEL, ext, a0, REG0(3), REG0(4), args[5]);
|
||||
break;
|
||||
|
||||
@@ -2895,11 +2987,13 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op)
|
||||
case INDEX_op_add_i64:
|
||||
case INDEX_op_sub_i32:
|
||||
case INDEX_op_sub_i64:
|
||||
return C_O1_I2(r, r, rA);
|
||||
|
||||
case INDEX_op_setcond_i32:
|
||||
case INDEX_op_setcond_i64:
|
||||
case INDEX_op_negsetcond_i32:
|
||||
case INDEX_op_negsetcond_i64:
|
||||
return C_O1_I2(r, r, rA);
|
||||
return C_O1_I2(r, r, rC);
|
||||
|
||||
case INDEX_op_mul_i32:
|
||||
case INDEX_op_mul_i64:
|
||||
@@ -2949,11 +3043,11 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op)
|
||||
|
||||
case INDEX_op_brcond_i32:
|
||||
case INDEX_op_brcond_i64:
|
||||
return C_O0_I2(r, rA);
|
||||
return C_O0_I2(r, rC);
|
||||
|
||||
case INDEX_op_movcond_i32:
|
||||
case INDEX_op_movcond_i64:
|
||||
return C_O1_I4(r, r, rA, rZ, rZ);
|
||||
return C_O1_I4(r, r, rC, rZ, rZ);
|
||||
|
||||
case INDEX_op_qemu_ld_a32_i32:
|
||||
case INDEX_op_qemu_ld_a64_i32:
|
||||
|
||||
@@ -138,6 +138,8 @@ typedef enum {
|
||||
#define TCG_TARGET_HAS_qemu_ldst_i128 1
|
||||
#endif
|
||||
|
||||
#define TCG_TARGET_HAS_tst 1
|
||||
|
||||
#define TCG_TARGET_HAS_v64 1
|
||||
#define TCG_TARGET_HAS_v128 1
|
||||
#define TCG_TARGET_HAS_v256 0
|
||||
|
||||
+46
-16
@@ -501,7 +501,8 @@ static bool is_shimm1632(uint32_t v32, int *cmode, int *imm8)
|
||||
* mov operand2: values represented with x << (2 * y), x < 0x100
|
||||
* add, sub, eor...: ditto
|
||||
*/
|
||||
static bool tcg_target_const_match(int64_t val, TCGType type, int ct, int vece)
|
||||
static bool tcg_target_const_match(int64_t val, int ct,
|
||||
TCGType type, TCGCond cond, int vece)
|
||||
{
|
||||
if (ct & TCG_CT_CONST) {
|
||||
return 1;
|
||||
@@ -1190,6 +1191,33 @@ static void tcg_out_mb(TCGContext *s, TCGArg a0)
|
||||
}
|
||||
}
|
||||
|
||||
static TCGCond tcg_out_cmp(TCGContext *s, TCGCond cond, TCGReg a,
|
||||
TCGArg b, int b_const)
|
||||
{
|
||||
if (!is_tst_cond(cond)) {
|
||||
tcg_out_dat_rIN(s, COND_AL, ARITH_CMP, ARITH_CMN, 0, a, b, b_const);
|
||||
return cond;
|
||||
}
|
||||
|
||||
cond = tcg_tst_eqne_cond(cond);
|
||||
if (b_const) {
|
||||
int imm12 = encode_imm(b);
|
||||
|
||||
/*
|
||||
* The compare constraints allow rIN, but TST does not support N.
|
||||
* Be prepared to load the constant into a scratch register.
|
||||
*/
|
||||
if (imm12 >= 0) {
|
||||
tcg_out_dat_imm(s, COND_AL, ARITH_TST, 0, a, imm12);
|
||||
return cond;
|
||||
}
|
||||
tcg_out_movi32(s, COND_AL, TCG_REG_TMP, b);
|
||||
b = TCG_REG_TMP;
|
||||
}
|
||||
tcg_out_dat_reg(s, COND_AL, ARITH_TST, 0, a, b, SHIFT_IMM_LSL(0));
|
||||
return cond;
|
||||
}
|
||||
|
||||
static TCGCond tcg_out_cmp2(TCGContext *s, const TCGArg *args,
|
||||
const int *const_args)
|
||||
{
|
||||
@@ -1217,6 +1245,13 @@ static TCGCond tcg_out_cmp2(TCGContext *s, const TCGArg *args,
|
||||
tcg_out_dat_rI(s, COND_EQ, ARITH_CMP, 0, al, bl, const_bl);
|
||||
return cond;
|
||||
|
||||
case TCG_COND_TSTEQ:
|
||||
case TCG_COND_TSTNE:
|
||||
/* Similar, but with TST instead of CMP. */
|
||||
tcg_out_dat_rI(s, COND_AL, ARITH_TST, 0, ah, bh, const_bh);
|
||||
tcg_out_dat_rI(s, COND_EQ, ARITH_TST, 0, al, bl, const_bl);
|
||||
return tcg_tst_eqne_cond(cond);
|
||||
|
||||
case TCG_COND_LT:
|
||||
case TCG_COND_GE:
|
||||
/* We perform a double-word subtraction and examine the result.
|
||||
@@ -1808,9 +1843,8 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
|
||||
/* Constraints mean that v2 is always in the same register as dest,
|
||||
* so we only need to do "if condition passed, move v1 to dest".
|
||||
*/
|
||||
tcg_out_dat_rIN(s, COND_AL, ARITH_CMP, ARITH_CMN, 0,
|
||||
args[1], args[2], const_args[2]);
|
||||
tcg_out_dat_rIK(s, tcg_cond_to_arm_cond[args[5]], ARITH_MOV,
|
||||
c = tcg_out_cmp(s, args[5], args[1], args[2], const_args[2]);
|
||||
tcg_out_dat_rIK(s, tcg_cond_to_arm_cond[c], ARITH_MOV,
|
||||
ARITH_MVN, args[0], 0, args[3], const_args[3]);
|
||||
break;
|
||||
case INDEX_op_add_i32:
|
||||
@@ -1960,25 +1994,21 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
|
||||
break;
|
||||
|
||||
case INDEX_op_brcond_i32:
|
||||
tcg_out_dat_rIN(s, COND_AL, ARITH_CMP, ARITH_CMN, 0,
|
||||
args[0], args[1], const_args[1]);
|
||||
tcg_out_goto_label(s, tcg_cond_to_arm_cond[args[2]],
|
||||
arg_label(args[3]));
|
||||
c = tcg_out_cmp(s, args[2], args[0], args[1], const_args[1]);
|
||||
tcg_out_goto_label(s, tcg_cond_to_arm_cond[c], arg_label(args[3]));
|
||||
break;
|
||||
case INDEX_op_setcond_i32:
|
||||
tcg_out_dat_rIN(s, COND_AL, ARITH_CMP, ARITH_CMN, 0,
|
||||
args[1], args[2], const_args[2]);
|
||||
tcg_out_dat_imm(s, tcg_cond_to_arm_cond[args[3]],
|
||||
c = tcg_out_cmp(s, args[3], args[1], args[2], const_args[2]);
|
||||
tcg_out_dat_imm(s, tcg_cond_to_arm_cond[c],
|
||||
ARITH_MOV, args[0], 0, 1);
|
||||
tcg_out_dat_imm(s, tcg_cond_to_arm_cond[tcg_invert_cond(args[3])],
|
||||
tcg_out_dat_imm(s, tcg_cond_to_arm_cond[tcg_invert_cond(c)],
|
||||
ARITH_MOV, args[0], 0, 0);
|
||||
break;
|
||||
case INDEX_op_negsetcond_i32:
|
||||
tcg_out_dat_rIN(s, COND_AL, ARITH_CMP, ARITH_CMN, 0,
|
||||
args[1], args[2], const_args[2]);
|
||||
tcg_out_dat_imm(s, tcg_cond_to_arm_cond[args[3]],
|
||||
c = tcg_out_cmp(s, args[3], args[1], args[2], const_args[2]);
|
||||
tcg_out_dat_imm(s, tcg_cond_to_arm_cond[c],
|
||||
ARITH_MVN, args[0], 0, 0);
|
||||
tcg_out_dat_imm(s, tcg_cond_to_arm_cond[tcg_invert_cond(args[3])],
|
||||
tcg_out_dat_imm(s, tcg_cond_to_arm_cond[tcg_invert_cond(c)],
|
||||
ARITH_MOV, args[0], 0, 0);
|
||||
break;
|
||||
|
||||
|
||||
@@ -125,6 +125,8 @@ extern bool use_neon_instructions;
|
||||
|
||||
#define TCG_TARGET_HAS_qemu_ldst_i128 0
|
||||
|
||||
#define TCG_TARGET_HAS_tst 1
|
||||
|
||||
#define TCG_TARGET_HAS_v64 use_neon_instructions
|
||||
#define TCG_TARGET_HAS_v128 use_neon_instructions
|
||||
#define TCG_TARGET_HAS_v256 0
|
||||
|
||||
@@ -20,7 +20,7 @@ C_O0_I2(L, L)
|
||||
C_O0_I2(qi, r)
|
||||
C_O0_I2(re, r)
|
||||
C_O0_I2(ri, r)
|
||||
C_O0_I2(r, re)
|
||||
C_O0_I2(r, reT)
|
||||
C_O0_I2(s, L)
|
||||
C_O0_I2(x, r)
|
||||
C_O0_I3(L, L, L)
|
||||
@@ -34,7 +34,7 @@ C_O1_I1(r, r)
|
||||
C_O1_I1(x, r)
|
||||
C_O1_I1(x, x)
|
||||
C_O1_I2(q, 0, qi)
|
||||
C_O1_I2(q, r, re)
|
||||
C_O1_I2(q, r, reT)
|
||||
C_O1_I2(r, 0, ci)
|
||||
C_O1_I2(r, 0, r)
|
||||
C_O1_I2(r, 0, re)
|
||||
@@ -50,7 +50,7 @@ C_N1_I2(r, r, r)
|
||||
C_N1_I2(r, r, rW)
|
||||
C_O1_I3(x, 0, x, x)
|
||||
C_O1_I3(x, x, x, x)
|
||||
C_O1_I4(r, r, re, r, 0)
|
||||
C_O1_I4(r, r, reT, r, 0)
|
||||
C_O1_I4(r, r, r, ri, ri)
|
||||
C_O2_I1(r, r, L)
|
||||
C_O2_I2(a, d, a, r)
|
||||
|
||||
@@ -28,5 +28,6 @@ REGS('s', ALL_BYTEL_REGS & ~SOFTMMU_RESERVE_REGS) /* qemu_st8_i32 data */
|
||||
*/
|
||||
CONST('e', TCG_CT_CONST_S32)
|
||||
CONST('I', TCG_CT_CONST_I32)
|
||||
CONST('T', TCG_CT_CONST_TST)
|
||||
CONST('W', TCG_CT_CONST_WSZ)
|
||||
CONST('Z', TCG_CT_CONST_U32)
|
||||
|
||||
+144
-57
@@ -132,6 +132,7 @@ static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot)
|
||||
#define TCG_CT_CONST_U32 0x200
|
||||
#define TCG_CT_CONST_I32 0x400
|
||||
#define TCG_CT_CONST_WSZ 0x800
|
||||
#define TCG_CT_CONST_TST 0x1000
|
||||
|
||||
/* Registers used with L constraint, which are the first argument
|
||||
registers on x86_64, and two random call clobbered registers on
|
||||
@@ -195,13 +196,15 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
|
||||
}
|
||||
|
||||
/* test if a constant matches the constraint */
|
||||
static bool tcg_target_const_match(int64_t val, TCGType type, int ct, int vece)
|
||||
static bool tcg_target_const_match(int64_t val, int ct,
|
||||
TCGType type, TCGCond cond, int vece)
|
||||
{
|
||||
if (ct & TCG_CT_CONST) {
|
||||
return 1;
|
||||
}
|
||||
if (type == TCG_TYPE_I32) {
|
||||
if (ct & (TCG_CT_CONST_S32 | TCG_CT_CONST_U32 | TCG_CT_CONST_I32)) {
|
||||
if (ct & (TCG_CT_CONST_S32 | TCG_CT_CONST_U32 |
|
||||
TCG_CT_CONST_I32 | TCG_CT_CONST_TST)) {
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
@@ -214,6 +217,17 @@ static bool tcg_target_const_match(int64_t val, TCGType type, int ct, int vece)
|
||||
if ((ct & TCG_CT_CONST_I32) && ~val == (int32_t)~val) {
|
||||
return 1;
|
||||
}
|
||||
/*
|
||||
* This will be used in combination with TCG_CT_CONST_S32,
|
||||
* so "normal" TESTQ is already matched. Also accept:
|
||||
* TESTQ -> TESTL (uint32_t)
|
||||
* TESTQ -> BT (is_power_of_2)
|
||||
*/
|
||||
if ((ct & TCG_CT_CONST_TST)
|
||||
&& is_tst_cond(cond)
|
||||
&& (val == (uint32_t)val || is_power_of_2(val))) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if ((ct & TCG_CT_CONST_WSZ) && val == (type == TCG_TYPE_I32 ? 32 : 64)) {
|
||||
return 1;
|
||||
@@ -395,6 +409,7 @@ static bool tcg_target_const_match(int64_t val, TCGType type, int ct, int vece)
|
||||
#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_TESTB (0x84)
|
||||
#define OPC_TESTL (0x85)
|
||||
#define OPC_TZCNT (0xbc | P_EXT | P_SIMDF3)
|
||||
#define OPC_UD2 (0x0b | P_EXT)
|
||||
@@ -441,6 +456,12 @@ static bool tcg_target_const_match(int64_t val, TCGType type, int ct, int vece)
|
||||
#define OPC_GRP3_Ev (0xf7)
|
||||
#define OPC_GRP5 (0xff)
|
||||
#define OPC_GRP14 (0x73 | P_EXT | P_DATA16)
|
||||
#define OPC_GRPBT (0xba | P_EXT)
|
||||
|
||||
#define OPC_GRPBT_BT 4
|
||||
#define OPC_GRPBT_BTS 5
|
||||
#define OPC_GRPBT_BTR 6
|
||||
#define OPC_GRPBT_BTC 7
|
||||
|
||||
/* Group 1 opcode extensions for 0x80-0x83.
|
||||
These are also used as modifiers for OPC_ARITH. */
|
||||
@@ -505,6 +526,8 @@ static const uint8_t tcg_cond_to_jcc[] = {
|
||||
[TCG_COND_GEU] = JCC_JAE,
|
||||
[TCG_COND_LEU] = JCC_JBE,
|
||||
[TCG_COND_GTU] = JCC_JA,
|
||||
[TCG_COND_TSTEQ] = JCC_JE,
|
||||
[TCG_COND_TSTNE] = JCC_JNE,
|
||||
};
|
||||
|
||||
#if TCG_TARGET_REG_BITS == 64
|
||||
@@ -1448,27 +1471,101 @@ static void tcg_out_jxx(TCGContext *s, int opc, TCGLabel *l, bool small)
|
||||
}
|
||||
}
|
||||
|
||||
static void tcg_out_cmp(TCGContext *s, TCGArg arg1, TCGArg arg2,
|
||||
int const_arg2, int rexw)
|
||||
static int tcg_out_cmp(TCGContext *s, TCGCond cond, TCGArg arg1,
|
||||
TCGArg arg2, int const_arg2, int rexw)
|
||||
{
|
||||
if (const_arg2) {
|
||||
if (arg2 == 0) {
|
||||
/* test r, r */
|
||||
int jz, js;
|
||||
|
||||
if (!is_tst_cond(cond)) {
|
||||
if (!const_arg2) {
|
||||
tgen_arithr(s, ARITH_CMP + rexw, arg1, arg2);
|
||||
} else if (arg2 == 0) {
|
||||
tcg_out_modrm(s, OPC_TESTL + rexw, arg1, arg1);
|
||||
} else {
|
||||
tcg_debug_assert(!rexw || arg2 == (int32_t)arg2);
|
||||
tgen_arithi(s, ARITH_CMP + rexw, arg1, arg2, 0);
|
||||
}
|
||||
} else {
|
||||
tgen_arithr(s, ARITH_CMP + rexw, arg1, arg2);
|
||||
return tcg_cond_to_jcc[cond];
|
||||
}
|
||||
|
||||
jz = tcg_cond_to_jcc[cond];
|
||||
js = (cond == TCG_COND_TSTNE ? JCC_JS : JCC_JNS);
|
||||
|
||||
if (!const_arg2) {
|
||||
tcg_out_modrm(s, OPC_TESTL + rexw, arg1, arg2);
|
||||
return jz;
|
||||
}
|
||||
|
||||
if (arg2 <= 0xff && (TCG_TARGET_REG_BITS == 64 || arg1 < 4)) {
|
||||
if (arg2 == 0x80) {
|
||||
tcg_out_modrm(s, OPC_TESTB | P_REXB_R, arg1, arg1);
|
||||
return js;
|
||||
}
|
||||
if (arg2 == 0xff) {
|
||||
tcg_out_modrm(s, OPC_TESTB | P_REXB_R, arg1, arg1);
|
||||
return jz;
|
||||
}
|
||||
tcg_out_modrm(s, OPC_GRP3_Eb | P_REXB_RM, EXT3_TESTi, arg1);
|
||||
tcg_out8(s, arg2);
|
||||
return jz;
|
||||
}
|
||||
|
||||
if ((arg2 & ~0xff00) == 0 && arg1 < 4) {
|
||||
if (arg2 == 0x8000) {
|
||||
tcg_out_modrm(s, OPC_TESTB, arg1 + 4, arg1 + 4);
|
||||
return js;
|
||||
}
|
||||
if (arg2 == 0xff00) {
|
||||
tcg_out_modrm(s, OPC_TESTB, arg1 + 4, arg1 + 4);
|
||||
return jz;
|
||||
}
|
||||
tcg_out_modrm(s, OPC_GRP3_Eb, EXT3_TESTi, arg1 + 4);
|
||||
tcg_out8(s, arg2 >> 8);
|
||||
return jz;
|
||||
}
|
||||
|
||||
if (arg2 == 0xffff) {
|
||||
tcg_out_modrm(s, OPC_TESTL | P_DATA16, arg1, arg1);
|
||||
return jz;
|
||||
}
|
||||
if (arg2 == 0xffffffffu) {
|
||||
tcg_out_modrm(s, OPC_TESTL, arg1, arg1);
|
||||
return jz;
|
||||
}
|
||||
|
||||
if (is_power_of_2(rexw ? arg2 : (uint32_t)arg2)) {
|
||||
int jc = (cond == TCG_COND_TSTNE ? JCC_JB : JCC_JAE);
|
||||
int sh = ctz64(arg2);
|
||||
|
||||
rexw = (sh & 32 ? P_REXW : 0);
|
||||
if ((sh & 31) == 31) {
|
||||
tcg_out_modrm(s, OPC_TESTL | rexw, arg1, arg1);
|
||||
return js;
|
||||
} else {
|
||||
tcg_out_modrm(s, OPC_GRPBT | rexw, OPC_GRPBT_BT, arg1);
|
||||
tcg_out8(s, sh);
|
||||
return jc;
|
||||
}
|
||||
}
|
||||
|
||||
if (rexw) {
|
||||
if (arg2 == (uint32_t)arg2) {
|
||||
rexw = 0;
|
||||
} else {
|
||||
tcg_debug_assert(arg2 == (int32_t)arg2);
|
||||
}
|
||||
}
|
||||
tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_TESTi, arg1);
|
||||
tcg_out32(s, arg2);
|
||||
return jz;
|
||||
}
|
||||
|
||||
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, rexw);
|
||||
tcg_out_jxx(s, tcg_cond_to_jcc[cond], label, small);
|
||||
int jcc = tcg_out_cmp(s, cond, arg1, arg2, const_arg2, rexw);
|
||||
tcg_out_jxx(s, jcc, label, small);
|
||||
}
|
||||
|
||||
#if TCG_TARGET_REG_BITS == 32
|
||||
@@ -1477,18 +1574,21 @@ static void tcg_out_brcond2(TCGContext *s, const TCGArg *args,
|
||||
{
|
||||
TCGLabel *label_next = gen_new_label();
|
||||
TCGLabel *label_this = arg_label(args[5]);
|
||||
TCGCond cond = args[4];
|
||||
|
||||
switch(args[4]) {
|
||||
switch (cond) {
|
||||
case TCG_COND_EQ:
|
||||
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],
|
||||
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);
|
||||
break;
|
||||
case TCG_COND_NE:
|
||||
tcg_out_brcond(s, 0, TCG_COND_NE, args[0], args[2], const_args[2],
|
||||
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, TCG_COND_NE, args[1], args[3], const_args[3],
|
||||
tcg_out_brcond(s, 0, cond, args[1], args[3], const_args[3],
|
||||
label_this, small);
|
||||
break;
|
||||
case TCG_COND_LT:
|
||||
@@ -1560,6 +1660,7 @@ static void tcg_out_setcond(TCGContext *s, int rexw, TCGCond cond,
|
||||
{
|
||||
bool inv = false;
|
||||
bool cleared;
|
||||
int jcc;
|
||||
|
||||
switch (cond) {
|
||||
case TCG_COND_NE:
|
||||
@@ -1596,7 +1697,7 @@ static void tcg_out_setcond(TCGContext *s, int rexw, TCGCond cond,
|
||||
* 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);
|
||||
tcg_out_cmp(s, TCG_COND_LTU, arg1, arg2, const_arg2, rexw);
|
||||
|
||||
/* X - X - C = -C = (C ? -1 : 0) */
|
||||
tgen_arithr(s, ARITH_SBB + (neg ? rexw : 0), dest, dest);
|
||||
@@ -1643,8 +1744,8 @@ static void tcg_out_setcond(TCGContext *s, int rexw, TCGCond cond,
|
||||
cleared = true;
|
||||
}
|
||||
|
||||
tcg_out_cmp(s, arg1, arg2, const_arg2, rexw);
|
||||
tcg_out_modrm(s, OPC_SETCC | tcg_cond_to_jcc[cond], 0, dest);
|
||||
jcc = tcg_out_cmp(s, cond, arg1, arg2, const_arg2, rexw);
|
||||
tcg_out_modrm(s, OPC_SETCC | jcc, 0, dest);
|
||||
|
||||
if (!cleared) {
|
||||
tcg_out_ext8u(s, dest, dest);
|
||||
@@ -1698,14 +1799,14 @@ static void tcg_out_setcond2(TCGContext *s, const TCGArg *args,
|
||||
}
|
||||
#endif
|
||||
|
||||
static void tcg_out_cmov(TCGContext *s, TCGCond cond, int rexw,
|
||||
static void tcg_out_cmov(TCGContext *s, int jcc, int rexw,
|
||||
TCGReg dest, TCGReg v1)
|
||||
{
|
||||
if (have_cmov) {
|
||||
tcg_out_modrm(s, OPC_CMOVCC | tcg_cond_to_jcc[cond] | rexw, dest, v1);
|
||||
tcg_out_modrm(s, OPC_CMOVCC | jcc | rexw, dest, v1);
|
||||
} else {
|
||||
TCGLabel *over = gen_new_label();
|
||||
tcg_out_jxx(s, tcg_cond_to_jcc[tcg_invert_cond(cond)], over, 1);
|
||||
tcg_out_jxx(s, jcc ^ 1, over, 1);
|
||||
tcg_out_mov(s, TCG_TYPE_I32, dest, v1);
|
||||
tcg_out_label(s, over);
|
||||
}
|
||||
@@ -1715,8 +1816,8 @@ 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, rexw);
|
||||
tcg_out_cmov(s, cond, rexw, dest, v1);
|
||||
int jcc = tcg_out_cmp(s, cond, c1, c2, const_c2, rexw);
|
||||
tcg_out_cmov(s, jcc, rexw, dest, v1);
|
||||
}
|
||||
|
||||
static void tcg_out_ctz(TCGContext *s, int rexw, TCGReg dest, TCGReg arg1,
|
||||
@@ -1728,12 +1829,12 @@ static void tcg_out_ctz(TCGContext *s, int rexw, TCGReg dest, TCGReg arg1,
|
||||
tcg_debug_assert(arg2 == (rexw ? 64 : 32));
|
||||
} else {
|
||||
tcg_debug_assert(dest != arg2);
|
||||
tcg_out_cmov(s, TCG_COND_LTU, rexw, 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, TCG_COND_EQ, rexw, dest, arg2);
|
||||
tcg_out_cmov(s, JCC_JE, rexw, dest, arg2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1746,7 +1847,7 @@ static void tcg_out_clz(TCGContext *s, int rexw, TCGReg dest, TCGReg arg1,
|
||||
tcg_debug_assert(arg2 == (rexw ? 64 : 32));
|
||||
} else {
|
||||
tcg_debug_assert(dest != arg2);
|
||||
tcg_out_cmov(s, TCG_COND_LTU, rexw, dest, arg2);
|
||||
tcg_out_cmov(s, JCC_JB, rexw, dest, arg2);
|
||||
}
|
||||
} else {
|
||||
tcg_debug_assert(!const_a2);
|
||||
@@ -1758,8 +1859,8 @@ static void tcg_out_clz(TCGContext *s, int rexw, TCGReg dest, TCGReg 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. */
|
||||
tcg_out_cmp(s, arg1, 0, 1, rexw);
|
||||
tcg_out_cmov(s, TCG_COND_EQ, rexw, dest, arg2);
|
||||
int jcc = tcg_out_cmp(s, TCG_COND_EQ, arg1, 0, 1, rexw);
|
||||
tcg_out_cmov(s, jcc, rexw, dest, arg2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1824,23 +1925,6 @@ static void tcg_out_nopn(TCGContext *s, int n)
|
||||
tcg_out8(s, 0x90);
|
||||
}
|
||||
|
||||
/* Test register R vs immediate bits I, setting Z flag for EQ/NE. */
|
||||
static void __attribute__((unused))
|
||||
tcg_out_testi(TCGContext *s, TCGReg r, uint32_t i)
|
||||
{
|
||||
/*
|
||||
* This is used for testing alignment, so we can usually use testb.
|
||||
* For i686, we have to use testl for %esi/%edi.
|
||||
*/
|
||||
if (i <= 0xff && (TCG_TARGET_REG_BITS == 64 || r < 4)) {
|
||||
tcg_out_modrm(s, OPC_GRP3_Eb | P_REXB_RM, EXT3_TESTi, r);
|
||||
tcg_out8(s, i);
|
||||
} else {
|
||||
tcg_out_modrm(s, OPC_GRP3_Ev, EXT3_TESTi, r);
|
||||
tcg_out32(s, i);
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
TCGReg base;
|
||||
int index;
|
||||
@@ -2101,16 +2185,17 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h,
|
||||
tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_L0, TCG_REG_L0,
|
||||
offsetof(CPUTLBEntry, addend));
|
||||
} else if (a_mask) {
|
||||
ldst = new_ldst_label(s);
|
||||
int jcc;
|
||||
|
||||
ldst = new_ldst_label(s);
|
||||
ldst->is_ld = is_ld;
|
||||
ldst->oi = oi;
|
||||
ldst->addrlo_reg = addrlo;
|
||||
ldst->addrhi_reg = addrhi;
|
||||
|
||||
tcg_out_testi(s, addrlo, a_mask);
|
||||
/* jne slow_path */
|
||||
tcg_out_opc(s, OPC_JCC_long + JCC_JNE, 0, 0, 0);
|
||||
jcc = tcg_out_cmp(s, TCG_COND_TSTNE, addrlo, a_mask, true, false);
|
||||
tcg_out_opc(s, OPC_JCC_long + jcc, 0, 0, 0);
|
||||
ldst->label_ptr[0] = s->code_ptr;
|
||||
s->code_ptr += 4;
|
||||
}
|
||||
@@ -2256,9 +2341,10 @@ static void tcg_out_qemu_ld_direct(TCGContext *s, TCGReg datalo, TCGReg datahi,
|
||||
} else {
|
||||
TCGLabel *l1 = gen_new_label();
|
||||
TCGLabel *l2 = gen_new_label();
|
||||
int jcc;
|
||||
|
||||
tcg_out_testi(s, h.base, 15);
|
||||
tcg_out_jxx(s, JCC_JNE, l1, true);
|
||||
jcc = tcg_out_cmp(s, TCG_COND_TSTNE, h.base, 15, true, false);
|
||||
tcg_out_jxx(s, jcc, l1, true);
|
||||
|
||||
tcg_out_vex_modrm_sib_offset(s, OPC_MOVDQA_VxWx + h.seg,
|
||||
TCG_TMP_VEC, 0,
|
||||
@@ -2384,9 +2470,10 @@ static void tcg_out_qemu_st_direct(TCGContext *s, TCGReg datalo, TCGReg datahi,
|
||||
} else {
|
||||
TCGLabel *l1 = gen_new_label();
|
||||
TCGLabel *l2 = gen_new_label();
|
||||
int jcc;
|
||||
|
||||
tcg_out_testi(s, h.base, 15);
|
||||
tcg_out_jxx(s, JCC_JNE, l1, true);
|
||||
jcc = tcg_out_cmp(s, TCG_COND_TSTNE, h.base, 15, true, false);
|
||||
tcg_out_jxx(s, jcc, l1, true);
|
||||
|
||||
tcg_out_vex_modrm_sib_offset(s, OPC_MOVDQA_WxVx + h.seg,
|
||||
TCG_TMP_VEC, 0,
|
||||
@@ -3373,7 +3460,7 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op)
|
||||
|
||||
case INDEX_op_brcond_i32:
|
||||
case INDEX_op_brcond_i64:
|
||||
return C_O0_I2(r, re);
|
||||
return C_O0_I2(r, reT);
|
||||
|
||||
case INDEX_op_bswap16_i32:
|
||||
case INDEX_op_bswap16_i64:
|
||||
@@ -3421,11 +3508,11 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op)
|
||||
case INDEX_op_setcond_i64:
|
||||
case INDEX_op_negsetcond_i32:
|
||||
case INDEX_op_negsetcond_i64:
|
||||
return C_O1_I2(q, r, re);
|
||||
return C_O1_I2(q, r, reT);
|
||||
|
||||
case INDEX_op_movcond_i32:
|
||||
case INDEX_op_movcond_i64:
|
||||
return C_O1_I4(r, r, re, r, 0);
|
||||
return C_O1_I4(r, r, reT, r, 0);
|
||||
|
||||
case INDEX_op_div2_i32:
|
||||
case INDEX_op_div2_i64:
|
||||
|
||||
@@ -198,6 +198,8 @@ typedef enum {
|
||||
#define TCG_TARGET_HAS_qemu_ldst_i128 \
|
||||
(TCG_TARGET_REG_BITS == 64 && (cpuinfo & CPUINFO_ATOMIC_VMOVDQA))
|
||||
|
||||
#define TCG_TARGET_HAS_tst 1
|
||||
|
||||
/* We do not support older SSE systems, only beginning with AVX1. */
|
||||
#define TCG_TARGET_HAS_v64 have_avx1
|
||||
#define TCG_TARGET_HAS_v128 have_avx1
|
||||
|
||||
@@ -183,7 +183,8 @@ static inline tcg_target_long sextreg(tcg_target_long val, int pos, int len)
|
||||
}
|
||||
|
||||
/* test if a constant matches the constraint */
|
||||
static bool tcg_target_const_match(int64_t val, TCGType type, int ct, int vece)
|
||||
static bool tcg_target_const_match(int64_t val, int ct,
|
||||
TCGType type, TCGCond cond, int vece)
|
||||
{
|
||||
if (ct & TCG_CT_CONST) {
|
||||
return true;
|
||||
|
||||
@@ -169,6 +169,8 @@ typedef enum {
|
||||
|
||||
#define TCG_TARGET_HAS_qemu_ldst_i128 (cpuinfo & CPUINFO_LSX)
|
||||
|
||||
#define TCG_TARGET_HAS_tst 0
|
||||
|
||||
#define TCG_TARGET_HAS_v64 0
|
||||
#define TCG_TARGET_HAS_v128 (cpuinfo & CPUINFO_LSX)
|
||||
#define TCG_TARGET_HAS_v256 0
|
||||
|
||||
@@ -188,7 +188,8 @@ static bool is_p2m1(tcg_target_long val)
|
||||
}
|
||||
|
||||
/* test if a constant matches the constraint */
|
||||
static bool tcg_target_const_match(int64_t val, TCGType type, int ct, int vece)
|
||||
static bool tcg_target_const_match(int64_t val, int ct,
|
||||
TCGType type, TCGCond cond, int vece)
|
||||
{
|
||||
if (ct & TCG_CT_CONST) {
|
||||
return 1;
|
||||
|
||||
@@ -194,6 +194,8 @@ extern bool use_mips32r2_instructions;
|
||||
|
||||
#define TCG_TARGET_HAS_qemu_ldst_i128 0
|
||||
|
||||
#define TCG_TARGET_HAS_tst 0
|
||||
|
||||
#define TCG_TARGET_DEFAULT_MO 0
|
||||
#define TCG_TARGET_NEED_LDST_LABELS
|
||||
#define TCG_TARGET_NEED_POOL_LABELS
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user