]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - gas/config/tc-i386.c
Fix a translation problem in the x86 assembler.
[thirdparty/binutils-gdb.git] / gas / config / tc-i386.c
index 992ae94f1f70e5f3f77c8ec0814defd0fe2acfb7..c70b9f47aa86af98634005c1686e03d0c6f1e33e 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.
 
@@ -30,6 +30,8 @@
 #include "subsegs.h"
 #include "dwarf2dbg.h"
 #include "dw2gencfi.h"
+#include "gen-sframe.h"
+#include "sframe.h"
 #include "elf/x86-64.h"
 #include "opcodes/i386-init.h"
 #include <limits.h>
 #define SHORT_MNEM_SUFFIX 's'
 #define LONG_MNEM_SUFFIX  'l'
 #define QWORD_MNEM_SUFFIX  'q'
-/* Intel Syntax.  Use a non-ascii letter since since it never appears
-   in instructions.  */
-#define LONG_DOUBLE_MNEM_SUFFIX '\1'
 
 #define END_OF_INSN '\0'
 
+#define OPERAND_TYPE_NONE { .bitfield = { .class = ClassNone } }
+
 /* This matches the C -> StaticRounding alias in the opcode table.  */
 #define commutative staticrounding
 
@@ -157,7 +158,7 @@ static int i386_intel_operand (char *, int);
 static int i386_intel_simplify (expressionS *);
 static int i386_intel_parse_name (const char *, expressionS *);
 static const reg_entry *parse_register (char *, char **);
-static char *parse_insn (char *, char *);
+static const char *parse_insn (const char *, char *);
 static char *parse_operands (char *, const char *);
 static void swap_operands (void);
 static void swap_2_operands (unsigned int, unsigned int);
@@ -236,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,
@@ -297,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;
@@ -311,6 +311,13 @@ struct _i386_insn
     /* The operand to a branch insn indicates an absolute branch.  */
     bool jumpabsolute;
 
+    /* The operand to a branch insn indicates a far branch.  */
+    bool far_branch;
+
+    /* There is a memory operand of (%dx) which should be only used
+       with input/output instructions.  */
+    bool input_output_operand;
+
     /* Extended states.  */
     enum
       {
@@ -458,6 +465,16 @@ static const struct RC_name RC_NamesTable[] =
   {  saeonly,  STRING_COMMA_LEN ("sae") },
 };
 
+/* To be indexed by segment register number.  */
+static const unsigned char i386_seg_prefixes[] = {
+  ES_PREFIX_OPCODE,
+  CS_PREFIX_OPCODE,
+  SS_PREFIX_OPCODE,
+  DS_PREFIX_OPCODE,
+  FS_PREFIX_OPCODE,
+  GS_PREFIX_OPCODE
+};
+
 /* List of chars besides those in app.c:symbol_chars that can start an
    operand.  Used to prevent the scrubber eating vital white-space.  */
 const char extra_symbol_chars[] = "*%-([{}"
@@ -587,6 +604,12 @@ static int use_big_obj = 0;
 #if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
 /* 1 if generating code for a shared library.  */
 static int shared = 0;
+
+unsigned int x86_sframe_cfa_sp_reg;
+/* The other CFA base register for SFrame unwind info.  */
+unsigned int x86_sframe_cfa_fp_reg;
+unsigned int x86_sframe_cfa_ra_reg;
+
 #endif
 
 /* 1 for intel syntax,
@@ -941,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),
@@ -974,15 +997,16 @@ static const arch_entry cpu_arch[] =
   ARCH (znver1, ZNVER, ZNVER1, false),
   ARCH (znver2, ZNVER, ZNVER2, false),
   ARCH (znver3, ZNVER, ZNVER3, false),
+  ARCH (znver4, ZNVER, ZNVER4, false),
   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),
@@ -1002,42 +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 (sse4a, SSE4A, SSE4A, 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),
@@ -1045,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),
@@ -1062,45 +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, RAO_INT, false),
+  SUBARCH (rmpquery, RMPQUERY, ANY_RMPQUERY, false),
 };
 
 #undef SUBARCH
@@ -1927,18 +1954,9 @@ operand_type_xor (i386_operand_type x, i386_operand_type y)
   return x;
 }
 
-static const i386_operand_type disp16_32 = OPERAND_TYPE_DISP16_32;
-static const i386_operand_type anydisp = OPERAND_TYPE_ANYDISP;
-static const i386_operand_type regxmm = OPERAND_TYPE_REGXMM;
-static const i386_operand_type imm8 = OPERAND_TYPE_IMM8;
-static const i386_operand_type imm8s = OPERAND_TYPE_IMM8S;
-static const i386_operand_type imm16 = OPERAND_TYPE_IMM16;
-static const i386_operand_type imm32 = OPERAND_TYPE_IMM32;
-static const i386_operand_type imm32s = OPERAND_TYPE_IMM32S;
-static const i386_operand_type imm64 = OPERAND_TYPE_IMM64;
-static const i386_operand_type imm16_32 = OPERAND_TYPE_IMM16_32;
-static const i386_operand_type imm16_32s = OPERAND_TYPE_IMM16_32S;
-static const i386_operand_type imm16_32_32s = OPERAND_TYPE_IMM16_32_32S;
+static const i386_operand_type anydisp = {
+  .bitfield = { .disp8 = 1, .disp16 = 1, .disp32 = 1, .disp64 = 1 }
+};
 
 enum operand_type
 {
@@ -1998,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));
 }
@@ -2073,7 +2099,7 @@ operand_size_match (const insn_template *t)
     {
       if (i.types[j].bitfield.class != Reg
          && i.types[j].bitfield.class != RegSIMD
-         && t->opcode_modifier.anysize)
+         && t->opcode_modifier.operandconstraint == ANY_SIZE)
        continue;
 
       if (t->operand_types[j].bitfield.class == Reg
@@ -2170,7 +2196,7 @@ operand_type_match (i386_operand_type overlap,
 
 /* If given types g0 and g1 are registers they must be of the same type
    unless the expected operand type register overlap is null.
-   Some Intel syntax memory operand size checking also happens here.  */
+   Intel syntax sized memory operands are also checked here.  */
 
 static INLINE int
 operand_type_register_match (i386_operand_type g0,
@@ -2180,18 +2206,14 @@ operand_type_register_match (i386_operand_type g0,
 {
   if (g0.bitfield.class != Reg
       && g0.bitfield.class != RegSIMD
-      && (!operand_type_check (g0, anymem)
-         || g0.bitfield.unspecified
-         || (t0.bitfield.class != Reg
-             && t0.bitfield.class != RegSIMD)))
+      && (g0.bitfield.unspecified
+         || !operand_type_check (g0, anymem)))
     return 1;
 
   if (g1.bitfield.class != Reg
       && g1.bitfield.class != RegSIMD
-      && (!operand_type_check (g1, anymem)
-         || g1.bitfield.unspecified
-         || (t1.bitfield.class != Reg
-             && t1.bitfield.class != RegSIMD)))
+      && (g1.bitfield.unspecified
+         || !operand_type_check (g1, anymem)))
     return 1;
 
   if (g0.bitfield.byte == g1.bitfield.byte
@@ -2947,6 +2969,8 @@ i386_mach (void)
     as_fatal (_("unknown architecture"));
 }
 \f
+#include "opcodes/i386-tbl.h"
+
 void
 md_begin (void)
 {
@@ -2957,32 +2981,16 @@ md_begin (void)
   op_hash = str_htab_create ();
 
   {
-    const insn_template *optab;
-    templates *core_optab;
-
-    /* Setup for loop.  */
-    optab = i386_optab;
-    core_optab = notes_alloc (sizeof (*core_optab));
-    core_optab->start = optab;
-
-    while (1)
-      {
-       ++optab;
-       if (optab->name == NULL
-           || strcmp (optab->name, (optab - 1)->name) != 0)
-         {
-           /* different name --> ship out current template list;
-              add to hash table; & begin anew.  */
-           core_optab->end = optab;
-           if (str_hash_insert (op_hash, (optab - 1)->name, core_optab, 0))
-             as_fatal (_("duplicate %s"), (optab - 1)->name);
-
-           if (optab->name == NULL)
-             break;
-           core_optab = notes_alloc (sizeof (*core_optab));
-           core_optab->start = optab;
-         }
-      }
+    const insn_template *const *sets = i386_op_sets;
+    const insn_template *const *end = sets + ARRAY_SIZE (i386_op_sets) - 1;
+
+    /* Type checks to compensate for the conversion through void * which
+       occurs during hash table insertion / lookup.  */
+    (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);
   }
 
   /* Initialize reg_hash hash table.  */
@@ -3095,6 +3103,10 @@ md_begin (void)
       x86_dwarf2_return_column = 16;
 #endif
       x86_cie_data_alignment = -8;
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+      x86_sframe_cfa_sp_reg = 7;
+      x86_sframe_cfa_fp_reg = 6;
+#endif
     }
   else
     {
@@ -3239,40 +3251,40 @@ static struct type_name
   }
 const type_names[] =
 {
-  { OPERAND_TYPE_REG8, "r8" },
-  { OPERAND_TYPE_REG16, "r16" },
-  { OPERAND_TYPE_REG32, "r32" },
-  { OPERAND_TYPE_REG64, "r64" },
-  { OPERAND_TYPE_ACC8, "acc8" },
-  { OPERAND_TYPE_ACC16, "acc16" },
-  { OPERAND_TYPE_ACC32, "acc32" },
-  { OPERAND_TYPE_ACC64, "acc64" },
-  { OPERAND_TYPE_IMM8, "i8" },
-  { OPERAND_TYPE_IMM8, "i8s" },
-  { OPERAND_TYPE_IMM16, "i16" },
-  { OPERAND_TYPE_IMM32, "i32" },
-  { OPERAND_TYPE_IMM32S, "i32s" },
-  { OPERAND_TYPE_IMM64, "i64" },
-  { OPERAND_TYPE_IMM1, "i1" },
-  { OPERAND_TYPE_BASEINDEX, "BaseIndex" },
-  { OPERAND_TYPE_DISP8, "d8" },
-  { OPERAND_TYPE_DISP16, "d16" },
-  { OPERAND_TYPE_DISP32, "d32" },
-  { OPERAND_TYPE_DISP64, "d64" },
-  { OPERAND_TYPE_INOUTPORTREG, "InOutPortReg" },
-  { OPERAND_TYPE_SHIFTCOUNT, "ShiftCount" },
-  { OPERAND_TYPE_CONTROL, "control reg" },
-  { OPERAND_TYPE_TEST, "test reg" },
-  { OPERAND_TYPE_DEBUG, "debug reg" },
-  { OPERAND_TYPE_FLOATREG, "FReg" },
-  { OPERAND_TYPE_FLOATACC, "FAcc" },
-  { OPERAND_TYPE_SREG, "SReg" },
-  { OPERAND_TYPE_REGMMX, "rMMX" },
-  { OPERAND_TYPE_REGXMM, "rXMM" },
-  { OPERAND_TYPE_REGYMM, "rYMM" },
-  { OPERAND_TYPE_REGZMM, "rZMM" },
-  { OPERAND_TYPE_REGTMM, "rTMM" },
-  { OPERAND_TYPE_REGMASK, "Mask reg" },
+  { { .bitfield = { .class = Reg, .byte = 1 } }, "r8" },
+  { { .bitfield = { .class = Reg, .word = 1 } }, "r16" },
+  { { .bitfield = { .class = Reg, .dword = 1 } }, "r32" },
+  { { .bitfield = { .class = Reg, .qword = 1 } }, "r64" },
+  { { .bitfield = { .instance = Accum, .byte = 1 } }, "acc8" },
+  { { .bitfield = { .instance = Accum, .word = 1 } }, "acc16" },
+  { { .bitfield = { .instance = Accum, .dword = 1 } }, "acc32" },
+  { { .bitfield = { .instance = Accum, .qword = 1 } }, "acc64" },
+  { { .bitfield = { .imm8 = 1 } }, "i8" },
+  { { .bitfield = { .imm8s = 1 } }, "i8s" },
+  { { .bitfield = { .imm16 = 1 } }, "i16" },
+  { { .bitfield = { .imm32 = 1 } }, "i32" },
+  { { .bitfield = { .imm32s = 1 } }, "i32s" },
+  { { .bitfield = { .imm64 = 1 } }, "i64" },
+  { { .bitfield = { .imm1 = 1 } }, "i1" },
+  { { .bitfield = { .baseindex = 1 } }, "BaseIndex" },
+  { { .bitfield = { .disp8 = 1 } }, "d8" },
+  { { .bitfield = { .disp16 = 1 } }, "d16" },
+  { { .bitfield = { .disp32 = 1 } }, "d32" },
+  { { .bitfield = { .disp64 = 1 } }, "d64" },
+  { { .bitfield = { .instance = RegD, .word = 1 } }, "InOutPortReg" },
+  { { .bitfield = { .instance = RegC, .byte = 1 } }, "ShiftCount" },
+  { { .bitfield = { .class = RegCR } }, "control reg" },
+  { { .bitfield = { .class = RegTR } }, "test reg" },
+  { { .bitfield = { .class = RegDR } }, "debug reg" },
+  { { .bitfield = { .class = Reg, .tbyte = 1 } }, "FReg" },
+  { { .bitfield = { .instance = Accum, .tbyte = 1 } }, "FAcc" },
+  { { .bitfield = { .class = SReg } }, "SReg" },
+  { { .bitfield = { .class = RegMMX } }, "rMMX" },
+  { { .bitfield = { .class = RegSIMD, .xmmword = 1 } }, "rXMM" },
+  { { .bitfield = { .class = RegSIMD, .ymmword = 1 } }, "rYMM" },
+  { { .bitfield = { .class = RegSIMD, .zmmword = 1 } }, "rZMM" },
+  { { .bitfield = { .class = RegSIMD, .tmmword = 1 } }, "rTMM" },
+  { { .bitfield = { .class = RegMask } }, "Mask reg" },
 };
 
 static void
@@ -3998,7 +4010,7 @@ process_immext (void)
 
   exp = &im_expressions[i.imm_operands++];
   i.op[i.operands].imms = exp;
-  i.types[i.operands] = imm8;
+  i.types[i.operands].bitfield.imm8 = 1;
   i.operands++;
   exp->X_op = O_constant;
   exp->X_add_number = i.tm.extension_opcode;
@@ -4295,7 +4307,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
@@ -4305,11 +4330,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
@@ -4520,7 +4540,7 @@ load_insn_p (void)
     {
       /* Anysize insns: lea, invlpg, clflush, prefetch*, bndmk, bndcl, bndcu,
         bndcn, bndstx, bndldx, clflushopt, clwb, cldemote.  */
-      if (i.tm.opcode_modifier.anysize)
+      if (i.tm.opcode_modifier.operandconstraint == ANY_SIZE)
        return 0;
 
       /* pop.   */
@@ -4832,6 +4852,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.  */
@@ -4840,10 +4876,14 @@ void
 md_assemble (char *line)
 {
   unsigned int j;
-  char mnemonic[MAX_MNEM_SIZE], mnem_suffix;
+  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++)
@@ -4856,26 +4896,48 @@ md_assemble (char *line)
      We assume that the scrubber has arranged it so that line[0] is the valid
      start of a (possibly prefixed) mnemonic.  */
 
-  line = parse_insn (line, mnemonic);
-  if (line == NULL)
-    return;
+  end = parse_insn (line, mnemonic);
+  if (end == NULL)
+    {
+      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.  */
 
   /* All Intel opcodes have reversed operands except for "bound", "enter",
      "invlpg*", "monitor*", "mwait*", "tpause", "umwait", "pvalidate",
-     "rmpadjust", and "rmpupdate".  We also don't reverse intersegment "jmp"
-     and "call" instructions with 2 immediate operands so that the immediate
-     segment precedes the offset consistently in Intel and AT&T modes.  */
+     "rmpadjust", "rmpupdate", and "rmpquery".  We also don't reverse
+     intersegment "jmp" and "call" instructions with 2 immediate operands so
+     that the immediate segment precedes the offset consistently in Intel and
+     AT&T modes.  */
   if (intel_syntax
       && i.operands > 1
       && (strcmp (mnemonic, "bound") != 0)
@@ -4886,7 +4948,8 @@ md_assemble (char *line)
       && !startswith (mnemonic, "rmp")
       && (strcmp (mnemonic, "tpause") != 0)
       && (strcmp (mnemonic, "umwait") != 0)
-      && !(operand_type_check (i.types[0], imm)
+      && !(i.operands == 2
+          && operand_type_check (i.types[0], imm)
           && operand_type_check (i.types[1], imm)))
     swap_operands ();
 
@@ -4942,7 +5005,135 @@ 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 = current_templates->start->name;
+         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 : current_templates->start->name);
+         return;
+       case unsupported_on_arch:
+         as_bad (_("`%s' is not supported on `%s%s'"),
+                 pass1_mnem ? pass1_mnem : current_templates->start->name,
+                 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 : current_templates->start->name,
+                       mnem_suffix);
+             else
+               as_bad (_("`%s%c' is only supported in 64-bit mode"),
+                       pass1_mnem ? pass1_mnem : current_templates->start->name,
+                       mnem_suffix);
+           }
+         else
+           {
+             if (flag_code == CODE_64BIT)
+               as_bad (_("`%s' is not supported in 64-bit mode"),
+                       pass1_mnem ? pass1_mnem : current_templates->start->name);
+             else
+               as_bad (_("`%s' is only supported in 64-bit mode"),
+                       pass1_mnem ? pass1_mnem : current_templates->start->name);
+           }
+                 
+         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 : current_templates->start->name);
+      return;
+    }
+
+  free (copy);
 
   if (sse_check != check_none
       /* The opcode space check isn't strictly needed; it's there only to
@@ -4992,14 +5183,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'"), i.tm.name);
+         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'"), i.tm.name);
+           return;
+         default:
+           break;
+         }
     }
 
   /* Check if HLE prefix is OK.  */
@@ -5045,6 +5252,17 @@ md_assemble (char *line)
       i.disp_operands = 0;
     }
 
+  /* The memory operand of (%dx) should be only used with input/output
+     instructions (base opcodes: 0x6c, 0x6e, 0xec, 0xee).  */
+  if (i.input_output_operand
+      && ((i.tm.base_opcode | 0x82) != 0xee
+         || i.tm.opcode_modifier.opcodespace != SPACE_BASE))
+    {
+      as_bad (_("input/output port address isn't allowed with `%s'"),
+             i.tm.name);
+      return;
+    }
+
   if (optimize && !i.no_optimize && i.tm.opcode_modifier.optimize)
     optimize_encoding ();
 
@@ -5108,7 +5326,7 @@ md_assemble (char *line)
       if (!process_operands ())
        return;
     }
-  else if (!quiet_warnings && i.tm.opcode_modifier.ugh)
+  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);
@@ -5243,12 +5461,29 @@ md_assemble (char *line)
     last_insn.kind = last_insn_other;
 }
 
-static char *
-parse_insn (char *line, char *mnemonic)
+/* 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)
 {
-  char *l = line;
-  char *token_start = l;
+  const char *l = line, *token_start = l;
   char *mnem_p;
+  bool pass1 = !current_templates;
   int supported;
   const insn_template *t;
   char *dot_p = NULL;
@@ -5418,8 +5653,10 @@ parse_insn (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)
        {
@@ -5461,13 +5698,39 @@ parse_insn (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;
        }
     }
@@ -5510,20 +5773,21 @@ parse_insn (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;
 }
@@ -6021,7 +6285,7 @@ check_VecOperands (const insn_template *t)
     }
 
   /* Check if default mask is allowed.  */
-  if (t->opcode_modifier.nodefmask
+  if (t->opcode_modifier.operandconstraint == NO_DEFAULT_MASK
       && (!i.mask.reg || i.mask.reg->reg_num == 0))
     {
       i.error = no_default_mask;
@@ -6103,7 +6367,7 @@ check_VecOperands (const insn_template *t)
 
   /* For some special instructions require that destination must be distinct
      from source registers.  */
-  if (t->opcode_modifier.distinctdest)
+  if (t->opcode_modifier.operandconstraint == DISTINCT_DEST)
     {
       unsigned int dest_reg = i.operands - 1;
 
@@ -6180,7 +6444,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;
 
@@ -6426,7 +6690,6 @@ match_template (char mnem_suffix)
   i386_operand_type overlap0, overlap1, overlap2, overlap3;
   i386_operand_type overlap4;
   unsigned int found_reverse_match;
-  i386_opcode_modifier suffix_check;
   i386_operand_type operand_types [MAX_OPERANDS];
   int addr_prefix_disp;
   unsigned int j, size_match, check_register, errline = __LINE__;
@@ -6440,35 +6703,6 @@ match_template (char mnem_suffix)
   found_reverse_match = 0;
   addr_prefix_disp = -1;
 
-  /* Prepare for mnemonic suffix check.  */
-  memset (&suffix_check, 0, sizeof (suffix_check));
-  switch (mnem_suffix)
-    {
-    case BYTE_MNEM_SUFFIX:
-      suffix_check.no_bsuf = 1;
-      break;
-    case WORD_MNEM_SUFFIX:
-      suffix_check.no_wsuf = 1;
-      break;
-    case SHORT_MNEM_SUFFIX:
-      suffix_check.no_ssuf = 1;
-      break;
-    case LONG_MNEM_SUFFIX:
-      suffix_check.no_lsuf = 1;
-      break;
-    case QWORD_MNEM_SUFFIX:
-      suffix_check.no_qsuf = 1;
-      break;
-    default:
-      /* NB: In Intel syntax, normally we can check for memory operand
-        size when there is no mnemonic suffix.  But jmp and call have
-        2 different encodings with Dword memory operand size, one with
-        No_ldSuf and the other without.  i.suffix is set to
-        LONG_DOUBLE_MNEM_SUFFIX to skip the one with No_ldSuf.  */
-      if (i.suffix == LONG_DOUBLE_MNEM_SUFFIX)
-       suffix_check.no_ldsuf = 1;
-    }
-
   for (t = current_templates->start; t < current_templates->end; t++)
     {
       addr_prefix_disp = -1;
@@ -6516,12 +6750,11 @@ match_template (char mnem_suffix)
 
       /* Check the suffix.  */
       specific_error = progress (invalid_instruction_suffix);
-      if ((t->opcode_modifier.no_bsuf && suffix_check.no_bsuf)
-         || (t->opcode_modifier.no_wsuf && suffix_check.no_wsuf)
-         || (t->opcode_modifier.no_lsuf && suffix_check.no_lsuf)
-         || (t->opcode_modifier.no_ssuf && suffix_check.no_ssuf)
-         || (t->opcode_modifier.no_qsuf && suffix_check.no_qsuf)
-         || (t->opcode_modifier.no_ldsuf && suffix_check.no_ldsuf))
+      if ((t->opcode_modifier.no_bsuf && mnem_suffix == BYTE_MNEM_SUFFIX)
+         || (t->opcode_modifier.no_wsuf && mnem_suffix == WORD_MNEM_SUFFIX)
+         || (t->opcode_modifier.no_lsuf && mnem_suffix == LONG_MNEM_SUFFIX)
+         || (t->opcode_modifier.no_ssuf && mnem_suffix == SHORT_MNEM_SUFFIX)
+         || (t->opcode_modifier.no_qsuf && mnem_suffix == QWORD_MNEM_SUFFIX))
        continue;
 
       specific_error = progress (operand_size_mismatch);
@@ -6539,23 +6772,24 @@ match_template (char mnem_suffix)
       if (i.jumpabsolute && t->opcode_modifier.jump != JUMP_ABSOLUTE)
        continue;
 
+      /* In Intel syntax, normally we can check for memory operand size when
+        there is no mnemonic suffix.  But jmp and call have 2 different
+        encodings with Dword memory operand size.  Skip the "near" one
+        (permitting a register operand) when "far" was requested.  */
+      if (i.far_branch
+         && t->opcode_modifier.jump == JUMP_ABSOLUTE
+         && t->operand_types[0].bitfield.class == Reg)
+       continue;
+
       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))
@@ -6626,28 +6860,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)
@@ -6673,18 +6887,21 @@ match_template (char mnem_suffix)
              && t->opcode_modifier.opcodespace == SPACE_BASE
              && i.types[0].bitfield.instance == Accum
              && i.types[0].bitfield.dword
-             && i.types[1].bitfield.instance == Accum
-             && i.types[1].bitfield.dword)
-           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))
+             && i.types[1].bitfield.instance == Accum)
            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:
@@ -6765,12 +6982,19 @@ match_template (char mnem_suffix)
                  specific_error = progress (i.error);
                  continue;
                }
-             /* found_reverse_match holds which of D or FloatR
+             /* found_reverse_match holds which variant of D
                 we've found.  */
              if (!t->opcode_modifier.d)
                found_reverse_match = 0;
              else if (operand_types[0].bitfield.tbyte)
-               found_reverse_match = Opcode_FloatD;
+               {
+                 if (t->opcode_modifier.operandconstraint != UGH)
+                   found_reverse_match = Opcode_FloatD;
+                 /* FSUB{,R} and FDIV{,R} may need a 2nd bit flipped.  */
+                 if ((t->base_opcode & 0x20)
+                     && (intel_syntax || intel_mnemonic))
+                   found_reverse_match |= Opcode_FloatR;
+               }
              else if (t->opcode_modifier.vexsources)
                {
                  found_reverse_match = Opcode_VexW;
@@ -6783,10 +7007,10 @@ match_template (char mnem_suffix)
                           || (t->base_opcode | 7) != 0x27))
                found_reverse_match = (t->base_opcode & 0xee) != 0x6e
                                      ? Opcode_ExtD : Opcode_SIMD_IntD;
-             else
+             else if (!t->opcode_modifier.commutative)
                found_reverse_match = Opcode_D;
-             if (t->opcode_modifier.floatr)
-               found_reverse_match |= Opcode_FloatR;
+             else
+               found_reverse_match = ~0;
            }
          else
            {
@@ -6871,81 +7095,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;
     }
 
@@ -6983,9 +7133,6 @@ match_template (char mnem_suffix)
 
       i.tm.base_opcode ^= found_reverse_match;
 
-      i.tm.operand_types[0] = operand_types[i.operands - 1];
-      i.tm.operand_types[i.operands - 1] = operand_types[0];
-
       /* Certain SIMD insns have their load forms specified in the opcode
         table, and hence we need to _set_ RegMem instead of clearing it.
         We need to avoid setting the bit though on insns like KMOVW.  */
@@ -6993,6 +7140,11 @@ match_template (char mnem_suffix)
        = i.tm.opcode_modifier.modrm && i.tm.opcode_modifier.d
          && i.tm.operands > 2U - i.tm.opcode_modifier.sse2avx
          && !i.tm.opcode_modifier.regmem;
+
+      /* Fall through.  */
+    case ~0:
+      i.tm.operand_types[0] = operand_types[i.operands - 1];
+      i.tm.operand_types[i.operands - 1] = operand_types[0];
       break;
 
     case Opcode_VexW:
@@ -7048,7 +7200,7 @@ process_suffix (void)
     i.suffix = QWORD_MNEM_SUFFIX;
   else if (i.reg_operands
           && (i.operands > 1 || i.types[0].bitfield.class == Reg)
-          && !i.tm.opcode_modifier.addrprefixopreg)
+          && i.tm.opcode_modifier.operandconstraint != ADDR_PREFIX_OP_REG)
     {
       unsigned int numop = i.operands;
 
@@ -7209,8 +7361,6 @@ process_suffix (void)
        suffixes |= 1 << 1;
       if (!i.tm.opcode_modifier.no_lsuf)
        suffixes |= 1 << 2;
-      if (!i.tm.opcode_modifier.no_ldsuf)
-       suffixes |= 1 << 3;
       if (!i.tm.opcode_modifier.no_ssuf)
        suffixes |= 1 << 4;
       if (flag_code == CODE_64BIT && !i.tm.opcode_modifier.no_qsuf)
@@ -7388,11 +7538,10 @@ process_suffix (void)
             need rex64. */
          && ! (i.operands == 2
                && i.tm.base_opcode == 0x90
-               && i.tm.extension_opcode == None
+               && i.tm.opcode_modifier.opcodespace == SPACE_BASE
                && i.types[0].bitfield.instance == Accum
                && i.types[0].bitfield.qword
-               && i.types[1].bitfield.instance == Accum
-               && i.types[1].bitfield.qword))
+               && i.types[1].bitfield.instance == Accum))
        i.rex |= REX_W;
 
       break;
@@ -7415,7 +7564,7 @@ process_suffix (void)
       break;
     }
 
