target/i386: move 3DNow to the new decoder

This adds another kind of weirdness when you thought you had seen it all:
an opcode byte that comes _after_ the address, not before.  It's not
worth adding a new X86_SPECIAL_* constant for it, but it's actually
not unlike VCMP; so, forgive me for exploiting the similarity and just
deciding to dispatch to the right gen_helper_* call in a single code
generation function.

In fact, the old decoder had a bug where s->rip_offset should have
been set to 1 for 3DNow! instructions, and it's fixed now.

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Paolo Bonzini 2022-09-05 23:27:53 +02:00
parent 0339ddfa75
commit 71a0891d61
6 changed files with 74 additions and 76 deletions

View File

@ -212,7 +212,6 @@ DEF_HELPER_2(ldmxcsr, void, env, i32)
DEF_HELPER_1(update_mxcsr, void, env)
DEF_HELPER_1(enter_mmx, void, env)
DEF_HELPER_1(emms, void, env)
DEF_HELPER_3(movq, void, env, ptr, ptr)
#define SHIFT 0
#include "ops_sse_header.h"

View File

@ -779,6 +779,14 @@ static void decode_0FE6(DisasContext *s, CPUX86State *env, X86OpEntry *entry, ui
}
static const X86OpEntry opcodes_0F[256] = {
[0x0E] = X86_OP_ENTRY0(EMMS, cpuid(3DNOW)), /* femms */
/*
* 3DNow!'s opcode byte comes *after* modrm and displacements, making it
* more like an Ib operand. Dispatch to the right helper in a single gen_*
* function.
*/
[0x0F] = X86_OP_ENTRY3(3dnow, P,q, Q,q, I,b, cpuid(3DNOW)),
[0x10] = X86_OP_GROUP0(0F10),
[0x11] = X86_OP_GROUP0(0F11),
[0x12] = X86_OP_GROUP0(0F12),
@ -1364,6 +1372,8 @@ static bool has_cpuid_feature(DisasContext *s, X86CPUIDFeature cpuid)
case X86_FEAT_AVX:
return (s->cpuid_ext_features & CPUID_EXT_AVX);
case X86_FEAT_3DNOW:
return (s->cpuid_ext2_features & CPUID_EXT2_3DNOW);
case X86_FEAT_SSE4A:
return (s->cpuid_ext3_features & CPUID_EXT3_SSE4A);

View File

@ -96,6 +96,7 @@ typedef enum X86OpSize {
typedef enum X86CPUIDFeature {
X86_FEAT_None,
X86_FEAT_3DNOW,
X86_FEAT_ADX,
X86_FEAT_AES,
X86_FEAT_AVX,

View File

@ -19,6 +19,7 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
typedef void (*SSEFunc_0_epp)(TCGv_ptr env, TCGv_ptr reg_a, TCGv_ptr reg_b);
typedef void (*SSEFunc_0_epppti)(TCGv_ptr env, TCGv_ptr reg_a, TCGv_ptr reg_b,
TCGv_ptr reg_c, TCGv a0, TCGv_i32 scale);
@ -326,6 +327,66 @@ static void gen_store_sse(DisasContext *s, X86DecodedInsn *decode, int src_ofs)
}
}
static void gen_helper_pavgusb(TCGv_ptr env, TCGv_ptr reg_a, TCGv_ptr reg_b)
{
gen_helper_pavgb_mmx(env, reg_a, reg_a, reg_b);
}
#define FN_3DNOW_MOVE ((SSEFunc_0_epp) (uintptr_t) 1)
static const SSEFunc_0_epp fns_3dnow[] = {
[0x0c] = gen_helper_pi2fw,
[0x0d] = gen_helper_pi2fd,
[0x1c] = gen_helper_pf2iw,
[0x1d] = gen_helper_pf2id,
[0x8a] = gen_helper_pfnacc,
[0x8e] = gen_helper_pfpnacc,
[0x90] = gen_helper_pfcmpge,
[0x94] = gen_helper_pfmin,
[0x96] = gen_helper_pfrcp,
[0x97] = gen_helper_pfrsqrt,
[0x9a] = gen_helper_pfsub,
[0x9e] = gen_helper_pfadd,
[0xa0] = gen_helper_pfcmpgt,
[0xa4] = gen_helper_pfmax,
[0xa6] = FN_3DNOW_MOVE, /* PFRCPIT1; no need to actually increase precision */
[0xa7] = FN_3DNOW_MOVE, /* PFRSQIT1 */
[0xb6] = FN_3DNOW_MOVE, /* PFRCPIT2 */
[0xaa] = gen_helper_pfsubr,
[0xae] = gen_helper_pfacc,
[0xb0] = gen_helper_pfcmpeq,
[0xb4] = gen_helper_pfmul,
[0xb7] = gen_helper_pmulhrw_mmx,
[0xbb] = gen_helper_pswapd,
[0xbf] = gen_helper_pavgusb,
};
static void gen_3dnow(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode)
{
uint8_t b = decode->immediate;
SSEFunc_0_epp fn = b < ARRAY_SIZE(fns_3dnow) ? fns_3dnow[b] : NULL;
if (!fn) {
gen_illegal_opcode(s);
return;
}
if (s->flags & HF_TS_MASK) {
gen_NM_exception(s);
return;
}
if (s->flags & HF_EM_MASK) {
gen_illegal_opcode(s);
return;
}
gen_helper_enter_mmx(cpu_env);
if (fn == FN_3DNOW_MOVE) {
tcg_gen_ld_i64(s->tmp1_i64, cpu_env, decode->op[1].offset);
tcg_gen_st_i64(s->tmp1_i64, cpu_env, decode->op[0].offset);
} else {
fn(cpu_env, OP_PTR0, OP_PTR1);
}
}
/*
* 00 = v*ps Vps, Hps, Wpd
* 66 = v*pd Vpd, Hpd, Wps

View File

@ -3126,12 +3126,6 @@ void helper_emms(CPUX86State *env)
*(uint32_t *)(env->fptags + 4) = 0x01010101;
}
/* XXX: suppress */
void helper_movq(CPUX86State *env, void *d, void *s)
{
*(uint64_t *)d = *(uint64_t *)s;
}
#define SHIFT 0
#include "ops_sse.h"

View File

@ -3011,7 +3011,6 @@ static bool first = true; static unsigned long limit;
#define SSE_OPF_CMP (1 << 1) /* does not write for first operand */
#define SSE_OPF_BLENDV (1 << 2) /* blendv* instruction */
#define SSE_OPF_SPECIAL (1 << 3) /* magic */
#define SSE_OPF_3DNOW (1 << 4) /* 3DNow! instruction */
#define SSE_OPF_MMX (1 << 5) /* MMX/integer/AVX2 instruction */
#define SSE_OPF_SCALAR (1 << 6) /* Has SSE scalar variants */
#define SSE_OPF_SHUF (1 << 9) /* pshufx/shufpx */
@ -3045,13 +3044,9 @@ struct SSEOpHelper_table1 {
SSEFuncs fn[4];
};
#define SSE_3DNOW { SSE_OPF_3DNOW }
#define SSE_SPECIAL { SSE_OPF_SPECIAL }
static const struct SSEOpHelper_table1 sse_op_table1[256] = {
/* 3DNow! extensions */
[0x0e] = SSE_SPECIAL, /* femms */
[0x0f] = SSE_3DNOW, /* pf... (sse_op_table5) */
/* pure SSE operations */
[0x10] = SSE_SPECIAL, /* movups, movupd, movss, movsd */
[0x11] = SSE_SPECIAL, /* movups, movupd, movss, movsd */
@ -3260,38 +3255,6 @@ static const SSEFunc_0_eppp sse_op_table4[8][4] = {
};
#undef SSE_CMP
static void gen_helper_pavgusb(TCGv_ptr env, TCGv_ptr reg_a, TCGv_ptr reg_b)
{
gen_helper_pavgb_mmx(env, reg_a, reg_a, reg_b);
}
static const SSEFunc_0_epp sse_op_table5[256] = {
[0x0c] = gen_helper_pi2fw,
[0x0d] = gen_helper_pi2fd,
[0x1c] = gen_helper_pf2iw,
[0x1d] = gen_helper_pf2id,
[0x8a] = gen_helper_pfnacc,
[0x8e] = gen_helper_pfpnacc,
[0x90] = gen_helper_pfcmpge,
[0x94] = gen_helper_pfmin,
[0x96] = gen_helper_pfrcp,
[0x97] = gen_helper_pfrsqrt,
[0x9a] = gen_helper_pfsub,
[0x9e] = gen_helper_pfadd,
[0xa0] = gen_helper_pfcmpgt,
[0xa4] = gen_helper_pfmax,
[0xa6] = gen_helper_movq, /* pfrcpit1; no need to actually increase precision */
[0xa7] = gen_helper_movq, /* pfrsqit1 */
[0xaa] = gen_helper_pfsubr,
[0xae] = gen_helper_pfacc,
[0xb0] = gen_helper_pfcmpeq,
[0xb4] = gen_helper_pfmul,
[0xb6] = gen_helper_movq, /* pfrcpit2 */
[0xb7] = gen_helper_pmulhrw_mmx,
[0xbb] = gen_helper_pswapd,
[0xbf] = gen_helper_pavgusb,
};
struct SSEOpHelper_table6 {
SSEFuncs fn[2];
uint32_t ext_mask;
@ -3443,7 +3406,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b)
b1 = 0;
sse_op_flags = sse_op_table1[b].flags;
sse_op_fn = sse_op_table1[b].fn[b1];
if ((sse_op_flags & (SSE_OPF_SPECIAL | SSE_OPF_3DNOW)) == 0
if ((sse_op_flags & SSE_OPF_SPECIAL) == 0
&& !sse_op_fn.op1) {
goto unknown_op;
}
@ -3457,11 +3420,6 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b)
is_xmm = 1;
}
}
if (sse_op_flags & SSE_OPF_3DNOW) {
if (!(s->cpuid_ext2_features & CPUID_EXT2_3DNOW)) {
goto illegal_op;
}
}
/* simple MMX/SSE operation */
if (s->flags & HF_TS_MASK) {
gen_exception(s, EXCP07_PREX);
@ -3477,15 +3435,6 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b)
&& (b != 0x38 && b != 0x3a)) {
goto unknown_op;
}
if (b == 0x0e) {
if (!(s->cpuid_ext2_features & CPUID_EXT2_3DNOW)) {
/* If we were fully decoding this we might use illegal_op. */
goto unknown_op;
}
/* femms */
gen_helper_emms(cpu_env);
return;
}
if (b == 0x77) {
/* emms */
gen_helper_emms(cpu_env);
@ -4643,18 +4592,6 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b)
rm = (modrm & 7);
op2_offset = offsetof(CPUX86State,fpregs[rm].mmx);
}
if (sse_op_flags & SSE_OPF_3DNOW) {
/* 3DNow! data insns */
val = x86_ldub_code(env, s);
SSEFunc_0_epp op_3dnow = sse_op_table5[val];
if (!op_3dnow) {
goto unknown_op;
}
tcg_gen_addi_ptr(s->ptr0, cpu_env, op1_offset);
tcg_gen_addi_ptr(s->ptr1, cpu_env, op2_offset);
op_3dnow(cpu_env, s->ptr0, s->ptr1);
return;
}
}
@ -4783,7 +4720,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
#endif
if (use_new &&
(b == 0x138 || b == 0x13a ||
(b >= 0x110 && b <= 0x117) ||
(b >= 0x10e && b <= 0x117) ||
(b >= 0x128 && b <= 0x12f) ||
(b >= 0x150 && b <= 0x17f) ||
b == 0x1c2 || (b >= 0x1c4 && b <= 0x1c6) ||
@ -8512,10 +8449,6 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
set_cc_op(s, CC_OP_POPCNT);
break;
case 0x10e ... 0x10f:
/* 3DNow! instructions, ignore prefixes */
s->prefix &= ~(PREFIX_REPZ | PREFIX_REPNZ | PREFIX_DATA);
/* fall through */
case 0x110 ... 0x117:
case 0x128 ... 0x12f:
case 0x138 ... 0x13a: