x86: fold a few of the "alternative" NOP patterns
[binutils-gdb.git] / gas / config / tc-i386.c
index 438180cf4e8d08cb225962241ac8e6a89146db99..57ae6c522a715ffe5e3a0db852d1900f7238723d 100644 (file)
@@ -131,12 +131,14 @@ typedef struct
   unsigned int len:8;          /* arch string length */
   bool skip:1;                 /* show_arch should skip this. */
   enum processor_type type;    /* arch type */
+  enum { vsz_none, vsz_set, vsz_reset } vsz; /* vector size control */
   i386_cpu_flags enable;               /* cpu feature enable flags */
   i386_cpu_flags disable;      /* cpu feature disable flags */
 }
 arch_entry;
 
 static void update_code_flag (int, int);
+static void s_insn (int);
 static void set_code_flag (int);
 static void set_16bit_gcc_code_flag (int);
 static void set_intel_syntax (int);
@@ -158,14 +160,14 @@ static int i386_att_operand (char *);
 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 const char *parse_insn (const char *, char *);
+static const reg_entry *parse_register (const char *, char **);
+static const char *parse_insn (const char *, char *, bool);
 static char *parse_operands (char *, const char *);
 static void swap_operands (void);
 static void swap_2_operands (unsigned int, unsigned int);
-static enum flag_code i386_addressing_mode (void);
+static enum i386_flag_code i386_addressing_mode (void);
 static void optimize_imm (void);
-static void optimize_disp (void);
+static bool optimize_disp (const insn_template *t);
 static const insn_template *match_template (char);
 static int check_string (void);
 static int process_suffix (void);
@@ -253,6 +255,7 @@ enum i386_error
     no_default_mask,
     unsupported_rc_sae,
     invalid_register_operand,
+    internal_error,
   };
 
 struct _i386_insn
@@ -287,6 +290,7 @@ struct _i386_insn
     unsigned int flags[MAX_OPERANDS];
 #define Operand_PCrel 1
 #define Operand_Mem   2
+#define Operand_Signed 4 /* .insn only */
 
     /* Relocation type for operand */
     enum bfd_reloc_code_real reloc[MAX_OPERANDS];
@@ -306,6 +310,12 @@ struct _i386_insn
     unsigned int prefixes;
     unsigned char prefix[MAX_PREFIXES];
 
+    /* .insn allows for reserved opcode spaces.  */
+    unsigned char insn_opcode_space;
+
+    /* .insn also allows (requires) specifying immediate size.  */
+    unsigned char imm_bits[MAX_OPERANDS];
+
     /* Register is in low 3 bits of opcode.  */
     bool short_form;
 
@@ -427,6 +437,7 @@ struct _i386_insn
        vex_encoding_vex,
        vex_encoding_vex3,
        vex_encoding_evex,
+       vex_encoding_evex512,
        vex_encoding_error
       } vec_encoding;
 
@@ -531,17 +542,15 @@ const char FLT_CHARS[] = "fFdDxXhHbB";
 static char mnemonic_chars[256];
 static char register_chars[256];
 static char operand_chars[256];
-static char identifier_chars[256];
 
 /* Lexical macros.  */
-#define is_mnemonic_char(x) (mnemonic_chars[(unsigned char) x])
 #define is_operand_char(x) (operand_chars[(unsigned char) x])
 #define is_register_char(x) (register_chars[(unsigned char) x])
 #define is_space_char(x) ((x) == ' ')
-#define is_identifier_char(x) (identifier_chars[(unsigned char) x])
 
-/* All non-digit non-letter characters that may occur in an operand.  */
-static char operand_special_chars[] = "%$-+(,)*._~/<>|&^!:[@]";
+/* All non-digit non-letter characters that may occur in an operand and
+   which aren't already in extra_symbol_chars[].  */
+static const char operand_special_chars[] = "$+,)._~/<>|&^!=:@]";
 
 /* md_assemble() always leaves the strings it's passed unaltered.  To
    effect this we maintain a stack of saved characters that we've smashed
@@ -567,15 +576,11 @@ static expressionS im_expressions[MAX_IMMEDIATE_OPERANDS];
 /* Current operand we are working on.  */
 static int this_operand = -1;
 
-/* We support four different modes.  FLAG_CODE variable is used to distinguish
-   these.  */
+/* Are we processing a .insn directive?  */
+#define dot_insn() (i.tm.mnem_off == MN__insn)
 
-enum flag_code {
-       CODE_32BIT,
-       CODE_16BIT,
-       CODE_64BIT };
-
-static enum flag_code flag_code;
+enum i386_flag_code i386_flag_code;
+#define flag_code i386_flag_code /* Permit to continue using original name.  */
 static unsigned int object_64bit;
 static unsigned int disallow_64bit_reloc;
 static int use_rela_relocations = 0;
@@ -797,7 +802,7 @@ static const char *cpu_arch_name = NULL;
 static char *cpu_sub_arch_name = NULL;
 
 /* CPU feature flags.  */
-static i386_cpu_flags cpu_arch_flags = CPU_UNKNOWN_FLAGS;
+i386_cpu_flags cpu_arch_flags = CPU_UNKNOWN_FLAGS;
 
 /* If we have selected a cpu we are generating instructions for.  */
 static int cpu_arch_tune_set = 0;
@@ -805,9 +810,6 @@ static int cpu_arch_tune_set = 0;
 /* Cpu we are generating instructions for.  */
 enum processor_type cpu_arch_tune = PROCESSOR_UNKNOWN;
 
-/* CPU feature flags of cpu we are generating instructions for.  */
-static i386_cpu_flags cpu_arch_tune_flags;
-
 /* CPU instruction set architecture used.  */
 enum processor_type cpu_arch_isa = PROCESSOR_UNKNOWN;
 
@@ -818,12 +820,24 @@ i386_cpu_flags cpu_arch_isa_flags;
    larger than a byte offset.  */
 static bool no_cond_jump_promotion = false;
 
+/* This will be set from an expression parser hook if there's any
+   applicable operator involved in an expression.  */
+static enum {
+  expr_operator_none,
+  expr_operator_present,
+  expr_large_value,
+} expr_mode;
+
 /* Encode SSE instructions with VEX prefix.  */
 static unsigned int sse2avx;
 
 /* Encode aligned vector move as unaligned vector move.  */
 static unsigned int use_unaligned_vector_move;
 
+/* Maximum permitted vector size. */
+#define VSZ_DEFAULT VSZ512
+static unsigned int vector_size = VSZ_DEFAULT;
+
 /* Encode scalar AVX instructions with specific vector length.  */
 static enum
   {
@@ -952,11 +966,14 @@ const relax_typeS md_relax_table[] =
 };
 
 #define ARCH(n, t, f, s) \
