/* 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
Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
#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'
+/* 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 template *start;
+ const 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;
+
+/* The SSE5 instructions have a two bit instruction modifier (OC) that
+ is stored in two separate bytes in the instruction. Pick apart OC
+ into the 2 separate bits for instruction. */
+#define DREX_OC0(x) (((x) & 1) != 0)
+#define DREX_OC1(x) (((x) & 2) != 0)
+
+#define DREX_OC0_MASK (1 << 3) /* set OC0 in byte 4 */
+#define DREX_OC1_MASK (1 << 2) /* set OC1 in byte 3 */
+
+/* OC mappings */
+#define DREX_XMEM_X1_X2_X2 0 /* 4 op insn, dest = src3, src1 = reg/mem */
+#define DREX_X1_XMEM_X2_X2 1 /* 4 op insn, dest = src3, src2 = reg/mem */
+#define DREX_X1_XMEM_X2_X1 2 /* 4 op insn, dest = src1, src2 = reg/mem */
+#define DREX_X1_X2_XMEM_X1 3 /* 4 op insn, dest = src1, src3 = reg/mem */
+
+#define DREX_XMEM_X1_X2 0 /* 3 op insn, src1 = reg/mem */
+#define DREX_X1_XMEM_X2 1 /* 3 op insn, src1 = reg/mem */
+
+/* Information needed to create the DREX byte in SSE5 instructions. */
+typedef struct
+{
+ unsigned int reg; /* register */
+ unsigned int rex; /* REX flags */
+ unsigned int modrm_reg; /* which arg goes in the modrm.reg field */
+ unsigned int modrm_regmem; /* which arg goes in the modrm.regmem field */
+} drex_byte;
+
+/* 386 opcode byte to code indirect addressing. */
+typedef struct
+{
+ unsigned base;
+ unsigned index;
+ unsigned scale;
+}
+sib_byte;
+
+enum processor_type
+{
+ PROCESSOR_UNKNOWN,
+ PROCESSOR_I386,
+ PROCESSOR_I486,
+ PROCESSOR_PENTIUM,
+ PROCESSOR_PENTIUMPRO,
+ PROCESSOR_PENTIUM4,
+ PROCESSOR_NOCONA,
+ PROCESSOR_CORE,
+ PROCESSOR_CORE2,
+ PROCESSOR_K6,
+ PROCESSOR_ATHLON,
+ PROCESSOR_K8,
+ PROCESSOR_GENERIC32,
+ PROCESSOR_GENERIC64,
+ PROCESSOR_AMDFAM10
+};
+
+/* 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);
#endif
static void signed_cons (int);
static char *output_invalid (int c);
-static int i386_operand (char *);
+static int i386_att_operand (char *);
static int i386_intel_operand (char *, int);
static const reg_entry *parse_register (char *, char **);
static char *parse_insn (char *, char *);
/* TM holds the template for the insn were currently assembling. */
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. */
/* 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 fake index register, eiz/riz, is allowed . */
+/* 1 if pseudo index register, eiz/riz, is allowed . */
static int allow_index_reg = 0;
/* Register prefix used for error message. */
/* 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 i386_cpu_flags cpu_arch_flags = CPU_UNKNOWN_FLAGS;
-/* Bitwise NOT of cpu_arch_flags. */
-static i386_cpu_flags cpu_arch_flags_not;
-
/* If we have selected a cpu we are generating instructions for. */
static int cpu_arch_tune_set = 0;
static const arch_entry cpu_arch[] =
{
- {"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 },
- {"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 },
- {".mmx", PROCESSOR_UNKNOWN,
- CPU_MMX_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 },
- {".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 },
- {".sse5", PROCESSOR_UNKNOWN,
- CPU_SSE5_FLAGS },
+ { "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 },
+ { "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 },
+ { ".mmx", PROCESSOR_UNKNOWN,
+ CPU_MMX_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 },
+ { ".vmx", PROCESSOR_UNKNOWN,
+ CPU_VMX_FLAGS },
+ { ".smx", PROCESSOR_UNKNOWN,
+ CPU_SMX_FLAGS },
+ { ".xsave", PROCESSOR_UNKNOWN,
+ CPU_XSAVE_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 },
+ { ".sse5", PROCESSOR_UNKNOWN,
+ CPU_SSE5_FLAGS },
};
const pseudo_typeS md_pseudo_table[] =
}
static INLINE int
-uints_all_zero (const unsigned int *x, unsigned int size)
+operand_type_all_zero (const union i386_operand_type *x)
{
- switch (size)
+ switch (ARRAY_SIZE(x->array))
{
case 3:
- if (x[2])
+ if (x->array[2])
return 0;
case 2:
- if (x[1])
+ if (x->array[1])
return 0;
case 1:
- return !x[0];
+ return !x->array[0];
default:
abort ();
}
}
static INLINE void
-uints_set (unsigned int *x, unsigned int v, unsigned int size)
+operand_type_set (union i386_operand_type *x, unsigned int v)
{
- switch (size)
+ switch (ARRAY_SIZE(x->array))
{
case 3:
- x[2] = v;
+ x->array[2] = v;
case 2:
- x[1] = v;
+ x->array[1] = v;
case 1:
- x[0] = v;
+ x->array[0] = v;
break;
default:
abort ();
}
static INLINE int
-uints_equal (const unsigned int *x, const unsigned int *y,
- unsigned int size)
+operand_type_equal (const union i386_operand_type *x,
+ const union i386_operand_type *y)
{
- switch (size)
+ switch (ARRAY_SIZE(x->array))
{
case 3:
- if (x[2] != y [2])
+ if (x->array[2] != y->array[2])
return 0;
case 2:
- if (x[1] != y [1])
+ if (x->array[1] != y->array[1])
return 0;
case 1:
- return x[0] == y [0];
+ return x->array[0] == y->array[0];
break;
default:
abort ();
}
}
-#define UINTS_ALL_ZERO(x) \
- uints_all_zero ((x).array, ARRAY_SIZE ((x).array))
-#define UINTS_SET(x, v) \
- uints_set ((x).array, v, ARRAY_SIZE ((x).array))
-#define UINTS_CLEAR(x) \
- uints_set ((x).array, 0, ARRAY_SIZE ((x).array))
-#define UINTS_EQUAL(x, y) \
- uints_equal ((x).array, (y).array, ARRAY_SIZE ((x).array))
-
static INLINE int
-cpu_flags_check_cpu64 (i386_cpu_flags f)
+cpu_flags_all_zero (const union i386_cpu_flags *x)
{
- return !((flag_code == CODE_64BIT && f.bitfield.cpuno64)
- || (flag_code != CODE_64BIT && f.bitfield.cpu64));
+ 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 i386_cpu_flags
-cpu_flags_not (i386_cpu_flags x)
+static INLINE void
+cpu_flags_set (union i386_cpu_flags *x, unsigned int v)
{
- switch (ARRAY_SIZE (x.array))
+ switch (ARRAY_SIZE(x->array))
{
case 3:
- x.array [2] = ~x.array [2];
+ x->array[2] = v;
case 2:
- x.array [1] = ~x.array [1];
+ x->array[1] = v;
case 1:
- x.array [0] = ~x.array [0];
+ x->array[0] = v;
break;
default:
abort ();
}
+}
-#ifdef CpuUnused
- x.bitfield.unused = 0;
-#endif
+static INLINE int
+cpu_flags_equal (const union i386_cpu_flags *x,
+ const union i386_cpu_flags *y)
+{
+ 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 ();
+ }
+}
- return x;
+static INLINE int
+cpu_flags_check_cpu64 (i386_cpu_flags f)
+{
+ return !((flag_code == CODE_64BIT && f.bitfield.cpuno64)
+ || (flag_code != CODE_64BIT && f.bitfield.cpu64));
}
static INLINE i386_cpu_flags
return x;
}
+/* Return 3 if there is a perfect match, 2 if compatible with 64bit,
+ 1 if compatible with arch, 0 if there is no match. */
+
static int
cpu_flags_match (i386_cpu_flags x)
{
- i386_cpu_flags not = cpu_arch_flags_not;
-
- not.bitfield.cpu64 = 1;
- not.bitfield.cpuno64 = 1;
+ int overlap = cpu_flags_check_cpu64 (x) ? 2 : 0;
x.bitfield.cpu64 = 0;
x.bitfield.cpuno64 = 0;
- not = cpu_flags_and (x, not);
- return UINTS_ALL_ZERO (not);
+ if (cpu_flags_all_zero (&x))
+ overlap |= 1;
+ else
+ {
+ i386_cpu_flags cpu = cpu_arch_flags;
+
+ cpu.bitfield.cpu64 = 0;
+ cpu.bitfield.cpuno64 = 0;
+ cpu = cpu_flags_and (x, cpu);
+ overlap |= cpu_flags_all_zero (&cpu) ? 0 : 1;
+ }
+ return overlap;
}
static INLINE i386_operand_type
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;
}
}
+/* Return 1 if there is no conflict in 8bit/16bit/32bit/64bit on
+ operand J for instruction template T. */
+
+static INLINE int
+match_reg_size (const 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));
+}
+
+/* Return 1 if there is no conflict in any size on operand J for
+ instruction template T. */
+
+static INLINE int
+match_mem_size (const template *t, unsigned int j)
+{
+ 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)));
+}
+
+/* Return 1 if there is no size conflict on any operands for
+ instruction template T. */
+
+static INLINE int
+operand_size_match (const 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++)
+ {
+ if (t->operand_types[j].bitfield.anysize)
+ continue;
+
+ if (t->operand_types[j].bitfield.acc && !match_reg_size (t, j))
+ {
+ match = 0;
+ break;
+ }
+
+ if (i.types[j].bitfield.mem && !match_mem_size (t, j))
+ {
+ match = 0;
+ break;
+ }
+ }
+
+ if (match
+ || (!t->opcode_modifier.d && !t->opcode_modifier.floatd))
+ return match;
+
+ /* Check reverse. */
+ assert (i.operands == 2);
+
+ 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;
+ }
+ }
+
+ return match;
+}
+
static INLINE int
operand_type_match (i386_operand_type overlap,
i386_operand_type given)
i386_operand_type temp = overlap;
temp.bitfield.jumpabsolute = 0;
- if (UINTS_ALL_ZERO (temp))
+ 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;
+ if (operand_type_all_zero (&temp))
return 0;
return (given.bitfield.baseindex == overlap.bitfield.baseindex
&& given.bitfield.jumpabsolute == overlap.bitfield.jumpabsolute);
}
-/* If given types r0 and r1 are registers they must be of the same type
+/* 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. */
{
i386_operand_type t;
- UINTS_CLEAR (t);
+ operand_type_set (&t, 0);
t.bitfield.imm64 = 1;
if (cpu_arch_tune != PROCESSOR_I486 && num == 1)
{
cpu_arch_flags.bitfield.cpu64 = 1;
cpu_arch_flags.bitfield.cpuno64 = 0;
- cpu_arch_flags_not.bitfield.cpu64 = 0;
- cpu_arch_flags_not.bitfield.cpuno64 = 1;
}
else
{
cpu_arch_flags.bitfield.cpu64 = 0;
cpu_arch_flags.bitfield.cpuno64 = 1;
- cpu_arch_flags_not.bitfield.cpu64 = 1;
- cpu_arch_flags_not.bitfield.cpuno64 = 0;
}
if (value == CODE_64BIT && !cpu_arch_flags.bitfield.cpulm )
{
abort ();
cpu_arch_flags.bitfield.cpu64 = 0;
cpu_arch_flags.bitfield.cpuno64 = 1;
- cpu_arch_flags_not.bitfield.cpu64 = 1;
- cpu_arch_flags_not.bitfield.cpuno64 = 0;
stackop_size = LONG_MNEM_SUFFIX;
}
static void
set_intel_mnemonic (int mnemonic_flag)
{
- /* Find out if register prefixing is specified. */
- int ask_naked_reg = 0;
-
- SKIP_WHITESPACE ();
- if (!is_end_of_line[(unsigned char) *input_line_pointer])
- {
- char *string = input_line_pointer;
- int e = get_symbol_end ();
-
- 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;
- }
- demand_empty_rest_of_line ();
-
- /* intel_mnemonic implies intel_syntax. */
- intel_mnemonic = intel_syntax = mnemonic_flag;
-
- if (ask_naked_reg == 0)
- allow_naked_reg = (intel_mnemonic
- && (bfd_get_symbol_leading_char (stdoutput) != '\0'));
- else
- allow_naked_reg = (ask_naked_reg < 0);
-
- identifier_chars['%'] = intel_mnemonic && allow_naked_reg ? '%' : 0;
- identifier_chars['$'] = intel_mnemonic ? '$' : 0;
- register_prefix = allow_naked_reg ? "" : "%";
+ intel_mnemonic = mnemonic_flag;
}
static void
cpu_arch_flags.bitfield.cpu64 = 0;
cpu_arch_flags.bitfield.cpuno64 = 1;
}
- cpu_arch_flags_not = cpu_flags_not (cpu_arch_flags);
cpu_arch_isa = cpu_arch[i].type;
cpu_arch_isa_flags = cpu_arch[i].flags;
if (!cpu_arch_tune_set)
flags = cpu_flags_or (cpu_arch_flags,
cpu_arch[i].flags);
- if (!UINTS_EQUAL (flags, cpu_arch_flags))
+ if (!cpu_flags_equal (&flags, &cpu_arch_flags))
{
- cpu_sub_arch_name = cpu_arch[i].name;
+ 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;
- cpu_arch_flags_not = cpu_flags_not (cpu_arch_flags);
}
*input_line_pointer = e;
demand_empty_rest_of_line ();
{
const char *hash_err;
- cpu_arch_flags_not = cpu_flags_not (cpu_arch_flags);
-
/* Initialize op_hash hash table. */
op_hash = hash_new ();
return 1;
}
+static void
+process_immext (void)
+{
+ expressionS *exp;
+
+ if (i.tm.cpu_flags.bitfield.cpusse3 && i.operands > 0)
+ {
+ /* 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;
+
+ 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 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.
+
+ SSE5 also uses this encoding, for some of its 3 argument
+ instructions. */
+
+ assert (i.imm_operands == 0
+ && (i.operands <= 2
+ || (i.tm.cpu_flags.bitfield.cpusse5
+ && i.operands <= 3)));
+
+ 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;
+}
+
/* 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;
+md_assemble (char *line)
{
unsigned int j;
char mnemonic[MAX_MNEM_SIZE];
if (!match_template ())
return;
- if (intel_syntax)
+ /* 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)
{
- /* 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;
-
- /* 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)
- {
- if (i.reg_operands < 2
- && !i.suffix
- && (!i.tm.opcode_modifier.no_bsuf
- || !i.tm.opcode_modifier.no_wsuf
- || !i.tm.opcode_modifier.no_lsuf
- || !i.tm.opcode_modifier.no_ssuf
- || !i.tm.opcode_modifier.no_ldsuf
- || !i.tm.opcode_modifier.no_qsuf))
- as_bad (_("ambiguous operand size for `%s'"), i.tm.name);
+ /* 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;
- }
+ i.suffix = 0;
}
if (i.tm.opcode_modifier.fwait)
i.reg_operands--;
if (i.tm.opcode_modifier.immext)
- {
- expressionS *exp;
-
- if (i.tm.cpu_flags.bitfield.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.
- SSE5 also uses this encoding, for some of its 3 argument
- instructions. */
-
- assert (i.imm_operands == 0
- && (i.operands <= 2
- || (i.tm.cpu_flags.bitfield.cpusse5
- && i.operands <= 3)));
-
- exp = &im_expressions[i.imm_operands++];
- i.op[i.operands].imms = exp;
- UINTS_CLEAR (i.types[i.operands]);
- i.types[i.operands].bitfield.imm8 = 1;
- i.operands++;
- exp->X_op = O_constant;
- exp->X_add_number = i.tm.extension_opcode;
- i.tm.extension_opcode = None;
- }
+ process_immext ();
/* For insns with operands there are more diddles to do to the opcode. */
if (i.operands)
supported = 0;
for (t = current_templates->start; t < current_templates->end; ++t)
{
- if (cpu_flags_match (t->cpu_flags))
- supported |= 1;
- if (cpu_flags_check_cpu64 (t->cpu_flags))
- supported |= 2;
+ supported |= cpu_flags_match (t->cpu_flags);
+ if (supported == 3)
+ goto skip;
}
+
if (!(supported & 2))
{
as_bad (flag_code == CODE_64BIT
}
if (!(supported & 1))
{
- as_warn (_("`%s' is not supported on `%s%s'"),
- current_templates->start->name,
- cpu_arch_name,
- cpu_sub_arch_name ? cpu_sub_arch_name : "");
+ as_bad (_("`%s' is not supported on `%s%s'"),
+ current_templates->start->name, cpu_arch_name,
+ cpu_sub_arch_name ? cpu_sub_arch_name : "");
+ return NULL;
}
- else if (!cpu_arch_flags.bitfield.cpui386
+
+skip:
+ if (!cpu_arch_flags.bitfield.cpui386
&& (flag_code != CODE_16BIT))
{
as_warn (_("use .code16 to ensure correct addressing mode"));
{ /* 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)"),
i386_intel_operand (token_start,
intel_float_operand (mnemonic));
else
- operand_ok = i386_operand (token_start);
+ operand_ok = i386_att_operand (token_start);
RESTORE_END_STRING (l);
if (!operand_ok)
i386_operand_type mask, allowed;
const template *t;
- UINTS_CLEAR (mask);
- UINTS_CLEAR (allowed);
+ operand_type_set (&mask, 0);
+ operand_type_set (&allowed, 0);
for (t = current_templates->start;
t < current_templates->end;
break;
}
allowed = operand_type_and (mask, allowed);
- if (!UINTS_ALL_ZERO (allowed))
+ if (!operand_type_all_zero (&allowed))
i.types[op] = operand_type_and (i.types[op], mask);
}
break;
i386_operand_type operand_types [MAX_OPERANDS];
int addr_prefix_disp;
unsigned int j;
- i386_cpu_flags overlap;
+ unsigned int found_cpu_match;
+ unsigned int check_register;
#if MAX_OPERANDS != 4
# error "MAX_OPERANDS must be 4."
if (i.operands != t->operands)
continue;
- /* Check AT&T mnemonic and old gcc support. */
- if (t->opcode_modifier.attmnemonic
- && (intel_mnemonic
- || (!old_gcc
- && t->opcode_modifier.oldgcc)))
+ /* Check processor support. */
+ found_cpu_match = cpu_flags_match (t->cpu_flags) == 3;
+ if (!found_cpu_match)
+ continue;
+
+ /* Check old gcc support. */
+ if (!old_gcc && t->opcode_modifier.oldgcc)
+ continue;
+
+ /* Check AT&T mnemonic. */
+ if (intel_mnemonic && t->opcode_modifier.attmnemonic)
continue;
- /* Check Intel mnemonic. */
- if (!intel_mnemonic && t->opcode_modifier.intelmnemonic)
+ /* 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. */
|| (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];
+ 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
|| 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;
+
/* Do not verify operands when there are none. */
- else
+ else
{
- overlap = cpu_flags_and (t->cpu_flags, cpu_arch_flags_not);
if (!t->operands)
- {
- if (!UINTS_ALL_ZERO (overlap))
- continue;
- /* We've found a match; break out of loop. */
- break;
- }
+ /* We've found a match; break out of loop. */
+ break;
}
/* Address size prefix will turn Disp64/Disp32/Disp16 operand
}
}
+ /* 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)
{
zero-extend %eax to %rax. */
if (flag_code == CODE_64BIT
&& t->base_opcode == 0x90
- && UINTS_EQUAL (i.types [0], acc32)
- && UINTS_EQUAL (i.types [1], acc32))
+ && operand_type_equal (&i.types [0], &acc32)
+ && operand_type_equal (&i.types [1], &acc32))
continue;
case 3:
case 4:
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])
- /* 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. It is
- also true for invlpga, vmload, vmrun and vmsave in
- SVME. */
- || !((t->base_opcode == 0x0f01
- && (t->extension_opcode == 0xc8
- || t->extension_opcode == 0xd8
- || t->extension_opcode == 0xda
- || t->extension_opcode == 0xdb
- || t->extension_opcode == 0xdf))
- || t->base_opcode == 0xf20f38f1
- || operand_type_register_match (overlap0, i.types[0],
+ || (check_register
+ && !operand_type_register_match (overlap0, i.types[0],
operand_types[0],
overlap1, i.types[1],
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])
- || !operand_type_register_match (overlap0, i.types[0],
- operand_types[1],
- overlap1, i.types[1],
- operand_types[0]))
+ || (check_register
+ && !operand_type_register_match (overlap0,
+ i.types[0],
+ operand_types[1],
+ overlap1,
+ i.types[1],
+ operand_types[0])))
{
/* Does not match either direction. */
continue;
{
case 4:
if (!operand_type_match (overlap3, i.types[3])
- || !operand_type_register_match (overlap2,
- i.types[2],
- operand_types[2],
- overlap3,
- i.types[3],
- operand_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
operand instructions only need to be checked for
register consistency between operands 2 and 3. */
if (!operand_type_match (overlap2, i.types[2])
- || !operand_type_register_match (overlap1,
- i.types[1],
- operand_types[1],
- overlap2,
- i.types[2],
- operand_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 (!UINTS_ALL_ZERO (overlap))
+ if (!found_cpu_match)
{
found_reverse_match = 0;
continue;
if (!check_word_reg ())
return 0;
}
+ else if (i.suffix == XMMWORD_MNEM_SUFFIX)
+ {
+ /* Skip if the instruction has x 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. */
;
suffixes |= 1 << 1;
if (!i.tm.opcode_modifier.no_lsuf)
suffixes |= 1 << 2;
- if (!i.tm.opcode_modifier.no_lsuf)
+ if (!i.tm.opcode_modifier.no_ldsuf)
suffixes |= 1 << 3;
if (!i.tm.opcode_modifier.no_ssuf)
suffixes |= 1 << 4;
/* 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)
+ if (i.suffix
+ && i.suffix != BYTE_MNEM_SUFFIX
+ && i.suffix != XMMWORD_MNEM_SUFFIX)
{
/* It's not a byte, select word/dword operation. */
if (i.tm.opcode_modifier.w)
if (! (i.operands == 2
&& i.tm.base_opcode == 0x90
&& i.tm.extension_opcode == None
- && UINTS_EQUAL (i.types [0], acc64)
- && UINTS_EQUAL (i.types [1], acc64))
+ && 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
|| overlap.bitfield.imm32
|| overlap.bitfield.imm32s
|| overlap.bitfield.imm64)
- && !UINTS_EQUAL (overlap, imm8)
- && !UINTS_EQUAL (overlap, imm8s)
- && !UINTS_EQUAL (overlap, imm16)
- && !UINTS_EQUAL (overlap, imm32)
- && !UINTS_EQUAL (overlap, imm32s)
- && !UINTS_EQUAL (overlap, imm64))
+ && !operand_type_equal (&overlap, &imm8)
+ && !operand_type_equal (&overlap, &imm8s)
+ && !operand_type_equal (&overlap, &imm16)
+ && !operand_type_equal (&overlap, &imm32)
+ && !operand_type_equal (&overlap, &imm32s)
+ && !operand_type_equal (&overlap, &imm64))
{
if (i.suffix)
{
i386_operand_type temp;
- UINTS_CLEAR (temp);
+ operand_type_set (&temp, 0);
if (i.suffix == BYTE_MNEM_SUFFIX)
{
temp.bitfield.imm8 = overlap.bitfield.imm8;
temp.bitfield.imm32 = overlap.bitfield.imm32;
overlap = temp;
}
- else if (UINTS_EQUAL (overlap, imm16_32_32s)
- || UINTS_EQUAL (overlap, imm16_32)
- || UINTS_EQUAL (overlap, imm16_32s))
+ else if (operand_type_equal (&overlap, &imm16_32_32s)
+ || operand_type_equal (&overlap, &imm16_32)
+ || operand_type_equal (&overlap, &imm16_32s))
{
- UINTS_CLEAR (overlap);
if ((flag_code == CODE_16BIT) ^ (i.prefix[DATA_PREFIX] != 0))
- overlap.bitfield.imm16 = 1;
+ overlap = imm16;
else
- overlap.bitfield.imm32s = 1;
+ overlap = imm32s;
}
- if (!UINTS_EQUAL (overlap, imm8)
- && !UINTS_EQUAL (overlap, imm8s)
- && !UINTS_EQUAL (overlap, imm16)
- && !UINTS_EQUAL (overlap, imm32)
- && !UINTS_EQUAL (overlap, imm32s)
- && !UINTS_EQUAL (overlap, imm64))
+ 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"));
static void
process_drex (void)
{
- i.drex.modrm_reg = None;
- i.drex.modrm_regmem = None;
+ i.drex.modrm_reg = 0;
+ i.drex.modrm_regmem = 0;
/* SSE5 4 operand instructions must have the destination the same as
one of the inputs. Figure out the destination register and cache
&& i.op[0].regs->reg_flags == i.op[3].regs->reg_flags)
{
/* Clear the arguments that are stored in drex. */
- UINTS_CLEAR (i.types[0]);
- UINTS_CLEAR (i.types[3]);
+ operand_type_set (&i.types[0], 0);
+ operand_type_set (&i.types[3], 0);
i.reg_operands -= 2;
/* There are two different ways to encode a 4 operand
&& i.op[0].regs->reg_flags == i.op[3].regs->reg_flags)
{
/* clear the arguments that are stored in drex */
- UINTS_CLEAR (i.types[0]);
- UINTS_CLEAR (i.types[3]);
+ operand_type_set (&i.types[0], 0);
+ operand_type_set (&i.types[3], 0);
i.reg_operands -= 2;
/* Specify the modrm encoding for memory addressing. Include
&& i.op[0].regs->reg_flags == i.op[3].regs->reg_flags)
{
/* Clear the arguments that are stored in drex. */
- UINTS_CLEAR (i.types[0]);
- UINTS_CLEAR (i.types[3]);
+ operand_type_set (&i.types[0], 0);
+ operand_type_set (&i.types[3], 0);
i.reg_operands -= 2;
/* Specify the modrm encoding for memory addressing. Include
&& i.op[2].regs->reg_flags == i.op[3].regs->reg_flags)
{
/* clear the arguments that are stored in drex */
- UINTS_CLEAR (i.types[2]);
- UINTS_CLEAR (i.types[3]);
+ operand_type_set (&i.types[2], 0);
+ operand_type_set (&i.types[3], 0);
i.reg_operands -= 2;
/* There are two different ways to encode a 4 operand
&& i.op[2].regs->reg_flags == i.op[3].regs->reg_flags)
{
/* Clear the arguments that are stored in drex. */
- UINTS_CLEAR (i.types[2]);
- UINTS_CLEAR (i.types[3]);
+ operand_type_set (&i.types[2], 0);
+ operand_type_set (&i.types[3], 0);
i.reg_operands -= 2;
/* Specify the modrm encoding and remember the register
&& i.op[2].regs->reg_flags == i.op[3].regs->reg_flags)
{
/* clear the arguments that are stored in drex */
- UINTS_CLEAR (i.types[2]);
- UINTS_CLEAR (i.types[3]);
+ operand_type_set (&i.types[2], 0);
+ operand_type_set (&i.types[3], 0);
i.reg_operands -= 2;
/* Specify the modrm encoding and remember the register
&& i.op[0].regs->reg_flags == i.op[3].regs->reg_flags)
{
/* clear the arguments that are stored in drex */
- UINTS_CLEAR (i.types[0]);
- UINTS_CLEAR (i.types[3]);
+ operand_type_set (&i.types[0], 0);
+ operand_type_set (&i.types[3], 0);
i.reg_operands -= 2;
/* Specify the modrm encoding and remember the register
&& i.types[2].bitfield.regxmm != 0)
{
/* Clear the arguments that are stored in drex. */
- UINTS_CLEAR (i.types[2]);
+ operand_type_set (&i.types[2], 0);
i.reg_operands--;
/* Specify the modrm encoding and remember the register
&& i.types[2].bitfield.regxmm != 0)
{
/* Clear the arguments that are stored in drex. */
- UINTS_CLEAR (i.types[2]);
+ operand_type_set (&i.types[2], 0);
i.reg_operands--;
/* Specify the modrm encoding and remember the register
&& i.types[2].bitfield.regxmm != 0)
{
/* Clear the arguments that are stored in drex. */
- UINTS_CLEAR (i.types[2]);
+ operand_type_set (&i.types[2], 0);
i.reg_operands--;
/* Specify the modrm encoding and remember the register
&& i.types[3].bitfield.regxmm != 0)
{
/* clear the arguments that are stored in drex */
- UINTS_CLEAR (i.types[3]);
+ operand_type_set (&i.types[3], 0);
i.reg_operands--;
/* Specify the modrm encoding and remember the register
&& operand_type_check (i.types[3], imm) != 0)
{
/* clear the arguments that are stored in drex */
- UINTS_CLEAR (i.types[2]);
+ operand_type_set (&i.types[2], 0);
i.reg_operands--;
/* Specify the modrm encoding and remember the register
unsigned int j;
/* The first operand is implicit and must be xmm0. */
- assert (i.reg_operands && UINTS_EQUAL (i.types[0], regxmm));
+ assert (i.reg_operands
+ && operand_type_equal (&i.types[0], ®xmm));
if (i.op[0].regs->reg_num != 0)
{
if (intel_syntax)
&& operand_type_check (i.types[op], disp))
{
i386_operand_type temp;
- UINTS_CLEAR (temp);
+ operand_type_set (&temp, 0);
temp.bitfield.disp8 = i.types[op].bitfield.disp8;
i.types[op] = temp;
if (i.prefix[ADDR_PREFIX] == 0)
expressionS *exp;
i386_operand_type types;
- UINTS_SET (types, ~0);
+ operand_type_set (&types, ~0);
if (i.imm_operands == MAX_IMMEDIATE_OPERANDS)
{
return 0;
}
- UINTS_CLEAR (bigdisp);
+ operand_type_set (&bigdisp, 0);
if ((i.types[this_operand].bitfield.jumpabsolute)
|| (!current_templates->start->opcode_modifier.jump
&& !current_templates->start->opcode_modifier.jumpdword))
bigdisp.bitfield.disp32 = 0;
bigdisp.bitfield.disp32s = 0;
bigdisp.bitfield.disp64 = 0;
- if (UINTS_ALL_ZERO (bigdisp))
+ if (operand_type_all_zero (&bigdisp))
i.types[this_operand] = operand_type_and (i.types[this_operand],
types);
on error. */
static int
-i386_operand (char *operand_string)
+i386_att_operand (char *operand_string)
{
const reg_entry *r;
char *end_op;
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++;
}
/* Special case for (%dx) while doing input/output op. */
if (i.base_reg
- && UINTS_EQUAL (i.base_reg->reg_type, reg16_inoutportreg)
+ && operand_type_equal (&i.base_reg->reg_type,
+ ®16_inoutportreg)
&& i.index_reg == 0
&& i.log2_scale_factor == 0
&& i.seg[i.mem_operands] == 0
&& !operand_type_check (i.types[this_operand], disp))
{
- UINTS_CLEAR (i.types[this_operand]);
- i.types[this_operand].bitfield.inoutportreg = 1;
+ i.types[this_operand] = inoutportreg;
return 1;
}
if (i386_index_check (operand_string) == 0)
return 0;
+ i.types[this_operand].bitfield.mem = 1;
i.mem_operands++;
}
else
}
}
+ if (r == NULL || allow_pseudo_reg)
+ return r;
+
+ if (operand_type_all_zero (&r->reg_type))
+ return (const reg_entry *) NULL;
+
+ 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;
+
+ if (r->reg_type.bitfield.regmmx && !cpu_arch_flags.bitfield.cpummx)
+ return (const reg_entry *) NULL;
+
+ if (r->reg_type.bitfield.regxmm && !cpu_arch_flags.bitfield.cpusse)
+ return (const reg_entry *) NULL;
+
/* Don't allow fake index register unless allow_index_reg isn't 0. */
- if (r != NULL
- && !allow_index_reg
+ if (!allow_index_reg
&& (r->reg_num == RegEiz || r->reg_num == RegRiz))
return (const reg_entry *) NULL;
- if (r != NULL
- && ((r->reg_flags & (RegRex64 | RegRex))
- || r->reg_type.bitfield.reg64)
+ if (((r->reg_flags & (RegRex64 | RegRex))
+ || r->reg_type.bitfield.reg64)
&& (!cpu_arch_flags.bitfield.cpulm
- || !UINTS_EQUAL (r->reg_type, control))
+ || !operand_type_equal (&r->reg_type, &control))
&& flag_code != CODE_64BIT)
return (const reg_entry *) NULL;
+ if (r->reg_type.bitfield.sreg3 && r->reg_num == RegFlat && !intel_syntax)
+ return (const reg_entry *) NULL;
+
return r;
}
md_parse_option (int c, char *arg)
{
unsigned int i;
+ char *arch, *next;
switch (c)
{
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)
+ 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++)
{
- cpu_arch_isa = cpu_arch[i].type;
- cpu_arch_isa_flags = cpu_arch[i].flags;
- if (!cpu_arch_tune_set)
+ 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)
{
- cpu_arch_tune = cpu_arch_isa;
- cpu_arch_tune_flags = cpu_arch_isa_flags;
+ /* ISA entension. */
+ i386_cpu_flags flags;
+ flags = cpu_flags_or (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;
}
- break;
}
+
+ if (i >= ARRAY_SIZE (cpu_arch))
+ as_fatal (_("Invalid -march= option: `%s'"), arg);
+
+ arch = next;
}
- if (i >= ARRAY_SIZE (cpu_arch))
- as_fatal (_("Invalid -march= option: `%s'"), arg);
+ while (next != NULL );
break;
case OPTION_MTUNE:
case OPTION_MOLD_GCC:
old_gcc = 1;
- intel_mnemonic = 0;
break;
default:
--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"));
-
+ -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, k6, k6_2, athlon, k8, amdfam10,\n\
+ generic32, generic64\n\
+ EXTENSION is combination of:\n\
+ mmx, sse, sse2, sse3, ssse3, sse4.1, sse4.2, sse4,\n\
+ vmx, smx, xsave, 3dnow, 3dnowa, sse4a, sse5, svme,\n\
+ abm, padlock\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, k6, k6_2, athlon, k8, amdfam10,\n\
+ generic32, generic64\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"));
}
#if ((defined (OBJ_MAYBE_COFF) && defined (OBJ_MAYBE_AOUT)) \
if (!strcmp (default_arch, "x86_64"))
{
set_code_flag (CODE_64BIT);
- if (UINTS_ALL_ZERO (cpu_arch_isa_flags))
+ 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.cpui686 = 1;
cpu_arch_isa_flags.bitfield.cpup4 = 1;
cpu_arch_isa_flags.bitfield.cpummx= 1;
- cpu_arch_isa_flags.bitfield.cpummx2 = 1;
cpu_arch_isa_flags.bitfield.cpusse = 1;
cpu_arch_isa_flags.bitfield.cpusse2 = 1;
}
- if (UINTS_ALL_ZERO (cpu_arch_tune_flags))
+ 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.cpui686 = 1;
cpu_arch_tune_flags.bitfield.cpup4 = 1;
cpu_arch_tune_flags.bitfield.cpummx= 1;
- cpu_arch_tune_flags.bitfield.cpummx2 = 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 (UINTS_ALL_ZERO (cpu_arch_isa_flags))
+ 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 (UINTS_ALL_ZERO (cpu_arch_tune_flags))
+ if (cpu_flags_all_zero (&cpu_arch_tune_flags))
{
cpu_arch_tune_flags.bitfield.cpui186 = 1;
cpu_arch_tune_flags.bitfield.cpui286 = 1;
else
{
char *s = intel_parser.disp;
+ i.types[this_operand].bitfield.mem = 1;
i.mem_operands++;
if (!quiet_warnings && intel_parser.is_mem < 0)
/* 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 (i.mem_operands < 2 && i.seg[i.mem_operands])
+ {
+ if (!(intel_parser.op_modifier & (1 << T_OFFSET)))
+ as_warn (_("Segment override ignored"));
+ i.seg[i.mem_operands] = NULL;
+ }
+ ret = i386_immediate (intel_parser.disp);
+ }
if (intel_parser.next_operand && this_operand >= MAX_OPERANDS - 1)
ret = 0;
break;
intel_parser.op_string = intel_parser.next_operand;
this_operand = i.operands++;
+ i.types[this_operand].bitfield.unspecified = 1;
}
free (p);
char suffix;
if (prev_token.code == T_BYTE)
- suffix = BYTE_MNEM_SUFFIX;
+ {
+ suffix = BYTE_MNEM_SUFFIX;
+ i.types[this_operand].bitfield.byte = 1;
+ }
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)
+ if ((current_templates->start->name[0] == 'l'
+ && current_templates->start->name[2] == 's'
+ && current_templates->start->name[3] == 0)
+ || current_templates->start->base_opcode == 0x62 /* bound */)
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;
+ i.types[this_operand].bitfield.word = 1;
}
else if (prev_token.code == T_DWORD)
{
- if (current_templates->start->name[0] == 'l'
- && current_templates->start->name[2] == 's'
- && current_templates->start->name[3] == 0)
+ if ((current_templates->start->name[0] == 'l'
+ && current_templates->start->name[2] == 's'
+ && current_templates->start->name[3] == 0)
+ || current_templates->start->base_opcode == 0x62 /* bound */)
suffix = WORD_MNEM_SUFFIX;
else if (flag_code == CODE_16BIT
&& (current_templates->start->opcode_modifier.jump
suffix = SHORT_MNEM_SUFFIX;
else
suffix = LONG_MNEM_SUFFIX;
+ i.types[this_operand].bitfield.dword = 1;
}
else if (prev_token.code == T_FWORD)
}
else
suffix = BYTE_MNEM_SUFFIX; /* so it will cause an error */
+ i.types[this_operand].bitfield.fword = 1;
}
else if (prev_token.code == T_QWORD)
{
- if (intel_parser.got_a_float == 1) /* "f..." */
+ if (current_templates->start->base_opcode == 0x62 /* bound */
+ || intel_parser.got_a_float == 1) /* "f..." */
suffix = LONG_MNEM_SUFFIX;
else
suffix = QWORD_MNEM_SUFFIX;
+ i.types[this_operand].bitfield.qword = 1;
}
else if (prev_token.code == T_TBYTE)
else if (prev_token.code == T_XMMWORD)
{
- /* XXX ignored for now, but accepted since gcc uses it */
- suffix = 0;
+ suffix = XMMWORD_MNEM_SUFFIX;
+ i.types[this_operand].bitfield.xmmword = 1;
}
else
return 0;
}
+ i.types[this_operand].bitfield.unspecified = 0;
+
/* Operands for jump/call using 'ptr' notation denote absolute
addresses. */
if (current_templates->start->opcode_modifier.jump
reg->reg_name);
return 0;
}
+ else if (i.mem_operands >= 2)
+ as_warn (_("Segment override ignored"));
else if (i.seg[i.mem_operands])
as_warn (_("Extra segment override ignored"));
else
}
}
+ else if (reg->reg_type.bitfield.sreg3 && reg->reg_num == RegFlat)
+ {
+ as_bad (_("cannot use `FLAT' here"));
+ return 0;
+ }
+
/* Not a segment register. Check for register scaling. */
else if (cur_token.code == '*')
{
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 = reg;
i.reg_operands++;
}
strcat (new_token.str, " FLAT:");
}
- /* ??? This is not mentioned in the MASM grammar. */
- else if (strcasecmp (new_token.str, "FLAT") == 0)
- {
- new_token.code = T_OFFSET;
- if (*q == ':')
- strcat (new_token.str, ":");
- else
- as_bad (_("`:' expected"));
- }
-
else
new_token.code = T_ID;
}
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;
+void
+tc_x86_parse_to_dw2regnum (expressionS *exp)
+{
+ int saved_naked_reg;
+ char saved_register_dot;
- if (flag_code == CODE_64BIT)
- {
- regnames = regnames_64;
- regnames_count = ARRAY_SIZE (regnames_64);
- }
- else
+ 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)
{
- regnames = regnames_32;
- regnames_count = ARRAY_SIZE (regnames_32);
+ 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;
}
-
- for (regnum = 0; regnum < regnames_count; regnum++)
- if (regnames[regnum] != NULL
- && strcmp (regname, regnames[regnum]) == 0)
- return regnum;
-
- return -1;
}
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);
+ 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);
}