Add support for intel SERIALIZE instruction
[deliverable/binutils-gdb.git] / gas / config / tc-i386.c
index 3a2a1b743536db577589e7235d453cb6fb073036..d67532c42230373ad3a3824f4e0d20c44023d233 100644 (file)
 #endif
 #endif
 
-#ifndef REGISTER_WARNINGS
-#define REGISTER_WARNINGS 1
-#endif
-
 #ifndef INFER_ADDR_PREFIX
 #define INFER_ADDR_PREFIX 1
 #endif
@@ -354,6 +350,9 @@ struct _i386_insn
     unsigned int prefixes;
     unsigned char prefix[MAX_PREFIXES];
 
+    /* Register is in low 3 bits of opcode.  */
+    bfd_boolean short_form;
+
     /* The operand to a branch insn indicates an absolute branch.  */
     bfd_boolean jumpabsolute;
 
@@ -598,9 +597,11 @@ static int shared = 0;
    0 if att syntax.  */
 static int intel_syntax = 0;
 
-/* 1 for Intel64 ISA,
-   0 if AMD64 ISA.  */
-static int intel64;
+static enum x86_64_isa
+{
+  amd64 = 1,   /* AMD64 ISA.  */
+  intel64      /* Intel64 ISA.  */
+} isa64;
 
 /* 1 for intel mnemonic,
    0 if att mnemonic.  */
@@ -628,7 +629,29 @@ static int omit_lock_prefix = 0;
    "lock addl $0, (%{re}sp)".  */
 static int avoid_fence = 0;
 
-/* Type of the previous instruction.  */
+/* 1 if lfence should be inserted after every load.  */
+static int lfence_after_load = 0;
+
+/* Non-zero if lfence should be inserted before indirect branch.  */
+static enum lfence_before_indirect_branch_kind
+  {
+    lfence_branch_none = 0,
+    lfence_branch_register,
+    lfence_branch_memory,
+    lfence_branch_all
+  }
+lfence_before_indirect_branch;
+
+/* Non-zero if lfence should be inserted before ret.  */
+static enum lfence_before_ret_kind
+  {
+    lfence_before_ret_none = 0,
+    lfence_before_ret_not,
+    lfence_before_ret_or
+  }
+lfence_before_ret;
+
+/* Types of previous instruction is .byte or prefix.  */
 static struct
   {
     segT seg;
@@ -686,6 +709,27 @@ static unsigned int align_branch = (align_branch_jcc_bit
                                    | align_branch_fused_bit
                                    | align_branch_jmp_bit);
 
+/* Types of condition jump used by macro-fusion.  */
+enum mf_jcc_kind
+  {
+    mf_jcc_jo = 0,  /* base opcode 0x70  */
+    mf_jcc_jc,      /* base opcode 0x72  */
+    mf_jcc_je,      /* base opcode 0x74  */
+    mf_jcc_jna,     /* base opcode 0x76  */
+    mf_jcc_js,      /* base opcode 0x78  */
+    mf_jcc_jp,      /* base opcode 0x7a  */
+    mf_jcc_jl,      /* base opcode 0x7c  */
+    mf_jcc_jle,     /* base opcode 0x7e  */
+  };
+
+/* Types of compare flag-modifying insntructions used by macro-fusion.  */
+enum mf_cmp_kind
+  {
+    mf_cmp_test_and,  /* test/cmp */
+    mf_cmp_alu_cmp,  /* add/sub/cmp */
+    mf_cmp_incdec  /* inc/dec */
+  };
+
 /* The maximum padding size for fused jcc.  CMP like instruction can
    be 9 bytes and jcc can be 6 bytes.  Leave room just in case for
    prefixes.   */
@@ -982,6 +1026,8 @@ static const arch_entry cpu_arch[] =
     CPU_SSE2_FLAGS, 0 },
   { STRING_COMMA_LEN (".sse3"), PROCESSOR_UNKNOWN,
     CPU_SSE3_FLAGS, 0 },
+  { STRING_COMMA_LEN (".sse4a"), PROCESSOR_UNKNOWN,
+    CPU_SSE4A_FLAGS, 0 },
   { STRING_COMMA_LEN (".ssse3"), PROCESSOR_UNKNOWN,
     CPU_SSSE3_FLAGS, 0 },
   { STRING_COMMA_LEN (".sse4.1"), PROCESSOR_UNKNOWN,
@@ -1052,6 +1098,8 @@ static const arch_entry cpu_arch[] =
     CPU_EPT_FLAGS, 0 },
   { STRING_COMMA_LEN (".lzcnt"), PROCESSOR_UNKNOWN,
     CPU_LZCNT_FLAGS, 0 },
+  { STRING_COMMA_LEN (".popcnt"), PROCESSOR_UNKNOWN,
+    CPU_POPCNT_FLAGS, 0 },
   { STRING_COMMA_LEN (".hle"), PROCESSOR_UNKNOWN,
     CPU_HLE_FLAGS, 0 },
   { STRING_COMMA_LEN (".rtm"), PROCESSOR_UNKNOWN,
@@ -1158,10 +1206,14 @@ static const arch_entry cpu_arch[] =
     CPU_AVX512_VP2INTERSECT_FLAGS, 0 },
   { STRING_COMMA_LEN (".enqcmd"), PROCESSOR_UNKNOWN,
     CPU_ENQCMD_FLAGS, 0 },
+  { STRING_COMMA_LEN (".serialize"), PROCESSOR_UNKNOWN,
+    CPU_SERIALIZE_FLAGS, 0 },
   { STRING_COMMA_LEN (".rdpru"), PROCESSOR_UNKNOWN,
     CPU_RDPRU_FLAGS, 0 },
   { STRING_COMMA_LEN (".mcommit"), PROCESSOR_UNKNOWN,
     CPU_MCOMMIT_FLAGS, 0 },
+  { STRING_COMMA_LEN (".sev_es"), PROCESSOR_UNKNOWN,
+    CPU_SEV_ES_FLAGS, 0 },
 };
 
 static const noarch_entry cpu_noarch[] =
@@ -1176,6 +1228,7 @@ static const noarch_entry cpu_noarch[] =
   { STRING_COMMA_LEN ("nosse"),  CPU_ANY_SSE_FLAGS },
   { STRING_COMMA_LEN ("nosse2"),  CPU_ANY_SSE2_FLAGS },
   { STRING_COMMA_LEN ("nosse3"),  CPU_ANY_SSE3_FLAGS },
+  { STRING_COMMA_LEN ("nosse4a"),  CPU_ANY_SSE4A_FLAGS },
   { STRING_COMMA_LEN ("nossse3"),  CPU_ANY_SSSE3_FLAGS },
   { STRING_COMMA_LEN ("nosse4.1"),  CPU_ANY_SSE4_1_FLAGS },
   { STRING_COMMA_LEN ("nosse4.2"),  CPU_ANY_SSE4_2_FLAGS },
@@ -1204,6 +1257,7 @@ static const noarch_entry cpu_noarch[] =
   { STRING_COMMA_LEN ("noavx512_bf16"), CPU_ANY_AVX512_BF16_FLAGS },
   { STRING_COMMA_LEN ("noavx512_vp2intersect"), CPU_ANY_SHSTK_FLAGS },
   { STRING_COMMA_LEN ("noenqcmd"), CPU_ANY_ENQCMD_FLAGS },
+  { STRING_COMMA_LEN ("noserialize"), CPU_ANY_SERIALIZE_FLAGS },
 };
 
 #ifdef I386COFF
@@ -1839,6 +1893,8 @@ cpu_flags_and_not (i386_cpu_flags x, i386_cpu_flags y)
   return x;
 }
 
+static const i386_cpu_flags avx512 = CPU_ANY_AVX512F_FLAGS;
+
 #define CPU_FLAGS_ARCH_MATCH           0x1
 #define CPU_FLAGS_64BIT_MATCH          0x2
 
@@ -2114,11 +2170,11 @@ match_mem_size (const insn_template *t, unsigned int wanted,
                  here.  Also for v{,p}broadcast*, {,v}pmov{s,z}*, and
                  down-conversion vpmov*.  */
               || ((t->operand_types[wanted].bitfield.class == RegSIMD
-                   && !t->opcode_modifier.broadcast
-                   && (t->operand_types[wanted].bitfield.byte
-                       || t->operand_types[wanted].bitfield.word
-                       || t->operand_types[wanted].bitfield.dword
-                       || t->operand_types[wanted].bitfield.qword))
+                   && t->operand_types[wanted].bitfield.byte
+                      + t->operand_types[wanted].bitfield.word
+                      + t->operand_types[wanted].bitfield.dword
+                      + t->operand_types[wanted].bitfield.qword
+                      > !!t->opcode_modifier.broadcast)
                   ? (i.types[given].bitfield.xmmword
                      || i.types[given].bitfield.ymmword
                      || i.types[given].bitfield.zmmword)
@@ -2181,7 +2237,7 @@ operand_size_match (const insn_template *t)
 
   if (!t->opcode_modifier.d)
     {
-mismatch:
+    mismatch:
       if (!match)
        i.error = operand_size_mismatch;
       return match;
@@ -2236,15 +2292,14 @@ operand_type_match (i386_operand_type overlap,
   if (given.bitfield.baseindex == overlap.bitfield.baseindex)
     return 1;
 
-mismatch:
+ mismatch:
   i.error = operand_type_mismatch;
   return 0;
 }
 
 /* If given types g0 and g1 are registers they must be of the same type
    unless the expected operand type register overlap is null.
-   Memory operand size of certain SIMD instructions is also being checked
-   here.  */
+   Some Intel syntax memory operand size checking also happens here.  */
 
 static INLINE int
 operand_type_register_match (i386_operand_type g0,
@@ -2256,14 +2311,16 @@ operand_type_register_match (i386_operand_type g0,
       && g0.bitfield.class != RegSIMD
       && (!operand_type_check (g0, anymem)
          || g0.bitfield.unspecified
-         || t0.bitfield.class != RegSIMD))
+         || (t0.bitfield.class != Reg
+             && t0.bitfield.class != RegSIMD)))
     return 1;
 
   if (g1.bitfield.class != Reg
       && g1.bitfield.class != RegSIMD
       && (!operand_type_check (g1, anymem)
          || g1.bitfield.unspecified
-         || t1.bitfield.class != RegSIMD))
+         || (t1.bitfield.class != Reg
+             && t1.bitfield.class != RegSIMD)))
     return 1;
 
   if (g0.bitfield.byte == g1.bitfield.byte
@@ -3394,7 +3451,6 @@ tc_i386_fix_adjustable (fixS *fixP ATTRIBUTE_UNUSED)
   if (fixP->fx_r_type == BFD_RELOC_SIZE32
       || fixP->fx_r_type == BFD_RELOC_SIZE64
       || fixP->fx_r_type == BFD_RELOC_386_GOTOFF
-      || fixP->fx_r_type == BFD_RELOC_386_PLT32
       || fixP->fx_r_type == BFD_RELOC_386_GOT32
       || fixP->fx_r_type == BFD_RELOC_386_GOT32X
       || fixP->fx_r_type == BFD_RELOC_386_TLS_GD
@@ -3407,7 +3463,6 @@ tc_i386_fix_adjustable (fixS *fixP ATTRIBUTE_UNUSED)
       || fixP->fx_r_type == BFD_RELOC_386_TLS_LE
       || fixP->fx_r_type == BFD_RELOC_386_TLS_GOTDESC
       || fixP->fx_r_type == BFD_RELOC_386_TLS_DESC_CALL
-      || fixP->fx_r_type == BFD_RELOC_X86_64_PLT32
       || fixP->fx_r_type == BFD_RELOC_X86_64_GOT32
       || fixP->fx_r_type == BFD_RELOC_X86_64_GOTPCREL
       || fixP->fx_r_type == BFD_RELOC_X86_64_GOTPCRELX
@@ -4082,7 +4137,6 @@ optimize_encoding (void)
              i.tm.base_opcode = 0xb8;
              i.tm.extension_opcode = None;
              i.tm.opcode_modifier.w = 0;
-             i.tm.opcode_modifier.shortform = 1;
              i.tm.opcode_modifier.modrm = 0;
            }
        }
@@ -4282,6 +4336,283 @@ optimize_encoding (void)
     }
 }
 
+/* Return non-zero for load instruction.  */
+
+static int
+load_insn_p (void)
+{
+  unsigned int dest;
+  int any_vex_p = is_any_vex_encoding (&i.tm);
+  unsigned int base_opcode = i.tm.base_opcode | 1;
+
+  if (!any_vex_p)
+    {
+      /* lea  */
+      if (i.tm.base_opcode == 0x8d)
+       return 0;
+
+      /* pop  */
+      if ((i.tm.base_opcode & ~7) == 0x58
+         || (i.tm.base_opcode == 0x8f && i.tm.extension_opcode == 0))
+       return 1;
+
+      /* movs, cmps, lods, scas.  */
+      if ((i.tm.base_opcode | 0xb) == 0xaf)
+       return 1;
+
+      /* outs */
+      if (base_opcode == 0x6f)
+       return 1;
+    }
+
+  /* No memory operand.  */
+  if (!i.mem_operands)
+    return 0;
+
+  if (any_vex_p)
+    {
+      /* vldmxcsr.  */
+      if (i.tm.base_opcode == 0xae
+         && i.tm.opcode_modifier.vex
+         && i.tm.opcode_modifier.vexopcode == VEX0F
+         && i.tm.extension_opcode == 2)
+       return 1;
+    }
+  else
+    {
+      /* test, not, neg, mul, imul, div, idiv.  */
+      if ((i.tm.base_opcode == 0xf6 || i.tm.base_opcode == 0xf7)
+         && i.tm.extension_opcode != 1)
+       return 1;
+
+      /* inc, dec.  */
+      if (base_opcode == 0xff && i.tm.extension_opcode <= 1)
+       return 1;
+
+      /* add, or, adc, sbb, and, sub, xor, cmp.  */
+      if (i.tm.base_opcode >= 0x80 && i.tm.base_opcode <= 0x83)
+       return 1;
+
+      /* bt, bts, btr, btc.  */
+      if (i.tm.base_opcode == 0xfba
+         && (i.tm.extension_opcode >= 4 && i.tm.extension_opcode <= 7))
+       return 1;
+
+      /* rol, ror, rcl, rcr, shl/sal, shr, sar. */
+      if ((base_opcode == 0xc1
+          || (i.tm.base_opcode >= 0xd0 && i.tm.base_opcode <= 0xd3))
+         && i.tm.extension_opcode != 6)
+       return 1;
+
+      /* cmpxchg8b, cmpxchg16b, xrstors.  */
+      if (i.tm.base_opcode == 0xfc7
+         && (i.tm.extension_opcode == 1 || i.tm.extension_opcode == 3))
+       return 1;
+
+      /* fxrstor, ldmxcsr, xrstor.  */
+      if (i.tm.base_opcode == 0xfae
+         && (i.tm.extension_opcode == 1
+             || i.tm.extension_opcode == 2
+             || i.tm.extension_opcode == 5))
+       return 1;
+
+      /* lgdt, lidt, lmsw.  */
+      if (i.tm.base_opcode == 0xf01
+         && (i.tm.extension_opcode == 2
+             || i.tm.extension_opcode == 3
+             || i.tm.extension_opcode == 6))
+       return 1;
+
+      /* vmptrld */
+      if (i.tm.base_opcode == 0xfc7
+         && i.tm.extension_opcode == 6)
+       return 1;
+
+      /* Check for x87 instructions.  */
+      if (i.tm.base_opcode >= 0xd8 && i.tm.base_opcode <= 0xdf)
+       {
+         /* Skip fst, fstp, fstenv, fstcw.  */
+         if (i.tm.base_opcode == 0xd9
+             && (i.tm.extension_opcode == 2
+                 || i.tm.extension_opcode == 3
+                 || i.tm.extension_opcode == 6
+                 || i.tm.extension_opcode == 7))
+           return 0;
+
+         /* Skip fisttp, fist, fistp, fstp.  */
+         if (i.tm.base_opcode == 0xdb
+             && (i.tm.extension_opcode == 1
+                 || i.tm.extension_opcode == 2
+                 || i.tm.extension_opcode == 3
+                 || i.tm.extension_opcode == 7))
+           return 0;
+
+         /* Skip fisttp, fst, fstp, fsave, fstsw.  */
+         if (i.tm.base_opcode == 0xdd
+             && (i.tm.extension_opcode == 1
+                 || i.tm.extension_opcode == 2
+                 || i.tm.extension_opcode == 3
+                 || i.tm.extension_opcode == 6
+                 || i.tm.extension_opcode == 7))
+           return 0;
+
+         /* Skip fisttp, fist, fistp, fbstp, fistp.  */
+         if (i.tm.base_opcode == 0xdf
+             && (i.tm.extension_opcode == 1
+                 || i.tm.extension_opcode == 2
+                 || i.tm.extension_opcode == 3
+                 || i.tm.extension_opcode == 6
+                 || i.tm.extension_opcode == 7))
+           return 0;
+
+         return 1;
+       }
+    }
+
+  dest = i.operands - 1;
+
+  /* Check fake imm8 operand and 3 source operands.  */
+  if ((i.tm.opcode_modifier.immext
+       || i.tm.opcode_modifier.vexsources == VEX3SOURCES)
+      && i.types[dest].bitfield.imm8)
+    dest--;
+
+  /* add, or, adc, sbb, and, sub, xor, cmp, test, xchg, xadd  */
+  if (!any_vex_p
+      && (base_opcode == 0x1
+         || base_opcode == 0x9
+         || base_opcode == 0x11
+         || base_opcode == 0x19
+         || base_opcode == 0x21
+         || base_opcode == 0x29
+         || base_opcode == 0x31
+         || base_opcode == 0x39
+         || (i.tm.base_opcode >= 0x84 && i.tm.base_opcode <= 0x87)
+         || base_opcode == 0xfc1))
+    return 1;
+
+  /* Check for load instruction.  */
+  return (i.types[dest].bitfield.class != ClassNone
+         || i.types[dest].bitfield.instance == Accum);
+}
+
+/* Output lfence, 0xfaee8, after instruction.  */
+
+static void
+insert_lfence_after (void)
+{
+  if (lfence_after_load && load_insn_p ())
+    {
+      char *p = frag_more (3);
+      *p++ = 0xf;
+      *p++ = 0xae;
+      *p = 0xe8;
+    }
+}
+
+/* Output lfence, 0xfaee8, before instruction.  */
+
+static void
+insert_lfence_before (void)
+{
+  char *p;
+
+  if (is_any_vex_encoding (&i.tm))
+    return;
+
+  if (i.tm.base_opcode == 0xff
+      && (i.tm.extension_opcode == 2 || i.tm.extension_opcode == 4))
+    {
+      /* Insert lfence before indirect branch if needed.  */
+
+      if (lfence_before_indirect_branch == lfence_branch_none)
+       return;
+
+      if (i.operands != 1)
+       abort ();
+
+      if (i.reg_operands == 1)
+       {
+         /* Indirect branch via register.  Don't insert lfence with
+            -mlfence-after-load=yes.  */
+         if (lfence_after_load
+             || lfence_before_indirect_branch == lfence_branch_memory)
+           return;
+       }
+      else if (i.mem_operands == 1
+              && lfence_before_indirect_branch != lfence_branch_register)
+       {
+         as_warn (_("indirect `%s` with memory operand should be avoided"),
+                  i.tm.name);
+         return;
+       }
+      else
+       return;
+
+      if (last_insn.kind != last_insn_other
+         && last_insn.seg == now_seg)
+       {
+         as_warn_where (last_insn.file, last_insn.line,
+                        _("`%s` skips -mlfence-before-indirect-branch on `%s`"),
+                        last_insn.name, i.tm.name);
+         return;
+       }
+
+      p = frag_more (3);
+      *p++ = 0xf;
+      *p++ = 0xae;
+      *p = 0xe8;
+      return;
+    }
+
+  /* Output or/not and lfence before ret.  */
+  if (lfence_before_ret != lfence_before_ret_none
+      && (i.tm.base_opcode == 0xc2
+         || i.tm.base_opcode == 0xc3
+         || i.tm.base_opcode == 0xca
+         || i.tm.base_opcode == 0xcb))
+    {
+      if (last_insn.kind != last_insn_other
+         && last_insn.seg == now_seg)
+       {
+         as_warn_where (last_insn.file, last_insn.line,
+                        _("`%s` skips -mlfence-before-ret on `%s`"),
+                        last_insn.name, i.tm.name);
+         return;
+       }
+      if (lfence_before_ret == lfence_before_ret_or)
+       {
+         /* orl: 0x830c2400.  */
+         p = frag_more ((flag_code == CODE_64BIT ? 1 : 0) + 4 + 3);
+         if (flag_code == CODE_64BIT)
+           *p++ = 0x48;
+         *p++ = 0x83;
+         *p++ = 0xc;
+         *p++ = 0x24;
+         *p++ = 0x0;
+       }
+      else
+       {
+         p = frag_more ((flag_code == CODE_64BIT ? 2 : 0) + 6 + 3);
+         /* notl: 0xf71424.  */
+         if (flag_code == CODE_64BIT)
+           *p++ = 0x48;
+         *p++ = 0xf7;
+         *p++ = 0x14;
+         *p++ = 0x24;
+         /* notl: 0xf71424.  */
+         if (flag_code == CODE_64BIT)
+           *p++ = 0x48;
+         *p++ = 0xf7;
+         *p++ = 0x14;
+         *p++ = 0x24;
+       }
+      *p++ = 0xf;
+      *p++ = 0xae;
+      *p = 0xe8;
+    }
+}
+
 /* This is the guts of the machine-dependent assembler.  LINE points to a
    machine dependent instruction.  This function is supposed to emit
    the frags/bytes it assembles to.  */
@@ -4320,14 +4651,19 @@ md_assemble (char *line)
   /* Now we've parsed the mnemonic into a set of templates, and have the
      operands at hand.  */
 
-  /* All intel opcodes have reversed operands except for "bound" and
-     "enter".  We also don't reverse intersegment "jmp" and "call"
-     instructions with 2 immediate operands so that the immediate segment
-     precedes the offset, as it does when in AT&T mode. */
+  /* All Intel opcodes have reversed operands except for "bound", "enter",
+     "monitor*", "mwait*", "tpause", and "umwait".  We also don't reverse
+     intersegment "jmp" and "call" instructions with 2 immediate operands so
+     that the immediate segment precedes the offset, as it does when in AT&T
+     mode.  */
   if (intel_syntax
       && i.operands > 1
       && (strcmp (mnemonic, "bound") != 0)
       && (strcmp (mnemonic, "invlpga") != 0)
+      && (strncmp (mnemonic, "monitor", 7) != 0)
+      && (strncmp (mnemonic, "mwait", 5) != 0)
+      && (strcmp (mnemonic, "tpause") != 0)
+      && (strcmp (mnemonic, "umwait") != 0)
       && !(operand_type_check (i.types[0], imm)
           && operand_type_check (i.types[1], imm)))
     swap_operands ();
@@ -4378,22 +4714,6 @@ md_assemble (char *line)
        : as_bad) (_("SSE instruction `%s' is used"), i.tm.name);
     }
 
-  /* Zap movzx and movsx suffix.  The suffix has been set from
-     "word ptr" or "byte ptr" on the source operand in Intel syntax
-     or extracted from mnemonic in AT&T syntax.  But we'll use
-     the destination register to choose the suffix for encoding.  */
-  if ((i.tm.base_opcode & ~9) == 0x0fb6)
-    {
-      /* In Intel syntax, there must be a suffix.  In AT&T syntax, if
-        there is no suffix, the default will be byte extension.  */
-      if (i.reg_operands != 2
-         && !i.suffix
-         && intel_syntax)
-       as_bad (_("ambiguous operand size for `%s'"), i.tm.name);
-
-      i.suffix = 0;
-    }
-
   if (i.tm.opcode_modifier.fwait)
     if (!add_prefix (FWAIT_OPCODE))
       return;
@@ -4549,9 +4869,6 @@ md_assemble (char *line)
       i.op[0].disps->X_op = O_symbol;
     }
 
-  if (i.tm.opcode_modifier.rex64)
-    i.rex |= REX_W;
-
   /* For 8 bit registers we need an empty rex prefix.  Also if the
      instruction already has a prefix, we need to convert old
      registers to new ones.  */
@@ -4613,9 +4930,13 @@ md_assemble (char *line)
   if (i.rex != 0)
     add_prefix (REX_OPCODE | i.rex);
 
+  insert_lfence_before ();
+
   /* We are ready to output the insn.  */
   output_insn ();
 
+  insert_lfence_after ();
+
   last_insn.seg = now_seg;
 
   if (i.tm.opcode_modifier.isprefix)
