mirror of https://github.com/xemu-project/xemu.git
target/i386: use TSTEQ/TSTNE to test low bits
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.henderson@linaro.org> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
b776569a53
commit
15957eb9ef
|
@ -1209,7 +1209,7 @@ static void gen_CMPccXADD(DisasContext *s, CPUX86State *env, X86DecodedInsn *dec
|
||||||
[JCC_Z] = TCG_COND_EQ,
|
[JCC_Z] = TCG_COND_EQ,
|
||||||
[JCC_BE] = TCG_COND_LEU,
|
[JCC_BE] = TCG_COND_LEU,
|
||||||
[JCC_S] = TCG_COND_LT, /* test sign bit by comparing against 0 */
|
[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_L] = TCG_COND_LT,
|
||||||
[JCC_LE] = TCG_COND_LE,
|
[JCC_LE] = TCG_COND_LE,
|
||||||
};
|
};
|
||||||
|
@ -1260,8 +1260,7 @@ static void gen_CMPccXADD(DisasContext *s, CPUX86State *env, X86DecodedInsn *dec
|
||||||
case JCC_P:
|
case JCC_P:
|
||||||
tcg_gen_ext8u_tl(s->tmp0, s->T0);
|
tcg_gen_ext8u_tl(s->tmp0, s->T0);
|
||||||
tcg_gen_ctpop_tl(s->tmp0, s->tmp0);
|
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(1);
|
||||||
cmp_lhs = s->tmp0, cmp_rhs = tcg_constant_tl(0);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case JCC_S:
|
case JCC_S:
|
||||||
|
|
|
@ -928,11 +928,21 @@ typedef struct CCPrepare {
|
||||||
bool no_setcond;
|
bool no_setcond;
|
||||||
} CCPrepare;
|
} 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 */
|
/* compute eflags.C to reg */
|
||||||
static CCPrepare gen_prepare_eflags_c(DisasContext *s, TCGv reg)
|
static CCPrepare gen_prepare_eflags_c(DisasContext *s, TCGv reg)
|
||||||
{
|
{
|
||||||
TCGv t0, t1;
|
TCGv t0, t1;
|
||||||
int size, shift;
|
MemOp size;
|
||||||
|
|
||||||
switch (s->cc_op) {
|
switch (s->cc_op) {
|
||||||
case CC_OP_SUBB ... CC_OP_SUBQ:
|
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:
|
case CC_OP_SHLB ... CC_OP_SHLQ:
|
||||||
/* (CC_SRC >> (DATA_BITS - 1)) & 1 */
|
/* (CC_SRC >> (DATA_BITS - 1)) & 1 */
|
||||||
size = s->cc_op - CC_OP_SHLB;
|
size = s->cc_op - CC_OP_SHLB;
|
||||||
shift = (8 << size) - 1;
|
return gen_prepare_sign_nz(cpu_cc_src, size);
|
||||||
return (CCPrepare) { .cond = TCG_COND_NE, .reg = cpu_cc_src,
|
|
||||||
.mask = (target_ulong)1 << shift };
|
|
||||||
|
|
||||||
case CC_OP_MULB ... CC_OP_MULQ:
|
case CC_OP_MULB ... CC_OP_MULQ:
|
||||||
return (CCPrepare) { .cond = TCG_COND_NE,
|
return (CCPrepare) { .cond = TCG_COND_NE,
|
||||||
|
@ -1029,8 +1037,7 @@ static CCPrepare gen_prepare_eflags_s(DisasContext *s, TCGv reg)
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
MemOp size = (s->cc_op - CC_OP_ADDB) & 3;
|
MemOp size = (s->cc_op - CC_OP_ADDB) & 3;
|
||||||
TCGv t0 = gen_ext_tl(reg, cpu_cc_dst, size, true);
|
return gen_prepare_sign_nz(cpu_cc_dst, size);
|
||||||
return (CCPrepare) { .cond = TCG_COND_LT, .reg = t0, .mask = -1 };
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1077,8 +1084,13 @@ static CCPrepare gen_prepare_eflags_z(DisasContext *s, TCGv reg)
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
MemOp size = (s->cc_op - CC_OP_ADDB) & 3;
|
MemOp size = (s->cc_op - CC_OP_ADDB) & 3;
|
||||||
TCGv t0 = gen_ext_tl(reg, cpu_cc_dst, size, false);
|
if (size == MO_TL) {
|
||||||
return (CCPrepare) { .cond = TCG_COND_EQ, .reg = t0, .mask = -1 };
|
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 };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue