x86: abstract out obtaining of a template's mnemonic
[binutils-gdb.git] / gas / config / tc-i386.c
index e4c4198ae0dc30c8167ac99b070becfba9ca7de1..e75586944d0d4d34ecf570d22fc62a5f003a1adf 100644 (file)
@@ -1,5 +1,5 @@
 /* tc-i386.c -- Assemble code for the Intel 80386
-   Copyright (C) 1989-2022 Free Software Foundation, Inc.
+   Copyright (C) 1989-2023 Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
@@ -237,6 +237,8 @@ enum i386_error
     unsupported_with_intel_mnemonic,
     unsupported_syntax,
     unsupported,
+    unsupported_on_arch,
+    unsupported_64bit,
     invalid_sib_address,
     invalid_vsib_address,
     invalid_vector_register_set,
@@ -298,9 +300,6 @@ struct _i386_insn
        explicit segment overrides are given.  */
     const reg_entry *seg[2];
 
-    /* Copied first memory operand string, for re-checking.  */
-    char *memop1_string;
-
     /* PREFIX holds all the given prefix opcodes (usually null).
        PREFIXES is the number of prefix opcodes.  */
     unsigned int prefixes;
@@ -965,13 +964,13 @@ static const arch_entry cpu_arch[] =
   ARCH (generic32, GENERIC32, GENERIC32, false),
   ARCH (generic64, GENERIC64, GENERIC64, false),
   ARCH (i8086, UNKNOWN, NONE, false),
-  ARCH (i186, UNKNOWN, I186, false),
-  ARCH (i286, UNKNOWN, I286, false),
-  ARCH (i386, I386, I386, false),
-  ARCH (i486, I486, I486, false),
-  ARCH (i586, PENTIUM, I586, false),
-  ARCH (i686, PENTIUMPRO, I686, false),
-  ARCH (pentium, PENTIUM, I586, false),
+  ARCH (i186, UNKNOWN, 186, false),
+  ARCH (i286, UNKNOWN, 286, false),
+  ARCH (i386, I386, 386, false),
+  ARCH (i486, I486, 486, false),
+  ARCH (i586, PENTIUM, 586, false),
+  ARCH (i686, PENTIUMPRO, 686, false),
+  ARCH (pentium, PENTIUM, 586, false),
   ARCH (pentiumpro, PENTIUMPRO, PENTIUMPRO, false),
   ARCH (pentiumii, PENTIUMPRO, P2, false),
   ARCH (pentiumiii, PENTIUMPRO, P3, false),
@@ -1002,12 +1001,12 @@ static const arch_entry cpu_arch[] =
   ARCH (btver1, BT, BTVER1, false),
   ARCH (btver2, BT, BTVER2, false),
 
-  SUBARCH (8087, 8087, ANY_X87, false),
-  SUBARCH (87, NONE, ANY_X87, false), /* Disable only!  */
+  SUBARCH (8087, 8087, ANY_8087, false),
+  SUBARCH (87, NONE, ANY_8087, false), /* Disable only!  */
   SUBARCH (287, 287, ANY_287, false),
   SUBARCH (387, 387, ANY_387, false),
   SUBARCH (687, 687, ANY_687, false),
-  SUBARCH (cmov, CMOV, ANY_CMOV, false),
+  SUBARCH (cmov, CMOV, CMOV, false),
   SUBARCH (fxsr, FXSR, ANY_FXSR, false),
   SUBARCH (mmx, MMX, ANY_MMX, false),
   SUBARCH (sse, SSE, ANY_SSE, false),
@@ -1027,41 +1026,42 @@ static const arch_entry cpu_arch[] =
   SUBARCH (avx512dq, AVX512DQ, ANY_AVX512DQ, false),
   SUBARCH (avx512bw, AVX512BW, ANY_AVX512BW, false),
   SUBARCH (avx512vl, AVX512VL, ANY_AVX512VL, false),
-  SUBARCH (vmx, VMX, VMX, false),
-  SUBARCH (vmfunc, VMFUNC, VMFUNC, false),
+  SUBARCH (vmx, VMX, ANY_VMX, false),
+  SUBARCH (vmfunc, VMFUNC, ANY_VMFUNC, false),
   SUBARCH (smx, SMX, SMX, false),
-  SUBARCH (xsave, XSAVE, XSAVE, false),
-  SUBARCH (xsaveopt, XSAVEOPT, XSAVEOPT, false),
-  SUBARCH (xsavec, XSAVEC, XSAVEC, false),
-  SUBARCH (xsaves, XSAVES, XSAVES, false),
-  SUBARCH (aes, AES, AES, false),
-  SUBARCH (pclmul, PCLMUL, PCLMUL, false),
-  SUBARCH (clmul, PCLMUL, PCLMUL, true),
+  SUBARCH (xsave, XSAVE, ANY_XSAVE, false),
+  SUBARCH (xsaveopt, XSAVEOPT, ANY_XSAVEOPT, false),
+  SUBARCH (xsavec, XSAVEC, ANY_XSAVEC, false),
+  SUBARCH (xsaves, XSAVES, ANY_XSAVES, false),
+  SUBARCH (aes, AES, ANY_AES, false),
+  SUBARCH (pclmul, PCLMUL, ANY_PCLMUL, false),
+  SUBARCH (clmul, PCLMUL, ANY_PCLMUL, true),
   SUBARCH (fsgsbase, FSGSBASE, FSGSBASE, false),
   SUBARCH (rdrnd, RDRND, RDRND, false),
-  SUBARCH (f16c, F16C, F16C, false),
+  SUBARCH (f16c, F16C, ANY_F16C, false),
   SUBARCH (bmi2, BMI2, BMI2, false),
-  SUBARCH (fma, FMA, FMA, false),
-  SUBARCH (fma4, FMA4, FMA4, false),
-  SUBARCH (xop, XOP, XOP, false),
-  SUBARCH (lwp, LWP, LWP, false),
+  SUBARCH (fma, FMA, ANY_FMA, false),
+  SUBARCH (fma4, FMA4, ANY_FMA4, false),
+  SUBARCH (xop, XOP, ANY_XOP, false),
+  SUBARCH (lwp, LWP, ANY_LWP, false),
   SUBARCH (movbe, MOVBE, MOVBE, false),
   SUBARCH (cx16, CX16, CX16, false),
-  SUBARCH (ept, EPT, EPT, false),
+  SUBARCH (ept, EPT, ANY_EPT, false),
   SUBARCH (lzcnt, LZCNT, LZCNT, false),
   SUBARCH (popcnt, POPCNT, POPCNT, false),
   SUBARCH (hle, HLE, HLE, false),
-  SUBARCH (rtm, RTM, RTM, false),
+  SUBARCH (rtm, RTM, ANY_RTM, false),
+  SUBARCH (tsx, TSX, TSX, false),
   SUBARCH (invpcid, INVPCID, INVPCID, false),
   SUBARCH (clflush, CLFLUSH, CLFLUSH, false),
   SUBARCH (nop, NOP, NOP, false),
   SUBARCH (syscall, SYSCALL, SYSCALL, false),
   SUBARCH (rdtscp, RDTSCP, RDTSCP, false),
-  SUBARCH (3dnow, 3DNOW, 3DNOW, false),
-  SUBARCH (3dnowa, 3DNOWA, 3DNOWA, false),
+  SUBARCH (3dnow, 3DNOW, ANY_3DNOW, false),
+  SUBARCH (3dnowa, 3DNOWA, ANY_3DNOWA, false),
   SUBARCH (padlock, PADLOCK, PADLOCK, false),
-  SUBARCH (pacifica, SVME, SVME, true),
-  SUBARCH (svme, SVME, SVME, false),
+  SUBARCH (pacifica, SVME, ANY_SVME, true),
+  SUBARCH (svme, SVME, ANY_SVME, false),
   SUBARCH (abm, ABM, ABM, false),
   SUBARCH (bmi, BMI, BMI, false),
   SUBARCH (tbm, TBM, TBM, false),
@@ -1069,8 +1069,8 @@ static const arch_entry cpu_arch[] =
   SUBARCH (rdseed, RDSEED, RDSEED, false),
   SUBARCH (prfchw, PRFCHW, PRFCHW, false),
   SUBARCH (smap, SMAP, SMAP, false),
-  SUBARCH (mpx, MPX, MPX, false),
-  SUBARCH (sha, SHA, SHA, false),
+  SUBARCH (mpx, MPX, ANY_MPX, false),
+  SUBARCH (sha, SHA, ANY_SHA, false),
   SUBARCH (clflushopt, CLFLUSHOPT, CLFLUSHOPT, false),
   SUBARCH (prefetchwt1, PREFETCHWT1, PREFETCHWT1, false),
   SUBARCH (se1, SE1, SE1, false),
@@ -1086,48 +1086,48 @@ static const arch_entry cpu_arch[] =
   SUBARCH (avx_vnni, AVX_VNNI, ANY_AVX_VNNI, false),
   SUBARCH (clzero, CLZERO, CLZERO, false),
   SUBARCH (mwaitx, MWAITX, MWAITX, false),
-  SUBARCH (ospke, OSPKE, OSPKE, false),
+  SUBARCH (ospke, OSPKE, ANY_OSPKE, false),
   SUBARCH (rdpid, RDPID, RDPID, false),
   SUBARCH (ptwrite, PTWRITE, PTWRITE, false),
-  SUBARCH (ibt, IBT, ANY_IBT, false),
-  SUBARCH (shstk, SHSTK, ANY_SHSTK, false),
-  SUBARCH (gfni, GFNI, GFNI, false),
-  SUBARCH (vaes, VAES, VAES, false),
-  SUBARCH (vpclmulqdq, VPCLMULQDQ, VPCLMULQDQ, false),
+  SUBARCH (ibt, IBT, IBT, false),
+  SUBARCH (shstk, SHSTK, SHSTK, false),
+  SUBARCH (gfni, GFNI, ANY_GFNI, false),
+  SUBARCH (vaes, VAES, ANY_VAES, false),
+  SUBARCH (vpclmulqdq, VPCLMULQDQ, ANY_VPCLMULQDQ, false),
   SUBARCH (wbnoinvd, WBNOINVD, WBNOINVD, false),
   SUBARCH (pconfig, PCONFIG, PCONFIG, false),
   SUBARCH (waitpkg, WAITPKG, WAITPKG, false),
   SUBARCH (cldemote, CLDEMOTE, CLDEMOTE, false),
   SUBARCH (amx_int8, AMX_INT8, ANY_AMX_INT8, false),
   SUBARCH (amx_bf16, AMX_BF16, ANY_AMX_BF16, false),
-  SUBARCH (amx_fp16, AMX_FP16, AMX_FP16, false),
+  SUBARCH (amx_fp16, AMX_FP16, ANY_AMX_FP16, false),
   SUBARCH (amx_tile, AMX_TILE, ANY_AMX_TILE, false),
-  SUBARCH (movdiri, MOVDIRI, ANY_MOVDIRI, false),
-  SUBARCH (movdir64b, MOVDIR64B, ANY_MOVDIR64B, false),
+  SUBARCH (movdiri, MOVDIRI, MOVDIRI, false),
+  SUBARCH (movdir64b, MOVDIR64B, MOVDIR64B, false),
   SUBARCH (avx512_bf16, AVX512_BF16, ANY_AVX512_BF16, false),
   SUBARCH (avx512_vp2intersect, AVX512_VP2INTERSECT,
           ANY_AVX512_VP2INTERSECT, false),
-  SUBARCH (tdx, TDX, ANY_TDX, false),
-  SUBARCH (enqcmd, ENQCMD, ANY_ENQCMD, false),
-  SUBARCH (serialize, SERIALIZE, ANY_SERIALIZE, false),
+  SUBARCH (tdx, TDX, TDX, false),
+  SUBARCH (enqcmd, ENQCMD, ENQCMD, false),
+  SUBARCH (serialize, SERIALIZE, SERIALIZE, false),
   SUBARCH (rdpru, RDPRU, RDPRU, false),
   SUBARCH (mcommit, MCOMMIT, MCOMMIT, false),
-  SUBARCH (sev_es, SEV_ES, SEV_ES, false),
+  SUBARCH (sev_es, SEV_ES, ANY_SEV_ES, false),
   SUBARCH (tsxldtrk, TSXLDTRK, ANY_TSXLDTRK, false),
   SUBARCH (kl, KL, ANY_KL, false),
   SUBARCH (widekl, WIDEKL, ANY_WIDEKL, false),
-  SUBARCH (uintr, UINTR, ANY_UINTR, false),
-  SUBARCH (hreset, HRESET, ANY_HRESET, false),
+  SUBARCH (uintr, UINTR, UINTR, false),
+  SUBARCH (hreset, HRESET, HRESET, false),
   SUBARCH (avx512_fp16, AVX512_FP16, ANY_AVX512_FP16, false),
   SUBARCH (prefetchi, PREFETCHI, PREFETCHI, false),
   SUBARCH (avx_ifma, AVX_IFMA, ANY_AVX_IFMA, false),
   SUBARCH (avx_vnni_int8, AVX_VNNI_INT8, ANY_AVX_VNNI_INT8, false),
-  SUBARCH (cmpccxadd, CMPCCXADD, ANY_CMPCCXADD, false),
-  SUBARCH (wrmsrns, WRMSRNS, ANY_WRMSRNS, false),
-  SUBARCH (msrlist, MSRLIST, ANY_MSRLIST, false),
+  SUBARCH (cmpccxadd, CMPCCXADD, CMPCCXADD, false),
+  SUBARCH (wrmsrns, WRMSRNS, WRMSRNS, false),
+  SUBARCH (msrlist, MSRLIST, MSRLIST, false),
   SUBARCH (avx_ne_convert, AVX_NE_CONVERT, ANY_AVX_NE_CONVERT, false),
-  SUBARCH (rao_int, RAO_INT, ANY_RAO_INT, false),
-  SUBARCH (rmpquery, RMPQUERY, RMPQUERY, false),
+  SUBARCH (rao_int, RAO_INT, RAO_INT, false),
+  SUBARCH (rmpquery, RMPQUERY, ANY_RMPQUERY, false),
 };
 
 #undef SUBARCH
@@ -2016,7 +2016,15 @@ match_operand_size (const insn_template *t, unsigned int wanted,
           || (i.types[given].bitfield.dword
               && !t->operand_types[wanted].bitfield.dword)
           || (i.types[given].bitfield.qword
-              && !t->operand_types[wanted].bitfield.qword)
+              && (!t->operand_types[wanted].bitfield.qword
+                  /* Don't allow 64-bit (memory) operands outside of 64-bit
+                     mode, when they're used where a 64-bit GPR could also
+                     be used.  Checking is needed for Intel Syntax only.  */
+                  || (intel_syntax
+                      && flag_code != CODE_64BIT
+                      && (t->operand_types[wanted].bitfield.class == Reg
+                          || t->operand_types[wanted].bitfield.class == Accum
+                          || t->opcode_modifier.isstring))))
           || (i.types[given].bitfield.tbyte
               && !t->operand_types[wanted].bitfield.tbyte));
 }
@@ -2418,6 +2426,11 @@ offset_in_range (offsetT val, int size)
   return val & mask;
 }
 
+static INLINE const char *insn_name (const insn_template *t)
+{
+  return t->name;
+}
+
 enum PREFIX_GROUP
 {
   PREFIX_EXIST = 0,
@@ -2978,11 +2991,11 @@ md_begin (void)
 
     /* Type checks to compensate for the conversion through void * which
        occurs during hash table insertion / lookup.  */
-    (void)(sets == &current_templates->start);
-    (void)(end == &current_templates->end);
+    (void) sizeof (sets == &current_templates->start);
+    (void) sizeof (end == &current_templates->end);
     for (; sets < end; ++sets)
-      if (str_hash_insert (op_hash, (*sets)->name, sets, 0))
-       as_fatal (_("duplicate %s"), (*sets)->name);
+      if (str_hash_insert (op_hash, insn_name (*sets), sets, 0))
+       as_fatal (_("duplicate %s"), insn_name (*sets));
   }
 
   /* Initialize reg_hash hash table.  */
@@ -3801,7 +3814,7 @@ get_broadcast_bytes (const insn_template *t, bool diag)
 
   if (diag)
     as_warn (_("ambiguous broadcast for `%s', using %u-bit form"),
-            t->name, bytes * 8);
+            insn_name (t), bytes * 8);
 
   return bytes;
 }
@@ -4022,7 +4035,7 @@ check_hle (void)
     case PrefixNoTrack:
     case PrefixRep:
       as_bad (_("invalid instruction `%s' after `%s'"),
-             i.tm.name, i.hle_prefix);
+             insn_name (&i.tm), i.hle_prefix);
       return 0;
     case PrefixHLELock:
       if (i.prefix[LOCK_PREFIX])
@@ -4035,13 +4048,13 @@ check_hle (void)
       if (i.prefix[HLE_PREFIX] != XRELEASE_PREFIX_OPCODE)
        {
          as_bad (_("instruction `%s' after `xacquire' not allowed"),
-                 i.tm.name);
+                 insn_name (&i.tm));
          return 0;
        }
       if (i.mem_operands == 0 || !(i.flags[i.operands - 1] & Operand_Mem))
        {
          as_bad (_("memory destination needed for instruction `%s'"
-                   " after `xrelease'"), i.tm.name);
+                   " after `xrelease'"), insn_name (&i.tm));
          return 0;
        }
       return 1;
@@ -4299,7 +4312,20 @@ optimize_encoding (void)
           movq $imm31, %r64   -> movl $imm31, %r32
           movq $imm32, %r64   -> movl $imm32, %r32
         */
-      i.tm.opcode_modifier.norex64 = 1;
+      i.tm.opcode_modifier.size = SIZE32;
+      if (i.imm_operands)
+       {
+         i.types[0].bitfield.imm32 = 1;
+         i.types[0].bitfield.imm32s = 0;
+         i.types[0].bitfield.imm64 = 0;
+       }
+      else
+       {
+         i.types[0].bitfield.dword = 1;
+         i.types[0].bitfield.qword = 0;
+       }
+      i.types[1].bitfield.dword = 1;
+      i.types[1].bitfield.qword = 0;
       if (i.tm.base_opcode == 0xb8 || (i.tm.base_opcode | 1) == 0xc7)
        {
          /* Handle
@@ -4309,11 +4335,6 @@ optimize_encoding (void)
          i.tm.operand_types[0].bitfield.imm32 = 1;
          i.tm.operand_types[0].bitfield.imm32s = 0;
          i.tm.operand_types[0].bitfield.imm64 = 0;
-         i.types[0].bitfield.imm32 = 1;
-         i.types[0].bitfield.imm32s = 0;
-         i.types[0].bitfield.imm64 = 0;
-         i.types[1].bitfield.dword = 1;
-         i.types[1].bitfield.qword = 0;
          if ((i.tm.base_opcode | 1) == 0xc7)
            {
              /* Handle
@@ -4528,7 +4549,7 @@ load_insn_p (void)
        return 0;
 
       /* pop.   */
-      if (strcmp (i.tm.name, "pop") == 0)
+      if (strcmp (insn_name (&i.tm), "pop") == 0)
        return 1;
     }
 
@@ -4707,7 +4728,7 @@ insert_lfence_after (void)
          && i.prefix[REP_PREFIX])
        {
            as_warn (_("`%s` changes flags which would affect control flow behavior"),
-                    i.tm.name);
+                    insn_name (&i.tm));
        }
       char *p = frag_more (3);
       *p++ = 0xf;
@@ -4749,7 +4770,7 @@ insert_lfence_before (void)
               && lfence_before_indirect_branch != lfence_branch_register)
        {
          as_warn (_("indirect `%s` with memory operand should be avoided"),
-                  i.tm.name);
+                  insn_name (&i.tm));
          return;
        }
       else
@@ -4760,7 +4781,7 @@ insert_lfence_before (void)
        {
          as_warn_where (last_insn.file, last_insn.line,
                         _("`%s` skips -mlfence-before-indirect-branch on `%s`"),
-                        last_insn.name, i.tm.name);
+                        last_insn.name, insn_name (&i.tm));
          return;
        }
 
@@ -4781,7 +4802,7 @@ insert_lfence_before (void)
        {
          as_warn_where (last_insn.file, last_insn.line,
                         _("`%s` skips -mlfence-before-ret on `%s`"),
-                        last_insn.name, i.tm.name);
+                        last_insn.name, insn_name (&i.tm));
          return;
        }
 
@@ -4836,6 +4857,22 @@ insert_lfence_before (void)
     }
 }
 
+/* Helper for md_assemble() to decide whether to prepare for a possible 2nd
+   parsing pass. Instead of introducing a rarely use new insn attribute this
+   utilizes a common pattern between affected templates. It is deemed
+   acceptable that this will lead to unnecessary pass 2 preparations in a
+   limited set of cases.  */
+static INLINE bool may_need_pass2 (const insn_template *t)
+{
+  return t->opcode_modifier.sse2avx
+        /* Note that all SSE2AVX templates have at least one operand.  */
+        ? t->operand_types[t->operands - 1].bitfield.class == RegSIMD
+        : (t->opcode_modifier.opcodespace == SPACE_0F
+           && (t->base_opcode | 1) == 0xbf)
+          || (t->opcode_modifier.opcodespace == SPACE_BASE
+              && t->base_opcode == 0x63);
+}
+
 /* This is the guts of the machine-dependent assembler.  LINE points to a
    machine dependent instruction.  This function is supposed to emit
    the frags/bytes it assembles to.  */
@@ -4844,11 +4881,14 @@ void
 md_assemble (char *line)
 {
   unsigned int j;
-  char mnemonic[MAX_MNEM_SIZE], mnem_suffix;
-  const char *end;
+  char mnemonic[MAX_MNEM_SIZE], mnem_suffix = 0, *copy = NULL;
+  const char *end, *pass1_mnem = NULL;
+  enum i386_error pass1_err = 0;
   const insn_template *t;
 
   /* Initialize globals.  */
+  current_templates = NULL;
+ retry:
   memset (&i, '\0', sizeof (i));
   i.rounding.type = rc_none;
   for (j = 0; j < MAX_OPERANDS; j++)
@@ -4863,16 +4903,36 @@ md_assemble (char *line)
 
   end = parse_insn (line, mnemonic);
   if (end == NULL)
-    return;
+    {
+      if (pass1_mnem != NULL)
+       goto match_error;
+      if (i.error != no_error)
+       {
+         gas_assert (current_templates != NULL);
+         if (may_need_pass2 (current_templates->start) && !i.suffix)
+           goto no_match;
+         /* No point in trying a 2nd pass - it'll only find the same suffix
+            again.  */
+         mnem_suffix = i.suffix;
+         goto match_error;
+       }
+      return;
+    }
+  if (may_need_pass2 (current_templates->start))
+    {
+      /* Make a copy of the full line in case we need to retry.  */
+      copy = xstrdup (line);
+    }
   line += end - line;
   mnem_suffix = i.suffix;
 
   line = parse_operands (line, mnemonic);
   this_operand = -1;
-  xfree (i.memop1_string);
-  i.memop1_string = NULL;
   if (line == NULL)
-    return;
+    {
+      free (copy);
+      return;
+    }
 
   /* Now we've parsed the mnemonic into a set of templates, and have the
      operands at hand.  */
@@ -4950,7 +5010,134 @@ md_assemble (char *line)
      with the template operand types.  */
 
   if (!(t = match_template (mnem_suffix)))
-    return;
+    {
+      const char *err_msg;
+
+      if (copy && !mnem_suffix)
+       {
+         line = copy;
+         copy = NULL;
+  no_match:
+         pass1_err = i.error;
+         pass1_mnem = insn_name (current_templates->start);
+         goto retry;
+       }
+
+      /* If a non-/only-64bit template (group) was found in pass 1, and if
+        _some_ template (group) was found in pass 2, squash pass 1's
+        error.  */
+      if (pass1_err == unsupported_64bit)
+       pass1_mnem = NULL;
+
+  match_error:
+      free (copy);
+
+      switch (pass1_mnem ? pass1_err : i.error)
+       {
+       default:
+         abort ();
+       case operand_size_mismatch:
+         err_msg = _("operand size mismatch");
+         break;
+       case operand_type_mismatch:
+         err_msg = _("operand type mismatch");
+         break;
+       case register_type_mismatch:
+         err_msg = _("register type mismatch");
+         break;
+       case number_of_operands_mismatch:
+         err_msg = _("number of operands mismatch");
+         break;
+       case invalid_instruction_suffix:
+         err_msg = _("invalid instruction suffix");
+         break;
+       case bad_imm4:
+         err_msg = _("constant doesn't fit in 4 bits");
+         break;
+       case unsupported_with_intel_mnemonic:
+         err_msg = _("unsupported with Intel mnemonic");
+         break;
+       case unsupported_syntax:
+         err_msg = _("unsupported syntax");
+         break;
+       case unsupported:
+         as_bad (_("unsupported instruction `%s'"),
+                 pass1_mnem ? pass1_mnem : insn_name (current_templates->start));
+         return;
+       case unsupported_on_arch:
+         as_bad (_("`%s' is not supported on `%s%s'"),
+                 pass1_mnem ? pass1_mnem : insn_name (current_templates->start),
+                 cpu_arch_name ? cpu_arch_name : default_arch,
+                 cpu_sub_arch_name ? cpu_sub_arch_name : "");
+         return;
+       case unsupported_64bit:
+         if (ISLOWER (mnem_suffix))
+           {
+             if (flag_code == CODE_64BIT)
+               as_bad (_("`%s%c' is not supported in 64-bit mode"),
+                       pass1_mnem ? pass1_mnem : insn_name (current_templates->start),
+                       mnem_suffix);
+             else
+               as_bad (_("`%s%c' is only supported in 64-bit mode"),
+                       pass1_mnem ? pass1_mnem : insn_name (current_templates->start),
+                       mnem_suffix);
+           }
+         else
+           {
+             if (flag_code == CODE_64BIT)
+               as_bad (_("`%s' is not supported in 64-bit mode"),
+                       pass1_mnem ? pass1_mnem : insn_name (current_templates->start));
+             else
+               as_bad (_("`%s' is only supported in 64-bit mode"),
+                       pass1_mnem ? pass1_mnem : insn_name (current_templates->start));
+           }
+         return;
+       case invalid_sib_address:
+         err_msg = _("invalid SIB address");
+         break;
+       case invalid_vsib_address:
+         err_msg = _("invalid VSIB address");
+         break;
+       case invalid_vector_register_set:
+         err_msg = _("mask, index, and destination registers must be distinct");
+         break;
+       case invalid_tmm_register_set:
+         err_msg = _("all tmm registers must be distinct");
+         break;
+       case invalid_dest_and_src_register_set:
+         err_msg = _("destination and source registers must be distinct");
+         break;
+       case unsupported_vector_index_register:
+         err_msg = _("unsupported vector index register");
+         break;
+       case unsupported_broadcast:
+         err_msg = _("unsupported broadcast");
+         break;
+       case broadcast_needed:
+         err_msg = _("broadcast is needed for operand of such type");
+         break;
+       case unsupported_masking:
+         err_msg = _("unsupported masking");
+         break;
+       case mask_not_on_destination:
+         err_msg = _("mask not on destination operand");
+         break;
+       case no_default_mask:
+         err_msg = _("default mask isn't allowed");
+         break;
+       case unsupported_rc_sae:
+         err_msg = _("unsupported static rounding/sae");
+         break;
+       case invalid_register_operand:
+         err_msg = _("invalid register operand");
+         break;
+       }
+      as_bad (_("%s for `%s'"), err_msg,
+             pass1_mnem ? pass1_mnem : insn_name (current_templates->start));
+      return;
+    }
+
+  free (copy);
 
   if (sse_check != check_none
       /* The opcode space check isn't strictly needed; it's there only to
@@ -4973,7 +5160,7 @@ md_assemble (char *line)
       if (j >= t->operands && simd)
        (sse_check == check_warning
         ? as_warn
-        : as_bad) (_("SSE instruction `%s' is used"), i.tm.name);
+        : as_bad) (_("SSE instruction `%s' is used"), insn_name (&i.tm));
     }
 
   if (i.tm.opcode_modifier.fwait)
@@ -4984,7 +5171,7 @@ md_assemble (char *line)
   if (i.rep_prefix && i.tm.opcode_modifier.prefixok != PrefixRep)
     {
       as_bad (_("invalid instruction `%s' after `%s'"),
-               i.tm.name, i.rep_prefix);
+               insn_name (&i.tm), i.rep_prefix);
       return;
     }
 
@@ -5000,14 +5187,30 @@ md_assemble (char *line)
       return;
     }
 
-  /* Check for data size prefix on VEX/XOP/EVEX encoded and SIMD insns.  */
-  if (i.prefix[DATA_PREFIX]
-      && (is_any_vex_encoding (&i.tm)
-         || i.tm.operand_types[i.imm_operands].bitfield.class >= RegMMX
-         || i.tm.operand_types[i.imm_operands + 1].bitfield.class >= RegMMX))
+  if (is_any_vex_encoding (&i.tm)
+      || i.tm.operand_types[i.imm_operands].bitfield.class >= RegMMX
+      || i.tm.operand_types[i.imm_operands + 1].bitfield.class >= RegMMX)
     {
-      as_bad (_("data size prefix invalid with `%s'"), i.tm.name);
-      return;
+      /* Check for data size prefix on VEX/XOP/EVEX encoded and SIMD insns.  */
+      if (i.prefix[DATA_PREFIX])
+       {
+         as_bad (_("data size prefix invalid with `%s'"), insn_name (&i.tm));
+         return;
+       }
+
+      /* Don't allow e.g. KMOV in TLS code sequences.  */
+      for (j = i.imm_operands; j < i.operands; ++j)
+       switch (i.reloc[j])
+         {
+         case BFD_RELOC_386_TLS_GOTIE:
+         case BFD_RELOC_386_TLS_LE_32:
+         case BFD_RELOC_X86_64_GOTTPOFF:
+         case BFD_RELOC_X86_64_TLSLD:
+           as_bad (_("TLS relocation cannot be used with `%s'"), insn_name (&i.tm));
+           return;
+         default:
+           break;
+         }
     }
 
   /* Check if HLE prefix is OK.  */
@@ -5060,7 +5263,7 @@ md_assemble (char *line)
          || i.tm.opcode_modifier.opcodespace != SPACE_BASE))
     {
       as_bad (_("input/output port address isn't allowed with `%s'"),
-             i.tm.name);
+             insn_name (&i.tm));
       return;
     }
 
@@ -5076,7 +5279,7 @@ md_assemble (char *line)
   /* Check if IP-relative addressing requirements can be satisfied.  */
   if (i.tm.cpu_flags.bitfield.cpuprefetchi
       && !(i.base_reg && i.base_reg->reg_num == RegIP))
-    as_warn (_("'%s' only supports RIP-relative address"), i.tm.name);
+    as_warn (_("'%s' only supports RIP-relative address"), insn_name (&i.tm));
 
   /* Update operand types and check extended states.  */
   for (j = 0; j < i.operands; j++)
@@ -5130,7 +5333,7 @@ md_assemble (char *line)
   else if (!quiet_warnings && i.tm.opcode_modifier.operandconstraint == UGH)
     {
       /* UnixWare fsub no args is alias for fsubp, fadd -> faddp, etc.  */
-      as_warn (_("translating to `%sp'"), i.tm.name);
+      as_warn (_("translating to `%sp'"), insn_name (&i.tm));
     }
 
   if (is_any_vex_encoding (&i.tm))
@@ -5138,14 +5341,14 @@ md_assemble (char *line)
       if (!cpu_arch_flags.bitfield.cpui286)
        {
          as_bad (_("instruction `%s' isn't supported outside of protected mode."),
-                 i.tm.name);
+                 insn_name (&i.tm));
          return;
        }
 
       /* Check for explicit REX prefix.  */
       if (i.prefix[REX_PREFIX] || i.rex_encoding)
        {
-         as_bad (_("REX prefix invalid with `%s'"), i.tm.name);
+         as_bad (_("REX prefix invalid with `%s'"), insn_name (&i.tm));
          return;
        }
 
@@ -5255,18 +5458,36 @@ md_assemble (char *line)
   if (i.tm.opcode_modifier.isprefix)
     {
       last_insn.kind = last_insn_prefix;
-      last_insn.name = i.tm.name;
+      last_insn.name = insn_name (&i.tm);
       last_insn.file = as_where (&last_insn.line);
     }
   else
     last_insn.kind = last_insn_other;
 }
 
+/* The Q suffix is generally valid only in 64-bit mode, with very few
+   exceptions: fild, fistp, fisttp, and cmpxchg8b.  Note that for fild
+   and fisttp only one of their two templates is matched below: That's
+   sufficient since other relevant attributes are the same between both
+   respective templates.  */
+static INLINE bool q_suffix_allowed(const insn_template *t)
+{
+  return flag_code == CODE_64BIT
+        || (t->opcode_modifier.opcodespace == SPACE_BASE
+            && t->base_opcode == 0xdf
+            && (t->extension_opcode & 1)) /* fild / fistp / fisttp */
+        || (t->opcode_modifier.opcodespace == SPACE_0F
+            && t->base_opcode == 0xc7
+            && t->opcode_modifier.opcodeprefix == PREFIX_NONE
+            && t->extension_opcode == 1) /* cmpxchg8b */;
+}
+
 static const char *
 parse_insn (const char *line, char *mnemonic)
 {
   const char *l = line, *token_start = l;
   char *mnem_p;
+  bool pass1 = !current_templates;
   int supported;
   const insn_template *t;
   char *dot_p = NULL;
@@ -5318,7 +5539,7 @@ parse_insn (const char *line, char *mnemonic)
              as_bad ((flag_code != CODE_64BIT
                       ? _("`%s' is only supported in 64-bit mode")
                       : _("`%s' is not supported in 64-bit mode")),
-                     current_templates->start->name);
+                     insn_name (current_templates->start));
              return NULL;
            }
          /* If we are in 16-bit mode, do not allow addr16 or data16.
@@ -5330,7 +5551,7 @@ parse_insn (const char *line, char *mnemonic)
                  ^ (flag_code == CODE_16BIT)))
            {
              as_bad (_("redundant %s prefix"),
-                     current_templates->start->name);
+                     insn_name (current_templates->start));
              return NULL;
            }
 
@@ -5392,15 +5613,15 @@ parse_insn (const char *line, char *mnemonic)
                  return NULL;
                case PREFIX_DS:
                  if (current_templates->start->cpu_flags.bitfield.cpuibt)
-                   i.notrack_prefix = current_templates->start->name;
+                   i.notrack_prefix = insn_name (current_templates->start);
                  break;
                case PREFIX_REP:
                  if (current_templates->start->cpu_flags.bitfield.cpuhle)
-                   i.hle_prefix = current_templates->start->name;
+                   i.hle_prefix = insn_name (current_templates->start);
                  else if (current_templates->start->cpu_flags.bitfield.cpumpx)
-                   i.bnd_prefix = current_templates->start->name;
+                   i.bnd_prefix = insn_name (current_templates->start);
                  else
-                   i.rep_prefix = current_templates->start->name;
+                   i.rep_prefix = insn_name (current_templates->start);
                  break;
                default:
                  break;
@@ -5436,8 +5657,10 @@ parse_insn (const char *line, char *mnemonic)
       current_templates = (const templates *) str_hash_find (op_hash, mnemonic);
     }
 
-  if (!current_templates)
+  if (!current_templates || !pass1)
     {
+      current_templates = NULL;
+
     check_suffix:
       if (mnem_p > mnemonic)
        {
@@ -5479,13 +5702,39 @@ parse_insn (const char *line, char *mnemonic)
                  current_templates
                    = (const templates *) str_hash_find (op_hash, mnemonic);
                }
+             /* For compatibility reasons accept MOVSD and CMPSD without
+                operands even in AT&T mode.  */
+             else if (*l == END_OF_INSN
+                      || (is_space_char (*l) && l[1] == END_OF_INSN))
+               {
+                 mnem_p[-1] = '\0';
+                 current_templates
+                   = (const templates *) str_hash_find (op_hash, mnemonic);
+                 if (current_templates != NULL
+                     /* MOVS or CMPS */
+                     && (current_templates->start->base_opcode | 2) == 0xa6
+                     && current_templates->start->opcode_modifier.opcodespace
+                        == SPACE_BASE
+                     && mnem_p[-2] == 's')
+                   {
+                     as_warn (_("found `%sd'; assuming `%sl' was meant"),
+                              mnemonic, mnemonic);
+                     i.suffix = LONG_MNEM_SUFFIX;
+                   }
+                 else
+                   {
+                     current_templates = NULL;
+                     mnem_p[-1] = 'd';
+                   }
+               }
              break;
            }
        }
 
       if (!current_templates)
        {
-         as_bad (_("no such instruction: `%s'"), token_start);
+         if (pass1)
+           as_bad (_("no such instruction: `%s'"), token_start);
          return NULL;
        }
     }
@@ -5528,20 +5777,21 @@ parse_insn (const char *line, char *mnemonic)
   for (t = current_templates->start; t < current_templates->end; ++t)
     {
       supported |= cpu_flags_match (t);
+
+      if (i.suffix == QWORD_MNEM_SUFFIX && !q_suffix_allowed (t))
+       supported &= ~CPU_FLAGS_64BIT_MATCH;
+
       if (supported == CPU_FLAGS_PERFECT_MATCH)
        return l;
     }
 
-  if (!(supported & CPU_FLAGS_64BIT_MATCH))
-    as_bad (flag_code == CODE_64BIT
-           ? _("`%s' is not supported in 64-bit mode")
-           : _("`%s' is only supported in 64-bit mode"),
-           current_templates->start->name);
-  else
-    as_bad (_("`%s' is not supported on `%s%s'"),
-           current_templates->start->name,
-           cpu_arch_name ? cpu_arch_name : default_arch,
-           cpu_sub_arch_name ? cpu_sub_arch_name : "");
+  if (pass1)
+    {
+      if (supported & CPU_FLAGS_64BIT_MATCH)
+        i.error = unsupported_on_arch;
+      else
+        i.error = unsupported_64bit;
+    }
 
   return NULL;
 }
@@ -6198,7 +6448,7 @@ check_VecOperands (const insn_template *t)
       if (operand_type_all_zero (&overlap))
          goto bad_broadcast;
 
-      if (t->opcode_modifier.checkregsize)
+      if (t->opcode_modifier.checkoperandsize)
        {
          unsigned int j;
 
@@ -6538,24 +6788,16 @@ match_template (char mnem_suffix)
       for (j = 0; j < MAX_OPERANDS; j++)
        operand_types[j] = t->operand_types[j];
 
-      /* In general, don't allow
-        - 64-bit operands outside of 64-bit mode,
-        - 32-bit operands on pre-386.  */
+      /* In general, don't allow 32-bit operands on pre-386.  */
       specific_error = progress (mnem_suffix ? invalid_instruction_suffix
                                             : operand_size_mismatch);
       j = i.imm_operands + (t->operands > i.imm_operands + 1);
-      if (((i.suffix == QWORD_MNEM_SUFFIX
-           && flag_code != CODE_64BIT
-           && !(t->opcode_modifier.opcodespace == SPACE_0F
-                && t->base_opcode == 0xc7
-                && t->opcode_modifier.opcodeprefix == PREFIX_NONE
-                && t->extension_opcode == 1) /* cmpxchg8b */)
-          || (i.suffix == LONG_MNEM_SUFFIX
-              && !cpu_arch_flags.bitfield.cpui386))
+      if (i.suffix == LONG_MNEM_SUFFIX
+         && !cpu_arch_flags.bitfield.cpui386
          && (intel_syntax
              ? (t->opcode_modifier.mnemonicsize != IGNORESIZE
-                && !intel_float_operand (t->name))
-             : intel_float_operand (t->name) != 2)
+                && !intel_float_operand (insn_name (t)))
+             : intel_float_operand (insn_name (t)) != 2)
          && (t->operands == i.imm_operands
              || (operand_types[i.imm_operands].bitfield.class != RegMMX
               && operand_types[i.imm_operands].bitfield.class != RegSIMD
@@ -6622,28 +6864,8 @@ match_template (char mnem_suffix)
            }
        }
 
-      switch (i.reloc[0])
-       {
-       case BFD_RELOC_386_GOT32:
-         /* Force 0x8b encoding for "mov foo@GOT, %eax".  */
-         if (t->base_opcode == 0xa0
-             && t->opcode_modifier.opcodespace == SPACE_BASE)
-           continue;
-         break;
-       case BFD_RELOC_386_TLS_GOTIE:
-       case BFD_RELOC_386_TLS_LE_32:
-       case BFD_RELOC_X86_64_GOTTPOFF:
-       case BFD_RELOC_X86_64_TLSLD:
-         /* Don't allow KMOV in TLS code sequences.  */
-         if (t->opcode_modifier.vex)
-           continue;
-         break;
-       default:
-         break;
-       }
-
       /* We check register size if needed.  */
-      if (t->opcode_modifier.checkregsize)
+      if (t->opcode_modifier.checkoperandsize)
        {
          check_register = (1 << t->operands) - 1;
          if (i.broadcast.type || i.broadcast.bytes)
@@ -6671,15 +6893,19 @@ match_template (char mnem_suffix)
              && i.types[0].bitfield.dword
              && i.types[1].bitfield.instance == Accum)
            continue;
-         /* xrelease mov %eax, <disp> is another special case. It must not
-            match the accumulator-only encoding of mov.  */
-         if (flag_code != CODE_64BIT
-             && i.hle_prefix
-             && t->base_opcode == 0xa0
-             && t->opcode_modifier.opcodespace == SPACE_BASE
-             && i.types[0].bitfield.instance == Accum
-             && (i.flags[1] & Operand_Mem))
-           continue;
+
+         if (t->base_opcode == MOV_AX_DISP32
+             && t->opcode_modifier.opcodespace == SPACE_BASE)
+           {
+             /* Force 0x8b encoding for "mov foo@GOT, %eax".  */
+             if (i.reloc[0] == BFD_RELOC_386_GOT32)
+               continue;
+
+             /* xrelease mov %eax, <disp> is another special case. It must not
+                match the accumulator-only encoding of mov.  */
+             if (i.hle_prefix)
+               continue;
+           }
          /* Fall through.  */
 
        case 3:
@@ -6873,81 +7099,7 @@ match_template (char mnem_suffix)
   if (t == current_templates->end)
     {
       /* We found no match.  */
-      const char *err_msg;
-      switch (specific_error)
-       {
-       default:
-         abort ();
-       case operand_size_mismatch:
-         err_msg = _("operand size mismatch");
-         break;
-       case operand_type_mismatch:
-         err_msg = _("operand type mismatch");
-         break;
-       case register_type_mismatch:
-         err_msg = _("register type mismatch");
-         break;
-       case number_of_operands_mismatch:
-         err_msg = _("number of operands mismatch");
-         break;
-       case invalid_instruction_suffix:
-         err_msg = _("invalid instruction suffix");
-         break;
-       case bad_imm4:
-         err_msg = _("constant doesn't fit in 4 bits");
-         break;
-       case unsupported_with_intel_mnemonic:
-         err_msg = _("unsupported with Intel mnemonic");
-         break;
-       case unsupported_syntax:
-         err_msg = _("unsupported syntax");
-         break;
-       case unsupported:
-         as_bad (_("unsupported instruction `%s'"),
-                 current_templates->start->name);
-         return NULL;
-       case invalid_sib_address:
-         err_msg = _("invalid SIB address");
-         break;
-       case invalid_vsib_address:
-         err_msg = _("invalid VSIB address");
-         break;
-       case invalid_vector_register_set:
-         err_msg = _("mask, index, and destination registers must be distinct");
-         break;
-       case invalid_tmm_register_set:
-         err_msg = _("all tmm registers must be distinct");
-         break;
-       case invalid_dest_and_src_register_set:
-         err_msg = _("destination and source registers must be distinct");
-         break;
-       case unsupported_vector_index_register:
-         err_msg = _("unsupported vector index register");
-         break;
-       case unsupported_broadcast:
-         err_msg = _("unsupported broadcast");
-         break;
-       case broadcast_needed:
-         err_msg = _("broadcast is needed for operand of such type");
-         break;
-       case unsupported_masking:
-         err_msg = _("unsupported masking");
-         break;
-       case mask_not_on_destination:
-         err_msg = _("mask not on destination operand");
-         break;
-       case no_default_mask:
-         err_msg = _("default mask isn't allowed");
-         break;
-       case unsupported_rc_sae:
-         err_msg = _("unsupported static rounding/sae");
-         break;
-       case invalid_register_operand:
-         err_msg = _("invalid register operand");
-         break;
-       }
-      as_bad (_("%s for `%s'"), err_msg,
-             current_templates->start->name);
+      i.error = specific_error;
       return NULL;
     }
 
@@ -6955,14 +7107,14 @@ match_template (char mnem_suffix)
     {
       if (!intel_syntax
          && (i.jumpabsolute != (t->opcode_modifier.jump == JUMP_ABSOLUTE)))
-       as_warn (_("indirect %s without `*'"), t->name);
+       as_warn (_("indirect %s without `*'"), insn_name (t));
 
       if (t->opcode_modifier.isprefix
          && t->opcode_modifier.mnemonicsize == IGNORESIZE)
        {
          /* Warn them that a data or address size prefix doesn't
             affect assembly of the next line of code.  */
-         as_warn (_("stand-alone `%s' prefix"), t->name);
+         as_warn (_("stand-alone `%s' prefix"), insn_name (t));
        }
     }
 
@@ -7022,7 +7174,7 @@ check_string (void)
   if (i.seg[op] != NULL && i.seg[op] != reg_es)
     {
       as_bad (_("`%s' operand %u must use `%ses' segment"),
-             i.tm.name,
+             insn_name (&i.tm),
              intel_syntax ? i.tm.operands - es_op : es_op + 1,
              register_prefix);
       return 0;
@@ -7161,7 +7313,7 @@ process_suffix (void)
          /* Warn about changed behavior for segment register push/pop.  */
          else if ((i.tm.base_opcode | 1) == 0x07)
            as_warn (_("generating 32-bit `%s', unlike earlier gas versions"),
-                    i.tm.name);
+                    insn_name (&i.tm));
        }
     }
   else if (!i.suffix
@@ -7277,13 +7429,13 @@ process_suffix (void)
              && (i.tm.opcode_modifier.mnemonicsize != DEFAULTSIZE
                  || operand_check == check_error))
            {
-             as_bad (_("ambiguous operand size for `%s'"), i.tm.name);
+             as_bad (_("ambiguous operand size for `%s'"), insn_name (&i.tm));
              return 0;
            }
          if (operand_check == check_error)
            {
              as_bad (_("no instruction mnemonic suffix given and "
-                       "no register operands; can't size `%s'"), i.tm.name);
+                       "no register operands; can't size `%s'"), insn_name (&i.tm));
              return 0;
            }
          if (operand_check == check_warning)
@@ -7292,7 +7444,7 @@ process_suffix (void)
                       ? _("ambiguous operand size")
                       : _("no instruction mnemonic suffix given and "
                           "no register operands"),
-                      i.tm.name);
+                      insn_name (&i.tm));
 
          if (i.tm.opcode_modifier.floatmf)
            i.suffix = SHORT_MNEM_SUFFIX;
@@ -7430,7 +7582,7 @@ process_suffix (void)
              && i.op[0].regs->reg_type.bitfield.word)
            {
              as_bad (_("16-bit addressing unavailable for `%s'"),
-                     i.tm.name);
+                     insn_name (&i.tm));
              return 0;
            }
 
@@ -7498,7 +7650,7 @@ process_suffix (void)
                }
 
              as_bad (_("invalid register operand size for `%s'"),
-                     i.tm.name);
+                     insn_name (&i.tm));
              return 0;
            }
        }
@@ -7539,7 +7691,7 @@ check_byte_reg (void)
       /* Any other register is bad.  */
       as_bad (_("`%s%s' not allowed with `%s%c'"),
              register_prefix, i.op[op].regs->reg_name,
-             i.tm.name, i.suffix);
+             insn_name (&i.tm), i.suffix);
       return 0;
     }
   return 1;
@@ -7565,7 +7717,7 @@ check_long_reg (void)
        as_bad (_("`%s%s' not allowed with `%s%c'"),
                register_prefix,
                i.op[op].regs->reg_name,
-               i.tm.name,
+               insn_name (&i.tm),
                i.suffix);
        return 0;
       }
@@ -7613,7 +7765,7 @@ check_qword_reg (void)
        as_bad (_("`%s%s' not allowed with `%s%c'"),
                register_prefix,
                i.op[op].regs->reg_name,
-               i.tm.name,
+               insn_name (&i.tm),
                i.suffix);
        return 0;
       }
@@ -7652,7 +7804,7 @@ check_word_reg (void)
        as_bad (_("`%s%s' not allowed with `%s%c'"),
                register_prefix,
                i.op[op].regs->reg_name,
-               i.tm.name,
+               insn_name (&i.tm),
                i.suffix);
        return 0;
       }
@@ -7909,7 +8061,7 @@ process_operands (void)
                 register_prefix, i.op[1].regs->reg_name,
                 register_prefix, i.op[1].regs->reg_name, first_reg_in_group,
                 register_prefix, i.op[1].regs->reg_name, last_reg_in_group,
