RE: [PATCH v1 1/2] Support AVX10_V2_AUX instructions

"Jiang, Haochen" <[email protected]>
Newsgroups gmane.comp.gnu.binutils
Message-ID <IA4PR11MB90099AD311BE8AAFACDF3873ECE82@IA4PR11MB9009.namprd11.prod.outlook.com>
> From: Ganesh Gopalasubramanian <[email protected]>
> Sent: Saturday, June 27, 2026 5:56 PM

Hi Ganesh,

First of all, you should always omit those generated files like what you
have done in ACE patch.

> 
> - AVX10_V1_AUX instructions are already present as part of AVX10.2
> instructions. They are just available under new cpuid bit.

What is your plan on supporting that bit?

> diff --git a/gas/testsuite/gas/i386/x86-64-avx10_v2_aux.d
> b/gas/testsuite/gas/i386/x86-64-avx10_v2_aux.d
> +[ 	]*[a-f0-9]+:[ 	]*62 f5 7d 08 38 01[ 	]*vcvtrops2hf8
> \(%rcx\),%xmm0

Your test did not cover the full set of the insts. You could only emit
128 bit memory here, no 256/512 bit according to your upcoming
Implementation.

> diff --git a/gas/testsuite/gas/i386/x86-64-avx10_v2_aux.s
> b/gas/testsuite/gas/i386/x86-64-avx10_v2_aux.s
> new file mode 100644
> index 00000000000..24c2901f599
> --- /dev/null
> +++ b/gas/testsuite/gas/i386/x86-64-avx10_v2_aux.s
> @@ -0,0 +1,149 @@
> +	.text
> +	.arch .avx10_v2_aux
> +_start:
> +	# VCVTPS2BF8 - F3.MAP5.W0 opcode 39
> +	vcvtps2bf8	%xmm1, %xmm0
> +	vcvtps2bf8	%ymm1, %xmm0
> +	vcvtps2bf8	%zmm1, %xmm0
> +	vcvtps2bf8	(%rcx), %xmm0
> +	vcvtps2bf8	0x10(%rcx), %xmm0
> +	vcvtps2bf8	%xmm1, %xmm0{%k1}
> +	vcvtps2bf8	%xmm1, %xmm0{%k1}{z}
> +
> +	# VCVTPS2BF8S - F3.MAP5.W0 opcode 3B
> +	vcvtps2bf8s	%xmm1, %xmm0
> +	vcvtps2bf8s	%ymm1, %xmm0
> +	vcvtps2bf8s	%zmm1, %xmm0
> +	vcvtps2bf8s	(%rcx), %xmm0
> +	vcvtps2bf8s	%xmm1, %xmm0{%k1}
> +
> +	# VCVTPS2HF8 - F3.MAP5.W0 opcode 38
> +	vcvtps2hf8	%xmm1, %xmm0
> +	vcvtps2hf8	%ymm1, %xmm0
> +	vcvtps2hf8	%zmm1, %xmm0
> +	vcvtps2hf8	(%rcx), %xmm0
> +	vcvtps2hf8	%xmm1, %xmm0{%k1}
> +
> +	# VCVTPS2HF8S - F3.MAP5.W0 opcode 3A
> +	vcvtps2hf8s	%xmm1, %xmm0
> +	vcvtps2hf8s	%ymm1, %xmm0
> +	vcvtps2hf8s	%zmm1, %xmm0
> +	vcvtps2hf8s	(%rcx), %xmm0
> +	vcvtps2hf8s	%xmm1, %xmm0{%k1}

Please use .irp to shrink the testcase lines.

> diff --git a/opcodes/i386-gen.c b/opcodes/i386-gen.c
> index be580d48a18..11cc4ff19dc 100644
> --- a/opcodes/i386-gen.c
> +++ b/opcodes/i386-gen.c
> @@ -249,6 +249,8 @@ static const dependency isa_dependencies[] =
> 
> "|AVX512_VNNI|AVX512_BF16|AVX512_FP16|AVX512_VPOPCNTDQ|AVX
> 512_BITALG" },
>    { "AVX10_2",
>      "AVX10_1" },
> +  { "AVX10_V2_AUX",
> +    "AVX10_2" },

Are you sure this should be AVX10_2 but not AVX10_1? According to the
documentation for CPUID ACEv1 emulation:

"
To detect full ACE v1 support, software should verify:
1. (AVX10.1 and AVX10_V1_AUX) or AVX10.2
2. AVX10_V2_AUX
"

There will be possibilities for some x86 vendors have not full AVX10.2
support but AVX10_V2_AUX support, or the documentation won't do
so.

Now it is the assembler and disassembler part. Before the comments
coming in, I would like to mention for those convert insts:

When the encoding is designed as this, we are trying to keep the
encoding as consistent as we can. We have the following rules for
convert when assigning encoding:

For down convert:
- The different dst size will result in different opcode.
- W bit will indicate the src size pairs, i.e., PS=PD, PH-BF16, HF8-BF8, etc.
The former is always at W0, the latter is always at W1.
- The different type of convert is indicated at prefixes, where cvtbias at
NP, cvt at F3, cvt2 at F2, leaving 66 for special types in case we need it
(Here is the cvtro).

For up covert, since we have fewer variants for convert (we definitely
won't have cvt2), we may choose to fold them a little bit, but we will still
keep the W rule in down convert.

Then it is the comment part. If you don't want to do some of the combine
or table pass simplification, I will have an upcoming patch to do so. We
need at least to keep the implementation is correct, i.e, all the tables
needed are passed and the assembler/disassembler is doing what they
should do.

> diff --git a/opcodes/i386-dis-evex-prefix.h b/opcodes/i386-dis-evex-prefix.h
> index 1aeac210c5d..ffecef5e796 100644
> --- a/opcodes/i386-dis-evex-prefix.h
> +++ b/opcodes/i386-dis-evex-prefix.h
> +  /* PREFIX_EVEX_MAP5_36 */
> +  {
> +    { VEX_W_TABLE (EVEX_W_MAP5_36_P_0) },
> +  },

You could avoid W table pass by adding a macro like
%XF, to output hf for W1 and bf for W0. And the same
for similar both hf/bf existing cases. For those only
one of them exists, you still need to pass W table to
invalid the other one, like...

> +  /* PREFIX_EVEX_MAP5_37 */
> +  {
> +    { "vcvtbf42hf8",	{ XM, EXxmmq }, 0 },

... here. You need to pass W table.

> +    { Bad_Opcode },
> +    { VEX_W_TABLE (EVEX_W_MAP5_37_P_2) },
> +  },
> +  /* PREFIX_EVEX_MAP5_38 */
> +  {
> +    { "vcvtbiasps2hf8",	{ XMM, Vex, EXx }, 0 },
> +    { "vcvtps2hf8",	{ XMM, EXx }, 0 },
> +    { "vcvtrops2hf8",	{ XMM, EXx }, 0 },

It is what I mentioned in testcase part, you will need
a suffix for ATT syntax if memory is involved and you
could not determine the memory size according to
other operands. Unlike Intel syntax has the memory
size directly at memory operand, ATT syntax won't.
The only way to distinguish them is adding x/y/z
when needed at the end of the mnemonics.

Take this scenario as example, here we need suffix
for vcvtps2hf8 and vcvtrops2hf8, since the other
operand will always be xmm, it does not contain
any info to indicate the other operand. Adding %XZ
is needed since it needs all x/y/z.
vcvtbiasps2hf8 does not need that suffix because the
second operand contains the info.

Please also check other similar scenarios. If I don't
miss something, should be vcvt[ro,]ps2[h,b]f8[,s] if
they exists.

> +  /* PREFIX_EVEX_MAP5_3C */
> +  {
> +    { Bad_Opcode },
> +    { "vcvthf82hf6s",	{ XM, EXx }, 0 },
> +  },

There are several mod table pass missing throughout
the implementation. You need restrict MOD.R/M as
11 here.

Also, for non-broadcast operands, please use
EXEvexXNoBcst instead of EXx.

Similar for vunpackb and vcvtbf82bf6s.

> +  /* PREFIX_EVEX_MAP5_3D */
> +  {
> +    { Bad_Opcode },
> +    { VEX_W_TABLE (EVEX_W_MAP5_3D_P_1) },
> +  },
> +  /* PREFIX_EVEX_MAP5_3E */
> +  {
> +    { Bad_Opcode },
> +    { VEX_W_TABLE (EVEX_W_MAP5_3E_P_1) },
> +  },
>    /* PREFIX_EVEX_MAP5_74 */
>    {
>      { "vcvtbiasp%XH2bf8s",	{ XMxmmq, Vex, EXxh }, 0 },
> diff --git a/opcodes/i386-dis-evex-w.h b/opcodes/i386-dis-evex-w.h
> index 310f121f499..6e94bc45fe1 100644
> --- a/opcodes/i386-dis-evex-w.h
> +++ b/opcodes/i386-dis-evex-w.h
> +  /* EVEX_W_MAP5_3E_P_1 */
> +  {
> +    { Bad_Opcode },
> +    { "vcvtbf82bf6s",	{ XM, EXx }, 0 },
> +  },

Please pass W table before prefix table to reduce
potential tree size.

> diff --git a/opcodes/i386-dis-evex.h b/opcodes/i386-dis-evex.h
> index b2f02e494f9..7d555aa9e11 100644
> --- a/opcodes/i386-dis-evex.h
> +++ b/opcodes/i386-dis-evex.h
> @@ -652,7 +652,7 @@ static const struct dis386 evex_table[][256] = {
>      { EVEX_LEN_TABLE (EVEX_LEN_0F3A3A) },
>      { EVEX_LEN_TABLE (EVEX_LEN_0F3A3B) },
>      { Bad_Opcode },
> -    { Bad_Opcode },
> +    { "vunpackb",	{ XM, EXx, Ib }, 0 },

Missing W and prefix table pass here.

> diff --git a/opcodes/i386-opc.tbl b/opcodes/i386-opc.tbl
> index 7042ca4512e..3d3e37b09aa 100644
> --- a/opcodes/i386-opc.tbl
> +++ b/opcodes/i386-opc.tbl
> @@ -3620,6 +3620,95 @@ vucomxs<sdh>, 0x<sdh:spfx>2e, AVX10_2,
> Modrm|EVexLIG|<sdh:spc1>|<sdh:vexw>|Disp8
> 
>  // AVX10.2 instructions end.
> 
> +// AVX10_V2_AUX instructions.
> +
> +// VCVTPS2BF8, VCVTPS2BF8S, VCVTPS2HF8, VCVTPS2HF8S - narrowing 2-
> op (F3.MAP5)
> +// VCVTROPS2HF8, VCVTROPS2HF8S - narrowing 2-op (66.MAP5)
> +
> +<cvtps8:opc:pfx, +
> +    bf8:39:f3, +
> +    bf8s:3b:f3, +
> +    hf8:38:f3, +
> +    hf8s:3a:f3>

Why do you need to put pfx in iterator? They are all f3.

And we could simply separate them as <fp8> and <sat> here, not <cvtps8>,
<cvtrops8>, <cvtbiasps8>, where <fp8> has the base opcode 38 and 39,
<sat> add 2 for them when there is saturation.

And just as mentioned, you will also need to handle ATT Syntax here, you will
need a new <Exyz>.

> +
> +vcvtps2<cvtps8>, 0x<cvtps8:pfx><cvtps8:opc>, AVX10_V2_AUX,
> Modrm|Map5|EVex128|VexW0|Masking|Broadcast|Disp8MemShift=4|NoS
> uf, { RegXMM|Dword|Unspecified|BaseIndex, RegXMM }
> +vcvtps2<cvtps8>, 0x<cvtps8:pfx><cvtps8:opc>, AVX10_V2_AUX,
> Modrm|Map5|EVex256|VexW0|Masking|Broadcast|Disp8MemShift=5|NoS
> uf, { RegYMM|Dword|Unspecified|BaseIndex, RegXMM }
> +vcvtps2<cvtps8>, 0x<cvtps8:pfx><cvtps8:opc>, AVX10_V2_AUX,
> Modrm|Map5|EVex512|VexW0|Masking|Broadcast|Disp8MemShift=6|NoS
> uf, { RegZMM|Dword|Unspecified|BaseIndex, RegXMM }

Disp8ShiftVL will combine Disp8MemShift=4/5/6. Then you could combine the
templates. Similar for vcvtro and vcvtbias.

> +
> +<cvtps8>
> +
> +<cvtrops8:opc, +
> +    hf8:38, +
> +    hf8s:3a>
> +
> +vcvtrops2<cvtrops8>, 0x66<cvtrops8:opc>, AVX10_V2_AUX,
> Modrm|Map5|EVex128|VexW0|Masking|Broadcast|Disp8MemShift=4|NoS
> uf, { RegXMM|Dword|Unspecified|BaseIndex, RegXMM }
> +vcvtrops2<cvtrops8>, 0x66<cvtrops8:opc>, AVX10_V2_AUX,
> Modrm|Map5|EVex256|VexW0|Masking|Broadcast|Disp8MemShift=5|NoS
> uf, { RegYMM|Dword|Unspecified|BaseIndex, RegXMM }
> +vcvtrops2<cvtrops8>, 0x66<cvtrops8:opc>, AVX10_V2_AUX,
> Modrm|Map5|EVex512|VexW0|Masking|Broadcast|Disp8MemShift=6|NoS
> uf, { RegZMM|Dword|Unspecified|BaseIndex, RegXMM }
> +
> +<cvtrops8>
> +
> +// VCVTBIASPS2BF8, VCVTBIASPS2BF8S, VCVTBIASPS2HF8,
> VCVTBIASPS2HF8S - 3-op narrowing (NP.MAP5)
> +
> +<cvtbiasps:opc, +
> +    bf8:39, +
> +    bf8s:3b, +
> +    hf8:38, +
> +    hf8s:3a>
> +
> +vcvtbiasps2<cvtbiasps>, 0x<cvtbiasps:opc>, AVX10_V2_AUX,
> Modrm|Map5|EVex128|Src1VVVV|VexW0|Masking|Broadcast|Disp8Mem
> Shift=4|NoSuf, { RegXMM|Dword|Unspecified|BaseIndex, RegXMM,
> RegXMM }
> +vcvtbiasps2<cvtbiasps>, 0x<cvtbiasps:opc>, AVX10_V2_AUX,
> Modrm|Map5|EVex256|Src1VVVV|VexW0|Masking|Broadcast|Disp8Mem
> Shift=5|NoSuf, { RegYMM|Dword|Unspecified|BaseIndex, RegYMM,
> RegXMM }
> +vcvtbiasps2<cvtbiasps>, 0x<cvtbiasps:opc>, AVX10_V2_AUX,
> Modrm|Map5|EVex512|Src1VVVV|VexW0|Masking|Broadcast|Disp8Mem
> Shift=6|NoSuf, { RegZMM|Dword|Unspecified|BaseIndex, RegZMM,
> RegXMM }
> +
> +<cvtbiasps>
> +
> +// VCVTBF82PS (NP.MAP5.W1) and VCVTHF82PS (NP.MAP5.W0) - widening
> xmm/m to xmm/ymm/zmm
> +vcvtbf82ps, 0x36, AVX10_V2_AUX,
> Modrm|Map5|EVex128|VexW1|Masking|Disp8MemShift=2|NoSuf,
> { RegXMM|Dword|Unspecified|BaseIndex, RegXMM }
> +vcvtbf82ps, 0x36, AVX10_V2_AUX,
> Modrm|Map5|EVex256|VexW1|Masking|Disp8MemShift=3|NoSuf,
> { RegXMM|Qword|Unspecified|BaseIndex, RegYMM }
> +vcvtbf82ps, 0x36, AVX10_V2_AUX,
> Modrm|Map5|EVex512|VexW1|Masking|Disp8MemShift=4|NoSuf,
> { RegXMM|Unspecified|BaseIndex, RegZMM }
> +
> +vcvthf82ps, 0x36, AVX10_V2_AUX,
> Modrm|Map5|EVex128|VexW0|Masking|Disp8MemShift=2|NoSuf,
> { RegXMM|Dword|Unspecified|BaseIndex, RegXMM }
> +vcvthf82ps, 0x36, AVX10_V2_AUX,
> Modrm|Map5|EVex256|VexW0|Masking|Disp8MemShift=3|NoSuf,
> { RegXMM|Qword|Unspecified|BaseIndex, RegYMM }
> +vcvthf82ps, 0x36, AVX10_V2_AUX,
> Modrm|Map5|EVex512|VexW0|Masking|Disp8MemShift=4|NoSuf,
> { RegXMM|Unspecified|BaseIndex, RegZMM }

You could combine bf and hf with <fp>, where bf as VexW1, hf as VexW0.
Similar for other cases.

> +
> +// VCVTBF82BF4S (F3.MAP5.W1) and VCVTHF82BF4S (F3.MAP5.W0) -
> narrowing, no mask
> +vcvtbf82bf4s, 0xf33d, AVX10_V2_AUX,
> Modrm|Map5|EVex128|VexW1|Disp8MemShift=3|NoSuf, { RegXMM,
> RegXMM|Qword|Unspecified|BaseIndex }

We may need RegMem to swap the operand.

If I miss something, I will reply afterwards.

Thx,
Haochen
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.