`.arch cpu_type' pseudo for x86.

This commit is contained in:
Alan Modra 2000-05-13 09:26:23 +00:00
parent 5ee1baa27d
commit e413e4e996
6 changed files with 1030 additions and 860 deletions

View file

@ -1,3 +1,23 @@
2000-05-13 Alan Modra <alan@linuxcare.com.au>
Alexander Sokolov <robocop@netlink.ru>
* doc/c-i386.texi (i386-Arch): New section.
(i386-Syntax): Mention .intel_syntax and .att_syntax.
* config/tc-i386.c (cpu_arch_name, cpu_arch_flags): New.
(smallest_imm_type): Use smallest opcode for shift by one if cpu
architecture has been given and is not 486.
(set_cpu_arch): New.
(md_pseudo_table): Add .arch.
(md_assemble): Warn if cpu architecture has been given and an
unsupported instruction.
* config/tc-i386.h (SMALLEST_DISP_TYPE): Delete.
Move operand_types bit defines after relevant template field.
(template): Add cpu_flags.
(Cpu*): Define.
(arch_entry): New.
2000-05-12 Alexandre Oliva <aoliva@cygnus.com>
* config/tc-mn10300.h (md_end): Define.

View file

@ -62,6 +62,7 @@ static int add_prefix PARAMS ((unsigned int));
static void set_16bit_code_flag PARAMS ((int));
static void set_16bit_gcc_code_flag PARAMS((int));
static void set_intel_syntax PARAMS ((int));
static void set_cpu_arch PARAMS ((int));
#ifdef BFD_ASSEMBLER
static bfd_reloc_code_real_type reloc
@ -216,13 +217,18 @@ static const templates *current_templates;
/* Per instruction expressionS buffers: 2 displacements & 2 immediate max. */
static expressionS disp_expressions[2], im_expressions[2];
static int this_operand; /* current operand we are working on */
static int this_operand; /* Current operand we are working on. */
static int flag_do_long_jump; /* FIXME what does this do? */
static int flag_16bit_code; /* 1 if we're writing 16-bit code, 0 if 32-bit */
static int flag_16bit_code; /* 1 if we're writing 16-bit code,
0 if 32-bit. */
static int intel_syntax = 0; /* 1 for intel syntax, 0 if att syntax */
static int intel_syntax = 0; /* 1 for intel syntax, 0 if att syntax. */
static const char *cpu_arch_name = NULL; /* cpu name */
static unsigned int cpu_arch_flags = 0; /* cpu feature flags */
static int allow_naked_reg = 0; /* 1 if register prefix % not required */
@ -301,6 +307,21 @@ const relax_typeS md_relax_table[] =
};
static const arch_entry cpu_arch[] = {
{"i8086", Cpu086 },
{"i186", Cpu086|Cpu186 },
{"i286", Cpu086|Cpu186|Cpu286 },
{"i386", Cpu086|Cpu186|Cpu286|Cpu386 },
{"i486", Cpu086|Cpu186|Cpu286|Cpu386|Cpu486 },
{"i586", Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|CpuMMX },
{"i686", Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuMMX|CpuSSE },
{"pentium", Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|CpuMMX },
{"pentiumpro",Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuMMX|CpuSSE },
{"k6", Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|CpuMMX|Cpu3dnow },
{"athlon", Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuMMX|Cpu3dnow },
{NULL, 0 }
};
void
i386_align_code (fragP, count)
@ -441,16 +462,17 @@ static int
smallest_imm_type (num)
offsetT num;
{
#if 0
/* This code is disabled because all the Imm1 forms in the opcode table
are slower on the i486, and they're the versions with the implicitly
specified single-position displacement, which has another syntax if
you really want to use that form. If you really prefer to have the
one-byte-shorter Imm1 form despite these problems, re-enable this
code. */
if (cpu_arch_flags != 0
&& cpu_arch_flags != (Cpu086|Cpu186|Cpu286|Cpu386|Cpu486))
{
/* This code is disabled on the 486 because all the Imm1 forms
in the opcode table are slower on the i486. They're the
versions with the implicitly specified single-position
displacement, which has another syntax if you really want to
use that form. */
if (num == 1)
return Imm1 | Imm8 | Imm8S | Imm16 | Imm32;
#endif
}
return (fits_in_signed_byte (num)
? (Imm8S | Imm8 | Imm16 | Imm32)
: fits_in_unsigned_byte (num)
@ -600,15 +622,48 @@ set_intel_syntax (syntax_flag)
allow_naked_reg = (ask_naked_reg < 0);
}
static void
set_cpu_arch (dummy)
int dummy ATTRIBUTE_UNUSED;
{
SKIP_WHITESPACE();
if (! is_end_of_line[(unsigned char) *input_line_pointer])
{
char *string = input_line_pointer;
int e = get_symbol_end ();
int i;
for (i = 0; cpu_arch[i].name; i++)
{
if (strcmp (string, cpu_arch[i].name) == 0)
{
cpu_arch_name = cpu_arch[i].name;
cpu_arch_flags = cpu_arch[i].flags;
break;
}
}
if (!cpu_arch[i].name)
as_bad (_("no such architecture: `%s'"), string);
*input_line_pointer = e;
}
else
as_bad (_("missing cpu architecture"));
demand_empty_rest_of_line ();
}
const pseudo_typeS md_pseudo_table[] =
{
#ifndef I386COFF
{"bss", s_bss, 0},
#endif
#if !defined(OBJ_AOUT) && !defined(USE_ALIGN_PTWO)
{"align", s_align_bytes, 0},
#else
{"align", s_align_ptwo, 0},
#endif
{"arch", set_cpu_arch, 0},
#ifndef I386COFF
{"bss", s_bss, 0},
#endif
{"ffloat", float_cons, 'f'},
{"dfloat", float_cons, 'd'},
@ -1058,7 +1113,7 @@ md_assemble (line)
mnem_p++;
if (mnem_p >= mnemonic + sizeof (mnemonic))
{
as_bad (_("no such 386 instruction: `%s'"), token_start);
as_bad (_("no such instruction: `%s'"), token_start);
return;
}
l++;
@ -1141,11 +1196,25 @@ md_assemble (line)
}
if (!current_templates)
{
as_bad (_("no such 386 instruction: `%s'"), token_start);
as_bad (_("no such instruction: `%s'"), token_start);
return;
}
}
/* Check if instruction is supported on specified architecture. */
if (cpu_arch_flags != 0)
{
if (current_templates->start->cpu_flags & ~ cpu_arch_flags)
{
as_warn (_("`%s' is not supported on `%s'"),
current_templates->start->name, cpu_arch_name);
}
else if ((Cpu386 & ~ cpu_arch_flags) && !flag_16bit_code)
{
as_warn (_("use .code16 to ensure correct addressing mode"));
}
}
/* check for rep/repne without a string instruction */
if (expecting_string_instruction
&& !(current_templates->start->opcode_modifier & IsString))

View file

@ -239,14 +239,85 @@ extern const char extra_symbol_chars[];
#define OFFSET_FLAT 6
#define FLAT 7
#define NONE_FOUND 8
/*
When an operand is read in it is classified by its type. This type includes
all the possible ways an operand can be used. Thus, '%eax' is both 'register
# 0' and 'The Accumulator'. In our language this is expressed by OR'ing
'Reg32' (any 32 bit register) and 'Acc' (the accumulator).
Operands are classified so that we can match given operand types with
the opcode table in opcode/i386.h.
*/
typedef struct
{
/* instruction name sans width suffix ("mov" for movl insns) */
char *name;
/* how many operands */
unsigned int operands;
/* base_opcode is the fundamental opcode byte without optional
prefix(es). */
unsigned int base_opcode;
/* extension_opcode is the 3 bit extension for group <n> insns.
This field is also used to store the 8-bit opcode suffix for the
AMD 3DNow! instructions.
If this template has no extension opcode (the usual case) use None */
unsigned int extension_opcode;
#define None 0xffff /* If no extension_opcode is possible. */
/* cpu feature flags */
unsigned int cpu_flags;
#define Cpu086 0x1 /* Any old cpu will do, 0 does the same */
#define Cpu186 0x2 /* i186 or better required */
#define Cpu286 0x4 /* i286 or better required */
#define Cpu386 0x8 /* i386 or better required */
#define Cpu486 0x10 /* i486 or better required */
#define Cpu586 0x20 /* i585 or better required */
#define Cpu686 0x40 /* i686 or better required */
#define CpuMMX 0x80 /* MMX support required */
#define CpuSSE 0x100 /* Streaming SIMD extensions required */
#define Cpu3dnow 0x200 /* 3dnow! support required */
/* the bits in opcode_modifier are used to generate the final opcode from
the base_opcode. These bits also are used to detect alternate forms of
the same instruction */
unsigned int opcode_modifier;
/* opcode_modifier bits: */
#define W 0x1 /* set if operands can be words or dwords
encoded the canonical way */
#define D 0x2 /* D = 0 if Reg --> Regmem;
D = 1 if Regmem --> Reg: MUST BE 0x2 */
#define Modrm 0x4
#define FloatR 0x8 /* src/dest swap for floats: MUST BE 0x8 */
#define ShortForm 0x10 /* register is in low 3 bits of opcode */
#define FloatMF 0x20 /* FP insn memory format bit, sized by 0x4 */
#define Jump 0x40 /* special case for jump insns. */
#define JumpDword 0x80 /* call and jump */
#define JumpByte 0x100 /* loop and jecxz */
#define JumpInterSegment 0x200 /* special case for intersegment leaps/calls */
#define FloatD 0x400 /* direction for float insns: MUST BE 0x400 */
#define Seg2ShortForm 0x800 /* encoding of load segment reg insns */
#define Seg3ShortForm 0x1000 /* fs/gs segment register insns. */
#define Size16 0x2000 /* needs size prefix if in 32-bit mode */
#define Size32 0x4000 /* needs size prefix if in 16-bit mode */
#define IgnoreSize 0x8000 /* instruction ignores operand size prefix */
#define DefaultSize 0x10000 /* default insn size depends on mode */
#define No_bSuf 0x20000 /* b suffix on instruction illegal */
#define No_wSuf 0x40000 /* w suffix on instruction illegal */
#define No_lSuf 0x80000 /* l suffix on instruction illegal */
#define No_sSuf 0x100000 /* s suffix on instruction illegal */
#define No_dSuf 0x200000 /* d suffix on instruction illegal */
#define No_xSuf 0x400000 /* x suffix on instruction illegal */
#define FWait 0x800000 /* instruction needs FWAIT */
#define IsString 0x1000000 /* quick test for string instructions */
#define regKludge 0x2000000 /* fake an extra reg operand for clr, imul */
#define IsPrefix 0x4000000 /* opcode is a prefix */
#define ImmExt 0x8000000 /* instruction has extension in 8 bit imm */
#define Ugh 0x80000000 /* deprecated fp insn, gets a warning */
/* operand_types[i] describes the type of operand i. This is made
by OR'ing together all of the possible type masks. (e.g.
'operand_types[i] = Reg|Imm' specifies that operand i can be
either a register or an immediate operand. */
unsigned int operand_types[3];
/* operand_types[i] bits */
/* register */
#define Reg8 0x1 /* 8 bit reg */
#define Reg16 0x2 /* 16 bit reg */
@ -307,72 +378,6 @@ extern const char extra_symbol_chars[];
#define ShortMem AnyMem /* 16 bit memory ref */
#define WordMem AnyMem /* 16 or 32 bit memory ref */
#define ByteMem AnyMem /* 8 bit memory ref */
#define SMALLEST_DISP_TYPE(num) \
(fits_in_signed_byte(num) ? (Disp8|Disp32) : Disp32)
typedef struct
{
/* instruction name sans width suffix ("mov" for movl insns) */
char *name;
/* how many operands */
unsigned int operands;
/* base_opcode is the fundamental opcode byte without optional
prefix(es). */
unsigned int base_opcode;
/* extension_opcode is the 3 bit extension for group <n> insns.
This field is also used to store the 8-bit opcode suffix for the
AMD 3DNow! instructions.
If this template has no extension opcode (the usual case) use None */
unsigned int extension_opcode;
#define None 0xffff /* If no extension_opcode is possible. */
/* the bits in opcode_modifier are used to generate the final opcode from
the base_opcode. These bits also are used to detect alternate forms of
the same instruction */
unsigned int opcode_modifier;
/* opcode_modifier bits: */
#define W 0x1 /* set if operands can be words or dwords
encoded the canonical way */
#define D 0x2 /* D = 0 if Reg --> Regmem;
D = 1 if Regmem --> Reg: MUST BE 0x2 */
#define Modrm 0x4
#define FloatR 0x8 /* src/dest swap for floats: MUST BE 0x8 */
#define ShortForm 0x10 /* register is in low 3 bits of opcode */
#define FloatMF 0x20 /* FP insn memory format bit, sized by 0x4 */
#define Jump 0x40 /* special case for jump insns. */
#define JumpDword 0x80 /* call and jump */
#define JumpByte 0x100 /* loop and jecxz */
#define JumpInterSegment 0x200 /* special case for intersegment leaps/calls */
#define FloatD 0x400 /* direction for float insns: MUST BE 0x400 */
#define Seg2ShortForm 0x800 /* encoding of load segment reg insns */
#define Seg3ShortForm 0x1000 /* fs/gs segment register insns. */
#define Size16 0x2000 /* needs size prefix if in 32-bit mode */
#define Size32 0x4000 /* needs size prefix if in 16-bit mode */
#define IgnoreSize 0x8000 /* instruction ignores operand size prefix */
#define DefaultSize 0x10000 /* default insn size depends on mode */
#define No_bSuf 0x20000 /* b suffix on instruction illegal */
#define No_wSuf 0x40000 /* w suffix on instruction illegal */
#define No_lSuf 0x80000 /* l suffix on instruction illegal */
#define No_sSuf 0x100000 /* s suffix on instruction illegal */
#define No_dSuf 0x200000 /* d suffix on instruction illegal */
#define No_xSuf 0x400000 /* x suffix on instruction illegal */
#define FWait 0x800000 /* instruction needs FWAIT */
#define IsString 0x1000000 /* quick test for string instructions */
#define regKludge 0x2000000 /* fake an extra reg operand for clr, imul */
#define IsPrefix 0x4000000 /* opcode is a prefix */
#define ImmExt 0x8000000 /* instruction has extension in 8 bit imm */
#define Ugh 0x80000000 /* deprecated fp insn, gets a warning */
/* operand_types[i] describes the type of operand i. This is made
by OR'ing together all of the possible type masks. (e.g.
'operand_types[i] = Reg|Imm' specifies that operand i can be
either a register or an immediate operand */
unsigned int operand_types[3];
}
template;
@ -387,7 +392,8 @@ typedef struct
{
const template *start;
const template *end;
} templates;
}
templates;
/* these are for register name --> number & type hash lookup */
typedef struct
@ -423,6 +429,14 @@ typedef struct
}
sib_byte;
/* x86 arch names and features */
typedef struct
{
const char *name; /* arch name */
unsigned int flags; /* cpu feature flags */
}
arch_entry;
/* The name of the global offset table generated by the compiler. Allow
this to be overridden if need be. */
#ifndef GLOBAL_OFFSET_TABLE_NAME