@@ -4800,7 +5121,7 @@ parse_insn (char *line, char *mnemonic)
 
   if (!current_templates)
     {
-check_suffix:
+    check_suffix:
       if (mnem_p > mnemonic)
        {
          /* See if we can get a match by trimming off a suffix.  */
@@ -5368,7 +5689,6 @@ check_VecOperands (const insn_template *t)
 {
   unsigned int op;
   i386_cpu_flags cpu;
-  static const i386_cpu_flags avx512 = CPU_ANY_AVX512F_FLAGS;
 
   /* Templates allowing for ZMMword as well as YMMword and/or XMMword for
      any one operand are implicity requiring AVX512VL support if the actual
@@ -5519,6 +5839,16 @@ check_VecOperands (const insn_template *t)
        }
 
       overlap = operand_type_and (type, t->operand_types[op]);
+      if (t->operand_types[op].bitfield.class == RegSIMD
+         && t->operand_types[op].bitfield.byte
+            + t->operand_types[op].bitfield.word
+            + t->operand_types[op].bitfield.dword
+            + t->operand_types[op].bitfield.qword > 1)
+       {
+         overlap.bitfield.xmmword = 0;
+         overlap.bitfield.ymmword = 0;
+         overlap.bitfield.zmmword = 0;
+       }
       if (operand_type_all_zero (&overlap))
          goto bad_broadcast;
 
@@ -5805,14 +6135,32 @@ match_template (char mnem_suffix)
       if (intel_mnemonic && t->opcode_modifier.attmnemonic)
        continue;
 
-      /* Check AT&T/Intel syntax and Intel64/AMD64 ISA.   */
+      /* Check AT&T/Intel syntax.  */
       i.error = unsupported_syntax;
       if ((intel_syntax && t->opcode_modifier.attsyntax)
-         || (!intel_syntax && t->opcode_modifier.intelsyntax)
-         || (intel64 && t->opcode_modifier.amd64)
-         || (!intel64 && t->opcode_modifier.intel64))
+         || (!intel_syntax && t->opcode_modifier.intelsyntax))
        continue;
 
+      /* Check Intel64/AMD64 ISA.   */
+      switch (isa64)
+       {
+       default:
+         /* Default: Don't accept Intel64.  */
+         if (t->opcode_modifier.isa64 == INTEL64)
+           continue;
+         break;
+       case amd64:
+         /* -mamd64: Don't accept Intel64 and Intel64 only.  */
+         if (t->opcode_modifier.isa64 >= INTEL64)
+           continue;
+         break;
+       case intel64:
+         /* -mintel64: Don't accept AMD64.  */
+         if (t->opcode_modifier.isa64 == AMD64 && flag_code == CODE_64BIT)
+           continue;
+         break;
+       }
+
       /* Check the suffix.  */
       i.error = invalid_instruction_suffix;
       if ((t->opcode_modifier.no_bsuf && suffix_check.no_bsuf)
@@ -5842,43 +6190,34 @@ match_template (char mnem_suffix)
       for (j = 0; j < MAX_OPERANDS; j++)
        operand_types[j] = t->operand_types[j];
 
-      /* In general, don't allow 64-bit operands in 32-bit mode.  */
-      if (i.suffix == QWORD_MNEM_SUFFIX
-         && flag_code != CODE_64BIT
+      /* In general, don't allow
+        - 64-bit operands outside of 64-bit mode,
+        - 32-bit operands on pre-386.  */
+      j = i.imm_operands + (t->operands > i.imm_operands + 1);
+      if (((i.suffix == QWORD_MNEM_SUFFIX
+           && flag_code != CODE_64BIT
+           && (t->base_opcode != 0x0fc7
+               || t->extension_opcode != 1 /* cmpxchg8b */))
+          || (i.suffix == LONG_MNEM_SUFFIX
+              && !cpu_arch_flags.bitfield.cpui386))
          && (intel_syntax
-             ? (!t->opcode_modifier.ignoresize
-                && !t->opcode_modifier.broadcast
+             ? (t->opcode_modifier.mnemonicsize != IGNORESIZE
                 && !intel_float_operand (t->name))
              : intel_float_operand (t->name) != 2)
-         && ((operand_types[0].bitfield.class != RegMMX
-              && operand_types[0].bitfield.class != RegSIMD)
-             || (operand_types[t->operands > 1].bitfield.class != RegMMX
-                 && operand_types[t->operands > 1].bitfield.class != RegSIMD))
-         && (t->base_opcode != 0x0fc7
-             || t->extension_opcode != 1 /* cmpxchg8b */))
-       continue;
-
-      /* In general, don't allow 32-bit operands on pre-386.  */
-      else if (i.suffix == LONG_MNEM_SUFFIX
-              && !cpu_arch_flags.bitfield.cpui386
-              && (intel_syntax
-                  ? (!t->opcode_modifier.ignoresize
-                     && !intel_float_operand (t->name))
-                  : intel_float_operand (t->name) != 2)
-              && ((operand_types[0].bitfield.class != RegMMX
-                   && operand_types[0].bitfield.class != RegSIMD)
-                  || (operand_types[t->operands > 1].bitfield.class != RegMMX
-                      && operand_types[t->operands > 1].bitfield.class
-                         != RegSIMD)))
+         && (t->operands == i.imm_operands
+             || (operand_types[i.imm_operands].bitfield.class != RegMMX
+              && operand_types[i.imm_operands].bitfield.class != RegSIMD
+              && operand_types[i.imm_operands].bitfield.class != RegMask)
+             || (operand_types[j].bitfield.class != RegMMX
+                 && operand_types[j].bitfield.class != RegSIMD
+                 && operand_types[j].bitfield.class != RegMask))
+         && !t->opcode_modifier.vecsib)
        continue;
 
       /* Do not verify operands when there are none.  */
-      else
-       {
-         if (!t->operands)
-           /* We've found a match; break out of loop.  */
-           break;
-       }
+      if (!t->operands)
+       /* We've found a match; break out of loop.  */
+       break;
 
       if (!t->opcode_modifier.jump
          || t->opcode_modifier.jump == JUMP_ABSOLUTE)
@@ -6021,7 +6360,7 @@ match_template (char mnem_suffix)
              if (!t->opcode_modifier.d)
                continue;
 
-check_reverse:
+           check_reverse:
              if (!(size_match & MATCH_REVERSE))
                continue;
              /* Try reversing direction of operands.  */
@@ -6217,7 +6556,7 @@ check_reverse:
        as_warn (_("indirect %s without `*'"), t->name);
 
       if (t->opcode_modifier.isprefix
-         && t->opcode_modifier.ignoresize)
+         && t->opcode_modifier.mnemonicsize == IGNORESIZE)
        {
          /* Warn them that a data or address size prefix doesn't
             affect assembly of the next line of code.  */
@@ -6291,8 +6630,23 @@ process_suffix (void)
   else if (i.tm.opcode_modifier.size == SIZE64)
     i.suffix = QWORD_MNEM_SUFFIX;
   else if (i.reg_operands
-          && (i.operands > 1 || i.types[0].bitfield.class == Reg))
+          && (i.operands > 1 || i.types[0].bitfield.class == Reg)
+          && !i.tm.opcode_modifier.addrprefixopreg)
     {
+      unsigned int numop = i.operands;
+
+      /* movsx/movzx want only their source operand considered here, for the
+        ambiguity checking below.  The suffix will be replaced afterwards
+        to represent the destination (register).  */
+      if (((i.tm.base_opcode | 8) == 0xfbe && i.tm.opcode_modifier.w)
+         || (i.tm.base_opcode == 0x63 && i.tm.cpu_flags.bitfield.cpu64))
+       --i.operands;
+
+      /* crc32 needs REX.W set regardless of suffix / source operand size.  */
+      if (i.tm.base_opcode == 0xf20f38f0
+          && i.tm.operand_types[1].bitfield.qword)
+        i.rex |= REX_W;
+
       /* If there's no instruction mnemonic suffix we try to invent one
         based on GPR operands.  */
       if (!i.suffix)
@@ -6321,11 +6675,17 @@ process_suffix (void)
                  continue;
                break;
              }
+
+         /* As an exception, movsx/movzx silently default to a byte source
+            in AT&T mode.  */
+         if ((i.tm.base_opcode | 8) == 0xfbe && i.tm.opcode_modifier.w
+             && !i.suffix && !intel_syntax)
+           i.suffix = BYTE_MNEM_SUFFIX;
        }
       else if (i.suffix == BYTE_MNEM_SUFFIX)
        {
          if (intel_syntax
-             && i.tm.opcode_modifier.ignoresize
+             && i.tm.opcode_modifier.mnemonicsize == IGNORESIZE
              && i.tm.opcode_modifier.no_bsuf)
            i.suffix = 0;
          else if (!check_byte_reg ())
@@ -6334,7 +6694,7 @@ process_suffix (void)
       else if (i.suffix == LONG_MNEM_SUFFIX)
        {
          if (intel_syntax
-             && i.tm.opcode_modifier.ignoresize
+             && i.tm.opcode_modifier.mnemonicsize == IGNORESIZE
              && i.tm.opcode_modifier.no_lsuf
              && !i.tm.opcode_modifier.todword
              && !i.tm.opcode_modifier.toqword)
@@ -6345,7 +6705,7 @@ process_suffix (void)
       else if (i.suffix == QWORD_MNEM_SUFFIX)
        {
          if (intel_syntax
-             && i.tm.opcode_modifier.ignoresize
+             && i.tm.opcode_modifier.mnemonicsize == IGNORESIZE
              && i.tm.opcode_modifier.no_qsuf
              && !i.tm.opcode_modifier.todword
              && !i.tm.opcode_modifier.toqword)
@@ -6356,22 +6716,24 @@ process_suffix (void)
       else if (i.suffix == WORD_MNEM_SUFFIX)
        {
          if (intel_syntax
-             && i.tm.opcode_modifier.ignoresize
+             && i.tm.opcode_modifier.mnemonicsize == IGNORESIZE
              && i.tm.opcode_modifier.no_wsuf)
            i.suffix = 0;
          else if (!check_word_reg ())
            return 0;
        }
-      else if (intel_syntax && i.tm.opcode_modifier.ignoresize)
+      else if (intel_syntax
+              && i.tm.opcode_modifier.mnemonicsize == IGNORESIZE)
        /* Do nothing if the instruction is going to ignore the prefix.  */
        ;
       else
        abort ();
+
+      /* Undo the movsx/movzx change done above.  */
+      i.operands = numop;
     }
-  else if (i.tm.opcode_modifier.defaultsize
-          && !i.suffix
-          /* exclude fldenv/frstor/fsave/fstenv */
-          && i.tm.opcode_modifier.no_ssuf)
+  else if (i.tm.opcode_modifier.mnemonicsize == DEFAULTSIZE
+          && !i.suffix)
     {
       i.suffix = stackop_size;
       if (stackop_size == LONG_MNEM_SUFFIX)
@@ -6420,10 +6782,16 @@ process_suffix (void)
     }
 
   if (!i.suffix
-      && !i.tm.opcode_modifier.defaultsize
-      && !i.tm.opcode_modifier.ignoresize)
+      && (i.tm.opcode_modifier.mnemonicsize != DEFAULTSIZE
+         /* Also cover lret/retf/iret in 64-bit mode.  */
+         || (flag_code == CODE_64BIT
+             && !i.tm.opcode_modifier.no_lsuf
+             && !i.tm.opcode_modifier.no_qsuf))
+      && i.tm.opcode_modifier.mnemonicsize != IGNORESIZE
+      /* Accept FLDENV et al without suffix.  */
+      && (i.tm.opcode_modifier.no_ssuf || i.tm.opcode_modifier.floatmf))
     {
-      unsigned int suffixes;
+      unsigned int suffixes, evex = 0;
 
       suffixes = !i.tm.opcode_modifier.no_bsuf;
       if (!i.tm.opcode_modifier.no_wsuf)
@@ -6437,10 +6805,63 @@ process_suffix (void)
       if (flag_code == CODE_64BIT && !i.tm.opcode_modifier.no_qsuf)
        suffixes |= 1 << 5;
 
-      /* Are multiple suffixes allowed?  */
+      /* For [XYZ]MMWORD operands inspect operand sizes.  While generally
+        also suitable for AT&T syntax mode, it was requested that this be
+        restricted to just Intel syntax.  */
+      if (intel_syntax && is_any_vex_encoding (&i.tm) && !i.broadcast)
+       {
+         unsigned int op;
+
+         for (op = 0; op < i.tm.operands; ++op)
+           {
+             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;
+                 if (i.tm.operand_types[op].bitfield.zmmword)
+                   i.tm.operand_types[op].bitfield.ymmword = 0;
+                 if (!i.tm.opcode_modifier.evex
+                     || i.tm.opcode_modifier.evex == EVEXDYN)
+                   i.tm.opcode_modifier.evex = EVEX512;
+               }
+
+             if (i.tm.operand_types[op].bitfield.xmmword
+                 + i.tm.operand_types[op].bitfield.ymmword
+                 + i.tm.operand_types[op].bitfield.zmmword < 2)
+               continue;
+
+             /* Any properly sized operand disambiguates the insn.  */
+             if (i.types[op].bitfield.xmmword
+                 || i.types[op].bitfield.ymmword
+                 || i.types[op].bitfield.zmmword)
+               {
+                 suffixes &= ~(7 << 6);
+                 evex = 0;
+                 break;
+               }
+
+             if ((i.flags[op] & Operand_Mem)
+                 && i.tm.operand_types[op].bitfield.unspecified)
+               {
+                 if (i.tm.operand_types[op].bitfield.xmmword)
+                   suffixes |= 1 << 6;
+                 if (i.tm.operand_types[op].bitfield.ymmword)
+                   suffixes |= 1 << 7;
+                 if (i.tm.operand_types[op].bitfield.zmmword)
+                   suffixes |= 1 << 8;
+                 if (is_evex_encoding (&i.tm))
+                   evex = EVEX512;
+               }
+           }
+       }
+
+      /* Are multiple suffixes / operand sizes allowed?  */
       if (suffixes & (suffixes - 1))
        {
-         if (intel_syntax)
+         if (intel_syntax
+             && (i.tm.opcode_modifier.mnemonicsize != DEFAULTSIZE
+                 || operand_check == check_error))
            {
              as_bad (_("ambiguous operand size for `%s'"), i.tm.name);
              return 0;
@@ -6452,12 +6873,21 @@ process_suffix (void)
              return 0;
            }
          if (operand_check == check_warning)
-           as_warn (_("no instruction mnemonic suffix given and "
-                      "no register operands; using default for `%s'"),
-                    i.tm.name);
+           as_warn (_("%s; using default for `%s'"),
+                      intel_syntax
+                      ? _("ambiguous operand size")
+                      : _("no instruction mnemonic suffix given and "
+                          "no register operands"),
+                      i.tm.name);
 
          if (i.tm.opcode_modifier.floatmf)
            i.suffix = SHORT_MNEM_SUFFIX;
+         else if ((i.tm.base_opcode | 8) == 0xfbe
+                  || (i.tm.base_opcode == 0x63
+                      && i.tm.cpu_flags.bitfield.cpu64))
+           /* handled below */;
+         else if (evex)
+           i.tm.opcode_modifier.evex = evex;
          else if (flag_code == CODE_16BIT)
            i.suffix = WORD_MNEM_SUFFIX;
          else if (!i.tm.opcode_modifier.no_lsuf)
@@ -6467,6 +6897,36 @@ process_suffix (void)
        }
     }
 
+  if ((i.tm.base_opcode | 8) == 0xfbe
+      || (i.tm.base_opcode == 0x63 && i.tm.cpu_flags.bitfield.cpu64))
+    {
+      /* In Intel syntax, movsx/movzx must have a "suffix" (checked above).
+        In AT&T syntax, if there is no suffix (warned about above), the default
+        will be byte extension.  */
+      if (i.tm.opcode_modifier.w && i.suffix && i.suffix != BYTE_MNEM_SUFFIX)
+       i.tm.base_opcode |= 1;
+
+      /* For further processing, the suffix should represent the destination
+        (register).  This is already the case when one was used with
+        mov[sz][bw]*, but we need to replace it for mov[sz]x, or if there was
+        no suffix to begin with.  */
+      if (i.tm.opcode_modifier.w || i.tm.base_opcode == 0x63 || !i.suffix)
+       {
+         if (i.types[1].bitfield.word)
+           i.suffix = WORD_MNEM_SUFFIX;
+         else if (i.types[1].bitfield.qword)
+           i.suffix = QWORD_MNEM_SUFFIX;
+         else
+           i.suffix = LONG_MNEM_SUFFIX;
+
+         i.tm.opcode_modifier.w = 0;
+       }
+    }
+
+  if (!i.tm.opcode_modifier.modrm && i.reg_operands && i.tm.operands < 3)
+    i.short_form = (i.tm.operand_types[0].bitfield.class == Reg)
+                  != (i.tm.operand_types[1].bitfield.class == Reg);
+
   /* Change the opcode based on the operand size given by i.suffix.  */
   switch (i.suffix)
     {
@@ -6483,7 +6943,7 @@ process_suffix (void)
       /* It's not a byte, select word/dword operation.  */
       if (i.tm.opcode_modifier.w)
        {
-         if (i.tm.opcode_modifier.shortform)
+         if (i.short_form)
            i.tm.base_opcode |= 8;
          else
            i.tm.base_opcode |= 1;
@@ -6493,28 +6953,13 @@ process_suffix (void)
       /* Now select between word & dword operations via the operand
         size prefix, except for instructions that will ignore this
         prefix anyway.  */
-      if (i.reg_operands > 0
-         && i.types[0].bitfield.class == Reg
-         && i.tm.opcode_modifier.addrprefixopreg
-         && (i.tm.operand_types[0].bitfield.instance == Accum
-             || i.operands == 1))
-       {
-         /* The address size override prefix changes the size of the
-            first operand.  */
-         if ((flag_code == CODE_32BIT
-              && i.op[0].regs->reg_type.bitfield.word)
-             || (flag_code != CODE_32BIT
-                 && i.op[0].regs->reg_type.bitfield.dword))
-           if (!add_prefix (ADDR_PREFIX_OPCODE))
-             return 0;
-       }
-      else if (i.suffix != QWORD_MNEM_SUFFIX
-              && !i.tm.opcode_modifier.ignoresize
-              && !i.tm.opcode_modifier.floatmf
-              && !is_any_vex_encoding (&i.tm)
-              && ((i.suffix == LONG_MNEM_SUFFIX) == (flag_code == CODE_16BIT)
-                  || (flag_code == CODE_64BIT
-                      && i.tm.opcode_modifier.jump == JUMP_BYTE)))
+      if (i.suffix != QWORD_MNEM_SUFFIX
+         && i.tm.opcode_modifier.mnemonicsize != IGNORESIZE
+         && !i.tm.opcode_modifier.floatmf
+         && !is_any_vex_encoding (&i.tm)
+         && ((i.suffix == LONG_MNEM_SUFFIX) == (flag_code == CODE_16BIT)
+             || (flag_code == CODE_64BIT
+                 && i.tm.opcode_modifier.jump == JUMP_BYTE)))
        {
          unsigned int prefix = DATA_PREFIX_OPCODE;
 
@@ -6529,6 +6974,7 @@ process_suffix (void)
       if (i.suffix == QWORD_MNEM_SUFFIX
          && flag_code == CODE_64BIT
          && !i.tm.opcode_modifier.norex64
+         && !i.tm.opcode_modifier.vexw
          /* Special case for xchg %rax,%rax.  It is NOP and doesn't
             need rex64. */
          && ! (i.operands == 2
@@ -6543,39 +6989,70 @@ process_suffix (void)
       break;
     }
 
-  if (i.reg_operands != 0
-      && i.operands > 1
-      && i.tm.opcode_modifier.addrprefixopreg
-      && i.tm.operand_types[0].bitfield.instance != Accum)
+  if (i.tm.opcode_modifier.addrprefixopreg)
     {
-      /* Check invalid register operand when the address size override
-        prefix changes the size of register operands.  */
-      unsigned int op;
-      enum { need_word, need_dword, need_qword } need;
+      gas_assert (!i.suffix);
+      gas_assert (i.reg_operands);
+
+      if (i.tm.operand_types[0].bitfield.instance == Accum
+         || i.operands == 1)
+       {
+         /* The address size override prefix changes the size of the
+            first operand.  */
+         if (flag_code == CODE_64BIT
+             && i.op[0].regs->reg_type.bitfield.word)
+           {
+             as_bad (_("16-bit addressing unavailable for `%s'"),
+                     i.tm.name);
+             return 0;
+           }
 
-      if (flag_code == CODE_32BIT)
-       need = i.prefix[ADDR_PREFIX] ? need_word : need_dword;
+         if ((flag_code == CODE_32BIT
+              ? i.op[0].regs->reg_type.bitfield.word
+              : i.op[0].regs->reg_type.bitfield.dword)
+             && !add_prefix (ADDR_PREFIX_OPCODE))
+           return 0;
+       }
       else
        {
-         if (i.prefix[ADDR_PREFIX])
+         /* Check invalid register operand when the address size override
+            prefix changes the size of register operands.  */
+         unsigned int op;
+         enum { need_word, need_dword, need_qword } need;
+
+         if (flag_code == CODE_32BIT)
+           need = i.prefix[ADDR_PREFIX] ? need_word : need_dword;
+         else if (i.prefix[ADDR_PREFIX])
            need = need_dword;
          else
            need = flag_code == CODE_64BIT ? need_qword : need_word;
-       }
 
-      for (op = 0; op < i.operands; op++)
-       if (i.types[op].bitfield.class == Reg
-           && ((need == need_word
-                && !i.op[op].regs->reg_type.bitfield.word)
-               || (need == need_dword
-                   && !i.op[op].regs->reg_type.bitfield.dword)
-               || (need == need_qword
-                   && !i.op[op].regs->reg_type.bitfield.qword)))
-         {
-           as_bad (_("invalid register operand size for `%s'"),
-                   i.tm.name);
-           return 0;
-         }
+         for (op = 0; op < i.operands; op++)
+           {
+             if (i.types[op].bitfield.class != Reg)
+               continue;
+
+             switch (need)
+               {
+               case need_word:
+                 if (i.op[op].regs->reg_type.bitfield.word)
+                   continue;
+                 break;
+               case need_dword:
+                 if (i.op[op].regs->reg_type.bitfield.dword)
+                   continue;
+                 break;
+               case need_qword:
+                 if (i.op[op].regs->reg_type.bitfield.qword)
+                   continue;
+                 break;
+               }
+
+             as_bad (_("invalid register operand size for `%s'"),
+                     i.tm.name);
+             return 0;
+           }
+       }
     }
 
   return 1;
@@ -6603,31 +7080,10 @@ check_byte_reg (void)
          && i.tm.operand_types[op].bitfield.word)
        continue;
 
-      /* crc32 doesn't generate this warning.  */
-      if (i.tm.base_opcode == 0xf20f38f0)
+      /* crc32 only wants its source operand checked here.  */
+      if (i.tm.base_opcode == 0xf20f38f0 && op)
        continue;
 
-      if ((i.types[op].bitfield.word
-          || i.types[op].bitfield.dword
-          || i.types[op].bitfield.qword)
-         && i.op[op].regs->reg_num < 4
-         /* Prohibit these changes in 64bit mode, since the lowering
-            would be more complicated.  */
-         && flag_code != CODE_64BIT)
-       {
-#if REGISTER_WARNINGS
-         if (!quiet_warnings)
-           as_warn (_("using `%s%s' instead of `%s%s' due to `%c' suffix"),
-                    register_prefix,
-                    (i.op[op].regs + (i.types[op].bitfield.word
-                                      ? REGNAM_AL - REGNAM_AX
-                                      : REGNAM_AL - REGNAM_EAX))->reg_name,
-                    register_prefix,
-                    i.op[op].regs->reg_name,
-                    i.suffix);
-#endif
-         continue;
-       }
       /* Any other register is bad.  */
       if (i.types[op].bitfield.class == Reg
          || i.types[op].bitfield.class == RegMMX
@@ -6672,28 +7128,16 @@ check_long_reg (void)
                i.suffix);
        return 0;
       }
-    /* Warn if the e prefix on a general reg is missing.  */
-    else if ((!quiet_warnings || flag_code == CODE_64BIT)
-            && i.types[op].bitfield.word
+    /* Error if the e prefix on a general reg is missing.  */
+    else if (i.types[op].bitfield.word
             && (i.tm.operand_types[op].bitfield.class == Reg
                 || i.tm.operand_types[op].bitfield.instance == Accum)
             && i.tm.operand_types[op].bitfield.dword)
       {
-       /* Prohibit these changes in the 64bit mode, since the
-          lowering is more complicated.  */
-       if (flag_code == CODE_64BIT)
-         {
-           as_bad (_("incorrect register `%s%s' used with `%c' suffix"),
-                   register_prefix, i.op[op].regs->reg_name,
-                   i.suffix);
-           return 0;
-         }
-#if REGISTER_WARNINGS
-       as_warn (_("using `%s%s' instead of `%s%s' due to `%c' suffix"),
-                register_prefix,
-                (i.op[op].regs + REGNAM_EAX - REGNAM_AX)->reg_name,
-                register_prefix, i.op[op].regs->reg_name, i.suffix);
-#endif
+       as_bad (_("incorrect register `%s%s' used with `%c' suffix"),
+               register_prefix, i.op[op].regs->reg_name,
+               i.suffix);
+       return 0;
       }
     /* Warn if the r prefix on a general reg is present.  */
     else if (i.types[op].bitfield.qword
@@ -6793,29 +7237,17 @@ check_word_reg (void)
                i.suffix);
        return 0;
       }
-    /* Warn if the e or r prefix on a general reg is present.  */
-    else if ((!quiet_warnings || flag_code == CODE_64BIT)
-            && (i.types[op].bitfield.dword
+    /* Error if the e or r prefix on a general reg is present.  */
+    else if ((i.types[op].bitfield.dword
                 || i.types[op].bitfield.qword)
             && (i.tm.operand_types[op].bitfield.class == Reg
                 || i.tm.operand_types[op].bitfield.instance == Accum)
             && i.tm.operand_types[op].bitfield.word)
       {
-       /* Prohibit these changes in the 64bit mode, since the
-          lowering is more complicated.  */
-       if (flag_code == CODE_64BIT)
-         {
-           as_bad (_("incorrect register `%s%s' used with `%c' suffix"),
-                   register_prefix, i.op[op].regs->reg_name,
-                   i.suffix);
-           return 0;
-         }
-#if REGISTER_WARNINGS
-       as_warn (_("using `%s%s' instead of `%s%s' due to `%c' suffix"),
-                register_prefix,
-                (i.op[op].regs + REGNAM_AX - REGNAM_EAX)->reg_name,
-                register_prefix, i.op[op].regs->reg_name, i.suffix);
-#endif
+       as_bad (_("incorrect register `%s%s' used with `%c' suffix"),
+               register_prefix, i.op[op].regs->reg_name,
+               i.suffix);
+       return 0;
       }
   return 1;
 }
@@ -6981,7 +7413,7 @@ process_operands (void)
        }
       else
        {
-duplicate:
+       duplicate:
          i.operands++;
          i.reg_operands++;
          i.tm.operands++;
@@ -7091,7 +7523,7 @@ duplicate:
         on one of their operands, the default segment is ds.  */
       default_seg = &ds;
     }
-  else if (i.tm.opcode_modifier.shortform)
+  else if (i.short_form)
     {
       /* The register or float register operand is in operand
         0 or 1.  */
@@ -7121,17 +7553,27 @@ duplicate:
        }
     }
 
-  if (i.tm.base_opcode == 0x8d /* lea */
-      && i.seg[0]
-      && !quiet_warnings)
-    as_warn (_("segment override on `%s' is ineffectual"), i.tm.name);
+  if ((i.seg[0] || i.prefix[SEG_PREFIX])
+      && i.tm.base_opcode == 0x8d /* lea */
+      && !is_any_vex_encoding(&i.tm))
+    {
+      if (!quiet_warnings)
+       as_warn (_("segment override on `%s' is ineffectual"), i.tm.name);
+      if (optimize)
+       {
+         i.seg[0] = NULL;
+         i.prefix[SEG_PREFIX] = 0;
+       }
+    }
 
   /* If a segment was explicitly specified, and the specified segment
-     is not the default, use an opcode prefix to select it.  If we
-     never figured out what the default segment is, then default_seg
-     will be zero at this point, and the specified segment prefix will
-     always be used.  */
-  if ((i.seg[0]) && (i.seg[0] != default_seg))
+     is neither the default nor the one already recorded from a prefix,
+     use an opcode prefix to select it.  If we never figured out what
+     the default segment is, then default_seg will be zero at this
+     point, and the specified segment prefix will always be used.  */
+  if (i.seg[0]
+      && i.seg[0] != default_seg
+      && i.seg[0]->seg_prefix != i.prefix[SEG_PREFIX])
     {
       if (!add_prefix (i.seg[0]->seg_prefix))
        return 0;
@@ -8270,10 +8712,22 @@ encoding_length (const fragS *start_frag, offsetT start_off,
 }
 
 /* Return 1 for test, and, cmp, add, sub, inc and dec which may
-   be macro-fused with conditional jumps.  */
+   be macro-fused with conditional jumps.
+   NB: If TEST/AND/CMP/ADD/SUB/INC/DEC is of RIP relative address,
+   or is one of the following format:
+
+    cmp m, imm
+    add m, imm
+    sub m, imm
+   test m, imm
+    and m, imm
+    inc m
+    dec m
+
+   it is unfusible.  */
 
 static int
-maybe_fused_with_jcc_p (void)
+maybe_fused_with_jcc_p (enum mf_cmp_kind* mf_cmp_p)
 {
   /* No RIP address.  */
   if (i.base_reg && i.base_reg->reg_num == RegIP)
@@ -8283,36 +8737,54 @@ maybe_fused_with_jcc_p (void)
   if (is_any_vex_encoding (&i.tm))
     return 0;
 
-  /* and, add, sub with destination register.  */
-  if ((i.tm.base_opcode >= 0x20 && i.tm.base_opcode <= 0x25)
-      || i.tm.base_opcode <= 5
+  /* add, sub without add/sub m, imm.  */
+  if (i.tm.base_opcode <= 5
       || (i.tm.base_opcode >= 0x28 && i.tm.base_opcode <= 0x2d)
       || ((i.tm.base_opcode | 3) == 0x83
-         && ((i.tm.extension_opcode | 1) == 0x5
+         && (i.tm.extension_opcode == 0x5
              || i.tm.extension_opcode == 0x0)))
-    return (i.types[1].bitfield.class == Reg
-           || i.types[1].bitfield.instance == Accum);
+    {
+      *mf_cmp_p = mf_cmp_alu_cmp;
+      return !(i.mem_operands && i.imm_operands);
+    }
+
+  /* and without and m, imm.  */
+  if ((i.tm.base_opcode >= 0x20 && i.tm.base_opcode <= 0x25)
+      || ((i.tm.base_opcode | 3) == 0x83
+         && i.tm.extension_opcode == 0x4))
+    {
+      *mf_cmp_p = mf_cmp_test_and;
+      return !(i.mem_operands && i.imm_operands);
+    }
 
-  /* test, cmp with any register.  */
+  /* test without test m imm.  */
   if ((i.tm.base_opcode | 1) == 0x85
       || (i.tm.base_opcode | 1) == 0xa9
       || ((i.tm.base_opcode | 1) == 0xf7
-         && i.tm.extension_opcode == 0)
-      || (i.tm.base_opcode >= 0x38 && i.tm.base_opcode <= 0x3d)
+         && i.tm.extension_opcode == 0))
+    {
+      *mf_cmp_p = mf_cmp_test_and;
+      return !(i.mem_operands && i.imm_operands);
+    }
+
+  /* cmp without cmp m, imm.  */
+  if ((i.tm.base_opcode >= 0x38 && i.tm.base_opcode <= 0x3d)
       || ((i.tm.base_opcode | 3) == 0x83
          && (i.tm.extension_opcode == 0x7)))
-    return (i.types[0].bitfield.class == Reg
-           || i.types[0].bitfield.instance == Accum
-           || i.types[1].bitfield.class == Reg
-           || i.types[1].bitfield.instance == Accum);
+    {
+      *mf_cmp_p = mf_cmp_alu_cmp;
+      return !(i.mem_operands && i.imm_operands);
+    }
 
-  /* inc, dec with any register.   */
+  /* inc, dec without inc/dec m.   */
   if ((i.tm.cpu_flags.bitfield.cpuno64
        && (i.tm.base_opcode | 0xf) == 0x4f)
       || ((i.tm.base_opcode | 1) == 0xff
          && i.tm.extension_opcode <= 0x1))
-    return (i.types[0].bitfield.class == Reg
-           || i.types[0].bitfield.instance == Accum);
+    {
+      *mf_cmp_p = mf_cmp_incdec;
+      return !i.mem_operands;
+    }
 
   return 0;
 }
@@ -8320,7 +8792,7 @@ maybe_fused_with_jcc_p (void)
 /* Return 1 if a FUSED_JCC_PADDING frag should be generated.  */
 
 static int
-add_fused_jcc_padding_frag_p (void)
+add_fused_jcc_padding_frag_p (enum mf_cmp_kind* mf_cmp_p)
 {
   /* NB: Don't work with COND_JUMP86 without i386.  */
   if (!align_branch_power
@@ -8329,7 +8801,7 @@ add_fused_jcc_padding_frag_p (void)
       || !(align_branch & align_branch_fused_bit))
     return 0;
 
-  if (maybe_fused_with_jcc_p ())
+  if (maybe_fused_with_jcc_p (mf_cmp_p))
     {
       if (last_insn.kind == last_insn_other
          || last_insn.seg != now_seg)
@@ -8377,7 +8849,8 @@ add_branch_prefix_frag_p (void)
 /* Return 1 if a BRANCH_PADDING frag should be generated.  */
 
 static int
-add_branch_padding_frag_p (enum align_branch_kind *branch_p)
+add_branch_padding_frag_p (enum align_branch_kind *branch_p,
+                          enum mf_jcc_kind *mf_jcc_p)
 {
   int add_padding;
 
@@ -8399,6 +8872,9 @@ add_branch_padding_frag_p (enum align_branch_kind *branch_p)
        }
       else
        {
+         /* Because J<cc> and JN<cc> share same group in macro-fusible table,
+            igore the lowest bit.  */
+         *mf_jcc_p = (i.tm.base_opcode & 0x0e) >> 1;
          *branch_p = align_branch_jcc;
          if ((align_branch & align_branch_jcc_bit))
            add_padding = 1;
@@ -8469,6 +8945,10 @@ output_insn (void)
   offsetT insn_start_off;
   fragS *fragP = NULL;
   enum align_branch_kind branch = align_branch_none;
+  /* The initializer is arbitrary just to avoid uninitialized error.
+     it's actually either assigned in add_branch_padding_frag_p
+     or never be used.  */
+  enum mf_jcc_kind mf_jcc = mf_jcc_jo;
 
 #if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
   if (IS_ELF && x86_used_note)
@@ -8532,7 +9012,9 @@ output_insn (void)
        x86_feature_2_used |= GNU_PROPERTY_X86_FEATURE_2_X87;
       if (i.has_regmmx
          || i.tm.base_opcode == 0xf77 /* emms */
-         || i.tm.base_opcode == 0xf0e /* femms */)
+         || i.tm.base_opcode == 0xf0e /* femms */
+         || i.tm.base_opcode == 0xf2a /* cvtpi2ps */
+         || i.tm.base_opcode == 0x660f2a /* cvtpi2pd */)
        x86_feature_2_used |= GNU_PROPERTY_X86_FEATURE_2_MMX;
       if (i.has_regxmm)
        x86_feature_2_used |= GNU_PROPERTY_X86_FEATURE_2_XMM;
@@ -8559,7 +9041,7 @@ output_insn (void)
   insn_start_frag = frag_now;
   insn_start_off = frag_now_fix ();
 
-  if (add_branch_padding_frag_p (&branch))
+  if (add_branch_padding_frag_p (&branch, &mf_jcc))
     {
       char *p;
       /* Branch can be 8 bytes.  Leave some room for prefixes.  */
@@ -8580,6 +9062,7 @@ output_insn (void)
                ENCODE_RELAX_STATE (BRANCH_PADDING, 0),
                NULL, 0, p);
 
+      fragP->tc_frag_data.mf_type = mf_jcc;
       fragP->tc_frag_data.branch_type = branch;
       fragP->tc_frag_data.max_bytes = max_branch_padding_size;
     }
@@ -8599,6 +9082,7 @@ output_insn (void)
       unsigned char *q;
       unsigned int j;
       unsigned int prefix;
+      enum mf_cmp_kind mf_cmp;
 
       if (avoid_fence
          && (i.tm.base_opcode == 0xfaee8
@@ -8625,7 +9109,7 @@ output_insn (void)
       if (branch)
        /* Skip if this is a branch.  */
        ;
-      else if (add_fused_jcc_padding_frag_p ())
+      else if (add_fused_jcc_padding_frag_p (&mf_cmp))
        {
          /* Make room for padding.  */
          frag_grow (MAX_FUSED_JCC_PADDING_SIZE);
@@ -8637,6 +9121,7 @@ output_insn (void)
                    ENCODE_RELAX_STATE (FUSED_JCC_PADDING, 0),
                    NULL, 0, p);
 
+         fragP->tc_frag_data.mf_type = mf_cmp;
          fragP->tc_frag_data.branch_type = align_branch_fused;
          fragP->tc_frag_data.max_bytes = MAX_FUSED_JCC_PADDING_SIZE;
        }
@@ -9063,13 +9548,14 @@ output_disp (fragS *insn_start_frag, offsetT insn_start_off)
                          && i.rm.regmem == 5))
                  && (i.rm.mode == 2
                      || (i.rm.mode == 0 && i.rm.regmem == 5))
+                 && !is_any_vex_encoding(&i.tm)
                  && ((i.operands == 1
                       && i.tm.base_opcode == 0xff
                       && (i.rm.reg == 2 || i.rm.reg == 4))
                      || (i.operands == 2
                          && (i.tm.base_opcode == 0x8b
                              || i.tm.base_opcode == 0x85
-                             || (i.tm.base_opcode & 0xc7) == 0x03))))
+                             || (i.tm.base_opcode & ~0x38) == 0x03))))
                {
                  if (object_64bit)
                    {
@@ -9964,7 +10450,7 @@ i386_displacement (char *disp_start, char *disp_end)
          if (t->opcode_modifier.jump
              != current_templates->start->opcode_modifier.jump)
            break;
-         if (t->opcode_modifier.intel64)
+         if ((t->opcode_modifier.isa64 >= INTEL64))
            has_intel64 = TRUE;
        }
       if (t < current_templates->end)
@@ -10183,6 +10669,21 @@ 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
+          /* 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.  */
+          && !i.types[this_operand].bitfield.baseindex)
+    {
+      /* MPX insn memory operands with neither base nor index must be forced
+        to use 32-bit addressing in 16-bit mode.  */
+      addr_mode = CODE_32BIT;
+      i.prefix[ADDR_PREFIX] = ADDR_PREFIX_OPCODE;
+      ++i.prefixes;
+      gas_assert (!i.types[this_operand].bitfield.disp16);
+      gas_assert (!i.types[this_operand].bitfield.disp32);
+    }
   else
     {
       addr_mode = flag_code;
@@ -10297,7 +10798,7 @@ i386_index_check (const char *operand_string)
       else
        return 1;
 
-bad_address:
+    bad_address:
       as_bad (_("`%s' is not a valid %s expression"),
              operand_string, kind);
       return 0;
@@ -10841,6 +11342,42 @@ elf_symbol_resolved_in_segment_p (symbolS *fr_symbol, offsetT fr_var)
 }
 #endif
 
+/* Table 3-2. Macro-Fusible Instructions in Haswell Microarchitecture
+   Note also work for Skylake and Cascadelake.
+---------------------------------------------------------------------
+|   JCC   | ADD/SUB/CMP | INC/DEC | TEST/AND |
+| ------  | ----------- | ------- | -------- |
+|   Jo    |      N      |    N    |     Y    |
+|   Jno   |      N      |    N    |     Y    |
+|  Jc/Jb  |      Y      |    N    |     Y    |
+| Jae/Jnb |      Y      |    N    |     Y    |
+|  Je/Jz  |      Y      |    Y    |     Y    |
+| Jne/Jnz |      Y      |    Y    |     Y    |
+| Jna/Jbe |      Y      |    N    |     Y    |
+| Ja/Jnbe |      Y      |    N    |     Y    |
+|   Js    |      N      |    N    |     Y    |
+|   Jns   |      N      |    N    |     Y    |
+|  Jp/Jpe |      N      |    N    |     Y    |
+| Jnp/Jpo |      N      |    N    |     Y    |
+| Jl/Jnge |      Y      |    Y    |     Y    |
+| Jge/Jnl |      Y      |    Y    |     Y    |
+| Jle/Jng |      Y      |    Y    |     Y    |
+| Jg/Jnle |      Y      |    Y    |     Y    |
+---------------------------------------------------------------------  */
+static int
+i386_macro_fusible_p (enum mf_cmp_kind mf_cmp, enum mf_jcc_kind mf_jcc)
+{
+  if (mf_cmp == mf_cmp_alu_cmp)
+    return ((mf_jcc >= mf_jcc_jc && mf_jcc <= mf_jcc_jna)
+           || mf_jcc == mf_jcc_jl || mf_jcc == mf_jcc_jle);
+  if (mf_cmp == mf_cmp_incdec)
+    return (mf_jcc == mf_jcc_je || mf_jcc == mf_jcc_jl
+           || mf_jcc == mf_jcc_jle);
+  if (mf_cmp == mf_cmp_test_and)
+    return 1;
+  return 0;
+}
+
 /* Return the next non-empty frag.  */
 
 static fragS *
@@ -10860,20 +11397,23 @@ i386_next_non_empty_frag (fragS *fragP)
 /* Return the next jcc frag after BRANCH_PADDING.  */
 
 static fragS *
-i386_next_jcc_frag (fragS *fragP)
+i386_next_fusible_jcc_frag (fragS *maybe_cmp_fragP, fragS *pad_fragP)
 {
-  if (!fragP)
+  fragS *branch_fragP;
+  if (!pad_fragP)
     return NULL;
 
-  if (fragP->fr_type == rs_machine_dependent
-      && (TYPE_FROM_RELAX_STATE (fragP->fr_subtype)
+  if (pad_fragP->fr_type == rs_machine_dependent
+      && (TYPE_FROM_RELAX_STATE (pad_fragP->fr_subtype)
          == BRANCH_PADDING))
     {
-      fragP = i386_next_non_empty_frag (fragP);
-      if (fragP->fr_type != rs_machine_dependent)
+      branch_fragP = i386_next_non_empty_frag (pad_fragP);
+      if (branch_fragP->fr_type != rs_machine_dependent)
        return NULL;
-      if (TYPE_FROM_RELAX_STATE (fragP->fr_subtype) == COND_JUMP)
-       return fragP;
+      if (TYPE_FROM_RELAX_STATE (branch_fragP->fr_subtype) == COND_JUMP
+         && i386_macro_fusible_p (maybe_cmp_fragP->tc_frag_data.mf_type,
+                                  pad_fragP->tc_frag_data.mf_type))
+       return branch_fragP;
     }
 
   return NULL;
@@ -10918,7 +11458,7 @@ i386_classify_machine_dependent_frag (fragS *fragP)
               */
            cmp_fragP = i386_next_non_empty_frag (next_fragP);
            pad_fragP = i386_next_non_empty_frag (cmp_fragP);
-           branch_fragP = i386_next_jcc_frag (pad_fragP);
+           branch_fragP = i386_next_fusible_jcc_frag (next_fragP, pad_fragP);
            if (branch_fragP)
              {
                /* The BRANCH_PADDING frag is merged with the
@@ -12016,6 +12556,9 @@ const char *md_shortopts = "qnO::";
 #define OPTION_MALIGN_BRANCH_PREFIX_SIZE (OPTION_MD_BASE + 28)
 #define OPTION_MALIGN_BRANCH (OPTION_MD_BASE + 29)
 #define OPTION_MBRANCHES_WITH_32B_BOUNDARIES (OPTION_MD_BASE + 30)
+#define OPTION_MLFENCE_AFTER_LOAD (OPTION_MD_BASE + 31)
+#define OPTION_MLFENCE_BEFORE_INDIRECT_BRANCH (OPTION_MD_BASE + 32)
+#define OPTION_MLFENCE_BEFORE_RET (OPTION_MD_BASE + 33)
 
 struct option md_longopts[] =
 {
@@ -12055,6 +12598,10 @@ struct option md_longopts[] =
   {"malign-branch-prefix-size", required_argument, NULL, OPTION_MALIGN_BRANCH_PREFIX_SIZE},
   {"malign-branch", required_argument, NULL, OPTION_MALIGN_BRANCH},
   {"mbranches-within-32B-boundaries", no_argument, NULL, OPTION_MBRANCHES_WITH_32B_BOUNDARIES},
+  {"mlfence-after-load", required_argument, NULL, OPTION_MLFENCE_AFTER_LOAD},
+  {"mlfence-before-indirect-branch", required_argument, NULL,
+   OPTION_MLFENCE_BEFORE_INDIRECT_BRANCH},
+  {"mlfence-before-ret", required_argument, NULL, OPTION_MLFENCE_BEFORE_RET},
   {"mamd64", no_argument, NULL, OPTION_MAMD64},
   {"mintel64", no_argument, NULL, OPTION_MINTEL64},
   {NULL, no_argument, NULL, 0}
@@ -12434,6 +12981,41 @@ md_parse_option (int c, const char *arg)
         as_fatal (_("invalid -mfence-as-lock-add= option: `%s'"), arg);
       break;
 
+    case OPTION_MLFENCE_AFTER_LOAD:
+      if (strcasecmp (arg, "yes") == 0)
+       lfence_after_load = 1;
+      else if (strcasecmp (arg, "no") == 0)
+       lfence_after_load = 0;
+      else
+        as_fatal (_("invalid -mlfence-after-load= option: `%s'"), arg);
+      break;
+
+    case OPTION_MLFENCE_BEFORE_INDIRECT_BRANCH:
+      if (strcasecmp (arg, "all") == 0)
+       lfence_before_indirect_branch = lfence_branch_all;
+      else if (strcasecmp (arg, "memory") == 0)
+       lfence_before_indirect_branch = lfence_branch_memory;
+      else if (strcasecmp (arg, "register") == 0)
+       lfence_before_indirect_branch = lfence_branch_register;
+      else if (strcasecmp (arg, "none") == 0)
+       lfence_before_indirect_branch = lfence_branch_none;
+      else
+        as_fatal (_("invalid -mlfence-before-indirect-branch= option: `%s'"),
+                 arg);
+      break;
+
+    case OPTION_MLFENCE_BEFORE_RET:
+      if (strcasecmp (arg, "or") == 0)
+       lfence_before_ret = lfence_before_ret_or;
+      else if (strcasecmp (arg, "not") == 0)
+       lfence_before_ret = lfence_before_ret_not;
+      else if (strcasecmp (arg, "none") == 0)
+       lfence_before_ret = lfence_before_ret_none;
+      else
+        as_fatal (_("invalid -mlfence-before-ret= option: `%s'"),
+                 arg);
+      break;
+
     case OPTION_MRELAX_RELOCATIONS:
       if (strcasecmp (arg, "yes") == 0)
         generate_relax_relocations = 1;
@@ -12526,11 +13108,11 @@ md_parse_option (int c, const char *arg)
       break;
 
     case OPTION_MAMD64:
-      intel64 = 0;
+      isa64 = amd64;
       break;
 
     case OPTION_MINTEL64:
-      intel64 = 1;
+      isa64 = intel64;
       break;
 
     case 'O':
@@ -12791,6 +13373,15 @@ md_show_usage (FILE *stream)
   -mbranches-within-32B-boundaries\n\
                           align branches within 32 byte boundary\n"));
   fprintf (stream, _("\
+  -mlfence-after-load=[no|yes] (default: no)\n\
+                          generate lfence after load\n"));
+  fprintf (stream, _("\
+  -mlfence-before-indirect-branch=[none|all|register|memory] (default: none)\n\
+                          generate lfence before indirect near branch\n"));
+  fprintf (stream, _("\
+  -mlfence-before-ret=[none|or|not] (default: none)\n\
+                          generate lfence before ret\n"));
+  fprintf (stream, _("\
   -mamd64                 accept only AMD64 ISA [default]\n"));
   fprintf (stream, _("\
   -mintel64               accept only Intel64 ISA\n"));
@@ -13020,6 +13611,16 @@ i386_cons_align (int ignore ATTRIBUTE_UNUSED)
       last_insn.kind = last_insn_directive;
       last_insn.name = "constant directive";
       last_insn.file = as_where (&last_insn.line);
+      if (lfence_before_ret != lfence_before_ret_none)
+       {
+         if (lfence_before_indirect_branch != lfence_branch_none)
+           as_warn (_("constant directive skips -mlfence-before-ret "
+                      "and -mlfence-before-indirect-branch"));
+         else
+           as_warn (_("constant directive skips -mlfence-before-ret"));
+       }
+      else if (lfence_before_indirect_branch != lfence_branch_none)
+       as_warn (_("constant directive skips -mlfence-before-indirect-branch"));
     }
 }
 
This page took 0.045136 seconds and 4 git commands to generate.