* [PATCH v5 01/19] x86/CPUID: enable AVX10 leaf
2026-11-11 13:40 [PATCH v5 00/19] x86: support AVX10 Jan Beulich
@ 2026-11-11 13:41 ` Jan Beulich
2026-11-11 13:42 ` [PATCH v5 02/19] x86emul: support SIMD MOVRS Jan Beulich
` (17 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Jan Beulich @ 2026-11-11 13:41 UTC (permalink / raw)
To: xen-devel@lists.xenproject.org
Cc: Andrew Cooper, Teddy Astie, Roger Pau Monné
This requires bumping the number of basic leaves we support. Apart from
this the logic is modeled as closely as possible after that of leaf 7
handling.
Signed-off-by: Jan Beulich <jbeulich@suse.com>
---
The gen-cpuid.py adjustment is merely the minimum needed. It's not
really clear to me whether someone turning off e.g. AVX512BW might then
also validly expect AVX10 to be turned off.
Do we want to synthesize AVX10 in the (max?) policies when all necessary
AVX512* features are available, thus allowing migration from an AVX10
host to a suitable non-AVX10 one?
The prior vsz<N> bits are now defined as reserved-at-1: No idea yet how
to represent this properly.
How a toolstack side equivalent (if any) of the init_dom0_cpuid_policy()
change would look like is entirely unclear to me. How much should we
take from the max policy, and how much should we permit/require the user
to specify (and how would the latter look like)?
While, as per a comment next to the call site of
recalculate_cpuid_policy(), recalculate_*() are supposed to go away when
x86_cpu_policies_are_compatible() is complete, some of the checking done
in recalculate_misc() really wouldn't below there. We'd need another "is
self-consistent" checking function.
---
v4: Drop all traces of AVX10/256. Add max_subleaf check to
x86_cpu_policies_are_compatible(). Add/adjust vsz<N> checks in
recalculate_misc(). In the max policies, synthesize AVX512* when
AVX10 is available.
v3: Re-base.
v2: Add logic to init_dom0_cpuid_policy(). Drop vsz128 field. Re-base.
--- a/xen/arch/x86/cpu-policy.c
+++ b/xen/arch/x86/cpu-policy.c
@@ -211,7 +211,7 @@ static void recalculate_xstate(struct cp
if ( p->feat.mpx )
xstates |= X86_XCR0_BNDREGS | X86_XCR0_BNDCSR;
- if ( p->feat.avx512f )
+ if ( p->feat.avx512f || p->feat.avx10 )
xstates |= X86_XCR0_OPMASK | X86_XCR0_ZMM | X86_XCR0_HI_ZMM;
if ( p->feat.pku )
@@ -272,6 +272,18 @@ static void recalculate_misc(struct cpu_
p->basic.raw[0xc] = EMPTY_LEAF;
+ zero_leaves(p->basic.raw, 0xe, 0x23);
+
+ p->avx10.raw[0].b &= 0x000700ff;
+ p->avx10.raw[0].c = 0;
+ p->avx10.raw[0].d = 0;
+ if ( !p->feat.avx10 || !p->avx10.version ||
+ !p->avx10.vsz512 || !p->avx10.vsz256 || !p->avx10.vsz128 )
+ {
+ p->feat.avx10 = false;
+ memset(p->avx10.raw, 0, sizeof(p->avx10.raw));
+ }
+
p->extd.e1d &= ~CPUID_COMMON_1D_FEATURES;
/* Most of Power/RAS hidden from guests. */
@@ -407,6 +419,7 @@ static void __init guest_common_max_leav
{
p->basic.max_leaf = ARRAY_SIZE(p->basic.raw) - 1;
p->feat.max_subleaf = ARRAY_SIZE(p->feat.raw) - 1;
+ p->avx10.max_subleaf = ARRAY_SIZE(p->avx10.raw) - 1;
p->extd.max_leaf = 0x80000000U + ARRAY_SIZE(p->extd.raw) - 1;
}
@@ -415,6 +428,7 @@ static void __init guest_common_default_
{
p->basic.max_leaf = host_cpu_policy.basic.max_leaf;
p->feat.max_subleaf = host_cpu_policy.feat.max_subleaf;
+ p->avx10.max_subleaf = host_cpu_policy.avx10.max_subleaf;
p->extd.max_leaf = host_cpu_policy.extd.max_leaf;
}
@@ -510,6 +524,28 @@ static void __init guest_common_max_feat
* function correctly when migrated here, even if ERMS isn't available.
*/
__set_bit(X86_FEATURE_ERMS, fs);
+
+ /*
+ * AVX10 is merely a re-declaration of a combination of AVX512 features.
+ * Synthesize the latter from the former, when available. Doing it the
+ * other way around would also require synthesizing the AVX10 CPUID leaf.
+ */
+ if ( test_bit(X86_FEATURE_AVX10, fs) )
+ {
+ __set_bit(X86_FEATURE_AVX512F, fs);
+ __set_bit(X86_FEATURE_AVX512VL, fs);
+ __set_bit(X86_FEATURE_AVX512BW, fs);
+ __set_bit(X86_FEATURE_AVX512DQ, fs);
+ __set_bit(X86_FEATURE_AVX512_BF16, fs);
+ __set_bit(X86_FEATURE_AVX512_FP16, fs);
+ __set_bit(X86_FEATURE_AVX512CD, fs);
+ __set_bit(X86_FEATURE_AVX512_BITALG, fs);
+ __set_bit(X86_FEATURE_AVX512_IFMA, fs);
+ __set_bit(X86_FEATURE_AVX512_VBMI, fs);
+ __set_bit(X86_FEATURE_AVX512_VBMI2, fs);
+ __set_bit(X86_FEATURE_AVX512_VNNI, fs);
+ __set_bit(X86_FEATURE_AVX512_VPOPCNTDQ, fs);
+ }
}
static void __init guest_common_default_feature_adjustments(uint32_t *fs)
@@ -972,6 +1008,7 @@ void recalculate_cpuid_policy(struct dom
p->basic.max_leaf = min(p->basic.max_leaf, max->basic.max_leaf);
p->feat.max_subleaf = min(p->feat.max_subleaf, max->feat.max_subleaf);
+ p->avx10.max_subleaf = min(p->avx10.max_subleaf, max->avx10.max_subleaf);
p->extd.max_leaf = 0x80000000U | min(p->extd.max_leaf & 0xffff,
((p->x86_vendor & (X86_VENDOR_AMD |
X86_VENDOR_HYGON))
@@ -1018,6 +1055,8 @@ void recalculate_cpuid_policy(struct dom
if ( p->basic.max_leaf < XSTATE_CPUID )
__clear_bit(X86_FEATURE_XSAVE, fs);
+ if ( p->basic.max_leaf < 0x24 )
+ __clear_bit(X86_FEATURE_AVX10, fs);
sanitise_featureset(fs);
@@ -1087,9 +1126,18 @@ void __init init_dom0_cpuid_policy(struc
/* Apply dom0-cpuid= command line settings, if provided. */
if ( dom0_cpuid_cmdline )
{
+ const struct cpu_policy *max = is_pv_domain(d)
+ ? (IS_ENABLED(CONFIG_PV) ? &pv_max_cpu_policy : NULL)
+ : (IS_ENABLED(CONFIG_HVM) ? &hvm_max_cpu_policy : NULL);
uint32_t fs[FSCAPINTS];
unsigned int i;
+ if ( !max )
+ {
+ ASSERT_UNREACHABLE();
+ return;
+ }
+
x86_cpu_policy_to_featureset(p, fs);
for ( i = 0; i < ARRAY_SIZE(fs); ++i )
@@ -1099,6 +1147,13 @@ void __init init_dom0_cpuid_policy(struc
}
x86_cpu_featureset_to_policy(fs, p);
+
+ /*
+ * Default-off features with their own leaves need those leaves
+ * re-populated from the max policy.
+ */
+ if ( p->feat.avx10 )
+ p->avx10 = max->avx10;
}
/*
@@ -1131,6 +1186,8 @@ static void __init __maybe_unused build_
sizeof(raw_cpu_policy.feat.raw));
BUILD_BUG_ON(sizeof(raw_cpu_policy.xstate) !=
sizeof(raw_cpu_policy.xstate.raw));
+ BUILD_BUG_ON(sizeof(raw_cpu_policy.avx10) !=
+ sizeof(raw_cpu_policy.avx10.raw));
BUILD_BUG_ON(sizeof(raw_cpu_policy.extd) !=
sizeof(raw_cpu_policy.extd.raw));
}
--- a/xen/arch/x86/cpuid.c
+++ b/xen/arch/x86/cpuid.c
@@ -226,6 +226,15 @@ void guest_cpuid(const struct vcpu *v, u
*res = array_access_nospec(p->xstate.raw, subleaf);
break;
+ case 0x24:
+ ASSERT(p->avx10.max_subleaf < ARRAY_SIZE(p->avx10.raw));
+ if ( subleaf > min_t(uint32_t, p->avx10.max_subleaf,
+ ARRAY_SIZE(p->avx10.raw) - 1) )
+ return;
+
+ *res = array_access_nospec(p->avx10.raw, subleaf);
+ break;
+
default:
*res = array_access_nospec(p->basic.raw, leaf);
break;
--- a/xen/arch/x86/lib/cpu-policy/copy-to-buffer.c
+++ b/xen/arch/x86/lib/cpu-policy/copy-to-buffer.c
@@ -123,6 +123,13 @@ int x86_cpuid_copy_to_buffer(const struc
break;
}
+ case 0x24:
+ for ( subleaf = 0;
+ subleaf <= MIN(p->avx10.max_subleaf,
+ ARRAY_SIZE(p->avx10.raw) - 1); ++subleaf )
+ COPY_LEAF(leaf, subleaf, &p->avx10.raw[subleaf]);
+ break;
+
default:
COPY_LEAF(leaf, XEN_CPUID_NO_SUBLEAF, &p->basic.raw[leaf]);
break;
--- a/xen/arch/x86/lib/cpu-policy/copy-from-buffer.c
+++ b/xen/arch/x86/lib/cpu-policy/copy-from-buffer.c
@@ -108,6 +108,13 @@ int x86_cpuid_copy_from_buffer(struct cp
array_access_nospec(p->xstate.raw, data.subleaf) = l;
break;
+ case 0x24:
+ if ( data.subleaf >= ARRAY_SIZE(p->avx10.raw) )
+ goto out_of_range;
+
+ array_access_nospec(p->avx10.raw, data.subleaf) = l;
+ break;
+
default:
if ( data.subleaf != XEN_CPUID_NO_SUBLEAF )
goto out_of_range;
--- a/xen/arch/x86/lib/cpu-policy/cpuid.c
+++ b/xen/arch/x86/lib/cpu-policy/cpuid.c
@@ -125,6 +125,7 @@ void x86_cpu_policy_fill_native(struct c
switch ( i )
{
case 0x4: case 0x7: case 0xb: case 0xd:
+ case 0x24:
/* Multi-invocation leaves. Deferred. */
continue;
}
@@ -218,6 +219,15 @@ void x86_cpu_policy_fill_native(struct c
}
}
+ if ( p->basic.max_leaf >= 0x24 )
+ {
+ cpuid_count_leaf(0x24, 0, &p->avx10.raw[0]);
+
+ for ( i = 1; i <= MIN(p->avx10.max_subleaf,
+ ARRAY_SIZE(p->avx10.raw) - 1); ++i )
+ cpuid_count_leaf(0x24, i, &p->avx10.raw[i]);
+ }
+
/* Extended leaves. */
cpuid_leaf(0x80000000U, &p->extd.raw[0]);
for ( i = 1; i <= MIN(p->extd.max_leaf & 0xffffU,
@@ -287,6 +297,9 @@ void x86_cpu_policy_clear_out_of_range_l
ARRAY_SIZE(p->xstate.raw) - 1);
}
+ if ( p->basic.max_leaf < 0x24 )
+ memset(p->avx10.raw, 0, sizeof(p->avx10.raw));
+
zero_leaves(p->extd.raw,
((p->extd.max_leaf >> 16) == 0x8000
? (p->extd.max_leaf & 0xffff) + 1 : 0),
@@ -299,6 +312,8 @@ void __init x86_cpu_policy_bound_max_lea
min_t(uint32_t, p->basic.max_leaf, ARRAY_SIZE(p->basic.raw) - 1);
p->feat.max_subleaf =
min_t(uint32_t, p->feat.max_subleaf, ARRAY_SIZE(p->feat.raw) - 1);
+ p->avx10.max_subleaf =
+ min_t(uint32_t, p->avx10.max_subleaf, ARRAY_SIZE(p->avx10.raw) - 1);
p->extd.max_leaf = 0x80000000U | min_t(uint32_t, p->extd.max_leaf & 0xffff,
ARRAY_SIZE(p->extd.raw) - 1);
}
@@ -326,6 +341,8 @@ void x86_cpu_policy_shrink_max_leaves(st
*/
p->basic.raw[0xd] = p->xstate.raw[0];
+ p->basic.raw[0x24] = p->avx10.raw[0];
+
for ( i = p->basic.max_leaf; i; --i )
if ( p->basic.raw[i].a | p->basic.raw[i].b |
p->basic.raw[i].c | p->basic.raw[i].d )
--- a/xen/arch/x86/lib/cpu-policy/policy.c
+++ b/xen/arch/x86/lib/cpu-policy/policy.c
@@ -24,6 +24,10 @@ int x86_cpu_policies_are_compatible(cons
if ( guest->feat.max_subleaf > host->feat.max_subleaf )
FAIL_CPUID(7, 0);
+ if ( guest->avx10.version > host->avx10.version ||
+ guest->avx10.max_subleaf > host->avx10.max_subleaf )
+ FAIL_CPUID(0x24, 0);
+
if ( guest->extd.max_leaf > host->extd.max_leaf )
FAIL_CPUID(0x80000000U, NA);
--- a/xen/include/public/arch-x86/cpufeatureset.h
+++ b/xen/include/public/arch-x86/cpufeatureset.h
@@ -366,6 +366,7 @@ XEN_CPUFEATURE(PREFETCHI, 15*32
XEN_CPUFEATURE(USER_MSR, 15*32+15) /*s U{RD,WR}MSR Instructions */
XEN_CPUFEATURE(UIRET_UIF, 15*32+17) /* UIRET updates UIF */
XEN_CPUFEATURE(CET_SSS, 15*32+18) /* CET Supervisor Shadow Stacks safe to use */
+XEN_CPUFEATURE(AVX10, 15*32+19) /* AVX10 Converged Vector ISA */
XEN_CPUFEATURE(SLSM, 15*32+24) /* Static Lockstep Mode */
/* Intel-defined CPU features, MSR_ARCH_CAPS 0x10a.eax, word 16 */
--- a/xen/include/xen/lib/x86/cpu-policy.h
+++ b/xen/include/xen/lib/x86/cpu-policy.h
@@ -59,11 +59,12 @@ unsigned int x86_cpuid_lookup_vendor(uin
*/
const char *x86_cpuid_vendor_to_str(unsigned int vendor);
-#define CPUID_GUEST_NR_BASIC (0xdu + 1)
+#define CPUID_GUEST_NR_BASIC (0x24u + 1)
#define CPUID_GUEST_NR_CACHE (5u + 1)
#define CPUID_GUEST_NR_FEAT (2u + 1)
#define CPUID_GUEST_NR_TOPO (1u + 1)
#define CPUID_GUEST_NR_XSTATE (62u + 1)
+#define CPUID_GUEST_NR_AVX10 (0u + 1)
#define CPUID_GUEST_NR_EXTD_INTEL (0x8u + 1)
#define CPUID_GUEST_NR_EXTD_AMD (0x21u + 1)
#define CPUID_GUEST_NR_EXTD MAX(CPUID_GUEST_NR_EXTD_INTEL, \
@@ -264,6 +265,19 @@ struct cpu_policy
} comp[CPUID_GUEST_NR_XSTATE];
} xstate;
+ /* Structured AVX10 information leaf: 0x000000024[xx] */
+ union {
+ struct cpuid_leaf raw[CPUID_GUEST_NR_AVX10];
+ struct {
+ /* Subleaf 0. */
+ uint32_t max_subleaf;
+ uint32_t version:8, :8;
+ bool vsz128:1, vsz256:1, vsz512:1;
+ uint32_t :13;
+ uint32_t /* c */:32, /* d */:32;
+ };
+ } avx10;
+
/* Extended leaves: 0x800000xx */
union {
struct cpuid_leaf raw[CPUID_GUEST_NR_EXTD];
--- a/xen/tools/gen-cpuid.py
+++ b/xen/tools/gen-cpuid.py
@@ -294,7 +294,7 @@ def crunch_numbers(state):
# enabled. Certain later extensions, acting on 256-bit vectors of
# integers, better depend on AVX2 than AVX.
AVX2: [AVX512F, VAES, VPCLMULQDQ, AVX_VNNI, AVX_IFMA, AVX_VNNI_INT8,
- AVX_VNNI_INT16, SHA512, SM4],
+ AVX_VNNI_INT16, SHA512, SM4, AVX10],
# AVX512F is taken to mean hardware support for 512bit registers
# (which in practice depends on the EVEX prefix to encode) as well
^ permalink raw reply [flat|nested] 20+ messages in thread* [PATCH v5 02/19] x86emul: support SIMD MOVRS
2026-11-11 13:40 [PATCH v5 00/19] x86: support AVX10 Jan Beulich
2026-11-11 13:41 ` [PATCH v5 01/19] x86/CPUID: enable AVX10 leaf Jan Beulich
@ 2026-11-11 13:42 ` Jan Beulich
2026-11-11 13:42 ` [PATCH v5 03/19] x86emul: support AVX10 forms of SM4 insns Jan Beulich
` (16 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Jan Beulich @ 2026-11-11 13:42 UTC (permalink / raw)
To: xen-devel@lists.xenproject.org
Cc: Andrew Cooper, Teddy Astie, Roger Pau Monné
As we ignore cachability aspects of insns, they're treated like simple
VMOVs.
Signed-off-by: Jan Beulich <jbeulich@suse.com>
---
SDE: -dmr
---
v4: Correct main switch case labels to reference Map5. Switch to using
fallthrough pseudo-keyword. Move ahead in series, switching feature
dependency to plain AVX10.
v3: New.
--- a/tools/tests/x86_emulator/evex-disp8.c
+++ b/tools/tests/x86_emulator/evex-disp8.c
@@ -720,6 +720,13 @@ static const struct test vpclmulqdq_all[
INSN(pclmulqdq, 66, 0f3a, 44, vl, q_nb, vl)
};
+static const struct test movrs_all[] = {
+ INSN(movrsb, f2, map5, 6f, vl, b, vl),
+ INSN(movrsd, f3, map5, 6f, vl, d_nb, vl),
+ INSN(movrsq, f3, map5, 6f, vl, q_nb, vl),
+ INSN(movrsw, f2, map5, 6f, vl, w, vl),
+};
+
static const unsigned char vl_all[] = { VL_512, VL_128, VL_256 };
static const unsigned char vl_128[] = { VL_128 };
static const unsigned char vl_no128[] = { VL_512, VL_256 };
@@ -1071,8 +1078,8 @@ void evex_disp8_test(void *instr, struct
emulops.read = read;
emulops.write = write;
-#define RUN(feat, vl) do { \
- if ( cpu_has_##feat ) \
+#define run(cond, feat, vl) do { \
+ if ( cond ) \
{ \
printf("%-40s", "Testing " #feat "/" #vl " disp8 handling..."); \
test_group(feat ## _ ## vl, ARRAY_SIZE(feat ## _ ## vl), \
@@ -1081,6 +1088,8 @@ void evex_disp8_test(void *instr, struct
} \
} while ( false )
+#define RUN(feat, vl) run(cpu_has_ ## feat, feat, vl)
+
RUN(avx512f, all);
RUN(avx512f, 128);
RUN(avx512f, no128);
@@ -1111,4 +1120,9 @@ void evex_disp8_test(void *instr, struct
RUN(vaes, all);
RUN(vpclmulqdq, all);
}
+
+ if ( cpu_has_avx10 )
+ {
+ run(ctxt->addr_size == 64 && cpu_has_movrs, movrs, all);
+ }
}
--- a/tools/tests/x86_emulator/predicates.c
+++ b/tools/tests/x86_emulator/predicates.c
@@ -2124,6 +2124,8 @@ static const struct evex {
{ { 0x5f }, 2, T, R, pfx_no, W0, Ln }, /* vmaxph */
{ { 0x5f }, 2, T, R, pfx_f3, W0, LIG }, /* vmaxsh */
{ { 0x6e }, 2, T, R, pfx_66, WIG, L0 }, /* vmovw */
+ { { 0x6f }, 2, T, R, pfx_f3, Wn, Ln }, /* vmovrs{d,q} */
+ { { 0x6f }, 2, T, R, pfx_f2, Wn, Ln }, /* vmovrs{b,w} */
{ { 0x78 }, 2, T, R, pfx_no, W0, Ln }, /* vcvttph2udq */
{ { 0x78 }, 2, T, R, pfx_66, W0, Ln }, /* vcvttph2uqq */
{ { 0x78 }, 2, T, R, pfx_f3, Wn, LIG }, /* vcvttsh2usi */
--- a/tools/tests/x86_emulator/x86-emulate.h
+++ b/tools/tests/x86_emulator/x86-emulate.h
@@ -211,12 +211,14 @@ void wrpkru(unsigned int val);
xcr0_mask(0xe6))
#define cpu_has_cmpccxadd cpu_policy.feat.cmpccxadd
#define cpu_has_avx_ifma (cpu_policy.feat.avx_ifma && xcr0_mask(6))
+#define cpu_has_movrs cpu_policy.feat.movrs
#define cpu_has_avx_vnni_int8 (cpu_policy.feat.avx_vnni_int8 && \
xcr0_mask(6))
#define cpu_has_avx_ne_convert (cpu_policy.feat.avx_ne_convert && \
xcr0_mask(6))
#define cpu_has_avx_vnni_int16 (cpu_policy.feat.avx_vnni_int16 && \
xcr0_mask(6))
+#define cpu_has_avx10 (cpu_policy.feat.avx10 && xcr0_mask(0xe6))
#define cpu_has_xgetbv1 (cpu_has_xsave && cpu_policy.xstate.xgetbv1)
--- a/xen/arch/x86/x86_emulate/private.h
+++ b/xen/arch/x86/x86_emulate/private.h
@@ -622,6 +622,8 @@ amd_like(const struct x86_emulate_ctxt *
#define vcpu_has_avx_vnni_int16() (ctxt->cpuid->feat.avx_vnni_int16)
#define vcpu_has_user_msr() (ctxt->cpuid->feat.user_msr)
+#define vcpu_has_avx10() (ctxt->cpuid->feat.avx10)
+
#define vcpu_must_have(feat) \
generate_exception_if(!vcpu_has_##feat(), X86_EXC_UD)
--- a/xen/arch/x86/x86_emulate/x86_emulate.c
+++ b/xen/arch/x86/x86_emulate/x86_emulate.c
@@ -7930,6 +7930,17 @@ x86_emulate(
op_bytes = 8 << evex.lr;
goto simd_zmm;
+ case X86EMUL_OPC_EVEX_F2(5, 0x6f): /* vmovrs{b,w} mem,[xyz]mm{k} */
+ elem_bytes = 1 << evex.w;
+ fallthrough;
+ case X86EMUL_OPC_EVEX_F3(5, 0x6f): /* vmovrs{d,q} mem,[xyz]mm{k} */
+ generate_exception_if(ea.type != OP_MEM || evex.brs, X86_EXC_UD);
+ vcpu_must_have(avx10);
+ vcpu_must_have(movrs);
+ avx512_vlen_check(false);
+ op_bytes = 16 << evex.lr;
+ goto simd_zmm;
+
case X86EMUL_OPC_EVEX_66(5, 0x78): /* vcvttph2uqq xmm/mem,[xyz]mm{k} */
case X86EMUL_OPC_EVEX_66(5, 0x79): /* vcvtph2uqq xmm/mem,[xyz]mm{k} */
case X86EMUL_OPC_EVEX_66(5, 0x7a): /* vcvttph2qq xmm/mem,[xyz]mm{k} */
^ permalink raw reply [flat|nested] 20+ messages in thread* [PATCH v5 03/19] x86emul: support AVX10 forms of SM4 insns
2026-11-11 13:40 [PATCH v5 00/19] x86: support AVX10 Jan Beulich
2026-11-11 13:41 ` [PATCH v5 01/19] x86/CPUID: enable AVX10 leaf Jan Beulich
2026-11-11 13:42 ` [PATCH v5 02/19] x86emul: support SIMD MOVRS Jan Beulich
@ 2026-11-11 13:42 ` Jan Beulich
2026-11-11 13:42 ` [PATCH v5 04/19] x86emul: support AVX10.1 Jan Beulich
` (15 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Jan Beulich @ 2026-11-11 13:42 UTC (permalink / raw)
To: xen-devel@lists.xenproject.org
Cc: Andrew Cooper, Teddy Astie, Roger Pau Monné
Simply clone the VEX-encoded handling to cover the EVEX forms.
Signed-off-by: Jan Beulich <jbeulich@suse.com>
---
SDE: -dmr / -future
---
v4: Address v3 TODO. Move ahead in series, switching feature dependency to
plain AVX10. Add call to avx512_vlen_check().
v3: New.
--- a/tools/tests/x86_emulator/evex-disp8.c
+++ b/tools/tests/x86_emulator/evex-disp8.c
@@ -727,6 +727,11 @@ static const struct test movrs_all[] = {
INSN(movrsw, f2, map5, 6f, vl, w, vl),
};
+static const struct test sm4_all[] = {
+ INSN(sm4key4, f3, 0f38, da, vl, d_nb, vl),
+ INSN(sm4rnds4, f2, 0f38, da, vl, d_nb, vl),
+};
+
static const unsigned char vl_all[] = { VL_512, VL_128, VL_256 };
static const unsigned char vl_128[] = { VL_128 };
static const unsigned char vl_no128[] = { VL_512, VL_256 };
@@ -1124,5 +1129,6 @@ void evex_disp8_test(void *instr, struct
if ( cpu_has_avx10 )
{
run(ctxt->addr_size == 64 && cpu_has_movrs, movrs, all);
+ run(cpu_has_sm4, sm4, all);
}
}
--- a/tools/tests/x86_emulator/predicates.c
+++ b/tools/tests/x86_emulator/predicates.c
@@ -2025,6 +2025,8 @@ static const struct evex {
{ { 0xcc }, 2, T, R, pfx_66, Wn, L2 }, /* vrsqrt28p{s,d} */
{ { 0xcd }, 2, T, R, pfx_66, Wn, LIG }, /* vrsqrt28s{s,d} */
{ { 0xcf }, 2, T, R, pfx_66, W0, Ln }, /* vgf2p8mulb */
+ { { 0xda }, 2, T, R, pfx_f3, W0, Ln }, /* vsm4key4 */
+ { { 0xda }, 2, T, R, pfx_f2, W0, Ln }, /* vsm4rnds4 */
{ { 0xdc }, 2, T, R, pfx_66, WIG, Ln }, /* vaesenc */
{ { 0xdd }, 2, T, R, pfx_66, WIG, Ln }, /* vaesenclast */
{ { 0xde }, 2, T, R, pfx_66, WIG, Ln }, /* vaesdec */
--- a/xen/arch/x86/x86_emulate/decode.c
+++ b/xen/arch/x86/x86_emulate/decode.c
@@ -438,7 +438,7 @@ static const struct ext0f38_table {
[0xd3] = { .simd_size = simd_other },
[0xd6] = { .simd_size = simd_other, .d8s = d8s_vl },
[0xd7] = { .simd_size = simd_scalar_vexw, .d8s = d8s_dq },
- [0xda] = { .simd_size = simd_other },
+ [0xda] = { .simd_size = simd_other, .d8s = d8s_vl },
[0xdb] = { .simd_size = simd_packed_int, .two_op = 1 },
[0xdc ... 0xdf] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
[0xe0 ... 0xef] = { .to_mem = 1 },
--- a/xen/arch/x86/x86_emulate/x86_emulate.c
+++ b/xen/arch/x86/x86_emulate/x86_emulate.c
@@ -6869,6 +6869,15 @@ x86_emulate(
op_bytes = 16 << vex.l;
goto simd_0f_ymm;
+ case X86EMUL_OPC_EVEX_F3(0x0f38, 0xda): /* vsm4key4 [xyz]mm/mem,[xyz]mm,[xyz]mm */
+ case X86EMUL_OPC_EVEX_F2(0x0f38, 0xda): /* vsm4rnds4 [xyz]mm/mem,[xyz]mm,[xyz]mm */
+ vcpu_must_have(avx10);
+ vcpu_must_have(sm4);
+ generate_exception_if(evex.w || evex.brs || evex.opmsk, X86_EXC_UD);
+ avx512_vlen_check(false);
+ op_bytes = 16 << evex.lr;
+ goto simd_zmm;
+
case X86EMUL_OPC_VEX_66(0x0f38, 0xdc): /* vaesenc {x,y}mm/mem,{x,y}mm,{x,y}mm */
case X86EMUL_OPC_VEX_66(0x0f38, 0xdd): /* vaesenclast {x,y}mm/mem,{x,y}mm,{x,y}mm */
case X86EMUL_OPC_VEX_66(0x0f38, 0xde): /* vaesdec {x,y}mm/mem,{x,y}mm,{x,y}mm */
^ permalink raw reply [flat|nested] 20+ messages in thread* [PATCH v5 04/19] x86emul: support AVX10.1
2026-11-11 13:40 [PATCH v5 00/19] x86: support AVX10 Jan Beulich
` (2 preceding siblings ...)
2026-11-11 13:42 ` [PATCH v5 03/19] x86emul: support AVX10 forms of SM4 insns Jan Beulich
@ 2026-11-11 13:42 ` Jan Beulich
2026-11-11 13:43 ` [PATCH v5 05/19] x86emul/test: use simd_check_avx512*() in main() Jan Beulich
` (14 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Jan Beulich @ 2026-11-11 13:42 UTC (permalink / raw)
To: xen-devel@lists.xenproject.org
Cc: Andrew Cooper, Teddy Astie, Roger Pau Monné
This requires relaxing various pre-existing AVX512* checks, as AVX10.1
covers all AVX512* except PF, ER, 4FMAPS, 4VNNIW (support for all of
which was removed meanwhile anyway), and VP2INTERSECT. At the same time
all vector widths are always supported.
While in most cases the changes to x86_emulate() are entirely
mechanical, for opmask insns earlier unconditional AVX512F checks are
converted into "else" clauses to existing if/else-if ones.
To be certain that no uses remain, also drop respective remaining
cpu_has_avx512* (except in the test harness) and vcpu_has_avx512*().
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
---
Probably avx512_vlen_check() should have the avx512_ prefix dropped, now
that it also covers AVX10. But if so that wants to be either a prereq or
a follow-on patch.
visa_check() won't cover AVX10.2 and higher, but probably we will want
independent checking logic for that anyway.
---
v5: Re-base, in particular over the removal of host_and_vcpu_must_have().
v4: Switch to using fallthrough pseudo-keyword. Drop new _vlen_check()
helper again. Re-base.
v3: Add ChangeLog entry.
v2: Drop use of vsz128 field. Re-base, in particular over dropping of
Xeon Phi support.
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,6 +16,8 @@ The format is based on [Keep a Changelog
afterwards.
### Added
+ - On x86:
+ - Support for AVX10.1. (Experimental)
### Removed
- On Arm:
--- a/xen/arch/x86/include/asm/cpufeature.h
+++ b/xen/arch/x86/include/asm/cpufeature.h
@@ -181,12 +181,10 @@ static inline bool boot_cpu_has(unsigned
#define cpu_has_pqe boot_cpu_has(X86_FEATURE_PQE)
#define cpu_has_fpu_sel (!boot_cpu_has(X86_FEATURE_NO_FPU_SEL))
#define cpu_has_mpx boot_cpu_has(X86_FEATURE_MPX)
-#define cpu_has_avx512f boot_cpu_has(X86_FEATURE_AVX512F)
#define cpu_has_smap boot_cpu_has(X86_FEATURE_SMAP)
#define cpu_has_clflushopt boot_cpu_has(X86_FEATURE_CLFLUSHOPT)
#define cpu_has_clwb boot_cpu_has(X86_FEATURE_CLWB)
#define cpu_has_proc_trace boot_cpu_has(X86_FEATURE_PROC_TRACE)
-#define cpu_has_avx512bw boot_cpu_has(X86_FEATURE_AVX512BW)
/* CPUID level 0x00000007:0.ecx */
#define cpu_has_pku boot_cpu_has(X86_FEATURE_PKU)
--- a/xen/arch/x86/x86_emulate/private.h
+++ b/xen/arch/x86/x86_emulate/private.h
@@ -577,26 +577,15 @@ amd_like(const struct x86_emulate_ctxt *
#define vcpu_has_invpcid() (ctxt->cpuid->feat.invpcid)
#define vcpu_has_rtm() (ctxt->cpuid->feat.rtm)
#define vcpu_has_mpx() (ctxt->cpuid->feat.mpx)
-#define vcpu_has_avx512f() (ctxt->cpuid->feat.avx512f)
-#define vcpu_has_avx512dq() (ctxt->cpuid->feat.avx512dq)
#define vcpu_has_rdseed() (ctxt->cpuid->feat.rdseed)
#define vcpu_has_adx() (ctxt->cpuid->feat.adx)
#define vcpu_has_smap() (ctxt->cpuid->feat.smap)
-#define vcpu_has_avx512_ifma() (ctxt->cpuid->feat.avx512_ifma)
#define vcpu_has_clflushopt() (ctxt->cpuid->feat.clflushopt)
#define vcpu_has_clwb() (ctxt->cpuid->feat.clwb)
-#define vcpu_has_avx512cd() (ctxt->cpuid->feat.avx512cd)
#define vcpu_has_sha() (ctxt->cpuid->feat.sha)
-#define vcpu_has_avx512bw() (ctxt->cpuid->feat.avx512bw)
-#define vcpu_has_avx512vl() (ctxt->cpuid->feat.avx512vl)
-#define vcpu_has_avx512_vbmi() (ctxt->cpuid->feat.avx512_vbmi)
-#define vcpu_has_avx512_vbmi2() (ctxt->cpuid->feat.avx512_vbmi2)
#define vcpu_has_gfni() (ctxt->cpuid->feat.gfni)
#define vcpu_has_vaes() (ctxt->cpuid->feat.vaes)
#define vcpu_has_vpclmulqdq() (ctxt->cpuid->feat.vpclmulqdq)
-#define vcpu_has_avx512_vnni() (ctxt->cpuid->feat.avx512_vnni)
-#define vcpu_has_avx512_bitalg() (ctxt->cpuid->feat.avx512_bitalg)
-#define vcpu_has_avx512_vpopcntdq() (ctxt->cpuid->feat.avx512_vpopcntdq)
#define vcpu_has_rdpid() (ctxt->cpuid->feat.rdpid)
#define vcpu_has_movdiri() (ctxt->cpuid->feat.movdiri)
#define vcpu_has_movdir64b() (ctxt->cpuid->feat.movdir64b)
@@ -604,12 +593,10 @@ amd_like(const struct x86_emulate_ctxt *
#define vcpu_has_avx512_vp2intersect() (ctxt->cpuid->feat.avx512_vp2intersect)
#define vcpu_has_serialize() (ctxt->cpuid->feat.serialize)
#define vcpu_has_tsxldtrk() (ctxt->cpuid->feat.tsxldtrk)
-#define vcpu_has_avx512_fp16() (ctxt->cpuid->feat.avx512_fp16)
#define vcpu_has_sha512() (ctxt->cpuid->feat.sha512)
#define vcpu_has_sm3() (ctxt->cpuid->feat.sm3)
#define vcpu_has_sm4() (ctxt->cpuid->feat.sm4)
#define vcpu_has_avx_vnni() (ctxt->cpuid->feat.avx_vnni)
-#define vcpu_has_avx512_bf16() (ctxt->cpuid->feat.avx512_bf16)
#define vcpu_has_cmpccxadd() (ctxt->cpuid->feat.cmpccxadd)
#define vcpu_has_lkgs() (ctxt->cpuid->feat.lkgs)
#define vcpu_has_wrmsrns() (ctxt->cpuid->feat.wrmsrns)
--- a/xen/arch/x86/x86_emulate/x86_emulate.c
+++ b/xen/arch/x86/x86_emulate/x86_emulate.c
@@ -1202,6 +1202,10 @@ static unsigned long *decode_vex_gpr(
return decode_gpr(regs, ~vex_reg & (mode_64bit() ? 0xf : 7));
}
+#define visa_check(subfeat) \
+ generate_exception_if(!cp->feat.avx512 ## subfeat && !cp->feat.avx10, \
+ X86_EXC_UD)
+
#define avx512_vlen_check(lig) do { \
switch ( evex.lr ) \
{ \
@@ -1211,7 +1215,7 @@ static unsigned long *decode_vex_gpr(
break; \
case 0: case 1: \
if ( !(lig) ) \
- vcpu_must_have(avx512vl); \
+ visa_check(vl); \
break; \
} \
} while ( false )
@@ -1446,7 +1450,9 @@ x86_emulate(
/* KMOV{W,Q} %k<n>, (%rax) */
stb[0] = 0xc4;
stb[1] = 0xe1;
- stb[2] = cpu_has_avx512bw ? 0xf8 : 0x78;
+ stb[2] = cp->feat.avx512bw || cp->feat.avx10
+ ? 0xf8 /* L0.NP.W1 - kmovq */
+ : 0x78 /* L0.NP.W0 - kmovw */;
stb[3] = 0x91;
stb[4] = evex.opmsk << 3;
insn_bytes = 5;
@@ -3473,7 +3479,7 @@ x86_emulate(
(ea.type != OP_REG && evex.brs &&
(evex.pfx & VEX_PREFIX_SCALAR_MASK))),
X86_EXC_UD);
- vcpu_must_have(avx512f);
+ visa_check(f);
if ( ea.type != OP_REG || !evex.brs )
avx512_vlen_check(evex.pfx & VEX_PREFIX_SCALAR_MASK);
simd_zmm:
@@ -3529,7 +3535,7 @@ x86_emulate(
generate_exception_if((evex.lr || evex.opmsk || evex.brs ||
evex.w != (evex.pfx & VEX_PREFIX_DOUBLE_MASK)),
X86_EXC_UD);
- vcpu_must_have(avx512f);
+ visa_check(f);
if ( (d & DstMask) != DstMem )
d &= ~TwoOp;
op_bytes = 8;
@@ -3556,7 +3562,7 @@ x86_emulate(
generate_exception_if((evex.brs ||
evex.w != (evex.pfx & VEX_PREFIX_DOUBLE_MASK)),
X86_EXC_UD);
- vcpu_must_have(avx512f);
+ visa_check(f);
avx512_vlen_check(false);
d |= TwoOp;
op_bytes = !(evex.pfx & VEX_PREFIX_DOUBLE_MASK) || evex.lr
@@ -3593,7 +3599,7 @@ x86_emulate(
case X86EMUL_OPC_EVEX_66(0x0f38, 0x64): /* vpblendm{d,q} [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
case X86EMUL_OPC_EVEX_66(0x0f38, 0x65): /* vblendmp{s,d} [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
avx512f_no_sae:
- vcpu_must_have(avx512f);
+ visa_check(f);
generate_exception_if(ea.type != OP_MEM && evex.brs, X86_EXC_UD);
avx512_vlen_check(false);
goto simd_zmm;
@@ -3673,13 +3679,13 @@ x86_emulate(
case X86EMUL_OPC_EVEX_F3(5, 0x2a): /* vcvtsi2sh r/m,xmm,xmm */
case X86EMUL_OPC_EVEX_F3(5, 0x7b): /* vcvtusi2sh r/m,xmm,xmm */
- vcpu_must_have(avx512_fp16);
+ visa_check(_fp16);
/* fall through */
CASE_SIMD_SCALAR_FP(_EVEX, 0x0f, 0x2a): /* vcvtsi2s{s,d} r/m,xmm,xmm */
CASE_SIMD_SCALAR_FP(_EVEX, 0x0f, 0x7b): /* vcvtusi2s{s,d} r/m,xmm,xmm */
generate_exception_if(evex.opmsk || (ea.type != OP_REG && evex.brs),
X86_EXC_UD);
- vcpu_must_have(avx512f);
+ visa_check(f);
if ( !evex.brs )
avx512_vlen_check(true);
get_fpu(X86EMUL_FPU_zmm);
@@ -3792,7 +3798,7 @@ x86_emulate(
case X86EMUL_OPC_EVEX_F3(5, 0x2d): /* vcvtsh2si xmm/mem,reg */
case X86EMUL_OPC_EVEX_F3(5, 0x78): /* vcvttsh2usi xmm/mem,reg */
case X86EMUL_OPC_EVEX_F3(5, 0x79): /* vcvtsh2usi xmm/mem,reg */
- vcpu_must_have(avx512_fp16);
+ visa_check(_fp16);
/* fall through */
CASE_SIMD_SCALAR_FP(_EVEX, 0x0f, 0x2c): /* vcvtts{s,d}2si xmm/mem,reg */
CASE_SIMD_SCALAR_FP(_EVEX, 0x0f, 0x2d): /* vcvts{s,d}2si xmm/mem,reg */
@@ -3802,7 +3808,7 @@ x86_emulate(
evex.opmsk ||
(ea.type != OP_REG && evex.brs)),
X86_EXC_UD);
- vcpu_must_have(avx512f);
+ visa_check(f);
if ( !evex.brs )
avx512_vlen_check(true);
get_fpu(X86EMUL_FPU_zmm);
@@ -3868,7 +3874,7 @@ x86_emulate(
case X86EMUL_OPC_EVEX(5, 0x2e): /* vucomish xmm/m16,xmm */
case X86EMUL_OPC_EVEX(5, 0x2f): /* vcomish xmm/m16,xmm */
- vcpu_must_have(avx512_fp16);
+ visa_check(_fp16);
generate_exception_if(evex.w, X86_EXC_UD);
/* fall through */
CASE_SIMD_PACKED_FP(_EVEX, 0x0f, 0x2e): /* vucomis{s,d} xmm/mem,xmm */
@@ -3877,7 +3883,7 @@ x86_emulate(
(ea.type != OP_REG && evex.brs) ||
evex.w != evex.pfx),
X86_EXC_UD);
- vcpu_must_have(avx512f);
+ visa_check(f);
if ( !evex.brs )
avx512_vlen_check(true);
get_fpu(X86EMUL_FPU_zmm);
@@ -4021,7 +4027,7 @@ x86_emulate(
case X86EMUL_OPC_VEX(0x0f, 0x4a): /* kadd{w,q} k,k,k */
if ( !vex.w )
- vcpu_must_have(avx512dq);
+ visa_check(dq);
/* fall through */
case X86EMUL_OPC_VEX(0x0f, 0x41): /* kand{w,q} k,k,k */
case X86EMUL_OPC_VEX_66(0x0f, 0x41): /* kand{b,d} k,k,k */
@@ -4037,11 +4043,12 @@ x86_emulate(
generate_exception_if(!vex.l, X86_EXC_UD);
opmask_basic:
if ( vex.w )
- vcpu_must_have(avx512bw);
+ visa_check(bw);
else if ( vex.pfx )
- vcpu_must_have(avx512dq);
+ visa_check(dq);
+ else
+ visa_check(f);
opmask_common:
- vcpu_must_have(avx512f);
generate_exception_if(!vex.r || (mode_64bit() && !(vex.reg & 8)) ||
ea.type != OP_REG, X86_EXC_UD);
@@ -4064,13 +4071,14 @@ x86_emulate(
generate_exception_if(vex.l || vex.reg != 0xf, X86_EXC_UD);
goto opmask_basic;
- case X86EMUL_OPC_VEX(0x0f, 0x4b): /* kunpck{w,d}{d,q} k,k,k */
+ case X86EMUL_OPC_VEX(0x0f, 0x4b): /* kunpck{wd,dq} k,k,k */
generate_exception_if(!vex.l, X86_EXC_UD);
- vcpu_must_have(avx512bw);
+ visa_check(bw);
goto opmask_common;
case X86EMUL_OPC_VEX_66(0x0f, 0x4b): /* kunpckbw k,k,k */
generate_exception_if(!vex.l || vex.w, X86_EXC_UD);
+ visa_check(f);
goto opmask_common;
#endif /* X86EMUL_NO_SIMD */
@@ -4138,7 +4146,7 @@ x86_emulate(
generate_exception_if((evex.w != (evex.pfx & VEX_PREFIX_DOUBLE_MASK) ||
(ea.type != OP_MEM && evex.brs)),
X86_EXC_UD);
- vcpu_must_have(avx512dq);
+ visa_check(dq);
avx512_vlen_check(false);
goto simd_zmm;
@@ -4177,12 +4185,12 @@ x86_emulate(
case X86EMUL_OPC_EVEX_F2(0x0f, 0x7a): /* vcvtudq2ps [xyz]mm/mem,[xyz]mm{k} */
/* vcvtuqq2ps [xyz]mm/mem,{x,y}mm{k} */
if ( evex.w )
- vcpu_must_have(avx512dq);
+ visa_check(dq);
else
{
case X86EMUL_OPC_EVEX(0x0f, 0x78): /* vcvttp{s,d}2udq [xyz]mm/mem,[xyz]mm{k} */
case X86EMUL_OPC_EVEX(0x0f, 0x79): /* vcvtp{s,d}2udq [xyz]mm/mem,[xyz]mm{k} */
- vcpu_must_have(avx512f);
+ visa_check(f);
}
if ( ea.type != OP_REG || !evex.brs )
avx512_vlen_check(false);
@@ -4399,7 +4407,7 @@ x86_emulate(
case X86EMUL_OPC_EVEX_66(0x0f38, 0x0b): /* vpmulhrsw [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
case X86EMUL_OPC_EVEX_66(0x0f38, 0x1c): /* vpabsb [xyz]mm/mem,[xyz]mm{k} */
case X86EMUL_OPC_EVEX_66(0x0f38, 0x1d): /* vpabsw [xyz]mm/mem,[xyz]mm{k} */
- vcpu_must_have(avx512bw);
+ visa_check(bw);
generate_exception_if(evex.brs, X86_EXC_UD);
elem_bytes = 1 << (b & 1);
goto avx512f_no_sae;
@@ -4431,7 +4439,7 @@ x86_emulate(
generate_exception_if(b != 0x27 && evex.w != (b & 1), X86_EXC_UD);
goto avx512f_no_sae;
}
- vcpu_must_have(avx512bw);
+ visa_check(bw);
generate_exception_if(evex.brs, X86_EXC_UD);
elem_bytes = 1 << (ext == ext_0f ? b & 1 : evex.w);
avx512_vlen_check(false);
@@ -4504,7 +4512,7 @@ x86_emulate(
dst.bytes = 2;
/* fall through */
case X86EMUL_OPC_EVEX_66(5, 0x6e): /* vmovw r/m16,xmm */
- vcpu_must_have(avx512_fp16);
+ visa_check(_fp16);
generate_exception_if(evex.w, X86_EXC_UD);
/* fall through */
case X86EMUL_OPC_EVEX_66(0x0f, 0x6e): /* vmov{d,q} r/m,xmm */
@@ -4512,7 +4520,7 @@ x86_emulate(
generate_exception_if((evex.lr || evex.opmsk || evex.brs ||
evex.reg != 0xf || !evex.RX),
X86_EXC_UD);
- vcpu_must_have(avx512f);
+ visa_check(f);
get_fpu(X86EMUL_FPU_zmm);
opc = init_evex(stub);
@@ -4570,7 +4578,7 @@ x86_emulate(
case X86EMUL_OPC_EVEX_F2(0x0f, 0x6f): /* vmovdqu{8,16} [xyz]mm/mem,[xyz]mm{k} */
case X86EMUL_OPC_EVEX_F2(0x0f, 0x7f): /* vmovdqu{8,16} [xyz]mm,[xyz]mm/mem{k} */
- vcpu_must_have(avx512bw);
+ visa_check(bw);
elem_bytes = 1 << evex.w;
goto vmovdqa;
@@ -4663,7 +4671,7 @@ x86_emulate(
generate_exception_if(evex.w, X86_EXC_UD);
else
{
- vcpu_must_have(avx512bw);
+ visa_check(bw);
generate_exception_if(evex.brs, X86_EXC_UD);
}
d = (d & ~SrcMask) | SrcMem | TwoOp;
@@ -4909,7 +4917,7 @@ x86_emulate(
case X86EMUL_OPC_EVEX_F3(0x0f, 0xe6): /* vcvtdq2pd {x,y}mm/mem,[xyz]mm{k} */
/* vcvtqq2pd [xyz]mm/mem,[xyz]mm{k} */
if ( evex.pfx != vex_f3 )
- vcpu_must_have(avx512f);
+ visa_check(f);
else if ( evex.w )
{
case X86EMUL_OPC_EVEX_66(0x0f, 0x78): /* vcvttps2uqq {x,y}mm/mem,[xyz]mm{k} */
@@ -4920,11 +4928,11 @@ x86_emulate(
/* vcvttpd2qq [xyz]mm/mem,[xyz]mm{k} */
case X86EMUL_OPC_EVEX_66(0x0f, 0x7b): /* vcvtps2qq {x,y}mm/mem,[xyz]mm{k} */
/* vcvtpd2qq [xyz]mm/mem,[xyz]mm{k} */
- vcpu_must_have(avx512dq);
+ visa_check(dq);
}
else
{
- vcpu_must_have(avx512f);
+ visa_check(f);
/*
* While SDM version 085 has explicit wording towards embedded
* rounding being ignored, it's still not entirely unambiguous with
@@ -4971,7 +4979,7 @@ x86_emulate(
case X86EMUL_OPC_EVEX_66(0x0f, 0xd6): /* vmovq xmm,xmm/m64 */
generate_exception_if(evex.lr || !evex.w || evex.opmsk || evex.brs,
X86_EXC_UD);
- vcpu_must_have(avx512f);
+ visa_check(f);
d |= TwoOp;
op_bytes = 8;
goto simd_zmm;
@@ -4997,19 +5005,21 @@ x86_emulate(
case X86EMUL_OPC_VEX(0x0f, 0x90): /* kmov{w,q} k/mem,k */
case X86EMUL_OPC_VEX_66(0x0f, 0x90): /* kmov{b,d} k/mem,k */
generate_exception_if(vex.l || !vex.r, X86_EXC_UD);
- vcpu_must_have(avx512f);
if ( vex.w )
{
- vcpu_must_have(avx512bw);
+ visa_check(bw);
op_bytes = 4 << !vex.pfx;
}
else if ( vex.pfx )
{
- vcpu_must_have(avx512dq);
+ visa_check(dq);
op_bytes = 1;
}
else
+ {
+ visa_check(f);
op_bytes = 2;
+ }
get_fpu(X86EMUL_FPU_opmask);
@@ -5031,14 +5041,15 @@ x86_emulate(
generate_exception_if(vex.l || !vex.r || vex.reg != 0xf ||
ea.type != OP_REG, X86_EXC_UD);
- vcpu_must_have(avx512f);
if ( vex.pfx == vex_f2 )
- vcpu_must_have(avx512bw);
+ visa_check(bw);
else
{
generate_exception_if(vex.w, X86_EXC_UD);
if ( vex.pfx )
- vcpu_must_have(avx512dq);
+ visa_check(dq);
+ else
+ visa_check(f);
}
get_fpu(X86EMUL_FPU_opmask);
@@ -5070,10 +5081,9 @@ x86_emulate(
dst = ea;
dst.reg = decode_gpr(&_regs, modrm_reg);
- vcpu_must_have(avx512f);
if ( vex.pfx == vex_f2 )
{
- vcpu_must_have(avx512bw);
+ visa_check(bw);
dst.bytes = 4 << (mode_64bit() && vex.w);
}
else
@@ -5081,7 +5091,9 @@ x86_emulate(
generate_exception_if(vex.w, X86_EXC_UD);
dst.bytes = 4;
if ( vex.pfx )
- vcpu_must_have(avx512dq);
+ visa_check(dq);
+ else
+ visa_check(f);
}
get_fpu(X86EMUL_FPU_opmask);
@@ -5103,20 +5115,18 @@ x86_emulate(
ASSERT(!state->simd_size);
break;
- case X86EMUL_OPC_VEX(0x0f, 0x99): /* ktest{w,q} k,k */
- if ( !vex.w )
- vcpu_must_have(avx512dq);
- /* fall through */
case X86EMUL_OPC_VEX(0x0f, 0x98): /* kortest{w,q} k,k */
case X86EMUL_OPC_VEX_66(0x0f, 0x98): /* kortest{b,d} k,k */
+ case X86EMUL_OPC_VEX(0x0f, 0x99): /* ktest{w,q} k,k */
case X86EMUL_OPC_VEX_66(0x0f, 0x99): /* ktest{b,d} k,k */
generate_exception_if(vex.l || !vex.r || vex.reg != 0xf ||
ea.type != OP_REG, X86_EXC_UD);
- vcpu_must_have(avx512f);
if ( vex.w )
- vcpu_must_have(avx512bw);
- else if ( vex.pfx )
- vcpu_must_have(avx512dq);
+ visa_check(bw);
+ else if ( vex.pfx || (b & 1) )
+ visa_check(dq);
+ else
+ visa_check(f);
get_fpu(X86EMUL_FPU_opmask);
@@ -5403,7 +5413,7 @@ x86_emulate(
(evex.pfx & VEX_PREFIX_SCALAR_MASK)) ||
!evex.r || !evex.R || evex.z),
X86_EXC_UD);
- vcpu_must_have(avx512f);
+ visa_check(f);
if ( ea.type != OP_REG || !evex.brs )
avx512_vlen_check(evex.pfx & VEX_PREFIX_SCALAR_MASK);
simd_imm8_zmm:
@@ -5447,9 +5457,9 @@ x86_emulate(
case X86EMUL_OPC_EVEX_66(0x0f3a, 0x22): /* vpinsr{d,q} $imm8,r/m,xmm,xmm */
generate_exception_if(evex.lr || evex.opmsk || evex.brs, X86_EXC_UD);
if ( b & 2 )
- vcpu_must_have(avx512dq);
+ visa_check(dq);
else
- vcpu_must_have(avx512bw);
+ visa_check(bw);
if ( !mode_64bit() )
evex.w = 0;
memcpy(mmvalp, &src.val, src.bytes);
@@ -5486,7 +5496,7 @@ x86_emulate(
/* fall through */
case X86EMUL_OPC_EVEX_66(0x0f3a, 0x25): /* vpternlog{d,q} $imm8,[xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
avx512f_imm8_no_sae:
- vcpu_must_have(avx512f);
+ visa_check(f);
generate_exception_if(ea.type != OP_MEM && evex.brs, X86_EXC_UD);
avx512_vlen_check(false);
goto simd_imm8_zmm;
@@ -5585,7 +5595,7 @@ x86_emulate(
case X86EMUL_OPC_EVEX_66(0x0f, 0xe4): /* vpmulhuw [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
case X86EMUL_OPC_EVEX_66(0x0f, 0xea): /* vpminsw [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
case X86EMUL_OPC_EVEX_66(0x0f, 0xee): /* vpmaxsw [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
- vcpu_must_have(avx512bw);
+ visa_check(bw);
generate_exception_if(evex.brs, X86_EXC_UD);
elem_bytes = b & 0x10 ? 1 : 2;
goto avx512f_no_sae;
@@ -5810,7 +5820,7 @@ x86_emulate(
case X86EMUL_OPC_EVEX_66(0x0f38, 0x10): /* vpsrlvw [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
case X86EMUL_OPC_EVEX_66(0x0f38, 0x11): /* vpsravw [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
case X86EMUL_OPC_EVEX_66(0x0f38, 0x12): /* vpsllvw [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
- vcpu_must_have(avx512bw);
+ visa_check(bw);
generate_exception_if(!evex.w || evex.brs, X86_EXC_UD);
elem_bytes = 2;
goto avx512f_no_sae;
@@ -5820,7 +5830,7 @@ x86_emulate(
case X86EMUL_OPC_EVEX_F3(0x0f38, 0x20): /* vpmovswb [xyz]mm,{x,y}mm/mem{k} */
case X86EMUL_OPC_EVEX_66(0x0f38, 0x30): /* vpmovzxbw {x,y}mm/mem,[xyz]mm{k} */
case X86EMUL_OPC_EVEX_F3(0x0f38, 0x30): /* vpmovwb [xyz]mm,{x,y}mm/mem{k} */
- vcpu_must_have(avx512bw);
+ visa_check(bw);
if ( evex.pfx != vex_f3 )
{
case X86EMUL_OPC_EVEX_66(0x0f38, 0x21): /* vpmovsxbd xmm/mem,[xyz]mm{k} */
@@ -5868,7 +5878,7 @@ x86_emulate(
case X86EMUL_OPC_EVEX_66(0x0f38, 0x13): /* vcvtph2ps {x,y}mm/mem,[xyz]mm{k} */
generate_exception_if(evex.w || (ea.type != OP_REG && evex.brs), X86_EXC_UD);
- vcpu_must_have(avx512f);
+ visa_check(f);
if ( !evex.brs )
avx512_vlen_check(false);
op_bytes = 8 << evex.lr;
@@ -5922,7 +5932,7 @@ x86_emulate(
op_bytes = 8;
generate_exception_if(evex.brs, X86_EXC_UD);
if ( !evex.w )
- vcpu_must_have(avx512dq);
+ visa_check(dq);
goto avx512_broadcast;
case X86EMUL_OPC_EVEX_66(0x0f38, 0x1a): /* vbroadcastf32x4 m128,{y,z}mm{k} */
@@ -5932,7 +5942,7 @@ x86_emulate(
generate_exception_if(ea.type != OP_MEM || !evex.lr || evex.brs,
X86_EXC_UD);
if ( evex.w )
- vcpu_must_have(avx512dq);
+ visa_check(dq);
goto avx512_broadcast;
case X86EMUL_OPC_VEX_66(0x0f38, 0x20): /* vpmovsxbw xmm/mem,{x,y}mm */
@@ -5957,9 +5967,9 @@ x86_emulate(
case X86EMUL_OPC_EVEX_F3(0x0f38, 0x28): /* vpmovm2{b,w} k,[xyz]mm */
case X86EMUL_OPC_EVEX_F3(0x0f38, 0x38): /* vpmovm2{d,q} k,[xyz]mm */
if ( b & 0x10 )
- vcpu_must_have(avx512dq);
+ visa_check(dq);
else
- vcpu_must_have(avx512bw);
+ visa_check(bw);
generate_exception_if(evex.opmsk || ea.type != OP_REG, X86_EXC_UD);
d |= TwoOp;
op_bytes = 16 << evex.lr;
@@ -6002,7 +6012,7 @@ x86_emulate(
fault_suppression = false;
/* fall through */
case X86EMUL_OPC_EVEX_66(0x0f38, 0x44): /* vplzcnt{d,q} [xyz]mm/mem,[xyz]mm{k} */
- vcpu_must_have(avx512cd);
+ visa_check(cd);
goto avx512f_no_sae;
case X86EMUL_OPC_VEX_66(0x0f38, 0x2c): /* vmaskmovps mem,{x,y}mm,{x,y}mm */
@@ -6078,7 +6088,7 @@ x86_emulate(
case X86EMUL_OPC_EVEX_66(0x0f38, 0xba): /* vfmsub231p{s,d} [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
case X86EMUL_OPC_EVEX_66(0x0f38, 0xbc): /* vfnmadd231p{s,d} [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
case X86EMUL_OPC_EVEX_66(0x0f38, 0xbe): /* vfnmsub231p{s,d} [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
- vcpu_must_have(avx512f);
+ visa_check(f);
if ( ea.type != OP_REG || !evex.brs )
avx512_vlen_check(false);
goto simd_zmm;
@@ -6097,7 +6107,7 @@ x86_emulate(
case X86EMUL_OPC_EVEX_66(0x0f38, 0xbb): /* vfmsub231s{s,d} xmm/mem,xmm,xmm{k} */
case X86EMUL_OPC_EVEX_66(0x0f38, 0xbd): /* vfnmadd231s{s,d} xmm/mem,xmm,xmm{k} */
case X86EMUL_OPC_EVEX_66(0x0f38, 0xbf): /* vfnmsub231s{s,d} xmm/mem,xmm,xmm{k} */
- vcpu_must_have(avx512f);
+ visa_check(f);
generate_exception_if(ea.type != OP_REG && evex.brs, X86_EXC_UD);
if ( !evex.brs )
avx512_vlen_check(true);
@@ -6111,14 +6121,14 @@ x86_emulate(
case X86EMUL_OPC_EVEX_66(0x0f38, 0x3a): /* vpminuw [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
case X86EMUL_OPC_EVEX_66(0x0f38, 0x3c): /* vpmaxsb [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
case X86EMUL_OPC_EVEX_66(0x0f38, 0x3e): /* vpmaxuw [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
- vcpu_must_have(avx512bw);
+ visa_check(bw);
generate_exception_if(evex.brs, X86_EXC_UD);
elem_bytes = b & 2 ?: 1;
goto avx512f_no_sae;
case X86EMUL_OPC_EVEX_66(0x0f38, 0x40): /* vpmull{d,q} [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
if ( evex.w )
- vcpu_must_have(avx512dq);
+ visa_check(dq);
goto avx512f_no_sae;
case X86EMUL_OPC_66(0x0f38, 0xdb): /* aesimc xmm/m128,xmm */
@@ -6158,7 +6168,7 @@ x86_emulate(
case X86EMUL_OPC_EVEX_66(0x0f38, 0x51): /* vpdpbusds [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
case X86EMUL_OPC_EVEX_66(0x0f38, 0x52): /* vpdpwssd [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
case X86EMUL_OPC_EVEX_66(0x0f38, 0x53): /* vpdpwssds [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
- vcpu_must_have(avx512_vnni);
+ visa_check(_vnni);
generate_exception_if(evex.w, X86_EXC_UD);
goto avx512f_no_sae;
@@ -6170,7 +6180,7 @@ x86_emulate(
d |= TwoOp;
/* fall through */
case X86EMUL_OPC_EVEX_F3(0x0f38, 0x52): /* vdpbf16ps [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
- vcpu_must_have(avx512_bf16);
+ visa_check(_bf16);
generate_exception_if(evex.w, X86_EXC_UD);
op_bytes = 16 << evex.lr;
goto avx512f_no_sae;
@@ -6187,7 +6197,7 @@ x86_emulate(
case X86EMUL_OPC_EVEX_66(0x0f38, 0x4d): /* vrcp14s{s,d} xmm/mem,xmm,xmm{k} */
case X86EMUL_OPC_EVEX_66(0x0f38, 0x4f): /* vrsqrt14s{s,d} xmm/mem,xmm,xmm{k} */
- vcpu_must_have(avx512f);
+ visa_check(f);
generate_exception_if(evex.brs, X86_EXC_UD);
avx512_vlen_check(true);
goto simd_zmm;
@@ -6196,16 +6206,16 @@ x86_emulate(
generate_exception_if(evex.w || !evex.r || !evex.R || evex.z, X86_EXC_UD);
/* fall through */
case X86EMUL_OPC_EVEX_66(0x0f38, 0x54): /* vpopcnt{b,w} [xyz]mm/mem,[xyz]mm{k} */
- vcpu_must_have(avx512_bitalg);
+ visa_check(_bitalg);
/* fall through */
case X86EMUL_OPC_EVEX_66(0x0f38, 0x66): /* vpblendm{b,w} [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
- vcpu_must_have(avx512bw);
+ visa_check(bw);
generate_exception_if(evex.brs, X86_EXC_UD);
elem_bytes = 1 << evex.w;
goto avx512f_no_sae;
case X86EMUL_OPC_EVEX_66(0x0f38, 0x55): /* vpopcnt{d,q} [xyz]mm/mem,[xyz]mm{k} */
- vcpu_must_have(avx512_vpopcntdq);
+ visa_check(_vpopcntdq);
goto avx512f_no_sae;
case X86EMUL_OPC_VEX_66(0x0f38, 0x5a): /* vbroadcasti128 m128,ymm */
@@ -6214,14 +6224,14 @@ x86_emulate(
case X86EMUL_OPC_EVEX_66(0x0f38, 0x62): /* vpexpand{b,w} [xyz]mm/mem,[xyz]mm{k} */
case X86EMUL_OPC_EVEX_66(0x0f38, 0x63): /* vpcompress{b,w} [xyz]mm,[xyz]mm/mem{k} */
- vcpu_must_have(avx512_vbmi2);
+ visa_check(_vbmi2);
elem_bytes = 1 << evex.w;
/* fall through */
case X86EMUL_OPC_EVEX_66(0x0f38, 0x88): /* vexpandp{s,d} [xyz]mm/mem,[xyz]mm{k} */
case X86EMUL_OPC_EVEX_66(0x0f38, 0x89): /* vpexpand{d,q} [xyz]mm/mem,[xyz]mm{k} */
case X86EMUL_OPC_EVEX_66(0x0f38, 0x8a): /* vcompressp{s,d} [xyz]mm,[xyz]mm/mem{k} */
case X86EMUL_OPC_EVEX_66(0x0f38, 0x8b): /* vpcompress{d,q} [xyz]mm,[xyz]mm/mem{k} */
- vcpu_must_have(avx512f);
+ visa_check(f);
generate_exception_if(evex.brs, X86_EXC_UD);
avx512_vlen_check(false);
/*
@@ -6257,7 +6267,7 @@ x86_emulate(
/* fall through */
case X86EMUL_OPC_EVEX_66(0x0f38, 0x71): /* vpshldv{d,q} [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
case X86EMUL_OPC_EVEX_66(0x0f38, 0x73): /* vpshrdv{d,q} [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
- vcpu_must_have(avx512_vbmi2);
+ visa_check(_vbmi2);
goto avx512f_no_sae;
case X86EMUL_OPC_VEX (0x0f38, 0xb0): /* vcvtneoph2ps mem,[xy]mm */
@@ -6277,16 +6287,16 @@ x86_emulate(
case X86EMUL_OPC_EVEX_66(0x0f38, 0x7d): /* vpermt2{b,w} [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
case X86EMUL_OPC_EVEX_66(0x0f38, 0x8d): /* vperm{b,w} [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
if ( !evex.w )
- vcpu_must_have(avx512_vbmi);
+ visa_check(_vbmi);
else
- vcpu_must_have(avx512bw);
+ visa_check(bw);
generate_exception_if(evex.brs, X86_EXC_UD);
fault_suppression = false;
goto avx512f_no_sae;
case X86EMUL_OPC_EVEX_66(0x0f38, 0x78): /* vpbroadcastb xmm/m8,[xyz]mm{k} */
case X86EMUL_OPC_EVEX_66(0x0f38, 0x79): /* vpbroadcastw xmm/m16,[xyz]mm{k} */
- vcpu_must_have(avx512bw);
+ visa_check(bw);
generate_exception_if(evex.w || evex.brs, X86_EXC_UD);
op_bytes = elem_bytes = 1 << (b & 1);
/* See the comment at the avx512_broadcast label. */
@@ -6295,14 +6305,14 @@ x86_emulate(
case X86EMUL_OPC_EVEX_66(0x0f38, 0x7a): /* vpbroadcastb r32,[xyz]mm{k} */
case X86EMUL_OPC_EVEX_66(0x0f38, 0x7b): /* vpbroadcastw r32,[xyz]mm{k} */
- vcpu_must_have(avx512bw);
+ visa_check(bw);
generate_exception_if(evex.w, X86_EXC_UD);
/* fall through */
case X86EMUL_OPC_EVEX_66(0x0f38, 0x7c): /* vpbroadcast{d,q} reg,[xyz]mm{k} */
generate_exception_if((ea.type != OP_REG || evex.brs ||
evex.reg != 0xf || !evex.RX),
X86_EXC_UD);
- vcpu_must_have(avx512f);
+ visa_check(f);
avx512_vlen_check(false);
get_fpu(X86EMUL_FPU_zmm);
@@ -6371,7 +6381,7 @@ x86_emulate(
case X86EMUL_OPC_EVEX_66(0x0f38, 0x83): /* vpmultishiftqb [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
generate_exception_if(!evex.w, X86_EXC_UD);
- vcpu_must_have(avx512_vbmi);
+ visa_check(_vbmi);
fault_suppression = false;
goto avx512f_no_sae;
@@ -6529,8 +6539,8 @@ x86_emulate(
evex.reg != 0xf ||
modrm_reg == state->sib_index),
X86_EXC_UD);
+ visa_check(f);
avx512_vlen_check(false);
- vcpu_must_have(avx512f);
get_fpu(X86EMUL_FPU_zmm);
/* Read destination and index registers. */
@@ -6691,8 +6701,8 @@ x86_emulate(
evex.reg != 0xf ||
modrm_reg == state->sib_index),
X86_EXC_UD);
+ visa_check(f);
avx512_vlen_check(false);
- vcpu_must_have(avx512f);
get_fpu(X86EMUL_FPU_zmm);
/* Read source and index registers. */
@@ -6808,7 +6818,7 @@ x86_emulate(
case X86EMUL_OPC_EVEX_66(0x0f38, 0xb4): /* vpmadd52luq [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
case X86EMUL_OPC_EVEX_66(0x0f38, 0xb5): /* vpmadd52huq [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
- vcpu_must_have(avx512_ifma);
+ visa_check(_ifma);
generate_exception_if(!evex.w, X86_EXC_UD);
goto avx512f_no_sae;
@@ -7288,7 +7298,7 @@ x86_emulate(
/* fall through */
case X86EMUL_OPC_EVEX_66(0x0f3a, 0x08): /* vrndscaleps $imm8,[xyz]mm/mem,[xyz]mm{k} */
case X86EMUL_OPC_EVEX_66(0x0f3a, 0x09): /* vrndscalepd $imm8,[xyz]mm/mem,[xyz]mm{k} */
- vcpu_must_have(avx512f);
+ visa_check(f);
generate_exception_if(evex.w != (b & 1), X86_EXC_UD);
avx512_vlen_check(b & 2);
goto simd_imm8_zmm;
@@ -7297,7 +7307,7 @@ x86_emulate(
generate_exception_if(ea.type != OP_REG && evex.brs, X86_EXC_UD);
/* fall through */
case X86EMUL_OPC_EVEX(0x0f3a, 0x08): /* vrndscaleph $imm8,[xyz]mm/mem,[xyz]mm{k} */
- vcpu_must_have(avx512_fp16);
+ visa_check(_fp16);
generate_exception_if(evex.w, X86_EXC_UD);
avx512_vlen_check(b & 2);
goto simd_imm8_zmm;
@@ -7410,11 +7420,11 @@ x86_emulate(
evex.opmsk || evex.brs),
X86_EXC_UD);
if ( !(b & 2) )
- vcpu_must_have(avx512bw);
+ visa_check(bw);
else if ( !(b & 1) )
- vcpu_must_have(avx512dq);
+ visa_check(dq);
else
- vcpu_must_have(avx512f);
+ visa_check(f);
get_fpu(X86EMUL_FPU_zmm);
opc = init_evex(stub);
goto pextr;
@@ -7428,7 +7438,7 @@ x86_emulate(
case X86EMUL_OPC_EVEX_66(0x0f3a, 0x39): /* vextracti32x4 $imm8,{y,z}mm,xmm/m128{k} */
/* vextracti64x2 $imm8,{y,z}mm,xmm/m128{k} */
if ( evex.w )
- vcpu_must_have(avx512dq);
+ visa_check(dq);
generate_exception_if(evex.brs, X86_EXC_UD);
/* fall through */
case X86EMUL_OPC_EVEX_66(0x0f3a, 0x23): /* vshuff32x4 $imm8,{y,z}mm/mem,{y,z}mm,{y,z}mm{k} */
@@ -7448,7 +7458,7 @@ x86_emulate(
case X86EMUL_OPC_EVEX_66(0x0f3a, 0x3b): /* vextracti32x8 $imm8,zmm,ymm/m256{k} */
/* vextracti64x4 $imm8,zmm,ymm/m256{k} */
if ( !evex.w )
- vcpu_must_have(avx512dq);
+ visa_check(dq);
generate_exception_if(evex.lr != 2 || evex.brs, X86_EXC_UD);
fault_suppression = false;
goto avx512f_imm8_no_sae;
@@ -7464,7 +7474,7 @@ x86_emulate(
generate_exception_if((evex.w || evex.reg != 0xf || !evex.RX ||
(ea.type != OP_REG && evex.brs)),
X86_EXC_UD);
- vcpu_must_have(avx512f);
+ visa_check(f);
avx512_vlen_check(false);
opc = init_evex(stub);
}
@@ -7556,7 +7566,7 @@ x86_emulate(
if ( !(b & 0x20) )
goto avx512f_imm8_no_sae;
avx512bw_imm:
- vcpu_must_have(avx512bw);
+ visa_check(bw);
generate_exception_if(evex.brs, X86_EXC_UD);
elem_bytes = 1 << evex.w;
avx512_vlen_check(false);
@@ -7595,7 +7605,7 @@ x86_emulate(
goto simd_0f_imm8_avx;
case X86EMUL_OPC_EVEX_66(0x0f3a, 0x21): /* vinsertps $imm8,xmm/m32,xmm,xmm */
- vcpu_must_have(avx512f);
+ visa_check(f);
generate_exception_if(evex.lr || evex.w || evex.opmsk || evex.brs,
X86_EXC_UD);
op_bytes = 4;
@@ -7603,18 +7613,18 @@ x86_emulate(
case X86EMUL_OPC_EVEX_66(0x0f3a, 0x50): /* vrangep{s,d} $imm8,[xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
case X86EMUL_OPC_EVEX_66(0x0f3a, 0x56): /* vreducep{s,d} $imm8,[xyz]mm/mem,[xyz]mm{k} */
- vcpu_must_have(avx512dq);
+ visa_check(dq);
/* fall through */
case X86EMUL_OPC_EVEX_66(0x0f3a, 0x26): /* vgetmantp{s,d} $imm8,[xyz]mm/mem,[xyz]mm{k} */
case X86EMUL_OPC_EVEX_66(0x0f3a, 0x54): /* vfixupimmp{s,d} $imm8,[xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
- vcpu_must_have(avx512f);
+ visa_check(f);
if ( ea.type != OP_REG || !evex.brs )
avx512_vlen_check(false);
goto simd_imm8_zmm;
case X86EMUL_OPC_EVEX(0x0f3a, 0x26): /* vgetmantph $imm8,[xyz]mm/mem,[xyz]mm{k} */
case X86EMUL_OPC_EVEX(0x0f3a, 0x56): /* vreduceph $imm8,[xyz]mm/mem,[xyz]mm{k} */
- vcpu_must_have(avx512_fp16);
+ visa_check(_fp16);
generate_exception_if(evex.w, X86_EXC_UD);
if ( ea.type != OP_REG || !evex.brs )
avx512_vlen_check(false);
@@ -7622,11 +7632,11 @@ x86_emulate(
case X86EMUL_OPC_EVEX_66(0x0f3a, 0x51): /* vranges{s,d} $imm8,xmm/mem,xmm,xmm{k} */
case X86EMUL_OPC_EVEX_66(0x0f3a, 0x57): /* vreduces{s,d} $imm8,xmm/mem,xmm,xmm{k} */
- vcpu_must_have(avx512dq);
+ visa_check(dq);
/* fall through */
case X86EMUL_OPC_EVEX_66(0x0f3a, 0x27): /* vgetmants{s,d} $imm8,xmm/mem,xmm,xmm{k} */
case X86EMUL_OPC_EVEX_66(0x0f3a, 0x55): /* vfixupimms{s,d} $imm8,xmm/mem,xmm,xmm{k} */
- vcpu_must_have(avx512f);
+ visa_check(f);
generate_exception_if(ea.type != OP_REG && evex.brs, X86_EXC_UD);
if ( !evex.brs )
avx512_vlen_check(true);
@@ -7634,7 +7644,7 @@ x86_emulate(
case X86EMUL_OPC_EVEX(0x0f3a, 0x27): /* vgetmantsh $imm8,xmm/mem,xmm,xmm{k} */
case X86EMUL_OPC_EVEX(0x0f3a, 0x57): /* vreducesh $imm8,xmm/mem,xmm,xmm{k} */
- vcpu_must_have(avx512_fp16);
+ visa_check(_fp16);
generate_exception_if(evex.w, X86_EXC_UD);
if ( !evex.brs )
avx512_vlen_check(true);
@@ -7645,18 +7655,19 @@ x86_emulate(
case X86EMUL_OPC_VEX_66(0x0f3a, 0x30): /* kshiftr{b,w} $imm8,k,k */
case X86EMUL_OPC_VEX_66(0x0f3a, 0x32): /* kshiftl{b,w} $imm8,k,k */
if ( !vex.w )
- vcpu_must_have(avx512dq);
+ visa_check(dq);
+ else
+ visa_check(f);
opmask_shift_imm:
generate_exception_if(vex.l || !vex.r || vex.reg != 0xf ||
ea.type != OP_REG, X86_EXC_UD);
- vcpu_must_have(avx512f);
get_fpu(X86EMUL_FPU_opmask);
op_bytes = 1; /* Any non-zero value will do. */
goto simd_0f_imm8;
case X86EMUL_OPC_VEX_66(0x0f3a, 0x31): /* kshiftr{d,q} $imm8,k,k */
case X86EMUL_OPC_VEX_66(0x0f3a, 0x33): /* kshiftl{d,q} $imm8,k,k */
- vcpu_must_have(avx512bw);
+ visa_check(bw);
goto opmask_shift_imm;
case X86EMUL_OPC_66(0x0f3a, 0x44): /* pclmulqdq $imm8,xmm/m128,xmm */
@@ -7797,7 +7808,7 @@ x86_emulate(
case X86EMUL_OPC_EVEX_66(0x0f3a, 0x66): /* vfpclassp{s,d} $imm8,[xyz]mm/mem,k{k} */
case X86EMUL_OPC_EVEX_66(0x0f3a, 0x67): /* vfpclasss{s,d} $imm8,xmm/mem,k{k} */
- vcpu_must_have(avx512dq);
+ visa_check(dq);
generate_exception_if(!evex.r || !evex.R || evex.z, X86_EXC_UD);
if ( !(b & 1) )
goto avx512f_imm8_no_sae;
@@ -7807,7 +7818,7 @@ x86_emulate(
case X86EMUL_OPC_EVEX(0x0f3a, 0x66): /* vfpclassph $imm8,[xyz]mm/mem,k{k} */
case X86EMUL_OPC_EVEX(0x0f3a, 0x67): /* vfpclasssh $imm8,xmm/mem,k{k} */
- vcpu_must_have(avx512_fp16);
+ visa_check(_fp16);
generate_exception_if(evex.w || !evex.r || !evex.R || evex.z, X86_EXC_UD);
if ( !(b & 1) )
goto avx512f_imm8_no_sae;
@@ -7822,14 +7833,14 @@ x86_emulate(
/* fall through */
case X86EMUL_OPC_EVEX_66(0x0f3a, 0x71): /* vpshld{d,q} $imm8,[xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
case X86EMUL_OPC_EVEX_66(0x0f3a, 0x73): /* vpshrd{d,q} $imm8,[xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
- vcpu_must_have(avx512_vbmi2);
+ visa_check(_vbmi2);
goto avx512f_imm8_no_sae;
case X86EMUL_OPC_EVEX_F3(0x0f3a, 0xc2): /* vcmpsh $imm8,xmm/mem,xmm,k{k} */
generate_exception_if(ea.type != OP_REG && evex.brs, X86_EXC_UD);
/* fall through */
case X86EMUL_OPC_EVEX(0x0f3a, 0xc2): /* vcmpph $imm8,[xyz]mm/mem,[xyz]mm,k{k} */
- vcpu_must_have(avx512_fp16);
+ visa_check(_fp16);
generate_exception_if(evex.w || !evex.r || !evex.R || evex.z, X86_EXC_UD);
if ( ea.type != OP_REG || !evex.brs )
avx512_vlen_check(evex.pfx & VEX_PREFIX_SCALAR_MASK);
@@ -7905,13 +7916,13 @@ x86_emulate(
CASE_SIMD_SINGLE_FP(_EVEX, 5, 0x5d): /* vmin{p,s}h [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
CASE_SIMD_SINGLE_FP(_EVEX, 5, 0x5e): /* vdiv{p,s}h [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
CASE_SIMD_SINGLE_FP(_EVEX, 5, 0x5f): /* vmax{p,s}h [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
- vcpu_must_have(avx512_fp16);
+ visa_check(_fp16);
generate_exception_if(evex.w, X86_EXC_UD);
goto avx512f_all_fp;
CASE_SIMD_ALL_FP(_EVEX, 5, 0x5a): /* vcvtp{h,d}2p{h,d} [xyz]mm/mem,[xyz]mm{k} */
/* vcvts{h,d}2s{h,d} xmm/mem,xmm,xmm{k} */
- vcpu_must_have(avx512_fp16);
+ visa_check(_fp16);
if ( vex.pfx & VEX_PREFIX_SCALAR_MASK )
d &= ~TwoOp;
op_bytes = 2 << (((evex.pfx & VEX_PREFIX_SCALAR_MASK) ? 0 : 1 + evex.lr) +
@@ -7922,7 +7933,7 @@ x86_emulate(
/* vcvtqq2ph [xyz]mm/mem,xmm{k} */
case X86EMUL_OPC_EVEX_F2(5, 0x7a): /* vcvtudq2ph [xyz]mm/mem,[xy]mm{k} */
/* vcvtuqq2ph [xyz]mm/mem,xmm{k} */
- vcpu_must_have(avx512_fp16);
+ visa_check(_fp16);
if ( ea.type != OP_REG || !evex.brs )
avx512_vlen_check(false);
op_bytes = 16 << evex.lr;
@@ -7932,7 +7943,7 @@ x86_emulate(
case X86EMUL_OPC_EVEX_F3(5, 0x5b): /* vcvttph2dq [xy]mm/mem,[xyz]mm{k} */
case X86EMUL_OPC_EVEX (5, 0x78): /* vcvttph2udq [xy]mm/mem,[xyz]mm{k} */
case X86EMUL_OPC_EVEX (5, 0x79): /* vcvtph2udq [xy]mm/mem,[xyz]mm{k} */
- vcpu_must_have(avx512_fp16);
+ visa_check(_fp16);
generate_exception_if(evex.w, X86_EXC_UD);
if ( ea.type != OP_REG || !evex.brs )
avx512_vlen_check(false);
@@ -7954,7 +7965,7 @@ x86_emulate(
case X86EMUL_OPC_EVEX_66(5, 0x79): /* vcvtph2uqq xmm/mem,[xyz]mm{k} */
case X86EMUL_OPC_EVEX_66(5, 0x7a): /* vcvttph2qq xmm/mem,[xyz]mm{k} */
case X86EMUL_OPC_EVEX_66(5, 0x7b): /* vcvtph2qq xmm/mem,[xyz]mm{k} */
- vcpu_must_have(avx512_fp16);
+ visa_check(_fp16);
generate_exception_if(evex.w, X86_EXC_UD);
if ( ea.type != OP_REG || !evex.brs )
avx512_vlen_check(false);
@@ -7991,7 +8002,7 @@ x86_emulate(
case X86EMUL_OPC_EVEX_66(6, 0xba): /* vfmsub231ph [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
case X86EMUL_OPC_EVEX_66(6, 0xbc): /* vfnmadd231ph [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
case X86EMUL_OPC_EVEX_66(6, 0xbe): /* vfnmsub231ph [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
- vcpu_must_have(avx512_fp16);
+ visa_check(_fp16);
generate_exception_if(evex.w, X86_EXC_UD);
if ( ea.type != OP_REG || !evex.brs )
avx512_vlen_check(false);
@@ -8013,7 +8024,7 @@ x86_emulate(
case X86EMUL_OPC_EVEX_66(6, 0xbb): /* vfmsub231sh xmm/m16,xmm,xmm{k} */
case X86EMUL_OPC_EVEX_66(6, 0xbd): /* vfnmadd231sh xmm/m16,xmm,xmm{k} */
case X86EMUL_OPC_EVEX_66(6, 0xbf): /* vfnmsub231sh xmm/m16,xmm,xmm{k} */
- vcpu_must_have(avx512_fp16);
+ visa_check(_fp16);
generate_exception_if(evex.w || (ea.type != OP_REG && evex.brs),
X86_EXC_UD);
if ( !evex.brs )
@@ -8022,13 +8033,13 @@ x86_emulate(
case X86EMUL_OPC_EVEX_66(6, 0x4c): /* vrcpph [xyz]mm/mem,[xyz]mm{k} */
case X86EMUL_OPC_EVEX_66(6, 0x4e): /* vrsqrtph [xyz]mm/mem,[xyz]mm{k} */
- vcpu_must_have(avx512_fp16);
+ visa_check(_fp16);
generate_exception_if(evex.w, X86_EXC_UD);
goto avx512f_no_sae;
case X86EMUL_OPC_EVEX_66(6, 0x4d): /* vrcpsh xmm/m16,xmm,xmm{k} */
case X86EMUL_OPC_EVEX_66(6, 0x4f): /* vrsqrtsh xmm/m16,xmm,xmm{k} */
- vcpu_must_have(avx512_fp16);
+ visa_check(_fp16);
generate_exception_if(evex.w || evex.brs, X86_EXC_UD);
avx512_vlen_check(true);
goto simd_zmm;
@@ -8046,7 +8057,7 @@ x86_emulate(
{
unsigned int src1 = ~evex.reg;
- vcpu_must_have(avx512_fp16);
+ visa_check(_fp16);
generate_exception_if(evex.w || ((b & 1) && ea.type != OP_REG && evex.brs),
X86_EXC_UD);
if ( mode_64bit() )
--- a/xen/arch/x86/xstate.c
+++ b/xen/arch/x86/xstate.c
@@ -814,7 +814,7 @@ static void __init noinline xstate_check
if ( cpu_has_mpx )
check_new_xstate(&s, X86_XCR0_BNDCSR | X86_XCR0_BNDREGS);
- if ( cpu_has_avx512f )
+ if ( boot_cpu_has(X86_FEATURE_AVX512F) || boot_cpu_has(X86_FEATURE_AVX10) )
check_new_xstate(&s, X86_XCR0_HI_ZMM | X86_XCR0_ZMM | X86_XCR0_OPMASK);
/*
--- a/xen/include/public/arch-x86/cpufeatureset.h
+++ b/xen/include/public/arch-x86/cpufeatureset.h
@@ -366,7 +366,7 @@ XEN_CPUFEATURE(PREFETCHI, 15*32
XEN_CPUFEATURE(USER_MSR, 15*32+15) /*s U{RD,WR}MSR Instructions */
XEN_CPUFEATURE(UIRET_UIF, 15*32+17) /* UIRET updates UIF */
XEN_CPUFEATURE(CET_SSS, 15*32+18) /* CET Supervisor Shadow Stacks safe to use */
-XEN_CPUFEATURE(AVX10, 15*32+19) /* AVX10 Converged Vector ISA */
+XEN_CPUFEATURE(AVX10, 15*32+19) /*a AVX10 Converged Vector ISA */
XEN_CPUFEATURE(SLSM, 15*32+24) /* Static Lockstep Mode */
/* Intel-defined CPU features, MSR_ARCH_CAPS 0x10a.eax, word 16 */
^ permalink raw reply [flat|nested] 20+ messages in thread* [PATCH v5 05/19] x86emul/test: use simd_check_avx512*() in main()
2026-11-11 13:40 [PATCH v5 00/19] x86: support AVX10 Jan Beulich
` (3 preceding siblings ...)
2026-11-11 13:42 ` [PATCH v5 04/19] x86emul: support AVX10.1 Jan Beulich
@ 2026-11-11 13:43 ` Jan Beulich
2026-11-11 13:44 ` [PATCH v5 06/19] x86emul/test: drop cpu_has_avx512vl Jan Beulich
` (13 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Jan Beulich @ 2026-11-11 13:43 UTC (permalink / raw)
To: xen-devel@lists.xenproject.org
Cc: Andrew Cooper, Teddy Astie, Roger Pau Monné
In preparation for having these also cover AVX10, use the helper
functions in preference of open-coded cpu_has_avx512* for those features
that AVX10 includes. Introduce a couple further helper functions where
they weren't previously needed.
Note that this way simd_check_avx512f_sha_vl() gains an AVX512F check
(which is likely benign) and simd_check_avx512bw_gf_vl() gains an
AVX512BW check (which was clearly missing).
Signed-off-by: Jan Beulich <jbeulich@suse.com>
---
v2: Re-base over dropping of Xeon Phi support.
--- a/tools/tests/x86_emulator/test_x86_emulator.c
+++ b/tools/tests/x86_emulator/test_x86_emulator.c
@@ -167,6 +167,11 @@ static bool simd_check_avx512vbmi_vl(voi
return cpu_has_avx512_vbmi && cpu_has_avx512vl;
}
+static bool simd_check_avx512vbmi2(void)
+{
+ return cpu_has_avx512_vbmi2;
+}
+
static bool simd_check_sse4_sha(void)
{
return cpu_has_sha && cpu_has_sse4_2;
@@ -179,7 +184,7 @@ static bool simd_check_avx_sha(void)
static bool simd_check_avx512f_sha_vl(void)
{
- return cpu_has_sha && cpu_has_avx512vl;
+ return cpu_has_sha && simd_check_avx512f_vl();
}
static bool simd_check_avx2_vaes(void)
@@ -189,13 +194,13 @@ static bool simd_check_avx2_vaes(void)
static bool simd_check_avx512bw_vaes(void)
{
- return cpu_has_aesni && cpu_has_vaes && cpu_has_avx512bw;
+ return cpu_has_aesni && cpu_has_vaes && simd_check_avx512bw();
}
static bool simd_check_avx512bw_vaes_vl(void)
{
return cpu_has_aesni && cpu_has_vaes &&
- cpu_has_avx512bw && cpu_has_avx512vl;
+ simd_check_avx512bw_vl();
}
static bool simd_check_avx2_vpclmulqdq(void)
@@ -205,22 +210,22 @@ static bool simd_check_avx2_vpclmulqdq(v
static bool simd_check_avx512bw_vpclmulqdq(void)
{
- return cpu_has_vpclmulqdq && cpu_has_avx512bw;
+ return cpu_has_vpclmulqdq && simd_check_avx512bw();
}
static bool simd_check_avx512bw_vpclmulqdq_vl(void)
{
- return cpu_has_vpclmulqdq && cpu_has_avx512bw && cpu_has_avx512vl;
+ return cpu_has_vpclmulqdq && simd_check_avx512bw_vl();
}
static bool simd_check_avx512vbmi2_vpclmulqdq(void)
{
- return cpu_has_avx512_vbmi2 && simd_check_avx512bw_vpclmulqdq();
+ return simd_check_avx512vbmi2() && simd_check_avx512bw_vpclmulqdq();
}
static bool simd_check_avx512vbmi2_vpclmulqdq_vl(void)
{
- return cpu_has_avx512_vbmi2 && simd_check_avx512bw_vpclmulqdq_vl();
+ return simd_check_avx512vbmi2() && simd_check_avx512bw_vpclmulqdq_vl();
}
static bool simd_check_sse2_gf(void)
@@ -235,12 +240,17 @@ static bool simd_check_avx2_gf(void)
static bool simd_check_avx512bw_gf(void)
{
- return cpu_has_gfni && cpu_has_avx512bw;
+ return cpu_has_gfni && simd_check_avx512bw();
}
static bool simd_check_avx512bw_gf_vl(void)
{
- return cpu_has_gfni && cpu_has_avx512vl;
+ return cpu_has_gfni && simd_check_avx512bw_vl();
+}
+
+static bool simd_check_avx512vnni(void)
+{
+ return cpu_has_avx512_vnni;
}
static bool simd_check_avx512fp16(void)
@@ -3192,7 +3202,7 @@ int main(int argc, char **argv)
printf("skipped\n");
printf("%-40s", "Testing {evex} vmovq %xmm1,32(%edx)...");
- if ( stack_exec && cpu_has_avx512f )
+ if ( stack_exec && simd_check_avx512f() )
{
decl_insn(evex_vmovq_to_mem);
@@ -3216,7 +3226,7 @@ int main(int argc, char **argv)
printf("skipped\n");
printf("%-40s", "Testing {evex} vmovq 32(%edx),%xmm0...");
- if ( stack_exec && cpu_has_avx512f )
+ if ( stack_exec && simd_check_avx512f() )
{
decl_insn(evex_vmovq_from_mem);
@@ -3339,7 +3349,7 @@ int main(int argc, char **argv)
printf("skipped\n");
printf("%-40s", "Testing vmovdqu32 %zmm2,(%ecx){%k1}...");
- if ( stack_exec && cpu_has_avx512f )
+ if ( stack_exec && simd_check_avx512f() )
{
decl_insn(vmovdqu32_to_mem);
@@ -3369,7 +3379,7 @@ int main(int argc, char **argv)
printf("skipped\n");
printf("%-40s", "Testing vmovdqu32 64(%edx),%zmm2{%k2}...");
- if ( stack_exec && cpu_has_avx512f )
+ if ( stack_exec && simd_check_avx512f() )
{
decl_insn(vmovdqu32_from_mem);
@@ -3394,7 +3404,7 @@ int main(int argc, char **argv)
printf("skipped\n");
printf("%-40s", "Testing vmovdqu16 %zmm3,(%ecx){%k1}...");
- if ( stack_exec && cpu_has_avx512bw )
+ if ( stack_exec && simd_check_avx512bw() )
{
decl_insn(vmovdqu16_to_mem);
@@ -3426,7 +3436,7 @@ int main(int argc, char **argv)
printf("skipped\n");
printf("%-40s", "Testing vmovdqu16 64(%edx),%zmm3{%k2}...");
- if ( stack_exec && cpu_has_avx512bw )
+ if ( stack_exec && simd_check_avx512bw() )
{
decl_insn(vmovdqu16_from_mem);
@@ -3554,7 +3564,7 @@ int main(int argc, char **argv)
printf("%-40s", "Testing vmovsd %xmm5,16(%ecx){%k3}...");
memset(res, 0x88, 128);
memset(res + 20, 0x77, 8);
- if ( stack_exec && cpu_has_avx512f )
+ if ( stack_exec && simd_check_avx512f() )
{
decl_insn(vmovsd_masked_to_mem);
@@ -3589,7 +3599,7 @@ int main(int argc, char **argv)
}
printf("%-40s", "Testing vmovaps (%edx),%zmm7{%k3}{z}...");
- if ( stack_exec && cpu_has_avx512f )
+ if ( stack_exec && simd_check_avx512f() )
{
decl_insn(vmovaps_masked_from_mem);
@@ -3772,7 +3782,7 @@ int main(int argc, char **argv)
printf("skipped\n");
printf("%-40s", "Testing {evex} vmovd %xmm3,32(%ecx)...");
- if ( stack_exec && cpu_has_avx512f )
+ if ( stack_exec && simd_check_avx512f() )
{
decl_insn(evex_vmovd_to_mem);
@@ -3797,7 +3807,7 @@ int main(int argc, char **argv)
printf("skipped\n");
printf("%-40s", "Testing {evex} vmovd 32(%ecx),%xmm4...");
- if ( stack_exec && cpu_has_avx512f )
+ if ( stack_exec && simd_check_avx512f() )
{
decl_insn(evex_vmovd_from_mem);
@@ -3987,7 +3997,7 @@ int main(int argc, char **argv)
printf("skipped\n");
printf("%-40s", "Testing {evex} vmovd %xmm2,%ebx...");
- if ( stack_exec && cpu_has_avx512f )
+ if ( stack_exec && simd_check_avx512f() )
{
decl_insn(evex_vmovd_to_reg);
@@ -4013,7 +4023,7 @@ int main(int argc, char **argv)
printf("skipped\n");
printf("%-40s", "Testing {evex} vmovd %ebx,%xmm1...");
- if ( stack_exec && cpu_has_avx512f )
+ if ( stack_exec && simd_check_avx512f() )
{
decl_insn(evex_vmovd_from_reg);
@@ -4115,7 +4125,7 @@ int main(int argc, char **argv)
printf("skipped\n");
printf("%-40s", "Testing {evex} vmovq %xmm11,32(%ecx)...");
- if ( stack_exec && cpu_has_avx512f )
+ if ( stack_exec && simd_check_avx512f() )
{
decl_insn(evex_vmovq_to_mem2);
@@ -4205,7 +4215,7 @@ int main(int argc, char **argv)
printf("skipped\n");
printf("%-40s", "Testing vmovq %xmm22,%rbx...");
- if ( stack_exec && cpu_has_avx512f )
+ if ( stack_exec && simd_check_avx512f() )
{
decl_insn(evex_vmovq_to_reg);
@@ -4398,7 +4408,7 @@ int main(int argc, char **argv)
printf("skipped\n");
printf("%-40s", "Testing vmovntdqa 64(%ecx),%zmm4...");
- if ( stack_exec && cpu_has_avx512f )
+ if ( stack_exec && simd_check_avx512f() )
{
decl_insn(evex_vmovntdqa);
@@ -4994,7 +5004,7 @@ int main(int argc, char **argv)
printf("skipped\n");
printf("%-40s", "Testing vcvtph2ps 32(%ecx),%zmm7{%k4}...");
- if ( stack_exec && cpu_has_avx512f )
+ if ( stack_exec && simd_check_avx512f() )
{
decl_insn(evex_vcvtph2ps);
decl_insn(evex_vcvtps2ph);
@@ -5037,7 +5047,7 @@ int main(int argc, char **argv)
printf("skipped\n");
printf("%-40s", "Testing vfixupimmpd $0,8(%edx){1to8},%zmm3,%zmm4...");
- if ( stack_exec && cpu_has_avx512f )
+ if ( stack_exec && simd_check_avx512f() )
{
decl_insn(vfixupimmpd);
static const struct {
@@ -5076,7 +5086,7 @@ int main(int argc, char **argv)
printf("%-40s", "Testing vfpclasspsz $0x46,64(%edx),%k2...");
- if ( stack_exec && cpu_has_avx512dq )
+ if ( stack_exec && simd_check_avx512dq() )
{
decl_insn(vfpclassps);
@@ -5108,7 +5118,7 @@ int main(int argc, char **argv)
printf("skipped\n");
printf("%-40s", "Testing vfpclassphz $0x46,128(%ecx),%k3...");
- if ( stack_exec && cpu_has_avx512_fp16 )
+ if ( stack_exec && simd_check_avx512fp16() )
{
decl_insn(vfpclassph);
@@ -5151,7 +5161,7 @@ int main(int argc, char **argv)
* on the mapping boundaries) that elements controlled by clear mask
* bits don't get accessed.
*/
- if ( stack_exec && cpu_has_avx512f )
+ if ( stack_exec && simd_check_avx512f() )
{
decl_insn(vpcompressd);
decl_insn(vpcompressq);
@@ -5253,7 +5263,7 @@ int main(int argc, char **argv)
}
#if __GNUC__ > 7 /* can't check for __AVX512VBMI2__ here */
- if ( stack_exec && cpu_has_avx512_vbmi2 )
+ if ( stack_exec && simd_check_avx512vbmi2() )
{
decl_insn(vpcompressb);
decl_insn(vpcompressw);
@@ -5441,7 +5451,7 @@ int main(int argc, char **argv)
}
printf("%-40s", "Testing vpdpwssd (%ecx),%{y,z}mmA,%{y,z}mmB...");
- if ( stack_exec && cpu_has_avx512_vnni && cpu_has_avx_vnni )
+ if ( stack_exec && simd_check_avx512vnni() && cpu_has_avx_vnni )
{
/* Do the same operation two ways and compare the results. */
decl_insn(vpdpwssd_vex1);
@@ -5496,7 +5506,7 @@ int main(int argc, char **argv)
printf("skipped\n");
printf("%-40s", "Testing vmovsh 8(%ecx),%xmm5...");
- if ( stack_exec && cpu_has_avx512_fp16 )
+ if ( stack_exec && simd_check_avx512fp16() )
{
decl_insn(vmovsh_from_mem);
decl_insn(vmovw_to_gpr);
^ permalink raw reply [flat|nested] 20+ messages in thread* [PATCH v5 06/19] x86emul/test: drop cpu_has_avx512vl
2026-11-11 13:40 [PATCH v5 00/19] x86: support AVX10 Jan Beulich
` (4 preceding siblings ...)
2026-11-11 13:43 ` [PATCH v5 05/19] x86emul/test: use simd_check_avx512*() in main() Jan Beulich
@ 2026-11-11 13:44 ` Jan Beulich
2026-11-11 13:44 ` [PATCH v5 07/19] x86emul: AVX10.1 testing Jan Beulich
` (12 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Jan Beulich @ 2026-11-11 13:44 UTC (permalink / raw)
To: xen-devel@lists.xenproject.org
Cc: Andrew Cooper, Teddy Astie, Roger Pau Monné
AVX512VL not being a standalone feature anyway, but always needing
to be combined with some other AVX512*, replace uses of
cpu_has_avx512vl by just the feature bit check.
Signed-off-by: Jan Beulich <jbeulich@suse.com>
---
v2: Re-base over dropping of Xeon Phi support.
--- a/tools/tests/x86_emulator/evex-disp8.c
+++ b/tools/tests/x86_emulator/evex-disp8.c
@@ -1025,7 +1025,8 @@ static void test_group(const struct test
{
for ( j = 0; j < nr_vl; ++j )
{
- if ( vl[0] == VL_512 && vl[j] != VL_512 && !cpu_has_avx512vl )
+ if ( vl[0] == VL_512 && vl[j] != VL_512 &&
+ !cpu_policy.feat.avx512vl )
continue;
switch ( tests[i].esz )
--- a/tools/tests/x86_emulator/test_x86_emulator.c
+++ b/tools/tests/x86_emulator/test_x86_emulator.c
@@ -131,7 +131,7 @@ static bool simd_check_avx512f(void)
static bool simd_check_avx512f_vl(void)
{
- return cpu_has_avx512f && cpu_has_avx512vl;
+ return cpu_has_avx512f && cpu_policy.feat.avx512vl;
}
#define simd_check_avx512vl_sg simd_check_avx512f_vl
@@ -143,7 +143,7 @@ static bool simd_check_avx512dq(void)
static bool simd_check_avx512dq_vl(void)
{
- return cpu_has_avx512dq && cpu_has_avx512vl;
+ return cpu_has_avx512dq && cpu_policy.feat.avx512vl;
}
static bool simd_check_avx512bw(void)
@@ -154,7 +154,7 @@ static bool simd_check_avx512bw(void)
static bool simd_check_avx512bw_vl(void)
{
- return cpu_has_avx512bw && cpu_has_avx512vl;
+ return cpu_has_avx512bw && cpu_policy.feat.avx512vl;
}
static bool simd_check_avx512vbmi(void)
@@ -164,7 +164,7 @@ static bool simd_check_avx512vbmi(void)
static bool simd_check_avx512vbmi_vl(void)
{
- return cpu_has_avx512_vbmi && cpu_has_avx512vl;
+ return cpu_has_avx512_vbmi && cpu_policy.feat.avx512vl;
}
static bool simd_check_avx512vbmi2(void)
@@ -260,7 +260,7 @@ static bool simd_check_avx512fp16(void)
static bool simd_check_avx512fp16_vl(void)
{
- return cpu_has_avx512_fp16 && cpu_has_avx512vl;
+ return cpu_has_avx512_fp16 && cpu_policy.feat.avx512vl;
}
static void simd_set_regs(struct cpu_user_regs *regs)
--- a/tools/tests/x86_emulator/x86-emulate.h
+++ b/tools/tests/x86_emulator/x86-emulate.h
@@ -181,8 +181,6 @@ void wrpkru(unsigned int val);
#define cpu_has_sha cpu_policy.feat.sha
#define cpu_has_avx512bw (cpu_policy.feat.avx512bw && \
xcr0_mask(0xe6))
-#define cpu_has_avx512vl (cpu_policy.feat.avx512vl && \
- xcr0_mask(0xe6))
#define cpu_has_avx512_vbmi (cpu_policy.feat.avx512_vbmi && \
xcr0_mask(0xe6))
#define cpu_has_avx512_vbmi2 (cpu_policy.feat.avx512_vbmi2 && \
^ permalink raw reply [flat|nested] 20+ messages in thread* [PATCH v5 07/19] x86emul: AVX10.1 testing
2026-11-11 13:40 [PATCH v5 00/19] x86: support AVX10 Jan Beulich
` (5 preceding siblings ...)
2026-11-11 13:44 ` [PATCH v5 06/19] x86emul/test: drop cpu_has_avx512vl Jan Beulich
@ 2026-11-11 13:44 ` Jan Beulich
2026-11-11 13:45 ` [PATCH v5 08/19] x86emul/test: engage AVX512VL via command line option Jan Beulich
` (11 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Jan Beulich @ 2026-11-11 13:44 UTC (permalink / raw)
To: xen-devel@lists.xenproject.org
Cc: Andrew Cooper, Teddy Astie, Roger Pau Monné
Re-use respective AVX512 tests, by suitably adjusting the predicate
functions. This leaves test names ("Testing ... NN-bit code sequence")
somewhat misleading, but I think we can live with that.
Note that the AVX512{BW,DQ} opmask tests cannot be run as-is for the
AVX10/256 case, as they include 512-bit vector <-> opmask insn tests.
Signed-off-by: Jan Beulich <jbeulich@suse.com>
---
SDE: -gnr
---
TBD: The testcase.mk change was for AVX10.1/256. It may, however, be
worthwhile to keep it.
TBD: May want to have separate AVX10 test blobs built, utilizing all of
the implied AVX512 sub-features.
The AVX512{BW,DQ} opmask tests could of course be cloned (i.e. rebuilt
another time with -mavx512vl passed) accordingly, but the coverage gain
would be pretty marginal.
---
v4: Drop use of vsz<N> fields. Series re-ordering adjustments. Drop stale
Phi leftovers. Re-base.
v2: Drop SDE 9.27.0 workaround. Re-base over dropping of Xeon Phi
support.
--- a/tools/tests/x86_emulator/evex-disp8.c
+++ b/tools/tests/x86_emulator/evex-disp8.c
@@ -1026,7 +1026,7 @@ static void test_group(const struct test
for ( j = 0; j < nr_vl; ++j )
{
if ( vl[0] == VL_512 && vl[j] != VL_512 &&
- !cpu_policy.feat.avx512vl )
+ !cpu_policy.feat.avx512vl && !cpu_policy.feat.avx10 )
continue;
switch ( tests[i].esz )
@@ -1077,6 +1077,24 @@ static void test_group(const struct test
}
}
+/* AVX512 (sub)features implied by AVX10. */
+#define avx10_has_avx512f cpu_has_avx10
+#define avx10_has_avx512bw cpu_has_avx10
+#define avx10_has_avx512cd cpu_has_avx10
+#define avx10_has_avx512dq cpu_has_avx10
+#define avx10_has_avx512_bf16 cpu_has_avx10
+#define avx10_has_avx512_bitalg cpu_has_avx10
+#define avx10_has_avx512_fp16 cpu_has_avx10
+#define avx10_has_avx512_ifma cpu_has_avx10
+#define avx10_has_avx512_vbmi cpu_has_avx10
+#define avx10_has_avx512_vbmi2 cpu_has_avx10
+#define avx10_has_avx512_vnni cpu_has_avx10
+#define avx10_has_avx512_vpopcntdq cpu_has_avx10
+
+/* AVX512 sub-feature(s) /not/ implied by AVX10. */
+#define avx10_has_avx512_vp2intersect false
+#define avx10_has_avx512_bmm false
+
void evex_disp8_test(void *instr, struct x86_emulate_ctxt *ctxt,
const struct x86_emulate_ops *ops)
{
@@ -1094,7 +1112,7 @@ void evex_disp8_test(void *instr, struct
} \
} while ( false )
-#define RUN(feat, vl) run(cpu_has_ ## feat, feat, vl)
+#define RUN(feat, vl) run(cpu_has_ ## feat || avx10_has_ ## feat, feat, vl)
RUN(avx512f, all);
RUN(avx512f, 128);
@@ -1120,11 +1138,15 @@ void evex_disp8_test(void *instr, struct
RUN(avx512_bmm, all);
RUN(avx512_bmm, no128);
- if ( cpu_has_avx512f )
+#undef RUN
+
+ if ( cpu_has_avx512f || cpu_has_avx10 )
{
+#define RUN(feat, vl) run(cpu_has_ ## feat, feat, vl)
RUN(gfni, all);
RUN(vaes, all);
RUN(vpclmulqdq, all);
+#undef RUN
}
if ( cpu_has_avx10 )
--- a/tools/tests/x86_emulator/testcase.mk
+++ b/tools/tests/x86_emulator/testcase.mk
@@ -7,6 +7,22 @@ $(call cc-options-add,CFLAGS,CC,$(EMBEDD
CFLAGS += -ffreestanding -nostdinc -I$(XEN_ROOT)/tools/firmware/include
CFLAGS += -fno-stack-protector -g0 $($(TESTCASE)-cflags)
+ifneq ($(filter -mavx512%,$($(TESTCASE)-cflags)),)
+
+cflags-vsz64 :=
+cflags-vsz32 := -mprefer-vector-width=256
+cflags-vsz16 := -mprefer-vector-width=128
+# Scalar tests don't set VEC_SIZE (and VEC_MAX is used by S/G ones only)
+cflags-vsz := -mprefer-vector-width=128
+
+ifneq ($(filter -DVEC_SIZE=%,$($(TESTCASE)-cflags)),)
+CFLAGS += $(cflags-vsz$(patsubst -DVEC_SIZE=%,%,$(filter -DVEC_SIZE=%,$($(TESTCASE)-cflags))))
+else
+CFLAGS += $(cflags-vsz$(patsubst -DVEC_MAX=%,%,$(filter -DVEC_MAX=%,$($(TESTCASE)-cflags))))
+endif
+
+endif
+
LDFLAGS_DIRECT += $(shell { $(LD) -v --warn-rwx-segments; } >/dev/null 2>&1 && echo --no-warn-rwx-segments)
.PHONY: all
--- a/tools/tests/x86_emulator/test_x86_emulator.c
+++ b/tools/tests/x86_emulator/test_x86_emulator.c
@@ -124,52 +124,56 @@ static bool simd_check_avx_pclmul(void)
static bool simd_check_avx512f(void)
{
- return cpu_has_avx512f;
+ return cpu_has_avx512f || cpu_has_avx10;
}
#define simd_check_avx512f_opmask simd_check_avx512f
#define simd_check_avx512f_sg simd_check_avx512f
static bool simd_check_avx512f_vl(void)
{
- return cpu_has_avx512f && cpu_policy.feat.avx512vl;
+ return (cpu_has_avx512f && cpu_policy.feat.avx512vl) ||
+ cpu_has_avx10;
}
#define simd_check_avx512vl_sg simd_check_avx512f_vl
static bool simd_check_avx512dq(void)
{
- return cpu_has_avx512dq;
+ return cpu_has_avx512dq || cpu_has_avx10;
}
#define simd_check_avx512dq_opmask simd_check_avx512dq
static bool simd_check_avx512dq_vl(void)
{
- return cpu_has_avx512dq && cpu_policy.feat.avx512vl;
+ return (cpu_has_avx512dq && cpu_policy.feat.avx512vl) ||
+ cpu_has_avx10;
}
static bool simd_check_avx512bw(void)
{
- return cpu_has_avx512bw;
+ return cpu_has_avx512bw || cpu_has_avx10;
}
#define simd_check_avx512bw_opmask simd_check_avx512bw
static bool simd_check_avx512bw_vl(void)
{
- return cpu_has_avx512bw && cpu_policy.feat.avx512vl;
+ return (cpu_has_avx512bw && cpu_policy.feat.avx512vl) ||
+ cpu_has_avx10;
}
static bool simd_check_avx512vbmi(void)
{
- return cpu_has_avx512_vbmi;
+ return cpu_has_avx512_vbmi || cpu_has_avx10;
}
static bool simd_check_avx512vbmi_vl(void)
{
- return cpu_has_avx512_vbmi && cpu_policy.feat.avx512vl;
+ return (cpu_has_avx512_vbmi && cpu_policy.feat.avx512vl) ||
+ cpu_has_avx10;
}
static bool simd_check_avx512vbmi2(void)
{
- return cpu_has_avx512_vbmi2;
+ return cpu_has_avx512_vbmi2 || cpu_has_avx10;
}
static bool simd_check_sse4_sha(void)
@@ -250,17 +254,18 @@ static bool simd_check_avx512bw_gf_vl(vo
static bool simd_check_avx512vnni(void)
{
- return cpu_has_avx512_vnni;
+ return cpu_has_avx512_vnni || cpu_has_avx10;
}
static bool simd_check_avx512fp16(void)
{
- return cpu_has_avx512_fp16;
+ return cpu_has_avx512_fp16 || cpu_has_avx10;
}
static bool simd_check_avx512fp16_vl(void)
{
- return cpu_has_avx512_fp16 && cpu_policy.feat.avx512vl;
+ return (cpu_has_avx512_fp16 && cpu_policy.feat.avx512vl) ||
+ cpu_has_avx10;
}
static void simd_set_regs(struct cpu_user_regs *regs)
@@ -3238,11 +3243,22 @@ int main(int argc, char **argv)
rc = x86_emulate(&ctxt, &emulops);
if ( rc != X86EMUL_OKAY || !check_eip(evex_vmovq_from_mem) )
goto fail;
- asm ( "vmovq %1, %%xmm1\n\t"
- "vpcmpeqq %%zmm0, %%zmm1, %%k0\n"
- "kmovw %%k0, %0" : "=r" (rc) : "m" (res[8]) );
- if ( rc != 0xff )
- goto fail;
+ if ( simd_check_avx512f() )
+ {
+ asm ( "vmovq %1, %%xmm1\n\t"
+ "vpcmpeqq %%zmm0, %%zmm1, %%k0\n"
+ "kmovw %%k0, %0" : "=r" (rc) : "m" (res[8]) );
+ if ( rc != 0x00ff )
+ goto fail;
+ }
+ else
+ {
+ asm ( "vmovq %1, %%xmm1\n\t"
+ "vpcmpeqq %%xmm0, %%xmm1, %%k0\n"
+ "kmovb %%k0, %0" : "=r" (rc) : "m" (res[8]) );
+ if ( rc != 0x03 )
+ goto fail;
+ }
printf("okay\n");
}
else
@@ -3820,11 +3836,22 @@ int main(int argc, char **argv)
rc = x86_emulate(&ctxt, &emulops);
if ( rc != X86EMUL_OKAY || !check_eip(evex_vmovd_from_mem) )
goto fail;
- asm ( "vmovd %1, %%xmm0\n\t"
- "vpcmpeqd %%zmm4, %%zmm0, %%k0\n\t"
- "kmovw %%k0, %0" : "=r" (rc) : "m" (res[8]) );
- if ( rc != 0xffff )
- goto fail;
+ if ( simd_check_avx512f() )
+ {
+ asm ( "vmovd %1, %%xmm0\n\t"
+ "vpcmpeqd %%zmm4, %%zmm0, %%k0\n\t"
+ "kmovw %%k0, %0" : "=r" (rc) : "m" (res[8]) );
+ if ( rc != 0xffff )
+ goto fail;
+ }
+ else
+ {
+ asm ( "vmovd %1, %%xmm0\n\t"
+ "vpcmpeqd %%xmm4, %%xmm0, %%k0\n\t"
+ "kmovb %%k0, %0" : "=r" (rc) : "m" (res[8]) );
+ if ( rc != 0x0f )
+ goto fail;
+ }
printf("okay\n");
}
else
@@ -4037,11 +4064,22 @@ int main(int argc, char **argv)
rc = x86_emulate(&ctxt, &emulops);
if ( (rc != X86EMUL_OKAY) || !check_eip(evex_vmovd_from_reg) )
goto fail;
- asm ( "vmovd %1, %%xmm0\n\t"
- "vpcmpeqd %%zmm1, %%zmm0, %%k0\n\t"
- "kmovw %%k0, %0" : "=r" (rc) : "m" (res[8]) );
- if ( rc != 0xffff )
- goto fail;
+ if ( simd_check_avx512f() )
+ {
+ asm ( "vmovd %1, %%xmm0\n\t"
+ "vpcmpeqd %%zmm1, %%zmm0, %%k0\n\t"
+ "kmovw %%k0, %0" : "=r" (rc) : "m" (res[8]) );
+ if ( rc != 0xffff )
+ goto fail;
+ }
+ else
+ {
+ asm ( "vmovd %1, %%xmm0\n\t"
+ "vpcmpeqd %%xmm1, %%xmm0, %%k0\n\t"
+ "kmovb %%k0, %0" : "=r" (rc) : "m" (res[8]) );
+ if ( rc != 0x0f )
+ goto fail;
+ }
printf("okay\n");
}
else
@@ -5524,14 +5562,28 @@ int main(int argc, char **argv)
rc = x86_emulate(&ctxt, &emulops);
if ( (rc != X86EMUL_OKAY) || !check_eip(vmovsh_from_mem) )
goto fail;
- asm volatile ( "kmovw %2, %%k1\n\t"
- "vmovdqu16 %1, %%zmm4%{%%k1%}%{z%}\n\t"
- "vpcmpeqw %%zmm4, %%zmm5, %%k0\n\t"
- "kmovw %%k0, %0"
- : "=g" (rc)
- : "m" (res[2]), "r" (1) );
- if ( rc != 0xffff )
- goto fail;
+ if ( simd_check_avx512fp16() )
+ {
+ asm volatile ( "kmovw %2, %%k1\n\t"
+ "vmovdqu16 %1, %%zmm4%{%%k1%}%{z%}\n\t"
+ "vpcmpeqw %%zmm4, %%zmm5, %%k0\n\t"
+ "kmovw %%k0, %0"
+ : "=g" (rc)
+ : "m" (res[2]), "r" (1) );
+ if ( rc != 0xffff )
+ goto fail;
+ }
+ else
+ {
+ asm volatile ( "kmovb %2, %%k1\n\t"
+ "vmovdqu16 %1, %%xmm4%{%%k1%}%{z%}\n\t"
+ "vpcmpeqw %%xmm4, %%xmm5, %%k0\n\t"
+ "kmovb %%k0, %0"
+ : "=g" (rc)
+ : "m" (res[2]), "r" (1) );
+ if ( rc != 0xff )
+ goto fail;
+ }
printf("okay\n");
printf("%-40s", "Testing vmovsh %xmm4,2(%eax){%k3}...");
--- a/tools/tests/x86_emulator/x86-emulate.c
+++ b/tools/tests/x86_emulator/x86-emulate.c
@@ -223,7 +223,7 @@ int emul_test_get_fpu(
break;
case X86EMUL_FPU_opmask:
case X86EMUL_FPU_zmm:
- if ( cpu_has_avx512f )
+ if ( cpu_has_avx512f || cpu_has_avx10 )
break;
default:
return X86EMUL_UNHANDLEABLE;
^ permalink raw reply [flat|nested] 20+ messages in thread* [PATCH v5 08/19] x86emul/test: engage AVX512VL via command line option
2026-11-11 13:40 [PATCH v5 00/19] x86: support AVX10 Jan Beulich
` (6 preceding siblings ...)
2026-11-11 13:44 ` [PATCH v5 07/19] x86emul: AVX10.1 testing Jan Beulich
@ 2026-11-11 13:45 ` Jan Beulich
2026-11-11 13:45 ` [PATCH v5 09/19] x86/CPUID: enable AVX10.2 sub-leaf Jan Beulich
` (10 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Jan Beulich @ 2026-11-11 13:45 UTC (permalink / raw)
To: xen-devel@lists.xenproject.org
Cc: Andrew Cooper, Teddy Astie, Roger Pau Monné
Now that we have machinery in testcase.mk to set vector length dependent
flags for AVX512 tests, let's avoid using a pragma to enable AVX512VL
insns for the compiler. This way, correct settings are in place from the
very beginning of compilation.
No change to the generated test blobs, and hence no functional change.
Signed-off-by: Jan Beulich <jbeulich@suse.com>
--- a/tools/tests/x86_emulator/simd.h
+++ b/tools/tests/x86_emulator/simd.h
@@ -215,10 +215,6 @@ DECL_OCTET(half);
# define __builtin_ia32_shuf_i32x4_512_mask __builtin_ia32_shuf_i32x4_mask
# define __builtin_ia32_shuf_i64x2_512_mask __builtin_ia32_shuf_i64x2_mask
-# if VEC_SIZE > ELEM_SIZE && (defined(VEC_MAX) ? VEC_MAX : VEC_SIZE) < 64
-# pragma GCC target ( "avx512vl" )
-# endif
-
# define REN(insn, old, new) \
asm ( ".macro v" #insn #old " o:vararg \n\t" \
"v" #insn #new " \\o \n\t" \
--- a/tools/tests/x86_emulator/testcase.mk
+++ b/tools/tests/x86_emulator/testcase.mk
@@ -10,8 +10,8 @@ CFLAGS += -fno-stack-protector -g0 $($(T
ifneq ($(filter -mavx512%,$($(TESTCASE)-cflags)),)
cflags-vsz64 :=
-cflags-vsz32 := -mprefer-vector-width=256
-cflags-vsz16 := -mprefer-vector-width=128
+cflags-vsz32 := -mavx512vl -mprefer-vector-width=256
+cflags-vsz16 := -mavx512vl -mprefer-vector-width=128
# Scalar tests don't set VEC_SIZE (and VEC_MAX is used by S/G ones only)
cflags-vsz := -mprefer-vector-width=128
^ permalink raw reply [flat|nested] 20+ messages in thread* [PATCH v5 09/19] x86/CPUID: enable AVX10.2 sub-leaf
2026-11-11 13:40 [PATCH v5 00/19] x86: support AVX10 Jan Beulich
` (7 preceding siblings ...)
2026-11-11 13:45 ` [PATCH v5 08/19] x86emul/test: engage AVX512VL via command line option Jan Beulich
@ 2026-11-11 13:45 ` Jan Beulich
2026-11-11 13:46 ` [PATCH v5 10/19] x86emul: support AVX10.2 scalar compare insns Jan Beulich
` (9 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Jan Beulich @ 2026-11-11 13:45 UTC (permalink / raw)
To: xen-devel@lists.xenproject.org
Cc: Andrew Cooper, Teddy Astie, Roger Pau Monné
The logic is modeled as closely as possible after that of leaf 7
sub-leaf handling.
Also include AVX10-BMM right away.
Signed-off-by: Jan Beulich <jbeulich@suse.com>
---
While the "AVX10" infix is necessary everywhere, the "avx10" prefix on
the bitfield name is redundant with the containing structure's field
name (see "x86emul: support AVX10.2 media insns" for how this looks like
in actual use). Do we want to special-case this in gen-cpuid.py?
---
v5: Add AVX10.2-aux and AVX10-BMM.
v4: New.
--- a/tools/libs/light/libxl_cpuid.c
+++ b/tools/libs/light/libxl_cpuid.c
@@ -343,6 +343,7 @@ int libxl_cpuid_parse_config(libxl_cpuid
MSR_ENTRY(0x10a, CPUID_REG_EAX),
MSR_ENTRY(0x10a, CPUID_REG_EDX),
CPUID_ENTRY(0x80000021, NA, CPUID_REG_ECX),
+ CPUID_ENTRY(0x00000024, 1, CPUID_REG_ECX),
#undef MSR_ENTRY
#undef CPUID_ENTRY
};
--- a/tools/misc/xen-cpuid.c
+++ b/tools/misc/xen-cpuid.c
@@ -38,6 +38,7 @@ static const struct {
{ "MSR_ARCH_CAPS.lo", "m10Al" },
{ "MSR_ARCH_CAPS.hi", "m10Ah" },
{ "CPUID 0x80000021.ecx", "e21c" },
+ { "CPUID 0x00000024:1.ecx", "24c1" },
};
#define COL_ALIGN "24"
--- a/xen/arch/x86/cpu/common.c
+++ b/xen/arch/x86/cpu/common.c
@@ -594,6 +594,17 @@ void identify_cpu(struct cpuinfo_x86 *c)
&c->x86_capability[FEATURESET_Da1],
&tmp, &tmp, &tmp);
+ if (cpu_has(c, X86_FEATURE_AVX10) && c->cpuid_level >= 0x24) {
+ uint32_t max_subleaf;
+
+ cpuid_count(0x24, 0, &max_subleaf, &tmp, &tmp, &tmp);
+ if (max_subleaf >= 1)
+ cpuid_count(0x24, 1,
+ &tmp, &tmp,
+ &c->x86_capability[FEATURESET_24c1],
+ &tmp);
+ }
+
if (test_bit(X86_FEATURE_ARCH_CAPS, c->x86_capability)) {
val = rdmsr(MSR_ARCH_CAPABILITIES);
c->x86_capability[FEATURESET_m10Al] = val;
--- a/xen/arch/x86/cpu-policy.c
+++ b/xen/arch/x86/cpu-policy.c
@@ -277,6 +277,9 @@ static void recalculate_misc(struct cpu_
p->avx10.raw[0].b &= 0x000700ff;
p->avx10.raw[0].c = 0;
p->avx10.raw[0].d = 0;
+ p->avx10.raw[1].a = 0;
+ p->avx10.raw[1].b = 0;
+ p->avx10.raw[1].d = 0;
if ( !p->feat.avx10 || !p->avx10.version ||
!p->avx10.vsz512 || !p->avx10.vsz256 || !p->avx10.vsz128 )
{
--- a/xen/include/public/arch-x86/cpufeatureset.h
+++ b/xen/include/public/arch-x86/cpufeatureset.h
@@ -409,6 +409,11 @@ XEN_CPUFEATURE(ITS_NO, 16*32
XEN_CPUFEATURE(TSA_SQ_NO, 18*32+ 1) /*A No Store Queue Transitive Scheduler Attacks */
XEN_CPUFEATURE(TSA_L1_NO, 18*32+ 2) /*A No L1D Transitive Scheduler Attacks */
+/* x86-ecosystem-defined CPU features, CPUID level 0x00000024:1.ecx, word 19 */
+XEN_CPUFEATURE(AVX10_BMM, 19*32+ 1) /* AVX10-BMM Instructions */
+XEN_CPUFEATURE(AVX10_V1_AUX, 19*32+ 2) /* AVX10 V1 Auxiliary Instructions */
+XEN_CPUFEATURE(AVX10_V2_AUX, 19*32+ 3) /* AVX10 V2 Auxiliary Instructions */
+
#endif /* XEN_CPUFEATURE */
/* Clean up from a default include. Close the enum (for C). */
--- a/xen/include/xen/lib/x86/cpu-policy.h
+++ b/xen/include/xen/lib/x86/cpu-policy.h
@@ -23,6 +23,7 @@
#define FEATURESET_m10Al 16 /* 0x0000010a.eax */
#define FEATURESET_m10Ah 17 /* 0x0000010a.edx */
#define FEATURESET_e21c 18 /* 0x80000021.ecx */
+#define FEATURESET_24c1 19 /* 0x00000024:1.ecx */
struct cpuid_leaf
{
@@ -64,7 +65,7 @@ const char *x86_cpuid_vendor_to_str(unsi
#define CPUID_GUEST_NR_FEAT (2u + 1)
#define CPUID_GUEST_NR_TOPO (1u + 1)
#define CPUID_GUEST_NR_XSTATE (62u + 1)
-#define CPUID_GUEST_NR_AVX10 (0u + 1)
+#define CPUID_GUEST_NR_AVX10 (1u + 1)
#define CPUID_GUEST_NR_EXTD_INTEL (0x8u + 1)
#define CPUID_GUEST_NR_EXTD_AMD (0x21u + 1)
#define CPUID_GUEST_NR_EXTD MAX(CPUID_GUEST_NR_EXTD_INTEL, \
@@ -275,6 +276,14 @@ struct cpu_policy
bool vsz128:1, vsz256:1, vsz512:1;
uint32_t :13;
uint32_t /* c */:32, /* d */:32;
+
+ /* Subleaf 1. */
+ uint32_t /* a */:32, /* b */:32;
+ union {
+ uint32_t _24c1;
+ struct { DECL_BITFIELD(24c1); };
+ };
+ uint32_t /* d */:32;
};
} avx10;
--- a/xen/arch/x86/lib/cpu-policy/cpuid.c
+++ b/xen/arch/x86/lib/cpu-policy/cpuid.c
@@ -82,6 +82,7 @@ void x86_cpu_policy_to_featureset(
fs[FEATURESET_m10Al] = p->arch_caps.lo;
fs[FEATURESET_m10Ah] = p->arch_caps.hi;
fs[FEATURESET_e21c] = p->extd.e21c;
+ fs[FEATURESET_24c1] = p->avx10._24c1;
}
void x86_cpu_featureset_to_policy(
@@ -106,6 +107,7 @@ void x86_cpu_featureset_to_policy(
p->arch_caps.lo = fs[FEATURESET_m10Al];
p->arch_caps.hi = fs[FEATURESET_m10Ah];
p->extd.e21c = fs[FEATURESET_e21c];
+ p->avx10._24c1 = fs[FEATURESET_24c1];
}
void x86_cpu_policy_recalc_synth(struct cpu_policy *p)
--- a/xen/tools/gen-cpuid.py
+++ b/xen/tools/gen-cpuid.py
@@ -310,6 +310,9 @@ def crunch_numbers(state):
AVX512BW: [AVX512_VBMI, AVX512_VBMI2, AVX512_BITALG, AVX512_BF16,
AVX512_FP16, AVX512_BMM],
+ # AVX10 discrete features.
+ AVX10: [AVX10_BMM, AVX10_V1_AUX, AVX10_V2_AUX],
+
# Extensions with VEX/EVEX encodings keyed to a separate feature
# flag are made dependents of their respective legacy feature.
PCLMULQDQ: [VPCLMULQDQ],
^ permalink raw reply [flat|nested] 20+ messages in thread* [PATCH v5 10/19] x86emul: support AVX10.2 scalar compare insns
2026-11-11 13:40 [PATCH v5 00/19] x86: support AVX10 Jan Beulich
` (8 preceding siblings ...)
2026-11-11 13:45 ` [PATCH v5 09/19] x86/CPUID: enable AVX10.2 sub-leaf Jan Beulich
@ 2026-11-11 13:46 ` Jan Beulich
2026-11-11 13:46 ` [PATCH v5 11/19] x86emul: support AVX10.2 partial copy insns Jan Beulich
` (8 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Jan Beulich @ 2026-11-11 13:46 UTC (permalink / raw)
To: xen-devel@lists.xenproject.org
Cc: Andrew Cooper, Teddy Astie, Roger Pau Monné
Simply clone code from their V{,U}COMIS{S,D,H} counterparts.
While there drop a redundant EVEX.W check from V{,U}COMISH handling.
Signed-off-by: Jan Beulich <jbeulich@suse.com>
---
SDE: -dmr / -future
---
v4: Update encodings to latest spec version. Series re-ordering
adjustments.
v3: New.
--- a/tools/tests/x86_emulator/evex-disp8.c
+++ b/tools/tests/x86_emulator/evex-disp8.c
@@ -81,6 +81,7 @@ enum esz {
ESZ_w,
ESZ_bw,
ESZ_fp16,
+#define ESZ_bf16 ESZ_fp16
};
#ifndef __i386__
@@ -720,6 +721,14 @@ static const struct test vpclmulqdq_all[
INSN(pclmulqdq, 66, 0f3a, 44, vl, q_nb, vl)
};
+static const struct test avx10_2_all[] = {
+ INSN(comisbf16, 66, map5, 2f, el, bf16, el),
+ INSN_SFP(comx, 0f, 2f),
+ INSN(comxsh, f3, map5, 2f, el, fp16, el),
+ INSN_SFP(ucomx, 0f, 2e),
+ INSN(ucomxsh, f3, map5, 2e, el, fp16, el),
+};
+
static const struct test movrs_all[] = {
INSN(movrsb, f2, map5, 6f, vl, b, vl),
INSN(movrsd, f3, map5, 6f, vl, d_nb, vl),
@@ -1154,4 +1163,6 @@ void evex_disp8_test(void *instr, struct
run(ctxt->addr_size == 64 && cpu_has_movrs, movrs, all);
run(cpu_has_sm4, sm4, all);
}
+
+ run(cpu_has_avx10_2, avx10_2, all);
}
--- a/tools/tests/x86_emulator/predicates.c
+++ b/tools/tests/x86_emulator/predicates.c
@@ -1682,8 +1682,12 @@ static const struct evex {
{ { 0x2d }, 2, T, R, pfx_f2, Wn, LIG }, /* vcvtsd2si */
{ { 0x2e }, 2, T, R, pfx_no, W0, LIG }, /* vucomiss */
{ { 0x2e }, 2, T, R, pfx_66, W1, LIG }, /* vucomisd */
+ { { 0x2e }, 2, T, R, pfx_f2, W1, LIG }, /* vucomxsd */
+ { { 0x2e }, 2, T, R, pfx_f3, W0, LIG }, /* vucomxss */
{ { 0x2f }, 2, T, R, pfx_no, W0, LIG }, /* vcomiss */
{ { 0x2f }, 2, T, R, pfx_66, W1, LIG }, /* vcomisd */
+ { { 0x2f }, 2, T, R, pfx_f2, W1, LIG }, /* vcomxsd */
+ { { 0x2f }, 2, T, R, pfx_f3, W0, LIG }, /* vcomxss */
{ { 0x51 }, 2, T, R, pfx_no, W0, Ln }, /* vsqrtps */
{ { 0x51 }, 2, T, R, pfx_66, W1, Ln }, /* vsqrtpd */
{ { 0x51 }, 2, T, R, pfx_f3, W0, LIG }, /* vsqrtss */
@@ -2102,7 +2106,10 @@ static const struct evex {
{ { 0x2c }, 2, T, R, pfx_f3, Wn, LIG }, /* vcvttsh2si */
{ { 0x2d }, 2, T, R, pfx_f3, Wn, LIG }, /* vcvtsh2si */
{ { 0x2e }, 2, T, R, pfx_no, W0, LIG }, /* vucomish */
+ { { 0x2e }, 2, T, R, pfx_f3, W0, LIG }, /* vucomxsh */
{ { 0x2f }, 2, T, R, pfx_no, W0, LIG }, /* vcomish */
+ { { 0x2f }, 2, T, R, pfx_66, W0, LIG }, /* vcomisbf16 */
+ { { 0x2f }, 2, T, R, pfx_f3, W0, LIG }, /* vcomxsh */
{ { 0x51 }, 2, T, R, pfx_no, W0, Ln }, /* vsqrtph */
{ { 0x51 }, 2, T, R, pfx_f3, W0, LIG }, /* vsqrtsh */
{ { 0x58 }, 2, T, R, pfx_no, W0, Ln }, /* vaddph */
--- a/tools/tests/x86_emulator/x86-emulate.h
+++ b/tools/tests/x86_emulator/x86-emulate.h
@@ -217,6 +217,8 @@ void wrpkru(unsigned int val);
#define cpu_has_avx_vnni_int16 (cpu_policy.feat.avx_vnni_int16 && \
xcr0_mask(6))
#define cpu_has_avx10 (cpu_policy.feat.avx10 && xcr0_mask(0xe6))
+#define cpu_has_avx10_2 (cpu_policy.avx10.version >= 2 && \
+ xcr0_mask(0xe6))
#define cpu_has_xgetbv1 (cpu_has_xsave && cpu_policy.xstate.xgetbv1)
--- a/xen/arch/x86/x86_emulate/decode.c
+++ b/xen/arch/x86/x86_emulate/decode.c
@@ -1515,9 +1515,8 @@ int x86emul_decode(struct x86_emulate_st
s->fp16 = true;
break;
- case 0x2e: case 0x2f: /* v{,u}comish */
- if ( !s->evex.pfx )
- s->fp16 = true;
+ case 0x2e: case 0x2f: /* v{,u}com{i,x}sh, vcomisbf16 */
+ s->fp16 = true;
s->simd_size = simd_none;
break;
--- a/xen/arch/x86/x86_emulate/private.h
+++ b/xen/arch/x86/x86_emulate/private.h
@@ -318,7 +318,7 @@ struct x86_emulate_state {
bool lock_prefix;
bool not_64bit; /* Instruction not available in 64bit. */
bool fpu_ctrl; /* Instruction is an FPU control one. */
- bool fp16; /* Instruction has half-precision FP source operand. */
+ bool fp16; /* Instruction has half-precision FP or BF16 source. */
opcode_desc_t desc;
union vex vex;
union evex evex;
@@ -609,10 +609,10 @@ amd_like(const struct x86_emulate_ctxt *
#define vcpu_has_avx_vnni_int16() (ctxt->cpuid->feat.avx_vnni_int16)
#define vcpu_has_user_msr() (ctxt->cpuid->feat.user_msr)
-#define vcpu_has_avx10() (ctxt->cpuid->feat.avx10)
+#define vcpu_has_avx10(minor) (ctxt->cpuid->avx10.version >= (minor))
-#define vcpu_must_have(feat) \
- generate_exception_if(!vcpu_has_##feat(), X86_EXC_UD)
+#define vcpu_must_have(feat, ...) \
+ generate_exception_if(!vcpu_has_##feat(__VA_ARGS__), X86_EXC_UD)
/*
* Instruction emulation:
--- a/xen/arch/x86/x86_emulate/x86_emulate.c
+++ b/xen/arch/x86/x86_emulate/x86_emulate.c
@@ -3875,7 +3875,6 @@ x86_emulate(
case X86EMUL_OPC_EVEX(5, 0x2e): /* vucomish xmm/m16,xmm */
case X86EMUL_OPC_EVEX(5, 0x2f): /* vcomish xmm/m16,xmm */
visa_check(_fp16);
- generate_exception_if(evex.w, X86_EXC_UD);
/* fall through */
CASE_SIMD_PACKED_FP(_EVEX, 0x0f, 0x2e): /* vucomis{s,d} xmm/mem,xmm */
CASE_SIMD_PACKED_FP(_EVEX, 0x0f, 0x2f): /* vcomis{s,d} xmm/mem,xmm */
@@ -3884,6 +3883,7 @@ x86_emulate(
evex.w != evex.pfx),
X86_EXC_UD);
visa_check(f);
+ vcomi_evex:
if ( !evex.brs )
avx512_vlen_check(true);
get_fpu(X86EMUL_FPU_zmm);
@@ -3892,6 +3892,17 @@ x86_emulate(
op_bytes = 2 << (!state->fp16 + evex.w);
goto vcomi;
+ CASE_SIMD_SCALAR_FP(_EVEX, 0x0f, 0x2e): /* vucomxs{s,d} xmm/mem,xmm */
+ CASE_SIMD_SCALAR_FP(_EVEX, 0x0f, 0x2f): /* vcomxs{s,d} xmm/mem,xmm */
+ case X86EMUL_OPC_EVEX_F3(5, 0x2e): /* vucomxsh xmm/m16,xmm */
+ case X86EMUL_OPC_EVEX_66(5, 0x2f): /* vcomisbf16 xmm/m16,xmm */
+ case X86EMUL_OPC_EVEX_F3(5, 0x2f): /* vcomxsh xmm/m16,xmm */
+ generate_exception_if((evex.reg != 0xf || !evex.RX || evex.opmsk ||
+ evex.w != (evex.pfx == vex_f2)),
+ X86_EXC_UD);
+ vcpu_must_have(avx10, 2);
+ goto vcomi_evex;
+
#endif
case X86EMUL_OPC(0x0f, 0x30): /* wrmsr */
@@ -6881,7 +6892,7 @@ x86_emulate(
case X86EMUL_OPC_EVEX_F3(0x0f38, 0xda): /* vsm4key4 [xyz]mm/mem,[xyz]mm,[xyz]mm */
case X86EMUL_OPC_EVEX_F2(0x0f38, 0xda): /* vsm4rnds4 [xyz]mm/mem,[xyz]mm,[xyz]mm */
- vcpu_must_have(avx10);
+ vcpu_must_have(avx10, 1);
vcpu_must_have(sm4);
generate_exception_if(evex.w || evex.brs || evex.opmsk, X86_EXC_UD);
avx512_vlen_check(false);
@@ -7955,7 +7966,7 @@ x86_emulate(
fallthrough;
case X86EMUL_OPC_EVEX_F3(5, 0x6f): /* vmovrs{d,q} mem,[xyz]mm{k} */
generate_exception_if(ea.type != OP_MEM || evex.brs, X86_EXC_UD);
- vcpu_must_have(avx10);
+ vcpu_must_have(avx10, 1);
vcpu_must_have(movrs);
avx512_vlen_check(false);
op_bytes = 16 << evex.lr;
^ permalink raw reply [flat|nested] 20+ messages in thread* [PATCH v5 11/19] x86emul: support AVX10.2 partial copy insns
2026-11-11 13:40 [PATCH v5 00/19] x86: support AVX10 Jan Beulich
` (9 preceding siblings ...)
2026-11-11 13:46 ` [PATCH v5 10/19] x86emul: support AVX10.2 scalar compare insns Jan Beulich
@ 2026-11-11 13:46 ` Jan Beulich
2026-11-11 13:47 ` [PATCH v5 12/19] x86emul: support AVX10.2 media insns Jan Beulich
` (7 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Jan Beulich @ 2026-11-11 13:46 UTC (permalink / raw)
To: xen-devel@lists.xenproject.org
Cc: Andrew Cooper, Teddy Astie, Roger Pau Monné
Extend existing VMOV{Q,W} logic accordingly.
Signed-off-by: Jan Beulich <jbeulich@suse.com>
---
SDE: -dmr / -future
---
v4: Series re-ordering adjustments.
v3: New.
--- a/tools/tests/x86_emulator/evex-disp8.c
+++ b/tools/tests/x86_emulator/evex-disp8.c
@@ -729,6 +729,13 @@ static const struct test avx10_2_all[] =
INSN(ucomxsh, f3, map5, 2e, el, fp16, el),
};
+static const struct test avx10_2_128[] = {
+ INSN(movd, f3, 0f, 7e, el, d, el),
+ INSN(movd, 66, 0f, d6, el, d, el),
+ INSN(movw, f3, map5, 6e, el, fp16, el),
+ INSN(movw, f3, map5, 7e, el, fp16, el),
+};
+
static const struct test movrs_all[] = {
INSN(movrsb, f2, map5, 6f, vl, b, vl),
INSN(movrsd, f3, map5, 6f, vl, d_nb, vl),
@@ -1165,4 +1172,5 @@ void evex_disp8_test(void *instr, struct
}
run(cpu_has_avx10_2, avx10_2, all);
+ run(cpu_has_avx10_2, avx10_2, 128);
}
--- a/tools/tests/x86_emulator/predicates.c
+++ b/tools/tests/x86_emulator/predicates.c
@@ -1782,7 +1782,7 @@ static const struct evex {
{ { 0x7b }, 2, T, R, pfx_f3, Wn, LIG }, /* vcvtusi2ss */
{ { 0x7b }, 2, T, R, pfx_f2, Wn, LIG }, /* vcvtusi2sd */
{ { 0x7e }, 2, T, W, pfx_66, Wn, L0 }, /* vmov{d,q} */
- { { 0x7e }, 2, T, R, pfx_f3, W1, L0 }, /* vmovq */
+ { { 0x7e }, 2, T, R, pfx_f3, Wn, L0 }, /* vmov{d,q} */
{ { 0x7f }, 2, T, W, pfx_66, Wn, Ln }, /* vmovdqa{32,64} */
{ { 0x7f }, 2, T, W, pfx_f3, Wn, Ln }, /* vmovdqu{32,64} */
{ { 0x7f }, 2, T, W, pfx_f2, Wn, Ln }, /* vmovdqu{8,16} */
@@ -1799,7 +1799,7 @@ static const struct evex {
{ { 0xd3 }, 2, T, R, pfx_66, W1, Ln }, /* vpsrlq */
{ { 0xd4 }, 2, T, R, pfx_66, W1, Ln }, /* vpaddq */
{ { 0xd5 }, 2, T, R, pfx_66, WIG, Ln }, /* vpmullw */
- { { 0xd6 }, 2, T, W, pfx_66, W1, L0 }, /* vmovq */
+ { { 0xd6 }, 2, T, W, pfx_66, Wn, L0 }, /* vmov{d,q} */
{ { 0xd8 }, 2, T, R, pfx_66, WIG, Ln }, /* vpsubusb */
{ { 0xd9 }, 2, T, R, pfx_66, WIG, Ln }, /* vpsubusw */
{ { 0xda }, 2, T, R, pfx_66, WIG, Ln }, /* vpminub */
@@ -2133,6 +2133,7 @@ static const struct evex {
{ { 0x5f }, 2, T, R, pfx_no, W0, Ln }, /* vmaxph */
{ { 0x5f }, 2, T, R, pfx_f3, W0, LIG }, /* vmaxsh */
{ { 0x6e }, 2, T, R, pfx_66, WIG, L0 }, /* vmovw */
+ { { 0x6e }, 2, T, R, pfx_f3, W0, L0 }, /* vmovw */
{ { 0x6f }, 2, T, R, pfx_f3, Wn, Ln }, /* vmovrs{d,q} */
{ { 0x6f }, 2, T, R, pfx_f2, Wn, Ln }, /* vmovrs{b,w} */
{ { 0x78 }, 2, T, R, pfx_no, W0, Ln }, /* vcvttph2udq */
@@ -2153,6 +2154,7 @@ static const struct evex {
{ { 0x7d }, 2, T, R, pfx_f3, W0, Ln }, /* vcvtw2ph */
{ { 0x7d }, 2, T, R, pfx_f2, W0, Ln }, /* vcvtuwph */
{ { 0x7e }, 2, T, W, pfx_66, WIG, L0 }, /* vmovw */
+ { { 0x7e }, 2, T, W, pfx_f3, W0, L0 }, /* vmovw */
}, evex_map6[] = {
{ { 0x13 }, 2, T, R, pfx_66, W0, Ln }, /* vcvtph2psx */
{ { 0x13 }, 2, T, R, pfx_no, W0, LIG }, /* vcvtsh2ss */
--- a/xen/arch/x86/x86_emulate/decode.c
+++ b/xen/arch/x86/x86_emulate/decode.c
@@ -293,7 +293,7 @@ static const struct twobyte_table {
[0xd0] = { DstImplicit|SrcMem|ModRM, simd_other },
[0xd1 ... 0xd3] = { DstImplicit|SrcMem|ModRM, simd_128, 4 },
[0xd4 ... 0xd5] = { DstImplicit|SrcMem|ModRM, simd_packed_int, d8s_vl },
- [0xd6] = { DstMem|SrcImplicit|ModRM|Mov, simd_other, 3 },
+ [0xd6] = { DstMem|SrcImplicit|ModRM|Mov, simd_other, d8s_dq },
[0xd7] = { DstReg|SrcImplicit|ModRM|Mov },
[0xd8 ... 0xdf] = { DstImplicit|SrcMem|ModRM, simd_packed_int, d8s_vl },
[0xe0] = { DstImplicit|SrcMem|ModRM, simd_packed_int, d8s_vl },
@@ -803,7 +803,7 @@ decode_twobyte(struct x86_emulate_state
if ( s->vex.pfx == vex_f3 ) /* movq xmm/m64,xmm */
{
case X86EMUL_OPC_VEX_F3(0, 0x7e): /* vmovq xmm/m64,xmm */
- case X86EMUL_OPC_EVEX_F3(0, 0x7e): /* vmovq xmm/m64,xmm */
+ case X86EMUL_OPC_EVEX_F3(0, 0x7e): /* vmov{d,q} xmm/mem,xmm */
s->desc = DstImplicit | SrcMem | TwoOp;
s->simd_size = simd_other;
/* Avoid the s->desc clobbering of TwoOp below. */
@@ -1416,7 +1416,7 @@ int x86emul_decode(struct x86_emulate_st
break;
case 0x7e: /* vmovq xmm/m64,xmm needs special casing */
- if ( disp8scale == 2 && s->evex.pfx == vex_f3 )
+ if ( disp8scale == 2 && s->evex.pfx == vex_f3 && s->evex.w )
disp8scale = 3;
break;
@@ -1525,13 +1525,13 @@ int x86emul_decode(struct x86_emulate_st
s->fp16 = true;
break;
- case 0x6e: /* vmovw r/m16, xmm */
+ case 0x6e: /* vmovw r/x/m16, xmm */
d = (d & ~SrcMask) | SrcMem16;
/* fall through */
- case 0x7e: /* vmovw xmm, r/m16 */
+ case 0x7e: /* vmovw xmm, r/x/m16 */
+ s->fp16 = true;
if ( s->evex.pfx == vex_66 )
- s->fp16 = true;
- s->simd_size = simd_none;
+ s->simd_size = simd_none;
break;
case 0x78: case 0x79: /* vcvt{,t}ph2u{d,q}q, vcvt{,t}sh2usi */
--- a/xen/arch/x86/x86_emulate/x86_emulate.c
+++ b/xen/arch/x86/x86_emulate/x86_emulate.c
@@ -4986,13 +4986,17 @@ x86_emulate(
op_bytes = 8;
goto simd_0f_int;
- case X86EMUL_OPC_EVEX_F3(0x0f, 0x7e): /* vmovq xmm/m64,xmm */
- case X86EMUL_OPC_EVEX_66(0x0f, 0xd6): /* vmovq xmm,xmm/m64 */
- generate_exception_if(evex.lr || !evex.w || evex.opmsk || evex.brs,
- X86_EXC_UD);
- visa_check(f);
+ case X86EMUL_OPC_EVEX_F3(0x0f, 0x7e): /* vmov{d,q} xmm/mem,xmm */
+ case X86EMUL_OPC_EVEX_66(0x0f, 0xd6): /* vmov{d,q} xmm,xmm/mem */
+ case X86EMUL_OPC_EVEX_F3(5, 0x6e): /* vmovw xmm/m16,xmm */
+ case X86EMUL_OPC_EVEX_F3(5, 0x7e): /* vmovw xmm,xmm/m16 */
+ generate_exception_if(evex.lr || evex.opmsk || evex.brs, X86_EXC_UD);
+ if ( evex.w )
+ visa_check(f);
+ else
+ vcpu_must_have(avx10, 2);
d |= TwoOp;
- op_bytes = 8;
+ op_bytes = 2 << (!state->fp16 + evex.w);
goto simd_zmm;
#endif /* !X86EMUL_NO_SIMD */
^ permalink raw reply [flat|nested] 20+ messages in thread* [PATCH v5 12/19] x86emul: support AVX10.2 media insns
2026-11-11 13:40 [PATCH v5 00/19] x86: support AVX10 Jan Beulich
` (10 preceding siblings ...)
2026-11-11 13:46 ` [PATCH v5 11/19] x86emul: support AVX10.2 partial copy insns Jan Beulich
@ 2026-11-11 13:47 ` Jan Beulich
2026-11-11 13:47 ` [PATCH v5 13/19] x86emul: support AVX10.2 minmax insns Jan Beulich
` (6 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Jan Beulich @ 2026-11-11 13:47 UTC (permalink / raw)
To: xen-devel@lists.xenproject.org
Cc: Andrew Cooper, Teddy Astie, Roger Pau Monné
These are all very similar to various existing insns.
Signed-off-by: Jan Beulich <jbeulich@suse.com>
---
SDE: -dmr / -future
---
In evex-disp8.c, should we separately have avx10_v1_aux_all[]? If so, all
the convert insns would also need moving/copying there.
---
v4: Series re-ordering adjustments. Update to spec version 6.
v3: New.
--- a/tools/tests/x86_emulator/evex-disp8.c
+++ b/tools/tests/x86_emulator/evex-disp8.c
@@ -725,6 +725,20 @@ static const struct test avx10_2_all[] =
INSN(comisbf16, 66, map5, 2f, el, bf16, el),
INSN_SFP(comx, 0f, 2f),
INSN(comxsh, f3, map5, 2f, el, fp16, el),
+ INSN(dpphps, , 0f38, 52, vl, d, vl),
+ INSN(mpsadbw, f3, 0f3a, 42, vl, d_nb, vl),
+ INSN(pdpbssd, f2, 0f38, 50, vl, d, vl),
+ INSN(pdpbssds, f2, 0f38, 51, vl, d, vl),
+ INSN(pdpbsud, f3, 0f38, 50, vl, d, vl),
+ INSN(pdpbsuds, f3, 0f38, 51, vl, d, vl),
+ INSN(pdpbuud, , 0f38, 50, vl, d, vl),
+ INSN(pdpbuuds, , 0f38, 51, vl, d, vl),
+ INSN(pdpwsud, f3, 0f38, d2, vl, d, vl),
+ INSN(pdpwsuds, f3, 0f38, d3, vl, d, vl),
+ INSN(pdpwusd, 66, 0f38, d2, vl, d, vl),
+ INSN(pdpwusds, 66, 0f38, d3, vl, d, vl),
+ INSN(pdpwuud, , 0f38, d2, vl, d, vl),
+ INSN(pdpwuuds, , 0f38, d3, vl, d, vl),
INSN_SFP(ucomx, 0f, 2e),
INSN(ucomxsh, f3, map5, 2e, el, fp16, el),
};
--- a/tools/tests/x86_emulator/predicates.c
+++ b/tools/tests/x86_emulator/predicates.c
@@ -1927,8 +1927,15 @@ static const struct evex {
{ { 0x4d }, 2, T, R, pfx_66, Wn, LIG }, /* vrcp14s{s,d} */
{ { 0x4e }, 2, T, R, pfx_66, Wn, Ln }, /* vrsqrt14p{s,d} */
{ { 0x4f }, 2, T, R, pfx_66, Wn, LIG }, /* vrsqrt14s{s,d} */
+ { { 0x50 }, 2, T, R, pfx_no, W0, Ln }, /* vpdpbuud */
{ { 0x50 }, 2, T, R, pfx_66, W0, Ln }, /* vpdpbusd */
+ { { 0x50 }, 2, T, R, pfx_f3, W0, Ln }, /* vpdpbsud */
+ { { 0x50 }, 2, T, R, pfx_f2, W0, Ln }, /* vpdpbssd */
+ { { 0x51 }, 2, T, R, pfx_no, W0, Ln }, /* vpdpbuuds */
{ { 0x51 }, 2, T, R, pfx_66, W0, Ln }, /* vpdpbusds */
+ { { 0x51 }, 2, T, R, pfx_f3, W0, Ln }, /* vpdpbsuds */
+ { { 0x51 }, 2, T, R, pfx_f2, W0, Ln }, /* vpdpbssds */
+ { { 0x52 }, 2, T, R, pfx_no, W0, Ln }, /* vdpphps */
{ { 0x52 }, 2, T, R, pfx_66, W0, Ln }, /* vpdpwssd */
{ { 0x52 }, 2, T, R, pfx_f3, W0, Ln }, /* vdpbf16ps */
{ { 0x52 }, 2, T, R, pfx_f2, W0, L2 }, /* vp4dpwssd */
@@ -2029,6 +2036,12 @@ static const struct evex {
{ { 0xcc }, 2, T, R, pfx_66, Wn, L2 }, /* vrsqrt28p{s,d} */
{ { 0xcd }, 2, T, R, pfx_66, Wn, LIG }, /* vrsqrt28s{s,d} */
{ { 0xcf }, 2, T, R, pfx_66, W0, Ln }, /* vgf2p8mulb */
+ { { 0xd2 }, 2, T, R, pfx_no, W0, Ln }, /* vpdpwuud */
+ { { 0xd2 }, 2, T, R, pfx_66, W0, Ln }, /* vpdpwusd */
+ { { 0xd2 }, 2, T, R, pfx_f3, W0, Ln }, /* vpdpwsud */
+ { { 0xd3 }, 2, T, R, pfx_no, W0, Ln }, /* vpdpwuuds */
+ { { 0xd3 }, 2, T, R, pfx_66, W0, Ln }, /* vpdpwusds */
+ { { 0xd3 }, 2, T, R, pfx_f3, W0, Ln }, /* vpdpwsuds */
{ { 0xda }, 2, T, R, pfx_f3, W0, Ln }, /* vsm4key4 */
{ { 0xda }, 2, T, R, pfx_f2, W0, Ln }, /* vsm4rnds4 */
{ { 0xdc }, 2, T, R, pfx_66, WIG, Ln }, /* vaesenc */
@@ -2075,6 +2088,7 @@ static const struct evex {
{ { 0x3e }, 3, T, R, pfx_66, Wn, Ln }, /* vpcmpu{b,w} */
{ { 0x3f }, 3, T, R, pfx_66, Wn, Ln }, /* vpcmp{b,w} */
{ { 0x42 }, 3, T, R, pfx_66, W0, Ln }, /* vdbpsadbw */
+ { { 0x42 }, 3, T, R, pfx_f3, W0, Ln }, /* vmpsadbw */
{ { 0x43 }, 3, T, R, pfx_66, Wn, L1|L2 }, /* vshufi{32x4,64x2} */
{ { 0x44 }, 3, T, R, pfx_66, WIG, Ln }, /* vpclmulqdq */
{ { 0x50 }, 3, T, R, pfx_66, Wn, Ln }, /* vrangep{s,d} */
--- a/xen/arch/x86/x86_emulate/decode.c
+++ b/xen/arch/x86/x86_emulate/decode.c
@@ -434,8 +434,8 @@ static const struct ext0f38_table {
[0xcb] = { .simd_size = simd_other, .d8s = d8s_vl },
[0xcc ... 0xcd] = { .simd_size = simd_other, .two_op = 1, .d8s = d8s_vl },
[0xcf] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
- [0xd2] = { .simd_size = simd_other },
- [0xd3] = { .simd_size = simd_other },
+ [0xd2] = { .simd_size = simd_other, .d8s = d8s_vl },
+ [0xd3] = { .simd_size = simd_other, .d8s = d8s_vl },
[0xd6] = { .simd_size = simd_other, .d8s = d8s_vl },
[0xd7] = { .simd_size = simd_scalar_vexw, .d8s = d8s_dq },
[0xda] = { .simd_size = simd_other, .d8s = d8s_vl },
--- a/xen/arch/x86/x86_emulate/x86_emulate.c
+++ b/xen/arch/x86/x86_emulate/x86_emulate.c
@@ -6217,6 +6217,30 @@ x86_emulate(
avx512_vlen_check(true);
goto simd_zmm;
+ case X86EMUL_OPC_EVEX (0x0f38, 0x50): /* vpdpbuud [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
+ case X86EMUL_OPC_EVEX_F3(0x0f38, 0x50): /* vpdpbsud [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
+ case X86EMUL_OPC_EVEX_F2(0x0f38, 0x50): /* vpdpbssd [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
+ case X86EMUL_OPC_EVEX (0x0f38, 0x51): /* vpdpbuuds [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
+ case X86EMUL_OPC_EVEX_F3(0x0f38, 0x51): /* vpdpbsuds [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
+ case X86EMUL_OPC_EVEX_F2(0x0f38, 0x51): /* vpdpbssds [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
+ case X86EMUL_OPC_EVEX (0x0f38, 0xd2): /* vpdpwuud [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
+ case X86EMUL_OPC_EVEX_66(0x0f38, 0xd2): /* vpdpwusd [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
+ case X86EMUL_OPC_EVEX_F3(0x0f38, 0xd2): /* vpdpwsud [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
+ case X86EMUL_OPC_EVEX (0x0f38, 0xd3): /* vpdpwuuds [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
+ case X86EMUL_OPC_EVEX_66(0x0f38, 0xd3): /* vpdpwusds [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
+ case X86EMUL_OPC_EVEX_F3(0x0f38, 0xd3): /* vpdpwsuds [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
+ generate_exception_if(evex.w, X86_EXC_UD);
+ if ( !cp->avx10.avx10_v1_aux )
+ vcpu_must_have(avx10, 2);
+ op_bytes = 16 << evex.lr;
+ goto avx512f_no_sae;
+
+ case X86EMUL_OPC_EVEX (0x0f38, 0x52): /* vdpphps [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
+ generate_exception_if(evex.w, X86_EXC_UD);
+ vcpu_must_have(avx10, 2);
+ op_bytes = 16 << evex.lr;
+ goto avx512f_no_sae;
+
case X86EMUL_OPC_EVEX_66(0x0f38, 0x8f): /* vpshufbitqmb [xyz]mm/mem,[xyz]mm,k{k} */
generate_exception_if(evex.w || !evex.r || !evex.R || evex.z, X86_EXC_UD);
/* fall through */
@@ -7685,6 +7709,14 @@ x86_emulate(
visa_check(bw);
goto opmask_shift_imm;
+ case X86EMUL_OPC_EVEX_F3(0x0f3a, 0x42): /* vmpsadbw $imm8,[xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
+ generate_exception_if(evex.w || evex.brs, X86_EXC_UD);
+ vcpu_must_have(avx10, 2);
+ avx512_vlen_check(false);
+ op_bytes = 16 << evex.lr;
+ fault_suppression = false;
+ goto simd_imm8_zmm;
+
case X86EMUL_OPC_66(0x0f3a, 0x44): /* pclmulqdq $imm8,xmm/m128,xmm */
case X86EMUL_OPC_VEX_66(0x0f3a, 0x44): /* vpclmulqdq $imm8,{x,y}mm/mem,{x,y}mm,{x,y}mm */
vcpu_must_have(pclmulqdq);
^ permalink raw reply [flat|nested] 20+ messages in thread* [PATCH v5 13/19] x86emul: support AVX10.2 minmax insns
2026-11-11 13:40 [PATCH v5 00/19] x86: support AVX10 Jan Beulich
` (11 preceding siblings ...)
2026-11-11 13:47 ` [PATCH v5 12/19] x86emul: support AVX10.2 media insns Jan Beulich
@ 2026-11-11 13:47 ` Jan Beulich
2026-11-11 13:47 ` [PATCH v5 14/19] x86emul: support AVX10.2 BFloat16 insns Jan Beulich
` (5 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Jan Beulich @ 2026-11-11 13:47 UTC (permalink / raw)
To: xen-devel@lists.xenproject.org
Cc: Andrew Cooper, Teddy Astie, Roger Pau Monné
While they use new major opcodes, they are still pretty similar to
various existing insns.
Signed-off-by: Jan Beulich <jbeulich@suse.com>
---
SDE: -dmr / -future
---
v4: Update to spec version 3. Switch to using fallthrough pseudo-
keyword.
v3: New.
--- a/tools/tests/x86_emulator/evex-disp8.c
+++ b/tools/tests/x86_emulator/evex-disp8.c
@@ -726,6 +726,11 @@ static const struct test avx10_2_all[] =
INSN_SFP(comx, 0f, 2f),
INSN(comxsh, f3, map5, 2f, el, fp16, el),
INSN(dpphps, , 0f38, 52, vl, d, vl),
+ INSN(minmax, 66, 0f3a, 52, vl, sd, vl),
+ INSN(minmax, 66, 0f3a, 53, el, sd, el),
+ INSN(minmaxbf16, f2, 0f3a, 52, vl, bf16, vl),
+ INSN(minmaxph, , 0f3a, 52, vl, fp16, vl),
+ INSN(minmaxsh, , 0f3a, 53, el, fp16, el),
INSN(mpsadbw, f3, 0f3a, 42, vl, d_nb, vl),
INSN(pdpbssd, f2, 0f38, 50, vl, d, vl),
INSN(pdpbssds, f2, 0f38, 51, vl, d, vl),
--- a/tools/tests/x86_emulator/predicates.c
+++ b/tools/tests/x86_emulator/predicates.c
@@ -2093,6 +2093,11 @@ static const struct evex {
{ { 0x44 }, 3, T, R, pfx_66, WIG, Ln }, /* vpclmulqdq */
{ { 0x50 }, 3, T, R, pfx_66, Wn, Ln }, /* vrangep{s,d} */
{ { 0x51 }, 3, T, R, pfx_66, Wn, LIG }, /* vranges{s,d} */
+ { { 0x52 }, 3, T, R, pfx_no, W0, Ln }, /* vminmaxph */
+ { { 0x52 }, 3, T, R, pfx_66, Wn, Ln }, /* vminmaxp{s,d} */
+ { { 0x52 }, 3, T, R, pfx_f2, W0, Ln }, /* vminmaxbf16 */
+ { { 0x53 }, 3, T, R, pfx_no, W0, LIG }, /* vminmaxsh */
+ { { 0x53 }, 3, T, R, pfx_66, Wn, LIG }, /* vminmaxs{s,d} */
{ { 0x54 }, 3, T, R, pfx_66, Wn, Ln }, /* vfixupimmp{s,d} */
{ { 0x55 }, 3, T, R, pfx_66, Wn, LIG }, /* vfixumpimms{s,d} */
{ { 0x56 }, 3, T, R, pfx_no, W0, Ln }, /* vreduceph */
--- a/xen/arch/x86/x86_emulate/decode.c
+++ b/xen/arch/x86/x86_emulate/decode.c
@@ -500,6 +500,8 @@ static const struct ext0f3a_table {
[0x4c] = { .simd_size = simd_packed_int, .four_op = 1 },
[0x50] = { .simd_size = simd_packed_fp, .d8s = d8s_vl },
[0x51] = { .simd_size = simd_scalar_vexw, .d8s = d8s_dq },
+ [0x52] = { .simd_size = simd_packed_fp, .d8s = d8s_vl },
+ [0x53] = { .simd_size = simd_scalar_vexw, .d8s = d8s_dq },
[0x54] = { .simd_size = simd_packed_fp, .d8s = d8s_vl },
[0x55] = { .simd_size = simd_scalar_vexw, .d8s = d8s_dq },
[0x56] = { .simd_size = simd_packed_fp, .two_op = 1, .d8s = d8s_vl },
@@ -1468,6 +1470,7 @@ int x86emul_decode(struct x86_emulate_st
case 0x0a: /* vrndscalesh */
case 0x26: /* vfpclassph */
case 0x27: /* vfpclasssh */
+ case 0x53: /* vminmaxsh */
case 0x56: /* vgetmantph */
case 0x57: /* vgetmantsh */
case 0x66: /* vreduceph */
@@ -1476,6 +1479,11 @@ int x86emul_decode(struct x86_emulate_st
s->fp16 = true;
break;
+ case 0x52: /* vminmax{ph,bf16} */
+ if ( !s->evex.pfx || s->evex.pfx == vex_f2 )
+ s->fp16 = true;
+ break;
+
case 0xc2: /* vpcmp{p,s}h */
if ( !(s->evex.pfx & VEX_PREFIX_DOUBLE_MASK) )
s->fp16 = true;
--- a/xen/arch/x86/x86_emulate/x86_emulate.c
+++ b/xen/arch/x86/x86_emulate/x86_emulate.c
@@ -7747,6 +7747,21 @@ x86_emulate(
generate_exception_if(vex.w, X86_EXC_UD);
goto simd_0f_int_imm8;
+ case X86EMUL_OPC_EVEX_F2(0x0f3a, 0x52): /* vminmaxbf16 $imm8,[xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
+ generate_exception_if(ea.type != OP_MEM && evex.brs, X86_EXC_UD);
+ op_bytes = 16 << evex.lr;
+ fallthrough;
+ case X86EMUL_OPC_EVEX(0x0f3a, 0x52): /* vminmaxph $imm8,[xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
+ case X86EMUL_OPC_EVEX(0x0f3a, 0x53): /* vminmaxsh $imm,xmm/m16,xmm,xmm,xmm{k} */
+ generate_exception_if(vex.w, X86_EXC_UD);
+ fallthrough;
+ case X86EMUL_OPC_EVEX_66(0x0f3a, 0x52): /* vminmaxp{s,d} $imm8,[xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
+ case X86EMUL_OPC_EVEX_66(0x0f3a, 0x53): /* vminmaxs{s,d} $imm8,xmm/mem,xmm,xmm{k} */
+ vcpu_must_have(avx10, 2);
+ if ( ea.type != OP_REG || !evex.brs )
+ avx512_vlen_check(b & 1);
+ goto simd_imm8_zmm;
+
case X86EMUL_OPC_VEX_66(0x0f3a, 0x5c): /* vfmaddsubps {x,y}mm,{x,y}mm/mem,{x,y}mm,{x,y}mm */
/* vfmaddsubps {x,y}mm/mem,{x,y}mm,{x,y}mm,{x,y}mm */
case X86EMUL_OPC_VEX_66(0x0f3a, 0x5d): /* vfmaddsubpd {x,y}mm,{x,y}mm/mem,{x,y}mm,{x,y}mm */
^ permalink raw reply [flat|nested] 20+ messages in thread* [PATCH v5 14/19] x86emul: support AVX10.2 BFloat16 insns
2026-11-11 13:40 [PATCH v5 00/19] x86: support AVX10 Jan Beulich
` (12 preceding siblings ...)
2026-11-11 13:47 ` [PATCH v5 13/19] x86emul: support AVX10.2 minmax insns Jan Beulich
@ 2026-11-11 13:47 ` Jan Beulich
2026-11-11 13:48 ` [PATCH v5 15/19] x86emul: support AVX10.2 saturating convert insns Jan Beulich
` (4 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Jan Beulich @ 2026-11-11 13:47 UTC (permalink / raw)
To: xen-devel@lists.xenproject.org
Cc: Andrew Cooper, Teddy Astie, Roger Pau Monné
These are all very similar to various existing insns. VGETEXPPBF16, not
living in the expected place, benefits from the respective
twobyte_table[] entry already having Mov (aka TwoOp).
Signed-off-by: Jan Beulich <jbeulich@suse.com>
---
SDE: -dmr / -future
---
v4: Update to spec version 3. Switch to using fallthrough pseudo-
keyword.
v3: New.
--- a/tools/tests/x86_emulator/evex-disp8.c
+++ b/tools/tests/x86_emulator/evex-disp8.c
@@ -722,15 +722,36 @@ static const struct test vpclmulqdq_all[
};
static const struct test avx10_2_all[] = {
+ INSN(addbf16, 66, map5, 58, vl, bf16, vl),
+ INSN(cmpbf16, f2, 0f3a, c2, vl, bf16, vl),
INSN(comisbf16, 66, map5, 2f, el, bf16, el),
INSN_SFP(comx, 0f, 2f),
INSN(comxsh, f3, map5, 2f, el, fp16, el),
+ INSN(divbf16, 66, map5, 5e, vl, bf16, vl),
INSN(dpphps, , 0f38, 52, vl, d, vl),
+ INSN(fmadd132bf16, , map6, 98, vl, bf16, vl),
+ INSN(fmadd213bf16, , map6, a8, vl, bf16, vl),
+ INSN(fmadd231bf16, , map6, b8, vl, bf16, vl),
+ INSN(fmsub132bf16, , map6, 9a, vl, bf16, vl),
+ INSN(fmsub213bf16, , map6, aa, vl, bf16, vl),
+ INSN(fmsub231bf16, , map6, ba, vl, bf16, vl),
+ INSN(fnmadd132bf16, , map6, 9c, vl, bf16, vl),
+ INSN(fnmadd213bf16, , map6, ac, vl, bf16, vl),
+ INSN(fnmadd231bf16, , map6, bc, vl, bf16, vl),
+ INSN(fnmsub132bf16, , map6, 9e, vl, bf16, vl),
+ INSN(fnmsub213bf16, , map6, ae, vl, bf16, vl),
+ INSN(fnmsub231bf16, , map6, be, vl, bf16, vl),
+ INSN(fpclassbf16, f2, 0f3a, 66, vl, bf16, vl),
+ INSN(getexpbf16, , map6, 42, vl, bf16, vl),
+ INSN(getmantbf16, f2, 0f3a, 26, vl, bf16, vl),
+ INSN(maxbf16, 66, map5, 5f, vl, bf16, vl),
+ INSN(minbf16, 66, map5, 5d, vl, bf16, vl),
INSN(minmax, 66, 0f3a, 52, vl, sd, vl),
INSN(minmax, 66, 0f3a, 53, el, sd, el),
INSN(minmaxbf16, f2, 0f3a, 52, vl, bf16, vl),
INSN(minmaxph, , 0f3a, 52, vl, fp16, vl),
INSN(minmaxsh, , 0f3a, 53, el, fp16, el),
+ INSN(mulbf16, 66, map5, 59, vl, bf16, vl),
INSN(mpsadbw, f3, 0f3a, 42, vl, d_nb, vl),
INSN(pdpbssd, f2, 0f38, 50, vl, d, vl),
INSN(pdpbssds, f2, 0f38, 51, vl, d, vl),
@@ -744,6 +765,13 @@ static const struct test avx10_2_all[] =
INSN(pdpwusds, 66, 0f38, d3, vl, d, vl),
INSN(pdpwuud, , 0f38, d2, vl, d, vl),
INSN(pdpwuuds, , 0f38, d3, vl, d, vl),
+ INSN(rcpph, , map6, 4c, vl, bf16, vl),
+ INSN(reducebf16, f2, 0f3a, 56, vl, bf16, vl),
+ INSN(rndscalebf16, f2, 0f3a, 08, vl, bf16, vl),
+ INSN(rsqrtph, , map6, 4e, vl, bf16, vl),
+ INSN(scalefbf16, , map6, 2c, vl, bf16, vl),
+ INSN(sqrtbf16, 66, map5, 51, vl, bf16, vl),
+ INSN(subbf16, 66, map5, 5c, vl, bf16, vl),
INSN_SFP(ucomx, 0f, 2e),
INSN(ucomxsh, f3, map5, 2e, el, fp16, el),
};
--- a/tools/tests/x86_emulator/predicates.c
+++ b/tools/tests/x86_emulator/predicates.c
@@ -2056,6 +2056,7 @@ static const struct evex {
{ { 0x05 }, 3, T, R, pfx_66, W1, Ln }, /* vpermilpd */
{ { 0x08 }, 3, T, R, pfx_no, W0, Ln }, /* vrndscaleph */
{ { 0x08 }, 3, T, R, pfx_66, W0, Ln }, /* vrndscaleps */
+ { { 0x08 }, 3, T, R, pfx_f2, W0, Ln }, /* vrndscalebf16 */
{ { 0x09 }, 3, T, R, pfx_66, W1, Ln }, /* vrndscalepd */
{ { 0x0a }, 3, T, R, pfx_no, W0, LIG }, /* vrndscalesh */
{ { 0x0a }, 3, T, R, pfx_66, W0, LIG }, /* vrndscaless */
@@ -2079,6 +2080,7 @@ static const struct evex {
{ { 0x25 }, 3, T, R, pfx_66, Wn, Ln }, /* vpternlog{d,q} */
{ { 0x26 }, 3, T, R, pfx_no, W0, Ln }, /* vgetmantph */
{ { 0x26 }, 3, T, R, pfx_66, Wn, Ln }, /* vgetmantp{s,d} */
+ { { 0x26 }, 3, T, R, pfx_f2, W0, Ln }, /* vgetmantbf16 */
{ { 0x27 }, 3, T, R, pfx_no, W0, LIG }, /* vgetmantsh */
{ { 0x27 }, 3, T, R, pfx_66, Wn, LIG }, /* vgetmants{s,d} */
{ { 0x38 }, 3, T, R, pfx_66, Wn, L1|L2 }, /* vinserti{32x4,64x2} */
@@ -2102,10 +2104,12 @@ static const struct evex {
{ { 0x55 }, 3, T, R, pfx_66, Wn, LIG }, /* vfixumpimms{s,d} */
{ { 0x56 }, 3, T, R, pfx_no, W0, Ln }, /* vreduceph */
{ { 0x56 }, 3, T, R, pfx_66, Wn, Ln }, /* vreducep{s,d} */
+ { { 0x56 }, 3, T, R, pfx_f2, W0, Ln }, /* vreducebf16 */
{ { 0x57 }, 3, T, R, pfx_no, W0, LIG }, /* vreducesh */
{ { 0x57 }, 3, T, R, pfx_66, Wn, LIG }, /* vreduces{s,d} */
{ { 0x66 }, 3, T, R, pfx_no, W0, Ln }, /* vfpclassph */
{ { 0x66 }, 3, T, R, pfx_66, Wn, Ln }, /* vfpclassp{s,d} */
+ { { 0x66 }, 3, T, R, pfx_f2, W0, Ln }, /* vfpclassbf16 */
{ { 0x67 }, 3, T, R, pfx_no, W0, LIG }, /* vfpclasssh */
{ { 0x67 }, 3, T, R, pfx_66, Wn, LIG }, /* vfpclasss{s,d} */
{ { 0x70 }, 3, T, R, pfx_66, W1, Ln }, /* vshldw */
@@ -2114,6 +2118,7 @@ static const struct evex {
{ { 0x73 }, 3, T, R, pfx_66, Wn, Ln }, /* vshrd{d,q} */
{ { 0xc2 }, 3, T, R, pfx_no, W0, Ln }, /* vcmpph */
{ { 0xc2 }, 3, T, R, pfx_f3, W0, LIG }, /* vcmpsh */
+ { { 0xc2 }, 3, T, R, pfx_f2, W0, Ln }, /* vcmpbf16 */
{ { 0xce }, 3, T, R, pfx_66, W1, Ln }, /* vgf2p8affineqb */
{ { 0xcf }, 3, T, R, pfx_66, W1, Ln }, /* vgf2p8affineinvqb */
}, evex_map5[] = {
@@ -2130,10 +2135,13 @@ static const struct evex {
{ { 0x2f }, 2, T, R, pfx_66, W0, LIG }, /* vcomisbf16 */
{ { 0x2f }, 2, T, R, pfx_f3, W0, LIG }, /* vcomxsh */
{ { 0x51 }, 2, T, R, pfx_no, W0, Ln }, /* vsqrtph */
+ { { 0x51 }, 2, T, R, pfx_66, W0, Ln }, /* vsqrtbf16 */
{ { 0x51 }, 2, T, R, pfx_f3, W0, LIG }, /* vsqrtsh */
{ { 0x58 }, 2, T, R, pfx_no, W0, Ln }, /* vaddph */
+ { { 0x58 }, 2, T, R, pfx_66, W0, Ln }, /* vaddbf16 */
{ { 0x58 }, 2, T, R, pfx_f3, W0, LIG }, /* vaddsh */
{ { 0x59 }, 2, T, R, pfx_no, W0, Ln }, /* vmulph */
+ { { 0x59 }, 2, T, R, pfx_66, W0, Ln }, /* vmulbf16 */
{ { 0x59 }, 2, T, R, pfx_f3, W0, LIG }, /* vmulsh */
{ { 0x5a }, 2, T, R, pfx_no, W0, Ln }, /* vcvtph2pd */
{ { 0x5a }, 2, T, R, pfx_66, W1, Ln }, /* vcvtpd2ph */
@@ -2144,12 +2152,16 @@ static const struct evex {
{ { 0x5b }, 2, T, R, pfx_66, W0, Ln }, /* vcvtph2dq */
{ { 0x5b }, 2, T, R, pfx_f3, W0, Ln }, /* vcvttph2dq */
{ { 0x5c }, 2, T, R, pfx_no, W0, Ln }, /* vsubph */
+ { { 0x5c }, 2, T, R, pfx_66, W0, Ln }, /* vsubbf16 */
{ { 0x5c }, 2, T, R, pfx_f3, W0, LIG }, /* vsubsh */
{ { 0x5d }, 2, T, R, pfx_no, W0, Ln }, /* vminph */
+ { { 0x5d }, 2, T, R, pfx_66, W0, Ln }, /* vminbf16 */
{ { 0x5d }, 2, T, R, pfx_f3, W0, LIG }, /* vminsh */
{ { 0x5e }, 2, T, R, pfx_no, W0, Ln }, /* vdivph */
+ { { 0x5e }, 2, T, R, pfx_66, W0, Ln }, /* vdivbf16 */
{ { 0x5e }, 2, T, R, pfx_f3, W0, LIG }, /* vdivsh */
{ { 0x5f }, 2, T, R, pfx_no, W0, Ln }, /* vmaxph */
+ { { 0x5f }, 2, T, R, pfx_66, W0, Ln }, /* vmaxbf16 */
{ { 0x5f }, 2, T, R, pfx_f3, W0, LIG }, /* vmaxsh */
{ { 0x6e }, 2, T, R, pfx_66, WIG, L0 }, /* vmovw */
{ { 0x6e }, 2, T, R, pfx_f3, W0, L0 }, /* vmovw */
@@ -2177,12 +2189,16 @@ static const struct evex {
}, evex_map6[] = {
{ { 0x13 }, 2, T, R, pfx_66, W0, Ln }, /* vcvtph2psx */
{ { 0x13 }, 2, T, R, pfx_no, W0, LIG }, /* vcvtsh2ss */
+ { { 0x2c }, 2, T, R, pfx_no, W0, Ln }, /* vscalefbf16 */
{ { 0x2c }, 2, T, R, pfx_66, W0, Ln }, /* vscalefph */
{ { 0x2d }, 2, T, R, pfx_66, W0, LIG }, /* vscalefsh */
+ { { 0x42 }, 2, T, R, pfx_no, W0, Ln }, /* vgetexpbf16 */
{ { 0x42 }, 2, T, R, pfx_66, W0, Ln }, /* vgetexpph */
{ { 0x43 }, 2, T, R, pfx_66, W0, LIG }, /* vgetexpsh */
+ { { 0x4c }, 2, T, R, pfx_no, W0, Ln }, /* vrcpbf16 */
{ { 0x4c }, 2, T, R, pfx_66, W0, Ln }, /* vrcpph */
{ { 0x4d }, 2, T, R, pfx_66, W0, LIG }, /* vrcpsh */
+ { { 0x4e }, 2, T, R, pfx_no, W0, Ln }, /* vrsqrtbf16 */
{ { 0x4e }, 2, T, R, pfx_66, W0, Ln }, /* vrsqrtph */
{ { 0x4f }, 2, T, R, pfx_66, W0, LIG }, /* vrsqrtsh */
{ { 0x56 }, 2, T, R, pfx_f3, W0, Ln }, /* vfmaddcph */
--- a/xen/arch/x86/x86_emulate/decode.c
+++ b/xen/arch/x86/x86_emulate/decode.c
@@ -1466,31 +1466,34 @@ int x86emul_decode(struct x86_emulate_st
{
switch ( b )
{
- case 0x08: /* vrndscaleph */
+ case 0x08: /* vrndscale{ph,bf16} */
+ case 0x26: /* vfpclass{ph,bf16} */
+ case 0x52: /* vminmax{ph,bf16} */
+ case 0x56: /* vgetmant{ph,bf16} */
+ case 0x66: /* vreduce{ph,bf16} */
+ if ( !s->evex.pfx || s->evex.pfx == vex_f2 )
+ s->fp16 = true;
+ break;
+
case 0x0a: /* vrndscalesh */
- case 0x26: /* vfpclassph */
case 0x27: /* vfpclasssh */
case 0x53: /* vminmaxsh */
- case 0x56: /* vgetmantph */
case 0x57: /* vgetmantsh */
- case 0x66: /* vreduceph */
case 0x67: /* vreducesh */
if ( !s->evex.pfx )
s->fp16 = true;
break;
- case 0x52: /* vminmax{ph,bf16} */
- if ( !s->evex.pfx || s->evex.pfx == vex_f2 )
- s->fp16 = true;
- break;
-
- case 0xc2: /* vpcmp{p,s}h */
- if ( !(s->evex.pfx & VEX_PREFIX_DOUBLE_MASK) )
+ case 0xc2: /* vpcmp{p,s}h, vcmpbf16 */
+ if ( s->evex.pfx != vex_66 )
s->fp16 = true;
break;
}
- disp8scale = decode_disp8scale(ext0f3a_table[b].d8s, s);
+ if ( s->fp16 && s->evex.pfx == vex_f2 && !s->evex.brs )
+ disp8scale = 4 + s->evex.lr;
+ else
+ disp8scale = decode_disp8scale(ext0f3a_table[b].d8s, s);
}
break;
@@ -1498,7 +1501,7 @@ int x86emul_decode(struct x86_emulate_st
switch ( b )
{
default:
- if ( !(s->evex.pfx & VEX_PREFIX_DOUBLE_MASK) )
+ if ( s->evex.pfx != vex_f2 )
s->fp16 = true;
break;
@@ -1528,6 +1531,11 @@ int x86emul_decode(struct x86_emulate_st
s->simd_size = simd_none;
break;
+ case 0x5a: /* vcvt{p,s}d2{p,s}h, vcvt{p,s}h2{p,s}d */
+ if ( !(s->evex.pfx & VEX_PREFIX_DOUBLE_MASK) )
+ s->fp16 = true;
+ break;
+
case 0x5b: /* vcvt{d,q}q2ph, vcvt{,t}ph2dq */
if ( s->evex.pfx && s->evex.pfx != vex_f2 )
s->fp16 = true;
@@ -1580,6 +1588,14 @@ int x86emul_decode(struct x86_emulate_st
disp8scale = 1;
break;
+ case 0x42: /* vgetexpbf16 needs special casing */
+ if ( s->evex.pfx == vex_66 )
+ {
+ s->simd_size = simd_packed_fp;
+ disp8scale = s->evex.brs ? 1 : 4 + s->evex.lr;
+ }
+ break;
+
case 0x5a: /* vcvtph2pd needs special casing */
if ( !s->evex.pfx && !s->evex.brs )
disp8scale -= 2;
@@ -1612,7 +1628,7 @@ int x86emul_decode(struct x86_emulate_st
switch ( b )
{
default:
- if ( s->evex.pfx == vex_66 )
+ if ( !(s->evex.pfx & VEX_PREFIX_SCALAR_MASK) )
s->fp16 = true;
break;
@@ -1934,6 +1950,13 @@ int x86emul_decode(struct x86_emulate_st
s->op_bytes = 4 >> s->fp16;
break;
case vex_f2:
+ if ( s->fp16 )
+ {
+ ASSERT(evex_encoded());
+ generate_exception_if(s->evex.w, X86_EXC_UD);
+ s->op_bytes = 0;
+ break;
+ }
generate_exception_if(evex_encoded() && !s->evex.w, X86_EXC_UD);
s->op_bytes = 8;
break;
--- a/xen/arch/x86/x86_emulate/x86_emulate.c
+++ b/xen/arch/x86/x86_emulate/x86_emulate.c
@@ -7351,6 +7351,20 @@ x86_emulate(
avx512_vlen_check(b & 2);
goto simd_imm8_zmm;
+ case X86EMUL_OPC_EVEX_F2(0x0f3a, 0x66): /* vfpclassbf16 $imm8,[xyz]mm/mem,k{k} */
+ case X86EMUL_OPC_EVEX_F2(0x0f3a, 0xc2): /* vcmpbf16 $imm8,[xyz]mm/mem,[xyz]mm,k{k} */
+ generate_exception_if(!evex.r || !evex.R || evex.z, X86_EXC_UD);
+ fallthrough;
+ case X86EMUL_OPC_EVEX_F2(0x0f3a, 0x08): /* vrndscalebf16 $imm8,[xyz]mm/mem,[xyz]mm{k} */
+ case X86EMUL_OPC_EVEX_F2(0x0f3a, 0x26): /* vgetmantbf16 $imm8,[xyz]mm/mem,[xyz]mm{k} */
+ case X86EMUL_OPC_EVEX_F2(0x0f3a, 0x56): /* vreducebf16 $imm8,[xyz]mm/mem,[xyz]mm{k} */
+ generate_exception_if(evex.w || (ea.type != OP_MEM && evex.brs),
+ X86_EXC_UD);
+ vcpu_must_have(avx10, 2);
+ avx512_vlen_check(false);
+ op_bytes = 16 << evex.lr;
+ goto simd_imm8_zmm;
+
#endif /* X86EMUL_NO_SIMD */
CASE_SIMD_PACKED_INT(0x0f3a, 0x0f): /* palignr $imm8,{,x}mm/mem,{,x}mm */
@@ -7982,6 +7996,36 @@ x86_emulate(
generate_exception_if(evex.w, X86_EXC_UD);
goto avx512f_all_fp;
+ case X86EMUL_OPC_EVEX_66(5, 0x51): /* vsqrtbf16 [xyz]mm/mem,[xyz]mm{k} */
+ case X86EMUL_OPC_EVEX_66(5, 0x58): /* vaddbf16 [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
+ case X86EMUL_OPC_EVEX_66(5, 0x59): /* vmulbf16 [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
+ case X86EMUL_OPC_EVEX_66(5, 0x5c): /* vsubbf16 [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
+ case X86EMUL_OPC_EVEX_66(5, 0x5d): /* vminbf16 [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
+ case X86EMUL_OPC_EVEX_66(5, 0x5e): /* vdivbf16 [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
+ case X86EMUL_OPC_EVEX_66(5, 0x5f): /* vmaxbf16 [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
+ case X86EMUL_OPC_EVEX(6, 0x2c): /* vscalefbf16 [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
+ case X86EMUL_OPC_EVEX(6, 0x42): /* vgetexpbf16 [xyz]mm/mem,[xyz]mm{k} */
+ case X86EMUL_OPC_EVEX(6, 0x4c): /* vrcpbf16 [xyz]mm/mem,[xyz]mm{k} */
+ case X86EMUL_OPC_EVEX(6, 0x4e): /* vrsqrtbf16 [xyz]mm/mem,[xyz]mm{k} */
+ case X86EMUL_OPC_EVEX(6, 0x98): /* vfmadd132bf16 [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
+ case X86EMUL_OPC_EVEX(6, 0x9a): /* vfmsub132bf16 [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
+ case X86EMUL_OPC_EVEX(6, 0x9c): /* vfnmadd132bf16 [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
+ case X86EMUL_OPC_EVEX(6, 0x9e): /* vfnmsub132bf16 [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
+ case X86EMUL_OPC_EVEX(6, 0xa8): /* vfmadd213bf16 [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
+ case X86EMUL_OPC_EVEX(6, 0xaa): /* vfmsub213bf16 [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
+ case X86EMUL_OPC_EVEX(6, 0xac): /* vfnmadd213bf16 [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
+ case X86EMUL_OPC_EVEX(6, 0xae): /* vfnmsub213bf16 [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
+ case X86EMUL_OPC_EVEX(6, 0xb8): /* vfmadd231bf16 [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
+ case X86EMUL_OPC_EVEX(6, 0xba): /* vfmsub231bf16 [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
+ case X86EMUL_OPC_EVEX(6, 0xbc): /* vfnmadd231bf16 [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
+ case X86EMUL_OPC_EVEX(6, 0xbe): /* vfnmsub231bf16 [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
+ generate_exception_if(evex.w || (ea.type != OP_MEM && evex.brs),
+ X86_EXC_UD);
+ vcpu_must_have(avx10, 2);
+ avx512_vlen_check(false);
+ op_bytes = 16 << evex.lr;
+ goto simd_zmm;
+
CASE_SIMD_ALL_FP(_EVEX, 5, 0x5a): /* vcvtp{h,d}2p{h,d} [xyz]mm/mem,[xyz]mm{k} */
/* vcvts{h,d}2s{h,d} xmm/mem,xmm,xmm{k} */
visa_check(_fp16);
^ permalink raw reply [flat|nested] 20+ messages in thread* [PATCH v5 15/19] x86emul: support AVX10.2 saturating convert insns
2026-11-11 13:40 [PATCH v5 00/19] x86: support AVX10 Jan Beulich
` (13 preceding siblings ...)
2026-11-11 13:47 ` [PATCH v5 14/19] x86emul: support AVX10.2 BFloat16 insns Jan Beulich
@ 2026-11-11 13:48 ` Jan Beulich
2026-11-11 13:48 ` [PATCH v5 16/19] x86emul: support other AVX10.2 " Jan Beulich
` (3 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Jan Beulich @ 2026-11-11 13:48 UTC (permalink / raw)
To: xen-devel@lists.xenproject.org
Cc: Andrew Cooper, Teddy Astie, Roger Pau Monné
While the to-byte ones are somewhat different from what has been there
(yet then nicely regular from an operands perspective), the others are
pretty similar to various existing insns.
Signed-off-by: Jan Beulich <jbeulich@suse.com>
---
Spec rev 002 says VCVTTNEBF162I{,U}BS, yet that's going to change to
VCVTTBF162I{,U}BS.
---
SDE: -dmr / -future
---
v4: Update to spec version 3. Switch to using fallthrough pseudo-
keyword. Series re-ordering adjustments.
v3: New.
--- a/tools/tests/x86_emulator/evex-disp8.c
+++ b/tools/tests/x86_emulator/evex-disp8.c
@@ -727,6 +727,30 @@ static const struct test avx10_2_all[] =
INSN(comisbf16, 66, map5, 2f, el, bf16, el),
INSN_SFP(comx, 0f, 2f),
INSN(comxsh, f3, map5, 2f, el, fp16, el),
+ INSN(cvtbf162ibs, f2, map5, 69, vl, bf16, vl),
+ INSN(cvtbf162iubs, f2, map5, 6b, vl, bf16, vl),
+ INSN(cvtph2ibs, , map5, 69, vl, fp16, vl),
+ INSN(cvtph2iubs, , map5, 6b, vl, fp16, vl),
+ INSN(cvtps2ibs, 66, map5, 69, vl, d, vl),
+ INSN(cvtps2iubs, 66, map5, 6b, vl, d, vl),
+ INSN(cvttbf162ibs, f2, map5, 68, vl, bf16, vl),
+ INSN(cvttbf162iubs, f2, map5, 6a, vl, bf16, vl),
+ INSN(cvttpd2dqs, , map5, 6d, vl, q, vl),
+ INSN(cvttpd2qqs, 66, map5, 6d, vl, q, vl),
+ INSN(cvttpd2udqs, , map5, 6c, vl, q, vl),
+ INSN(cvttpd2uqqs, 66, map5, 6c, vl, q, vl),
+ INSN(cvttph2ibs, , map5, 68, vl, fp16, vl),
+ INSN(cvttph2iubs, , map5, 6a, vl, fp16, vl),
+ INSN(cvttps2dqs, , map5, 6d, vl, d, vl),
+ INSN(cvttps2ibs, 66, map5, 68, vl, d, vl),
+ INSN(cvttps2iubs, 66, map5, 6a, vl, d, vl),
+ INSN(cvttps2qqs, 66, map5, 6d, vl_2, d, vl),
+ INSN(cvttps2udqs, , map5, 6c, vl, d, vl),
+ INSN(cvttps2uqqs, 66, map5, 6c, vl_2, d, vl),
+ INSN(cvttsd2sis, f2, map5, 6d, el, q, el),
+ INSN(cvttsd2usis, f2, map5, 6c, el, q, el),
+ INSN(cvttss2sis, f3, map5, 6d, el, d, el),
+ INSN(cvttss2usis, f3, map5, 6c, el, d, el),
INSN(divbf16, 66, map5, 5e, vl, bf16, vl),
INSN(dpphps, , 0f38, 52, vl, d, vl),
INSN(fmadd132bf16, , map6, 98, vl, bf16, vl),
--- a/tools/tests/x86_emulator/predicates.c
+++ b/tools/tests/x86_emulator/predicates.c
@@ -2163,6 +2163,26 @@ static const struct evex {
{ { 0x5f }, 2, T, R, pfx_no, W0, Ln }, /* vmaxph */
{ { 0x5f }, 2, T, R, pfx_66, W0, Ln }, /* vmaxbf16 */
{ { 0x5f }, 2, T, R, pfx_f3, W0, LIG }, /* vmaxsh */
+ { { 0x68 }, 2, T, R, pfx_no, W0, Ln }, /* vcvttph2ibs */
+ { { 0x68 }, 2, T, R, pfx_66, W0, Ln }, /* vcvttps2ibs */
+ { { 0x68 }, 2, T, R, pfx_f2, W0, Ln }, /* vcvttbf162ibs */
+ { { 0x69 }, 2, T, R, pfx_no, W0, Ln }, /* vcvtph2ibs */
+ { { 0x69 }, 2, T, R, pfx_66, W0, Ln }, /* vcvtps2ibs */
+ { { 0x69 }, 2, T, R, pfx_f2, W0, Ln }, /* vcvtbf162ibs */
+ { { 0x6a }, 2, T, R, pfx_no, W0, Ln }, /* vcvttph2iubs */
+ { { 0x6a }, 2, T, R, pfx_66, W0, Ln }, /* vcvttps2iubs */
+ { { 0x6a }, 2, T, R, pfx_f2, W0, Ln }, /* vcvttbf162iubs */
+ { { 0x6b }, 2, T, R, pfx_no, W0, Ln }, /* vcvtph2iubs */
+ { { 0x6b }, 2, T, R, pfx_66, W0, Ln }, /* vcvtps2iubs */
+ { { 0x6b }, 2, T, R, pfx_f2, W0, Ln }, /* vcvtbf162iubs */
+ { { 0x6c }, 2, T, R, pfx_no, Wn, Ln }, /* vcvttp{s,d}2udqs */
+ { { 0x6c }, 2, T, R, pfx_66, Wn, Ln }, /* vcvttp{s,d}2uqqs */
+ { { 0x6c }, 2, T, R, pfx_f3, Wn, LIG }, /* vcvttss2usis */
+ { { 0x6c }, 2, T, R, pfx_f2, Wn, LIG }, /* vcvttsd2usis */
+ { { 0x6d }, 2, T, R, pfx_no, Wn, Ln }, /* vcvttp{s,d}2dqs */
+ { { 0x6d }, 2, T, R, pfx_66, Wn, Ln }, /* vcvttp{s,d}2qqs */
+ { { 0x6d }, 2, T, R, pfx_f3, Wn, LIG }, /* vcvttss2sis */
+ { { 0x6d }, 2, T, R, pfx_f2, Wn, LIG }, /* vcvttsd2sis */
{ { 0x6e }, 2, T, R, pfx_66, WIG, L0 }, /* vmovw */
{ { 0x6e }, 2, T, R, pfx_f3, W0, L0 }, /* vmovw */
{ { 0x6f }, 2, T, R, pfx_f3, Wn, Ln }, /* vmovrs{d,q} */
--- a/xen/arch/x86/x86_emulate/decode.c
+++ b/xen/arch/x86/x86_emulate/decode.c
@@ -1541,6 +1541,19 @@ int x86emul_decode(struct x86_emulate_st
s->fp16 = true;
break;
+ case 0x68: /* vcvtt{ph,ps,bf16}2ibs */
+ case 0x69: /* vcvt{ph,ps,nebf16}2ibs */
+ case 0x6a: /* vcvtt{ph,ps,bf16}2iubs */
+ case 0x6b: /* vcvt{ph,ps,nebf16}2iubs */
+ if ( !s->evex.pfx || s->evex.pfx == vex_f2 )
+ s->fp16 = true;
+ fallthrough;
+ case 0x6c: /* vcvttp{s,d}2u{d,q}qs, vcvtts{s,d}2usis */
+ case 0x6d: /* vcvttp{s,d}2{d,q}qs, vcvtts{s,d}2sis */
+ d |= TwoOp;
+ s->simd_size = simd_other;
+ break;
+
case 0x6e: /* vmovw r/x/m16, xmm */
d = (d & ~SrcMask) | SrcMem16;
/* fall through */
@@ -1606,6 +1619,14 @@ int x86emul_decode(struct x86_emulate_st
--disp8scale;
break;
+ case 0x6c: /* vcvttps2uqqs and vcvts{s,d}2usi need special casing */
+ case 0x6d: /* vcvttps2qqs and vcvts{s,d}2si need special casing */
+ if ( s->evex.pfx == vex_66 && !s->evex.w && !s->evex.brs )
+ --disp8scale;
+ else if ( s->evex.pfx & VEX_PREFIX_SCALAR_MASK )
+ disp8scale = s->evex.pfx & VEX_PREFIX_DOUBLE_MASK ? 3 : 2;
+ break;
+
case 0x7a: case 0x7b: /* vcvt{,t}ph2qq need special casing */
if ( s->evex.pfx == vex_66 && !s->evex.brs )
disp8scale = s->evex.brs ? 1 : 2 + s->evex.lr;
--- a/xen/arch/x86/x86_emulate/x86_emulate.c
+++ b/xen/arch/x86/x86_emulate/x86_emulate.c
@@ -8056,6 +8056,55 @@ x86_emulate(
op_bytes = 8 << evex.lr;
goto simd_zmm;
+ case X86EMUL_OPC_EVEX_F2(5, 0x68): /* vcvttbf162ibs [xyz]mm/mem,[xyz]mm{k} */
+ case X86EMUL_OPC_EVEX_F2(5, 0x69): /* vcvtbf162ibs [xyz]mm/mem,[xyz]mm{k} */
+ case X86EMUL_OPC_EVEX_F2(5, 0x6a): /* vcvttbf162iubs [xyz]mm/mem,[xyz]mm{k} */
+ case X86EMUL_OPC_EVEX_F2(5, 0x6b): /* vcvtbf162iubs [xyz]mm/mem,[xyz]mm{k} */
+ generate_exception_if(ea.type != OP_MEM && evex.brs, X86_EXC_UD);
+ fallthrough;
+ case X86EMUL_OPC_EVEX (5, 0x68): /* vcvttph2ibs [xyz]mm/mem,[xyz]mm{k} */
+ case X86EMUL_OPC_EVEX_66(5, 0x68): /* vcvttps2ibs [xyz]mm/mem,[xyz]mm{k} */
+ case X86EMUL_OPC_EVEX (5, 0x69): /* vcvtph2ibs [xyz]mm/mem,[xyz]mm{k} */
+ case X86EMUL_OPC_EVEX_66(5, 0x69): /* vcvtps2ibs [xyz]mm/mem,[xyz]mm{k} */
+ case X86EMUL_OPC_EVEX (5, 0x6a): /* vcvttph2iubs [xyz]mm/mem,[xyz]mm{k} */
+ case X86EMUL_OPC_EVEX_66(5, 0x6a): /* vcvttps2iubs [xyz]mm/mem,[xyz]mm{k} */
+ case X86EMUL_OPC_EVEX (5, 0x6b): /* vcvtph2iubs [xyz]mm/mem,[xyz]mm{k} */
+ case X86EMUL_OPC_EVEX_66(5, 0x6b): /* vcvtps2iubs [xyz]mm/mem,[xyz]mm{k} */
+ generate_exception_if(evex.w, X86_EXC_UD);
+ vcpu_must_have(avx10, 2);
+ if ( ea.type != OP_REG || !evex.brs )
+ avx512_vlen_check(false);
+ op_bytes = 16 << evex.lr;
+ goto simd_zmm;
+
+ case X86EMUL_OPC_EVEX (5, 0x6c): /* vcvttps2udqs [xyz]mm/mem,[xyz]mm{k} */
+ /* vcvttpd2udqs [xyz]mm/mem,{x,y}mm{k} */
+ case X86EMUL_OPC_EVEX_66(5, 0x6c): /* vcvttps2uqqs {x,y}mm/mem,[xyz]mm{k} */
+ /* vcvttpd2uqqs [xyz]mm/mem,[xyz]mm{k} */
+ case X86EMUL_OPC_EVEX (5, 0x6d): /* vcvttps2dqs [xyz]mm/mem,[xyz]mm{k} */
+ /* vcvttpd2dqs [xyz]mm/mem,{x,y}mm{k} */
+ case X86EMUL_OPC_EVEX_66(5, 0x6d): /* vcvttps2qqs {x,y}mm/mem,[xyz]mm{k} */
+ /* vcvttpd2qqs [xyz]mm/mem,[xyz]mm{k} */
+ vcpu_must_have(avx10, 2);
+ if ( ea.type != OP_REG || !evex.brs )
+ avx512_vlen_check(false);
+ op_bytes = 8 << ((evex.w || !evex.pfx) + evex.lr);
+ goto simd_zmm;
+
+ CASE_SIMD_SCALAR_FP(_EVEX, 5, 0x6c): /* vcvtts{s,d}2usis xmm/mem,reg */
+ CASE_SIMD_SCALAR_FP(_EVEX, 5, 0x6d): /* vcvtts{s,d}2sis xmm/mem,reg */
+ generate_exception_if((evex.reg != 0xf || !evex.RX || !evex.R ||
+ evex.opmsk),
+ X86_EXC_UD);
+ vcpu_must_have(avx10, 2);
+ if ( !evex.brs )
+ avx512_vlen_check(true);
+ else
+ generate_exception_if(ea.type != OP_REG, X86_EXC_UD);
+ get_fpu(X86EMUL_FPU_zmm);
+ opc = init_evex(stub);
+ goto cvts_2si;
+
case X86EMUL_OPC_EVEX_F2(5, 0x6f): /* vmovrs{b,w} mem,[xyz]mm{k} */
elem_bytes = 1 << evex.w;
fallthrough;
^ permalink raw reply [flat|nested] 20+ messages in thread* [PATCH v5 16/19] x86emul: support other AVX10.2 convert insns
2026-11-11 13:40 [PATCH v5 00/19] x86: support AVX10 Jan Beulich
` (14 preceding siblings ...)
2026-11-11 13:48 ` [PATCH v5 15/19] x86emul: support AVX10.2 saturating convert insns Jan Beulich
@ 2026-11-11 13:48 ` Jan Beulich
2026-11-11 13:48 ` [PATCH v5 17/19] x86emul: support AVX10.2-aux misc insns Jan Beulich
` (2 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Jan Beulich @ 2026-11-11 13:48 UTC (permalink / raw)
To: xen-devel@lists.xenproject.org
Cc: Andrew Cooper, Teddy Astie, Roger Pau Monné
Despite most of them being about conversion to BF8/HF8, they are still
somewhat similar to various existing convert insns.
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
---
SDE: -dmr / -future
---
v4: Update to spec version 3. Switch to using fallthrough pseudo-keyword.
Series re-ordering adjustments. Update to spec version 6. Add ChangeLog entry.
v3: New.
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -17,7 +17,7 @@ The format is based on [Keep a Changelog
### Added
- On x86:
- - Support for AVX10.1. (Experimental)
+ - Support for AVX10.2. (Experimental)
### Removed
- On Arm:
--- a/tools/tests/x86_emulator/evex-disp8.c
+++ b/tools/tests/x86_emulator/evex-disp8.c
@@ -727,8 +727,22 @@ static const struct test avx10_2_all[] =
INSN(comisbf16, 66, map5, 2f, el, bf16, el),
INSN_SFP(comx, 0f, 2f),
INSN(comxsh, f3, map5, 2f, el, fp16, el),
+ INSN(cvt2ph2bf8, f2, 0f38, 74, vl, fp16, vl),
+ INSN(cvt2ph2bf8s, f2, map5, 74, vl, fp16, vl),
+ INSN(cvt2ph2hf8, f2, map5, 18, vl, fp16, vl),
+ INSN(cvt2ph2hf8s, f2, map5, 1b, vl, fp16, vl),
+ INSN(cvt2ps2phx, 66, 0f38, 67, vl, d, vl),
+ INSN(cvtbiasph2bf8, , 0f38, 74, vl, fp16, vl),
+ INSN(cvtbiasph2bf8s, , map5, 74, vl, fp16, vl),
+ INSN(cvtbiasph2hf8, , map5, 18, vl, fp16, vl),
+ INSN(cvtbiasph2hf8s, , map5, 1b, vl, fp16, vl),
+ INSN(cvthf82ph, f2, map5, 1e, vl_2, b, vl),
INSN(cvtbf162ibs, f2, map5, 69, vl, bf16, vl),
INSN(cvtbf162iubs, f2, map5, 6b, vl, bf16, vl),
+ INSN(cvtph2bf8, f3, 0f38, 74, vl, fp16, vl),
+ INSN(cvtph2bf8s, f3, map5, 74, vl, fp16, vl),
+ INSN(cvtph2hf8, f3, map5, 18, vl, fp16, vl),
+ INSN(cvtph2hf8s, f3, map5, 1b, vl, fp16, vl),
INSN(cvtph2ibs, , map5, 69, vl, fp16, vl),
INSN(cvtph2iubs, , map5, 6b, vl, fp16, vl),
INSN(cvtps2ibs, 66, map5, 69, vl, d, vl),
--- a/tools/tests/x86_emulator/predicates.c
+++ b/tools/tests/x86_emulator/predicates.c
@@ -1952,6 +1952,7 @@ static const struct evex {
{ { 0x64 }, 2, T, R, pfx_66, Wn, Ln }, /* vpblendm{d,q} */
{ { 0x65 }, 2, T, R, pfx_66, Wn, Ln }, /* vblendmp{s,d} */
{ { 0x66 }, 2, T, R, pfx_66, Wn, Ln }, /* vpblendm{b,w} */
+ { { 0x67 }, 2, T, R, pfx_66, W0, Ln }, /* vcvt2ps2phx */
{ { 0x68 }, 2, T, R, pfx_f2, Wn, Ln }, /* vp2intersect{d,q} */
{ { 0x70 }, 2, T, R, pfx_66, W1, Ln }, /* vpshldvw */
{ { 0x71 }, 2, T, R, pfx_66, Wn, Ln }, /* vpshldv{d,q} */
@@ -1959,6 +1960,9 @@ static const struct evex {
{ { 0x72 }, 2, T, R, pfx_f3, W1, Ln }, /* vcvtneps2bf16 */
{ { 0x72 }, 2, T, R, pfx_f2, W1, Ln }, /* vcvtne2ps2bf16 */
{ { 0x73 }, 2, T, R, pfx_66, Wn, Ln }, /* vpshrdv{d,q} */
+ { { 0x74 }, 2, T, R, pfx_no, W0, Ln }, /* vcvtbiasph2bf8 */
+ { { 0x74 }, 2, T, R, pfx_f3, W0, Ln }, /* vcvtph2bf8 */
+ { { 0x74 }, 2, T, R, pfx_f2, W0, Ln }, /* vcvt2ph2bf8 */
{ { 0x75 }, 2, T, R, pfx_66, Wn, Ln }, /* vpermi2{b,w} */
{ { 0x76 }, 2, T, R, pfx_66, Wn, Ln }, /* vpermi2{d,q} */
{ { 0x77 }, 2, T, R, pfx_66, Wn, Ln }, /* vpermi2p{s,d} */
@@ -2124,8 +2128,15 @@ static const struct evex {
}, evex_map5[] = {
{ { 0x10 }, 2, T, R, pfx_f3, W0, LIG }, /* vmovsh */
{ { 0x11 }, 2, T, W, pfx_f3, W0, LIG }, /* vmovsh */
+ { { 0x18 }, 2, T, R, pfx_no, W0, Ln }, /* vcvtbiasph2hf8 */
+ { { 0x18 }, 2, T, R, pfx_f3, W0, Ln }, /* vcvtph2hf8 */
+ { { 0x18 }, 2, T, R, pfx_f2, W0, Ln }, /* vcvt2ph2hf8 */
+ { { 0x1b }, 2, T, R, pfx_no, W0, Ln }, /* vcvtbiasph2hf8s */
+ { { 0x1b }, 2, T, R, pfx_f3, W0, Ln }, /* vcvtph2hf8s */
+ { { 0x1b }, 2, T, R, pfx_f2, W0, Ln }, /* vcvt2ph2hf8s */
{ { 0x1d }, 2, T, R, pfx_66, W0, Ln }, /* vcvtps2phx */
{ { 0x1d }, 2, T, R, pfx_no, W0, LIG }, /* vcvtss2sh */
+ { { 0x1e }, 2, T, R, pfx_f2, W0, Ln }, /* cvthf82ph */
{ { 0x2a }, 2, T, R, pfx_f3, Wn, LIG }, /* vcvtsi2sh */
{ { 0x2c }, 2, T, R, pfx_f3, Wn, LIG }, /* vcvttsh2si */
{ { 0x2d }, 2, T, R, pfx_f3, Wn, LIG }, /* vcvtsh2si */
@@ -2187,6 +2198,9 @@ static const struct evex {
{ { 0x6e }, 2, T, R, pfx_f3, W0, L0 }, /* vmovw */
{ { 0x6f }, 2, T, R, pfx_f3, Wn, Ln }, /* vmovrs{d,q} */
{ { 0x6f }, 2, T, R, pfx_f2, Wn, Ln }, /* vmovrs{b,w} */
+ { { 0x74 }, 2, T, R, pfx_no, W0, Ln }, /* vcvtbiasph2bf8s */
+ { { 0x74 }, 2, T, R, pfx_f3, W0, Ln }, /* vcvtph2bf8s */
+ { { 0x74 }, 2, T, R, pfx_f2, W0, Ln }, /* vcvt2ph2bf8s */
{ { 0x78 }, 2, T, R, pfx_no, W0, Ln }, /* vcvttph2udq */
{ { 0x78 }, 2, T, R, pfx_66, W0, Ln }, /* vcvttph2uqq */
{ { 0x78 }, 2, T, R, pfx_f3, Wn, LIG }, /* vcvttsh2usi */
--- a/xen/arch/x86/x86_emulate/decode.c
+++ b/xen/arch/x86/x86_emulate/decode.c
@@ -378,8 +378,10 @@ static const struct ext0f38_table {
[0x62] = { .simd_size = simd_packed_int, .two_op = 1, .d8s = d8s_bw },
[0x63] = { .simd_size = simd_packed_int, .to_mem = 1, .two_op = 1, .d8s = d8s_bw },
[0x64 ... 0x66] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
+ [0x67] = { .simd_size = simd_other, .d8s = d8s_vl },
[0x68] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
[0x70 ... 0x73] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
+ [0x74] = { .simd_size = simd_other, .d8s = d8s_vl },
[0x75 ... 0x76] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
[0x77] = { .simd_size = simd_packed_fp, .d8s = d8s_vl },
[0x78] = { .simd_size = simd_other, .two_op = 1 },
@@ -1439,6 +1441,15 @@ int x86emul_decode(struct x86_emulate_st
s->simd_size = ext0f38_table[b].simd_size;
if ( evex_encoded() )
{
+ switch ( b )
+ {
+ case 0x74: /* cvt{bias,ne,ne2}ph2bf8 */
+ s->fp16 = true;
+ if ( s->evex.pfx != vex_f2 )
+ d |= TwoOp;
+ break;
+ }
+
/*
* VPMOVUS* are identical to VPMOVS* Disp8-scaling-wise, but
* their attributes don't match those of the vex_66 encoded
@@ -1586,6 +1597,23 @@ int x86emul_decode(struct x86_emulate_st
switch ( b )
{
+ case 0x18: /* vcvt{bias,ne,ne2}ph2hf8 */
+ case 0x1b: /* vcvt{bias,ne,ne2}ph2hf8s */
+ case 0x74: /* vcvt{bias,ne,ne2}ph2bf8s */
+ s->fp16 = true;
+ d = DstReg | SrcMem;
+ if ( s->evex.pfx != vex_f2 )
+ d |= TwoOp;
+ s->simd_size = simd_other;
+ disp8scale = s->evex.brs ? 1 : 4 + s->evex.lr;
+ break;
+
+ case 0x1e: /* vcvthf82ph */
+ d = DstReg | SrcMem | TwoOp;
+ s->simd_size = simd_other;
+ disp8scale = 3 + s->evex.lr;
+ break;
+
case 0x78:
case 0x79:
/* vcvt{,t}ph2u{d,q}q need special casing */
--- a/xen/arch/x86/x86_emulate/x86_emulate.c
+++ b/xen/arch/x86/x86_emulate/x86_emulate.c
@@ -6293,6 +6293,30 @@ x86_emulate(
}
goto simd_zmm;
+ case X86EMUL_OPC_EVEX (0x0f38, 0x74): /* vcvtbiasph2bf8 [xyz]mm,[xyz]mm/mem{k} */
+ case X86EMUL_OPC_EVEX_F3(0x0f38, 0x74): /* vcvtph2bf8 [xyz]mm,[xyz]mm/mem{k} */
+ case X86EMUL_OPC_EVEX_F2(0x0f38, 0x74): /* vcvt2ph2bf8 [xyz]mm,[xyz]mm,[xyz]mm/mem{k} */
+ case X86EMUL_OPC_EVEX ( 5, 0x18): /* vcvtbiasph2hf8 [xyz]mm,[xyz]mm/mem{k} */
+ case X86EMUL_OPC_EVEX_F3( 5, 0x18): /* vcvtph2hf8 [xyz]mm,[xyz]mm/mem{k} */
+ case X86EMUL_OPC_EVEX_F2( 5, 0x18): /* vcvt2ph2hf8 [xyz]mm,[xyz]mm,[xyz]mm/mem{k} */
+ case X86EMUL_OPC_EVEX ( 5, 0x1b): /* vcvtbiasph2hf8s [xyz]mm,[xyz]mm/mem{k} */
+ case X86EMUL_OPC_EVEX_F3( 5, 0x1b): /* vcvtph2hf8s [xyz]mm,[xyz]mm/mem{k} */
+ case X86EMUL_OPC_EVEX_F2( 5, 0x1b): /* vcvt2ph2hf8s [xyz]mm,[xyz]mm,[xyz]mm/mem{k} */
+ case X86EMUL_OPC_EVEX ( 5, 0x74): /* vcvtbiasph2bf8s [xyz]mm,[xyz]mm/mem{k} */
+ case X86EMUL_OPC_EVEX_F3( 5, 0x74): /* vcvtph2bf8s [xyz]mm,[xyz]mm/mem{k} */
+ case X86EMUL_OPC_EVEX_F2( 5, 0x74): /* vcvt2ph2bf8s [xyz]mm,[xyz]mm,[xyz]mm/mem{k} */
+ generate_exception_if(ea.type != OP_MEM && evex.brs, X86_EXC_UD);
+ fault_suppression = false;
+ fallthrough;
+ case X86EMUL_OPC_EVEX_66(0x0f38, 0x67): /* vcvt2ps2phx [xyz]mm,[xyz]mm,[xyz]mm/mem{k} */
+ generate_exception_if(evex.w, X86_EXC_UD);
+ if ( !cp->avx10.avx10_v1_aux )
+ vcpu_must_have(avx10, 2);
+ if ( ea.type != OP_REG || !evex.brs )
+ avx512_vlen_check(false);
+ op_bytes = 16 << evex.lr;
+ goto simd_zmm;
+
case X86EMUL_OPC_EVEX_F2(0x0f38, 0x68): /* vp2intersect{d,q} [xyz]mm/mem,[xyz]mm,k+1 */
vcpu_must_have(avx512_vp2intersect);
generate_exception_if(evex.opmsk || !evex.r || !evex.R, X86_EXC_UD);
@@ -7996,6 +8020,15 @@ x86_emulate(
generate_exception_if(evex.w, X86_EXC_UD);
goto avx512f_all_fp;
+ case X86EMUL_OPC_EVEX_F2(5, 0x1e): /* vcvthf82ph [xyz]mm,[xyz]mm/mem{k} */
+ generate_exception_if(evex.w || evex.brs, X86_EXC_UD);
+ if ( !cp->avx10.avx10_v1_aux )
+ vcpu_must_have(avx10, 2);
+ if ( ea.type != OP_REG || !evex.brs )
+ avx512_vlen_check(false);
+ op_bytes = 8 << evex.lr;
+ goto simd_zmm;
+
case X86EMUL_OPC_EVEX_66(5, 0x51): /* vsqrtbf16 [xyz]mm/mem,[xyz]mm{k} */
case X86EMUL_OPC_EVEX_66(5, 0x58): /* vaddbf16 [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
case X86EMUL_OPC_EVEX_66(5, 0x59): /* vmulbf16 [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
--- a/xen/include/public/arch-x86/cpufeatureset.h
+++ b/xen/include/public/arch-x86/cpufeatureset.h
@@ -411,7 +411,7 @@ XEN_CPUFEATURE(TSA_L1_NO, 18*32
/* x86-ecosystem-defined CPU features, CPUID level 0x00000024:1.ecx, word 19 */
XEN_CPUFEATURE(AVX10_BMM, 19*32+ 1) /* AVX10-BMM Instructions */
-XEN_CPUFEATURE(AVX10_V1_AUX, 19*32+ 2) /* AVX10 V1 Auxiliary Instructions */
+XEN_CPUFEATURE(AVX10_V1_AUX, 19*32+ 2) /*a AVX10 V1 Auxiliary Instructions */
XEN_CPUFEATURE(AVX10_V2_AUX, 19*32+ 3) /* AVX10 V2 Auxiliary Instructions */
#endif /* XEN_CPUFEATURE */
^ permalink raw reply [flat|nested] 20+ messages in thread* [PATCH v5 17/19] x86emul: support AVX10.2-aux misc insns
2026-11-11 13:40 [PATCH v5 00/19] x86: support AVX10 Jan Beulich
` (15 preceding siblings ...)
2026-11-11 13:48 ` [PATCH v5 16/19] x86emul: support other AVX10.2 " Jan Beulich
@ 2026-11-11 13:48 ` Jan Beulich
2026-11-11 13:49 ` [PATCH v5 18/19] x86emul: support AVX10.2-aux {B,H}F{4,6} <-> {B,H}F8 converts Jan Beulich
2026-11-11 13:49 ` [PATCH v5 19/19] x86emul: support AVX10.2-aux PS <-> {B,H}F8{,S} converts Jan Beulich
18 siblings, 0 replies; 20+ messages in thread
From: Jan Beulich @ 2026-11-11 13:48 UTC (permalink / raw)
To: xen-devel@lists.xenproject.org
Cc: Andrew Cooper, Teddy Astie, Roger Pau Monné
VPMOVSSDB is a counterpart to VPMOVSDB, so handle it the same.
VUNPACKB otoh is regular (without fault suppression or broadcast) as to
its memory operand, and hence straightforward to handle.
Signed-off-by: Jan Beulich <jbeulich@suse.com>
---
SDE: ???
---
v5: New.
--- a/tools/tests/x86_emulator/evex-disp8.c
+++ b/tools/tests/x86_emulator/evex-disp8.c
@@ -821,6 +821,11 @@ static const struct test avx10_2_128[] =
INSN(movw, f3, map5, 7e, el, fp16, el),
};
+static const struct test avx10_2_aux_all[] = {
+ INSN(pmovssdb, f3, 0f38, 41, vl_4, b, vl),
+ INSN(unpackb, , 0f3a, 3d, vl, b, vl),
+};
+
static const struct test movrs_all[] = {
INSN(movrsb, f2, map5, 6f, vl, b, vl),
INSN(movrsd, f3, map5, 6f, vl, d_nb, vl),
@@ -1258,4 +1263,6 @@ void evex_disp8_test(void *instr, struct
run(cpu_has_avx10_2, avx10_2, all);
run(cpu_has_avx10_2, avx10_2, 128);
+
+ run(cpu_has_avx10_2_aux, avx10_2_aux, all);
}
--- a/tools/tests/x86_emulator/predicates.c
+++ b/tools/tests/x86_emulator/predicates.c
@@ -1917,6 +1917,7 @@ static const struct evex {
{ { 0x3e }, 2, T, R, pfx_66, WIG, Ln }, /* vpmaxuw */
{ { 0x3f }, 2, T, R, pfx_66, Wn, Ln }, /* vpmaxu{d,q} */
{ { 0x40 }, 2, T, R, pfx_66, Wn, Ln }, /* vpmull{d,q} */
+ { { 0x41 }, 2, T, W, pfx_f3, W0, Ln }, /* vpmovssdb */
{ { 0x42 }, 2, T, R, pfx_66, Wn, Ln }, /* vgetexpp{s,d} */
{ { 0x43 }, 2, T, R, pfx_66, Wn, LIG }, /* vgetexps{s,d} */
{ { 0x44 }, 2, T, R, pfx_66, Wn, Ln }, /* vlzcnt{d,q} */
@@ -2091,6 +2092,7 @@ static const struct evex {
{ { 0x39 }, 3, T, W, pfx_66, Wn, L1|L2 }, /* vextracti{32x4,64x2} */
{ { 0x3a }, 3, T, R, pfx_66, Wn, L2 }, /* vinserti{32x8,64x4} */
{ { 0x3b }, 3, T, W, pfx_66, Wn, L2 }, /* vextracti{32x8,64x4} */
+ { { 0x3d }, 3, T, R, pfx_no, W0, Ln }, /* vunpackb */
{ { 0x3e }, 3, T, R, pfx_66, Wn, Ln }, /* vpcmpu{b,w} */
{ { 0x3f }, 3, T, R, pfx_66, Wn, Ln }, /* vpcmp{b,w} */
{ { 0x42 }, 3, T, R, pfx_66, W0, Ln }, /* vdbpsadbw */
--- a/tools/tests/x86_emulator/x86-emulate.h
+++ b/tools/tests/x86_emulator/x86-emulate.h
@@ -219,6 +219,8 @@ void wrpkru(unsigned int val);
#define cpu_has_avx10 (cpu_policy.feat.avx10 && xcr0_mask(0xe6))
#define cpu_has_avx10_2 (cpu_policy.avx10.version >= 2 && \
xcr0_mask(0xe6))
+#define cpu_has_avx10_2_aux (cpu_policy.avx10.avx10_v2_aux && \
+ xcr0_mask(0xe6))
#define cpu_has_xgetbv1 (cpu_has_xsave && cpu_policy.xstate.xgetbv1)
--- a/xen/arch/x86/x86_emulate/decode.c
+++ b/xen/arch/x86/x86_emulate/decode.c
@@ -492,6 +492,7 @@ static const struct ext0f3a_table {
[0x3a] = { .simd_size = simd_256, .d8s = d8s_vl_by_2 },
[0x39] = { .simd_size = simd_128, .to_mem = 1, .two_op = 1, .d8s = 4 },
[0x3b] = { .simd_size = simd_256, .to_mem = 1, .two_op = 1, .d8s = d8s_vl_by_2 },
+ [0x3d] = { .simd_size = simd_packed_int, .two_op = 1, .d8s = d8s_vl },
[0x3e ... 0x3f] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
[0x40 ... 0x41] = { .simd_size = simd_packed_fp },
[0x42 ... 0x43] = { .simd_size = simd_packed_int, .d8s = d8s_vl },
@@ -1456,14 +1457,20 @@ int x86emul_decode(struct x86_emulate_st
* insns with the same base opcodes. Rather than adding new
* columns to the table, handle this here for now.
*/
- if ( s->evex.pfx != vex_f3 || (b & 0xf8) != 0x10 )
- disp8scale = decode_disp8scale(ext0f38_table[b].d8s, s);
- else
+ if ( s->evex.pfx == vex_f3 && (b & 0xf8) == 0x10 )
{
disp8scale = decode_disp8scale(ext0f38_table[b ^ 0x30].d8s,
s);
s->simd_size = simd_other;
}
+ /* Same for VPMOVSSDB vs VPMOVSDB. */
+ else if ( s->evex.pfx == vex_f3 && b == 0x41 )
+ {
+ disp8scale = decode_disp8scale(ext0f38_table[0x21].d8s, s);
+ s->simd_size = simd_other;
+ }
+ else
+ disp8scale = decode_disp8scale(ext0f38_table[b].d8s, s);
}
break;
--- a/xen/arch/x86/x86_emulate/private.h
+++ b/xen/arch/x86/x86_emulate/private.h
@@ -610,6 +610,7 @@ amd_like(const struct x86_emulate_ctxt *
#define vcpu_has_user_msr() (ctxt->cpuid->feat.user_msr)
#define vcpu_has_avx10(minor) (ctxt->cpuid->avx10.version >= (minor))
+#define vcpu_has_avx10_2_aux() (ctxt->cpuid->avx10.avx10_v2_aux)
#define vcpu_must_have(feat, ...) \
generate_exception_if(!vcpu_has_##feat(__VA_ARGS__), X86_EXC_UD)
--- a/xen/arch/x86/x86_emulate/util.c
+++ b/xen/arch/x86/x86_emulate/util.c
@@ -150,6 +150,7 @@ bool cf_check x86_insn_is_mem_write(cons
X86EMUL_OPC_EVEX_F3(0x0f38, 0x25): /* VPMOVS* */
case X86EMUL_OPC_EVEX_F3(0x0f38, 0x30) ...
X86EMUL_OPC_EVEX_F3(0x0f38, 0x35): /* VPMOV{D,Q,W}* */
+ case X86EMUL_OPC_EVEX_F3(0x0f38, 0x41): /* VPMOVSSDB */
return s->modrm_mod != 3;
}
--- a/xen/arch/x86/x86_emulate/x86_emulate.c
+++ b/xen/arch/x86/x86_emulate/x86_emulate.c
@@ -5840,6 +5840,9 @@ x86_emulate(
elem_bytes = 2;
goto avx512f_no_sae;
+ case X86EMUL_OPC_EVEX_F3(0x0f38, 0x41): /* vpmovssdb [xyz]mm,xmm/mem{k} */
+ vcpu_must_have(avx10_2_aux);
+ fallthrough;
case X86EMUL_OPC_EVEX_F3(0x0f38, 0x10): /* vpmovuswb [xyz]mm,{x,y}mm/mem{k} */
case X86EMUL_OPC_EVEX_66(0x0f38, 0x20): /* vpmovsxbw {x,y}mm/mem,[xyz]mm{k} */
case X86EMUL_OPC_EVEX_F3(0x0f38, 0x20): /* vpmovswb [xyz]mm,{x,y}mm/mem{k} */
@@ -7747,6 +7750,13 @@ x86_emulate(
visa_check(bw);
goto opmask_shift_imm;
+ case X86EMUL_OPC_EVEX(0x0f3a, 0x3d): /* vunpackb $imm8,[xyz]mm/mem,[xyz]mm{k} */
+ generate_exception_if(evex.w || evex.brs, X86_EXC_UD);
+ vcpu_must_have(avx10_2_aux);
+ avx512_vlen_check(false);
+ fault_suppression = false;
+ goto simd_imm8_zmm;
+
case X86EMUL_OPC_EVEX_F3(0x0f3a, 0x42): /* vmpsadbw $imm8,[xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
generate_exception_if(evex.w || evex.brs, X86_EXC_UD);
vcpu_must_have(avx10, 2);
^ permalink raw reply [flat|nested] 20+ messages in thread* [PATCH v5 18/19] x86emul: support AVX10.2-aux {B,H}F{4,6} <-> {B,H}F8 converts
2026-11-11 13:40 [PATCH v5 00/19] x86: support AVX10 Jan Beulich
` (16 preceding siblings ...)
2026-11-11 13:48 ` [PATCH v5 17/19] x86emul: support AVX10.2-aux misc insns Jan Beulich
@ 2026-11-11 13:49 ` Jan Beulich
2026-11-11 13:49 ` [PATCH v5 19/19] x86emul: support AVX10.2-aux PS <-> {B,H}F8{,S} converts Jan Beulich
18 siblings, 0 replies; 20+ messages in thread
From: Jan Beulich @ 2026-11-11 13:49 UTC (permalink / raw)
To: xen-devel@lists.xenproject.org
Cc: Andrew Cooper, Teddy Astie, Roger Pau Monné
Their handling follows that of other convert insns.
Signed-off-by: Jan Beulich <jbeulich@suse.com>
---
SDE: ???
---
v5: New.
--- a/tools/tests/x86_emulator/evex-disp8.c
+++ b/tools/tests/x86_emulator/evex-disp8.c
@@ -821,7 +821,18 @@ static const struct test avx10_2_128[] =
INSN(movw, f3, map5, 7e, el, fp16, el),
};
+/*
+ * Element size w is used here in place of b, to have test_one() set EVEX.W.
+ * As those insns don't permit broadcast, using the wrong size is benign.
+ */
static const struct test avx10_2_aux_all[] = {
+ INSN(cvtbf42hf8, , map5, 37, vl_2, b, vl),
+// cvtbf62hf8, 66, map5, 37, vl, w, vl
+ INSN(cvtbf82bf4s, f3, map5, 3d, vl_2, b, vl),
+// cvtbf82bf6s, f3, map5, 3e, vl, w, vl
+// cvthf62hf8, 66, map5, 37, vl, b, vl
+ INSN(cvthf82bf4s, f3, map5, 3d, vl_2, w, vl),
+// cvthf82hf6s, f3, map5, 3e, vl, b, vl
INSN(pmovssdb, f3, 0f38, 41, vl_4, b, vl),
INSN(unpackb, , 0f3a, 3d, vl, b, vl),
};
--- a/tools/tests/x86_emulator/predicates.c
+++ b/tools/tests/x86_emulator/predicates.c
@@ -2147,6 +2147,11 @@ static const struct evex {
{ { 0x2f }, 2, T, R, pfx_no, W0, LIG }, /* vcomish */
{ { 0x2f }, 2, T, R, pfx_66, W0, LIG }, /* vcomisbf16 */
{ { 0x2f }, 2, T, R, pfx_f3, W0, LIG }, /* vcomxsh */
+ { { 0x37 }, 2, T, R, pfx_no, W0, Ln }, /* vcvtbf42hf8 */
+ { { 0x37, 0xc0 }, 2, F, N, pfx_66, Wn, Ln }, /* vcvt{b,h}f62hf8 */
+ { { 0x3c, 0xc0 }, 2, F, N, pfx_f3, W0, Ln }, /* vcvthf82hf6s */
+ { { 0x3d }, 2, T, W, pfx_f3, Wn, Ln }, /* vcvt{b,h}f82bf4s */
+ { { 0x3e, 0xc0 }, 2, F, N, pfx_f3, W1, Ln }, /* vcvtbf82bf6s */
{ { 0x51 }, 2, T, R, pfx_no, W0, Ln }, /* vsqrtph */
{ { 0x51 }, 2, T, R, pfx_66, W0, Ln }, /* vsqrtbf16 */
{ { 0x51 }, 2, T, R, pfx_f3, W0, LIG }, /* vsqrtsh */
--- a/xen/arch/x86/x86_emulate/decode.c
+++ b/xen/arch/x86/x86_emulate/decode.c
@@ -1253,9 +1253,10 @@ int x86emul_decode(struct x86_emulate_st
opcode |= MASK_INSR(5, X86EMUL_OPC_EXT_MASK);
/*
* Re-use twobyte_table[] here, for the similarity of
- * the entries valid in map 5.
+ * the entries valid in map 5. There's always a
+ * ModR/M byte, though.
*/
- d = twobyte_table[b].desc;
+ d = twobyte_table[b].desc | ModRM;
s->simd_size = twobyte_table[b].size ?: simd_other;
break;
@@ -1616,8 +1617,17 @@ int x86emul_decode(struct x86_emulate_st
break;
case 0x1e: /* vcvthf82ph */
+ case 0x37: /* vcvt{bf4,bf6,hf6}2hf8 */
+ case 0x3c: /* vcvthf82hf6s */
+ case 0x3e: /* vcvtbf82bf6s */
d = DstReg | SrcMem | TwoOp;
s->simd_size = simd_other;
+ /* Not correct for f6<->f8, but those are register-only. */
+ disp8scale = 3 + s->evex.lr;
+ break;
+
+ case 0x3d: /* vcvt{b,h}f82hf4s */
+ d = DstMem | SrcReg | TwoOp;
disp8scale = 3 + s->evex.lr;
break;
--- a/xen/arch/x86/x86_emulate/x86_emulate.c
+++ b/xen/arch/x86/x86_emulate/x86_emulate.c
@@ -8039,6 +8039,29 @@ x86_emulate(
op_bytes = 8 << evex.lr;
goto simd_zmm;
+ case X86EMUL_OPC_EVEX_F3(5, 0x3d): /* vcvt{b,h}f82bf4s [xyz]mm,[xy]mm/m{64,128,256} */
+ generate_exception_if(evex.opmsk, X86_EXC_UD);
+ fallthrough;
+ case X86EMUL_OPC_EVEX (5, 0x37): /* vcvtbf42hf8 [xy]mm/m{64,128,256},[xyz]mm{k} */
+ generate_exception_if((evex.w && (b & 2)) || evex.brs, X86_EXC_UD);
+ vcpu_must_have(avx10_2_aux);
+ avx512_vlen_check(false);
+ op_bytes = 8 << evex.lr;
+ fault_suppression = false;
+ goto simd_zmm;
+
+ case X86EMUL_OPC_EVEX_F3(5, 0x3c): /* vcvthf82hf6s [xyz]mm,[xyz]mm */
+ case X86EMUL_OPC_EVEX_F3(5, 0x3e): /* vcvtbf82bf6s [xyz]mm,[xyz]mm */
+ generate_exception_if(evex.w == !(b & 2), X86_EXC_UD);
+ fallthrough;
+ case X86EMUL_OPC_EVEX_66(5, 0x37): /* vcvt{b,h}f62hf8 [xyz]mm,[xyz]mm */
+ generate_exception_if(ea.type != OP_REG || evex.opmsk || evex.brs,
+ X86_EXC_UD);
+ vcpu_must_have(avx10_2_aux);
+ avx512_vlen_check(false);
+ op_bytes = 1; /* Any non-zero value will do. */
+ goto simd_zmm;
+
case X86EMUL_OPC_EVEX_66(5, 0x51): /* vsqrtbf16 [xyz]mm/mem,[xyz]mm{k} */
case X86EMUL_OPC_EVEX_66(5, 0x58): /* vaddbf16 [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
case X86EMUL_OPC_EVEX_66(5, 0x59): /* vmulbf16 [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
^ permalink raw reply [flat|nested] 20+ messages in thread* [PATCH v5 19/19] x86emul: support AVX10.2-aux PS <-> {B,H}F8{,S} converts
2026-11-11 13:40 [PATCH v5 00/19] x86: support AVX10 Jan Beulich
` (17 preceding siblings ...)
2026-11-11 13:49 ` [PATCH v5 18/19] x86emul: support AVX10.2-aux {B,H}F{4,6} <-> {B,H}F8 converts Jan Beulich
@ 2026-11-11 13:49 ` Jan Beulich
18 siblings, 0 replies; 20+ messages in thread
From: Jan Beulich @ 2026-11-11 13:49 UTC (permalink / raw)
To: xen-devel@lists.xenproject.org
Cc: Andrew Cooper, Teddy Astie, Roger Pau Monné
Their handling again follows that of other convert insns.
Signed-off-by: Jan Beulich <jbeulich@suse.com>
---
SDE: ???
---
v5: New.
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -18,6 +18,7 @@ The format is based on [Keep a Changelog
### Added
- On x86:
- Support for AVX10.2. (Experimental)
+ - Support for AVX10-V2-AUX. (Experimental)
### Removed
- On Arm:
--- a/tools/tests/x86_emulator/evex-disp8.c
+++ b/tools/tests/x86_emulator/evex-disp8.c
@@ -830,9 +830,21 @@ static const struct test avx10_2_aux_all
// cvtbf62hf8, 66, map5, 37, vl, w, vl
INSN(cvtbf82bf4s, f3, map5, 3d, vl_2, b, vl),
// cvtbf82bf6s, f3, map5, 3e, vl, w, vl
+ INSN(cvtbf82ps, , map5, 36, vl_4, w, vl),
+ INSN(cvtbiasps2hf8, , map5, 38, vl, d, vl),
+ INSN(cvtbiasps2bf8, , map5, 39, vl, d, vl),
+ INSN(cvtbiasps2hf8s, , map5, 3a, vl, d, vl),
+ INSN(cvtbiasps2bf8s, , map5, 3b, vl, d, vl),
// cvthf62hf8, 66, map5, 37, vl, b, vl
INSN(cvthf82bf4s, f3, map5, 3d, vl_2, w, vl),
// cvthf82hf6s, f3, map5, 3e, vl, b, vl
+ INSN(cvthf82ps, , map5, 36, vl_4, b, vl),
+ INSN(cvtps2hf8, f3, map5, 38, vl, d, vl),
+ INSN(cvtps2bf8, f3, map5, 39, vl, d, vl),
+ INSN(cvtps2hf8s, f3, map5, 3a, vl, d, vl),
+ INSN(cvtps2bf8s, f3, map5, 3b, vl, d, vl),
+ INSN(cvtrops2hf8, 66, map5, 38, vl, d, vl),
+ INSN(cvtrops2hf8s, 66, map5, 3a, vl, d, vl),
INSN(pmovssdb, f3, 0f38, 41, vl_4, b, vl),
INSN(unpackb, , 0f3a, 3d, vl, b, vl),
};
--- a/tools/tests/x86_emulator/predicates.c
+++ b/tools/tests/x86_emulator/predicates.c
@@ -2147,8 +2147,19 @@ static const struct evex {
{ { 0x2f }, 2, T, R, pfx_no, W0, LIG }, /* vcomish */
{ { 0x2f }, 2, T, R, pfx_66, W0, LIG }, /* vcomisbf16 */
{ { 0x2f }, 2, T, R, pfx_f3, W0, LIG }, /* vcomxsh */
+ { { 0x36 }, 2, T, R, pfx_no, Wn, Ln }, /* vcvt{b,h}f82ps */
{ { 0x37 }, 2, T, R, pfx_no, W0, Ln }, /* vcvtbf42hf8 */
{ { 0x37, 0xc0 }, 2, F, N, pfx_66, Wn, Ln }, /* vcvt{b,h}f62hf8 */
+ { { 0x38 }, 2, T, R, pfx_no, W0, Ln }, /* vcvtbiasps2hf8 */
+ { { 0x38 }, 2, T, R, pfx_66, W0, Ln }, /* vcvtrops2hf8 */
+ { { 0x38 }, 2, T, R, pfx_f3, W0, Ln }, /* vcvtps2hf8 */
+ { { 0x39 }, 2, T, R, pfx_no, W0, Ln }, /* vcvtbiasps2bf8 */
+ { { 0x39 }, 2, T, R, pfx_f3, W0, Ln }, /* vcvtps2bf8 */
+ { { 0x3a }, 2, T, R, pfx_no, W0, Ln }, /* vcvtbiasps2hf8s */
+ { { 0x3a }, 2, T, R, pfx_66, W0, Ln }, /* vcvtrops2hf8s */
+ { { 0x3a }, 2, T, R, pfx_f3, W0, Ln }, /* vcvtps2hf8s */
+ { { 0x3b }, 2, T, R, pfx_no, W0, Ln }, /* vcvtbiasps2bf8s */
+ { { 0x3b }, 2, T, R, pfx_f3, W0, Ln }, /* vcvtps2bf8s */
{ { 0x3c, 0xc0 }, 2, F, N, pfx_f3, W0, Ln }, /* vcvthf82hf6s */
{ { 0x3d }, 2, T, W, pfx_f3, Wn, Ln }, /* vcvt{b,h}f82bf4s */
{ { 0x3e, 0xc0 }, 2, F, N, pfx_f3, W1, Ln }, /* vcvtbf82bf6s */
--- a/xen/arch/x86/x86_emulate/decode.c
+++ b/xen/arch/x86/x86_emulate/decode.c
@@ -1254,9 +1254,10 @@ int x86emul_decode(struct x86_emulate_st
/*
* Re-use twobyte_table[] here, for the similarity of
* the entries valid in map 5. There's always a
- * ModR/M byte, though.
+ * ModR/M byte, though, and never an immediate.
*/
- d = twobyte_table[b].desc | ModRM;
+ d = (twobyte_table[b].desc | ModRM) &
+ ~(SrcImmByte | SrcImm);
s->simd_size = twobyte_table[b].size ?: simd_other;
break;
@@ -1626,6 +1627,21 @@ int x86emul_decode(struct x86_emulate_st
disp8scale = 3 + s->evex.lr;
break;
+ case 0x36: /* vcvt{b,h}f82ps */
+ d = DstReg | SrcMem | TwoOp;
+ disp8scale = 2 + s->evex.lr;
+ break;
+
+ case 0x38: /* vcvt{,bias,ro}ps2hf8 */
+ case 0x39: /* vcvt{,bias}ps2bf8 */
+ case 0x3a: /* vcvt{,bias,ro}ps2hf8s */
+ case 0x3b: /* vcvt{,bias}ps2bf8s */
+ d = DstReg | SrcMem;
+ if ( s->evex.pfx )
+ d |= TwoOp;
+ disp8scale = s->evex.brs ? 2 : 4 + s->evex.lr;
+ break;
+
case 0x3d: /* vcvt{b,h}f82hf4s */
d = DstMem | SrcReg | TwoOp;
disp8scale = 3 + s->evex.lr;
--- a/xen/arch/x86/x86_emulate/x86_emulate.c
+++ b/xen/arch/x86/x86_emulate/x86_emulate.c
@@ -8039,6 +8039,13 @@ x86_emulate(
op_bytes = 8 << evex.lr;
goto simd_zmm;
+ case X86EMUL_OPC_EVEX(5, 0x36): /* vcvt{b,h}f82ps [xy]mm/m{32,64,128}[xyz]mm */
+ generate_exception_if(evex.brs, X86_EXC_UD);
+ vcpu_must_have(avx10_2_aux);
+ avx512_vlen_check(false);
+ op_bytes = 4 << evex.lr;
+ goto simd_zmm;
+
case X86EMUL_OPC_EVEX_F3(5, 0x3d): /* vcvt{b,h}f82bf4s [xyz]mm,[xy]mm/m{64,128,256} */
generate_exception_if(evex.opmsk, X86_EXC_UD);
fallthrough;
@@ -8062,6 +8069,23 @@ x86_emulate(
op_bytes = 1; /* Any non-zero value will do. */
goto simd_zmm;
+ case X86EMUL_OPC_EVEX (5, 0x38): /* vcvtbiasps2hf8 [xyz]mm/mem,xmm{k} */
+ case X86EMUL_OPC_EVEX_66(5, 0x38): /* vcvtrops2hf8 [xyz]mm/mem,xmm{k} */
+ case X86EMUL_OPC_EVEX_F3(5, 0x38): /* vcvtps2hf8 [xyz]mm/mem,xmm{k} */
+ case X86EMUL_OPC_EVEX (5, 0x39): /* vcvtbiasps2bf8 [xyz]mm/mem,xmm{k} */
+ case X86EMUL_OPC_EVEX_F3(5, 0x39): /* vcvtps2bf8 [xyz]mm/mem,xmm{k} */
+ case X86EMUL_OPC_EVEX (5, 0x3a): /* vcvtbiasps2hf8s [xyz]mm/mem,xmm{k} */
+ case X86EMUL_OPC_EVEX_66(5, 0x3a): /* vcvtrops2hf8s [xyz]mm/mem,xmm{k} */
+ case X86EMUL_OPC_EVEX_F3(5, 0x3a): /* vcvtps2hf8s [xyz]mm/mem,xmm{k} */
+ case X86EMUL_OPC_EVEX (5, 0x3b): /* vcvtbiasps2bf8s [xyz]mm/mem,xmm{k} */
+ case X86EMUL_OPC_EVEX_F3(5, 0x3b): /* vcvtps2bf8s [xyz]mm/mem,xmm{k} */
+ generate_exception_if(evex.w || (ea.type != OP_MEM && evex.brs),
+ X86_EXC_UD);
+ vcpu_must_have(avx10_2_aux);
+ avx512_vlen_check(false);
+ op_bytes = evex.brs ? 4 : 8 << evex.lr;
+ goto simd_zmm;
+
case X86EMUL_OPC_EVEX_66(5, 0x51): /* vsqrtbf16 [xyz]mm/mem,[xyz]mm{k} */
case X86EMUL_OPC_EVEX_66(5, 0x58): /* vaddbf16 [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
case X86EMUL_OPC_EVEX_66(5, 0x59): /* vmulbf16 [xyz]mm/mem,[xyz]mm,[xyz]mm{k} */
--- a/xen/include/public/arch-x86/cpufeatureset.h
+++ b/xen/include/public/arch-x86/cpufeatureset.h
@@ -412,7 +412,7 @@ XEN_CPUFEATURE(TSA_L1_NO, 18*32
/* x86-ecosystem-defined CPU features, CPUID level 0x00000024:1.ecx, word 19 */
XEN_CPUFEATURE(AVX10_BMM, 19*32+ 1) /* AVX10-BMM Instructions */
XEN_CPUFEATURE(AVX10_V1_AUX, 19*32+ 2) /*a AVX10 V1 Auxiliary Instructions */
-XEN_CPUFEATURE(AVX10_V2_AUX, 19*32+ 3) /* AVX10 V2 Auxiliary Instructions */
+XEN_CPUFEATURE(AVX10_V2_AUX, 19*32+ 3) /*a AVX10 V2 Auxiliary Instructions */
#endif /* XEN_CPUFEATURE */
^ permalink raw reply [flat|nested] 20+ messages in thread