-  { STRING_COMMA_LEN (#n), s, PROCESSOR_ ## t, CPU_ ## f ## _FLAGS, \
+  { STRING_COMMA_LEN (#n), s, PROCESSOR_ ## t, vsz_none, CPU_ ## f ## _FLAGS, \
     CPU_NONE_FLAGS }
 #define SUBARCH(n, e, d, s) \
-  { STRING_COMMA_LEN (#n), s, PROCESSOR_NONE, CPU_ ## e ## _FLAGS, \
+  { STRING_COMMA_LEN (#n), s, PROCESSOR_NONE, vsz_none, CPU_ ## e ## _FLAGS, \
     CPU_ ## d ## _FLAGS }
+#define VECARCH(n, e, d, v) \
+  { STRING_COMMA_LEN (#n), false, PROCESSOR_NONE, vsz_ ## v, \
+    CPU_ ## e ## _FLAGS, CPU_ ## d ## _FLAGS }
 
 static const arch_entry cpu_arch[] =
 {
@@ -970,8 +987,8 @@ static const arch_entry cpu_arch[] =
   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 (i686, I686, 686, false),
   ARCH (pentiumpro, PENTIUMPRO, PENTIUMPRO, false),
   ARCH (pentiumii, PENTIUMPRO, P2, false),
   ARCH (pentiumiii, PENTIUMPRO, P3, false),
@@ -1018,15 +1035,16 @@ static const arch_entry cpu_arch[] =
   SUBARCH (sse4.1, SSE4_1, ANY_SSE4_1, false),
   SUBARCH (sse4.2, SSE4_2, ANY_SSE4_2, false),
   SUBARCH (sse4, SSE4_2, ANY_SSE4_1, false),
-  SUBARCH (avx, AVX, ANY_AVX, false),
-  SUBARCH (avx2, AVX2, ANY_AVX2, false),
-  SUBARCH (avx512f, AVX512F, ANY_AVX512F, false),
-  SUBARCH (avx512cd, AVX512CD, ANY_AVX512CD, false),
-  SUBARCH (avx512er, AVX512ER, ANY_AVX512ER, false),
-  SUBARCH (avx512pf, AVX512PF, ANY_AVX512PF, false),
-  SUBARCH (avx512dq, AVX512DQ, ANY_AVX512DQ, false),
-  SUBARCH (avx512bw, AVX512BW, ANY_AVX512BW, false),
-  SUBARCH (avx512vl, AVX512VL, ANY_AVX512VL, false),
+  VECARCH (avx, AVX, ANY_AVX, reset),
+  VECARCH (avx2, AVX2, ANY_AVX2, reset),
+  VECARCH (avx512f, AVX512F, ANY_AVX512F, reset),
+  VECARCH (avx512cd, AVX512CD, ANY_AVX512CD, reset),
+  VECARCH (avx512er, AVX512ER, ANY_AVX512ER, reset),
+  VECARCH (avx512pf, AVX512PF, ANY_AVX512PF, reset),
+  VECARCH (avx512dq, AVX512DQ, ANY_AVX512DQ, reset),
+  VECARCH (avx512bw, AVX512BW, ANY_AVX512BW, reset),
+  VECARCH (avx512vl, AVX512VL, ANY_AVX512VL, reset),
+  SUBARCH (monitor, MONITOR, MONITOR, false),
   SUBARCH (vmx, VMX, ANY_VMX, false),
   SUBARCH (vmfunc, VMFUNC, ANY_VMFUNC, false),
   SUBARCH (smx, SMX, SMX, false),
@@ -1035,8 +1053,8 @@ static const arch_entry cpu_arch[] =
   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 (pclmul, PCLMULQDQ, ANY_PCLMULQDQ, false),
+  SUBARCH (clmul, PCLMULQDQ, ANY_PCLMULQDQ, true),
   SUBARCH (fsgsbase, FSGSBASE, FSGSBASE, false),
   SUBARCH (rdrnd, RDRND, RDRND, false),
   SUBARCH (f16c, F16C, ANY_F16C, false),
@@ -1047,6 +1065,7 @@ static const arch_entry cpu_arch[] =
   SUBARCH (lwp, LWP, ANY_LWP, false),
   SUBARCH (movbe, MOVBE, MOVBE, false),
   SUBARCH (cx16, CX16, CX16, false),
+  SUBARCH (lahf_sahf, LAHF_SAHF, LAHF_SAHF, false),
   SUBARCH (ept, EPT, ANY_EPT, false),
   SUBARCH (lzcnt, LZCNT, LZCNT, false),
   SUBARCH (popcnt, POPCNT, POPCNT, false),
@@ -1076,15 +1095,15 @@ static const arch_entry cpu_arch[] =
   SUBARCH (prefetchwt1, PREFETCHWT1, PREFETCHWT1, false),
   SUBARCH (se1, SE1, SE1, false),
   SUBARCH (clwb, CLWB, CLWB, false),
-  SUBARCH (avx512ifma, AVX512IFMA, ANY_AVX512IFMA, false),
-  SUBARCH (avx512vbmi, AVX512VBMI, ANY_AVX512VBMI, false),
-  SUBARCH (avx512_4fmaps, AVX512_4FMAPS, ANY_AVX512_4FMAPS, false),
-  SUBARCH (avx512_4vnniw, AVX512_4VNNIW, ANY_AVX512_4VNNIW, false),
-  SUBARCH (avx512_vpopcntdq, AVX512_VPOPCNTDQ, ANY_AVX512_VPOPCNTDQ, false),
-  SUBARCH (avx512_vbmi2, AVX512_VBMI2, ANY_AVX512_VBMI2, false),
-  SUBARCH (avx512_vnni, AVX512_VNNI, ANY_AVX512_VNNI, false),
-  SUBARCH (avx512_bitalg, AVX512_BITALG, ANY_AVX512_BITALG, false),
-  SUBARCH (avx_vnni, AVX_VNNI, ANY_AVX_VNNI, false),
+  VECARCH (avx512ifma, AVX512IFMA, ANY_AVX512IFMA, reset),
+  VECARCH (avx512vbmi, AVX512VBMI, ANY_AVX512VBMI, reset),
+  VECARCH (avx512_4fmaps, AVX512_4FMAPS, ANY_AVX512_4FMAPS, reset),
+  VECARCH (avx512_4vnniw, AVX512_4VNNIW, ANY_AVX512_4VNNIW, reset),
+  VECARCH (avx512_vpopcntdq, AVX512_VPOPCNTDQ, ANY_AVX512_VPOPCNTDQ, reset),
+  VECARCH (avx512_vbmi2, AVX512_VBMI2, ANY_AVX512_VBMI2, reset),
+  VECARCH (avx512_vnni, AVX512_VNNI, ANY_AVX512_VNNI, reset),
+  VECARCH (avx512_bitalg, AVX512_BITALG, ANY_AVX512_BITALG, reset),
+  VECARCH (avx_vnni, AVX_VNNI, ANY_AVX_VNNI, reset),
   SUBARCH (clzero, CLZERO, CLZERO, false),
   SUBARCH (mwaitx, MWAITX, MWAITX, false),
   SUBARCH (ospke, OSPKE, ANY_OSPKE, false),
@@ -1093,8 +1112,8 @@ static const arch_entry cpu_arch[] =
   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),
+  VECARCH (vaes, VAES, ANY_VAES, reset),
+  VECARCH (vpclmulqdq, VPCLMULQDQ, ANY_VPCLMULQDQ, reset),
   SUBARCH (wbnoinvd, WBNOINVD, WBNOINVD, false),
   SUBARCH (pconfig, PCONFIG, PCONFIG, false),
   SUBARCH (waitpkg, WAITPKG, WAITPKG, false),
@@ -1102,12 +1121,13 @@ static const arch_entry cpu_arch[] =
   SUBARCH (amx_int8, AMX_INT8, ANY_AMX_INT8, false),
   SUBARCH (amx_bf16, AMX_BF16, ANY_AMX_BF16, false),
   SUBARCH (amx_fp16, AMX_FP16, ANY_AMX_FP16, false),
+  SUBARCH (amx_complex, AMX_COMPLEX, ANY_AMX_COMPLEX, false),
   SUBARCH (amx_tile, AMX_TILE, ANY_AMX_TILE, 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),
+  VECARCH (avx512_bf16, AVX512_BF16, ANY_AVX512_BF16, reset),
+  VECARCH (avx512_vp2intersect, AVX512_VP2INTERSECT,
+          ANY_AVX512_VP2INTERSECT, reset),
   SUBARCH (tdx, TDX, TDX, false),
   SUBARCH (enqcmd, ENQCMD, ENQCMD, false),
   SUBARCH (serialize, SERIALIZE, SERIALIZE, false),
@@ -1119,16 +1139,24 @@ static const arch_entry cpu_arch[] =
   SUBARCH (widekl, WIDEKL, ANY_WIDEKL, false),
   SUBARCH (uintr, UINTR, UINTR, false),
   SUBARCH (hreset, HRESET, HRESET, false),
-  SUBARCH (avx512_fp16, AVX512_FP16, ANY_AVX512_FP16, false),
+  VECARCH (avx512_fp16, AVX512_FP16, ANY_AVX512_FP16, reset),
   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),
+  VECARCH (avx_ifma, AVX_IFMA, ANY_AVX_IFMA, reset),
+  VECARCH (avx_vnni_int8, AVX_VNNI_INT8, ANY_AVX_VNNI_INT8, reset),
   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),
+  VECARCH (avx_ne_convert, AVX_NE_CONVERT, ANY_AVX_NE_CONVERT, reset),
   SUBARCH (rao_int, RAO_INT, RAO_INT, false),
   SUBARCH (rmpquery, RMPQUERY, ANY_RMPQUERY, false),
+  SUBARCH (fred, FRED, ANY_FRED, false),
+  SUBARCH (lkgs, LKGS, ANY_LKGS, false),
+  VECARCH (avx_vnni_int16, AVX_VNNI_INT16, ANY_AVX_VNNI_INT16, reset),
+  VECARCH (sha512, SHA512, ANY_SHA512, reset),
+  VECARCH (sm3, SM3, ANY_SM3, reset),
+  VECARCH (sm4, SM4, ANY_SM4, reset),
+  SUBARCH (pbndkb, PBNDKB, PBNDKB, false),
+  VECARCH (avx10.1, AVX10_1, ANY_AVX512F, set),
 };
 
 #undef SUBARCH
@@ -1196,6 +1224,7 @@ const pseudo_typeS md_pseudo_table[] =
   {"bfloat16", float_cons, 'b'},
   {"value", cons, 2},
   {"slong", signed_cons, 4},
+  {"insn", s_insn, 0},
   {"noopt", s_ignore, 0},
   {"optim", s_ignore, 0},
   {"code16gcc", set_16bit_gcc_code_flag, CODE_16BIT},
@@ -1244,16 +1273,32 @@ static const unsigned char f32_2[] =
   {0x66,0x90};                         /* xchg %ax,%ax         */
 static const unsigned char f32_3[] =
   {0x8d,0x76,0x00};                    /* leal 0(%esi),%esi    */
-static const unsigned char f32_4[] =
-  {0x8d,0x74,0x26,0x00};               /* leal 0(%esi,1),%esi  */
+#define f32_4 (f32_5 + 1)      /* leal 0(%esi,%eiz),%esi */
+static const unsigned char f32_5[] =
+  {0x2e,0x8d,0x74,0x26,0x00};          /* leal %cs:0(%esi,%eiz),%esi   */
 static const unsigned char f32_6[] =
   {0x8d,0xb6,0x00,0x00,0x00,0x00};     /* leal 0L(%esi),%esi   */
-static const unsigned char f32_7[] =
-  {0x8d,0xb4,0x26,0x00,0x00,0x00,0x00};        /* leal 0L(%esi,1),%esi */
+#define f32_7 (f32_8 + 1)      /* leal 0L(%esi,%eiz),%esi */
+static const unsigned char f32_8[] =
+  {0x2e,0x8d,0xb4,0x26,0x00,0x00,0x00,0x00}; /* leal %cs:0L(%esi,%eiz),%esi */
+static const unsigned char f64_3[] =
+  {0x48,0x89,0xf6};                    /* mov %rsi,%rsi        */
+static const unsigned char f64_4[] =
+  {0x48,0x8d,0x76,0x00};               /* lea 0(%rsi),%rsi     */
+#define f64_5 (f64_6 + 1)              /* lea 0(%rsi,%riz),%rsi        */
+static const unsigned char f64_6[] =
+  {0x2e,0x48,0x8d,0x74,0x26,0x00};     /* lea %cs:0(%rsi,%riz),%rsi    */
+static const unsigned char f64_7[] =
+  {0x48,0x8d,0xb6,0x00,0x00,0x00,0x00};        /* lea 0L(%rsi),%rsi    */
+#define f64_8 (f64_9 + 1)              /* lea 0L(%rsi,%riz),%rsi */
+static const unsigned char f64_9[] =
+  {0x2e,0x48,0x8d,0xb4,0x26,0x00,0x00,0x00,0x00}; /* lea %cs:0L(%rsi,%riz),%rsi */
+#define f16_2 (f64_3 + 1)              /* mov %si,%si  */
 static const unsigned char f16_3[] =
   {0x8d,0x74,0x00};                    /* lea 0(%si),%si       */
-static const unsigned char f16_4[] =
-  {0x8d,0xb4,0x00,0x00};               /* lea 0W(%si),%si      */
+#define f16_4 (f16_5 + 1)              /* lea 0W(%si),%si */
+static const unsigned char f16_5[] =
+  {0x2e,0x8d,0xb4,0x00,0x00};          /* lea %cs:0W(%si),%si  */
 static const unsigned char jump_disp8[] =
   {0xeb};                              /* jmp disp8           */
 static const unsigned char jump32_disp32[] =
@@ -1262,11 +1307,15 @@ static const unsigned char jump16_disp32[] =
   {0x66,0xe9};                         /* jmp disp32          */
 /* 32-bit NOPs patterns.  */
 static const unsigned char *const f32_patt[] = {
-  f32_1, f32_2, f32_3, f32_4, NULL, f32_6, f32_7
+  f32_1, f32_2, f32_3, f32_4, f32_5, f32_6, f32_7, f32_8
+};
+/* 64-bit NOPs patterns.  */
+static const unsigned char *const f64_patt[] = {
+  f32_1, f32_2, f64_3, f64_4, f64_5, f64_6, f64_7, f64_8, f64_9
 };
 /* 16-bit NOPs patterns.  */
 static const unsigned char *const f16_patt[] = {
-  f32_1, f32_2, f16_3, f16_4
+  f32_1, f16_2, f16_3, f16_4, f16_5
 };
 /* nopl (%[re]ax) */
 static const unsigned char alt_3[] =
@@ -1275,8 +1324,7 @@ static const unsigned char alt_3[] =
 static const unsigned char alt_4[] =
   {0x0f,0x1f,0x40,0x00};
 /* nopl 0(%[re]ax,%[re]ax,1) */
-static const unsigned char alt_5[] =
-  {0x0f,0x1f,0x44,0x00,0x00};
+#define alt_5 (alt_6 + 1)
 /* nopw 0(%[re]ax,%[re]ax,1) */
 static const unsigned char alt_6[] =
   {0x66,0x0f,0x1f,0x44,0x00,0x00};
@@ -1284,14 +1332,12 @@ static const unsigned char alt_6[] =
 static const unsigned char alt_7[] =
   {0x0f,0x1f,0x80,0x00,0x00,0x00,0x00};
 /* nopl 0L(%[re]ax,%[re]ax,1) */
-static const unsigned char alt_8[] =
-  {0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00};
+#define alt_8 (alt_9 + 1)
 /* nopw 0L(%[re]ax,%[re]ax,1) */
 static const unsigned char alt_9[] =
   {0x66,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00};
 /* nopw %cs:0L(%[re]ax,%[re]ax,1) */
-static const unsigned char alt_10[] =
-  {0x66,0x2e,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00};
+#define alt_10 (alt_11 + 1)
 /* data16 nopw %cs:0L(%eax,%eax,1) */
 static const unsigned char alt_11[] =
   {0x66,0x66,0x2e,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00};
@@ -1322,14 +1368,6 @@ i386_output_nops (char *where, const unsigned char *const *patt,
     }
 
   nops = patt[max_single_nop_size - 1];
-
-  /* Use the smaller one if the requsted one isn't available.  */
-  if (nops == NULL)
-    {
-      max_single_nop_size--;
-      nops = patt[max_single_nop_size - 1];
-    }
-
   last = count % max_single_nop_size;
 
   count -= last;
@@ -1339,17 +1377,7 @@ i386_output_nops (char *where, const unsigned char *const *patt,
   if (last)
     {
       nops = patt[last - 1];
-      if (nops == NULL)
-       {
-         /* Use the smaller one plus one-byte NOP if the needed one
-            isn't available.  */
-         last--;
-         nops = patt[last - 1];
-         memcpy (where + offset, nops, last);
-         where[offset + last] = *patt[0];
-       }
-      else
-       memcpy (where + offset, nops, last);
+      memcpy (where + offset, nops, last);
     }
 }
 
@@ -1394,18 +1422,18 @@ i386_generate_nops (fragS *fragP, char *where, offsetT count, int limit)
   /* We need to decide which NOP sequence to use for 32bit and
      64bit. When -mtune= is used:
 
-     1. For PROCESSOR_I386, PROCESSOR_I486, PROCESSOR_PENTIUM and
+     1. For PROCESSOR_I?86, PROCESSOR_PENTIUM, PROCESSOR_IAMCU, and
      PROCESSOR_GENERIC32, f32_patt will be used.
      2. For the rest, alt_patt will be used.
 
      When -mtune= isn't used, alt_patt will be used if
-     cpu_arch_isa_flags has CpuNop.  Otherwise, f32_patt will
+     cpu_arch_isa_flags has CpuNop.  Otherwise, f32_patt/f64_patt will
      be used.
 
      When -march= or .arch is used, we can't use anything beyond
      cpu_arch_isa_flags.   */
 
-  if (flag_code == CODE_16BIT)
+  if (fragP->tc_frag_data.code == CODE_16BIT)
     {
       patt = f16_patt;
       max_single_nop_size = sizeof (f16_patt) / sizeof (f16_patt[0]);
@@ -1414,19 +1442,21 @@ i386_generate_nops (fragS *fragP, char *where, offsetT count, int limit)
     }
   else
     {
+      patt = fragP->tc_frag_data.code == CODE_64BIT ? f64_patt : f32_patt;
       if (fragP->tc_frag_data.isa == PROCESSOR_UNKNOWN)
        {
-         /* PROCESSOR_UNKNOWN means that all ISAs may be used.  */
-         switch (cpu_arch_tune)
+         /* PROCESSOR_UNKNOWN means that all ISAs may be used, unless
+            explicitly disabled.  */
+         switch (fragP->tc_frag_data.tune)
            {
            case PROCESSOR_UNKNOWN:
              /* We use cpu_arch_isa_flags to check if we SHOULD
                 optimize with nops.  */
-             if (fragP->tc_frag_data.isa_flags.bitfield.cpunop)
+             if (fragP->tc_frag_data.isanop)
                patt = alt_patt;
-             else
-               patt = f32_patt;
              break;
+
+           case PROCESSOR_PENTIUMPRO:
            case PROCESSOR_PENTIUM4:
            case PROCESSOR_NOCONA:
            case PROCESSOR_CORE:
@@ -1440,15 +1470,16 @@ i386_generate_nops (fragS *fragP, char *where, offsetT count, int limit)
            case PROCESSOR_BD:
            case PROCESSOR_ZNVER:
            case PROCESSOR_BT:
-             patt = alt_patt;
+             if (fragP->tc_frag_data.cpunop)
+               patt = alt_patt;
              break;
+
            case PROCESSOR_I386:
            case PROCESSOR_I486:
            case PROCESSOR_PENTIUM:
-           case PROCESSOR_PENTIUMPRO:
+           case PROCESSOR_I686:
            case PROCESSOR_IAMCU:
            case PROCESSOR_GENERIC32:
-             patt = f32_patt;
              break;
            case PROCESSOR_NONE:
              abort ();
@@ -1464,47 +1495,22 @@ i386_generate_nops (fragS *fragP, char *where, offsetT count, int limit)
              abort ();
              break;
 
-           case PROCESSOR_I386:
-           case PROCESSOR_I486:
-           case PROCESSOR_PENTIUM:
-           case PROCESSOR_IAMCU:
-           case PROCESSOR_K6:
-           case PROCESSOR_ATHLON:
-           case PROCESSOR_K8:
-           case PROCESSOR_AMDFAM10:
-           case PROCESSOR_BD:
-           case PROCESSOR_ZNVER:
-           case PROCESSOR_BT:
-           case PROCESSOR_GENERIC32:
+           default:
              /* We use cpu_arch_isa_flags to check if we CAN optimize
                 with nops.  */
-             if (fragP->tc_frag_data.isa_flags.bitfield.cpunop)
-               patt = alt_patt;
-             else
-               patt = f32_patt;
-             break;
-           case PROCESSOR_PENTIUMPRO:
-           case PROCESSOR_PENTIUM4:
-           case PROCESSOR_NOCONA:
-           case PROCESSOR_CORE:
-           case PROCESSOR_CORE2:
-           case PROCESSOR_COREI7:
-             if (fragP->tc_frag_data.isa_flags.bitfield.cpunop)
+             if (fragP->tc_frag_data.isanop)
                patt = alt_patt;
-             else
-               patt = f32_patt;
-             break;
-           case PROCESSOR_GENERIC64:
-             patt = alt_patt;
              break;
+
            case PROCESSOR_NONE:
              abort ();
            }
        }
 
-      if (patt == f32_patt)
+      if (patt != alt_patt)
        {
-         max_single_nop_size = sizeof (f32_patt) / sizeof (f32_patt[0]);
+         max_single_nop_size = patt == f32_patt ? ARRAY_SIZE (f32_patt)
+                                                : ARRAY_SIZE (f64_patt);
          /* Limit number of NOPs to 2 for older processors.  */
          max_number_of_nops = 2;
        }
@@ -1644,6 +1650,51 @@ operand_type_equal (const union i386_operand_type *x,
     }
 }
 
+static INLINE bool
+is_cpu (const insn_template *t, enum i386_cpu cpu)
+{
+  switch (cpu)
+    {
+    case Cpu287:      return t->cpu.bitfield.cpu287;
+    case Cpu387:      return t->cpu.bitfield.cpu387;
+    case Cpu3dnow:    return t->cpu.bitfield.cpu3dnow;
+    case Cpu3dnowA:   return t->cpu.bitfield.cpu3dnowa;
+    case CpuAVX:      return t->cpu.bitfield.cpuavx;
+    case CpuHLE:      return t->cpu.bitfield.cpuhle;
+    case CpuAVX512F:  return t->cpu.bitfield.cpuavx512f;
+    case CpuAVX512VL: return t->cpu.bitfield.cpuavx512vl;
+    case Cpu64:       return t->cpu.bitfield.cpu64;
+    case CpuNo64:     return t->cpu.bitfield.cpuno64;
+    default:
+      gas_assert (cpu < CpuAttrEnums);
+    }
+  return t->cpu.bitfield.isa == cpu + 1u;
+}
+
+static i386_cpu_flags cpu_flags_from_attr (i386_cpu_attr a)
+{
+  const unsigned int bps = sizeof (a.array[0]) * CHAR_BIT;
+  i386_cpu_flags f = { .array[0] = 0 };
+
+  switch (ARRAY_SIZE(a.array))
+    {
+    case 1:
+      f.array[CpuAttrEnums / bps]
+        |= (a.array[0] >> CpuIsaBits) << (CpuAttrEnums % bps);
+      if (CpuAttrEnums % bps > CpuIsaBits)
+       f.array[CpuAttrEnums / bps + 1]
+         = (a.array[0] >> CpuIsaBits) >> (bps - CpuAttrEnums % bps);
+      break;
+    default:
+      abort ();
+    }
+
+  if (a.bitfield.isa)
+    f.array[(a.bitfield.isa - 1) / bps] |= 1u << ((a.bitfield.isa - 1) % bps);
+
+  return f;
+}
+
 static INLINE int
 cpu_flags_all_zero (const union i386_cpu_flags *x)
 {
@@ -1703,10 +1754,11 @@ cpu_flags_equal (const union i386_cpu_flags *x,
 }
 
 static INLINE int
-cpu_flags_check_cpu64 (i386_cpu_flags f)
+cpu_flags_check_cpu64 (const insn_template *t)
 {
-  return !((flag_code == CODE_64BIT && f.bitfield.cpuno64)
-          || (flag_code != CODE_64BIT && f.bitfield.cpu64));
+  return flag_code == CODE_64BIT
+        ? !t->cpu.bitfield.cpuno64
+        : !t->cpu.bitfield.cpu64;
 }
 
 static INLINE i386_cpu_flags
@@ -1789,6 +1841,13 @@ cpu_flags_and_not (i386_cpu_flags x, i386_cpu_flags y)
 
 static const i386_cpu_flags avx512 = CPU_ANY_AVX512F_FLAGS;
 
+static INLINE bool need_evex_encoding (void)
+{
+  return i.vec_encoding == vex_encoding_evex
+       || i.vec_encoding == vex_encoding_evex512
+       || i.mask.reg;
+}
+
 #define CPU_FLAGS_ARCH_MATCH           0x1
 #define CPU_FLAGS_64BIT_MATCH          0x2
 
@@ -1800,8 +1859,8 @@ static const i386_cpu_flags avx512 = CPU_ANY_AVX512F_FLAGS;
 static int
 cpu_flags_match (const insn_template *t)
 {
-  i386_cpu_flags x = t->cpu_flags;
-  int match = cpu_flags_check_cpu64 (x) ? CPU_FLAGS_64BIT_MATCH : 0;
+  i386_cpu_flags x = cpu_flags_from_attr (t->cpu);
+  int match = cpu_flags_check_cpu64 (t) ? CPU_FLAGS_64BIT_MATCH : 0;
 
   x.bitfield.cpu64 = 0;
   x.bitfield.cpuno64 = 0;
@@ -1816,6 +1875,31 @@ cpu_flags_match (const insn_template *t)
       /* This instruction is available only on some archs.  */
       i386_cpu_flags cpu = cpu_arch_flags;
 
+      /* Dual VEX/EVEX templates may need stripping of one of the flags.  */
+      if (t->opcode_modifier.vex && t->opcode_modifier.evex)
+       {
+         /* Dual AVX/AVX512F templates need to retain AVX512F only if we already
+            know that EVEX encoding will be needed.  */
+         if ((x.bitfield.cpuavx || x.bitfield.cpuavx2)
+             && x.bitfield.cpuavx512f)
+           {
+             if (need_evex_encoding ())
+               {
+                 x.bitfield.cpuavx = 0;
+                 x.bitfield.cpuavx2 = 0;
+               }
+             /* need_evex_encoding() isn't reliable before operands were
+                parsed.  */
+             else if (i.operands)
+               {
+                 x.bitfield.cpuavx512f = 0;
+                 x.bitfield.cpuavx512vl = 0;
+                 if (x.bitfield.cpufma && !cpu.bitfield.cpufma)
+                   x.bitfield.cpuavx = 0;
+               }
+           }
+       }
+
       /* AVX512VL is no standalone feature - match it and then strip it.  */
       if (x.bitfield.cpuavx512vl && !cpu.bitfield.cpuavx512vl)
        return match;
@@ -1830,7 +1914,19 @@ cpu_flags_match (const insn_template *t)
       cpu = cpu_flags_and (x, cpu);
       if (!cpu_flags_all_zero (&cpu))
        {
-         if (x.bitfield.cpuavx)
+         if (t->cpu.bitfield.cpuavx && t->cpu.bitfield.cpuavx512f)
+           {
+             if ((need_evex_encoding ()
+                  ? cpu.bitfield.cpuavx512f
+                  : cpu.bitfield.cpuavx)
+                 && (!x.bitfield.cpufma || cpu.bitfield.cpufma
+                     || cpu_arch_flags.bitfield.cpuavx512f)
+                 && (!x.bitfield.cpugfni || cpu.bitfield.cpugfni)
+                 && (!x.bitfield.cpuvaes || cpu.bitfield.cpuvaes)
+                 && (!x.bitfield.cpuvpclmulqdq || cpu.bitfield.cpuvpclmulqdq))
+               match |= CPU_FLAGS_ARCH_MATCH;
+           }
+         else if (x.bitfield.cpuavx)
            {
              /* We need to check a few extra flags with AVX.  */
              if (cpu.bitfield.cpuavx
@@ -1838,16 +1934,16 @@ cpu_flags_match (const insn_template *t)
                      || (sse2avx && !i.prefix[DATA_PREFIX]))
                  && (!x.bitfield.cpuaes || cpu.bitfield.cpuaes)
                  && (!x.bitfield.cpugfni || cpu.bitfield.cpugfni)
-                 && (!x.bitfield.cpupclmul || cpu.bitfield.cpupclmul))
+                 && (!x.bitfield.cpupclmulqdq || cpu.bitfield.cpupclmulqdq))
                match |= CPU_FLAGS_ARCH_MATCH;
            }
+         else if (x.bitfield.cpuavx2 && cpu.bitfield.cpuavx2)
+           match |= CPU_FLAGS_ARCH_MATCH;
          else if (x.bitfield.cpuavx512f)
            {
              /* We need to check a few extra flags with AVX512F.  */
              if (cpu.bitfield.cpuavx512f
-                 && (!x.bitfield.cpugfni || cpu.bitfield.cpugfni)
-                 && (!x.bitfield.cpuvaes || cpu.bitfield.cpuvaes)
-                 && (!x.bitfield.cpuvpclmulqdq || cpu.bitfield.cpuvpclmulqdq))
+                 && (!x.bitfield.cpugfni || cpu.bitfield.cpugfni))
                match |= CPU_FLAGS_ARCH_MATCH;
            }
          else
@@ -2135,16 +2231,15 @@ operand_size_match (const insn_template *t)
     return match;
 
   /* Check reverse.  */
-  gas_assert ((i.operands >= 2 && i.operands <= 3)
-             || t->opcode_modifier.vexsources);
+  gas_assert (i.operands >= 2);
 
   for (j = 0; j < i.operands; j++)
     {
       unsigned int given = i.operands - j - 1;
 
-      /* For 4- and 5-operand insns VEX.W controls just the first two
+      /* For FMA4 and XOP insns VEX.W controls just the first two
         register operands.  */
-      if (t->opcode_modifier.vexsources)
+      if (is_cpu (t, CpuFMA4) || is_cpu (t, CpuXOP))
        given = j < 2 ? 1 - j : j;
 
       if (t->operand_types[j].bitfield.class == Reg
@@ -2347,7 +2442,8 @@ fits_in_disp8 (offsetT num)
 static INLINE int
 fits_in_imm4 (offsetT num)
 {
-  return (num & 0xf) == num;
+  /* Despite the name, check for imm3 if we're dealing with EVEX.  */
+  return (num & (i.vec_encoding != vex_encoding_evex ? 0xf : 7)) == num;
 }
 
 static i386_operand_type
@@ -2374,7 +2470,8 @@ smallest_imm_type (offsetT num)
     }
   else if (fits_in_signed_byte (num))
     {
-      t.bitfield.imm8 = 1;
+      if (fits_in_unsigned_byte (num))
+       t.bitfield.imm8 = 1;
       t.bitfield.imm8s = 1;
       t.bitfield.imm16 = 1;
       t.bitfield.imm32 = 1;
@@ -2526,37 +2623,24 @@ add_prefix (unsigned int prefix)
 static void
 update_code_flag (int value, int check)
 {
-  PRINTF_LIKE ((*as_error));
+  PRINTF_LIKE ((*as_error)) = check ? as_fatal : as_bad;
 
-  flag_code = (enum flag_code) value;
-  if (flag_code == CODE_64BIT)
-    {
-      cpu_arch_flags.bitfield.cpu64 = 1;
-      cpu_arch_flags.bitfield.cpuno64 = 0;
-    }
-  else
-    {
-      cpu_arch_flags.bitfield.cpu64 = 0;
-      cpu_arch_flags.bitfield.cpuno64 = 1;
-    }
-  if (value == CODE_64BIT && !cpu_arch_flags.bitfield.cpulm )
+  if (value == CODE_64BIT && !cpu_arch_flags.bitfield.cpu64 )
     {
-      if (check)
-       as_error = as_fatal;
-      else
-       as_error = as_bad;
-      (*as_error) (_("64bit mode not supported on `%s'."),
-                  cpu_arch_name ? cpu_arch_name : default_arch);
+      as_error (_("64bit mode not supported on `%s'."),
+               cpu_arch_name ? cpu_arch_name : default_arch);
+      return;
     }
+
   if (value == CODE_32BIT && !cpu_arch_flags.bitfield.cpui386)
     {
-      if (check)
-       as_error = as_fatal;
-      else
-       as_error = as_bad;
-      (*as_error) (_("32bit mode not supported on `%s'."),
-                  cpu_arch_name ? cpu_arch_name : default_arch);
+      as_error (_("32bit mode not supported on `%s'."),
+               cpu_arch_name ? cpu_arch_name : default_arch);
+      return;
     }
+
+  flag_code = (enum flag_code) value;
+
   stackop_size = '\0';
 }
 
@@ -2572,8 +2656,6 @@ set_16bit_gcc_code_flag (int new_code_flag)
   flag_code = (enum flag_code) new_code_flag;
   if (flag_code != CODE_16BIT)
     abort ();
-  cpu_arch_flags.bitfield.cpu64 = 0;
-  cpu_arch_flags.bitfield.cpuno64 = 1;
   stackop_size = LONG_MNEM_SUFFIX;
 }
 
@@ -2609,8 +2691,6 @@ set_intel_syntax (int syntax_flag)
 
   expr_set_rank (O_full_ptr, syntax_flag ? 10 : 0);
 
-  identifier_chars['%'] = intel_syntax && allow_naked_reg ? '%' : 0;
-  identifier_chars['$'] = intel_syntax ? '$' : 0;
   register_prefix = allow_naked_reg ? "" : "%";
 }
 
@@ -2696,13 +2776,41 @@ check_cpu_arch_compatible (const char *name ATTRIBUTE_UNUSED,
 }
 
 static void
-extend_cpu_sub_arch_name (const char *name)
+extend_cpu_sub_arch_name (const char *pfx, const char *name)
 {
   if (cpu_sub_arch_name)
     cpu_sub_arch_name = reconcat (cpu_sub_arch_name, cpu_sub_arch_name,
-                                 ".", name, (const char *) NULL);
+                                 pfx, name, (const char *) NULL);
   else
-    cpu_sub_arch_name = concat (".", name, (const char *) NULL);
+    cpu_sub_arch_name = concat (pfx, name, (const char *) NULL);
+}
+
+static void isa_enable (unsigned int idx)
+{
+  i386_cpu_flags flags = cpu_flags_or (cpu_arch_flags, cpu_arch[idx].enable);
+
+  if (!cpu_flags_equal (&flags, &cpu_arch_flags))
+    {
+      extend_cpu_sub_arch_name (".", cpu_arch[idx].name);
+      cpu_arch_flags = flags;
+    }
+
+  cpu_arch_isa_flags = cpu_flags_or (cpu_arch_isa_flags, cpu_arch[idx].enable);
+}
+
+static void isa_disable (unsigned int idx)
+{
+  i386_cpu_flags flags
+    = cpu_flags_and_not (cpu_arch_flags, cpu_arch[idx].disable);
+
+  if (!cpu_flags_equal (&flags, &cpu_arch_flags))
+    {
+      extend_cpu_sub_arch_name (".no", cpu_arch[idx].name);
+      cpu_arch_flags = flags;
+    }
+
+  cpu_arch_isa_flags
+    = cpu_flags_and_not (cpu_arch_isa_flags, cpu_arch[idx].disable);
 }
 
 static void
@@ -2717,210 +2825,231 @@ set_cpu_arch (int dummy ATTRIBUTE_UNUSED)
     i386_cpu_flags isa_flags;
     enum processor_type isa;
     enum flag_code flag_code;
+    unsigned int vector_size;
     char stackop_size;
     bool no_cond_jump_promotion;
   } arch_stack_entry;
   static const arch_stack_entry *arch_stack_top;
+  char *s;
+  int e;
+  const char *string;
+  unsigned int j = 0;
 
   SKIP_WHITESPACE ();
 
-  if (!is_end_of_line[(unsigned char) *input_line_pointer])
+  if (is_end_of_line[(unsigned char) *input_line_pointer])
+    {
+      as_bad (_("missing cpu architecture"));
+      input_line_pointer++;
+      return;
+    }
+
+  e = get_symbol_name (&s);
+  string = s;
+
+  if (strcmp (string, "push") == 0)
+    {
+      arch_stack_entry *top = XNEW (arch_stack_entry);
+
+      top->name = cpu_arch_name;
+      if (cpu_sub_arch_name)
+       top->sub_name = xstrdup (cpu_sub_arch_name);
+      else
+       top->sub_name = NULL;
+      top->flags = cpu_arch_flags;
+      top->isa = cpu_arch_isa;
+      top->isa_flags = cpu_arch_isa_flags;
+      top->flag_code = flag_code;
+      top->vector_size = vector_size;
+      top->stackop_size = stackop_size;
+      top->no_cond_jump_promotion = no_cond_jump_promotion;
+
+      top->prev = arch_stack_top;
+      arch_stack_top = top;
+
+      (void) restore_line_pointer (e);
+      demand_empty_rest_of_line ();
+      return;
+    }
+
+  if (strcmp (string, "pop") == 0)
     {
-      char *s;
-      int e = get_symbol_name (&s);
-      const char *string = s;
-      unsigned int j = 0;
-      i386_cpu_flags flags;
+      const arch_stack_entry *top = arch_stack_top;
 
-      if (strcmp (string, "default") == 0)
+      if (!top)
+       as_bad (_(".arch stack is empty"));
+      else if (top->flag_code != flag_code
+              || top->stackop_size != stackop_size)
        {
-         if (strcmp (default_arch, "iamcu") == 0)
-           string = default_arch;
-         else
-           {
-             static const i386_cpu_flags cpu_unknown_flags = CPU_UNKNOWN_FLAGS;
+         static const unsigned int bits[] = {
+           [CODE_16BIT] = 16,
+           [CODE_32BIT] = 32,
+           [CODE_64BIT] = 64,
+         };
 
-             cpu_arch_name = NULL;
-             free (cpu_sub_arch_name);
-             cpu_sub_arch_name = NULL;
-             cpu_arch_flags = cpu_unknown_flags;
-             if (flag_code == CODE_64BIT)
-               {
-                 cpu_arch_flags.bitfield.cpu64 = 1;
-                 cpu_arch_flags.bitfield.cpuno64 = 0;
-               }
-             else
-               {
-                 cpu_arch_flags.bitfield.cpu64 = 0;
-                 cpu_arch_flags.bitfield.cpuno64 = 1;
-               }
-             cpu_arch_isa = PROCESSOR_UNKNOWN;
-             cpu_arch_isa_flags = cpu_arch[flag_code == CODE_64BIT].enable;
-             if (!cpu_arch_tune_set)
-               {
-                 cpu_arch_tune = cpu_arch_isa;
-                 cpu_arch_tune_flags = cpu_arch_isa_flags;
-               }
+         as_bad (_("this `.arch pop' requires `.code%u%s' to be in effect"),
+                 bits[top->flag_code],
+                 top->stackop_size == LONG_MNEM_SUFFIX ? "gcc" : "");
+       }
+      else
+       {
+         arch_stack_top = top->prev;
 
-             j = ARRAY_SIZE (cpu_arch) + 1;
-           }
+         cpu_arch_name = top->name;
+         free (cpu_sub_arch_name);
+         cpu_sub_arch_name = top->sub_name;
+         cpu_arch_flags = top->flags;
+         cpu_arch_isa = top->isa;
+         cpu_arch_isa_flags = top->isa_flags;
+         vector_size = top->vector_size;
+         no_cond_jump_promotion = top->no_cond_jump_promotion;
+
+         XDELETE (top);
        }
-      else if (strcmp (string, "push") == 0)
+
+      (void) restore_line_pointer (e);
+      demand_empty_rest_of_line ();
+      return;
+    }
+
+  if (strcmp (string, "default") == 0)
+    {
+      if (strcmp (default_arch, "iamcu") == 0)
+       string = default_arch;
+      else
        {
-         arch_stack_entry *top = XNEW (arch_stack_entry);
+         static const i386_cpu_flags cpu_unknown_flags = CPU_UNKNOWN_FLAGS;
 
-         top->name = cpu_arch_name;
-         if (cpu_sub_arch_name)
-           top->sub_name = xstrdup (cpu_sub_arch_name);
-         else
-           top->sub_name = NULL;
-         top->flags = cpu_arch_flags;
-         top->isa = cpu_arch_isa;
-         top->isa_flags = cpu_arch_isa_flags;
-         top->flag_code = flag_code;
-         top->stackop_size = stackop_size;
-         top->no_cond_jump_promotion = no_cond_jump_promotion;
+         cpu_arch_name = NULL;
+         free (cpu_sub_arch_name);
+         cpu_sub_arch_name = NULL;
+         cpu_arch_flags = cpu_unknown_flags;
+         cpu_arch_isa = PROCESSOR_UNKNOWN;
+         cpu_arch_isa_flags = cpu_arch[flag_code == CODE_64BIT].enable;
+         if (!cpu_arch_tune_set)
+           cpu_arch_tune = PROCESSOR_UNKNOWN;
 
-         top->prev = arch_stack_top;
-         arch_stack_top = top;
+         vector_size = VSZ_DEFAULT;
 
-         (void) restore_line_pointer (e);
-         demand_empty_rest_of_line ();
-         return;
+         j = ARRAY_SIZE (cpu_arch) + 1;
        }
-      else if (strcmp (string, "pop") == 0)
-       {
-         const arch_stack_entry *top = arch_stack_top;
+    }
 
-         if (!top)
-           as_bad (_(".arch stack is empty"));
-         else if (top->flag_code != flag_code
-                  || top->stackop_size != stackop_size)
+  for (; j < ARRAY_SIZE (cpu_arch); j++)
+    {
+      if (strcmp (string + (*string == '.'), cpu_arch[j].name) == 0
+         && (*string == '.') == (cpu_arch[j].type == PROCESSOR_NONE))
+       {
+         if (*string != '.')
            {
-             static const unsigned int bits[] = {
-               [CODE_16BIT] = 16,
-               [CODE_32BIT] = 32,
-               [CODE_64BIT] = 64,
-             };
+             check_cpu_arch_compatible (string, cpu_arch[j].enable);
 
-             as_bad (_("this `.arch pop' requires `.code%u%s' to be in effect"),
-                     bits[top->flag_code],
-                     top->stackop_size == LONG_MNEM_SUFFIX ? "gcc" : "");
-           }
-         else
-           {
-             arch_stack_top = top->prev;
+             if (flag_code == CODE_64BIT && !cpu_arch[j].enable.bitfield.cpu64 )
+               {
+                 as_bad (_("64bit mode not supported on `%s'."),
+                         cpu_arch[j].name);
+                 (void) restore_line_pointer (e);
+                 ignore_rest_of_line ();
+                 return;
+               }
+
+             if (flag_code == CODE_32BIT && !cpu_arch[j].enable.bitfield.cpui386)
+               {
+                 as_bad (_("32bit mode not supported on `%s'."),
+                         cpu_arch[j].name);
+                 (void) restore_line_pointer (e);
+                 ignore_rest_of_line ();
+                 return;
+               }
 
-             cpu_arch_name = top->name;
+             cpu_arch_name = cpu_arch[j].name;
              free (cpu_sub_arch_name);
-             cpu_sub_arch_name = top->sub_name;
-             cpu_arch_flags = top->flags;
-             cpu_arch_isa = top->isa;
-             cpu_arch_isa_flags = top->isa_flags;
-             no_cond_jump_promotion = top->no_cond_jump_promotion;
+             cpu_sub_arch_name = NULL;
+             cpu_arch_flags = cpu_arch[j].enable;
+             cpu_arch_isa = cpu_arch[j].type;
+             cpu_arch_isa_flags = cpu_arch[j].enable;
+             if (!cpu_arch_tune_set)
+               cpu_arch_tune = cpu_arch_isa;
+
+             vector_size = VSZ_DEFAULT;
 
-             XDELETE (top);
+             pre_386_16bit_warned = false;
+             break;
            }
 
+         if (cpu_flags_all_zero (&cpu_arch[j].enable))
+           continue;
+
+         isa_enable (j);
+
          (void) restore_line_pointer (e);
-         demand_empty_rest_of_line ();
-         return;
-       }
 
-      for (; j < ARRAY_SIZE (cpu_arch); j++)
-       {
-         if (strcmp (string + (*string == '.'), cpu_arch[j].name) == 0
-            && (*string == '.') == (cpu_arch[j].type == PROCESSOR_NONE))
+         switch (cpu_arch[j].vsz)
            {
-             if (*string != '.')
-               {
-                 check_cpu_arch_compatible (string, cpu_arch[j].enable);
+           default:
+             break;
 
-                 cpu_arch_name = cpu_arch[j].name;
-                 free (cpu_sub_arch_name);
-                 cpu_sub_arch_name = NULL;
-                 cpu_arch_flags = cpu_arch[j].enable;
-                 if (flag_code == CODE_64BIT)
-                   {
-                     cpu_arch_flags.bitfield.cpu64 = 1;
-                     cpu_arch_flags.bitfield.cpuno64 = 0;
-                   }
-                 else
-                   {
-                     cpu_arch_flags.bitfield.cpu64 = 0;
-                     cpu_arch_flags.bitfield.cpuno64 = 1;
-                   }
-                 cpu_arch_isa = cpu_arch[j].type;
-                 cpu_arch_isa_flags = cpu_arch[j].enable;
-                 if (!cpu_arch_tune_set)
+           case vsz_set:
+#ifdef SVR4_COMMENT_CHARS
+             if (*input_line_pointer == ':' || *input_line_pointer == '/')
+#else
+             if (*input_line_pointer == '/')
+#endif
+               {
+                 ++input_line_pointer;
+                 switch (get_absolute_expression ())
                    {
-                     cpu_arch_tune = cpu_arch_isa;
-                     cpu_arch_tune_flags = cpu_arch_isa_flags;
+                   case 512: vector_size = VSZ512; break;
+                   case 256: vector_size = VSZ256; break;
+                   case 128: vector_size = VSZ128; break;
+                   default:
+                     as_bad (_("Unrecognized vector size specifier"));
+                     ignore_rest_of_line ();
+                     return;
                    }
-                 pre_386_16bit_warned = false;
                  break;
                }
-
-             if (cpu_flags_all_zero (&cpu_arch[j].enable))
-               continue;
-
-             flags = cpu_flags_or (cpu_arch_flags,
-                                   cpu_arch[j].enable);
-
-             if (!cpu_flags_equal (&flags, &cpu_arch_flags))
-               {
-                 extend_cpu_sub_arch_name (string + 1);
-                 cpu_arch_flags = flags;
-                 cpu_arch_isa_flags = flags;
-               }
-             else
-               cpu_arch_isa_flags
-                 = cpu_flags_or (cpu_arch_isa_flags,
-                                 cpu_arch[j].enable);
-             (void) restore_line_pointer (e);
-             demand_empty_rest_of_line ();
-             return;
+               /* Fall through.  */
+           case vsz_reset:
+             vector_size = VSZ_DEFAULT;
+             break;
            }
-       }
 
-      if (startswith (string, ".no") && j >= ARRAY_SIZE (cpu_arch))
-       {
-         /* Disable an ISA extension.  */
-         for (j = 0; j < ARRAY_SIZE (cpu_arch); j++)
-           if (cpu_arch[j].type == PROCESSOR_NONE
-               && strcmp (string + 3, cpu_arch[j].name) == 0)
-             {
-               flags = cpu_flags_and_not (cpu_arch_flags,
-                                          cpu_arch[j].disable);
-               if (!cpu_flags_equal (&flags, &cpu_arch_flags))
-                 {
-                   extend_cpu_sub_arch_name (string + 1);
-                   cpu_arch_flags = flags;
-                   cpu_arch_isa_flags = flags;
-                 }
-               (void) restore_line_pointer (e);
-               demand_empty_rest_of_line ();
-               return;
-             }
+         demand_empty_rest_of_line ();
+         return;
        }
+    }
+
+  if (startswith (string, ".no") && j >= ARRAY_SIZE (cpu_arch))
+    {
+      /* Disable an ISA extension.  */
+      for (j = 0; j < ARRAY_SIZE (cpu_arch); j++)
+       if (cpu_arch[j].type == PROCESSOR_NONE
+           && strcmp (string + 3, cpu_arch[j].name) == 0)
+         {
+           isa_disable (j);
 
-      if (j == ARRAY_SIZE (cpu_arch))
-       as_bad (_("no such architecture: `%s'"), string);
+           if (cpu_arch[j].vsz == vsz_set)
+             vector_size = VSZ_DEFAULT;
 
-      *input_line_pointer = e;
+           (void) restore_line_pointer (e);
+           demand_empty_rest_of_line ();
+           return;
+         }
     }
-  else
-    as_bad (_("missing cpu architecture"));
+
+  if (j == ARRAY_SIZE (cpu_arch))
+    as_bad (_("no such architecture: `%s'"), string);
+
+  *input_line_pointer = e;
 
   no_cond_jump_promotion = 0;
   if (*input_line_pointer == ','
       && !is_end_of_line[(unsigned char) input_line_pointer[1]])
     {
-      char *string;
-      char e;
-
       ++input_line_pointer;
-      e = get_symbol_name (&string);
+      e = get_symbol_name (&s);
+      string = s;
 
       if (strcmp (string, "nojumps") == 0)
        no_cond_jump_promotion = 1;
@@ -3048,7 +3177,7 @@ md_begin (void)
   /* Fill in lexical tables:  mnemonic_chars, operand_chars.  */
   {
     int c;
-    char *p;
+    const char *p;
 
     for (c = 0; c < 256; c++)
       {
@@ -3064,38 +3193,21 @@ md_begin (void)
            register_chars[c] = mnemonic_chars[c];
            operand_chars[c] = c;
          }
-       else if (c == '{' || c == '}')
-         {
-           mnemonic_chars[c] = c;
-           operand_chars[c] = c;
-         }
 #ifdef SVR4_COMMENT_CHARS
        else if (c == '\\' && strchr (i386_comment_chars, '/'))
          operand_chars[c] = c;
 #endif
 
-       if (ISALPHA (c) || ISDIGIT (c))
-         identifier_chars[c] = c;
-       else if (c >= 128)
-         {
-           identifier_chars[c] = c;
-           operand_chars[c] = c;
-         }
+       if (c >= 128)
+         operand_chars[c] = c;
       }
 
-#ifdef LEX_AT
-    identifier_chars['@'] = '@';
-#endif
-#ifdef LEX_QM
-    identifier_chars['?'] = '?';
-    operand_chars['?'] = '?';
-#endif
     mnemonic_chars['_'] = '_';
     mnemonic_chars['-'] = '-';
     mnemonic_chars['.'] = '.';
-    identifier_chars['_'] = '_';
-    identifier_chars['.'] = '.';
 
+    for (p = extra_symbol_chars; *p != '\0'; p++)
+      operand_chars[(unsigned char) *p] = *p;
     for (p = operand_special_chars; *p != '\0'; p++)
       operand_chars[(unsigned char) *p] = *p;
   }
@@ -3203,8 +3315,8 @@ pte (insn_template *t)
   fprintf (stdout, " %d operands ", t->operands);
   if (opc_pfx[t->opcode_modifier.opcodeprefix])
     fprintf (stdout, "pfx %x ", opc_pfx[t->opcode_modifier.opcodeprefix]);
-  if (opc_spc[t->opcode_modifier.opcodespace])
-    fprintf (stdout, "space %s ", opc_spc[t->opcode_modifier.opcodespace]);
+  if (opc_spc[t->opcode_space])
+    fprintf (stdout, "space %s ", opc_spc[t->opcode_space]);
   fprintf (stdout, "opcode %x ", t->base_opcode);
   if (t->extension_opcode != None)
     fprintf (stdout, "ext %x ", t->extension_opcode);
@@ -3487,8 +3599,7 @@ want_disp32 (const insn_template *t)
 {
   return flag_code != CODE_64BIT
         || i.prefix[ADDR_PREFIX]
-        || (t->base_opcode == 0x8d
-            && t->opcode_modifier.opcodespace == SPACE_BASE
+        || (t->mnem_off == MN_lea
             && (!i.types[1].bitfield.qword
                || t->opcode_modifier.size == SIZE32));
 }
@@ -3553,7 +3664,28 @@ install_template (const insn_template *t)
 
   i.tm = *t;
 
-  /* Note that for pseudo prefixes this produces a length of 1. But for them
+  /* Dual VEX/EVEX templates need stripping one of the possible variants.  */
+  if (t->opcode_modifier.vex && t->opcode_modifier.evex)
+  {
+      if ((is_cpu (t, CpuAVX) || is_cpu (t, CpuAVX2))
+         && is_cpu (t, CpuAVX512F))
+       {
+         if (need_evex_encoding ())
+           {
+             i.tm.opcode_modifier.vex = 0;
+             i.tm.cpu.bitfield.cpuavx = 0;
+             if (is_cpu (&i.tm, CpuAVX2))
+               i.tm.cpu.bitfield.isa = 0;
+           }
+         else
+           {
+             i.tm.opcode_modifier.evex = 0;
+             i.tm.cpu.bitfield.cpuavx512f = 0;
+           }
+       }
+  }
+
+  /* Note that for pseudo prefixes this produces a length of 1. But for them
      the length isn't interesting at all.  */
   for (l = 1; l < 4; ++l)
     if (!(t->base_opcode >> (8 * l)))
@@ -3588,20 +3720,13 @@ build_vex_prefix (const insn_template *t)
       && i.dir_encoding == dir_encoding_default
       && i.operands == i.reg_operands
       && operand_type_equal (&i.types[0], &i.types[i.operands - 1])
-      && i.tm.opcode_modifier.opcodespace == SPACE_0F
+      && i.tm.opcode_space == SPACE_0F
       && (i.tm.opcode_modifier.load || i.tm.opcode_modifier.d)
       && i.rex == REX_B)
     {
-      unsigned int xchg = i.operands - 1;
-      union i386_op temp_op;
-      i386_operand_type temp_type;
+      unsigned int xchg;
 
-      temp_type = i.types[xchg];
-      i.types[xchg] = i.types[0];
-      i.types[0] = temp_type;
-      temp_op = i.op[xchg];
-      i.op[xchg] = i.op[0];
-      i.op[0] = temp_op;
+      swap_2_operands (0, i.operands - 1);
 
       gas_assert (i.rm.mode == 3);
 
@@ -3624,27 +3749,21 @@ build_vex_prefix (const insn_template *t)
       && i.reg_operands == i.operands - i.imm_operands
       && i.tm.opcode_modifier.vex
       && i.tm.opcode_modifier.commutative
-      && (i.tm.opcode_modifier.sse2avx || optimize > 1)
+      && (i.tm.opcode_modifier.sse2avx
+         || (optimize > 1 && !i.no_optimize))
       && i.rex == REX_B
       && i.vex.register_specifier
       && !(i.vex.register_specifier->reg_flags & RegRex))
     {
       unsigned int xchg = i.operands - i.reg_operands;
-      union i386_op temp_op;
-      i386_operand_type temp_type;
 
-      gas_assert (i.tm.opcode_modifier.opcodespace == SPACE_0F);
+      gas_assert (i.tm.opcode_space == SPACE_0F);
       gas_assert (!i.tm.opcode_modifier.sae);
       gas_assert (operand_type_equal (&i.types[i.operands - 2],
                                       &i.types[i.operands - 3]));
       gas_assert (i.rm.mode == 3);
 
-      temp_type = i.types[xchg];
-      i.types[xchg] = i.types[xchg + 1];
-      i.types[xchg + 1] = temp_type;
-      temp_op = i.op[xchg];
-      i.op[xchg] = i.op[xchg + 1];
-      i.op[xchg + 1] = temp_op;
+      swap_2_operands (xchg, xchg + 1);
 
       i.rex = 0;
       xchg = i.rm.regmem | 8;
@@ -3658,6 +3777,8 @@ build_vex_prefix (const insn_template *t)
     vector_length = avxscalar;
   else if (i.tm.opcode_modifier.vex == VEX256)
     vector_length = 1;
+  else if (dot_insn () && i.tm.opcode_modifier.vex == VEX128)
+    vector_length = 0;
   else
     {
       unsigned int op;
@@ -3686,7 +3807,7 @@ build_vex_prefix (const insn_template *t)
   /* Use 2-byte VEX prefix if possible.  */
   if (w == 0
       && i.vec_encoding != vex_encoding_vex3
-      && i.tm.opcode_modifier.opcodespace == SPACE_0F
+      && i.tm.opcode_space == SPACE_0F
       && (i.rex & (REX_W | REX_X | REX_B)) == 0)
     {
       /* 2-byte VEX prefix.  */
@@ -3707,7 +3828,7 @@ build_vex_prefix (const insn_template *t)
       /* 3-byte VEX prefix.  */
       i.vex.length = 3;
 
-      switch (i.tm.opcode_modifier.opcodespace)
+      switch (i.tm.opcode_space)
        {
        case SPACE_0F:
        case SPACE_0F38:
@@ -3725,7 +3846,9 @@ build_vex_prefix (const insn_template *t)
 
       /* The high 3 bits of the second VEX byte are 1's compliment
         of RXB bits from REX.  */
-      i.vex.bytes[1] = (~i.rex & 0x7) << 5 | i.tm.opcode_modifier.opcodespace;
+      i.vex.bytes[1] = ((~i.rex & 7) << 5)
+                      | (!dot_insn () ? i.tm.opcode_space
+                                      : i.insn_opcode_space);
 
       i.vex.bytes[2] = (w << 7
                        | register_specifier << 3
@@ -3755,8 +3878,7 @@ get_broadcast_bytes (const insn_template *t, bool diag)
   const i386_operand_type *types;
 
   if (i.broadcast.type)
-    return i.broadcast.bytes = ((1 << (t->opcode_modifier.broadcast - 1))
-                               * i.broadcast.type);
+    return (1 << (t->opcode_modifier.broadcast - 1)) * i.broadcast.type;
 
   gas_assert (intel_syntax);
 
@@ -3860,9 +3982,11 @@ build_evex_prefix (void)
 
   /* The high 3 bits of the second EVEX byte are 1's compliment of RXB
      bits from REX.  */
-  gas_assert (i.tm.opcode_modifier.opcodespace >= SPACE_0F);
-  gas_assert (i.tm.opcode_modifier.opcodespace <= SPACE_EVEXMAP6);
-  i.vex.bytes[1] = (~i.rex & 0x7) << 5 | i.tm.opcode_modifier.opcodespace;
+  gas_assert (i.tm.opcode_space >= SPACE_0F);
+  gas_assert (i.tm.opcode_space <= SPACE_EVEXMAP6);
+  i.vex.bytes[1] = ((~i.rex & 7) << 5)
+                  | (!dot_insn () ? i.tm.opcode_space
+                                  : i.insn_opcode_space);
 
   /* The fifth bit of the second EVEX byte is 1's compliment of the
      REX_R bit in VREX.  */
@@ -3940,7 +4064,8 @@ build_evex_prefix (void)
                    i.tm.opcode_modifier.evex = EVEX128;
                    break;
                  }
-               else if (i.broadcast.bytes && op == i.broadcast.operand)
+               else if ((i.broadcast.type || i.broadcast.bytes)
+                        && op == i.broadcast.operand)
                  {
                    switch (get_broadcast_bytes (&i.tm, true))
                      {
@@ -3978,13 +4103,20 @@ build_evex_prefix (void)
        case EVEX512:
          vec_length = 2 << 5;
          break;
+       case EVEX_L3:
+         if (dot_insn ())
+           {
+             vec_length = 3 << 5;
+             break;
+           }
+         /* Fall through.  */
        default:
          abort ();
          break;
        }
       i.vex.bytes[3] |= vec_length;
       /* Encode the broadcast bit.  */
-      if (i.broadcast.bytes)
+      if (i.broadcast.type || i.broadcast.bytes)
        i.vex.bytes[3] |= 0x10;
     }
   else if (i.rounding.type != saeonly)
@@ -4072,14 +4204,14 @@ encode_with_unaligned_vector_move (void)
     case 0x28: /* Load instructions.  */
     case 0x29: /* Store instructions.  */
       /* movaps/movapd/vmovaps/vmovapd.  */
-      if (i.tm.opcode_modifier.opcodespace == SPACE_0F
+      if (i.tm.opcode_space == SPACE_0F
          && i.tm.opcode_modifier.opcodeprefix <= PREFIX_0X66)
        i.tm.base_opcode = 0x10 | (i.tm.base_opcode & 1);
       break;
     case 0x6f: /* Load instructions.  */
     case 0x7f: /* Store instructions.  */
       /* movdqa/vmovdqa/vmovdqa64/vmovdqa32. */
-      if (i.tm.opcode_modifier.opcodespace == SPACE_0F
+      if (i.tm.opcode_space == SPACE_0F
          && i.tm.opcode_modifier.opcodeprefix == PREFIX_0X66)
        i.tm.opcode_modifier.opcodeprefix = PREFIX_0XF3;
       break;
@@ -4095,8 +4227,7 @@ optimize_encoding (void)
 {
   unsigned int j;
 
-  if (i.tm.opcode_modifier.opcodespace == SPACE_BASE
-      && i.tm.base_opcode == 0x8d)
+  if (i.tm.mnem_off == MN_lea)
     {
       /* Optimize: -O:
           lea symbol, %rN    -> mov $symbol, %rN
@@ -4222,7 +4353,7 @@ optimize_encoding (void)
            {
              if (flag_code != CODE_32BIT)
                return;
-             i.tm.opcode_modifier.opcodespace = SPACE_0F;
+             i.tm.opcode_space = SPACE_0F;
              i.tm.base_opcode = 0xb7;
            }
          else
@@ -4244,15 +4375,12 @@ optimize_encoding (void)
     }
 
   if (optimize_for_space
-      && i.tm.opcode_modifier.opcodespace == SPACE_BASE
+      && i.tm.mnem_off == MN_test
       && i.reg_operands == 1
       && i.imm_operands == 1
       && !i.types[1].bitfield.byte
       && i.op[0].imms->X_op == O_constant
-      && fits_in_imm7 (i.op[0].imms->X_add_number)
-      && (i.tm.base_opcode == 0xa8
-         || (i.tm.base_opcode == 0xf6
-             && i.tm.extension_opcode == 0x0)))
+      && fits_in_imm7 (i.op[0].imms->X_add_number))
     {
       /* Optimize: -Os:
           test $imm7, %r64/%r32/%r16  -> test $imm7, %r8
@@ -4276,7 +4404,7 @@ optimize_encoding (void)
        }
     }
   else if (flag_code == CODE_64BIT
-          && i.tm.opcode_modifier.opcodespace == SPACE_BASE
+          && i.tm.opcode_space == SPACE_BASE
           && ((i.types[1].bitfield.qword
                && i.reg_operands == 1
                && i.imm_operands == 1
@@ -4285,12 +4413,11 @@ optimize_encoding (void)
                     && i.tm.extension_opcode == None
                     && fits_in_unsigned_long (i.op[0].imms->X_add_number))
                    || (fits_in_imm31 (i.op[0].imms->X_add_number)
-                       && ((i.tm.base_opcode == 0x24
-                            || i.tm.base_opcode == 0xa8)
+                       && (i.tm.base_opcode == 0x24
                            || (i.tm.base_opcode == 0x80
                                && i.tm.extension_opcode == 0x4)
-                           || ((i.tm.base_opcode == 0xf6
-                                || (i.tm.base_opcode | 1) == 0xc7)
+                           || i.tm.mnem_off == MN_test
+                           || ((i.tm.base_opcode | 1) == 0xc7
                                && i.tm.extension_opcode == 0x0)))
                    || (fits_in_imm7 (i.op[0].imms->X_add_number)
                        && i.tm.base_opcode == 0x83
@@ -4298,11 +4425,9 @@ optimize_encoding (void)
               || (i.types[0].bitfield.qword
                   && ((i.reg_operands == 2
                        && i.op[0].regs == i.op[1].regs
-                       && (i.tm.base_opcode == 0x30
-                           || i.tm.base_opcode == 0x28))
-                      || (i.reg_operands == 1
-                          && i.operands == 1
-                          && i.tm.base_opcode == 0x30)))))
+                       && (i.tm.mnem_off == MN_xor
+                           || i.tm.mnem_off == MN_sub))
+                      || i.tm.mnem_off == MN_clr))))
     {
       /* Optimize: -O:
           andq $imm31, %r64   -> andl $imm31, %r32
@@ -4327,7 +4452,7 @@ optimize_encoding (void)
        }
       i.types[1].bitfield.dword = 1;
       i.types[1].bitfield.qword = 0;
-      if (i.tm.base_opcode == 0xb8 || (i.tm.base_opcode | 1) == 0xc7)
+      if (i.tm.mnem_off == MN_mov || i.tm.mnem_off == MN_lea)
        {
          /* Handle
               movq $imm31, %r64   -> movl $imm31, %r32
@@ -4350,11 +4475,9 @@ optimize_encoding (void)
     }
   else if (optimize > 1
           && !optimize_for_space
-          && i.tm.opcode_modifier.opcodespace == SPACE_BASE
           && i.reg_operands == 2
           && i.op[0].regs == i.op[1].regs
-          && ((i.tm.base_opcode & ~(Opcode_D | 1)) == 0x8
-              || (i.tm.base_opcode & ~(Opcode_D | 1)) == 0x20)
+          && (i.tm.mnem_off == MN_and || i.tm.mnem_off == MN_or)
           && (flag_code != CODE_64BIT || !i.types[0].bitfield.dword))
     {
       /* Optimize: -O2:
@@ -4372,6 +4495,42 @@ optimize_encoding (void)
        */
       i.tm.base_opcode = 0x84 | (i.tm.base_opcode & 1);
     }
+  else if (i.tm.base_opcode == 0xba
+          && i.tm.opcode_space == SPACE_0F
+          && i.reg_operands == 1
+          && i.op[0].imms->X_op == O_constant
+          && i.op[0].imms->X_add_number >= 0)
+    {
+      /* Optimize: -O:
+          btw $n, %rN -> btl $n, %rN (outside of 16-bit mode, n < 16)
+          btq $n, %rN -> btl $n, %rN (in 64-bit mode, n < 32, N < 8)
+          btl $n, %rN -> btw $n, %rN (in 16-bit mode, n < 16)
+
+          With <BT> one of bts, btr, and bts also:
+          <BT>w $n, %rN -> btl $n, %rN (in 32-bit mode, n < 16)
+          <BT>l $n, %rN -> btw $n, %rN (in 16-bit mode, n < 16)
+       */
+      switch (flag_code)
+       {
+       case CODE_64BIT:
+         if (i.tm.extension_opcode != 4)
+           break;
+         if (i.types[1].bitfield.qword
+             && i.op[0].imms->X_add_number < 32
+             && !(i.op[1].regs->reg_flags & RegRex))
+           i.tm.opcode_modifier.size = SIZE32;
+         /* Fall through.  */
+       case CODE_32BIT:
+         if (i.types[1].bitfield.word
+             && i.op[0].imms->X_add_number < 16)
+           i.tm.opcode_modifier.size = SIZE32;
+         break;
+       case CODE_16BIT:
+         if (i.op[0].imms->X_add_number < 16)
+           i.tm.opcode_modifier.size = SIZE16;
+         break;
+       }
+    }
   else if (i.reg_operands == 3
           && i.op[0].regs == i.op[1].regs
           && !i.types[2].bitfield.xmmword
@@ -4380,10 +4539,10 @@ optimize_encoding (void)
                   && is_evex_encoding (&i.tm)
                   && (i.vec_encoding != vex_encoding_evex
                       || cpu_arch_isa_flags.bitfield.cpuavx512vl
-                      || i.tm.cpu_flags.bitfield.cpuavx512vl
+                      || is_cpu (&i.tm, CpuAVX512VL)
                       || (i.tm.operand_types[2].bitfield.zmmword
                           && i.types[2].bitfield.ymmword))))
-          && i.tm.opcode_modifier.opcodespace == SPACE_0F
+          && i.tm.opcode_space == SPACE_0F
           && ((i.tm.base_opcode | 2) == 0x57
               || i.tm.base_opcode == 0xdf
               || i.tm.base_opcode == 0xef
@@ -4433,6 +4592,8 @@ optimize_encoding (void)
              i.tm.opcode_modifier.vex = VEX128;
              i.tm.opcode_modifier.vexw = VEXW0;
              i.tm.opcode_modifier.evex = 0;
+             i.vec_encoding = vex_encoding_vex;
+             i.mask.reg = NULL;
            }
          else if (optimize > 1)
            i.tm.opcode_modifier.evex = EVEX128;
@@ -4458,6 +4619,7 @@ optimize_encoding (void)
           && !i.types[0].bitfield.zmmword
           && !i.types[1].bitfield.zmmword
           && !i.mask.reg
+          && !i.broadcast.type
           && !i.broadcast.bytes
           && is_evex_encoding (&i.tm)
           && ((i.tm.base_opcode & ~Opcode_SIMD_IntD) == 0x6f
@@ -4531,6 +4693,90 @@ optimize_encoding (void)
        i.types[j].bitfield.disp8
          = fits_in_disp8 (i.op[j].disps->X_add_number);
     }
+  else if (optimize_for_space
+          && i.tm.base_opcode == 0x29
+          && i.tm.opcode_space == SPACE_0F38
+          && i.operands == i.reg_operands
+          && i.op[0].regs == i.op[1].regs
+          && (!i.tm.opcode_modifier.vex
+              || !(i.op[0].regs->reg_flags & RegRex))
+          && !is_evex_encoding (&i.tm))
+    {
+      /* Optimize: -Os:
+         pcmpeqq %xmmN, %xmmN          -> pcmpeqd %xmmN, %xmmN
+         vpcmpeqq %xmmN, %xmmN, %xmmM  -> vpcmpeqd %xmmN, %xmmN, %xmmM (N < 8)
+         vpcmpeqq %ymmN, %ymmN, %ymmM  -> vpcmpeqd %ymmN, %ymmN, %ymmM (N < 8)
+       */
+      i.tm.opcode_space = SPACE_0F;
+      i.tm.base_opcode = 0x76;
+    }
+  else if (((i.tm.base_opcode >= 0x64
+            && i.tm.base_opcode <= 0x66
+            && i.tm.opcode_space == SPACE_0F)
+           || (i.tm.base_opcode == 0x37
+               && i.tm.opcode_space == SPACE_0F38))
+          && i.operands == i.reg_operands
+          && i.op[0].regs == i.op[1].regs
+          && !is_evex_encoding (&i.tm))
+    {
+      /* Optimize: -O:
+         pcmpgt[bwd] %mmN, %mmN             -> pxor %mmN, %mmN
+         pcmpgt[bwdq] %xmmN, %xmmN          -> pxor %xmmN, %xmmN
+         vpcmpgt[bwdq] %xmmN, %xmmN, %xmmM  -> vpxor %xmmN, %xmmN, %xmmM (N < 8)
+         vpcmpgt[bwdq] %xmmN, %xmmN, %xmmM  -> vpxor %xmm0, %xmm0, %xmmM (N > 7)
+         vpcmpgt[bwdq] %ymmN, %ymmN, %ymmM  -> vpxor %ymmN, %ymmN, %ymmM (N < 8)
+         vpcmpgt[bwdq] %ymmN, %ymmN, %ymmM  -> vpxor %ymm0, %ymm0, %ymmM (N > 7)
+       */
+      i.tm.opcode_space = SPACE_0F;
+      i.tm.base_opcode = 0xef;
+      if (i.tm.opcode_modifier.vex && (i.op[0].regs->reg_flags & RegRex))
+       {
+         if (i.operands == 2)
+           {
+             gas_assert (i.tm.opcode_modifier.sse2avx);
+
+             i.operands = 3;
+             i.reg_operands = 3;
+             i.tm.operands = 3;
+
+             i.op[2].regs = i.op[0].regs;
+             i.types[2] = i.types[0];
+             i.flags[2] = i.flags[0];
+             i.tm.operand_types[2] = i.tm.operand_types[0];
+
+             i.tm.opcode_modifier.sse2avx = 0;
+           }
+         i.op[0].regs -= i.op[0].regs->reg_num + 8;
+         i.op[1].regs = i.op[0].regs;
+       }
+    }
+  else if (optimize_for_space
+          && i.tm.base_opcode == 0x59
+          && i.tm.opcode_space == SPACE_0F38
+          && i.operands == i.reg_operands
+          && i.tm.opcode_modifier.vex
+          && !(i.op[0].regs->reg_flags & RegRex)
+          && i.op[0].regs->reg_type.bitfield.xmmword
+          && i.vec_encoding != vex_encoding_vex3)
+    {
+      /* Optimize: -Os:
+         vpbroadcastq %xmmN, %xmmM  -> vpunpcklqdq %xmmN, %xmmN, %xmmM (N < 8)
+       */
+      i.tm.opcode_space = SPACE_0F;
+      i.tm.base_opcode = 0x6c;
+      i.tm.opcode_modifier.vexvvvv = 1;
+
+      ++i.operands;
+      ++i.reg_operands;
+      ++i.tm.operands;
+
+      i.op[2].regs = i.op[0].regs;
+      i.types[2] = i.types[0];
+      i.flags[2] = i.flags[0];
+      i.tm.operand_types[2] = i.tm.operand_types[0];
+
+      swap_2_operands (1, 2);
+    }
 }
 
 /* Return non-zero for load instruction.  */
@@ -4554,7 +4800,7 @@ load_insn_p (void)
        return 1;
     }
 
-  if (i.tm.opcode_modifier.opcodespace == SPACE_BASE)
+  if (i.tm.opcode_space == SPACE_BASE)
     {
       /* popf, popa.   */
       if (i.tm.base_opcode == 0x9d
@@ -4579,19 +4825,13 @@ load_insn_p (void)
 
   if (any_vex_p)
     {
-      /* vldmxcsr.  */
-      if (i.tm.base_opcode == 0xae
-         && i.tm.opcode_modifier.vex
-         && i.tm.opcode_modifier.opcodespace == SPACE_0F
-         && i.tm.opcode_modifier.opcodeprefix == PREFIX_NONE
-         && i.tm.extension_opcode == 2)
+      if (i.tm.mnem_off == MN_vldmxcsr)
        return 1;
     }
-  else if (i.tm.opcode_modifier.opcodespace == SPACE_BASE)
+  else if (i.tm.opcode_space == SPACE_BASE)
     {
       /* test, not, neg, mul, imul, div, idiv.  */
-      if ((i.tm.base_opcode == 0xf6 || i.tm.base_opcode == 0xf7)
-         && i.tm.extension_opcode != 1)
+      if (base_opcode == 0xf7 && i.tm.extension_opcode != 1)
        return 1;
 
       /* inc, dec.  */
@@ -4603,13 +4843,12 @@ load_insn_p (void)
        return 1;
 
       /* rol, ror, rcl, rcr, shl/sal, shr, sar. */
-      if ((base_opcode == 0xc1
-          || (i.tm.base_opcode >= 0xd0 && i.tm.base_opcode <= 0xd3))
+      if ((base_opcode == 0xc1 || (base_opcode | 2) == 0xd3)
          && i.tm.extension_opcode != 6)
        return 1;
 
       /* Check for x87 instructions.  */
-      if (base_opcode >= 0xd8 && base_opcode <= 0xdf)
+      if ((base_opcode | 6) == 0xdf)
        {
          /* Skip fst, fstp, fstenv, fstcw.  */
          if (i.tm.base_opcode == 0xd9
@@ -4648,11 +4887,11 @@ load_insn_p (void)
          return 1;
        }
     }
-  else if (i.tm.opcode_modifier.opcodespace == SPACE_0F)
+  else if (i.tm.opcode_space == SPACE_0F)
     {
       /* bt, bts, btr, btc.  */
       if (i.tm.base_opcode == 0xba
-         && (i.tm.extension_opcode >= 4 && i.tm.extension_opcode <= 7))
+         && (i.tm.extension_opcode | 3) == 7)
        return 1;
 
       /* cmpxchg8b, cmpxchg16b, xrstors, vmptrld.  */
@@ -4681,26 +4920,17 @@ load_insn_p (void)
 
   /* Check fake imm8 operand and 3 source operands.  */
   if ((i.tm.opcode_modifier.immext
-       || i.tm.opcode_modifier.vexsources == VEX3SOURCES)
+       || i.reg_operands + i.mem_operands == 4)
       && i.types[dest].bitfield.imm8)
     dest--;
 
   /* add, or, adc, sbb, and, sub, xor, cmp, test, xchg.  */
-  if (i.tm.opcode_modifier.opcodespace == SPACE_BASE
-      && (base_opcode == 0x1
-         || base_opcode == 0x9
-         || base_opcode == 0x11
-         || base_opcode == 0x19
-         || base_opcode == 0x21
-         || base_opcode == 0x29
-         || base_opcode == 0x31
-         || base_opcode == 0x39
+  if (i.tm.opcode_space == SPACE_BASE
+      && ((base_opcode | 0x38) == 0x39
          || (base_opcode | 2) == 0x87))
     return 1;
 
-  /* xadd.  */
-  if (i.tm.opcode_modifier.opcodespace == SPACE_0F
-      && base_opcode == 0xc1)
+  if (i.tm.mnem_off == MN_xadd)
     return 1;
 
   /* Check for load instruction.  */
@@ -4724,8 +4954,7 @@ insert_lfence_after (void)
         chosen by the adversary using an LVI method,
         then this data-dependent behavior may leak some aspect
         of the secret.  */
-      if (((i.tm.base_opcode | 0x1) == 0xa7
-          || (i.tm.base_opcode | 0x1) == 0xaf)
+      if (((i.tm.base_opcode | 0x9) == 0xaf)
          && i.prefix[REP_PREFIX])
        {
            as_warn (_("`%s` changes flags which would affect control flow behavior"),
@@ -4745,7 +4974,7 @@ insert_lfence_before (void)
 {
   char *p;
 
-  if (i.tm.opcode_modifier.opcodespace != SPACE_BASE)
+  if (i.tm.opcode_space != SPACE_BASE)
     return;
 
   if (i.tm.base_opcode == 0xff
@@ -4795,8 +5024,7 @@ insert_lfence_before (void)
 
   /* Output or/not/shl and lfence before near ret.  */
   if (lfence_before_ret != lfence_before_ret_none
-      && (i.tm.base_opcode == 0xc2
-         || i.tm.base_opcode == 0xc3))
+      && (i.tm.base_opcode | 1) == 0xc3)
     {
       if (last_insn.kind != last_insn_other
          && last_insn.seg == now_seg)
@@ -4858,6 +5086,20 @@ insert_lfence_before (void)
     }
 }
 
+/* Shared helper for md_assemble() and s_insn().  */
+static void init_globals (void)
+{
+  unsigned int j;
+
+  memset (&i, '\0', sizeof (i));
+  i.rounding.type = rc_none;
+  for (j = 0; j < MAX_OPERANDS; j++)
+    i.reloc[j] = NO_RELOC;
+  memset (disp_expressions, '\0', sizeof (disp_expressions));
+  memset (im_expressions, '\0', sizeof (im_expressions));
+  save_stack_p = save_stack;
+}
+
 /* 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
@@ -4868,9 +5110,9 @@ 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->opcode_space == SPACE_0F
            && (t->base_opcode | 1) == 0xbf)
-          || (t->opcode_modifier.opcodespace == SPACE_BASE
+          || (t->opcode_space == SPACE_BASE
               && t->base_opcode == 0x63);
 }
 
@@ -4890,19 +5132,13 @@ md_assemble (char *line)
   /* Initialize globals.  */
   current_templates = NULL;
  retry:
-  memset (&i, '\0', sizeof (i));
-  i.rounding.type = rc_none;
-  for (j = 0; j < MAX_OPERANDS; j++)
-    i.reloc[j] = NO_RELOC;
-  memset (disp_expressions, '\0', sizeof (disp_expressions));
-  memset (im_expressions, '\0', sizeof (im_expressions));
-  save_stack_p = save_stack;
+  init_globals ();
 
   /* First parse an instruction mnemonic & call i386_operand for the operands.
      We assume that the scrubber has arranged it so that line[0] is the valid
      start of a (possibly prefixed) mnemonic.  */
 
-  end = parse_insn (line, mnemonic);
+  end = parse_insn (line, mnemonic, false);
   if (end == NULL)
     {
       if (pass1_mnem != NULL)
@@ -4969,42 +5205,8 @@ md_assemble (char *line)
   if (i.imm_operands)
     optimize_imm ();
 
-  if (i.disp_operands && !want_disp32 (t)
-      && (!t->opcode_modifier.jump
-         || i.jumpabsolute || i.types[0].bitfield.baseindex))
-    {
-      for (j = 0; j < i.operands; ++j)
-       {
-         const expressionS *exp = i.op[j].disps;
-
-         if (!operand_type_check (i.types[j], disp))
-           continue;
-
-         if (exp->X_op != O_constant)
-           continue;
-
-         /* Since displacement is signed extended to 64bit, don't allow
-            disp32 if it is out of range.  */
-         if (fits_in_signed_long (exp->X_add_number))
-           continue;
-
-         i.types[j].bitfield.disp32 = 0;
-         if (i.types[j].bitfield.baseindex)
-           {
-             as_bad (_("0x%" PRIx64 " out of range of signed 32bit displacement"),
-                     (uint64_t) exp->X_add_number);
-             return;
-           }
-       }
-    }
-
-  /* Don't optimize displacement for movabs since it only takes 64bit
-     displacement.  */
-  if (i.disp_operands
-      && i.disp_encoding <= disp_encoding_8bit
-      && (flag_code != CODE_64BIT
-         || strcmp (mnemonic, "movabs") != 0))
-    optimize_disp ();
+  if (i.disp_operands && !optimize_disp (t))
+    return;
 
   /* Next, we find a template that matches the given insn,
      making sure the overlap of the given operands types is consistent
@@ -5132,6 +5334,9 @@ md_assemble (char *line)
        case invalid_register_operand:
          err_msg = _("invalid register operand");
          break;
+       case internal_error:
+         err_msg = _("internal error");
+         break;
        }
       as_bad (_("%s for `%s'"), err_msg,
              pass1_mnem ? pass1_mnem : insn_name (current_templates->start));
@@ -5143,9 +5348,9 @@ md_assemble (char *line)
   if (sse_check != check_none
       /* The opcode space check isn't strictly needed; it's there only to
         bypass the logic below when easily possible.  */
-      && t->opcode_modifier.opcodespace >= SPACE_0F
-      && t->opcode_modifier.opcodespace <= SPACE_0F3A
-      && !i.tm.cpu_flags.bitfield.cpusse4a
+      && t->opcode_space >= SPACE_0F
+      && t->opcode_space <= SPACE_0F3A
+      && !is_cpu (&i.tm, CpuSSE4a)
       && !is_any_vex_encoding (t))
     {
       bool simd = false;
@@ -5178,14 +5383,20 @@ md_assemble (char *line)
 
   /* Check for lock without a lockable instruction.  Destination operand
      must be memory unless it is xchg (0x86).  */
-  if (i.prefix[LOCK_PREFIX]
-      && (i.tm.opcode_modifier.prefixok < PrefixLock
+  if (i.prefix[LOCK_PREFIX])
+    {
+      if (i.tm.opcode_modifier.prefixok < PrefixLock
          || i.mem_operands == 0
          || (i.tm.base_opcode != 0x86
-             && !(i.flags[i.operands - 1] & Operand_Mem))))
-    {
-      as_bad (_("expecting lockable instruction after `lock'"));
-      return;
+             && !(i.flags[i.operands - 1] & Operand_Mem)))
+       {
+         as_bad (_("expecting lockable instruction after `lock'"));
+         return;
+       }
+
+      /* Zap the redundant prefix from XCHG when optimizing.  */
+      if (i.tm.base_opcode == 0x86 && optimize && !i.no_optimize)
+       i.prefix[LOCK_PREFIX] = 0;
     }
 
   if (is_any_vex_encoding (&i.tm)
@@ -5226,7 +5437,7 @@ md_assemble (char *line)
   if (i.notrack_prefix && i.tm.opcode_modifier.prefixok != PrefixNoTrack)
     as_bad (_("expecting indirect branch instruction after `notrack'"));
 
-  if (i.tm.cpu_flags.bitfield.cpumpx)
+  if (is_cpu (&i.tm, CpuMPX))
     {
       if (flag_code == CODE_64BIT && i.prefix[ADDR_PREFIX])
        as_bad (_("32-bit address isn't allowed in 64-bit MPX instructions."));
@@ -5261,7 +5472,7 @@ md_assemble (char *line)
      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))
+         || i.tm.opcode_space != SPACE_BASE))
     {
       as_bad (_("input/output port address isn't allowed with `%s'"),
              insn_name (&i.tm));
@@ -5271,6 +5482,11 @@ md_assemble (char *line)
   if (optimize && !i.no_optimize && i.tm.opcode_modifier.optimize)
     optimize_encoding ();
 
+  /* Past optimization there's no need to distinguish vex_encoding_evex and
+     vex_encoding_evex512 anymore.  */
+  if (i.vec_encoding == vex_encoding_evex512)
+    i.vec_encoding = vex_encoding_evex;
+
   if (use_unaligned_vector_move)
     encode_with_unaligned_vector_move ();
 
@@ -5278,7 +5494,7 @@ md_assemble (char *line)
     return;
 
   /* Check if IP-relative addressing requirements can be satisfied.  */
-  if (i.tm.cpu_flags.bitfield.cpuprefetchi
+  if (is_cpu (&i.tm, CpuPREFETCHI)
       && !(i.base_reg && i.base_reg->reg_num == RegIP))
     as_warn (_("'%s' only supports RIP-relative address"), insn_name (&i.tm));
 
@@ -5299,9 +5515,12 @@ md_assemble (char *line)
        case RegSIMD:
          if (i.tm.operand_types[j].bitfield.tmmword)
            i.xstate |= xstate_tmm;
-         else if (i.tm.operand_types[j].bitfield.zmmword)
+         else if (i.tm.operand_types[j].bitfield.zmmword
+                  && !i.tm.opcode_modifier.vex
+                  && vector_size >= VSZ512)
            i.xstate |= xstate_zmm;
-         else if (i.tm.operand_types[j].bitfield.ymmword)
+         else if (i.tm.operand_types[j].bitfield.ymmword
+                  && vector_size >= VSZ256)
            i.xstate |= xstate_ymm;
          else if (i.tm.operand_types[j].bitfield.xmmword)
            i.xstate |= xstate_xmm;
@@ -5354,12 +5573,8 @@ md_assemble (char *line)
       i.rex &= REX_OPCODE;
     }
 
-  /* Handle conversion of 'int $3' --> special int3 insn.  XOP or FMA4
-     instructions may define INT_OPCODE as well, so avoid this corner
-     case for those instructions that use MODRM.  */
-  if (i.tm.opcode_modifier.opcodespace == SPACE_BASE
-      && i.tm.base_opcode == INT_OPCODE
-      && !i.tm.opcode_modifier.modrm
+  /* Handle conversion of 'int $3' --> special int3 insn.  */
+  if (i.tm.mnem_off == MN_int
       && i.op[0].imms->X_add_number == 3)
     {
       i.tm.base_opcode = INT3_OPCODE;
@@ -5466,17 +5681,14 @@ md_assemble (char *line)
 static INLINE bool q_suffix_allowed(const insn_template *t)
 {
   return flag_code == CODE_64BIT
-        || (t->opcode_modifier.opcodespace == SPACE_BASE
+        || (t->opcode_space == 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 */;
+        || t->mnem_off == MN_cmpxchg8b;
 }
 
 static const char *
-parse_insn (const char *line, char *mnemonic)
+parse_insn (const char *line, char *mnemonic, bool prefix_only)
 {
   const char *l = line, *token_start = l;
   char *mnem_p;
@@ -5488,6 +5700,12 @@ parse_insn (const char *line, char *mnemonic)
   while (1)
     {
       mnem_p = mnemonic;
+      /* Pseudo-prefixes start with an opening figure brace.  */
+      if ((*mnem_p = *l) == '{')
+       {
+         ++mnem_p;
+         ++l;
+       }
       while ((*mnem_p = mnemonic_chars[(unsigned char) *l]) != 0)
        {
          if (*mnem_p == '.')
@@ -5495,17 +5713,32 @@ parse_insn (const char *line, char *mnemonic)
          mnem_p++;
          if (mnem_p >= mnemonic + MAX_MNEM_SIZE)
            {
+           too_long:
              as_bad (_("no such instruction: `%s'"), token_start);
              return NULL;
            }
          l++;
        }
-      if (!is_space_char (*l)
-         && *l != END_OF_INSN
-         && (intel_syntax
-             || (*l != PREFIX_SEPARATOR
-                 && *l != ',')))
+      /* Pseudo-prefixes end with a closing figure brace.  */
+      if (*mnemonic == '{' && *l == '}')
+       {
+         *mnem_p++ = *l++;
+         if (mnem_p >= mnemonic + MAX_MNEM_SIZE)
+           goto too_long;
+         *mnem_p = '\0';
+
+         /* Point l at the closing brace if there's no other separator.  */
+         if (*l != END_OF_INSN && !is_space_char (*l)
+             && *l != PREFIX_SEPARATOR)
+           --l;
+       }
+      else if (!is_space_char (*l)
+              && *l != END_OF_INSN
+              && (intel_syntax
+                  || (*l != PREFIX_SEPARATOR && *l != ',')))
        {
+         if (prefix_only)
+           break;
          as_bad (_("invalid character %s in mnemonic"),
                  output_invalid (*l));
          return NULL;
@@ -5527,7 +5760,7 @@ parse_insn (const char *line, char *mnemonic)
          && current_templates
          && current_templates->start->opcode_modifier.isprefix)
        {
-         if (!cpu_flags_check_cpu64 (current_templates->start->cpu_flags))
+         if (!cpu_flags_check_cpu64 (current_templates->start))
            {
              as_bad ((flag_code != CODE_64BIT
                       ? _("`%s' is only supported in 64-bit mode")
@@ -5605,13 +5838,13 @@ parse_insn (const char *line, char *mnemonic)
                case PREFIX_EXIST:
                  return NULL;
                case PREFIX_DS:
-                 if (current_templates->start->cpu_flags.bitfield.cpuibt)
+                 if (is_cpu (current_templates->start, CpuIBT))
                    i.notrack_prefix = insn_name (current_templates->start);
                  break;
                case PREFIX_REP:
-                 if (current_templates->start->cpu_flags.bitfield.cpuhle)
+                 if (is_cpu (current_templates->start, CpuHLE))
                    i.hle_prefix = insn_name (current_templates->start);
-                 else if (current_templates->start->cpu_flags.bitfield.cpumpx)
+                 else if (is_cpu (current_templates->start, CpuMPX))
                    i.bnd_prefix = insn_name (current_templates->start);
                  else
                    i.rep_prefix = insn_name (current_templates->start);
@@ -5627,6 +5860,9 @@ parse_insn (const char *line, char *mnemonic)
        break;
     }
 
+  if (prefix_only)
+    return token_start;
+
   if (!current_templates)
     {
       /* Deprecated functionality (new code should use pseudo-prefixes instead):
@@ -5706,7 +5942,7 @@ parse_insn (const char *line, char *mnemonic)
                  if (current_templates != NULL
                      /* MOVS or CMPS */
                      && (current_templates->start->base_opcode | 2) == 0xa6
-                     && current_templates->start->opcode_modifier.opcodespace
+                     && current_templates->start->opcode_space
                         == SPACE_BASE
                      && mnem_p[-2] == 's')
                    {
@@ -5940,6 +6176,10 @@ swap_2_operands (unsigned int xchg1, unsigned int xchg2)
   i.reloc[xchg2] = i.reloc[xchg1];
   i.reloc[xchg1] = temp_reloc;
 
+  temp_flags = i.imm_bits[xchg2];
+  i.imm_bits[xchg2] = i.imm_bits[xchg1];
+  i.imm_bits[xchg1] = temp_flags;
+
   if (i.mask.reg)
     {
       if (i.mask.operand == xchg1)
@@ -6022,8 +6262,16 @@ optimize_imm (void)
            break;
          }
     }
-  else if ((flag_code == CODE_16BIT) ^ (i.prefix[DATA_PREFIX] != 0))
+  else if ((flag_code == CODE_16BIT)
+           ^ (i.prefix[DATA_PREFIX] != 0 && !(i.prefix[REX_PREFIX] & REX_W)))
     guess_suffix = WORD_MNEM_SUFFIX;
+  else if (flag_code != CODE_64BIT
+          || (!(i.prefix[REX_PREFIX] & REX_W)
+              /* A more generic (but also more involved) way of dealing
+                 with the special case(s) would be to go look for
+                 DefaultSize attributes on any of the templates.  */
+              && current_templates->start->mnem_off != MN_push))
+    guess_suffix = LONG_MNEM_SUFFIX;
 
   for (op = i.operands; --op >= 0;)
     if (operand_type_check (i.types[op], imm))
@@ -6134,12 +6382,47 @@ optimize_imm (void)
 }
 
 /* Try to use the smallest displacement type too.  */
-static void
-optimize_disp (void)
+static bool
+optimize_disp (const insn_template *t)
 {
-  int op;
+  unsigned int op;
 
-  for (op = i.operands; --op >= 0;)
+  if (!want_disp32 (t)
+      && (!t->opcode_modifier.jump
+         || i.jumpabsolute || i.types[0].bitfield.baseindex))
+    {
+      for (op = 0; op < i.operands; ++op)
+       {
+         const expressionS *exp = i.op[op].disps;
+
+         if (!operand_type_check (i.types[op], disp))
+           continue;
+
+         if (exp->X_op != O_constant)
+           continue;
+
+         /* Since displacement is signed extended to 64bit, don't allow
+            disp32 if it is out of range.  */
+         if (fits_in_signed_long (exp->X_add_number))
+           continue;
+
+         i.types[op].bitfield.disp32 = 0;
+         if (i.types[op].bitfield.baseindex)
+           {
+             as_bad (_("0x%" PRIx64 " out of range of signed 32bit displacement"),
+                     (uint64_t) exp->X_add_number);
+             return false;
+           }
+       }
+    }
+
+  /* Don't optimize displacement for movabs since it only takes 64bit
+     displacement.  */
+  if (i.disp_encoding > disp_encoding_8bit
+      || (flag_code == CODE_64BIT && t->mnem_off == MN_movabs))
+    return true;
+
+  for (op = i.operands; op-- > 0;)
     if (operand_type_check (i.types[op], disp))
       {
        if (i.op[op].disps->X_op == O_constant)
@@ -6168,8 +6451,8 @@ optimize_disp (void)
            /* Optimize 64-bit displacement to 32-bit for 64-bit BFD.  */
            if ((flag_code != CODE_64BIT
                 ? i.types[op].bitfield.disp32
-                : want_disp32 (current_templates->start)
-                  && (!current_templates->start->opcode_modifier.jump
+                : want_disp32 (t)
+                  && (!t->opcode_modifier.jump
                       || i.jumpabsolute || i.types[op].bitfield.baseindex))
                && fits_in_unsigned_long (op_disp))
              {
@@ -6205,6 +6488,8 @@ optimize_disp (void)
          /* We only support 64bit displacement on constants.  */
          i.types[op].bitfield.disp64 = 0;
       }
+
+  return true;
 }
 
 /* Return 1 if there is a match in broadcast bytes between operand
@@ -6236,10 +6521,11 @@ check_VecOperands (const insn_template *t)
      operand size is YMMword or XMMword.  Since this function runs after
      template matching, there's no need to check for YMMword/XMMword in
      the template.  */
-  cpu = cpu_flags_and (t->cpu_flags, avx512);
+  cpu = cpu_flags_and (cpu_flags_from_attr (t->cpu), avx512);
   if (!cpu_flags_all_zero (&cpu)
-      && !t->cpu_flags.bitfield.cpuavx512vl
-      && !cpu_arch_flags.bitfield.cpuavx512vl)
+      && !is_cpu (t, CpuAVX512VL)
+      && !cpu_arch_flags.bitfield.cpuavx512vl
+      && (!t->opcode_modifier.vex || need_evex_encoding ()))
     {
       for (op = 0; op < t->operands; ++op)
        {
@@ -6255,8 +6541,7 @@ check_VecOperands (const insn_template *t)
 
   /* Somewhat similarly, templates specifying both AVX and AVX2 are
      requiring AVX2 support if the actual operand size is YMMword.  */
-  if (t->cpu_flags.bitfield.cpuavx
-      && t->cpu_flags.bitfield.cpuavx2
+  if (is_cpu (t, CpuAVX) && is_cpu (t, CpuAVX2)
       && !cpu_arch_flags.bitfield.cpuavx2)
     {
       for (op = 0; op < t->operands; ++op)
@@ -6399,9 +6684,6 @@ check_VecOperands (const insn_template *t)
          return 1;
        }
 
-      if (i.broadcast.type)
-       i.broadcast.bytes = ((1 << (t->opcode_modifier.broadcast - 1))
-                            * i.broadcast.type);
       operand_type_set (&type, 0);
       switch (get_broadcast_bytes (t, false))
        {
@@ -6418,9 +6700,13 @@ check_VecOperands (const insn_template *t)
          type.bitfield.xmmword = 1;
          break;
        case 32:
+         if (vector_size < VSZ256)
+           goto bad_broadcast;
          type.bitfield.ymmword = 1;
          break;
        case 64:
+         if (vector_size < VSZ512)
+           goto bad_broadcast;
          type.bitfield.zmmword = 1;
          break;
        default:
@@ -6479,36 +6765,25 @@ check_VecOperands (const insn_template *t)
   /* Check if requested masking is supported.  */
   if (i.mask.reg)
     {
-      switch (t->opcode_modifier.masking)
+      if (!t->opcode_modifier.masking)
        {
-       case BOTH_MASKING:
-         break;
-       case MERGING_MASKING:
-         if (i.mask.zeroing)
-           {
-       case 0:
-             i.error = unsupported_masking;
-             return 1;
-           }
-         break;
-       case DYNAMIC_MASKING:
-         /* Memory destinations allow only merging masking.  */
-         if (i.mask.zeroing && i.mem_operands)
-           {
-             /* Find memory operand.  */
-             for (op = 0; op < i.operands; op++)
-               if (i.flags[op] & Operand_Mem)
-                 break;
-             gas_assert (op < i.operands);
-             if (op == i.operands - 1)
-               {
-                 i.error = unsupported_masking;
-                 return 1;
-               }
-           }
-         break;
-       default:
-         abort ();
+         i.error = unsupported_masking;
+         return 1;
+       }
+
+      /* Common rules for masking:
+        - mask register destinations permit only zeroing-masking, without
+          that actually being expressed by a {z} operand suffix or EVEX.z,
+        - memory destinations allow only merging-masking,
+        - scatter/gather insns (i.e. ones using vSIB) only allow merging-
+          masking.  */
+      if (i.mask.zeroing
+         && (t->operand_types[t->operands - 1].bitfield.class == RegMask
+             || (i.flags[t->operands - 1] & Operand_Mem)
+             || t->opcode_modifier.sib))
+       {
+         i.error = unsupported_masking;
+         return 1;
        }
     }
 
@@ -6546,7 +6821,7 @@ check_VecOperands (const insn_template *t)
     }
 
   /* Check the special Imm4 cases; must be the first operand.  */
-  if (t->cpu_flags.bitfield.cpuxop && t->operands == 5)
+  if (is_cpu (t, CpuXOP) && t->operands == 5)
     {
       if (i.op[0].imms->X_op != O_constant
          || !fits_in_imm4 (i.op[0].imms->X_add_number))
@@ -6561,9 +6836,11 @@ check_VecOperands (const insn_template *t)
 
   /* Check vector Disp8 operand.  */
   if (t->opcode_modifier.disp8memshift
+      && (!t->opcode_modifier.vex
+          || need_evex_encoding ())
       && i.disp_encoding <= disp_encoding_8bit)
     {
-      if (i.broadcast.bytes)
+      if (i.broadcast.type || i.broadcast.bytes)
        i.memshift = t->opcode_modifier.broadcast - 1;
       else if (t->opcode_modifier.disp8memshift != DISP8_SHIFT_VL)
        i.memshift = t->opcode_modifier.disp8memshift;
@@ -6643,7 +6920,21 @@ VEX_check_encoding (const insn_template *t)
       return 1;
     }
 
-  if (i.vec_encoding == vex_encoding_evex)
+  /* Vector size restrictions.  */
+  if ((vector_size < VSZ512
+       && (t->opcode_modifier.evex == EVEX512
+          || t->opcode_modifier.vsz >= VSZ512))
+      || (vector_size < VSZ256
+         && (t->opcode_modifier.evex == EVEX256
+             || t->opcode_modifier.vex == VEX256
+             || t->opcode_modifier.vsz >= VSZ256)))
+    {
+      i.error = unsupported;
+      return 1;
+    }
+
+  if (i.vec_encoding == vex_encoding_evex
+      || i.vec_encoding == vex_encoding_evex512)
     {
       /* This instruction must be encoded with EVEX prefix.  */
       if (!is_evex_encoding (t))
@@ -6873,22 +7164,44 @@ match_template (char mnem_suffix)
        case 1:
          if (!operand_type_match (overlap0, i.types[0]))
            continue;
+
+         /* Allow the ModR/M encoding to be requested by using the {load} or
+            {store} pseudo prefix on an applicable insn.  */
+         if (!t->opcode_modifier.modrm
+             && i.reg_operands == 1
+             && ((i.dir_encoding == dir_encoding_load
+                  && t->mnem_off != MN_pop)
+                 || (i.dir_encoding == dir_encoding_store
+                     && t->mnem_off != MN_push))
+             /* Avoid BSWAP.  */
+             && t->mnem_off != MN_bswap)
+           continue;
          break;
+
        case 2:
          /* xchg %eax, %eax is a special case. It is an alias for nop
             only in 32bit mode and we can use opcode 0x90.  In 64bit
             mode, we can't use 0x90 for xchg %eax, %eax since it should
             zero-extend %eax to %rax.  */
-         if (flag_code == CODE_64BIT
-             && t->base_opcode == 0x90
-             && t->opcode_modifier.opcodespace == SPACE_BASE
-             && i.types[0].bitfield.instance == Accum
-             && i.types[0].bitfield.dword
-             && i.types[1].bitfield.instance == Accum)
-           continue;
+         if (t->base_opcode == 0x90
+             && t->opcode_space == SPACE_BASE)
+           {
+             if (flag_code == CODE_64BIT
+                 && i.types[0].bitfield.instance == Accum
+                 && i.types[0].bitfield.dword
+                 && i.types[1].bitfield.instance == Accum)
+               continue;
+
+             /* Allow the ModR/M encoding to be requested by using the
+                {load} or {store} pseudo prefix.  */
+             if (i.dir_encoding == dir_encoding_load
+                 || i.dir_encoding == dir_encoding_store)
+               continue;
+           }
 
          if (t->base_opcode == MOV_AX_DISP32
-             && t->opcode_modifier.opcodespace == SPACE_BASE)
+             && t->opcode_space == SPACE_BASE
+             && t->mnem_off != MN_movabs)
            {
              /* Force 0x8b encoding for "mov foo@GOT, %eax".  */
              if (i.reloc[0] == BFD_RELOC_386_GOT32)
@@ -6898,6 +7211,38 @@ match_template (char mnem_suffix)
                 match the accumulator-only encoding of mov.  */
              if (i.hle_prefix)
                continue;
+
+             /* Allow the ModR/M encoding to be requested by using a suitable
+                {load} or {store} pseudo prefix.  */
+             if (i.dir_encoding == (i.types[0].bitfield.instance == Accum
+                                    ? dir_encoding_store
+                                    : dir_encoding_load)
+                 && !i.types[0].bitfield.disp64
+                 && !i.types[1].bitfield.disp64)
+               continue;
+           }
+
+         /* Allow the ModR/M encoding to be requested by using the {load} or
+            {store} pseudo prefix on an applicable insn.  */
+         if (!t->opcode_modifier.modrm
+             && i.reg_operands == 1
+             && i.imm_operands == 1
+             && (i.dir_encoding == dir_encoding_load
+                 || i.dir_encoding == dir_encoding_store)
+             && t->opcode_space == SPACE_BASE)
+           {
+             if (t->base_opcode == 0xb0 /* mov $imm, %reg */
+                 && i.dir_encoding == dir_encoding_store)
+               continue;
+
+             if ((t->base_opcode | 0x38) == 0x3c /* <alu> $imm, %acc */
+                 && (t->base_opcode != 0x3c /* cmp $imm, %acc */
+                     || i.dir_encoding == dir_encoding_load))
+               continue;
+
+             if (t->base_opcode == 0xa8 /* test $imm, %acc */
+                 && i.dir_encoding == dir_encoding_load)
+               continue;
            }
          /* Fall through.  */
 
@@ -6960,7 +7305,8 @@ match_template (char mnem_suffix)
              if (!(size_match & MATCH_REVERSE))
                continue;
              /* Try reversing direction of operands.  */
-             j = t->opcode_modifier.vexsources ? 1 : i.operands - 1;
+             j = is_cpu (t, CpuFMA4)
+                 || is_cpu (t, CpuXOP) ? 1 : i.operands - 1;
              overlap0 = operand_type_and (i.types[0], operand_types[j]);
              overlap1 = operand_type_and (i.types[j], operand_types[0]);
              overlap2 = operand_type_and (i.types[1], operand_types[1]);
@@ -6994,13 +7340,13 @@ match_template (char mnem_suffix)
                      && (intel_syntax || intel_mnemonic))
                    found_reverse_match |= Opcode_FloatR;
                }
-             else if (t->opcode_modifier.vexsources)
+             else if (is_cpu (t, CpuFMA4) || is_cpu (t, CpuXOP))
                {
                  found_reverse_match = Opcode_VexW;
                  goto check_operands_345;
                }
-             else if (t->opcode_modifier.opcodespace != SPACE_BASE
-                      && (t->opcode_modifier.opcodespace != SPACE_0F
+             else if (t->opcode_space != SPACE_BASE
+                      && (t->opcode_space != SPACE_0F
                           /* MOV to/from CR/DR/TR, as an exception, follow
                              the base opcode space encoding model.  */
                           || (t->base_opcode | 7) != 0x27))
@@ -7085,6 +7431,33 @@ match_template (char mnem_suffix)
          continue;
        }
 
+      /* Check whether to use the shorter VEX encoding for certain insns where
+        the EVEX enconding comes first in the table.  This requires the respective
+        AVX-* feature to be explicitly enabled.  */
+      if (t == current_templates->start
+         && t->opcode_modifier.disp8memshift
+         && !t->opcode_modifier.vex
+         && !need_evex_encoding ()
+         && t + 1 < current_templates->end
+         && t[1].opcode_modifier.vex)
+       {
+         i386_cpu_flags cpu;
+         unsigned int memshift = i.memshift;
+
+         i.memshift = 0;
+         cpu = cpu_flags_and (cpu_flags_from_attr (t[1].cpu), cpu_arch_isa_flags);
+         if (!cpu_flags_all_zero (&cpu)
+             && (!i.types[0].bitfield.disp8
+                 || !operand_type_check (i.types[0], disp)
+                 || i.op[0].disps->X_op != O_constant
+                 || fits_in_disp8 (i.op[0].disps->X_add_number)))
+           {
+             specific_error = progress (internal_error);
+             continue;
+           }
+         i.memshift = memshift;
+       }
+
       /* We've found a match; break out of loop.  */
       break;
     }
@@ -7193,7 +7566,7 @@ check_string (void)
 static int
 process_suffix (void)
 {
-  bool is_crc32 = false, is_movx = false;
+  bool is_movx = false;
 
   /* If matched instruction specifies an explicit instruction mnemonic
      suffix, use it.  */
@@ -7210,16 +7583,11 @@ process_suffix (void)
       unsigned int numop = i.operands;
 
       /* MOVSX/MOVZX */
-      is_movx = (i.tm.opcode_modifier.opcodespace == SPACE_0F
+      is_movx = (i.tm.opcode_space == SPACE_0F
                 && (i.tm.base_opcode | 8) == 0xbe)
-               || (i.tm.opcode_modifier.opcodespace == SPACE_BASE
+               || (i.tm.opcode_space == SPACE_BASE
                    && i.tm.base_opcode == 0x63
-                   && i.tm.cpu_flags.bitfield.cpu64);
-
-      /* CRC32 */
-      is_crc32 = (i.tm.base_opcode == 0xf0
-                 && i.tm.opcode_modifier.opcodespace == SPACE_0F38
-                 && i.tm.opcode_modifier.opcodeprefix == PREFIX_0XF2);
+                   && is_cpu (&i.tm, Cpu64));
 
       /* movsx/movzx want only their source operand considered here, for the
         ambiguity checking below.  The suffix will be replaced afterwards
@@ -7228,7 +7596,7 @@ process_suffix (void)
        --i.operands;
 
       /* crc32 needs REX.W set regardless of suffix / source operand size.  */
-      if (is_crc32 && i.tm.operand_types[1].bitfield.qword)
+      if (i.tm.mnem_off == MN_crc32 && i.tm.operand_types[1].bitfield.qword)
         i.rex |= REX_W;
 
       /* If there's no instruction mnemonic suffix we try to invent one
@@ -7239,7 +7607,7 @@ process_suffix (void)
             Destination register type is more significant than source
             register type.  crc32 in SSE4.2 prefers source register
             type. */
-         unsigned int op = is_crc32 ? 1 : i.operands;
+         unsigned int op = i.tm.mnem_off == MN_crc32 ? 1 : i.operands;
 
          while (op--)
            if (i.tm.operand_types[op].bitfield.instance == InstanceNone
@@ -7321,7 +7689,7 @@ process_suffix (void)
           && (i.tm.opcode_modifier.jump == JUMP_ABSOLUTE
               || i.tm.opcode_modifier.jump == JUMP_BYTE
               || i.tm.opcode_modifier.jump == JUMP_INTERSEGMENT
-              || (i.tm.opcode_modifier.opcodespace == SPACE_0F
+              || (i.tm.opcode_space == SPACE_0F
                   && i.tm.base_opcode == 0x01 /* [ls][gi]dt */
                   && i.tm.extension_opcode <= 3)))
     {
@@ -7381,8 +7749,27 @@ process_suffix (void)
 
          for (op = 0; op < i.tm.operands; ++op)
            {
-             if (is_evex_encoding (&i.tm)
-                 && !cpu_arch_flags.bitfield.cpuavx512vl)
+             if (vector_size < VSZ512)
+               {
+                 i.tm.operand_types[op].bitfield.zmmword = 0;
+                 if (vector_size < VSZ256)
+                   {
+                     i.tm.operand_types[op].bitfield.ymmword = 0;
+                     if (i.tm.operand_types[op].bitfield.xmmword
+                         && (i.tm.opcode_modifier.evex == EVEXDYN
+                             || (!i.tm.opcode_modifier.evex
+                                 && is_evex_encoding (&i.tm))))
+                       i.tm.opcode_modifier.evex = EVEX128;
+                   }
+                 else if (i.tm.operand_types[op].bitfield.ymmword
+                          && !i.tm.operand_types[op].bitfield.xmmword
+                          && (i.tm.opcode_modifier.evex == EVEXDYN
+                              || (!i.tm.opcode_modifier.evex
+                                  && is_evex_encoding (&i.tm))))
+                   i.tm.opcode_modifier.evex = EVEX256;
+               }
+             else if (is_evex_encoding (&i.tm)
+                      && !cpu_arch_flags.bitfield.cpuavx512vl)
                {
                  if (i.tm.operand_types[op].bitfield.ymmword)
                    i.tm.operand_types[op].bitfield.xmmword = 0;
@@ -7543,7 +7930,7 @@ process_suffix (void)
             need rex64. */
          && ! (i.operands == 2
                && i.tm.base_opcode == 0x90
-               && i.tm.opcode_modifier.opcodespace == SPACE_BASE
+               && i.tm.opcode_space == SPACE_BASE
                && i.types[0].bitfield.instance == Accum
                && i.types[0].bitfield.qword
                && i.types[1].bitfield.instance == Accum))
@@ -7563,8 +7950,7 @@ process_suffix (void)
                      /* InOutPortReg */
                      || i.tm.operand_types[0].bitfield.instance == RegD
                      || i.tm.operand_types[1].bitfield.instance == RegD
-                     /* CRC32 */
-                     || is_crc32))))
+                     || i.tm.mnem_off == MN_crc32))))
        i.tm.base_opcode |= 1;
       break;
     }
@@ -7683,10 +8069,7 @@ check_byte_reg (void)
        continue;
 
       /* crc32 only wants its source operand checked here.  */
-      if (i.tm.base_opcode == 0xf0
-         && i.tm.opcode_modifier.opcodespace == SPACE_0F38
-         && i.tm.opcode_modifier.opcodeprefix == PREFIX_0XF2
-         && op != 0)
+      if (i.tm.mnem_off == MN_crc32 && op != 0)
        continue;
 
       /* Any other register is bad.  */
@@ -7828,6 +8211,18 @@ static int
 update_imm (unsigned int j)
 {
   i386_operand_type overlap = i.types[j];
+
+  if (i.tm.operand_types[j].bitfield.imm8
+      && i.tm.operand_types[j].bitfield.imm8s
+      && overlap.bitfield.imm8 && overlap.bitfield.imm8s)
+    {
+      /* This combination is used on 8-bit immediates where e.g. $~0 is
+        desirable to permit.  We're past operand type matching, so simply
+        put things back in the shape they were before introducing the
+        distinction between Imm8, Imm8S, and Imm8|Imm8S.  */
+      overlap.bitfield.imm8s = 0;
+    }
+
   if (overlap.bitfield.imm8
       + overlap.bitfield.imm8s
       + overlap.bitfield.imm16
@@ -7873,7 +8268,8 @@ update_imm (unsigned int j)
               || operand_type_equal (&overlap, &imm16_32)
               || operand_type_equal (&overlap, &imm16_32s))
        {
-         if ((flag_code == CODE_16BIT) ^ (i.prefix[DATA_PREFIX] != 0))
+         if ((flag_code == CODE_16BIT)
+             ^ (i.prefix[DATA_PREFIX] != 0 && !(i.prefix[REX_PREFIX] & REX_W)))
            overlap = imm16;
          else
            overlap = imm32s;
@@ -7920,6 +8316,25 @@ finalize_imm (void)
   return 1;
 }
 
+static INLINE void set_rex_vrex (const reg_entry *r, unsigned int rex_bit,
+                                bool do_sse2avx)
+{
+  if (r->reg_flags & RegRex)
+    {
+      if (i.rex & rex_bit)
+       as_bad (_("same type of prefix used twice"));
+      i.rex |= rex_bit;
+    }
+  else if (do_sse2avx && (i.rex & rex_bit) && i.vex.register_specifier)
+    {
+      gas_assert (i.vex.register_specifier == r);
+      i.vex.register_specifier += 8;
+    }
+
+  if (r->reg_flags & RegVRex)
+    i.vrex |= rex_bit;
+}
+
 static int
 process_operands (void)
 {
@@ -7947,6 +8362,22 @@ process_operands (void)
   else if (i.tm.opcode_modifier.immext)
     process_immext ();
 
+  /* TILEZERO is unusual in that it has a single operand encoded in ModR/M.reg,
+     not ModR/M.rm.  To avoid special casing this in build_modrm_byte(), fake a
+     new destination operand here, while converting the source one to register
+     number 0.  */
+  if (i.tm.mnem_off == MN_tilezero)
+    {
+      i.op[1].regs = i.op[0].regs;
+      i.op[0].regs -= i.op[0].regs->reg_num;
+      i.types[1] = i.types[0];
+      i.tm.operand_types[1] = i.tm.operand_types[0];
+      i.flags[1] = i.flags[0];
+      i.operands++;
+      i.reg_operands++;
+      i.tm.operands++;
+    }
+
   if (i.tm.opcode_modifier.sse2avx && i.tm.opcode_modifier.vexvvvv)
     {
       static const i386_operand_type regxmm = {
@@ -7964,7 +8395,6 @@ process_operands (void)
       if (i.tm.operand_types[0].bitfield.instance == Accum
          && i.tm.operand_types[0].bitfield.xmmword)
        {
-         gas_assert (i.tm.opcode_modifier.vexsources == VEX3SOURCES);
          /* Keep xmm0 for instructions with VEX prefix and 3
             sources.  */
          i.tm.operand_types[0].bitfield.instance = InstanceNone;
@@ -7975,9 +8405,7 @@ process_operands (void)
 
       if (i.tm.opcode_modifier.operandconstraint == IMPLICIT_1ST_XMM0)
        {
-         gas_assert ((MAX_OPERANDS - 1) > dupl
-                     && (i.tm.opcode_modifier.vexsources
-                         == VEX3SOURCES));
+         gas_assert ((MAX_OPERANDS - 1) > dupl);
 
          /* Add the implicit xmm0 for instructions with VEX prefix
             and 3 sources.  */
@@ -8106,7 +8534,7 @@ process_operands (void)
            }
        }
     }
-  else if (i.types[0].bitfield.class == SReg)
+  else if (i.types[0].bitfield.class == SReg && !dot_insn ())
     {
       if (flag_code != CODE_64BIT
          ? i.tm.base_opcode == POP_SEG_SHORT
@@ -8119,14 +8547,14 @@ process_operands (void)
          return 0;
        }
       if (i.op[0].regs->reg_num > 3
-         && i.tm.opcode_modifier.opcodespace == SPACE_BASE )
+         && i.tm.opcode_space == SPACE_BASE )
        {
          i.tm.base_opcode ^= (POP_SEG_SHORT ^ POP_SEG386_SHORT) & 0xff;
-         i.tm.opcode_modifier.opcodespace = SPACE_0F;
+         i.tm.opcode_space = SPACE_0F;
        }
       i.tm.base_opcode |= (i.op[0].regs->reg_num << 3);
     }
-  else if (i.tm.opcode_modifier.opcodespace == SPACE_BASE
+  else if (i.tm.opcode_space == SPACE_BASE
           && (i.tm.base_opcode & ~3) == MOV_AX_DISP32)
     {
       default_seg = reg_ds;
@@ -8139,26 +8567,40 @@ process_operands (void)
     }
   else if (i.short_form)
     {
-      /* The register operand is in operand 0 or 1.  */
-      const reg_entry *r = i.op[0].regs;
+      /* The register operand is in the 1st or 2nd non-immediate operand.  */
+      const reg_entry *r = i.op[i.imm_operands].regs;
 
-      if (i.imm_operands
-         || (r->reg_type.bitfield.instance == Accum && i.op[1].regs))
-       r = i.op[1].regs;
+      if (!dot_insn ()
+         && r->reg_type.bitfield.instance == Accum
+         && i.op[i.imm_operands + 1].regs)
+       r = i.op[i.imm_operands + 1].regs;
       /* Register goes in low 3 bits of opcode.  */
       i.tm.base_opcode |= r->reg_num;
-      if ((r->reg_flags & RegRex) != 0)
-       i.rex |= REX_B;
+      set_rex_vrex (r, REX_B, false);
+
+      if (dot_insn () && i.reg_operands == 2)
+       {
+         gas_assert (is_any_vex_encoding (&i.tm)
+                     || i.vec_encoding != vex_encoding_default);
+         i.vex.register_specifier = i.op[i.operands - 1].regs;
+       }
+    }
+  else if (i.reg_operands == 1
+          && !i.flags[i.operands - 1]
+          && i.tm.operand_types[i.operands - 1].bitfield.instance
+             == InstanceNone)
+    {
+      gas_assert (is_any_vex_encoding (&i.tm)
+                 || i.vec_encoding != vex_encoding_default);
+      i.vex.register_specifier = i.op[i.operands - 1].regs;
     }
 
   if ((i.seg[0] || i.prefix[SEG_PREFIX])
-      && i.tm.base_opcode == 0x8d /* lea */
-      && i.tm.opcode_modifier.opcodespace == SPACE_BASE
-      && !is_any_vex_encoding(&i.tm))
+      && i.tm.mnem_off == MN_lea)
     {
       if (!quiet_warnings)
        as_warn (_("segment override on `%s' is ineffectual"), insn_name (&i.tm));
-      if (optimize)
+      if (optimize && !i.no_optimize)
        {
          i.seg[0] = NULL;
          i.prefix[SEG_PREFIX] = 0;
@@ -8180,66 +8622,58 @@ process_operands (void)
   return 1;
 }
 
-static INLINE void set_rex_vrex (const reg_entry *r, unsigned int rex_bit,
-                                bool do_sse2avx)
-{
-  if (r->reg_flags & RegRex)
-    {
-      if (i.rex & rex_bit)
-       as_bad (_("same type of prefix used twice"));
-      i.rex |= rex_bit;
-    }
-  else if (do_sse2avx && (i.rex & rex_bit) && i.vex.register_specifier)
-    {
-      gas_assert (i.vex.register_specifier == r);
-      i.vex.register_specifier += 8;
-    }
-
-  if (r->reg_flags & RegVRex)
-    i.vrex |= rex_bit;
-}
-
-static const reg_entry *
-build_modrm_byte (void)
+static const reg_entry *
+build_modrm_byte (void)
 {
   const reg_entry *default_seg = NULL;
-  unsigned int source, dest;
-  int vex_3_sources;
+  unsigned int source = i.imm_operands - i.tm.opcode_modifier.immext
+                       /* Compensate for kludge in md_assemble().  */
+                       + i.tm.operand_types[0].bitfield.imm1;
+  unsigned int dest = i.operands - 1 - i.tm.opcode_modifier.immext;
+  unsigned int v, op, reg_slot = ~0;
+
+  /* Accumulator (in particular %st), shift count (%cl), and alike need
+     to be skipped just like immediate operands do.  */
+  if (i.tm.operand_types[source].bitfield.instance)
+    ++source;
+  while (i.tm.operand_types[dest].bitfield.instance)
+    --dest;
+
+  for (op = source; op < i.operands; ++op)
+    if (i.tm.operand_types[op].bitfield.baseindex)
+      break;
 
-  vex_3_sources = i.tm.opcode_modifier.vexsources == VEX3SOURCES;
-  if (vex_3_sources)
+  if (i.reg_operands + i.mem_operands + (i.tm.extension_opcode != None) == 4)
     {
-      unsigned int nds, reg_slot;
       expressionS *exp;
 
-      dest = i.operands - 1;
-      nds = dest - 1;
-
       /* There are 2 kinds of instructions:
         1. 5 operands: 4 register operands or 3 register operands
         plus 1 memory operand plus one Imm4 operand, VexXDS, and
         VexW0 or VexW1.  The destination must be either XMM, YMM or
         ZMM register.
         2. 4 operands: 4 register operands or 3 register operands
-        plus 1 memory operand, with VexXDS.  */
-      gas_assert ((i.reg_operands == 4
-                  || (i.reg_operands == 3 && i.mem_operands == 1))
-                 && i.tm.opcode_modifier.vexvvvv == VEXXDS
-                 && i.tm.opcode_modifier.vexw
-                 && i.tm.operand_types[dest].bitfield.class == RegSIMD);
+        plus 1 memory operand, with VexXDS.
+        3. Other equivalent combinations when coming from s_insn().  */
+      gas_assert (i.tm.opcode_modifier.vexvvvv
+                 && i.tm.opcode_modifier.vexw);
+      gas_assert (dot_insn ()
+                 || i.tm.operand_types[dest].bitfield.class == RegSIMD);
+
+      /* Of the first two non-immediate operands the one with the template
+        not allowing for a memory one is encoded in the immediate operand.  */
+      if (source == op)
+       reg_slot = source + 1;
+      else
+       reg_slot = source++;
 
-      /* If VexW1 is set, the first non-immediate operand is the source and
-        the second non-immediate one is encoded in the immediate operand.  */
-      if (i.tm.opcode_modifier.vexw == VEXW1)
+      if (!dot_insn ())
        {
-         source = i.imm_operands;
-         reg_slot = i.imm_operands + 1;
+         gas_assert (i.tm.operand_types[reg_slot].bitfield.class == RegSIMD);
+         gas_assert (!(i.op[reg_slot].regs->reg_flags & RegVRex));
        }
       else
-       {
-         source = i.imm_operands + 1;
-         reg_slot = i.imm_operands;
-       }
+       gas_assert (i.tm.operand_types[reg_slot].bitfield.class != ClassNone);
 
       if (i.imm_operands == 0)
        {
@@ -8250,10 +8684,7 @@ build_modrm_byte (void)
          i.types[i.operands].bitfield.imm8 = 1;
          i.operands++;
 
-         gas_assert (i.tm.operand_types[reg_slot].bitfield.class == RegSIMD);
          exp->X_op = O_constant;
-         exp->X_add_number = register_number (i.op[reg_slot].regs) << 4;
-         gas_assert ((i.op[reg_slot].regs->reg_flags & RegVRex) == 0);
        }
       else
        {
@@ -8264,163 +8695,47 @@ build_modrm_byte (void)
          /* Turn on Imm8 again so that output_imm will generate it.  */
          i.types[0].bitfield.imm8 = 1;
 
-         gas_assert (i.tm.operand_types[reg_slot].bitfield.class == RegSIMD);
-         i.op[0].imms->X_add_number
-             |= register_number (i.op[reg_slot].regs) << 4;
-         gas_assert ((i.op[reg_slot].regs->reg_flags & RegVRex) == 0);
+         exp = i.op[0].imms;
        }
-
-      gas_assert (i.tm.operand_types[nds].bitfield.class == RegSIMD);
-      i.vex.register_specifier = i.op[nds].regs;
+      exp->X_add_number |= register_number (i.op[reg_slot].regs)
+                          << (3 + !(is_evex_encoding (&i.tm)
+                                    || i.vec_encoding == vex_encoding_evex));
     }
-  else
-    source = dest = 0;
-
-  /* i.reg_operands MUST be the number of real register operands;
-     implicit registers do not count.  If there are 3 register
-     operands, it must be a instruction with VexNDS.  For a
-     instruction with VexNDD, the destination register is encoded
-     in VEX prefix.  If there are 4 register operands, it must be
-     a instruction with VEX prefix and 3 sources.  */
-  if (i.mem_operands == 0
-      && ((i.reg_operands == 2
-          && i.tm.opcode_modifier.vexvvvv <= VEXXDS)
-         || (i.reg_operands == 3
-             && i.tm.opcode_modifier.vexvvvv == VEXXDS)
-         || (i.reg_operands == 4 && vex_3_sources)))
-    {
-      switch (i.operands)
-       {
-       case 2:
-         source = 0;
-         break;
-       case 3:
-         /* When there are 3 operands, one of them may be immediate,
-            which may be the first or the last operand.  Otherwise,
-            the first operand must be shift count register (cl) or it
-            is an instruction with VexNDS. */
-         gas_assert (i.imm_operands == 1
-                     || (i.imm_operands == 0
-                         && (i.tm.opcode_modifier.vexvvvv == VEXXDS
-                             || (i.types[0].bitfield.instance == RegC
-                                 && i.types[0].bitfield.byte))));
-         if (operand_type_check (i.types[0], imm)
-             || (i.types[0].bitfield.instance == RegC
-                 && i.types[0].bitfield.byte))
-           source = 1;
-         else
-           source = 0;
-         break;
-       case 4:
-         /* When there are 4 operands, the first two must be 8bit
-            immediate operands. The source operand will be the 3rd
-            one.
-
-            For instructions with VexNDS, if the first operand
-            an imm8, the source operand is the 2nd one.  If the last
-            operand is imm8, the source operand is the first one.  */
-         gas_assert ((i.imm_operands == 2
-                      && i.types[0].bitfield.imm8
-                      && i.types[1].bitfield.imm8)
-                     || (i.tm.opcode_modifier.vexvvvv == VEXXDS
-                         && i.imm_operands == 1
-                         && (i.types[0].bitfield.imm8
-                             || i.types[i.operands - 1].bitfield.imm8)));
-         if (i.imm_operands == 2)
-           source = 2;
-         else
-           {
-             if (i.types[0].bitfield.imm8)
-               source = 1;
-             else
-               source = 0;
-           }
-         break;
-       case 5:
-         gas_assert (!is_evex_encoding (&i.tm));
-         gas_assert (i.imm_operands == 1 && vex_3_sources);
-         break;
-       default:
-         abort ();
-       }
-
-      if (!vex_3_sources)
-       {
-         dest = source + 1;
-
-         if (i.tm.opcode_modifier.vexvvvv == VEXXDS)
-           {
-             /* For instructions with VexNDS, the register-only source
-                operand must be a 32/64bit integer, XMM, YMM, ZMM, or mask
-                register.  It is encoded in VEX prefix.  */
 
-             i386_operand_type op;
-             unsigned int vvvv;
+  for (v = source + 1; v < dest; ++v)
+    if (v != reg_slot)
+      break;
+  if (v >= dest)
+    v = ~0;
+  if (i.tm.extension_opcode != None)
+    {
+      if (dest != source)
+       v = dest;
+      dest = ~0;
+    }
+  gas_assert (source < dest);
+  if (i.tm.opcode_modifier.operandconstraint == SWAP_SOURCES
+      && source != op)
+    {
+      unsigned int tmp = source;
 
-             /* Swap two source operands if needed.  */
-             if (i.tm.opcode_modifier.operandconstraint == SWAP_SOURCES)
-               {
-                 vvvv = source;
-                 source = dest;
-               }
-             else
-               vvvv = dest;
-
-             op = i.tm.operand_types[vvvv];
-             if ((dest + 1) >= i.operands
-                 || ((op.bitfield.class != Reg
-                      || (!op.bitfield.dword && !op.bitfield.qword))
-                     && op.bitfield.class != RegSIMD
-                     && op.bitfield.class != RegMask))
-               abort ();
-             i.vex.register_specifier = i.op[vvvv].regs;
-             dest++;
-           }
-       }
+      source = v;
+      v = tmp;
+    }
 
-      i.rm.mode = 3;
-      /* One of the register operands will be encoded in the i.rm.reg
-        field, the other in the combined i.rm.mode and i.rm.regmem
-        fields.  If no form of this instruction supports a memory
-        destination operand, then we assume the source operand may
-        sometimes be a memory operand and so we need to store the
-        destination in the i.rm.reg field.  */
-      if (!i.tm.opcode_modifier.regmem
-         && operand_type_check (i.tm.operand_types[dest], anymem) == 0)
-       {
-         i.rm.reg = i.op[dest].regs->reg_num;
-         i.rm.regmem = i.op[source].regs->reg_num;
-         set_rex_vrex (i.op[dest].regs, REX_R, i.tm.opcode_modifier.sse2avx);
-         set_rex_vrex (i.op[source].regs, REX_B, false);
-       }
-      else
-       {
-         i.rm.reg = i.op[source].regs->reg_num;
-         i.rm.regmem = i.op[dest].regs->reg_num;
-         set_rex_vrex (i.op[dest].regs, REX_B, i.tm.opcode_modifier.sse2avx);
-         set_rex_vrex (i.op[source].regs, REX_R, false);
-       }
-      if (flag_code != CODE_64BIT && (i.rex & REX_R))
-       {
-         if (i.types[!i.tm.opcode_modifier.regmem].bitfield.class != RegCR)
-           abort ();
-         i.rex &= ~REX_R;
-         add_prefix (LOCK_PREFIX_OPCODE);
-       }
+  if (v < MAX_OPERANDS)
+    {
+      gas_assert (i.tm.opcode_modifier.vexvvvv);
+      i.vex.register_specifier = i.op[v].regs;
     }
-  else
-    {                  /* If it's not 2 reg operands...  */
-      unsigned int mem;
 
+  if (op < i.operands)
+    {
       if (i.mem_operands)
        {
          unsigned int fake_zero_displacement = 0;
-         unsigned int op;
 
-         for (op = 0; op < i.operands; op++)
-           if (i.flags[op] & Operand_Mem)
-             break;
-         gas_assert (op < i.operands);
+         gas_assert (i.flags[op] & Operand_Mem);
 
          if (i.tm.opcode_modifier.sib)
            {
@@ -8650,174 +8965,62 @@ build_modrm_byte (void)
              exp->X_add_symbol = (symbolS *) 0;
              exp->X_op_symbol = (symbolS *) 0;
            }
-
-         mem = op;
        }
-      else
-       mem = ~0;
-
-      if (i.tm.opcode_modifier.vexsources == XOP2SOURCES)
+    else
        {
-         if (operand_type_check (i.types[0], imm))
-           i.vex.register_specifier = NULL;
-         else
-           {
-             /* VEX.vvvv encodes one of the sources when the first
-                operand is not an immediate.  */
-             if (i.tm.opcode_modifier.vexw == VEXW0)
-               i.vex.register_specifier = i.op[0].regs;
-             else
-               i.vex.register_specifier = i.op[1].regs;
-           }
-
-         /* Destination is a XMM register encoded in the ModRM.reg
-            and VEX.R bit.  */
-         i.rm.reg = i.op[2].regs->reg_num;
-         if ((i.op[2].regs->reg_flags & RegRex) != 0)
-           i.rex |= REX_R;
-
-         /* ModRM.rm and VEX.B encodes the other source.  */
-         if (!i.mem_operands)
-           {
-             i.rm.mode = 3;
-
-             if (i.tm.opcode_modifier.vexw == VEXW0)
-               i.rm.regmem = i.op[1].regs->reg_num;
-             else
-               i.rm.regmem = i.op[0].regs->reg_num;
-
-             if ((i.op[1].regs->reg_flags & RegRex) != 0)
-               i.rex |= REX_B;
-           }
+      i.rm.mode = 3;
+      i.rm.regmem = i.op[op].regs->reg_num;
+      set_rex_vrex (i.op[op].regs, REX_B, false);
        }
-      else if (i.tm.opcode_modifier.vexvvvv == VEXLWP)
+
+      if (op == dest)
+       dest = ~0;
+      if (op == source)
+       source = ~0;
+    }
+  else
+    {
+      i.rm.mode = 3;
+      if (!i.tm.opcode_modifier.regmem)
        {
-         i.vex.register_specifier = i.op[2].regs;
-         if (!i.mem_operands)
-           {
-             i.rm.mode = 3;
-             i.rm.regmem = i.op[1].regs->reg_num;
-             if ((i.op[1].regs->reg_flags & RegRex) != 0)
-               i.rex |= REX_B;
-           }
+         gas_assert (source < MAX_OPERANDS);
+         i.rm.regmem = i.op[source].regs->reg_num;
+         set_rex_vrex (i.op[source].regs, REX_B,
+                       dest >= MAX_OPERANDS && i.tm.opcode_modifier.sse2avx);
+         source = ~0;
        }
-      /* Fill in i.rm.reg or i.rm.regmem field with register operand
-        (if any) based on i.tm.extension_opcode.  Again, we must be
-        careful to make sure that segment/control/debug/test/MMX
-        registers are coded into the i.rm.reg field.  */
-      else if (i.reg_operands)
+      else
        {
-         unsigned int op;
-         unsigned int vex_reg = ~0;
-
-         for (op = 0; op < i.operands; op++)
-           if (i.types[op].bitfield.class == Reg
-               || i.types[op].bitfield.class == RegBND
-               || i.types[op].bitfield.class == RegMask
-               || i.types[op].bitfield.class == SReg
-               || i.types[op].bitfield.class == RegCR
-               || i.types[op].bitfield.class == RegDR
-               || i.types[op].bitfield.class == RegTR
-               || i.types[op].bitfield.class == RegSIMD
-               || i.types[op].bitfield.class == RegMMX)
-             break;
-
-         if (vex_3_sources)
-           op = dest;
-         else if (i.tm.opcode_modifier.vexvvvv == VEXXDS)
-           {
-             /* For instructions with VexNDS, the register-only
-                source operand is encoded in VEX prefix. */
-             gas_assert (mem != (unsigned int) ~0);
-
-             if (op > mem || i.tm.cpu_flags.bitfield.cpucmpccxadd)
-               {
-                 vex_reg = op++;
-                 gas_assert (op < i.operands);
-               }
-             else
-               {
-                 /* Check register-only source operand when two source
-                    operands are swapped.  */
-                 if (!i.tm.operand_types[op].bitfield.baseindex
-                     && i.tm.operand_types[op + 1].bitfield.baseindex)
-                   {
-                     vex_reg = op;
-                     op += 2;
-                     gas_assert (mem == (vex_reg + 1)
-                                 && op < i.operands);
-                   }
-                 else
-                   {
-                     vex_reg = op + 1;
-                     gas_assert (vex_reg < i.operands);
-                   }
-               }
-           }
-         else if (i.tm.opcode_modifier.vexvvvv == VEXNDD)
-           {
-             /* For instructions with VexNDD, the register destination
-                is encoded in VEX prefix.  */
-             if (i.mem_operands == 0)
-               {
-                 /* There is no memory operand.  */
-                 gas_assert ((op + 2) == i.operands);
-                 vex_reg = op + 1;
-               }
-             else
-               {
-                 /* There are only 2 non-immediate operands.  */
-                 gas_assert (op < i.imm_operands + 2
-                             && i.operands == i.imm_operands + 2);
-                 vex_reg = i.imm_operands + 1;
-               }
-           }
-         else
-           gas_assert (op < i.operands);
-
-         if (vex_reg != (unsigned int) ~0)
-           {
-             i386_operand_type *type = &i.tm.operand_types[vex_reg];
-
-             if ((type->bitfield.class != Reg
-                  || (!type->bitfield.dword && !type->bitfield.qword))
-                 && type->bitfield.class != RegSIMD
-                 && type->bitfield.class != RegMask)
-               abort ();
-
-             i.vex.register_specifier = i.op[vex_reg].regs;
-           }
-
-         /* Don't set OP operand twice.  */
-         if (vex_reg != op)
-           {
-             /* If there is an extension opcode to put here, the
-                register number must be put into the regmem field.  */
-             if (i.tm.extension_opcode != None)
-               {
-                 i.rm.regmem = i.op[op].regs->reg_num;
-                 set_rex_vrex (i.op[op].regs, REX_B,
-                               i.tm.opcode_modifier.sse2avx);
-               }
-             else
-               {
-                 i.rm.reg = i.op[op].regs->reg_num;
-                 set_rex_vrex (i.op[op].regs, REX_R,
-                               i.tm.opcode_modifier.sse2avx);
-               }
-           }
-
-         /* Now, if no memory operand has set i.rm.mode = 0, 1, 2 we
-            must set it to 3 to indicate this is a register operand
-            in the regmem field.  */
-         if (!i.mem_operands)
-           i.rm.mode = 3;
+         gas_assert (dest < MAX_OPERANDS);
+         i.rm.regmem = i.op[dest].regs->reg_num;
+         set_rex_vrex (i.op[dest].regs, REX_B, i.tm.opcode_modifier.sse2avx);
+         dest = ~0;
        }
+    }
+
+  /* Fill in i.rm.reg field with extension opcode (if any) or the
+     appropriate register.  */
+  if (i.tm.extension_opcode != None)
+    i.rm.reg = i.tm.extension_opcode;
+  else if (!i.tm.opcode_modifier.regmem && dest < MAX_OPERANDS)
+    {
+      i.rm.reg = i.op[dest].regs->reg_num;
+      set_rex_vrex (i.op[dest].regs, REX_R, i.tm.opcode_modifier.sse2avx);
+    }
+  else
+    {
+      gas_assert (source < MAX_OPERANDS);
+      i.rm.reg = i.op[source].regs->reg_num;
+      set_rex_vrex (i.op[source].regs, REX_R, false);
+    }
 
-      /* Fill in i.rm.reg field with extension opcode (if any).  */
-      if (i.tm.extension_opcode != None)
-       i.rm.reg = i.tm.extension_opcode;
+  if (flag_code != CODE_64BIT && (i.rex & REX_R))
+    {
+      gas_assert (i.types[!i.tm.opcode_modifier.regmem].bitfield.class == RegCR);
+      i.rex &= ~REX_R;
+      add_prefix (LOCK_PREFIX_OPCODE);
     }
+
   return default_seg;
 }
 
@@ -8929,8 +9132,6 @@ output_branch (void)
       off = 0;
     }
 
-  frag_now->tc_frag_data.code64 = flag_code == CODE_64BIT;
-
   /* 1 possible extra opcode + 4 byte displacement go in var part.
      Pass reloc in fr_var.  */
   frag_var (rs_machine_dependent, 5, i.reloc[0], subtype, sym, off, p);
@@ -9081,7 +9282,7 @@ output_jump (void)
       break;
 
     case 2:
-      if (i.tm.base_opcode == 0xc7f8)
+      if (i.tm.mnem_off == MN_xbegin)
        fixP->fx_signed = 1;
       break;
 
@@ -9363,7 +9564,7 @@ maybe_fused_with_jcc_p (enum mf_cmp_kind* mf_cmp_p)
     return 0;
 
   /* No opcodes outside of base encoding space.  */
-  if (i.tm.opcode_modifier.opcodespace != SPACE_BASE)
+  if (i.tm.opcode_space != SPACE_BASE)
     return 0;
 
   /* add, sub without add/sub m, imm.  */
@@ -9406,7 +9607,7 @@ maybe_fused_with_jcc_p (enum mf_cmp_kind* mf_cmp_p)
     }
 
   /* inc, dec without inc/dec m.   */
-  if ((i.tm.cpu_flags.bitfield.cpuno64
+  if ((is_cpu (&i.tm, CpuNo64)
        && (i.tm.base_opcode | 0xf) == 0x4f)
       || ((i.tm.base_opcode | 1) == 0xff
          && i.tm.extension_opcode <= 0x1))
@@ -9454,7 +9655,7 @@ add_branch_prefix_frag_p (void)
   if (!align_branch_power
       || !align_branch_prefix_size
       || now_seg == absolute_section
-      || i.tm.cpu_flags.bitfield.cpupadlock
+      || is_cpu (&i.tm, CpuPadLock)
       || !cpu_arch_flags.bitfield.cpui386)
     return 0;
 
@@ -9487,7 +9688,7 @@ add_branch_padding_frag_p (enum align_branch_kind *branch_p,
   if (!align_branch_power
       || now_seg == absolute_section
       || !cpu_arch_flags.bitfield.cpui386
-      || i.tm.opcode_modifier.opcodespace != SPACE_BASE)
+      || i.tm.opcode_space != SPACE_BASE)
     return 0;
 
   add_padding = 0;
@@ -9582,21 +9783,19 @@ output_insn (void)
   if (IS_ELF && x86_used_note && now_seg != absolute_section)
     {
       if ((i.xstate & xstate_tmm) == xstate_tmm
-         || i.tm.cpu_flags.bitfield.cpuamx_tile)
+         || is_cpu (&i.tm, CpuAMX_TILE))
        x86_feature_2_used |= GNU_PROPERTY_X86_FEATURE_2_TMM;
 
-      if (i.tm.cpu_flags.bitfield.cpu8087
-         || i.tm.cpu_flags.bitfield.cpu287
-         || i.tm.cpu_flags.bitfield.cpu387
-         || i.tm.cpu_flags.bitfield.cpu687
-         || i.tm.cpu_flags.bitfield.cpufisttp)
+      if (is_cpu (&i.tm, Cpu8087)
+         || is_cpu (&i.tm, Cpu287)
+         || is_cpu (&i.tm, Cpu387)
+         || is_cpu (&i.tm, Cpu687)
+         || is_cpu (&i.tm, CpuFISTTP))
        x86_feature_2_used |= GNU_PROPERTY_X86_FEATURE_2_X87;
 
       if ((i.xstate & xstate_mmx)
-         || (i.tm.opcode_modifier.opcodespace == SPACE_0F
-             && !is_any_vex_encoding (&i.tm)
-             && (i.tm.base_opcode == 0x77 /* emms */
-                 || i.tm.base_opcode == 0x0e /* femms */)))
+         || i.tm.mnem_off == MN_emms
+         || i.tm.mnem_off == MN_femms)
        x86_feature_2_used |= GNU_PROPERTY_X86_FEATURE_2_MMX;
 
       if (i.index_reg)
@@ -9610,16 +9809,16 @@ output_insn (void)
        }
 
       /* vzeroall / vzeroupper */
-      if (i.tm.base_opcode == 0x77 && i.tm.cpu_flags.bitfield.cpuavx)
+      if (i.tm.base_opcode == 0x77 && is_cpu (&i.tm, CpuAVX))
        i.xstate |= xstate_ymm;
 
       if ((i.xstate & xstate_xmm)
          /* ldmxcsr / stmxcsr / vldmxcsr / vstmxcsr */
          || (i.tm.base_opcode == 0xae
-             && (i.tm.cpu_flags.bitfield.cpusse
-                 || i.tm.cpu_flags.bitfield.cpuavx))
-         || i.tm.cpu_flags.bitfield.cpuwidekl
-         || i.tm.cpu_flags.bitfield.cpukl)
+             && (is_cpu (&i.tm, CpuSSE)
+                 || is_cpu (&i.tm, CpuAVX)))
+         || is_cpu (&i.tm, CpuWideKL)
+         || is_cpu (&i.tm, CpuKL))
        x86_feature_2_used |= GNU_PROPERTY_X86_FEATURE_2_XMM;
 
       if ((i.xstate & xstate_ymm) == xstate_ymm)
@@ -9628,68 +9827,65 @@ output_insn (void)
        x86_feature_2_used |= GNU_PROPERTY_X86_FEATURE_2_ZMM;
       if (i.mask.reg || (i.xstate & xstate_mask) == xstate_mask)
        x86_feature_2_used |= GNU_PROPERTY_X86_FEATURE_2_MASK;
-      if (i.tm.cpu_flags.bitfield.cpufxsr)
+      if (is_cpu (&i.tm, CpuFXSR))
        x86_feature_2_used |= GNU_PROPERTY_X86_FEATURE_2_FXSR;
-      if (i.tm.cpu_flags.bitfield.cpuxsave)
+      if (is_cpu (&i.tm, CpuXsave))
        x86_feature_2_used |= GNU_PROPERTY_X86_FEATURE_2_XSAVE;
-      if (i.tm.cpu_flags.bitfield.cpuxsaveopt)
+      if (is_cpu (&i.tm, CpuXsaveopt))
        x86_feature_2_used |= GNU_PROPERTY_X86_FEATURE_2_XSAVEOPT;
-      if (i.tm.cpu_flags.bitfield.cpuxsavec)
+      if (is_cpu (&i.tm, CpuXSAVEC))
        x86_feature_2_used |= GNU_PROPERTY_X86_FEATURE_2_XSAVEC;
 
       if (x86_feature_2_used
-         || i.tm.cpu_flags.bitfield.cpucmov
-         || i.tm.cpu_flags.bitfield.cpusyscall
-         || (i.tm.opcode_modifier.opcodespace == SPACE_0F
-             && i.tm.base_opcode == 0xc7
-             && i.tm.opcode_modifier.opcodeprefix == PREFIX_NONE
-             && i.tm.extension_opcode == 1) /* cmpxchg8b */)
+         || is_cpu (&i.tm, CpuCMOV)
+         || is_cpu (&i.tm, CpuSYSCALL)
+         || i.tm.mnem_off == MN_cmpxchg8b)
        x86_isa_1_used |= GNU_PROPERTY_X86_ISA_1_BASELINE;
-      if (i.tm.cpu_flags.bitfield.cpusse3
-         || i.tm.cpu_flags.bitfield.cpussse3
-         || i.tm.cpu_flags.bitfield.cpusse4_1
-         || i.tm.cpu_flags.bitfield.cpusse4_2
-         || i.tm.cpu_flags.bitfield.cpucx16
-         || i.tm.cpu_flags.bitfield.cpupopcnt
+      if (is_cpu (&i.tm, CpuSSE3)
+         || is_cpu (&i.tm, CpuSSSE3)
+         || is_cpu (&i.tm, CpuSSE4_1)
+         || is_cpu (&i.tm, CpuSSE4_2)
+         || is_cpu (&i.tm, CpuCX16)
+         || is_cpu (&i.tm, CpuPOPCNT)
          /* LAHF-SAHF insns in 64-bit mode.  */
          || (flag_code == CODE_64BIT
              && (i.tm.base_opcode | 1) == 0x9f
-             && i.tm.opcode_modifier.opcodespace == SPACE_BASE))
+             && i.tm.opcode_space == SPACE_BASE))
        x86_isa_1_used |= GNU_PROPERTY_X86_ISA_1_V2;
-      if (i.tm.cpu_flags.bitfield.cpuavx
-         || i.tm.cpu_flags.bitfield.cpuavx2
+      if (is_cpu (&i.tm, CpuAVX)
+         || is_cpu (&i.tm, CpuAVX2)
          /* Any VEX encoded insns execpt for AVX512F, AVX512BW, AVX512DQ,
             XOP, FMA4, LPW, TBM, and AMX.  */
          || (i.tm.opcode_modifier.vex
-             && !i.tm.cpu_flags.bitfield.cpuavx512f
-             && !i.tm.cpu_flags.bitfield.cpuavx512bw
-             && !i.tm.cpu_flags.bitfield.cpuavx512dq
-             && !i.tm.cpu_flags.bitfield.cpuxop
-             && !i.tm.cpu_flags.bitfield.cpufma4
-             && !i.tm.cpu_flags.bitfield.cpulwp
-             && !i.tm.cpu_flags.bitfield.cputbm
+             && !is_cpu (&i.tm, CpuAVX512F)
+             && !is_cpu (&i.tm, CpuAVX512BW)
+             && !is_cpu (&i.tm, CpuAVX512DQ)
+             && !is_cpu (&i.tm, CpuXOP)
+             && !is_cpu (&i.tm, CpuFMA4)
+             && !is_cpu (&i.tm, CpuLWP)
+             && !is_cpu (&i.tm, CpuTBM)
              && !(x86_feature_2_used & GNU_PROPERTY_X86_FEATURE_2_TMM))
-         || i.tm.cpu_flags.bitfield.cpuf16c
-         || i.tm.cpu_flags.bitfield.cpufma
-         || i.tm.cpu_flags.bitfield.cpulzcnt
-         || i.tm.cpu_flags.bitfield.cpumovbe
-         || i.tm.cpu_flags.bitfield.cpuxsaves
+         || is_cpu (&i.tm, CpuF16C)
+         || is_cpu (&i.tm, CpuFMA)
+         || is_cpu (&i.tm, CpuLZCNT)
+         || is_cpu (&i.tm, CpuMovbe)
+         || is_cpu (&i.tm, CpuXSAVES)
          || (x86_feature_2_used
              & (GNU_PROPERTY_X86_FEATURE_2_XSAVE
                 | GNU_PROPERTY_X86_FEATURE_2_XSAVEOPT
                 | GNU_PROPERTY_X86_FEATURE_2_XSAVEC)) != 0)
        x86_isa_1_used |= GNU_PROPERTY_X86_ISA_1_V3;
-      if (i.tm.cpu_flags.bitfield.cpuavx512f
-         || i.tm.cpu_flags.bitfield.cpuavx512bw
-         || i.tm.cpu_flags.bitfield.cpuavx512dq
-         || i.tm.cpu_flags.bitfield.cpuavx512vl
+      if (is_cpu (&i.tm, CpuAVX512F)
+         || is_cpu (&i.tm, CpuAVX512BW)
+         || is_cpu (&i.tm, CpuAVX512DQ)
+         || is_cpu (&i.tm, CpuAVX512VL)
          /* Any EVEX encoded insns except for AVX512ER, AVX512PF,
             AVX512-4FMAPS, and AVX512-4VNNIW.  */
          || (i.tm.opcode_modifier.evex
-             && !i.tm.cpu_flags.bitfield.cpuavx512er
-             && !i.tm.cpu_flags.bitfield.cpuavx512pf
-             && !i.tm.cpu_flags.bitfield.cpuavx512_4fmaps
-             && !i.tm.cpu_flags.bitfield.cpuavx512_4vnniw))
+             && !is_cpu (&i.tm, CpuAVX512ER)
+             && !is_cpu (&i.tm, CpuAVX512PF)
+             && !is_cpu (&i.tm, CpuAVX512_4FMAPS)
+             && !is_cpu (&i.tm, CpuAVX512_4VNNIW)))
        x86_isa_1_used |= GNU_PROPERTY_X86_ISA_1_V4;
     }
 #endif
@@ -9834,7 +10030,7 @@ output_insn (void)
              add_prefix (0xf2);
              break;
            case PREFIX_0XF3:
-             if (!i.tm.cpu_flags.bitfield.cpupadlock
+             if (!is_cpu (&i.tm, CpuPadLock)
                  || (i.prefix[REP_PREFIX] != 0xf3))
                add_prefix (0xf3);
              break;
@@ -9913,7 +10109,7 @@ output_insn (void)
       /* Now the opcode; be careful about word order here!  */
       j = i.opcode_length;
       if (!i.vex.length)
-       switch (i.tm.opcode_modifier.opcodespace)
+       switch (i.tm.opcode_space)
          {
          case SPACE_BASE:
            break;
@@ -9938,11 +10134,11 @@ output_insn (void)
        {
          p = frag_more (j);
          if (!i.vex.length
-             && i.tm.opcode_modifier.opcodespace != SPACE_BASE)
+             && i.tm.opcode_space != SPACE_BASE)
            {
              *p++ = 0x0f;
-             if (i.tm.opcode_modifier.opcodespace != SPACE_0F)
-               *p++ = i.tm.opcode_modifier.opcodespace == SPACE_0F38
+             if (i.tm.opcode_space != SPACE_0F)
+               *p++ = i.tm.opcode_space == SPACE_0F38
                       ? 0x38 : 0x3a;
            }
 
@@ -10014,7 +10210,7 @@ output_insn (void)
 
              /* Count prefixes for extended opcode maps.  */
              if (!i.vex.length)
-               switch (i.tm.opcode_modifier.opcodespace)
+               switch (i.tm.opcode_space)
                  {
                  case SPACE_BASE:
                    break;
@@ -10172,13 +10368,13 @@ output_disp (fragS *insn_start_frag, offsetT insn_start_off)
                    if (operand_type_check (i.types[n1], imm))
                      {
                        /* Only one immediate is allowed for PC
-                          relative address.  */
-                       gas_assert (sz == 0);
-                       sz = imm_size (n1);
-                       i.op[n].disps->X_add_number -= sz;
+                          relative address, except with .insn.  */
+                       gas_assert (sz == 0 || dot_insn ());
+                       sz += imm_size (n1);
                      }
-                 /* We should find the immediate.  */
+                 /* We should find at least one immediate.  */
                  gas_assert (sz != 0);
+                 i.op[n].disps->X_add_number -= sz;
                }
 
              p = frag_more (size);
@@ -10252,7 +10448,7 @@ output_disp (fragS *insn_start_frag, offsetT insn_start_off)
                          && i.rm.regmem == 5))
                  && (i.rm.mode == 2
                      || (i.rm.mode == 0 && i.rm.regmem == 5))
-                 && i.tm.opcode_modifier.opcodespace == SPACE_BASE
+                 && i.tm.opcode_space == SPACE_BASE
                  && ((i.operands == 1
                       && i.tm.base_opcode == 0xff
                       && (i.rm.reg == 2 || i.rm.reg == 4))
@@ -10310,7 +10506,9 @@ output_imm (fragS *insn_start_frag, offsetT insn_start_off)
 
              if (i.types[n].bitfield.imm32s
                  && (i.suffix == QWORD_MNEM_SUFFIX
-                     || (!i.suffix && i.tm.opcode_modifier.no_lsuf)))
+                     || (!i.suffix && i.tm.opcode_modifier.no_lsuf)
+                     || (i.prefix[REX_PREFIX] & REX_W)
+                     || dot_insn ()))
                sign = 1;
              else
                sign = 0;
@@ -10542,158 +10740,932 @@ lex_got (enum bfd_reloc_code_real *rel,
     return NULL;
 #endif
 
-  for (cp = input_line_pointer; *cp != '@'; cp++)
-    if (is_end_of_line[(unsigned char) *cp] || *cp == ',')
-      return NULL;
+  for (cp = input_line_pointer; *cp != '@'; cp++)
+    if (is_end_of_line[(unsigned char) *cp] || *cp == ',')
+      return NULL;
+
+  for (j = 0; j < ARRAY_SIZE (gotrel); j++)
+    {
+      int len = gotrel[j].len;
+      if (strncasecmp (cp + 1, gotrel[j].str, len) == 0)
+       {
+         if (gotrel[j].rel[object_64bit] != 0)
+           {
+             int first, second;
+             char *tmpbuf, *past_reloc;
+
+             *rel = gotrel[j].rel[object_64bit];
+
+             if (types)
+               {
+                 if (flag_code != CODE_64BIT)
+                   {
+                     types->bitfield.imm32 = 1;
+                     types->bitfield.disp32 = 1;
+                   }
+                 else
+                   *types = gotrel[j].types64;
+               }
+
+             if (gotrel[j].need_GOT_symbol && GOT_symbol == NULL)
+               GOT_symbol = symbol_find_or_make (GLOBAL_OFFSET_TABLE_NAME);
+
+             /* The length of the first part of our input line.  */
+             first = cp - input_line_pointer;
+
+             /* The second part goes from after the reloc token until
+                (and including) an end_of_line char or comma.  */
+             past_reloc = cp + 1 + len;
+             cp = past_reloc;
+             while (!is_end_of_line[(unsigned char) *cp] && *cp != ',')
+               ++cp;
+             second = cp + 1 - past_reloc;
+
+             /* Allocate and copy string.  The trailing NUL shouldn't
+                be necessary, but be safe.  */
+             tmpbuf = XNEWVEC (char, first + second + 2);
+             memcpy (tmpbuf, input_line_pointer, first);
+             if (second != 0 && *past_reloc != ' ')
+               /* Replace the relocation token with ' ', so that
+                  errors like foo@GOTOFF1 will be detected.  */
+               tmpbuf[first++] = ' ';
+             else
+               /* Increment length by 1 if the relocation token is
+                  removed.  */
+               len++;
+             if (adjust)
+               *adjust = len;
+             memcpy (tmpbuf + first, past_reloc, second);
+             tmpbuf[first + second] = '\0';
+             return tmpbuf;
+           }
+
+         as_bad (_("@%s reloc is not supported with %d-bit output format"),
+                 gotrel[j].str, 1 << (5 + object_64bit));
+         return NULL;
+       }
+    }
+
+  /* Might be a symbol version string.  Don't as_bad here.  */
+  return NULL;
+}
+#endif
+
+bfd_reloc_code_real_type
+x86_cons (expressionS *exp, int size)
+{
+  bfd_reloc_code_real_type got_reloc = NO_RELOC;
+
+  intel_syntax = -intel_syntax;
+  exp->X_md = 0;
+  expr_mode = expr_operator_none;
+
+#if ((defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)) \
+      && !defined (LEX_AT)) \
+    || defined (TE_PE)
+  if (size == 4 || (object_64bit && size == 8))
+    {
+      /* Handle @GOTOFF and the like in an expression.  */
+      char *save;
+      char *gotfree_input_line;
+      int adjust = 0;
+
+      save = input_line_pointer;
+      gotfree_input_line = lex_got (&got_reloc, &adjust, NULL);
+      if (gotfree_input_line)
+       input_line_pointer = gotfree_input_line;
+
+      expression (exp);
+
+      if (gotfree_input_line)
+       {
+         /* expression () has merrily parsed up to the end of line,
+            or a comma - in the wrong buffer.  Transfer how far
+            input_line_pointer has moved to the right buffer.  */
+         input_line_pointer = (save
+                               + (input_line_pointer - gotfree_input_line)
+                               + adjust);
+         free (gotfree_input_line);
+         if (exp->X_op == O_constant
+             || exp->X_op == O_absent
+             || exp->X_op == O_illegal
+             || exp->X_op == O_register
+             || exp->X_op == O_big)
+           {
+             char c = *input_line_pointer;
+             *input_line_pointer = 0;
+             as_bad (_("missing or invalid expression `%s'"), save);
+             *input_line_pointer = c;
+           }
+         else if ((got_reloc == BFD_RELOC_386_PLT32
+                   || got_reloc == BFD_RELOC_X86_64_PLT32)
+                  && exp->X_op != O_symbol)
+           {
+             char c = *input_line_pointer;
+             *input_line_pointer = 0;
+             as_bad (_("invalid PLT expression `%s'"), save);
+             *input_line_pointer = c;
+           }
+       }
+    }
+  else
+#endif
+    expression (exp);
+
+  intel_syntax = -intel_syntax;
+
+  if (intel_syntax)
+    i386_intel_simplify (exp);
+
+  /* If not 64bit, massage value, to account for wraparound when !BFD64.  */
+  if (size <= 4 && expr_mode == expr_operator_present
+      && exp->X_op == O_constant && !object_64bit)
+    exp->X_add_number = extend_to_32bit_address (exp->X_add_number);
+
+  return got_reloc;
+}
+
+static void
+signed_cons (int size)
+{
+  if (object_64bit)
+    cons_sign = 1;
+  cons (size);
+  cons_sign = -1;
+}
+
+static void
+s_insn (int dummy ATTRIBUTE_UNUSED)
+{
+  char mnemonic[MAX_MNEM_SIZE], *line = input_line_pointer, *ptr;
+  char *saved_ilp = find_end_of_line (line, false), saved_char;
+  const char *end;
+  unsigned int j;
+  valueT val;
+  bool vex = false, xop = false, evex = false;
+  static const templates tt = { &i.tm, &i.tm + 1 };
+
+  init_globals ();
+
+  saved_char = *saved_ilp;
+  *saved_ilp = 0;
+
+  end = parse_insn (line, mnemonic, true);
+  if (end == NULL)
+    {
+  bad:
+      *saved_ilp = saved_char;
+      ignore_rest_of_line ();
+      i.tm.mnem_off = 0;
+      return;
+    }
+  line += end - line;
+
+  current_templates = &tt;
+  i.tm.mnem_off = MN__insn;
+  i.tm.extension_opcode = None;
+
+  if (startswith (line, "VEX")
+      && (line[3] == '.' || is_space_char (line[3])))
+    {
+      vex = true;
+      line += 3;
+    }
+  else if (startswith (line, "XOP") && ISDIGIT (line[3]))
+    {
+      char *e;
+      unsigned long n = strtoul (line + 3, &e, 16);
+
+      if (e == line + 5 && n >= 0x08 && n <= 0x1f
+         && (*e == '.' || is_space_char (*e)))
+       {
+         xop = true;
+         /* Arrange for build_vex_prefix() to emit 0x8f.  */
+         i.tm.opcode_space = SPACE_XOP08;
+         i.insn_opcode_space = n;
+         line = e;
+       }
+    }
+  else if (startswith (line, "EVEX")
+          && (line[4] == '.' || is_space_char (line[4])))
+    {
+      evex = true;
+      line += 4;
+    }
+
+  if (vex || xop
+      ? i.vec_encoding == vex_encoding_evex
+      : evex
+       ? i.vec_encoding == vex_encoding_vex
+         || i.vec_encoding == vex_encoding_vex3
+       : i.vec_encoding != vex_encoding_default)
+    {
+      as_bad (_("pseudo-prefix conflicts with encoding specifier"));
+      goto bad;
+    }
+
+  if (line > end && i.vec_encoding == vex_encoding_default)
+    i.vec_encoding = evex ? vex_encoding_evex : vex_encoding_vex;
+
+  if (i.vec_encoding != vex_encoding_default)
+    {
+      /* Only address size and segment override prefixes are permitted with
+         VEX/XOP/EVEX encodings.  */
+      const unsigned char *p = i.prefix;
+
+      for (j = 0; j < ARRAY_SIZE (i.prefix); ++j, ++p)
+       {
+         if (!*p)
+           continue;
+
+         switch (j)
+           {
+           case SEG_PREFIX:
+           case ADDR_PREFIX:
+             break;
+           default:
+                 as_bad (_("illegal prefix used with VEX/XOP/EVEX"));
+                 goto bad;
+           }
+       }
+    }
+
+  if (line > end && *line == '.')
+    {
+      /* Length specifier (VEX.L, XOP.L, EVEX.L'L).  */
+      switch (line[1])
+       {
+       case 'L':
+         switch (line[2])
+           {
+           case '0':
+             if (evex)
+               i.tm.opcode_modifier.evex = EVEX128;
+             else
+               i.tm.opcode_modifier.vex = VEX128;
+             break;
+
+           case '1':
+             if (evex)
+               i.tm.opcode_modifier.evex = EVEX256;
+             else
+               i.tm.opcode_modifier.vex = VEX256;
+             break;
+
+           case '2':
+             if (evex)
+               i.tm.opcode_modifier.evex = EVEX512;
+             break;
+
+           case '3':
+             if (evex)
+               i.tm.opcode_modifier.evex = EVEX_L3;
+             break;
+
+           case 'I':
+             if (line[3] == 'G')
+               {
+                 if (evex)
+                   i.tm.opcode_modifier.evex = EVEXLIG;
+                 else
+                   i.tm.opcode_modifier.vex = VEXScalar; /* LIG */
+                 ++line;
+               }
+             break;
+           }
+
+         if (i.tm.opcode_modifier.vex || i.tm.opcode_modifier.evex)
+           line += 3;
+         break;
+
+       case '1':
+         if (line[2] == '2' && line[3] == '8')
+           {
+             if (evex)
+               i.tm.opcode_modifier.evex = EVEX128;
+             else
+               i.tm.opcode_modifier.vex = VEX128;
+             line += 4;
+           }
+         break;
+
+       case '2':
+         if (line[2] == '5' && line[3] == '6')
+           {
+             if (evex)
+               i.tm.opcode_modifier.evex = EVEX256;
+             else
+               i.tm.opcode_modifier.vex = VEX256;
+             line += 4;
+           }
+         break;
+
+       case '5':
+         if (evex && line[2] == '1' && line[3] == '2')
+           {
+             i.tm.opcode_modifier.evex = EVEX512;
+             line += 4;
+           }
+         break;
+       }
+    }
+
+  if (line > end && *line == '.')
+    {
+      /* embedded prefix (VEX.pp, XOP.pp, EVEX.pp).  */
+      switch (line[1])
+       {
+       case 'N':
+         if (line[2] == 'P')
+           line += 3;
+         break;
+
+       case '6':
+         if (line[2] == '6')
+           {
+             i.tm.opcode_modifier.opcodeprefix = PREFIX_0X66;
+             line += 3;
+           }
+         break;
+
+       case 'F': case 'f':
+         if (line[2] == '3')
+           {
+             i.tm.opcode_modifier.opcodeprefix = PREFIX_0XF3;
+             line += 3;
+           }
+         else if (line[2] == '2')
+           {
+             i.tm.opcode_modifier.opcodeprefix = PREFIX_0XF2;
+             line += 3;
+           }
+         break;
+       }
+    }
+
+  if (line > end && !xop && *line == '.')
+    {
+      /* Encoding space (VEX.mmmmm, EVEX.mmmm).  */
+      switch (line[1])
+       {
+       case '0':
+         if (TOUPPER (line[2]) != 'F')
+           break;
+         if (line[3] == '.' || is_space_char (line[3]))
+           {
+             i.insn_opcode_space = SPACE_0F;
+             line += 3;
+           }
+         else if (line[3] == '3'
+                  && (line[4] == '8' || TOUPPER (line[4]) == 'A')
+                  && (line[5] == '.' || is_space_char (line[5])))
+           {
+             i.insn_opcode_space = line[4] == '8' ? SPACE_0F38 : SPACE_0F3A;
+             line += 5;
+           }
+         break;
+
+       case 'M':
+         if (ISDIGIT (line[2]) && line[2] != '0')
+           {
+             char *e;
+             unsigned long n = strtoul (line + 2, &e, 10);
+
+             if (n <= (evex ? 15 : 31)
+                 && (*e == '.' || is_space_char (*e)))
+               {
+                 i.insn_opcode_space = n;
+                 line = e;
+               }
+           }
+         break;
+       }
+    }
+
+  if (line > end && *line == '.' && line[1] == 'W')
+    {
+      /* VEX.W, XOP.W, EVEX.W  */
+      switch (line[2])
+       {
+       case '0':
+         i.tm.opcode_modifier.vexw = VEXW0;
+         break;
+
+       case '1':
+         i.tm.opcode_modifier.vexw = VEXW1;
+         break;
+
+       case 'I':
+         if (line[3] == 'G')
+           {
+             i.tm.opcode_modifier.vexw = VEXWIG;
+             ++line;
+           }
+         break;
+       }
+
+      if (i.tm.opcode_modifier.vexw)
+       line += 3;
+    }
+
+  if (line > end && *line && !is_space_char (*line))
+    {
+      /* Improve diagnostic a little.  */
+      if (*line == '.' && line[1] && !is_space_char (line[1]))
+       ++line;
+      goto done;
+    }
+
+  /* Before processing the opcode expression, find trailing "+r" or
+     "/<digit>" specifiers.  */
+  for (ptr = line; ; ++ptr)
+    {
+      unsigned long n;
+      char *e;
+
+      ptr = strpbrk (ptr, "+/,");
+      if (ptr == NULL || *ptr == ',')
+       break;
+
+      if (*ptr == '+' && ptr[1] == 'r'
+         && (ptr[2] == ',' || (is_space_char (ptr[2]) && ptr[3] == ',')))
+       {
+         *ptr = ' ';
+         ptr[1] = ' ';
+         i.short_form = true;
+         break;
+       }
+
+      if (*ptr == '/' && ISDIGIT (ptr[1])
+         && (n = strtoul (ptr + 1, &e, 8)) < 8
+         && e == ptr + 2
+         && (ptr[2] == ',' || (is_space_char (ptr[2]) && ptr[3] == ',')))
+       {
+         *ptr = ' ';
+         ptr[1] = ' ';
+         i.tm.extension_opcode = n;
+         i.tm.opcode_modifier.modrm = 1;
+         break;
+       }
+    }
+
+  input_line_pointer = line;
+  val = get_absolute_expression ();
+  line = input_line_pointer;
+
+  if (i.short_form && (val & 7))
+    as_warn ("`+r' assumes low three opcode bits to be clear");
+
+  for (j = 1; j < sizeof(val); ++j)
+    if (!(val >> (j * 8)))
+      break;
+
+  /* Trim off a prefix if present.  */
+  if (j > 1 && !vex && !xop && !evex)
+    {
+      uint8_t byte = val >> ((j - 1) * 8);
+
+      switch (byte)
+       {
+       case DATA_PREFIX_OPCODE:
+       case REPE_PREFIX_OPCODE:
+       case REPNE_PREFIX_OPCODE:
+         if (!add_prefix (byte))
+           goto bad;
+         val &= ((uint64_t)1 << (--j * 8)) - 1;
+         break;
+       }
+    }
+
+  /* Trim off encoding space.  */
+  if (j > 1 && !i.insn_opcode_space && (val >> ((j - 1) * 8)) == 0x0f)
+    {
+      uint8_t byte = val >> ((--j - 1) * 8);
+
+      i.insn_opcode_space = SPACE_0F;
+      switch (byte & -(j > 1))
+       {
+       case 0x38:
+         i.insn_opcode_space = SPACE_0F38;
+         --j;
+         break;
+       case 0x3a:
+         i.insn_opcode_space = SPACE_0F3A;
+         --j;
+         break;
+       }
+      i.tm.opcode_space = i.insn_opcode_space;
+      val &= ((uint64_t)1 << (j * 8)) - 1;
+    }
+  if (!i.tm.opcode_space && (vex || evex))
+    /* Arrange for build_vex_prefix() to properly emit 0xC4/0xC5.
+       Also avoid hitting abort() there or in build_evex_prefix().  */
+    i.tm.opcode_space = i.insn_opcode_space == SPACE_0F ? SPACE_0F
+                                                  : SPACE_0F38;
+
+  if (j > 2)
+    {
+      as_bad (_("opcode residual (%#"PRIx64") too wide"), (uint64_t) val);
+      goto bad;
+    }
+  i.opcode_length = j;
+
+  /* Handle operands, if any.  */
+  if (*line == ',')
+    {
+      i386_operand_type combined;
+      expressionS *disp_exp = NULL;
+      bool changed;
+
+      i.memshift = -1;
+
+      ptr = parse_operands (line + 1, &i386_mnemonics[MN__insn]);
+      this_operand = -1;
+      if (!ptr)
+       goto bad;
+      line = ptr;
+
+      if (!i.operands)
+       {
+         as_bad (_("expecting operand after ','; got nothing"));
+         goto done;
+       }
+
+      if (i.mem_operands > 1)
+       {
+         as_bad (_("too many memory references for `%s'"),
+                 &i386_mnemonics[MN__insn]);
+         goto done;
+       }
+
+      /* No need to distinguish vex_encoding_evex and vex_encoding_evex512.  */
+      if (i.vec_encoding == vex_encoding_evex512)
+       i.vec_encoding = vex_encoding_evex;
+
+      /* Are we to emit ModR/M encoding?  */
+      if (!i.short_form
+         && (i.mem_operands
+             || i.reg_operands > (i.vec_encoding != vex_encoding_default)
+             || i.tm.extension_opcode != None))
+       i.tm.opcode_modifier.modrm = 1;
+
+      if (!i.tm.opcode_modifier.modrm
+         && (i.reg_operands
+             > i.short_form + 0U + (i.vec_encoding != vex_encoding_default)
+             || i.mem_operands))
+       {
+         as_bad (_("too many register/memory operands"));
+         goto done;
+       }
+
+      /* Enforce certain constraints on operands.  */
+      switch (i.reg_operands + i.mem_operands
+             + (i.tm.extension_opcode != None))
+       {
+       case 0:
+         if (i.short_form)
+           {
+             as_bad (_("too few register/memory operands"));
+             goto done;
+           }
+         /* Fall through.  */
+       case 1:
+         if (i.tm.opcode_modifier.modrm)
+           {
+             as_bad (_("too few register/memory operands"));
+             goto done;
+           }
+         break;
+
+       case 2:
+         break;
+
+       case 4:
+         if (i.imm_operands
+             && (i.op[0].imms->X_op != O_constant
+                 || !fits_in_imm4 (i.op[0].imms->X_add_number)))
+           {
+             as_bad (_("constant doesn't fit in %d bits"), evex ? 3 : 4);
+             goto done;
+           }
+         /* Fall through.  */
+       case 3:
+         if (i.vec_encoding != vex_encoding_default)
+           {
+             i.tm.opcode_modifier.vexvvvv = 1;
+             break;
+           }
+         /* Fall through.  */
+       default:
+         as_bad (_("too many register/memory operands"));
+         goto done;
+       }
+
+      /* Bring operands into canonical order (imm, mem, reg).  */
+      do
+       {
+         changed = false;
+
+         for (j = 1; j < i.operands; ++j)
+           {
+             if ((!operand_type_check (i.types[j - 1], imm)
+                  && operand_type_check (i.types[j], imm))
+                 || (i.types[j - 1].bitfield.class != ClassNone
+                     && i.types[j].bitfield.class == ClassNone))
+               {
+                 swap_2_operands (j - 1, j);
+                 changed = true;
+               }
+           }
+       }
+      while (changed);
+
+      /* For Intel syntax swap the order of register operands.  */
+      if (intel_syntax)
+       switch (i.reg_operands)
+         {
+         case 0:
+         case 1:
+           break;
+
+         case 4:
+           swap_2_operands (i.imm_operands + i.mem_operands + 1, i.operands - 2);
+           /* Fall through.  */
+         case 3:
+         case 2:
+           swap_2_operands (i.imm_operands + i.mem_operands, i.operands - 1);
+           break;
+
+         default:
+           abort ();
+         }
+
+      /* Enforce constraints when using VSIB.  */
+      if (i.index_reg
+         && (i.index_reg->reg_type.bitfield.xmmword
+             || i.index_reg->reg_type.bitfield.ymmword
+             || i.index_reg->reg_type.bitfield.zmmword))
+       {
+         if (i.vec_encoding == vex_encoding_default)
+           {
+             as_bad (_("VSIB unavailable with legacy encoding"));
+             goto done;
+           }
+
+         if (i.vec_encoding == vex_encoding_evex
+             && i.reg_operands > 1)
+           {
+             /* We could allow two register operands, encoding the 2nd one in
+                an 8-bit immediate like for 4-register-operand insns, but that
+                would require ugly fiddling with process_operands() and/or
+                build_modrm_byte().  */
+             as_bad (_("too many register operands with VSIB"));
+             goto done;
+           }
+
+         i.tm.opcode_modifier.sib = 1;
+       }
+
+      /* Establish operand size encoding.  */
+      operand_type_set (&combined, 0);
+
+      for (j = i.imm_operands; j < i.operands; ++j)
+       {
+         i.types[j].bitfield.instance = InstanceNone;
+
+         if (operand_type_check (i.types[j], disp))
+           {
+             i.types[j].bitfield.baseindex = 1;
+             disp_exp = i.op[j].disps;
+           }
+
+         if (evex && i.types[j].bitfield.baseindex)
+           {
+             unsigned int n = i.memshift;
+
+             if (i.types[j].bitfield.byte)
+               n = 0;
+             else if (i.types[j].bitfield.word)
+               n = 1;
+             else if (i.types[j].bitfield.dword)
+               n = 2;
+             else if (i.types[j].bitfield.qword)
+               n = 3;
+             else if (i.types[j].bitfield.xmmword)
+               n = 4;
+             else if (i.types[j].bitfield.ymmword)
+               n = 5;
+             else if (i.types[j].bitfield.zmmword)
+               n = 6;
+
+             if (i.memshift < 32 && n != i.memshift)
+               as_warn ("conflicting memory operand size specifiers");
+             i.memshift = n;
+           }
+
+         if ((i.broadcast.type || i.broadcast.bytes)
+             && j == i.broadcast.operand)
+           continue;
+
+         combined = operand_type_or (combined, i.types[j]);
+         combined.bitfield.class = ClassNone;
+       }
+
+      switch ((i.broadcast.type ? i.broadcast.type : 1)
+             << (i.memshift < 32 ? i.memshift : 0))
+       {
+       case 64: combined.bitfield.zmmword = 1; break;
+       case 32: combined.bitfield.ymmword = 1; break;
+       case 16: combined.bitfield.xmmword = 1; break;
+       case  8: combined.bitfield.qword = 1; break;
+       case  4: combined.bitfield.dword = 1; break;
+       }
+
+      if (i.vec_encoding == vex_encoding_default)
+       {
+         if (flag_code == CODE_64BIT && combined.bitfield.qword)
+           i.rex |= REX_W;
+         else if ((flag_code == CODE_16BIT ? combined.bitfield.dword
+                                           : combined.bitfield.word)
+                  && !add_prefix (DATA_PREFIX_OPCODE))
+           goto done;
+       }
+      else if (!i.tm.opcode_modifier.vexw)
+       {
+         if (flag_code == CODE_64BIT)
+           {
+             if (combined.bitfield.qword)
+               i.tm.opcode_modifier.vexw = VEXW1;
+             else if (combined.bitfield.dword)
+               i.tm.opcode_modifier.vexw = VEXW0;
+           }
+
+         if (!i.tm.opcode_modifier.vexw)
+           i.tm.opcode_modifier.vexw = VEXWIG;
+       }
 
-  for (j = 0; j < ARRAY_SIZE (gotrel); j++)
-    {
-      int len = gotrel[j].len;
-      if (strncasecmp (cp + 1, gotrel[j].str, len) == 0)
+      if (vex || xop)
        {
-         if (gotrel[j].rel[object_64bit] != 0)
+         if (!i.tm.opcode_modifier.vex)
            {
-             int first, second;
-             char *tmpbuf, *past_reloc;
+             if (combined.bitfield.ymmword)
+               i.tm.opcode_modifier.vex = VEX256;
+             else if (combined.bitfield.xmmword)
+               i.tm.opcode_modifier.vex = VEX128;
+           }
+       }
+      else if (evex)
+       {
+         if (!i.tm.opcode_modifier.evex)
+           {
+             /* Do _not_ consider AVX512VL here.  */
+             if (i.rounding.type != rc_none || combined.bitfield.zmmword)
+               i.tm.opcode_modifier.evex = EVEX512;
+             else if (combined.bitfield.ymmword)
+               i.tm.opcode_modifier.evex = EVEX256;
+             else if (combined.bitfield.xmmword)
+               i.tm.opcode_modifier.evex = EVEX128;
+           }
 
-             *rel = gotrel[j].rel[object_64bit];
+         if (i.memshift >= 32)
+           {
+             unsigned int n = 0;
 
-             if (types)
+             switch (i.tm.opcode_modifier.evex)
                {
-                 if (flag_code != CODE_64BIT)
-                   {
-                     types->bitfield.imm32 = 1;
-                     types->bitfield.disp32 = 1;
-                   }
-                 else
-                   *types = gotrel[j].types64;
+               case EVEX512: n = 64; break;
+               case EVEX256: n = 32; break;
+               case EVEX128: n = 16; break;
                }
 
-             if (gotrel[j].need_GOT_symbol && GOT_symbol == NULL)
-               GOT_symbol = symbol_find_or_make (GLOBAL_OFFSET_TABLE_NAME);
+             if (i.broadcast.type)
+               n /= i.broadcast.type;
+
+             if (n > 0)
+               for (i.memshift = 0; !(n & 1); n >>= 1)
+                 ++i.memshift;
+             else if (disp_exp != NULL && disp_exp->X_op == O_constant
+                      && disp_exp->X_add_number != 0
+                      && i.disp_encoding != disp_encoding_32bit)
+               {
+                 if (!quiet_warnings)
+                   as_warn ("cannot determine memory operand size");
+                 i.disp_encoding = disp_encoding_32bit;
+               }
+           }
+       }
 
-             /* The length of the first part of our input line.  */
-             first = cp - input_line_pointer;
+      if (i.memshift >= 32)
+       i.memshift = 0;
+      else if (!evex)
+       i.vec_encoding = vex_encoding_error;
 
-             /* The second part goes from after the reloc token until
-                (and including) an end_of_line char or comma.  */
-             past_reloc = cp + 1 + len;
-             cp = past_reloc;
-             while (!is_end_of_line[(unsigned char) *cp] && *cp != ',')
-               ++cp;
-             second = cp + 1 - past_reloc;
+      if (i.disp_operands && !optimize_disp (&i.tm))
+       goto done;
 
-             /* Allocate and copy string.  The trailing NUL shouldn't
-                be necessary, but be safe.  */
-             tmpbuf = XNEWVEC (char, first + second + 2);
-             memcpy (tmpbuf, input_line_pointer, first);
-             if (second != 0 && *past_reloc != ' ')
-               /* Replace the relocation token with ' ', so that
-                  errors like foo@GOTOFF1 will be detected.  */
-               tmpbuf[first++] = ' ';
+      /* Establish size for immediate operands.  */
+      for (j = 0; j < i.imm_operands; ++j)
+       {
+         expressionS *expP = i.op[j].imms;
+
+         gas_assert (operand_type_check (i.types[j], imm));
+         operand_type_set (&i.types[j], 0);
+
+         if (i.imm_bits[j] > 32)
+           i.types[j].bitfield.imm64 = 1;
+         else if (i.imm_bits[j] > 16)
+           {
+             if (flag_code == CODE_64BIT && (i.flags[j] & Operand_Signed))
+               i.types[j].bitfield.imm32s = 1;
              else
-               /* Increment length by 1 if the relocation token is
-                  removed.  */
-               len++;
-             if (adjust)
-               *adjust = len;
-             memcpy (tmpbuf + first, past_reloc, second);
-             tmpbuf[first + second] = '\0';
-             return tmpbuf;
+               i.types[j].bitfield.imm32 = 1;
            }
-
-         as_bad (_("@%s reloc is not supported with %d-bit output format"),
-                 gotrel[j].str, 1 << (5 + object_64bit));
-         return NULL;
+         else if (i.imm_bits[j] > 8)
+           i.types[j].bitfield.imm16 = 1;
+         else if (i.imm_bits[j] > 0)
+           {
+             if (i.flags[j] & Operand_Signed)
+               i.types[j].bitfield.imm8s = 1;
+             else
+               i.types[j].bitfield.imm8 = 1;
+           }
+         else if (expP->X_op == O_constant)
+           {
+             i.types[j] = smallest_imm_type (expP->X_add_number);
+             i.types[j].bitfield.imm1 = 0;
+             /* Oddly enough imm_size() checks imm64 first, so the bit needs
+                zapping since smallest_imm_type() sets it unconditionally.  */
+             if (flag_code != CODE_64BIT)
+               {
+                 i.types[j].bitfield.imm64 = 0;
+                 i.types[j].bitfield.imm32s = 0;
+                 i.types[j].bitfield.imm32 = 1;
+               }
+             else if (i.types[j].bitfield.imm32 || i.types[j].bitfield.imm32s)
+               i.types[j].bitfield.imm64 = 0;
+           }
+         else
+           /* Non-constant expressions are sized heuristically.  */
+           switch (flag_code)
+             {
+             case CODE_64BIT: i.types[j].bitfield.imm32s = 1; break;
+             case CODE_32BIT: i.types[j].bitfield.imm32 = 1; break;
+             case CODE_16BIT: i.types[j].bitfield.imm16 = 1; break;
+             }
        }
-    }
 
-  /* Might be a symbol version string.  Don't as_bad here.  */
-  return NULL;
-}
-#endif
+      for (j = 0; j < i.operands; ++j)
+       i.tm.operand_types[j] = i.types[j];
 
-bfd_reloc_code_real_type
-x86_cons (expressionS *exp, int size)
-{
-  bfd_reloc_code_real_type got_reloc = NO_RELOC;
+      process_operands ();
+    }
 
-#if ((defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)) \
-      && !defined (LEX_AT)) \
-    || defined (TE_PE)
-  intel_syntax = -intel_syntax;
+  /* Don't set opcode until after processing operands, to avoid any
+     potential special casing there.  */
+  i.tm.base_opcode |= val;
 
-  exp->X_md = 0;
-  if (size == 4 || (object_64bit && size == 8))
+  if (i.vec_encoding == vex_encoding_error
+      || (i.vec_encoding != vex_encoding_evex
+         ? i.broadcast.type || i.broadcast.bytes
+           || i.rounding.type != rc_none
+           || i.mask.reg
+         : (i.mem_operands && i.rounding.type != rc_none)
+           || ((i.broadcast.type || i.broadcast.bytes)
+               && !(i.flags[i.broadcast.operand] & Operand_Mem))))
     {
-      /* Handle @GOTOFF and the like in an expression.  */
-      char *save;
-      char *gotfree_input_line;
-      int adjust = 0;
-
-      save = input_line_pointer;
-      gotfree_input_line = lex_got (&got_reloc, &adjust, NULL);
-      if (gotfree_input_line)
-       input_line_pointer = gotfree_input_line;
+      as_bad (_("conflicting .insn operands"));
+      goto done;
+    }
 
-      expression (exp);
+  if (vex || xop)
+    {
+      if (!i.tm.opcode_modifier.vex)
+       i.tm.opcode_modifier.vex = VEXScalar; /* LIG */
 
-      if (gotfree_input_line)
-       {
-         /* expression () has merrily parsed up to the end of line,
-            or a comma - in the wrong buffer.  Transfer how far
-            input_line_pointer has moved to the right buffer.  */
-         input_line_pointer = (save
-                               + (input_line_pointer - gotfree_input_line)
-                               + adjust);
-         free (gotfree_input_line);
-         if (exp->X_op == O_constant
-             || exp->X_op == O_absent
-             || exp->X_op == O_illegal
-             || exp->X_op == O_register
-             || exp->X_op == O_big)
-           {
-             char c = *input_line_pointer;
-             *input_line_pointer = 0;
-             as_bad (_("missing or invalid expression `%s'"), save);
-             *input_line_pointer = c;
-           }
-         else if ((got_reloc == BFD_RELOC_386_PLT32
-                   || got_reloc == BFD_RELOC_X86_64_PLT32)
-                  && exp->X_op != O_symbol)
-           {
-             char c = *input_line_pointer;
-             *input_line_pointer = 0;
-             as_bad (_("invalid PLT expression `%s'"), save);
-             *input_line_pointer = c;
-           }
-       }
+      build_vex_prefix (NULL);
+      i.rex &= REX_OPCODE;
     }
-  else
-    expression (exp);
+  else if (evex)
+    {
+      if (!i.tm.opcode_modifier.evex)
+       i.tm.opcode_modifier.evex = EVEXLIG;
 
-  intel_syntax = -intel_syntax;
+      build_evex_prefix ();
+      i.rex &= REX_OPCODE;
+    }
+  else if (i.rex != 0)
+    add_prefix (REX_OPCODE | i.rex);
 
-  if (intel_syntax)
-    i386_intel_simplify (exp);
-#else
-  expression (exp);
-#endif
+  output_insn ();
 
-  /* If not 64bit, massage value, to account for wraparound when !BFD64.  */
-  if (size == 4 && exp->X_op == O_constant && !object_64bit)
-    exp->X_add_number = extend_to_32bit_address (exp->X_add_number);
+ done:
+  *saved_ilp = saved_char;
+  input_line_pointer = line;
 
-  return got_reloc;
-}
+  demand_empty_rest_of_line ();
 
-static void
-signed_cons (int size)
-{
-  if (object_64bit)
-    cons_sign = 1;
-  cons (size);
-  cons_sign = -1;
+  /* Make sure dot_insn() won't yield "true" anymore.  */
+  i.tm.mnem_off = 0;
 }
 
 #ifdef TE_PE
@@ -10753,6 +11725,12 @@ RC_SAE_specifier (const char *pstr)
              return NULL;
            }
 
+         if (i.vec_encoding == vex_encoding_default)
+           i.vec_encoding = vex_encoding_evex512;
+         else if (i.vec_encoding != vex_encoding_evex
+                  && i.vec_encoding != vex_encoding_evex512)
+           return NULL;
+
          i.rounding.type = RC_NamesTable[j].type;
 
          return (char *)(pstr + RC_NamesTable[j].len);
@@ -10812,8 +11790,59 @@ check_VecOperations (char *op_string)
                }
              op_string++;
 
+             if (i.vec_encoding == vex_encoding_default)
+               i.vec_encoding = vex_encoding_evex;
+             else if (i.vec_encoding != vex_encoding_evex
+                      && i.vec_encoding != vex_encoding_evex512)
+               goto unknown_vec_op;
+
              i.broadcast.type = bcst_type;
              i.broadcast.operand = this_operand;
+
+             /* For .insn a data size specifier may be appended.  */
+             if (dot_insn () && *op_string == ':')
+               goto dot_insn_modifier;
+           }
+         /* Check .insn special cases.  */
+         else if (dot_insn () && *op_string == ':')
+           {
+           dot_insn_modifier:
+             switch (op_string[1])
+               {
+                 unsigned long n;
+
+               case 'd':
+                 if (i.memshift < 32)
+                   goto duplicated_vec_op;
+
+                 n = strtoul (op_string + 2, &end_op, 0);
+                 if (n)
+                   for (i.memshift = 0; !(n & 1); n >>= 1)
+                     ++i.memshift;
+                 if (i.memshift < 32 && n == 1)
+                   op_string = end_op;
+                 break;
+
+               case 's': case 'u':
+                 /* This isn't really a "vector" operation, but a sign/size
+                    specifier for immediate operands of .insn.  Note that AT&T
+                    syntax handles the same in i386_immediate().  */
+                 if (!intel_syntax)
+                   break;
+
+                 if (i.imm_bits[this_operand])
+                   goto duplicated_vec_op;
+
+                 n = strtoul (op_string + 2, &end_op, 0);
+                 if (n && n <= (flag_code == CODE_64BIT ? 64 : 32))
+                   {
+                     i.imm_bits[this_operand] = n;
+                     if (op_string[1] == 's')
+                       i.flags[this_operand] |= Operand_Signed;
+                     op_string = end_op;
+                   }
+                 break;
+               }
            }
          /* Check masking operation.  */
          else if ((mask = parse_register (op_string, &end_op)) != NULL)
@@ -10949,8 +11978,25 @@ i386_immediate (char *imm_start)
   if (gotfree_input_line)
     input_line_pointer = gotfree_input_line;
 
+  expr_mode = expr_operator_none;
   exp_seg = expression (exp);
 
+  /* For .insn immediates there may be a size specifier.  */
+  if (dot_insn () && *input_line_pointer == '{' && input_line_pointer[1] == ':'
+      && (input_line_pointer[2] == 's' || input_line_pointer[2] == 'u'))
+    {
+      char *e;
+      unsigned long n = strtoul (input_line_pointer + 3, &e, 0);
+
+      if (*e == '}' && n && n <= (flag_code == CODE_64BIT ? 64 : 32))
+       {
+         i.imm_bits[this_operand] = n;
+         if (input_line_pointer[2] == 's')
+           i.flags[this_operand] |= Operand_Signed;
+         input_line_pointer = e + 1;
+       }
+    }
+
   SKIP_WHITESPACE ();
   if (*input_line_pointer)
     as_bad (_("junk `%s' after expression"), input_line_pointer);
@@ -10991,7 +12037,8 @@ i386_finalize_immediate (segT exp_seg ATTRIBUTE_UNUSED, expressionS *exp,
 
       /* If not 64bit, sign/zero extend val, to account for wraparound
         when !BFD64.  */
-      if (flag_code != CODE_64BIT)
+      if (expr_mode == expr_operator_present
+         && flag_code != CODE_64BIT && !object_64bit)
        exp->X_add_number = extend_to_32bit_address (exp->X_add_number);
     }
 #if (defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT))
@@ -11213,6 +12260,7 @@ i386_displacement (char *disp_start, char *disp_end)
   if (gotfree_input_line)
     input_line_pointer = gotfree_input_line;
 
+  expr_mode = expr_operator_none;
   exp_seg = expression (exp);
 
   SKIP_WHITESPACE ();
@@ -11283,7 +12331,8 @@ i386_finalize_displacement (segT exp_seg ATTRIBUTE_UNUSED, expressionS *exp,
 
         If not 64bit, sign/zero extend val, to account for wraparound
         when !BFD64.  */
-      if (flag_code != CODE_64BIT)
+      if (expr_mode == expr_operator_present
+         && flag_code != CODE_64BIT && !object_64bit)
        exp->X_add_number = extend_to_32bit_address (exp->X_add_number);
     }
 
@@ -11325,7 +12374,7 @@ i386_addressing_mode (void)
   if (i.prefix[ADDR_PREFIX])
     addr_mode = flag_code == CODE_32BIT ? CODE_16BIT : CODE_32BIT;
   else if (flag_code == CODE_16BIT
-          && current_templates->start->cpu_flags.bitfield.cpumpx
+          && is_cpu (current_templates->start, CpuMPX)
           /* Avoid replacing the "16-bit addressing not allowed" diagnostic
              from md_assemble() by "is not a valid base/index expression"
              when there is a base and/or index.  */
@@ -11405,13 +12454,13 @@ i386_index_check (const char *operand_string)
       /* Memory operands of string insns are special in that they only allow
         a single register (rDI, rSI, or rBX) as their memory address.  */
       const reg_entry *expected_reg;
-      static const char *di_si[][2] =
+      static const char di_si[][2][4] =
        {
          { "esi", "edi" },
          { "si", "di" },
          { "rsi", "rdi" }
        };
-      static const char *bx[] = { "ebx", "bx", "rbx" };
+      static const char bx[][4] = { "ebx", "bx", "rbx" };
 
       kind = "string address";
 
@@ -11495,12 +12544,9 @@ i386_index_check (const char *operand_string)
            goto bad_address;
 
          /* bndmk, bndldx, bndstx and mandatory non-vector SIB have special restrictions. */
-         if ((t->opcode_modifier.opcodeprefix == PREFIX_0XF3
-              && t->opcode_modifier.opcodespace == SPACE_0F
-              && t->base_opcode == 0x1b)
-             || (t->opcode_modifier.opcodeprefix == PREFIX_NONE
-                 && t->opcode_modifier.opcodespace == SPACE_0F
-                 && (t->base_opcode & ~1) == 0x1a)
+         if (t->mnem_off == MN_bndmk
+             || t->mnem_off == MN_bndldx
+             || t->mnem_off == MN_bndstx
              || t->opcode_modifier.sib == SIBMEM)
            {
              /* They cannot use RIP-relative addressing. */
@@ -11511,9 +12557,7 @@ i386_index_check (const char *operand_string)
                }
 
              /* bndldx and bndstx ignore their scale factor. */
-             if (t->opcode_modifier.opcodeprefix == PREFIX_NONE
-                 && t->opcode_modifier.opcodespace == SPACE_0F
-                 && (t->base_opcode & ~1) == 0x1a
+             if ((t->mnem_off == MN_bndldx || t->mnem_off == MN_bndstx)
                  && i.log2_scale_factor)
                as_warn (_("register scaling is being ignored here"));
            }
@@ -11575,7 +12619,7 @@ RC_SAE_immediate (const char *imm_start)
 static INLINE bool starts_memory_operand (char c)
 {
   return ISDIGIT (c)
-        || is_identifier_char (c)
+        || is_name_beginner (c)
         || strchr ("([\"+-!~", c);
 }
 
@@ -11594,7 +12638,8 @@ i386_att_operand (char *operand_string)
 
   /* We check for an absolute prefix (differentiating,
      for example, 'jmp pc_relative_label' from 'jmp *absolute_label'.  */
-  if (*op_string == ABSOLUTE_PREFIX)
+  if (*op_string == ABSOLUTE_PREFIX
+      && current_templates->start->opcode_modifier.jump)
     {
       ++op_string;
       if (is_space_char (*op_string))
@@ -11625,7 +12670,8 @@ i386_att_operand (char *operand_string)
            ++op_string;
 
          /* Handle case of %es:*foo.  */
-         if (!i.jumpabsolute && *op_string == ABSOLUTE_PREFIX)
+         if (!i.jumpabsolute && *op_string == ABSOLUTE_PREFIX
+             && current_templates->start->opcode_modifier.jump)
            {
              ++op_string;
              if (is_space_char (*op_string))
@@ -11654,6 +12700,15 @@ i386_att_operand (char *operand_string)
          as_bad (_("junk `%s' after register"), op_string);
          return 0;
        }
+
+       /* Reject pseudo registers for .insn.  */
+      if (dot_insn () && r->reg_type.bitfield.class == ClassNone)
+       {
+         as_bad (_("`%s%s' cannot be used here"),
+                 register_prefix, r->reg_name);
+         return 0;
+       }
+
       temp = r->reg_type;
       temp.bitfield.baseindex = 0;
       i.types[this_operand] = operand_type_or (i.types[this_operand],
@@ -12437,7 +13492,8 @@ md_estimate_size_before_relax (fragS *fragP, segT segment)
       else if (size == 2)
        reloc_type = BFD_RELOC_16_PCREL;
 #if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
-      else if (fragP->tc_frag_data.code64 && fragP->fr_offset == 0
+      else if (fragP->tc_frag_data.code == CODE_64BIT
+              && fragP->fr_offset == 0
               && need_plt32_p (fragP->fr_symbol))
        reloc_type = BFD_RELOC_X86_64_PLT32;
 #endif
@@ -13002,6 +14058,21 @@ static bool check_register (const reg_entry *r)
        }
     }
 
+  if (r->reg_type.bitfield.zmmword)
+    {
+      if (vector_size < VSZ512)
+       return false;
+
+      if (i.vec_encoding == vex_encoding_default)
+       i.vec_encoding = vex_encoding_evex512;
+      else if (i.vec_encoding != vex_encoding_evex
+              && i.vec_encoding != vex_encoding_evex512)
+       i.vec_encoding = vex_encoding_error;
+    }
+
+  if (vector_size < VSZ256 && r->reg_type.bitfield.ymmword)
+    return false;
+
   if (r->reg_type.bitfield.tmmword
       && (!cpu_arch_flags.bitfield.cpuamx_tile
           || flag_code != CODE_64BIT))
@@ -13022,14 +14093,17 @@ static bool check_register (const reg_entry *r)
          || flag_code != CODE_64BIT)
        return false;
 
-      if (i.vec_encoding == vex_encoding_default)
+      if (i.vec_encoding == vex_encoding_default
+         || i.vec_encoding == vex_encoding_evex512)
        i.vec_encoding = vex_encoding_evex;
       else if (i.vec_encoding != vex_encoding_evex)
        i.vec_encoding = vex_encoding_error;
     }
 
   if (((r->reg_flags & (RegRex64 | RegRex)) || r->reg_type.bitfield.qword)
-      && (!cpu_arch_flags.bitfield.cpulm || r->reg_type.bitfield.class != RegCR)
+      && (!cpu_arch_flags.bitfield.cpu64
+         || r->reg_type.bitfield.class != RegCR
+         || dot_insn ())
       && flag_code != CODE_64BIT)
     return false;
 
@@ -13043,9 +14117,9 @@ static bool check_register (const reg_entry *r)
 /* REG_STRING starts *before* REGISTER_PREFIX.  */
 
 static const reg_entry *
-parse_real_register (char *reg_string, char **end_op)
+parse_real_register (const char *reg_string, char **end_op)
 {
-  char *s = reg_string;
+  const char *s = reg_string;
   char *p;
   char reg_name_given[MAX_REG_NAME_SIZE + 1];
   const reg_entry *r;
@@ -13065,13 +14139,10 @@ parse_real_register (char *reg_string, char **end_op)
       s++;
     }
 
-  /* For naked regs, make sure that we are not dealing with an identifier.
-     This prevents confusing an identifier like `eax_var' with register
-     `eax'.  */
-  if (allow_naked_reg && identifier_chars[(unsigned char) *s])
+  if (is_part_of_name (*s))
     return (const reg_entry *) NULL;
 
-  *end_op = s;
+  *end_op = (char *) s;
 
   r = (const reg_entry *) str_hash_find (reg_hash, reg_name_given);
 
@@ -13099,7 +14170,7 @@ parse_real_register (char *reg_string, char **end_op)
                ++s;
              if (*s == ')')
                {
-                 *end_op = s + 1;
+                 *end_op = (char *) s + 1;
                  know (r[fpr].reg_num == fpr);
                  return r + fpr;
                }
@@ -13115,7 +14186,7 @@ parse_real_register (char *reg_string, char **end_op)
 /* REG_STRING starts *before* REGISTER_PREFIX.  */
 
 static const reg_entry *
-parse_register (char *reg_string, char **end_op)
+parse_register (const char *reg_string, char **end_op)
 {
   const reg_entry *r;
 
@@ -13126,17 +14197,17 @@ parse_register (char *reg_string, char **end_op)
   if (!r)
     {
       char *save = input_line_pointer;
-      char c;
+      char *buf = xstrdup (reg_string), *name;
       symbolS *symbolP;
 
-      input_line_pointer = reg_string;
-      c = get_symbol_name (&reg_string);
-      symbolP = symbol_find (reg_string);
-      while (symbolP && S_GET_SEGMENT (symbolP) != reg_section)
+      input_line_pointer = buf;
+      get_symbol_name (&name);
+      symbolP = symbol_find (name);
+      while (symbolP && symbol_equated_p (symbolP))
        {
          const expressionS *e = symbol_get_value_expression(symbolP);
 
-         if (e->X_op != O_symbol || e->X_add_number)
+         if (e->X_add_number)
            break;
          symbolP = e->X_add_symbol;
        }
@@ -13144,20 +14215,22 @@ parse_register (char *reg_string, char **end_op)
        {
          const expressionS *e = symbol_get_value_expression (symbolP);
 
-         know (e->X_op == O_register);
-         know (e->X_add_number >= 0
-               && (valueT) e->X_add_number < i386_regtab_size);
-         r = i386_regtab + e->X_add_number;
-         if (!check_register (r))
+         if (e->X_op == O_register)
+           {
+             know (e->X_add_number >= 0
+                   && (valueT) e->X_add_number < i386_regtab_size);
+             r = i386_regtab + e->X_add_number;
+             *end_op = (char *) reg_string + (input_line_pointer - buf);
+           }
+         if (r && !check_register (r))
            {
              as_bad (_("register '%s%s' cannot be used here"),
                      register_prefix, r->reg_name);
              r = &bad_reg;
            }
-         *end_op = input_line_pointer;
        }
-      *input_line_pointer = c;
       input_line_pointer = save;
+      free (buf);
     }
   return r;
 }
@@ -13168,6 +14241,13 @@ i386_parse_name (char *name, expressionS *e, char *nextcharP)
   const reg_entry *r = NULL;
   char *end = input_line_pointer;
 
+  /* We only know the terminating character here.  It being double quote could
+     be the closing one of a quoted symbol name, or an opening one from a
+     following string (or another quoted symbol name).  Since the latter can't
+     be valid syntax for anything, bailing in either case is good enough.  */
+  if (*nextcharP == '"')
+    return 0;
+
   *end = *nextcharP;
   if (*name == REGISTER_PREFIX || allow_naked_reg)
     r = parse_real_register (name, &input_line_pointer);
@@ -13175,13 +14255,8 @@ i386_parse_name (char *name, expressionS *e, char *nextcharP)
     {
       *nextcharP = *input_line_pointer;
       *input_line_pointer = 0;
-      if (r != &bad_reg)
-       {
-         e->X_op = O_register;
-         e->X_add_number = r - i386_regtab;
-       }
-      else
-         e->X_op = O_illegal;
+      e->X_op = O_register;
+      e->X_add_number = r - i386_regtab;
       return 1;
     }
   input_line_pointer = end;
@@ -13228,6 +14303,41 @@ md_operand (expressionS *e)
     }
 }
 
+#ifdef BFD64
+/* To maintain consistency with !BFD64 builds of gas record, whether any
+   (binary) operator was involved in an expression.  As expressions are
+   evaluated in only 32 bits when !BFD64, we use this to decide whether to
+   truncate results.  */
+bool i386_record_operator (operatorT op,
+                          const expressionS *left,
+                          const expressionS *right)
+{
+  if (op == O_absent)
+    return false;
+
+  if (!left)
+    {
+      /* Since the expression parser applies unary operators fine to bignum
+        operands, we don't need to be concerned of respective operands not
+        fitting in 32 bits.  */
+      if (right->X_op == O_constant && right->X_unsigned
+         && !fits_in_unsigned_long (right->X_add_number))
+       return false;
+    }
+  /* This isn't entirely right: The pattern can also result when constant
+     expressions are folded (e.g. 0xffffffff + 1).  */
+  else if ((left->X_op == O_constant && left->X_unsigned
+           && !fits_in_unsigned_long (left->X_add_number))
+          || (right->X_op == O_constant && right->X_unsigned
+              && !fits_in_unsigned_long (right->X_add_number)))
+    expr_mode = expr_large_value;
+
+  if (expr_mode != expr_large_value)
+    expr_mode = expr_operator_present;
+
+  return false;
+}
+#endif
 \f
 #if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
 const char *md_shortopts = "kVQ:sqnO::";
@@ -13420,7 +14530,21 @@ md_parse_option (int c, const char *arg)
 #endif
 
     case OPTION_32:
-      default_arch = "i386";
+      {
+       const char **list, **l;
+
+       list = bfd_target_list ();
+       for (l = list; *l != NULL; l++)
+         if (strstr (*l, "-i386")
+             || strstr (*l, "-go32"))
+           {
+             default_arch = "i386";
+             break;
+           }
+       if (*l == NULL)
+         as_fatal (_("no compiled in support for ix86"));
+       free (list);
+      }
       break;
 
     case OPTION_DIVIDE:
@@ -13448,13 +14572,21 @@ md_parse_option (int c, const char *arg)
        arch++;
       do
        {
+         char *vsz;
+
          if (*arch == '.')
            as_fatal (_("invalid -march= option: `%s'"), arg);
          next = strchr (arch, '+');
          if (next)
            *next++ = '\0';
+         vsz = strchr (arch, '/');
+         if (vsz)
+           *vsz++ = '\0';
          for (j = 0; j < ARRAY_SIZE (cpu_arch); j++)
            {
+             if (vsz && cpu_arch[j].vsz != vsz_set)
+               continue;
+
              if (arch == saved && cpu_arch[j].type != PROCESSOR_NONE
                  && strcmp (arch, cpu_arch[j].name) == 0)
                {
@@ -13469,10 +14601,8 @@ md_parse_option (int c, const char *arg)
                  cpu_arch_isa = cpu_arch[j].type;
                  cpu_arch_isa_flags = cpu_arch[j].enable;
                  if (!cpu_arch_tune_set)
-                   {
-                     cpu_arch_tune = cpu_arch_isa;
-                     cpu_arch_tune_flags = cpu_arch_isa_flags;
-                   }
+                   cpu_arch_tune = cpu_arch_isa;
+                 vector_size = VSZ_DEFAULT;
                  break;
                }
              else if (cpu_arch[j].type == PROCESSOR_NONE
@@ -13480,21 +14610,38 @@ md_parse_option (int c, const char *arg)
                       && !cpu_flags_all_zero (&cpu_arch[j].enable))
                {
                  /* ISA extension.  */
-                 i386_cpu_flags flags;
-
-                 flags = cpu_flags_or (cpu_arch_flags,
-                                       cpu_arch[j].enable);
+                 isa_enable (j);
 
-                 if (!cpu_flags_equal (&flags, &cpu_arch_flags))
+                 switch (cpu_arch[j].vsz)
                    {
-                     extend_cpu_sub_arch_name (arch);
-                     cpu_arch_flags = flags;
-                     cpu_arch_isa_flags = flags;
+                   default:
+                     break;
+
+                   case vsz_set:
+                     if (vsz)
+                       {
+                         char *end;
+                         unsigned long val = strtoul (vsz, &end, 0);
+
+                         if (*end)
+                           val = 0;
+                         switch (val)
+                           {
+                           case 512: vector_size = VSZ512; break;
+                           case 256: vector_size = VSZ256; break;
+                           case 128: vector_size = VSZ128; break;
+                           default:
+                             as_warn (_("Unrecognized vector size specifier ignored"));
+                             break;
+                           }
+                         break;
+                       }
+                       /* Fall through.  */
+                   case vsz_reset:
+                     vector_size = VSZ_DEFAULT;
+                     break;
                    }
-                 else
-                   cpu_arch_isa_flags
-                     = cpu_flags_or (cpu_arch_isa_flags,
-                                     cpu_arch[j].enable);
+
                  break;
                }
            }
@@ -13506,16 +14653,9 @@ md_parse_option (int c, const char *arg)
                if (cpu_arch[j].type == PROCESSOR_NONE
                    && strcmp (arch + 2, cpu_arch[j].name) == 0)
                  {
-                   i386_cpu_flags flags;
-
-                   flags = cpu_flags_and_not (cpu_arch_flags,
-                                              cpu_arch[j].disable);
-                   if (!cpu_flags_equal (&flags, &cpu_arch_flags))
-                     {
-                       extend_cpu_sub_arch_name (arch);
-                       cpu_arch_flags = flags;
-                       cpu_arch_isa_flags = flags;
-                     }
+                   isa_disable (j);
+                   if (cpu_arch[j].vsz == vsz_set)
+                     vector_size = VSZ_DEFAULT;
                    break;
                  }
            }
@@ -13539,7 +14679,6 @@ md_parse_option (int c, const char *arg)
            {
              cpu_arch_tune_set = 1;
              cpu_arch_tune = cpu_arch [j].type;
-             cpu_arch_tune_flags = cpu_arch[j].enable;
              break;
            }
        }
@@ -14145,10 +15284,7 @@ i386_target_format (void)
          cpu_arch_isa = PROCESSOR_IAMCU;
          cpu_arch_isa_flags = iamcu_flags;
          if (!cpu_arch_tune_set)
-           {
-             cpu_arch_tune = cpu_arch_isa;
-             cpu_arch_tune_flags = cpu_arch_isa_flags;
-           }
+           cpu_arch_tune = PROCESSOR_IAMCU;
        }
       else if (cpu_arch_isa != PROCESSOR_IAMCU)
        as_fatal (_("Intel MCU doesn't support `%s' architecture"),
@@ -14159,8 +15295,6 @@ i386_target_format (void)
 
   if (cpu_flags_all_zero (&cpu_arch_isa_flags))
     cpu_arch_isa_flags = cpu_arch[flag_code == CODE_64BIT].enable;
-  if (cpu_flags_all_zero (&cpu_arch_tune_flags))
-    cpu_arch_tune_flags = cpu_arch[flag_code == CODE_64BIT].enable;
 
   switch (OUTPUT_FLAVOR)
     {
@@ -14781,15 +15915,6 @@ x86_64_section_letter (int letter, const char **ptr_msg)
   return -1;
 }
 
-bfd_vma
-x86_64_section_word (char *str, size_t len)
-{
-  if (len == 5 && flag_code == CODE_64BIT && startswith (str, "large"))
-    return SHF_X86_64_LARGE;
-
-  return -1;
-}
-
 static void
 handle_large_common (int small ATTRIBUTE_UNUSED)
 {