View file

@ -24,6 +24,7 @@
* i386-Float:: Floating Point
* i386-SIMD:: Intel's MMX and AMD's 3DNow! SIMD Operations
* i386-16bit:: Writing 16-bit Code
* i386-Arch:: Specifying an x86 CPU architecture
* i386-Bugs:: AT&T Syntax bugs
* i386-Notes:: Notes
@end menu
@ -35,13 +36,23 @@
@cindex i386 options (none)
The 80386 has no machine dependent options.
@node i386-Syntax
@section AT&T Syntax versus Intel Syntax
@cindex i386 intel_syntax pseudo op
@cindex intel_syntax pseudo op, i386
@cindex i386 att_syntax pseudo op
@cindex att_syntax pseudo op, i386
@cindex i386 syntax compatibility
@cindex syntax compatibility, i386
In order to maintain compatibility with the output of @code{@value{GCC}},
@code{@value{AS}} supports AT&T System V/386 assembler syntax. This is quite
@code{@value{AS}} now supports assembly using Intel assembler syntax.
@code{.intel_syntax} selects Intel mode, and @code{.att_syntax} switches
back to the usual AT&T mode for compatibility with the output of
@code{@value{GCC}}. Either of these directives may have an optional
argument, @code{prefix}, or @code{noprefix} specifying whether registers
require a @samp{%} prefix. AT&T System V/386 assembler syntax is quite
different from Intel syntax. We mention these differences because
almost all 80386 documents use Intel syntax. Notable differences
between the two syntaxes are:
@ -506,6 +517,31 @@ non-commutative arithmetic floating point operations with two register
operands where the source register is @samp{%st} and the destination
register is @samp{%st(i)}.
@node i386-Arch
@section Specifying CPU Architecture
@cindex arch directive, i386
@cindex i386 arch directive
@code{@value{AS}} may be told to assemble for a particular CPU
architecture with the @code{.arch @var{cpu_type}} directive. This
directive enables a warning when gas detects an instruction that is not
supported on the CPU specified. The choices for @var{cpu_type} are:
@multitable @columnfractions .20 .20 .20 .20
@item @samp{i8086} @tab @samp{i186} @tab @samp{i286} @tab @samp{i386}
@item @samp{i486} @tab @samp{i586} @tab @samp{i686} @tab @samp{pentium}
@item @samp{pentiumpro} @tab @samp{k6} @tab @samp{athlon}
@end multitable
Apart from the warning, there is only one other effect on
@code{@value{AS}} operation; If you specify a CPU other than
@samp{i486}, then shift by one instructions such as @samp{sarl $1, %eax}
will automatically use a two byte opcode sequence. The larger three
byte opcode sequence is used on the 486 (and when no architecture is
specified) because it executes faster on the 486. Note that you can
explicitly request the two byte opcode by writing @samp{sarl %eax}.
@node i386-Notes
@section Notes

View file

@ -1,3 +1,13 @@
2000-05-13 Alan Modra <alan@linuxcare.com.au>,
Alexander Sokolov <robocop@netlink.ru>
* i386.h (i386_optab): Add cpu_flags for all instructions.
2000-05-13 Alan Modra <alan@linuxcare.com.au>
From Gavin Romig-Koch <gavin@cygnus.com>
* i386.h (wld_Suf): Define. Use on pushf, popf, pusha, popa.
2000-05-04 Timothy Wall <twall@cygnus.com>
* tic54x.h: New.

File diff suppressed because it is too large Load diff