X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;ds=sidebyside;f=gas%2Fconfig%2Ftc-i386.c;h=80a1ac836683601914fb350358dc3b363e951eaf;hb=192dc9c6fdb23ca962c3be3053dda8753dc0b065;hp=222ab099bbc0f16e1d341438ea1d4b3e09a07637;hpb=fc4adea1ba8fa8abe3c0a78ebb64e8aefec1bc4b;p=platform%2Fupstream%2Fbinutils.git diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c index 222ab09..80a1ac8 100644 --- a/gas/config/tc-i386.c +++ b/gas/config/tc-i386.c @@ -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 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. @@ -55,6 +55,128 @@ #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); @@ -66,7 +188,7 @@ 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_att_operand (char *); static int i386_intel_operand (char *, int); static const reg_entry *parse_register (char *, char **); static char *parse_insn (char *, char *); @@ -113,8 +235,8 @@ struct _i386_insn /* 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. */ @@ -291,6 +413,9 @@ 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; @@ -313,14 +438,11 @@ 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 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; @@ -430,92 +552,98 @@ const relax_typeS md_relax_table[] = 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[] = @@ -896,34 +1024,34 @@ i386_align_code (fragS *fragP, int count) } 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 (); @@ -931,62 +1059,85 @@ uints_set (unsigned int *x, unsigned int v, unsigned int size) } 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 @@ -1025,19 +1176,29 @@ cpu_flags_or (i386_cpu_flags x, i386_cpu_flags y) 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 @@ -1097,6 +1258,8 @@ operand_type_xor (i386_operand_type x, i386_operand_type y) 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; @@ -1163,6 +1326,102 @@ operand_type_check (i386_operand_type t, enum operand_type c) } } +/* 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) @@ -1170,14 +1429,22 @@ operand_type_match (i386_operand_type overlap, 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. */ @@ -1286,7 +1553,7 @@ smallest_imm_type (offsetT num) { i386_operand_type t; - UINTS_CLEAR (t); + operand_type_set (&t, 0); t.bitfield.imm64 = 1; if (cpu_arch_tune != PROCESSOR_I486 && num == 1) @@ -1445,15 +1712,11 @@ set_code_flag (int value) { 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 ) { @@ -1474,8 +1737,6 @@ set_16bit_gcc_code_flag (int new_code_flag) 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; } @@ -1517,37 +1778,7 @@ set_intel_syntax (int syntax_flag) 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 @@ -1587,7 +1818,6 @@ set_cpu_arch (int dummy ATTRIBUTE_UNUSED) 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) @@ -1600,11 +1830,19 @@ set_cpu_arch (int dummy ATTRIBUTE_UNUSED) 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 (); @@ -1655,8 +1893,6 @@ md_begin () { const char *hash_err; - cpu_arch_flags_not = cpu_flags_not (cpu_arch_flags); - /* Initialize op_hash hash table. */ op_hash = hash_new (); @@ -2159,13 +2395,56 @@ intel_float_operand (const char *mnemonic) 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]; @@ -2229,30 +2508,20 @@ md_assemble (line) 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) @@ -2285,48 +2554,7 @@ md_assemble (line) 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) @@ -2582,11 +2810,11 @@ parse_insn (char *line, char *mnemonic) 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 @@ -2597,12 +2825,14 @@ parse_insn (char *line, char *mnemonic) } 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")); @@ -2701,6 +2931,7 @@ parse_operands (char *l, const char *mnemonic) { /* 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)"), @@ -2715,7 +2946,7 @@ parse_operands (char *l, const char *mnemonic) 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) @@ -2904,8 +3135,8 @@ optimize_imm (void) 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; @@ -2931,7 +3162,7 @@ optimize_imm (void) 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; @@ -3025,7 +3256,8 @@ match_template (void) 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." @@ -3047,8 +3279,6 @@ match_template (void) suffix_check.no_qsuf = 1; else if (i.suffix == LONG_DOUBLE_MNEM_SUFFIX) suffix_check.no_ldsuf = 1; - else if (i.suffix == XMMWORD_MNEM_SUFFIX) - suffix_check.no_xsuf = 1; for (t = current_templates->start; t < current_templates->end; t++) { @@ -3058,15 +3288,22 @@ match_template (void) 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 Intel mnemonic. */ - if (!intel_mnemonic && t->opcode_modifier.intelmnemonic) + /* 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. */ @@ -3079,20 +3316,11 @@ match_template (void) || (t->opcode_modifier.no_ldsuf && suffix_check.no_ldsuf))) continue; - /* Check the memory size in Intel mode when it is provided if - needed. */ - if (intel_syntax - && i.suffix - && t->opcode_modifier.checksize - && (!t->opcode_modifier.byte || !suffix_check.no_bsuf) - && (!t->opcode_modifier.word || !suffix_check.no_wsuf) - && (!t->opcode_modifier.dword || !suffix_check.no_lsuf) - && (!t->opcode_modifier.qword || !suffix_check.no_qsuf) - && (!t->opcode_modifier.xmmword || !suffix_check.no_xsuf)) + 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 @@ -3109,17 +3337,25 @@ match_template (void) || 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 @@ -3168,6 +3404,9 @@ match_template (void) } } + /* 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) { @@ -3182,27 +3421,16 @@ match_template (void) 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]))) @@ -3216,10 +3444,13 @@ match_template (void) 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; @@ -3253,12 +3484,13 @@ match_template (void) { 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 @@ -3266,12 +3498,13 @@ match_template (void) 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; } @@ -3279,7 +3512,7 @@ match_template (void) /* 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; @@ -3608,8 +3841,8 @@ process_suffix (void) 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 @@ -3875,18 +4108,18 @@ update_imm (unsigned int j) || 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; @@ -3903,22 +4136,21 @@ update_imm (unsigned int j) 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")); @@ -3948,8 +4180,8 @@ finalize_imm (void) 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 @@ -3970,8 +4202,8 @@ process_drex (void) && 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 @@ -3998,8 +4230,8 @@ process_drex (void) && 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 @@ -4021,8 +4253,8 @@ process_drex (void) && 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 @@ -4044,8 +4276,8 @@ process_drex (void) && 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 @@ -4074,8 +4306,8 @@ process_drex (void) && 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 @@ -4096,8 +4328,8 @@ process_drex (void) && 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 @@ -4131,8 +4363,8 @@ process_drex (void) && 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 @@ -4164,7 +4396,7 @@ process_drex (void) && 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 @@ -4182,7 +4414,7 @@ process_drex (void) && 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 @@ -4201,7 +4433,7 @@ process_drex (void) && 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 @@ -4231,7 +4463,7 @@ process_drex (void) && 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 @@ -4253,7 +4485,7 @@ process_drex (void) && 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 @@ -4294,7 +4526,8 @@ process_operands (void) 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) @@ -4661,7 +4894,7 @@ build_modrm_byte (void) && 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) @@ -5673,7 +5906,7 @@ i386_immediate (char *imm_start) expressionS *exp; i386_operand_type types; - UINTS_SET (types, ~0); + operand_type_set (&types, ~0); if (i.imm_operands == MAX_IMMEDIATE_OPERANDS) { @@ -5825,7 +6058,7 @@ i386_displacement (char *disp_start, char *disp_end) 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)) @@ -6006,7 +6239,7 @@ i386_displacement (char *disp_start, char *disp_end) 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); @@ -6112,7 +6345,7 @@ i386_index_check (const char *operand_string) on error. */ static int -i386_operand (char *operand_string) +i386_att_operand (char *operand_string) { const reg_entry *r; char *end_op; @@ -6199,6 +6432,7 @@ i386_operand (char *operand_string) 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++; } @@ -6378,19 +6612,20 @@ i386_operand (char *operand_string) /* 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 @@ -6886,20 +7121,41 @@ parse_real_register (char *reg_string, char **end_op) } } + 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; } @@ -7017,6 +7273,7 @@ int md_parse_option (int c, char *arg) { unsigned int i; + char *arch, *next; switch (c) { @@ -7092,24 +7349,62 @@ md_parse_option (int c, char *arg) 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) { - cpu_arch_tune = cpu_arch_isa; - cpu_arch_tune_flags = cpu_arch_isa_flags; + /* 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; + 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: @@ -7157,7 +7452,6 @@ md_parse_option (int c, char *arg) case OPTION_MOLD_GCC: old_gcc = 1; - intel_mnemonic = 0; break; default: @@ -7195,9 +7489,22 @@ md_show_usage (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")); + -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, _("\ @@ -7221,7 +7528,7 @@ i386_target_format (void) 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; @@ -7231,11 +7538,10 @@ i386_target_format (void) 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; @@ -7245,7 +7551,6 @@ i386_target_format (void) 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; } @@ -7253,13 +7558,13 @@ i386_target_format (void) 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; @@ -7873,6 +8178,7 @@ i386_intel_operand (char *operand_string, int got_a_float) else { char *s = intel_parser.disp; + i.types[this_operand].bitfield.mem = 1; i.mem_operands++; if (!quiet_warnings && intel_parser.is_mem < 0) @@ -7907,7 +8213,15 @@ i386_intel_operand (char *operand_string, int got_a_float) /* 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; @@ -7915,6 +8229,7 @@ i386_intel_operand (char *operand_string, int got_a_float) break; intel_parser.op_string = intel_parser.next_operand; this_operand = i.operands++; + i.types[this_operand].bitfield.unspecified = 1; } free (p); @@ -8123,25 +8438,31 @@ intel_e09 (void) 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 @@ -8151,6 +8472,7 @@ intel_e09 (void) suffix = SHORT_MNEM_SUFFIX; else suffix = LONG_MNEM_SUFFIX; + i.types[this_operand].bitfield.dword = 1; } else if (prev_token.code == T_FWORD) @@ -8167,14 +8489,17 @@ intel_e09 (void) } 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) @@ -8188,6 +8513,7 @@ intel_e09 (void) else if (prev_token.code == T_XMMWORD) { suffix = XMMWORD_MNEM_SUFFIX; + i.types[this_operand].bitfield.xmmword = 1; } else @@ -8196,6 +8522,8 @@ intel_e09 (void) 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 @@ -8427,6 +8755,8 @@ intel_e11 (void) 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 @@ -8457,6 +8787,12 @@ intel_e11 (void) } } + 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 == '*') { @@ -8526,6 +8862,7 @@ intel_e11 (void) 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++; } @@ -8847,16 +9184,6 @@ intel_get_token (void) 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; } @@ -8903,79 +9230,54 @@ intel_putback_token (void) 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); }