-                i.tm.name);
+                insn_name (&i.tm));
     }
   else if (i.tm.opcode_modifier.operandconstraint == REG_KLUDGE)
     {
@@ -7949,7 +8101,7 @@ process_operands (void)
            && i.op[0].regs->reg_num < 4)
        {
          as_bad (_("you can't `%s %s%s'"),
-                 i.tm.name, register_prefix, i.op[0].regs->reg_name);
+                 insn_name (&i.tm), register_prefix, i.op[0].regs->reg_name);
          return 0;
        }
       if (i.op[0].regs->reg_num > 3
@@ -7990,13 +8142,13 @@ process_operands (void)
          if (i.operands != 2)
            {
              /* Extraneous `l' suffix on fp insn.  */
-             as_warn (_("translating to `%s %s%s'"), i.tm.name,
+             as_warn (_("translating to `%s %s%s'"), insn_name (&i.tm),
                       register_prefix, i.op[0].regs->reg_name);
            }
          else if (i.op[0].regs->reg_type.bitfield.instance != Accum)
            {
              /* Reversed arguments on faddp or fmulp.  */
-             as_warn (_("translating to `%s %s%s,%s%s'"), i.tm.name,
+             as_warn (_("translating to `%s %s%s,%s%s'"), insn_name (&i.tm),
                       register_prefix, i.op[!intel_syntax].regs->reg_name,
                       register_prefix, i.op[intel_syntax].regs->reg_name);
            }
@@ -8009,7 +8161,7 @@ process_operands (void)
       && !is_any_vex_encoding(&i.tm))
     {
       if (!quiet_warnings)
-       as_warn (_("segment override on `%s' is ineffectual"), i.tm.name);
+       as_warn (_("segment override on `%s' is ineffectual"), insn_name (&i.tm));
       if (optimize)
        {
          i.seg[0] = NULL;
@@ -8741,7 +8893,7 @@ output_branch (void)
     }
 
   if (i.prefixes != 0)
-    as_warn (_("skipping prefixes on `%s'"), i.tm.name);
+    as_warn (_("skipping prefixes on `%s'"), insn_name (&i.tm));
 
   /* It's always a symbol;  End frag & setup for relax.
      Make sure there is enough room in this frag for the largest
@@ -8889,7 +9041,7 @@ output_jump (void)
     }
 
   if (i.prefixes != 0)
-    as_warn (_("skipping prefixes on `%s'"), i.tm.name);
+    as_warn (_("skipping prefixes on `%s'"), insn_name (&i.tm));
 
   if (now_seg == absolute_section)
     {
@@ -8971,7 +9123,7 @@ output_interseg_jump (void)
     size = 2;
 
   if (i.prefixes != 0)
-    as_warn (_("skipping prefixes on `%s'"), i.tm.name);
+    as_warn (_("skipping prefixes on `%s'"), insn_name (&i.tm));
 
   if (now_seg == absolute_section)
     {
@@ -9290,7 +9442,7 @@ add_fused_jcc_padding_frag_p (enum mf_cmp_kind* mf_cmp_p)
       if (flag_debug)
        as_warn_where (last_insn.file, last_insn.line,
                       _("`%s` skips -malign-branch-boundary on `%s`"),
-                      last_insn.name, i.tm.name);
+                      last_insn.name, insn_name (&i.tm));
     }
 
   return 0;
@@ -9322,7 +9474,7 @@ add_branch_prefix_frag_p (void)
   if (flag_debug)
     as_warn_where (last_insn.file, last_insn.line,
                   _("`%s` skips -malign-branch-boundary on `%s`"),
-                  last_insn.name, i.tm.name);
+                  last_insn.name, insn_name (&i.tm));
 
   return 0;
 }
@@ -9411,7 +9563,7 @@ add_branch_padding_frag_p (enum align_branch_kind *branch_p,
       if (flag_debug)
        as_warn_where (last_insn.file, last_insn.line,
                       _("`%s` skips -malign-branch-boundary on `%s`"),
-                      last_insn.name, i.tm.name);
+                      last_insn.name, insn_name (&i.tm));
       return 0;
     }
 
@@ -9611,10 +9763,10 @@ output_insn (void)
          /* Encode lfence, mfence, and sfence as
             f0 83 04 24 00   lock addl $0x0, (%{re}sp).  */
          if (flag_code == CODE_16BIT)
-           as_bad (_("Cannot convert `%s' in 16-bit mode"), i.tm.name);
+           as_bad (_("Cannot convert `%s' in 16-bit mode"), insn_name (&i.tm));
          else if (omit_lock_prefix)
            as_bad (_("Cannot convert `%s' with `-momit-lock-prefix=yes' in effect"),
-                   i.tm.name);
+                   insn_name (&i.tm));
          else if (now_seg != absolute_section)
            {
              offsetT val = 0x240483f0ULL;
@@ -11250,11 +11402,9 @@ i386_index_check (const char *operand_string)
 {
   const char *kind = "base/index";
   enum flag_code addr_mode = i386_addressing_mode ();
-  const insn_template *t = current_templates->start;
+  const insn_template *t = current_templates->end - 1;
 
-  if (t->opcode_modifier.isstring
-      && (current_templates->end[-1].opcode_modifier.isstring
-         || i.mem_operands))
+  if (t->opcode_modifier.isstring)
     {
       /* Memory operands of string insns are special in that they only allow
         a single register (rDI, rSI, or rBX) as their memory address.  */
@@ -11271,14 +11421,12 @@ i386_index_check (const char *operand_string)
 
       if (t->opcode_modifier.prefixok == PrefixRep)
        {
-         int es_op = current_templates->end[-1].opcode_modifier.isstring
-                     - IS_STRING_ES_OP0;
+         int es_op = t->opcode_modifier.isstring - IS_STRING_ES_OP0;
          int op = 0;
 
-         if (!current_templates->end[-1].operand_types[0].bitfield.baseindex
+         if (!t->operand_types[0].bitfield.baseindex
              || ((!i.mem_operands != !intel_syntax)
-                 && current_templates->end[-1].operand_types[1]
-                    .bitfield.baseindex))
+                 && t->operand_types[1].bitfield.baseindex))
            op = 1;
          expected_reg
            = (const reg_entry *) str_hash_find (reg_hash,
@@ -11321,6 +11469,8 @@ i386_index_check (const char *operand_string)
     }
   else
     {
+      t = current_templates->start;
+
       if (addr_mode != CODE_16BIT)
        {
          /* 32-bit/64-bit checks.  */
@@ -11426,49 +11576,6 @@ RC_SAE_immediate (const char *imm_start)
   return 1;
 }
 
-/* Only string instructions can have a second memory operand, so
-   reduce current_templates to just those if it contains any.  */
-static int
-maybe_adjust_templates (void)
-{
-  const insn_template *t;
-
-  gas_assert (i.mem_operands == 1);
-
-  for (t = current_templates->start; t < current_templates->end; ++t)
-    if (t->opcode_modifier.isstring)
-      break;
-
-  if (t < current_templates->end)
-    {
-      static templates aux_templates;
-      bool recheck;
-
-      aux_templates.start = t;
-      for (; t < current_templates->end; ++t)
-       if (!t->opcode_modifier.isstring)
-         break;
-      aux_templates.end = t;
-
-      /* Determine whether to re-check the first memory operand.  */
-      recheck = (aux_templates.start != current_templates->start
-                || t != current_templates->end);
-
-      current_templates = &aux_templates;
-
-      if (recheck)
-       {
-         i.mem_operands = 0;
-         if (i.memop1_string != NULL
-             && i386_index_check (i.memop1_string) == 0)
-           return 0;
-         i.mem_operands = 1;
-       }
-    }
-
-  return 1;
-}
-
 static INLINE bool starts_memory_operand (char c)
 {
   return ISDIGIT (c)
@@ -11570,7 +11677,7 @@ i386_att_operand (char *operand_string)
            if (i.rounding.type == RC_NamesTable[j].type)
              break;
          as_bad (_("`%s': misplaced `{%s}'"),
-                 current_templates->start->name, RC_NamesTable[j].name);
+                 insn_name (current_templates->start), RC_NamesTable[j].name);
          return 0;
        }
     }
@@ -11592,7 +11699,7 @@ i386_att_operand (char *operand_string)
       if (i.rounding.type != rc_none)
        {
          as_bad (_("`%s': RC/SAE operand must follow immediate operands"),
-                 current_templates->start->name);
+                 insn_name (current_templates->start));
          return 0;
        }
     }
@@ -11605,7 +11712,7 @@ i386_att_operand (char *operand_string)
              && i.op[0].regs->reg_type.bitfield.class != Reg))
        {
          as_bad (_("`%s': misplaced `%s'"),
-                 current_templates->start->name, operand_string);
+                 insn_name (current_templates->start), operand_string);
          return 0;
        }
     }
@@ -11619,17 +11726,6 @@ i386_att_operand (char *operand_string)
       char *displacement_string_end;
 
     do_memory_reference:
-      if (i.mem_operands == 1 && !maybe_adjust_templates ())
-       return 0;
-      if ((i.mem_operands == 1
-          && !current_templates->start->opcode_modifier.isstring)
-         || i.mem_operands == 2)
-       {
-         as_bad (_("too many memory references for `%s'"),
-                 current_templates->start->name);
-         return 0;
-       }
-
       /* Check for base index form.  We detect the base index form by
         looking for an ')' at the end of the operand, searching
         for the '(' matching it, and finding a REGISTER_PREFIX or ','
@@ -11837,8 +11933,6 @@ i386_att_operand (char *operand_string)
       if (i386_index_check (operand_string) == 0)
        return 0;
       i.flags[this_operand] |= Operand_Mem;
-      if (i.mem_operands == 0)
-       i.memop1_string = xstrdup (operand_string);
       i.mem_operands++;
     }
   else