[PATCH 2/2] x86: fold F16C templates with their AVX512VL counterparts

Jan Beulich jbeulich@suse.com
Fri Jul 17 13:50:22 GMT 2026


It's not quite clear why this wasn't done so far. These, conceptually,
aren't any different from the FMA ones.

Doing so actually made me notice a flaw in FMA template handling, which is
being fixed alongside making the necessary changes to accommodate F16C:
Both features aren't prereqs of AVX512F. When they're disabled, enabling
AVX512VL would still not allow the 128- and 256-bit forms to assemble.
---
This actually points out another issue with FMA and F16C: Code created
prior to the introduction of AVX512 might have used ".arch .no{fma,f16c}"
to have uses of the respective insns properly rejected. That protection
suddenly ceased to work properly when AVX512 support was added to the
assembler: Those insns would now assemble to their AVX512VL EVEX forms.
The least bad option to deal with this looks to be to reject the AVX512VL
forms also when FMA/F16C are explicitly disabled while AVX512VL isn't
explicitly enabled. Are there any better suggestions?

--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -2314,14 +2314,18 @@ cpu_flags_match (const insn_template *t)
     {
       /* Dual AVX/AVX512 templates need to retain AVX512* only if we already
 	 know that EVEX encoding will be needed.  */
-      if ((any.bitfield.cpuavx || any.bitfield.cpuavx2 || any.bitfield.cpufma)
+      if ((any.bitfield.cpuavx || any.bitfield.cpuavx2
+	   || any.bitfield.cpufma || any.bitfield.cpuf16c)
 	  && (any.bitfield.cpuavx512f || any.bitfield.cpuavx512vl))
 	{
-	  if (need_evex_encoding (t))
+	  if (need_evex_encoding (t)
+	      || (any.bitfield.cpufma && !cpu_arch_flags.bitfield.cpufma)
+	      || (any.bitfield.cpuf16c && !cpu_arch_flags.bitfield.cpuf16c))
 	    {
 	      any.bitfield.cpuavx = 0;
 	      any.bitfield.cpuavx2 = 0;
 	      any.bitfield.cpufma = 0;
+	      any.bitfield.cpuf16c = 0;
 	    }
 	  /* need_evex_encoding(t) isn't reliable before operands were
 	     parsed.  */
@@ -4232,10 +4236,12 @@ install_template (const insn_template *t
   if (t->opcode_modifier.vex && t->opcode_modifier.evex)
     {
       if ((maybe_cpu (t, CpuAVX) || maybe_cpu (t, CpuAVX2)
-	   || maybe_cpu (t, CpuFMA))
+	   || maybe_cpu (t, CpuFMA) || maybe_cpu (t, CpuF16C))
 	  && (maybe_cpu (t, CpuAVX512F) || maybe_cpu (t, CpuAVX512VL)))
 	{
-	  if (need_evex_encoding (t))
+	  if (need_evex_encoding (t)
+	      || (maybe_cpu (t, CpuFMA) && !cpu_arch_flags.bitfield.cpufma)
+	      || (maybe_cpu (t, CpuF16C) && !cpu_arch_flags.bitfield.cpuf16c))
 	    {
 	      i.tm.opcode_modifier.vex = 0;
 	      i.tm.cpu.bitfield.cpuavx512f = i.tm.cpu_any.bitfield.cpuavx512f;
@@ -8799,7 +8805,10 @@ check_VecOperands (const insn_template *
   if (!cpu_flags_all_zero (&cpu)
       && !cpu.bitfield.cpuavx512vl
       && !cpu_arch_flags.bitfield.cpuavx512vl
-      && (!t->opcode_modifier.vex || need_evex_encoding (t)))
+      && (!t->opcode_modifier.vex || need_evex_encoding (t)
+	  /* Note: No need to check F16C here.  Those insns have distinct
+	     templates for distinct VEX.L / EVEX.L'L.  */
+	  || (maybe_cpu (t, CpuFMA) && !cpu_arch_flags.bitfield.cpufma)))
     {
       for (op = 0; op < t->operands; ++op)
 	{
--- a/gas/testsuite/gas/i386/avx512vl-plain.l
+++ b/gas/testsuite/gas/i386/avx512vl-plain.l
@@ -1,8 +1,8 @@
 .*: Assembler messages:
 .*:5: Error: .*
-.*:6: Error: .*
-.*:7: Error: .*
-.*:20: Error: .*
+.*:8: Error: .*
+.*:9: Error: .*
+.*:22: Error: .*
 GAS LISTING .*
 
 
@@ -11,23 +11,27 @@ GAS LISTING .*
 [ 	]*3[ 	]+\.arch \.avx512vl
 [ 	]*4[ 	]+_start:
 [ 	]*5[ 	]+\{evex\} vaesenc[ 	]+%ymm1, %ymm2, %ymm3
-[ 	]*6[ 	]+vgf2p8mulb[ 	]+%ymm1, %ymm2, %ymm3\{%k4\}
-[ 	]*7[ 	]+\{evex\} vpclmulqdq[ 	]+\$0, %ymm1, %ymm2, %ymm3
-[ 	]*8[ 	]*
-[ 	]*9[ 	]+\.arch \.vaes
-[ 	]*10[ 	]+\?\?\?\? 62F26D28[ 	]+\{evex\} vaesenc[ 	]+%ymm1, %ymm2, %ymm3
-[ 	]*10[ 	]+DCD9
-[ 	]*11[ 	]*
-[ 	]*12[ 	]+\.arch \.gfni
-[ 	]*13[ 	]+\?\?\?\? 62F26D2C[ 	]+vgf2p8mulb[ 	]+%ymm1, %ymm2, %ymm3\{%k4\}
-[ 	]*13[ 	]+CFD9
-[ 	]*14[ 	]*
-[ 	]*15[ 	]+\.arch \.vpclmulqdq
-[ 	]*16[ 	]+\?\?\?\? 62F36D28[ 	]+\{evex\} vpclmulqdq[ 	]+\$0, %ymm1, %ymm2, %ymm3
-[ 	]*16[ 	]+44D900
-[ 	]*17[ 	]*
-[ 	]*18[ 	]+\.arch generic32
-[ 	]*19[ 	]+\.arch \.avx512f
-[ 	]*20[ 	]+\{evex\}[ 	]+vpermd[ 	]+%ymm1, %ymm2, %ymm3
-[ 	]*21[ 	]+\?\?\?\? C4E26D36[ 	]+vpermd[ 	]+%ymm1, %ymm2, %ymm3
+[ 	]*6[ 	]+\?\?\?\? 62F27D08[ 	]+vcvtph2ps[ 	]+%xmm1, %xmm2
+[ 	]*6[ 	]+13D1
+[ 	]*7[ 	]+\?\?\?\? 62F26D08[ 	]+vfmadd132ps[ 	]+%xmm1, %xmm2, %xmm3
+[ 	]*7[ 	]+98D9
+[ 	]*8[ 	]+vgf2p8mulb[ 	]+%ymm1, %ymm2, %ymm3\{%k4\}
+[ 	]*9[ 	]+\{evex\} vpclmulqdq[ 	]+\$0, %ymm1, %ymm2, %ymm3
+[ 	]*10[ 	]*
+[ 	]*11[ 	]+\.arch \.vaes
+[ 	]*12[ 	]+\?\?\?\? 62F26D28[ 	]+\{evex\} vaesenc[ 	]+%ymm1, %ymm2, %ymm3
+[ 	]*12[ 	]+DCD9
+[ 	]*13[ 	]*
+[ 	]*14[ 	]+\.arch \.gfni
+[ 	]*15[ 	]+\?\?\?\? 62F26D2C[ 	]+vgf2p8mulb[ 	]+%ymm1, %ymm2, %ymm3\{%k4\}
+[ 	]*15[ 	]+CFD9
+[ 	]*16[ 	]*
+[ 	]*17[ 	]+\.arch \.vpclmulqdq
+[ 	]*18[ 	]+\?\?\?\? 62F36D28[ 	]+\{evex\} vpclmulqdq[ 	]+\$0, %ymm1, %ymm2, %ymm3
+[ 	]*18[ 	]+44D900
+[ 	]*19[ 	]*
+[ 	]*20[ 	]+\.arch generic32
+[ 	]*21[ 	]+\.arch \.avx512f
+[ 	]*22[ 	]+\{evex\}[ 	]+vpermd[ 	]+%ymm1, %ymm2, %ymm3
+[ 	]*23[ 	]+\?\?\?\? C4E26D36[ 	]+vpermd[ 	]+%ymm1, %ymm2, %ymm3
 #pass
--- a/gas/testsuite/gas/i386/avx512vl-plain.s
+++ b/gas/testsuite/gas/i386/avx512vl-plain.s
@@ -3,6 +3,8 @@
 	.arch .avx512vl
 _start:
 	{evex} vaesenc		%ymm1, %ymm2, %ymm3
+	       vcvtph2ps	%xmm1, %xmm2
+	       vfmadd132ps	%xmm1, %xmm2, %xmm3
 	       vgf2p8mulb	%ymm1, %ymm2, %ymm3{%k4}
 	{evex} vpclmulqdq	$0, %ymm1, %ymm2, %ymm3
 
--- a/opcodes/i386-opc.tbl
+++ b/opcodes/i386-opc.tbl
@@ -1922,17 +1922,20 @@ vgf2p8affineinvqb, 0x66cf, AVX&GFNI, Mod
 vgf2p8affineqb, 0x66ce, AVX&GFNI, Modrm|Vex|Space0F3A|Src1VVVV|VexW1|CheckOperandSize|NoSuf, { Imm8, Unspecified|BaseIndex|RegXMM|RegYMM, RegXMM|RegYMM, RegXMM|RegYMM }
 vgf2p8mulb, 0x66cf, GFNI&(AVX|AVX512F), Modrm|Vex|EVexDYN|Masking|Space0F38|Src1VVVV|VexW0|Disp8ShiftVL|CheckOperandSize|NoSuf, { RegXMM|RegYMM|RegZMM|Unspecified|BaseIndex, RegXMM|RegYMM|RegZMM, RegXMM|RegYMM|RegZMM }
 
-// FSGSBASE, RDRND and F16C
+// FSGSBASE and RDRND
 
 rdfsbase, 0xf30fae/0, FSGSBase, Modrm|IgnoreSize|NoSuf, { Reg32|Reg64 }
 rdgsbase, 0xf30fae/1, FSGSBase, Modrm|IgnoreSize|NoSuf, { Reg32|Reg64 }
 rdrand, 0xfc7/6, RdRnd, Modrm|NoSuf, { Reg16|Reg32|Reg64 }
 wrfsbase, 0xf30fae/2, FSGSBase, Modrm|IgnoreSize|NoSuf, { Reg32|Reg64 }
 wrgsbase, 0xf30fae/3, FSGSBase, Modrm|IgnoreSize|NoSuf, { Reg32|Reg64 }
-vcvtph2ps, 0x6613, F16C, Modrm|Vex|Space0F38|VexW0|NoSuf, { Qword|Unspecified|BaseIndex|RegXMM, RegXMM }
-vcvtph2ps, 0x6613, F16C, Modrm|Vex=2|Space0F38|VexW=1|NoSuf, { Unspecified|BaseIndex|RegXMM, RegYMM }
-vcvtps2ph, 0x661d, F16C, Modrm|Vex|Space0F3A|VexW0|NoSuf, { Imm8, RegXMM, Qword|Unspecified|BaseIndex|RegXMM }
-vcvtps2ph, 0x661d, F16C, Modrm|Vex=2|Space0F3A|VexW=1|NoSuf, { Imm8, RegYMM, Unspecified|BaseIndex|RegXMM }
+
+// F16C instructions
+
+vcvtph2ps, 0x6613, F16C|AVX512VL, Modrm|Vex128|EVex128|Masking|Space0F38|VexW0|Disp8MemShift=3|NoSuf, { Qword|Unspecified|BaseIndex|RegXMM, RegXMM }
+vcvtph2ps, 0x6613, F16C|AVX512VL, Modrm|Vex256|EVex256|Masking|Space0F38|VexW0|Disp8MemShift=4|NoSuf, { Unspecified|BaseIndex|RegXMM, RegYMM }
+vcvtps2ph, 0x661d, F16C|AVX512VL, Modrm|Vex128|EVex128|Masking|Space0F3A|VexW0|Disp8MemShift=3|NoSuf, { Imm8, RegXMM, Qword|Unspecified|BaseIndex|RegXMM }
+vcvtps2ph, 0x661d, F16C|AVX512VL, Modrm|Vex256|EVex256|Masking|Space0F3A|VexW0|Disp8MemShift=4|NoSuf, { Imm8, RegYMM, Unspecified|BaseIndex|RegXMM }
 
 // FMA instructions
 
@@ -2655,15 +2658,9 @@ vcvtdq2pd, 0xF3E6, AVX512VL, Modrm|EVex2
 vcvtudq2pd, 0xF37A, AVX512VL, Modrm|EVex128|Masking|Space0F|VexW0|Broadcast|Disp8MemShift=3|NoSuf, { RegXMM|Dword|Qword|Unspecified|BaseIndex, RegXMM }
 vcvtudq2pd, 0xF37A, AVX512VL, Modrm|EVex256|Masking|Space0F|VexW0|Broadcast|Disp8MemShift=4|NoSuf, { RegXMM|Dword|Unspecified|BaseIndex, RegYMM }
 
-vcvtph2ps, 0x6613, AVX512VL, Modrm|EVex=2|Masking|Space0F38|VexW0|Disp8MemShift=3|NoSuf, { RegXMM|Qword|Unspecified|BaseIndex, RegXMM }
-vcvtph2ps, 0x6613, AVX512VL, Modrm|EVex=3|Masking|Space0F38|VexW=1|Disp8MemShift=4|NoSuf, { RegXMM|Unspecified|BaseIndex, RegYMM }
-
 vcvtps2pd, 0x5A, AVX512VL, Modrm|EVex128|Masking|Space0F|VexW0|Broadcast|Disp8MemShift=3|NoSuf, { RegXMM|Dword|Qword|Unspecified|BaseIndex, RegXMM }
 vcvtps2pd, 0x5A, AVX512VL, Modrm|EVex256|Masking|Space0F|VexW0|Broadcast|Disp8MemShift=4|NoSuf, { RegXMM|Dword|Unspecified|BaseIndex, RegYMM }
 
-vcvtps2ph, 0x661D, AVX512VL, Modrm|EVex128|Masking|Space0F3A|VexW0|Disp8MemShift=3|NoSuf, { Imm8, RegXMM, RegXMM|Qword|Unspecified|BaseIndex }
-vcvtps2ph, 0x661D, AVX512VL, Modrm|EVex256|Masking|Space0F3A|VexW0|Disp8MemShift=4|NoSuf, { Imm8, RegYMM, RegXMM|Unspecified|BaseIndex }
-
 vmovddup, 0xF212, AVX512VL, Modrm|EVex=2|Masking|Space0F|VexW1|Disp8MemShift=3|NoSuf, { RegXMM|Qword|Unspecified|BaseIndex, RegXMM }
 
 vp<movn>db, 0xf3<movn:opc>1, AVX512VL, Modrm|EVex128|Masking|Space0F38|VexW0|Disp8MemShift=2|NoSuf, { RegXMM, RegXMM|Dword|Unspecified|BaseIndex }



More information about the Binutils mailing list