x86: split insn templates' CPU field
[binutils-gdb.git] / gas / config / tc-i386.c
index c6a15216d3b7c9f35d86a8b385859e998487c6bf..bb02347eb7f4ec34ac1aa107c70baa6624395f92 100644 (file)
@@ -1655,24 +1655,36 @@ operand_type_equal (const union i386_operand_type *x,
 }
 
 static INLINE bool
-is_cpu (const insn_template *t, enum i386_cpu cpu)
+_is_cpu (const i386_cpu_attr *a, enum i386_cpu cpu)
 {
   switch (cpu)
     {
-    case Cpu287:      return t->cpu.bitfield.cpu287;
-    case Cpu387:      return t->cpu.bitfield.cpu387;
-    case Cpu3dnow:    return t->cpu.bitfield.cpu3dnow;
-    case Cpu3dnowA:   return t->cpu.bitfield.cpu3dnowa;
-    case CpuAVX:      return t->cpu.bitfield.cpuavx;
-    case CpuHLE:      return t->cpu.bitfield.cpuhle;
-    case CpuAVX512F:  return t->cpu.bitfield.cpuavx512f;
-    case CpuAVX512VL: return t->cpu.bitfield.cpuavx512vl;
-    case Cpu64:       return t->cpu.bitfield.cpu64;
-    case CpuNo64:     return t->cpu.bitfield.cpuno64;
+    case Cpu287:      return a->bitfield.cpu287;
+    case Cpu387:      return a->bitfield.cpu387;
+    case Cpu3dnow:    return a->bitfield.cpu3dnow;
+    case Cpu3dnowA:   return a->bitfield.cpu3dnowa;
+    case CpuAVX:      return a->bitfield.cpuavx;
+    case CpuHLE:      return a->bitfield.cpuhle;
+    case CpuAVX512F:  return a->bitfield.cpuavx512f;
+    case CpuAVX512VL: return a->bitfield.cpuavx512vl;
+    case Cpu64:       return a->bitfield.cpu64;
+    case CpuNo64:     return a->bitfield.cpuno64;
     default:
       gas_assert (cpu < CpuAttrEnums);
     }
-  return t->cpu.bitfield.isa == cpu + 1u;
+  return a->bitfield.isa == cpu + 1u;
+}
+
+static INLINE bool
+is_cpu (const insn_template *t, enum i386_cpu cpu)
+{
+  return _is_cpu(&t->cpu, cpu);
+}
+
+static INLINE bool
+maybe_cpu (const insn_template *t, enum i386_cpu cpu)
+{
+  return _is_cpu(&t->cpu_any, cpu);
 }
 
 static i386_cpu_flags cpu_flags_from_attr (i386_cpu_attr a)
@@ -1863,96 +1875,68 @@ static INLINE bool need_evex_encoding (void)
 static int
 cpu_flags_match (const insn_template *t)
 {
-  i386_cpu_flags x = cpu_flags_from_attr (t->cpu);
+  i386_cpu_flags cpu, active, all = cpu_flags_from_attr (t->cpu);
+  i386_cpu_flags any = cpu_flags_from_attr (t->cpu_any);
   int match = cpu_flags_check_cpu64 (t) ? CPU_FLAGS_64BIT_MATCH : 0;
 
-  x.bitfield.cpu64 = 0;
-  x.bitfield.cpuno64 = 0;
+  all.bitfield.cpu64 = 0;
+  all.bitfield.cpuno64 = 0;
+  gas_assert (!any.bitfield.cpu64);
+  gas_assert (!any.bitfield.cpuno64);
 
-  if (cpu_flags_all_zero (&x))
+  if (cpu_flags_all_zero (&all) && cpu_flags_all_zero (&any))
     {
       /* This instruction is available on all archs.  */
-      match |= CPU_FLAGS_ARCH_MATCH;
+      return match | CPU_FLAGS_ARCH_MATCH;
     }
-  else
-    {
-      /* This instruction is available only on some archs.  */
-      i386_cpu_flags active, cpu;
 
-      if (flag_code != CODE_64BIT)
-       active = cpu_flags_and_not (cpu_arch_flags, cpu_64_flags);
-      else
-       active = cpu_arch_flags;
+  /* This instruction is available only on some archs.  */
 
-      /* Dual VEX/EVEX templates may need stripping of one of the flags.  */
-      if (t->opcode_modifier.vex && t->opcode_modifier.evex)
+  /* Dual VEX/EVEX templates may need stripping of one of the flags.  */
+  if (t->opcode_modifier.vex && t->opcode_modifier.evex)
+    {
+      /* 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)
+         && (any.bitfield.cpuavx512f || any.bitfield.cpuavx512vl))
        {
-         /* Dual AVX/AVX512F templates need to retain AVX512F only if we already
-            know that EVEX encoding will be needed.  */
-         if ((x.bitfield.cpuavx || x.bitfield.cpuavx2)
-             && x.bitfield.cpuavx512f)
+         if (need_evex_encoding ())
            {
-             if (need_evex_encoding ())
-               {
-                 x.bitfield.cpuavx = 0;
-                 x.bitfield.cpuavx2 = 0;
-               }
-             /* need_evex_encoding() isn't reliable before operands were
-                parsed.  */
-             else if (i.operands)
-               {
-                 x.bitfield.cpuavx512f = 0;
-                 x.bitfield.cpuavx512vl = 0;
-                 if (x.bitfield.cpufma && !active.bitfield.cpufma)
-                   x.bitfield.cpuavx = 0;
-               }
+             any.bitfield.cpuavx = 0;
+             any.bitfield.cpuavx2 = 0;
+             any.bitfield.cpufma = 0;
+           }
+         /* need_evex_encoding() isn't reliable before operands were
+            parsed.  */
+         else if (i.operands)
+           {
+             any.bitfield.cpuavx512f = 0;
+             any.bitfield.cpuavx512vl = 0;
            }
        }
+    }
 
-      /* AVX512VL is no standalone feature - match it and then strip it.  */
-      if (x.bitfield.cpuavx512vl && !active.bitfield.cpuavx512vl)
-       return match;
-      x.bitfield.cpuavx512vl = 0;
-
+  if (flag_code != CODE_64BIT)
+    active = cpu_flags_and_not (cpu_arch_flags, cpu_64_flags);
+  else
+    active = cpu_arch_flags;
+  cpu = cpu_flags_and (all, active);
+  if (cpu_flags_equal (&cpu, &all))
+    {
       /* AVX and AVX2 present at the same time express an operand size
         dependency - strip AVX2 for the purposes here.  The operand size
         dependent check occurs in check_vecOperands().  */
-      if (x.bitfield.cpuavx && x.bitfield.cpuavx2)
-       x.bitfield.cpuavx2 = 0;
-
-      cpu = cpu_flags_and (x, active);
-      if (!cpu_flags_all_zero (&cpu))
-       {
-         if (t->cpu.bitfield.cpuavx && t->cpu.bitfield.cpuavx512f)
-           {
-             if ((need_evex_encoding ()
-                  ? cpu.bitfield.cpuavx512f
-                  : cpu.bitfield.cpuavx)
-                 && (!x.bitfield.cpufma || cpu.bitfield.cpufma
-                     || active.bitfield.cpuavx512f)
-                 && (!x.bitfield.cpugfni || cpu.bitfield.cpugfni)
-                 && (!x.bitfield.cpuvaes || cpu.bitfield.cpuvaes)
-                 && (!x.bitfield.cpuvpclmulqdq || cpu.bitfield.cpuvpclmulqdq))
-               match |= CPU_FLAGS_ARCH_MATCH;
-           }
-         else if (x.bitfield.cpuavx)
-           {
-             /* We need to check a few extra flags with AVX.  */
-             if (cpu.bitfield.cpuavx
-                 && (!t->opcode_modifier.sse2avx
-                     || (sse2avx && !i.prefix[DATA_PREFIX]))
-                 && (!x.bitfield.cpuaes || cpu.bitfield.cpuaes)
-                 && (!x.bitfield.cpugfni || cpu.bitfield.cpugfni)
-                 && (!x.bitfield.cpupclmulqdq || cpu.bitfield.cpupclmulqdq))
-               match |= CPU_FLAGS_ARCH_MATCH;
-           }
-         else if (x.bitfield.cpuavx2 && cpu.bitfield.cpuavx2)
-           match |= CPU_FLAGS_ARCH_MATCH;
-         else if (x.bitfield.cpuavx512f)
+      if (any.bitfield.cpuavx && any.bitfield.cpuavx2)
+       any.bitfield.cpuavx2 = 0;
+
+      cpu = cpu_flags_and (any, active);
+      if (cpu_flags_all_zero (&any) || !cpu_flags_all_zero (&cpu))
+       {
+         if (all.bitfield.cpuavx)
            {
-             /* We need to check a few extra flags with AVX512F.  */
-             if (cpu.bitfield.cpuavx512f
-                 && (!x.bitfield.cpugfni || cpu.bitfield.cpugfni))
+             /* We need to check SSE2AVX with AVX.  */
+             if (!t->opcode_modifier.sse2avx
+                 || (sse2avx && !i.prefix[DATA_PREFIX]))
                match |= CPU_FLAGS_ARCH_MATCH;
            }
          else
@@ -3679,20 +3663,25 @@ install_template (const insn_template *t)
   /* Dual VEX/EVEX templates need stripping one of the possible variants.  */
   if (t->opcode_modifier.vex && t->opcode_modifier.evex)
   {
-      if ((is_cpu (t, CpuAVX) || is_cpu (t, CpuAVX2))
-         && is_cpu (t, CpuAVX512F))
+      if ((maybe_cpu (t, CpuAVX) || maybe_cpu (t, CpuAVX2)
+          || maybe_cpu (t, CpuFMA))
+         && (maybe_cpu (t, CpuAVX512F) || maybe_cpu (t, CpuAVX512VL)))
        {
          if (need_evex_encoding ())
            {
              i.tm.opcode_modifier.vex = 0;
-             i.tm.cpu.bitfield.cpuavx = 0;
-             if (is_cpu (&i.tm, CpuAVX2))
-               i.tm.cpu.bitfield.isa = 0;
+             i.tm.cpu.bitfield.cpuavx512f = i.tm.cpu_any.bitfield.cpuavx512f;
+             i.tm.cpu.bitfield.cpuavx512vl = i.tm.cpu_any.bitfield.cpuavx512vl;
            }
          else
            {
              i.tm.opcode_modifier.evex = 0;
-             i.tm.cpu.bitfield.cpuavx512f = 0;
+             if (i.tm.cpu_any.bitfield.cpuavx)
+               i.tm.cpu.bitfield.cpuavx = 1;
+             else if (!i.tm.cpu.bitfield.isa)
+               i.tm.cpu.bitfield.isa = i.tm.cpu_any.bitfield.isa;
+             else
+               gas_assert (i.tm.cpu.bitfield.isa == i.tm.cpu_any.bitfield.isa);
            }
        }
   }
@@ -6570,7 +6559,7 @@ check_VecOperands (const insn_template *t)
 
   /* Somewhat similarly, templates specifying both AVX and AVX2 are
      requiring AVX2 support if the actual operand size is YMMword.  */
-  if (is_cpu (t, CpuAVX) && is_cpu (t, CpuAVX2)
+  if (maybe_cpu (t, CpuAVX) && maybe_cpu (t, CpuAVX2)
       && !cpu_arch_flags.bitfield.cpuavx2)
     {
       for (op = 0; op < t->operands; ++op)