aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2022-09-05 23:27:53 +0200
committerPaolo Bonzini <pbonzini@redhat.com>2022-10-18 13:58:05 +0200
commit71a0891d611189b651887414f56f8bb10c796d6f (patch)
tree73a12441cf6f06b73777f8084c41f46cd2325f05
parent0339ddfa7562d835cca1dd468c2ad08b84a7abb5 (diff)
downloadqemu-71a0891d611189b651887414f56f8bb10c796d6f.zip
qemu-71a0891d611189b651887414f56f8bb10c796d6f.tar.gz
qemu-71a0891d611189b651887414f56f8bb10c796d6f.tar.bz2
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>
-rw-r--r--target/i386/helper.h1
-rw-r--r--target/i386/tcg/decode-new.c.inc10
-rw-r--r--target/i386/tcg/decode-new.h1
-rw-r--r--target/i386/tcg/emit.c.inc61
-rw-r--r--target/i386/tcg/fpu_helper.c6
-rw-r--r--target/i386/tcg/translate.c71
6 files changed, 74 insertions, 76 deletions
diff --git a/target/i386/helper.h b/target/i386/helper.h
index a2c2c08..88143b2 100644
--- a/target/i386/helper.h
+++ b/target/i386/helper.h
@@ -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"
diff --git a/target/i386/tcg/decode-new.c.inc b/target/i386/tcg/decode-new.c.inc
index 5f4268b..9e43de6 100644
--- a/target/i386/tcg/decode-new.c.inc
+++ b/target/i386/tcg/decode-new.c.inc
@@ -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);
diff --git a/target/i386/tcg/decode-new.h b/target/i386/tcg/decode-new.h
index 2f0b0e4..f159c26 100644
--- a/target/i386/tcg/decode-new.h
+++ b/target/i386/tcg/decode-new.h
@@ -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,
diff --git a/target/i386/tcg/emit.c.inc b/target/i386/tcg/emit.c.inc
index d7c2290..63af60b 100644
--- a/target/i386/tcg/emit.c.inc
+++ b/target/i386/tcg/emit.c.inc
@@ -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
diff --git a/target/i386/tcg/fpu_helper.c b/target/i386/tcg/fpu_helper.c
index 7670739..a6a90a1 100644
--- a/target/i386/tcg/fpu_helper.c
+++ b/target/i386/tcg/fpu_helper.c
@@ -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"
diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index cf895e4..e9af467 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -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: