--- gcc/config/i386/i386.h 2018/04/24 18:10:27 1.1 +++ gcc/config/i386/i386.h 2018/04/24 18:30:40 1.1.1.4 @@ -1,5 +1,6 @@ -/* Definitions of target machine for GNU compiler for Intel 80386. - Copyright (C) 1988, 1992 Free Software Foundation, Inc. +/* Definitions of target machine for GNU compiler for Intel X86 + (386, 486, Pentium). + Copyright (C) 1988, 1992, 1994, 1995 Free Software Foundation, Inc. This file is part of GNU CC. @@ -15,7 +16,8 @@ GNU General Public License for more deta You should have received a copy of the GNU General Public License along with GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ /* The purpose of this file is to define the characteristics of the i386, @@ -57,72 +59,157 @@ extern int target_flags; /* Macros used in the machine description to test the flags. */ -/* configure can arrage to make this 2, to force a 486. */ +/* configure can arrange to make this 2, to force a 486. */ #ifndef TARGET_CPU_DEFAULT #define TARGET_CPU_DEFAULT 0 #endif -/* Compile 80387 insns for floating point (not library calls). */ -#define TARGET_80387 (target_flags & 1) -/* Compile code for an i486. */ -#define TARGET_486 (target_flags & 2) +/* Masks for the -m switches */ +#define MASK_80387 000000000001 /* Hardware floating point */ +#define MASK_486 000000000002 /* 80486 specific */ +#define MASK_NOTUSED1 000000000004 /* bit not currently used */ +#define MASK_RTD 000000000010 /* Use ret that pops args */ +#define MASK_ALIGN_DOUBLE 000000000020 /* align doubles to 2 word boundary */ +#define MASK_SVR3_SHLIB 000000000040 /* Uninit locals into bss */ +#define MASK_IEEE_FP 000000000100 /* IEEE fp comparisons */ +#define MASK_FLOAT_RETURNS 000000000200 /* Return float in st(0) */ +#define MASK_NO_FANCY_MATH_387 000000000400 /* Disable sin, cos, sqrt */ + + /* Temporary codegen switches */ +#define MASK_DEBUG_ADDR 000001000000 /* Debug GO_IF_LEGITIMATE_ADDRESS */ +#define MASK_NO_WIDE_MULTIPLY 000002000000 /* Disable 32x32->64 multiplies */ +#define MASK_NO_MOVE 000004000000 /* Don't generate mem->mem */ +#define MASK_DEBUG_ARG 000010000000 /* Debug function_arg */ + +/* Use the floating point instructions */ +#define TARGET_80387 (target_flags & MASK_80387) + /* Compile using ret insn that pops args. This will not work unless you use prototypes at least for all functions that can take varying numbers of args. */ -#define TARGET_RTD (target_flags & 8) -/* Compile passing first two args in regs 0 and 1. - This exists only to test compiler features that will - be needed for RISC chips. It is not usable - and is not intended to be usable on this cpu. */ -#define TARGET_REGPARM (target_flags & 020) +#define TARGET_RTD (target_flags & MASK_RTD) + +/* Align doubles to a two word boundary. This breaks compatibility with + the published ABI's for structures containing doubles, but produces + faster code on the pentium. */ +#define TARGET_ALIGN_DOUBLE (target_flags & MASK_ALIGN_DOUBLE) /* Put uninitialized locals into bss, not data. Meaningful only on svr3. */ -#define TARGET_SVR3_SHLIB (target_flags & 040) +#define TARGET_SVR3_SHLIB (target_flags & MASK_SVR3_SHLIB) /* Use IEEE floating point comparisons. These handle correctly the cases where the result of a comparison is unordered. Normally SIGFPE is generated in such cases, in which case this isn't needed. */ -#define TARGET_IEEE_FP (target_flags & 0100) +#define TARGET_IEEE_FP (target_flags & MASK_IEEE_FP) /* Functions that return a floating point value may return that value in the 387 FPU or in 386 integer registers. If set, this flag causes the 387 to be used, which is compatible with most calling conventions. */ -#define TARGET_FLOAT_RETURNS_IN_80387 (target_flags & 0200) +#define TARGET_FLOAT_RETURNS_IN_80387 (target_flags & MASK_FLOAT_RETURNS) + +/* Disable generation of FP sin, cos and sqrt operations for 387. + This is because FreeBSD lacks these in the math-emulator-code */ +#define TARGET_NO_FANCY_MATH_387 (target_flags & MASK_NO_FANCY_MATH_387) + +/* Temporary switches for tuning code generation */ + +/* Disable 32x32->64 bit multiplies that are used for long long multiplies + and division by constants, but sometimes cause reload problems. */ +#define TARGET_NO_WIDE_MULTIPLY (target_flags & MASK_NO_WIDE_MULTIPLY) +#define TARGET_WIDE_MULTIPLY (!TARGET_NO_WIDE_MULTIPLY) + +/* Debug GO_IF_LEGITIMATE_ADDRESS */ +#define TARGET_DEBUG_ADDR (target_flags & MASK_DEBUG_ADDR) + +/* Debug FUNCTION_ARG macros */ +#define TARGET_DEBUG_ARG (target_flags & MASK_DEBUG_ARG) + +/* Hack macros for tuning code generation */ +#define TARGET_MOVE ((target_flags & MASK_NO_MOVE) == 0) /* Don't generate memory->memory */ + +/* Specific hardware switches */ +#define TARGET_486 (target_flags & MASK_486) /* 80486DX, 80486SX, 80486DX[24] */ +#define TARGET_386 (!TARGET_486) /* 80386 */ + +#define TARGET_SWITCHES \ +{ { "80387", MASK_80387 }, \ + { "no-80387", -MASK_80387 }, \ + { "hard-float", MASK_80387 }, \ + { "soft-float", -MASK_80387 }, \ + { "no-soft-float", MASK_80387 }, \ + { "386", -MASK_486 }, \ + { "no-386", MASK_486 }, \ + { "486", MASK_486 }, \ + { "no-486", -MASK_486 }, \ + { "rtd", MASK_RTD }, \ + { "no-rtd", -MASK_RTD }, \ + { "align-double", MASK_ALIGN_DOUBLE }, \ + { "no-align-double", -MASK_ALIGN_DOUBLE }, \ + { "svr3-shlib", MASK_SVR3_SHLIB }, \ + { "no-svr3-shlib", -MASK_SVR3_SHLIB }, \ + { "ieee-fp", MASK_IEEE_FP }, \ + { "no-ieee-fp", -MASK_IEEE_FP }, \ + { "fp-ret-in-387", MASK_FLOAT_RETURNS }, \ + { "no-fp-ret-in-387", -MASK_FLOAT_RETURNS }, \ + { "no-fancy-math-387", MASK_NO_FANCY_MATH_387 }, \ + { "fancy-math-387", -MASK_NO_FANCY_MATH_387 }, \ + { "no-wide-multiply", MASK_NO_WIDE_MULTIPLY }, \ + { "wide-multiply", -MASK_NO_WIDE_MULTIPLY }, \ + { "debug-addr", MASK_DEBUG_ADDR }, \ + { "no-debug-addr", -MASK_DEBUG_ADDR }, \ + { "move", -MASK_NO_MOVE }, \ + { "no-move", MASK_NO_MOVE }, \ + { "debug-arg", MASK_DEBUG_ARG }, \ + { "no-debug-arg", -MASK_DEBUG_ARG }, \ + SUBTARGET_SWITCHES \ + { "", TARGET_DEFAULT | TARGET_CPU_DEFAULT}} + +/* This macro is similar to `TARGET_SWITCHES' but defines names of + command options that have values. Its definition is an + initializer with a subgrouping for each command option. + + Each subgrouping contains a string constant, that defines the + fixed part of the option name, and the address of a variable. The + variable, type `char *', is set to the variable part of the given + option if the fixed part matches. The actual option name is made + by appending `-m' to the specified name. */ +#define TARGET_OPTIONS \ +{ { "reg-alloc=", &i386_reg_alloc_order }, \ + { "regparm=", &i386_regparm_string }, \ + { "align-loops=", &i386_align_loops_string }, \ + { "align-jumps=", &i386_align_jumps_string }, \ + { "align-functions=", &i386_align_funcs_string }, \ + SUBTARGET_OPTIONS \ +} + +/* Sometimes certain combinations of command options do not make + sense on a particular target machine. You can define a macro + `OVERRIDE_OPTIONS' to take account of this. This macro, if + defined, is executed once just after all the command options have + been parsed. + + Don't use this macro to turn on various extra optimizations for + `-O'. That is what `OPTIMIZATION_OPTIONS' is for. */ -/* Macro to define tables used to set the flags. - This is a list in braces of pairs in braces, - each pair being { "NAME", VALUE } - where VALUE is the bits to set or minus the bits to clear. - An empty string NAME is used to identify the default VALUE. */ - -#define TARGET_SWITCHES \ - { { "80387", 1}, \ - { "no-80387", -1}, \ - { "soft-float", -1}, \ - { "no-soft-float", 1}, \ - { "486", 2}, \ - { "no-486", -2}, \ - { "386", -2}, \ - { "rtd", 8}, \ - { "no-rtd", -8}, \ - { "regparm", 020}, \ - { "no-regparm", -020}, \ - { "svr3-shlib", 040}, \ - { "no-svr3-shlib", -040}, \ - { "ieee-fp", 0100}, \ - { "no-ieee-fp", -0100}, \ - { "fp-ret-in-387", 0200}, \ - { "no-fp-ret-in-387", -0200}, \ - SUBTARGET_SWITCHES \ - { "", TARGET_DEFAULT | TARGET_CPU_DEFAULT}} +#define OVERRIDE_OPTIONS override_options () -/* This is meant to be redefined in the host dependent files */ +/* These are meant to be redefined in the host dependent files */ #define SUBTARGET_SWITCHES +#define SUBTARGET_OPTIONS /* target machine storage layout */ +/* Define for XFmode extended real floating point support. + This will automatically cause REAL_ARITHMETIC to be defined. */ +#define LONG_DOUBLE_TYPE_SIZE 96 + +/* Define if you don't want extended real, but do want to use the + software floating point emulator for REAL_ARITHMETIC and + decimal <-> binary conversion. */ +/* #define REAL_ARITHMETIC */ + /* Define this if most significant byte of a word is the lowest numbered. */ /* That is true on the 80386. */ @@ -162,7 +249,7 @@ extern int target_flags; /* Allocation boundary (in *bits*) for the code of a function. For i486, we get better performance by aligning to a cache line (i.e. 16 byte) boundary. */ -#define FUNCTION_BOUNDARY (TARGET_486 ? 128 : 32) +#define FUNCTION_BOUNDARY (1 << (i386_align_funcs + 3)) /* Alignment of field after `int : 0' in a structure. */ @@ -172,8 +259,11 @@ extern int target_flags; and all fundamental data types supported by the hardware might need to be aligned. No data type wants to be aligned rounder than this. The i386 supports 64-bit floating point - quantities, but these can be aligned on any 32-bit boundary. */ -#define BIGGEST_ALIGNMENT 32 + quantities, but these can be aligned on any 32-bit boundary. + The published ABIs say that doubles should be aligned on word + boundaries, but the Pentium gets better performance with them + aligned on 64 bit boundaries. */ +#define BIGGEST_ALIGNMENT (TARGET_ALIGN_DOUBLE ? 64 : 32) /* Set this non-zero if move instructions will actually fail to work when given unaligned data. */ @@ -184,15 +274,17 @@ extern int target_flags; /* Required on the 386 since it doesn't have bitfield insns. */ #define PCC_BITFIELD_TYPE_MATTERS 1 +/* Maximum power of 2 that code can be aligned to. */ +#define MAX_CODE_ALIGN 6 /* 64 byte alignment */ + /* Align loop starts for optimal branching. */ -#define ASM_OUTPUT_LOOP_ALIGN(FILE) \ - ASM_OUTPUT_ALIGN (FILE, 2) +#define ASM_OUTPUT_LOOP_ALIGN(FILE) ASM_OUTPUT_ALIGN (FILE, i386_align_loops) /* This is how to align an instruction for optimal branching. On i486 we'll get better performance by aligning on a cache line (i.e. 16 byte) boundary. */ -#define ASM_OUTPUT_ALIGN_CODE(FILE) \ - ASM_OUTPUT_ALIGN ((FILE), (TARGET_486 ? 4 : 2)) +#define ASM_OUTPUT_ALIGN_CODE(FILE) ASM_OUTPUT_ALIGN ((FILE), i386_align_jumps) + /* Standard register usage. */ @@ -237,6 +329,44 @@ extern int target_flags; /*ax,dx,cx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7,arg*/ \ { 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } +/* Order in which to allocate registers. Each register must be + listed once, even those in FIXED_REGISTERS. List frame pointer + late and fixed registers last. Note that, in general, we prefer + registers listed in CALL_USED_REGISTERS, keeping the others + available for storage of persistent values. + + Three different versions of REG_ALLOC_ORDER have been tried: + + If the order is edx, ecx, eax, ... it produces a slightly faster compiler, + but slower code on simple functions returning values in eax. + + If the order is eax, ecx, edx, ... it causes reload to abort when compiling + perl 4.036 due to not being able to create a DImode register (to hold a 2 + word union). + + If the order is eax, edx, ecx, ... it produces better code for simple + functions, and a slightly slower compiler. Users complained about the code + generated by allocating edx first, so restore the 'natural' order of things. */ + +#define REG_ALLOC_ORDER \ +/*ax,dx,cx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7,arg*/ \ +{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 } + +/* A C statement (sans semicolon) to choose the order in which to + allocate hard registers for pseudo-registers local to a basic + block. + + Store the desired register order in the array `reg_alloc_order'. + Element 0 should be the register to allocate first; element 1, the + next register; and so on. + + The macro body should not assume anything about the contents of + `reg_alloc_order' before execution of the macro. + + On most machines, it is not necessary to define this macro. */ + +#define ORDER_REGS_FOR_LOCAL_ALLOC order_regs_for_local_alloc () + /* Macro to conditionally modify fixed_regs/call_used_regs. */ #define CONDITIONAL_REGISTER_USAGE \ { \ @@ -281,7 +411,7 @@ extern int target_flags; #define HARD_REGNO_MODE_OK(REGNO, MODE) \ ((REGNO) < 2 ? 1 \ : (REGNO) < 4 ? 1 \ - : FP_REGNO_P ((REGNO)) \ + : FP_REGNO_P (REGNO) \ ? (((int) GET_MODE_CLASS (MODE) == (int) MODE_FLOAT \ || (int) GET_MODE_CLASS (MODE) == (int) MODE_COMPLEX_FLOAT) \ && GET_MODE_UNIT_SIZE (MODE) <= 12) \ @@ -349,6 +479,27 @@ extern int target_flags; /* Place in which caller passes the structure value address. 0 means push the value on the stack like an argument. */ #define STRUCT_VALUE 0 + +/* A C expression which can inhibit the returning of certain function + values in registers, based on the type of value. A nonzero value + says to return the function value in memory, just as large + structures are always returned. Here TYPE will be a C expression + of type `tree', representing the data type of the value. + + Note that values of mode `BLKmode' must be explicitly handled by + this macro. Also, the option `-fpcc-struct-return' takes effect + regardless of this macro. On most systems, it is possible to + leave the macro undefined; this causes a default definition to be + used, whose value is the constant 1 for `BLKmode' values, and 0 + otherwise. + + Do not use this macro to indicate that structures and unions + should always be returned in memory. You should instead use + `DEFAULT_PCC_STRUCT_RETURN' to indicate this. */ + +#define RETURN_IN_MEMORY(TYPE) \ + ((TYPE_MODE (TYPE) == BLKmode) || int_size_in_bytes (TYPE) > 12) + /* Define the classes of registers for register constraints in the machine description. Also define ranges of constants. @@ -378,6 +529,7 @@ enum reg_class { NO_REGS, AREG, DREG, CREG, BREG, + AD_REGS, /* %eax/%edx for DImode */ Q_REGS, /* %eax %ebx %ecx %edx */ SIREG, DIREG, INDEX_REGS, /* %eax %ebx %ecx %edx %esi %edi %ebp */ @@ -396,6 +548,7 @@ enum reg_class #define REG_CLASS_NAMES \ { "NO_REGS", \ "AREG", "DREG", "CREG", "BREG", \ + "AD_REGS", \ "Q_REGS", \ "SIREG", "DIREG", \ "INDEX_REGS", \ @@ -411,9 +564,10 @@ enum reg_class #define REG_CLASS_CONTENTS \ { 0, \ 0x1, 0x2, 0x4, 0x8, /* AREG, DREG, CREG, BREG */ \ + 0x3, /* AD_REGS */ \ 0xf, /* Q_REGS */ \ 0x10, 0x20, /* SIREG, DIREG */ \ - 0x1007f, /* INDEX_REGS */ \ + 0x07f, /* INDEX_REGS */ \ 0x100ff, /* GENERAL_REGS */ \ 0x0100, 0x0200, /* FP_TOP_REG, FP_SECOND_REG */ \ 0xff00, /* FLOAT_REGS */ \ @@ -424,7 +578,6 @@ enum reg_class reg number REGNO. This could be a conditional expression or could index an array. */ -extern enum reg_class regclass_map[FIRST_PSEUDO_REGISTER]; #define REGNO_REG_CLASS(REGNO) (regclass_map[REGNO]) /* When defined, the compiler allows registers explicitly used in the @@ -482,6 +635,7 @@ extern enum reg_class regclass_map[FIRST (C) == 'b' ? BREG : \ (C) == 'c' ? CREG : \ (C) == 'd' ? DREG : \ + (C) == 'A' ? AD_REGS : \ (C) == 'D' ? DIREG : \ (C) == 'S' ? SIREG : NO_REGS) @@ -503,6 +657,7 @@ extern enum reg_class regclass_map[FIRST (C) == 'K' ? (VALUE) == 0xff : \ (C) == 'L' ? (VALUE) == 0xffff : \ (C) == 'M' ? (VALUE) >= 0 && (VALUE) <= 3 : \ + (C) == 'N' ? (VALUE) >= 0 && (VALUE) <= 255 :\ 0) /* Similar, but for floating constants, and defining letters G and H. @@ -555,6 +710,32 @@ extern enum reg_class regclass_map[FIRST #define CLASS_MAX_NREGS(CLASS, MODE) \ (FLOAT_CLASS_P (CLASS) ? 1 : \ ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)) + +/* A C expression whose value is nonzero if pseudos that have been + assigned to registers of class CLASS would likely be spilled + because registers of CLASS are needed for spill registers. + + The default value of this macro returns 1 if CLASS has exactly one + register and zero otherwise. On most machines, this default + should be used. Only define this macro to some other expression + if pseudo allocated by `local-alloc.c' end up in memory because + their hard registers were needed for spill registers. If this + macro returns nonzero for those classes, those pseudos will only + be allocated by `global.c', which knows how to reallocate the + pseudo to another register. If there would not be another + register available for reallocation, you should not change the + definition of this macro since the only effect of such a + definition would be to slow down register allocation. */ + +#define CLASS_LIKELY_SPILLED_P(CLASS) \ + (((CLASS) == AREG) \ + || ((CLASS) == DREG) \ + || ((CLASS) == CREG) \ + || ((CLASS) == BREG) \ + || ((CLASS) == AD_REGS) \ + || ((CLASS) == SIREG) \ + || ((CLASS) == DIREG)) + /* Stack layout; function entry, exit and calling. */ @@ -587,6 +768,7 @@ extern enum reg_class regclass_map[FIRST /* Value is the number of bytes of arguments automatically popped when returning from a subroutine call. + FUNDECL is the declaration node of the function (as a tree), FUNTYPE is the data type of the function (as a tree), or for a library call it is an identifier node for the subroutine name. SIZE is the number of bytes of arguments passed on the stack. @@ -597,15 +779,12 @@ extern enum reg_class regclass_map[FIRST because the library is compiled with the Unix compiler. Use of RTD is a selectable option, since it is incompatible with standard Unix calling sequences. If the option is not selected, - the caller must always pop the args. */ + the caller must always pop the args. + + The attribute stdcall is equivalent to RTD on a per module basis. */ -#define RETURN_POPS_ARGS(FUNTYPE,SIZE) \ - (TREE_CODE (FUNTYPE) == IDENTIFIER_NODE ? 0 \ - : (TARGET_RTD \ - && (TYPE_ARG_TYPES (FUNTYPE) == 0 \ - || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (FUNTYPE))) \ - == void_type_node))) ? (SIZE) \ - : (aggregate_value_p (FUNTYPE)) ? GET_MODE_SIZE (Pmode) : 0) +#define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) \ + (i386_return_pops_args (FUNDECL, FUNTYPE, SIZE)) /* Define how to find the value returned by a function. VALTYPE is the data type of the value (as a tree). @@ -627,41 +806,34 @@ extern enum reg_class regclass_map[FIRST #define APPLY_RESULT_SIZE (8+108) -/* 1 if N is a possible register number for function argument passing. - On the 80386, no registers are used in this way. - *NOTE* -mregparm does not work. - It exists only to test register calling conventions. */ - -#define FUNCTION_ARG_REGNO_P(N) 0 +/* 1 if N is a possible register number for function argument passing. */ +#define FUNCTION_ARG_REGNO_P(N) ((N) >= 0 && (N) < REGPARM_MAX) /* Define a data type for recording info about an argument list during the scan of that argument list. This data type should hold all necessary information about the function itself and about the args processed so far, enough to enable macros - such as FUNCTION_ARG to determine where the next arg should go. - - On the 80386, this is a single integer, which is a number of bytes - of arguments scanned so far. */ + such as FUNCTION_ARG to determine where the next arg should go. */ -#define CUMULATIVE_ARGS int +typedef struct i386_args { + int words; /* # words passed so far */ + int nregs; /* # registers available for passing */ + int regno; /* next available register number */ +} CUMULATIVE_ARGS; /* Initialize a variable CUM of type CUMULATIVE_ARGS for a call to a function whose data type is FNTYPE. - For a library call, FNTYPE is 0. - - On the 80386, the offset starts at 0. */ + For a library call, FNTYPE is 0. */ #define INIT_CUMULATIVE_ARGS(CUM,FNTYPE,LIBNAME) \ - ((CUM) = 0) + (init_cumulative_args (&CUM, FNTYPE, LIBNAME)) /* Update the data in CUM to advance over an argument of mode MODE and data type TYPE. (TYPE is null for libcalls where that information may not be available.) */ #define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ - ((CUM) += ((MODE) != BLKmode \ - ? (GET_MODE_SIZE (MODE) + 3) & ~3 \ - : (int_size_in_bytes (TYPE) + 3) & ~3)) + (function_arg_advance (&CUM, MODE, TYPE, NAMED)) /* Define where to put the arguments to a function. Value is zero to push the argument on the stack, @@ -676,26 +848,15 @@ extern enum reg_class regclass_map[FIRST NAMED is nonzero if this argument is a named parameter (otherwise it is an extra parameter matching an ellipsis). */ - -/* On the 80386 all args are pushed, except if -mregparm is specified - then the first two words of arguments are passed in EAX, EDX. - *NOTE* -mregparm does not work. - It exists only to test register calling conventions. */ - #define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ -((TARGET_REGPARM && (CUM) < 8) ? gen_rtx (REG, (MODE), (CUM) / 4) : 0) + (function_arg (&CUM, MODE, TYPE, NAMED)) /* For an arg passed partly in registers and partly in memory, this is the number of registers used. For args passed entirely in registers or entirely in memory, zero. */ - #define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) \ -((TARGET_REGPARM && (CUM) < 8 \ - && 8 < ((CUM) + ((MODE) == BLKmode \ - ? int_size_in_bytes (TYPE) \ - : GET_MODE_SIZE (MODE)))) \ - ? 2 - (CUM) / 4 : 0) + (function_arg_partial_nregs (&CUM, MODE, TYPE, NAMED)) /* This macro generates the assembly code for function entry. FILE is a stdio stream to output the code to. @@ -726,6 +887,102 @@ extern enum reg_class regclass_map[FIRST } \ } +/* A C statement or compound statement to output to FILE some + assembler code to initialize basic-block profiling for the current + object module. This code should call the subroutine + `__bb_init_func' once per object module, passing it as its sole + argument the address of a block allocated in the object module. + + The name of the block is a local symbol made with this statement: + + ASM_GENERATE_INTERNAL_LABEL (BUFFER, "LPBX", 0); + + Of course, since you are writing the definition of + `ASM_GENERATE_INTERNAL_LABEL' as well as that of this macro, you + can take a short cut in the definition of this macro and use the + name that you know will result. + + The first word of this block is a flag which will be nonzero if the + object module has already been initialized. So test this word + first, and do not call `__bb_init_func' if the flag is nonzero. */ + +#undef FUNCTION_BLOCK_PROFILER +#define FUNCTION_BLOCK_PROFILER(STREAM, LABELNO) \ +do \ + { \ + static int num_func = 0; \ + rtx xops[8]; \ + char block_table[80], false_label[80]; \ + \ + ASM_GENERATE_INTERNAL_LABEL (block_table, "LPBX", 0); \ + ASM_GENERATE_INTERNAL_LABEL (false_label, "LPBZ", num_func); \ + \ + xops[0] = const0_rtx; \ + xops[1] = gen_rtx (SYMBOL_REF, VOIDmode, block_table); \ + xops[2] = gen_rtx (MEM, Pmode, gen_rtx (SYMBOL_REF, VOIDmode, false_label)); \ + xops[3] = gen_rtx (MEM, Pmode, gen_rtx (SYMBOL_REF, VOIDmode, "__bb_init_func")); \ + xops[4] = gen_rtx (MEM, Pmode, xops[1]); \ + xops[5] = stack_pointer_rtx; \ + xops[6] = GEN_INT (4); \ + xops[7] = gen_rtx (REG, Pmode, 0); /* eax */ \ + \ + CONSTANT_POOL_ADDRESS_P (xops[1]) = TRUE; \ + CONSTANT_POOL_ADDRESS_P (xops[2]) = TRUE; \ + \ + output_asm_insn (AS2(cmp%L4,%0,%4), xops); \ + output_asm_insn (AS1(jne,%2), xops); \ + \ + if (!flag_pic) \ + output_asm_insn (AS1(push%L1,%1), xops); \ + else \ + { \ + output_asm_insn (AS2 (lea%L7,%a1,%7), xops); \ + output_asm_insn (AS1 (push%L7,%7), xops); \ + } \ + \ + output_asm_insn (AS1(call,%P3), xops); \ + output_asm_insn (AS2(add%L0,%6,%5), xops); \ + ASM_OUTPUT_INTERNAL_LABEL (STREAM, "LPBZ", num_func); \ + num_func++; \ + } \ +while (0) + + +/* A C statement or compound statement to increment the count + associated with the basic block number BLOCKNO. Basic blocks are + numbered separately from zero within each compilation. The count + associated with block number BLOCKNO is at index BLOCKNO in a + vector of words; the name of this array is a local symbol made + with this statement: + + ASM_GENERATE_INTERNAL_LABEL (BUFFER, "LPBX", 2); + + Of course, since you are writing the definition of + `ASM_GENERATE_INTERNAL_LABEL' as well as that of this macro, you + can take a short cut in the definition of this macro and use the + name that you know will result. */ + +#define BLOCK_PROFILER(STREAM, BLOCKNO) \ +do \ + { \ + rtx xops[1], cnt_rtx; \ + char counts[80]; \ + \ + ASM_GENERATE_INTERNAL_LABEL (counts, "LPBX", 2); \ + cnt_rtx = gen_rtx (SYMBOL_REF, VOIDmode, counts); \ + SYMBOL_REF_FLAG (cnt_rtx) = TRUE; \ + \ + if (BLOCKNO) \ + cnt_rtx = plus_constant (cnt_rtx, (BLOCKNO)*4); \ + \ + if (flag_pic) \ + cnt_rtx = gen_rtx (PLUS, Pmode, pic_offset_table_rtx, cnt_rtx); \ + \ + xops[0] = gen_rtx (MEM, SImode, cnt_rtx); \ + output_asm_insn (AS1(inc%L0,%0), xops); \ + } \ +while (0) + /* EXIT_IGNORE_STACK should be nonzero if, when returning from a function, the stack pointer does not matter. The value is tested only in functions that have frame pointers. @@ -889,36 +1146,35 @@ do { \ After reload, it makes no difference, since pseudo regs have been eliminated by then. */ -#ifndef REG_OK_STRICT - -/* Nonzero if X is a hard reg that can be used as an index or if - it is a pseudo reg. */ -#define REG_OK_FOR_INDEX_P(X) \ - (REGNO (X) < STACK_POINTER_REGNUM \ +/* Non strict versions, pseudos are ok */ +#define REG_OK_FOR_INDEX_NONSTRICT_P(X) \ + (REGNO (X) < STACK_POINTER_REGNUM \ || REGNO (X) >= FIRST_PSEUDO_REGISTER) -/* Nonzero if X is a hard reg that can be used as a base reg - of if it is a pseudo reg. */ - /* ?wfs */ - -#define REG_OK_FOR_BASE_P(X) \ - (REGNO (X) <= STACK_POINTER_REGNUM \ - || REGNO (X) == ARG_POINTER_REGNUM \ - || REGNO(X) >= FIRST_PSEUDO_REGISTER) +#define REG_OK_FOR_BASE_NONSTRICT_P(X) \ + (REGNO (X) <= STACK_POINTER_REGNUM \ + || REGNO (X) == ARG_POINTER_REGNUM \ + || REGNO (X) >= FIRST_PSEUDO_REGISTER) -#define REG_OK_FOR_STRREG_P(X) \ +#define REG_OK_FOR_STRREG_NONSTRICT_P(X) \ (REGNO (X) == 4 || REGNO (X) == 5 || REGNO (X) >= FIRST_PSEUDO_REGISTER) -#else - -/* Nonzero if X is a hard reg that can be used as an index. */ -#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X)) -/* Nonzero if X is a hard reg that can be used as a base reg. */ -#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X)) -#define REG_OK_FOR_STRREG_P(X) \ +/* Strict versions, hard registers only */ +#define REG_OK_FOR_INDEX_STRICT_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X)) +#define REG_OK_FOR_BASE_STRICT_P(X) REGNO_OK_FOR_BASE_P (REGNO (X)) +#define REG_OK_FOR_STRREG_STRICT_P(X) \ (REGNO_OK_FOR_DIREG_P (REGNO (X)) || REGNO_OK_FOR_SIREG_P (REGNO (X))) +#ifndef REG_OK_STRICT +#define REG_OK_FOR_INDEX_P(X) REG_OK_FOR_INDEX_NONSTRICT_P(X) +#define REG_OK_FOR_BASE_P(X) REG_OK_FOR_BASE_NONSTRICT_P(X) +#define REG_OK_FOR_STRREG_P(X) REG_OK_FOR_STRREG_NONSTRICT_P(X) + +#else +#define REG_OK_FOR_INDEX_P(X) REG_OK_FOR_INDEX_STRICT_P(X) +#define REG_OK_FOR_BASE_P(X) REG_OK_FOR_BASE_STRICT_P(X) +#define REG_OK_FOR_STRREG_P(X) REG_OK_FOR_STRREG_STRICT_P(X) #endif /* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression @@ -944,62 +1200,22 @@ do { \ #define LEGITIMATE_CONSTANT_P(X) 1 -#define GO_IF_INDEXABLE_BASE(X, ADDR) \ - if (GET_CODE (X) == REG && REG_OK_FOR_BASE_P (X)) goto ADDR - -#define LEGITIMATE_INDEX_REG_P(X) \ - (GET_CODE (X) == REG && REG_OK_FOR_INDEX_P (X)) - -/* Return 1 if X is an index or an index times a scale. */ - -#define LEGITIMATE_INDEX_P(X) \ - (LEGITIMATE_INDEX_REG_P (X) \ - || (GET_CODE (X) == MULT \ - && LEGITIMATE_INDEX_REG_P (XEXP (X, 0)) \ - && GET_CODE (XEXP (X, 1)) == CONST_INT \ - && (INTVAL (XEXP (X, 1)) == 2 \ - || INTVAL (XEXP (X, 1)) == 4 \ - || INTVAL (XEXP (X, 1)) == 8))) - -/* Go to ADDR if X is an index term, a base reg, or a sum of those. */ - -#define GO_IF_INDEXING(X, ADDR) \ -{ if (LEGITIMATE_INDEX_P (X)) goto ADDR; \ - GO_IF_INDEXABLE_BASE (X, ADDR); \ - if (GET_CODE (X) == PLUS && LEGITIMATE_INDEX_P (XEXP (X, 0))) \ - { GO_IF_INDEXABLE_BASE (XEXP (X, 1), ADDR); } \ - if (GET_CODE (X) == PLUS && LEGITIMATE_INDEX_P (XEXP (X, 1))) \ - { GO_IF_INDEXABLE_BASE (XEXP (X, 0), ADDR); } } - -/* We used to allow this, but it isn't ever used. - || ((GET_CODE (X) == POST_DEC || GET_CODE (X) == POST_INC) \ - && REG_P (XEXP (X, 0)) \ - && REG_OK_FOR_STRREG_P (XEXP (X, 0))) \ -*/ +#ifdef REG_OK_STRICT +#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ +{ \ + if (legitimate_address_p (MODE, X, 1)) \ + goto ADDR; \ +} -#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ +#else +#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ { \ - if (CONSTANT_ADDRESS_P (X) \ - && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (X))) \ + if (legitimate_address_p (MODE, X, 0)) \ goto ADDR; \ - GO_IF_INDEXING (X, ADDR); \ - if (GET_CODE (X) == PLUS && CONSTANT_ADDRESS_P (XEXP (X, 1))) \ - { \ - rtx x0 = XEXP (X, 0); \ - if (! flag_pic || ! SYMBOLIC_CONST (XEXP (X, 1))) \ - { GO_IF_INDEXING (x0, ADDR); } \ - else if (x0 == pic_offset_table_rtx) \ - goto ADDR; \ - else if (GET_CODE (x0) == PLUS) \ - { \ - if (XEXP (x0, 0) == pic_offset_table_rtx) \ - { GO_IF_INDEXABLE_BASE (XEXP (x0, 1), ADDR); } \ - if (XEXP (x0, 1) == pic_offset_table_rtx) \ - { GO_IF_INDEXABLE_BASE (XEXP (x0, 0), ADDR); } \ - } \ - } \ } +#endif + /* Try machine-dependent ways of modifying an illegitimate address to be legitimate. If we find one, return the new, valid address. This macro is used in only one place: `memory_address' in explow.c. @@ -1021,38 +1237,13 @@ do { \ When -fpic is used, special handling is needed for symbolic references. See comments by legitimize_pic_address in i386.c for details. */ -#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) \ -{ extern rtx legitimize_pic_address (); \ - int ch = (X) != (OLDX); \ - if (flag_pic && SYMBOLIC_CONST (X)) \ - { \ - (X) = legitimize_pic_address (X, 0); \ - if (memory_address_p (MODE, X)) \ - goto WIN; \ - } \ - if (GET_CODE (X) == PLUS) \ - { if (GET_CODE (XEXP (X, 0)) == MULT) \ - ch = 1, XEXP (X, 0) = force_operand (XEXP (X, 0), 0); \ - if (GET_CODE (XEXP (X, 1)) == MULT) \ - ch = 1, XEXP (X, 1) = force_operand (XEXP (X, 1), 0); \ - if (ch && GET_CODE (XEXP (X, 1)) == REG \ - && GET_CODE (XEXP (X, 0)) == REG) \ - goto WIN; \ - if (flag_pic && SYMBOLIC_CONST (XEXP (X, 1))) \ - ch = 1, (X) = legitimize_pic_address (X, 0); \ - if (ch) { GO_IF_LEGITIMATE_ADDRESS (MODE, X, WIN); } \ - if (GET_CODE (XEXP (X, 0)) == REG) \ - { register rtx temp = gen_reg_rtx (Pmode); \ - register rtx val = force_operand (XEXP (X, 1), temp); \ - if (val != temp) emit_move_insn (temp, val); \ - XEXP (X, 1) = temp; \ - goto WIN; } \ - else if (GET_CODE (XEXP (X, 1)) == REG) \ - { register rtx temp = gen_reg_rtx (Pmode); \ - register rtx val = force_operand (XEXP (X, 0), temp); \ - if (val != temp) emit_move_insn (temp, val); \ - XEXP (X, 0) = temp; \ - goto WIN; }}} +#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) \ +{ \ + rtx orig_x = (X); \ + (X) = legitimize_address (X, OLDX, MODE); \ + if (memory_address_p (MODE, X)) \ + goto WIN; \ +} /* Nonzero if the constant value X is a legitimate general operand when generating PIC code. It is given that flag_pic is on and @@ -1101,6 +1292,58 @@ while (0) functions. */ #define INIT_EXPANDERS clear_386_stack_locals () + +/* The `FINALIZE_PIC' macro serves as a hook to emit these special + codes once the function is being compiled into assembly code, but + not before. (It is not done before, because in the case of + compiling an inline function, it would lead to multiple PIC + prologues being included in functions which used inline functions + and were compiled to assembly language.) */ + +#define FINALIZE_PIC \ +do \ + { \ + extern int current_function_uses_pic_offset_table; \ + \ + current_function_uses_pic_offset_table |= profile_flag | profile_block_flag; \ + } \ +while (0) + + +/* If defined, a C expression whose value is nonzero if IDENTIFIER + with arguments ARGS is a valid machine specific attribute for DECL. + The attributes in ATTRIBUTES have previously been assigned to DECL. */ + +#define VALID_MACHINE_DECL_ATTRIBUTE(DECL, ATTRIBUTES, NAME, ARGS) \ + (i386_valid_decl_attribute_p (DECL, ATTRIBUTES, NAME, ARGS)) + +/* If defined, a C expression whose value is nonzero if IDENTIFIER + with arguments ARGS is a valid machine specific attribute for TYPE. + The attributes in ATTRIBUTES have previously been assigned to TYPE. */ + +#define VALID_MACHINE_TYPE_ATTRIBUTE(TYPE, ATTRIBUTES, NAME, ARGS) \ + (i386_valid_type_attribute_p (TYPE, ATTRIBUTES, NAME, ARGS)) + +/* If defined, a C expression whose value is zero if the attributes on + TYPE1 and TYPE2 are incompatible, one if they are compatible, and + two if they are nearly compatible (which causes a warning to be + generated). */ + +#define COMP_TYPE_ATTRIBUTES(TYPE1, TYPE2) \ + (i386_comp_type_attributes (TYPE1, TYPE2)) + +/* If defined, a C statement that assigns default attributes to newly + defined TYPE. */ + +/* #define SET_DEFAULT_TYPE_ATTRIBUTES (TYPE) */ + +/* Max number of args passed in registers. If this is more than 3, we will + have problems with ebx (register #4), since it is a caller save register and + is also used as the pic register in ELF. So for now, don't allow more than + 3 registers to be passed in registers. */ + +#define REGPARM_MAX 3 + /* Specify the machine mode that this machine uses for the index in the tablejump instruction. */ @@ -1172,24 +1415,34 @@ while (0) /* Define this if addresses of constant functions shouldn't be put through pseudo regs where they can be cse'd. Desirable on the 386 because a CALL with a constant address is - not much slower than one with a register address. */ + not much slower than one with a register address. On a 486, + it is faster to call with a constant address than indirect. */ #define NO_FUNCTION_CSE /* Provide the costs of a rtl expression. This is in the body of a switch on CODE. */ -#define RTX_COSTS(X,CODE,OUTER_CODE) \ - case MULT: \ - return COSTS_N_INSNS (10); \ - case DIV: \ - case UDIV: \ - case MOD: \ - case UMOD: \ - return COSTS_N_INSNS (40); \ - case PLUS: \ - if (GET_CODE (XEXP (X, 0)) == REG \ - && GET_CODE (XEXP (X, 1)) == CONST_INT) \ - return 1; \ +#define RTX_COSTS(X,CODE,OUTER_CODE) \ + case MULT: \ + return COSTS_N_INSNS (20); \ + case DIV: \ + case UDIV: \ + case MOD: \ + case UMOD: \ + return COSTS_N_INSNS (20); \ + case ASHIFTRT: \ + case LSHIFTRT: \ + case ASHIFT: \ + return (4 + rtx_cost (XEXP (X, 0), OUTER_CODE) \ + + rtx_cost (XEXP (X, 1), OUTER_CODE)); \ + case PLUS: \ + if (GET_CODE (XEXP (X, 0)) == MULT \ + && GET_CODE (XEXP (XEXP (X, 0), 1)) == CONST_INT \ + && (INTVAL (XEXP (XEXP (X, 0), 1)) == 2 \ + || INTVAL (XEXP (XEXP (X, 0), 1)) == 4 \ + || INTVAL (XEXP (XEXP (X, 0), 1)) == 8)) \ + return (2 + rtx_cost (XEXP (XEXP (X, 0), 0), OUTER_CODE) \ + + rtx_cost (XEXP (X, 1), OUTER_CODE)); \ break; @@ -1259,7 +1512,6 @@ while (0) stored from the compare operation. Note that we can't use "rtx" here since it hasn't been defined! */ -extern struct rtx_def *i386_compare_op0, *i386_compare_op1; extern struct rtx_def *(*i386_compare_gen)(), *(*i386_compare_gen_eq)(); /* Tell final.c how to eliminate redundant test instructions. */ @@ -1365,19 +1617,38 @@ number as al, and ax. /* This is how to output an assembler line defining a `double' constant. */ -#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ - fprintf (FILE, "%s %.22e\n", ASM_DOUBLE, (VALUE)) +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ +do { long l[2]; \ + REAL_VALUE_TO_TARGET_DOUBLE (VALUE, l); \ + if (sizeof (int) == sizeof (long)) \ + fprintf (FILE, "%s 0x%x,0x%x\n", ASM_LONG, l[0], l[1]); \ + else \ + fprintf (FILE, "%s 0x%lx,0x%lx\n", ASM_LONG, l[0], l[1]); \ + } while (0) + +/* This is how to output a `long double' extended real constant. */ +#undef ASM_OUTPUT_LONG_DOUBLE +#define ASM_OUTPUT_LONG_DOUBLE(FILE,VALUE) \ +do { long l[3]; \ + REAL_VALUE_TO_TARGET_LONG_DOUBLE (VALUE, l); \ + if (sizeof (int) == sizeof (long)) \ + fprintf (FILE, "%s 0x%x,0x%x,0x%x\n", ASM_LONG, l[0], l[1], l[2]); \ + else \ + fprintf (FILE, "%s 0x%lx,0x%lx,0x%lx\n", ASM_LONG, l[0], l[1], l[2]); \ + } while (0) /* This is how to output an assembler line defining a `float' constant. */ -#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ -do { union { float f; long l;} tem; \ - tem.f = (VALUE); \ - fprintf((FILE), "%s 0x%x\n", ASM_LONG, tem.l); \ +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ +do { long l; \ + REAL_VALUE_TO_TARGET_SINGLE (VALUE, l); \ + if (sizeof (int) == sizeof (long)) \ + fprintf ((FILE), "%s 0x%x\n", ASM_LONG, l); \ + else \ + fprintf ((FILE), "%s 0x%lx\n", ASM_LONG, l); \ } while (0) - /* Store in OUTPUT a string (made with alloca) containing an assembler-name for a local static variable named NAME. LABELNO is an integer which is different for each call. */ @@ -1471,7 +1742,7 @@ do { union { float f; long l;} tem; \ On the 80386, we use several such letters: f -- float insn (print a CONST_DOUBLE as a float rather than in hex). - L,W,B,Q,S -- print the opcode suffix for specified size of operand. + L,W,B,Q,S,T -- print the opcode suffix for specified size of operand. R -- print the prefix for register names. z -- print the opcode suffix for the size of the current operand. * -- print a star (in certain assembler syntax) @@ -1512,6 +1783,7 @@ extern char *qi_high_reg_name[]; } \ case 4: \ case 8: \ + case 12: \ if (! FP_REG_P (X)) fputs ("e", FILE); \ case 2: \ fputs (hi_reg_name[REGNO (X)], FILE); \ @@ -1544,11 +1816,12 @@ extern char *qi_high_reg_name[]; { fputs ("argp", FILE); break; } \ if (STACK_TOP_P (X)) \ { fputs ("st(0)", FILE); break; } \ + if (FP_REG_P (X)) \ + { fputs (hi_name[REGNO(X)], FILE); break; } \ switch (GET_MODE_SIZE (GET_MODE (X))) \ { \ - case 8: \ - case 4: \ - if (! FP_REG_P (X)) fputs ("e", FILE); \ + default: \ + fputs ("e", FILE); \ case 2: \ fputs (hi_name[REGNO (X)], FILE); \ break; \ @@ -1584,6 +1857,76 @@ extern char *qi_high_reg_name[]; #define RET return "" #define AT_SP(mode) (gen_rtx (MEM, (mode), stack_pointer_rtx)) +/* Functions in i386.c */ +extern void override_options (); +extern void order_regs_for_local_alloc (); +extern int i386_valid_decl_attribute_p (); +extern int i386_valid_type_attribute_p (); +extern int i386_return_pops_args (); +extern int i386_comp_type_attributes (); +extern void init_cumulative_args (); +extern void function_arg_advance (); +extern struct rtx_def *function_arg (); +extern int function_arg_partial_nregs (); +extern void output_op_from_reg (); +extern void output_to_reg (); +extern char *singlemove_string (); +extern char *output_move_double (); +extern char *output_move_memory (); +extern char *output_move_pushmem (); +extern int standard_80387_constant_p (); +extern char *output_move_const_single (); +extern int symbolic_operand (); +extern int call_insn_operand (); +extern int expander_call_insn_operand (); +extern int symbolic_reference_mentioned_p (); +extern void emit_pic_move (); +extern void function_prologue (); +extern int simple_386_epilogue (); +extern void function_epilogue (); +extern int legitimate_address_p (); +extern struct rtx_def *legitimize_pic_address (); +extern struct rtx_def *legitimize_address (); +extern void print_operand (); +extern void print_operand_address (); +extern void notice_update_cc (); +extern void split_di (); +extern int binary_387_op (); +extern int shift_op (); +extern int VOIDmode_compare_op (); +extern char *output_387_binary_op (); +extern char *output_fix_trunc (); +extern char *output_float_compare (); +extern char *output_fp_cc0_set (); +extern void save_386_machine_status (); +extern void restore_386_machine_status (); +extern void clear_386_stack_locals (); +extern struct rtx_def *assign_386_stack_local (); + +/* Variables in i386.c */ +extern char *i386_reg_alloc_order; /* register allocation order */ +extern char *i386_regparm_string; /* # registers to use to pass args */ +extern char *i386_align_loops_string; /* power of two alignment for loops */ +extern char *i386_align_jumps_string; /* power of two alignment for non-loop jumps */ +extern char *i386_align_funcs_string; /* power of two alignment for functions */ +extern int i386_regparm; /* i386_regparm_string as a number */ +extern int i386_align_loops; /* power of two alignment for loops */ +extern int i386_align_jumps; /* power of two alignment for non-loop jumps */ +extern int i386_align_funcs; /* power of two alignment for functions */ +extern char *hi_reg_name[]; /* names for 16 bit regs */ +extern char *qi_reg_name[]; /* names for 8 bit regs (low) */ +extern char *qi_high_reg_name[]; /* names for 8 bit regs (high) */ +extern enum reg_class regclass_map[]; /* smalled class containing REGNO */ +extern struct rtx_def *i386_compare_op0; /* operand 0 for comparisons */ +extern struct rtx_def *i386_compare_op1; /* operand 1 for comparisons */ + +/* External variables used */ +extern int optimize; /* optimization level */ +extern int obey_regdecls; /* TRUE if stupid register allocation */ + +/* External functions used */ +extern struct rtx_def *force_operand (); + /* Local variables: version-control: t