target-i386: Use clz and ctz opcodes

Backports commit e5143c90883cd32a432eb793cdcce6bee747834a from qemu
This commit is contained in:
Richard Henderson 2018-03-01 16:14:50 -05:00 committed by Lioncash
parent 9cde8bfc44
commit 22ebc5fcee
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7
3 changed files with 13 additions and 35 deletions

View file

@ -203,14 +203,6 @@ DEF_HELPER_FLAGS_3(xsetbv, TCG_CALL_NO_WG, void, env, i32, i64)
DEF_HELPER_FLAGS_2(rdpkru, TCG_CALL_NO_WG, i64, env, i32)
DEF_HELPER_FLAGS_3(wrpkru, TCG_CALL_NO_WG, void, env, i32, i64)
DEF_HELPER_FLAGS_1(clz_x86, TCG_CALL_NO_RWG_SE, tl, tl)
#ifdef TARGET_I386
#define helper_clz helper_clz_x86
#define gen_helper_clz gen_helper_clz_x86
#endif
DEF_HELPER_FLAGS_1(ctz, TCG_CALL_NO_RWG_SE, tl, tl)
DEF_HELPER_FLAGS_2(pdep, TCG_CALL_NO_RWG_SE, tl, tl, tl)
DEF_HELPER_FLAGS_2(pext, TCG_CALL_NO_RWG_SE, tl, tl, tl)

View file

@ -417,17 +417,6 @@ void helper_idivq_EAX(CPUX86State *env, target_ulong t0)
# define clztl clz64
#endif
/* bit operations */
target_ulong helper_ctz(target_ulong t0)
{
return ctztl(t0);
}
target_ulong helper_clz_x86(target_ulong t0)
{
return clztl(t0);
}
target_ulong helper_pdep(target_ulong src, target_ulong mask)
{
target_ulong dest = 0;

View file

@ -7481,21 +7481,18 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
? s->cpuid_ext3_features & CPUID_EXT3_ABM
: s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_BMI1)) {
int size = 8 << ot;
/* For lzcnt/tzcnt, C bit is defined related to the input. */
tcg_gen_mov_tl(tcg_ctx, cpu_cc_src, cpu_T0);
if (b & 1) {
/* For lzcnt, reduce the target_ulong result by the
number of zeros that we expect to find at the top. */
gen_helper_clz(tcg_ctx, cpu_T0, cpu_T0);
tcg_gen_clzi_tl(tcg_ctx, cpu_T0, cpu_T0, TARGET_LONG_BITS);
tcg_gen_subi_tl(tcg_ctx, cpu_T0, cpu_T0, TARGET_LONG_BITS - size);
} else {
/* For tzcnt, a zero input must return the operand size:
force all bits outside the operand size to 1. */
target_ulong mask = (target_ulong)-2 << (size - 1);
tcg_gen_ori_tl(tcg_ctx, cpu_T0, cpu_T0, mask);
gen_helper_ctz(tcg_ctx, cpu_T0, cpu_T0);
/* For tzcnt, a zero input must return the operand size. */
tcg_gen_ctzi_tl(tcg_ctx, cpu_T0, cpu_T0, size);
}
/* For lzcnt/tzcnt, C and Z bits are defined and are
related to the result. */
/* For lzcnt/tzcnt, Z bit is defined related to the result. */
gen_op_update1_cc(tcg_ctx);
set_cc_op(s, CC_OP_BMILGB + ot);
} else {
@ -7503,20 +7500,20 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
to the input and not the result. */
tcg_gen_mov_tl(tcg_ctx, cpu_cc_dst, cpu_T0);
set_cc_op(s, CC_OP_LOGICB + ot);
/* ??? The manual says that the output is undefined when the
input is zero, but real hardware leaves it unchanged, and
real programs appear to depend on that. Accomplish this
by passing the output as the value to return upon zero. */
if (b & 1) {
/* For bsr, return the bit index of the first 1 bit,
not the count of leading zeros. */
gen_helper_clz(tcg_ctx, cpu_T0, cpu_T0);
tcg_gen_xori_tl(tcg_ctx, cpu_T1, cpu_regs[reg], TARGET_LONG_BITS - 1);
tcg_gen_clz_tl(tcg_ctx, cpu_T0, cpu_T0, cpu_T1);
tcg_gen_xori_tl(tcg_ctx, cpu_T0, cpu_T0, TARGET_LONG_BITS - 1);
} else {
gen_helper_ctz(tcg_ctx, cpu_T0, cpu_T0);
tcg_gen_ctz_tl(tcg_ctx, cpu_T0, cpu_T0, cpu_regs[reg]);
}
/* ??? The manual says that the output is undefined when the
input is zero, but real hardware leaves it unchanged, and
real programs appear to depend on that. */
tcg_gen_movi_tl(tcg_ctx, cpu_tmp0, 0);
tcg_gen_movcond_tl(tcg_ctx, TCG_COND_EQ, cpu_T0, cpu_cc_dst, cpu_tmp0,
cpu_regs[reg], cpu_T0);
}
gen_op_mov_reg_v(tcg_ctx, ot, reg, cpu_T0);
break;