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:
parent
0339ddfa75
commit
71a0891d61
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in New Issue