]> oss.titaniummirror.com Git - msp430-binutils.git/blobdiff - gas/config/tc-i386.c
Merge commit 'upstream/2.20'
[msp430-binutils.git] / gas / config / tc-i386.c
index 5d53c5aaa11c64262a2301a14006d8109fee2b1a..a8dc7fc879fb1e0e5faf5adf2490b5de154419c1 100644 (file)
@@ -1,6 +1,6 @@
 /* tc-i386.c -- Assemble code for the Intel 80386
    Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
    Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
@@ -33,6 +33,7 @@
 #include "dwarf2dbg.h"
 #include "dw2gencfi.h"
 #include "elf/x86-64.h"
+#include "opcodes/i386-init.h"
 
 #ifndef REGISTER_WARNINGS
 #define REGISTER_WARNINGS 1
 #define INFER_ADDR_PREFIX 1
 #endif
 
-#ifndef SCALE1_WHEN_NO_INDEX
-/* Specifying a scale factor besides 1 when there is no index is
-   futile.  eg. `mov (%ebx,2),%al' does exactly the same as
-   `mov (%ebx),%al'.  To slavishly follow what the programmer
-   specified, set SCALE1_WHEN_NO_INDEX to 0.  */
-#define SCALE1_WHEN_NO_INDEX 1
-#endif
-
 #ifndef DEFAULT_ARCH
 #define DEFAULT_ARCH "i386"
 #endif
 #endif
 #endif
 
+/* Prefixes will be emitted in the order defined below.
+   WAIT_PREFIX must be the first prefix since FWAIT is really is an
+   instruction, and so must come before any prefixes.
+   The preferred prefix order is SEG_PREFIX, ADDR_PREFIX, DATA_PREFIX,
+   LOCKREP_PREFIX.  */
+#define WAIT_PREFIX    0
+#define SEG_PREFIX     1
+#define ADDR_PREFIX    2
+#define DATA_PREFIX    3
+#define LOCKREP_PREFIX 4
+#define REX_PREFIX     5       /* must come last.  */
+#define MAX_PREFIXES   6       /* max prefixes per opcode */
+
+/* we define the syntax here (modulo base,index,scale syntax) */
+#define REGISTER_PREFIX '%'
+#define IMMEDIATE_PREFIX '$'
+#define ABSOLUTE_PREFIX '*'
+
+/* these are the instruction mnemonic suffixes in AT&T syntax or
+   memory operand size in Intel syntax.  */
+#define WORD_MNEM_SUFFIX  'w'
+#define BYTE_MNEM_SUFFIX  'b'
+#define SHORT_MNEM_SUFFIX 's'
+#define LONG_MNEM_SUFFIX  'l'
+#define QWORD_MNEM_SUFFIX  'q'
+#define XMMWORD_MNEM_SUFFIX  'x'
+#define YMMWORD_MNEM_SUFFIX 'y'
+/* Intel Syntax.  Use a non-ascii letter since since it never appears
+   in instructions.  */
+#define LONG_DOUBLE_MNEM_SUFFIX '\1'
+
+#define END_OF_INSN '\0'
+
+/*
+  'templates' is for grouping together 'template' structures for opcodes
+  of the same name.  This is only used for storing the insns in the grand
+  ole hash table of insns.
+  The templates themselves start at START and range up to (but not including)
+  END.
+  */
+typedef struct
+{
+  const insn_template *start;
+  const insn_template *end;
+}
+templates;
+
+/* 386 operand encoding bytes:  see 386 book for details of this.  */
+typedef struct
+{
+  unsigned int regmem; /* codes register or memory operand */
+  unsigned int reg;    /* codes register operand (or extended opcode) */
+  unsigned int mode;   /* how to interpret regmem & reg */
+}
+modrm_byte;
+
+/* x86-64 extension prefix.  */
+typedef int rex_byte;
+
+/* 386 opcode byte to code indirect addressing.  */
+typedef struct
+{
+  unsigned base;
+  unsigned index;
+  unsigned scale;
+}
+sib_byte;
+
+/* x86 arch names, types and features */
+typedef struct
+{
+  const char *name;            /* arch name */
+  enum processor_type type;    /* arch type */
+  i386_cpu_flags flags;                /* cpu feature flags */
+}
+arch_entry;
+
 static void set_code_flag (int);
 static void set_16bit_gcc_code_flag (int);
 static void set_intel_syntax (int);
+static void set_intel_mnemonic (int);
+static void set_allow_index_reg (int);
+static void set_sse_check (int);
 static void set_cpu_arch (int);
 #ifdef TE_PE
 static void pe_directive_secrel (int);
 #endif
 static void signed_cons (int);
 static char *output_invalid (int c);
-static int i386_operand (char *);
+static int i386_finalize_immediate (segT, expressionS *, i386_operand_type,
+                                   const char *);
+static int i386_finalize_displacement (segT, expressionS *, i386_operand_type,
+                                      const char *);
+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 char *parse_insn (char *, char *);
 static char *parse_operands (char *, const char *);
@@ -80,7 +159,7 @@ static void swap_operands (void);
 static void swap_2_operands (int, int);
 static void optimize_imm (void);
 static void optimize_disp (void);
-static int match_template (void);
+static const insn_template *match_template (void);
 static int check_string (void);
 static int process_suffix (void);
 static int check_byte_reg (void);
@@ -102,6 +181,16 @@ static void handle_large_common (int small ATTRIBUTE_UNUSED);
 
 static const char *default_arch = DEFAULT_ARCH;
 
+/* VEX prefix.  */
+typedef struct
+{
+  /* VEX prefix is either 2 byte or 3 byte.  */
+  unsigned char bytes[3];
+  unsigned int length;
+  /* Destination or source register specifier.  */
+  const reg_entry *register_specifier;
+} vex_prefix;
+
 /* 'md_assemble ()' gathers together information and puts it into a
    i386_insn.  */
 
@@ -115,10 +204,10 @@ union i386_op
 struct _i386_insn
   {
     /* TM holds the template for the insn were currently assembling.  */
-    template tm;
+    insn_template tm;
 
-    /* SUFFIX holds the instruction mnemonic suffix if given.
-       (e.g. 'l' for 'movl')  */
+    /* SUFFIX holds the instruction size suffix for byte, word, dword
+       or qword, if given.  */
     char suffix;
 
     /* OPERANDS gives the number of given operands.  */
@@ -131,7 +220,7 @@ struct _i386_insn
 
     /* TYPES [i] is the type (see above #defines) which tells us how to
        use OP[i] for the corresponding operand.  */
-    unsigned int types[MAX_OPERANDS];
+    i386_operand_type types[MAX_OPERANDS];
 
     /* Displacement expression, immediate expression, or register for each
        operand.  */
@@ -161,10 +250,13 @@ struct _i386_insn
 
     /* RM and SIB are the modrm byte and the sib byte where the
        addressing modes of this insn are encoded.  */
-
     modrm_byte rm;
     rex_byte rex;
     sib_byte sib;
+    vex_prefix vex;
+
+    /* Swap operand in encoding.  */
+    unsigned int swap_operand : 1;
   };
 
 typedef struct _i386_insn i386_insn;
@@ -260,7 +352,7 @@ static expressionS disp_expressions[MAX_MEMORY_OPERANDS];
 static expressionS im_expressions[MAX_IMMEDIATE_OPERANDS];
 
 /* Current operand we are working on.  */
-static int this_operand;
+static int this_operand = -1;
 
 /* We support four different modes.  FLAG_CODE variable is used to distinguish
    these.  */
@@ -269,7 +361,6 @@ enum flag_code {
        CODE_32BIT,
        CODE_16BIT,
        CODE_64BIT };
-#define NUM_FLAG_CODE ((int) CODE_64BIT + 1)
 
 static enum flag_code flag_code;
 static unsigned int object_64bit;
@@ -287,9 +378,30 @@ static const char *flag_code_names[] =
    0 if att syntax.  */
 static int intel_syntax = 0;
 
+/* 1 for intel mnemonic,
+   0 if att mnemonic.  */
+static int intel_mnemonic = !SYSV386_COMPAT;
+
+/* 1 if support old (<= 2.8.1) versions of gcc.  */
+static int old_gcc = OLDGCC_COMPAT;
+
+/* 1 if pseudo registers are permitted.  */
+static int allow_pseudo_reg = 0;
+
 /* 1 if register prefix % not required.  */
 static int allow_naked_reg = 0;
 
+/* 1 if pseudo index register, eiz/riz, is allowed .  */
+static int allow_index_reg = 0;
+
+static enum
+  {
+    sse_check_none = 0,
+    sse_check_warning,
+    sse_check_error
+  }
+sse_check;
+
 /* Register prefix used for error message.  */
 static const char *register_prefix = "%";
 
@@ -306,30 +418,33 @@ static int quiet_warnings = 0;
 
 /* CPU name.  */
 static const char *cpu_arch_name = NULL;
-static const char *cpu_sub_arch_name = NULL;
+static char *cpu_sub_arch_name = NULL;
 
 /* CPU feature flags.  */
-static unsigned int cpu_arch_flags = CpuUnknownFlags | CpuNo64;
+static 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;
 
 /* Cpu we are generating instructions for.  */
-static enum processor_type cpu_arch_tune = PROCESSOR_UNKNOWN;
+enum processor_type cpu_arch_tune = PROCESSOR_UNKNOWN;
 
 /* CPU feature flags of cpu we are generating instructions for.  */
-static unsigned int cpu_arch_tune_flags = 0;
+static i386_cpu_flags cpu_arch_tune_flags;
 
 /* CPU instruction set architecture used.  */
-static enum processor_type cpu_arch_isa = PROCESSOR_UNKNOWN;
+enum processor_type cpu_arch_isa = PROCESSOR_UNKNOWN;
 
 /* CPU feature flags of instruction set architecture used.  */
-static unsigned int cpu_arch_isa_flags = 0;
+i386_cpu_flags cpu_arch_isa_flags;
 
 /* If set, conditional jumps are not automatically promoted to handle
    larger than a byte offset.  */
 static unsigned int no_cond_jump_promotion = 0;
 
+/* Encode SSE instructions with VEX prefix.  */
+static unsigned int sse2avx;
+
 /* Pre-defined "_GLOBAL_OFFSET_TABLE_".  */
 static symbolS *GOT_symbol;
 
@@ -420,106 +535,180 @@ const relax_typeS md_relax_table[] =
 
 static const arch_entry cpu_arch[] =
 {
-  {"generic32", PROCESSOR_GENERIC32,
-   Cpu186|Cpu286|Cpu386},
-  {"generic64", PROCESSOR_GENERIC64,
-   Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuP4|CpuMMX
-   |CpuMMX2|CpuSSE|CpuSSE2},
-  {"i8086", PROCESSOR_UNKNOWN,
-   0},
-  {"i186", PROCESSOR_UNKNOWN,
-   Cpu186},
-  {"i286", PROCESSOR_UNKNOWN,
-   Cpu186|Cpu286},
-  {"i386", PROCESSOR_I386,
-   Cpu186|Cpu286|Cpu386},
-  {"i486", PROCESSOR_I486,
-   Cpu186|Cpu286|Cpu386|Cpu486},
-  {"i586", PROCESSOR_PENTIUM,
-   Cpu186|Cpu286|Cpu386|Cpu486|Cpu586},
-  {"i686", PROCESSOR_PENTIUMPRO,
-   Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686},
-  {"pentium", PROCESSOR_PENTIUM,
-   Cpu186|Cpu286|Cpu386|Cpu486|Cpu586},
-  {"pentiumpro",PROCESSOR_PENTIUMPRO,
-   Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686},
-  {"pentiumii",        PROCESSOR_PENTIUMPRO,
-   Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuMMX},
-  {"pentiumiii",PROCESSOR_PENTIUMPRO,
-   Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuMMX|CpuMMX2|CpuSSE},
-  {"pentium4", PROCESSOR_PENTIUM4,
-   Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuP4|CpuMMX
-   |CpuMMX2|CpuSSE|CpuSSE2},
-  {"prescott", PROCESSOR_NOCONA,
-   Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuP4|CpuMMX
-   |CpuMMX2|CpuSSE|CpuSSE2|CpuSSE3},
-  {"nocona", PROCESSOR_NOCONA,
-   Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuP4|CpuMMX
-   |CpuMMX2|CpuSSE|CpuSSE2|CpuSSE3},
-  {"yonah", PROCESSOR_CORE,
-   Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuP4|CpuMMX
-   |CpuMMX2|CpuSSE|CpuSSE2|CpuSSE3},
-  {"core", PROCESSOR_CORE,
-   Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuP4|CpuMMX
-   |CpuMMX2|CpuSSE|CpuSSE2|CpuSSE3},
-  {"merom", PROCESSOR_CORE2,
-   Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuP4|CpuMMX
-   |CpuMMX2|CpuSSE|CpuSSE2|CpuSSE3|CpuSSSE3},
-  {"core2", PROCESSOR_CORE2,
-   Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuP4|CpuMMX
-   |CpuMMX2|CpuSSE|CpuSSE2|CpuSSE3|CpuSSSE3},
-  {"k6", PROCESSOR_K6,
-   Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|CpuK6|CpuMMX},
-  {"k6_2", PROCESSOR_K6,
-   Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|CpuK6|CpuMMX|Cpu3dnow},
-  {"athlon", PROCESSOR_ATHLON,
-   Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuK6
-   |CpuMMX|CpuMMX2|Cpu3dnow|Cpu3dnowA},
-  {"sledgehammer", PROCESSOR_K8,
-   Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuK6
-   |CpuSledgehammer|CpuMMX|CpuMMX2|Cpu3dnow|Cpu3dnowA|CpuSSE|CpuSSE2},
-  {"opteron", PROCESSOR_K8,
-   Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuK6
-   |CpuSledgehammer|CpuMMX|CpuMMX2|Cpu3dnow|Cpu3dnowA|CpuSSE|CpuSSE2},
-  {"k8", PROCESSOR_K8,
-   Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuK6
-   |CpuSledgehammer|CpuMMX|CpuMMX2|Cpu3dnow|Cpu3dnowA|CpuSSE|CpuSSE2},
-  {"amdfam10", PROCESSOR_AMDFAM10,
-   Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuK6|CpuSledgehammer
-   |CpuMMX|CpuMMX2|Cpu3dnow|Cpu3dnowA|CpuSSE|CpuSSE2|CpuSSE3|CpuSSE4a
-   |CpuABM},
-  {".mmx", PROCESSOR_UNKNOWN,
-   CpuMMX},
-  {".sse", PROCESSOR_UNKNOWN,
-   CpuMMX|CpuMMX2|CpuSSE},
-  {".sse2", PROCESSOR_UNKNOWN,
-   CpuMMX|CpuMMX2|CpuSSE|CpuSSE2},
-  {".sse3", PROCESSOR_UNKNOWN,
-   CpuMMX|CpuMMX2|CpuSSE|CpuSSE2|CpuSSE3},
-  {".ssse3", PROCESSOR_UNKNOWN,
-   CpuMMX|CpuMMX2|CpuSSE|CpuSSE2|CpuSSE3|CpuSSSE3},
-  {".sse4.1", PROCESSOR_UNKNOWN,
-   CpuMMX|CpuMMX2|CpuSSE|CpuSSE2|CpuSSE3|CpuSSSE3|CpuSSE4_1},
-  {".sse4.2", PROCESSOR_UNKNOWN,
-   CpuMMX|CpuMMX2|CpuSSE|CpuSSE2|CpuSSE3|CpuSSSE3|CpuSSE4},
-  {".sse4", PROCESSOR_UNKNOWN,
-   CpuMMX|CpuMMX2|CpuSSE|CpuSSE2|CpuSSE3|CpuSSSE3|CpuSSE4},
-  {".3dnow", PROCESSOR_UNKNOWN,
-   CpuMMX|Cpu3dnow},
-  {".3dnowa", PROCESSOR_UNKNOWN,
-   CpuMMX|CpuMMX2|Cpu3dnow|Cpu3dnowA},
-  {".padlock", PROCESSOR_UNKNOWN,
-   CpuPadLock},
-  {".pacifica", PROCESSOR_UNKNOWN,
-   CpuSVME},
-  {".svme", PROCESSOR_UNKNOWN,
-   CpuSVME},
-  {".sse4a", PROCESSOR_UNKNOWN,
-   CpuMMX|CpuMMX2|CpuSSE|CpuSSE2|CpuSSE3|CpuSSE4a},
-  {".abm", PROCESSOR_UNKNOWN,
-   CpuABM}
+  { "generic32", PROCESSOR_GENERIC32,
+    CPU_GENERIC32_FLAGS },
+  { "generic64", PROCESSOR_GENERIC64,
+    CPU_GENERIC64_FLAGS },
+  { "i8086", PROCESSOR_UNKNOWN,
+    CPU_NONE_FLAGS },
+  { "i186", PROCESSOR_UNKNOWN,
+    CPU_I186_FLAGS },
+  { "i286", PROCESSOR_UNKNOWN,
+    CPU_I286_FLAGS },
+  { "i386", PROCESSOR_I386,
+    CPU_I386_FLAGS },
+  { "i486", PROCESSOR_I486,
+    CPU_I486_FLAGS },
+  { "i586", PROCESSOR_PENTIUM,
+    CPU_I586_FLAGS },
+  { "i686", PROCESSOR_PENTIUMPRO,
+    CPU_I686_FLAGS },
+  { "pentium", PROCESSOR_PENTIUM,
+    CPU_I586_FLAGS },
+  { "pentiumpro", PROCESSOR_PENTIUMPRO,
+    CPU_I686_FLAGS },
+  { "pentiumii", PROCESSOR_PENTIUMPRO,
+    CPU_P2_FLAGS },
+  { "pentiumiii",PROCESSOR_PENTIUMPRO,
+    CPU_P3_FLAGS },
+  { "pentium4", PROCESSOR_PENTIUM4,
+    CPU_P4_FLAGS },
+  { "prescott", PROCESSOR_NOCONA,
+    CPU_CORE_FLAGS },
+  { "nocona", PROCESSOR_NOCONA,
+    CPU_NOCONA_FLAGS },
+  { "yonah", PROCESSOR_CORE,
+    CPU_CORE_FLAGS },
+  { "core", PROCESSOR_CORE,
+    CPU_CORE_FLAGS },
+  { "merom", PROCESSOR_CORE2,
+    CPU_CORE2_FLAGS },
+  { "core2", PROCESSOR_CORE2,
+    CPU_CORE2_FLAGS },
+  { "corei7", PROCESSOR_COREI7,
+    CPU_COREI7_FLAGS },
+  { "l1om", PROCESSOR_L1OM,
+    CPU_L1OM_FLAGS },
+  { "k6", PROCESSOR_K6,
+    CPU_K6_FLAGS },
+  { "k6_2", PROCESSOR_K6,
+    CPU_K6_2_FLAGS },
+  { "athlon", PROCESSOR_ATHLON,
+    CPU_ATHLON_FLAGS },
+  { "sledgehammer", PROCESSOR_K8,
+    CPU_K8_FLAGS },
+  { "opteron", PROCESSOR_K8,
+    CPU_K8_FLAGS },
+  { "k8", PROCESSOR_K8,
+    CPU_K8_FLAGS },
+  { "amdfam10", PROCESSOR_AMDFAM10,
+    CPU_AMDFAM10_FLAGS },
+  { ".8087", PROCESSOR_UNKNOWN,
+    CPU_8087_FLAGS },
+  { ".287", PROCESSOR_UNKNOWN,
+    CPU_287_FLAGS },
+  { ".387", PROCESSOR_UNKNOWN,
+    CPU_387_FLAGS },
+  { ".no87", PROCESSOR_UNKNOWN,
+    CPU_ANY87_FLAGS },
+  { ".mmx", PROCESSOR_UNKNOWN,
+    CPU_MMX_FLAGS },
+  { ".nommx", PROCESSOR_UNKNOWN,
+    CPU_3DNOWA_FLAGS },
+  { ".sse", PROCESSOR_UNKNOWN,
+    CPU_SSE_FLAGS },
+  { ".sse2", PROCESSOR_UNKNOWN,
+    CPU_SSE2_FLAGS },
+  { ".sse3", PROCESSOR_UNKNOWN,
+    CPU_SSE3_FLAGS },
+  { ".ssse3", PROCESSOR_UNKNOWN,
+    CPU_SSSE3_FLAGS },
+  { ".sse4.1", PROCESSOR_UNKNOWN,
+    CPU_SSE4_1_FLAGS },
+  { ".sse4.2", PROCESSOR_UNKNOWN,
+    CPU_SSE4_2_FLAGS },
+  { ".sse4", PROCESSOR_UNKNOWN,
+    CPU_SSE4_2_FLAGS },
+  { ".nosse", PROCESSOR_UNKNOWN,
+    CPU_ANY_SSE_FLAGS },
+  { ".avx", PROCESSOR_UNKNOWN,
+    CPU_AVX_FLAGS },
+  { ".noavx", PROCESSOR_UNKNOWN,
+    CPU_ANY_AVX_FLAGS },
+  { ".vmx", PROCESSOR_UNKNOWN,
+    CPU_VMX_FLAGS },
+  { ".smx", PROCESSOR_UNKNOWN,
+    CPU_SMX_FLAGS },
+  { ".xsave", PROCESSOR_UNKNOWN,
+    CPU_XSAVE_FLAGS },
+  { ".aes", PROCESSOR_UNKNOWN,
+    CPU_AES_FLAGS },
+  { ".pclmul", PROCESSOR_UNKNOWN,
+    CPU_PCLMUL_FLAGS },
+  { ".clmul", PROCESSOR_UNKNOWN,
+    CPU_PCLMUL_FLAGS },
+  { ".fma", PROCESSOR_UNKNOWN,
+    CPU_FMA_FLAGS },
+  { ".fma4", PROCESSOR_UNKNOWN,
+    CPU_FMA4_FLAGS },
+  { ".movbe", PROCESSOR_UNKNOWN,
+    CPU_MOVBE_FLAGS },
+  { ".ept", PROCESSOR_UNKNOWN,
+    CPU_EPT_FLAGS },
+  { ".clflush", PROCESSOR_UNKNOWN,
+    CPU_CLFLUSH_FLAGS },
+  { ".syscall", PROCESSOR_UNKNOWN,
+    CPU_SYSCALL_FLAGS },
+  { ".rdtscp", PROCESSOR_UNKNOWN,
+    CPU_RDTSCP_FLAGS },
+  { ".3dnow", PROCESSOR_UNKNOWN,
+    CPU_3DNOW_FLAGS },
+  { ".3dnowa", PROCESSOR_UNKNOWN,
+    CPU_3DNOWA_FLAGS },
+  { ".padlock", PROCESSOR_UNKNOWN,
+    CPU_PADLOCK_FLAGS },
+  { ".pacifica", PROCESSOR_UNKNOWN,
+    CPU_SVME_FLAGS },
+  { ".svme", PROCESSOR_UNKNOWN,
+    CPU_SVME_FLAGS },
+  { ".sse4a", PROCESSOR_UNKNOWN,
+    CPU_SSE4A_FLAGS },
+  { ".abm", PROCESSOR_UNKNOWN,
+    CPU_ABM_FLAGS },
 };
 
+#ifdef I386COFF
+/* Like s_lcomm_internal in gas/read.c but the alignment string
+   is allowed to be optional.  */
+
+static symbolS *
+pe_lcomm_internal (int needs_align, symbolS *symbolP, addressT size)
+{
+  addressT align = 0;
+
+  SKIP_WHITESPACE ();
+
+  if (needs_align
+      && *input_line_pointer == ',')
+    {
+      align = parse_align (needs_align - 1);
+
+      if (align == (addressT) -1)
+       return NULL;
+    }
+  else
+    {
+      if (size >= 8)
+       align = 3;
+      else if (size >= 4)
+       align = 2;
+      else if (size >= 2)
+       align = 1;
+      else
+       align = 0;
+    }
+
+  bss_alloc (symbolP, size, align);
+  return symbolP;
+}
+
+static void
+pe_lcomm (int needs_align)
+{
+  s_comm_internal (needs_align * 2, pe_lcomm_internal);
+}
+#endif
+
 const pseudo_typeS md_pseudo_table[] =
 {
 #if !defined(OBJ_AOUT) && !defined(USE_ALIGN_PTWO)
@@ -530,6 +719,8 @@ const pseudo_typeS md_pseudo_table[] =
   {"arch", set_cpu_arch, 0},
 #ifndef I386COFF
   {"bss", s_bss, 0},
+#else
+  {"lcomm", pe_lcomm, 1},
 #endif
   {"ffloat", float_cons, 'f'},
   {"dfloat", float_cons, 'd'},
@@ -544,6 +735,11 @@ const pseudo_typeS md_pseudo_table[] =
   {"code64", set_code_flag, CODE_64BIT},
   {"intel_syntax", set_intel_syntax, 1},
   {"att_syntax", set_intel_syntax, 0},
+  {"intel_mnemonic", set_intel_mnemonic, 1},
+  {"att_mnemonic", set_intel_mnemonic, 0},
+  {"allow_index_reg", set_allow_index_reg, 1},
+  {"disallow_index_reg", set_allow_index_reg, 0},
+  {"sse_check", set_sse_check, 0},
 #if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
   {"largecomm", handle_large_common, 0},
 #else
@@ -751,8 +947,8 @@ i386_align_code (fragS *fragP, int count)
      1. For PROCESSOR_I386, PROCESSOR_I486, PROCESSOR_PENTIUM and
      PROCESSOR_GENERIC32, f32_patt will be used.
      2. For PROCESSOR_PENTIUMPRO, PROCESSOR_PENTIUM4, PROCESSOR_NOCONA,
-     PROCESSOR_CORE, PROCESSOR_CORE2, and PROCESSOR_GENERIC64,
-     alt_long_patt will be used.
+     PROCESSOR_CORE, PROCESSOR_CORE2, PROCESSOR_COREI7, and
+     PROCESSOR_GENERIC64, alt_long_patt will be used.
      3. For PROCESSOR_ATHLON, PROCESSOR_K6, PROCESSOR_K8 and
      PROCESSOR_AMDFAM10, alt_short_patt will be used.
 
@@ -780,7 +976,7 @@ i386_align_code (fragS *fragP, int count)
     {
       const char *const *patt = NULL;
 
-      if (cpu_arch_isa == PROCESSOR_UNKNOWN)
+      if (fragP->tc_frag_data.isa == PROCESSOR_UNKNOWN)
        {
          /* PROCESSOR_UNKNOWN means that all ISAs may be used.  */
          switch (cpu_arch_tune)
@@ -788,7 +984,7 @@ i386_align_code (fragS *fragP, int count)
            case PROCESSOR_UNKNOWN:
              /* We use cpu_arch_isa_flags to check if we SHOULD
                 optimize for Cpu686.  */
-             if ((cpu_arch_isa_flags & Cpu686) != 0)
+             if (fragP->tc_frag_data.isa_flags.bitfield.cpui686)
                patt = alt_long_patt;
              else
                patt = f32_patt;
@@ -798,6 +994,8 @@ i386_align_code (fragS *fragP, int count)
            case PROCESSOR_NOCONA:
            case PROCESSOR_CORE:
            case PROCESSOR_CORE2:
+           case PROCESSOR_COREI7:
+           case PROCESSOR_L1OM:
            case PROCESSOR_GENERIC64:
              patt = alt_long_patt;
              break;
@@ -817,10 +1015,10 @@ i386_align_code (fragS *fragP, int count)
        }
       else
        {
-         switch (cpu_arch_tune)
+         switch (fragP->tc_frag_data.tune)
            {
            case PROCESSOR_UNKNOWN:
-             /* When cpu_arch_isa is net, cpu_arch_tune shouldn't be
+             /* When cpu_arch_isa is set, cpu_arch_tune shouldn't be
                 PROCESSOR_UNKNOWN.  */
              abort ();
              break;
@@ -835,7 +1033,7 @@ i386_align_code (fragS *fragP, int count)
            case PROCESSOR_GENERIC32:
              /* We use cpu_arch_isa_flags to check if we CAN optimize
                 for Cpu686.  */
-             if ((cpu_arch_isa_flags & Cpu686) != 0)
+             if (fragP->tc_frag_data.isa_flags.bitfield.cpui686)
                patt = alt_short_patt;
              else
                patt = f32_patt;
@@ -845,7 +1043,9 @@ i386_align_code (fragS *fragP, int count)
            case PROCESSOR_NOCONA:
            case PROCESSOR_CORE:
            case PROCESSOR_CORE2:
-             if ((cpu_arch_isa_flags & Cpu686) != 0)
+           case PROCESSOR_COREI7:
+           case PROCESSOR_L1OM:
+             if (fragP->tc_frag_data.isa_flags.bitfield.cpui686)
                patt = alt_long_patt;
              else
                patt = f32_patt;
@@ -860,8 +1060,16 @@ i386_align_code (fragS *fragP, int count)
        {
          /* If the padding is less than 15 bytes, we use the normal
             ones.  Otherwise, we use a jump instruction and adjust
-            its offset.  */
-         if (count < 15)
+            its offset.   */
+         int limit;
+         
+         /* For 64bit, the limit is 3 bytes.  */
+         if (flag_code == CODE_64BIT
+             && fragP->tc_frag_data.isa_flags.bitfield.cpulm)
+           limit = 3;
+         else
+           limit = 15;
+         if (count < limit)
            memcpy (fragP->fr_literal + fragP->fr_fix,
                    patt[count - 1], count);
          else
@@ -893,7002 +1101,7400 @@ i386_align_code (fragS *fragP, int count)
   fragP->fr_var = count;
 }
 
-static INLINE unsigned int
-mode_from_disp_size (unsigned int t)
+static INLINE int
+operand_type_all_zero (const union i386_operand_type *x)
 {
-  return (t & Disp8) ? 1 : (t & (Disp16 | Disp32 | Disp32S)) ? 2 : 0;
+  switch (ARRAY_SIZE(x->array))
+    {
+    case 3:
+      if (x->array[2])
+       return 0;
+    case 2:
+      if (x->array[1])
+       return 0;
+    case 1:
+      return !x->array[0];
+    default:
+      abort ();
+    }
 }
 
-static INLINE int
-fits_in_signed_byte (offsetT num)
+static INLINE void
+operand_type_set (union i386_operand_type *x, unsigned int v)
 {
-  return (num >= -128) && (num <= 127);
+  switch (ARRAY_SIZE(x->array))
+    {
+    case 3:
+      x->array[2] = v;
+    case 2:
+      x->array[1] = v;
+    case 1:
+      x->array[0] = v;
+      break;
+    default:
+      abort ();
+    }
 }
 
 static INLINE int
-fits_in_unsigned_byte (offsetT num)
+operand_type_equal (const union i386_operand_type *x,
+                   const union i386_operand_type *y)
 {
-  return (num & 0xff) == num;
+  switch (ARRAY_SIZE(x->array))
+    {
+    case 3:
+      if (x->array[2] != y->array[2])
+       return 0;
+    case 2:
+      if (x->array[1] != y->array[1])
+       return 0;
+    case 1:
+      return x->array[0] == y->array[0];
+      break;
+    default:
+      abort ();
+    }
 }
 
 static INLINE int
-fits_in_unsigned_word (offsetT num)
+cpu_flags_all_zero (const union i386_cpu_flags *x)
 {
-  return (num & 0xffff) == num;
+  switch (ARRAY_SIZE(x->array))
+    {
+    case 3:
+      if (x->array[2])
+       return 0;
+    case 2:
+      if (x->array[1])
+       return 0;
+    case 1:
+      return !x->array[0];
+    default:
+      abort ();
+    }
 }
 
-static INLINE int
-fits_in_signed_word (offsetT num)
+static INLINE void
+cpu_flags_set (union i386_cpu_flags *x, unsigned int v)
 {
-  return (-32768 <= num) && (num <= 32767);
+  switch (ARRAY_SIZE(x->array))
+    {
+    case 3:
+      x->array[2] = v;
+    case 2:
+      x->array[1] = v;
+    case 1:
+      x->array[0] = v;
+      break;
+    default:
+      abort ();
+    }
 }
 
 static INLINE int
-fits_in_signed_long (offsetT num ATTRIBUTE_UNUSED)
+cpu_flags_equal (const union i386_cpu_flags *x,
+                const union i386_cpu_flags *y)
 {
-#ifndef BFD64
-  return 1;
-#else
-  return (!(((offsetT) -1 << 31) & num)
-         || (((offsetT) -1 << 31) & num) == ((offsetT) -1 << 31));
-#endif
-}                              /* fits_in_signed_long() */
+  switch (ARRAY_SIZE(x->array))
+    {
+    case 3:
+      if (x->array[2] != y->array[2])
+       return 0;
+    case 2:
+      if (x->array[1] != y->array[1])
+       return 0;
+    case 1:
+      return x->array[0] == y->array[0];
+      break;
+    default:
+      abort ();
+    }
+}
 
 static INLINE int
-fits_in_unsigned_long (offsetT num ATTRIBUTE_UNUSED)
+cpu_flags_check_cpu64 (i386_cpu_flags f)
 {
-#ifndef BFD64
-  return 1;
-#else
-  return (num & (((offsetT) 2 << 31) - 1)) == num;
-#endif
-}                              /* fits_in_unsigned_long() */
+  return !((flag_code == CODE_64BIT && f.bitfield.cpuno64)
+          || (flag_code != CODE_64BIT && f.bitfield.cpu64));
+}
 
-static unsigned int
-smallest_imm_type (offsetT num)
+static INLINE i386_cpu_flags
+cpu_flags_and (i386_cpu_flags x, i386_cpu_flags y)
 {
-  if (cpu_arch_flags != (Cpu186 | Cpu286 | Cpu386 | Cpu486 | CpuNo64))
+  switch (ARRAY_SIZE (x.array))
     {
-      /* This code is disabled on the 486 because all the Imm1 forms
-        in the opcode table are slower on the i486.  They're the
-        versions with the implicitly specified single-position
-        displacement, which has another syntax if you really want to
-        use that form.  */
-      if (num == 1)
-       return Imm1 | Imm8 | Imm8S | Imm16 | Imm32 | Imm32S | Imm64;
-    }
-  return (fits_in_signed_byte (num)
-         ? (Imm8S | Imm8 | Imm16 | Imm32 | Imm32S | Imm64)
-         : fits_in_unsigned_byte (num)
-         ? (Imm8 | Imm16 | Imm32 | Imm32S | Imm64)
-         : (fits_in_signed_word (num) || fits_in_unsigned_word (num))
-         ? (Imm16 | Imm32 | Imm32S | Imm64)
-         : fits_in_signed_long (num)
-         ? (Imm32 | Imm32S | Imm64)
-         : fits_in_unsigned_long (num)
-         ? (Imm32 | Imm64)
-         : Imm64);
+    case 3:
+      x.array [2] &= y.array [2];
+    case 2:
+      x.array [1] &= y.array [1];
+    case 1:
+      x.array [0] &= y.array [0];
+      break;
+    default:
+      abort ();
+    }
+  return x;
 }
 
-static offsetT
-offset_in_range (offsetT val, int size)
+static INLINE i386_cpu_flags
+cpu_flags_or (i386_cpu_flags x, i386_cpu_flags y)
 {
-  addressT mask;
-
-  switch (size)
+  switch (ARRAY_SIZE (x.array))
     {
-    case 1: mask = ((addressT) 1 <<  8) - 1; break;
-    case 2: mask = ((addressT) 1 << 16) - 1; break;
-    case 4: mask = ((addressT) 2 << 31) - 1; break;
-#ifdef BFD64
-    case 8: mask = ((addressT) 2 << 63) - 1; break;
-#endif
-    default: abort ();
+    case 3:
+      x.array [2] |= y.array [2];
+    case 2:
+      x.array [1] |= y.array [1];
+    case 1:
+      x.array [0] |= y.array [0];
+      break;
+    default:
+      abort ();
     }
+  return x;
+}
 
-  /* If BFD64, sign extend val.  */
-  if (!use_rela_relocations)
-    if ((val & ~(((addressT) 2 << 31) - 1)) == 0)
-      val = (val ^ ((addressT) 1 << 31)) - ((addressT) 1 << 31);
-
-  if ((val & ~mask) != 0 && (val & ~mask) != ~mask)
+static INLINE i386_cpu_flags
+cpu_flags_and_not (i386_cpu_flags x, i386_cpu_flags y)
+{
+  switch (ARRAY_SIZE (x.array))
     {
-      char buf1[40], buf2[40];
-
-      sprint_value (buf1, val);
-      sprint_value (buf2, val & mask);
-      as_warn (_("%s shortened to %s"), buf1, buf2);
+    case 3:
+      x.array [2] &= ~y.array [2];
+    case 2:
+      x.array [1] &= ~y.array [1];
+    case 1:
+      x.array [0] &= ~y.array [0];
+      break;
+    default:
+      abort ();
     }
-  return val & mask;
+  return x;
 }
 
-/* Returns 0 if attempting to add a prefix where one from the same
-   class already exists, 1 if non rep/repne added, 2 if rep/repne
-   added.  */
+#define CPU_FLAGS_ARCH_MATCH           0x1
+#define CPU_FLAGS_64BIT_MATCH          0x2
+#define CPU_FLAGS_AES_MATCH            0x4
+#define CPU_FLAGS_PCLMUL_MATCH         0x8
+#define CPU_FLAGS_AVX_MATCH           0x10
+
+#define CPU_FLAGS_32BIT_MATCH \
+  (CPU_FLAGS_ARCH_MATCH | CPU_FLAGS_AES_MATCH \
+   | CPU_FLAGS_PCLMUL_MATCH | CPU_FLAGS_AVX_MATCH)
+#define CPU_FLAGS_PERFECT_MATCH \
+  (CPU_FLAGS_32BIT_MATCH | CPU_FLAGS_64BIT_MATCH)
+
+/* Return CPU flags match bits. */
+
 static int
-add_prefix (unsigned int prefix)
+cpu_flags_match (const insn_template *t)
 {
-  int ret = 1;
-  unsigned int q;
+  i386_cpu_flags x = t->cpu_flags;
+  int match = cpu_flags_check_cpu64 (x) ? CPU_FLAGS_64BIT_MATCH : 0;
 
-  if (prefix >= REX_OPCODE && prefix < REX_OPCODE + 16
-      && flag_code == CODE_64BIT)
+  x.bitfield.cpu64 = 0;
+  x.bitfield.cpuno64 = 0;
+
+  if (cpu_flags_all_zero (&x))
     {
-      if ((i.prefix[REX_PREFIX] & prefix & REX_W)
-         || ((i.prefix[REX_PREFIX] & (REX_R | REX_X | REX_B))
-             && (prefix & (REX_R | REX_X | REX_B))))
-       ret = 0;
-      q = REX_PREFIX;
+      /* This instruction is available on all archs.  */
+      match |= CPU_FLAGS_32BIT_MATCH;
     }
   else
     {
-      switch (prefix)
-       {
-       default:
-         abort ();
-
-       case CS_PREFIX_OPCODE:
-       case DS_PREFIX_OPCODE:
-       case ES_PREFIX_OPCODE:
-       case FS_PREFIX_OPCODE:
-       case GS_PREFIX_OPCODE:
-       case SS_PREFIX_OPCODE:
-         q = SEG_PREFIX;
-         break;
-
-       case REPNE_PREFIX_OPCODE:
-       case REPE_PREFIX_OPCODE:
-         ret = 2;
-         /* fall thru */
-       case LOCK_PREFIX_OPCODE:
-         q = LOCKREP_PREFIX;
-         break;
+      /* This instruction is available only on some archs.  */
+      i386_cpu_flags cpu = cpu_arch_flags;
 
-       case FWAIT_OPCODE:
-         q = WAIT_PREFIX;
-         break;
-
-       case ADDR_PREFIX_OPCODE:
-         q = ADDR_PREFIX;
-         break;
-
-       case DATA_PREFIX_OPCODE:
-         q = DATA_PREFIX;
-         break;
+      cpu.bitfield.cpu64 = 0;
+      cpu.bitfield.cpuno64 = 0;
+      cpu = cpu_flags_and (x, cpu);
+      if (!cpu_flags_all_zero (&cpu))
+       {
+         if (x.bitfield.cpuavx)
+           {
+             /* We only need to check AES/PCLMUL/SSE2AVX with AVX.  */
+             if (cpu.bitfield.cpuavx)
+               {
+                 /* Check SSE2AVX.  */
+                 if (!t->opcode_modifier.sse2avx|| sse2avx)
+                   {
+                     match |= (CPU_FLAGS_ARCH_MATCH
+                               | CPU_FLAGS_AVX_MATCH);
+                     /* Check AES.  */
+                     if (!x.bitfield.cpuaes || cpu.bitfield.cpuaes)
+                       match |= CPU_FLAGS_AES_MATCH;
+                     /* Check PCLMUL.  */
+                     if (!x.bitfield.cpupclmul
+                         || cpu.bitfield.cpupclmul)
+                       match |= CPU_FLAGS_PCLMUL_MATCH;
+                   }
+               }
+             else
+               match |= CPU_FLAGS_ARCH_MATCH;
+           }
+         else
+           match |= CPU_FLAGS_32BIT_MATCH;
        }
-      if (i.prefix[q] != 0)
-       ret = 0;
     }
+  return match;
+}
 
-  if (ret)
+static INLINE i386_operand_type
+operand_type_and (i386_operand_type x, i386_operand_type y)
+{
+  switch (ARRAY_SIZE (x.array))
     {
-      if (!i.prefix[q])
-       ++i.prefixes;
-      i.prefix[q] |= prefix;
-    }
-  else
-    as_bad (_("same type of prefix used twice"));
-
-  return ret;
+    case 3:
+      x.array [2] &= y.array [2];
+    case 2:
+      x.array [1] &= y.array [1];
+    case 1:
+      x.array [0] &= y.array [0];
+      break;
+    default:
+      abort ();
+    }
+  return x;
 }
 
-static void
-set_code_flag (int value)
+static INLINE i386_operand_type
+operand_type_or (i386_operand_type x, i386_operand_type y)
 {
-  flag_code = value;
-  cpu_arch_flags &= ~(Cpu64 | CpuNo64);
-  cpu_arch_flags |= (flag_code == CODE_64BIT ? Cpu64 : CpuNo64);
-  if (value == CODE_64BIT && !(cpu_arch_flags & CpuSledgehammer))
-    {
-      as_bad (_("64bit mode not supported on this CPU."));
-    }
-  if (value == CODE_32BIT && !(cpu_arch_flags & Cpu386))
+  switch (ARRAY_SIZE (x.array))
     {
-      as_bad (_("32bit mode not supported on this CPU."));
+    case 3:
+      x.array [2] |= y.array [2];
+    case 2:
+      x.array [1] |= y.array [1];
+    case 1:
+      x.array [0] |= y.array [0];
+      break;
+    default:
+      abort ();
     }
-  stackop_size = '\0';
+  return x;
 }
 
-static void
-set_16bit_gcc_code_flag (int new_code_flag)
+static INLINE i386_operand_type
+operand_type_xor (i386_operand_type x, i386_operand_type y)
 {
-  flag_code = new_code_flag;
-  cpu_arch_flags &= ~(Cpu64 | CpuNo64);
-  cpu_arch_flags |= (flag_code == CODE_64BIT ? Cpu64 : CpuNo64);
-  stackop_size = LONG_MNEM_SUFFIX;
+  switch (ARRAY_SIZE (x.array))
+    {
+    case 3:
+      x.array [2] ^= y.array [2];
+    case 2:
+      x.array [1] ^= y.array [1];
+    case 1:
+      x.array [0] ^= y.array [0];
+      break;
+    default:
+      abort ();
+    }
+  return x;
 }
 
-static void
-set_intel_syntax (int syntax_flag)
+static const i386_operand_type acc32 = OPERAND_TYPE_ACC32;
+static const i386_operand_type acc64 = OPERAND_TYPE_ACC64;
+static const i386_operand_type control = OPERAND_TYPE_CONTROL;
+static const i386_operand_type inoutportreg
+  = OPERAND_TYPE_INOUTPORTREG;
+static const i386_operand_type reg16_inoutportreg
+  = OPERAND_TYPE_REG16_INOUTPORTREG;
+static const i386_operand_type disp16 = OPERAND_TYPE_DISP16;
+static const i386_operand_type disp32 = OPERAND_TYPE_DISP32;
+static const i386_operand_type disp32s = OPERAND_TYPE_DISP32S;
+static const i386_operand_type disp16_32 = OPERAND_TYPE_DISP16_32;
+static const i386_operand_type anydisp
+  = OPERAND_TYPE_ANYDISP;
+static const i386_operand_type regxmm = OPERAND_TYPE_REGXMM;
+static const i386_operand_type regymm = OPERAND_TYPE_REGYMM;
+static const i386_operand_type imm8 = OPERAND_TYPE_IMM8;
+static const i386_operand_type imm8s = OPERAND_TYPE_IMM8S;
+static const i386_operand_type imm16 = OPERAND_TYPE_IMM16;
+static const i386_operand_type imm32 = OPERAND_TYPE_IMM32;
+static const i386_operand_type imm32s = OPERAND_TYPE_IMM32S;
+static const i386_operand_type imm64 = OPERAND_TYPE_IMM64;
+static const i386_operand_type imm16_32 = OPERAND_TYPE_IMM16_32;
+static const i386_operand_type imm16_32s = OPERAND_TYPE_IMM16_32S;
+static const i386_operand_type imm16_32_32s = OPERAND_TYPE_IMM16_32_32S;
+
+enum operand_type
 {
-  /* Find out if register prefixing is specified.  */
-  int ask_naked_reg = 0;
+  reg,
+  imm,
+  disp,
+  anymem
+};
 
-  SKIP_WHITESPACE ();
-  if (!is_end_of_line[(unsigned char) *input_line_pointer])
+static INLINE int
+operand_type_check (i386_operand_type t, enum operand_type c)
+{
+  switch (c)
     {
-      char *string = input_line_pointer;
-      int e = get_symbol_end ();
+    case reg:
+      return (t.bitfield.reg8
+             || t.bitfield.reg16
+             || t.bitfield.reg32
+             || t.bitfield.reg64);
+
+    case imm:
+      return (t.bitfield.imm8
+             || t.bitfield.imm8s
+             || t.bitfield.imm16
+             || t.bitfield.imm32
+             || t.bitfield.imm32s
+             || t.bitfield.imm64);
+
+    case disp:
+      return (t.bitfield.disp8
+             || t.bitfield.disp16
+             || t.bitfield.disp32
+             || t.bitfield.disp32s
+             || t.bitfield.disp64);
+
+    case anymem:
+      return (t.bitfield.disp8
+             || t.bitfield.disp16
+             || t.bitfield.disp32
+             || t.bitfield.disp32s
+             || t.bitfield.disp64
+             || t.bitfield.baseindex);
 
-      if (strcmp (string, "prefix") == 0)
-       ask_naked_reg = 1;
-      else if (strcmp (string, "noprefix") == 0)
-       ask_naked_reg = -1;
-      else
-       as_bad (_("bad argument to syntax directive."));
-      *input_line_pointer = e;
+    default:
+      abort ();
     }
-  demand_empty_rest_of_line ();
 
-  intel_syntax = syntax_flag;
+  return 0;
+}
 
-  if (ask_naked_reg == 0)
-    allow_naked_reg = (intel_syntax
-                      && (bfd_get_symbol_leading_char (stdoutput) != '\0'));
-  else
-    allow_naked_reg = (ask_naked_reg < 0);
+/* Return 1 if there is no conflict in 8bit/16bit/32bit/64bit on
+   operand J for instruction template T.  */
 
-  identifier_chars['%'] = intel_syntax && allow_naked_reg ? '%' : 0;
-  identifier_chars['$'] = intel_syntax ? '$' : 0;
-  register_prefix = allow_naked_reg ? "" : "%";
+static INLINE int
+match_reg_size (const insn_template *t, unsigned int j)
+{
+  return !((i.types[j].bitfield.byte
+           && !t->operand_types[j].bitfield.byte)
+          || (i.types[j].bitfield.word
+              && !t->operand_types[j].bitfield.word)
+          || (i.types[j].bitfield.dword
+              && !t->operand_types[j].bitfield.dword)
+          || (i.types[j].bitfield.qword
+              && !t->operand_types[j].bitfield.qword));
 }
 
-static void
-set_cpu_arch (int dummy ATTRIBUTE_UNUSED)
+/* Return 1 if there is no conflict in any size on operand J for
+   instruction template T.  */
+
+static INLINE int
+match_mem_size (const insn_template *t, unsigned int j)
 {
-  SKIP_WHITESPACE ();
+  return (match_reg_size (t, j)
+         && !((i.types[j].bitfield.unspecified
+               && !t->operand_types[j].bitfield.unspecified)
+              || (i.types[j].bitfield.fword
+                  && !t->operand_types[j].bitfield.fword)
+              || (i.types[j].bitfield.tbyte
+                  && !t->operand_types[j].bitfield.tbyte)
+              || (i.types[j].bitfield.xmmword
+                  && !t->operand_types[j].bitfield.xmmword)
+              || (i.types[j].bitfield.ymmword
+                  && !t->operand_types[j].bitfield.ymmword)));
+}
 
-  if (!is_end_of_line[(unsigned char) *input_line_pointer])
+/* Return 1 if there is no size conflict on any operands for
+   instruction template T.  */
+
+static INLINE int
+operand_size_match (const insn_template *t)
+{
+  unsigned int j;
+  int match = 1;
+
+  /* Don't check jump instructions.  */
+  if (t->opcode_modifier.jump
+      || t->opcode_modifier.jumpbyte
+      || t->opcode_modifier.jumpdword
+      || t->opcode_modifier.jumpintersegment)
+    return match;
+
+  /* Check memory and accumulator operand size.  */
+  for (j = 0; j < i.operands; j++)
     {
-      char *string = input_line_pointer;
-      int e = get_symbol_end ();
-      unsigned int i;
+      if (t->operand_types[j].bitfield.anysize)
+       continue;
 
-      for (i = 0; i < ARRAY_SIZE (cpu_arch); i++)
+      if (t->operand_types[j].bitfield.acc && !match_reg_size (t, j))
        {
-         if (strcmp (string, cpu_arch[i].name) == 0)
-           {
-             if (*string != '.')
-               {
-                 cpu_arch_name = cpu_arch[i].name;
-                 cpu_sub_arch_name = NULL;
-                 cpu_arch_flags = (cpu_arch[i].flags
-                                   | (flag_code == CODE_64BIT
-                                      ? Cpu64 : CpuNo64));
-                 cpu_arch_isa = cpu_arch[i].type;
-                 cpu_arch_isa_flags = cpu_arch[i].flags;
-                 if (!cpu_arch_tune_set)
-                   {
-                     cpu_arch_tune = cpu_arch_isa;
-                     cpu_arch_tune_flags = cpu_arch_isa_flags;
-                   }
-                 break;
-               }
-             if ((cpu_arch_flags | cpu_arch[i].flags) != cpu_arch_flags)
-               {
-                 cpu_sub_arch_name = cpu_arch[i].name;
-                 cpu_arch_flags |= cpu_arch[i].flags;
-               }
-             *input_line_pointer = e;
-             demand_empty_rest_of_line ();
-             return;
-           }
+         match = 0;
+         break;
        }
-      if (i >= ARRAY_SIZE (cpu_arch))
-       as_bad (_("no such architecture: `%s'"), string);
 
-      *input_line_pointer = e;
+      if (i.types[j].bitfield.mem && !match_mem_size (t, j))
+       {
+         match = 0;
+         break;
+       }
     }
-  else
-    as_bad (_("missing cpu architecture"));
 
-  no_cond_jump_promotion = 0;
-  if (*input_line_pointer == ','
-      && !is_end_of_line[(unsigned char) input_line_pointer[1]])
-    {
-      char *string = ++input_line_pointer;
-      int e = get_symbol_end ();
+  if (match
+      || (!t->opcode_modifier.d && !t->opcode_modifier.floatd))
+    return match;
 
-      if (strcmp (string, "nojumps") == 0)
-       no_cond_jump_promotion = 1;
-      else if (strcmp (string, "jumps") == 0)
-       ;
-      else
-       as_bad (_("no such architecture modifier: `%s'"), string);
+  /* Check reverse.  */
+  gas_assert (i.operands == 2);
 
-      *input_line_pointer = e;
+  match = 1;
+  for (j = 0; j < 2; j++)
+    {
+      if (t->operand_types[j].bitfield.acc
+         && !match_reg_size (t, j ? 0 : 1))
+       {
+         match = 0;
+         break;
+       }
+
+      if (i.types[j].bitfield.mem
+         && !match_mem_size (t, j ? 0 : 1))
+       {
+         match = 0;
+         break;
+       }
     }
 
-  demand_empty_rest_of_line ();
+  return match;
 }
 
-unsigned long
-i386_mach ()
+static INLINE int
+operand_type_match (i386_operand_type overlap,
+                   i386_operand_type given)
 {
-  if (!strcmp (default_arch, "x86_64"))
-    return bfd_mach_x86_64;
-  else if (!strcmp (default_arch, "i386"))
-    return bfd_mach_i386_i386;
-  else
-    as_fatal (_("Unknown architecture"));
+  i386_operand_type temp = overlap;
+
+  temp.bitfield.jumpabsolute = 0;
+  temp.bitfield.unspecified = 0;
+  temp.bitfield.byte = 0;
+  temp.bitfield.word = 0;
+  temp.bitfield.dword = 0;
+  temp.bitfield.fword = 0;
+  temp.bitfield.qword = 0;
+  temp.bitfield.tbyte = 0;
+  temp.bitfield.xmmword = 0;
+  temp.bitfield.ymmword = 0;
+  if (operand_type_all_zero (&temp))
+    return 0;
+
+  return (given.bitfield.baseindex == overlap.bitfield.baseindex
+         && given.bitfield.jumpabsolute == overlap.bitfield.jumpabsolute);
 }
-\f
-void
-md_begin ()
-{
-  const char *hash_err;
 
-  /* Initialize op_hash hash table.  */
-  op_hash = hash_new ();
+/* If given types g0 and g1 are registers they must be of the same type
+   unless the expected operand type register overlap is null.
+   Note that Acc in a template matches every size of reg.  */
 
-  {
-    const template *optab;
-    templates *core_optab;
+static INLINE int
+operand_type_register_match (i386_operand_type m0,
+                            i386_operand_type g0,
+                            i386_operand_type t0,
+                            i386_operand_type m1,
+                            i386_operand_type g1,
+                            i386_operand_type t1)
+{
+  if (!operand_type_check (g0, reg))
+    return 1;
 
-    /* Setup for loop.  */
-    optab = i386_optab;
-    core_optab = (templates *) xmalloc (sizeof (templates));
-    core_optab->start = optab;
+  if (!operand_type_check (g1, reg))
+    return 1;
 
-    while (1)
-      {
-       ++optab;
-       if (optab->name == NULL
-           || strcmp (optab->name, (optab - 1)->name) != 0)
-         {
-           /* different name --> ship out current template list;
-              add to hash table; & begin anew.  */
-           core_optab->end = optab;
-           hash_err = hash_insert (op_hash,
-                                   (optab - 1)->name,
-                                   (PTR) core_optab);
-           if (hash_err)
-             {
-               as_fatal (_("Internal Error:  Can't hash %s: %s"),
-                         (optab - 1)->name,
-                         hash_err);
-             }
-           if (optab->name == NULL)
-             break;
-           core_optab = (templates *) xmalloc (sizeof (templates));
-           core_optab->start = optab;
-         }
-      }
-  }
+  if (g0.bitfield.reg8 == g1.bitfield.reg8
+      && g0.bitfield.reg16 == g1.bitfield.reg16
+      && g0.bitfield.reg32 == g1.bitfield.reg32
+      && g0.bitfield.reg64 == g1.bitfield.reg64)
+    return 1;
 
-  /* Initialize reg_hash hash table.  */
-  reg_hash = hash_new ();
-  {
-    const reg_entry *regtab;
-    unsigned int regtab_size = i386_regtab_size;
+  if (m0.bitfield.acc)
+    {
+      t0.bitfield.reg8 = 1;
+      t0.bitfield.reg16 = 1;
+      t0.bitfield.reg32 = 1;
+      t0.bitfield.reg64 = 1;
+    }
 
-    for (regtab = i386_regtab; regtab_size--; regtab++)
-      {
-       hash_err = hash_insert (reg_hash, regtab->reg_name, (PTR) regtab);
-       if (hash_err)
-         as_fatal (_("Internal Error:  Can't hash %s: %s"),
-                   regtab->reg_name,
-                   hash_err);
-      }
-  }
+  if (m1.bitfield.acc)
+    {
+      t1.bitfield.reg8 = 1;
+      t1.bitfield.reg16 = 1;
+      t1.bitfield.reg32 = 1;
+      t1.bitfield.reg64 = 1;
+    }
 
-  /* Fill in lexical tables:  mnemonic_chars, operand_chars.  */
-  {
-    int c;
-    char *p;
+  return (!(t0.bitfield.reg8 & t1.bitfield.reg8)
+         && !(t0.bitfield.reg16 & t1.bitfield.reg16)
+         && !(t0.bitfield.reg32 & t1.bitfield.reg32)
+         && !(t0.bitfield.reg64 & t1.bitfield.reg64));
+}
 
-    for (c = 0; c < 256; c++)
-      {
-       if (ISDIGIT (c))
-         {
-           digit_chars[c] = c;
-           mnemonic_chars[c] = c;
-           register_chars[c] = c;
-           operand_chars[c] = c;
-         }
-       else if (ISLOWER (c))
-         {
-           mnemonic_chars[c] = c;
-           register_chars[c] = c;
-           operand_chars[c] = c;
-         }
-       else if (ISUPPER (c))
-         {
-           mnemonic_chars[c] = TOLOWER (c);
-           register_chars[c] = mnemonic_chars[c];
-           operand_chars[c] = c;
-         }
+static INLINE unsigned int
+mode_from_disp_size (i386_operand_type t)
+{
+  if (t.bitfield.disp8)
+    return 1;
+  else if (t.bitfield.disp16
+          || t.bitfield.disp32
+          || t.bitfield.disp32s)
+    return 2;
+  else
+    return 0;
+}
 
-       if (ISALPHA (c) || ISDIGIT (c))
-         identifier_chars[c] = c;
-       else if (c >= 128)
-         {
-           identifier_chars[c] = c;
-           operand_chars[c] = c;
-         }
-      }
+static INLINE int
+fits_in_signed_byte (offsetT num)
+{
+  return (num >= -128) && (num <= 127);
+}
 
-#ifdef LEX_AT
-    identifier_chars['@'] = '@';
-#endif
-#ifdef LEX_QM
-    identifier_chars['?'] = '?';
-    operand_chars['?'] = '?';
+static INLINE int
+fits_in_unsigned_byte (offsetT num)
+{
+  return (num & 0xff) == num;
+}
+
+static INLINE int
+fits_in_unsigned_word (offsetT num)
+{
+  return (num & 0xffff) == num;
+}
+
+static INLINE int
+fits_in_signed_word (offsetT num)
+{
+  return (-32768 <= num) && (num <= 32767);
+}
+
+static INLINE int
+fits_in_signed_long (offsetT num ATTRIBUTE_UNUSED)
+{
+#ifndef BFD64
+  return 1;
+#else
+  return (!(((offsetT) -1 << 31) & num)
+         || (((offsetT) -1 << 31) & num) == ((offsetT) -1 << 31));
 #endif
-    digit_chars['-'] = '-';
-    mnemonic_chars['-'] = '-';
-    mnemonic_chars['.'] = '.';
-    identifier_chars['_'] = '_';
-    identifier_chars['.'] = '.';
+}                              /* fits_in_signed_long() */
 
-    for (p = operand_special_chars; *p != '\0'; p++)
-      operand_chars[(unsigned char) *p] = *p;
-  }
+static INLINE int
+fits_in_unsigned_long (offsetT num ATTRIBUTE_UNUSED)
+{
+#ifndef BFD64
+  return 1;
+#else
+  return (num & (((offsetT) 2 << 31) - 1)) == num;
+#endif
+}                              /* fits_in_unsigned_long() */
 
-#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
-  if (IS_ELF)
+static i386_operand_type
+smallest_imm_type (offsetT num)
+{
+  i386_operand_type t;
+
+  operand_type_set (&t, 0);
+  t.bitfield.imm64 = 1;
+
+  if (cpu_arch_tune != PROCESSOR_I486 && num == 1)
     {
-      record_alignment (text_section, 2);
-      record_alignment (data_section, 2);
-      record_alignment (bss_section, 2);
+      /* This code is disabled on the 486 because all the Imm1 forms
+        in the opcode table are slower on the i486.  They're the
+        versions with the implicitly specified single-position
+        displacement, which has another syntax if you really want to
+        use that form.  */
+      t.bitfield.imm1 = 1;
+      t.bitfield.imm8 = 1;
+      t.bitfield.imm8s = 1;
+      t.bitfield.imm16 = 1;
+      t.bitfield.imm32 = 1;
+      t.bitfield.imm32s = 1;
     }
-#endif
-
-  if (flag_code == CODE_64BIT)
+  else if (fits_in_signed_byte (num))
     {
-      x86_dwarf2_return_column = 16;
-      x86_cie_data_alignment = -8;
+      t.bitfield.imm8 = 1;
+      t.bitfield.imm8s = 1;
+      t.bitfield.imm16 = 1;
+      t.bitfield.imm32 = 1;
+      t.bitfield.imm32s = 1;
     }
-  else
+  else if (fits_in_unsigned_byte (num))
     {
-      x86_dwarf2_return_column = 8;
-      x86_cie_data_alignment = -4;
+      t.bitfield.imm8 = 1;
+      t.bitfield.imm16 = 1;
+      t.bitfield.imm32 = 1;
+      t.bitfield.imm32s = 1;
+    }
+  else if (fits_in_signed_word (num) || fits_in_unsigned_word (num))
+    {
+      t.bitfield.imm16 = 1;
+      t.bitfield.imm32 = 1;
+      t.bitfield.imm32s = 1;
+    }
+  else if (fits_in_signed_long (num))
+    {
+      t.bitfield.imm32 = 1;
+      t.bitfield.imm32s = 1;
     }
+  else if (fits_in_unsigned_long (num))
+    t.bitfield.imm32 = 1;
+
+  return t;
 }
 
-void
-i386_print_statistics (FILE *file)
+static offsetT
+offset_in_range (offsetT val, int size)
 {
-  hash_print_statistics (file, "i386 opcode", op_hash);
-  hash_print_statistics (file, "i386 register", reg_hash);
-}
-\f
-#ifdef DEBUG386
+  addressT mask;
 
-/* Debugging routines for md_assemble.  */
-static void pte (template *);
-static void pt (unsigned int);
-static void pe (expressionS *);
-static void ps (symbolS *);
+  switch (size)
+    {
+    case 1: mask = ((addressT) 1 <<  8) - 1; break;
+    case 2: mask = ((addressT) 1 << 16) - 1; break;
+    case 4: mask = ((addressT) 2 << 31) - 1; break;
+#ifdef BFD64
+    case 8: mask = ((addressT) 2 << 63) - 1; break;
+#endif
+    default: abort ();
+    }
 
-static void
-pi (char *line, i386_insn *x)
-{
-  unsigned int i;
+  /* If BFD64, sign extend val.  */
+  if (!use_rela_relocations)
+    if ((val & ~(((addressT) 2 << 31) - 1)) == 0)
+      val = (val ^ ((addressT) 1 << 31)) - ((addressT) 1 << 31);
 
-  fprintf (stdout, "%s: template ", line);
-  pte (&x->tm);
-  fprintf (stdout, "  address: base %s  index %s  scale %x\n",
-          x->base_reg ? x->base_reg->reg_name : "none",
-          x->index_reg ? x->index_reg->reg_name : "none",
-          x->log2_scale_factor);
-  fprintf (stdout, "  modrm:  mode %x  reg %x  reg/mem %x\n",
-          x->rm.mode, x->rm.reg, x->rm.regmem);
-  fprintf (stdout, "  sib:  base %x  index %x  scale %x\n",
-          x->sib.base, x->sib.index, x->sib.scale);
-  fprintf (stdout, "  rex: 64bit %x  extX %x  extY %x  extZ %x\n",
-          (x->rex & REX_W) != 0,
-          (x->rex & REX_R) != 0,
-          (x->rex & REX_X) != 0,
-          (x->rex & REX_B) != 0);
-  for (i = 0; i < x->operands; i++)
+  if ((val & ~mask) != 0 && (val & ~mask) != ~mask)
     {
-      fprintf (stdout, "    #%d:  ", i + 1);
-      pt (x->types[i]);
-      fprintf (stdout, "\n");
-      if (x->types[i]
-         & (Reg | SReg2 | SReg3 | Control | Debug | Test | RegMMX | RegXMM))
-       fprintf (stdout, "%s\n", x->op[i].regs->reg_name);
-      if (x->types[i] & Imm)
-       pe (x->op[i].imms);
-      if (x->types[i] & Disp)
-       pe (x->op[i].disps);
+      char buf1[40], buf2[40];
+
+      sprint_value (buf1, val);
+      sprint_value (buf2, val & mask);
+      as_warn (_("%s shortened to %s"), buf1, buf2);
     }
+  return val & mask;
 }
 
-static void
-pte (template *t)
+/* Returns 0 if attempting to add a prefix where one from the same
+   class already exists, 1 if non rep/repne added, 2 if rep/repne
+   added.  */
+static int
+add_prefix (unsigned int prefix)
 {
-  unsigned int i;
-  fprintf (stdout, " %d operands ", t->operands);
-  fprintf (stdout, "opcode %x ", t->base_opcode);
-  if (t->extension_opcode != None)
-    fprintf (stdout, "ext %x ", t->extension_opcode);
-  if (t->opcode_modifier & D)
-    fprintf (stdout, "D");
-  if (t->opcode_modifier & W)
-    fprintf (stdout, "W");
-  fprintf (stdout, "\n");
-  for (i = 0; i < t->operands; i++)
+  int ret = 1;
+  unsigned int q;
+
+  if (prefix >= REX_OPCODE && prefix < REX_OPCODE + 16
+      && flag_code == CODE_64BIT)
     {
-      fprintf (stdout, "    #%d type ", i + 1);
-      pt (t->operand_types[i]);
-      fprintf (stdout, "\n");
+      if ((i.prefix[REX_PREFIX] & prefix & REX_W)
+         || ((i.prefix[REX_PREFIX] & (REX_R | REX_X | REX_B))
+             && (prefix & (REX_R | REX_X | REX_B))))
+       ret = 0;
+      q = REX_PREFIX;
+    }
+  else
+    {
+      switch (prefix)
+       {
+       default:
+         abort ();
+
+       case CS_PREFIX_OPCODE:
+       case DS_PREFIX_OPCODE:
+       case ES_PREFIX_OPCODE:
+       case FS_PREFIX_OPCODE:
+       case GS_PREFIX_OPCODE:
+       case SS_PREFIX_OPCODE:
+         q = SEG_PREFIX;
+         break;
+
+       case REPNE_PREFIX_OPCODE:
+       case REPE_PREFIX_OPCODE:
+         ret = 2;
+         /* fall thru */
+       case LOCK_PREFIX_OPCODE:
+         q = LOCKREP_PREFIX;
+         break;
+
+       case FWAIT_OPCODE:
+         q = WAIT_PREFIX;
+         break;
+
+       case ADDR_PREFIX_OPCODE:
+         q = ADDR_PREFIX;
+         break;
+
+       case DATA_PREFIX_OPCODE:
+         q = DATA_PREFIX;
+         break;
+       }
+      if (i.prefix[q] != 0)
+       ret = 0;
+    }
+
+  if (ret)
+    {
+      if (!i.prefix[q])
+       ++i.prefixes;
+      i.prefix[q] |= prefix;
     }
+  else
+    as_bad (_("same type of prefix used twice"));
+
+  return ret;
 }
 
 static void
-pe (expressionS *e)
+set_code_flag (int value)
 {
-  fprintf (stdout, "    operation     %d\n", e->X_op);
-  fprintf (stdout, "    add_number    %ld (%lx)\n",
-          (long) e->X_add_number, (long) e->X_add_number);
-  if (e->X_add_symbol)
+  flag_code = (enum flag_code) value;
+  if (flag_code == CODE_64BIT)
     {
-      fprintf (stdout, "    add_symbol    ");
-      ps (e->X_add_symbol);
-      fprintf (stdout, "\n");
+      cpu_arch_flags.bitfield.cpu64 = 1;
+      cpu_arch_flags.bitfield.cpuno64 = 0;
     }
-  if (e->X_op_symbol)
+  else
     {
-      fprintf (stdout, "    op_symbol    ");
-      ps (e->X_op_symbol);
-      fprintf (stdout, "\n");
+      cpu_arch_flags.bitfield.cpu64 = 0;
+      cpu_arch_flags.bitfield.cpuno64 = 1;
+    }
+  if (value == CODE_64BIT && !cpu_arch_flags.bitfield.cpulm )
+    {
+      as_bad (_("64bit mode not supported on this CPU."));
     }
+  if (value == CODE_32BIT && !cpu_arch_flags.bitfield.cpui386)
+    {
+      as_bad (_("32bit mode not supported on this CPU."));
+    }
+  stackop_size = '\0';
 }
 
 static void
-ps (symbolS *s)
+set_16bit_gcc_code_flag (int new_code_flag)
 {
-  fprintf (stdout, "%s type %s%s",
-          S_GET_NAME (s),
-          S_IS_EXTERNAL (s) ? "EXTERNAL " : "",
-          segment_name (S_GET_SEGMENT (s)));
+  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;
 }
 
-static struct type_name
-  {
-    unsigned int mask;
-    char *tname;
-  }
-const type_names[] =
-{
-  { Reg8, "r8" },
-  { Reg16, "r16" },
-  { Reg32, "r32" },
-  { Reg64, "r64" },
-  { Imm8, "i8" },
-  { Imm8S, "i8s" },
-  { Imm16, "i16" },
-  { Imm32, "i32" },
-  { Imm32S, "i32s" },
-  { Imm64, "i64" },
-  { Imm1, "i1" },
-  { BaseIndex, "BaseIndex" },
-  { Disp8, "d8" },
-  { Disp16, "d16" },
-  { Disp32, "d32" },
-  { Disp32S, "d32s" },
-  { Disp64, "d64" },
-  { InOutPortReg, "InOutPortReg" },
-  { ShiftCount, "ShiftCount" },
-  { Control, "control reg" },
-  { Test, "test reg" },
-  { Debug, "debug reg" },
-  { FloatReg, "FReg" },
-  { FloatAcc, "FAcc" },
-  { SReg2, "SReg2" },
-  { SReg3, "SReg3" },
-  { Acc, "Acc" },
-  { JumpAbsolute, "Jump Absolute" },
-  { RegMMX, "rMMX" },
-  { RegXMM, "rXMM" },
-  { EsSeg, "es" },
-  { 0, "" }
-};
-
 static void
-pt (t)
-     unsigned int t;
+set_intel_syntax (int syntax_flag)
 {
-  const struct type_name *ty;
+  /* Find out if register prefixing is specified.  */
+  int ask_naked_reg = 0;
 
-  for (ty = type_names; ty->mask; ty++)
-    if (t & ty->mask)
-      fprintf (stdout, "%s, ", ty->tname);
-  fflush (stdout);
-}
+  SKIP_WHITESPACE ();
+  if (!is_end_of_line[(unsigned char) *input_line_pointer])
+    {
+      char *string = input_line_pointer;
+      int e = get_symbol_end ();
 
-#endif /* DEBUG386 */
-\f
-static bfd_reloc_code_real_type
-reloc (unsigned int size,
-       int pcrel,
-       int sign,
-       bfd_reloc_code_real_type other)
-{
-  if (other != NO_RELOC)
-    {
-      reloc_howto_type *reloc;
-
-      if (size == 8)
-       switch (other)
-         {
-         case BFD_RELOC_X86_64_GOT32:
-           return BFD_RELOC_X86_64_GOT64;
-           break;
-         case BFD_RELOC_X86_64_PLTOFF64:
-           return BFD_RELOC_X86_64_PLTOFF64;
-           break;
-         case BFD_RELOC_X86_64_GOTPC32:
-           other = BFD_RELOC_X86_64_GOTPC64;
-           break;
-         case BFD_RELOC_X86_64_GOTPCREL:
-           other = BFD_RELOC_X86_64_GOTPCREL64;
-           break;
-         case BFD_RELOC_X86_64_TPOFF32:
-           other = BFD_RELOC_X86_64_TPOFF64;
-           break;
-         case BFD_RELOC_X86_64_DTPOFF32:
-           other = BFD_RELOC_X86_64_DTPOFF64;
-           break;
-         default:
-           break;
-         }
-
-      /* Sign-checking 4-byte relocations in 16-/32-bit code is pointless.  */
-      if (size == 4 && flag_code != CODE_64BIT)
-       sign = -1;
-
-      reloc = bfd_reloc_type_lookup (stdoutput, other);
-      if (!reloc)
-       as_bad (_("unknown relocation (%u)"), other);
-      else if (size != bfd_get_reloc_size (reloc))
-       as_bad (_("%u-byte relocation cannot be applied to %u-byte field"),
-               bfd_get_reloc_size (reloc),
-               size);
-      else if (pcrel && !reloc->pc_relative)
-       as_bad (_("non-pc-relative relocation for pc-relative field"));
-      else if ((reloc->complain_on_overflow == complain_overflow_signed
-               && !sign)
-              || (reloc->complain_on_overflow == complain_overflow_unsigned
-                  && sign > 0))
-       as_bad (_("relocated field and relocation type differ in signedness"));
+      if (strcmp (string, "prefix") == 0)
+       ask_naked_reg = 1;
+      else if (strcmp (string, "noprefix") == 0)
+       ask_naked_reg = -1;
       else
-       return other;
-      return NO_RELOC;
+       as_bad (_("bad argument to syntax directive."));
+      *input_line_pointer = e;
     }
+  demand_empty_rest_of_line ();
 
-  if (pcrel)
-    {
-      if (!sign)
-       as_bad (_("there are no unsigned pc-relative relocations"));
-      switch (size)
-       {
-       case 1: return BFD_RELOC_8_PCREL;
-       case 2: return BFD_RELOC_16_PCREL;
-       case 4: return BFD_RELOC_32_PCREL;
-       case 8: return BFD_RELOC_64_PCREL;
-       }
-      as_bad (_("cannot do %u byte pc-relative relocation"), size);
-    }
+  intel_syntax = syntax_flag;
+
+  if (ask_naked_reg == 0)
+    allow_naked_reg = (intel_syntax
+                      && (bfd_get_symbol_leading_char (stdoutput) != '\0'));
   else
-    {
-      if (sign > 0)
-       switch (size)
-         {
-         case 4: return BFD_RELOC_X86_64_32S;
-         }
-      else
-       switch (size)
-         {
-         case 1: return BFD_RELOC_8;
-         case 2: return BFD_RELOC_16;
-         case 4: return BFD_RELOC_32;
-         case 8: return BFD_RELOC_64;
-         }
-      as_bad (_("cannot do %s %u byte relocation"),
-             sign > 0 ? "signed" : "unsigned", size);
-    }
+    allow_naked_reg = (ask_naked_reg < 0);
 
-  abort ();
-  return BFD_RELOC_NONE;
-}
+  expr_set_rank (O_full_ptr, syntax_flag ? 10 : 0);
 
-/* Here we decide which fixups can be adjusted to make them relative to
-   the beginning of the section instead of the symbol.  Basically we need
-   to make sure that the dynamic relocations are done correctly, so in
-   some cases we force the original symbol to be used.  */
+  identifier_chars['%'] = intel_syntax && allow_naked_reg ? '%' : 0;
+  identifier_chars['$'] = intel_syntax ? '$' : 0;
+  register_prefix = allow_naked_reg ? "" : "%";
+}
 
-int
-tc_i386_fix_adjustable (fixS *fixP ATTRIBUTE_UNUSED)
+static void
+set_intel_mnemonic (int mnemonic_flag)
 {
-#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
-  if (!IS_ELF)
-    return 1;
-
-  /* Don't adjust pc-relative references to merge sections in 64-bit
-     mode.  */
-  if (use_rela_relocations
-      && (S_GET_SEGMENT (fixP->fx_addsy)->flags & SEC_MERGE) != 0
-      && fixP->fx_pcrel)
-    return 0;
-
-  /* The x86_64 GOTPCREL are represented as 32bit PCrel relocations
-     and changed later by validate_fix.  */
-  if (GOT_symbol && fixP->fx_subsy == GOT_symbol
-      && fixP->fx_r_type == BFD_RELOC_32_PCREL)
-    return 0;
-
-  /* adjust_reloc_syms doesn't know about the GOT.  */
-  if (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_TLS_GD
-      || fixP->fx_r_type == BFD_RELOC_386_TLS_LDM
-      || fixP->fx_r_type == BFD_RELOC_386_TLS_LDO_32
-      || fixP->fx_r_type == BFD_RELOC_386_TLS_IE_32
-      || fixP->fx_r_type == BFD_RELOC_386_TLS_IE
-      || fixP->fx_r_type == BFD_RELOC_386_TLS_GOTIE
-      || fixP->fx_r_type == BFD_RELOC_386_TLS_LE_32
-      || 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_TLSGD
-      || fixP->fx_r_type == BFD_RELOC_X86_64_TLSLD
-      || fixP->fx_r_type == BFD_RELOC_X86_64_DTPOFF32
-      || fixP->fx_r_type == BFD_RELOC_X86_64_DTPOFF64
-      || fixP->fx_r_type == BFD_RELOC_X86_64_GOTTPOFF
-      || fixP->fx_r_type == BFD_RELOC_X86_64_TPOFF32
-      || fixP->fx_r_type == BFD_RELOC_X86_64_TPOFF64
-      || fixP->fx_r_type == BFD_RELOC_X86_64_GOTOFF64
-      || fixP->fx_r_type == BFD_RELOC_X86_64_GOTPC32_TLSDESC
-      || fixP->fx_r_type == BFD_RELOC_X86_64_TLSDESC_CALL
-      || fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
-      || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
-    return 0;
-#endif
-  return 1;
+  intel_mnemonic = mnemonic_flag;
 }
 
-static int
-intel_float_operand (const char *mnemonic)
+static void
+set_allow_index_reg (int flag)
 {
-  /* Note that the value returned is meaningful only for opcodes with (memory)
-     operands, hence the code here is free to improperly handle opcodes that
-     have no operands (for better performance and smaller code). */
+  allow_index_reg = flag;
+}
 
-  if (mnemonic[0] != 'f')
-    return 0; /* non-math */
+static void
+set_sse_check (int dummy ATTRIBUTE_UNUSED)
+{
+  SKIP_WHITESPACE ();
 
-  switch (mnemonic[1])
+  if (!is_end_of_line[(unsigned char) *input_line_pointer])
     {
-    /* fclex, fdecstp, fdisi, femms, feni, fincstp, finit, fsetpm, and
-       the fs segment override prefix not currently handled because no
-       call path can make opcodes without operands get here */
-    case 'i':
-      return 2 /* integer op */;
-    case 'l':
-      if (mnemonic[2] == 'd' && (mnemonic[3] == 'c' || mnemonic[3] == 'e'))
-       return 3; /* fldcw/fldenv */
-      break;
-    case 'n':
-      if (mnemonic[2] != 'o' /* fnop */)
-       return 3; /* non-waiting control op */
-      break;
-    case 'r':
-      if (mnemonic[2] == 's')
-       return 3; /* frstor/frstpm */
-      break;
-    case 's':
-      if (mnemonic[2] == 'a')
-       return 3; /* fsave */
-      if (mnemonic[2] == 't')
-       {
-         switch (mnemonic[3])
-           {
-           case 'c': /* fstcw */
-           case 'd': /* fstdw */
-           case 'e': /* fstenv */
-           case 's': /* fsts[gw] */
-             return 3;
-           }
-       }
-      break;
-    case 'x':
-      if (mnemonic[2] == 'r' || mnemonic[2] == 's')
-       return 0; /* fxsave/fxrstor are not really math ops */
-      break;
+      char *string = input_line_pointer;
+      int e = get_symbol_end ();
+
+      if (strcmp (string, "none") == 0)
+       sse_check = sse_check_none;
+      else if (strcmp (string, "warning") == 0)
+       sse_check = sse_check_warning;
+      else if (strcmp (string, "error") == 0)
+       sse_check = sse_check_error;
+      else
+       as_bad (_("bad argument to sse_check directive."));
+      *input_line_pointer = e;
     }
+  else
+    as_bad (_("missing argument for sse_check directive"));
 
-  return 1;
+  demand_empty_rest_of_line ();
 }
 
-/* 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.  */
-
-void
-md_assemble (line)
-     char *line;
+static void
+check_cpu_arch_compatible (const char *name ATTRIBUTE_UNUSED,
+                          i386_cpu_flags new_flag ATTRIBUTE_UNUSED)
 {
-  int j;
-  char mnemonic[MAX_MNEM_SIZE];
-
-  /* Initialize globals.  */
-  memset (&i, '\0', sizeof (i));
-  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;
-
-  /* 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.  */
-
-  line = parse_insn (line, mnemonic);
-  if (line == NULL)
-    return;
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+  static const char *arch;
 
-  line = parse_operands (line, mnemonic);
-  if (line == NULL)
+  /* Intel LIOM is only supported on ELF.  */
+  if (!IS_ELF)
     return;
 
-  /* The order of the immediates should be reversed
-     for 2 immediates extrq and insertq instructions */
-  if ((i.imm_operands == 2)
-      && ((strcmp (mnemonic, "extrq") == 0)
-         || (strcmp (mnemonic, "insertq") == 0)))
+  if (!arch)
     {
-      swap_2_operands (0, 1);
-      /* "extrq" and insertq" are the only two instructions whose operands
-        have to be reversed even though they have two immediate operands.
-      */
-      if (intel_syntax)
-       swap_operands ();
+      /* Use cpu_arch_name if it is set in md_parse_option.  Otherwise
+        use default_arch.  */
+      arch = cpu_arch_name;
+      if (!arch)
+       arch = default_arch;
     }
 
-  /* Now we've parsed the mnemonic into a set of templates, and have the
-     operands at hand.  */
+  /* If we are targeting Intel L1OM, we must enable it.  */
+  if (get_elf_backend_data (stdoutput)->elf_machine_code != EM_L1OM
+      || new_flag.bitfield.cpul1om)
+    return;
+  
+  as_bad (_("`%s' is not supported on `%s'"), name, arch);
+#endif
+}
 
-  /* 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. */
-  if (intel_syntax
-      && i.operands > 1
-      && (strcmp (mnemonic, "bound") != 0)
-      && (strcmp (mnemonic, "invlpga") != 0)
-      && !((i.types[0] & Imm) && (i.types[1] & Imm)))
-    swap_operands ();
-
-  if (i.imm_operands)
-    optimize_imm ();
-
-  /* Don't optimize displacement for movabs since it only takes 64bit
-     displacement.  */
-  if (i.disp_operands
-      && (flag_code != CODE_64BIT
-         || strcmp (mnemonic, "movabs") != 0))
-    optimize_disp ();
-
-  /* Next, we find a template that matches the given insn,
-     making sure the overlap of the given operands types is consistent
-     with the template operand types.  */
-
-  if (!match_template ())
-    return;
+static void
+set_cpu_arch (int dummy ATTRIBUTE_UNUSED)
+{
+  SKIP_WHITESPACE ();
 
-  if (intel_syntax)
+  if (!is_end_of_line[(unsigned char) *input_line_pointer])
     {
-      /* Undo SYSV386_COMPAT brokenness when in Intel mode.  See i386.h  */
-      if (SYSV386_COMPAT
-         && (i.tm.base_opcode & 0xfffffde0) == 0xdce0)
-       i.tm.base_opcode ^= Opcode_FloatR;
+      char *string = input_line_pointer;
+      int e = get_symbol_end ();
+      unsigned int i;
+      i386_cpu_flags flags;
 
-      /* Zap movzx and movsx suffix.  The suffix may have been set from
-        "word ptr" or "byte ptr" on the source operand, but we'll use
-        the suffix later to choose the destination register.  */
-      if ((i.tm.base_opcode & ~9) == 0x0fb6)
+      for (i = 0; i < ARRAY_SIZE (cpu_arch); i++)
        {
-         if (i.reg_operands < 2
-             && !i.suffix
-             && (~i.tm.opcode_modifier
-                 & (No_bSuf
-                    | No_wSuf
-                    | No_lSuf
-                    | No_sSuf
-                    | No_xSuf
-                    | No_qSuf)))
-           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;
-
-  /* Check string instruction segment overrides.  */
-  if ((i.tm.opcode_modifier & IsString) != 0 && i.mem_operands != 0)
-    {
-      if (!check_string ())
-       return;
-    }
+         if (strcmp (string, cpu_arch[i].name) == 0)
+           {
+             check_cpu_arch_compatible (string, cpu_arch[i].flags);
 
-  if (!process_suffix ())
-    return;
+             if (*string != '.')
+               {
+                 cpu_arch_name = cpu_arch[i].name;
+                 cpu_sub_arch_name = NULL;
+                 cpu_arch_flags = cpu_arch[i].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 = cpu_arch[i].type;
+                 cpu_arch_isa_flags = cpu_arch[i].flags;
+                 if (!cpu_arch_tune_set)
+                   {
+                     cpu_arch_tune = cpu_arch_isa;
+                     cpu_arch_tune_flags = cpu_arch_isa_flags;
+                   }
+                 break;
+               }
 
-  /* Make still unresolved immediate matches conform to size of immediate
-     given in i.suffix.  */
-  if (!finalize_imm ())
-    return;
+             if (strncmp (string + 1, "no", 2))
+               flags = cpu_flags_or (cpu_arch_flags,
+                                     cpu_arch[i].flags);
+             else
+               flags = cpu_flags_and_not (cpu_arch_flags,
+                                          cpu_arch[i].flags);
+             if (!cpu_flags_equal (&flags, &cpu_arch_flags))
+               {
+                 if (cpu_sub_arch_name)
+                   {
+                     char *name = cpu_sub_arch_name;
+                     cpu_sub_arch_name = concat (name,
+                                                 cpu_arch[i].name,
+                                                 (const char *) NULL);
+                     free (name);
+                   }
+                 else
+                   cpu_sub_arch_name = xstrdup (cpu_arch[i].name);
+                 cpu_arch_flags = flags;
+               }
+             *input_line_pointer = e;
+             demand_empty_rest_of_line ();
+             return;
+           }
+       }
+      if (i >= ARRAY_SIZE (cpu_arch))
+       as_bad (_("no such architecture: `%s'"), string);
 
-  if (i.types[0] & Imm1)
-    i.imm_operands = 0;        /* kludge for shift insns.  */
-  if (i.types[0] & ImplicitRegister)
-    i.reg_operands--;
-  if (i.types[1] & ImplicitRegister)
-    i.reg_operands--;
-  if (i.types[2] & ImplicitRegister)
-    i.reg_operands--;
+      *input_line_pointer = e;
+    }
+  else
+    as_bad (_("missing cpu architecture"));
 
-  if (i.tm.opcode_modifier & ImmExt)
+  no_cond_jump_promotion = 0;
+  if (*input_line_pointer == ','
+      && !is_end_of_line[(unsigned char) input_line_pointer[1]])
     {
-      expressionS *exp;
+      char *string = ++input_line_pointer;
+      int e = get_symbol_end ();
 
-      if ((i.tm.cpu_flags & CpuSSE3) && i.operands > 0)
-       {
-         /* Streaming SIMD extensions 3 Instructions have the fixed
-            operands with an opcode suffix which is coded in the same
-            place as an 8-bit immediate field would be. Here we check
-            those operands and remove them afterwards.  */
-         unsigned int x;
-
-         for (x = 0; x < i.operands; x++)
-           if (i.op[x].regs->reg_num != x)
-             as_bad (_("can't use register '%s%s' as operand %d in '%s'."),
-                     register_prefix,
-                     i.op[x].regs->reg_name,
-                     x + 1,
-                     i.tm.name);
-         i.operands = 0;
-       }
-
-      /* These AMD 3DNow! and Intel Katmai New Instructions have an
-        opcode suffix which is coded in the same place as an 8-bit
-        immediate field would be.  Here we fake an 8-bit immediate
-        operand from the opcode suffix stored in tm.extension_opcode.  */
-
-      assert (i.imm_operands == 0 && i.operands <= 2 && 2 < MAX_OPERANDS);
-
-      exp = &im_expressions[i.imm_operands++];
-      i.op[i.operands].imms = exp;
-      i.types[i.operands++] = Imm8;
-      exp->X_op = O_constant;
-      exp->X_add_number = i.tm.extension_opcode;
-      i.tm.extension_opcode = None;
-    }
+      if (strcmp (string, "nojumps") == 0)
+       no_cond_jump_promotion = 1;
+      else if (strcmp (string, "jumps") == 0)
+       ;
+      else
+       as_bad (_("no such architecture modifier: `%s'"), string);
 
-  /* For insns with operands there are more diddles to do to the opcode.  */
-  if (i.operands)
-    {
-      if (!process_operands ())
-       return;
-    }
-  else if (!quiet_warnings && (i.tm.opcode_modifier & Ugh) != 0)
-    {
-      /* UnixWare fsub no args is alias for fsubp, fadd -> faddp, etc.  */
-      as_warn (_("translating to `%sp'"), i.tm.name);
+      *input_line_pointer = e;
     }
 
-  /* Handle conversion of 'int $3' --> special int3 insn.  */
-  if (i.tm.base_opcode == INT_OPCODE && i.op[0].imms->X_add_number == 3)
-    {
-      i.tm.base_opcode = INT3_OPCODE;
-      i.imm_operands = 0;
-    }
+  demand_empty_rest_of_line ();
+}
 
-  if ((i.tm.opcode_modifier & (Jump | JumpByte | JumpDword))
-      && i.op[0].disps->X_op == O_constant)
+enum bfd_architecture
+i386_arch (void)
+{
+  if (cpu_arch_isa == PROCESSOR_L1OM)
     {
-      /* Convert "jmp constant" (and "call constant") to a jump (call) to
-        the absolute address given by the constant.  Since ix86 jumps and
-        calls are pc relative, we need to generate a reloc.  */
-      i.op[0].disps->X_add_symbol = &abs_symbol;
-      i.op[0].disps->X_op = O_symbol;
+      if (OUTPUT_FLAVOR != bfd_target_elf_flavour
+         || flag_code != CODE_64BIT)
+       as_fatal (_("Intel L1OM is 64bit ELF only"));
+      return bfd_arch_l1om;
     }
+  else
+    return bfd_arch_i386;
+}
 
-  if ((i.tm.opcode_modifier & Rex64) != 0)
-    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.  */
-
-  if (((i.types[0] & Reg8) != 0
-       && (i.op[0].regs->reg_flags & RegRex64) != 0)
-      || ((i.types[1] & Reg8) != 0
-         && (i.op[1].regs->reg_flags & RegRex64) != 0)
-      || (((i.types[0] & Reg8) != 0 || (i.types[1] & Reg8) != 0)
-         && i.rex != 0))
+unsigned long
+i386_mach ()
+{
+  if (!strcmp (default_arch, "x86_64"))
     {
-      int x;
-
-      i.rex |= REX_OPCODE;
-      for (x = 0; x < 2; x++)
+      if (cpu_arch_isa == PROCESSOR_L1OM)
        {
-         /* Look for 8 bit operand that uses old registers.  */
-         if ((i.types[x] & Reg8) != 0
-             && (i.op[x].regs->reg_flags & RegRex64) == 0)
-           {
-             /* In case it is "hi" register, give up.  */
-             if (i.op[x].regs->reg_num > 3)
-               as_bad (_("can't encode register '%s%s' in an "
-                         "instruction requiring REX prefix."),
-                       register_prefix, i.op[x].regs->reg_name);
-
-             /* Otherwise it is equivalent to the extended register.
-                Since the encoding doesn't change this is merely
-                cosmetic cleanup for debug output.  */
-
-             i.op[x].regs = i.op[x].regs + 8;
-           }
+         if (OUTPUT_FLAVOR != bfd_target_elf_flavour)
+           as_fatal (_("Intel L1OM is 64bit ELF only"));
+         return bfd_mach_l1om;
        }
+      else
+       return bfd_mach_x86_64;
     }
-
-  if (i.rex != 0)
-    add_prefix (REX_OPCODE | i.rex);
-
-  /* We are ready to output the insn.  */
-  output_insn ();
+  else if (!strcmp (default_arch, "i386"))
+    return bfd_mach_i386_i386;
+  else
+    as_fatal (_("Unknown architecture"));
 }
-
-static char *
-parse_insn (char *line, char *mnemonic)
+\f
+void
+md_begin ()
 {
-  char *l = line;
-  char *token_start = l;
-  char *mnem_p;
-  int supported;
-  const template *t;
+  const char *hash_err;
 
-  /* Non-zero if we found a prefix only acceptable with string insns.  */
-  const char *expecting_string_instruction = NULL;
+  /* Initialize op_hash hash table.  */
+  op_hash = hash_new ();
 
-  while (1)
-    {
-      mnem_p = mnemonic;
-      while ((*mnem_p = mnemonic_chars[(unsigned char) *l]) != 0)
-       {
-         mnem_p++;
-         if (mnem_p >= mnemonic + MAX_MNEM_SIZE)
-           {
-             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 != ',')))
-       {
-         as_bad (_("invalid character %s in mnemonic"),
-                 output_invalid (*l));
-         return NULL;
-       }
-      if (token_start == l)
-       {
-         if (!intel_syntax && *l == PREFIX_SEPARATOR)
-           as_bad (_("expecting prefix; got nothing"));
-         else
-           as_bad (_("expecting mnemonic; got nothing"));
-         return NULL;
-       }
+  {
+    const insn_template *optab;
+    templates *core_optab;
 
-      /* Look up instruction (or prefix) via hash table.  */
-      current_templates = hash_find (op_hash, mnemonic);
+    /* Setup for loop.  */
+    optab = i386_optab;
+    core_optab = (templates *) xmalloc (sizeof (templates));
+    core_optab->start = optab;
 
-      if (*l != END_OF_INSN
-         && (!is_space_char (*l) || l[1] != END_OF_INSN)
-         && current_templates
-         && (current_templates->start->opcode_modifier & IsPrefix))
-       {
-         if (current_templates->start->cpu_flags
-             & (flag_code != CODE_64BIT ? Cpu64 : CpuNo64))
-           {
-             as_bad ((flag_code != CODE_64BIT
-                      ? _("`%s' is only supported in 64-bit mode")
-                      : _("`%s' is not supported in 64-bit mode")),
-                     current_templates->start->name);
-             return NULL;
-           }
-         /* If we are in 16-bit mode, do not allow addr16 or data16.
-            Similarly, in 32-bit mode, do not allow addr32 or data32.  */
-         if ((current_templates->start->opcode_modifier & (Size16 | Size32))
-             && flag_code != CODE_64BIT
-             && (((current_templates->start->opcode_modifier & Size32) != 0)
-                 ^ (flag_code == CODE_16BIT)))
-           {
-             as_bad (_("redundant %s prefix"),
-                     current_templates->start->name);
-             return NULL;
-           }
-         /* Add prefix, checking for repeated prefixes.  */
-         switch (add_prefix (current_templates->start->base_opcode))
-           {
-           case 0:
-             return NULL;
-           case 2:
-             expecting_string_instruction = current_templates->start->name;
-             break;
-           }
-         /* Skip past PREFIX_SEPARATOR and reset token_start.  */
-         token_start = ++l;
-       }
-      else
-       break;
-    }
+    while (1)
+      {
+       ++optab;
+       if (optab->name == NULL
+           || strcmp (optab->name, (optab - 1)->name) != 0)
+         {
+           /* different name --> ship out current template list;
+              add to hash table; & begin anew.  */
+           core_optab->end = optab;
+           hash_err = hash_insert (op_hash,
+                                   (optab - 1)->name,
+                                   (void *) core_optab);
+           if (hash_err)
+             {
+               as_fatal (_("Internal Error:  Can't hash %s: %s"),
+                         (optab - 1)->name,
+                         hash_err);
+             }
+           if (optab->name == NULL)
+             break;
+           core_optab = (templates *) xmalloc (sizeof (templates));
+           core_optab->start = optab;
+         }
+      }
+  }
 
-  if (!current_templates)
-    {
-      /* See if we can get a match by trimming off a suffix.  */
-      switch (mnem_p[-1])
-       {
-       case WORD_MNEM_SUFFIX:
-         if (intel_syntax && (intel_float_operand (mnemonic) & 2))
-           i.suffix = SHORT_MNEM_SUFFIX;
-         else
-       case BYTE_MNEM_SUFFIX:
-       case QWORD_MNEM_SUFFIX:
-         i.suffix = mnem_p[-1];
-         mnem_p[-1] = '\0';
-         current_templates = hash_find (op_hash, mnemonic);
-         break;
-       case SHORT_MNEM_SUFFIX:
-       case LONG_MNEM_SUFFIX:
-         if (!intel_syntax)
-           {
-             i.suffix = mnem_p[-1];
-             mnem_p[-1] = '\0';
-             current_templates = hash_find (op_hash, mnemonic);
-           }
-         break;
+  /* Initialize reg_hash hash table.  */
+  reg_hash = hash_new ();
+  {
+    const reg_entry *regtab;
+    unsigned int regtab_size = i386_regtab_size;
 
-         /* Intel Syntax.  */
-       case 'd':
-         if (intel_syntax)
-           {
-             if (intel_float_operand (mnemonic) == 1)
-               i.suffix = SHORT_MNEM_SUFFIX;
-             else
-               i.suffix = LONG_MNEM_SUFFIX;
-             mnem_p[-1] = '\0';
-             current_templates = hash_find (op_hash, mnemonic);
-           }
-         break;
-       }
-      if (!current_templates)
-       {
-         as_bad (_("no such instruction: `%s'"), token_start);
-         return NULL;
-       }
-    }
+    for (regtab = i386_regtab; regtab_size--; regtab++)
+      {
+       hash_err = hash_insert (reg_hash, regtab->reg_name, (void *) regtab);
+       if (hash_err)
+         as_fatal (_("Internal Error:  Can't hash %s: %s"),
+                   regtab->reg_name,
+                   hash_err);
+      }
+  }
 
-  if (current_templates->start->opcode_modifier & (Jump | JumpByte))
-    {
-      /* Check for a branch hint.  We allow ",pt" and ",pn" for
-        predict taken and predict not taken respectively.
-        I'm not sure that branch hints actually do anything on loop
-        and jcxz insns (JumpByte) for current Pentium4 chips.  They
-        may work in the future and it doesn't hurt to accept them
-        now.  */
-      if (l[0] == ',' && l[1] == 'p')
-       {
-         if (l[2] == 't')
-           {
-             if (!add_prefix (DS_PREFIX_OPCODE))
-               return NULL;
-             l += 3;
-           }
-         else if (l[2] == 'n')
-           {
-             if (!add_prefix (CS_PREFIX_OPCODE))
-               return NULL;
-             l += 3;
-           }
-       }
-    }
-  /* Any other comma loses.  */
-  if (*l == ',')
-    {
-      as_bad (_("invalid character %s in mnemonic"),
-             output_invalid (*l));
-      return NULL;
-    }
+  /* Fill in lexical tables:  mnemonic_chars, operand_chars.  */
+  {
+    int c;
+    char *p;
 
-  /* Check if instruction is supported on specified architecture.  */
-  supported = 0;
-  for (t = current_templates->start; t < current_templates->end; ++t)
-    {
-      if (!((t->cpu_flags & ~(Cpu64 | CpuNo64))
-           & ~(cpu_arch_flags & ~(Cpu64 | CpuNo64))))
-       supported |= 1;
-      if (!(t->cpu_flags & (flag_code == CODE_64BIT ? CpuNo64 : Cpu64)))
-       supported |= 2;
-    }
-  if (!(supported & 2))
-    {
-      as_bad (flag_code == CODE_64BIT
-             ? _("`%s' is not supported in 64-bit mode")
-             : _("`%s' is only supported in 64-bit mode"),
-             current_templates->start->name);
-      return NULL;
-    }
-  if (!(supported & 1))
+    for (c = 0; c < 256; c++)
+      {
+       if (ISDIGIT (c))
+         {
+           digit_chars[c] = c;
+           mnemonic_chars[c] = c;
+           register_chars[c] = c;
+           operand_chars[c] = c;
+         }
+       else if (ISLOWER (c))
+         {
+           mnemonic_chars[c] = c;
+           register_chars[c] = c;
+           operand_chars[c] = c;
+         }
+       else if (ISUPPER (c))
+         {
+           mnemonic_chars[c] = TOLOWER (c);
+           register_chars[c] = mnemonic_chars[c];
+           operand_chars[c] = c;
+         }
+
+       if (ISALPHA (c) || ISDIGIT (c))
+         identifier_chars[c] = c;
+       else if (c >= 128)
+         {
+           identifier_chars[c] = c;
+           operand_chars[c] = c;
+         }
+      }
+
+#ifdef LEX_AT
+    identifier_chars['@'] = '@';
+#endif
+#ifdef LEX_QM
+    identifier_chars['?'] = '?';
+    operand_chars['?'] = '?';
+#endif
+    digit_chars['-'] = '-';
+    mnemonic_chars['_'] = '_';
+    mnemonic_chars['-'] = '-';
+    mnemonic_chars['.'] = '.';
+    identifier_chars['_'] = '_';
+    identifier_chars['.'] = '.';
+
+    for (p = operand_special_chars; *p != '\0'; p++)
+      operand_chars[(unsigned char) *p] = *p;
+  }
+
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+  if (IS_ELF)
     {
-      as_warn (_("`%s' is not supported on `%s%s'"),
-              current_templates->start->name,
-              cpu_arch_name,
-              cpu_sub_arch_name ? cpu_sub_arch_name : "");
+      record_alignment (text_section, 2);
+      record_alignment (data_section, 2);
+      record_alignment (bss_section, 2);
     }
-  else if ((Cpu386 & ~cpu_arch_flags) && (flag_code != CODE_16BIT))
+#endif
+
+  if (flag_code == CODE_64BIT)
     {
-      as_warn (_("use .code16 to ensure correct addressing mode"));
+      x86_dwarf2_return_column = 16;
+      x86_cie_data_alignment = -8;
     }
-
-  /* Check for rep/repne without a string instruction.  */
-  if (expecting_string_instruction)
+  else
     {
-      static templates override;
-
-      for (t = current_templates->start; t < current_templates->end; ++t)
-       if (t->opcode_modifier & IsString)
-         break;
-      if (t >= current_templates->end)
-       {
-         as_bad (_("expecting string instruction after `%s'"),
-                 expecting_string_instruction);
-         return NULL;
-       }
-      for (override.start = t; t < current_templates->end; ++t)
-       if (!(t->opcode_modifier & IsString))
-         break;
-      override.end = t;
-      current_templates = &override;
+      x86_dwarf2_return_column = 8;
+      x86_cie_data_alignment = -4;
     }
-
-  return l;
 }
 
-static char *
-parse_operands (char *l, const char *mnemonic)
+void
+i386_print_statistics (FILE *file)
 {
-  char *token_start;
+  hash_print_statistics (file, "i386 opcode", op_hash);
+  hash_print_statistics (file, "i386 register", reg_hash);
+}
+\f
+#ifdef DEBUG386
 
-  /* 1 if operand is pending after ','.  */
-  unsigned int expecting_operand = 0;
+/* Debugging routines for md_assemble.  */
+static void pte (insn_template *);
+static void pt (i386_operand_type);
+static void pe (expressionS *);
+static void ps (symbolS *);
 
-  /* Non-zero if operand parens not balanced.  */
-  unsigned int paren_not_balanced;
+static void
+pi (char *line, i386_insn *x)
+{
+  unsigned int i;
 
-  while (*l != END_OF_INSN)
+  fprintf (stdout, "%s: template ", line);
+  pte (&x->tm);
+  fprintf (stdout, "  address: base %s  index %s  scale %x\n",
+          x->base_reg ? x->base_reg->reg_name : "none",
+          x->index_reg ? x->index_reg->reg_name : "none",
+          x->log2_scale_factor);
+  fprintf (stdout, "  modrm:  mode %x  reg %x  reg/mem %x\n",
+          x->rm.mode, x->rm.reg, x->rm.regmem);
+  fprintf (stdout, "  sib:  base %x  index %x  scale %x\n",
+          x->sib.base, x->sib.index, x->sib.scale);
+  fprintf (stdout, "  rex: 64bit %x  extX %x  extY %x  extZ %x\n",
+          (x->rex & REX_W) != 0,
+          (x->rex & REX_R) != 0,
+          (x->rex & REX_X) != 0,
+          (x->rex & REX_B) != 0);
+  for (i = 0; i < x->operands; i++)
     {
-      /* Skip optional white space before operand.  */
-      if (is_space_char (*l))
-       ++l;
-      if (!is_operand_char (*l) && *l != END_OF_INSN)
-       {
-         as_bad (_("invalid character %s before operand %d"),
-                 output_invalid (*l),
-                 i.operands + 1);
-         return NULL;
-       }
-      token_start = l; /* after white space */
-      paren_not_balanced = 0;
-      while (paren_not_balanced || *l != ',')
-       {
-         if (*l == END_OF_INSN)
-           {
-             if (paren_not_balanced)
-               {
-                 if (!intel_syntax)
-                   as_bad (_("unbalanced parenthesis in operand %d."),
-                           i.operands + 1);
-                 else
-                   as_bad (_("unbalanced brackets in operand %d."),
-                           i.operands + 1);
-                 return NULL;
-               }
-             else
-               break;  /* we are done */
-           }
-         else if (!is_operand_char (*l) && !is_space_char (*l))
-           {
-             as_bad (_("invalid character %s in operand %d"),
-                     output_invalid (*l),
-                     i.operands + 1);
-             return NULL;
-           }
-         if (!intel_syntax)
-           {
-             if (*l == '(')
-               ++paren_not_balanced;
-             if (*l == ')')
-               --paren_not_balanced;
-           }
-         else
-           {
-             if (*l == '[')
-               ++paren_not_balanced;
-             if (*l == ']')
-               --paren_not_balanced;
-           }
-         l++;
-       }
-      if (l != token_start)
-       {                       /* Yes, we've read in another operand.  */
-         unsigned int operand_ok;
-         this_operand = i.operands++;
-         if (i.operands > MAX_OPERANDS)
-           {
-             as_bad (_("spurious operands; (%d operands/instruction max)"),
-                     MAX_OPERANDS);
-             return NULL;
-           }
-         /* Now parse operand adding info to 'i' as we go along.  */
-         END_STRING_AND_SAVE (l);
-
-         if (intel_syntax)
-           operand_ok =
-             i386_intel_operand (token_start,
-                                 intel_float_operand (mnemonic));
-         else
-           operand_ok = i386_operand (token_start);
-
-         RESTORE_END_STRING (l);
-         if (!operand_ok)
-           return NULL;
-       }
-      else
-       {
-         if (expecting_operand)
-           {
-           expecting_operand_after_comma:
-             as_bad (_("expecting operand after ','; got nothing"));
-             return NULL;
-           }
-         if (*l == ',')
-           {
-             as_bad (_("expecting operand before ','; got nothing"));
-             return NULL;
-           }
-       }
-
-      /* Now *l must be either ',' or END_OF_INSN.  */
-      if (*l == ',')
-       {
-         if (*++l == END_OF_INSN)
-           {
-             /* Just skip it, if it's \n complain.  */
-             goto expecting_operand_after_comma;
-           }
-         expecting_operand = 1;
-       }
+      fprintf (stdout, "    #%d:  ", i + 1);
+      pt (x->types[i]);
+      fprintf (stdout, "\n");
+      if (x->types[i].bitfield.reg8
+         || x->types[i].bitfield.reg16
+         || x->types[i].bitfield.reg32
+         || x->types[i].bitfield.reg64
+         || x->types[i].bitfield.regmmx
+         || x->types[i].bitfield.regxmm
+         || x->types[i].bitfield.regymm
+         || x->types[i].bitfield.sreg2
+         || x->types[i].bitfield.sreg3
+         || x->types[i].bitfield.control
+         || x->types[i].bitfield.debug
+         || x->types[i].bitfield.test)
+       fprintf (stdout, "%s\n", x->op[i].regs->reg_name);
+      if (operand_type_check (x->types[i], imm))
+       pe (x->op[i].imms);
+      if (operand_type_check (x->types[i], disp))
+       pe (x->op[i].disps);
     }
-  return l;
 }
 
 static void
-swap_2_operands (int xchg1, int xchg2)
+pte (insn_template *t)
 {
-  union i386_op temp_op;
-  unsigned int temp_type;
-  enum bfd_reloc_code_real temp_reloc;
-
-  temp_type = i.types[xchg2];
-  i.types[xchg2] = i.types[xchg1];
-  i.types[xchg1] = temp_type;
-  temp_op = i.op[xchg2];
-  i.op[xchg2] = i.op[xchg1];
-  i.op[xchg1] = temp_op;
-  temp_reloc = i.reloc[xchg2];
-  i.reloc[xchg2] = i.reloc[xchg1];
-  i.reloc[xchg1] = temp_reloc;
+  unsigned int i;
+  fprintf (stdout, " %d operands ", t->operands);
+  fprintf (stdout, "opcode %x ", t->base_opcode);
+  if (t->extension_opcode != None)
+    fprintf (stdout, "ext %x ", t->extension_opcode);
+  if (t->opcode_modifier.d)
+    fprintf (stdout, "D");
+  if (t->opcode_modifier.w)
+    fprintf (stdout, "W");
+  fprintf (stdout, "\n");
+  for (i = 0; i < t->operands; i++)
+    {
+      fprintf (stdout, "    #%d type ", i + 1);
+      pt (t->operand_types[i]);
+      fprintf (stdout, "\n");
+    }
 }
 
 static void
-swap_operands (void)
+pe (expressionS *e)
 {
-  switch (i.operands)
+  fprintf (stdout, "    operation     %d\n", e->X_op);
+  fprintf (stdout, "    add_number    %ld (%lx)\n",
+          (long) e->X_add_number, (long) e->X_add_number);
+  if (e->X_add_symbol)
     {
-    case 4:
-      swap_2_operands (1, i.operands - 2);
-    case 3:
-    case 2:
-      swap_2_operands (0, i.operands - 1);
-      break;
-    default:
-      abort ();
+      fprintf (stdout, "    add_symbol    ");
+      ps (e->X_add_symbol);
+      fprintf (stdout, "\n");
     }
-
-  if (i.mem_operands == 2)
+  if (e->X_op_symbol)
     {
-      const seg_entry *temp_seg;
-      temp_seg = i.seg[0];
-      i.seg[0] = i.seg[1];
-      i.seg[1] = temp_seg;
+      fprintf (stdout, "    op_symbol    ");
+      ps (e->X_op_symbol);
+      fprintf (stdout, "\n");
     }
 }
 
-/* Try to ensure constant immediates are represented in the smallest
-   opcode possible.  */
 static void
-optimize_imm (void)
+ps (symbolS *s)
 {
-  char guess_suffix = 0;
-  int op;
+  fprintf (stdout, "%s type %s%s",
+          S_GET_NAME (s),
+          S_IS_EXTERNAL (s) ? "EXTERNAL " : "",
+          segment_name (S_GET_SEGMENT (s)));
+}
 
-  if (i.suffix)
-    guess_suffix = i.suffix;
-  else if (i.reg_operands)
+static struct type_name
+  {
+    i386_operand_type mask;
+    const char *name;
+  }
+const type_names[] =
+{
+  { OPERAND_TYPE_REG8, "r8" },
+  { OPERAND_TYPE_REG16, "r16" },
+  { OPERAND_TYPE_REG32, "r32" },
+  { OPERAND_TYPE_REG64, "r64" },
+  { OPERAND_TYPE_IMM8, "i8" },
+  { OPERAND_TYPE_IMM8, "i8s" },
+  { OPERAND_TYPE_IMM16, "i16" },
+  { OPERAND_TYPE_IMM32, "i32" },
+  { OPERAND_TYPE_IMM32S, "i32s" },
+  { OPERAND_TYPE_IMM64, "i64" },
+  { OPERAND_TYPE_IMM1, "i1" },
+  { OPERAND_TYPE_BASEINDEX, "BaseIndex" },
+  { OPERAND_TYPE_DISP8, "d8" },
+  { OPERAND_TYPE_DISP16, "d16" },
+  { OPERAND_TYPE_DISP32, "d32" },
+  { OPERAND_TYPE_DISP32S, "d32s" },
+  { OPERAND_TYPE_DISP64, "d64" },
+  { OPERAND_TYPE_INOUTPORTREG, "InOutPortReg" },
+  { OPERAND_TYPE_SHIFTCOUNT, "ShiftCount" },
+  { OPERAND_TYPE_CONTROL, "control reg" },
+  { OPERAND_TYPE_TEST, "test reg" },
+  { OPERAND_TYPE_DEBUG, "debug reg" },
+  { OPERAND_TYPE_FLOATREG, "FReg" },
+  { OPERAND_TYPE_FLOATACC, "FAcc" },
+  { OPERAND_TYPE_SREG2, "SReg2" },
+  { OPERAND_TYPE_SREG3, "SReg3" },
+  { OPERAND_TYPE_ACC, "Acc" },
+  { OPERAND_TYPE_JUMPABSOLUTE, "Jump Absolute" },
+  { OPERAND_TYPE_REGMMX, "rMMX" },
+  { OPERAND_TYPE_REGXMM, "rXMM" },
+  { OPERAND_TYPE_REGYMM, "rYMM" },
+  { OPERAND_TYPE_ESSEG, "es" },
+};
+
+static void
+pt (i386_operand_type t)
+{
+  unsigned int j;
+  i386_operand_type a;
+
+  for (j = 0; j < ARRAY_SIZE (type_names); j++)
     {
-      /* Figure out a suffix from the last register operand specified.
-        We can't do this properly yet, ie. excluding InOutPortReg,
-        but the following works for instructions with immediates.
-        In any case, we can't set i.suffix yet.  */
-      for (op = i.operands; --op >= 0;)
-       if (i.types[op] & Reg)
+      a = operand_type_and (t, type_names[j].mask);
+      if (!operand_type_all_zero (&a))
+       fprintf (stdout, "%s, ",  type_names[j].name);
+    }
+  fflush (stdout);
+}
+
+#endif /* DEBUG386 */
+\f
+static bfd_reloc_code_real_type
+reloc (unsigned int size,
+       int pcrel,
+       int sign,
+       bfd_reloc_code_real_type other)
+{
+  if (other != NO_RELOC)
+    {
+      reloc_howto_type *reloc;
+
+      if (size == 8)
+       switch (other)
          {
-           if (i.types[op] & Reg8)
-             guess_suffix = BYTE_MNEM_SUFFIX;
-           else if (i.types[op] & Reg16)
-             guess_suffix = WORD_MNEM_SUFFIX;
-           else if (i.types[op] & Reg32)
-             guess_suffix = LONG_MNEM_SUFFIX;
-           else if (i.types[op] & Reg64)
-             guess_suffix = QWORD_MNEM_SUFFIX;
+         case BFD_RELOC_X86_64_GOT32:
+           return BFD_RELOC_X86_64_GOT64;
+           break;
+         case BFD_RELOC_X86_64_PLTOFF64:
+           return BFD_RELOC_X86_64_PLTOFF64;
+           break;
+         case BFD_RELOC_X86_64_GOTPC32:
+           other = BFD_RELOC_X86_64_GOTPC64;
+           break;
+         case BFD_RELOC_X86_64_GOTPCREL:
+           other = BFD_RELOC_X86_64_GOTPCREL64;
+           break;
+         case BFD_RELOC_X86_64_TPOFF32:
+           other = BFD_RELOC_X86_64_TPOFF64;
+           break;
+         case BFD_RELOC_X86_64_DTPOFF32:
+           other = BFD_RELOC_X86_64_DTPOFF64;
+           break;
+         default:
            break;
          }
-    }
-  else if ((flag_code == CODE_16BIT) ^ (i.prefix[DATA_PREFIX] != 0))
-    guess_suffix = WORD_MNEM_SUFFIX;
 
-  for (op = i.operands; --op >= 0;)
-    if (i.types[op] & Imm)
-      {
-       switch (i.op[op].imms->X_op)
-         {
-         case O_constant:
-           /* If a suffix is given, this operand may be shortened.  */
-           switch (guess_suffix)
-             {
-             case LONG_MNEM_SUFFIX:
-               i.types[op] |= Imm32 | Imm64;
-               break;
-             case WORD_MNEM_SUFFIX:
-               i.types[op] |= Imm16 | Imm32S | Imm32 | Imm64;
-               break;
-             case BYTE_MNEM_SUFFIX:
-               i.types[op] |= Imm16 | Imm8 | Imm8S | Imm32S | Imm32 | Imm64;
-               break;
-             }
+      /* Sign-checking 4-byte relocations in 16-/32-bit code is pointless.  */
+      if (size == 4 && flag_code != CODE_64BIT)
+       sign = -1;
 
-           /* If this operand is at most 16 bits, convert it
-              to a signed 16 bit number before trying to see
-              whether it will fit in an even smaller size.
-              This allows a 16-bit operand such as $0xffe0 to
-              be recognised as within Imm8S range.  */
-           if ((i.types[op] & Imm16)
-               && (i.op[op].imms->X_add_number & ~(offsetT) 0xffff) == 0)
-             {
-               i.op[op].imms->X_add_number =
-                 (((i.op[op].imms->X_add_number & 0xffff) ^ 0x8000) - 0x8000);
-             }
-           if ((i.types[op] & Imm32)
-               && ((i.op[op].imms->X_add_number & ~(((offsetT) 2 << 31) - 1))
-                   == 0))
-             {
-               i.op[op].imms->X_add_number = ((i.op[op].imms->X_add_number
-                                               ^ ((offsetT) 1 << 31))
-                                              - ((offsetT) 1 << 31));
-             }
-           i.types[op] |= smallest_imm_type (i.op[op].imms->X_add_number);
-
-           /* We must avoid matching of Imm32 templates when 64bit
-              only immediate is available.  */
-           if (guess_suffix == QWORD_MNEM_SUFFIX)
-             i.types[op] &= ~Imm32;
-           break;
-
-         case O_absent:
-         case O_register:
-           abort ();
-
-           /* Symbols and expressions.  */
-         default:
-           /* Convert symbolic operand to proper sizes for matching, but don't
-              prevent matching a set of insns that only supports sizes other
-              than those matching the insn suffix.  */
-           {
-             unsigned int mask, allowed = 0;
-             const template *t;
+      reloc = bfd_reloc_type_lookup (stdoutput, other);
+      if (!reloc)
+       as_bad (_("unknown relocation (%u)"), other);
+      else if (size != bfd_get_reloc_size (reloc))
+       as_bad (_("%u-byte relocation cannot be applied to %u-byte field"),
+               bfd_get_reloc_size (reloc),
+               size);
+      else if (pcrel && !reloc->pc_relative)
+       as_bad (_("non-pc-relative relocation for pc-relative field"));
+      else if ((reloc->complain_on_overflow == complain_overflow_signed
+               && !sign)
+              || (reloc->complain_on_overflow == complain_overflow_unsigned
+                  && sign > 0))
+       as_bad (_("relocated field and relocation type differ in signedness"));
+      else
+       return other;
+      return NO_RELOC;
+    }
 
-             for (t = current_templates->start;
-                  t < current_templates->end;
-                  ++t)
-               allowed |= t->operand_types[op];
-             switch (guess_suffix)
-               {
-               case QWORD_MNEM_SUFFIX:
-                 mask = Imm64 | Imm32S;
-                 break;
-               case LONG_MNEM_SUFFIX:
-                 mask = Imm32;
-                 break;
-               case WORD_MNEM_SUFFIX:
-                 mask = Imm16;
-                 break;
-               case BYTE_MNEM_SUFFIX:
-                 mask = Imm8;
-                 break;
-               default:
-                 mask = 0;
-                 break;
-               }
-             if (mask & allowed)
-               i.types[op] &= mask;
-           }
-           break;
+  if (pcrel)
+    {
+      if (!sign)
+       as_bad (_("there are no unsigned pc-relative relocations"));
+      switch (size)
+       {
+       case 1: return BFD_RELOC_8_PCREL;
+       case 2: return BFD_RELOC_16_PCREL;
+       case 4: return BFD_RELOC_32_PCREL;
+       case 8: return BFD_RELOC_64_PCREL;
+       }
+      as_bad (_("cannot do %u byte pc-relative relocation"), size);
+    }
+  else
+    {
+      if (sign > 0)
+       switch (size)
+         {
+         case 4: return BFD_RELOC_X86_64_32S;
          }
-      }
+      else
+       switch (size)
+         {
+         case 1: return BFD_RELOC_8;
+         case 2: return BFD_RELOC_16;
+         case 4: return BFD_RELOC_32;
+         case 8: return BFD_RELOC_64;
+         }
+      as_bad (_("cannot do %s %u byte relocation"),
+             sign > 0 ? "signed" : "unsigned", size);
+    }
+
+  return NO_RELOC;
 }
 
-/* Try to use the smallest displacement type too.  */
-static void
-optimize_disp (void)
+/* Here we decide which fixups can be adjusted to make them relative to
+   the beginning of the section instead of the symbol.  Basically we need
+   to make sure that the dynamic relocations are done correctly, so in
+   some cases we force the original symbol to be used.  */
+
+int
+tc_i386_fix_adjustable (fixS *fixP ATTRIBUTE_UNUSED)
 {
-  int op;
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+  if (!IS_ELF)
+    return 1;
 
-  for (op = i.operands; --op >= 0;)
-    if (i.types[op] & Disp)
-      {
-       if (i.op[op].disps->X_op == O_constant)
-         {
-           offsetT disp = i.op[op].disps->X_add_number;
+  /* Don't adjust pc-relative references to merge sections in 64-bit
+     mode.  */
+  if (use_rela_relocations
+      && (S_GET_SEGMENT (fixP->fx_addsy)->flags & SEC_MERGE) != 0
+      && fixP->fx_pcrel)
+    return 0;
 
-           if ((i.types[op] & Disp16)
-               && (disp & ~(offsetT) 0xffff) == 0)
-             {
-               /* If this operand is at most 16 bits, convert
-                  to a signed 16 bit number and don't use 64bit
-                  displacement.  */
-               disp = (((disp & 0xffff) ^ 0x8000) - 0x8000);
-               i.types[op] &= ~Disp64;
-             }
-           if ((i.types[op] & Disp32)
-               && (disp & ~(((offsetT) 2 << 31) - 1)) == 0)
-             {
-               /* If this operand is at most 32 bits, convert
-                  to a signed 32 bit number and don't use 64bit
-                  displacement.  */
-               disp &= (((offsetT) 2 << 31) - 1);
-               disp = (disp ^ ((offsetT) 1 << 31)) - ((addressT) 1 << 31);
-               i.types[op] &= ~Disp64;
-             }
-           if (!disp && (i.types[op] & BaseIndex))
-             {
-               i.types[op] &= ~Disp;
-               i.op[op].disps = 0;
-               i.disp_operands--;
-             }
-           else if (flag_code == CODE_64BIT)
-             {
-               if (fits_in_signed_long (disp))
-                 {
-                   i.types[op] &= ~Disp64;
-                   i.types[op] |= Disp32S;
-                 }
-               if (fits_in_unsigned_long (disp))
-                 i.types[op] |= Disp32;
-             }
-           if ((i.types[op] & (Disp32 | Disp32S | Disp16))
-               && fits_in_signed_byte (disp))
-             i.types[op] |= Disp8;
-         }
-       else if (i.reloc[op] == BFD_RELOC_386_TLS_DESC_CALL
-                || i.reloc[op] == BFD_RELOC_X86_64_TLSDESC_CALL)
-         {
-           fix_new_exp (frag_now, frag_more (0) - frag_now->fr_literal, 0,
-                        i.op[op].disps, 0, i.reloc[op]);
-           i.types[op] &= ~Disp;
-         }
-       else
-         /* We only support 64bit displacement on constants.  */
-         i.types[op] &= ~Disp64;
-      }
+  /* The x86_64 GOTPCREL are represented as 32bit PCrel relocations
+     and changed later by validate_fix.  */
+  if (GOT_symbol && fixP->fx_subsy == GOT_symbol
+      && fixP->fx_r_type == BFD_RELOC_32_PCREL)
+    return 0;
+
+  /* adjust_reloc_syms doesn't know about the GOT.  */
+  if (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_TLS_GD
+      || fixP->fx_r_type == BFD_RELOC_386_TLS_LDM
+      || fixP->fx_r_type == BFD_RELOC_386_TLS_LDO_32
+      || fixP->fx_r_type == BFD_RELOC_386_TLS_IE_32
+      || fixP->fx_r_type == BFD_RELOC_386_TLS_IE
+      || fixP->fx_r_type == BFD_RELOC_386_TLS_GOTIE
+      || fixP->fx_r_type == BFD_RELOC_386_TLS_LE_32
+      || 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_TLSGD
+      || fixP->fx_r_type == BFD_RELOC_X86_64_TLSLD
+      || fixP->fx_r_type == BFD_RELOC_X86_64_DTPOFF32
+      || fixP->fx_r_type == BFD_RELOC_X86_64_DTPOFF64
+      || fixP->fx_r_type == BFD_RELOC_X86_64_GOTTPOFF
+      || fixP->fx_r_type == BFD_RELOC_X86_64_TPOFF32
+      || fixP->fx_r_type == BFD_RELOC_X86_64_TPOFF64
+      || fixP->fx_r_type == BFD_RELOC_X86_64_GOTOFF64
+      || fixP->fx_r_type == BFD_RELOC_X86_64_GOTPC32_TLSDESC
+      || fixP->fx_r_type == BFD_RELOC_X86_64_TLSDESC_CALL
+      || fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
+      || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
+    return 0;
+#endif
+  return 1;
 }
 
 static int
-match_template (void)
+intel_float_operand (const char *mnemonic)
 {
-  /* Points to template once we've found it.  */
-  const template *t;
-  unsigned int overlap0, overlap1, overlap2, overlap3;
-  unsigned int found_reverse_match;
-  int suffix_check;
-  unsigned int operand_types [MAX_OPERANDS];
-  int addr_prefix_disp;
-  unsigned int j;
-
-#if MAX_OPERANDS != 4
-# error "MAX_OPERANDS must be 4."
-#endif
+  /* Note that the value returned is meaningful only for opcodes with (memory)
+     operands, hence the code here is free to improperly handle opcodes that
+     have no operands (for better performance and smaller code). */
 
-#define MATCH(overlap, given, template)                                \
-  ((overlap & ~JumpAbsolute)                                   \
-   && (((given) & (BaseIndex | JumpAbsolute))                  \
-       == ((overlap) & (BaseIndex | JumpAbsolute))))
-
-  /* If given types r0 and r1 are registers they must be of the same type
-     unless the expected operand type register overlap is null.
-     Note that Acc in a template matches every size of reg.  */
-#define CONSISTENT_REGISTER_MATCH(m0, g0, t0, m1, g1, t1)      \
-  (((g0) & Reg) == 0 || ((g1) & Reg) == 0                      \
-   || ((g0) & Reg) == ((g1) & Reg)                             \
-   || ((((m0) & Acc) ? Reg : (t0)) & (((m1) & Acc) ? Reg : (t1)) & Reg) == 0 )
-
-  overlap0 = 0;
-  overlap1 = 0;
-  overlap2 = 0;
-  overlap3 = 0;
-  found_reverse_match = 0;
-  for (j = 0; j < MAX_OPERANDS; j++)
-    operand_types [j] = 0;
-  addr_prefix_disp = -1;
-  suffix_check = (i.suffix == BYTE_MNEM_SUFFIX
-                 ? No_bSuf
-                 : (i.suffix == WORD_MNEM_SUFFIX
-                    ? No_wSuf
-                    : (i.suffix == SHORT_MNEM_SUFFIX
-                       ? No_sSuf
-                       : (i.suffix == LONG_MNEM_SUFFIX
-                          ? No_lSuf
-                          : (i.suffix == QWORD_MNEM_SUFFIX
-                             ? No_qSuf
-                             : (i.suffix == LONG_DOUBLE_MNEM_SUFFIX
-                                ? No_xSuf : 0))))));
+  if (mnemonic[0] != 'f')
+    return 0; /* non-math */
 
-  for (t = current_templates->start; t < current_templates->end; t++)
+  switch (mnemonic[1])
     {
-      addr_prefix_disp = -1;
+    /* fclex, fdecstp, fdisi, femms, feni, fincstp, finit, fsetpm, and
+       the fs segment override prefix not currently handled because no
+       call path can make opcodes without operands get here */
+    case 'i':
+      return 2 /* integer op */;
+    case 'l':
+      if (mnemonic[2] == 'd' && (mnemonic[3] == 'c' || mnemonic[3] == 'e'))
+       return 3; /* fldcw/fldenv */
+      break;
+    case 'n':
+      if (mnemonic[2] != 'o' /* fnop */)
+       return 3; /* non-waiting control op */
+      break;
+    case 'r':
+      if (mnemonic[2] == 's')
+       return 3; /* frstor/frstpm */
+      break;
+    case 's':
+      if (mnemonic[2] == 'a')
+       return 3; /* fsave */
+      if (mnemonic[2] == 't')
+       {
+         switch (mnemonic[3])
+           {
+           case 'c': /* fstcw */
+           case 'd': /* fstdw */
+           case 'e': /* fstenv */
+           case 's': /* fsts[gw] */
+             return 3;
+           }
+       }
+      break;
+    case 'x':
+      if (mnemonic[2] == 'r' || mnemonic[2] == 's')
+       return 0; /* fxsave/fxrstor are not really math ops */
+      break;
+    }
 
-      /* Must have right number of operands.  */
-      if (i.operands != t->operands)
-       continue;
+  return 1;
+}
 
-      /* Check the suffix, except for some instructions in intel mode.  */
-      if ((t->opcode_modifier & suffix_check)
-         && !(intel_syntax
-              && (t->opcode_modifier & IgnoreSize)))
-       continue;
+/* Build the VEX prefix.  */
 
-      for (j = 0; j < MAX_OPERANDS; j++)
-       operand_types [j] = t->operand_types [j];
+static void
+build_vex_prefix (const insn_template *t)
+{
+  unsigned int register_specifier;
+  unsigned int implied_prefix;
+  unsigned int vector_length;
 
-      /* In general, don't allow 64-bit operands in 32-bit mode.  */
-      if (i.suffix == QWORD_MNEM_SUFFIX
-         && flag_code != CODE_64BIT
-         && (intel_syntax
-             ? (!(t->opcode_modifier & IgnoreSize)
-                && !intel_float_operand (t->name))
-             : intel_float_operand (t->name) != 2)
-         && (!(operand_types[0] & (RegMMX | RegXMM))
-             || !(operand_types[t->operands > 1] & (RegMMX | RegXMM)))
-         && (t->base_opcode != 0x0fc7
-             || t->extension_opcode != 1 /* cmpxchg8b */))
-       continue;
+  /* Check register specifier.  */
+  if (i.vex.register_specifier)
+    {
+      register_specifier = i.vex.register_specifier->reg_num;
+      if ((i.vex.register_specifier->reg_flags & RegRex))
+       register_specifier += 8;
+      register_specifier = ~register_specifier & 0xf;
+    }
+  else
+    register_specifier = 0xf;
 
-      /* Do not verify operands when there are none.  */
-      else if (!t->operands)
-       {
-         if (t->cpu_flags & ~cpu_arch_flags)
-           continue;
-         /* We've found a match; break out of loop.  */
-         break;
-       }
+  /* Use 2-byte VEX prefix by swappping destination and source
+     operand.  */
+  if (!i.swap_operand
+      && i.operands == i.reg_operands
+      && i.tm.opcode_modifier.vex0f
+      && i.tm.opcode_modifier.s
+      && i.rex == REX_B)
+    {
+      unsigned int xchg = i.operands - 1;
+      union i386_op temp_op;
+      i386_operand_type temp_type;
 
-      /* Address size prefix will turn Disp64/Disp32/Disp16 operand
-        into Disp32/Disp16/Disp32 operand.  */
-      if (i.prefix[ADDR_PREFIX] != 0)
-         {
-           unsigned int DispOn = 0, DispOff = 0;
+      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;
 
-           switch (flag_code)
-           {
-           case CODE_16BIT:
-             DispOn = Disp32;
-             DispOff = Disp16;
-             break;
-           case CODE_32BIT:
-             DispOn = Disp16;
-             DispOff = Disp32;
-             break;
-           case CODE_64BIT:
-             DispOn = Disp32;
-             DispOff = Disp64;
-             break;
-           }
+      gas_assert (i.rm.mode == 3);
 
-           for (j = 0; j < MAX_OPERANDS; j++)
-             {
-               /* There should be only one Disp operand.  */
-               if ((operand_types[j] & DispOff))
-                 {
-                   addr_prefix_disp = j;
-                   operand_types[j] |= DispOn;
-                   operand_types[j] &= ~DispOff;
-                   break;
-                 }
-             }
-         }
+      i.rex = REX_R;
+      xchg = i.rm.regmem;
+      i.rm.regmem = i.rm.reg;
+      i.rm.reg = xchg;
 
-      overlap0 = i.types[0] & operand_types[0];
-      switch (t->operands)
-       {
-       case 1:
-         if (!MATCH (overlap0, i.types[0], operand_types[0]))
-           continue;
-         break;
-       case 2:
-         /* xchg %eax, %eax is a special case. It is an aliase 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
-             && i.types [0] == (Acc | Reg32)
-             && i.types [1] == (Acc | Reg32))
-           continue;
-       case 3:
-       case 4:
-         overlap1 = i.types[1] & operand_types[1];
-         if (!MATCH (overlap0, i.types[0], operand_types[0])
-             || !MATCH (overlap1, i.types[1], operand_types[1])
-             /* monitor in SSE3 is a very special case.  The first
-                register and the second register may have different
-                sizes.  The same applies to crc32 in SSE4.2.  */
-             || !((t->base_opcode == 0x0f01
-                   && t->extension_opcode == 0xc8)
-                  || t->base_opcode == 0xf20f38f1
-                  || CONSISTENT_REGISTER_MATCH (overlap0, i.types[0],
-                                                operand_types[0],
-                                                overlap1, i.types[1],
-                                                operand_types[1])))
-           {
-             /* Check if other direction is valid ...  */
-             if ((t->opcode_modifier & (D | FloatD)) == 0)
-               continue;
+      /* Use the next insn.  */
+      i.tm = t[1];
+    }
 
-             /* Try reversing direction of operands.  */
-             overlap0 = i.types[0] & operand_types[1];
-             overlap1 = i.types[1] & operand_types[0];
-             if (!MATCH (overlap0, i.types[0], operand_types[1])
-                 || !MATCH (overlap1, i.types[1], operand_types[0])
-                 || !CONSISTENT_REGISTER_MATCH (overlap0, i.types[0],
-                                                operand_types[1],
-                                                overlap1, i.types[1],
-                                                operand_types[0]))
-               {
-                 /* Does not match either direction.  */
-                 continue;
-               }
-             /* found_reverse_match holds which of D or FloatDR
-                we've found.  */
-             if ((t->opcode_modifier & D))
-               found_reverse_match = Opcode_D;
-             else if ((t->opcode_modifier & FloatD))
-               found_reverse_match = Opcode_FloatD;
-             else
-               found_reverse_match = 0;
-             if ((t->opcode_modifier & FloatR))
-               found_reverse_match |= Opcode_FloatR;
-           }
-         else
-           {
-             /* Found a forward 2 operand match here.  */
-             switch (t->operands)
-               {
-               case 4:
-                 overlap3 = i.types[3] & operand_types[3];
-               case 3:
-                 overlap2 = i.types[2] & operand_types[2];
-                 break;
-               }
+  vector_length = i.tm.opcode_modifier.vex256 ? 1 : 0;
 
-             switch (t->operands)
-               {
-               case 4:
-                 if (!MATCH (overlap3, i.types[3], operand_types[3])
-                     || !CONSISTENT_REGISTER_MATCH (overlap2,
-                                                    i.types[2],
-                                                    operand_types[2],
-                                                    overlap3,
-                                                    i.types[3],
-                                                    operand_types[3]))
-                   continue;
-               case 3:
-                 /* Here we make use of the fact that there are no
-                    reverse match 3 operand instructions, and all 3
-                    operand instructions only need to be checked for
-                    register consistency between operands 2 and 3.  */
-                 if (!MATCH (overlap2, i.types[2], operand_types[2])
-                     || !CONSISTENT_REGISTER_MATCH (overlap1,
-                                                    i.types[1],
-                                                    operand_types[1],
-                                                    overlap2,
-                                                    i.types[2],
-                                                    operand_types[2]))
-                   continue;
-                 break;
-               }
-           }
-         /* Found either forward/reverse 2, 3 or 4 operand match here:
-            slip through to break.  */
-       }
-      if (t->cpu_flags & ~cpu_arch_flags)
-       {
-         found_reverse_match = 0;
-         continue;
-       }
-      /* We've found a match; break out of loop.  */
+  switch ((i.tm.base_opcode >> 8) & 0xff)
+    {
+    case 0:
+      implied_prefix = 0;
+      break;
+    case DATA_PREFIX_OPCODE:
+      implied_prefix = 1;
+      break;
+    case REPE_PREFIX_OPCODE:
+      implied_prefix = 2;
+      break;
+    case REPNE_PREFIX_OPCODE:
+      implied_prefix = 3;
       break;
+    default:
+      abort ();
     }
 
-  if (t == current_templates->end)
+  /* Use 2-byte VEX prefix if possible.  */
+  if (i.tm.opcode_modifier.vex0f
+      && (i.rex & (REX_W | REX_X | REX_B)) == 0)
     {
-      /* We found no match.  */
-      as_bad (_("suffix or operands invalid for `%s'"),
-             current_templates->start->name);
-      return 0;
-    }
+      /* 2-byte VEX prefix.  */
+      unsigned int r;
 
-  if (!quiet_warnings)
+      i.vex.length = 2;
+      i.vex.bytes[0] = 0xc5;
+
+      /* Check the REX.R bit.  */
+      r = (i.rex & REX_R) ? 0 : 1;
+      i.vex.bytes[1] = (r << 7
+                       | register_specifier << 3
+                       | vector_length << 2
+                       | implied_prefix);
+    }
+  else
     {
-      if (!intel_syntax
-         && ((i.types[0] & JumpAbsolute)
-             != (operand_types[0] & JumpAbsolute)))
-       {
-         as_warn (_("indirect %s without `*'"), t->name);
-       }
+      /* 3-byte VEX prefix.  */
+      unsigned int m, w;
+
+      if (i.tm.opcode_modifier.vex0f)
+       m = 0x1;
+      else if (i.tm.opcode_modifier.vex0f38)
+       m = 0x2;
+      else if (i.tm.opcode_modifier.vex0f3a)
+       m = 0x3;
+      else
+       abort ();
+
+      i.vex.length = 3;
+      i.vex.bytes[0] = 0xc4;
+
+      /* 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 | m;
 
-      if ((t->opcode_modifier & (IsPrefix | IgnoreSize))
-         == (IsPrefix | IgnoreSize))
+      /* Check the REX.W bit.  */
+      w = (i.rex & REX_W) ? 1 : 0;
+      if (i.tm.opcode_modifier.vexw0 || i.tm.opcode_modifier.vexw1)
        {
-         /* Warn them that a data or address size prefix doesn't
-            affect assembly of the next line of code.  */
-         as_warn (_("stand-alone `%s' prefix"), t->name);
+         if (w)
+           abort ();
+
+         if (i.tm.opcode_modifier.vexw1)
+           w = 1;
        }
-    }
 
-  /* Copy the template we found.  */
-  i.tm = *t;
+      i.vex.bytes[2] = (w << 7
+                       | register_specifier << 3
+                       | vector_length << 2
+                       | implied_prefix);
+    }
+}
 
-  if (addr_prefix_disp != -1)
-    i.tm.operand_types[addr_prefix_disp]
-      = operand_types[addr_prefix_disp];
+static void
+process_immext (void)
+{
+  expressionS *exp;
 
-  if (found_reverse_match)
+  if (i.tm.cpu_flags.bitfield.cpusse3 && i.operands > 0)
     {
-      /* If we found a reverse match we must alter the opcode
-        direction bit.  found_reverse_match holds bits to change
-        (different for int & float insns).  */
+      /* SSE3 Instructions have the fixed operands with an opcode
+        suffix which is coded in the same place as an 8-bit immediate
+        field would be.  Here we check those operands and remove them
+        afterwards.  */
+      unsigned int x;
 
-      i.tm.base_opcode ^= found_reverse_match;
+      for (x = 0; x < i.operands; x++)
+       if (i.op[x].regs->reg_num != x)
+         as_bad (_("can't use register '%s%s' as operand %d in '%s'."),
+                 register_prefix, i.op[x].regs->reg_name, x + 1,
+                 i.tm.name);
 
-      i.tm.operand_types[0] = operand_types[1];
-      i.tm.operand_types[1] = operand_types[0];
+      i.operands = 0;
     }
 
-  return 1;
+  /* These AMD 3DNow! and SSE2 instructions have an opcode suffix
+     which is coded in the same place as an 8-bit immediate field
+     would be.  Here we fake an 8-bit immediate operand from the
+     opcode suffix stored in tm.extension_opcode.
+
+     AVX instructions also use this encoding, for some of
+     3 argument instructions.  */
+
+  gas_assert (i.imm_operands == 0
+             && (i.operands <= 2
+                 || (i.tm.opcode_modifier.vex
+                     && i.operands <= 4)));
+
+  exp = &im_expressions[i.imm_operands++];
+  i.op[i.operands].imms = exp;
+  i.types[i.operands] = imm8;
+  i.operands++;
+  exp->X_op = O_constant;
+  exp->X_add_number = i.tm.extension_opcode;
+  i.tm.extension_opcode = None;
 }
 
-static int
-check_string (void)
+/* 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.  */
+
+void
+md_assemble (char *line)
 {
-  int mem_op = (i.types[0] & AnyMem) ? 0 : 1;
-  if ((i.tm.operand_types[mem_op] & EsSeg) != 0)
+  unsigned int j;
+  char mnemonic[MAX_MNEM_SIZE];
+  const insn_template *t;
+
+  /* Initialize globals.  */
+  memset (&i, '\0', sizeof (i));
+  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;
+
+  /* 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.  */
+
+  line = parse_insn (line, mnemonic);
+  if (line == NULL)
+    return;
+
+  line = parse_operands (line, mnemonic);
+  this_operand = -1;
+  if (line == NULL)
+    return;
+
+  /* Now we've parsed the mnemonic into a set of templates, and have the
+     operands at hand.  */
+
+  /* All intel opcodes have reversed operands except for "bound" 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. */
+  if (intel_syntax
+      && i.operands > 1
+      && (strcmp (mnemonic, "bound") != 0)
+      && (strcmp (mnemonic, "invlpga") != 0)
+      && !(operand_type_check (i.types[0], imm)
+          && operand_type_check (i.types[1], imm)))
+    swap_operands ();
+
+  /* The order of the immediates should be reversed
+     for 2 immediates extrq and insertq instructions */
+  if (i.imm_operands == 2
+      && (strcmp (mnemonic, "extrq") == 0
+         || strcmp (mnemonic, "insertq") == 0))
+      swap_2_operands (0, 1);
+
+  if (i.imm_operands)
+    optimize_imm ();
+
+  /* Don't optimize displacement for movabs since it only takes 64bit
+     displacement.  */
+  if (i.disp_operands
+      && (flag_code != CODE_64BIT
+         || strcmp (mnemonic, "movabs") != 0))
+    optimize_disp ();
+
+  /* Next, we find a template that matches the given insn,
+     making sure the overlap of the given operands types is consistent
+     with the template operand types.  */
+
+  if (!(t = match_template ()))
+    return;
+
+  if (sse_check != sse_check_none
+      && !i.tm.opcode_modifier.noavx
+      && (i.tm.cpu_flags.bitfield.cpusse
+         || i.tm.cpu_flags.bitfield.cpusse2
+         || 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))
     {
-      if (i.seg[0] != NULL && i.seg[0] != &es)
-       {
-         as_bad (_("`%s' operand %d must use `%%es' segment"),
-                 i.tm.name,
-                 mem_op + 1);
-         return 0;
-       }
-      /* There's only ever one segment override allowed per instruction.
-        This instruction possibly has a legal segment override on the
-        second operand, so copy the segment to where non-string
-        instructions store it, allowing common code.  */
-      i.seg[0] = i.seg[1];
+      (sse_check == sse_check_warning
+       ? as_warn
+       : as_bad) (_("SSE instruction `%s' is used"), i.tm.name);
     }
-  else if ((i.tm.operand_types[mem_op + 1] & EsSeg) != 0)
+
+  /* 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)
     {
-      if (i.seg[1] != NULL && i.seg[1] != &es)
-       {
-         as_bad (_("`%s' operand %d must use `%%es' segment"),
-                 i.tm.name,
-                 mem_op + 2);
-         return 0;
-       }
+      /* 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;
     }
-  return 1;
-}
 
-static int
-process_suffix (void)
-{
-  /* If matched instruction specifies an explicit instruction mnemonic
-     suffix, use it.  */
-  if (i.tm.opcode_modifier & (Size16 | Size32 | Size64))
+  if (i.tm.opcode_modifier.fwait)
+    if (!add_prefix (FWAIT_OPCODE))
+      return;
+
+  /* Check string instruction segment overrides.  */
+  if (i.tm.opcode_modifier.isstring && i.mem_operands != 0)
     {
-      if (i.tm.opcode_modifier & Size16)
-       i.suffix = WORD_MNEM_SUFFIX;
-      else if (i.tm.opcode_modifier & Size64)
-       i.suffix = QWORD_MNEM_SUFFIX;
-      else
-       i.suffix = LONG_MNEM_SUFFIX;
+      if (!check_string ())
+       return;
+      i.disp_operands = 0;
     }
-  else if (i.reg_operands)
-    {
-      /* If there's no instruction mnemonic suffix we try to invent one
-        based on register operands.  */
-      if (!i.suffix)
-       {
-         /* We take i.suffix from the last register operand specified,
-            Destination register type is more significant than source
-            register type.  crc32 in SSE4.2 prefers source register
-            type. */
-         if (i.tm.base_opcode == 0xf20f38f1)
-           {
-             if ((i.types[0] & Reg))
-               i.suffix = ((i.types[0] & Reg16) ? WORD_MNEM_SUFFIX :
-                           LONG_MNEM_SUFFIX);
-           }
-         else if (i.tm.base_opcode == 0xf20f38f0)
-           {
-             if ((i.types[0] & Reg8))
-               i.suffix = BYTE_MNEM_SUFFIX;
-           }
 
-         if (!i.suffix)
+  if (!process_suffix ())
+    return;
+
+  /* Update operand types.  */
+  for (j = 0; j < i.operands; j++)
+    i.types[j] = operand_type_and (i.types[j], i.tm.operand_types[j]);
+
+  /* Make still unresolved immediate matches conform to size of immediate
+     given in i.suffix.  */
+  if (!finalize_imm ())
+    return;
+
+  if (i.types[0].bitfield.imm1)
+    i.imm_operands = 0;        /* kludge for shift insns.  */
+
+  /* We only need to check those implicit registers for instructions
+     with 3 operands or less.  */
+  if (i.operands <= 3)
+    for (j = 0; j < i.operands; j++)
+      if (i.types[j].bitfield.inoutportreg
+         || i.types[j].bitfield.shiftcount
+         || i.types[j].bitfield.acc
+         || i.types[j].bitfield.floatacc)
+       i.reg_operands--;
+
+  /* ImmExt should be processed after SSE2AVX.  */
+  if (!i.tm.opcode_modifier.sse2avx
+      && i.tm.opcode_modifier.immext)
+    process_immext ();
+
+  /* For insns with operands there are more diddles to do to the opcode.  */
+  if (i.operands)
+    {
+      if (!process_operands ())
+       return;
+    }
+  else if (!quiet_warnings && i.tm.opcode_modifier.ugh)
+    {
+      /* UnixWare fsub no args is alias for fsubp, fadd -> faddp, etc.  */
+      as_warn (_("translating to `%sp'"), i.tm.name);
+    }
+
+  if (i.tm.opcode_modifier.vex)
+    build_vex_prefix (t);
+
+  /* Handle conversion of 'int $3' --> special int3 insn.  */
+  if (i.tm.base_opcode == INT_OPCODE && i.op[0].imms->X_add_number == 3)
+    {
+      i.tm.base_opcode = INT3_OPCODE;
+      i.imm_operands = 0;
+    }
+
+  if ((i.tm.opcode_modifier.jump
+       || i.tm.opcode_modifier.jumpbyte
+       || i.tm.opcode_modifier.jumpdword)
+      && i.op[0].disps->X_op == O_constant)
+    {
+      /* Convert "jmp constant" (and "call constant") to a jump (call) to
+        the absolute address given by the constant.  Since ix86 jumps and
+        calls are pc relative, we need to generate a reloc.  */
+      i.op[0].disps->X_add_symbol = &abs_symbol;
+      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.  */
+
+  if ((i.types[0].bitfield.reg8
+       && (i.op[0].regs->reg_flags & RegRex64) != 0)
+      || (i.types[1].bitfield.reg8
+         && (i.op[1].regs->reg_flags & RegRex64) != 0)
+      || ((i.types[0].bitfield.reg8
+          || i.types[1].bitfield.reg8)
+         && i.rex != 0))
+    {
+      int x;
+
+      i.rex |= REX_OPCODE;
+      for (x = 0; x < 2; x++)
+       {
+         /* Look for 8 bit operand that uses old registers.  */
+         if (i.types[x].bitfield.reg8
+             && (i.op[x].regs->reg_flags & RegRex64) == 0)
            {
-             int op;
+             /* In case it is "hi" register, give up.  */
+             if (i.op[x].regs->reg_num > 3)
+               as_bad (_("can't encode register '%s%s' in an "
+                         "instruction requiring REX prefix."),
+                       register_prefix, i.op[x].regs->reg_name);
 
-             if (i.tm.base_opcode == 0xf20f38f1
-                 || i.tm.base_opcode == 0xf20f38f0)
-               {
-                 /* We have to know the operand size for crc32.  */
-                 as_bad (_("ambiguous memory operand size for `%s`"),
-                         i.tm.name);
-                 return 0;
-               }
+             /* Otherwise it is equivalent to the extended register.
+                Since the encoding doesn't change this is merely
+                cosmetic cleanup for debug output.  */
 
-             for (op = i.operands; --op >= 0;)
-               if ((i.types[op] & Reg)
-                   && !(i.tm.operand_types[op] & InOutPortReg))
-                 {
-                   i.suffix = ((i.types[op] & Reg8) ? BYTE_MNEM_SUFFIX :
-                               (i.types[op] & Reg16) ? WORD_MNEM_SUFFIX :
-                               (i.types[op] & Reg64) ? QWORD_MNEM_SUFFIX :
-                               LONG_MNEM_SUFFIX);
-                   break;
-                 }
+             i.op[x].regs = i.op[x].regs + 8;
            }
        }
-      else if (i.suffix == BYTE_MNEM_SUFFIX)
+    }
+
+  if (i.rex != 0)
+    add_prefix (REX_OPCODE | i.rex);
+
+  /* We are ready to output the insn.  */
+  output_insn ();
+}
+
+static char *
+parse_insn (char *line, char *mnemonic)
+{
+  char *l = line;
+  char *token_start = l;
+  char *mnem_p;
+  int supported;
+  const insn_template *t;
+  char *dot_p = NULL;
+
+  /* Non-zero if we found a prefix only acceptable with string insns.  */
+  const char *expecting_string_instruction = NULL;
+
+  while (1)
+    {
+      mnem_p = mnemonic;
+      while ((*mnem_p = mnemonic_chars[(unsigned char) *l]) != 0)
        {
-         if (!check_byte_reg ())
-           return 0;
+         if (*mnem_p == '.')
+           dot_p = mnem_p;
+         mnem_p++;
+         if (mnem_p >= mnemonic + MAX_MNEM_SIZE)
+           {
+             as_bad (_("no such instruction: `%s'"), token_start);
+             return NULL;
+           }
+         l++;
        }
-      else if (i.suffix == LONG_MNEM_SUFFIX)
+      if (!is_space_char (*l)
+         && *l != END_OF_INSN
+         && (intel_syntax
+             || (*l != PREFIX_SEPARATOR
+                 && *l != ',')))
        {
-         if (!check_long_reg ())
-           return 0;
+         as_bad (_("invalid character %s in mnemonic"),
+                 output_invalid (*l));
+         return NULL;
        }
-      else if (i.suffix == QWORD_MNEM_SUFFIX)
+      if (token_start == l)
        {
-         if (!check_qword_reg ())
-           return 0;
+         if (!intel_syntax && *l == PREFIX_SEPARATOR)
+           as_bad (_("expecting prefix; got nothing"));
+         else
+           as_bad (_("expecting mnemonic; got nothing"));
+         return NULL;
        }
-      else if (i.suffix == WORD_MNEM_SUFFIX)
+
+      /* Look up instruction (or prefix) via hash table.  */
+      current_templates = (const templates *) hash_find (op_hash, mnemonic);
+
+      if (*l != END_OF_INSN
+         && (!is_space_char (*l) || l[1] != END_OF_INSN)
+         && current_templates
+         && current_templates->start->opcode_modifier.isprefix)
        {
-         if (!check_word_reg ())
-           return 0;
+         if (!cpu_flags_check_cpu64 (current_templates->start->cpu_flags))
+           {
+             as_bad ((flag_code != CODE_64BIT
+                      ? _("`%s' is only supported in 64-bit mode")
+                      : _("`%s' is not supported in 64-bit mode")),
+                     current_templates->start->name);
+             return NULL;
+           }
+         /* If we are in 16-bit mode, do not allow addr16 or data16.
+            Similarly, in 32-bit mode, do not allow addr32 or data32.  */
+         if ((current_templates->start->opcode_modifier.size16
+              || current_templates->start->opcode_modifier.size32)
+             && flag_code != CODE_64BIT
+             && (current_templates->start->opcode_modifier.size32
+                 ^ (flag_code == CODE_16BIT)))
+           {
+             as_bad (_("redundant %s prefix"),
+                     current_templates->start->name);
+             return NULL;
+           }
+         /* Add prefix, checking for repeated prefixes.  */
+         switch (add_prefix (current_templates->start->base_opcode))
+           {
+           case 0:
+             return NULL;
+           case 2:
+             expecting_string_instruction = current_templates->start->name;
+             break;
+           }
+         /* Skip past PREFIX_SEPARATOR and reset token_start.  */
+         token_start = ++l;
        }
-      else if (intel_syntax && (i.tm.opcode_modifier & IgnoreSize))
-       /* Do nothing if the instruction is going to ignore the prefix.  */
-       ;
       else
-       abort ();
+       break;
     }
-  else if ((i.tm.opcode_modifier & DefaultSize)
-          && !i.suffix
-          /* exclude fldenv/frstor/fsave/fstenv */
-          && (i.tm.opcode_modifier & No_sSuf))
+
+  if (!current_templates)
     {
-      i.suffix = stackop_size;
+      /* Check if we should swap operand in encoding.  */
+      if (mnem_p - 2 == dot_p && dot_p[1] == 's')
+       i.swap_operand = 1;
+      else
+       goto check_suffix;
+      mnem_p = dot_p;
+      *dot_p = '\0';
+      current_templates = (const templates *) hash_find (op_hash, mnemonic);
     }
-  else if (intel_syntax
-          && !i.suffix
-          && ((i.tm.operand_types[0] & JumpAbsolute)
-              || (i.tm.opcode_modifier & (JumpByte|JumpInterSegment))
-              || (i.tm.base_opcode == 0x0f01 /* [ls][gi]dt */
-                  && i.tm.extension_opcode <= 3)))
+
+  if (!current_templates)
     {
-      switch (flag_code)
+check_suffix:
+      /* See if we can get a match by trimming off a suffix.  */
+      switch (mnem_p[-1])
        {
-       case CODE_64BIT:
-         if (!(i.tm.opcode_modifier & No_qSuf))
+       case WORD_MNEM_SUFFIX:
+         if (intel_syntax && (intel_float_operand (mnemonic) & 2))
+           i.suffix = SHORT_MNEM_SUFFIX;
+         else
+       case BYTE_MNEM_SUFFIX:
+       case QWORD_MNEM_SUFFIX:
+         i.suffix = mnem_p[-1];
+         mnem_p[-1] = '\0';
+         current_templates = (const templates *) hash_find (op_hash,
+                                                             mnemonic);
+         break;
+       case SHORT_MNEM_SUFFIX:
+       case LONG_MNEM_SUFFIX:
+         if (!intel_syntax)
            {
-             i.suffix = QWORD_MNEM_SUFFIX;
-             break;
+             i.suffix = mnem_p[-1];
+             mnem_p[-1] = '\0';
+             current_templates = (const templates *) hash_find (op_hash,
+                                                                 mnemonic);
            }
-       case CODE_32BIT:
-         if (!(i.tm.opcode_modifier & No_lSuf))
-           i.suffix = LONG_MNEM_SUFFIX;
          break;
-       case CODE_16BIT:
-         if (!(i.tm.opcode_modifier & No_wSuf))
-           i.suffix = WORD_MNEM_SUFFIX;
+
+         /* Intel Syntax.  */
+       case 'd':
+         if (intel_syntax)
+           {
+             if (intel_float_operand (mnemonic) == 1)
+               i.suffix = SHORT_MNEM_SUFFIX;
+             else
+               i.suffix = LONG_MNEM_SUFFIX;
+             mnem_p[-1] = '\0';
+             current_templates = (const templates *) hash_find (op_hash,
+                                                                 mnemonic);
+           }
          break;
        }
+      if (!current_templates)
+       {
+         as_bad (_("no such instruction: `%s'"), token_start);
+         return NULL;
+       }
     }
 
-  if (!i.suffix)
+  if (current_templates->start->opcode_modifier.jump
+      || current_templates->start->opcode_modifier.jumpbyte)
     {
-      if (!intel_syntax)
+      /* Check for a branch hint.  We allow ",pt" and ",pn" for
+        predict taken and predict not taken respectively.
+        I'm not sure that branch hints actually do anything on loop
+        and jcxz insns (JumpByte) for current Pentium4 chips.  They
+        may work in the future and it doesn't hurt to accept them
+        now.  */
+      if (l[0] == ',' && l[1] == 'p')
        {
-         if (i.tm.opcode_modifier & W)
+         if (l[2] == 't')
            {
-             as_bad (_("no instruction mnemonic suffix given and "
-                       "no register operands; can't size instruction"));
-             return 0;
+             if (!add_prefix (DS_PREFIX_OPCODE))
+               return NULL;
+             l += 3;
            }
-       }
-      else
-       {
-         unsigned int suffixes = (~i.tm.opcode_modifier
-                                  & (No_bSuf
-                                     | No_wSuf
-                                     | No_lSuf
-                                     | No_sSuf
-                                     | No_xSuf
-                                     | No_qSuf));
-
-         if ((i.tm.opcode_modifier & W)
-             || ((suffixes & (suffixes - 1))
-                 && !(i.tm.opcode_modifier & (DefaultSize | IgnoreSize))))
+         else if (l[2] == 'n')
            {
-             as_bad (_("ambiguous operand size for `%s'"), i.tm.name);
-             return 0;
+             if (!add_prefix (CS_PREFIX_OPCODE))
+               return NULL;
+             l += 3;
            }
        }
     }
+  /* Any other comma loses.  */
+  if (*l == ',')
+    {
+      as_bad (_("invalid character %s in mnemonic"),
+             output_invalid (*l));
+      return NULL;
+    }
 
-  /* Change the opcode based on the operand size given by i.suffix;
-     We don't need to change things for byte insns.  */
-
-  if (i.suffix && i.suffix != BYTE_MNEM_SUFFIX)
+  /* Check if instruction is supported on specified architecture.  */
+  supported = 0;
+  for (t = current_templates->start; t < current_templates->end; ++t)
     {
-      /* It's not a byte, select word/dword operation.  */
-      if (i.tm.opcode_modifier & W)
-       {
-         if (i.tm.opcode_modifier & ShortForm)
-           i.tm.base_opcode |= 8;
-         else
-           i.tm.base_opcode |= 1;
-       }
+      supported |= cpu_flags_match (t);
+      if (supported == CPU_FLAGS_PERFECT_MATCH)
+       goto skip;
+    }
 
-      /* Now select between word & dword operations via the operand
-        size prefix, except for instructions that will ignore this
-        prefix anyway.  */
-      if (i.tm.base_opcode == 0x0f01 && i.tm.extension_opcode == 0xc8)
-       {
-         /* monitor in SSE3 is a very special case. The default size
-            of AX is the size of mode. The address size override
-            prefix will change the size of AX.  */
-         if (i.op->regs[0].reg_type &
-             (flag_code == CODE_32BIT ? Reg16 : Reg32))
-           if (!add_prefix (ADDR_PREFIX_OPCODE))
-             return 0;
-       }
-      else if (i.suffix != QWORD_MNEM_SUFFIX
-              && i.suffix != LONG_DOUBLE_MNEM_SUFFIX
-              && !(i.tm.opcode_modifier & (IgnoreSize | FloatMF))
-              && ((i.suffix == LONG_MNEM_SUFFIX) == (flag_code == CODE_16BIT)
-                  || (flag_code == CODE_64BIT
-                      && (i.tm.opcode_modifier & JumpByte))))
-       {
-         unsigned int prefix = DATA_PREFIX_OPCODE;
+  if (!(supported & CPU_FLAGS_64BIT_MATCH))
+    {
+      as_bad (flag_code == CODE_64BIT
+             ? _("`%s' is not supported in 64-bit mode")
+             : _("`%s' is only supported in 64-bit mode"),
+             current_templates->start->name);
+      return NULL;
+    }
+  if (supported != CPU_FLAGS_PERFECT_MATCH)
+    {
+      as_bad (_("`%s' is not supported on `%s%s'"),
+             current_templates->start->name,
+             cpu_arch_name ? cpu_arch_name : default_arch,
+             cpu_sub_arch_name ? cpu_sub_arch_name : "");
+      return NULL;
+    }
 
-         if (i.tm.opcode_modifier & JumpByte) /* jcxz, loop */
-           prefix = ADDR_PREFIX_OPCODE;
+skip:
+  if (!cpu_arch_flags.bitfield.cpui386
+          && (flag_code != CODE_16BIT))
+    {
+      as_warn (_("use .code16 to ensure correct addressing mode"));
+    }
 
-         if (!add_prefix (prefix))
-           return 0;
-       }
+  /* Check for rep/repne without a string instruction.  */
+  if (expecting_string_instruction)
+    {
+      static templates override;
 
-      /* Set mode64 for an operand.  */
-      if (i.suffix == QWORD_MNEM_SUFFIX
-         && flag_code == CODE_64BIT
-         && (i.tm.opcode_modifier & NoRex64) == 0)
+      for (t = current_templates->start; t < current_templates->end; ++t)
+       if (t->opcode_modifier.isstring)
+         break;
+      if (t >= current_templates->end)
        {
-         /* Special case for xchg %rax,%rax.  It is NOP and doesn't
-            need rex64.  */
-         if (i.operands != 2
-             || i.types [0] != (Acc | Reg64)
-             || i.types [1] != (Acc | Reg64)
-             || i.tm.base_opcode != 0x90)
-           i.rex |= REX_W;
+         as_bad (_("expecting string instruction after `%s'"),
+                 expecting_string_instruction);
+         return NULL;
        }
-
-      /* Size floating point instruction.  */
-      if (i.suffix == LONG_MNEM_SUFFIX)
-       if (i.tm.opcode_modifier & FloatMF)
-         i.tm.base_opcode ^= 4;
+      for (override.start = t; t < current_templates->end; ++t)
+       if (!t->opcode_modifier.isstring)
+         break;
+      override.end = t;
+      current_templates = &override;
     }
 
-  return 1;
+  return l;
 }
 
-static int
-check_byte_reg (void)
+static char *
+parse_operands (char *l, const char *mnemonic)
 {
-  int op;
+  char *token_start;
 
-  for (op = i.operands; --op >= 0;)
-    {
-      /* If this is an eight bit register, it's OK.  If it's the 16 or
-        32 bit version of an eight bit register, we will just use the
-        low portion, and that's OK too.  */
-      if (i.types[op] & Reg8)
-       continue;
+  /* 1 if operand is pending after ','.  */
+  unsigned int expecting_operand = 0;
 
-      /* movzx, movsx, pextrb and pinsrb should not generate this
-        warning.  */
-      if (intel_syntax
-         && (i.tm.base_opcode == 0xfb7
-             || i.tm.base_opcode == 0xfb6
-             || i.tm.base_opcode == 0x63
-             || i.tm.base_opcode == 0xfbe
-             || i.tm.base_opcode == 0xfbf
-             || i.tm.base_opcode == 0x660f3a14
-             || i.tm.base_opcode == 0x660f3a20))
-       continue;
+  /* Non-zero if operand parens not balanced.  */
+  unsigned int paren_not_balanced;
 
-      /* crc32 doesn't generate this warning.  */
-      if (i.tm.base_opcode == 0xf20f38f0)
-       continue;
+  while (*l != END_OF_INSN)
+    {
+      /* Skip optional white space before operand.  */
+      if (is_space_char (*l))
+       ++l;
+      if (!is_operand_char (*l) && *l != END_OF_INSN)
+       {
+         as_bad (_("invalid character %s before operand %d"),
+                 output_invalid (*l),
+                 i.operands + 1);
+         return NULL;
+       }
+      token_start = l; /* after white space */
+      paren_not_balanced = 0;
+      while (paren_not_balanced || *l != ',')
+       {
+         if (*l == END_OF_INSN)
+           {
+             if (paren_not_balanced)
+               {
+                 if (!intel_syntax)
+                   as_bad (_("unbalanced parenthesis in operand %d."),
+                           i.operands + 1);
+                 else
+                   as_bad (_("unbalanced brackets in operand %d."),
+                           i.operands + 1);
+                 return NULL;
+               }
+             else
+               break;  /* we are done */
+           }
+         else if (!is_operand_char (*l) && !is_space_char (*l))
+           {
+             as_bad (_("invalid character %s in operand %d"),
+                     output_invalid (*l),
+                     i.operands + 1);
+             return NULL;
+           }
+         if (!intel_syntax)
+           {
+             if (*l == '(')
+               ++paren_not_balanced;
+             if (*l == ')')
+               --paren_not_balanced;
+           }
+         else
+           {
+             if (*l == '[')
+               ++paren_not_balanced;
+             if (*l == ']')
+               --paren_not_balanced;
+           }
+         l++;
+       }
+      if (l != token_start)
+       {                       /* Yes, we've read in another operand.  */
+         unsigned int operand_ok;
+         this_operand = i.operands++;
+         i.types[this_operand].bitfield.unspecified = 1;
+         if (i.operands > MAX_OPERANDS)
+           {
+             as_bad (_("spurious operands; (%d operands/instruction max)"),
+                     MAX_OPERANDS);
+             return NULL;
+           }
+         /* Now parse operand adding info to 'i' as we go along.  */
+         END_STRING_AND_SAVE (l);
+
+         if (intel_syntax)
+           operand_ok =
+             i386_intel_operand (token_start,
+                                 intel_float_operand (mnemonic));
+         else
+           operand_ok = i386_att_operand (token_start);
 
-      if ((i.types[op] & WordReg) && i.op[op].regs->reg_num < 4)
+         RESTORE_END_STRING (l);
+         if (!operand_ok)
+           return NULL;
+       }
+      else
        {
-         /* Prohibit these changes in the 64bit mode, since the
-            lowering is more complicated.  */
-         if (flag_code == CODE_64BIT
-             && (i.tm.operand_types[op] & InOutPortReg) == 0)
+         if (expecting_operand)
            {
-             as_bad (_("Incorrect register `%s%s' used with `%c' suffix"),
-                     register_prefix, i.op[op].regs->reg_name,
-                     i.suffix);
-             return 0;
+           expecting_operand_after_comma:
+             as_bad (_("expecting operand after ','; got nothing"));
+             return NULL;
+           }
+         if (*l == ',')
+           {
+             as_bad (_("expecting operand before ','; got nothing"));
+             return NULL;
            }
-#if REGISTER_WARNINGS
-         if (!quiet_warnings
-             && (i.tm.operand_types[op] & InOutPortReg) == 0)
-           as_warn (_("using `%s%s' instead of `%s%s' due to `%c' suffix"),
-                    register_prefix,
-                    (i.op[op].regs + (i.types[op] & Reg16
-                                      ? 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] & (Reg | RegMMX | RegXMM
-                        | SReg2 | SReg3
-                        | Control | Debug | Test
-                        | FloatReg | FloatAcc))
+
+      /* Now *l must be either ',' or END_OF_INSN.  */
+      if (*l == ',')
        {
-         as_bad (_("`%s%s' not allowed with `%s%c'"),
-                 register_prefix,
-                 i.op[op].regs->reg_name,
-                 i.tm.name,
-                 i.suffix);
-         return 0;
+         if (*++l == END_OF_INSN)
+           {
+             /* Just skip it, if it's \n complain.  */
+             goto expecting_operand_after_comma;
+           }
+         expecting_operand = 1;
        }
     }
-  return 1;
+  return l;
 }
 
-static int
-check_long_reg (void)
+static void
+swap_2_operands (int xchg1, int xchg2)
 {
-  int op;
+  union i386_op temp_op;
+  i386_operand_type temp_type;
+  enum bfd_reloc_code_real temp_reloc;
 
-  for (op = i.operands; --op >= 0;)
-    /* Reject eight bit registers, except where the template requires
-       them. (eg. movzb)  */
-    if ((i.types[op] & Reg8) != 0
-       && (i.tm.operand_types[op] & (Reg16 | Reg32 | Acc)) != 0)
-      {
-       as_bad (_("`%s%s' not allowed with `%s%c'"),
-               register_prefix,
-               i.op[op].regs->reg_name,
-               i.tm.name,
-               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] & Reg16) != 0
-            && (i.tm.operand_types[op] & (Reg32 | Acc)) != 0)
-      {
-       /* 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
-       else
-         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
-      }
-  /* Warn if the r prefix on a general reg is missing.  */
-    else if ((i.types[op] & Reg64) != 0
-            && (i.tm.operand_types[op] & (Reg32 | Acc)) != 0)
-      {
-       if (intel_syntax
-           && i.tm.base_opcode == 0xf30f2d
-           && (i.types[0] & RegXMM) == 0)
-         {
-           /* cvtss2si converts DWORD memory to Reg64.  We want
-              REX byte. */
-           i.suffix = QWORD_MNEM_SUFFIX;
-         }
-       else
-         {
-           as_bad (_("Incorrect register `%s%s' used with `%c' suffix"),
-                   register_prefix, i.op[op].regs->reg_name,
-                   i.suffix);
-           return 0;
-         }
-      }
-  return 1;
+  temp_type = i.types[xchg2];
+  i.types[xchg2] = i.types[xchg1];
+  i.types[xchg1] = temp_type;
+  temp_op = i.op[xchg2];
+  i.op[xchg2] = i.op[xchg1];
+  i.op[xchg1] = temp_op;
+  temp_reloc = i.reloc[xchg2];
+  i.reloc[xchg2] = i.reloc[xchg1];
+  i.reloc[xchg1] = temp_reloc;
 }
 
-static int
-check_qword_reg (void)
+static void
+swap_operands (void)
+{
+  switch (i.operands)
+    {
+    case 5:
+    case 4:
+      swap_2_operands (1, i.operands - 2);
+    case 3:
+    case 2:
+      swap_2_operands (0, i.operands - 1);
+      break;
+    default:
+      abort ();
+    }
+
+  if (i.mem_operands == 2)
+    {
+      const seg_entry *temp_seg;
+      temp_seg = i.seg[0];
+      i.seg[0] = i.seg[1];
+      i.seg[1] = temp_seg;
+    }
+}
+
+/* Try to ensure constant immediates are represented in the smallest
+   opcode possible.  */
+static void
+optimize_imm (void)
 {
+  char guess_suffix = 0;
   int op;
 
-  for (op = i.operands; --op >= 0; )
-    /* Reject eight bit registers, except where the template requires
-       them. (eg. movzb)  */
-    if ((i.types[op] & Reg8) != 0
-       && (i.tm.operand_types[op] & (Reg16 | Reg32 | Acc)) != 0)
-      {
-       as_bad (_("`%s%s' not allowed with `%s%c'"),
-               register_prefix,
-               i.op[op].regs->reg_name,
-               i.tm.name,
-               i.suffix);
-       return 0;
-      }
-  /* Warn if the e prefix on a general reg is missing.  */
-    else if ((i.types[op] & (Reg16 | Reg32)) != 0
-            && (i.tm.operand_types[op] & (Reg32 | Acc)) != 0)
-      {
-       /* Prohibit these changes in the 64bit mode, since the
-          lowering is more complicated.  */
-       if (intel_syntax
-           && i.tm.base_opcode == 0xf20f2d
-           && (i.types[0] & RegXMM) == 0)
+  if (i.suffix)
+    guess_suffix = i.suffix;
+  else if (i.reg_operands)
+    {
+      /* Figure out a suffix from the last register operand specified.
+        We can't do this properly yet, ie. excluding InOutPortReg,
+        but the following works for instructions with immediates.
+        In any case, we can't set i.suffix yet.  */
+      for (op = i.operands; --op >= 0;)
+       if (i.types[op].bitfield.reg8)
          {
-           /* cvtsd2si converts QWORD memory to Reg32.  We don't want
-              REX byte. */
-           i.suffix = LONG_MNEM_SUFFIX;
+           guess_suffix = BYTE_MNEM_SUFFIX;
+           break;
          }
-       else
+       else if (i.types[op].bitfield.reg16)
          {
-           as_bad (_("Incorrect register `%s%s' used with `%c' suffix"),
-                   register_prefix, i.op[op].regs->reg_name,
-                   i.suffix);
-           return 0;
+           guess_suffix = WORD_MNEM_SUFFIX;
+           break;
+         }
+       else if (i.types[op].bitfield.reg32)
+         {
+           guess_suffix = LONG_MNEM_SUFFIX;
+           break;
+         }
+       else if (i.types[op].bitfield.reg64)
+         {
+           guess_suffix = QWORD_MNEM_SUFFIX;
+           break;
+         }
+    }
+  else if ((flag_code == CODE_16BIT) ^ (i.prefix[DATA_PREFIX] != 0))
+    guess_suffix = WORD_MNEM_SUFFIX;
+
+  for (op = i.operands; --op >= 0;)
+    if (operand_type_check (i.types[op], imm))
+      {
+       switch (i.op[op].imms->X_op)
+         {
+         case O_constant:
+           /* If a suffix is given, this operand may be shortened.  */
+           switch (guess_suffix)
+             {
+             case LONG_MNEM_SUFFIX:
+               i.types[op].bitfield.imm32 = 1;
+               i.types[op].bitfield.imm64 = 1;
+               break;
+             case WORD_MNEM_SUFFIX:
+               i.types[op].bitfield.imm16 = 1;
+               i.types[op].bitfield.imm32 = 1;
+               i.types[op].bitfield.imm32s = 1;
+               i.types[op].bitfield.imm64 = 1;
+               break;
+             case BYTE_MNEM_SUFFIX:
+               i.types[op].bitfield.imm8 = 1;
+               i.types[op].bitfield.imm8s = 1;
+               i.types[op].bitfield.imm16 = 1;
+               i.types[op].bitfield.imm32 = 1;
+               i.types[op].bitfield.imm32s = 1;
+               i.types[op].bitfield.imm64 = 1;
+               break;
+             }
+
+           /* If this operand is at most 16 bits, convert it
+              to a signed 16 bit number before trying to see
+              whether it will fit in an even smaller size.
+              This allows a 16-bit operand such as $0xffe0 to
+              be recognised as within Imm8S range.  */
+           if ((i.types[op].bitfield.imm16)
+               && (i.op[op].imms->X_add_number & ~(offsetT) 0xffff) == 0)
+             {
+               i.op[op].imms->X_add_number =
+                 (((i.op[op].imms->X_add_number & 0xffff) ^ 0x8000) - 0x8000);
+             }
+           if ((i.types[op].bitfield.imm32)
+               && ((i.op[op].imms->X_add_number & ~(((offsetT) 2 << 31) - 1))
+                   == 0))
+             {
+               i.op[op].imms->X_add_number = ((i.op[op].imms->X_add_number
+                                               ^ ((offsetT) 1 << 31))
+                                              - ((offsetT) 1 << 31));
+             }
+           i.types[op]
+             = operand_type_or (i.types[op],
+                                smallest_imm_type (i.op[op].imms->X_add_number));
+
+           /* We must avoid matching of Imm32 templates when 64bit
+              only immediate is available.  */
+           if (guess_suffix == QWORD_MNEM_SUFFIX)
+             i.types[op].bitfield.imm32 = 0;
+           break;
+
+         case O_absent:
+         case O_register:
+           abort ();
+
+           /* Symbols and expressions.  */
+         default:
+           /* Convert symbolic operand to proper sizes for matching, but don't
+              prevent matching a set of insns that only supports sizes other
+              than those matching the insn suffix.  */
+           {
+             i386_operand_type mask, allowed;
+             const insn_template *t;
+
+             operand_type_set (&mask, 0);
+             operand_type_set (&allowed, 0);
+
+             for (t = current_templates->start;
+                  t < current_templates->end;
+                  ++t)
+               allowed = operand_type_or (allowed,
+                                          t->operand_types[op]);
+             switch (guess_suffix)
+               {
+               case QWORD_MNEM_SUFFIX:
+                 mask.bitfield.imm64 = 1;
+                 mask.bitfield.imm32s = 1;
+                 break;
+               case LONG_MNEM_SUFFIX:
+                 mask.bitfield.imm32 = 1;
+                 break;
+               case WORD_MNEM_SUFFIX:
+                 mask.bitfield.imm16 = 1;
+                 break;
+               case BYTE_MNEM_SUFFIX:
+                 mask.bitfield.imm8 = 1;
+                 break;
+               default:
+                 break;
+               }
+             allowed = operand_type_and (mask, allowed);
+             if (!operand_type_all_zero (&allowed))
+               i.types[op] = operand_type_and (i.types[op], mask);
+           }
+           break;
          }
       }
-  return 1;
 }
 
-static int
-check_word_reg (void)
+/* Try to use the smallest displacement type too.  */
+static void
+optimize_disp (void)
 {
   int op;
+
   for (op = i.operands; --op >= 0;)
-    /* Reject eight bit registers, except where the template requires
-       them. (eg. movzb)  */
-    if ((i.types[op] & Reg8) != 0
-       && (i.tm.operand_types[op] & (Reg16 | Reg32 | Acc)) != 0)
-      {
-       as_bad (_("`%s%s' not allowed with `%s%c'"),
-               register_prefix,
-               i.op[op].regs->reg_name,
-               i.tm.name,
-               i.suffix);
-       return 0;
-      }
-  /* Warn if the e prefix on a general reg is present.  */
-    else if ((!quiet_warnings || flag_code == CODE_64BIT)
-            && (i.types[op] & Reg32) != 0
-            && (i.tm.operand_types[op] & (Reg16 | Acc)) != 0)
+    if (operand_type_check (i.types[op], disp))
       {
-       /* Prohibit these changes in the 64bit mode, since the
-          lowering is more complicated.  */
-       if (flag_code == CODE_64BIT)
+       if (i.op[op].disps->X_op == O_constant)
          {
-           as_bad (_("Incorrect register `%s%s' used with `%c' suffix"),
-                   register_prefix, i.op[op].regs->reg_name,
-                   i.suffix);
-           return 0;
+           offsetT disp = i.op[op].disps->X_add_number;
+
+           if (i.types[op].bitfield.disp16
+               && (disp & ~(offsetT) 0xffff) == 0)
+             {
+               /* If this operand is at most 16 bits, convert
+                  to a signed 16 bit number and don't use 64bit
+                  displacement.  */
+               disp = (((disp & 0xffff) ^ 0x8000) - 0x8000);
+               i.types[op].bitfield.disp64 = 0;
+             }
+           if (i.types[op].bitfield.disp32
+               && (disp & ~(((offsetT) 2 << 31) - 1)) == 0)
+             {
+               /* If this operand is at most 32 bits, convert
+                  to a signed 32 bit number and don't use 64bit
+                  displacement.  */
+               disp &= (((offsetT) 2 << 31) - 1);
+               disp = (disp ^ ((offsetT) 1 << 31)) - ((addressT) 1 << 31);
+               i.types[op].bitfield.disp64 = 0;
+             }
+           if (!disp && i.types[op].bitfield.baseindex)
+             {
+               i.types[op].bitfield.disp8 = 0;
+               i.types[op].bitfield.disp16 = 0;
+               i.types[op].bitfield.disp32 = 0;
+               i.types[op].bitfield.disp32s = 0;
+               i.types[op].bitfield.disp64 = 0;
+               i.op[op].disps = 0;
+               i.disp_operands--;
+             }
+           else if (flag_code == CODE_64BIT)
+             {
+               if (fits_in_signed_long (disp))
+                 {
+                   i.types[op].bitfield.disp64 = 0;
+                   i.types[op].bitfield.disp32s = 1;
+                 }
+               if (fits_in_unsigned_long (disp))
+                 i.types[op].bitfield.disp32 = 1;
+             }
+           if ((i.types[op].bitfield.disp32
+                || i.types[op].bitfield.disp32s
+                || i.types[op].bitfield.disp16)
+               && fits_in_signed_byte (disp))
+             i.types[op].bitfield.disp8 = 1;
          }
-       else
-#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
+       else if (i.reloc[op] == BFD_RELOC_386_TLS_DESC_CALL
+                || i.reloc[op] == BFD_RELOC_X86_64_TLSDESC_CALL)
+         {
+           fix_new_exp (frag_now, frag_more (0) - frag_now->fr_literal, 0,
+                        i.op[op].disps, 0, i.reloc[op]);
+           i.types[op].bitfield.disp8 = 0;
+           i.types[op].bitfield.disp16 = 0;
+           i.types[op].bitfield.disp32 = 0;
+           i.types[op].bitfield.disp32s = 0;
+           i.types[op].bitfield.disp64 = 0;
+         }
+       else
+         /* We only support 64bit displacement on constants.  */
+         i.types[op].bitfield.disp64 = 0;
       }
-  return 1;
 }
 
-static int
-finalize_imm (void)
+static const insn_template *
+match_template (void)
 {
-  unsigned int overlap0, overlap1, overlap2;
+  /* Points to template once we've found it.  */
+  const insn_template *t;
+  i386_operand_type overlap0, overlap1, overlap2, overlap3;
+  i386_operand_type overlap4;
+  unsigned int found_reverse_match;
+  i386_opcode_modifier suffix_check;
+  i386_operand_type operand_types [MAX_OPERANDS];
+  int addr_prefix_disp;
+  unsigned int j;
+  unsigned int found_cpu_match;
+  unsigned int check_register;
+
+#if MAX_OPERANDS != 5
+# error "MAX_OPERANDS must be 5."
+#endif
+
+  found_reverse_match = 0;
+  addr_prefix_disp = -1;
 
-  overlap0 = i.types[0] & i.tm.operand_types[0];
-  if ((overlap0 & (Imm8 | Imm8S | Imm16 | Imm32 | Imm32S | Imm64))
-      && overlap0 != Imm8 && overlap0 != Imm8S
-      && overlap0 != Imm16 && overlap0 != Imm32S
-      && overlap0 != Imm32 && overlap0 != Imm64)
+  memset (&suffix_check, 0, sizeof (suffix_check));
+  if (i.suffix == BYTE_MNEM_SUFFIX)
+    suffix_check.no_bsuf = 1;
+  else if (i.suffix == WORD_MNEM_SUFFIX)
+    suffix_check.no_wsuf = 1;
+  else if (i.suffix == SHORT_MNEM_SUFFIX)
+    suffix_check.no_ssuf = 1;
+  else if (i.suffix == LONG_MNEM_SUFFIX)
+    suffix_check.no_lsuf = 1;
+  else if (i.suffix == QWORD_MNEM_SUFFIX)
+    suffix_check.no_qsuf = 1;
+  else if (i.suffix == LONG_DOUBLE_MNEM_SUFFIX)
+    suffix_check.no_ldsuf = 1;
+
+  for (t = current_templates->start; t < current_templates->end; t++)
     {
-      if (i.suffix)
-       {
-         overlap0 &= (i.suffix == BYTE_MNEM_SUFFIX
-                      ? Imm8 | Imm8S
-                      : (i.suffix == WORD_MNEM_SUFFIX
-                         ? Imm16
-                         : (i.suffix == QWORD_MNEM_SUFFIX
-                            ? Imm64 | Imm32S
-                            : Imm32)));
-       }
-      else if (overlap0 == (Imm16 | Imm32S | Imm32)
-              || overlap0 == (Imm16 | Imm32)
-              || overlap0 == (Imm16 | Imm32S))
-       {
-         overlap0 = ((flag_code == CODE_16BIT) ^ (i.prefix[DATA_PREFIX] != 0)
-                     ? Imm16 : Imm32S);
-       }
-      if (overlap0 != Imm8 && overlap0 != Imm8S
-         && overlap0 != Imm16 && overlap0 != Imm32S
-         && overlap0 != Imm32 && overlap0 != Imm64)
-       {
-         as_bad (_("no instruction mnemonic suffix given; "
-                   "can't determine immediate size"));
-         return 0;
-       }
-    }
-  i.types[0] = overlap0;
+      addr_prefix_disp = -1;
 
-  overlap1 = i.types[1] & i.tm.operand_types[1];
-  if ((overlap1 & (Imm8 | Imm8S | Imm16 | Imm32S | Imm32 | Imm64))
-      && overlap1 != Imm8 && overlap1 != Imm8S
-      && overlap1 != Imm16 && overlap1 != Imm32S
-      && overlap1 != Imm32 && overlap1 != Imm64)
-    {
-      if (i.suffix)
-       {
-         overlap1 &= (i.suffix == BYTE_MNEM_SUFFIX
-                      ? Imm8 | Imm8S
-                      : (i.suffix == WORD_MNEM_SUFFIX
-                         ? Imm16
-                         : (i.suffix == QWORD_MNEM_SUFFIX
-                            ? Imm64 | Imm32S
-                            : Imm32)));
-       }
-      else if (overlap1 == (Imm16 | Imm32 | Imm32S)
-              || overlap1 == (Imm16 | Imm32)
-              || overlap1 == (Imm16 | Imm32S))
-       {
-         overlap1 = ((flag_code == CODE_16BIT) ^ (i.prefix[DATA_PREFIX] != 0)
-                     ? Imm16 : Imm32S);
-       }
-      if (overlap1 != Imm8 && overlap1 != Imm8S
-         && overlap1 != Imm16 && overlap1 != Imm32S
-         && overlap1 != Imm32 && overlap1 != Imm64)
-       {
-         as_bad (_("no instruction mnemonic suffix given; "
-                   "can't determine immediate size %x %c"),
-                 overlap1, i.suffix);
-         return 0;
-       }
-    }
-  i.types[1] = overlap1;
+      /* Must have right number of operands.  */
+      if (i.operands != t->operands)
+       continue;
 
-  overlap2 = i.types[2] & i.tm.operand_types[2];
-  assert ((overlap2 & Imm) == 0);
-  i.types[2] = overlap2;
+      /* Check processor support.  */
+      found_cpu_match = (cpu_flags_match (t)
+                        == CPU_FLAGS_PERFECT_MATCH);
+      if (!found_cpu_match)
+       continue;
 
-  return 1;
-}
+      /* Check old gcc support. */
+      if (!old_gcc && t->opcode_modifier.oldgcc)
+       continue;
 
-static int
-process_operands (void)
-{
-  /* Default segment register this instruction will use for memory
-     accesses.  0 means unknown.  This is only for optimizing out
-     unnecessary segment overrides.  */
-  const seg_entry *default_seg = 0;
+      /* Check AT&T mnemonic.   */
+      if (intel_mnemonic && t->opcode_modifier.attmnemonic)
+       continue;
+
+      /* Check AT&T syntax Intel syntax.   */
+      if ((intel_syntax && t->opcode_modifier.attsyntax)
+         || (!intel_syntax && t->opcode_modifier.intelsyntax))
+       continue;
+
+      /* Check the suffix, except for some instructions in intel mode.  */
+      if ((!intel_syntax || !t->opcode_modifier.ignoresize)
+         && ((t->opcode_modifier.no_bsuf && suffix_check.no_bsuf)
+             || (t->opcode_modifier.no_wsuf && suffix_check.no_wsuf)
+             || (t->opcode_modifier.no_lsuf && suffix_check.no_lsuf)
+             || (t->opcode_modifier.no_ssuf && suffix_check.no_ssuf)
+             || (t->opcode_modifier.no_qsuf && suffix_check.no_qsuf)
+             || (t->opcode_modifier.no_ldsuf && suffix_check.no_ldsuf)))
+       continue;
+
+      if (!operand_size_match (t))
+       continue;
+
+      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
+         && (intel_syntax
+             ? (!t->opcode_modifier.ignoresize
+                && !intel_float_operand (t->name))
+             : intel_float_operand (t->name) != 2)
+         && ((!operand_types[0].bitfield.regmmx
+              && !operand_types[0].bitfield.regxmm
+              && !operand_types[0].bitfield.regymm)
+             || (!operand_types[t->operands > 1].bitfield.regmmx
+                 && !!operand_types[t->operands > 1].bitfield.regxmm
+                 && !!operand_types[t->operands > 1].bitfield.regymm))
+         && (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.regmmx
+                   && !operand_types[0].bitfield.regxmm)
+                  || (!operand_types[t->operands > 1].bitfield.regmmx
+                      && !!operand_types[t->operands > 1].bitfield.regxmm)))
+       continue;
 
-  /* The imul $imm, %reg instruction is converted into
-     imul $imm, %reg, %reg, and the clr %reg instruction
-     is converted into xor %reg, %reg.  */
-  if (i.tm.opcode_modifier & RegKludge)
-    {
-       if ((i.tm.cpu_flags & CpuSSE4_1))
-        {
-          /* The first operand in instruction blendvpd, blendvps and
-             pblendvb in SSE4.1 is implicit and must be xmm0.  */
-          assert (i.operands == 3
-                  && i.reg_operands >= 2
-                  && i.types[0] == RegXMM);
-          if (i.op[0].regs->reg_num != 0)
-            {
-              if (intel_syntax)
-                as_bad (_("the last operand of `%s' must be `%sxmm0'"),
-                        i.tm.name, register_prefix);
-              else
-                as_bad (_("the first operand of `%s' must be `%sxmm0'"),
-                        i.tm.name, register_prefix);
-              return 0;
-            }
-          i.op[0] = i.op[1];
-          i.op[1] = i.op[2];
-          i.types[0] = i.types[1];
-          i.types[1] = i.types[2];
-          i.operands--;
-          i.reg_operands--;
-
-          /* We need to adjust fields in i.tm since they are used by
-             build_modrm_byte.  */
-          i.tm.operand_types [0] = i.tm.operand_types [1];
-          i.tm.operand_types [1] = i.tm.operand_types [2];
-          i.tm.operands--;
-        }
-       else
-        {
-          unsigned int first_reg_op = (i.types[0] & Reg) ? 0 : 1;
-          /* Pretend we saw the extra register operand.  */
-          assert (i.reg_operands == 1
-                  && i.op[first_reg_op + 1].regs == 0);
-          i.op[first_reg_op + 1].regs = i.op[first_reg_op].regs;
-          i.types[first_reg_op + 1] = i.types[first_reg_op];
-          i.operands++;
-          i.reg_operands++;
-        }
-    }
-
-  if (i.tm.opcode_modifier & ShortForm)
-    {
-      if (i.types[0] & (SReg2 | SReg3))
+      /* Do not verify operands when there are none.  */
+      else
        {
-         if (i.tm.base_opcode == POP_SEG_SHORT
-             && i.op[0].regs->reg_num == 1)
+         if (!t->operands)
+           /* We've found a match; break out of loop.  */
+           break;
+       }
+
+      /* Address size prefix will turn Disp64/Disp32/Disp16 operand
+        into Disp32/Disp16/Disp32 operand.  */
+      if (i.prefix[ADDR_PREFIX] != 0)
+         {
+           /* There should be only one Disp operand.  */
+           switch (flag_code)
            {
-             as_bad (_("you can't `pop %%cs'"));
-             return 0;
+           case CODE_16BIT:
+             for (j = 0; j < MAX_OPERANDS; j++)
+               {
+                 if (operand_types[j].bitfield.disp16)
+                   {
+                     addr_prefix_disp = j;
+                     operand_types[j].bitfield.disp32 = 1;
+                     operand_types[j].bitfield.disp16 = 0;
+                     break;
+                   }
+               }
+             break;
+           case CODE_32BIT:
+             for (j = 0; j < MAX_OPERANDS; j++)
+               {
+                 if (operand_types[j].bitfield.disp32)
+                   {
+                     addr_prefix_disp = j;
+                     operand_types[j].bitfield.disp32 = 0;
+                     operand_types[j].bitfield.disp16 = 1;
+                     break;
+                   }
+               }
+             break;
+           case CODE_64BIT:
+             for (j = 0; j < MAX_OPERANDS; j++)
+               {
+                 if (operand_types[j].bitfield.disp64)
+                   {
+                     addr_prefix_disp = j;
+                     operand_types[j].bitfield.disp64 = 0;
+                     operand_types[j].bitfield.disp32 = 1;
+                     break;
+                   }
+               }
+             break;
            }
-         i.tm.base_opcode |= (i.op[0].regs->reg_num << 3);
-         if ((i.op[0].regs->reg_flags & RegRex) != 0)
-           i.rex |= REX_B;
-       }
-      else
+         }
+
+      /* We check register size only if size of operands can be
+        encoded the canonical way.  */
+      check_register = t->opcode_modifier.w;
+      overlap0 = operand_type_and (i.types[0], operand_types[0]);
+      switch (t->operands)
        {
-         /* The register or float register operand is in operand 0 or 1.  */
-         unsigned int op = (i.types[0] & (Reg | FloatReg)) ? 0 : 1;
-         /* Register goes in low 3 bits of opcode.  */
-         i.tm.base_opcode |= i.op[op].regs->reg_num;
-         if ((i.op[op].regs->reg_flags & RegRex) != 0)
-           i.rex |= REX_B;
-         if (!quiet_warnings && (i.tm.opcode_modifier & Ugh) != 0)
+       case 1:
+         if (!operand_type_match (overlap0, i.types[0]))
+           continue;
+         break;
+       case 2:
+         /* xchg %eax, %eax is a special case. It is an aliase 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
+             && operand_type_equal (&i.types [0], &acc32)
+             && operand_type_equal (&i.types [1], &acc32))
+           continue;
+         if (i.swap_operand)
            {
-             /* Warn about some common errors, but press on regardless.
-                The first case can be generated by gcc (<= 2.8.1).  */
-             if (i.operands == 2)
+             /* If we swap operand in encoding, we either match
+                the next one or reverse direction of operands.  */
+             if (t->opcode_modifier.s)
+               continue;
+             else if (t->opcode_modifier.d)
+               goto check_reverse;
+           }
+
+       case 3:
+         /* If we swap operand in encoding, we match the next one.  */
+         if (i.swap_operand && t->opcode_modifier.s)
+           continue;
+       case 4:
+       case 5:
+         overlap1 = operand_type_and (i.types[1], operand_types[1]);
+         if (!operand_type_match (overlap0, i.types[0])
+             || !operand_type_match (overlap1, i.types[1])
+             || (check_register
+                 && !operand_type_register_match (overlap0, i.types[0],
+                                                  operand_types[0],
+                                                  overlap1, i.types[1],
+                                                  operand_types[1])))
+           {
+             /* Check if other direction is valid ...  */
+             if (!t->opcode_modifier.d && !t->opcode_modifier.floatd)
+               continue;
+
+check_reverse:
+             /* Try reversing direction of operands.  */
+             overlap0 = operand_type_and (i.types[0], operand_types[1]);
+             overlap1 = operand_type_and (i.types[1], operand_types[0]);
+             if (!operand_type_match (overlap0, i.types[0])
+                 || !operand_type_match (overlap1, i.types[1])
+                 || (check_register
+                     && !operand_type_register_match (overlap0,
+                                                      i.types[0],
+                                                      operand_types[1],
+                                                      overlap1,
+                                                      i.types[1],
+                                                      operand_types[0])))
                {
-                 /* Reversed arguments on faddp, fsubp, etc.  */
-                 as_warn (_("translating to `%s %s%s,%s%s'"), i.tm.name,
-                          register_prefix, i.op[1].regs->reg_name,
-                          register_prefix, i.op[0].regs->reg_name);
+                 /* Does not match either direction.  */
+                 continue;
                }
+             /* found_reverse_match holds which of D or FloatDR
+                we've found.  */
+             if (t->opcode_modifier.d)
+               found_reverse_match = Opcode_D;
+             else if (t->opcode_modifier.floatd)
+               found_reverse_match = Opcode_FloatD;
              else
+               found_reverse_match = 0;
+             if (t->opcode_modifier.floatr)
+               found_reverse_match |= Opcode_FloatR;
+           }
+         else
+           {
+             /* Found a forward 2 operand match here.  */
+             switch (t->operands)
                {
-                 /* Extraneous `l' suffix on fp insn.  */
-                 as_warn (_("translating to `%s %s%s'"), i.tm.name,
-                          register_prefix, i.op[0].regs->reg_name);
+               case 5:
+                 overlap4 = operand_type_and (i.types[4],
+                                              operand_types[4]);
+               case 4:
+                 overlap3 = operand_type_and (i.types[3],
+                                              operand_types[3]);
+               case 3:
+                 overlap2 = operand_type_and (i.types[2],
+                                              operand_types[2]);
+                 break;
+               }
+
+             switch (t->operands)
+               {
+               case 5:
+                 if (!operand_type_match (overlap4, i.types[4])
+                     || !operand_type_register_match (overlap3,
+                                                      i.types[3],
+                                                      operand_types[3],
+                                                      overlap4,
+                                                      i.types[4],
+                                                      operand_types[4]))
+                   continue;
+               case 4:
+                 if (!operand_type_match (overlap3, i.types[3])
+                     || (check_register
+                         && !operand_type_register_match (overlap2,
+                                                          i.types[2],
+                                                          operand_types[2],
+                                                          overlap3,
+                                                          i.types[3],
+                                                          operand_types[3])))
+                   continue;
+               case 3:
+                 /* Here we make use of the fact that there are no
+                    reverse match 3 operand instructions, and all 3
+                    operand instructions only need to be checked for
+                    register consistency between operands 2 and 3.  */
+                 if (!operand_type_match (overlap2, i.types[2])
+                     || (check_register
+                         && !operand_type_register_match (overlap1,
+                                                          i.types[1],
+                                                          operand_types[1],
+                                                          overlap2,
+                                                          i.types[2],
+                                                          operand_types[2])))
+                   continue;
+                 break;
                }
            }
+         /* Found either forward/reverse 2, 3 or 4 operand match here:
+            slip through to break.  */
+       }
+      if (!found_cpu_match)
+       {
+         found_reverse_match = 0;
+         continue;
        }
-    }
-  else if (i.tm.opcode_modifier & Modrm)
-    {
-      /* The opcode is completed (modulo i.tm.extension_opcode which
-        must be put into the modrm byte).  Now, we make the modrm and
-        index base bytes based on all the info we've collected.  */
 
-      default_seg = build_modrm_byte ();
+      /* We've found a match; break out of loop.  */
+      break;
     }
-  else if ((i.tm.base_opcode & ~0x3) == MOV_AX_DISP32)
+
+  if (t == current_templates->end)
     {
-      default_seg = &ds;
+      /* We found no match.  */
+      if (intel_syntax)
+       as_bad (_("ambiguous operand size or operands invalid for `%s'"),
+               current_templates->start->name);
+      else
+       as_bad (_("suffix or operands invalid for `%s'"),
+               current_templates->start->name);
+      return NULL;
     }
-  else if ((i.tm.opcode_modifier & IsString) != 0)
+
+  if (!quiet_warnings)
     {
-      /* For the string instructions that allow a segment override
-        on one of their operands, the default segment is ds.  */
-      default_seg = &ds;
+      if (!intel_syntax
+         && (i.types[0].bitfield.jumpabsolute
+             != operand_types[0].bitfield.jumpabsolute))
+       {
+         as_warn (_("indirect %s without `*'"), t->name);
+       }
+
+      if (t->opcode_modifier.isprefix
+         && t->opcode_modifier.ignoresize)
+       {
+         /* Warn them that a data or address size prefix doesn't
+            affect assembly of the next line of code.  */
+         as_warn (_("stand-alone `%s' prefix"), t->name);
+       }
     }
 
-  if ((i.tm.base_opcode == 0x8d /* lea */
-       || (i.tm.cpu_flags & CpuSVME))
-      && i.seg[0] && !quiet_warnings)
-    as_warn (_("segment override on `%s' is ineffectual"), i.tm.name);
+  /* Copy the template we found.  */
+  i.tm = *t;
 
-  /* 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))
+  if (addr_prefix_disp != -1)
+    i.tm.operand_types[addr_prefix_disp]
+      = operand_types[addr_prefix_disp];
+
+  if (found_reverse_match)
     {
-      if (!add_prefix (i.seg[0]->seg_prefix))
-       return 0;
+      /* If we found a reverse match we must alter the opcode
+        direction bit.  found_reverse_match holds bits to change
+        (different for int & float insns).  */
+
+      i.tm.base_opcode ^= found_reverse_match;
+
+      i.tm.operand_types[0] = operand_types[1];
+      i.tm.operand_types[1] = operand_types[0];
     }
-  return 1;
+
+  return t;
 }
 
-static const seg_entry *
-build_modrm_byte (void)
+static int
+check_string (void)
 {
-  const seg_entry *default_seg = 0;
-
-  /* i.reg_operands MUST be the number of real register operands;
-     implicit registers do not count.  */
-  if (i.reg_operands == 2)
+  int mem_op = operand_type_check (i.types[0], anymem) ? 0 : 1;
+  if (i.tm.operand_types[mem_op].bitfield.esseg)
     {
-      unsigned int source, dest;
-
-      switch (i.operands)
+      if (i.seg[0] != NULL && i.seg[0] != &es)
        {
-       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). */
-         assert (i.imm_operands == 1
-                 || (i.imm_operands == 0
-                     && (i.types[0] & ShiftCount)));
-         source = (i.types[0] & (Imm | ShiftCount)) ? 1 : 0;
-         break;
-       case 4:
-         /* When there are 4 operands, the first two must be immediate
-            operands. The source operand will be the 3rd one.  */
-         assert (i.imm_operands == 2
-                 && (i.types[0] & Imm)
-                 && (i.types[1] & Imm));
-         source = 2;
-         break;
-       default:
-         abort ();
+         as_bad (_("`%s' operand %d must use `%ses' segment"),
+                 i.tm.name,
+                 mem_op + 1,
+                 register_prefix);
+         return 0;
        }
-
-      dest = source + 1;
-
-      i.rm.mode = 3;
-      /* One of the register operands will be encoded in the i.tm.reg
-        field, the other in the combined i.tm.mode and i.tm.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.operand_types[dest] & (AnyMem | RegMem)) == 0)
-       {
-         i.rm.reg = i.op[dest].regs->reg_num;
-         i.rm.regmem = i.op[source].regs->reg_num;
-         if ((i.op[dest].regs->reg_flags & RegRex) != 0)
-           i.rex |= REX_R;
-         if ((i.op[source].regs->reg_flags & RegRex) != 0)
-           i.rex |= REX_B;
-       }
-      else
-       {
-         i.rm.reg = i.op[source].regs->reg_num;
-         i.rm.regmem = i.op[dest].regs->reg_num;
-         if ((i.op[dest].regs->reg_flags & RegRex) != 0)
-           i.rex |= REX_B;
-         if ((i.op[source].regs->reg_flags & RegRex) != 0)
-           i.rex |= REX_R;
-       }
-      if (flag_code != CODE_64BIT && (i.rex & (REX_R | REX_B)))
+      /* There's only ever one segment override allowed per instruction.
+        This instruction possibly has a legal segment override on the
+        second operand, so copy the segment to where non-string
+        instructions store it, allowing common code.  */
+      i.seg[0] = i.seg[1];
+    }
+  else if (i.tm.operand_types[mem_op + 1].bitfield.esseg)
+    {
+      if (i.seg[1] != NULL && i.seg[1] != &es)
        {
-         if (!((i.types[0] | i.types[1]) & Control))
-           abort ();
-         i.rex &= ~(REX_R | REX_B);
-         add_prefix (LOCK_PREFIX_OPCODE);
+         as_bad (_("`%s' operand %d must use `%ses' segment"),
+                 i.tm.name,
+                 mem_op + 2,
+                 register_prefix);
+         return 0;
        }
     }
-  else
-    {                  /* If it's not 2 reg operands...  */
-      if (i.mem_operands)
-       {
-         unsigned int fake_zero_displacement = 0;
-         unsigned int op;
-
-         for (op = 0; op < i.operands; op++)
-           if ((i.types[op] & AnyMem))
-             break;
-         assert (op < i.operands);
-
-         default_seg = &ds;
+  return 1;
+}
 
-         if (i.base_reg == 0)
-           {
-             i.rm.mode = 0;
-             if (!i.disp_operands)
-               fake_zero_displacement = 1;
-             if (i.index_reg == 0)
-               {
-                 /* Operand is just <disp>  */
-                 if (flag_code == CODE_64BIT)
-                   {
-                     /* 64bit mode overwrites the 32bit absolute
-                        addressing by RIP relative addressing and
-                        absolute addressing is encoded by one of the
-                        redundant SIB forms.  */
-                     i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING;
-                     i.sib.base = NO_BASE_REGISTER;
-                     i.sib.index = NO_INDEX_REGISTER;
-                     i.types[op] = ((i.prefix[ADDR_PREFIX] == 0)
-                                    ? Disp32S : Disp32);
-                   }
-                 else if ((flag_code == CODE_16BIT)
-                          ^ (i.prefix[ADDR_PREFIX] != 0))
-                   {
-                     i.rm.regmem = NO_BASE_REGISTER_16;
-                     i.types[op] = Disp16;
-                   }
-                 else
-                   {
-                     i.rm.regmem = NO_BASE_REGISTER;
-                     i.types[op] = Disp32;
-                   }
-               }
-             else /* !i.base_reg && i.index_reg  */
-               {
-                 i.sib.index = i.index_reg->reg_num;
-                 i.sib.base = NO_BASE_REGISTER;
-                 i.sib.scale = i.log2_scale_factor;
-                 i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING;
-                 i.types[op] &= ~Disp;
-                 if (flag_code != CODE_64BIT)
-                   i.types[op] |= Disp32;      /* Must be 32 bit */
-                 else
-                   i.types[op] |= Disp32S;
-                 if ((i.index_reg->reg_flags & RegRex) != 0)
-                   i.rex |= REX_X;
-               }
-           }
-         /* RIP addressing for 64bit mode.  */
-         else if (i.base_reg->reg_type == BaseIndex)
+static int
+process_suffix (void)
+{
+  /* If matched instruction specifies an explicit instruction mnemonic
+     suffix, use it.  */
+  if (i.tm.opcode_modifier.size16)
+    i.suffix = WORD_MNEM_SUFFIX;
+  else if (i.tm.opcode_modifier.size32)
+    i.suffix = LONG_MNEM_SUFFIX;
+  else if (i.tm.opcode_modifier.size64)
+    i.suffix = QWORD_MNEM_SUFFIX;
+  else if (i.reg_operands)
+    {
+      /* If there's no instruction mnemonic suffix we try to invent one
+        based on register operands.  */
+      if (!i.suffix)
+       {
+         /* We take i.suffix from the last register operand specified,
+            Destination register type is more significant than source
+            register type.  crc32 in SSE4.2 prefers source register
+            type. */
+         if (i.tm.base_opcode == 0xf20f38f1)
            {
-             i.rm.regmem = NO_BASE_REGISTER;
-             i.types[op] &= ~ Disp;
-             i.types[op] |= Disp32S;
-             i.flags[op] |= Operand_PCrel;
-             if (! i.disp_operands)
-               fake_zero_displacement = 1;
+             if (i.types[0].bitfield.reg16)
+               i.suffix = WORD_MNEM_SUFFIX;
+             else if (i.types[0].bitfield.reg32)
+               i.suffix = LONG_MNEM_SUFFIX;
+             else if (i.types[0].bitfield.reg64)
+               i.suffix = QWORD_MNEM_SUFFIX;
            }
-         else if (i.base_reg->reg_type & Reg16)
+         else if (i.tm.base_opcode == 0xf20f38f0)
            {
-             switch (i.base_reg->reg_num)
-               {
-               case 3: /* (%bx)  */
-                 if (i.index_reg == 0)
-                   i.rm.regmem = 7;
-                 else /* (%bx,%si) -> 0, or (%bx,%di) -> 1  */
-                   i.rm.regmem = i.index_reg->reg_num - 6;
-                 break;
-               case 5: /* (%bp)  */
-                 default_seg = &ss;
-                 if (i.index_reg == 0)
-                   {
-                     i.rm.regmem = 6;
-                     if ((i.types[op] & Disp) == 0)
-                       {
-                         /* fake (%bp) into 0(%bp)  */
-                         i.types[op] |= Disp8;
-                         fake_zero_displacement = 1;
-                       }
-                   }
-                 else /* (%bp,%si) -> 2, or (%bp,%di) -> 3  */
-                   i.rm.regmem = i.index_reg->reg_num - 6 + 2;
-                 break;
-               default: /* (%si) -> 4 or (%di) -> 5  */
-                 i.rm.regmem = i.base_reg->reg_num - 6 + 4;
-               }
-             i.rm.mode = mode_from_disp_size (i.types[op]);
+             if (i.types[0].bitfield.reg8)
+               i.suffix = BYTE_MNEM_SUFFIX;
            }
-         else /* i.base_reg and 32/64 bit mode  */
+
+         if (!i.suffix)
            {
-             if (flag_code == CODE_64BIT
-                 && (i.types[op] & Disp))
-               i.types[op] = ((i.types[op] & Disp8)
-                              | (i.prefix[ADDR_PREFIX] == 0
-                                 ? Disp32S : Disp32));
+             int op;
 
-             i.rm.regmem = i.base_reg->reg_num;
-             if ((i.base_reg->reg_flags & RegRex) != 0)
-               i.rex |= REX_B;
-             i.sib.base = i.base_reg->reg_num;
-             /* x86-64 ignores REX prefix bit here to avoid decoder
-                complications.  */
-             if ((i.base_reg->reg_num & 7) == EBP_REG_NUM)
-               {
-                 default_seg = &ss;
-                 if (i.disp_operands == 0)
-                   {
-                     fake_zero_displacement = 1;
-                     i.types[op] |= Disp8;
-                   }
-               }
-             else if (i.base_reg->reg_num == ESP_REG_NUM)
-               {
-                 default_seg = &ss;
-               }
-             i.sib.scale = i.log2_scale_factor;
-             if (i.index_reg == 0)
-               {
-                 /* <disp>(%esp) becomes two byte modrm with no index
-                    register.  We've already stored the code for esp
-                    in i.rm.regmem ie. ESCAPE_TO_TWO_BYTE_ADDRESSING.
-                    Any base register besides %esp will not use the
-                    extra modrm byte.  */
-                 i.sib.index = NO_INDEX_REGISTER;
-#if !SCALE1_WHEN_NO_INDEX
-                 /* Another case where we force the second modrm byte.  */
-                 if (i.log2_scale_factor)
-                   i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING;
-#endif
-               }
-             else
+             if (i.tm.base_opcode == 0xf20f38f1
+                 || i.tm.base_opcode == 0xf20f38f0)
                {
-                 i.sib.index = i.index_reg->reg_num;
-                 i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING;
-                 if ((i.index_reg->reg_flags & RegRex) != 0)
-                   i.rex |= REX_X;
+                 /* We have to know the operand size for crc32.  */
+                 as_bad (_("ambiguous memory operand size for `%s`"),
+                         i.tm.name);
+                 return 0;
                }
 
-             if (i.disp_operands
-                 && (i.reloc[op] == BFD_RELOC_386_TLS_DESC_CALL
-                     || i.reloc[op] == BFD_RELOC_X86_64_TLSDESC_CALL))
-               i.rm.mode = 0;
-             else
-               i.rm.mode = mode_from_disp_size (i.types[op]);
+             for (op = i.operands; --op >= 0;)
+               if (!i.tm.operand_types[op].bitfield.inoutportreg)
+                 {
+                   if (i.types[op].bitfield.reg8)
+                     {
+                       i.suffix = BYTE_MNEM_SUFFIX;
+                       break;
+                     }
+                   else if (i.types[op].bitfield.reg16)
+                     {
+                       i.suffix = WORD_MNEM_SUFFIX;
+                       break;
+                     }
+                   else if (i.types[op].bitfield.reg32)
+                     {
+                       i.suffix = LONG_MNEM_SUFFIX;
+                       break;
+                     }
+                   else if (i.types[op].bitfield.reg64)
+                     {
+                       i.suffix = QWORD_MNEM_SUFFIX;
+                       break;
+                     }
+                 }
            }
-
-         if (fake_zero_displacement)
+       }
+      else if (i.suffix == BYTE_MNEM_SUFFIX)
+       {
+         if (!check_byte_reg ())
+           return 0;
+       }
+      else if (i.suffix == LONG_MNEM_SUFFIX)
+       {
+         if (!check_long_reg ())
+           return 0;
+       }
+      else if (i.suffix == QWORD_MNEM_SUFFIX)
+       {
+         if (intel_syntax
+             && i.tm.opcode_modifier.ignoresize
+             && i.tm.opcode_modifier.no_qsuf)
+           i.suffix = 0;
+         else if (!check_qword_reg ())
+           return 0;
+       }
+      else if (i.suffix == WORD_MNEM_SUFFIX)
+       {
+         if (!check_word_reg ())
+           return 0;
+       }
+      else if (i.suffix == XMMWORD_MNEM_SUFFIX
+              || i.suffix == YMMWORD_MNEM_SUFFIX)
+       {
+         /* Skip if the instruction has x/y suffix.  match_template
+            should check if it is a valid suffix.  */
+       }
+      else if (intel_syntax && i.tm.opcode_modifier.ignoresize)
+       /* Do nothing if the instruction is going to ignore the prefix.  */
+       ;
+      else
+       abort ();
+    }
+  else if (i.tm.opcode_modifier.defaultsize
+          && !i.suffix
+          /* exclude fldenv/frstor/fsave/fstenv */
+          && i.tm.opcode_modifier.no_ssuf)
+    {
+      i.suffix = stackop_size;
+    }
+  else if (intel_syntax
+          && !i.suffix
+          && (i.tm.operand_types[0].bitfield.jumpabsolute
+              || i.tm.opcode_modifier.jumpbyte
+              || i.tm.opcode_modifier.jumpintersegment
+              || (i.tm.base_opcode == 0x0f01 /* [ls][gi]dt */
+                  && i.tm.extension_opcode <= 3)))
+    {
+      switch (flag_code)
+       {
+       case CODE_64BIT:
+         if (!i.tm.opcode_modifier.no_qsuf)
            {
-             /* Fakes a zero displacement assuming that i.types[op]
-                holds the correct displacement size.  */
-             expressionS *exp;
-
-             assert (i.op[op].disps == 0);
-             exp = &disp_expressions[i.disp_operands++];
-             i.op[op].disps = exp;
-             exp->X_op = O_constant;
-             exp->X_add_number = 0;
-             exp->X_add_symbol = (symbolS *) 0;
-             exp->X_op_symbol = (symbolS *) 0;
+             i.suffix = QWORD_MNEM_SUFFIX;
+             break;
            }
+       case CODE_32BIT:
+         if (!i.tm.opcode_modifier.no_lsuf)
+           i.suffix = LONG_MNEM_SUFFIX;
+         break;
+       case CODE_16BIT:
+         if (!i.tm.opcode_modifier.no_wsuf)
+           i.suffix = WORD_MNEM_SUFFIX;
+         break;
        }
+    }
 
-      /* 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.  */
-      if (i.reg_operands)
+  if (!i.suffix)
+    {
+      if (!intel_syntax)
        {
-         unsigned int op;
-
-         for (op = 0; op < i.operands; op++)
-           if ((i.types[op] & (Reg | RegMMX | RegXMM
-                               | SReg2 | SReg3
-                               | Control | Debug | Test)))
-             break;
-         assert (op < i.operands);
-
-         /* 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)
+         if (i.tm.opcode_modifier.w)
            {
-             i.rm.regmem = i.op[op].regs->reg_num;
-             if ((i.op[op].regs->reg_flags & RegRex) != 0)
-               i.rex |= REX_B;
+             as_bad (_("no instruction mnemonic suffix given and "
+                       "no register operands; can't size instruction"));
+             return 0;
            }
-         else
+       }
+      else
+       {
+         unsigned int suffixes;
+
+         suffixes = !i.tm.opcode_modifier.no_bsuf;
+         if (!i.tm.opcode_modifier.no_wsuf)
+           suffixes |= 1 << 1;
+         if (!i.tm.opcode_modifier.no_lsuf)
+           suffixes |= 1 << 2;
+         if (!i.tm.opcode_modifier.no_ldsuf)
+           suffixes |= 1 << 3;
+         if (!i.tm.opcode_modifier.no_ssuf)
+           suffixes |= 1 << 4;
+         if (!i.tm.opcode_modifier.no_qsuf)
+           suffixes |= 1 << 5;
+
+         /* There are more than suffix matches.  */
+         if (i.tm.opcode_modifier.w
+             || ((suffixes & (suffixes - 1))
+                 && !i.tm.opcode_modifier.defaultsize
+                 && !i.tm.opcode_modifier.ignoresize))
            {
-             i.rm.reg = i.op[op].regs->reg_num;
-             if ((i.op[op].regs->reg_flags & RegRex) != 0)
-               i.rex |= REX_R;
+             as_bad (_("ambiguous operand size for `%s'"), i.tm.name);
+             return 0;
            }
-
-         /* 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;
        }
-
-      /* Fill in i.rm.reg field with extension opcode (if any).  */
-      if (i.tm.extension_opcode != None)
-       i.rm.reg = i.tm.extension_opcode;
     }
-  return default_seg;
-}
-
-static void
-output_branch (void)
-{
-  char *p;
-  int code16;
-  int prefix;
-  relax_substateT subtype;
-  symbolS *sym;
-  offsetT off;
 
-  code16 = 0;
-  if (flag_code == CODE_16BIT)
-    code16 = CODE16;
+  /* Change the opcode based on the operand size given by i.suffix;
+     We don't need to change things for byte insns.  */
 
-  prefix = 0;
-  if (i.prefix[DATA_PREFIX] != 0)
-    {
-      prefix = 1;
-      i.prefixes -= 1;
-      code16 ^= CODE16;
-    }
-  /* Pentium4 branch hints.  */
-  if (i.prefix[SEG_PREFIX] == CS_PREFIX_OPCODE /* not taken */
-      || i.prefix[SEG_PREFIX] == DS_PREFIX_OPCODE /* taken */)
-    {
-      prefix++;
-      i.prefixes--;
-    }
-  if (i.prefix[REX_PREFIX] != 0)
+  if (i.suffix
+      && i.suffix != BYTE_MNEM_SUFFIX
+      && i.suffix != XMMWORD_MNEM_SUFFIX
+      && i.suffix != YMMWORD_MNEM_SUFFIX)
     {
-      prefix++;
-      i.prefixes--;
-    }
+      /* It's not a byte, select word/dword operation.  */
+      if (i.tm.opcode_modifier.w)
+       {
+         if (i.tm.opcode_modifier.shortform)
+           i.tm.base_opcode |= 8;
+         else
+           i.tm.base_opcode |= 1;
+       }
 
-  if (i.prefixes != 0 && !intel_syntax)
-    as_warn (_("skipping prefixes on this instruction"));
+      /* Now select between word & dword operations via the operand
+        size prefix, except for instructions that will ignore this
+        prefix anyway.  */
+      if (i.tm.opcode_modifier.addrprefixop0)
+       {
+         /* The address size override prefix changes the size of the
+            first operand.  */
+         if ((flag_code == CODE_32BIT
+              && i.op->regs[0].reg_type.bitfield.reg16)
+             || (flag_code != CODE_32BIT
+                 && i.op->regs[0].reg_type.bitfield.reg32))
+           if (!add_prefix (ADDR_PREFIX_OPCODE))
+             return 0;
+       }
+      else if (i.suffix != QWORD_MNEM_SUFFIX
+              && i.suffix != LONG_DOUBLE_MNEM_SUFFIX
+              && !i.tm.opcode_modifier.ignoresize
+              && !i.tm.opcode_modifier.floatmf
+              && ((i.suffix == LONG_MNEM_SUFFIX) == (flag_code == CODE_16BIT)
+                  || (flag_code == CODE_64BIT
+                      && i.tm.opcode_modifier.jumpbyte)))
+       {
+         unsigned int prefix = DATA_PREFIX_OPCODE;
 
-  /* It's always a symbol;  End frag & setup for relax.
-     Make sure there is enough room in this frag for the largest
-     instruction we may generate in md_convert_frag.  This is 2
-     bytes for the opcode and room for the prefix and largest
-     displacement.  */
-  frag_grow (prefix + 2 + 4);
-  /* Prefix and 1 opcode byte go in fr_fix.  */
-  p = frag_more (prefix + 1);
-  if (i.prefix[DATA_PREFIX] != 0)
-    *p++ = DATA_PREFIX_OPCODE;
-  if (i.prefix[SEG_PREFIX] == CS_PREFIX_OPCODE
-      || i.prefix[SEG_PREFIX] == DS_PREFIX_OPCODE)
-    *p++ = i.prefix[SEG_PREFIX];
-  if (i.prefix[REX_PREFIX] != 0)
-    *p++ = i.prefix[REX_PREFIX];
-  *p = i.tm.base_opcode;
+         if (i.tm.opcode_modifier.jumpbyte) /* jcxz, loop */
+           prefix = ADDR_PREFIX_OPCODE;
 
-  if ((unsigned char) *p == JUMP_PC_RELATIVE)
-    subtype = ENCODE_RELAX_STATE (UNCOND_JUMP, SMALL);
-  else if ((cpu_arch_flags & Cpu386) != 0)
-    subtype = ENCODE_RELAX_STATE (COND_JUMP, SMALL);
-  else
-    subtype = ENCODE_RELAX_STATE (COND_JUMP86, SMALL);
-  subtype |= code16;
+         if (!add_prefix (prefix))
+           return 0;
+       }
 
-  sym = i.op[0].disps->X_add_symbol;
-  off = i.op[0].disps->X_add_number;
+      /* Set mode64 for an operand.  */
+      if (i.suffix == QWORD_MNEM_SUFFIX
+         && flag_code == CODE_64BIT
+         && !i.tm.opcode_modifier.norex64)
+       {
+         /* Special case for xchg %rax,%rax.  It is NOP and doesn't
+            need rex64.  cmpxchg8b is also a special case. */
+         if (! (i.operands == 2
+                && i.tm.base_opcode == 0x90
+                && i.tm.extension_opcode == None
+                && operand_type_equal (&i.types [0], &acc64)
+                && operand_type_equal (&i.types [1], &acc64))
+             && ! (i.operands == 1
+                   && i.tm.base_opcode == 0xfc7
+                   && i.tm.extension_opcode == 1
+                   && !operand_type_check (i.types [0], reg)
+                   && operand_type_check (i.types [0], anymem)))
+           i.rex |= REX_W;
+       }
 
-  if (i.op[0].disps->X_op != O_constant
-      && i.op[0].disps->X_op != O_symbol)
-    {
-      /* Handle complex expressions.  */
-      sym = make_expr_symbol (i.op[0].disps);
-      off = 0;
+      /* Size floating point instruction.  */
+      if (i.suffix == LONG_MNEM_SUFFIX)
+       if (i.tm.opcode_modifier.floatmf)
+         i.tm.base_opcode ^= 4;
     }
 
-  /* 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);
+  return 1;
 }
 
-static void
-output_jump (void)
+static int
+check_byte_reg (void)
 {
-  char *p;
-  int size;
-  fixS *fixP;
+  int op;
 
-  if (i.tm.opcode_modifier & JumpByte)
-    {
-      /* This is a loop or jecxz type instruction.  */
-      size = 1;
-      if (i.prefix[ADDR_PREFIX] != 0)
-       {
-         FRAG_APPEND_1_CHAR (ADDR_PREFIX_OPCODE);
-         i.prefixes -= 1;
-       }
-      /* Pentium4 branch hints.  */
-      if (i.prefix[SEG_PREFIX] == CS_PREFIX_OPCODE /* not taken */
-         || i.prefix[SEG_PREFIX] == DS_PREFIX_OPCODE /* taken */)
-       {
-         FRAG_APPEND_1_CHAR (i.prefix[SEG_PREFIX]);
-         i.prefixes--;
-       }
-    }
-  else
+  for (op = i.operands; --op >= 0;)
     {
-      int code16;
+      /* If this is an eight bit register, it's OK.  If it's the 16 or
+        32 bit version of an eight bit register, we will just use the
+        low portion, and that's OK too.  */
+      if (i.types[op].bitfield.reg8)
+       continue;
 
-      code16 = 0;
-      if (flag_code == CODE_16BIT)
-       code16 = CODE16;
+      /* Don't generate this warning if not needed.  */
+      if (intel_syntax && i.tm.opcode_modifier.byteokintel)
+       continue;
 
-      if (i.prefix[DATA_PREFIX] != 0)
+      /* crc32 doesn't generate this warning.  */
+      if (i.tm.base_opcode == 0xf20f38f0)
+       continue;
+
+      if ((i.types[op].bitfield.reg16
+          || i.types[op].bitfield.reg32
+          || i.types[op].bitfield.reg64)
+         && i.op[op].regs->reg_num < 4)
        {
-         FRAG_APPEND_1_CHAR (DATA_PREFIX_OPCODE);
-         i.prefixes -= 1;
-         code16 ^= CODE16;
+         /* Prohibit these changes in the 64bit mode, since the
+            lowering is more complicated.  */
+         if (flag_code == CODE_64BIT
+             && !i.tm.operand_types[op].bitfield.inoutportreg)
+           {
+             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
+         if (!quiet_warnings
+             && !i.tm.operand_types[op].bitfield.inoutportreg)
+           as_warn (_("using `%s%s' instead of `%s%s' due to `%c' suffix"),
+                    register_prefix,
+                    (i.op[op].regs + (i.types[op].bitfield.reg16
+                                      ? 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.reg16
+         || i.types[op].bitfield.reg32
+         || i.types[op].bitfield.reg64
+         || i.types[op].bitfield.regmmx
+         || i.types[op].bitfield.regxmm
+         || i.types[op].bitfield.regymm
+         || i.types[op].bitfield.sreg2
+         || i.types[op].bitfield.sreg3
+         || i.types[op].bitfield.control
+         || i.types[op].bitfield.debug
+         || i.types[op].bitfield.test
+         || i.types[op].bitfield.floatreg
+         || i.types[op].bitfield.floatacc)
+       {
+         as_bad (_("`%s%s' not allowed with `%s%c'"),
+                 register_prefix,
+                 i.op[op].regs->reg_name,
+                 i.tm.name,
+                 i.suffix);
+         return 0;
        }
-
-      size = 4;
-      if (code16)
-       size = 2;
-    }
-
-  if (i.prefix[REX_PREFIX] != 0)
-    {
-      FRAG_APPEND_1_CHAR (i.prefix[REX_PREFIX]);
-      i.prefixes -= 1;
     }
-
-  if (i.prefixes != 0 && !intel_syntax)
-    as_warn (_("skipping prefixes on this instruction"));
-
-  p = frag_more (1 + size);
-  *p++ = i.tm.base_opcode;
-
-  fixP = fix_new_exp (frag_now, p - frag_now->fr_literal, size,
-                     i.op[0].disps, 1, reloc (size, 1, 1, i.reloc[0]));
-
-  /* All jumps handled here are signed, but don't use a signed limit
-     check for 32 and 16 bit jumps as we want to allow wrap around at
-     4G and 64k respectively.  */
-  if (size == 1)
-    fixP->fx_signed = 1;
+  return 1;
 }
 
-static void
-output_interseg_jump (void)
+static int
+check_long_reg (void)
 {
-  char *p;
-  int size;
-  int prefix;
-  int code16;
-
-  code16 = 0;
-  if (flag_code == CODE_16BIT)
-    code16 = CODE16;
+  int op;
 
-  prefix = 0;
-  if (i.prefix[DATA_PREFIX] != 0)
-    {
-      prefix = 1;
-      i.prefixes -= 1;
-      code16 ^= CODE16;
-    }
-  if (i.prefix[REX_PREFIX] != 0)
-    {
-      prefix++;
-      i.prefixes -= 1;
-    }
-
-  size = 4;
-  if (code16)
-    size = 2;
-
-  if (i.prefixes != 0 && !intel_syntax)
-    as_warn (_("skipping prefixes on this instruction"));
+  for (op = i.operands; --op >= 0;)
+    /* Reject eight bit registers, except where the template requires
+       them. (eg. movzb)  */
+    if (i.types[op].bitfield.reg8
+       && (i.tm.operand_types[op].bitfield.reg16
+           || i.tm.operand_types[op].bitfield.reg32
+           || i.tm.operand_types[op].bitfield.acc))
+      {
+       as_bad (_("`%s%s' not allowed with `%s%c'"),
+               register_prefix,
+               i.op[op].regs->reg_name,
+               i.tm.name,
+               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.reg16
+            && (i.tm.operand_types[op].bitfield.reg32
+                || i.tm.operand_types[op].bitfield.acc))
+      {
+       /* 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
+       else
+         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
+      }
+  /* Warn if the r prefix on a general reg is missing.  */
+    else if (i.types[op].bitfield.reg64
+            && (i.tm.operand_types[op].bitfield.reg32
+                || i.tm.operand_types[op].bitfield.acc))
+      {
+       if (intel_syntax
+           && i.tm.opcode_modifier.toqword
+           && !i.types[0].bitfield.regxmm)
+         {
+           /* Convert to QWORD.  We want REX byte. */
+           i.suffix = QWORD_MNEM_SUFFIX;
+         }
+       else
+         {
+           as_bad (_("Incorrect register `%s%s' used with `%c' suffix"),
+                   register_prefix, i.op[op].regs->reg_name,
+                   i.suffix);
+           return 0;
+         }
+      }
+  return 1;
+}
 
-  /* 1 opcode; 2 segment; offset  */
-  p = frag_more (prefix + 1 + 2 + size);
+static int
+check_qword_reg (void)
+{
+  int op;
 
-  if (i.prefix[DATA_PREFIX] != 0)
-    *p++ = DATA_PREFIX_OPCODE;
+  for (op = i.operands; --op >= 0; )
+    /* Reject eight bit registers, except where the template requires
+       them. (eg. movzb)  */
+    if (i.types[op].bitfield.reg8
+       && (i.tm.operand_types[op].bitfield.reg16
+           || i.tm.operand_types[op].bitfield.reg32
+           || i.tm.operand_types[op].bitfield.acc))
+      {
+       as_bad (_("`%s%s' not allowed with `%s%c'"),
+               register_prefix,
+               i.op[op].regs->reg_name,
+               i.tm.name,
+               i.suffix);
+       return 0;
+      }
+  /* Warn if the e prefix on a general reg is missing.  */
+    else if ((i.types[op].bitfield.reg16
+             || i.types[op].bitfield.reg32)
+            && (i.tm.operand_types[op].bitfield.reg32
+                || i.tm.operand_types[op].bitfield.acc))
+      {
+       /* Prohibit these changes in the 64bit mode, since the
+          lowering is more complicated.  */
+       if (intel_syntax
+           && i.tm.opcode_modifier.todword
+           && !i.types[0].bitfield.regxmm)
+         {
+           /* Convert to DWORD.  We don't want REX byte. */
+           i.suffix = LONG_MNEM_SUFFIX;
+         }
+       else
+         {
+           as_bad (_("Incorrect register `%s%s' used with `%c' suffix"),
+                   register_prefix, i.op[op].regs->reg_name,
+                   i.suffix);
+           return 0;
+         }
+      }
+  return 1;
+}
 
-  if (i.prefix[REX_PREFIX] != 0)
-    *p++ = i.prefix[REX_PREFIX];
+static int
+check_word_reg (void)
+{
+  int op;
+  for (op = i.operands; --op >= 0;)
+    /* Reject eight bit registers, except where the template requires
+       them. (eg. movzb)  */
+    if (i.types[op].bitfield.reg8
+       && (i.tm.operand_types[op].bitfield.reg16
+           || i.tm.operand_types[op].bitfield.reg32
+           || i.tm.operand_types[op].bitfield.acc))
+      {
+       as_bad (_("`%s%s' not allowed with `%s%c'"),
+               register_prefix,
+               i.op[op].regs->reg_name,
+               i.tm.name,
+               i.suffix);
+       return 0;
+      }
+  /* Warn if the e prefix on a general reg is present.  */
+    else if ((!quiet_warnings || flag_code == CODE_64BIT)
+            && i.types[op].bitfield.reg32
+            && (i.tm.operand_types[op].bitfield.reg16
+                || i.tm.operand_types[op].bitfield.acc))
+      {
+       /* 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;
+         }
+       else
+#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
+      }
+  return 1;
+}
 
-  *p++ = i.tm.base_opcode;
-  if (i.op[1].imms->X_op == O_constant)
+static int
+update_imm (unsigned int j)
+{
+  i386_operand_type overlap = i.types[j];
+  if ((overlap.bitfield.imm8
+       || overlap.bitfield.imm8s
+       || overlap.bitfield.imm16
+       || overlap.bitfield.imm32
+       || overlap.bitfield.imm32s
+       || overlap.bitfield.imm64)
+      && !operand_type_equal (&overlap, &imm8)
+      && !operand_type_equal (&overlap, &imm8s)
+      && !operand_type_equal (&overlap, &imm16)
+      && !operand_type_equal (&overlap, &imm32)
+      && !operand_type_equal (&overlap, &imm32s)
+      && !operand_type_equal (&overlap, &imm64))
     {
-      offsetT n = i.op[1].imms->X_add_number;
+      if (i.suffix)
+       {
+         i386_operand_type temp;
 
-      if (size == 2
-         && !fits_in_unsigned_word (n)
-         && !fits_in_signed_word (n))
+         operand_type_set (&temp, 0);
+         if (i.suffix == BYTE_MNEM_SUFFIX)
+           {
+             temp.bitfield.imm8 = overlap.bitfield.imm8;
+             temp.bitfield.imm8s = overlap.bitfield.imm8s;
+           }
+         else if (i.suffix == WORD_MNEM_SUFFIX)
+           temp.bitfield.imm16 = overlap.bitfield.imm16;
+         else if (i.suffix == QWORD_MNEM_SUFFIX)
+           {
+             temp.bitfield.imm64 = overlap.bitfield.imm64;
+             temp.bitfield.imm32s = overlap.bitfield.imm32s;
+           }
+         else
+           temp.bitfield.imm32 = overlap.bitfield.imm32;
+         overlap = temp;
+       }
+      else if (operand_type_equal (&overlap, &imm16_32_32s)
+              || operand_type_equal (&overlap, &imm16_32)
+              || operand_type_equal (&overlap, &imm16_32s))
        {
-         as_bad (_("16-bit jump out of range"));
-         return;
+         if ((flag_code == CODE_16BIT) ^ (i.prefix[DATA_PREFIX] != 0))
+           overlap = imm16;
+         else
+           overlap = imm32s;
+       }
+      if (!operand_type_equal (&overlap, &imm8)
+         && !operand_type_equal (&overlap, &imm8s)
+         && !operand_type_equal (&overlap, &imm16)
+         && !operand_type_equal (&overlap, &imm32)
+         && !operand_type_equal (&overlap, &imm32s)
+         && !operand_type_equal (&overlap, &imm64))
+       {
+         as_bad (_("no instruction mnemonic suffix given; "
+                   "can't determine immediate size"));
+         return 0;
        }
-      md_number_to_chars (p, n, size);
     }
-  else
-    fix_new_exp (frag_now, p - frag_now->fr_literal, size,
-                i.op[1].imms, 0, reloc (size, 0, 0, i.reloc[1]));
-  if (i.op[0].imms->X_op != O_constant)
-    as_bad (_("can't handle non absolute segment in `%s'"),
-           i.tm.name);
-  md_number_to_chars (p + size, (valueT) i.op[0].imms->X_add_number, 2);
+  i.types[j] = overlap;
+
+  return 1;
 }
 
-static void
-output_insn (void)
+static int
+finalize_imm (void)
 {
-  fragS *insn_start_frag;
-  offsetT insn_start_off;
+  unsigned int j, n;
 
-  /* Tie dwarf2 debug info to the address at the start of the insn.
-     We can't do this after the insn has been output as the current
-     frag may have been closed off.  eg. by frag_var.  */
-  dwarf2_emit_insn (0);
+  /* Update the first 2 immediate operands.  */
+  n = i.operands > 2 ? 2 : i.operands;
+  if (n)
+    {
+      for (j = 0; j < n; j++)
+       if (update_imm (j) == 0)
+         return 0;
 
-  insn_start_frag = frag_now;
-  insn_start_off = frag_now_fix ();
+      /* The 3rd operand can't be immediate operand.  */
+      gas_assert (operand_type_check (i.types[2], imm) == 0);
+    }
 
-  /* Output jumps.  */
-  if (i.tm.opcode_modifier & Jump)
-    output_branch ();
-  else if (i.tm.opcode_modifier & (JumpByte | JumpDword))
-    output_jump ();
-  else if (i.tm.opcode_modifier & JumpInterSegment)
-    output_interseg_jump ();
+  return 1;
+}
+
+static int
+bad_implicit_operand (int xmm)
+{
+  const char *reg = xmm ? "xmm0" : "ymm0";
+  if (intel_syntax)
+    as_bad (_("the last operand of `%s' must be `%s%s'"),
+           i.tm.name, register_prefix, reg);
   else
+    as_bad (_("the first operand of `%s' must be `%s%s'"),
+           i.tm.name, register_prefix, reg);
+  return 0;
+}
+
+static int
+process_operands (void)
+{
+  /* Default segment register this instruction will use for memory
+     accesses.  0 means unknown.  This is only for optimizing out
+     unnecessary segment overrides.  */
+  const seg_entry *default_seg = 0;
+
+  if (i.tm.opcode_modifier.sse2avx
+      && (i.tm.opcode_modifier.vexnds
+         || i.tm.opcode_modifier.vexndd))
     {
-      /* Output normal instructions here.  */
-      char *p;
-      unsigned char *q;
-      unsigned int prefix;
+      unsigned int dup = i.operands;
+      unsigned int dest = dup - 1;
+      unsigned int j;
 
-      /* All opcodes on i386 have either 1 or 2 bytes.  SSSE3 and
-        SSE4 instructions have 3 bytes.  We may use one more higher
-        byte to specify a prefix the instruction requires.  Exclude
-        instructions which are in both SSE4 and ABM.  */
-      if ((i.tm.cpu_flags & (CpuSSSE3 | CpuSSE4)) != 0
-         && (i.tm.cpu_flags & CpuABM) == 0)
+      /* The destination must be an xmm register.  */
+      gas_assert (i.reg_operands
+                 && MAX_OPERANDS > dup
+                 && operand_type_equal (&i.types[dest], &regxmm));
+
+      if (i.tm.opcode_modifier.firstxmm0)
        {
-         if (i.tm.base_opcode & 0xff000000)
+         /* The first operand is implicit and must be xmm0.  */
+         gas_assert (operand_type_equal (&i.types[0], &regxmm));
+         if (i.op[0].regs->reg_num != 0)
+           return bad_implicit_operand (1);
+
+         if (i.tm.opcode_modifier.vex3sources)
            {
-             prefix = (i.tm.base_opcode >> 24) & 0xff;
-             goto check_prefix;
+             /* Keep xmm0 for instructions with VEX prefix and 3
+                sources.  */
+             goto duplicate;
            }
-       }
-      else if ((i.tm.base_opcode & 0xff0000) != 0)
-       {
-         prefix = (i.tm.base_opcode >> 16) & 0xff;
-         if ((i.tm.cpu_flags & CpuPadLock) != 0)
+         else
            {
-           check_prefix:
-             if (prefix != REPE_PREFIX_OPCODE
-                 || i.prefix[LOCKREP_PREFIX] != REPE_PREFIX_OPCODE)
-               add_prefix (prefix);
+             /* We remove the first xmm0 and keep the number of
+                operands unchanged, which in fact duplicates the
+                destination.  */
+             for (j = 1; j < i.operands; j++)
+               {
+                 i.op[j - 1] = i.op[j];
+                 i.types[j - 1] = i.types[j];
+                 i.tm.operand_types[j - 1] = i.tm.operand_types[j];
+               }
            }
-         else
-           add_prefix (prefix);
        }
-
-      /* The prefix bytes.  */
-      for (q = i.prefix;
-          q < i.prefix + sizeof (i.prefix) / sizeof (i.prefix[0]);
-          q++)
+      else if (i.tm.opcode_modifier.implicit1stxmm0)
        {
-         if (*q)
+         gas_assert ((MAX_OPERANDS - 1) > dup
+                     && i.tm.opcode_modifier.vex3sources);
+
+         /* Add the implicit xmm0 for instructions with VEX prefix
+            and 3 sources.  */
+         for (j = i.operands; j > 0; j--)
            {
-             p = frag_more (1);
-             md_number_to_chars (p, (valueT) *q, 1);
+             i.op[j] = i.op[j - 1];
+             i.types[j] = i.types[j - 1];
+             i.tm.operand_types[j] = i.tm.operand_types[j - 1];
            }
-       }
-
-      /* Now the opcode; be careful about word order here!  */
-      if (fits_in_unsigned_byte (i.tm.base_opcode))
-       {
-         FRAG_APPEND_1_CHAR (i.tm.base_opcode);
+         i.op[0].regs
+           = (const reg_entry *) hash_find (reg_hash, "xmm0");
+         i.types[0] = regxmm;
+         i.tm.operand_types[0] = regxmm;
+
+         i.operands += 2;
+         i.reg_operands += 2;
+         i.tm.operands += 2;
+
+         dup++;
+         dest++;
+         i.op[dup] = i.op[dest];
+         i.types[dup] = i.types[dest];
+         i.tm.operand_types[dup] = i.tm.operand_types[dest];
        }
       else
        {
-         if ((i.tm.cpu_flags & (CpuSSSE3 | CpuSSE4)) != 0
-             && (i.tm.cpu_flags & CpuABM) == 0)
-           {
-             p = frag_more (3);
-             *p++ = (i.tm.base_opcode >> 16) & 0xff;
-           }
-         else
-           p = frag_more (2);
-
-         /* Put out high byte first: can't use md_number_to_chars!  */
-         *p++ = (i.tm.base_opcode >> 8) & 0xff;
-         *p = i.tm.base_opcode & 0xff;
+duplicate:
+         i.operands++;
+         i.reg_operands++;
+         i.tm.operands++;
+
+         i.op[dup] = i.op[dest];
+         i.types[dup] = i.types[dest];
+         i.tm.operand_types[dup] = i.tm.operand_types[dest];
        }
 
-      /* Now the modrm byte and sib byte (if present).  */
-      if (i.tm.opcode_modifier & Modrm)
+       if (i.tm.opcode_modifier.immext)
+        process_immext ();
+    }
+  else if (i.tm.opcode_modifier.firstxmm0)
+    {
+      unsigned int j;
+
+      /* The first operand is implicit and must be xmm0/ymm0.  */
+      gas_assert (i.reg_operands
+                 && (operand_type_equal (&i.types[0], &regxmm)
+                     || operand_type_equal (&i.types[0], &regymm)));
+      if (i.op[0].regs->reg_num != 0)
+       return bad_implicit_operand (i.types[0].bitfield.regxmm);
+
+      for (j = 1; j < i.operands; j++)
        {
-         p = frag_more (1);
-         md_number_to_chars (p,
-                             (valueT) (i.rm.regmem << 0
-                                       | i.rm.reg << 3
-                                       | i.rm.mode << 6),
-                             1);
-         /* If i.rm.regmem == ESP (4)
-            && i.rm.mode != (Register mode)
-            && not 16 bit
-            ==> need second modrm byte.  */
-         if (i.rm.regmem == ESCAPE_TO_TWO_BYTE_ADDRESSING
-             && i.rm.mode != 3
-             && !(i.base_reg && (i.base_reg->reg_type & Reg16) != 0))
-           {
-             p = frag_more (1);
-             md_number_to_chars (p,
-                                 (valueT) (i.sib.base << 0
-                                           | i.sib.index << 3
-                                           | i.sib.scale << 6),
-                                 1);
-           }
+         i.op[j - 1] = i.op[j];
+         i.types[j - 1] = i.types[j];
+
+         /* We need to adjust fields in i.tm since they are used by
+            build_modrm_byte.  */
+         i.tm.operand_types [j - 1] = i.tm.operand_types [j];
        }
 
-      if (i.disp_operands)
-       output_disp (insn_start_frag, insn_start_off);
+      i.operands--;
+      i.reg_operands--;
+      i.tm.operands--;
+    }
+  else if (i.tm.opcode_modifier.regkludge)
+    {
+      /* The imul $imm, %reg instruction is converted into
+        imul $imm, %reg, %reg, and the clr %reg instruction
+        is converted into xor %reg, %reg.  */
 
-      if (i.imm_operands)
-       output_imm (insn_start_frag, insn_start_off);
+      unsigned int first_reg_op;
+
+      if (operand_type_check (i.types[0], reg))
+       first_reg_op = 0;
+      else
+       first_reg_op = 1;
+      /* Pretend we saw the extra register operand.  */
+      gas_assert (i.reg_operands == 1
+                 && i.op[first_reg_op + 1].regs == 0);
+      i.op[first_reg_op + 1].regs = i.op[first_reg_op].regs;
+      i.types[first_reg_op + 1] = i.types[first_reg_op];
+      i.operands++;
+      i.reg_operands++;
     }
 
-#ifdef DEBUG386
-  if (flag_debug)
+  if (i.tm.opcode_modifier.shortform)
     {
-      pi ("" /*line*/, &i);
-    }
-#endif /* DEBUG386  */
-}
+      if (i.types[0].bitfield.sreg2
+         || i.types[0].bitfield.sreg3)
+       {
+         if (i.tm.base_opcode == POP_SEG_SHORT
+             && i.op[0].regs->reg_num == 1)
+           {
+             as_bad (_("you can't `pop %scs'"), register_prefix);
+             return 0;
+           }
+         i.tm.base_opcode |= (i.op[0].regs->reg_num << 3);
+         if ((i.op[0].regs->reg_flags & RegRex) != 0)
+           i.rex |= REX_B;
+       }
+      else
+       {
+         /* The register or float register operand is in operand
+            0 or 1.  */
+         unsigned int op;
 
-/* Return the size of the displacement operand N.  */
+         if (i.types[0].bitfield.floatreg
+             || operand_type_check (i.types[0], reg))
+           op = 0;
+         else
+           op = 1;
+         /* Register goes in low 3 bits of opcode.  */
+         i.tm.base_opcode |= i.op[op].regs->reg_num;
+         if ((i.op[op].regs->reg_flags & RegRex) != 0)
+           i.rex |= REX_B;
+         if (!quiet_warnings && i.tm.opcode_modifier.ugh)
+           {
+             /* Warn about some common errors, but press on regardless.
+                The first case can be generated by gcc (<= 2.8.1).  */
+             if (i.operands == 2)
+               {
+                 /* Reversed arguments on faddp, fsubp, etc.  */
+                 as_warn (_("translating to `%s %s%s,%s%s'"), i.tm.name,
+                          register_prefix, i.op[!intel_syntax].regs->reg_name,
+                          register_prefix, i.op[intel_syntax].regs->reg_name);
+               }
+             else
+               {
+                 /* Extraneous `l' suffix on fp insn.  */
+                 as_warn (_("translating to `%s %s%s'"), i.tm.name,
+                          register_prefix, i.op[0].regs->reg_name);
+               }
+           }
+       }
+    }
+  else if (i.tm.opcode_modifier.modrm)
+    {
+      /* The opcode is completed (modulo i.tm.extension_opcode which
+        must be put into the modrm byte).  Now, we make the modrm and
+        index base bytes based on all the info we've collected.  */
 
-static int
-disp_size (unsigned int n)
-{
-  int size = 4;
-  if (i.types[n] & (Disp8 | Disp16 | Disp64))
+      default_seg = build_modrm_byte ();
+    }
+  else if ((i.tm.base_opcode & ~0x3) == MOV_AX_DISP32)
     {
-      size = 2;
-      if (i.types[n] & Disp8)
-       size = 1;
-      if (i.types[n] & Disp64)
-       size = 8;
+      default_seg = &ds;
+    }
+  else if (i.tm.opcode_modifier.isstring)
+    {
+      /* For the string instructions that allow a segment override
+        on one of their operands, the default segment is ds.  */
+      default_seg = &ds;
     }
-  return size;
-}
 
-/* Return the size of the immediate operand N.  */
+  if (i.tm.base_opcode == 0x8d /* lea */
+      && i.seg[0]
+      && !quiet_warnings)
+    as_warn (_("segment override on `%s' is ineffectual"), i.tm.name);
 
-static int
-imm_size (unsigned int n)
-{
-  int size = 4;
-  if (i.types[n] & (Imm8 | Imm8S | Imm16 | Imm64))
+  /* 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))
     {
-      size = 2;
-      if (i.types[n] & (Imm8 | Imm8S))
-       size = 1;
-      if (i.types[n] & Imm64)
-       size = 8;
+      if (!add_prefix (i.seg[0]->seg_prefix))
+       return 0;
     }
-  return size;
+  return 1;
 }
 
-static void
-output_disp (fragS *insn_start_frag, offsetT insn_start_off)
+static const seg_entry *
+build_modrm_byte (void)
 {
-  char *p;
-  unsigned int n;
+  const seg_entry *default_seg = 0;
+  unsigned int source, dest;
+  int vex_3_sources;
 
-  for (n = 0; n < i.operands; n++)
+  /* The first operand of instructions with VEX prefix and 3 sources
+     must be VEX_Imm4.  */
+  vex_3_sources = i.tm.opcode_modifier.vex3sources;
+  if (vex_3_sources)
     {
-      if (i.types[n] & Disp)
+      unsigned int nds, reg;
+
+      if (i.tm.opcode_modifier.veximmext
+         && i.tm.opcode_modifier.immext)
        {
-         if (i.op[n].disps->X_op == O_constant)
-           {
-             int size = disp_size (n);
-             offsetT val;
+         dest = i.operands - 2;
+         gas_assert (dest == 3);
+       }
+      else
+      dest = i.operands - 1;
+      nds = dest - 1;
+
+      /* This instruction must have 4 register operands 
+        or 3 register operands plus 1 memory operand.  
+        It must have VexNDS and VexImmExt.  */
+      gas_assert ((i.reg_operands == 4
+                     || (i.reg_operands == 3 && i.mem_operands == 1))
+                 && i.tm.opcode_modifier.vexnds
+                 && i.tm.opcode_modifier.veximmext
+           && (operand_type_equal (&i.tm.operand_types[dest], &regxmm)
+               || operand_type_equal (&i.tm.operand_types[dest], &regymm)));
+
+      /* Generate an 8bit immediate operand to encode the register
+        operand.  */
+      expressionS *exp = &im_expressions[i.imm_operands++];
+      i.op[i.operands].imms = exp;
+      i.types[i.operands] = imm8;
+      i.operands++;
+      /* If VexW1 is set, the first operand is the source and
+        the second operand is encoded in the immediate operand.  */
+      if (i.tm.opcode_modifier.vexw1)
+       {
+         source = 0;
+         reg = 1;
+       }
+      else
+       {
+         source = 1;
+         reg = 0;
+       }      
+      /* FMA4 swaps REG and NDS.  */
+      if (i.tm.cpu_flags.bitfield.cpufma4)
+       {
+         unsigned int tmp;
+         tmp = reg;
+         reg = nds;
+         nds = tmp;
+       }      
+      gas_assert ((operand_type_equal (&i.tm.operand_types[reg], &regxmm)
+                  || operand_type_equal (&i.tm.operand_types[reg],
+                                         &regymm)) 
+                 && (operand_type_equal (&i.tm.operand_types[nds], &regxmm)
+                     || operand_type_equal (&i.tm.operand_types[nds], 
+                                            &regymm)));
+      exp->X_op = O_constant;
+      exp->X_add_number
+       = ((i.op[reg].regs->reg_num
+           + ((i.op[reg].regs->reg_flags & RegRex) ? 8 : 0)) << 4);      
+      i.vex.register_specifier = i.op[nds].regs;
+    }
+  else
+    source = dest = 0;
 
-             val = offset_in_range (i.op[n].disps->X_add_number,
-                                    size);
-             p = frag_more (size);
-             md_number_to_chars (p, val, size);
+  /* 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.vexndd)
+         || (i.reg_operands == 3
+             && i.tm.opcode_modifier.vexnds)
+         || (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.vexnds
+                             || i.types[0].bitfield.shiftcount)));
+         if (operand_type_check (i.types[0], imm)
+             || i.types[0].bitfield.shiftcount)
+           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.vexnds
+                         && i.imm_operands == 1
+                         && (i.types[0].bitfield.imm8
+                             || i.types[i.operands - 1].bitfield.imm8)));
+         if (i.tm.opcode_modifier.vexnds)
+           {
+             if (i.types[0].bitfield.imm8)
+               source = 1;
+             else
+               source = 0;
            }
          else
+           source = 2;
+         break;
+       case 5:
+         break;
+       default:
+         abort ();
+       }
+
+      if (!vex_3_sources)
+       {
+         dest = source + 1;
+
+         if (i.tm.opcode_modifier.vexnds)
            {
-             enum bfd_reloc_code_real reloc_type;
-             int size = disp_size (n);
-             int sign = (i.types[n] & Disp32S) != 0;
-             int pcrel = (i.flags[n] & Operand_PCrel) != 0;
+             /* For instructions with VexNDS, the register-only
+                source operand must be XMM or YMM register. It is
+                encoded in VEX prefix.  We need to clear RegMem bit
+                before calling operand_type_equal.  */
+             i386_operand_type op = i.tm.operand_types[dest];
+             op.bitfield.regmem = 0;
+             if ((dest + 1) >= i.operands
+                 || (!operand_type_equal (&op, &regxmm)
+                     && !operand_type_equal (&op, &regymm)))
+               abort ();
+             i.vex.register_specifier = i.op[dest].regs;
+             dest++;
+           }
+       }
 
-             /* We can't have 8 bit displacement here.  */
-             assert ((i.types[n] & Disp8) == 0);
+      i.rm.mode = 3;
+      /* One of the register operands will be encoded in the i.tm.reg
+        field, the other in the combined i.tm.mode and i.tm.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.operand_types[dest].bitfield.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;
+         if ((i.op[dest].regs->reg_flags & RegRex) != 0)
+           i.rex |= REX_R;
+         if ((i.op[source].regs->reg_flags & RegRex) != 0)
+           i.rex |= REX_B;
+       }
+      else
+       {
+         i.rm.reg = i.op[source].regs->reg_num;
+         i.rm.regmem = i.op[dest].regs->reg_num;
+         if ((i.op[dest].regs->reg_flags & RegRex) != 0)
+           i.rex |= REX_B;
+         if ((i.op[source].regs->reg_flags & RegRex) != 0)
+           i.rex |= REX_R;
+       }
+      if (flag_code != CODE_64BIT && (i.rex & (REX_R | REX_B)))
+       {
+         if (!i.types[0].bitfield.control
+             && !i.types[1].bitfield.control)
+           abort ();
+         i.rex &= ~(REX_R | REX_B);
+         add_prefix (LOCK_PREFIX_OPCODE);
+       }
+    }
+  else
+    {                  /* If it's not 2 reg operands...  */
+      unsigned int mem;
 
-             /* The PC relative address is computed relative
-                to the instruction boundary, so in case immediate
-                fields follows, we need to adjust the value.  */
-             if (pcrel && i.imm_operands)
-               {
-                 unsigned int n1;
-                 int sz = 0;
+      if (i.mem_operands)
+       {
+         unsigned int fake_zero_displacement = 0;
+         unsigned int op;
 
-                 for (n1 = 0; n1 < i.operands; n1++)
-                   if (i.types[n1] & Imm)
-                     {
-                       /* Only one immediate is allowed for PC
-                          relative address.  */
-                       assert (sz == 0);
-                       sz = imm_size (n1);
-                       i.op[n].disps->X_add_number -= sz;
-                     }
-                 /* We should find the immediate.  */
-                 assert (sz != 0);
-               }
+         for (op = 0; op < i.operands; op++)
+           if (operand_type_check (i.types[op], anymem))
+             break;
+         gas_assert (op < i.operands);
 
-             p = frag_more (size);
-             reloc_type = reloc (size, pcrel, sign, i.reloc[n]);
-             if (GOT_symbol
-                 && GOT_symbol == i.op[n].disps->X_add_symbol
-                 && (((reloc_type == BFD_RELOC_32
-                       || reloc_type == BFD_RELOC_X86_64_32S
-                       || (reloc_type == BFD_RELOC_64
-                           && object_64bit))
-                      && (i.op[n].disps->X_op == O_symbol
-                          || (i.op[n].disps->X_op == O_add
-                              && ((symbol_get_value_expression
-                                   (i.op[n].disps->X_op_symbol)->X_op)
-                                  == O_subtract))))
-                     || reloc_type == BFD_RELOC_32_PCREL))
-               {
-                 offsetT add;
+         default_seg = &ds;
 
-                 if (insn_start_frag == frag_now)
-                   add = (p - frag_now->fr_literal) - insn_start_off;
-                 else
+         if (i.base_reg == 0)
+           {
+             i.rm.mode = 0;
+             if (!i.disp_operands)
+               fake_zero_displacement = 1;
+             if (i.index_reg == 0)
+               {
+                 /* Operand is just <disp>  */
+                 if (flag_code == CODE_64BIT)
                    {
-                     fragS *fr;
-
-                     add = insn_start_frag->fr_fix - insn_start_off;
-                     for (fr = insn_start_frag->fr_next;
-                          fr && fr != frag_now; fr = fr->fr_next)
-                       add += fr->fr_fix;
-                     add += p - frag_now->fr_literal;
+                     /* 64bit mode overwrites the 32bit absolute
+                        addressing by RIP relative addressing and
+                        absolute addressing is encoded by one of the
+                        redundant SIB forms.  */
+                     i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING;
+                     i.sib.base = NO_BASE_REGISTER;
+                     i.sib.index = NO_INDEX_REGISTER;
+                     i.types[op] = ((i.prefix[ADDR_PREFIX] == 0)
+                                    ? disp32s : disp32);
                    }
-
-                 if (!object_64bit)
+                 else if ((flag_code == CODE_16BIT)
+                          ^ (i.prefix[ADDR_PREFIX] != 0))
                    {
-                     reloc_type = BFD_RELOC_386_GOTPC;
-                     i.op[n].imms->X_add_number += add;
+                     i.rm.regmem = NO_BASE_REGISTER_16;
+                     i.types[op] = disp16;
                    }
-                 else if (reloc_type == BFD_RELOC_64)
-                   reloc_type = BFD_RELOC_X86_64_GOTPC64;
                  else
-                   /* Don't do the adjustment for x86-64, as there
-                      the pcrel addressing is relative to the _next_
-                      insn, and that is taken care of in other code.  */
-                   reloc_type = BFD_RELOC_X86_64_GOTPC32;
+                   {
+                     i.rm.regmem = NO_BASE_REGISTER;
+                     i.types[op] = disp32;
+                   }
+               }
+             else /* !i.base_reg && i.index_reg  */
+               {
+                 if (i.index_reg->reg_num == RegEiz
+                     || i.index_reg->reg_num == RegRiz)
+                   i.sib.index = NO_INDEX_REGISTER;
+                 else
+                   i.sib.index = i.index_reg->reg_num;
+                 i.sib.base = NO_BASE_REGISTER;
+                 i.sib.scale = i.log2_scale_factor;
+                 i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING;
+                 i.types[op].bitfield.disp8 = 0;
+                 i.types[op].bitfield.disp16 = 0;
+                 i.types[op].bitfield.disp64 = 0;
+                 if (flag_code != CODE_64BIT)
+                   {
+                     /* Must be 32 bit */
+                     i.types[op].bitfield.disp32 = 1;
+                     i.types[op].bitfield.disp32s = 0;
+                   }
+                 else
+                   {
+                     i.types[op].bitfield.disp32 = 0;
+                     i.types[op].bitfield.disp32s = 1;
+                   }
+                 if ((i.index_reg->reg_flags & RegRex) != 0)
+                   i.rex |= REX_X;
                }
-             fix_new_exp (frag_now, p - frag_now->fr_literal, size,
-                          i.op[n].disps, pcrel, reloc_type);
            }
-       }
-    }
-}
-
-static void
-output_imm (fragS *insn_start_frag, offsetT insn_start_off)
-{
-  char *p;
-  unsigned int n;
-
-  for (n = 0; n < i.operands; n++)
-    {
-      if (i.types[n] & Imm)
-       {
-         if (i.op[n].imms->X_op == O_constant)
+         /* RIP addressing for 64bit mode.  */
+         else if (i.base_reg->reg_num == RegRip ||
+                  i.base_reg->reg_num == RegEip)
            {
-             int size = imm_size (n);
-             offsetT val;
-
-             val = offset_in_range (i.op[n].imms->X_add_number,
-                                    size);
-             p = frag_more (size);
-             md_number_to_chars (p, val, size);
+             i.rm.regmem = NO_BASE_REGISTER;
+             i.types[op].bitfield.disp8 = 0;
+             i.types[op].bitfield.disp16 = 0;
+             i.types[op].bitfield.disp32 = 0;
+             i.types[op].bitfield.disp32s = 1;
+             i.types[op].bitfield.disp64 = 0;
+             i.flags[op] |= Operand_PCrel;
+             if (! i.disp_operands)
+               fake_zero_displacement = 1;
            }
-         else
+         else if (i.base_reg->reg_type.bitfield.reg16)
            {
-             /* Not absolute_section.
-                Need a 32-bit fixup (don't support 8bit
-                non-absolute imms).  Try to support other
-                sizes ...  */
-             enum bfd_reloc_code_real reloc_type;
-             int size = imm_size (n);
-             int sign;
+             switch (i.base_reg->reg_num)
+               {
+               case 3: /* (%bx)  */
+                 if (i.index_reg == 0)
+                   i.rm.regmem = 7;
+                 else /* (%bx,%si) -> 0, or (%bx,%di) -> 1  */
+                   i.rm.regmem = i.index_reg->reg_num - 6;
+                 break;
+               case 5: /* (%bp)  */
+                 default_seg = &ss;
+                 if (i.index_reg == 0)
+                   {
+                     i.rm.regmem = 6;
+                     if (operand_type_check (i.types[op], disp) == 0)
+                       {
+                         /* fake (%bp) into 0(%bp)  */
+                         i.types[op].bitfield.disp8 = 1;
+                         fake_zero_displacement = 1;
+                       }
+                   }
+                 else /* (%bp,%si) -> 2, or (%bp,%di) -> 3  */
+                   i.rm.regmem = i.index_reg->reg_num - 6 + 2;
+                 break;
+               default: /* (%si) -> 4 or (%di) -> 5  */
+                 i.rm.regmem = i.base_reg->reg_num - 6 + 4;
+               }
+             i.rm.mode = mode_from_disp_size (i.types[op]);
+           }
+         else /* i.base_reg and 32/64 bit mode  */
+           {
+             if (flag_code == CODE_64BIT
+                 && operand_type_check (i.types[op], disp))
+               {
+                 i386_operand_type temp;
+                 operand_type_set (&temp, 0);
+                 temp.bitfield.disp8 = i.types[op].bitfield.disp8;
+                 i.types[op] = temp;
+                 if (i.prefix[ADDR_PREFIX] == 0)
+                   i.types[op].bitfield.disp32s = 1;
+                 else
+                   i.types[op].bitfield.disp32 = 1;
+               }
 
-             if ((i.types[n] & (Imm32S))
-                 && (i.suffix == QWORD_MNEM_SUFFIX
-                     || (!i.suffix && (i.tm.opcode_modifier & No_lSuf))))
-               sign = 1;
+             i.rm.regmem = i.base_reg->reg_num;
+             if ((i.base_reg->reg_flags & RegRex) != 0)
+               i.rex |= REX_B;
+             i.sib.base = i.base_reg->reg_num;
+             /* x86-64 ignores REX prefix bit here to avoid decoder
+                complications.  */
+             if ((i.base_reg->reg_num & 7) == EBP_REG_NUM)
+               {
+                 default_seg = &ss;
+                 if (i.disp_operands == 0)
+                   {
+                     fake_zero_displacement = 1;
+                     i.types[op].bitfield.disp8 = 1;
+                   }
+               }
+             else if (i.base_reg->reg_num == ESP_REG_NUM)
+               {
+                 default_seg = &ss;
+               }
+             i.sib.scale = i.log2_scale_factor;
+             if (i.index_reg == 0)
+               {
+                 /* <disp>(%esp) becomes two byte modrm with no index
+                    register.  We've already stored the code for esp
+                    in i.rm.regmem ie. ESCAPE_TO_TWO_BYTE_ADDRESSING.
+                    Any base register besides %esp will not use the
+                    extra modrm byte.  */
+                 i.sib.index = NO_INDEX_REGISTER;
+               }
              else
-               sign = 0;
-
-             p = frag_more (size);
-             reloc_type = reloc (size, 0, sign, i.reloc[n]);
-
-             /*   This is tough to explain.  We end up with this one if we
-              * have operands that look like
-              * "_GLOBAL_OFFSET_TABLE_+[.-.L284]".  The goal here is to
-              * obtain the absolute address of the GOT, and it is strongly
-              * preferable from a performance point of view to avoid using
-              * a runtime relocation for this.  The actual sequence of
-              * instructions often look something like:
-              *
-              *        call    .L66
-              * .L66:
-              *        popl    %ebx
-              *        addl    $_GLOBAL_OFFSET_TABLE_+[.-.L66],%ebx
-              *
-              *   The call and pop essentially return the absolute address
-              * of the label .L66 and store it in %ebx.  The linker itself
-              * will ultimately change the first operand of the addl so
-              * that %ebx points to the GOT, but to keep things simple, the
-              * .o file must have this operand set so that it generates not
-              * the absolute address of .L66, but the absolute address of
-              * itself.  This allows the linker itself simply treat a GOTPC
-              * relocation as asking for a pcrel offset to the GOT to be
-              * added in, and the addend of the relocation is stored in the
-              * operand field for the instruction itself.
-              *
-              *   Our job here is to fix the operand so that it would add
-              * the correct offset so that %ebx would point to itself.  The
-              * thing that is tricky is that .-.L66 will point to the
-              * beginning of the instruction, so we need to further modify
-              * the operand so that it will point to itself.  There are
-              * other cases where you have something like:
-              *
-              *        .long   $_GLOBAL_OFFSET_TABLE_+[.-.L66]
-              *
-              * and here no correction would be required.  Internally in
-              * the assembler we treat operands of this form as not being
-              * pcrel since the '.' is explicitly mentioned, and I wonder
-              * whether it would simplify matters to do it this way.  Who
-              * knows.  In earlier versions of the PIC patches, the
-              * pcrel_adjust field was used to store the correction, but
-              * since the expression is not pcrel, I felt it would be
-              * confusing to do it this way.  */
-
-             if ((reloc_type == BFD_RELOC_32
-                  || reloc_type == BFD_RELOC_X86_64_32S
-                  || reloc_type == BFD_RELOC_64)
-                 && GOT_symbol
-                 && GOT_symbol == i.op[n].imms->X_add_symbol
-                 && (i.op[n].imms->X_op == O_symbol
-                     || (i.op[n].imms->X_op == O_add
-                         && ((symbol_get_value_expression
-                              (i.op[n].imms->X_op_symbol)->X_op)
-                             == O_subtract))))
                {
-                 offsetT add;
-
-                 if (insn_start_frag == frag_now)
-                   add = (p - frag_now->fr_literal) - insn_start_off;
+                 if (i.index_reg->reg_num == RegEiz
+                     || i.index_reg->reg_num == RegRiz)
+                   i.sib.index = NO_INDEX_REGISTER;
                  else
-                   {
-                     fragS *fr;
+                   i.sib.index = i.index_reg->reg_num;
+                 i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING;
+                 if ((i.index_reg->reg_flags & RegRex) != 0)
+                   i.rex |= REX_X;
+               }
 
-                     add = insn_start_frag->fr_fix - insn_start_off;
-                     for (fr = insn_start_frag->fr_next;
-                          fr && fr != frag_now; fr = fr->fr_next)
-                       add += fr->fr_fix;
-                     add += p - frag_now->fr_literal;
-                   }
+             if (i.disp_operands
+                 && (i.reloc[op] == BFD_RELOC_386_TLS_DESC_CALL
+                     || i.reloc[op] == BFD_RELOC_X86_64_TLSDESC_CALL))
+               i.rm.mode = 0;
+             else
+               i.rm.mode = mode_from_disp_size (i.types[op]);
+           }
 
-                 if (!object_64bit)
-                   reloc_type = BFD_RELOC_386_GOTPC;
-                 else if (size == 4)
-                   reloc_type = BFD_RELOC_X86_64_GOTPC32;
-                 else if (size == 8)
-                   reloc_type = BFD_RELOC_X86_64_GOTPC64;
-                 i.op[n].imms->X_add_number += add;
-               }
-             fix_new_exp (frag_now, p - frag_now->fr_literal, size,
-                          i.op[n].imms, 0, reloc_type);
+         if (fake_zero_displacement)
+           {
+             /* Fakes a zero displacement assuming that i.types[op]
+                holds the correct displacement size.  */
+             expressionS *exp;
+
+             gas_assert (i.op[op].disps == 0);
+             exp = &disp_expressions[i.disp_operands++];
+             i.op[op].disps = exp;
+             exp->X_op = O_constant;
+             exp->X_add_number = 0;
+             exp->X_add_symbol = (symbolS *) 0;
+             exp->X_op_symbol = (symbolS *) 0;
            }
-       }
-    }
-}
-\f
-/* x86_cons_fix_new is called via the expression parsing code when a
-   reloc is needed.  We use this hook to get the correct .got reloc.  */
-static enum bfd_reloc_code_real got_reloc = NO_RELOC;
-static int cons_sign = -1;
 
-void
-x86_cons_fix_new (fragS *frag, unsigned int off, unsigned int len,
-                 expressionS *exp)
-{
-  enum bfd_reloc_code_real r = reloc (len, 0, cons_sign, got_reloc);
+         mem = op;
+       }
+      else
+       mem = ~0;
 
-  got_reloc = NO_RELOC;
+      /* 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.  */
+      if (i.reg_operands)
+       {
+         unsigned int op;
+         unsigned int vex_reg = ~0;
 
-#ifdef TE_PE
-  if (exp->X_op == O_secrel)
-    {
-      exp->X_op = O_symbol;
-      r = BFD_RELOC_32_SECREL;
-    }
-#endif
+         for (op = 0; op < i.operands; op++)
+           if (i.types[op].bitfield.reg8
+               || i.types[op].bitfield.reg16
+               || i.types[op].bitfield.reg32
+               || i.types[op].bitfield.reg64
+               || i.types[op].bitfield.regmmx
+               || i.types[op].bitfield.regxmm
+               || i.types[op].bitfield.regymm
+               || i.types[op].bitfield.sreg2
+               || i.types[op].bitfield.sreg3
+               || i.types[op].bitfield.control
+               || i.types[op].bitfield.debug
+               || i.types[op].bitfield.test)
+             break;
 
-  fix_new_exp (frag, off, len, exp, 0, r);
-}
+         if (vex_3_sources)
+           op = dest;
+         else if (i.tm.opcode_modifier.vexnds)
+           {
+             /* For instructions with VexNDS, the register-only
+                source operand is encoded in VEX prefix. */
+             gas_assert (mem != (unsigned int) ~0);
 
-#if (!defined (OBJ_ELF) && !defined (OBJ_MAYBE_ELF)) || defined (LEX_AT)
-# define lex_got(reloc, adjust, types) NULL
-#else
-/* Parse operands of the form
-   <symbol>@GOTOFF+<nnn>
-   and similar .plt or .got references.
-
-   If we find one, set up the correct relocation in RELOC and copy the
-   input string, minus the `@GOTOFF' into a malloc'd buffer for
-   parsing by the calling routine.  Return this buffer, and if ADJUST
-   is non-null set it to the length of the string we removed from the
-   input line.  Otherwise return NULL.  */
-static char *
-lex_got (enum bfd_reloc_code_real *reloc,
-        int *adjust,
-        unsigned int *types)
-{
-  /* Some of the relocations depend on the size of what field is to
-     be relocated.  But in our callers i386_immediate and i386_displacement
-     we don't yet know the operand size (this will be set by insn
-     matching).  Hence we record the word32 relocation here,
-     and adjust the reloc according to the real size in reloc().  */
-  static const struct {
-    const char *str;
-    const enum bfd_reloc_code_real rel[2];
-    const unsigned int types64;
-  } gotrel[] = {
-    { "PLTOFF",   { 0,
-                   BFD_RELOC_X86_64_PLTOFF64 },
-      Imm64 },
-    { "PLT",      { BFD_RELOC_386_PLT32,
-                   BFD_RELOC_X86_64_PLT32    },
-      Imm32 | Imm32S | Disp32 },
-    { "GOTPLT",   { 0,
-                   BFD_RELOC_X86_64_GOTPLT64 },
-      Imm64 | Disp64 },
-    { "GOTOFF",   { BFD_RELOC_386_GOTOFF,
-                   BFD_RELOC_X86_64_GOTOFF64 },
-      Imm64 | Disp64 },
-    { "GOTPCREL", { 0,
-                   BFD_RELOC_X86_64_GOTPCREL },
-      Imm32 | Imm32S | Disp32 },
-    { "TLSGD",    { BFD_RELOC_386_TLS_GD,
-                   BFD_RELOC_X86_64_TLSGD    },
-      Imm32 | Imm32S | Disp32 },
-    { "TLSLDM",   { BFD_RELOC_386_TLS_LDM,
-                   0                         },
-      0 },
-    { "TLSLD",    { 0,
-                   BFD_RELOC_X86_64_TLSLD    },
-      Imm32 | Imm32S | Disp32 },
-    { "GOTTPOFF", { BFD_RELOC_386_TLS_IE_32,
-                   BFD_RELOC_X86_64_GOTTPOFF },
-      Imm32 | Imm32S | Disp32 },
-    { "TPOFF",    { BFD_RELOC_386_TLS_LE_32,
-                   BFD_RELOC_X86_64_TPOFF32  },
-      Imm32 | Imm32S | Imm64 | Disp32 | Disp64 },
-    { "NTPOFF",   { BFD_RELOC_386_TLS_LE,
-                   0                         },
-      0 },
-    { "DTPOFF",   { BFD_RELOC_386_TLS_LDO_32,
-                   BFD_RELOC_X86_64_DTPOFF32 },
-      Imm32 | Imm32S | Imm64 | Disp32 | Disp64 },
-    { "GOTNTPOFF",{ BFD_RELOC_386_TLS_GOTIE,
-                   0                         },
-      0 },
-    { "INDNTPOFF",{ BFD_RELOC_386_TLS_IE,
-                   0                         },
-      0 },
-    { "GOT",      { BFD_RELOC_386_GOT32,
-                   BFD_RELOC_X86_64_GOT32    },
-      Imm32 | Imm32S | Disp32 | Imm64 },
-    { "TLSDESC",  { BFD_RELOC_386_TLS_GOTDESC,
-                   BFD_RELOC_X86_64_GOTPC32_TLSDESC },
-      Imm32 | Imm32S | Disp32 },
-    { "TLSCALL",  { BFD_RELOC_386_TLS_DESC_CALL,
-                   BFD_RELOC_X86_64_TLSDESC_CALL },
-      Imm32 | Imm32S | Disp32 }
-  };
-  char *cp;
-  unsigned int j;
-
-  if (!IS_ELF)
-    return NULL;
-
-  for (cp = input_line_pointer; *cp != '@'; cp++)
-    if (is_end_of_line[(unsigned char) *cp] || *cp == ',')
-      return NULL;
-
-  for (j = 0; j < sizeof (gotrel) / sizeof (gotrel[0]); j++)
-    {
-      int len;
-
-      len = strlen (gotrel[j].str);
-      if (strncasecmp (cp + 1, gotrel[j].str, len) == 0)
-       {
-         if (gotrel[j].rel[object_64bit] != 0)
-           {
-             int first, second;
-             char *tmpbuf, *past_reloc;
-
-             *reloc = gotrel[j].rel[object_64bit];
-             if (adjust)
-               *adjust = len;
-
-             if (types)
+             if (op > mem)
                {
-                 if (flag_code != CODE_64BIT)
-                   *types = Imm32 | Disp32;
-                 else
-                   *types = gotrel[j].types64;
+                 vex_reg = op++;
+                 gas_assert (op < i.operands);
                }
+             else
+               {
+                 vex_reg = op + 1;
+                 gas_assert (vex_reg < i.operands);
+               }
+           }
+         else if (i.tm.opcode_modifier.vexndd)
+           {
+             /* For instructions with VexNDD, there should be
+                no memory operand and the register destination
+                is encoded in VEX prefix.  */
+             gas_assert (i.mem_operands == 0
+                         && (op + 2) == i.operands);
+             vex_reg = op + 1;
+           }
+         else
+           gas_assert (op < i.operands);
 
-             if (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;
+         if (vex_reg != (unsigned int) ~0)
+           {
+             gas_assert (i.reg_operands == 2);
+
+             if (!operand_type_equal (&i.tm.operand_types[vex_reg],
+                                      & regxmm)
+                 && !operand_type_equal (&i.tm.operand_types[vex_reg],
+                                         &regymm))
+               abort ();
+             i.vex.register_specifier = i.op[vex_reg].regs;
+           }
 
-             /* Allocate and copy string.  The trailing NUL shouldn't
-                be necessary, but be safe.  */
-             tmpbuf = xmalloc (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++] = ' ';
-             memcpy (tmpbuf + first, past_reloc, second);
-             tmpbuf[first + second] = '\0';
-             return tmpbuf;
+         /* 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;
+             if ((i.op[op].regs->reg_flags & RegRex) != 0)
+               i.rex |= REX_B;
+           }
+         else
+           {
+             i.rm.reg = i.op[op].regs->reg_num;
+             if ((i.op[op].regs->reg_flags & RegRex) != 0)
+               i.rex |= REX_R;
            }
 
-         as_bad (_("@%s reloc is not supported with %d-bit output format"),
-                 gotrel[j].str, 1 << (5 + object_64bit));
-         return NULL;
+         /* 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;
        }
-    }
 
-  /* Might be a symbol version string.  Don't as_bad here.  */
-  return NULL;
+      /* Fill in i.rm.reg field with extension opcode (if any).  */
+      if (i.tm.extension_opcode != None)
+       i.rm.reg = i.tm.extension_opcode;
+    }
+  return default_seg;
 }
 
-void
-x86_cons (expressionS *exp, int size)
+static void
+output_branch (void)
 {
-  if (size == 4 || (object_64bit && size == 8))
+  char *p;
+  int code16;
+  int prefix;
+  relax_substateT subtype;
+  symbolS *sym;
+  offsetT off;
+
+  code16 = 0;
+  if (flag_code == CODE_16BIT)
+    code16 = CODE16;
+
+  prefix = 0;
+  if (i.prefix[DATA_PREFIX] != 0)
     {
-      /* Handle @GOTOFF and the like in an expression.  */
-      char *save;
-      char *gotfree_input_line;
-      int adjust;
+      prefix = 1;
+      i.prefixes -= 1;
+      code16 ^= CODE16;
+    }
+  /* Pentium4 branch hints.  */
+  if (i.prefix[SEG_PREFIX] == CS_PREFIX_OPCODE /* not taken */
+      || i.prefix[SEG_PREFIX] == DS_PREFIX_OPCODE /* taken */)
+    {
+      prefix++;
+      i.prefixes--;
+    }
+  if (i.prefix[REX_PREFIX] != 0)
+    {
+      prefix++;
+      i.prefixes--;
+    }
 
-      save = input_line_pointer;
-      gotfree_input_line = lex_got (&got_reloc, &adjust, NULL);
-      if (gotfree_input_line)
-       input_line_pointer = gotfree_input_line;
+  if (i.prefixes != 0 && !intel_syntax)
+    as_warn (_("skipping prefixes on this instruction"));
 
-      expression (exp);
+  /* It's always a symbol;  End frag & setup for relax.
+     Make sure there is enough room in this frag for the largest
+     instruction we may generate in md_convert_frag.  This is 2
+     bytes for the opcode and room for the prefix and largest
+     displacement.  */
+  frag_grow (prefix + 2 + 4);
+  /* Prefix and 1 opcode byte go in fr_fix.  */
+  p = frag_more (prefix + 1);
+  if (i.prefix[DATA_PREFIX] != 0)
+    *p++ = DATA_PREFIX_OPCODE;
+  if (i.prefix[SEG_PREFIX] == CS_PREFIX_OPCODE
+      || i.prefix[SEG_PREFIX] == DS_PREFIX_OPCODE)
+    *p++ = i.prefix[SEG_PREFIX];
+  if (i.prefix[REX_PREFIX] != 0)
+    *p++ = i.prefix[REX_PREFIX];
+  *p = i.tm.base_opcode;
 
-      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 ((unsigned char) *p == JUMP_PC_RELATIVE)
+    subtype = ENCODE_RELAX_STATE (UNCOND_JUMP, SMALL);
+  else if (cpu_arch_flags.bitfield.cpui386)
+    subtype = ENCODE_RELAX_STATE (COND_JUMP, SMALL);
   else
-    expression (exp);
-}
-#endif
-
-static void signed_cons (int size)
-{
-  if (flag_code == CODE_64BIT)
-    cons_sign = 1;
-  cons (size);
-  cons_sign = -1;
-}
+    subtype = ENCODE_RELAX_STATE (COND_JUMP86, SMALL);
+  subtype |= code16;
 
-#ifdef TE_PE
-static void
-pe_directive_secrel (dummy)
-     int dummy ATTRIBUTE_UNUSED;
-{
-  expressionS exp;
+  sym = i.op[0].disps->X_add_symbol;
+  off = i.op[0].disps->X_add_number;
 
-  do
+  if (i.op[0].disps->X_op != O_constant
+      && i.op[0].disps->X_op != O_symbol)
     {
-      expression (&exp);
-      if (exp.X_op == O_symbol)
-       exp.X_op = O_secrel;
-
-      emit_expr (&exp, 4);
+      /* Handle complex expressions.  */
+      sym = make_expr_symbol (i.op[0].disps);
+      off = 0;
     }
-  while (*input_line_pointer++ == ',');
 
-  input_line_pointer--;
-  demand_empty_rest_of_line ();
+  /* 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);
 }
-#endif
 
-static int
-i386_immediate (char *imm_start)
+static void
+output_jump (void)
 {
-  char *save_input_line_pointer;
-  char *gotfree_input_line;
-  segT exp_seg = 0;
-  expressionS *exp;
-  unsigned int types = ~0U;
+  char *p;
+  int size;
+  fixS *fixP;
 
-  if (i.imm_operands == MAX_IMMEDIATE_OPERANDS)
+  if (i.tm.opcode_modifier.jumpbyte)
     {
-      as_bad (_("at most %d immediate operands are allowed"),
-             MAX_IMMEDIATE_OPERANDS);
-      return 0;
+      /* This is a loop or jecxz type instruction.  */
+      size = 1;
+      if (i.prefix[ADDR_PREFIX] != 0)
+       {
+         FRAG_APPEND_1_CHAR (ADDR_PREFIX_OPCODE);
+         i.prefixes -= 1;
+       }
+      /* Pentium4 branch hints.  */
+      if (i.prefix[SEG_PREFIX] == CS_PREFIX_OPCODE /* not taken */
+         || i.prefix[SEG_PREFIX] == DS_PREFIX_OPCODE /* taken */)
+       {
+         FRAG_APPEND_1_CHAR (i.prefix[SEG_PREFIX]);
+         i.prefixes--;
+       }
     }
+  else
+    {
+      int code16;
 
-  exp = &im_expressions[i.imm_operands++];
-  i.op[this_operand].imms = exp;
-
-  if (is_space_char (*imm_start))
-    ++imm_start;
+      code16 = 0;
+      if (flag_code == CODE_16BIT)
+       code16 = CODE16;
 
-  save_input_line_pointer = input_line_pointer;
-  input_line_pointer = imm_start;
+      if (i.prefix[DATA_PREFIX] != 0)
+       {
+         FRAG_APPEND_1_CHAR (DATA_PREFIX_OPCODE);
+         i.prefixes -= 1;
+         code16 ^= CODE16;
+       }
 
-  gotfree_input_line = lex_got (&i.reloc[this_operand], NULL, &types);
-  if (gotfree_input_line)
-    input_line_pointer = gotfree_input_line;
+      size = 4;
+      if (code16)
+       size = 2;
+    }
 
-  exp_seg = expression (exp);
+  if (i.prefix[REX_PREFIX] != 0)
+    {
+      FRAG_APPEND_1_CHAR (i.prefix[REX_PREFIX]);
+      i.prefixes -= 1;
+    }
 
-  SKIP_WHITESPACE ();
-  if (*input_line_pointer)
-    as_bad (_("junk `%s' after expression"), input_line_pointer);
+  if (i.prefixes != 0 && !intel_syntax)
+    as_warn (_("skipping prefixes on this instruction"));
 
-  input_line_pointer = save_input_line_pointer;
-  if (gotfree_input_line)
-    free (gotfree_input_line);
+  p = frag_more (1 + size);
+  *p++ = i.tm.base_opcode;
 
-  if (exp->X_op == O_absent || exp->X_op == O_big)
-    {
-      /* Missing or bad expr becomes absolute 0.  */
-      as_bad (_("missing or invalid immediate expression `%s' taken as 0"),
-             imm_start);
-      exp->X_op = O_constant;
-      exp->X_add_number = 0;
-      exp->X_add_symbol = (symbolS *) 0;
-      exp->X_op_symbol = (symbolS *) 0;
-    }
-  else if (exp->X_op == O_constant)
-    {
-      /* Size it properly later.  */
-      i.types[this_operand] |= Imm64;
-      /* If BFD64, sign extend val.  */
-      if (!use_rela_relocations
-         && (exp->X_add_number & ~(((addressT) 2 << 31) - 1)) == 0)
-       exp->X_add_number
-         = (exp->X_add_number ^ ((addressT) 1 << 31)) - ((addressT) 1 << 31);
-    }
-#if (defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT))
-  else if (OUTPUT_FLAVOR == bfd_target_aout_flavour
-          && exp_seg != absolute_section
-          && exp_seg != text_section
-          && exp_seg != data_section
-          && exp_seg != bss_section
-          && exp_seg != undefined_section
-          && !bfd_is_com_section (exp_seg))
-    {
-      as_bad (_("unimplemented segment %s in operand"), exp_seg->name);
-      return 0;
-    }
-#endif
-  else if (!intel_syntax && exp->X_op == O_register)
-    {
-      as_bad (_("illegal immediate register operand %s"), imm_start);
-      return 0;
-    }
-  else
-    {
-      /* This is an address.  The size of the address will be
-        determined later, depending on destination register,
-        suffix, or the default for the section.  */
-      i.types[this_operand] |= Imm8 | Imm16 | Imm32 | Imm32S | Imm64;
-      i.types[this_operand] &= types;
-    }
+  fixP = fix_new_exp (frag_now, p - frag_now->fr_literal, size,
+                     i.op[0].disps, 1, reloc (size, 1, 1, i.reloc[0]));
 
-  return 1;
+  /* All jumps handled here are signed, but don't use a signed limit
+     check for 32 and 16 bit jumps as we want to allow wrap around at
+     4G and 64k respectively.  */
+  if (size == 1)
+    fixP->fx_signed = 1;
 }
 
-static char *
-i386_scale (char *scale)
+static void
+output_interseg_jump (void)
 {
-  offsetT val;
-  char *save = input_line_pointer;
+  char *p;
+  int size;
+  int prefix;
+  int code16;
 
-  input_line_pointer = scale;
-  val = get_absolute_expression ();
+  code16 = 0;
+  if (flag_code == CODE_16BIT)
+    code16 = CODE16;
 
-  switch (val)
+  prefix = 0;
+  if (i.prefix[DATA_PREFIX] != 0)
     {
-    case 1:
-      i.log2_scale_factor = 0;
-      break;
-    case 2:
-      i.log2_scale_factor = 1;
-      break;
-    case 4:
-      i.log2_scale_factor = 2;
-      break;
-    case 8:
-      i.log2_scale_factor = 3;
-      break;
-    default:
-      {
-       char sep = *input_line_pointer;
-
-       *input_line_pointer = '\0';
-       as_bad (_("expecting scale factor of 1, 2, 4, or 8: got `%s'"),
-               scale);
-       *input_line_pointer = sep;
-       input_line_pointer = save;
-       return NULL;
-      }
+      prefix = 1;
+      i.prefixes -= 1;
+      code16 ^= CODE16;
     }
-  if (i.log2_scale_factor != 0 && i.index_reg == 0)
+  if (i.prefix[REX_PREFIX] != 0)
     {
-      as_warn (_("scale factor of %d without an index register"),
-              1 << i.log2_scale_factor);
-#if SCALE1_WHEN_NO_INDEX
-      i.log2_scale_factor = 0;
-#endif
+      prefix++;
+      i.prefixes -= 1;
     }
-  scale = input_line_pointer;
-  input_line_pointer = save;
-  return scale;
-}
 
-static int
-i386_displacement (char *disp_start, char *disp_end)
-{
-  expressionS *exp;
-  segT exp_seg = 0;
-  char *save_input_line_pointer;
-  char *gotfree_input_line;
-  int bigdisp, override;
-  unsigned int types = Disp;
+  size = 4;
+  if (code16)
+    size = 2;
 
-  if (i.disp_operands == MAX_MEMORY_OPERANDS)
-    {
-      as_bad (_("at most %d displacement operands are allowed"),
-             MAX_MEMORY_OPERANDS);
-      return 0;
-    }
+  if (i.prefixes != 0 && !intel_syntax)
+    as_warn (_("skipping prefixes on this instruction"));
 
-  if ((i.types[this_operand] & JumpAbsolute)
-      || !(current_templates->start->opcode_modifier & (Jump | JumpDword)))
-    {
-      bigdisp = Disp32;
-      override = (i.prefix[ADDR_PREFIX] != 0);
-    }
-  else
-    {
-      /* For PC-relative branches, the width of the displacement
-        is dependent upon data size, not address size.  */
-      bigdisp = 0;
-      override = (i.prefix[DATA_PREFIX] != 0);
-    }
-  if (flag_code == CODE_64BIT)
-    {
-      if (!bigdisp)
-       bigdisp = ((override || i.suffix == WORD_MNEM_SUFFIX)
-                  ? Disp16
-                  : Disp32S | Disp32);
-      else if (!override)
-       bigdisp = Disp64 | Disp32S | Disp32;
-    }
-  else
+  /* 1 opcode; 2 segment; offset  */
+  p = frag_more (prefix + 1 + 2 + size);
+
+  if (i.prefix[DATA_PREFIX] != 0)
+    *p++ = DATA_PREFIX_OPCODE;
+
+  if (i.prefix[REX_PREFIX] != 0)
+    *p++ = i.prefix[REX_PREFIX];
+
+  *p++ = i.tm.base_opcode;
+  if (i.op[1].imms->X_op == O_constant)
     {
-      if (!bigdisp)
+      offsetT n = i.op[1].imms->X_add_number;
+
+      if (size == 2
+         && !fits_in_unsigned_word (n)
+         && !fits_in_signed_word (n))
        {
-         if (!override)
-           override = (i.suffix == (flag_code != CODE_16BIT
-                                    ? WORD_MNEM_SUFFIX
-                                    : LONG_MNEM_SUFFIX));
-         bigdisp = Disp32;
+         as_bad (_("16-bit jump out of range"));
+         return;
        }
-      if ((flag_code == CODE_16BIT) ^ override)
-       bigdisp = Disp16;
+      md_number_to_chars (p, n, size);
     }
-  i.types[this_operand] |= bigdisp;
+  else
+    fix_new_exp (frag_now, p - frag_now->fr_literal, size,
+                i.op[1].imms, 0, reloc (size, 0, 0, i.reloc[1]));
+  if (i.op[0].imms->X_op != O_constant)
+    as_bad (_("can't handle non absolute segment in `%s'"),
+           i.tm.name);
+  md_number_to_chars (p + size, (valueT) i.op[0].imms->X_add_number, 2);
+}
 
-  exp = &disp_expressions[i.disp_operands];
-  i.op[this_operand].disps = exp;
-  i.disp_operands++;
-  save_input_line_pointer = input_line_pointer;
-  input_line_pointer = disp_start;
-  END_STRING_AND_SAVE (disp_end);
+static void
+output_insn (void)
+{
+  fragS *insn_start_frag;
+  offsetT insn_start_off;
 
-#ifndef GCC_ASM_O_HACK
-#define GCC_ASM_O_HACK 0
-#endif
-#if GCC_ASM_O_HACK
-  END_STRING_AND_SAVE (disp_end + 1);
-  if ((i.types[this_operand] & BaseIndex) != 0
-      && displacement_string_end[-1] == '+')
-    {
-      /* This hack is to avoid a warning when using the "o"
-        constraint within gcc asm statements.
-        For instance:
+  /* Tie dwarf2 debug info to the address at the start of the insn.
+     We can't do this after the insn has been output as the current
+     frag may have been closed off.  eg. by frag_var.  */
+  dwarf2_emit_insn (0);
 
-        #define _set_tssldt_desc(n,addr,limit,type) \
-        __asm__ __volatile__ ( \
-        "movw %w2,%0\n\t" \
-        "movw %w1,2+%0\n\t" \
-        "rorl $16,%1\n\t" \
-        "movb %b1,4+%0\n\t" \
-        "movb %4,5+%0\n\t" \
-        "movb $0,6+%0\n\t" \
-        "movb %h1,7+%0\n\t" \
-        "rorl $16,%1" \
-        : "=o"(*(n)) : "q" (addr), "ri"(limit), "i"(type))
+  insn_start_frag = frag_now;
+  insn_start_off = frag_now_fix ();
 
-        This works great except that the output assembler ends
-        up looking a bit weird if it turns out that there is
-        no offset.  You end up producing code that looks like:
+  /* Output jumps.  */
+  if (i.tm.opcode_modifier.jump)
+    output_branch ();
+  else if (i.tm.opcode_modifier.jumpbyte
+          || i.tm.opcode_modifier.jumpdword)
+    output_jump ();
+  else if (i.tm.opcode_modifier.jumpintersegment)
+    output_interseg_jump ();
+  else
+    {
+      /* Output normal instructions here.  */
+      char *p;
+      unsigned char *q;
+      unsigned int j;
+      unsigned int prefix;
 
-        #APP
-        movw $235,(%eax)
-        movw %dx,2+(%eax)
-        rorl $16,%edx
-        movb %dl,4+(%eax)
-        movb $137,5+(%eax)
-        movb $0,6+(%eax)
-        movb %dh,7+(%eax)
-        rorl $16,%edx
-        #NO_APP
+      /* Since the VEX prefix contains the implicit prefix, we don't
+         need the explicit prefix.  */
+      if (!i.tm.opcode_modifier.vex)
+       {
+         switch (i.tm.opcode_length)
+           {
+           case 3:
+             if (i.tm.base_opcode & 0xff000000)
+               {
+                 prefix = (i.tm.base_opcode >> 24) & 0xff;
+                 goto check_prefix;
+               }
+             break;
+           case 2:
+             if ((i.tm.base_opcode & 0xff0000) != 0)
+               {
+                 prefix = (i.tm.base_opcode >> 16) & 0xff;
+                 if (i.tm.cpu_flags.bitfield.cpupadlock)
+                   {
+check_prefix:
+                     if (prefix != REPE_PREFIX_OPCODE
+                         || (i.prefix[LOCKREP_PREFIX]
+                             != REPE_PREFIX_OPCODE))
+                       add_prefix (prefix);
+                   }
+                 else
+                   add_prefix (prefix);
+               }
+             break;
+           case 1:
+             break;
+           default:
+             abort ();
+           }
 
-        So here we provide the missing zero.  */
+         /* The prefix bytes.  */
+         for (j = ARRAY_SIZE (i.prefix), q = i.prefix; j > 0; j--, q++)
+           if (*q)
+             FRAG_APPEND_1_CHAR (*q);
+       }
 
-      *displacement_string_end = '0';
-    }
-#endif
-  gotfree_input_line = lex_got (&i.reloc[this_operand], NULL, &types);
-  if (gotfree_input_line)
-    input_line_pointer = gotfree_input_line;
+      if (i.tm.opcode_modifier.vex)
+       {
+         for (j = 0, q = i.prefix; j < ARRAY_SIZE (i.prefix); j++, q++)
+           if (*q)
+             switch (j)
+               {
+               case REX_PREFIX:
+                 /* REX byte is encoded in VEX prefix.  */
+                 break;
+               case SEG_PREFIX:
+               case ADDR_PREFIX:
+                 FRAG_APPEND_1_CHAR (*q);
+                 break;
+               default:
+                 /* There should be no other prefixes for instructions
+                    with VEX prefix.  */
+                 abort ();
+               }
 
-  exp_seg = expression (exp);
+         /* Now the VEX prefix.  */
+         p = frag_more (i.vex.length);
+         for (j = 0; j < i.vex.length; j++)
+           p[j] = i.vex.bytes[j];
+       }
 
-  SKIP_WHITESPACE ();
-  if (*input_line_pointer)
-    as_bad (_("junk `%s' after expression"), input_line_pointer);
-#if GCC_ASM_O_HACK
-  RESTORE_END_STRING (disp_end + 1);
-#endif
-  RESTORE_END_STRING (disp_end);
-  input_line_pointer = save_input_line_pointer;
-  if (gotfree_input_line)
-    free (gotfree_input_line);
+      /* Now the opcode; be careful about word order here!  */
+      if (i.tm.opcode_length == 1)
+       {
+         FRAG_APPEND_1_CHAR (i.tm.base_opcode);
+       }
+      else
+       {
+         switch (i.tm.opcode_length)
+           {
+           case 3:
+             p = frag_more (3);
+             *p++ = (i.tm.base_opcode >> 16) & 0xff;
+             break;
+           case 2:
+             p = frag_more (2);
+             break;
+           default:
+             abort ();
+             break;
+           }
 
-  /* We do this to make sure that the section symbol is in
-     the symbol table.  We will ultimately change the relocation
-     to be relative to the beginning of the section.  */
-  if (i.reloc[this_operand] == BFD_RELOC_386_GOTOFF
-      || i.reloc[this_operand] == BFD_RELOC_X86_64_GOTPCREL
-      || i.reloc[this_operand] == BFD_RELOC_X86_64_GOTOFF64)
-    {
-      if (exp->X_op != O_symbol)
+         /* Put out high byte first: can't use md_number_to_chars!  */
+         *p++ = (i.tm.base_opcode >> 8) & 0xff;
+         *p = i.tm.base_opcode & 0xff;
+       }
+
+      /* Now the modrm byte and sib byte (if present).  */
+      if (i.tm.opcode_modifier.modrm)
        {
-         as_bad (_("bad expression used with @%s"),
-                 (i.reloc[this_operand] == BFD_RELOC_X86_64_GOTPCREL
-                  ? "GOTPCREL"
-                  : "GOTOFF"));
-         return 0;
+         FRAG_APPEND_1_CHAR ((i.rm.regmem << 0
+                              | i.rm.reg << 3
+                              | i.rm.mode << 6));
+         /* If i.rm.regmem == ESP (4)
+            && i.rm.mode != (Register mode)
+            && not 16 bit
+            ==> need second modrm byte.  */
+         if (i.rm.regmem == ESCAPE_TO_TWO_BYTE_ADDRESSING
+             && i.rm.mode != 3
+             && !(i.base_reg && i.base_reg->reg_type.bitfield.reg16))
+           FRAG_APPEND_1_CHAR ((i.sib.base << 0
+                                | i.sib.index << 3
+                                | i.sib.scale << 6));
        }
 
-      if (S_IS_LOCAL (exp->X_add_symbol)
-         && S_GET_SEGMENT (exp->X_add_symbol) != undefined_section)
-       section_symbol (S_GET_SEGMENT (exp->X_add_symbol));
-      exp->X_op = O_subtract;
-      exp->X_op_symbol = GOT_symbol;
-      if (i.reloc[this_operand] == BFD_RELOC_X86_64_GOTPCREL)
-       i.reloc[this_operand] = BFD_RELOC_32_PCREL;
-      else if (i.reloc[this_operand] == BFD_RELOC_X86_64_GOTOFF64)
-       i.reloc[this_operand] = BFD_RELOC_64;
-      else
-       i.reloc[this_operand] = BFD_RELOC_32;
-    }
+      if (i.disp_operands)
+       output_disp (insn_start_frag, insn_start_off);
 
-  if (exp->X_op == O_absent || exp->X_op == O_big)
-    {
-      /* Missing or bad expr becomes absolute 0.  */
-      as_bad (_("missing or invalid displacement expression `%s' taken as 0"),
-             disp_start);
-      exp->X_op = O_constant;
-      exp->X_add_number = 0;
-      exp->X_add_symbol = (symbolS *) 0;
-      exp->X_op_symbol = (symbolS *) 0;
+      if (i.imm_operands)
+       output_imm (insn_start_frag, insn_start_off);
     }
 
-#if (defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT))
-  if (exp->X_op != O_constant
-      && OUTPUT_FLAVOR == bfd_target_aout_flavour
-      && exp_seg != absolute_section
-      && exp_seg != text_section
-      && exp_seg != data_section
-      && exp_seg != bss_section
-      && exp_seg != undefined_section
-      && !bfd_is_com_section (exp_seg))
+#ifdef DEBUG386
+  if (flag_debug)
     {
-      as_bad (_("unimplemented segment %s in operand"), exp_seg->name);
-      return 0;
+      pi ("" /*line*/, &i);
     }
-#endif
-
-  if (!(i.types[this_operand] & ~Disp))
-    i.types[this_operand] &= types;
-
-  return 1;
+#endif /* DEBUG386  */
 }
 
-/* Make sure the memory operand we've been dealt is valid.
-   Return 1 on success, 0 on a failure.  */
+/* Return the size of the displacement operand N.  */
 
 static int
-i386_index_check (const char *operand_string)
+disp_size (unsigned int n)
 {
-  int ok;
-#if INFER_ADDR_PREFIX
-  int fudged = 0;
-
- tryprefix:
-#endif
-  ok = 1;
-  if ((current_templates->start->cpu_flags & CpuSVME)
-      && current_templates->end[-1].operand_types[0] == AnyMem)
-    {
-      /* Memory operands of SVME insns are special in that they only allow
-        rAX as their memory address and ignore any segment override.  */
-      unsigned RegXX;
-
-      /* SKINIT is even more restrictive: it always requires EAX.  */
-      if (strcmp (current_templates->start->name, "skinit") == 0)
-       RegXX = Reg32;
-      else if (flag_code == CODE_64BIT)
-       RegXX = i.prefix[ADDR_PREFIX] == 0 ? Reg64 : Reg32;
-      else
-       RegXX = ((flag_code == CODE_16BIT) ^ (i.prefix[ADDR_PREFIX] != 0)
-                ? Reg16
-                : Reg32);
-      if (!i.base_reg
-         || !(i.base_reg->reg_type & Acc)
-         || !(i.base_reg->reg_type & RegXX)
-         || i.index_reg
-         || (i.types[0] & Disp))
-       ok = 0;
-    }
-  else if (flag_code == CODE_64BIT)
-    {
-      unsigned RegXX = (i.prefix[ADDR_PREFIX] == 0 ? Reg64 : Reg32);
-
-      if ((i.base_reg
-          && ((i.base_reg->reg_type & RegXX) == 0)
-          && (i.base_reg->reg_type != BaseIndex
-              || i.index_reg))
-         || (i.index_reg
-             && ((i.index_reg->reg_type & (RegXX | BaseIndex))
-                 != (RegXX | BaseIndex))))
-       ok = 0;
-    }
-  else
-    {
-      if ((flag_code == CODE_16BIT) ^ (i.prefix[ADDR_PREFIX] != 0))
-       {
-         /* 16bit checks.  */
-         if ((i.base_reg
-              && ((i.base_reg->reg_type & (Reg16 | BaseIndex | RegRex))
-                  != (Reg16 | BaseIndex)))
-             || (i.index_reg
-                 && (((i.index_reg->reg_type & (Reg16 | BaseIndex))
-                      != (Reg16 | BaseIndex))
-                     || !(i.base_reg
-                          && i.base_reg->reg_num < 6
-                          && i.index_reg->reg_num >= 6
-                          && i.log2_scale_factor == 0))))
-           ok = 0;
-       }
-      else
-       {
-         /* 32bit checks.  */
-         if ((i.base_reg
-              && (i.base_reg->reg_type & (Reg32 | RegRex)) != Reg32)
-             || (i.index_reg
-                 && ((i.index_reg->reg_type & (Reg32 | BaseIndex | RegRex))
-                     != (Reg32 | BaseIndex))))
-           ok = 0;
-       }
-    }
-  if (!ok)
-    {
-#if INFER_ADDR_PREFIX
-      if (i.prefix[ADDR_PREFIX] == 0)
-       {
-         i.prefix[ADDR_PREFIX] = ADDR_PREFIX_OPCODE;
-         i.prefixes += 1;
-         /* Change the size of any displacement too.  At most one of
-            Disp16 or Disp32 is set.
-            FIXME.  There doesn't seem to be any real need for separate
-            Disp16 and Disp32 flags.  The same goes for Imm16 and Imm32.
-            Removing them would probably clean up the code quite a lot.  */
-         if (flag_code != CODE_64BIT
-             && (i.types[this_operand] & (Disp16 | Disp32)))
-           i.types[this_operand] ^= (Disp16 | Disp32);
-         fudged = 1;
-         goto tryprefix;
-       }
-      if (fudged)
-       as_bad (_("`%s' is not a valid base/index expression"),
-               operand_string);
-      else
-#endif
-       as_bad (_("`%s' is not a valid %s bit base/index expression"),
-               operand_string,
-               flag_code_names[flag_code]);
-    }
-  return ok;
+  int size = 4;
+  if (i.types[n].bitfield.disp64)
+    size = 8;
+  else if (i.types[n].bitfield.disp8)
+    size = 1;
+  else if (i.types[n].bitfield.disp16)
+    size = 2;
+  return size;
 }
 
-/* Parse OPERAND_STRING into the i386_insn structure I.  Returns non-zero
-   on error.  */
+/* Return the size of the immediate operand N.  */
 
 static int
-i386_operand (char *operand_string)
+imm_size (unsigned int n)
 {
-  const reg_entry *r;
-  char *end_op;
-  char *op_string = operand_string;
-
-  if (is_space_char (*op_string))
-    ++op_string;
+  int size = 4;
+  if (i.types[n].bitfield.imm64)
+    size = 8;
+  else if (i.types[n].bitfield.imm8 || i.types[n].bitfield.imm8s)
+    size = 1;
+  else if (i.types[n].bitfield.imm16)
+    size = 2;
+  return size;
+}
 
-  /* We check for an absolute prefix (differentiating,
-     for example, 'jmp pc_relative_label' from 'jmp *absolute_label'.  */
-  if (*op_string == ABSOLUTE_PREFIX)
-    {
-      ++op_string;
-      if (is_space_char (*op_string))
-       ++op_string;
-      i.types[this_operand] |= JumpAbsolute;
-    }
+static void
+output_disp (fragS *insn_start_frag, offsetT insn_start_off)
+{
+  char *p;
+  unsigned int n;
 
-  /* Check if operand is a register.  */
-  if ((r = parse_register (op_string, &end_op)) != NULL)
+  for (n = 0; n < i.operands; n++)
     {
-      /* Check for a segment override by searching for ':' after a
-        segment register.  */
-      op_string = end_op;
-      if (is_space_char (*op_string))
-       ++op_string;
-      if (*op_string == ':' && (r->reg_type & (SReg2 | SReg3)))
+      if (operand_type_check (i.types[n], disp))
        {
-         switch (r->reg_num)
+         if (i.op[n].disps->X_op == O_constant)
            {
-           case 0:
-             i.seg[i.mem_operands] = &es;
-             break;
-           case 1:
-             i.seg[i.mem_operands] = &cs;
-             break;
-           case 2:
-             i.seg[i.mem_operands] = &ss;
-             break;
-           case 3:
-             i.seg[i.mem_operands] = &ds;
-             break;
-           case 4:
-             i.seg[i.mem_operands] = &fs;
-             break;
-           case 5:
-             i.seg[i.mem_operands] = &gs;
-             break;
-           }
-
-         /* Skip the ':' and whitespace.  */
-         ++op_string;
-         if (is_space_char (*op_string))
-           ++op_string;
-
-         if (!is_digit_char (*op_string)
-             && !is_identifier_char (*op_string)
-             && *op_string != '('
-             && *op_string != ABSOLUTE_PREFIX)
-           {
-             as_bad (_("bad memory operand `%s'"), op_string);
-             return 0;
-           }
-         /* Handle case of %es:*foo.  */
-         if (*op_string == ABSOLUTE_PREFIX)
-           {
-             ++op_string;
-             if (is_space_char (*op_string))
-               ++op_string;
-             i.types[this_operand] |= JumpAbsolute;
-           }
-         goto do_memory_reference;
-       }
-      if (*op_string)
-       {
-         as_bad (_("junk `%s' after register"), op_string);
-         return 0;
-       }
-      i.types[this_operand] |= r->reg_type & ~BaseIndex;
-      i.op[this_operand].regs = r;
-      i.reg_operands++;
-    }
-  else if (*op_string == REGISTER_PREFIX)
-    {
-      as_bad (_("bad register name `%s'"), op_string);
-      return 0;
-    }
-  else if (*op_string == IMMEDIATE_PREFIX)
-    {
-      ++op_string;
-      if (i.types[this_operand] & JumpAbsolute)
-       {
-         as_bad (_("immediate operand illegal with absolute jump"));
-         return 0;
-       }
-      if (!i386_immediate (op_string))
-       return 0;
-    }
-  else if (is_digit_char (*op_string)
-          || is_identifier_char (*op_string)
-          || *op_string == '(')
-    {
-      /* This is a memory reference of some sort.  */
-      char *base_string;
-
-      /* Start and end of displacement string expression (if found).  */
-      char *displacement_string_start;
-      char *displacement_string_end;
-
-    do_memory_reference:
-      if ((i.mem_operands == 1
-          && (current_templates->start->opcode_modifier & IsString) == 0)
-         || i.mem_operands == 2)
-       {
-         as_bad (_("too many memory references for `%s'"),
-                 current_templates->start->name);
-         return 0;
-       }
-
-      /* Check for base index form.  We detect the base index form by
-        looking for an ')' at the end of the operand, searching
-        for the '(' matching it, and finding a REGISTER_PREFIX or ','
-        after the '('.  */
-      base_string = op_string + strlen (op_string);
-
-      --base_string;
-      if (is_space_char (*base_string))
-       --base_string;
-
-      /* If we only have a displacement, set-up for it to be parsed later.  */
-      displacement_string_start = op_string;
-      displacement_string_end = base_string + 1;
+             int size = disp_size (n);
+             offsetT val;
 
-      if (*base_string == ')')
-       {
-         char *temp_string;
-         unsigned int parens_balanced = 1;
-         /* We've already checked that the number of left & right ()'s are
-            equal, so this loop will not be infinite.  */
-         do
-           {
-             base_string--;
-             if (*base_string == ')')
-               parens_balanced++;
-             if (*base_string == '(')
-               parens_balanced--;
+             val = offset_in_range (i.op[n].disps->X_add_number,
+                                    size);
+             p = frag_more (size);
+             md_number_to_chars (p, val, size);
            }
-         while (parens_balanced);
-
-         temp_string = base_string;
-
-         /* Skip past '(' and whitespace.  */
-         ++base_string;
-         if (is_space_char (*base_string))
-           ++base_string;
-
-         if (*base_string == ','
-             || ((i.base_reg = parse_register (base_string, &end_op))
-                 != NULL))
+         else
            {
-             displacement_string_end = temp_string;
+             enum bfd_reloc_code_real reloc_type;
+             int size = disp_size (n);
+             int sign = i.types[n].bitfield.disp32s;
+             int pcrel = (i.flags[n] & Operand_PCrel) != 0;
 
-             i.types[this_operand] |= BaseIndex;
+             /* We can't have 8 bit displacement here.  */
+             gas_assert (!i.types[n].bitfield.disp8);
 
-             if (i.base_reg)
+             /* The PC relative address is computed relative
+                to the instruction boundary, so in case immediate
+                fields follows, we need to adjust the value.  */
+             if (pcrel && i.imm_operands)
                {
-                 base_string = end_op;
-                 if (is_space_char (*base_string))
-                   ++base_string;
+                 unsigned int n1;
+                 int sz = 0;
+
+                 for (n1 = 0; n1 < i.operands; n1++)
+                   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;
+                     }
+                 /* We should find the immediate.  */
+                 gas_assert (sz != 0);
                }
 
-             /* There may be an index reg or scale factor here.  */
-             if (*base_string == ',')
+             p = frag_more (size);
+             reloc_type = reloc (size, pcrel, sign, i.reloc[n]);
+             if (GOT_symbol
+                 && GOT_symbol == i.op[n].disps->X_add_symbol
+                 && (((reloc_type == BFD_RELOC_32
+                       || reloc_type == BFD_RELOC_X86_64_32S
+                       || (reloc_type == BFD_RELOC_64
+                           && object_64bit))
+                      && (i.op[n].disps->X_op == O_symbol
+                          || (i.op[n].disps->X_op == O_add
+                              && ((symbol_get_value_expression
+                                   (i.op[n].disps->X_op_symbol)->X_op)
+                                  == O_subtract))))
+                     || reloc_type == BFD_RELOC_32_PCREL))
                {
-                 ++base_string;
-                 if (is_space_char (*base_string))
-                   ++base_string;
-
-                 if ((i.index_reg = parse_register (base_string, &end_op))
-                     != NULL)
-                   {
-                     base_string = end_op;
-                     if (is_space_char (*base_string))
-                       ++base_string;
-                     if (*base_string == ',')
-                       {
-                         ++base_string;
-                         if (is_space_char (*base_string))
-                           ++base_string;
-                       }
-                     else if (*base_string != ')')
-                       {
-                         as_bad (_("expecting `,' or `)' "
-                                   "after index register in `%s'"),
-                                 operand_string);
-                         return 0;
-                       }
-                   }
-                 else if (*base_string == REGISTER_PREFIX)
-                   {
-                     as_bad (_("bad register name `%s'"), base_string);
-                     return 0;
-                   }
+                 offsetT add;
 
-                 /* Check for scale factor.  */
-                 if (*base_string != ')')
+                 if (insn_start_frag == frag_now)
+                   add = (p - frag_now->fr_literal) - insn_start_off;
+                 else
                    {
-                     char *end_scale = i386_scale (base_string);
-
-                     if (!end_scale)
-                       return 0;
+                     fragS *fr;
 
-                     base_string = end_scale;
-                     if (is_space_char (*base_string))
-                       ++base_string;
-                     if (*base_string != ')')
-                       {
-                         as_bad (_("expecting `)' "
-                                   "after scale factor in `%s'"),
-                                 operand_string);
-                         return 0;
-                       }
+                     add = insn_start_frag->fr_fix - insn_start_off;
+                     for (fr = insn_start_frag->fr_next;
+                          fr && fr != frag_now; fr = fr->fr_next)
+                       add += fr->fr_fix;
+                     add += p - frag_now->fr_literal;
                    }
-                 else if (!i.index_reg)
+
+                 if (!object_64bit)
                    {
-                     as_bad (_("expecting index register or scale factor "
-                               "after `,'; got '%c'"),
-                             *base_string);
-                     return 0;
+                     reloc_type = BFD_RELOC_386_GOTPC;
+                     i.op[n].imms->X_add_number += add;
                    }
+                 else if (reloc_type == BFD_RELOC_64)
+                   reloc_type = BFD_RELOC_X86_64_GOTPC64;
+                 else
+                   /* Don't do the adjustment for x86-64, as there
+                      the pcrel addressing is relative to the _next_
+                      insn, and that is taken care of in other code.  */
+                   reloc_type = BFD_RELOC_X86_64_GOTPC32;
                }
-             else if (*base_string != ')')
-               {
-                 as_bad (_("expecting `,' or `)' "
-                           "after base register in `%s'"),
-                         operand_string);
-                 return 0;
-               }
-           }
-         else if (*base_string == REGISTER_PREFIX)
-           {
-             as_bad (_("bad register name `%s'"), base_string);
-             return 0;
+             fix_new_exp (frag_now, p - frag_now->fr_literal, size,
+                          i.op[n].disps, pcrel, reloc_type);
            }
        }
+    }
+}
 
-      /* If there's an expression beginning the operand, parse it,
-        assuming displacement_string_start and
-        displacement_string_end are meaningful.  */
-      if (displacement_string_start != displacement_string_end)
-       {
-         if (!i386_displacement (displacement_string_start,
-                                 displacement_string_end))
-           return 0;
-       }
+static void
+output_imm (fragS *insn_start_frag, offsetT insn_start_off)
+{
+  char *p;
+  unsigned int n;
 
-      /* Special case for (%dx) while doing input/output op.  */
-      if (i.base_reg
-         && i.base_reg->reg_type == (Reg16 | InOutPortReg)
-         && i.index_reg == 0
-         && i.log2_scale_factor == 0
-         && i.seg[i.mem_operands] == 0
-         && (i.types[this_operand] & Disp) == 0)
+  for (n = 0; n < i.operands; n++)
+    {
+      if (operand_type_check (i.types[n], imm))
        {
-         i.types[this_operand] = InOutPortReg;
-         return 1;
-       }
+         if (i.op[n].imms->X_op == O_constant)
+           {
+             int size = imm_size (n);
+             offsetT val;
 
-      if (i386_index_check (operand_string) == 0)
-       return 0;
-      i.mem_operands++;
-    }
-  else
-    {
-      /* It's not a memory operand; argh!  */
-      as_bad (_("invalid char %s beginning operand %d `%s'"),
-             output_invalid (*op_string),
-             this_operand + 1,
-             op_string);
-      return 0;
-    }
-  return 1;                    /* Normal return.  */
-}
-\f
-/* md_estimate_size_before_relax()
+             val = offset_in_range (i.op[n].imms->X_add_number,
+                                    size);
+             p = frag_more (size);
+             md_number_to_chars (p, val, size);
+           }
+         else
+           {
+             /* Not absolute_section.
+                Need a 32-bit fixup (don't support 8bit
+                non-absolute imms).  Try to support other
+                sizes ...  */
+             enum bfd_reloc_code_real reloc_type;
+             int size = imm_size (n);
+             int sign;
 
-   Called just before relax() for rs_machine_dependent frags.  The x86
-   assembler uses these frags to handle variable size jump
-   instructions.
+             if (i.types[n].bitfield.imm32s
+                 && (i.suffix == QWORD_MNEM_SUFFIX
+                     || (!i.suffix && i.tm.opcode_modifier.no_lsuf)))
+               sign = 1;
+             else
+               sign = 0;
 
-   Any symbol that is now undefined will not become defined.
-   Return the correct fr_subtype in the frag.
-   Return the initial "guess for variable size of frag" to caller.
-   The guess is actually the growth beyond the fixed part.  Whatever
-   we do to grow the fixed or variable part contributes to our
-   returned value.  */
+             p = frag_more (size);
+             reloc_type = reloc (size, 0, sign, i.reloc[n]);
 
-int
-md_estimate_size_before_relax (fragP, segment)
-     fragS *fragP;
-     segT segment;
-{
-  /* We've already got fragP->fr_subtype right;  all we have to do is
-     check for un-relaxable symbols.  On an ELF system, we can't relax
-     an externally visible symbol, because it may be overridden by a
-     shared library.  */
-  if (S_GET_SEGMENT (fragP->fr_symbol) != segment
-#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
-      || (IS_ELF
-         && (S_IS_EXTERNAL (fragP->fr_symbol)
-             || S_IS_WEAK (fragP->fr_symbol)))
-#endif
-      )
-    {
-      /* Symbol is undefined in this segment, or we need to keep a
-        reloc so that weak symbols can be overridden.  */
-      int size = (fragP->fr_subtype & CODE16) ? 2 : 4;
-      enum bfd_reloc_code_real reloc_type;
-      unsigned char *opcode;
-      int old_fr_fix;
+             /*   This is tough to explain.  We end up with this one if we
+              * have operands that look like
+              * "_GLOBAL_OFFSET_TABLE_+[.-.L284]".  The goal here is to
+              * obtain the absolute address of the GOT, and it is strongly
+              * preferable from a performance point of view to avoid using
+              * a runtime relocation for this.  The actual sequence of
+              * instructions often look something like:
+              *
+              *        call    .L66
+              * .L66:
+              *        popl    %ebx
+              *        addl    $_GLOBAL_OFFSET_TABLE_+[.-.L66],%ebx
+              *
+              *   The call and pop essentially return the absolute address
+              * of the label .L66 and store it in %ebx.  The linker itself
+              * will ultimately change the first operand of the addl so
+              * that %ebx points to the GOT, but to keep things simple, the
+              * .o file must have this operand set so that it generates not
+              * the absolute address of .L66, but the absolute address of
+              * itself.  This allows the linker itself simply treat a GOTPC
+              * relocation as asking for a pcrel offset to the GOT to be
+              * added in, and the addend of the relocation is stored in the
+              * operand field for the instruction itself.
+              *
+              *   Our job here is to fix the operand so that it would add
+              * the correct offset so that %ebx would point to itself.  The
+              * thing that is tricky is that .-.L66 will point to the
+              * beginning of the instruction, so we need to further modify
+              * the operand so that it will point to itself.  There are
+              * other cases where you have something like:
+              *
+              *        .long   $_GLOBAL_OFFSET_TABLE_+[.-.L66]
+              *
+              * and here no correction would be required.  Internally in
+              * the assembler we treat operands of this form as not being
+              * pcrel since the '.' is explicitly mentioned, and I wonder
+              * whether it would simplify matters to do it this way.  Who
+              * knows.  In earlier versions of the PIC patches, the
+              * pcrel_adjust field was used to store the correction, but
+              * since the expression is not pcrel, I felt it would be
+              * confusing to do it this way.  */
 
-      if (fragP->fr_var != NO_RELOC)
-       reloc_type = fragP->fr_var;
-      else if (size == 2)
-       reloc_type = BFD_RELOC_16_PCREL;
-      else
-       reloc_type = BFD_RELOC_32_PCREL;
+             if ((reloc_type == BFD_RELOC_32
+                  || reloc_type == BFD_RELOC_X86_64_32S
+                  || reloc_type == BFD_RELOC_64)
+                 && GOT_symbol
+                 && GOT_symbol == i.op[n].imms->X_add_symbol
+                 && (i.op[n].imms->X_op == O_symbol
+                     || (i.op[n].imms->X_op == O_add
+                         && ((symbol_get_value_expression
+                              (i.op[n].imms->X_op_symbol)->X_op)
+                             == O_subtract))))
+               {
+                 offsetT add;
 
-      old_fr_fix = fragP->fr_fix;
-      opcode = (unsigned char *) fragP->fr_opcode;
+                 if (insn_start_frag == frag_now)
+                   add = (p - frag_now->fr_literal) - insn_start_off;
+                 else
+                   {
+                     fragS *fr;
 
-      switch (TYPE_FROM_RELAX_STATE (fragP->fr_subtype))
-       {
-       case UNCOND_JUMP:
-         /* Make jmp (0xeb) a (d)word displacement jump.  */
-         opcode[0] = 0xe9;
-         fragP->fr_fix += size;
-         fix_new (fragP, old_fr_fix, size,
-                  fragP->fr_symbol,
-                  fragP->fr_offset, 1,
-                  reloc_type);
-         break;
+                     add = insn_start_frag->fr_fix - insn_start_off;
+                     for (fr = insn_start_frag->fr_next;
+                          fr && fr != frag_now; fr = fr->fr_next)
+                       add += fr->fr_fix;
+                     add += p - frag_now->fr_literal;
+                   }
 
-       case COND_JUMP86:
-         if (size == 2
-             && (!no_cond_jump_promotion || fragP->fr_var != NO_RELOC))
-           {
-             /* Negate the condition, and branch past an
-                unconditional jump.  */
-             opcode[0] ^= 1;
-             opcode[1] = 3;
-             /* Insert an unconditional jump.  */
-             opcode[2] = 0xe9;
-             /* We added two extra opcode bytes, and have a two byte
-                offset.  */
-             fragP->fr_fix += 2 + 2;
-             fix_new (fragP, old_fr_fix + 2, 2,
-                      fragP->fr_symbol,
-                      fragP->fr_offset, 1,
-                      reloc_type);
-             break;
+                 if (!object_64bit)
+                   reloc_type = BFD_RELOC_386_GOTPC;
+                 else if (size == 4)
+                   reloc_type = BFD_RELOC_X86_64_GOTPC32;
+                 else if (size == 8)
+                   reloc_type = BFD_RELOC_X86_64_GOTPC64;
+                 i.op[n].imms->X_add_number += add;
+               }
+             fix_new_exp (frag_now, p - frag_now->fr_literal, size,
+                          i.op[n].imms, 0, reloc_type);
            }
-         /* Fall through.  */
-
-       case COND_JUMP:
-         if (no_cond_jump_promotion && fragP->fr_var == NO_RELOC)
-           {
-             fixS *fixP;
+       }
+    }
+}
+\f
+/* x86_cons_fix_new is called via the expression parsing code when a
+   reloc is needed.  We use this hook to get the correct .got reloc.  */
+static enum bfd_reloc_code_real got_reloc = NO_RELOC;
+static int cons_sign = -1;
 
-             fragP->fr_fix += 1;
-             fixP = fix_new (fragP, old_fr_fix, 1,
-                             fragP->fr_symbol,
-                             fragP->fr_offset, 1,
-                             BFD_RELOC_8_PCREL);
-             fixP->fx_signed = 1;
-             break;
-           }
+void
+x86_cons_fix_new (fragS *frag, unsigned int off, unsigned int len,
+                 expressionS *exp)
+{
+  enum bfd_reloc_code_real r = reloc (len, 0, cons_sign, got_reloc);
 
-         /* This changes the byte-displacement jump 0x7N
-            to the (d)word-displacement jump 0x0f,0x8N.  */
-         opcode[1] = opcode[0] + 0x10;
-         opcode[0] = TWO_BYTE_OPCODE_ESCAPE;
-         /* We've added an opcode byte.  */
-         fragP->fr_fix += 1 + size;
-         fix_new (fragP, old_fr_fix + 1, size,
-                  fragP->fr_symbol,
-                  fragP->fr_offset, 1,
-                  reloc_type);
-         break;
+  got_reloc = NO_RELOC;
 
-       default:
-         BAD_CASE (fragP->fr_subtype);
-         break;
-       }
-      frag_wane (fragP);
-      return fragP->fr_fix - old_fr_fix;
+#ifdef TE_PE
+  if (exp->X_op == O_secrel)
+    {
+      exp->X_op = O_symbol;
+      r = BFD_RELOC_32_SECREL;
     }
+#endif
 
-  /* Guess size depending on current relax state.  Initially the relax
-     state will correspond to a short jump and we return 1, because
-     the variable part of the frag (the branch offset) is one byte
-     long.  However, we can relax a section more than once and in that
-     case we must either set fr_subtype back to the unrelaxed state,
-     or return the value for the appropriate branch.  */
-  return md_relax_table[fragP->fr_subtype].rlx_length;
+  fix_new_exp (frag, off, len, exp, 0, r);
 }
 
-/* Called after relax() is finished.
-
-   In: Address of frag.
-       fr_type == rs_machine_dependent.
-       fr_subtype is what the address relaxed to.
-
-   Out:        Any fixSs and constants are set up.
-       Caller will turn frag into a ".space 0".  */
+#if (!defined (OBJ_ELF) && !defined (OBJ_MAYBE_ELF)) || defined (LEX_AT)
+# define lex_got(reloc, adjust, types) NULL
+#else
+/* Parse operands of the form
+   <symbol>@GOTOFF+<nnn>
+   and similar .plt or .got references.
 
-void
-md_convert_frag (abfd, sec, fragP)
-     bfd *abfd ATTRIBUTE_UNUSED;
-     segT sec ATTRIBUTE_UNUSED;
-     fragS *fragP;
+   If we find one, set up the correct relocation in RELOC and copy the
+   input string, minus the `@GOTOFF' into a malloc'd buffer for
+   parsing by the calling routine.  Return this buffer, and if ADJUST
+   is non-null set it to the length of the string we removed from the
+   input line.  Otherwise return NULL.  */
+static char *
+lex_got (enum bfd_reloc_code_real *reloc,
+        int *adjust,
+        i386_operand_type *types)
 {
-  unsigned char *opcode;
-  unsigned char *where_to_put_displacement = NULL;
-  offsetT target_address;
-  offsetT opcode_address;
-  unsigned int extension = 0;
-  offsetT displacement_from_opcode_start;
-
-  opcode = (unsigned char *) fragP->fr_opcode;
+  /* Some of the relocations depend on the size of what field is to
+     be relocated.  But in our callers i386_immediate and i386_displacement
+     we don't yet know the operand size (this will be set by insn
+     matching).  Hence we record the word32 relocation here,
+     and adjust the reloc according to the real size in reloc().  */
+  static const struct {
+    const char *str;
+    const enum bfd_reloc_code_real rel[2];
+    const i386_operand_type types64;
+  } gotrel[] = {
+    { "PLTOFF",   { _dummy_first_bfd_reloc_code_real,
+                   BFD_RELOC_X86_64_PLTOFF64 },
+      OPERAND_TYPE_IMM64 },
+    { "PLT",      { BFD_RELOC_386_PLT32,
+                   BFD_RELOC_X86_64_PLT32    },
+      OPERAND_TYPE_IMM32_32S_DISP32 },
+    { "GOTPLT",   { _dummy_first_bfd_reloc_code_real,
+                   BFD_RELOC_X86_64_GOTPLT64 },
+      OPERAND_TYPE_IMM64_DISP64 },
+    { "GOTOFF",   { BFD_RELOC_386_GOTOFF,
+                   BFD_RELOC_X86_64_GOTOFF64 },
+      OPERAND_TYPE_IMM64_DISP64 },
+    { "GOTPCREL", { _dummy_first_bfd_reloc_code_real,
+                   BFD_RELOC_X86_64_GOTPCREL },
+      OPERAND_TYPE_IMM32_32S_DISP32 },
+    { "TLSGD",    { BFD_RELOC_386_TLS_GD,
+                   BFD_RELOC_X86_64_TLSGD    },
+      OPERAND_TYPE_IMM32_32S_DISP32 },
+    { "TLSLDM",   { BFD_RELOC_386_TLS_LDM,
+                   _dummy_first_bfd_reloc_code_real },
+      OPERAND_TYPE_NONE },
+    { "TLSLD",    { _dummy_first_bfd_reloc_code_real,
+                   BFD_RELOC_X86_64_TLSLD    },
+      OPERAND_TYPE_IMM32_32S_DISP32 },
+    { "GOTTPOFF", { BFD_RELOC_386_TLS_IE_32,
+                   BFD_RELOC_X86_64_GOTTPOFF },
+      OPERAND_TYPE_IMM32_32S_DISP32 },
+    { "TPOFF",    { BFD_RELOC_386_TLS_LE_32,
+                   BFD_RELOC_X86_64_TPOFF32  },
+      OPERAND_TYPE_IMM32_32S_64_DISP32_64 },
+    { "NTPOFF",   { BFD_RELOC_386_TLS_LE,
+                   _dummy_first_bfd_reloc_code_real },
+      OPERAND_TYPE_NONE },
+    { "DTPOFF",   { BFD_RELOC_386_TLS_LDO_32,
+                   BFD_RELOC_X86_64_DTPOFF32 },
 
-  /* Address we want to reach in file space.  */
-  target_address = S_GET_VALUE (fragP->fr_symbol) + fragP->fr_offset;
+      OPERAND_TYPE_IMM32_32S_64_DISP32_64 },
+    { "GOTNTPOFF",{ BFD_RELOC_386_TLS_GOTIE,
+                   _dummy_first_bfd_reloc_code_real },
+      OPERAND_TYPE_NONE },
+    { "INDNTPOFF",{ BFD_RELOC_386_TLS_IE,
+                   _dummy_first_bfd_reloc_code_real },
+      OPERAND_TYPE_NONE },
+    { "GOT",      { BFD_RELOC_386_GOT32,
+                   BFD_RELOC_X86_64_GOT32    },
+      OPERAND_TYPE_IMM32_32S_64_DISP32 },
+    { "TLSDESC",  { BFD_RELOC_386_TLS_GOTDESC,
+                   BFD_RELOC_X86_64_GOTPC32_TLSDESC },
+      OPERAND_TYPE_IMM32_32S_DISP32 },
+    { "TLSCALL",  { BFD_RELOC_386_TLS_DESC_CALL,
+                   BFD_RELOC_X86_64_TLSDESC_CALL },
+      OPERAND_TYPE_IMM32_32S_DISP32 },
+  };
+  char *cp;
+  unsigned int j;
 
-  /* Address opcode resides at in file space.  */
-  opcode_address = fragP->fr_address + fragP->fr_fix;
+  if (!IS_ELF)
+    return NULL;
 
-  /* Displacement from opcode start to fill into instruction.  */
-  displacement_from_opcode_start = target_address - opcode_address;
+  for (cp = input_line_pointer; *cp != '@'; cp++)
+    if (is_end_of_line[(unsigned char) *cp] || *cp == ',')
+      return NULL;
 
-  if ((fragP->fr_subtype & BIG) == 0)
-    {
-      /* Don't have to change opcode.  */
-      extension = 1;           /* 1 opcode + 1 displacement  */
-      where_to_put_displacement = &opcode[1];
-    }
-  else
+  for (j = 0; j < ARRAY_SIZE (gotrel); j++)
     {
-      if (no_cond_jump_promotion
-         && TYPE_FROM_RELAX_STATE (fragP->fr_subtype) != UNCOND_JUMP)
-       as_warn_where (fragP->fr_file, fragP->fr_line,
-                      _("long jump required"));
+      int len;
 
-      switch (fragP->fr_subtype)
+      len = strlen (gotrel[j].str);
+      if (strncasecmp (cp + 1, gotrel[j].str, len) == 0)
        {
-       case ENCODE_RELAX_STATE (UNCOND_JUMP, BIG):
-         extension = 4;                /* 1 opcode + 4 displacement  */
-         opcode[0] = 0xe9;
-         where_to_put_displacement = &opcode[1];
-         break;
+         if (gotrel[j].rel[object_64bit] != 0)
+           {
+             int first, second;
+             char *tmpbuf, *past_reloc;
 
-       case ENCODE_RELAX_STATE (UNCOND_JUMP, BIG16):
-         extension = 2;                /* 1 opcode + 2 displacement  */
-         opcode[0] = 0xe9;
-         where_to_put_displacement = &opcode[1];
-         break;
+             *reloc = gotrel[j].rel[object_64bit];
+             if (adjust)
+               *adjust = len;
 
-       case ENCODE_RELAX_STATE (COND_JUMP, BIG):
-       case ENCODE_RELAX_STATE (COND_JUMP86, BIG):
-         extension = 5;                /* 2 opcode + 4 displacement  */
-         opcode[1] = opcode[0] + 0x10;
-         opcode[0] = TWO_BYTE_OPCODE_ESCAPE;
-         where_to_put_displacement = &opcode[2];
-         break;
+             if (types)
+               {
+                 if (flag_code != CODE_64BIT)
+                   {
+                     types->bitfield.imm32 = 1;
+                     types->bitfield.disp32 = 1;
+                   }
+                 else
+                   *types = gotrel[j].types64;
+               }
 
-       case ENCODE_RELAX_STATE (COND_JUMP, BIG16):
-         extension = 3;                /* 2 opcode + 2 displacement  */
-         opcode[1] = opcode[0] + 0x10;
-         opcode[0] = TWO_BYTE_OPCODE_ESCAPE;
-         where_to_put_displacement = &opcode[2];
-         break;
+             if (GOT_symbol == NULL)
+               GOT_symbol = symbol_find_or_make (GLOBAL_OFFSET_TABLE_NAME);
 
-       case ENCODE_RELAX_STATE (COND_JUMP86, BIG16):
-         extension = 4;
-         opcode[0] ^= 1;
-         opcode[1] = 3;
-         opcode[2] = 0xe9;
-         where_to_put_displacement = &opcode[3];
-         break;
+             /* The length of the first part of our input line.  */
+             first = cp - input_line_pointer;
 
-       default:
-         BAD_CASE (fragP->fr_subtype);
-         break;
-       }
-    }
+             /* 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 size if less then four we are sure that the operand fits,
-     but if it's 4, then it could be that the displacement is larger
-     then -/+ 2GB.  */
-  if (DISP_SIZE_FROM_RELAX_STATE (fragP->fr_subtype) == 4
-      && object_64bit
-      && ((addressT) (displacement_from_opcode_start - extension
-                     + ((addressT) 1 << 31))
-         > (((addressT) 2 << 31) - 1)))
-    {
-      as_bad_where (fragP->fr_file, fragP->fr_line,
-                   _("jump target out of range"));
-      /* Make us emit 0.  */
-      displacement_from_opcode_start = extension;
-    }
-  /* Now put displacement after opcode.  */
-  md_number_to_chars ((char *) where_to_put_displacement,
-                     (valueT) (displacement_from_opcode_start - extension),
-                     DISP_SIZE_FROM_RELAX_STATE (fragP->fr_subtype));
-  fragP->fr_fix += extension;
-}
-\f
-/* Size of byte displacement jmp.  */
-int md_short_jump_size = 2;
+             /* Allocate and copy string.  The trailing NUL shouldn't
+                be necessary, but be safe.  */
+             tmpbuf = (char *) xmalloc (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++] = ' ';
+             memcpy (tmpbuf + first, past_reloc, second);
+             tmpbuf[first + second] = '\0';
+             return tmpbuf;
+           }
 
-/* Size of dword displacement jmp.  */
-int md_long_jump_size = 5;
+         as_bad (_("@%s reloc is not supported with %d-bit output format"),
+                 gotrel[j].str, 1 << (5 + object_64bit));
+         return NULL;
+       }
+    }
 
-void
-md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol)
-     char *ptr;
-     addressT from_addr, to_addr;
-     fragS *frag ATTRIBUTE_UNUSED;
-     symbolS *to_symbol ATTRIBUTE_UNUSED;
-{
-  offsetT offset;
-
-  offset = to_addr - (from_addr + 2);
-  /* Opcode for byte-disp jump.  */
-  md_number_to_chars (ptr, (valueT) 0xeb, 1);
-  md_number_to_chars (ptr + 1, (valueT) offset, 1);
+  /* Might be a symbol version string.  Don't as_bad here.  */
+  return NULL;
 }
 
 void
-md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol)
-     char *ptr;
-     addressT from_addr, to_addr;
-     fragS *frag ATTRIBUTE_UNUSED;
-     symbolS *to_symbol ATTRIBUTE_UNUSED;
+x86_cons (expressionS *exp, int size)
 {
-  offsetT offset;
+  intel_syntax = -intel_syntax;
 
-  offset = to_addr - (from_addr + 5);
-  md_number_to_chars (ptr, (valueT) 0xe9, 1);
-  md_number_to_chars (ptr + 1, (valueT) offset, 4);
-}
-\f
-/* Apply a fixup (fixS) to segment data, once it has been determined
-   by our caller that we have all the info we need to fix it up.
+  if (size == 4 || (object_64bit && size == 8))
+    {
+      /* Handle @GOTOFF and the like in an expression.  */
+      char *save;
+      char *gotfree_input_line;
+      int adjust;
 
-   On the 386, immediates, displacements, and data pointers are all in
-   the same (little-endian) format, so we don't need to care about which
-   we are handling.  */
+      save = input_line_pointer;
+      gotfree_input_line = lex_got (&got_reloc, &adjust, NULL);
+      if (gotfree_input_line)
+       input_line_pointer = gotfree_input_line;
 
-void
-md_apply_fix (fixP, valP, seg)
-     /* The fix we're to put in.  */
-     fixS *fixP;
-     /* Pointer to the value of the bits.  */
-     valueT *valP;
-     /* Segment fix is from.  */
-     segT seg ATTRIBUTE_UNUSED;
-{
-  char *p = fixP->fx_where + fixP->fx_frag->fr_literal;
-  valueT value = *valP;
+      expression (exp);
 
-#if !defined (TE_Mach)
-  if (fixP->fx_pcrel)
-    {
-      switch (fixP->fx_r_type)
+      if (gotfree_input_line)
        {
-       default:
-         break;
+         /* 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
+    expression (exp);
 
-       case BFD_RELOC_64:
-         fixP->fx_r_type = BFD_RELOC_64_PCREL;
-         break;
-       case BFD_RELOC_32:
-       case BFD_RELOC_X86_64_32S:
-         fixP->fx_r_type = BFD_RELOC_32_PCREL;
-         break;
-       case BFD_RELOC_16:
-         fixP->fx_r_type = BFD_RELOC_16_PCREL;
-         break;
-       case BFD_RELOC_8:
-         fixP->fx_r_type = BFD_RELOC_8_PCREL;
-         break;
-       }
-    }
+  intel_syntax = -intel_syntax;
 
-  if (fixP->fx_addsy != NULL
-      && (fixP->fx_r_type == BFD_RELOC_32_PCREL
-         || fixP->fx_r_type == BFD_RELOC_64_PCREL
-         || fixP->fx_r_type == BFD_RELOC_16_PCREL
-         || fixP->fx_r_type == BFD_RELOC_8_PCREL)
-      && !use_rela_relocations)
-    {
-      /* This is a hack.  There should be a better way to handle this.
-        This covers for the fact that bfd_install_relocation will
-        subtract the current location (for partial_inplace, PC relative
-        relocations); see more below.  */
-#ifndef OBJ_AOUT
-      if (IS_ELF
-#ifdef TE_PE
-         || OUTPUT_FLAVOR == bfd_target_coff_flavour
-#endif
-         )
-       value += fixP->fx_where + fixP->fx_frag->fr_address;
+  if (intel_syntax)
+    i386_intel_simplify (exp);
+}
 #endif
-#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
-      if (IS_ELF)
-       {
-         segT sym_seg = S_GET_SEGMENT (fixP->fx_addsy);
 
-         if ((sym_seg == seg
-              || (symbol_section_p (fixP->fx_addsy)
-                  && sym_seg != absolute_section))
-             && !generic_force_reloc (fixP))
-           {
-             /* Yes, we add the values in twice.  This is because
-                bfd_install_relocation subtracts them out again.  I think
-                bfd_install_relocation is broken, but I don't dare change
-                it.  FIXME.  */
-             value += fixP->fx_where + fixP->fx_frag->fr_address;
-           }
-       }
-#endif
-#if defined (OBJ_COFF) && defined (TE_PE)
-      /* For some reason, the PE format does not store a
-        section address offset for a PC relative symbol.  */
-      if (S_GET_SEGMENT (fixP->fx_addsy) != seg
-         || S_IS_WEAK (fixP->fx_addsy))
-       value += md_pcrel_from (fixP);
-#endif
-    }
+static void signed_cons (int size)
+{
+  if (flag_code == CODE_64BIT)
+    cons_sign = 1;
+  cons (size);
+  cons_sign = -1;
+}
 
-  /* Fix a few things - the dynamic linker expects certain values here,
-     and we must not disappoint it.  */
-#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
-  if (IS_ELF && fixP->fx_addsy)
-    switch (fixP->fx_r_type)
-      {
-      case BFD_RELOC_386_PLT32:
-      case BFD_RELOC_X86_64_PLT32:
-       /* Make the jump instruction point to the address of the operand.  At
-          runtime we merely add the offset to the actual PLT entry.  */
-       value = -4;
-       break;
+#ifdef TE_PE
+static void
+pe_directive_secrel (dummy)
+     int dummy ATTRIBUTE_UNUSED;
+{
+  expressionS exp;
 
-      case BFD_RELOC_386_TLS_GD:
-      case BFD_RELOC_386_TLS_LDM:
-      case BFD_RELOC_386_TLS_IE_32:
-      case BFD_RELOC_386_TLS_IE:
-      case BFD_RELOC_386_TLS_GOTIE:
-      case BFD_RELOC_386_TLS_GOTDESC:
-      case BFD_RELOC_X86_64_TLSGD:
-      case BFD_RELOC_X86_64_TLSLD:
-      case BFD_RELOC_X86_64_GOTTPOFF:
-      case BFD_RELOC_X86_64_GOTPC32_TLSDESC:
-       value = 0; /* Fully resolved at runtime.  No addend.  */
-       /* Fallthrough */
-      case BFD_RELOC_386_TLS_LE:
-      case BFD_RELOC_386_TLS_LDO_32:
-      case BFD_RELOC_386_TLS_LE_32:
-      case BFD_RELOC_X86_64_DTPOFF32:
-      case BFD_RELOC_X86_64_DTPOFF64:
-      case BFD_RELOC_X86_64_TPOFF32:
-      case BFD_RELOC_X86_64_TPOFF64:
-       S_SET_THREAD_LOCAL (fixP->fx_addsy);
-       break;
+  do
+    {
+      expression (&exp);
+      if (exp.X_op == O_symbol)
+       exp.X_op = O_secrel;
 
-      case BFD_RELOC_386_TLS_DESC_CALL:
-      case BFD_RELOC_X86_64_TLSDESC_CALL:
-       value = 0; /* Fully resolved at runtime.  No addend.  */
-       S_SET_THREAD_LOCAL (fixP->fx_addsy);
-       fixP->fx_done = 0;
-       return;
+      emit_expr (&exp, 4);
+    }
+  while (*input_line_pointer++ == ',');
 
-      case BFD_RELOC_386_GOT32:
-      case BFD_RELOC_X86_64_GOT32:
-       value = 0; /* Fully resolved at runtime.  No addend.  */
-       break;
+  input_line_pointer--;
+  demand_empty_rest_of_line ();
+}
+#endif
 
-      case BFD_RELOC_VTABLE_INHERIT:
-      case BFD_RELOC_VTABLE_ENTRY:
-       fixP->fx_done = 0;
-       return;
+static int
+i386_immediate (char *imm_start)
+{
+  char *save_input_line_pointer;
+  char *gotfree_input_line;
+  segT exp_seg = 0;
+  expressionS *exp;
+  i386_operand_type types;
 
-      default:
-       break;
-      }
-#endif /* defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)  */
-  *valP = value;
-#endif /* !defined (TE_Mach)  */
+  operand_type_set (&types, ~0);
 
-  /* Are we finished with this relocation now?  */
-  if (fixP->fx_addsy == NULL)
-    fixP->fx_done = 1;
-  else if (use_rela_relocations)
+  if (i.imm_operands == MAX_IMMEDIATE_OPERANDS)
     {
-      fixP->fx_no_overflow = 1;
-      /* Remember value for tc_gen_reloc.  */
-      fixP->fx_addnumber = value;
-      value = 0;
+      as_bad (_("at most %d immediate operands are allowed"),
+             MAX_IMMEDIATE_OPERANDS);
+      return 0;
     }
 
-  md_number_to_chars (p, value, fixP->fx_size);
-}
-\f
-#define MAX_LITTLENUMS 6
-
-/* Turn the string pointed to by litP into a floating point constant
-   of type TYPE, and emit the appropriate bytes.  The number of
-   LITTLENUMS emitted is stored in *SIZEP.  An error message is
-   returned, or NULL on OK.  */
+  exp = &im_expressions[i.imm_operands++];
+  i.op[this_operand].imms = exp;
 
-char *
-md_atof (type, litP, sizeP)
-     int type;
-     char *litP;
-     int *sizeP;
-{
-  int prec;
-  LITTLENUM_TYPE words[MAX_LITTLENUMS];
-  LITTLENUM_TYPE *wordP;
-  char *t;
+  if (is_space_char (*imm_start))
+    ++imm_start;
 
-  switch (type)
-    {
-    case 'f':
-    case 'F':
-      prec = 2;
-      break;
+  save_input_line_pointer = input_line_pointer;
+  input_line_pointer = imm_start;
 
-    case 'd':
-    case 'D':
-      prec = 4;
-      break;
+  gotfree_input_line = lex_got (&i.reloc[this_operand], NULL, &types);
+  if (gotfree_input_line)
+    input_line_pointer = gotfree_input_line;
 
-    case 'x':
-    case 'X':
-      prec = 5;
-      break;
+  exp_seg = expression (exp);
 
-    default:
-      *sizeP = 0;
-      return _("Bad call to md_atof ()");
-    }
-  t = atof_ieee (input_line_pointer, type, words);
-  if (t)
-    input_line_pointer = t;
+  SKIP_WHITESPACE ();
+  if (*input_line_pointer)
+    as_bad (_("junk `%s' after expression"), input_line_pointer);
 
-  *sizeP = prec * sizeof (LITTLENUM_TYPE);
-  /* This loops outputs the LITTLENUMs in REVERSE order; in accord with
-     the bigendian 386.  */
-  for (wordP = words + prec - 1; prec--;)
+  input_line_pointer = save_input_line_pointer;
+  if (gotfree_input_line)
     {
-      md_number_to_chars (litP, (valueT) (*wordP--), sizeof (LITTLENUM_TYPE));
-      litP += sizeof (LITTLENUM_TYPE);
+      free (gotfree_input_line);
+
+      if (exp->X_op == O_constant || exp->X_op == O_register)
+       exp->X_op = O_illegal;
     }
-  return 0;
+
+  return i386_finalize_immediate (exp_seg, exp, types, imm_start);
 }
-\f
-static char output_invalid_buf[sizeof (unsigned char) * 2 + 6];
 
-static char *
-output_invalid (int c)
+static int
+i386_finalize_immediate (segT exp_seg ATTRIBUTE_UNUSED, expressionS *exp,
+                        i386_operand_type types, const char *imm_start)
 {
-  if (ISPRINT (c))
-    snprintf (output_invalid_buf, sizeof (output_invalid_buf),
-             "'%c'", c);
+  if (exp->X_op == O_absent || exp->X_op == O_illegal || exp->X_op == O_big)
+    {
+      as_bad (_("missing or invalid immediate expression `%s'"),
+             imm_start);
+      return 0;
+    }
+  else if (exp->X_op == O_constant)
+    {
+      /* Size it properly later.  */
+      i.types[this_operand].bitfield.imm64 = 1;
+      /* If BFD64, sign extend val.  */
+      if (!use_rela_relocations
+         && (exp->X_add_number & ~(((addressT) 2 << 31) - 1)) == 0)
+       exp->X_add_number
+         = (exp->X_add_number ^ ((addressT) 1 << 31)) - ((addressT) 1 << 31);
+    }
+#if (defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT))
+  else if (OUTPUT_FLAVOR == bfd_target_aout_flavour
+          && exp_seg != absolute_section
+          && exp_seg != text_section
+          && exp_seg != data_section
+          && exp_seg != bss_section
+          && exp_seg != undefined_section
+          && !bfd_is_com_section (exp_seg))
+    {
+      as_bad (_("unimplemented segment %s in operand"), exp_seg->name);
+      return 0;
+    }
+#endif
+  else if (!intel_syntax && exp->X_op == O_register)
+    {
+      as_bad (_("illegal immediate register operand %s"), imm_start);
+      return 0;
+    }
   else
-    snprintf (output_invalid_buf, sizeof (output_invalid_buf),
-             "(0x%x)", (unsigned char) c);
-  return output_invalid_buf;
-}
+    {
+      /* This is an address.  The size of the address will be
+        determined later, depending on destination register,
+        suffix, or the default for the section.  */
+      i.types[this_operand].bitfield.imm8 = 1;
+      i.types[this_operand].bitfield.imm16 = 1;
+      i.types[this_operand].bitfield.imm32 = 1;
+      i.types[this_operand].bitfield.imm32s = 1;
+      i.types[this_operand].bitfield.imm64 = 1;
+      i.types[this_operand] = operand_type_and (i.types[this_operand],
+                                               types);
+    }
 
-/* REG_STRING starts *before* REGISTER_PREFIX.  */
+  return 1;
+}
 
-static const reg_entry *
-parse_real_register (char *reg_string, char **end_op)
+static char *
+i386_scale (char *scale)
 {
-  char *s = reg_string;
-  char *p;
-  char reg_name_given[MAX_REG_NAME_SIZE + 1];
-  const reg_entry *r;
-
-  /* Skip possible REGISTER_PREFIX and possible whitespace.  */
-  if (*s == REGISTER_PREFIX)
-    ++s;
+  offsetT val;
+  char *save = input_line_pointer;
 
-  if (is_space_char (*s))
-    ++s;
+  input_line_pointer = scale;
+  val = get_absolute_expression ();
 
-  p = reg_name_given;
-  while ((*p++ = register_chars[(unsigned char) *s]) != '\0')
+  switch (val)
     {
-      if (p >= reg_name_given + MAX_REG_NAME_SIZE)
-       return (const reg_entry *) NULL;
-      s++;
-    }
+    case 1:
+      i.log2_scale_factor = 0;
+      break;
+    case 2:
+      i.log2_scale_factor = 1;
+      break;
+    case 4:
+      i.log2_scale_factor = 2;
+      break;
+    case 8:
+      i.log2_scale_factor = 3;
+      break;
+    default:
+      {
+       char sep = *input_line_pointer;
 
-  /* 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])
-    return (const reg_entry *) NULL;
+       *input_line_pointer = '\0';
+       as_bad (_("expecting scale factor of 1, 2, 4, or 8: got `%s'"),
+               scale);
+       *input_line_pointer = sep;
+       input_line_pointer = save;
+       return NULL;
+      }
+    }
+  if (i.log2_scale_factor != 0 && i.index_reg == 0)
+    {
+      as_warn (_("scale factor of %d without an index register"),
+              1 << i.log2_scale_factor);
+      i.log2_scale_factor = 0;
+    }
+  scale = input_line_pointer;
+  input_line_pointer = save;
+  return scale;
+}
 
-  *end_op = s;
+static int
+i386_displacement (char *disp_start, char *disp_end)
+{
+  expressionS *exp;
+  segT exp_seg = 0;
+  char *save_input_line_pointer;
+  char *gotfree_input_line;
+  int override;
+  i386_operand_type bigdisp, types = anydisp;
+  int ret;
 
-  r = (const reg_entry *) hash_find (reg_hash, reg_name_given);
+  if (i.disp_operands == MAX_MEMORY_OPERANDS)
+    {
+      as_bad (_("at most %d displacement operands are allowed"),
+             MAX_MEMORY_OPERANDS);
+      return 0;
+    }
 
-  /* Handle floating point regs, allowing spaces in the (i) part.  */
-  if (r == i386_regtab /* %st is first entry of table  */)
+  operand_type_set (&bigdisp, 0);
+  if ((i.types[this_operand].bitfield.jumpabsolute)
+      || (!current_templates->start->opcode_modifier.jump
+         && !current_templates->start->opcode_modifier.jumpdword))
     {
-      if (is_space_char (*s))
-       ++s;
-      if (*s == '(')
+      bigdisp.bitfield.disp32 = 1;
+      override = (i.prefix[ADDR_PREFIX] != 0);
+      if (flag_code == CODE_64BIT)
        {
-         ++s;
-         if (is_space_char (*s))
-           ++s;
-         if (*s >= '0' && *s <= '7')
+         if (!override)
            {
-             int fpr = *s - '0';
-             ++s;
-             if (is_space_char (*s))
-               ++s;
-             if (*s == ')')
-               {
-                 *end_op = s + 1;
-                 r = hash_find (reg_hash, "st(0)");
-                 know (r);
-                 return r + fpr;
-               }
+             bigdisp.bitfield.disp32s = 1;
+             bigdisp.bitfield.disp64 = 1;
            }
-         /* We have "%st(" then garbage.  */
-         return (const reg_entry *) NULL;
+       }
+      else if ((flag_code == CODE_16BIT) ^ override)
+       {
+         bigdisp.bitfield.disp32 = 0;
+         bigdisp.bitfield.disp16 = 1;
        }
     }
-
-  if (r != NULL
-      && ((r->reg_flags & (RegRex64 | RegRex)) | (r->reg_type & Reg64)) != 0
-      && (r->reg_type != Control || !(cpu_arch_flags & CpuSledgehammer))
-      && flag_code != CODE_64BIT)
-    return (const reg_entry *) NULL;
-
-  return r;
-}
-
-/* REG_STRING starts *before* REGISTER_PREFIX.  */
-
-static const reg_entry *
-parse_register (char *reg_string, char **end_op)
-{
-  const reg_entry *r;
-
-  if (*reg_string == REGISTER_PREFIX || allow_naked_reg)
-    r = parse_real_register (reg_string, end_op);
   else
-    r = NULL;
-  if (!r)
     {
-      char *save = input_line_pointer;
-      char c;
-      symbolS *symbolP;
-
-      input_line_pointer = reg_string;
-      c = get_symbol_end ();
-      symbolP = symbol_find (reg_string);
-      if (symbolP && S_GET_SEGMENT (symbolP) == reg_section)
+      /* For PC-relative branches, the width of the displacement
+        is dependent upon data size, not address size.  */
+      override = (i.prefix[DATA_PREFIX] != 0);
+      if (flag_code == CODE_64BIT)
        {
-         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;
-         *end_op = input_line_pointer;
+         if (override || i.suffix == WORD_MNEM_SUFFIX)
+           bigdisp.bitfield.disp16 = 1;
+         else
+           {
+             bigdisp.bitfield.disp32 = 1;
+             bigdisp.bitfield.disp32s = 1;
+           }
+       }
+      else
+       {
+         if (!override)
+           override = (i.suffix == (flag_code != CODE_16BIT
+                                    ? WORD_MNEM_SUFFIX
+                                    : LONG_MNEM_SUFFIX));
+         bigdisp.bitfield.disp32 = 1;
+         if ((flag_code == CODE_16BIT) ^ override)
+           {
+             bigdisp.bitfield.disp32 = 0;
+             bigdisp.bitfield.disp16 = 1;
+           }
        }
-      *input_line_pointer = c;
-      input_line_pointer = save;
     }
-  return r;
-}
+  i.types[this_operand] = operand_type_or (i.types[this_operand],
+                                          bigdisp);
 
-int
-i386_parse_name (char *name, expressionS *e, char *nextcharP)
-{
-  const reg_entry *r;
-  char *end = input_line_pointer;
+  exp = &disp_expressions[i.disp_operands];
+  i.op[this_operand].disps = exp;
+  i.disp_operands++;
+  save_input_line_pointer = input_line_pointer;
+  input_line_pointer = disp_start;
+  END_STRING_AND_SAVE (disp_end);
 
-  *end = *nextcharP;
-  r = parse_register (name, &input_line_pointer);
-  if (r && end <= input_line_pointer)
+#ifndef GCC_ASM_O_HACK
+#define GCC_ASM_O_HACK 0
+#endif
+#if GCC_ASM_O_HACK
+  END_STRING_AND_SAVE (disp_end + 1);
+  if (i.types[this_operand].bitfield.baseIndex
+      && displacement_string_end[-1] == '+')
     {
-      *nextcharP = *input_line_pointer;
-      *input_line_pointer = 0;
-      e->X_op = O_register;
-      e->X_add_number = r - i386_regtab;
-      return 1;
-    }
-  input_line_pointer = end;
-  *end = 0;
-  return 0;
-}
+      /* This hack is to avoid a warning when using the "o"
+        constraint within gcc asm statements.
+        For instance:
 
-void
-md_operand (expressionS *e)
-{
-  if (*input_line_pointer == REGISTER_PREFIX)
-    {
-      char *end;
-      const reg_entry *r = parse_real_register (input_line_pointer, &end);
+        #define _set_tssldt_desc(n,addr,limit,type) \
+        __asm__ __volatile__ ( \
+        "movw %w2,%0\n\t" \
+        "movw %w1,2+%0\n\t" \
+        "rorl $16,%1\n\t" \
+        "movb %b1,4+%0\n\t" \
+        "movb %4,5+%0\n\t" \
+        "movb $0,6+%0\n\t" \
+        "movb %h1,7+%0\n\t" \
+        "rorl $16,%1" \
+        : "=o"(*(n)) : "q" (addr), "ri"(limit), "i"(type))
 
-      if (r)
-       {
-         e->X_op = O_register;
-         e->X_add_number = r - i386_regtab;
-         input_line_pointer = end;
-       }
-    }
-}
+        This works great except that the output assembler ends
+        up looking a bit weird if it turns out that there is
+        no offset.  You end up producing code that looks like:
 
-\f
-#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
-const char *md_shortopts = "kVQ:sqn";
-#else
-const char *md_shortopts = "qn";
-#endif
+        #APP
+        movw $235,(%eax)
+        movw %dx,2+(%eax)
+        rorl $16,%edx
+        movb %dl,4+(%eax)
+        movb $137,5+(%eax)
+        movb $0,6+(%eax)
+        movb %dh,7+(%eax)
+        rorl $16,%edx
+        #NO_APP
 
-#define OPTION_32 (OPTION_MD_BASE + 0)
-#define OPTION_64 (OPTION_MD_BASE + 1)
-#define OPTION_DIVIDE (OPTION_MD_BASE + 2)
-#define OPTION_MARCH (OPTION_MD_BASE + 3)
-#define OPTION_MTUNE (OPTION_MD_BASE + 4)
+        So here we provide the missing zero.  */
 
-struct option md_longopts[] =
-{
-  {"32", no_argument, NULL, OPTION_32},
-#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) || defined(TE_PEP)
-  {"64", no_argument, NULL, OPTION_64},
+      *displacement_string_end = '0';
+    }
 #endif
-  {"divide", no_argument, NULL, OPTION_DIVIDE},
-  {"march", required_argument, NULL, OPTION_MARCH},
-  {"mtune", required_argument, NULL, OPTION_MTUNE},
-  {NULL, no_argument, NULL, 0}
-};
-size_t md_longopts_size = sizeof (md_longopts);
+  gotfree_input_line = lex_got (&i.reloc[this_operand], NULL, &types);
+  if (gotfree_input_line)
+    input_line_pointer = gotfree_input_line;
 
-int
-md_parse_option (int c, char *arg)
-{
-  unsigned int i;
+  exp_seg = expression (exp);
 
-  switch (c)
+  SKIP_WHITESPACE ();
+  if (*input_line_pointer)
+    as_bad (_("junk `%s' after expression"), input_line_pointer);
+#if GCC_ASM_O_HACK
+  RESTORE_END_STRING (disp_end + 1);
+#endif
+  input_line_pointer = save_input_line_pointer;
+  if (gotfree_input_line)
     {
-    case 'n':
-      optimize_align_code = 0;
-      break;
+      free (gotfree_input_line);
 
-    case 'q':
-      quiet_warnings = 1;
-      break;
+      if (exp->X_op == O_constant || exp->X_op == O_register)
+       exp->X_op = O_illegal;
+    }
 
-#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
-      /* -Qy, -Qn: SVR4 arguments controlling whether a .comment section
-        should be emitted or not.  FIXME: Not implemented.  */
-    case 'Q':
-      break;
+  ret = i386_finalize_displacement (exp_seg, exp, types, disp_start);
 
-      /* -V: SVR4 argument to print version ID.  */
-    case 'V':
-      print_version_id ();
-      break;
+  RESTORE_END_STRING (disp_end);
 
-      /* -k: Ignore for FreeBSD compatibility.  */
-    case 'k':
-      break;
+  return ret;
+}
 
-    case 's':
-      /* -s: On i386 Solaris, this tells the native assembler to use
-        .stab instead of .stab.excl.  We always use .stab anyhow.  */
-      break;
-#endif
-#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) || defined(TE_PEP)
-    case OPTION_64:
-      {
-       const char **list, **l;
+static int
+i386_finalize_displacement (segT exp_seg ATTRIBUTE_UNUSED, expressionS *exp,
+                           i386_operand_type types, const char *disp_start)
+{
+  i386_operand_type bigdisp;
+  int ret = 1;
 
-       list = bfd_target_list ();
-       for (l = list; *l != NULL; l++)
-         if (CONST_STRNEQ (*l, "elf64-x86-64")
-             || strcmp (*l, "coff-x86-64") == 0
-             || strcmp (*l, "pe-x86-64") == 0
-             || strcmp (*l, "pei-x86-64") == 0)
-           {
-             default_arch = "x86_64";
-             break;
-           }
-       if (*l == NULL)
-         as_fatal (_("No compiled in support for x86_64"));
-       free (list);
-      }
-      break;
-#endif
+  /* We do this to make sure that the section symbol is in
+     the symbol table.  We will ultimately change the relocation
+     to be relative to the beginning of the section.  */
+  if (i.reloc[this_operand] == BFD_RELOC_386_GOTOFF
+      || i.reloc[this_operand] == BFD_RELOC_X86_64_GOTPCREL
+      || i.reloc[this_operand] == BFD_RELOC_X86_64_GOTOFF64)
+    {
+      if (exp->X_op != O_symbol)
+       goto inv_disp;
 
-    case OPTION_32:
-      default_arch = "i386";
-      break;
+      if (S_IS_LOCAL (exp->X_add_symbol)
+         && S_GET_SEGMENT (exp->X_add_symbol) != undefined_section)
+       section_symbol (S_GET_SEGMENT (exp->X_add_symbol));
+      exp->X_op = O_subtract;
+      exp->X_op_symbol = GOT_symbol;
+      if (i.reloc[this_operand] == BFD_RELOC_X86_64_GOTPCREL)
+       i.reloc[this_operand] = BFD_RELOC_32_PCREL;
+      else if (i.reloc[this_operand] == BFD_RELOC_X86_64_GOTOFF64)
+       i.reloc[this_operand] = BFD_RELOC_64;
+      else
+       i.reloc[this_operand] = BFD_RELOC_32;
+    }
 
-    case OPTION_DIVIDE:
-#ifdef SVR4_COMMENT_CHARS
-      {
-       char *n, *t;
-       const char *s;
+  else if (exp->X_op == O_absent
+          || exp->X_op == O_illegal
+          || exp->X_op == O_big)
+    {
+    inv_disp:
+      as_bad (_("missing or invalid displacement expression `%s'"),
+             disp_start);
+      ret = 0;
+    }
 
-       n = (char *) xmalloc (strlen (i386_comment_chars) + 1);
-       t = n;
-       for (s = i386_comment_chars; *s != '\0'; s++)
-         if (*s != '/')
-           *t++ = *s;
-       *t = '\0';
-       i386_comment_chars = n;
-      }
+#if (defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT))
+  else if (exp->X_op != O_constant
+          && OUTPUT_FLAVOR == bfd_target_aout_flavour
+          && exp_seg != absolute_section
+          && exp_seg != text_section
+          && exp_seg != data_section
+          && exp_seg != bss_section
+          && exp_seg != undefined_section
+          && !bfd_is_com_section (exp_seg))
+    {
+      as_bad (_("unimplemented segment %s in operand"), exp_seg->name);
+      ret = 0;
+    }
 #endif
-      break;
-
-    case OPTION_MARCH:
-      if (*arg == '.')
-       as_fatal (_("Invalid -march= option: `%s'"), arg);
-      for (i = 0; i < ARRAY_SIZE (cpu_arch); i++)
-       {
-         if (strcmp (arg, cpu_arch [i].name) == 0)
-           {
-             cpu_arch_isa = cpu_arch[i].type;
-             cpu_arch_isa_flags = cpu_arch[i].flags;
-             if (!cpu_arch_tune_set)
-               {
-                 cpu_arch_tune = cpu_arch_isa;
-                 cpu_arch_tune_flags = cpu_arch_isa_flags;
-               }
-             break;
-           }
-       }
-      if (i >= ARRAY_SIZE (cpu_arch))
-       as_fatal (_("Invalid -march= option: `%s'"), arg);
-      break;
 
-    case OPTION_MTUNE:
-      if (*arg == '.')
-       as_fatal (_("Invalid -mtune= option: `%s'"), arg);
-      for (i = 0; i < ARRAY_SIZE (cpu_arch); i++)
-       {
-         if (strcmp (arg, cpu_arch [i].name) == 0)
-           {
-             cpu_arch_tune_set = 1;
-             cpu_arch_tune = cpu_arch [i].type;
-             cpu_arch_tune_flags = cpu_arch[i].flags;
-             break;
-           }
-       }
-      if (i >= ARRAY_SIZE (cpu_arch))
-       as_fatal (_("Invalid -mtune= option: `%s'"), arg);
-      break;
+  /* Check if this is a displacement only operand.  */
+  bigdisp = i.types[this_operand];
+  bigdisp.bitfield.disp8 = 0;
+  bigdisp.bitfield.disp16 = 0;
+  bigdisp.bitfield.disp32 = 0;
+  bigdisp.bitfield.disp32s = 0;
+  bigdisp.bitfield.disp64 = 0;
+  if (operand_type_all_zero (&bigdisp))
+    i.types[this_operand] = operand_type_and (i.types[this_operand],
+                                             types);
 
-    default:
-      return 0;
-    }
-  return 1;
+  return ret;
 }
 
-void
-md_show_usage (stream)
-     FILE *stream;
+/* Make sure the memory operand we've been dealt is valid.
+   Return 1 on success, 0 on a failure.  */
+
+static int
+i386_index_check (const char *operand_string)
 {
-#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
-  fprintf (stream, _("\
-  -Q                      ignored\n\
-  -V                      print assembler version number\n\
-  -k                      ignored\n"));
-#endif
-  fprintf (stream, _("\
-  -n                      Do not optimize code alignment\n\
-  -q                      quieten some warnings\n"));
-#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
-  fprintf (stream, _("\
-  -s                      ignored\n"));
-#endif
-#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) || defined(TE_PEP)
-  fprintf (stream, _("\
-  --32/--64               generate 32bit/64bit code\n"));
-#endif
-#ifdef SVR4_COMMENT_CHARS
-  fprintf (stream, _("\
-  --divide                do not treat `/' as a comment character\n"));
-#else
-  fprintf (stream, _("\
-  --divide                ignored\n"));
-#endif
-  fprintf (stream, _("\
-  -march=CPU/-mtune=CPU   generate code/optimize for CPU, where CPU is one of:\n\
-                           i386, i486, pentium, pentiumpro, pentium4, nocona,\n\
-                           core, core2, k6, athlon, k8, generic32, generic64\n"));
+  int ok;
+  const char *kind = "base/index";
+#if INFER_ADDR_PREFIX
+  int fudged = 0;
 
-}
+ tryprefix:
+#endif
+  ok = 1;
+  if (current_templates->start->opcode_modifier.isstring
+      && !current_templates->start->opcode_modifier.immext
+      && (current_templates->end[-1].opcode_modifier.isstring
+         || i.mem_operands))
+    {
+      /* Memory operands of string insns are special in that they only allow
+        a single register (rDI, rSI, or rBX) as their memory address.  */
+      unsigned int expected;
 
-#if ((defined (OBJ_MAYBE_COFF) && defined (OBJ_MAYBE_AOUT)) \
-     || defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) || defined (TE_PEP))
+      kind = "string address";
 
-/* Pick the target format to use.  */
+      if (current_templates->start->opcode_modifier.w)
+       {
+         i386_operand_type type = current_templates->end[-1].operand_types[0];
+
+         if (!type.bitfield.baseindex
+             || ((!i.mem_operands != !intel_syntax)
+                 && current_templates->end[-1].operand_types[1]
+                    .bitfield.baseindex))
+           type = current_templates->end[-1].operand_types[1];
+         expected = type.bitfield.esseg ? 7 /* rDI */ : 6 /* rSI */;
+       }
+      else
+       expected = 3 /* rBX */;
+
+      if (!i.base_reg || i.index_reg
+         || operand_type_check (i.types[this_operand], disp))
+       ok = -1;
+      else if (!(flag_code == CODE_64BIT
+                ? i.prefix[ADDR_PREFIX]
+                  ? i.base_reg->reg_type.bitfield.reg32
+                  : i.base_reg->reg_type.bitfield.reg64
+                : (flag_code == CODE_16BIT) ^ !i.prefix[ADDR_PREFIX]
+                  ? i.base_reg->reg_type.bitfield.reg32
+                  : i.base_reg->reg_type.bitfield.reg16))
+       ok = 0;
+      else if (i.base_reg->reg_num != expected)
+       ok = -1;
 
-const char *
-i386_target_format (void)
-{
-  if (!strcmp (default_arch, "x86_64"))
-    {
-      set_code_flag (CODE_64BIT);
-      if (cpu_arch_isa_flags == 0)
-       cpu_arch_isa_flags = Cpu186|Cpu286|Cpu386|Cpu486
-                            |Cpu586|Cpu686|CpuP4|CpuMMX|CpuMMX2
-                            |CpuSSE|CpuSSE2;
-      if (cpu_arch_tune_flags == 0)
-       cpu_arch_tune_flags = Cpu186|Cpu286|Cpu386|Cpu486
-                             |Cpu586|Cpu686|CpuP4|CpuMMX|CpuMMX2
-                             |CpuSSE|CpuSSE2;
+      if (ok < 0)
+       {
+         unsigned int j;
+
+         for (j = 0; j < i386_regtab_size; ++j)
+           if ((flag_code == CODE_64BIT
+                ? i.prefix[ADDR_PREFIX]
+                  ? i386_regtab[j].reg_type.bitfield.reg32
+                  : i386_regtab[j].reg_type.bitfield.reg64
+                : (flag_code == CODE_16BIT) ^ !i.prefix[ADDR_PREFIX]
+                  ? i386_regtab[j].reg_type.bitfield.reg32
+                  : i386_regtab[j].reg_type.bitfield.reg16)
+               && i386_regtab[j].reg_num == expected)
+             break;
+         gas_assert (j < i386_regtab_size);
+         as_warn (_("`%s' is not valid here (expected `%c%s%s%c')"),
+                  operand_string,
+                  intel_syntax ? '[' : '(',
+                  register_prefix,
+                  i386_regtab[j].reg_name,
+                  intel_syntax ? ']' : ')');
+         ok = 1;
+       }
     }
-  else if (!strcmp (default_arch, "i386"))
+  else if (flag_code == CODE_64BIT)
     {
-      set_code_flag (CODE_32BIT);
-      if (cpu_arch_isa_flags == 0)
-       cpu_arch_isa_flags = Cpu186|Cpu286|Cpu386;
-      if (cpu_arch_tune_flags == 0)
-       cpu_arch_tune_flags = Cpu186|Cpu286|Cpu386;
+      if ((i.base_reg
+          && ((i.prefix[ADDR_PREFIX] == 0
+               && !i.base_reg->reg_type.bitfield.reg64)
+              || (i.prefix[ADDR_PREFIX]
+                  && !i.base_reg->reg_type.bitfield.reg32))
+          && (i.index_reg
+              || i.base_reg->reg_num !=
+                 (i.prefix[ADDR_PREFIX] == 0 ? RegRip : RegEip)))
+         || (i.index_reg
+             && (!i.index_reg->reg_type.bitfield.baseindex
+                 || (i.prefix[ADDR_PREFIX] == 0
+                     && i.index_reg->reg_num != RegRiz
+                     && !i.index_reg->reg_type.bitfield.reg64
+                     )
+                 || (i.prefix[ADDR_PREFIX]
+                     && i.index_reg->reg_num != RegEiz
+                     && !i.index_reg->reg_type.bitfield.reg32))))
+       ok = 0;
     }
   else
-    as_fatal (_("Unknown architecture"));
-  switch (OUTPUT_FLAVOR)
     {
-#ifdef TE_PEP
-    case bfd_target_coff_flavour:
-      return flag_code == CODE_64BIT ? COFF_TARGET_FORMAT : "coff-i386";
-      break;
-#endif
-#ifdef OBJ_MAYBE_AOUT
-    case bfd_target_aout_flavour:
-      return AOUT_TARGET_FORMAT;
-#endif
-#ifdef OBJ_MAYBE_COFF
-    case bfd_target_coff_flavour:
-      return "coff-i386";
-#endif
-#if defined (OBJ_MAYBE_ELF) || defined (OBJ_ELF)
-    case bfd_target_elf_flavour:
-      {
-       if (flag_code == CODE_64BIT)
-         {
-           object_64bit = 1;
-           use_rela_relocations = 1;
-         }
-       return flag_code == CODE_64BIT ? ELF_TARGET_FORMAT64 : ELF_TARGET_FORMAT;
-      }
+      if ((flag_code == CODE_16BIT) ^ (i.prefix[ADDR_PREFIX] != 0))
+       {
+         /* 16bit checks.  */
+         if ((i.base_reg
+              && (!i.base_reg->reg_type.bitfield.reg16
+                  || !i.base_reg->reg_type.bitfield.baseindex))
+             || (i.index_reg
+                 && (!i.index_reg->reg_type.bitfield.reg16
+                     || !i.index_reg->reg_type.bitfield.baseindex
+                     || !(i.base_reg
+                          && i.base_reg->reg_num < 6
+                          && i.index_reg->reg_num >= 6
+                          && i.log2_scale_factor == 0))))
+           ok = 0;
+       }
+      else
+       {
+         /* 32bit checks.  */
+         if ((i.base_reg
+              && !i.base_reg->reg_type.bitfield.reg32)
+             || (i.index_reg
+                 && ((!i.index_reg->reg_type.bitfield.reg32
+                      && i.index_reg->reg_num != RegEiz)
+                     || !i.index_reg->reg_type.bitfield.baseindex)))
+           ok = 0;
+       }
+    }
+  if (!ok)
+    {
+#if INFER_ADDR_PREFIX
+      if (!i.mem_operands && !i.prefix[ADDR_PREFIX])
+       {
+         i.prefix[ADDR_PREFIX] = ADDR_PREFIX_OPCODE;
+         i.prefixes += 1;
+         /* Change the size of any displacement too.  At most one of
+            Disp16 or Disp32 is set.
+            FIXME.  There doesn't seem to be any real need for separate
+            Disp16 and Disp32 flags.  The same goes for Imm16 and Imm32.
+            Removing them would probably clean up the code quite a lot.  */
+         if (flag_code != CODE_64BIT
+             && (i.types[this_operand].bitfield.disp16
+                 || i.types[this_operand].bitfield.disp32))
+           i.types[this_operand]
+             = operand_type_xor (i.types[this_operand], disp16_32);
+         fudged = 1;
+         goto tryprefix;
+       }
+      if (fudged)
+       as_bad (_("`%s' is not a valid %s expression"),
+               operand_string,
+               kind);
+      else
 #endif
-    default:
-      abort ();
-      return NULL;
+       as_bad (_("`%s' is not a valid %s-bit %s expression"),
+               operand_string,
+               flag_code_names[i.prefix[ADDR_PREFIX]
+                                        ? flag_code == CODE_32BIT
+                                          ? CODE_16BIT
+                                          : CODE_32BIT
+                                        : flag_code],
+               kind);
     }
+  return ok;
 }
 
-#endif /* OBJ_MAYBE_ more than one  */
+/* Parse OPERAND_STRING into the i386_insn structure I.  Returns zero
+   on error.  */
 
-#if (defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF))
-void
-i386_elf_emit_arch_note (void)
+static int
+i386_att_operand (char *operand_string)
 {
-  if (IS_ELF && cpu_arch_name != NULL)
-    {
-      char *p;
-      asection *seg = now_seg;
-      subsegT subseg = now_subseg;
-      Elf_Internal_Note i_note;
-      Elf_External_Note e_note;
-      asection *note_secp;
-      int len;
+  const reg_entry *r;
+  char *end_op;
+  char *op_string = operand_string;
 
-      /* Create the .note section.  */
-      note_secp = subseg_new (".note", 0);
-      bfd_set_section_flags (stdoutput,
-                            note_secp,
-                            SEC_HAS_CONTENTS | SEC_READONLY);
+  if (is_space_char (*op_string))
+    ++op_string;
 
-      /* Process the arch string.  */
-      len = strlen (cpu_arch_name);
+  /* We check for an absolute prefix (differentiating,
+     for example, 'jmp pc_relative_label' from 'jmp *absolute_label'.  */
+  if (*op_string == ABSOLUTE_PREFIX)
+    {
+      ++op_string;
+      if (is_space_char (*op_string))
+       ++op_string;
+      i.types[this_operand].bitfield.jumpabsolute = 1;
+    }
 
-      i_note.namesz = len + 1;
-      i_note.descsz = 0;
-      i_note.type = NT_ARCH;
-      p = frag_more (sizeof (e_note.namesz));
-      md_number_to_chars (p, (valueT) i_note.namesz, sizeof (e_note.namesz));
-      p = frag_more (sizeof (e_note.descsz));
-      md_number_to_chars (p, (valueT) i_note.descsz, sizeof (e_note.descsz));
-      p = frag_more (sizeof (e_note.type));
-      md_number_to_chars (p, (valueT) i_note.type, sizeof (e_note.type));
-      p = frag_more (len + 1);
-      strcpy (p, cpu_arch_name);
+  /* Check if operand is a register.  */
+  if ((r = parse_register (op_string, &end_op)) != NULL)
+    {
+      i386_operand_type temp;
 
-      frag_align (2, 0, 0);
+      /* Check for a segment override by searching for ':' after a
+        segment register.  */
+      op_string = end_op;
+      if (is_space_char (*op_string))
+       ++op_string;
+      if (*op_string == ':'
+         && (r->reg_type.bitfield.sreg2
+             || r->reg_type.bitfield.sreg3))
+       {
+         switch (r->reg_num)
+           {
+           case 0:
+             i.seg[i.mem_operands] = &es;
+             break;
+           case 1:
+             i.seg[i.mem_operands] = &cs;
+             break;
+           case 2:
+             i.seg[i.mem_operands] = &ss;
+             break;
+           case 3:
+             i.seg[i.mem_operands] = &ds;
+             break;
+           case 4:
+             i.seg[i.mem_operands] = &fs;
+             break;
+           case 5:
+             i.seg[i.mem_operands] = &gs;
+             break;
+           }
 
-      subseg_set (seg, subseg);
+         /* Skip the ':' and whitespace.  */
+         ++op_string;
+         if (is_space_char (*op_string))
+           ++op_string;
+
+         if (!is_digit_char (*op_string)
+             && !is_identifier_char (*op_string)
+             && *op_string != '('
+             && *op_string != ABSOLUTE_PREFIX)
+           {
+             as_bad (_("bad memory operand `%s'"), op_string);
+             return 0;
+           }
+         /* Handle case of %es:*foo.  */
+         if (*op_string == ABSOLUTE_PREFIX)
+           {
+             ++op_string;
+             if (is_space_char (*op_string))
+               ++op_string;
+             i.types[this_operand].bitfield.jumpabsolute = 1;
+           }
+         goto do_memory_reference;
+       }
+      if (*op_string)
+       {
+         as_bad (_("junk `%s' after register"), op_string);
+         return 0;
+       }
+      temp = r->reg_type;
+      temp.bitfield.baseindex = 0;
+      i.types[this_operand] = operand_type_or (i.types[this_operand],
+                                              temp);
+      i.types[this_operand].bitfield.unspecified = 0;
+      i.op[this_operand].regs = r;
+      i.reg_operands++;
     }
-}
-#endif
-\f
-symbolS *
-md_undefined_symbol (name)
-     char *name;
-{
-  if (name[0] == GLOBAL_OFFSET_TABLE_NAME[0]
-      && name[1] == GLOBAL_OFFSET_TABLE_NAME[1]
-      && name[2] == GLOBAL_OFFSET_TABLE_NAME[2]
-      && strcmp (name, GLOBAL_OFFSET_TABLE_NAME) == 0)
+  else if (*op_string == REGISTER_PREFIX)
     {
-      if (!GOT_symbol)
+      as_bad (_("bad register name `%s'"), op_string);
+      return 0;
+    }
+  else if (*op_string == IMMEDIATE_PREFIX)
+    {
+      ++op_string;
+      if (i.types[this_operand].bitfield.jumpabsolute)
        {
-         if (symbol_find (name))
-           as_bad (_("GOT already in symbol table"));
-         GOT_symbol = symbol_new (name, undefined_section,
-                                  (valueT) 0, &zero_address_frag);
-       };
-      return GOT_symbol;
+         as_bad (_("immediate operand illegal with absolute jump"));
+         return 0;
+       }
+      if (!i386_immediate (op_string))
+       return 0;
     }
-  return 0;
-}
+  else if (is_digit_char (*op_string)
+          || is_identifier_char (*op_string)
+          || *op_string == '(')
+    {
+      /* This is a memory reference of some sort.  */
+      char *base_string;
 
-/* Round up a section size to the appropriate boundary.  */
+      /* Start and end of displacement string expression (if found).  */
+      char *displacement_string_start;
+      char *displacement_string_end;
 
-valueT
-md_section_align (segment, size)
-     segT segment ATTRIBUTE_UNUSED;
-     valueT size;
-{
-#if (defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT))
-  if (OUTPUT_FLAVOR == bfd_target_aout_flavour)
-    {
-      /* For a.out, force the section size to be aligned.  If we don't do
-        this, BFD will align it for us, but it will not write out the
-        final bytes of the section.  This may be a bug in BFD, but it is
-        easier to fix it here since that is how the other a.out targets
-        work.  */
-      int align;
+    do_memory_reference:
+      if ((i.mem_operands == 1
+          && !current_templates->start->opcode_modifier.isstring)
+         || i.mem_operands == 2)
+       {
+         as_bad (_("too many memory references for `%s'"),
+                 current_templates->start->name);
+         return 0;
+       }
 
-      align = bfd_get_section_alignment (stdoutput, segment);
-      size = ((size + (1 << align) - 1) & ((valueT) -1 << align));
-    }
-#endif
+      /* Check for base index form.  We detect the base index form by
+        looking for an ')' at the end of the operand, searching
+        for the '(' matching it, and finding a REGISTER_PREFIX or ','
+        after the '('.  */
+      base_string = op_string + strlen (op_string);
 
-  return size;
-}
+      --base_string;
+      if (is_space_char (*base_string))
+       --base_string;
 
-/* On the i386, PC-relative offsets are relative to the start of the
-   next instruction.  That is, the address of the offset, plus its
-   size, since the offset is always the last part of the insn.  */
+      /* If we only have a displacement, set-up for it to be parsed later.  */
+      displacement_string_start = op_string;
+      displacement_string_end = base_string + 1;
 
-long
-md_pcrel_from (fixS *fixP)
-{
-  return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address;
-}
+      if (*base_string == ')')
+       {
+         char *temp_string;
+         unsigned int parens_balanced = 1;
+         /* We've already checked that the number of left & right ()'s are
+            equal, so this loop will not be infinite.  */
+         do
+           {
+             base_string--;
+             if (*base_string == ')')
+               parens_balanced++;
+             if (*base_string == '(')
+               parens_balanced--;
+           }
+         while (parens_balanced);
 
-#ifndef I386COFF
+         temp_string = base_string;
 
-static void
-s_bss (int ignore ATTRIBUTE_UNUSED)
-{
-  int temp;
+         /* Skip past '(' and whitespace.  */
+         ++base_string;
+         if (is_space_char (*base_string))
+           ++base_string;
 
-#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
-  if (IS_ELF)
-    obj_elf_section_change_hook ();
-#endif
-  temp = get_absolute_expression ();
-  subseg_set (bss_section, (subsegT) temp);
-  demand_empty_rest_of_line ();
-}
+         if (*base_string == ','
+             || ((i.base_reg = parse_register (base_string, &end_op))
+                 != NULL))
+           {
+             displacement_string_end = temp_string;
 
-#endif
+             i.types[this_operand].bitfield.baseindex = 1;
 
-void
-i386_validate_fix (fixS *fixp)
-{
-  if (fixp->fx_subsy && fixp->fx_subsy == GOT_symbol)
-    {
-      if (fixp->fx_r_type == BFD_RELOC_32_PCREL)
-       {
-         if (!object_64bit)
-           abort ();
-         fixp->fx_r_type = BFD_RELOC_X86_64_GOTPCREL;
-       }
-      else
-       {
-         if (!object_64bit)
-           fixp->fx_r_type = BFD_RELOC_386_GOTOFF;
-         else
-           fixp->fx_r_type = BFD_RELOC_X86_64_GOTOFF64;
-       }
-      fixp->fx_subsy = 0;
-    }
-}
+             if (i.base_reg)
+               {
+                 base_string = end_op;
+                 if (is_space_char (*base_string))
+                   ++base_string;
+               }
 
-arelent *
-tc_gen_reloc (section, fixp)
-     asection *section ATTRIBUTE_UNUSED;
-     fixS *fixp;
-{
-  arelent *rel;
-  bfd_reloc_code_real_type code;
+             /* There may be an index reg or scale factor here.  */
+             if (*base_string == ',')
+               {
+                 ++base_string;
+                 if (is_space_char (*base_string))
+                   ++base_string;
 
-  switch (fixp->fx_r_type)
-    {
-    case BFD_RELOC_X86_64_PLT32:
-    case BFD_RELOC_X86_64_GOT32:
-    case BFD_RELOC_X86_64_GOTPCREL:
-    case BFD_RELOC_386_PLT32:
-    case BFD_RELOC_386_GOT32:
-    case BFD_RELOC_386_GOTOFF:
-    case BFD_RELOC_386_GOTPC:
-    case BFD_RELOC_386_TLS_GD:
-    case BFD_RELOC_386_TLS_LDM:
-    case BFD_RELOC_386_TLS_LDO_32:
-    case BFD_RELOC_386_TLS_IE_32:
-    case BFD_RELOC_386_TLS_IE:
-    case BFD_RELOC_386_TLS_GOTIE:
-    case BFD_RELOC_386_TLS_LE_32:
-    case BFD_RELOC_386_TLS_LE:
-    case BFD_RELOC_386_TLS_GOTDESC:
-    case BFD_RELOC_386_TLS_DESC_CALL:
-    case BFD_RELOC_X86_64_TLSGD:
-    case BFD_RELOC_X86_64_TLSLD:
-    case BFD_RELOC_X86_64_DTPOFF32:
-    case BFD_RELOC_X86_64_DTPOFF64:
-    case BFD_RELOC_X86_64_GOTTPOFF:
-    case BFD_RELOC_X86_64_TPOFF32:
-    case BFD_RELOC_X86_64_TPOFF64:
-    case BFD_RELOC_X86_64_GOTOFF64:
-    case BFD_RELOC_X86_64_GOTPC32:
-    case BFD_RELOC_X86_64_GOT64:
-    case BFD_RELOC_X86_64_GOTPCREL64:
-    case BFD_RELOC_X86_64_GOTPC64:
-    case BFD_RELOC_X86_64_GOTPLT64:
-    case BFD_RELOC_X86_64_PLTOFF64:
-    case BFD_RELOC_X86_64_GOTPC32_TLSDESC:
-    case BFD_RELOC_X86_64_TLSDESC_CALL:
-    case BFD_RELOC_RVA:
-    case BFD_RELOC_VTABLE_ENTRY:
-    case BFD_RELOC_VTABLE_INHERIT:
-#ifdef TE_PE
-    case BFD_RELOC_32_SECREL:
-#endif
-      code = fixp->fx_r_type;
-      break;
-    case BFD_RELOC_X86_64_32S:
-      if (!fixp->fx_pcrel)
-       {
-         /* Don't turn BFD_RELOC_X86_64_32S into BFD_RELOC_32.  */
-         code = fixp->fx_r_type;
-         break;
-       }
-    default:
-      if (fixp->fx_pcrel)
-       {
-         switch (fixp->fx_size)
-           {
-           default:
-             as_bad_where (fixp->fx_file, fixp->fx_line,
-                           _("can not do %d byte pc-relative relocation"),
-                           fixp->fx_size);
-             code = BFD_RELOC_32_PCREL;
-             break;
-           case 1: code = BFD_RELOC_8_PCREL;  break;
-           case 2: code = BFD_RELOC_16_PCREL; break;
-           case 4: code = BFD_RELOC_32_PCREL; break;
-#ifdef BFD64
-           case 8: code = BFD_RELOC_64_PCREL; break;
-#endif
+                 if ((i.index_reg = parse_register (base_string, &end_op))
+                     != NULL)
+                   {
+                     base_string = end_op;
+                     if (is_space_char (*base_string))
+                       ++base_string;
+                     if (*base_string == ',')
+                       {
+                         ++base_string;
+                         if (is_space_char (*base_string))
+                           ++base_string;
+                       }
+                     else if (*base_string != ')')
+                       {
+                         as_bad (_("expecting `,' or `)' "
+                                   "after index register in `%s'"),
+                                 operand_string);
+                         return 0;
+                       }
+                   }
+                 else if (*base_string == REGISTER_PREFIX)
+                   {
+                     as_bad (_("bad register name `%s'"), base_string);
+                     return 0;
+                   }
+
+                 /* Check for scale factor.  */
+                 if (*base_string != ')')
+                   {
+                     char *end_scale = i386_scale (base_string);
+
+                     if (!end_scale)
+                       return 0;
+
+                     base_string = end_scale;
+                     if (is_space_char (*base_string))
+                       ++base_string;
+                     if (*base_string != ')')
+                       {
+                         as_bad (_("expecting `)' "
+                                   "after scale factor in `%s'"),
+                                 operand_string);
+                         return 0;
+                       }
+                   }
+                 else if (!i.index_reg)
+                   {
+                     as_bad (_("expecting index register or scale factor "
+                               "after `,'; got '%c'"),
+                             *base_string);
+                     return 0;
+                   }
+               }
+             else if (*base_string != ')')
+               {
+                 as_bad (_("expecting `,' or `)' "
+                           "after base register in `%s'"),
+                         operand_string);
+                 return 0;
+               }
            }
-       }
-      else
-       {
-         switch (fixp->fx_size)
+         else if (*base_string == REGISTER_PREFIX)
            {
-           default:
-             as_bad_where (fixp->fx_file, fixp->fx_line,
-                           _("can not do %d byte relocation"),
-                           fixp->fx_size);
-             code = BFD_RELOC_32;
-             break;
-           case 1: code = BFD_RELOC_8;  break;
-           case 2: code = BFD_RELOC_16; break;
-           case 4: code = BFD_RELOC_32; break;
-#ifdef BFD64
-           case 8: code = BFD_RELOC_64; break;
-#endif
+             as_bad (_("bad register name `%s'"), base_string);
+             return 0;
            }
        }
-      break;
-    }
 
-  if ((code == BFD_RELOC_32
-       || code == BFD_RELOC_32_PCREL
-       || code == BFD_RELOC_X86_64_32S)
-      && GOT_symbol
-      && fixp->fx_addsy == GOT_symbol)
-    {
-      if (!object_64bit)
-       code = BFD_RELOC_386_GOTPC;
-      else
-       code = BFD_RELOC_X86_64_GOTPC32;
-    }
-  if ((code == BFD_RELOC_64 || code == BFD_RELOC_64_PCREL)
-      && GOT_symbol
-      && fixp->fx_addsy == GOT_symbol)
-    {
-      code = BFD_RELOC_X86_64_GOTPC64;
-    }
-
-  rel = (arelent *) xmalloc (sizeof (arelent));
-  rel->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
-  *rel->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
-
-  rel->address = fixp->fx_frag->fr_address + fixp->fx_where;
+      /* If there's an expression beginning the operand, parse it,
+        assuming displacement_string_start and
+        displacement_string_end are meaningful.  */
+      if (displacement_string_start != displacement_string_end)
+       {
+         if (!i386_displacement (displacement_string_start,
+                                 displacement_string_end))
+           return 0;
+       }
 
-  if (!use_rela_relocations)
-    {
-      /* HACK: Since i386 ELF uses Rel instead of Rela, encode the
-        vtable entry to be used in the relocation's section offset.  */
-      if (fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
-       rel->address = fixp->fx_offset;
+      /* Special case for (%dx) while doing input/output op.  */
+      if (i.base_reg
+         && operand_type_equal (&i.base_reg->reg_type,
+                                &reg16_inoutportreg)
+         && i.index_reg == 0
+         && i.log2_scale_factor == 0
+         && i.seg[i.mem_operands] == 0
+         && !operand_type_check (i.types[this_operand], disp))
+       {
+         i.types[this_operand] = inoutportreg;
+         return 1;
+       }
 
-      rel->addend = 0;
+      if (i386_index_check (operand_string) == 0)
+       return 0;
+      i.types[this_operand].bitfield.mem = 1;
+      i.mem_operands++;
     }
-  /* Use the rela in 64bit mode.  */
   else
     {
-      if (!fixp->fx_pcrel)
-       rel->addend = fixp->fx_offset;
-      else
-       switch (code)
-         {
-         case BFD_RELOC_X86_64_PLT32:
-         case BFD_RELOC_X86_64_GOT32:
-         case BFD_RELOC_X86_64_GOTPCREL:
-         case BFD_RELOC_X86_64_TLSGD:
-         case BFD_RELOC_X86_64_TLSLD:
-         case BFD_RELOC_X86_64_GOTTPOFF:
-         case BFD_RELOC_X86_64_GOTPC32_TLSDESC:
-         case BFD_RELOC_X86_64_TLSDESC_CALL:
-           rel->addend = fixp->fx_offset - fixp->fx_size;
-           break;
-         default:
-           rel->addend = (section->vma
-                          - fixp->fx_size
-                          + fixp->fx_addnumber
-                          + md_pcrel_from (fixp));
-           break;
-         }
-    }
-
-  rel->howto = bfd_reloc_type_lookup (stdoutput, code);
-  if (rel->howto == NULL)
-    {
-      as_bad_where (fixp->fx_file, fixp->fx_line,
-                   _("cannot represent relocation type %s"),
-                   bfd_get_reloc_code_name (code));
-      /* Set howto to a garbage value so that we can keep going.  */
-      rel->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_32);
-      assert (rel->howto != NULL);
+      /* It's not a memory operand; argh!  */
+      as_bad (_("invalid char %s beginning operand %d `%s'"),
+             output_invalid (*op_string),
+             this_operand + 1,
+             op_string);
+      return 0;
     }
-
-  return rel;
+  return 1;                    /* Normal return.  */
 }
-
 \f
-/* Parse operands using Intel syntax. This implements a recursive descent
-   parser based on the BNF grammar published in Appendix B of the MASM 6.1
-   Programmer's Guide.
+/* md_estimate_size_before_relax()
 
-   FIXME: We do not recognize the full operand grammar defined in the MASM
-         documentation.  In particular, all the structure/union and
-         high-level macro operands are missing.
+   Called just before relax() for rs_machine_dependent frags.  The x86
+   assembler uses these frags to handle variable size jump
+   instructions.
 
-   Uppercase words are terminals, lower case words are non-terminals.
-   Objects surrounded by double brackets '[[' ']]' are optional. Vertical
-   bars '|' denote choices. Most grammar productions are implemented in
-   functions called 'intel_<production>'.
+   Any symbol that is now undefined will not become defined.
+   Return the correct fr_subtype in the frag.
+   Return the initial "guess for variable size of frag" to caller.
+   The guess is actually the growth beyond the fixed part.  Whatever
+   we do to grow the fixed or variable part contributes to our
+   returned value.  */
 
-   Initial production is 'expr'.
+int
+md_estimate_size_before_relax (fragP, segment)
+     fragS *fragP;
+     segT segment;
+{
+  /* We've already got fragP->fr_subtype right;  all we have to do is
+     check for un-relaxable symbols.  On an ELF system, we can't relax
+     an externally visible symbol, because it may be overridden by a
+     shared library.  */
+  if (S_GET_SEGMENT (fragP->fr_symbol) != segment
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+      || (IS_ELF
+         && (S_IS_EXTERNAL (fragP->fr_symbol)
+             || S_IS_WEAK (fragP->fr_symbol)
+             || ((symbol_get_bfdsym (fragP->fr_symbol)->flags
+                  & BSF_GNU_INDIRECT_FUNCTION))))
+#endif
+#if defined (OBJ_COFF) && defined (TE_PE)
+      || (OUTPUT_FLAVOR == bfd_target_coff_flavour
+         && S_IS_WEAK (fragP->fr_symbol))
+#endif
+      )
+    {
+      /* Symbol is undefined in this segment, or we need to keep a
+        reloc so that weak symbols can be overridden.  */
+      int size = (fragP->fr_subtype & CODE16) ? 2 : 4;
+      enum bfd_reloc_code_real reloc_type;
+      unsigned char *opcode;
+      int old_fr_fix;
 
-    addOp              + | -
+      if (fragP->fr_var != NO_RELOC)
+       reloc_type = (enum bfd_reloc_code_real) fragP->fr_var;
+      else if (size == 2)
+       reloc_type = BFD_RELOC_16_PCREL;
+      else
+       reloc_type = BFD_RELOC_32_PCREL;
 
-    alpha              [a-zA-Z]
+      old_fr_fix = fragP->fr_fix;
+      opcode = (unsigned char *) fragP->fr_opcode;
 
-    binOp              & | AND | \| | OR | ^ | XOR
+      switch (TYPE_FROM_RELAX_STATE (fragP->fr_subtype))
+       {
+       case UNCOND_JUMP:
+         /* Make jmp (0xeb) a (d)word displacement jump.  */
+         opcode[0] = 0xe9;
+         fragP->fr_fix += size;
+         fix_new (fragP, old_fr_fix, size,
+                  fragP->fr_symbol,
+                  fragP->fr_offset, 1,
+                  reloc_type);
+         break;
 
-    byteRegister       AL | AH | BL | BH | CL | CH | DL | DH
+       case COND_JUMP86:
+         if (size == 2
+             && (!no_cond_jump_promotion || fragP->fr_var != NO_RELOC))
+           {
+             /* Negate the condition, and branch past an
+                unconditional jump.  */
+             opcode[0] ^= 1;
+             opcode[1] = 3;
+             /* Insert an unconditional jump.  */
+             opcode[2] = 0xe9;
+             /* We added two extra opcode bytes, and have a two byte
+                offset.  */
+             fragP->fr_fix += 2 + 2;
+             fix_new (fragP, old_fr_fix + 2, 2,
+                      fragP->fr_symbol,
+                      fragP->fr_offset, 1,
+                      reloc_type);
+             break;
+           }
+         /* Fall through.  */
 
-    constant           digits [[ radixOverride ]]
+       case COND_JUMP:
+         if (no_cond_jump_promotion && fragP->fr_var == NO_RELOC)
+           {
+             fixS *fixP;
 
-    dataType           BYTE | WORD | DWORD | FWORD | QWORD | TBYTE | OWORD | XMMWORD
+             fragP->fr_fix += 1;
+             fixP = fix_new (fragP, old_fr_fix, 1,
+                             fragP->fr_symbol,
+                             fragP->fr_offset, 1,
+                             BFD_RELOC_8_PCREL);
+             fixP->fx_signed = 1;
+             break;
+           }
 
-    digits             decdigit
-                       | digits decdigit
-                       | digits hexdigit
+         /* This changes the byte-displacement jump 0x7N
+            to the (d)word-displacement jump 0x0f,0x8N.  */
+         opcode[1] = opcode[0] + 0x10;
+         opcode[0] = TWO_BYTE_OPCODE_ESCAPE;
+         /* We've added an opcode byte.  */
+         fragP->fr_fix += 1 + size;
+         fix_new (fragP, old_fr_fix + 1, size,
+                  fragP->fr_symbol,
+                  fragP->fr_offset, 1,
+                  reloc_type);
+         break;
 
-    decdigit           [0-9]
+       default:
+         BAD_CASE (fragP->fr_subtype);
+         break;
+       }
+      frag_wane (fragP);
+      return fragP->fr_fix - old_fr_fix;
+    }
 
-    e04                        e04 addOp e05
-                       | e05
+  /* Guess size depending on current relax state.  Initially the relax
+     state will correspond to a short jump and we return 1, because
+     the variable part of the frag (the branch offset) is one byte
+     long.  However, we can relax a section more than once and in that
+     case we must either set fr_subtype back to the unrelaxed state,
+     or return the value for the appropriate branch.  */
+  return md_relax_table[fragP->fr_subtype].rlx_length;
+}
 
-    e05                        e05 binOp e06
-                       | e06
+/* Called after relax() is finished.
 
-    e06                        e06 mulOp e09
-                       | e09
+   In: Address of frag.
+       fr_type == rs_machine_dependent.
+       fr_subtype is what the address relaxed to.
 
-    e09                        OFFSET e10
-                       | SHORT e10
-                       | + e10
-                       | - e10
-                       | ~ e10
-                       | NOT e10
-                       | e09 PTR e10
-                       | e09 : e10
-                       | e10
+   Out:        Any fixSs and constants are set up.
+       Caller will turn frag into a ".space 0".  */
 
-    e10                        e10 [ expr ]
-                       | e11
+void
+md_convert_frag (abfd, sec, fragP)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     segT sec ATTRIBUTE_UNUSED;
+     fragS *fragP;
+{
+  unsigned char *opcode;
+  unsigned char *where_to_put_displacement = NULL;
+  offsetT target_address;
+  offsetT opcode_address;
+  unsigned int extension = 0;
+  offsetT displacement_from_opcode_start;
 
-    e11                        ( expr )
-                       | [ expr ]
-                       | constant
-                       | dataType
-                       | id
-                       | $
-                       | register
+  opcode = (unsigned char *) fragP->fr_opcode;
 
- => expr               expr cmpOp e04
-                       | e04
+  /* Address we want to reach in file space.  */
+  target_address = S_GET_VALUE (fragP->fr_symbol) + fragP->fr_offset;
 
-    gpRegister         AX | EAX | BX | EBX | CX | ECX | DX | EDX
-                       | BP | EBP | SP | ESP | DI | EDI | SI | ESI
+  /* Address opcode resides at in file space.  */
+  opcode_address = fragP->fr_address + fragP->fr_fix;
 
-    hexdigit           a | b | c | d | e | f
-                       | A | B | C | D | E | F
+  /* Displacement from opcode start to fill into instruction.  */
+  displacement_from_opcode_start = target_address - opcode_address;
 
-    id                 alpha
-                       | id alpha
-                       | id decdigit
+  if ((fragP->fr_subtype & BIG) == 0)
+    {
+      /* Don't have to change opcode.  */
+      extension = 1;           /* 1 opcode + 1 displacement  */
+      where_to_put_displacement = &opcode[1];
+    }
+  else
+    {
+      if (no_cond_jump_promotion
+         && TYPE_FROM_RELAX_STATE (fragP->fr_subtype) != UNCOND_JUMP)
+       as_warn_where (fragP->fr_file, fragP->fr_line,
+                      _("long jump required"));
 
-    mulOp              * | / | % | MOD | << | SHL | >> | SHR
+      switch (fragP->fr_subtype)
+       {
+       case ENCODE_RELAX_STATE (UNCOND_JUMP, BIG):
+         extension = 4;                /* 1 opcode + 4 displacement  */
+         opcode[0] = 0xe9;
+         where_to_put_displacement = &opcode[1];
+         break;
 
-    quote              " | '
+       case ENCODE_RELAX_STATE (UNCOND_JUMP, BIG16):
+         extension = 2;                /* 1 opcode + 2 displacement  */
+         opcode[0] = 0xe9;
+         where_to_put_displacement = &opcode[1];
+         break;
 
-    register           specialRegister
-                       | gpRegister
-                       | byteRegister
+       case ENCODE_RELAX_STATE (COND_JUMP, BIG):
+       case ENCODE_RELAX_STATE (COND_JUMP86, BIG):
+         extension = 5;                /* 2 opcode + 4 displacement  */
+         opcode[1] = opcode[0] + 0x10;
+         opcode[0] = TWO_BYTE_OPCODE_ESCAPE;
+         where_to_put_displacement = &opcode[2];
+         break;
 
-    segmentRegister    CS | DS | ES | FS | GS | SS
+       case ENCODE_RELAX_STATE (COND_JUMP, BIG16):
+         extension = 3;                /* 2 opcode + 2 displacement  */
+         opcode[1] = opcode[0] + 0x10;
+         opcode[0] = TWO_BYTE_OPCODE_ESCAPE;
+         where_to_put_displacement = &opcode[2];
+         break;
 
-    specialRegister    CR0 | CR2 | CR3 | CR4
-                       | DR0 | DR1 | DR2 | DR3 | DR6 | DR7
-                       | TR3 | TR4 | TR5 | TR6 | TR7
+       case ENCODE_RELAX_STATE (COND_JUMP86, BIG16):
+         extension = 4;
+         opcode[0] ^= 1;
+         opcode[1] = 3;
+         opcode[2] = 0xe9;
+         where_to_put_displacement = &opcode[3];
+         break;
 
-    We simplify the grammar in obvious places (e.g., register parsing is
-    done by calling parse_register) and eliminate immediate left recursion
-    to implement a recursive-descent parser.
+       default:
+         BAD_CASE (fragP->fr_subtype);
+         break;
+       }
+    }
 
-    expr       e04 expr'
+  /* If size if less then four we are sure that the operand fits,
+     but if it's 4, then it could be that the displacement is larger
+     then -/+ 2GB.  */
+  if (DISP_SIZE_FROM_RELAX_STATE (fragP->fr_subtype) == 4
+      && object_64bit
+      && ((addressT) (displacement_from_opcode_start - extension
+                     + ((addressT) 1 << 31))
+         > (((addressT) 2 << 31) - 1)))
+    {
+      as_bad_where (fragP->fr_file, fragP->fr_line,
+                   _("jump target out of range"));
+      /* Make us emit 0.  */
+      displacement_from_opcode_start = extension;
+    }
+  /* Now put displacement after opcode.  */
+  md_number_to_chars ((char *) where_to_put_displacement,
+                     (valueT) (displacement_from_opcode_start - extension),
+                     DISP_SIZE_FROM_RELAX_STATE (fragP->fr_subtype));
+  fragP->fr_fix += extension;
+}
+\f
+/* Apply a fixup (fixS) to segment data, once it has been determined
+   by our caller that we have all the info we need to fix it up.
 
-    expr'      cmpOp e04 expr'
-               | Empty
+   On the 386, immediates, displacements, and data pointers are all in
+   the same (little-endian) format, so we don't need to care about which
+   we are handling.  */
 
-    e04                e05 e04'
+void
+md_apply_fix (fixP, valP, seg)
+     /* The fix we're to put in.  */
+     fixS *fixP;
+     /* Pointer to the value of the bits.  */
+     valueT *valP;
+     /* Segment fix is from.  */
+     segT seg ATTRIBUTE_UNUSED;
+{
+  char *p = fixP->fx_where + fixP->fx_frag->fr_literal;
+  valueT value = *valP;
 
-    e04'       addOp e05 e04'
-               | Empty
+#if !defined (TE_Mach)
+  if (fixP->fx_pcrel)
+    {
+      switch (fixP->fx_r_type)
+       {
+       default:
+         break;
 
-    e05                e06 e05'
+       case BFD_RELOC_64:
+         fixP->fx_r_type = BFD_RELOC_64_PCREL;
+         break;
+       case BFD_RELOC_32:
+       case BFD_RELOC_X86_64_32S:
+         fixP->fx_r_type = BFD_RELOC_32_PCREL;
+         break;
+       case BFD_RELOC_16:
+         fixP->fx_r_type = BFD_RELOC_16_PCREL;
+         break;
+       case BFD_RELOC_8:
+         fixP->fx_r_type = BFD_RELOC_8_PCREL;
+         break;
+       }
+    }
 
-    e05'       binOp e06 e05'
-               | Empty
+  if (fixP->fx_addsy != NULL
+      && (fixP->fx_r_type == BFD_RELOC_32_PCREL
+         || fixP->fx_r_type == BFD_RELOC_64_PCREL
+         || fixP->fx_r_type == BFD_RELOC_16_PCREL
+         || fixP->fx_r_type == BFD_RELOC_8_PCREL)
+      && !use_rela_relocations)
+    {
+      /* This is a hack.  There should be a better way to handle this.
+        This covers for the fact that bfd_install_relocation will
+        subtract the current location (for partial_inplace, PC relative
+        relocations); see more below.  */
+#ifndef OBJ_AOUT
+      if (IS_ELF
+#ifdef TE_PE
+         || OUTPUT_FLAVOR == bfd_target_coff_flavour
+#endif
+         )
+       value += fixP->fx_where + fixP->fx_frag->fr_address;
+#endif
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+      if (IS_ELF)
+       {
+         segT sym_seg = S_GET_SEGMENT (fixP->fx_addsy);
 
-    e06                e09 e06'
+         if ((sym_seg == seg
+              || (symbol_section_p (fixP->fx_addsy)
+                  && sym_seg != absolute_section))
+             && !generic_force_reloc (fixP))
+           {
+             /* Yes, we add the values in twice.  This is because
+                bfd_install_relocation subtracts them out again.  I think
+                bfd_install_relocation is broken, but I don't dare change
+                it.  FIXME.  */
+             value += fixP->fx_where + fixP->fx_frag->fr_address;
+           }
+       }
+#endif
+#if defined (OBJ_COFF) && defined (TE_PE)
+      /* For some reason, the PE format does not store a
+        section address offset for a PC relative symbol.  */
+      if (S_GET_SEGMENT (fixP->fx_addsy) != seg
+         || S_IS_WEAK (fixP->fx_addsy))
+       value += md_pcrel_from (fixP);
+#endif
+    }
+#if defined (OBJ_COFF) && defined (TE_PE)
+  if (fixP->fx_addsy != NULL && S_IS_WEAK (fixP->fx_addsy))
+    {
+      value -= S_GET_VALUE (fixP->fx_addsy);
+    }
+#endif
 
-    e06'       mulOp e09 e06'
-               | Empty
+  /* Fix a few things - the dynamic linker expects certain values here,
+     and we must not disappoint it.  */
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+  if (IS_ELF && fixP->fx_addsy)
+    switch (fixP->fx_r_type)
+      {
+      case BFD_RELOC_386_PLT32:
+      case BFD_RELOC_X86_64_PLT32:
+       /* Make the jump instruction point to the address of the operand.  At
+          runtime we merely add the offset to the actual PLT entry.  */
+       value = -4;
+       break;
 
-    e09                OFFSET e10 e09'
-               | SHORT e10'
-               | + e10'
-               | - e10'
-               | ~ e10'
-               | NOT e10'
-               | e10 e09'
+      case BFD_RELOC_386_TLS_GD:
+      case BFD_RELOC_386_TLS_LDM:
+      case BFD_RELOC_386_TLS_IE_32:
+      case BFD_RELOC_386_TLS_IE:
+      case BFD_RELOC_386_TLS_GOTIE:
+      case BFD_RELOC_386_TLS_GOTDESC:
+      case BFD_RELOC_X86_64_TLSGD:
+      case BFD_RELOC_X86_64_TLSLD:
+      case BFD_RELOC_X86_64_GOTTPOFF:
+      case BFD_RELOC_X86_64_GOTPC32_TLSDESC:
+       value = 0; /* Fully resolved at runtime.  No addend.  */
+       /* Fallthrough */
+      case BFD_RELOC_386_TLS_LE:
+      case BFD_RELOC_386_TLS_LDO_32:
+      case BFD_RELOC_386_TLS_LE_32:
+      case BFD_RELOC_X86_64_DTPOFF32:
+      case BFD_RELOC_X86_64_DTPOFF64:
+      case BFD_RELOC_X86_64_TPOFF32:
+      case BFD_RELOC_X86_64_TPOFF64:
+       S_SET_THREAD_LOCAL (fixP->fx_addsy);
+       break;
 
-    e09'       PTR e10 e09'
-               | : e10 e09'
-               | Empty
+      case BFD_RELOC_386_TLS_DESC_CALL:
+      case BFD_RELOC_X86_64_TLSDESC_CALL:
+       value = 0; /* Fully resolved at runtime.  No addend.  */
+       S_SET_THREAD_LOCAL (fixP->fx_addsy);
+       fixP->fx_done = 0;
+       return;
 
-    e10                e11 e10'
+      case BFD_RELOC_386_GOT32:
+      case BFD_RELOC_X86_64_GOT32:
+       value = 0; /* Fully resolved at runtime.  No addend.  */
+       break;
 
-    e10'       [ expr ] e10'
-               | Empty
+      case BFD_RELOC_VTABLE_INHERIT:
+      case BFD_RELOC_VTABLE_ENTRY:
+       fixP->fx_done = 0;
+       return;
 
-    e11                ( expr )
-               | [ expr ]
-               | BYTE
-               | WORD
-               | DWORD
-               | FWORD
-               | QWORD
-               | TBYTE
-               | OWORD
-               | XMMWORD
-               | .
-               | $
-               | register
-               | id
-               | constant  */
+      default:
+       break;
+      }
+#endif /* defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)  */
+  *valP = value;
+#endif /* !defined (TE_Mach)  */
 
-/* Parsing structure for the intel syntax parser. Used to implement the
-   semantic actions for the operand grammar.  */
-struct intel_parser_s
-  {
-    char *op_string;           /* The string being parsed.  */
-    int got_a_float;           /* Whether the operand is a float.  */
-    int op_modifier;           /* Operand modifier.  */
-    int is_mem;                        /* 1 if operand is memory reference.  */
-    int in_offset;             /* >=1 if parsing operand of offset.  */
-    int in_bracket;            /* >=1 if parsing operand in brackets.  */
-    const reg_entry *reg;      /* Last register reference found.  */
-    char *disp;                        /* Displacement string being built.  */
-    char *next_operand;                /* Resume point when splitting operands.  */
-  };
+  /* Are we finished with this relocation now?  */
+  if (fixP->fx_addsy == NULL)
+    fixP->fx_done = 1;
+#if defined (OBJ_COFF) && defined (TE_PE)
+  else if (fixP->fx_addsy != NULL && S_IS_WEAK (fixP->fx_addsy))
+    {
+      fixP->fx_done = 0;
+      /* Remember value for tc_gen_reloc.  */
+      fixP->fx_addnumber = value;
+      /* Clear out the frag for now.  */
+      value = 0;
+    }
+#endif
+  else if (use_rela_relocations)
+    {
+      fixP->fx_no_overflow = 1;
+      /* Remember value for tc_gen_reloc.  */
+      fixP->fx_addnumber = value;
+      value = 0;
+    }
 
-static struct intel_parser_s intel_parser;
+  md_number_to_chars (p, value, fixP->fx_size);
+}
+\f
+char *
+md_atof (int type, char *litP, int *sizeP)
+{
+  /* This outputs the LITTLENUMs in REVERSE order;
+     in accord with the bigendian 386.  */
+  return ieee_md_atof (type, litP, sizeP, FALSE);
+}
+\f
+static char output_invalid_buf[sizeof (unsigned char) * 2 + 6];
 
-/* Token structure for parsing intel syntax.  */
-struct intel_token
-  {
-    int code;                  /* Token code.  */
-    const reg_entry *reg;      /* Register entry for register tokens.  */
-    char *str;                 /* String representation.  */
-  };
+static char *
+output_invalid (int c)
+{
+  if (ISPRINT (c))
+    snprintf (output_invalid_buf, sizeof (output_invalid_buf),
+             "'%c'", c);
+  else
+    snprintf (output_invalid_buf, sizeof (output_invalid_buf),
+             "(0x%x)", (unsigned char) c);
+  return output_invalid_buf;
+}
 
-static struct intel_token cur_token, prev_token;
-
-/* Token codes for the intel parser. Since T_SHORT is already used
-   by COFF, undefine it first to prevent a warning.  */
-#define T_NIL          -1
-#define T_CONST                1
-#define T_REG          2
-#define T_BYTE         3
-#define T_WORD         4
-#define T_DWORD                5
-#define T_FWORD                6
-#define T_QWORD                7
-#define T_TBYTE                8
-#define T_XMMWORD      9
-#undef  T_SHORT
-#define T_SHORT                10
-#define T_OFFSET       11
-#define T_PTR          12
-#define T_ID           13
-#define T_SHL          14
-#define T_SHR          15
-
-/* Prototypes for intel parser functions.  */
-static int intel_match_token (int);
-static void intel_putback_token        (void);
-static void intel_get_token (void);
-static int intel_expr (void);
-static int intel_e04 (void);
-static int intel_e05 (void);
-static int intel_e06 (void);
-static int intel_e09 (void);
-static int intel_e10 (void);
-static int intel_e11 (void);
+/* REG_STRING starts *before* REGISTER_PREFIX.  */
 
-static int
-i386_intel_operand (char *operand_string, int got_a_float)
+static const reg_entry *
+parse_real_register (char *reg_string, char **end_op)
 {
-  int ret;
+  char *s = reg_string;
   char *p;
+  char reg_name_given[MAX_REG_NAME_SIZE + 1];
+  const reg_entry *r;
+
+  /* Skip possible REGISTER_PREFIX and possible whitespace.  */
+  if (*s == REGISTER_PREFIX)
+    ++s;
 
-  p = intel_parser.op_string = xstrdup (operand_string);
-  intel_parser.disp = (char *) xmalloc (strlen (operand_string) + 1);
+  if (is_space_char (*s))
+    ++s;
 
-  for (;;)
+  p = reg_name_given;
+  while ((*p++ = register_chars[(unsigned char) *s]) != '\0')
     {
-      /* Initialize token holders.  */
-      cur_token.code = prev_token.code = T_NIL;
-      cur_token.reg = prev_token.reg = NULL;
-      cur_token.str = prev_token.str = NULL;
+      if (p >= reg_name_given + MAX_REG_NAME_SIZE)
+       return (const reg_entry *) NULL;
+      s++;
+    }
 
-      /* Initialize parser structure.  */
-      intel_parser.got_a_float = got_a_float;
-      intel_parser.op_modifier = 0;
-      intel_parser.is_mem = 0;
-      intel_parser.in_offset = 0;
-      intel_parser.in_bracket = 0;
-      intel_parser.reg = NULL;
-      intel_parser.disp[0] = '\0';
-      intel_parser.next_operand = NULL;
+  /* 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])
+    return (const reg_entry *) NULL;
 
-      /* Read the first token and start the parser.  */
-      intel_get_token ();
-      ret = intel_expr ();
+  *end_op = s;
 
-      if (!ret)
-       break;
+  r = (const reg_entry *) hash_find (reg_hash, reg_name_given);
 
-      if (cur_token.code != T_NIL)
-       {
-         as_bad (_("invalid operand for '%s' ('%s' unexpected)"),
-                 current_templates->start->name, cur_token.str);
-         ret = 0;
-       }
-      /* If we found a memory reference, hand it over to i386_displacement
-        to fill in the rest of the operand fields.  */
-      else if (intel_parser.is_mem)
+  /* Handle floating point regs, allowing spaces in the (i) part.  */
+  if (r == i386_regtab /* %st is first entry of table  */)
+    {
+      if (is_space_char (*s))
+       ++s;
+      if (*s == '(')
        {
-         if ((i.mem_operands == 1
-              && (current_templates->start->opcode_modifier & IsString) == 0)
-             || i.mem_operands == 2)
-           {
-             as_bad (_("too many memory references for '%s'"),
-                     current_templates->start->name);
-             ret = 0;
-           }
-         else
+         ++s;
+         if (is_space_char (*s))
+           ++s;
+         if (*s >= '0' && *s <= '7')
            {
-             char *s = intel_parser.disp;
-             i.mem_operands++;
-
-             if (!quiet_warnings && intel_parser.is_mem < 0)
-               /* See the comments in intel_bracket_expr.  */
-               as_warn (_("Treating `%s' as memory reference"), operand_string);
-
-             /* Add the displacement expression.  */
-             if (*s != '\0')
-               ret = i386_displacement (s, s + strlen (s));
-             if (ret)
+             int fpr = *s - '0';
+             ++s;
+             if (is_space_char (*s))
+               ++s;
+             if (*s == ')')
                {
-                 /* Swap base and index in 16-bit memory operands like
-                    [si+bx]. Since i386_index_check is also used in AT&T
-                    mode we have to do that here.  */
-                 if (i.base_reg
-                     && i.index_reg
-                     && (i.base_reg->reg_type & Reg16)
-                     && (i.index_reg->reg_type & Reg16)
-                     && i.base_reg->reg_num >= 6
-                     && i.index_reg->reg_num < 6)
-                   {
-                     const reg_entry *base = i.index_reg;
-
-                     i.index_reg = i.base_reg;
-                     i.base_reg = base;
-                   }
-                 ret = i386_index_check (operand_string);
+                 *end_op = s + 1;
+                 r = (const reg_entry *) hash_find (reg_hash, "st(0)");
+                 know (r);
+                 return r + fpr;
                }
            }
+         /* We have "%st(" then garbage.  */
+         return (const reg_entry *) NULL;
        }
-
-      /* Constant and OFFSET expressions are handled by i386_immediate.  */
-      else if ((intel_parser.op_modifier & (1 << T_OFFSET))
-              || intel_parser.reg == NULL)
-       ret = i386_immediate (intel_parser.disp);
-
-      if (intel_parser.next_operand && this_operand >= MAX_OPERANDS - 1)
-       ret = 0;
-      if (!ret || !intel_parser.next_operand)
-       break;
-      intel_parser.op_string = intel_parser.next_operand;
-      this_operand = i.operands++;
     }
 
-  free (p);
-  free (intel_parser.disp);
-
-  return ret;
-}
-
-#define NUM_ADDRESS_REGS (!!i.base_reg + !!i.index_reg)
-
-/* expr        e04 expr'
-
-   expr'  cmpOp e04 expr'
-       | Empty  */
-static int
-intel_expr (void)
-{
-  /* XXX Implement the comparison operators.  */
-  return intel_e04 ();
-}
-
-/* e04 e05 e04'
-
-   e04'        addOp e05 e04'
-       | Empty  */
-static int
-intel_e04 (void)
-{
-  int nregs = -1;
-
-  for (;;)
-    {
-      if (!intel_e05())
-       return 0;
+  if (r == NULL || allow_pseudo_reg)
+    return r;
 
-      if (nregs >= 0 && NUM_ADDRESS_REGS > nregs)
-       i.base_reg = i386_regtab + REGNAM_AL; /* al is invalid as base */
+  if (operand_type_all_zero (&r->reg_type))
+    return (const reg_entry *) NULL;
 
-      if (cur_token.code == '+')
-       nregs = -1;
-      else if (cur_token.code == '-')
-       nregs = NUM_ADDRESS_REGS;
-      else
-       return 1;
+  if ((r->reg_type.bitfield.reg32
+       || r->reg_type.bitfield.sreg3
+       || r->reg_type.bitfield.control
+       || r->reg_type.bitfield.debug
+       || r->reg_type.bitfield.test)
+      && !cpu_arch_flags.bitfield.cpui386)
+    return (const reg_entry *) NULL;
 
-      strcat (intel_parser.disp, cur_token.str);
-      intel_match_token (cur_token.code);
-    }
-}
+  if (r->reg_type.bitfield.floatreg
+      && !cpu_arch_flags.bitfield.cpu8087
+      && !cpu_arch_flags.bitfield.cpu287
+      && !cpu_arch_flags.bitfield.cpu387)
+    return (const reg_entry *) NULL;
 
-/* e05 e06 e05'
+  if (r->reg_type.bitfield.regmmx && !cpu_arch_flags.bitfield.cpummx)
+    return (const reg_entry *) NULL;
 
-   e05'        binOp e06 e05'
-       | Empty  */
-static int
-intel_e05 (void)
-{
-  int nregs = ~NUM_ADDRESS_REGS;
+  if (r->reg_type.bitfield.regxmm && !cpu_arch_flags.bitfield.cpusse)
+    return (const reg_entry *) NULL;
 
-  for (;;)
-    {
-      if (!intel_e06())
-       return 0;
+  if (r->reg_type.bitfield.regymm && !cpu_arch_flags.bitfield.cpuavx)
+    return (const reg_entry *) NULL;
 
-      if (cur_token.code == '&'
-         || cur_token.code == '|'
-         || cur_token.code == '^')
-       {
-         char str[2];
+  /* Don't allow fake index register unless allow_index_reg isn't 0. */
+  if (!allow_index_reg
+      && (r->reg_num == RegEiz || r->reg_num == RegRiz))
+    return (const reg_entry *) NULL;
 
-         str[0] = cur_token.code;
-         str[1] = 0;
-         strcat (intel_parser.disp, str);
-       }
-      else
-       break;
+  if (((r->reg_flags & (RegRex64 | RegRex))
+       || r->reg_type.bitfield.reg64)
+      && (!cpu_arch_flags.bitfield.cpulm
+         || !operand_type_equal (&r->reg_type, &control))
+      && flag_code != CODE_64BIT)
+    return (const reg_entry *) NULL;
 
-      intel_match_token (cur_token.code);
+  if (r->reg_type.bitfield.sreg3 && r->reg_num == RegFlat && !intel_syntax)
+    return (const reg_entry *) NULL;
 
-      if (nregs < 0)
-       nregs = ~nregs;
-    }
-  if (nregs >= 0 && NUM_ADDRESS_REGS > nregs)
-    i.base_reg = i386_regtab + REGNAM_AL + 1; /* cl is invalid as base */
-  return 1;
+  return r;
 }
 
-/* e06 e09 e06'
+/* REG_STRING starts *before* REGISTER_PREFIX.  */
 
-   e06'        mulOp e09 e06'
-       | Empty  */
-static int
-intel_e06 (void)
+static const reg_entry *
+parse_register (char *reg_string, char **end_op)
 {
-  int nregs = ~NUM_ADDRESS_REGS;
+  const reg_entry *r;
 
-  for (;;)
+  if (*reg_string == REGISTER_PREFIX || allow_naked_reg)
+    r = parse_real_register (reg_string, end_op);
+  else
+    r = NULL;
+  if (!r)
     {
-      if (!intel_e09())
-       return 0;
+      char *save = input_line_pointer;
+      char c;
+      symbolS *symbolP;
 
-      if (cur_token.code == '*'
-         || cur_token.code == '/'
-         || cur_token.code == '%')
+      input_line_pointer = reg_string;
+      c = get_symbol_end ();
+      symbolP = symbol_find (reg_string);
+      if (symbolP && S_GET_SEGMENT (symbolP) == reg_section)
        {
-         char str[2];
+         const expressionS *e = symbol_get_value_expression (symbolP);
 
-         str[0] = cur_token.code;
-         str[1] = 0;
-         strcat (intel_parser.disp, str);
+         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;
+         *end_op = input_line_pointer;
        }
-      else if (cur_token.code == T_SHL)
-       strcat (intel_parser.disp, "<<");
-      else if (cur_token.code == T_SHR)
-       strcat (intel_parser.disp, ">>");
-      else
-       break;
+      *input_line_pointer = c;
+      input_line_pointer = save;
+    }
+  return r;
+}
 
-      intel_match_token (cur_token.code);
+int
+i386_parse_name (char *name, expressionS *e, char *nextcharP)
+{
+  const reg_entry *r;
+  char *end = input_line_pointer;
 
-      if (nregs < 0)
-       nregs = ~nregs;
+  *end = *nextcharP;
+  r = parse_register (name, &input_line_pointer);
+  if (r && end <= input_line_pointer)
+    {
+      *nextcharP = *input_line_pointer;
+      *input_line_pointer = 0;
+      e->X_op = O_register;
+      e->X_add_number = r - i386_regtab;
+      return 1;
     }
-  if (nregs >= 0 && NUM_ADDRESS_REGS > nregs)
-    i.base_reg = i386_regtab + REGNAM_AL + 2; /* dl is invalid as base */
-  return 1;
+  input_line_pointer = end;
+  *end = 0;
+  return intel_syntax ? i386_intel_parse_name (name, e) : 0;
 }
 
-/* e09 OFFSET e09
-       | SHORT e09
-       | + e09
-       | - e09
-       | ~ e09
-       | NOT e09
-       | e10 e09'
-
-   e09'        PTR e10 e09'
-       | : e10 e09'
-       | Empty */
-static int
-intel_e09 (void)
+void
+md_operand (expressionS *e)
 {
-  int nregs = ~NUM_ADDRESS_REGS;
-  int in_offset = 0;
+  char *end;
+  const reg_entry *r;
 
-  for (;;)
+  switch (*input_line_pointer)
     {
-      /* Don't consume constants here.  */
-      if (cur_token.code == '+' || cur_token.code == '-')
+    case REGISTER_PREFIX:
+      r = parse_real_register (input_line_pointer, &end);
+      if (r)
        {
-         /* Need to look one token ahead - if the next token
-            is a constant, the current token is its sign.  */
-         int next_code;
-
-         intel_match_token (cur_token.code);
-         next_code = cur_token.code;
-         intel_putback_token ();
-         if (next_code == T_CONST)
-           break;
+         e->X_op = O_register;
+         e->X_add_number = r - i386_regtab;
+         input_line_pointer = end;
        }
+      break;
 
-      /* e09  OFFSET e09  */
-      if (cur_token.code == T_OFFSET)
+    case '[':
+      gas_assert (intel_syntax);
+      end = input_line_pointer++;
+      expression (e);
+      if (*input_line_pointer == ']')
        {
-         if (!in_offset++)
-           ++intel_parser.in_offset;
+         ++input_line_pointer;
+         e->X_op_symbol = make_expr_symbol (e);
+         e->X_add_symbol = NULL;
+         e->X_add_number = 0;
+         e->X_op = O_index;
        }
+      else
+       {
+         e->X_op = O_absent;
+         input_line_pointer = end;
+       }
+      break;
+    }
+}
 
-      /* e09  SHORT e09  */
-      else if (cur_token.code == T_SHORT)
-       intel_parser.op_modifier |= 1 << T_SHORT;
+\f
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+const char *md_shortopts = "kVQ:sqn";
+#else
+const char *md_shortopts = "qn";
+#endif
 
-      /* e09  + e09  */
-      else if (cur_token.code == '+')
-       strcat (intel_parser.disp, "+");
+#define OPTION_32 (OPTION_MD_BASE + 0)
+#define OPTION_64 (OPTION_MD_BASE + 1)
+#define OPTION_DIVIDE (OPTION_MD_BASE + 2)
+#define OPTION_MARCH (OPTION_MD_BASE + 3)
+#define OPTION_MTUNE (OPTION_MD_BASE + 4)
+#define OPTION_MMNEMONIC (OPTION_MD_BASE + 5)
+#define OPTION_MSYNTAX (OPTION_MD_BASE + 6)
+#define OPTION_MINDEX_REG (OPTION_MD_BASE + 7)
+#define OPTION_MNAKED_REG (OPTION_MD_BASE + 8)
+#define OPTION_MOLD_GCC (OPTION_MD_BASE + 9)
+#define OPTION_MSSE2AVX (OPTION_MD_BASE + 10)
+#define OPTION_MSSE_CHECK (OPTION_MD_BASE + 11)
 
-      /* e09  - e09
-             | ~ e09
-             | NOT e09  */
-      else if (cur_token.code == '-' || cur_token.code == '~')
-       {
-         char str[2];
+struct option md_longopts[] =
+{
+  {"32", no_argument, NULL, OPTION_32},
+#if (defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) \
+     || defined (TE_PE) || defined (TE_PEP))
+  {"64", no_argument, NULL, OPTION_64},
+#endif
+  {"divide", no_argument, NULL, OPTION_DIVIDE},
+  {"march", required_argument, NULL, OPTION_MARCH},
+  {"mtune", required_argument, NULL, OPTION_MTUNE},
+  {"mmnemonic", required_argument, NULL, OPTION_MMNEMONIC},
+  {"msyntax", required_argument, NULL, OPTION_MSYNTAX},
+  {"mindex-reg", no_argument, NULL, OPTION_MINDEX_REG},
+  {"mnaked-reg", no_argument, NULL, OPTION_MNAKED_REG},
+  {"mold-gcc", no_argument, NULL, OPTION_MOLD_GCC},
+  {"msse2avx", no_argument, NULL, OPTION_MSSE2AVX},
+  {"msse-check", required_argument, NULL, OPTION_MSSE_CHECK},
+  {NULL, no_argument, NULL, 0}
+};
+size_t md_longopts_size = sizeof (md_longopts);
 
-         if (nregs < 0)
-           nregs = ~nregs;
-         str[0] = cur_token.code;
-         str[1] = 0;
-         strcat (intel_parser.disp, str);
-       }
+int
+md_parse_option (int c, char *arg)
+{
+  unsigned int i;
+  char *arch, *next;
 
-      /* e09  e10 e09'  */
-      else
-       break;
+  switch (c)
+    {
+    case 'n':
+      optimize_align_code = 0;
+      break;
 
-      intel_match_token (cur_token.code);
-    }
+    case 'q':
+      quiet_warnings = 1;
+      break;
 
-  for (;;)
-    {
-      if (!intel_e10 ())
-       return 0;
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+      /* -Qy, -Qn: SVR4 arguments controlling whether a .comment section
+        should be emitted or not.  FIXME: Not implemented.  */
+    case 'Q':
+      break;
 
-      /* e09'  PTR e10 e09' */
-      if (cur_token.code == T_PTR)
-       {
-         char suffix;
+      /* -V: SVR4 argument to print version ID.  */
+    case 'V':
+      print_version_id ();
+      break;
 
-         if (prev_token.code == T_BYTE)
-           suffix = BYTE_MNEM_SUFFIX;
+      /* -k: Ignore for FreeBSD compatibility.  */
+    case 'k':
+      break;
 
-         else if (prev_token.code == T_WORD)
-           {
-             if (current_templates->start->name[0] == 'l'
-                 && current_templates->start->name[2] == 's'
-                 && current_templates->start->name[3] == 0)
-               suffix = BYTE_MNEM_SUFFIX; /* so it will cause an error */
-             else if (intel_parser.got_a_float == 2)   /* "fi..." */
-               suffix = SHORT_MNEM_SUFFIX;
-             else
-               suffix = WORD_MNEM_SUFFIX;
-           }
+    case 's':
+      /* -s: On i386 Solaris, this tells the native assembler to use
+        .stab instead of .stab.excl.  We always use .stab anyhow.  */
+      break;
+#endif
+#if (defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) \
+     || defined (TE_PE) || defined (TE_PEP))
+    case OPTION_64:
+      {
+       const char **list, **l;
 
-         else if (prev_token.code == T_DWORD)
+       list = bfd_target_list ();
+       for (l = list; *l != NULL; l++)
+         if (CONST_STRNEQ (*l, "elf64-x86-64")
+             || strcmp (*l, "coff-x86-64") == 0
+             || strcmp (*l, "pe-x86-64") == 0
+             || strcmp (*l, "pei-x86-64") == 0)
            {
-             if (current_templates->start->name[0] == 'l'
-                 && current_templates->start->name[2] == 's'
-                 && current_templates->start->name[3] == 0)
-               suffix = WORD_MNEM_SUFFIX;
-             else if (flag_code == CODE_16BIT
-                      && (current_templates->start->opcode_modifier
-                          & (Jump | JumpDword)))
-               suffix = LONG_DOUBLE_MNEM_SUFFIX;
-             else if (intel_parser.got_a_float == 1)   /* "f..." */
-               suffix = SHORT_MNEM_SUFFIX;
-             else
-               suffix = LONG_MNEM_SUFFIX;
+             default_arch = "x86_64";
+             break;
            }
+       if (*l == NULL)
+         as_fatal (_("No compiled in support for x86_64"));
+       free (list);
+      }
+      break;
+#endif
 
-         else if (prev_token.code == T_FWORD)
-           {
-             if (current_templates->start->name[0] == 'l'
-                 && current_templates->start->name[2] == 's'
-                 && current_templates->start->name[3] == 0)
-               suffix = LONG_MNEM_SUFFIX;
-             else if (!intel_parser.got_a_float)
-               {
-                 if (flag_code == CODE_16BIT)
-                   add_prefix (DATA_PREFIX_OPCODE);
-                 suffix = LONG_DOUBLE_MNEM_SUFFIX;
-               }
-             else
-               suffix = BYTE_MNEM_SUFFIX; /* so it will cause an error */
-           }
+    case OPTION_32:
+      default_arch = "i386";
+      break;
 
-         else if (prev_token.code == T_QWORD)
-           {
-             if (intel_parser.got_a_float == 1)        /* "f..." */
-               suffix = LONG_MNEM_SUFFIX;
-             else
-               suffix = QWORD_MNEM_SUFFIX;
-           }
+    case OPTION_DIVIDE:
+#ifdef SVR4_COMMENT_CHARS
+      {
+       char *n, *t;
+       const char *s;
 
-         else if (prev_token.code == T_TBYTE)
-           {
-             if (intel_parser.got_a_float == 1)
-               suffix = LONG_DOUBLE_MNEM_SUFFIX;
-             else
-               suffix = BYTE_MNEM_SUFFIX; /* so it will cause an error */
-           }
+       n = (char *) xmalloc (strlen (i386_comment_chars) + 1);
+       t = n;
+       for (s = i386_comment_chars; *s != '\0'; s++)
+         if (*s != '/')
+           *t++ = *s;
+       *t = '\0';
+       i386_comment_chars = n;
+      }
+#endif
+      break;
 
-         else if (prev_token.code == T_XMMWORD)
+    case OPTION_MARCH:
+      arch = xstrdup (arg);
+      do
+       {
+         if (*arch == '.')
+           as_fatal (_("Invalid -march= option: `%s'"), arg);
+         next = strchr (arch, '+');
+         if (next)
+           *next++ = '\0';
+         for (i = 0; i < ARRAY_SIZE (cpu_arch); i++)
            {
-             /* XXX ignored for now, but accepted since gcc uses it */
-             suffix = 0;
-           }
+             if (strcmp (arch, cpu_arch [i].name) == 0)
+               {
+                 /* Processor.  */
+                 cpu_arch_name = cpu_arch[i].name;
+                 cpu_sub_arch_name = NULL;
+                 cpu_arch_flags = cpu_arch[i].flags;
+                 cpu_arch_isa = cpu_arch[i].type;
+                 cpu_arch_isa_flags = cpu_arch[i].flags;
+                 if (!cpu_arch_tune_set)
+                   {
+                     cpu_arch_tune = cpu_arch_isa;
+                     cpu_arch_tune_flags = cpu_arch_isa_flags;
+                   }
+                 break;
+               }
+             else if (*cpu_arch [i].name == '.'
+                      && strcmp (arch, cpu_arch [i].name + 1) == 0)
+               {
+                 /* ISA entension.  */
+                 i386_cpu_flags flags;
 
-         else
-           {
-             as_bad (_("Unknown operand modifier `%s'"), prev_token.str);
-             return 0;
+                 if (strncmp (arch, "no", 2))
+                   flags = cpu_flags_or (cpu_arch_flags,
+                                         cpu_arch[i].flags);
+                 else
+                   flags = cpu_flags_and_not (cpu_arch_flags,
+                                              cpu_arch[i].flags);
+                 if (!cpu_flags_equal (&flags, &cpu_arch_flags))
+                   {
+                     if (cpu_sub_arch_name)
+                       {
+                         char *name = cpu_sub_arch_name;
+                         cpu_sub_arch_name = concat (name,
+                                                     cpu_arch[i].name,
+                                                     (const char *) NULL);
+                         free (name);
+                       }
+                     else
+                       cpu_sub_arch_name = xstrdup (cpu_arch[i].name);
+                     cpu_arch_flags = flags;
+                   }
+                 break;
+               }
            }
 
-         /* Operands for jump/call using 'ptr' notation denote absolute
-            addresses.  */
-         if (current_templates->start->opcode_modifier & (Jump | JumpDword))
-           i.types[this_operand] |= JumpAbsolute;
-
-         if (current_templates->start->base_opcode == 0x8d /* lea */)
-           ;
-         else if (!i.suffix)
-           i.suffix = suffix;
-         else if (i.suffix != suffix)
-           {
-             as_bad (_("Conflicting operand modifiers"));
-             return 0;
-           }
+         if (i >= ARRAY_SIZE (cpu_arch))
+           as_fatal (_("Invalid -march= option: `%s'"), arg);
 
+         arch = next;
        }
+      while (next != NULL );
+      break;
 
-      /* e09'  : e10 e09'  */
-      else if (cur_token.code == ':')
+    case OPTION_MTUNE:
+      if (*arg == '.')
+       as_fatal (_("Invalid -mtune= option: `%s'"), arg);
+      for (i = 0; i < ARRAY_SIZE (cpu_arch); i++)
        {
-         if (prev_token.code != T_REG)
+         if (strcmp (arg, cpu_arch [i].name) == 0)
            {
-             /* While {call,jmp} SSSS:OOOO is MASM syntax only when SSSS is a
-                segment/group identifier (which we don't have), using comma
-                as the operand separator there is even less consistent, since
-                there all branches only have a single operand.  */
-             if (this_operand != 0
-                 || intel_parser.in_offset
-                 || intel_parser.in_bracket
-                 || (!(current_templates->start->opcode_modifier
-                       & (Jump|JumpDword|JumpInterSegment))
-                     && !(current_templates->start->operand_types[0]
-                          & JumpAbsolute)))
-               return intel_match_token (T_NIL);
-             /* Remember the start of the 2nd operand and terminate 1st
-                operand here.
-                XXX This isn't right, yet (when SSSS:OOOO is right operand of
-                another expression), but it gets at least the simplest case
-                (a plain number or symbol on the left side) right.  */
-             intel_parser.next_operand = intel_parser.op_string;
-             *--intel_parser.op_string = '\0';
-             return intel_match_token (':');
+             cpu_arch_tune_set = 1;
+             cpu_arch_tune = cpu_arch [i].type;
+             cpu_arch_tune_flags = cpu_arch[i].flags;
+             break;
            }
        }
+      if (i >= ARRAY_SIZE (cpu_arch))
+       as_fatal (_("Invalid -mtune= option: `%s'"), arg);
+      break;
 
-      /* e09'  Empty  */
+    case OPTION_MMNEMONIC:
+      if (strcasecmp (arg, "att") == 0)
+       intel_mnemonic = 0;
+      else if (strcasecmp (arg, "intel") == 0)
+       intel_mnemonic = 1;
       else
-       break;
-
-      intel_match_token (cur_token.code);
-
-    }
-
-  if (in_offset)
-    {
-      --intel_parser.in_offset;
-      if (nregs < 0)
-       nregs = ~nregs;
-      if (NUM_ADDRESS_REGS > nregs)
-       {
-         as_bad (_("Invalid operand to `OFFSET'"));
-         return 0;
-       }
-      intel_parser.op_modifier |= 1 << T_OFFSET;
-    }
-
-  if (nregs >= 0 && NUM_ADDRESS_REGS > nregs)
-    i.base_reg = i386_regtab + REGNAM_AL + 3; /* bl is invalid as base */
-  return 1;
-}
-
-static int
-intel_bracket_expr (void)
-{
-  int was_offset = intel_parser.op_modifier & (1 << T_OFFSET);
-  const char *start = intel_parser.op_string;
-  int len;
-
-  if (i.op[this_operand].regs)
-    return intel_match_token (T_NIL);
+       as_fatal (_("Invalid -mmnemonic= option: `%s'"), arg);
+      break;
 
-  intel_match_token ('[');
+    case OPTION_MSYNTAX:
+      if (strcasecmp (arg, "att") == 0)
+       intel_syntax = 0;
+      else if (strcasecmp (arg, "intel") == 0)
+       intel_syntax = 1;
+      else
+       as_fatal (_("Invalid -msyntax= option: `%s'"), arg);
+      break;
 
-  /* Mark as a memory operand only if it's not already known to be an
-     offset expression.  If it's an offset expression, we need to keep
-     the brace in.  */
-  if (!intel_parser.in_offset)
-    {
-      ++intel_parser.in_bracket;
+    case OPTION_MINDEX_REG:
+      allow_index_reg = 1;
+      break;
 
-      /* Operands for jump/call inside brackets denote absolute addresses.  */
-      if (current_templates->start->opcode_modifier & (Jump | JumpDword))
-       i.types[this_operand] |= JumpAbsolute;
+    case OPTION_MNAKED_REG:
+      allow_naked_reg = 1;
+      break;
 
-      /* Unfortunately gas always diverged from MASM in a respect that can't
-        be easily fixed without risking to break code sequences likely to be
-        encountered (the testsuite even check for this): MASM doesn't consider
-        an expression inside brackets unconditionally as a memory reference.
-        When that is e.g. a constant, an offset expression, or the sum of the
-        two, this is still taken as a constant load. gas, however, always
-        treated these as memory references. As a compromise, we'll try to make
-        offset expressions inside brackets work the MASM way (since that's
-        less likely to be found in real world code), but make constants alone
-        continue to work the traditional gas way. In either case, issue a
-        warning.  */
-      intel_parser.op_modifier &= ~was_offset;
-    }
-  else
-    strcat (intel_parser.disp, "[");
+    case OPTION_MOLD_GCC:
+      old_gcc = 1;
+      break;
 
-  /* Add a '+' to the displacement string if necessary.  */
-  if (*intel_parser.disp != '\0'
-      && *(intel_parser.disp + strlen (intel_parser.disp) - 1) != '+')
-    strcat (intel_parser.disp, "+");
+    case OPTION_MSSE2AVX:
+      sse2avx = 1;
+      break;
 
-  if (intel_expr ()
-      && (len = intel_parser.op_string - start - 1,
-         intel_match_token (']')))
-    {
-      /* Preserve brackets when the operand is an offset expression.  */
-      if (intel_parser.in_offset)
-       strcat (intel_parser.disp, "]");
+    case OPTION_MSSE_CHECK:
+      if (strcasecmp (arg, "error") == 0)
+       sse_check = sse_check_error;
+      else if (strcasecmp (arg, "warning") == 0)
+       sse_check = sse_check_warning;
+      else if (strcasecmp (arg, "none") == 0)
+       sse_check = sse_check_none;
       else
-       {
-         --intel_parser.in_bracket;
-         if (i.base_reg || i.index_reg)
-           intel_parser.is_mem = 1;
-         if (!intel_parser.is_mem)
-           {
-             if (!(intel_parser.op_modifier & (1 << T_OFFSET)))
-               /* Defer the warning until all of the operand was parsed.  */
-               intel_parser.is_mem = -1;
-             else if (!quiet_warnings)
-               as_warn (_("`[%.*s]' taken to mean just `%.*s'"),
-                        len, start, len, start);
-           }
-       }
-      intel_parser.op_modifier |= was_offset;
+       as_fatal (_("Invalid -msse-check= option: `%s'"), arg);
+      break;
 
-      return 1;
+    default:
+      return 0;
     }
-  return 0;
+  return 1;
 }
 
-/* e10 e11 e10'
-
-   e10'        [ expr ] e10'
-       | Empty  */
-static int
-intel_e10 (void)
+void
+md_show_usage (stream)
+     FILE *stream;
 {
-  if (!intel_e11 ())
-    return 0;
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+  fprintf (stream, _("\
+  -Q                      ignored\n\
+  -V                      print assembler version number\n\
+  -k                      ignored\n"));
+#endif
+  fprintf (stream, _("\
+  -n                      Do not optimize code alignment\n\
+  -q                      quieten some warnings\n"));
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+  fprintf (stream, _("\
+  -s                      ignored\n"));
+#endif
+#if (defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) \
+     || defined (TE_PE) || defined (TE_PEP))
+  fprintf (stream, _("\
+  --32/--64               generate 32bit/64bit code\n"));
+#endif
+#ifdef SVR4_COMMENT_CHARS
+  fprintf (stream, _("\
+  --divide                do not treat `/' as a comment character\n"));
+#else
+  fprintf (stream, _("\
+  --divide                ignored\n"));
+#endif
+  fprintf (stream, _("\
+  -march=CPU[,+EXTENSION...]\n\
+                          generate code for CPU and EXTENSION, CPU is one of:\n\
+                           i8086, i186, i286, i386, i486, pentium, pentiumpro,\n\
+                           pentiumii, pentiumiii, pentium4, prescott, nocona,\n\
+                           core, core2, corei7, l1om, k6, k6_2, athlon, k8,\n\
+                           amdfam10, generic32, generic64\n\
+                          EXTENSION is combination of:\n\
+                           8087, 287, 387, no87, mmx, nommx, sse, sse2, sse3,\n\
+                           ssse3, sse4.1, sse4.2, sse4, nosse, avx, noavx,\n\
+                           vmx, smx, xsave, movbe, ept, aes, pclmul, fma,\n\
+                           clflush, syscall, rdtscp, 3dnow, 3dnowa, sse4a,\n\
+                           svme, abm, padlock, fma4\n"));
+  fprintf (stream, _("\
+  -mtune=CPU              optimize for CPU, CPU is one of:\n\
+                           i8086, i186, i286, i386, i486, pentium, pentiumpro,\n\
+                           pentiumii, pentiumiii, pentium4, prescott, nocona,\n\
+                           core, core2, corei7, l1om, k6, k6_2, athlon, k8,\n\
+                           amdfam10, generic32, generic64\n"));
+  fprintf (stream, _("\
+  -msse2avx               encode SSE instructions with VEX prefix\n"));
+  fprintf (stream, _("\
+  -msse-check=[none|error|warning]\n\
+                          check SSE instructions\n"));
+  fprintf (stream, _("\
+  -mmnemonic=[att|intel]  use AT&T/Intel mnemonic\n"));
+  fprintf (stream, _("\
+  -msyntax=[att|intel]    use AT&T/Intel syntax\n"));
+  fprintf (stream, _("\
+  -mindex-reg             support pseudo index registers\n"));
+  fprintf (stream, _("\
+  -mnaked-reg             don't require `%%' prefix for registers\n"));
+  fprintf (stream, _("\
+  -mold-gcc               support old (<= 2.8.1) versions of gcc\n"));
+}
 
-  while (cur_token.code == '[')
-    {
-      if (!intel_bracket_expr ())
-       return 0;
-    }
+#if ((defined (OBJ_MAYBE_COFF) && defined (OBJ_MAYBE_AOUT)) \
+     || defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) \
+     || defined (TE_PE) || defined (TE_PEP) || defined (OBJ_MACH_O))
 
-  return 1;
-}
+/* Pick the target format to use.  */
 
-/* e11 ( expr )
-       | [ expr ]
-       | BYTE
-       | WORD
-       | DWORD
-       | FWORD
-       | QWORD
-       | TBYTE
-       | OWORD
-       | XMMWORD
-       | $
-       | .
-       | register
-       | id
-       | constant  */
-static int
-intel_e11 (void)
+const char *
+i386_target_format (void)
 {
-  switch (cur_token.code)
+  if (!strcmp (default_arch, "x86_64"))
     {
-    /* e11  ( expr ) */
-    case '(':
-      intel_match_token ('(');
-      strcat (intel_parser.disp, "(");
-
-      if (intel_expr () && intel_match_token (')'))
+      set_code_flag (CODE_64BIT);
+      if (cpu_flags_all_zero (&cpu_arch_isa_flags))
        {
-         strcat (intel_parser.disp, ")");
-         return 1;
+         cpu_arch_isa_flags.bitfield.cpui186 = 1;
+         cpu_arch_isa_flags.bitfield.cpui286 = 1;
+         cpu_arch_isa_flags.bitfield.cpui386 = 1;
+         cpu_arch_isa_flags.bitfield.cpui486 = 1;
+         cpu_arch_isa_flags.bitfield.cpui586 = 1;
+         cpu_arch_isa_flags.bitfield.cpui686 = 1;
+         cpu_arch_isa_flags.bitfield.cpuclflush = 1;
+         cpu_arch_isa_flags.bitfield.cpummx= 1;
+         cpu_arch_isa_flags.bitfield.cpusse = 1;
+         cpu_arch_isa_flags.bitfield.cpusse2 = 1;
+         cpu_arch_isa_flags.bitfield.cpulm = 1;
        }
-      return 0;
-
-    /* e11  [ expr ] */
-    case '[':
-      return intel_bracket_expr ();
-
-    /* e11  $
-           | .  */
-    case '.':
-      strcat (intel_parser.disp, cur_token.str);
-      intel_match_token (cur_token.code);
-
-      /* Mark as a memory operand only if it's not already known to be an
-        offset expression.  */
-      if (!intel_parser.in_offset)
-       intel_parser.is_mem = 1;
-
-      return 1;
-
-    /* e11  register  */
-    case T_REG:
+      if (cpu_flags_all_zero (&cpu_arch_tune_flags))
+       {
+         cpu_arch_tune_flags.bitfield.cpui186 = 1;
+         cpu_arch_tune_flags.bitfield.cpui286 = 1;
+         cpu_arch_tune_flags.bitfield.cpui386 = 1;
+         cpu_arch_tune_flags.bitfield.cpui486 = 1;
+         cpu_arch_tune_flags.bitfield.cpui586 = 1;
+         cpu_arch_tune_flags.bitfield.cpui686 = 1;
+         cpu_arch_tune_flags.bitfield.cpuclflush = 1;
+         cpu_arch_tune_flags.bitfield.cpummx= 1;
+         cpu_arch_tune_flags.bitfield.cpusse = 1;
+         cpu_arch_tune_flags.bitfield.cpusse2 = 1;
+       }
+    }
+  else if (!strcmp (default_arch, "i386"))
+    {
+      set_code_flag (CODE_32BIT);
+      if (cpu_flags_all_zero (&cpu_arch_isa_flags))
+       {
+         cpu_arch_isa_flags.bitfield.cpui186 = 1;
+         cpu_arch_isa_flags.bitfield.cpui286 = 1;
+         cpu_arch_isa_flags.bitfield.cpui386 = 1;
+       }
+      if (cpu_flags_all_zero (&cpu_arch_tune_flags))
+       {
+         cpu_arch_tune_flags.bitfield.cpui186 = 1;
+         cpu_arch_tune_flags.bitfield.cpui286 = 1;
+         cpu_arch_tune_flags.bitfield.cpui386 = 1;
+       }
+    }
+  else
+    as_fatal (_("Unknown architecture"));
+  switch (OUTPUT_FLAVOR)
+    {
+#if defined (OBJ_MAYBE_AOUT) || defined (OBJ_AOUT)
+    case bfd_target_aout_flavour:
+      return AOUT_TARGET_FORMAT;
+#endif
+#if defined (OBJ_MAYBE_COFF) || defined (OBJ_COFF)
+# if defined (TE_PE) || defined (TE_PEP)
+    case bfd_target_coff_flavour:
+      return flag_code == CODE_64BIT ? "pe-x86-64" : "pe-i386";
+# elif defined (TE_GO32)
+    case bfd_target_coff_flavour:
+      return "coff-go32";
+# else
+    case bfd_target_coff_flavour:
+      return "coff-i386";
+# endif
+#endif
+#if defined (OBJ_MAYBE_ELF) || defined (OBJ_ELF)
+    case bfd_target_elf_flavour:
       {
-       const reg_entry *reg = intel_parser.reg = cur_token.reg;
-
-       intel_match_token (T_REG);
-
-       /* Check for segment change.  */
-       if (cur_token.code == ':')
-         {
-           if (!(reg->reg_type & (SReg2 | SReg3)))
-             {
-               as_bad (_("`%s' is not a valid segment register"),
-                       reg->reg_name);
-               return 0;
-             }
-           else if (i.seg[i.mem_operands])
-             as_warn (_("Extra segment override ignored"));
-           else
-             {
-               if (!intel_parser.in_offset)
-                 intel_parser.is_mem = 1;
-               switch (reg->reg_num)
-                 {
-                 case 0:
-                   i.seg[i.mem_operands] = &es;
-                   break;
-                 case 1:
-                   i.seg[i.mem_operands] = &cs;
-                   break;
-                 case 2:
-                   i.seg[i.mem_operands] = &ss;
-                   break;
-                 case 3:
-                   i.seg[i.mem_operands] = &ds;
-                   break;
-                 case 4:
-                   i.seg[i.mem_operands] = &fs;
-                   break;
-                 case 5:
-                   i.seg[i.mem_operands] = &gs;
-                   break;
-                 }
-             }
-         }
-
-       /* Not a segment register. Check for register scaling.  */
-       else if (cur_token.code == '*')
-         {
-           if (!intel_parser.in_bracket)
-             {
-               as_bad (_("Register scaling only allowed in memory operands"));
-               return 0;
-             }
-
-           if (reg->reg_type & Reg16) /* Disallow things like [si*1]. */
-             reg = i386_regtab + REGNAM_AX + 4; /* sp is invalid as index */
-           else if (i.index_reg)
-             reg = i386_regtab + REGNAM_EAX + 4; /* esp is invalid as index */
-
-           /* What follows must be a valid scale.  */
-           intel_match_token ('*');
-           i.index_reg = reg;
-           i.types[this_operand] |= BaseIndex;
-
-           /* Set the scale after setting the register (otherwise,
-              i386_scale will complain)  */
-           if (cur_token.code == '+' || cur_token.code == '-')
-             {
-               char *str, sign = cur_token.code;
-               intel_match_token (cur_token.code);
-               if (cur_token.code != T_CONST)
-                 {
-                   as_bad (_("Syntax error: Expecting a constant, got `%s'"),
-                           cur_token.str);
-                   return 0;
-                 }
-               str = (char *) xmalloc (strlen (cur_token.str) + 2);
-               strcpy (str + 1, cur_token.str);
-               *str = sign;
-               if (!i386_scale (str))
-                 return 0;
-               free (str);
-             }
-           else if (!i386_scale (cur_token.str))
-             return 0;
-           intel_match_token (cur_token.code);
-         }
-
-       /* No scaling. If this is a memory operand, the register is either a
-          base register (first occurrence) or an index register (second
-          occurrence).  */
-       else if (intel_parser.in_bracket)
+       if (flag_code == CODE_64BIT)
          {
-
-           if (!i.base_reg)
-             i.base_reg = reg;
-           else if (!i.index_reg)
-             i.index_reg = reg;
-           else
-             {
-               as_bad (_("Too many register references in memory operand"));
-               return 0;
-             }
-
-           i.types[this_operand] |= BaseIndex;
+           object_64bit = 1;
+           use_rela_relocations = 1;
          }
-
-       /* It's neither base nor index.  */
-       else if (!intel_parser.in_offset && !intel_parser.is_mem)
+       if (cpu_arch_isa == PROCESSOR_L1OM)
          {
-           i.types[this_operand] |= reg->reg_type & ~BaseIndex;
-           i.op[this_operand].regs = reg;
-           i.reg_operands++;
+           if (flag_code != CODE_64BIT)
+             as_fatal (_("Intel L1OM is 64bit only"));
+           return ELF_TARGET_L1OM_FORMAT;
          }
        else
-         {
-           as_bad (_("Invalid use of register"));
-           return 0;
-         }
-
-       /* Since registers are not part of the displacement string (except
-          when we're parsing offset operands), we may need to remove any
-          preceding '+' from the displacement string.  */
-       if (*intel_parser.disp != '\0'
-           && !intel_parser.in_offset)
-         {
-           char *s = intel_parser.disp;
-           s += strlen (s) - 1;
-           if (*s == '+')
-             *s = '\0';
-         }
-
-       return 1;
+         return (flag_code == CODE_64BIT
+                 ? ELF_TARGET_FORMAT64 : ELF_TARGET_FORMAT);
       }
+#endif
+#if defined (OBJ_MACH_O)
+    case bfd_target_mach_o_flavour:
+      return flag_code == CODE_64BIT ? "mach-o-x86-64" : "mach-o-i386";
+#endif
+    default:
+      abort ();
+      return NULL;
+    }
+}
 
-    /* e11  BYTE
-           | WORD
-           | DWORD
-           | FWORD
-           | QWORD
-           | TBYTE
-           | OWORD
-           | XMMWORD  */
-    case T_BYTE:
-    case T_WORD:
-    case T_DWORD:
-    case T_FWORD:
-    case T_QWORD:
-    case T_TBYTE:
-    case T_XMMWORD:
-      intel_match_token (cur_token.code);
-
-      if (cur_token.code == T_PTR)
-       return 1;
-
-      /* It must have been an identifier.  */
-      intel_putback_token ();
-      cur_token.code = T_ID;
-      /* FALLTHRU */
-
-    /* e11  id
-           | constant  */
-    case T_ID:
-      if (!intel_parser.in_offset && intel_parser.is_mem <= 0)
-       {
-         symbolS *symbolP;
-
-         /* The identifier represents a memory reference only if it's not
-            preceded by an offset modifier and if it's not an equate.  */
-         symbolP = symbol_find(cur_token.str);
-         if (!symbolP || S_GET_SEGMENT(symbolP) != absolute_section)
-           intel_parser.is_mem = 1;
-       }
-       /* FALLTHRU */
-
-    case T_CONST:
-    case '-':
-    case '+':
-      {
-       char *save_str, sign = 0;
-
-       /* Allow constants that start with `+' or `-'.  */
-       if (cur_token.code == '-' || cur_token.code == '+')
-         {
-           sign = cur_token.code;
-           intel_match_token (cur_token.code);
-           if (cur_token.code != T_CONST)
-             {
-               as_bad (_("Syntax error: Expecting a constant, got `%s'"),
-                       cur_token.str);
-               return 0;
-             }
-         }
-
-       save_str = (char *) xmalloc (strlen (cur_token.str) + 2);
-       strcpy (save_str + !!sign, cur_token.str);
-       if (sign)
-         *save_str = sign;
-
-       /* Get the next token to check for register scaling.  */
-       intel_match_token (cur_token.code);
-
-       /* Check if this constant is a scaling factor for an
-          index register.  */
-       if (cur_token.code == '*')
-         {
-           if (intel_match_token ('*') && cur_token.code == T_REG)
-             {
-               const reg_entry *reg = cur_token.reg;
-
-               if (!intel_parser.in_bracket)
-                 {
-                   as_bad (_("Register scaling only allowed "
-                             "in memory operands"));
-                   return 0;
-                 }
-
-                /* Disallow things like [1*si].
-                   sp and esp are invalid as index.  */
-               if (reg->reg_type & Reg16)
-                 reg = i386_regtab + REGNAM_AX + 4;
-               else if (i.index_reg)
-                 reg = i386_regtab + REGNAM_EAX + 4;
-
-               /* The constant is followed by `* reg', so it must be
-                  a valid scale.  */
-               i.index_reg = reg;
-               i.types[this_operand] |= BaseIndex;
-
-               /* Set the scale after setting the register (otherwise,
-                  i386_scale will complain)  */
-               if (!i386_scale (save_str))
-                 return 0;
-               intel_match_token (T_REG);
+#endif /* OBJ_MAYBE_ more than one  */
 
-               /* Since registers are not part of the displacement
-                  string, we may need to remove any preceding '+' from
-                  the displacement string.  */
-               if (*intel_parser.disp != '\0')
-                 {
-                   char *s = intel_parser.disp;
-                   s += strlen (s) - 1;
-                   if (*s == '+')
-                     *s = '\0';
-                 }
+#if (defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF))
+void
+i386_elf_emit_arch_note (void)
+{
+  if (IS_ELF && cpu_arch_name != NULL)
+    {
+      char *p;
+      asection *seg = now_seg;
+      subsegT subseg = now_subseg;
+      Elf_Internal_Note i_note;
+      Elf_External_Note e_note;
+      asection *note_secp;
+      int len;
 
-               free (save_str);
+      /* Create the .note section.  */
+      note_secp = subseg_new (".note", 0);
+      bfd_set_section_flags (stdoutput,
+                            note_secp,
+                            SEC_HAS_CONTENTS | SEC_READONLY);
 
-               return 1;
-             }
+      /* Process the arch string.  */
+      len = strlen (cpu_arch_name);
 
-           /* The constant was not used for register scaling. Since we have
-              already consumed the token following `*' we now need to put it
-              back in the stream.  */
-           intel_putback_token ();
-         }
+      i_note.namesz = len + 1;
+      i_note.descsz = 0;
+      i_note.type = NT_ARCH;
+      p = frag_more (sizeof (e_note.namesz));
+      md_number_to_chars (p, (valueT) i_note.namesz, sizeof (e_note.namesz));
+      p = frag_more (sizeof (e_note.descsz));
+      md_number_to_chars (p, (valueT) i_note.descsz, sizeof (e_note.descsz));
+      p = frag_more (sizeof (e_note.type));
+      md_number_to_chars (p, (valueT) i_note.type, sizeof (e_note.type));
+      p = frag_more (len + 1);
+      strcpy (p, cpu_arch_name);
 
-       /* Add the constant to the displacement string.  */
-       strcat (intel_parser.disp, save_str);
-       free (save_str);
+      frag_align (2, 0, 0);
 
-       return 1;
-      }
+      subseg_set (seg, subseg);
     }
-
-  as_bad (_("Unrecognized token '%s'"), cur_token.str);
-  return 0;
 }
-
-/* Match the given token against cur_token. If they match, read the next
-   token from the operand string.  */
-static int
-intel_match_token (int code)
+#endif
+\f
+symbolS *
+md_undefined_symbol (name)
+     char *name;
 {
-  if (cur_token.code == code)
-    {
-      intel_get_token ();
-      return 1;
-    }
-  else
+  if (name[0] == GLOBAL_OFFSET_TABLE_NAME[0]
+      && name[1] == GLOBAL_OFFSET_TABLE_NAME[1]
+      && name[2] == GLOBAL_OFFSET_TABLE_NAME[2]
+      && strcmp (name, GLOBAL_OFFSET_TABLE_NAME) == 0)
     {
-      as_bad (_("Unexpected token `%s'"), cur_token.str);
-      return 0;
+      if (!GOT_symbol)
+       {
+         if (symbol_find (name))
+           as_bad (_("GOT already in symbol table"));
+         GOT_symbol = symbol_new (name, undefined_section,
+                                  (valueT) 0, &zero_address_frag);
+       };
+      return GOT_symbol;
     }
+  return 0;
 }
 
-/* Read a new token from intel_parser.op_string and store it in cur_token.  */
-static void
-intel_get_token (void)
-{
-  char *end_op;
-  const reg_entry *reg;
-  struct intel_token new_token;
-
-  new_token.code = T_NIL;
-  new_token.reg = NULL;
-  new_token.str = NULL;
-
-  /* Free the memory allocated to the previous token and move
-     cur_token to prev_token.  */
-  if (prev_token.str)
-    free (prev_token.str);
-
-  prev_token = cur_token;
+/* Round up a section size to the appropriate boundary.  */
 
-  /* Skip whitespace.  */
-  while (is_space_char (*intel_parser.op_string))
-    intel_parser.op_string++;
+valueT
+md_section_align (segment, size)
+     segT segment ATTRIBUTE_UNUSED;
+     valueT size;
+{
+#if (defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT))
+  if (OUTPUT_FLAVOR == bfd_target_aout_flavour)
+    {
+      /* For a.out, force the section size to be aligned.  If we don't do
+        this, BFD will align it for us, but it will not write out the
+        final bytes of the section.  This may be a bug in BFD, but it is
+        easier to fix it here since that is how the other a.out targets
+        work.  */
+      int align;
 
-  /* Return an empty token if we find nothing else on the line.  */
-  if (*intel_parser.op_string == '\0')
-    {
-      cur_token = new_token;
-      return;
+      align = bfd_get_section_alignment (stdoutput, segment);
+      size = ((size + (1 << align) - 1) & ((valueT) -1 << align));
     }
+#endif
 
-  /* The new token cannot be larger than the remainder of the operand
-     string.  */
-  new_token.str = (char *) xmalloc (strlen (intel_parser.op_string) + 1);
-  new_token.str[0] = '\0';
+  return size;
+}
 
-  if (strchr ("0123456789", *intel_parser.op_string))
-    {
-      char *p = new_token.str;
-      char *q = intel_parser.op_string;
-      new_token.code = T_CONST;
+/* On the i386, PC-relative offsets are relative to the start of the
+   next instruction.  That is, the address of the offset, plus its
+   size, since the offset is always the last part of the insn.  */
 
-      /* Allow any kind of identifier char to encompass floating point and
-        hexadecimal numbers.  */
-      while (is_identifier_char (*q))
-       *p++ = *q++;
-      *p = '\0';
+long
+md_pcrel_from (fixS *fixP)
+{
+  return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address;
+}
 
-      /* Recognize special symbol names [0-9][bf].  */
-      if (strlen (intel_parser.op_string) == 2
-         && (intel_parser.op_string[1] == 'b'
-             || intel_parser.op_string[1] == 'f'))
-       new_token.code = T_ID;
-    }
+#ifndef I386COFF
 
-  else if ((reg = parse_register (intel_parser.op_string, &end_op)) != NULL)
-    {
-      size_t len = end_op - intel_parser.op_string;
+static void
+s_bss (int ignore ATTRIBUTE_UNUSED)
+{
+  int temp;
 
-      new_token.code = T_REG;
-      new_token.reg = reg;
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+  if (IS_ELF)
+    obj_elf_section_change_hook ();
+#endif
+  temp = get_absolute_expression ();
+  subseg_set (bss_section, (subsegT) temp);
+  demand_empty_rest_of_line ();
+}
 
-      memcpy (new_token.str, intel_parser.op_string, len);
-      new_token.str[len] = '\0';
-    }
+#endif
 
-  else if (is_identifier_char (*intel_parser.op_string))
+void
+i386_validate_fix (fixS *fixp)
+{
+  if (fixp->fx_subsy && fixp->fx_subsy == GOT_symbol)
     {
-      char *p = new_token.str;
-      char *q = intel_parser.op_string;
-
-      /* A '.' or '$' followed by an identifier char is an identifier.
-        Otherwise, it's operator '.' followed by an expression.  */
-      if ((*q == '.' || *q == '$') && !is_identifier_char (*(q + 1)))
+      if (fixp->fx_r_type == BFD_RELOC_32_PCREL)
        {
-         new_token.code = '.';
-         new_token.str[0] = '.';
-         new_token.str[1] = '\0';
+         if (!object_64bit)
+           abort ();
+         fixp->fx_r_type = BFD_RELOC_X86_64_GOTPCREL;
        }
       else
        {
-         while (is_identifier_char (*q) || *q == '@')
-           *p++ = *q++;
-         *p = '\0';
-
-         if (strcasecmp (new_token.str, "NOT") == 0)
-           new_token.code = '~';
-
-         else if (strcasecmp (new_token.str, "MOD") == 0)
-           new_token.code = '%';
-
-         else if (strcasecmp (new_token.str, "AND") == 0)
-           new_token.code = '&';
-
-         else if (strcasecmp (new_token.str, "OR") == 0)
-           new_token.code = '|';
-
-         else if (strcasecmp (new_token.str, "XOR") == 0)
-           new_token.code = '^';
-
-         else if (strcasecmp (new_token.str, "SHL") == 0)
-           new_token.code = T_SHL;
-
-         else if (strcasecmp (new_token.str, "SHR") == 0)
-           new_token.code = T_SHR;
-
-         else if (strcasecmp (new_token.str, "BYTE") == 0)
-           new_token.code = T_BYTE;
-
-         else if (strcasecmp (new_token.str, "WORD") == 0)
-           new_token.code = T_WORD;
-
-         else if (strcasecmp (new_token.str, "DWORD") == 0)
-           new_token.code = T_DWORD;
-
-         else if (strcasecmp (new_token.str, "FWORD") == 0)
-           new_token.code = T_FWORD;
-
-         else if (strcasecmp (new_token.str, "QWORD") == 0)
-           new_token.code = T_QWORD;
-
-         else if (strcasecmp (new_token.str, "TBYTE") == 0
-                  /* XXX remove (gcc still uses it) */
-                  || strcasecmp (new_token.str, "XWORD") == 0)
-           new_token.code = T_TBYTE;
-
-         else if (strcasecmp (new_token.str, "XMMWORD") == 0
-                  || strcasecmp (new_token.str, "OWORD") == 0)
-           new_token.code = T_XMMWORD;
-
-         else if (strcasecmp (new_token.str, "PTR") == 0)
-           new_token.code = T_PTR;
+         if (!object_64bit)
+           fixp->fx_r_type = BFD_RELOC_386_GOTOFF;
+         else
+           fixp->fx_r_type = BFD_RELOC_X86_64_GOTOFF64;
+       }
+      fixp->fx_subsy = 0;
+    }
+}
 
-         else if (strcasecmp (new_token.str, "SHORT") == 0)
-           new_token.code = T_SHORT;
+arelent *
+tc_gen_reloc (section, fixp)
+     asection *section ATTRIBUTE_UNUSED;
+     fixS *fixp;
+{
+  arelent *rel;
+  bfd_reloc_code_real_type code;
 
-         else if (strcasecmp (new_token.str, "OFFSET") == 0)
+  switch (fixp->fx_r_type)
+    {
+    case BFD_RELOC_X86_64_PLT32:
+    case BFD_RELOC_X86_64_GOT32:
+    case BFD_RELOC_X86_64_GOTPCREL:
+    case BFD_RELOC_386_PLT32:
+    case BFD_RELOC_386_GOT32:
+    case BFD_RELOC_386_GOTOFF:
+    case BFD_RELOC_386_GOTPC:
+    case BFD_RELOC_386_TLS_GD:
+    case BFD_RELOC_386_TLS_LDM:
+    case BFD_RELOC_386_TLS_LDO_32:
+    case BFD_RELOC_386_TLS_IE_32:
+    case BFD_RELOC_386_TLS_IE:
+    case BFD_RELOC_386_TLS_GOTIE:
+    case BFD_RELOC_386_TLS_LE_32:
+    case BFD_RELOC_386_TLS_LE:
+    case BFD_RELOC_386_TLS_GOTDESC:
+    case BFD_RELOC_386_TLS_DESC_CALL:
+    case BFD_RELOC_X86_64_TLSGD:
+    case BFD_RELOC_X86_64_TLSLD:
+    case BFD_RELOC_X86_64_DTPOFF32:
+    case BFD_RELOC_X86_64_DTPOFF64:
+    case BFD_RELOC_X86_64_GOTTPOFF:
+    case BFD_RELOC_X86_64_TPOFF32:
+    case BFD_RELOC_X86_64_TPOFF64:
+    case BFD_RELOC_X86_64_GOTOFF64:
+    case BFD_RELOC_X86_64_GOTPC32:
+    case BFD_RELOC_X86_64_GOT64:
+    case BFD_RELOC_X86_64_GOTPCREL64:
+    case BFD_RELOC_X86_64_GOTPC64:
+    case BFD_RELOC_X86_64_GOTPLT64:
+    case BFD_RELOC_X86_64_PLTOFF64:
+    case BFD_RELOC_X86_64_GOTPC32_TLSDESC:
+    case BFD_RELOC_X86_64_TLSDESC_CALL:
+    case BFD_RELOC_RVA:
+    case BFD_RELOC_VTABLE_ENTRY:
+    case BFD_RELOC_VTABLE_INHERIT:
+#ifdef TE_PE
+    case BFD_RELOC_32_SECREL:
+#endif
+      code = fixp->fx_r_type;
+      break;
+    case BFD_RELOC_X86_64_32S:
+      if (!fixp->fx_pcrel)
+       {
+         /* Don't turn BFD_RELOC_X86_64_32S into BFD_RELOC_32.  */
+         code = fixp->fx_r_type;
+         break;
+       }
+    default:
+      if (fixp->fx_pcrel)
+       {
+         switch (fixp->fx_size)
            {
-             new_token.code = T_OFFSET;
-
-             /* ??? This is not mentioned in the MASM grammar but gcc
-                    makes use of it with -mintel-syntax.  OFFSET may be
-                    followed by FLAT:  */
-             if (strncasecmp (q, " FLAT:", 6) == 0)
-               strcat (new_token.str, " FLAT:");
+           default:
+             as_bad_where (fixp->fx_file, fixp->fx_line,
+                           _("can not do %d byte pc-relative relocation"),
+                           fixp->fx_size);
+             code = BFD_RELOC_32_PCREL;
+             break;
+           case 1: code = BFD_RELOC_8_PCREL;  break;
+           case 2: code = BFD_RELOC_16_PCREL; break;
+           case 4: code = BFD_RELOC_32_PCREL; break;
+#ifdef BFD64
+           case 8: code = BFD_RELOC_64_PCREL; break;
+#endif
            }
-
-         /* ??? This is not mentioned in the MASM grammar.  */
-         else if (strcasecmp (new_token.str, "FLAT") == 0)
+       }
+      else
+       {
+         switch (fixp->fx_size)
            {
-             new_token.code = T_OFFSET;
-             if (*q == ':')
-               strcat (new_token.str, ":");
-             else
-               as_bad (_("`:' expected"));
+           default:
+             as_bad_where (fixp->fx_file, fixp->fx_line,
+                           _("can not do %d byte relocation"),
+                           fixp->fx_size);
+             code = BFD_RELOC_32;
+             break;
+           case 1: code = BFD_RELOC_8;  break;
+           case 2: code = BFD_RELOC_16; break;
+           case 4: code = BFD_RELOC_32; break;
+#ifdef BFD64
+           case 8: code = BFD_RELOC_64; break;
+#endif
            }
-
-         else
-           new_token.code = T_ID;
        }
+      break;
     }
 
-  else if (strchr ("+-/*%|&^:[]()~", *intel_parser.op_string))
+  if ((code == BFD_RELOC_32
+       || code == BFD_RELOC_32_PCREL
+       || code == BFD_RELOC_X86_64_32S)
+      && GOT_symbol
+      && fixp->fx_addsy == GOT_symbol)
     {
-      new_token.code = *intel_parser.op_string;
-      new_token.str[0] = *intel_parser.op_string;
-      new_token.str[1] = '\0';
+      if (!object_64bit)
+       code = BFD_RELOC_386_GOTPC;
+      else
+       code = BFD_RELOC_X86_64_GOTPC32;
     }
-
-  else if (strchr ("<>", *intel_parser.op_string)
-          && *intel_parser.op_string == *(intel_parser.op_string + 1))
+  if ((code == BFD_RELOC_64 || code == BFD_RELOC_64_PCREL)
+      && GOT_symbol
+      && fixp->fx_addsy == GOT_symbol)
     {
-      new_token.code = *intel_parser.op_string == '<' ? T_SHL : T_SHR;
-      new_token.str[0] = *intel_parser.op_string;
-      new_token.str[1] = *intel_parser.op_string;
-      new_token.str[2] = '\0';
+      code = BFD_RELOC_X86_64_GOTPC64;
     }
 
-  else
-    as_bad (_("Unrecognized token `%s'"), intel_parser.op_string);
+  rel = (arelent *) xmalloc (sizeof (arelent));
+  rel->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+  *rel->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
 
-  intel_parser.op_string += strlen (new_token.str);
-  cur_token = new_token;
-}
+  rel->address = fixp->fx_frag->fr_address + fixp->fx_where;
 
-/* Put cur_token back into the token stream and make cur_token point to
-   prev_token.  */
-static void
-intel_putback_token (void)
-{
-  if (cur_token.code != T_NIL)
+  if (!use_rela_relocations)
     {
-      intel_parser.op_string -= strlen (cur_token.str);
-      free (cur_token.str);
+      /* HACK: Since i386 ELF uses Rel instead of Rela, encode the
+        vtable entry to be used in the relocation's section offset.  */
+      if (fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
+       rel->address = fixp->fx_offset;
+#if defined (OBJ_COFF) && defined (TE_PE)
+      else if (fixp->fx_addsy && S_IS_WEAK (fixp->fx_addsy))
+       rel->addend = fixp->fx_addnumber - (S_GET_VALUE (fixp->fx_addsy) * 2);
+      else
+#endif
+      rel->addend = 0;
     }
-  cur_token = prev_token;
-
-  /* Forget prev_token.  */
-  prev_token.code = T_NIL;
-  prev_token.reg = NULL;
-  prev_token.str = NULL;
-}
-
-int
-tc_x86_regname_to_dw2regnum (char *regname)
-{
-  unsigned int regnum;
-  unsigned int regnames_count;
-  static const char *const regnames_32[] =
-    {
-      "eax", "ecx", "edx", "ebx",
-      "esp", "ebp", "esi", "edi",
-      "eip", "eflags", NULL,
-      "st0", "st1", "st2", "st3",
-      "st4", "st5", "st6", "st7",
-      NULL, NULL,
-      "xmm0", "xmm1", "xmm2", "xmm3",
-      "xmm4", "xmm5", "xmm6", "xmm7",
-      "mm0", "mm1", "mm2", "mm3",
-      "mm4", "mm5", "mm6", "mm7",
-      "fcw", "fsw", "mxcsr",
-      "es", "cs", "ss", "ds", "fs", "gs", NULL, NULL,
-      "tr", "ldtr"
-    };
-  static const char *const regnames_64[] =
-    {
-      "rax", "rdx", "rcx", "rbx",
-      "rsi", "rdi", "rbp", "rsp",
-      "r8",  "r9",  "r10", "r11",
-      "r12", "r13", "r14", "r15",
-      "rip",
-      "xmm0",  "xmm1",  "xmm2",  "xmm3",
-      "xmm4",  "xmm5",  "xmm6",  "xmm7",
-      "xmm8",  "xmm9",  "xmm10", "xmm11",
-      "xmm12", "xmm13", "xmm14", "xmm15",
-      "st0", "st1", "st2", "st3",
-      "st4", "st5", "st6", "st7",
-      "mm0", "mm1", "mm2", "mm3",
-      "mm4", "mm5", "mm6", "mm7",
-      "rflags",
-      "es", "cs", "ss", "ds", "fs", "gs", NULL, NULL,
-      "fs.base", "gs.base", NULL, NULL,
-      "tr", "ldtr",
-      "mxcsr", "fcw", "fsw"
-    };
-  const char *const *regnames;
-
-  if (flag_code == CODE_64BIT)
+  /* Use the rela in 64bit mode.  */
+  else
     {
-      regnames = regnames_64;
-      regnames_count = ARRAY_SIZE (regnames_64);
+      if (!fixp->fx_pcrel)
+       rel->addend = fixp->fx_offset;
+      else
+       switch (code)
+         {
+         case BFD_RELOC_X86_64_PLT32:
+         case BFD_RELOC_X86_64_GOT32:
+         case BFD_RELOC_X86_64_GOTPCREL:
+         case BFD_RELOC_X86_64_TLSGD:
+         case BFD_RELOC_X86_64_TLSLD:
+         case BFD_RELOC_X86_64_GOTTPOFF:
+         case BFD_RELOC_X86_64_GOTPC32_TLSDESC:
+         case BFD_RELOC_X86_64_TLSDESC_CALL:
+           rel->addend = fixp->fx_offset - fixp->fx_size;
+           break;
+         default:
+           rel->addend = (section->vma
+                          - fixp->fx_size
+                          + fixp->fx_addnumber
+                          + md_pcrel_from (fixp));
+           break;
+         }
     }
-  else
+
+  rel->howto = bfd_reloc_type_lookup (stdoutput, code);
+  if (rel->howto == NULL)
     {
-      regnames = regnames_32;
-      regnames_count = ARRAY_SIZE (regnames_32);
+      as_bad_where (fixp->fx_file, fixp->fx_line,
+                   _("cannot represent relocation type %s"),
+                   bfd_get_reloc_code_name (code));
+      /* Set howto to a garbage value so that we can keep going.  */
+      rel->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_32);
+      gas_assert (rel->howto != NULL);
     }
 
-  for (regnum = 0; regnum < regnames_count; regnum++)
-    if (regnames[regnum] != NULL
-       && strcmp (regname, regnames[regnum]) == 0)
-      return regnum;
+  return rel;
+}
+
+#include "tc-i386-intel.c"
 
-  return -1;
+void
+tc_x86_parse_to_dw2regnum (expressionS *exp)
+{
+  int saved_naked_reg;
+  char saved_register_dot;
+
+  saved_naked_reg = allow_naked_reg;
+  allow_naked_reg = 1;
+  saved_register_dot = register_chars['.'];
+  register_chars['.'] = '.';
+  allow_pseudo_reg = 1;
+  expression_and_evaluate (exp);
+  allow_pseudo_reg = 0;
+  register_chars['.'] = saved_register_dot;
+  allow_naked_reg = saved_naked_reg;
+
+  if (exp->X_op == O_register && exp->X_add_number >= 0)
+    {
+      if ((addressT) exp->X_add_number < i386_regtab_size)
+       {
+         exp->X_op = O_constant;
+         exp->X_add_number = i386_regtab[exp->X_add_number]
+                             .dw2_regnum[flag_code >> 1];
+       }
+      else
+       exp->X_op = O_illegal;
+    }
 }
 
 void
 tc_x86_frame_initial_instructions (void)
 {
-  static unsigned int sp_regno;
+  static unsigned int sp_regno[2];
+
+  if (!sp_regno[flag_code >> 1])
+    {
+      char *saved_input = input_line_pointer;
+      char sp[][4] = {"esp", "rsp"};
+      expressionS exp;
 
-  if (!sp_regno)
-    sp_regno = tc_x86_regname_to_dw2regnum (flag_code == CODE_64BIT
-                                           ? "rsp" : "esp");
+      input_line_pointer = sp[flag_code >> 1];
+      tc_x86_parse_to_dw2regnum (&exp);
+      gas_assert (exp.X_op == O_constant);
+      sp_regno[flag_code >> 1] = exp.X_add_number;
+      input_line_pointer = saved_input;
+    }
 
-  cfi_add_CFA_def_cfa (sp_regno, -x86_cie_data_alignment);
+  cfi_add_CFA_def_cfa (sp_regno[flag_code >> 1], -x86_cie_data_alignment);
   cfi_add_CFA_offset (x86_dwarf2_return_column, x86_cie_data_alignment);
 }
 
@@ -7903,6 +8509,15 @@ i386_elf_section_type (const char *str, size_t len)
   return -1;
 }
 
+#ifdef TE_SOLARIS
+void
+i386_solaris_fix_up_eh_frame (segT sec)
+{
+  if (flag_code == CODE_64BIT)
+    elf_section_type (sec) = SHT_X86_64_UNWIND;
+}
+#endif
+
 #ifdef TE_PE
 void
 tc_pe_dwarf2_emit_offset (symbolS *symbol, unsigned int size)
@@ -7919,7 +8534,7 @@ tc_pe_dwarf2_emit_offset (symbolS *symbol, unsigned int size)
 #if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
 /* For ELF on x86-64, add support for SHF_X86_64_LARGE.  */
 
-int
+bfd_vma
 x86_64_section_letter (int letter, char **ptr_msg)
 {
   if (flag_code == CODE_64BIT)
@@ -7934,7 +8549,7 @@ x86_64_section_letter (int letter, char **ptr_msg)
   return -1;
 }
 
-int
+bfd_vma
 x86_64_section_word (char *str, size_t len)
 {
   if (len == 5 && flag_code == CODE_64BIT && CONST_STRNEQ (str, "large"))