-  if (i.tm.opcode_modifier.addrprefixopreg)
+  if (i.tm.opcode_modifier.operandconstraint == ADDR_PREFIX_OP_REG)
     {
       gas_assert (!i.suffix);
       gas_assert (i.reg_operands);
@@ -7674,19 +7823,26 @@ static int
 update_imm (unsigned int j)
 {
   i386_operand_type overlap = i.types[j];
-  if ((overlap.bitfield.imm8
-       || overlap.bitfield.imm8s
-       || overlap.bitfield.imm16
-       || overlap.bitfield.imm32
-       || overlap.bitfield.imm32s
-       || overlap.bitfield.imm64)
-      && !operand_type_equal (&overlap, &imm8)
-      && !operand_type_equal (&overlap, &imm8s)
-      && !operand_type_equal (&overlap, &imm16)
-      && !operand_type_equal (&overlap, &imm32)
-      && !operand_type_equal (&overlap, &imm32s)
-      && !operand_type_equal (&overlap, &imm64))
-    {
+  if (overlap.bitfield.imm8
+      + overlap.bitfield.imm8s
+      + overlap.bitfield.imm16
+      + overlap.bitfield.imm32
+      + overlap.bitfield.imm32s
+      + overlap.bitfield.imm64 > 1)
+    {
+      static const i386_operand_type imm16 = { .bitfield = { .imm16 = 1 } };
+      static const i386_operand_type imm32 = { .bitfield = { .imm32 = 1 } };
+      static const i386_operand_type imm32s = { .bitfield = { .imm32s = 1 } };
+      static const i386_operand_type imm16_32 = { .bitfield =
+       { .imm16 = 1, .imm32 = 1 }
+      };
+      static const i386_operand_type imm16_32s =  { .bitfield =
+       { .imm16 = 1, .imm32s = 1 }
+      };
+      static const i386_operand_type imm16_32_32s = { .bitfield =
+       { .imm16 = 1, .imm32 = 1, .imm32s = 1 }
+      };
+
       if (i.suffix)
        {
          i386_operand_type temp;
@@ -7722,12 +7878,12 @@ update_imm (unsigned int j)
       else if (i.prefix[DATA_PREFIX])
        overlap = operand_type_and (overlap,
                                    flag_code != CODE_16BIT ? imm16 : imm32);
-      if (!operand_type_equal (&overlap, &imm8)
-         && !operand_type_equal (&overlap, &imm8s)
-         && !operand_type_equal (&overlap, &imm16)
-         && !operand_type_equal (&overlap, &imm32)
-         && !operand_type_equal (&overlap, &imm32s)
-         && !operand_type_equal (&overlap, &imm64))
+      if (overlap.bitfield.imm8
+         + overlap.bitfield.imm8s
+         + overlap.bitfield.imm16
+         + overlap.bitfield.imm32
+         + overlap.bitfield.imm32s
+         + overlap.bitfield.imm64 != 1)
        {
          as_bad (_("no instruction mnemonic suffix given; "
                    "can't determine immediate size"));
@@ -7781,6 +7937,9 @@ process_operands (void)
 
   if (i.tm.opcode_modifier.sse2avx && i.tm.opcode_modifier.vexvvvv)
     {
+      static const i386_operand_type regxmm = {
+        .bitfield = { .class = RegSIMD, .xmmword = 1 }
+      };
       unsigned int dupl = i.operands;
       unsigned int dest = dupl - 1;
       unsigned int j;
@@ -7815,7 +7974,7 @@ process_operands (void)
                }
            }
        }
-      else if (i.tm.opcode_modifier.implicit1stxmm0)
+      else if (i.tm.opcode_modifier.operandconstraint == IMPLICIT_1ST_XMM0)
        {
          gas_assert ((MAX_OPERANDS - 1) > dupl
                      && (i.tm.opcode_modifier.vexsources
@@ -7883,7 +8042,7 @@ process_operands (void)
       i.reg_operands--;
       i.tm.operands--;
     }
-  else if (i.tm.opcode_modifier.implicitquadgroup)
+  else if (i.tm.opcode_modifier.operandconstraint == IMPLICIT_QUAD_GROUP)
     {
       unsigned int regnum, first_reg_in_group, last_reg_in_group;
 
@@ -7900,7 +8059,7 @@ process_operands (void)
                 register_prefix, i.op[1].regs->reg_name, last_reg_in_group,
                 i.tm.name);
     }
-  else if (i.tm.opcode_modifier.regkludge)
+  else if (i.tm.opcode_modifier.operandconstraint == REG_KLUDGE)
     {
       /* The imul $imm, %reg instruction is converted into
         imul $imm, %reg, %reg, and the clr %reg instruction
@@ -7964,29 +8123,31 @@ process_operands (void)
     {
       /* The register or float register operand is in operand
         0 or 1.  */
-      unsigned int op = i.tm.operand_types[0].bitfield.class != Reg;
+      const reg_entry *r = i.op[0].regs;
 
+      if (i.imm_operands
+         || (r->reg_type.bitfield.instance == Accum && i.op[1].regs))
+       r = i.op[1].regs;
       /* Register goes in low 3 bits of opcode.  */
-      i.tm.base_opcode |= i.op[op].regs->reg_num;
-      if ((i.op[op].regs->reg_flags & RegRex) != 0)
+      i.tm.base_opcode |= r->reg_num;
+      if ((r->reg_flags & RegRex) != 0)
        i.rex |= REX_B;
-      if (!quiet_warnings && i.tm.opcode_modifier.ugh)
+      if (!quiet_warnings && i.tm.opcode_modifier.operandconstraint == UGH)
        {
-         /* Warn about some common errors, but press on regardless.
-            The first case can be generated by gcc (<= 2.8.1).  */
-         if (i.operands == 2)
-           {
-             /* Reversed arguments on faddp, fsubp, etc.  */
-             as_warn (_("translating to `%s %s%s,%s%s'"), i.tm.name,
-                      register_prefix, i.op[!intel_syntax].regs->reg_name,
-                      register_prefix, i.op[intel_syntax].regs->reg_name);
-           }
-         else
+         /* Warn about some common errors, but press on regardless.  */
+         if (i.operands != 2)
            {
              /* Extraneous `l' suffix on fp insn.  */
              as_warn (_("translating to `%s %s%s'"), i.tm.name,
                       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,
+                      register_prefix, i.op[!intel_syntax].regs->reg_name,
+                      register_prefix, i.op[intel_syntax].regs->reg_name);
+           }
        }
     }
 
@@ -8086,7 +8247,7 @@ build_modrm_byte (void)
             immediate operand to encode the first operand.  */
          exp = &im_expressions[i.imm_operands++];
          i.op[i.operands].imms = exp;
-         i.types[i.operands] = imm8;
+         i.types[i.operands].bitfield.imm8 = 1;
          i.operands++;
 
          gas_assert (i.tm.operand_types[reg_slot].bitfield.class == RegSIMD);
@@ -8197,7 +8358,7 @@ build_modrm_byte (void)
              unsigned int vvvv;
 
              /* Swap two source operands if needed.  */
-             if (i.tm.opcode_modifier.swapsources)
+             if (i.tm.opcode_modifier.operandconstraint == SWAP_SOURCES)
                {
                  vvvv = source;
                  source = dest;
@@ -9120,6 +9281,44 @@ x86_cleanup (void)
   if (seg && subseg)
     subseg_set (seg, subseg);
 }
+
+bool
+x86_support_sframe_p (void)
+{
+  /* At this time, SFrame unwind is supported for AMD64 ABI only.  */
+  return (x86_elf_abi == X86_64_ABI);
+}
+
+bool
+x86_sframe_ra_tracking_p (void)
+{
+  /* In AMD64, return address is always stored on the stack at a fixed offset
+     from the CFA (provided via x86_sframe_cfa_ra_offset ()).
+     Do not track explicitly via an SFrame Frame Row Entry.  */
+  return false;
+}
+
+offsetT
+x86_sframe_cfa_ra_offset (void)
+{
+  gas_assert (x86_elf_abi == X86_64_ABI);
+  return (offsetT) -8;
+}
+
+unsigned char
+x86_sframe_get_abi_arch (void)
+{
+  unsigned char sframe_abi_arch = 0;
+
+  if (x86_support_sframe_p ())
+    {
+      gas_assert (!target_big_endian);
+      sframe_abi_arch = SFRAME_ABI_AMD64_ENDIAN_LITTLE;
+    }
+
+  return sframe_abi_arch;
+}
+
 #endif
 
 static unsigned int
@@ -10256,15 +10455,25 @@ lex_got (enum bfd_reloc_code_real *rel,
   }
     gotrel[] =
   {
+
+#define OPERAND_TYPE_IMM32_32S_DISP32 { .bitfield = \
+  { .imm32 = 1, .imm32s = 1, .disp32 = 1 } }
+#define OPERAND_TYPE_IMM32_32S_64_DISP32 { .bitfield = \
+  { .imm32 = 1, .imm32s = 1, .imm64 = 1, .disp32 = 1 } }
+#define OPERAND_TYPE_IMM32_32S_64_DISP32_64 { .bitfield = \
+  { .imm32 = 1, .imm32s = 1, .imm64 = 1, .disp32 = 1, .disp64 = 1 } }
+#define OPERAND_TYPE_IMM64_DISP64 { .bitfield = \
+  { .imm64 = 1, .disp64 = 1 } }
+
 #ifndef TE_PE
 #if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
     { STRING_COMMA_LEN ("SIZE"),      { BFD_RELOC_SIZE32,
                                        BFD_RELOC_SIZE32 },
-      OPERAND_TYPE_IMM32_64, false },
+      { .bitfield = { .imm32 = 1, .imm64 = 1 } }, false },
 #endif
     { STRING_COMMA_LEN ("PLTOFF"),   { _dummy_first_bfd_reloc_code_real,
                                       BFD_RELOC_X86_64_PLTOFF64 },
-      OPERAND_TYPE_IMM64, true },
+      { .bitfield = { .imm64 = 1 } }, true },
     { STRING_COMMA_LEN ("PLT"),      { BFD_RELOC_386_PLT32,
                                       BFD_RELOC_X86_64_PLT32    },
       OPERAND_TYPE_IMM32_32S_DISP32, false },
@@ -10318,6 +10527,12 @@ lex_got (enum bfd_reloc_code_real *rel,
                                       BFD_RELOC_32_SECREL },
       OPERAND_TYPE_IMM32_32S_64_DISP32_64, false },
 #endif
+
+#undef OPERAND_TYPE_IMM32_32S_DISP32
+#undef OPERAND_TYPE_IMM32_32S_64_DISP32
+#undef OPERAND_TYPE_IMM32_32S_64_DISP32_64
+#undef OPERAND_TYPE_IMM64_DISP64
+
   };
   char *cp;
   unsigned int j;
@@ -11158,8 +11373,14 @@ i386_addressing_mode (void)
                  if (flag_code != CODE_64BIT
                      && (i.types[this_operand].bitfield.disp16
                          || i.types[this_operand].bitfield.disp32))
-                   i.types[this_operand]
-                     = operand_type_xor (i.types[this_operand], disp16_32);
+                   {
+                     static const i386_operand_type disp16_32 = {
+                       .bitfield = { .disp16 = 1, .disp32 = 1 }
+                     };
+
+                     i.types[this_operand]
+                       = operand_type_xor (i.types[this_operand], disp16_32);
+                   }
                }
            }
        }
@@ -11177,12 +11398,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
-      && !t->cpu_flags.bitfield.cpupadlock
-      && (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.  */
@@ -11199,14 +11417,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,
@@ -11249,6 +11465,8 @@ i386_index_check (const char *operand_string)
     }
   else
     {
+      t = current_templates->start;
+
       if (addr_mode != CODE_16BIT)
        {
          /* 32-bit/64-bit checks.  */
@@ -11354,49 +11572,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)
@@ -11547,17 +11722,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 ','
@@ -11758,14 +11922,13 @@ i386_att_operand (char *operand_string)
          && !operand_type_check (i.types[this_operand], disp))
        {
          i.types[this_operand] = i.base_reg->reg_type;
+         i.input_output_operand = true;
          return 1;
        }
 
       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