x86: fix SSE4a dependencies of ".arch .nosse*"
[deliverable/binutils-gdb.git] / gas / config / tc-i386.c
index 4f102a3de3d1f5583a9125277a7d9fecb20b1857..6b923ccb81b8c3b654c7e4bcc02f4eee3d9f18e0 100644 (file)
 #endif
 #endif
 
-#ifndef REGISTER_WARNINGS
-#define REGISTER_WARNINGS 1
-#endif
-
 #ifndef INFER_ADDR_PREFIX
 #define INFER_ADDR_PREFIX 1
 #endif
@@ -354,6 +350,9 @@ struct _i386_insn
     unsigned int prefixes;
     unsigned char prefix[MAX_PREFIXES];
 
+    /* Register is in low 3 bits of opcode.  */
+    bfd_boolean short_form;
+
     /* The operand to a branch insn indicates an absolute branch.  */
     bfd_boolean jumpabsolute;
 
@@ -598,9 +597,11 @@ static int shared = 0;
    0 if att syntax.  */
 static int intel_syntax = 0;
 
-/* 1 for Intel64 ISA,
-   0 if AMD64 ISA.  */
-static int intel64;
+static enum x86_64_isa
+{
+  amd64 = 1,   /* AMD64 ISA.  */
+  intel64      /* Intel64 ISA.  */
+} isa64;
 
 /* 1 for intel mnemonic,
    0 if att mnemonic.  */
@@ -1179,7 +1180,7 @@ static const noarch_entry cpu_noarch[] =
   { STRING_COMMA_LEN ("nossse3"),  CPU_ANY_SSSE3_FLAGS },
   { STRING_COMMA_LEN ("nosse4.1"),  CPU_ANY_SSE4_1_FLAGS },
   { STRING_COMMA_LEN ("nosse4.2"),  CPU_ANY_SSE4_2_FLAGS },
-  { STRING_COMMA_LEN ("nosse4"),  CPU_ANY_SSE4_1_FLAGS },
+  { STRING_COMMA_LEN ("nosse4"),  CPU_ANY_SSE4_FLAGS },
   { STRING_COMMA_LEN ("noavx"),  CPU_ANY_AVX_FLAGS },
   { STRING_COMMA_LEN ("noavx2"),  CPU_ANY_AVX2_FLAGS },
   { STRING_COMMA_LEN ("noavx512f"), CPU_ANY_AVX512F_FLAGS },
@@ -1839,6 +1840,8 @@ cpu_flags_and_not (i386_cpu_flags x, i386_cpu_flags y)
   return x;
 }
 
+static const i386_cpu_flags avx512 = CPU_ANY_AVX512F_FLAGS;
+
 #define CPU_FLAGS_ARCH_MATCH           0x1
 #define CPU_FLAGS_64BIT_MATCH          0x2
 
@@ -2243,8 +2246,7 @@ mismatch:
 
 /* If given types g0 and g1 are registers they must be of the same type
    unless the expected operand type register overlap is null.
-   Memory operand size of certain SIMD instructions is also being checked
-   here.  */
+   Some Intel syntax memory operand size checking also happens here.  */
 
 static INLINE int
 operand_type_register_match (i386_operand_type g0,
@@ -2256,14 +2258,16 @@ operand_type_register_match (i386_operand_type g0,
       && g0.bitfield.class != RegSIMD
       && (!operand_type_check (g0, anymem)
          || g0.bitfield.unspecified
-         || t0.bitfield.class != RegSIMD))
+         || (t0.bitfield.class != Reg
+             && t0.bitfield.class != RegSIMD)))
     return 1;
 
   if (g1.bitfield.class != Reg
       && g1.bitfield.class != RegSIMD
       && (!operand_type_check (g1, anymem)
          || g1.bitfield.unspecified
-         || t1.bitfield.class != RegSIMD))
+         || (t1.bitfield.class != Reg
+             && t1.bitfield.class != RegSIMD)))
     return 1;
 
   if (g0.bitfield.byte == g1.bitfield.byte
@@ -4082,7 +4086,6 @@ optimize_encoding (void)
              i.tm.base_opcode = 0xb8;
              i.tm.extension_opcode = None;
              i.tm.opcode_modifier.w = 0;
-             i.tm.opcode_modifier.shortform = 1;
              i.tm.opcode_modifier.modrm = 0;
            }
        }
@@ -5368,7 +5371,6 @@ check_VecOperands (const insn_template *t)
 {
   unsigned int op;
   i386_cpu_flags cpu;
-  static const i386_cpu_flags avx512 = CPU_ANY_AVX512F_FLAGS;
 
   /* Templates allowing for ZMMword as well as YMMword and/or XMMword for
      any one operand are implicity requiring AVX512VL support if the actual
@@ -5805,14 +5807,32 @@ match_template (char mnem_suffix)
       if (intel_mnemonic && t->opcode_modifier.attmnemonic)
        continue;
 
-      /* Check AT&T/Intel syntax and Intel64/AMD64 ISA.   */
+      /* Check AT&T/Intel syntax.  */
       i.error = unsupported_syntax;
       if ((intel_syntax && t->opcode_modifier.attsyntax)
-         || (!intel_syntax && t->opcode_modifier.intelsyntax)
-         || (intel64 && t->opcode_modifier.amd64)
-         || (!intel64 && t->opcode_modifier.intel64))
+         || (!intel_syntax && t->opcode_modifier.intelsyntax))
        continue;
 
+      /* Check Intel64/AMD64 ISA.   */
+      switch (isa64)
+       {
+       default:
+         /* Default: Don't accept Intel64.  */
+         if (t->opcode_modifier.isa64 == INTEL64)
+           continue;
+         break;
+       case amd64:
+         /* -mamd64: Don't accept Intel64 and Intel64 only.  */
+         if (t->opcode_modifier.isa64 >= INTEL64)
+           continue;
+         break;
+       case intel64:
+         /* -mintel64: Don't accept AMD64.  */
+         if (t->opcode_modifier.isa64 == AMD64 && flag_code == CODE_64BIT)
+           continue;
+         break;
+       }
+
       /* Check the suffix.  */
       i.error = invalid_instruction_suffix;
       if ((t->opcode_modifier.no_bsuf && suffix_check.no_bsuf)
@@ -6426,7 +6446,7 @@ process_suffix (void)
       /* Accept FLDENV et al without suffix.  */
       && (i.tm.opcode_modifier.no_ssuf || i.tm.opcode_modifier.floatmf))
     {
-      unsigned int suffixes;
+      unsigned int suffixes, evex = 0;
 
       suffixes = !i.tm.opcode_modifier.no_bsuf;
       if (!i.tm.opcode_modifier.no_wsuf)
@@ -6440,7 +6460,61 @@ process_suffix (void)
       if (flag_code == CODE_64BIT && !i.tm.opcode_modifier.no_qsuf)
        suffixes |= 1 << 5;
 
-      /* Are multiple suffixes allowed?  */
+      /* For [XYZ]MMWORD operands inspect operand sizes.  While generally
+        also suitable for AT&T syntax mode, it was requested that this be
+        restricted to just Intel syntax.  */
+      if (intel_syntax)
+       {
+         i386_cpu_flags cpu = cpu_flags_and (i.tm.cpu_flags, avx512);
+
+         if (!cpu_flags_all_zero (&cpu) && !i.broadcast)
+           {
+             unsigned int op;
+
+             for (op = 0; op < i.tm.operands; ++op)
+               {
+                 if (!cpu_arch_flags.bitfield.cpuavx512vl)
+                   {
+                     if (i.tm.operand_types[op].bitfield.ymmword)
+                       i.tm.operand_types[op].bitfield.xmmword = 0;
+                     if (i.tm.operand_types[op].bitfield.zmmword)
+                       i.tm.operand_types[op].bitfield.ymmword = 0;
+                     if (!i.tm.opcode_modifier.evex
+                         || i.tm.opcode_modifier.evex == EVEXDYN)
+                       i.tm.opcode_modifier.evex = EVEX512;
+                   }
+
+                 if (i.tm.operand_types[op].bitfield.xmmword
+                     + i.tm.operand_types[op].bitfield.ymmword
+                     + i.tm.operand_types[op].bitfield.zmmword < 2)
+                   continue;
+
+                 /* Any properly sized operand disambiguates the insn.  */
+                 if (i.types[op].bitfield.xmmword
+                     || i.types[op].bitfield.ymmword
+                     || i.types[op].bitfield.zmmword)
+                   {
+                     suffixes &= ~(7 << 6);
+                     evex = 0;
+                     break;
+                   }
+
+                 if ((i.flags[op] & Operand_Mem)
+                     && i.tm.operand_types[op].bitfield.unspecified)
+                   {
+                     if (i.tm.operand_types[op].bitfield.xmmword)
+                       suffixes |= 1 << 6;
+                     if (i.tm.operand_types[op].bitfield.ymmword)
+                       suffixes |= 1 << 7;
+                     if (i.tm.operand_types[op].bitfield.zmmword)
+                       suffixes |= 1 << 8;
+                     evex = EVEX512;
+                   }
+               }
+           }
+       }
+
+      /* Are multiple suffixes / operand sizes allowed?  */
       if (suffixes & (suffixes - 1))
        {
          if (intel_syntax
@@ -6466,6 +6540,8 @@ process_suffix (void)
 
          if (i.tm.opcode_modifier.floatmf)
            i.suffix = SHORT_MNEM_SUFFIX;
+         else if (evex)
+           i.tm.opcode_modifier.evex = evex;
          else if (flag_code == CODE_16BIT)
            i.suffix = WORD_MNEM_SUFFIX;
          else if (!i.tm.opcode_modifier.no_lsuf)
@@ -6475,6 +6551,10 @@ process_suffix (void)
        }
     }
 
+  if (!i.tm.opcode_modifier.modrm && i.reg_operands && i.tm.operands < 3)
+    i.short_form = (i.tm.operand_types[0].bitfield.class == Reg)
+                  != (i.tm.operand_types[1].bitfield.class == Reg);
+
   /* Change the opcode based on the operand size given by i.suffix.  */
   switch (i.suffix)
     {
@@ -6491,7 +6571,7 @@ process_suffix (void)
       /* It's not a byte, select word/dword operation.  */
       if (i.tm.opcode_modifier.w)
        {
-         if (i.tm.opcode_modifier.shortform)
+         if (i.short_form)
            i.tm.base_opcode |= 8;
          else
            i.tm.base_opcode |= 1;
@@ -6611,31 +6691,10 @@ check_byte_reg (void)
          && i.tm.operand_types[op].bitfield.word)
        continue;
 
-      /* crc32 doesn't generate this warning.  */
-      if (i.tm.base_opcode == 0xf20f38f0)
+      /* crc32 only wants its source operand checked here.  */
+      if (i.tm.base_opcode == 0xf20f38f0 && op)
        continue;
 
-      if ((i.types[op].bitfield.word
-          || i.types[op].bitfield.dword
-          || i.types[op].bitfield.qword)
-         && i.op[op].regs->reg_num < 4
-         /* Prohibit these changes in 64bit mode, since the lowering
-            would be more complicated.  */
-         && flag_code != CODE_64BIT)
-       {
-#if REGISTER_WARNINGS
-         if (!quiet_warnings)
-           as_warn (_("using `%s%s' instead of `%s%s' due to `%c' suffix"),
-                    register_prefix,
-                    (i.op[op].regs + (i.types[op].bitfield.word
-                                      ? REGNAM_AL - REGNAM_AX
-                                      : REGNAM_AL - REGNAM_EAX))->reg_name,
-                    register_prefix,
-                    i.op[op].regs->reg_name,
-                    i.suffix);
-#endif
-         continue;
-       }
       /* Any other register is bad.  */
       if (i.types[op].bitfield.class == Reg
          || i.types[op].bitfield.class == RegMMX
@@ -6791,29 +6850,17 @@ check_word_reg (void)
                i.suffix);
        return 0;
       }
-    /* Warn if the e or r prefix on a general reg is present.  */
-    else if ((!quiet_warnings || flag_code == CODE_64BIT)
-            && (i.types[op].bitfield.dword
+    /* Error if the e or r prefix on a general reg is present.  */
+    else if ((i.types[op].bitfield.dword
                 || i.types[op].bitfield.qword)
             && (i.tm.operand_types[op].bitfield.class == Reg
                 || i.tm.operand_types[op].bitfield.instance == Accum)
             && i.tm.operand_types[op].bitfield.word)
       {
-       /* Prohibit these changes in the 64bit mode, since the
-          lowering is more complicated.  */
-       if (flag_code == CODE_64BIT)
-         {
-           as_bad (_("incorrect register `%s%s' used with `%c' suffix"),
-                   register_prefix, i.op[op].regs->reg_name,
-                   i.suffix);
-           return 0;
-         }
-#if REGISTER_WARNINGS
-       as_warn (_("using `%s%s' instead of `%s%s' due to `%c' suffix"),
-                register_prefix,
-                (i.op[op].regs + REGNAM_AX - REGNAM_EAX)->reg_name,
-                register_prefix, i.op[op].regs->reg_name, i.suffix);
-#endif
+       as_bad (_("incorrect register `%s%s' used with `%c' suffix"),
+               register_prefix, i.op[op].regs->reg_name,
+               i.suffix);
+       return 0;
       }
   return 1;
 }
@@ -7089,7 +7136,7 @@ duplicate:
         on one of their operands, the default segment is ds.  */
       default_seg = &ds;
     }
-  else if (i.tm.opcode_modifier.shortform)
+  else if (i.short_form)
     {
       /* The register or float register operand is in operand
         0 or 1.  */
@@ -9061,13 +9108,14 @@ output_disp (fragS *insn_start_frag, offsetT insn_start_off)
                          && i.rm.regmem == 5))
                  && (i.rm.mode == 2
                      || (i.rm.mode == 0 && i.rm.regmem == 5))
+                 && !is_any_vex_encoding(&i.tm)
                  && ((i.operands == 1
                       && i.tm.base_opcode == 0xff
                       && (i.rm.reg == 2 || i.rm.reg == 4))
                      || (i.operands == 2
                          && (i.tm.base_opcode == 0x8b
                              || i.tm.base_opcode == 0x85
-                             || (i.tm.base_opcode & 0xc7) == 0x03))))
+                             || (i.tm.base_opcode & ~0x38) == 0x03))))
                {
                  if (object_64bit)
                    {
@@ -9962,7 +10010,7 @@ i386_displacement (char *disp_start, char *disp_end)
          if (t->opcode_modifier.jump
              != current_templates->start->opcode_modifier.jump)
            break;
-         if (t->opcode_modifier.intel64)
+         if ((t->opcode_modifier.isa64 >= INTEL64))
            has_intel64 = TRUE;
        }
       if (t < current_templates->end)
@@ -12524,11 +12572,11 @@ md_parse_option (int c, const char *arg)
       break;
 
     case OPTION_MAMD64:
-      intel64 = 0;
+      isa64 = amd64;
       break;
 
     case OPTION_MINTEL64:
-      intel64 = 1;
+      isa64 = intel64;
       break;
 
     case 'O':
This page took 0.030979 seconds and 4 git commands to generate.