When testing the sign bit or equality to zero of a partial register, it is useful to use a single TSTEQ or TSTNE operation. It can also be used to test the parity flag, using bit 0 of the population count.
Do not do this for target_ulong-sized values however; the optimizer would produce a comparison against zero anyway, and it avoids shifts by 64 which are undefined behavior. Reviewed-by: Richard Henderson <richard.hender...@linaro.org> Signed-off-by: Paolo Bonzini <pbonz...@redhat.com> --- target/i386/tcg/translate.c | 28 ++++++++++++++++++++-------- target/i386/tcg/emit.c.inc | 5 ++--- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index 051ffb5e1fd..4735f084d40 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -928,11 +928,21 @@ typedef struct CCPrepare { bool no_setcond; } CCPrepare; +static CCPrepare gen_prepare_sign_nz(TCGv src, MemOp size) +{ + if (size == MO_TL) { + return (CCPrepare) { .cond = TCG_COND_LT, .reg = src, .mask = -1 }; + } else { + return (CCPrepare) { .cond = TCG_COND_TSTNE, .reg = src, .mask = -1, + .imm = 1ull << ((8 << size) - 1) }; + } +} + /* compute eflags.C to reg */ static CCPrepare gen_prepare_eflags_c(DisasContext *s, TCGv reg) { TCGv t0, t1; - int size, shift; + MemOp size; switch (s->cc_op) { case CC_OP_SUBB ... CC_OP_SUBQ: @@ -967,9 +977,7 @@ static CCPrepare gen_prepare_eflags_c(DisasContext *s, TCGv reg) case CC_OP_SHLB ... CC_OP_SHLQ: /* (CC_SRC >> (DATA_BITS - 1)) & 1 */ size = s->cc_op - CC_OP_SHLB; - shift = (8 << size) - 1; - return (CCPrepare) { .cond = TCG_COND_NE, .reg = cpu_cc_src, - .mask = (target_ulong)1 << shift }; + return gen_prepare_sign_nz(cpu_cc_src, size); case CC_OP_MULB ... CC_OP_MULQ: return (CCPrepare) { .cond = TCG_COND_NE, @@ -1029,8 +1037,7 @@ static CCPrepare gen_prepare_eflags_s(DisasContext *s, TCGv reg) default: { MemOp size = (s->cc_op - CC_OP_ADDB) & 3; - TCGv t0 = gen_ext_tl(reg, cpu_cc_dst, size, true); - return (CCPrepare) { .cond = TCG_COND_LT, .reg = t0, .mask = -1 }; + return gen_prepare_sign_nz(cpu_cc_dst, size); } } } @@ -1077,8 +1084,13 @@ static CCPrepare gen_prepare_eflags_z(DisasContext *s, TCGv reg) default: { MemOp size = (s->cc_op - CC_OP_ADDB) & 3; - TCGv t0 = gen_ext_tl(reg, cpu_cc_dst, size, false); - return (CCPrepare) { .cond = TCG_COND_EQ, .reg = t0, .mask = -1 }; + if (size == MO_TL) { + return (CCPrepare) { .cond = TCG_COND_EQ, .reg = cpu_cc_dst, + .mask = -1 }; + } else { + return (CCPrepare) { .cond = TCG_COND_TSTEQ, .reg = cpu_cc_dst, + .mask = -1, .imm = (1ull << (8 << size)) - 1 }; + } } } } diff --git a/target/i386/tcg/emit.c.inc b/target/i386/tcg/emit.c.inc index 6bcf88ecd71..0e00f6635dd 100644 --- a/target/i386/tcg/emit.c.inc +++ b/target/i386/tcg/emit.c.inc @@ -1209,7 +1209,7 @@ static void gen_CMPccXADD(DisasContext *s, CPUX86State *env, X86DecodedInsn *dec [JCC_Z] = TCG_COND_EQ, [JCC_BE] = TCG_COND_LEU, [JCC_S] = TCG_COND_LT, /* test sign bit by comparing against 0 */ - [JCC_P] = TCG_COND_EQ, /* even parity - tests low bit of popcount */ + [JCC_P] = TCG_COND_TSTEQ, /* even parity - tests low bit of popcount */ [JCC_L] = TCG_COND_LT, [JCC_LE] = TCG_COND_LE, }; @@ -1260,8 +1260,7 @@ static void gen_CMPccXADD(DisasContext *s, CPUX86State *env, X86DecodedInsn *dec case JCC_P: tcg_gen_ext8u_tl(s->tmp0, s->T0); tcg_gen_ctpop_tl(s->tmp0, s->tmp0); - tcg_gen_andi_tl(s->tmp0, s->tmp0, 1); - cmp_lhs = s->tmp0, cmp_rhs = tcg_constant_tl(0); + cmp_lhs = s->tmp0, cmp_rhs = tcg_constant_tl(1); break; case JCC_S: -- 2.45.0