-/* Definitions of target machine for GNU compiler for Intel 80386.
- Copyright (C) 1988, 1992, 1994 Free Software Foundation, Inc.
+/* Definitions of target machine for GNU compiler for Intel X86
+ (386, 486, Pentium).
+ Copyright (C) 1988, 92, 94, 95, 96, 97, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
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,
independent of assembler syntax or operating system.
#define HALF_PIC_FINISH(STREAM)
#endif
+/* Define the specific costs for a given cpu */
+
+struct processor_costs {
+ int add; /* cost of an add instruction */
+ int lea; /* cost of a lea instruction */
+ int shift_var; /* variable shift costs */
+ int shift_const; /* constant shift costs */
+ int mult_init; /* cost of starting a multiply */
+ int mult_bit; /* cost of multiply per each bit set */
+ int divide; /* cost of a divide/mod */
+};
+
+extern struct processor_costs *ix86_cost;
+
/* Run-time compilation parameters selecting different hardware subsets. */
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_NOTUSED1 000000000002 /* bit not currently used */
+#define MASK_NOTUSED2 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 */
+#define MASK_OMIT_LEAF_FRAME_POINTER 0x00000800 /* omit leaf frame pointers */
+ /* 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_NO_PSEUDO 000010000000 /* Move op's args -> pseudos */
+#define MASK_DEBUG_ARG 000020000000 /* Debug function_arg */
+#define MASK_SCHEDULE_PROLOGUE 000040000000 /* Emit prologue as rtl */
+#define MASK_STACK_PROBE 000100000000 /* Enable stack probing */
+
+/* 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 & 0400)
-
-/* 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}, \
- { "no-fancy-math-387", 0400}, \
- { "fancy-math-387", -0400}, \
- SUBTARGET_SWITCHES \
- { "", TARGET_DEFAULT | TARGET_CPU_DEFAULT}}
-
-/* This is meant to be redefined in the host dependent files */
+#define TARGET_NO_FANCY_MATH_387 (target_flags & MASK_NO_FANCY_MATH_387)
+
+/* Don't create frame pointers for leaf functions */
+#define TARGET_OMIT_LEAF_FRAME_POINTER (target_flags & MASK_OMIT_LEAF_FRAME_POINTER)
+
+/* 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)
+
+/* Emit/Don't emit prologue as rtl */
+#define TARGET_SCHEDULE_PROLOGUE (target_flags & MASK_SCHEDULE_PROLOGUE)
+
+/* 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 */
+#define TARGET_PSEUDO ((target_flags & MASK_NO_PSEUDO) == 0) /* Move op's args into pseudos */
+
+#define TARGET_386 (ix86_cpu == PROCESSOR_I386)
+#define TARGET_486 (ix86_cpu == PROCESSOR_I486)
+#define TARGET_PENTIUM (ix86_cpu == PROCESSOR_PENTIUM)
+#define TARGET_PENTIUMPRO (ix86_cpu == PROCESSOR_PENTIUMPRO)
+#define TARGET_USE_LEAVE (ix86_cpu == PROCESSOR_I386)
+#define TARGET_PUSH_MEMORY (ix86_cpu == PROCESSOR_I386)
+#define TARGET_ZERO_EXTEND_WITH_AND (ix86_cpu != PROCESSOR_I386 \
+ && ix86_cpu != PROCESSOR_PENTIUMPRO)
+#define TARGET_DOUBLE_WITH_ADD (ix86_cpu != PROCESSOR_I386)
+#define TARGET_USE_BIT_TEST (ix86_cpu == PROCESSOR_I386)
+#define TARGET_UNROLL_STRLEN (ix86_cpu != PROCESSOR_I386)
+#define TARGET_USE_Q_REG (ix86_cpu == PROCESSOR_PENTIUM \
+ || ix86_cpu == PROCESSOR_PENTIUMPRO)
+#define TARGET_USE_ANY_REG (ix86_cpu == PROCESSOR_I486)
+#define TARGET_CMOVE (ix86_arch == PROCESSOR_PENTIUMPRO)
+#define TARGET_DEEP_BRANCH_PREDICTION (ix86_cpu == PROCESSOR_PENTIUMPRO)
+#define TARGET_STACK_PROBE (target_flags & MASK_STACK_PROBE)
+
+#define TARGET_SWITCHES \
+{ { "80387", MASK_80387 }, \
+ { "no-80387", -MASK_80387 }, \
+ { "hard-float", MASK_80387 }, \
+ { "soft-float", -MASK_80387 }, \
+ { "no-soft-float", MASK_80387 }, \
+ { "386", 0 }, \
+ { "no-386", 0 }, \
+ { "486", 0 }, \
+ { "no-486", 0 }, \
+ { "pentium", 0 }, \
+ { "pentiumpro", 0 }, \
+ { "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 }, \
+ { "omit-leaf-frame-pointer", MASK_OMIT_LEAF_FRAME_POINTER }, \
+ { "no-omit-leaf-frame-pointer",-MASK_OMIT_LEAF_FRAME_POINTER }, \
+ { "no-wide-multiply", MASK_NO_WIDE_MULTIPLY }, \
+ { "wide-multiply", -MASK_NO_WIDE_MULTIPLY }, \
+ { "schedule-prologue", MASK_SCHEDULE_PROLOGUE }, \
+ { "no-schedule-prologue", -MASK_SCHEDULE_PROLOGUE }, \
+ { "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 }, \
+ { "stack-arg-probe", MASK_STACK_PROBE }, \
+ { "no-stack-arg-probe", -MASK_STACK_PROBE }, \
+ { "windows", 0 }, \
+ { "dll", 0 }, \
+ SUBTARGET_SWITCHES \
+ { "", MASK_SCHEDULE_PROLOGUE | TARGET_DEFAULT}}
+
+/* Which processor to schedule for. The cpu attribute defines a list that
+ mirrors this list, so changes to i386.md must be made at the same time. */
+
+enum processor_type
+ {PROCESSOR_I386, /* 80386 */
+ PROCESSOR_I486, /* 80486DX, 80486SX, 80486DX[24] */
+ PROCESSOR_PENTIUM,
+ PROCESSOR_PENTIUMPRO};
+
+#define PROCESSOR_I386_STRING "i386"
+#define PROCESSOR_I486_STRING "i486"
+#define PROCESSOR_I586_STRING "i586"
+#define PROCESSOR_PENTIUM_STRING "pentium"
+#define PROCESSOR_I686_STRING "i686"
+#define PROCESSOR_PENTIUMPRO_STRING "pentiumpro"
+
+extern enum processor_type ix86_cpu;
+
+extern int ix86_arch;
+
+/* Define the default processor. This is overridden by other tm.h files. */
+#define PROCESSOR_DEFAULT \
+ ((enum processor_type) TARGET_CPU_DEFAULT == PROCESSOR_I486) \
+ ? PROCESSOR_I486 \
+ : ((enum processor_type) TARGET_CPU_DEFAULT == PROCESSOR_PENTIUM) \
+ ? PROCESSOR_PENTIUM \
+ : ((enum processor_type) TARGET_CPU_DEFAULT == PROCESSOR_PENTIUMPRO) \
+ ? PROCESSOR_PENTIUMPRO \
+ : PROCESSOR_I386
+#define PROCESSOR_DEFAULT_STRING \
+ ((enum processor_type) TARGET_CPU_DEFAULT == PROCESSOR_I486) \
+ ? PROCESSOR_I486_STRING \
+ : ((enum processor_type) TARGET_CPU_DEFAULT == PROCESSOR_PENTIUM) \
+ ? PROCESSOR_PENTIUM_STRING \
+ : ((enum processor_type) TARGET_CPU_DEFAULT == PROCESSOR_PENTIUMPRO) \
+ ? PROCESSOR_PENTIUMPRO_STRING \
+ : PROCESSOR_I386_STRING
+
+/* 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 \
+{ { "cpu=", &ix86_cpu_string}, \
+ { "arch=", &ix86_arch_string}, \
+ { "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 }, \
+ { "branch-cost=", &i386_branch_cost_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. */
+
+#define OVERRIDE_OPTIONS override_options ()
+
+/* These are meant to be redefined in the host dependent files */
#define SUBTARGET_SWITCHES
+#define SUBTARGET_OPTIONS
+
+/* Define this to change the optimizations performed by default. */
+#define OPTIMIZATION_OPTIONS(LEVEL,SIZE) optimization_options(LEVEL,SIZE)
+
+/* Specs for the compiler proper */
+
+#ifndef CC1_CPU_SPEC
+#define CC1_CPU_SPEC "\
+%{!mcpu*: \
+%{m386:-mcpu=i386 -march=i386} \
+%{mno-486:-mcpu=i386 -march=i386} \
+%{m486:-mcpu=i486 -march=i486} \
+%{mno-386:-mcpu=i486 -march=i486} \
+%{mno-pentium:-mcpu=i486 -march=i486} \
+%{mpentium:-mcpu=pentium} \
+%{mno-pentiumpro:-mcpu=pentium} \
+%{mpentiumpro:-mcpu=pentiumpro}}"
+#endif
+\f
+#ifndef CPP_CPU_DEFAULT_SPEC
+#if TARGET_CPU_DEFAULT == 1
+#define CPP_CPU_DEFAULT_SPEC "-Di486"
+#else
+#if TARGET_CPU_DEFAULT == 2
+#define CPP_CPU_DEFAULT_SPEC "-Dpentium -Di586"
+#else
+#if TARGET_CPU_DEFAULT == 3
+#define CPP_CPU_DEFAULT_SPEC "-Dpentiumpro -Di686"
+#else
+#define CPP_CPU_DEFAULT_SPEC ""
+#endif
+#endif
+#endif
+#endif /* CPP_CPU_DEFAULT_SPEC */
+
+#ifndef CPP_CPU_SPEC
+#define CPP_CPU_SPEC "\
+-Di386 -Asystem(unix) -Acpu(i386) -Amachine(i386) \
+%{mcpu=i486:-Di486} %{m486:-Di486} \
+%{mpentium:-Dpentium -Di586} %{mcpu=pentium:-Dpentium -Di586} \
+%{mpentiumpro:-Dpentiumpro -Di686} %{mcpu=pentiumpro:-Dpentiumpro -Di686} \
+%{!mcpu*:%{!m486:%{!mpentium*: %[cpp_cpu_default]}}}"
+#endif
-#define OVERRIDE_OPTIONS \
-{ \
- SUBTARGET_OVERRIDE_OPTIONS \
-}
+#ifndef CC1_SPEC
+#define CC1_SPEC "%(cc1_spec) "
+#endif
+
+/* This macro defines names of additional specifications to put in the
+ specs that can be used in various specifications like CC1_SPEC. Its
+ definition is an initializer with a subgrouping for each command option.
+
+ Each subgrouping contains a string constant, that defines the
+ specification name, and a string constant that used by the GNU CC driver
+ program.
+
+ Do not define this macro if it does not need to do anything. */
-/* This is meant to be redefined in the host dependent files */
-#define SUBTARGET_OVERRIDE_OPTIONS
+#ifndef SUBTARGET_EXTRA_SPECS
+#define SUBTARGET_EXTRA_SPECS
+#endif
+
+#define EXTRA_SPECS \
+ { "cpp_cpu_default", CPP_CPU_DEFAULT_SPEC }, \
+ { "cpp_cpu", CPP_CPU_SPEC }, \
+ { "cc1_cpu", CC1_CPU_SPEC }, \
+ SUBTARGET_EXTRA_SPECS
\f
/* target machine storage layout */
/* 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. */
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)
+
+/* If defined, a C expression to compute the alignment given to a
+ constant that is being placed in memory. CONSTANT is the constant
+ and ALIGN is the alignment that the object would ordinarily have.
+ The value of this macro is used instead of that alignment to align
+ the object.
+
+ If this macro is not defined, then ALIGN is used.
+
+ The typical use of this macro is to increase alignment for string
+ constants to be word aligned so that `strcpy' calls that copy
+ constants can be done inline. */
+
+#define CONSTANT_ALIGNMENT(EXP, ALIGN) \
+ (TREE_CODE (EXP) == REAL_CST \
+ ? ((TYPE_MODE (TREE_TYPE (EXP)) == DFmode && (ALIGN) < 64) \
+ ? 64 \
+ : (TYPE_MODE (TREE_TYPE (EXP)) == XFmode && (ALIGN) < 128) \
+ ? 128 \
+ : (ALIGN)) \
+ : TREE_CODE (EXP) == STRING_CST \
+ ? ((TREE_STRING_LENGTH (EXP) >= 31 && (ALIGN) < 256) \
+ ? 256 \
+ : (ALIGN)) \
+ : (ALIGN))
+
+/* If defined, a C expression to compute the alignment for a static
+ variable. TYPE is the data type, and ALIGN is the alignment that
+ the object would ordinarily have. The value of this macro is used
+ instead of that alignment to align the object.
+
+ If this macro is not defined, then ALIGN is used.
+
+ One use of this macro is to increase alignment of medium-size
+ data to make it all fit in fewer cache lines. Another is to
+ cause character arrays to be word-aligned so that `strcpy' calls
+ that copy constants to character arrays can be done inline. */
+
+#define DATA_ALIGNMENT(TYPE, ALIGN) \
+ ((AGGREGATE_TYPE_P (TYPE) \
+ && TYPE_SIZE (TYPE) \
+ && TREE_CODE (TYPE_SIZE (TYPE)) == INTEGER_CST \
+ && (TREE_INT_CST_LOW (TYPE_SIZE (TYPE)) >= 256 \
+ || TREE_INT_CST_HIGH (TYPE_SIZE (TYPE))) && (ALIGN) < 256) \
+ ? 256 \
+ : TREE_CODE (TYPE) == ARRAY_TYPE \
+ ? ((TYPE_MODE (TREE_TYPE (TYPE)) == DFmode && (ALIGN) < 64) \
+ ? 64 \
+ : (TYPE_MODE (TREE_TYPE (TYPE)) == XFmode && (ALIGN) < 128) \
+ ? 128 \
+ : (ALIGN)) \
+ : TREE_CODE (TYPE) == COMPLEX_TYPE \
+ ? ((TYPE_MODE (TYPE) == DCmode && (ALIGN) < 64) \
+ ? 64 \
+ : (TYPE_MODE (TYPE) == XCmode && (ALIGN) < 128) \
+ ? 128 \
+ : (ALIGN)) \
+ : ((TREE_CODE (TYPE) == RECORD_TYPE \
+ || TREE_CODE (TYPE) == UNION_TYPE \
+ || TREE_CODE (TYPE) == QUAL_UNION_TYPE) \
+ && TYPE_FIELDS (TYPE)) \
+ ? ((DECL_MODE (TYPE_FIELDS (TYPE)) == DFmode && (ALIGN) < 64) \
+ ? 64 \
+ : (DECL_MODE (TYPE_FIELDS (TYPE)) == XFmode && (ALIGN) < 128) \
+ ? 128 \
+ : (ALIGN)) \
+ : TREE_CODE (TYPE) == REAL_TYPE \
+ ? ((TYPE_MODE (TYPE) == DFmode && (ALIGN) < 64) \
+ ? 64 \
+ : (TYPE_MODE (TYPE) == XFmode && (ALIGN) < 128) \
+ ? 128 \
+ : (ALIGN)) \
+ : (ALIGN))
/* Set this non-zero if move instructions will actually fail to work
when given unaligned data. */
/* 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 LOOP_ALIGN(LABEL) (i386_align_loops)
+#define LOOP_ALIGN_MAX_SKIP (i386_align_loops_string ? 0 : 7)
/* 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 LABEL_ALIGN_AFTER_BARRIER(LABEL) (i386_align_jumps)
+#define LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP (i386_align_jumps_string ? 0 : 7)
+
\f
/* Standard register usage. */
for details. */
#define STACK_REGS
+#define IS_STACK_MODE(mode) (mode==DFmode || mode==SFmode || mode==XFmode)
/* Number of actual hardware registers.
The hardware registers are assigned numbers for the compiler
/*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. First allocate registers
- for which no insn operand demands that register, next those that are
- demanded by the least number of insns. List frame pointer late and fixed
- egisters last. Note that, in general, we want to put nonsaved registers
- late, but we put bx relatively early since it is not demanded by
- any insn operand. */
+/* 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 \
-/*si,di,bx,cx,dx,ax,bp,sp,st,st1,st2,st3,st4,st5,st6,st7,arg*/ \
-{ 4, 5, 3, 2, 1, 0, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
+/*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 \
: 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) \
- : (int) (MODE) != (int) QImode)
+ && GET_MODE_UNIT_SIZE (MODE) <= (LONG_DOUBLE_TYPE_SIZE == 96 ? 12 : 8))\
+ : (int) (MODE) != (int) QImode ? 1 \
+ : (reload_in_progress | reload_completed) == 1)
/* Value is 1 if it is a good idea to tie two pseudo registers
when one has mode MODE1 and one has mode MODE2.
#define MODES_TIEABLE_P(MODE1, MODE2) ((MODE1) == (MODE2))
-/* A C expression returning the cost of moving data from a register of class
- CLASS1 to one of CLASS2.
-
- On the i386, copying between floating-point and fixed-point
- registers is expensive. */
-
-#define REGISTER_MOVE_COST(CLASS1, CLASS2) \
- (((FLOAT_CLASS_P (CLASS1) && ! FLOAT_CLASS_P (CLASS2)) \
- || (! FLOAT_CLASS_P (CLASS1) && FLOAT_CLASS_P (CLASS2))) ? 10 \
- : 2)
-
/* Specify the registers used for certain standard purposes.
The values of these macros are register numbers. */
Zero means the frame pointer need not be set up (and parms
may be accessed via the stack pointer) in functions that seem suitable.
This is computed in `reload', in reload1.c. */
-#define FRAME_POINTER_REQUIRED 0
+#define FRAME_POINTER_REQUIRED (TARGET_OMIT_LEAF_FRAME_POINTER && !leaf_function_p ())
/* Base register for access to arguments of the function. */
#define ARG_POINTER_REGNUM 16
/* 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)
+
\f
/* Define the classes of registers for register constraints in the
machine description. Also define ranges of constants.
of length N_REG_CLASSES. */
#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 */ \
- 0x100ff, /* GENERAL_REGS */ \
- 0x0100, 0x0200, /* FP_TOP_REG, FP_SECOND_REG */ \
- 0xff00, /* FLOAT_REGS */ \
- 0x1ffff }
+{ {0}, \
+ {0x1}, {0x2}, {0x4}, {0x8}, /* AREG, DREG, CREG, BREG */ \
+ {0x3}, /* AD_REGS */ \
+ {0xf}, /* Q_REGS */ \
+ {0x10}, {0x20}, /* SIREG, DIREG */ \
+ {0x7f}, /* INDEX_REGS */ \
+ {0x100ff}, /* GENERAL_REGS */ \
+ {0x0100}, {0x0200}, /* FP_TOP_REG, FP_SECOND_REG */ \
+ {0xff00}, /* FLOAT_REGS */ \
+ {0x1ffff}}
/* The same information, inverted:
Return the class number of the smallest class containing
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
rtl to be used as spill registers but prevents the compiler from
extending the lifetime of these registers. */
-#define SMALL_REGISTER_CLASSES
+#define SMALL_REGISTER_CLASSES 1
#define QI_REG_P(X) \
(REG_P (X) && REGNO (X) < 4)
(C) == 'K' ? (VALUE) == 0xff : \
(C) == 'L' ? (VALUE) == 0xffff : \
(C) == 'M' ? (VALUE) >= 0 && (VALUE) <= 3 : \
+ (C) == 'N' ? (VALUE) >= 0 && (VALUE) <= 255 :\
+ (C) == 'O' ? (VALUE) >= 0 && (VALUE) <= 32 : \
0)
/* Similar, but for floating constants, and defining letters G and H.
#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))
+
\f
/* Stack layout; function entry, exit and calling. */
/* 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.
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.
-#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 (TREE_TYPE (FUNTYPE))) ? GET_MODE_SIZE (Pmode) : 0)
+ The attribute stdcall is equivalent to RTD on a per module basis. */
+
+#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).
If the precise function being called is known, FUNC is its FUNCTION_DECL;
otherwise, FUNC is 0. */
#define FUNCTION_VALUE(VALTYPE, FUNC) \
- gen_rtx (REG, TYPE_MODE (VALTYPE), \
+ gen_rtx_REG (TYPE_MODE (VALTYPE), \
VALUE_REGNO (TYPE_MODE (VALTYPE)))
/* Define how to find the value returned by a library function
assuming the value has mode MODE. */
#define LIBCALL_VALUE(MODE) \
- gen_rtx (REG, MODE, VALUE_REGNO (MODE))
+ gen_rtx_REG (MODE, VALUE_REGNO (MODE))
/* Define the size of the result block used for communication between
untyped_call and untyped_return. The block contains a DImode value
#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.
+ For a library call, FNTYPE is 0. */
- On the 80386, the offset starts at 0. */
-
-#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE,LIBNAME) \
- ((CUM) = 0)
+#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE,LIBNAME,INDIRECT) \
+ (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,
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 is invoked just before the start of a function.
+ It is used here to output code for -fpic that will load the
+ return address into %ebx. */
+
+#undef ASM_OUTPUT_FUNCTION_PREFIX
+#define ASM_OUTPUT_FUNCTION_PREFIX(FILE, FNNAME) \
+ asm_output_function_prefix (FILE, FNNAME)
/* This macro generates the assembly code for function entry.
FILE is a stdio stream to output the code to.
} \
}
+
+/* There are three profiling modes for basic blocks available.
+ The modes are selected at compile time by using the options
+ -a or -ax of the gnu compiler.
+ The variable `profile_block_flag' will be set according to the
+ selected option.
+
+ profile_block_flag == 0, no option used:
+
+ No profiling done.
+
+ profile_block_flag == 1, -a option used.
+
+ Count frequency of execution of every basic block.
+
+ profile_block_flag == 2, -ax option used.
+
+ Generate code to allow several different profiling modes at run time.
+ Available modes are:
+ Produce a trace of all basic blocks.
+ Count frequency of jump instructions executed.
+ In every mode it is possible to start profiling upon entering
+ certain functions and to disable profiling of some other functions.
+
+ The result of basic-block profiling will be written to a file `bb.out'.
+ If the -ax option is used parameters for the profiling will be read
+ from file `bb.in'.
+
+*/
+
+/* The following macro shall output assembler code to FILE
+ to initialize basic-block profiling.
+
+ If profile_block_flag == 2
+
+ Output code to call the subroutine `__bb_init_trace_func'
+ and pass two parameters to it. The first parameter is
+ the address of a block allocated in the object module.
+ The second parameter is the number of the first basic block
+ of the function.
+
+ 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 number of the first basic block of the function is
+ passed to the macro in BLOCK_OR_LABEL.
+
+ If described in a virtual assembler language the code to be
+ output looks like:
+
+ parameter1 <- LPBX0
+ parameter2 <- BLOCK_OR_LABEL
+ call __bb_init_trace_func
+
+ else if profile_block_flag != 0
+
+ Output code to call the subroutine `__bb_init_func'
+ and pass one single parameter to it, which is the same
+ as the first parameter to `__bb_init_trace_func'.
+
+ The first word of this parameter 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.
+ Note: When profile_block_flag == 2 the test need not be done
+ but `__bb_init_trace_func' *must* be called.
+
+ BLOCK_OR_LABEL may be used to generate a label number as a
+ branch destination in case `__bb_init_func' will not be called.
+
+ If described in a virtual assembler language the code to be
+ output looks like:
+
+ cmp (LPBX0),0
+ jne local_label
+ parameter1 <- LPBX0
+ call __bb_init_func
+local_label:
+
+*/
+
+#undef FUNCTION_BLOCK_PROFILER
+#define FUNCTION_BLOCK_PROFILER(FILE, BLOCK_OR_LABEL) \
+do \
+ { \
+ static int num_func = 0; \
+ rtx xops[8]; \
+ char block_table[80], false_label[80]; \
+ \
+ ASM_GENERATE_INTERNAL_LABEL (block_table, "LPBX", 0); \
+ \
+ xops[1] = gen_rtx_SYMBOL_REF (VOIDmode, block_table); \
+ xops[5] = stack_pointer_rtx; \
+ xops[7] = gen_rtx_REG (Pmode, 0); /* eax */ \
+ \
+ CONSTANT_POOL_ADDRESS_P (xops[1]) = TRUE; \
+ \
+ switch (profile_block_flag) \
+ { \
+ \
+ case 2: \
+ \
+ xops[2] = GEN_INT ((BLOCK_OR_LABEL)); \
+ xops[3] = gen_rtx_MEM (Pmode, gen_rtx_SYMBOL_REF (VOIDmode, "__bb_init_trace_func")); \
+ xops[6] = GEN_INT (8); \
+ \
+ output_asm_insn (AS1(push%L2,%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); \
+ \
+ break; \
+ \
+ default: \
+ \
+ ASM_GENERATE_INTERNAL_LABEL (false_label, "LPBZ", num_func); \
+ \
+ xops[0] = const0_rtx; \
+ 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[6] = GEN_INT (4); \
+ \
+ 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 (FILE, "LPBZ", num_func); \
+ num_func++; \
+ \
+ break; \
+ \
+ } \
+ } \
+while (0)
+
+/* The following macro shall output assembler code to FILE
+ to increment a counter associated with basic block number BLOCKNO.
+
+ If profile_block_flag == 2
+
+ Output code to initialize the global structure `__bb' and
+ call the function `__bb_trace_func' which will increment the
+ counter.
+
+ `__bb' consists of two words. In the first word the number
+ of the basic block has to be stored. In the second word
+ the address of a block allocated in the object module
+ has to be stored.
+
+ The basic block number is given by BLOCKNO.
+
+ The address of the block is given by the label created with
+
+ ASM_GENERATE_INTERNAL_LABEL (BUFFER, "LPBX", 0);
+
+ by FUNCTION_BLOCK_PROFILER.
+
+ 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.
+
+ If described in a virtual assembler language the code to be
+ output looks like:
+
+ move BLOCKNO -> (__bb)
+ move LPBX0 -> (__bb+4)
+ call __bb_trace_func
+
+ Note that function `__bb_trace_func' must not change the
+ machine state, especially the flag register. To grant
+ this, you must output code to save and restore registers
+ either in this macro or in the macros MACHINE_STATE_SAVE
+ and MACHINE_STATE_RESTORE. The last two macros will be
+ used in the function `__bb_trace_func', so you must make
+ sure that the function prologue does not change any
+ register prior to saving it with MACHINE_STATE_SAVE.
+
+ else if profile_block_flag != 0
+
+ Output code to increment the counter directly.
+ Basic blocks are numbered separately from zero within each
+ compiled object module. The count associated with block number
+ BLOCKNO is at index BLOCKNO in an array 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.
+
+ If described in a virtual assembler language the code to be
+ output looks like:
+
+ inc (LPBX2+4*BLOCKNO)
+
+*/
+
+#define BLOCK_PROFILER(FILE, BLOCKNO) \
+do \
+ { \
+ rtx xops[8], cnt_rtx; \
+ char counts[80]; \
+ char *block_table = counts; \
+ \
+ switch (profile_block_flag) \
+ { \
+ \
+ case 2: \
+ \
+ ASM_GENERATE_INTERNAL_LABEL (block_table, "LPBX", 0); \
+ \
+ xops[1] = gen_rtx_SYMBOL_REF (VOIDmode, block_table); \
+ xops[2] = GEN_INT ((BLOCKNO)); \
+ xops[3] = gen_rtx_MEM (Pmode, gen_rtx_SYMBOL_REF (VOIDmode, "__bb_trace_func")); \
+ xops[4] = gen_rtx_SYMBOL_REF (VOIDmode, "__bb"); \
+ xops[5] = plus_constant (xops[4], 4); \
+ xops[0] = gen_rtx_MEM (SImode, xops[4]); \
+ xops[6] = gen_rtx_MEM (SImode, xops[5]); \
+ \
+ CONSTANT_POOL_ADDRESS_P (xops[1]) = TRUE; \
+ \
+ fprintf(FILE, "\tpushf\n"); \
+ output_asm_insn (AS2(mov%L0,%2,%0), xops); \
+ if (flag_pic) \
+ { \
+ xops[7] = gen_rtx_REG (Pmode, 0); /* eax */ \
+ output_asm_insn (AS1(push%L7,%7), xops); \
+ output_asm_insn (AS2(lea%L7,%a1,%7), xops); \
+ output_asm_insn (AS2(mov%L6,%7,%6), xops); \
+ output_asm_insn (AS1(pop%L7,%7), xops); \
+ } \
+ else \
+ output_asm_insn (AS2(mov%L6,%1,%6), xops); \
+ output_asm_insn (AS1(call,%P3), xops); \
+ fprintf(FILE, "\tpopf\n"); \
+ \
+ break; \
+ \
+ default: \
+ \
+ 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); \
+ \
+ break; \
+ \
+ } \
+ } \
+while (0)
+
+/* The following macro shall output assembler code to FILE
+ to indicate a return from function during basic-block profiling.
+
+ If profiling_block_flag == 2:
+
+ Output assembler code to call function `__bb_trace_ret'.
+
+ Note that function `__bb_trace_ret' must not change the
+ machine state, especially the flag register. To grant
+ this, you must output code to save and restore registers
+ either in this macro or in the macros MACHINE_STATE_SAVE_RET
+ and MACHINE_STATE_RESTORE_RET. The last two macros will be
+ used in the function `__bb_trace_ret', so you must make
+ sure that the function prologue does not change any
+ register prior to saving it with MACHINE_STATE_SAVE_RET.
+
+ else if profiling_block_flag != 0:
+
+ The macro will not be used, so it need not distinguish
+ these cases.
+*/
+
+#define FUNCTION_BLOCK_PROFILER_EXIT(FILE) \
+do \
+ { \
+ rtx xops[1]; \
+ \
+ xops[0] = gen_rtx_MEM (Pmode, gen_rtx_SYMBOL_REF (VOIDmode, "__bb_trace_ret")); \
+ \
+ output_asm_insn (AS1(call,%P0), xops); \
+ \
+ } \
+while (0)
+
+/* The function `__bb_trace_func' is called in every basic block
+ and is not allowed to change the machine state. Saving (restoring)
+ the state can either be done in the BLOCK_PROFILER macro,
+ before calling function (rsp. after returning from function)
+ `__bb_trace_func', or it can be done inside the function by
+ defining the macros:
+
+ MACHINE_STATE_SAVE(ID)
+ MACHINE_STATE_RESTORE(ID)
+
+ In the latter case care must be taken, that the prologue code
+ of function `__bb_trace_func' does not already change the
+ state prior to saving it with MACHINE_STATE_SAVE.
+
+ The parameter `ID' is a string identifying a unique macro use.
+
+ On the i386 the initialization code at the begin of
+ function `__bb_trace_func' contains a `sub' instruction
+ therefore we handle save and restore of the flag register
+ in the BLOCK_PROFILER macro. */
+
+#define MACHINE_STATE_SAVE(ID) \
+ asm (" pushl %eax"); \
+ asm (" pushl %ecx"); \
+ asm (" pushl %edx"); \
+ asm (" pushl %esi");
+
+#define MACHINE_STATE_RESTORE(ID) \
+ asm (" popl %esi"); \
+ asm (" popl %edx"); \
+ asm (" popl %ecx"); \
+ asm (" popl %eax");
+
/* 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.
off the end. This happens if the function ends in an "exit" call, or
if a `return' insn is emitted directly into the function. */
-#define FUNCTION_EPILOGUE(FILE, SIZE) \
+#if 0
+#define FUNCTION_BEGIN_EPILOGUE(FILE) \
do { \
rtx last = get_last_insn (); \
if (last && GET_CODE (last) == NOTE) \
last = prev_nonnote_insn (last); \
- if (! last || GET_CODE (last) != BARRIER) \
- function_epilogue (FILE, SIZE); \
+/* if (! last || GET_CODE (last) != BARRIER) \
+ function_epilogue (FILE, SIZE);*/ \
} while (0)
+#endif
+
+#define FUNCTION_EPILOGUE(FILE, SIZE) \
+ function_epilogue (FILE, SIZE)
/* Output assembler code for a block containing the constant parts
of a trampoline, leaving space for the variable parts. */
#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT) \
{ \
- emit_move_insn (gen_rtx (MEM, SImode, plus_constant (TRAMP, 1)), CXT); \
- emit_move_insn (gen_rtx (MEM, SImode, plus_constant (TRAMP, 6)), FNADDR); \
+ emit_move_insn (gen_rtx_MEM (SImode, plus_constant (TRAMP, 1)), CXT); \
+ emit_move_insn (gen_rtx_MEM (SImode, plus_constant (TRAMP, 6)), FNADDR); \
}
\f
/* Definitions for register eliminations.
\
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) \
if ((regs_ever_live[regno] && ! call_used_regs[regno]) \
- || (current_function_uses_pic_offset_table \
- && regno == PIC_OFFSET_TABLE_REGNUM)) \
+ || ((current_function_uses_pic_offset_table \
+ || current_function_uses_const_pool) \
+ && flag_pic && regno == PIC_OFFSET_TABLE_REGNUM)) \
offset += 4; \
\
(OFFSET) = offset + get_frame_size (); \
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
#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.
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) \
+{ \
+ (X) = legitimize_address (X, OLDX, MODE); \
+ if (memory_address_p (MODE, X)) \
+ goto WIN; \
+}
+
+#define REWRITE_ADDRESS(x) rewrite_address(x)
/* Nonzero if the constant value X is a legitimate general operand
when generating PIC code. It is given that flag_pic is on and
{ \
rtx rtl = (TREE_CODE_CLASS (TREE_CODE (DECL)) != 'd' \
? TREE_CST_RTL (DECL) : DECL_RTL (DECL)); \
+ \
+ if (TARGET_DEBUG_ADDR \
+ && TREE_CODE_CLASS (TREE_CODE (DECL)) == 'd') \
+ { \
+ fprintf (stderr, "Encode %s, public = %d\n", \
+ IDENTIFIER_POINTER (DECL_NAME (DECL)), \
+ TREE_PUBLIC (DECL)); \
+ } \
+ \
SYMBOL_REF_FLAG (XEXP (rtl, 0)) \
= (TREE_CODE_CLASS (TREE_CODE (DECL)) != 'd' \
|| ! TREE_PUBLIC (DECL)); \
} \
while (0)
+\f
+/* 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
+
\f
/* Specify the machine mode that this machine uses
for the index in the tablejump instruction. */
#define CASE_VECTOR_MODE Pmode
-/* Define this if the tablejump instruction expects the table
- to contain offsets from the address of the table.
- Do not define this if the table should contain absolute addresses. */
-/* #define CASE_VECTOR_PC_RELATIVE */
+/* Define as C expression which evaluates to nonzero if the tablejump
+ instruction expects the table to contain offsets from the address of the
+ table.
+ Do not define this if the table should contain absolute addresses. */
+/* #define CASE_VECTOR_PC_RELATIVE 1 */
/* Specify the tree operation to be used to convert reals to integers.
This should be changed to take advantage of fist --wfs ??
in one reasonably fast instruction. */
#define MOVE_MAX 4
-/* MOVE_RATIO is the number of move instructions that is better than a
- block move. Make this large on i386, since the block move is very
- inefficient with small blocks, and the hard register needs of the
- block move require much reload work. */
-#define MOVE_RATIO 5
+/* The number of scalar move insns which should be generated instead
+ of a string move insn or a library call. Increasing the value
+ will always make code faster, but eventually incurs high cost in
+ increased code size.
-/* Define this if zero-extension is slow (more than one real instruction). */
-/* #define SLOW_ZERO_EXTEND */
+ If you don't define this, a reasonable default is used.
-/* Nonzero if access to memory by bytes is slow and undesirable. */
-#define SLOW_BYTE_ACCESS 0
+ Make this large on i386, since the block move is very inefficient with small
+ blocks, and the hard register needs of the block move require much reload
+ work. */
+
+#define MOVE_RATIO 5
/* Define if shifts truncate the shift count
which implies one can omit a sign-extension or zero-extension
of a shift count. */
-/* One i386, shifts do truncate the count. But bit opcodes don't. */
+/* On i386, shifts do truncate the count. But bit opcodes don't. */
/* #define SHIFT_COUNT_TRUNCATED */
is a byte address (for indexing purposes)
so give the MEM rtx a byte's mode. */
#define FUNCTION_MODE QImode
-
-/* 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. */
-#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; \
- break;
-
-
-/* Compute the cost of computing a constant rtl expression RTX
- whose rtx-code is CODE. The body of this macro is a portion
- of a switch statement. If the code is computed here,
- return it with a return statement. Otherwise, break from the switch. */
+\f
+/* A part of a C `switch' statement that describes the relative costs
+ of constant RTL expressions. It must contain `case' labels for
+ expression codes `const_int', `const', `symbol_ref', `label_ref'
+ and `const_double'. Each case must ultimately reach a `return'
+ statement to return the relative cost of the use of that kind of
+ constant value in an expression. The cost may depend on the
+ precise value of the constant, which is available for examination
+ in X, and the rtx code of the expression in which it is contained,
+ found in OUTER_CODE.
+
+ CODE is the expression code--redundant, since it can be obtained
+ with `GET_CODE (X)'. */
#define CONST_COSTS(RTX,CODE,OUTER_CODE) \
case CONST_INT: \
+ return (unsigned) INTVAL (RTX) < 256 ? 0 : 1; \
case CONST: \
case LABEL_REF: \
case SYMBOL_REF: \
- return flag_pic && SYMBOLIC_CONST (RTX) ? 2 : 0; \
+ return flag_pic && SYMBOLIC_CONST (RTX) ? 2 : 1; \
+ \
case CONST_DOUBLE: \
{ \
int code; \
if (GET_MODE (RTX) == VOIDmode) \
return 2; \
+ \
code = standard_80387_constant_p (RTX); \
return code == 1 ? 0 : \
code == 2 ? 1 : \
2; \
}
-/* Compute the cost of an address. This is meant to approximate the size
- and/or execution delay of an insn using that address. If the cost is
- approximated by the RTL complexity, including CONST_COSTS above, as
- is usually the case for CISC machines, this macro should not be defined.
- For aggressively RISCy machines, only one insn format is allowed, so
- this macro should be a constant. The value of this macro only matters
- for valid addresses.
+/* Delete the definition here when TOPLEVEL_COSTS_N_INSNS gets added to cse.c */
+#define TOPLEVEL_COSTS_N_INSNS(N) {total = COSTS_N_INSNS (N); break;}
+
+/* Like `CONST_COSTS' but applies to nonconstant RTL expressions.
+ This can be used, for example, to indicate how costly a multiply
+ instruction is. In writing this macro, you can use the construct
+ `COSTS_N_INSNS (N)' to specify a cost equal to N fast
+ instructions. OUTER_CODE is the code of the expression in which X
+ is contained.
+
+ This macro is optional; do not define it if the default cost
+ assumptions are adequate for the target machine. */
+
+#define RTX_COSTS(X,CODE,OUTER_CODE) \
+ case ASHIFT: \
+ if (GET_CODE (XEXP (X, 1)) == CONST_INT \
+ && GET_MODE (XEXP (X, 0)) == SImode) \
+ { \
+ HOST_WIDE_INT value = INTVAL (XEXP (X, 1)); \
+ \
+ if (value == 1) \
+ return COSTS_N_INSNS (ix86_cost->add) \
+ + rtx_cost(XEXP (X, 0), OUTER_CODE); \
+ \
+ if (value == 2 || value == 3) \
+ return COSTS_N_INSNS (ix86_cost->lea) \
+ + rtx_cost(XEXP (X, 0), OUTER_CODE); \
+ } \
+ /* fall through */ \
+ \
+ case ROTATE: \
+ case ASHIFTRT: \
+ case LSHIFTRT: \
+ case ROTATERT: \
+ if (GET_MODE (XEXP (X, 0)) == DImode) \
+ { \
+ if (GET_CODE (XEXP (X, 1)) == CONST_INT) \
+ { \
+ if (INTVAL (XEXP (X, 1)) > 32) \
+ return COSTS_N_INSNS(ix86_cost->shift_const + 2); \
+ return COSTS_N_INSNS(ix86_cost->shift_const * 2); \
+ } \
+ return ((GET_CODE (XEXP (X, 1)) == AND \
+ ? COSTS_N_INSNS(ix86_cost->shift_var * 2) \
+ : COSTS_N_INSNS(ix86_cost->shift_var * 6 + 2)) \
+ + rtx_cost(XEXP (X, 0), OUTER_CODE)); \
+ } \
+ return COSTS_N_INSNS (GET_CODE (XEXP (X, 1)) == CONST_INT \
+ ? ix86_cost->shift_const \
+ : ix86_cost->shift_var) \
+ + rtx_cost(XEXP (X, 0), OUTER_CODE); \
+ \
+ case MULT: \
+ if (GET_CODE (XEXP (X, 1)) == CONST_INT) \
+ { \
+ unsigned HOST_WIDE_INT value = INTVAL (XEXP (X, 1)); \
+ int nbits = 0; \
+ \
+ if (value == 2) \
+ return COSTS_N_INSNS (ix86_cost->add) \
+ + rtx_cost(XEXP (X, 0), OUTER_CODE); \
+ if (value == 4 || value == 8) \
+ return COSTS_N_INSNS (ix86_cost->lea) \
+ + rtx_cost(XEXP (X, 0), OUTER_CODE); \
+ \
+ while (value != 0) \
+ { \
+ nbits++; \
+ value >>= 1; \
+ } \
+ \
+ if (nbits == 1) \
+ return COSTS_N_INSNS (ix86_cost->shift_const) \
+ + rtx_cost(XEXP (X, 0), OUTER_CODE); \
+ \
+ return COSTS_N_INSNS (ix86_cost->mult_init \
+ + nbits * ix86_cost->mult_bit) \
+ + rtx_cost(XEXP (X, 0), OUTER_CODE); \
+ } \
+ \
+ else /* This is arbitrary */ \
+ TOPLEVEL_COSTS_N_INSNS (ix86_cost->mult_init \
+ + 7 * ix86_cost->mult_bit); \
+ \
+ case DIV: \
+ case UDIV: \
+ case MOD: \
+ case UMOD: \
+ TOPLEVEL_COSTS_N_INSNS (ix86_cost->divide); \
+ \
+ case PLUS: \
+ if (GET_CODE (XEXP (X, 0)) == REG \
+ && GET_MODE (XEXP (X, 0)) == SImode \
+ && GET_CODE (XEXP (X, 1)) == PLUS) \
+ return COSTS_N_INSNS (ix86_cost->lea); \
+ \
+ /* fall through */ \
+ case AND: \
+ case IOR: \
+ case XOR: \
+ case MINUS: \
+ if (GET_MODE (X) == DImode) \
+ return COSTS_N_INSNS (ix86_cost->add) * 2 \
+ + (rtx_cost (XEXP (X, 0), OUTER_CODE) \
+ << (GET_MODE (XEXP (X, 0)) != DImode)) \
+ + (rtx_cost (XEXP (X, 1), OUTER_CODE) \
+ << (GET_MODE (XEXP (X, 1)) != DImode)); \
+ case NEG: \
+ case NOT: \
+ if (GET_MODE (X) == DImode) \
+ TOPLEVEL_COSTS_N_INSNS (ix86_cost->add * 2) \
+ TOPLEVEL_COSTS_N_INSNS (ix86_cost->add)
+
+
+/* An expression giving the cost of an addressing mode that contains
+ ADDRESS. If not defined, the cost is computed from the ADDRESS
+ expression and the `CONST_COSTS' values.
+
+ For most CISC machines, the default cost is a good approximation
+ of the true cost of the addressing mode. However, on RISC
+ machines, all instructions normally have the same length and
+ execution time. Hence all addresses will have equal costs.
+
+ In cases where more than one form of an address is known, the form
+ with the lowest cost will be used. If multiple forms have the
+ same, lowest, cost, the one that is the most complex will be used.
+
+ For example, suppose an address that is equal to the sum of a
+ register and a constant is used twice in the same basic block.
+ When this macro is not defined, the address will be computed in a
+ register and memory references will be indirect through that
+ register. On machines where the cost of the addressing mode
+ containing the sum is no higher than that of a simple indirect
+ reference, this will produce an additional instruction and
+ possibly require an additional register. Proper specification of
+ this macro eliminates this overhead for such machines.
+
+ Similar use of this macro is made in strength reduction of loops.
+
+ ADDRESS need not be valid as an address. In such a case, the cost
+ is not relevant and can be any value; invalid addresses need not be
+ assigned a different cost.
+
+ On machines where an address involving more than one register is as
+ cheap as an address computation involving only one register,
+ defining `ADDRESS_COST' to reflect this can cause two registers to
+ be live over a region of code where only one would have been if
+ `ADDRESS_COST' were not defined in that manner. This effect should
+ be considered in the definition of this macro. Equivalent costs
+ should probably only be given to addresses with different numbers
+ of registers on machines with lots of registers.
+
+ This macro will normally either not be defined or be defined as a
+ constant.
For i386, it is better to use a complex address than let gcc copy
the address into a reg and make a new pseudo. But not if the address
&& REG_P (XEXP (RTX, 0)))) ? 0 \
: REG_P (RTX) ? 1 \
: 2)
+
+/* A C expression for the cost of moving data of mode M between a
+ register and memory. A value of 2 is the default; this cost is
+ relative to those in `REGISTER_MOVE_COST'.
+
+ If moving between registers and memory is more expensive than
+ between two registers, you should define this macro to express the
+ relative cost.
+
+ On the i386, copying between floating-point and fixed-point
+ registers is expensive. */
+
+#define REGISTER_MOVE_COST(CLASS1, CLASS2) \
+ (((FLOAT_CLASS_P (CLASS1) && ! FLOAT_CLASS_P (CLASS2)) \
+ || (! FLOAT_CLASS_P (CLASS1) && FLOAT_CLASS_P (CLASS2))) ? 10 \
+ : 2)
+
+
+/* A C expression for the cost of moving data of mode M between a
+ register and memory. A value of 2 is the default; this cost is
+ relative to those in `REGISTER_MOVE_COST'.
+
+ If moving between registers and memory is more expensive than
+ between two registers, you should define this macro to express the
+ relative cost. */
+
+/* #define MEMORY_MOVE_COST(M,C,I) 2 */
+
+/* A C expression for the cost of a branch instruction. A value of 1
+ is the default; other values are interpreted relative to that. */
+
+#define BRANCH_COST i386_branch_cost
+
+/* Define this macro as a C expression which is nonzero if accessing
+ less than a word of memory (i.e. a `char' or a `short') is no
+ faster than accessing a word of memory, i.e., if such access
+ require more than one instruction or if there is no difference in
+ cost between byte and (aligned) word loads.
+
+ When this macro is not defined, the compiler will access a field by
+ finding the smallest containing object; when it is defined, a
+ fullword load will be used if alignment permits. Unless bytes
+ accesses are faster than word accesses, using word accesses is
+ preferable since it may eliminate subsequent memory access if
+ subsequent accesses occur to other fields in the same word of the
+ structure, but to different bytes. */
+
+#define SLOW_BYTE_ACCESS 0
+
+/* Nonzero if access to memory by shorts is slow and undesirable. */
+#define SLOW_SHORT_ACCESS 0
+
+/* Define this macro if zero-extension (of a `char' or `short' to an
+ `int') can be done faster if the destination is a register that is
+ known to be zero.
+
+ If you define this macro, you must have instruction patterns that
+ recognize RTL structures like this:
+
+ (set (strict_low_part (subreg:QI (reg:SI ...) 0)) ...)
+
+ and likewise for `HImode'. */
+
+/* #define SLOW_ZERO_EXTEND */
+
+/* Define this macro to be the value 1 if unaligned accesses have a
+ cost many times greater than aligned accesses, for example if they
+ are emulated in a trap handler.
+
+ When this macro is non-zero, the compiler will act as if
+ `STRICT_ALIGNMENT' were non-zero when generating code for block
+ moves. This can cause significantly more instructions to be
+ produced. Therefore, do not set this macro non-zero if unaligned
+ accesses only add a cycle or two to the time for a memory access.
+
+ If the value of this macro is always zero, it need not be defined. */
+
+/* #define SLOW_UNALIGNED_ACCESS 0 */
+
+/* Define this macro to inhibit strength reduction of memory
+ addresses. (On some machines, such strength reduction seems to do
+ harm rather than good.) */
+
+/* #define DONT_REDUCE_ADDR */
+
+/* Define this macro if it is as good or better to call a constant
+ function address than to call an address kept in a register.
+
+ Desirable on the 386 because a CALL with a constant address is
+ faster than one with a register address. */
+
+#define NO_FUNCTION_CSE
+
+/* Define this macro if it is as good or better for a function to call
+ itself with an explicit address than to call an address kept in a
+ register. */
+
+#define NO_RECURSIVE_FUNCTION_CSE
+
+/* A C statement (sans semicolon) to update the integer variable COST
+ based on the relationship between INSN that is dependent on
+ DEP_INSN through the dependence LINK. The default is to make no
+ adjustment to COST. This can be used for example to specify to
+ the scheduler that an output- or anti-dependence does not incur
+ the same cost as a data-dependence. */
+
+#define ADJUST_COST(insn,link,dep_insn,cost) \
+ { \
+ rtx next_inst; \
+ if (GET_CODE (dep_insn) == CALL_INSN) \
+ (cost) = 0; \
+ \
+ else if (GET_CODE (dep_insn) == INSN \
+ && GET_CODE (PATTERN (dep_insn)) == SET \
+ && GET_CODE (SET_DEST (PATTERN (dep_insn))) == REG \
+ && GET_CODE (insn) == INSN \
+ && GET_CODE (PATTERN (insn)) == SET \
+ && !reg_overlap_mentioned_p (SET_DEST (PATTERN (dep_insn)), \
+ SET_SRC (PATTERN (insn)))) \
+ { \
+ (cost) = 0; \
+ } \
+ \
+ else if (GET_CODE (insn) == JUMP_INSN) \
+ { \
+ (cost) = 0; \
+ } \
+ \
+ if (TARGET_PENTIUM) \
+ { \
+ if (cost !=0 && is_fp_insn (insn) && is_fp_insn (dep_insn) \
+ && !is_fp_dest (dep_insn)) \
+ { \
+ (cost) = 0; \
+ } \
+ \
+ if (agi_dependent (insn, dep_insn)) \
+ { \
+ (cost) = 3; \
+ } \
+ else if (GET_CODE (insn) == INSN \
+ && GET_CODE (PATTERN (insn)) == SET \
+ && SET_DEST (PATTERN (insn)) == cc0_rtx \
+ && (next_inst = next_nonnote_insn (insn)) \
+ && GET_CODE (next_inst) == JUMP_INSN) \
+ { /* compare probably paired with jump */ \
+ (cost) = 0; \
+ } \
+ } \
+ else \
+ if (!is_fp_dest (dep_insn)) \
+ { \
+ if(!agi_dependent (insn, dep_insn)) \
+ (cost) = 0; \
+ else if (TARGET_486) \
+ (cost) = 2; \
+ } \
+ else \
+ if (is_fp_store (insn) && is_fp_insn (dep_insn) \
+ && NEXT_INSN (insn) && NEXT_INSN (NEXT_INSN (insn)) \
+ && NEXT_INSN (NEXT_INSN (NEXT_INSN (insn))) \
+ && (GET_CODE (NEXT_INSN (insn)) == INSN) \
+ && (GET_CODE (NEXT_INSN (NEXT_INSN (insn))) == JUMP_INSN) \
+ && (GET_CODE (NEXT_INSN (NEXT_INSN (NEXT_INSN (insn)))) == NOTE) \
+ && (NOTE_LINE_NUMBER (NEXT_INSN (NEXT_INSN (NEXT_INSN (insn)))) \
+ == NOTE_INSN_LOOP_END)) \
+ { \
+ (cost) = 3; \
+ } \
+ }
+
+
+#define ADJUST_BLOCKAGE(last_insn,insn,blockage) \
+{ \
+ if (is_fp_store (last_insn) && is_fp_insn (insn) \
+ && NEXT_INSN (last_insn) && NEXT_INSN (NEXT_INSN (last_insn)) \
+ && NEXT_INSN (NEXT_INSN (NEXT_INSN (last_insn))) \
+ && (GET_CODE (NEXT_INSN (last_insn)) == INSN) \
+ && (GET_CODE (NEXT_INSN (NEXT_INSN (last_insn))) == JUMP_INSN) \
+ && (GET_CODE (NEXT_INSN (NEXT_INSN (NEXT_INSN (last_insn)))) == NOTE) \
+ && (NOTE_LINE_NUMBER (NEXT_INSN (NEXT_INSN (NEXT_INSN (last_insn)))) \
+ == NOTE_INSN_LOOP_END)) \
+ { \
+ (blockage) = 3; \
+ } \
+}
+
\f
/* Add any extra modes needed to represent the condition code.
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. */
/* Here we define machine-dependent flags and fields in cc_status
(see `conditions.h'). */
+/* Set if the cc value was actually from the 80387 and
+ we are testing eax directly (i.e. no sahf) */
+#define CC_TEST_AX 020000
+
/* Set if the cc value is actually in the 80387, so a floating point
conditional branch must be output. */
#define CC_IN_80387 04000
the state of equality is indicated by zero in the carry bit. */
#define CC_Z_IN_NOT_C 010000
+/* Set if the CC value was actually from the 80387 and loaded directly
+ into the eflags instead of via eax/sahf. */
+#define CC_FCOMI 040000
+
/* Store in cc_status the expressions
that the condition codes will describe
after execution of an instruction whose pattern is EXP.
/* Table of additional register names to use in user input. */
#define ADDITIONAL_REGISTER_NAMES \
-{ "eax", 0, "edx", 1, "ecx", 2, "ebx", 3, \
- "esi", 4, "edi", 5, "ebp", 6, "esp", 7, \
- "al", 0, "dl", 1, "cl", 2, "bl", 3, \
- "ah", 0, "dh", 1, "ch", 2, "bh", 3 }
+{ { "eax", 0 }, { "edx", 1 }, { "ecx", 2 }, { "ebx", 3 }, \
+ { "esi", 4 }, { "edi", 5 }, { "ebp", 6 }, { "esp", 7 }, \
+ { "al", 0 }, { "dl", 1 }, { "cl", 2 }, { "bl", 3 }, \
+ { "ah", 0 }, { "dh", 1 }, { "ch", 2 }, { "bh", 3 } }
/* Note we are omitting these since currently I don't know how
to get gcc to use these, since they want the same but different
(n) == 7 ? 5 : \
(n) + 4)
+/* Before the prologue, RA is at 0(%esp). */
+#define INCOMING_RETURN_ADDR_RTX \
+ gen_rtx_MEM (VOIDmode, gen_rtx_REG (VOIDmode, STACK_POINTER_REGNUM))
+
+/* After the prologue, RA is at -4(AP) in the current frame. */
+#define RETURN_ADDR_RTX(COUNT, FRAME) \
+ ((COUNT) == 0 \
+ ? gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, arg_pointer_rtx, GEN_INT(-4)))\
+ : gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, (FRAME), GEN_INT(4))))
+
+/* PC is dbx register 8; let's use that column for RA. */
+#define DWARF_FRAME_RETURN_COLUMN 8
+
+/* Before the prologue, the top of the frame is at 4(%esp). */
+#define INCOMING_FRAME_SP_OFFSET 4
+
/* This is how to output the definition of a user-level label named NAME,
such as the label on a static function or variable NAME. */
#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]); \
+ 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. */
#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]); \
+ 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 { 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); \
+ fprintf ((FILE), "%s 0x%lx\n", ASM_LONG, l); \
} while (0)
/* Store in OUTPUT a string (made with alloca) containing
It need not be very fast code. */
#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \
- fprintf (FILE, "\tpushl e%s\n", reg_names[REGNO])
+ fprintf (FILE, "\tpushl %%e%s\n", reg_names[REGNO])
/* This is how to output an insn to pop a register from the stack.
It need not be very fast code. */
#define ASM_OUTPUT_REG_POP(FILE,REGNO) \
- fprintf (FILE, "\tpopl e%s\n", reg_names[REGNO])
+ fprintf (FILE, "\tpopl %%e%s\n", reg_names[REGNO])
/* This is how to output an element of a case-vector that is absolute.
*/
forward reference the differences.
*/
-#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL) \
+#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \
fprintf (FILE, "\t.word %s%d-%s%d\n",LPREFIX, VALUE,LPREFIX, REL)
/* Define the parentheses used to group arithmetic operations
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)
- w -- print the operand as if it's a "word" (HImode) even if it isn't.
- b -- print the operand as if it's a byte (QImode) even if it isn't.
- c -- don't print special prefixes before constant operands. */
+ P -- if PIC, print an @PLT suffix.
+ X -- don't print any sort of PIC '@' suffix for a symbol.
+ J -- print jump insn for arithmetic_comparison_operator.
+ s -- ??? something to do with double shifts. not actually used, afaik.
+ C -- print a conditional move suffix corresponding to the op code.
+ c -- likewise, but reverse the condition.
+ F,f -- likewise, but for floating-point. */
#define PRINT_OPERAND_PUNCT_VALID_P(CODE) \
((CODE) == '*')
we can use for operand syntax in the extended asm */
#define ASM_OPERAND_LETTER '#'
-\f
#define RET return ""
-#define AT_SP(mode) (gen_rtx (MEM, (mode), stack_pointer_rtx))
+#define AT_SP(mode) (gen_rtx_MEM ((mode), stack_pointer_rtx))
+\f
+/* Helper macros to expand a binary/unary operator if needed */
+#define IX86_EXPAND_BINARY_OPERATOR(OP, MODE, OPERANDS) \
+do { \
+ if (!ix86_expand_binary_operator (OP, MODE, OPERANDS)) \
+ FAIL; \
+} while (0)
+
+#define IX86_EXPAND_UNARY_OPERATOR(OP, MODE, OPERANDS) \
+do { \
+ if (!ix86_expand_unary_operator (OP, MODE, OPERANDS,)) \
+ FAIL; \
+} while (0)
+
+\f
+/* Functions in i386.c */
+extern void override_options ();
+extern void order_regs_for_local_alloc ();
+extern char *output_strlen_unroll ();
+extern struct rtx_def *i386_sext16_if_const ();
+extern int i386_aligned_p ();
+extern int i386_cc_probably_useless_p ();
+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 char *output_strlen_unroll ();
+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 int ix86_expand_binary_operator ();
+extern int ix86_binary_operator_ok ();
+extern int ix86_expand_unary_operator ();
+extern int ix86_unary_operator_ok ();
+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 ();
+extern int is_mul ();
+extern int is_div ();
+extern int last_to_set_cc ();
+extern int doesnt_set_condition_code ();
+extern int sets_condition_code ();
+extern int str_immediate_operand ();
+extern int is_fp_insn ();
+extern int is_fp_dest ();
+extern int is_fp_store ();
+extern int agi_dependent ();
+extern int reg_mentioned_in_mem ();
+
+#ifdef NOTYET
+extern struct rtx_def *copy_all_rtx ();
+extern void rewrite_address ();
+#endif
+
+/* Variables in i386.c */
+extern char *ix86_cpu_string; /* for -mcpu=<xxx> */
+extern char *ix86_arch_string; /* for -march=<xxx> */
+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 char *i386_branch_cost_string; /* values 1-5: see jump.c */
+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 int i386_branch_cost; /* values 1-5: see jump.c */
+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 ();
+
\f
/*
Local variables: