summaryrefslogtreecommitdiffstats
path: root/contrib
diff options
context:
space:
mode:
authorobrien <obrien@FreeBSD.org>2002-02-06 05:01:51 +0000
committerobrien <obrien@FreeBSD.org>2002-02-06 05:01:51 +0000
commita33632ba5a0d130d82627f88736619b44d682df9 (patch)
tree9a1a6d11193d120d078d559198d378523be76a20 /contrib
parentbad15f47f4fd63de2dd53ee98aba0d9f9ab9c15c (diff)
downloadFreeBSD-src-a33632ba5a0d130d82627f88736619b44d682df9.zip
FreeBSD-src-a33632ba5a0d130d82627f88736619b44d682df9.tar.gz
Use the stock [3.1-snap] file.
Diffstat (limited to 'contrib')
-rw-r--r--contrib/gcc/config/i386/i386.h3443
-rw-r--r--contrib/gcc/print-tree.c274
-rw-r--r--contrib/gcc/reload.c2831
3 files changed, 3574 insertions, 2974 deletions
diff --git a/contrib/gcc/config/i386/i386.h b/contrib/gcc/config/i386/i386.h
index e492e04..04d9718 100644
--- a/contrib/gcc/config/i386/i386.h
+++ b/contrib/gcc/config/i386/i386.h
@@ -1,6 +1,6 @@
-/* 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.
+/* Definitions of target machine for GNU compiler for IA-32.
+ Copyright (C) 1988, 1992, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+ 2001, 2002 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -17,7 +17,7 @@ GNU General Public License for more details.
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, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+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.
@@ -30,15 +30,13 @@ Boston, MA 02111-1307, USA. */
Many macros that specify assembler syntax are omitted entirely from
this file because they really belong in the files for particular
- assemblers. These include AS1, AS2, AS3, RP, IP, LPREFIX, L_SIZE,
- PUT_OP_SIZE, USE_STAR, ADDR_BEG, ADDR_END, PRINT_IREG, PRINT_SCALE,
- PRINT_B_I_S, and many that start with ASM_ or end in ASM_OP. */
+ assemblers. These include RP, IP, LPREFIX, PUT_OP_SIZE, USE_STAR,
+ ADDR_BEG, ADDR_END, PRINT_IREG, PRINT_SCALE, PRINT_B_I_S, and many
+ that start with ASM_ or end in ASM_OP. */
-/* $FreeBSD$ */
-/* Names to predefine in the preprocessor for this target machine. */
+/* $FreeBSD$ */
-#define I386 1
/* Stubs for half-pic support if not OSF/1 reference platform. */
@@ -48,25 +46,56 @@ Boston, MA 02111-1307, USA. */
#define HALF_PIC_NUMBER_REFS 0
#define HALF_PIC_ENCODE(DECL)
#define HALF_PIC_DECLARE(NAME)
-#define HALF_PIC_INIT() error ("half-pic init called on systems that don't support it.")
+#define HALF_PIC_INIT() error ("half-pic init called on systems that don't support it")
#define HALF_PIC_ADDRESS_P(X) 0
-#define HALF_PIC_PTR(X) X
+#define HALF_PIC_PTR(X) (X)
#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 */
+ const int add; /* cost of an add instruction */
+ const int lea; /* cost of a lea instruction */
+ const int shift_var; /* variable shift costs */
+ const int shift_const; /* constant shift costs */
+ const int mult_init; /* cost of starting a multiply */
+ const int mult_bit; /* cost of multiply per each bit set */
+ const int divide; /* cost of a divide/mod */
+ int movsx; /* The cost of movsx operation. */
+ int movzx; /* The cost of movzx operation. */
+ const int large_insn; /* insns larger than this cost more */
+ const int move_ratio; /* The threshold of number of scalar
+ memory-to-memory move insns. */
+ const int movzbl_load; /* cost of loading using movzbl */
+ const int int_load[3]; /* cost of loading integer registers
+ in QImode, HImode and SImode relative
+ to reg-reg move (2). */
+ const int int_store[3]; /* cost of storing integer register
+ in QImode, HImode and SImode */
+ const int fp_move; /* cost of reg,reg fld/fst */
+ const int fp_load[3]; /* cost of loading FP register
+ in SFmode, DFmode and XFmode */
+ const int fp_store[3]; /* cost of storing FP register
+ in SFmode, DFmode and XFmode */
+ const int mmx_move; /* cost of moving MMX register. */
+ const int mmx_load[2]; /* cost of loading MMX register
+ in SImode and DImode */
+ const int mmx_store[2]; /* cost of storing MMX register
+ in SImode and DImode */
+ const int sse_move; /* cost of moving SSE register. */
+ const int sse_load[3]; /* cost of loading SSE register
+ in SImode, DImode and TImode*/
+ const int sse_store[3]; /* cost of storing SSE register
+ in SImode, DImode and TImode*/
+ const int mmxsse_to_integer; /* cost of moving mmxsse register to
+ integer and vice versa. */
+ const int prefetch_block; /* bytes moved to cache for prefetch. */
+ const int simultaneous_prefetches; /* number of parallel prefetch
+ operations. */
};
-extern struct processor_costs *ix86_cost;
+extern const struct processor_costs *ix86_cost;
/* Run-time compilation parameters selecting different hardware subsets. */
@@ -75,29 +104,40 @@ extern int target_flags;
/* Macros used in the machine description to test the flags. */
/* configure can arrange to make this 2, to force a 486. */
+
#ifndef TARGET_CPU_DEFAULT
#define TARGET_CPU_DEFAULT 0
#endif
/* 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 */
+#define MASK_80387 0x00000001 /* Hardware floating point */
+#define MASK_RTD 0x00000002 /* Use ret that pops args */
+#define MASK_ALIGN_DOUBLE 0x00000004 /* align doubles to 2 word boundary */
+#define MASK_SVR3_SHLIB 0x00000008 /* Uninit locals into bss */
+#define MASK_IEEE_FP 0x00000010 /* IEEE fp comparisons */
+#define MASK_FLOAT_RETURNS 0x00000020 /* Return float in st(0) */
+#define MASK_NO_FANCY_MATH_387 0x00000040 /* Disable sin, cos, sqrt */
+#define MASK_OMIT_LEAF_FRAME_POINTER 0x080 /* omit leaf frame pointers */
+#define MASK_STACK_PROBE 0x00000100 /* Enable stack probing */
+#define MASK_NO_ALIGN_STROPS 0x00000200 /* Enable aligning of string ops. */
+#define MASK_INLINE_ALL_STROPS 0x00000400 /* Inline stringops in all cases */
+#define MASK_NO_PUSH_ARGS 0x00000800 /* Use push instructions */
+#define MASK_ACCUMULATE_OUTGOING_ARGS 0x00001000/* Accumulate outgoing args */
+#define MASK_ACCUMULATE_OUTGOING_ARGS_SET 0x00002000
+#define MASK_MMX 0x00004000 /* Support MMX regs/builtins */
+#define MASK_MMX_SET 0x00008000
+#define MASK_SSE 0x00010000 /* Support SSE regs/builtins */
+#define MASK_SSE_SET 0x00020000
+#define MASK_SSE2 0x00040000 /* Support SSE2 regs/builtins */
+#define MASK_SSE2_SET 0x00080000
+#define MASK_3DNOW 0x00100000 /* Support 3Dnow builtins */
+#define MASK_3DNOW_SET 0x00200000
+#define MASK_3DNOW_A 0x00400000 /* Support Athlon 3Dnow builtins */
+#define MASK_3DNOW_A_SET 0x00800000
+#define MASK_128BIT_LONG_DOUBLE 0x01000000 /* long double size is 128bit */
+#define MASK_64BIT 0x02000000 /* Produce 64bit code */
+/* ... overlap with subtarget options starts by 0x04000000. */
+#define MASK_NO_RED_ZONE 0x04000000 /* Do not use red zone */
/* Use the floating point instructions */
#define TARGET_80387 (target_flags & MASK_80387)
@@ -112,6 +152,13 @@ extern int target_flags;
faster code on the pentium. */
#define TARGET_ALIGN_DOUBLE (target_flags & MASK_ALIGN_DOUBLE)
+/* Use push instructions to save outgoing args. */
+#define TARGET_PUSH_ARGS (!(target_flags & MASK_NO_PUSH_ARGS))
+
+/* Accumulate stack adjustments to prologue/epilogue. */
+#define TARGET_ACCUMULATE_OUTGOING_ARGS \
+ (target_flags & MASK_ACCUMULATE_OUTGOING_ARGS)
+
/* Put uninitialized locals into bss, not data.
Meaningful only on svr3. */
#define TARGET_SVR3_SHLIB (target_flags & MASK_SVR3_SHLIB)
@@ -123,133 +170,248 @@ extern int target_flags;
/* 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. */
+ the 387 to be used, which is compatible with most calling conventions. */
#define TARGET_FLOAT_RETURNS_IN_80387 (target_flags & MASK_FLOAT_RETURNS)
+/* Long double is 128bit instead of 96bit, even when only 80bits are used.
+ This mode wastes cache, but avoid misaligned data accesses and simplifies
+ address calculations. */
+#define TARGET_128BIT_LONG_DOUBLE (target_flags & MASK_128BIT_LONG_DOUBLE)
+
/* 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)
/* 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)
+#define TARGET_OMIT_LEAF_FRAME_POINTER \
+ (target_flags & MASK_OMIT_LEAF_FRAME_POINTER)
/* Debug GO_IF_LEGITIMATE_ADDRESS */
-#define TARGET_DEBUG_ADDR (target_flags & MASK_DEBUG_ADDR)
+#define TARGET_DEBUG_ADDR (ix86_debug_addr_string != 0)
/* Debug FUNCTION_ARG macros */
-#define TARGET_DEBUG_ARG (target_flags & MASK_DEBUG_ARG)
+#define TARGET_DEBUG_ARG (ix86_debug_arg_string != 0)
-/* 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 */
+/* 64bit Sledgehammer mode */
+#ifdef TARGET_BI_ARCH
+#define TARGET_64BIT (target_flags & MASK_64BIT)
+#else
+#ifdef TARGET_64BIT_DEFAULT
+#define TARGET_64BIT 1
+#else
+#define TARGET_64BIT 0
+#endif
+#endif
#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_K6 (ix86_cpu == PROCESSOR_K6)
+#define TARGET_ATHLON (ix86_cpu == PROCESSOR_ATHLON)
+#define TARGET_PENTIUM4 (ix86_cpu == PROCESSOR_PENTIUM4)
#define CPUMASK (1 << ix86_cpu)
extern const int x86_use_leave, x86_push_memory, x86_zero_extend_with_and;
extern const int x86_use_bit_test, x86_cmove, x86_deep_branch;
-extern const int x86_unroll_strlen, x86_use_q_reg, x86_use_any_reg;
-extern const int x86_double_with_add;
+extern const int x86_branch_hints, x86_unroll_strlen;
+extern const int x86_double_with_add, x86_partial_reg_stall, x86_movx;
+extern const int x86_use_loop, x86_use_fiop, x86_use_mov0;
+extern const int x86_use_cltd, x86_read_modify_write;
+extern const int x86_read_modify, x86_split_long_moves;
+extern const int x86_promote_QImode, x86_single_stringop;
+extern const int x86_himode_math, x86_qimode_math, x86_promote_qi_regs;
+extern const int x86_promote_hi_regs, x86_integer_DFmode_moves;
+extern const int x86_add_esp_4, x86_add_esp_8, x86_sub_esp_4, x86_sub_esp_8;
+extern const int x86_partial_reg_dependency, x86_memory_mismatch_stall;
+extern const int x86_accumulate_outgoing_args, x86_prologue_using_move;
+extern const int x86_epilogue_using_move, x86_decompose_lea;
+extern int x86_prefetch_sse;
#define TARGET_USE_LEAVE (x86_use_leave & CPUMASK)
#define TARGET_PUSH_MEMORY (x86_push_memory & CPUMASK)
#define TARGET_ZERO_EXTEND_WITH_AND (x86_zero_extend_with_and & CPUMASK)
#define TARGET_USE_BIT_TEST (x86_use_bit_test & CPUMASK)
#define TARGET_UNROLL_STRLEN (x86_unroll_strlen & CPUMASK)
-#define TARGET_USE_Q_REG (x86_use_q_reg & CPUMASK)
-#define TARGET_USE_ANY_REG (x86_use_any_reg & CPUMASK)
-#define TARGET_CMOVE (x86_cmove & (1 << ix86_arch))
+/* For sane SSE instruction set generation we need fcomi instruction. It is
+ safe to enable all CMOVE instructions. */
+#define TARGET_CMOVE ((x86_cmove & (1 << ix86_arch)) || TARGET_SSE)
#define TARGET_DEEP_BRANCH_PREDICTION (x86_deep_branch & CPUMASK)
+#define TARGET_BRANCH_PREDICTION_HINTS (x86_branch_hints & CPUMASK)
#define TARGET_DOUBLE_WITH_ADD (x86_double_with_add & CPUMASK)
+#define TARGET_USE_SAHF ((x86_use_sahf & CPUMASK) && !TARGET_64BIT)
+#define TARGET_MOVX (x86_movx & CPUMASK)
+#define TARGET_PARTIAL_REG_STALL (x86_partial_reg_stall & CPUMASK)
+#define TARGET_USE_LOOP (x86_use_loop & CPUMASK)
+#define TARGET_USE_FIOP (x86_use_fiop & CPUMASK)
+#define TARGET_USE_MOV0 (x86_use_mov0 & CPUMASK)
+#define TARGET_USE_CLTD (x86_use_cltd & CPUMASK)
+#define TARGET_SPLIT_LONG_MOVES (x86_split_long_moves & CPUMASK)
+#define TARGET_READ_MODIFY_WRITE (x86_read_modify_write & CPUMASK)
+#define TARGET_READ_MODIFY (x86_read_modify & CPUMASK)
+#define TARGET_PROMOTE_QImode (x86_promote_QImode & CPUMASK)
+#define TARGET_SINGLE_STRINGOP (x86_single_stringop & CPUMASK)
+#define TARGET_QIMODE_MATH (x86_qimode_math & CPUMASK)
+#define TARGET_HIMODE_MATH (x86_himode_math & CPUMASK)
+#define TARGET_PROMOTE_QI_REGS (x86_promote_qi_regs & CPUMASK)
+#define TARGET_PROMOTE_HI_REGS (x86_promote_hi_regs & CPUMASK)
+#define TARGET_ADD_ESP_4 (x86_add_esp_4 & CPUMASK)
+#define TARGET_ADD_ESP_8 (x86_add_esp_8 & CPUMASK)
+#define TARGET_SUB_ESP_4 (x86_sub_esp_4 & CPUMASK)
+#define TARGET_SUB_ESP_8 (x86_sub_esp_8 & CPUMASK)
+#define TARGET_INTEGER_DFMODE_MOVES (x86_integer_DFmode_moves & CPUMASK)
+#define TARGET_PARTIAL_REG_DEPENDENCY (x86_partial_reg_dependency & CPUMASK)
+#define TARGET_MEMORY_MISMATCH_STALL (x86_memory_mismatch_stall & CPUMASK)
+#define TARGET_PROLOGUE_USING_MOVE (x86_prologue_using_move & CPUMASK)
+#define TARGET_EPILOGUE_USING_MOVE (x86_epilogue_using_move & CPUMASK)
+#define TARGET_DECOMPOSE_LEA (x86_decompose_lea & CPUMASK)
+#define TARGET_PREFETCH_SSE (x86_prefetch_sse)
#define TARGET_STACK_PROBE (target_flags & MASK_STACK_PROBE)
-#define TARGET_SWITCHES \
-{ { "80387", MASK_80387, "Use hardware fp" }, \
- { "no-80387", -MASK_80387, "Do not use hardware fp" },\
- { "hard-float", MASK_80387, "Use hardware fp" }, \
- { "soft-float", -MASK_80387, "Do not use hardware fp" },\
- { "no-soft-float", MASK_80387, "Use hardware fp" }, \
- { "386", 0, "Same as -mcpu=i386" }, \
- { "486", 0, "Same as -mcpu=i486" }, \
- { "pentium", 0, "Same as -mcpu=pentium" }, \
- { "pentiumpro", 0, "Same as -mcpu=pentiumpro" }, \
- { "rtd", MASK_RTD, "Alternate calling convention" },\
- { "no-rtd", -MASK_RTD, "Use normal calling convention" },\
- { "align-double", MASK_ALIGN_DOUBLE, "Align some doubles on dword boundary" },\
- { "no-align-double", -MASK_ALIGN_DOUBLE, "Align doubles on word boundary" }, \
- { "svr3-shlib", MASK_SVR3_SHLIB, "Uninitialized locals in .bss" }, \
- { "no-svr3-shlib", -MASK_SVR3_SHLIB, "Uninitialized locals in .data" }, \
- { "ieee-fp", MASK_IEEE_FP, "Use IEEE math for fp comparisons" }, \
- { "no-ieee-fp", -MASK_IEEE_FP, "Do not use IEEE math for fp comparisons" }, \
- { "fp-ret-in-387", MASK_FLOAT_RETURNS, "Return values of functions in FPU registers" }, \
- { "no-fp-ret-in-387", -MASK_FLOAT_RETURNS , "Do not return values of functions in FPU registers"}, \
- { "no-fancy-math-387", MASK_NO_FANCY_MATH_387, "Do not generate sin, cos, sqrt for 387" }, \
- { "fancy-math-387", -MASK_NO_FANCY_MATH_387, "Generate sin, cos, sqrt for FPU"}, \
- { "omit-leaf-frame-pointer", MASK_OMIT_LEAF_FRAME_POINTER, "Omit the frame pointer in leaf functions" }, \
- { "no-omit-leaf-frame-pointer",-MASK_OMIT_LEAF_FRAME_POINTER, "" }, \
- { "no-wide-multiply", MASK_NO_WIDE_MULTIPLY, "multiplies of 32 bits constrained to 32 bits" }, \
- { "wide-multiply", -MASK_NO_WIDE_MULTIPLY, "multiplies of 32 bits are 64 bits" }, \
- { "schedule-prologue", MASK_SCHEDULE_PROLOGUE, "Schedule function prologues" }, \
- { "no-schedule-prologue", -MASK_SCHEDULE_PROLOGUE, "" }, \
- { "debug-addr", MASK_DEBUG_ADDR, 0 /* intentionally undoc */ }, \
- { "no-debug-addr", -MASK_DEBUG_ADDR, 0 /* intentionally undoc */ }, \
- { "move", -MASK_NO_MOVE, "Generate mem-mem moves" }, \
- { "no-move", MASK_NO_MOVE, "Don't generate mem-mem moves" }, \
- { "debug-arg", MASK_DEBUG_ARG, 0 /* intentionally undoc */ }, \
- { "no-debug-arg", -MASK_DEBUG_ARG, 0 /* intentionally undoc */ }, \
- { "stack-arg-probe", MASK_STACK_PROBE, "Enable stack probing" }, \
- { "no-stack-arg-probe", -MASK_STACK_PROBE, "" }, \
- { "windows", 0, 0 /* intentionally undoc */ }, \
- { "dll", 0, 0 /* intentionally undoc */ }, \
- SUBTARGET_SWITCHES \
- { "", MASK_SCHEDULE_PROLOGUE | TARGET_DEFAULT, 0 }}
+#define TARGET_ALIGN_STRINGOPS (!(target_flags & MASK_NO_ALIGN_STROPS))
+#define TARGET_INLINE_ALL_STRINGOPS (target_flags & MASK_INLINE_ALL_STROPS)
+
+#define ASSEMBLER_DIALECT (ix86_asm_dialect)
+
+#define TARGET_SSE ((target_flags & (MASK_SSE | MASK_SSE2)) != 0)
+#define TARGET_SSE2 ((target_flags & MASK_SSE2) != 0)
+#define TARGET_SSE_MATH ((ix86_fpmath & FPMATH_SSE) != 0)
+#define TARGET_MIX_SSE_I387 ((ix86_fpmath & FPMATH_SSE) \
+ && (ix86_fpmath & FPMATH_387))
+#define TARGET_MMX ((target_flags & MASK_MMX) != 0)
+#define TARGET_3DNOW ((target_flags & MASK_3DNOW) != 0)
+#define TARGET_3DNOW_A ((target_flags & MASK_3DNOW_A) != 0)
+
+#define TARGET_RED_ZONE (!(target_flags & MASK_NO_RED_ZONE))
+
+#define TARGET_SWITCHES \
+{ { "80387", MASK_80387, N_("Use hardware fp") }, \
+ { "no-80387", -MASK_80387, N_("Do not use hardware fp") }, \
+ { "hard-float", MASK_80387, N_("Use hardware fp") }, \
+ { "soft-float", -MASK_80387, N_("Do not use hardware fp") }, \
+ { "no-soft-float", MASK_80387, N_("Use hardware fp") }, \
+ { "386", 0, N_("") /*Deprecated.*/}, \
+ { "486", 0, N_("") /*Deprecated.*/}, \
+ { "pentium", 0, N_("") /*Deprecated.*/}, \
+ { "pentiumpro", 0, N_("") /*Deprecated.*/}, \
+ { "intel-syntax", 0, N_("") /*Deprecated.*/}, \
+ { "no-intel-syntax", 0, N_("") /*Deprecated.*/}, \
+ { "rtd", MASK_RTD, \
+ N_("Alternate calling convention") }, \
+ { "no-rtd", -MASK_RTD, \
+ N_("Use normal calling convention") }, \
+ { "align-double", MASK_ALIGN_DOUBLE, \
+ N_("Align some doubles on dword boundary") }, \
+ { "no-align-double", -MASK_ALIGN_DOUBLE, \
+ N_("Align doubles on word boundary") }, \
+ { "svr3-shlib", MASK_SVR3_SHLIB, \
+ N_("Uninitialized locals in .bss") }, \
+ { "no-svr3-shlib", -MASK_SVR3_SHLIB, \
+ N_("Uninitialized locals in .data") }, \
+ { "ieee-fp", MASK_IEEE_FP, \
+ N_("Use IEEE math for fp comparisons") }, \
+ { "no-ieee-fp", -MASK_IEEE_FP, \
+ N_("Do not use IEEE math for fp comparisons") }, \
+ { "fp-ret-in-387", MASK_FLOAT_RETURNS, \
+ N_("Return values of functions in FPU registers") }, \
+ { "no-fp-ret-in-387", -MASK_FLOAT_RETURNS , \
+ N_("Do not return values of functions in FPU registers")}, \
+ { "no-fancy-math-387", MASK_NO_FANCY_MATH_387, \
+ N_("Do not generate sin, cos, sqrt for FPU") }, \
+ { "fancy-math-387", -MASK_NO_FANCY_MATH_387, \
+ N_("Generate sin, cos, sqrt for FPU")}, \
+ { "omit-leaf-frame-pointer", MASK_OMIT_LEAF_FRAME_POINTER, \
+ N_("Omit the frame pointer in leaf functions") }, \
+ { "no-omit-leaf-frame-pointer",-MASK_OMIT_LEAF_FRAME_POINTER, "" }, \
+ { "stack-arg-probe", MASK_STACK_PROBE, \
+ N_("Enable stack probing") }, \
+ { "no-stack-arg-probe", -MASK_STACK_PROBE, "" }, \
+ { "windows", 0, 0 /* undocumented */ }, \
+ { "dll", 0, 0 /* undocumented */ }, \
+ { "align-stringops", -MASK_NO_ALIGN_STROPS, \
+ N_("Align destination of the string operations") }, \
+ { "no-align-stringops", MASK_NO_ALIGN_STROPS, \
+ N_("Do not align destination of the string operations") }, \
+ { "inline-all-stringops", MASK_INLINE_ALL_STROPS, \
+ N_("Inline all known string operations") }, \
+ { "no-inline-all-stringops", -MASK_INLINE_ALL_STROPS, \
+ N_("Do not inline all known string operations") }, \
+ { "push-args", -MASK_NO_PUSH_ARGS, \
+ N_("Use push instructions to save outgoing arguments") }, \
+ { "no-push-args", MASK_NO_PUSH_ARGS, \
+ N_("Do not use push instructions to save outgoing arguments") }, \
+ { "accumulate-outgoing-args", (MASK_ACCUMULATE_OUTGOING_ARGS \
+ | MASK_ACCUMULATE_OUTGOING_ARGS_SET), \
+ N_("Use push instructions to save outgoing arguments") }, \
+ { "no-accumulate-outgoing-args",MASK_ACCUMULATE_OUTGOING_ARGS_SET, \
+ N_("Do not use push instructions to save outgoing arguments") }, \
+ { "mmx", MASK_MMX | MASK_MMX_SET, \
+ N_("Support MMX built-in functions") }, \
+ { "no-mmx", -MASK_MMX, \
+ N_("Do not support MMX built-in functions") }, \
+ { "no-mmx", MASK_MMX_SET, N_("") }, \
+ { "3dnow", MASK_3DNOW | MASK_3DNOW_SET, \
+ N_("Support 3DNow! built-in functions") }, \
+ { "no-3dnow", -MASK_3DNOW, N_("") }, \
+ { "no-3dnow", MASK_3DNOW_SET, \
+ N_("Do not support 3DNow! built-in functions") }, \
+ { "sse", MASK_SSE | MASK_SSE_SET, \
+ N_("Support MMX and SSE built-in functions and code generation") }, \
+ { "no-sse", -MASK_SSE, N_("") }, \
+ { "no-sse", MASK_SSE_SET, \
+ N_("Do not support MMX and SSE built-in functions and code generation") },\
+ { "sse2", MASK_SSE2 | MASK_SSE2_SET, \
+ N_("Support MMX, SSE and SSE2 built-in functions and code generation") }, \
+ { "no-sse2", -MASK_SSE2, N_("") }, \
+ { "no-sse2", MASK_SSE2_SET, \
+ N_("Do not support MMX, SSE and SSE2 built-in functions and code generation") }, \
+ { "128bit-long-double", MASK_128BIT_LONG_DOUBLE, \
+ N_("sizeof(long double) is 16") }, \
+ { "96bit-long-double", -MASK_128BIT_LONG_DOUBLE, \
+ N_("sizeof(long double) is 12") }, \
+ { "64", MASK_64BIT, \
+ N_("Generate 64bit x86-64 code") }, \
+ { "32", -MASK_64BIT, \
+ N_("Generate 32bit i386 code") }, \
+ { "red-zone", -MASK_NO_RED_ZONE, \
+ N_("Use red-zone in the x86-64 code") }, \
+ { "no-red-zone", MASK_NO_RED_ZONE, \
+ N_("Do not use red-zone in the x86-64 code") }, \
+ SUBTARGET_SWITCHES \
+ { "", TARGET_DEFAULT, 0 }}
+
+#ifdef TARGET_64BIT_DEFAULT
+#define TARGET_DEFAULT (MASK_64BIT | TARGET_SUBTARGET_DEFAULT)
+#else
+#define TARGET_DEFAULT TARGET_SUBTARGET_DEFAULT
+#endif
/* 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_I386, /* 80386 */
PROCESSOR_I486, /* 80486DX, 80486SX, 80486DX[24] */
PROCESSOR_PENTIUM,
PROCESSOR_PENTIUMPRO,
- PROCESSOR_K6};
-
-#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"
-#define PROCESSOR_K6_STRING "k6"
+ PROCESSOR_K6,
+ PROCESSOR_ATHLON,
+ PROCESSOR_PENTIUM4,
+ PROCESSOR_max
+};
+enum fpmath_unit
+{
+ FPMATH_387 = 1,
+ FPMATH_SSE = 2
+};
extern enum processor_type ix86_cpu;
+extern enum fpmath_unit ix86_fpmath;
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
-#define PROCESSOR_DEFAULT_STRING \
- (PROCESSOR_DEFAULT == PROCESSOR_I486 ? PROCESSOR_I486_STRING \
- : PROCESSOR_DEFAULT == PROCESSOR_PENTIUM ? PROCESSOR_PENTIUM_STRING \
- : PROCESSOR_DEFAULT == PROCESSOR_PENTIUMPRO ? PROCESSOR_PENTIUMPRO_STRING \
- : PROCESSOR_DEFAULT == PROCESSOR_K6 ? PROCESSOR_K6_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.
@@ -259,17 +421,35 @@ extern int ix86_arch;
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, "Schedule code for given CPU"}, \
- { "arch=", &ix86_arch_string, "Generate code for given CPU"}, \
- { "reg-alloc=", &i386_reg_alloc_order, "Control allocation order of integer registers" }, \
- { "regparm=", &i386_regparm_string, "Number of registers used to pass integer arguments" }, \
- { "align-loops=", &i386_align_loops_string, "Loop code aligned to this power of 2" }, \
- { "align-jumps=", &i386_align_jumps_string, "Jump targets are aligned to this power of 2" }, \
- { "align-functions=", &i386_align_funcs_string, "Function starts are aligned to this power of 2" }, \
- { "preferred-stack-boundary=", &i386_preferred_stack_boundary_string, "Attempt to keep stack aligned to this power of 2" }, \
- { "branch-cost=", &i386_branch_cost_string, "Branches are this expensive (1-5, arbitrary units)" }, \
- SUBTARGET_OPTIONS \
+#define TARGET_OPTIONS \
+{ { "cpu=", &ix86_cpu_string, \
+ N_("Schedule code for given CPU")}, \
+ { "fpmath=", &ix86_fpmath_string, \
+ N_("Generate floating point mathematics using given instruction set")},\
+ { "arch=", &ix86_arch_string, \
+ N_("Generate code for given CPU")}, \
+ { "regparm=", &ix86_regparm_string, \
+ N_("Number of registers used to pass integer arguments") }, \
+ { "align-loops=", &ix86_align_loops_string, \
+ N_("Loop code aligned to this power of 2") }, \
+ { "align-jumps=", &ix86_align_jumps_string, \
+ N_("Jump targets are aligned to this power of 2") }, \
+ { "align-functions=", &ix86_align_funcs_string, \
+ N_("Function starts are aligned to this power of 2") }, \
+ { "preferred-stack-boundary=", \
+ &ix86_preferred_stack_boundary_string, \
+ N_("Attempt to keep stack aligned to this power of 2") }, \
+ { "branch-cost=", &ix86_branch_cost_string, \
+ N_("Branches are this expensive (1-5, arbitrary units)") }, \
+ { "cmodel=", &ix86_cmodel_string, \
+ N_("Use given x86-64 code model") }, \
+ { "debug-arg", &ix86_debug_arg_string, \
+ N_("" /* Undocumented. */) }, \
+ { "debug-addr", &ix86_debug_addr_string, \
+ N_("" /* Undocumented. */) }, \
+ { "asm=", &ix86_asm_string, \
+ N_("Use given assembler dialect") }, \
+ SUBTARGET_OPTIONS \
}
/* Sometimes certain combinations of command options do not make
@@ -288,58 +468,176 @@ extern int ix86_arch;
#define SUBTARGET_OPTIONS
/* Define this to change the optimizations performed by default. */
-#define OPTIMIZATION_OPTIONS(LEVEL,SIZE) optimization_options(LEVEL,SIZE)
+#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} \
-%{m486:-mcpu=i486 -march=i486} \
-%{mpentium:-mcpu=pentium} \
-%{mpentiumpro:-mcpu=pentiumpro}}"
+%{m386:-mcpu=i386 \
+%n`-m386' is deprecated. Use `-march=i386' or `-mcpu=i386' instead.\n} \
+%{m486:-mcpu=i486 \
+%n`-m486' is deprecated. Use `-march=i486' or `-mcpu=i486' instead.\n} \
+%{mpentium:-mcpu=pentium \
+%n`-mpentium' is deprecated. Use `-march=pentium' or `-mcpu=pentium' instead.\n} \
+%{mpentiumpro:-mcpu=pentiumpro \
+%n`-mpentiumpro' is deprecated. Use `-march=pentiumpro' or `-mcpu=pentiumpro' instead.\n}} \
+%{mintel-syntax:-masm=intel \
+%n`-mintel-syntax' is deprecated. Use `-masm=intel' instead.\n} \
+%{mno-intel-syntax:-masm=att \
+%n`-mno-intel-syntax' is deprecated. Use `-masm=att' instead.\n}"
#endif
-#define CPP_486_SPEC "%{!ansi:-Di486} -D__i486 -D__i486__"
-#define CPP_586_SPEC "%{!ansi:-Di586 -Dpentium} \
- -D__i586 -D__i586__ -D__pentium -D__pentium__"
-#define CPP_K6_SPEC "%{!ansi:-Di586 -Dk6} \
- -D__i586 -D__i586__ -D__k6 -D__k6__"
-#define CPP_686_SPEC "%{!ansi:-Di686 -Dpentiumpro} \
- -D__i686 -D__i686__ -D__pentiumpro -D__pentiumpro__"
-
+#define TARGET_CPU_DEFAULT_i386 0
+#define TARGET_CPU_DEFAULT_i486 1
+#define TARGET_CPU_DEFAULT_pentium 2
+#define TARGET_CPU_DEFAULT_pentium_mmx 3
+#define TARGET_CPU_DEFAULT_pentiumpro 4
+#define TARGET_CPU_DEFAULT_pentium2 5
+#define TARGET_CPU_DEFAULT_pentium3 6
+#define TARGET_CPU_DEFAULT_pentium4 7
+#define TARGET_CPU_DEFAULT_k6 8
+#define TARGET_CPU_DEFAULT_k6_2 9
+#define TARGET_CPU_DEFAULT_k6_3 10
+#define TARGET_CPU_DEFAULT_athlon 11
+#define TARGET_CPU_DEFAULT_athlon_sse 12
+
+#define TARGET_CPU_DEFAULT_NAMES {"i386", "i486", "pentium", "pentium-mmx",\
+ "pentiumpro", "pentium2", "pentium3", \
+ "pentium4", "k6", "k6-2", "k6-3",\
+ "athlon", "athlon-4"}
#ifndef CPP_CPU_DEFAULT_SPEC
-#if TARGET_CPU_DEFAULT == 1
-#define CPP_CPU_DEFAULT_SPEC "%(cpp_486)"
+#if TARGET_CPU_DEFAULT == TARGET_CPU_DEFAULT_i486
+#define CPP_CPU_DEFAULT_SPEC "-D__tune_i486__"
+#endif
+#if TARGET_CPU_DEFAULT == TARGET_CPU_DEFAULT_pentium
+#define CPP_CPU_DEFAULT_SPEC "-D__tune_i586__ -D__tune_pentium__"
+#endif
+#if TARGET_CPU_DEFAULT == TARGET_CPU_DEFAULT_pentium_mmx
+#define CPP_CPU_DEFAULT_SPEC "-D__tune_i586__ -D__tune_pentium__ -D__tune_pentium_mmx__"
+#endif
+#if TARGET_CPU_DEFAULT == TARGET_CPU_DEFAULT_pentiumpro
+#define CPP_CPU_DEFAULT_SPEC "-D__tune_i686__ -D__tune_pentiumpro__"
+#endif
+#if TARGET_CPU_DEFAULT == TARGET_CPU_DEFAULT_pentium2
+#define CPP_CPU_DEFAULT_SPEC "-D__tune_i686__ -D__tune_pentiumpro__\
+-D__tune_pentium2__"
#endif
-#if TARGET_CPU_DEFAULT == 2
-#define CPP_CPU_DEFAULT_SPEC "%(cpp_586)"
+#if TARGET_CPU_DEFAULT == TARGET_CPU_DEFAULT_pentium3
+#define CPP_CPU_DEFAULT_SPEC "-D__tune_i686__ -D__tune_pentiumpro__\
+-D__tune_pentium2__ -D__tune_pentium3__"
#endif
-#if TARGET_CPU_DEFAULT == 3
-#define CPP_CPU_DEFAULT_SPEC "%(cpp_686)"
+#if TARGET_CPU_DEFAULT == TARGET_CPU_DEFAULT_pentium4
+#define CPP_CPU_DEFAULT_SPEC "-D__tune_pentium4__"
#endif
-#if TARGET_CPU_DEFAULT == 4
-#define CPP_CPU_DEFAULT_SPEC "%(cpp_k6)"
+#if TARGET_CPU_DEFAULT == TARGET_CPU_DEFAULT_k6
+#define CPP_CPU_DEFAULT_SPEC "-D__tune_k6__"
+#endif
+#if TARGET_CPU_DEFAULT == TARGET_CPU_DEFAULT_k6_2
+#define CPP_CPU_DEFAULT_SPEC "-D__tune_k6__ -D__tune_k6_2__"
+#endif
+#if TARGET_CPU_DEFAULT == TARGET_CPU_DEFAULT_k6_3
+#define CPP_CPU_DEFAULT_SPEC "-D__tune_k6__ -D__tune_k6_3__"
+#endif
+#if TARGET_CPU_DEFAULT == TARGET_CPU_DEFAULT_athlon
+#define CPP_CPU_DEFAULT_SPEC "-D__tune_athlon__"
+#endif
+#if TARGET_CPU_DEFAULT == TARGET_CPU_DEFAULT_athlon_sse
+#define CPP_CPU_DEFAULT_SPEC "-D__tune_athlon__ -D__tune_athlon_sse__"
#endif
#ifndef CPP_CPU_DEFAULT_SPEC
-#define CPP_CPU_DEFAULT_SPEC ""
+#define CPP_CPU_DEFAULT_SPEC "-D__tune_i386__"
#endif
#endif /* CPP_CPU_DEFAULT_SPEC */
+#ifdef TARGET_BI_ARCH
+#define NO_BUILTIN_SIZE_TYPE
+#define NO_BUILTIN_PTRDIFF_TYPE
+#endif
+
+#ifdef NO_BUILTIN_SIZE_TYPE
+#define CPP_CPU32_SIZE_TYPE_SPEC \
+ " -D__SIZE_TYPE__=unsigned\\ int -D__PTRDIFF_TYPE__=int"
+#define CPP_CPU64_SIZE_TYPE_SPEC \
+ " -D__SIZE_TYPE__=unsigned\\ long\\ int -D__PTRDIFF_TYPE__=long\\ int"
+#else
+#define CPP_CPU32_SIZE_TYPE_SPEC ""
+#define CPP_CPU64_SIZE_TYPE_SPEC ""
+#endif
+
+#define CPP_CPU32_SPEC \
+ "-Acpu=i386 -Amachine=i386 %{!ansi:%{!std=c*:%{!std=i*:-Di386}}} -D__i386 \
+-D__i386__ %(cpp_cpu32sizet)"
+
+#define CPP_CPU64_SPEC \
+ "-Acpu=x86_64 -Amachine=x86_64 -D__x86_64 -D__x86_64__ %(cpp_cpu64sizet)"
+
+#define CPP_CPUCOMMON_SPEC "\
+%{march=i386:%{!mcpu*:-D__tune_i386__ }}\
+%{march=i486:-D__i486 -D__i486__ %{!mcpu*:-D__tune_i486__ }}\
+%{march=pentium|march=i586:-D__i586 -D__i586__ -D__pentium -D__pentium__ \
+ %{!mcpu*:-D__tune_i586__ -D__tune_pentium__ }}\
+%{march=pentium-mmx:-D__i586 -D__i586__ -D__pentium -D__pentium__ \
+ -D__pentium__mmx__ \
+ %{!mcpu*:-D__tune_i586__ -D__tune_pentium__ -D__tune_pentium_mmx__}}\
+%{march=pentiumpro|march=i686:-D__i686 -D__i686__ \
+ -D__pentiumpro -D__pentiumpro__ \
+ %{!mcpu*:-D__tune_i686__ -D__tune_pentiumpro__ }}\
+%{march=k6:-D__k6 -D__k6__ %{!mcpu*:-D__tune_k6__ }}\
+%{march=k6-2:-D__k6 -D__k6__ -D__k6_2__ \
+ %{!mcpu*:-D__tune_k6__ -D__tune_k6_2__ }}\
+%{march=k6-3:-D__k6 -D__k6__ -D__k6_3__ \
+ %{!mcpu*:-D__tune_k6__ -D__tune_k6_3__ }}\
+%{march=athlon|march=athlon-tbird:-D__athlon -D__athlon__ \
+ %{!mcpu*:-D__tune_athlon__ }}\
+%{march=athlon-4|march=athlon-xp|march=athlon-mp:-D__athlon -D__athlon__ \
+ -D__athlon_sse__ \
+ %{!mcpu*:-D__tune_athlon__ -D__tune_athlon_sse__ }}\
+%{march=pentium4:-D__pentium4 -D__pentium4__ %{!mcpu*:-D__tune_pentium4__ }}\
+%{m386|mcpu=i386:-D__tune_i386__ }\
+%{m486|mcpu=i486:-D__tune_i486__ }\
+%{mpentium|mcpu=pentium|mcpu=i586|mcpu=pentium-mmx:-D__tune_i586__ -D__tune_pentium__ }\
+%{mpentiumpro|mcpu=pentiumpro|mcpu=i686|cpu=pentium2|cpu=pentium3:-D__tune_i686__ \
+-D__tune_pentiumpro__ }\
+%{mcpu=k6|mcpu=k6-2|mcpu=k6-3:-D__tune_k6__ }\
+%{mcpu=athlon|mcpu=athlon-tbird|mcpu=athlon-4|mcpu=athlon-xp|mcpu=athlon-mp:\
+-D__tune_athlon__ }\
+%{mcpu=athlon-4|mcpu=athlon-xp|mcpu=athlon-mp:\
+-D__tune_athlon_sse__ }\
+%{mcpu=pentium4:-D__tune_pentium4__ }\
+%{march=athlon-tbird|march=athlon-xp|march=athlon-mp|march=pentium3|march=pentium4:\
+-D__SSE__ }\
+%{march=pentium-mmx|march=k6|march=k6-2|march=k6-3\
+march=athlon|march=athlon-tbird|march=athlon-4|march=athlon-xp\
+|march=athlon-mp|march=pentium2|march=pentium3|march=pentium4: -D__MMX__ }\
+%{march=k6-2|march=k6-3\
+march=athlon|march=athlon-tbird|march=athlon-4|march=athlon-xp\
+|march=athlon-mp: -D__3dNOW__ }\
+%{march=athlon|march=athlon-tbird|march=athlon-4|march=athlon-xp\
+|march=athlon-mp: -D__3dNOW_A__ }\
+%{march=pentium4: -D__SSE2__ }\
+%{!march*:%{!mcpu*:%{!m386:%{!m486:%{!mpentium*:%(cpp_cpu_default)}}}}}"
+
#ifndef CPP_CPU_SPEC
-#define CPP_CPU_SPEC "\
--Acpu(i386) -Amachine(i386) \
-%{!ansi:-Di386} -D__i386 -D__i386__ \
-%{mcpu=i486:%(cpp_486)} %{m486:%(cpp_486)} \
-%{mpentium:%(cpp_586)} %{mcpu=pentium:%(cpp_586)} \
-%{mpentiumpro:%(cpp_686)} %{mcpu=pentiumpro:%(cpp_686)} \
-%{mcpu=k6:%(cpp_k6)} \
-%{!mcpu*:%{!m486:%{!mpentium*:%(cpp_cpu_default)}}}"
+#ifdef TARGET_BI_ARCH
+#ifdef TARGET_64BIT_DEFAULT
+#define CPP_CPU_SPEC "%{m32:%(cpp_cpu32)}%{!m32:%(cpp_cpu64)} %(cpp_cpucommon)"
+#else
+#define CPP_CPU_SPEC "%{m64:%(cpp_cpu64)}%{!m64:%(cpp_cpu32)} %(cpp_cpucommon)"
+#endif
+#else
+#ifdef TARGET_64BIT_DEFAULT
+#define CPP_CPU_SPEC "%(cpp_cpu64) %(cpp_cpucommon)"
+#else
+#define CPP_CPU_SPEC "%(cpp_cpu32) %(cpp_cpucommon)"
+#endif
+#endif
#endif
#ifndef CC1_SPEC
-#define CC1_SPEC "%(cc1_spec) "
+#define CC1_SPEC "%(cc1_cpu) "
#endif
/* This macro defines names of additional specifications to put in the
@@ -357,24 +655,55 @@ extern int ix86_arch;
#endif
#define EXTRA_SPECS \
- { "cpp_486", CPP_486_SPEC}, \
- { "cpp_586", CPP_586_SPEC}, \
- { "cpp_k6", CPP_K6_SPEC}, \
- { "cpp_686", CPP_686_SPEC}, \
{ "cpp_cpu_default", CPP_CPU_DEFAULT_SPEC }, \
{ "cpp_cpu", CPP_CPU_SPEC }, \
+ { "cpp_cpu32", CPP_CPU32_SPEC }, \
+ { "cpp_cpu64", CPP_CPU64_SPEC }, \
+ { "cpp_cpu32sizet", CPP_CPU32_SIZE_TYPE_SPEC }, \
+ { "cpp_cpu64sizet", CPP_CPU64_SIZE_TYPE_SPEC }, \
+ { "cpp_cpucommon", CPP_CPUCOMMON_SPEC }, \
{ "cc1_cpu", CC1_CPU_SPEC }, \
SUBTARGET_EXTRA_SPECS
/* 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 for XFmode or TFmode extended real floating point support.
+ This will automatically cause REAL_ARITHMETIC to be defined.
+
+ The XFmode is specified by i386 ABI, while TFmode may be faster
+ due to alignment and simplifications in the address calculations.
+ */
+#define LONG_DOUBLE_TYPE_SIZE (TARGET_128BIT_LONG_DOUBLE ? 128 : 96)
+#define MAX_LONG_DOUBLE_TYPE_SIZE 128
+#ifdef __x86_64__
+#define LIBGCC2_LONG_DOUBLE_TYPE_SIZE 128
+#else
+#define LIBGCC2_LONG_DOUBLE_TYPE_SIZE 96
+#endif
+/* Tell real.c that this is the 80-bit Intel extended float format
+ packaged in a 128-bit or 96bit entity. */
+#define INTEL_EXTENDED_IEEE_FORMAT 1
+
+
+#define SHORT_TYPE_SIZE 16
+#define INT_TYPE_SIZE 32
+#define FLOAT_TYPE_SIZE 32
+#define LONG_TYPE_SIZE BITS_PER_WORD
+#define MAX_WCHAR_TYPE_SIZE 32
+#define DOUBLE_TYPE_SIZE 64
+#define LONG_LONG_TYPE_SIZE 64
+
+#if defined (TARGET_BI_ARCH) || defined (TARGET_64BIT_DEFAULT)
+#define MAX_BITS_PER_WORD 64
+#define MAX_LONG_TYPE_SIZE 64
+#else
+#define MAX_BITS_PER_WORD 32
+#define MAX_LONG_TYPE_SIZE 32
+#endif
/* 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. */
+ decimal <-> binary conversion. */
/* #define REAL_ARITHMETIC */
/* Define this if most significant byte of a word is the lowest numbered. */
@@ -398,46 +727,68 @@ extern int ix86_arch;
Note that this is not necessarily the width of data type `int';
if using 16-bit ints on a 80386, this would still be 32.
But on a machine with 16-bit registers, this would be 16. */
-#define BITS_PER_WORD 32
+#define BITS_PER_WORD (TARGET_64BIT ? 64 : 32)
/* Width of a word, in units (bytes). */
-#define UNITS_PER_WORD 4
+#define UNITS_PER_WORD (TARGET_64BIT ? 8 : 4)
+#define MIN_UNITS_PER_WORD 4
/* Width in bits of a pointer.
See also the macro `Pmode' defined below. */
-#define POINTER_SIZE 32
+#define POINTER_SIZE BITS_PER_WORD
/* Allocation boundary (in *bits*) for storing arguments in argument list. */
-#define PARM_BOUNDARY 32
+#define PARM_BOUNDARY BITS_PER_WORD
-/* Boundary (in *bits*) on which the stack pointer must be aligned. */
-#define STACK_BOUNDARY 32
+/* Boundary (in *bits*) on which stack pointer should be aligned. */
+#define STACK_BOUNDARY BITS_PER_WORD
/* Boundary (in *bits*) on which the stack pointer preferrs to be
aligned; the compiler cannot rely on having this alignment. */
-#define PREFERRED_STACK_BOUNDARY i386_preferred_stack_boundary
+#define PREFERRED_STACK_BOUNDARY ix86_preferred_stack_boundary
+
+/* As of July 2001, many runtimes to not align the stack properly when
+ entering main. This causes expand_main_function to forcably align
+ the stack, which results in aligned frames for functions called from
+ main, though it does nothing for the alignment of main itself. */
+#define FORCE_PREFERRED_STACK_BOUNDARY_IN_MAIN \
+ (ix86_preferred_stack_boundary > STACK_BOUNDARY && !TARGET_64BIT)
-/* 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 (1 << (i386_align_funcs + 3))
+/* Allocation boundary for the code of a function. */
+#define FUNCTION_BOUNDARY 16
-/* Alignment of field after `int : 0' in a structure. */
+/* Alignment of field after `int : 0' in a structure. */
-#define EMPTY_FIELD_BOUNDARY 32
+#define EMPTY_FIELD_BOUNDARY BITS_PER_WORD
/* Minimum size in bits of the largest boundary to which any
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.
- 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)
+ rounder than this.
+
+ Pentium+ preferrs DFmode values to be aligned to 64 bit boundary
+ and Pentium Pro XFmode values at 128 bit boundaries. */
+
+#define BIGGEST_ALIGNMENT 128
+
+/* Decide whether a variable of mode MODE must be 128 bit aligned. */
+#define ALIGN_MODE_128(MODE) \
+ ((MODE) == XFmode || (MODE) == TFmode || ((MODE) == TImode) \
+ || (MODE) == V4SFmode || (MODE) == V4SImode)
+
+/* The published ABIs say that doubles should be aligned on word
+ boundaries, so lower the aligment for structure fields unless
+ -malign-double is set. */
+/* BIGGEST_FIELD_ALIGNMENT is also used in libobjc, where it must be
+ constant. Use the smaller value in that context. */
+#ifndef IN_TARGET_LIBS
+#define BIGGEST_FIELD_ALIGNMENT (TARGET_64BIT ? 128 : (TARGET_ALIGN_DOUBLE ? 64 : 32))
+#else
+#define BIGGEST_FIELD_ALIGNMENT 32
+#endif
/* If defined, a C expression to compute the alignment given to a
- constant that is being placed in memory. CONSTANT is the constant
+ constant that is being placed in memory. EXP 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.
@@ -448,18 +799,7 @@ extern int ix86_arch;
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))
+#define CONSTANT_ALIGNMENT(EXP, ALIGN) ix86_constant_alignment ((EXP), (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
@@ -473,41 +813,7 @@ extern int ix86_arch;
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))
+#define DATA_ALIGNMENT(TYPE, ALIGN) ix86_data_alignment ((TYPE), (ALIGN))
/* If defined, a C expression to compute the alignment for a local
variable. TYPE is the data type, and ALIGN is the alignment that
@@ -519,35 +825,14 @@ extern int ix86_arch;
One use of this macro is to increase alignment of medium-size
data to make it all fit in fewer cache lines. */
-#define LOCAL_ALIGNMENT(TYPE, ALIGN) \
- (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))
+#define LOCAL_ALIGNMENT(TYPE, ALIGN) ix86_local_alignment ((TYPE), (ALIGN))
+
+/* If defined, a C expression that gives the alignment boundary, in
+ bits, of an argument with the specified mode and type. If it is
+ not defined, `PARM_BOUNDARY' is used for all arguments. */
+
+#define FUNCTION_ARG_BOUNDARY(MODE, TYPE) \
+ ix86_function_arg_boundary ((MODE), (TYPE))
/* Set this non-zero if move instructions will actually fail to work
when given unaligned data. */
@@ -557,28 +842,16 @@ extern int ix86_arch;
and give entire struct the alignment of an int. */
/* 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 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 LABEL_ALIGN_AFTER_BARRIER(LABEL) (i386_align_jumps)
-#define LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP (i386_align_jumps_string ? 0 : 7)
-
/* Standard register usage. */
/* This processor has special stack-like registers. See reg-stack.c
- for details. */
+ for details. */
#define STACK_REGS
-#define IS_STACK_MODE(mode) (mode==DFmode || mode==SFmode || mode==XFmode)
+#define IS_STACK_MODE(MODE) \
+ ((MODE) == DFmode || (MODE) == SFmode || (MODE) == XFmode \
+ || (MODE) == TFmode)
/* Number of actual hardware registers.
The hardware registers are assigned numbers for the compiler
@@ -594,27 +867,62 @@ extern int ix86_arch;
Reg 16 does not correspond to any hardware register, but instead
appears in the RTL as an argument pointer prior to reload, and is
eliminated during reloading in favor of either the stack or frame
- pointer. */
+ pointer. */
+
+#define FIRST_PSEUDO_REGISTER 53
+
+/* Number of hardware registers that go into the DWARF-2 unwind info.
+ If not defined, equals FIRST_PSEUDO_REGISTER. */
-#define FIRST_PSEUDO_REGISTER 17
+#define DWARF_FRAME_REGISTERS 17
/* 1 for registers that have pervasive standard uses
and are not available for the register allocator.
- On the 80386, the stack pointer is such, as is the arg pointer. */
-#define FIXED_REGISTERS \
-/*ax,dx,cx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7,arg*/ \
-{ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 }
+ On the 80386, the stack pointer is such, as is the arg pointer.
+
+ The value is an mask - bit 1 is set for fixed registers
+ for 32bit target, while 2 is set for fixed registers for 64bit.
+ Proper value is computed in the CONDITIONAL_REGISTER_USAGE.
+ */
+#define FIXED_REGISTERS \
+/*ax,dx,cx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7*/ \
+{ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, \
+/*arg,flags,fpsr,dir,frame*/ \
+ 3, 3, 3, 3, 3, \
+/*xmm0,xmm1,xmm2,xmm3,xmm4,xmm5,xmm6,xmm7*/ \
+ 0, 0, 0, 0, 0, 0, 0, 0, \
+/*mmx0,mmx1,mmx2,mmx3,mmx4,mmx5,mmx6,mmx7*/ \
+ 0, 0, 0, 0, 0, 0, 0, 0, \
+/* r8, r9, r10, r11, r12, r13, r14, r15*/ \
+ 1, 1, 1, 1, 1, 1, 1, 1, \
+/*xmm8,xmm9,xmm10,xmm11,xmm12,xmm13,xmm14,xmm15*/ \
+ 1, 1, 1, 1, 1, 1, 1, 1}
+
/* 1 for registers not available across function calls.
These must include the FIXED_REGISTERS and also any
registers that can be used without being saved.
The latter must include the registers where values are returned
and the register where structure-value addresses are passed.
- Aside from that, you can include as many other registers as you like. */
-
-#define CALL_USED_REGISTERS \
-/*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 }
+ Aside from that, you can include as many other registers as you like.
+
+ The value is an mask - bit 1 is set for call used
+ for 32bit target, while 2 is set for call used for 64bit.
+ Proper value is computed in the CONDITIONAL_REGISTER_USAGE.
+*/
+#define CALL_USED_REGISTERS \
+/*ax,dx,cx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7*/ \
+{ 3, 3, 3, 0, 2, 2, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, \
+/*arg,flags,fpsr,dir,frame*/ \
+ 3, 3, 3, 3, 3, \
+/*xmm0,xmm1,xmm2,xmm3,xmm4,xmm5,xmm6,xmm7*/ \
+ 3, 3, 3, 3, 3, 3, 3, 3, \
+/*mmx0,mmx1,mmx2,mmx3,mmx4,mmx5,mmx6,mmx7*/ \
+ 3, 3, 3, 3, 3, 3, 3, 3, \
+/* r8, r9, r10, r11, r12, r13, r14, r15*/ \
+ 3, 3, 3, 3, 1, 1, 1, 1, \
+/*xmm8,xmm9,xmm10,xmm11,xmm12,xmm13,xmm14,xmm15*/ \
+ 3, 3, 3, 3, 3, 3, 3, 3} \
/* Order in which to allocate registers. Each register must be
listed once, even those in FIXED_REGISTERS. List frame pointer
@@ -633,45 +941,67 @@ extern int ix86_arch;
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 ()
+ generated by allocating edx first, so restore the 'natural' order of things. */
+
+#define REG_ALLOC_ORDER \
+/*ax,dx,cx,*/ \
+{ 0, 1, 2, \
+/* bx,si,di,bp,sp,*/ \
+ 3, 4, 5, 6, 7, \
+/*r8,r9,r10,r11,*/ \
+ 37,38, 39, 40, \
+/*r12,r15,r14,r13*/ \
+ 41, 44, 43, 42, \
+/*xmm0,xmm1,xmm2,xmm3,xmm4,xmm5,xmm6,xmm7*/ \
+ 21, 22, 23, 24, 25, 26, 27, 28, \
+/*xmm8,xmm9,xmm10,xmm11,xmm12,xmm13,xmm14,xmm15*/ \
+ 45, 46, 47, 48, 49, 50, 51, 52, \
+/*st,st1,st2,st3,st4,st5,st6,st7*/ \
+ 8, 9, 10, 11, 12, 13, 14, 15, \
+/*,arg,cc,fpsr,dir,frame*/ \
+ 16,17, 18, 19, 20, \
+/*mmx0,mmx1,mmx2,mmx3,mmx4,mmx5,mmx6,mmx7*/ \
+ 29, 30, 31, 32, 33, 34, 35, 36 }
/* Macro to conditionally modify fixed_regs/call_used_regs. */
-#define CONDITIONAL_REGISTER_USAGE \
- { \
- if (flag_pic) \
- { \
- fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1; \
- call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1; \
- } \
- if (! TARGET_80387 && ! TARGET_FLOAT_RETURNS_IN_80387) \
- { \
- int i; \
- HARD_REG_SET x; \
- COPY_HARD_REG_SET (x, reg_class_contents[(int)FLOAT_REGS]); \
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++ ) \
- if (TEST_HARD_REG_BIT (x, i)) \
- fixed_regs[i] = call_used_regs[i] = 1; \
- } \
- }
+#define CONDITIONAL_REGISTER_USAGE \
+do { \
+ int i; \
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) \
+ { \
+ fixed_regs[i] = (fixed_regs[i] & (TARGET_64BIT ? 2 : 1)) != 0; \
+ call_used_regs[i] = (call_used_regs[i] \
+ & (TARGET_64BIT ? 2 : 1)) != 0; \
+ } \
+ if (flag_pic) \
+ { \
+ fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1; \
+ call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1; \
+ } \
+ if (! TARGET_MMX) \
+ { \
+ int i; \
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) \
+ if (TEST_HARD_REG_BIT (reg_class_contents[(int)MMX_REGS], i)) \
+ fixed_regs[i] = call_used_regs[i] = 1; \
+ } \
+ if (! TARGET_SSE) \
+ { \
+ int i; \
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) \
+ if (TEST_HARD_REG_BIT (reg_class_contents[(int)SSE_REGS], i)) \
+ fixed_regs[i] = call_used_regs[i] = 1; \
+ } \
+ if (! TARGET_80387 && ! TARGET_FLOAT_RETURNS_IN_80387) \
+ { \
+ int i; \
+ HARD_REG_SET x; \
+ COPY_HARD_REG_SET (x, reg_class_contents[(int)FLOAT_REGS]); \
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) \
+ if (TEST_HARD_REG_BIT (x, i)) \
+ fixed_regs[i] = call_used_regs[i] = 1; \
+ } \
+ } while (0)
/* Return number of consecutive hard regs needed starting at reg REGNO
to hold something of mode MODE.
@@ -684,25 +1014,48 @@ extern int ix86_arch;
*/
#define HARD_REGNO_NREGS(REGNO, MODE) \
- (FP_REGNO_P (REGNO) ? 1 \
- : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD))
-
-/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
- On the 80386, the first 4 cpu registers can hold any mode
- while the floating point registers may hold only floating point.
- Make it clear that the fp regs could not hold a 16-byte float. */
-
-/* The casts to int placate a compiler on a microvax,
- for cross-compiler testing. */
-
-#define HARD_REGNO_MODE_OK(REGNO, MODE) \
- ((REGNO) < 4 ? 1 \
- : 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) <= (LONG_DOUBLE_TYPE_SIZE == 96 ? 12 : 8))\
- : (int) (MODE) != (int) QImode ? 1 \
- : (reload_in_progress | reload_completed) == 1)
+ (FP_REGNO_P (REGNO) || SSE_REGNO_P (REGNO) || MMX_REGNO_P (REGNO) \
+ ? (COMPLEX_MODE_P (MODE) ? 2 : 1) \
+ : ((MODE) == TFmode \
+ ? (TARGET_64BIT ? 2 : 3) \
+ : (MODE) == TCmode \
+ ? (TARGET_64BIT ? 4 : 6) \
+ : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)))
+
+#define VALID_SSE_REG_MODE(MODE) \
+ ((MODE) == TImode || (MODE) == V4SFmode || (MODE) == V4SImode \
+ || (MODE) == SFmode \
+ || (TARGET_SSE2 && ((MODE) == DFmode || VALID_MMX_REG_MODE (MODE))))
+
+#define VALID_MMX_REG_MODE_3DNOW(MODE) \
+ ((MODE) == V2SFmode || (MODE) == SFmode)
+
+#define VALID_MMX_REG_MODE(MODE) \
+ ((MODE) == DImode || (MODE) == V8QImode || (MODE) == V4HImode \
+ || (MODE) == V2SImode || (MODE) == SImode)
+
+#define VECTOR_MODE_SUPPORTED_P(MODE) \
+ (VALID_SSE_REG_MODE (MODE) && TARGET_SSE ? 1 \
+ : VALID_MMX_REG_MODE (MODE) && TARGET_MMX ? 1 \
+ : VALID_MMX_REG_MODE_3DNOW (MODE) && TARGET_3DNOW ? 1 : 0)
+
+#define VALID_FP_MODE_P(MODE) \
+ ((MODE) == SFmode || (MODE) == DFmode || (MODE) == TFmode \
+ || (!TARGET_64BIT && (MODE) == XFmode) \
+ || (MODE) == SCmode || (MODE) == DCmode || (MODE) == TCmode \
+ || (!TARGET_64BIT && (MODE) == XCmode))
+
+#define VALID_INT_MODE_P(MODE) \
+ ((MODE) == QImode || (MODE) == HImode || (MODE) == SImode \
+ || (MODE) == DImode \
+ || (MODE) == CQImode || (MODE) == CHImode || (MODE) == CSImode \
+ || (MODE) == CDImode \
+ || (TARGET_64BIT && ((MODE) == TImode || (MODE) == CTImode)))
+
+/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. */
+
+#define HARD_REGNO_MODE_OK(REGNO, MODE) \
+ ix86_hard_regno_mode_ok ((REGNO), (MODE))
/* Value is 1 if it is a good idea to tie two pseudo registers
when one has mode MODE1 and one has mode MODE2.
@@ -711,9 +1064,28 @@ extern int ix86_arch;
#define MODES_TIEABLE_P(MODE1, MODE2) \
((MODE1) == (MODE2) \
- || ((MODE1) == SImode && (MODE2) == HImode) \
- || ((MODE1) == HImode && (MODE2) == SImode))
-
+ || (((MODE1) == HImode || (MODE1) == SImode \
+ || ((MODE1) == QImode \
+ && (TARGET_64BIT || !TARGET_PARTIAL_REG_STALL)) \
+ || ((MODE1) == DImode && TARGET_64BIT)) \
+ && ((MODE2) == HImode || (MODE2) == SImode \
+ || ((MODE1) == QImode \
+ && (TARGET_64BIT || !TARGET_PARTIAL_REG_STALL)) \
+ || ((MODE2) == DImode && TARGET_64BIT))))
+
+
+/* Specify the modes required to caller save a given hard regno.
+ We do this on i386 to prevent flags from being saved at all.
+
+ Kill any attempts to combine saving of modes. */
+
+#define HARD_REGNO_CALLER_SAVE_MODE(REGNO, NREGS, MODE) \
+ (CC_REGNO_P (REGNO) ? VOIDmode \
+ : (MODE) == VOIDmode && (NREGS) != 1 ? VOIDmode \
+ : (MODE) == VOIDmode ? choose_hard_reg_mode ((REGNO), (NREGS)) \
+ : (MODE) == HImode && !TARGET_PARTIAL_REG_STALL ? SImode \
+ : (MODE) == QImode && (REGNO) >= 4 && !TARGET_64BIT ? SImode \
+ : (MODE))
/* Specify the registers used for certain standard purposes.
The values of these macros are register numbers. */
@@ -725,7 +1097,10 @@ extern int ix86_arch;
#define STACK_POINTER_REGNUM 7
/* Base register for access to local variables of the function. */
-#define FRAME_POINTER_REGNUM 6
+#define HARD_FRAME_POINTER_REGNUM 6
+
+/* Base register for access to local variables of the function. */
+#define FRAME_POINTER_REGNUM 20
/* First floating point reg */
#define FIRST_FLOAT_REG 8
@@ -734,21 +1109,51 @@ extern int ix86_arch;
#define FIRST_STACK_REG FIRST_FLOAT_REG
#define LAST_STACK_REG (FIRST_FLOAT_REG + 7)
+#define FLAGS_REG 17
+#define FPSR_REG 18
+#define DIRFLAG_REG 19
+
+#define FIRST_SSE_REG (FRAME_POINTER_REGNUM + 1)
+#define LAST_SSE_REG (FIRST_SSE_REG + 7)
+
+#define FIRST_MMX_REG (LAST_SSE_REG + 1)
+#define LAST_MMX_REG (FIRST_MMX_REG + 7)
+
+#define FIRST_REX_INT_REG (LAST_MMX_REG + 1)
+#define LAST_REX_INT_REG (FIRST_REX_INT_REG + 7)
+
+#define FIRST_REX_SSE_REG (LAST_REX_INT_REG + 1)
+#define LAST_REX_SSE_REG (FIRST_REX_SSE_REG + 7)
+
/* Value should be nonzero if functions must have frame pointers.
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 (TARGET_OMIT_LEAF_FRAME_POINTER && !leaf_function_p ())
+#define FRAME_POINTER_REQUIRED ix86_frame_pointer_required ()
+
+/* Override this in other tm.h files to cope with various OS losage
+ requiring a frame pointer. */
+#ifndef SUBTARGET_FRAME_POINTER_REQUIRED
+#define SUBTARGET_FRAME_POINTER_REQUIRED 0
+#endif
+
+/* Make sure we can access arbitrary call frames. */
+#define SETUP_FRAME_ADDRESSES() ix86_setup_frame_addresses ()
/* Base register for access to arguments of the function. */
#define ARG_POINTER_REGNUM 16
-/* Register in which static-chain is passed to a function. */
-#define STATIC_CHAIN_REGNUM 2
+/* Register in which static-chain is passed to a function.
+ We do use ECX as static chain register for 32 bit ABI. On the
+ 64bit ABI, ECX is an argument register, so we use R10 instead. */
+#define STATIC_CHAIN_REGNUM (TARGET_64BIT ? FIRST_REX_INT_REG + 10 - 8 : 2)
/* Register to hold the addressing base for position independent
- code access to data items. */
-#define PIC_OFFSET_TABLE_REGNUM 3
+ code access to data items.
+ We don't use PIC pointer for 64bit mode. Define the regnum to
+ dummy value to prevent gcc from pessimizing code dealing with EBX.
+ */
+#define PIC_OFFSET_TABLE_REGNUM (TARGET_64BIT ? INVALID_REGNUM : 3)
/* Register in which address to store a structure value
arrives in the function. On the 386, the prologue
@@ -777,7 +1182,7 @@ extern int ix86_arch;
`DEFAULT_PCC_STRUCT_RETURN' to indicate this. */
#define RETURN_IN_MEMORY(TYPE) \
- ((TYPE_MODE (TYPE) == BLKmode) || int_size_in_bytes (TYPE) > 12)
+ ix86_return_in_memory (TYPE)
/* Define the classes of registers for register constraints in the
@@ -802,55 +1207,105 @@ extern int ix86_arch;
It might seem that class BREG is unnecessary, since no useful 386
opcode needs reg %ebx. But some systems pass args to the OS in ebx,
- and the "b" register constraint is useful in asms for syscalls. */
+ and the "b" register constraint is useful in asms for syscalls.
+
+ The flags and fpsr registers are in no class. */
enum reg_class
{
NO_REGS,
- AREG, DREG, CREG, BREG,
+ AREG, DREG, CREG, BREG, SIREG, DIREG,
AD_REGS, /* %eax/%edx for DImode */
Q_REGS, /* %eax %ebx %ecx %edx */
- SIREG, DIREG,
+ NON_Q_REGS, /* %esi %edi %ebp %esp */
INDEX_REGS, /* %eax %ebx %ecx %edx %esi %edi %ebp */
- GENERAL_REGS, /* %eax %ebx %ecx %edx %esi %edi %ebp %esp */
+ LEGACY_REGS, /* %eax %ebx %ecx %edx %esi %edi %ebp %esp */
+ GENERAL_REGS, /* %eax %ebx %ecx %edx %esi %edi %ebp %esp %r8 - %r15*/
FP_TOP_REG, FP_SECOND_REG, /* %st(0) %st(1) */
FLOAT_REGS,
+ SSE_REGS,
+ MMX_REGS,
+ FP_TOP_SSE_REGS,
+ FP_SECOND_SSE_REGS,
+ FLOAT_SSE_REGS,
+ FLOAT_INT_REGS,
+ INT_SSE_REGS,
+ FLOAT_INT_SSE_REGS,
ALL_REGS, LIM_REG_CLASSES
};
-#define N_REG_CLASSES (int) LIM_REG_CLASSES
-
-#define FLOAT_CLASS_P(CLASS) (reg_class_subset_p (CLASS, FLOAT_REGS))
+#define N_REG_CLASSES ((int) LIM_REG_CLASSES)
+
+#define INTEGER_CLASS_P(CLASS) \
+ reg_class_subset_p ((CLASS), GENERAL_REGS)
+#define FLOAT_CLASS_P(CLASS) \
+ reg_class_subset_p ((CLASS), FLOAT_REGS)
+#define SSE_CLASS_P(CLASS) \
+ reg_class_subset_p ((CLASS), SSE_REGS)
+#define MMX_CLASS_P(CLASS) \
+ reg_class_subset_p ((CLASS), MMX_REGS)
+#define MAYBE_INTEGER_CLASS_P(CLASS) \
+ reg_classes_intersect_p ((CLASS), GENERAL_REGS)
+#define MAYBE_FLOAT_CLASS_P(CLASS) \
+ reg_classes_intersect_p ((CLASS), FLOAT_REGS)
+#define MAYBE_SSE_CLASS_P(CLASS) \
+ reg_classes_intersect_p (SSE_REGS, (CLASS))
+#define MAYBE_MMX_CLASS_P(CLASS) \
+ reg_classes_intersect_p (MMX_REGS, (CLASS))
+
+#define Q_CLASS_P(CLASS) \
+ reg_class_subset_p ((CLASS), Q_REGS)
/* Give names of register classes as strings for dump file. */
#define REG_CLASS_NAMES \
{ "NO_REGS", \
"AREG", "DREG", "CREG", "BREG", \
- "AD_REGS", \
- "Q_REGS", \
"SIREG", "DIREG", \
+ "AD_REGS", \
+ "Q_REGS", "NON_Q_REGS", \
"INDEX_REGS", \
+ "LEGACY_REGS", \
"GENERAL_REGS", \
"FP_TOP_REG", "FP_SECOND_REG", \
"FLOAT_REGS", \
+ "SSE_REGS", \
+ "MMX_REGS", \
+ "FP_TOP_SSE_REGS", \
+ "FP_SECOND_SSE_REGS", \
+ "FLOAT_SSE_REGS", \
+ "FLOAT_INT_REGS", \
+ "INT_SSE_REGS", \
+ "FLOAT_INT_SSE_REGS", \
"ALL_REGS" }
/* Define which registers fit in which classes.
This is an initializer for a vector of HARD_REG_SET
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 */ \
- {0x7f}, /* INDEX_REGS */ \
- {0x100ff}, /* GENERAL_REGS */ \
- {0x0100}, {0x0200}, /* FP_TOP_REG, FP_SECOND_REG */ \
- {0xff00}, /* FLOAT_REGS */ \
- {0x1ffff}}
+#define REG_CLASS_CONTENTS \
+{ { 0x00, 0x0 }, \
+ { 0x01, 0x0 }, { 0x02, 0x0 }, /* AREG, DREG */ \
+ { 0x04, 0x0 }, { 0x08, 0x0 }, /* CREG, BREG */ \
+ { 0x10, 0x0 }, { 0x20, 0x0 }, /* SIREG, DIREG */ \
+ { 0x03, 0x0 }, /* AD_REGS */ \
+ { 0x0f, 0x0 }, /* Q_REGS */ \
+ { 0x1100f0, 0x1fe0 }, /* NON_Q_REGS */ \
+ { 0x7f, 0x1fe0 }, /* INDEX_REGS */ \
+ { 0x1100ff, 0x0 }, /* LEGACY_REGS */ \
+ { 0x1100ff, 0x1fe0 }, /* GENERAL_REGS */ \
+ { 0x100, 0x0 }, { 0x0200, 0x0 },/* FP_TOP_REG, FP_SECOND_REG */\
+ { 0xff00, 0x0 }, /* FLOAT_REGS */ \
+{ 0x1fe00000,0x1fe000 }, /* SSE_REGS */ \
+{ 0xe0000000, 0x1f }, /* MMX_REGS */ \
+{ 0x1fe00100,0x1fe000 }, /* FP_TOP_SSE_REG */ \
+{ 0x1fe00200,0x1fe000 }, /* FP_SECOND_SSE_REG */ \
+{ 0x1fe0ff00,0x1fe000 }, /* FLOAT_SSE_REGS */ \
+ { 0x1ffff, 0x1fe0 }, /* FLOAT_INT_REGS */ \
+{ 0x1fe100ff,0x1fffe0 }, /* INT_SSE_REGS */ \
+{ 0x1fe1ffff,0x1fffe0 }, /* FLOAT_INT_SSE_REGS */ \
+{ 0xffffffff,0x1fffff } \
+}
/* The same information, inverted:
Return the class number of the smallest class containing
@@ -861,30 +1316,62 @@ enum reg_class
/* 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. */
+ extending the lifetime of these registers. */
#define SMALL_REGISTER_CLASSES 1
#define QI_REG_P(X) \
(REG_P (X) && REGNO (X) < 4)
+
+#define GENERAL_REGNO_P(N) \
+ ((N) < 8 || REX_INT_REGNO_P (N))
+
+#define GENERAL_REG_P(X) \
+ (REG_P (X) && GENERAL_REGNO_P (REGNO (X)))
+
+#define ANY_QI_REG_P(X) (TARGET_64BIT ? GENERAL_REG_P(X) : QI_REG_P (X))
+
#define NON_QI_REG_P(X) \
(REG_P (X) && REGNO (X) >= 4 && REGNO (X) < FIRST_PSEUDO_REGISTER)
+#define REX_INT_REGNO_P(N) ((N) >= FIRST_REX_INT_REG && (N) <= LAST_REX_INT_REG)
+#define REX_INT_REG_P(X) (REG_P (X) && REX_INT_REGNO_P (REGNO (X)))
+
#define FP_REG_P(X) (REG_P (X) && FP_REGNO_P (REGNO (X)))
-#define FP_REGNO_P(n) ((n) >= FIRST_STACK_REG && (n) <= LAST_STACK_REG)
+#define FP_REGNO_P(N) ((N) >= FIRST_STACK_REG && (N) <= LAST_STACK_REG)
+#define ANY_FP_REG_P(X) (REG_P (X) && ANY_FP_REGNO_P (REGNO (X)))
+#define ANY_FP_REGNO_P(N) (FP_REGNO_P (N) || SSE_REGNO_P (N))
+
+#define SSE_REGNO_P(N) \
+ (((N) >= FIRST_SSE_REG && (N) <= LAST_SSE_REG) \
+ || ((N) >= FIRST_REX_SSE_REG && (N) <= LAST_REX_SSE_REG))
+
+#define SSE_REGNO(N) \
+ ((N) < 8 ? FIRST_SSE_REG + (N) : FIRST_REX_SSE_REG + (N) - 8)
+#define SSE_REG_P(N) (REG_P (N) && SSE_REGNO_P (REGNO (N)))
+
+#define SSE_FLOAT_MODE_P(MODE) \
+ ((TARGET_SSE_MATH && (MODE) == SFmode) || (TARGET_SSE2 && (MODE) == DFmode))
+
+#define MMX_REGNO_P(N) ((N) >= FIRST_MMX_REG && (N) <= LAST_MMX_REG)
+#define MMX_REG_P(XOP) (REG_P (XOP) && MMX_REGNO_P (REGNO (XOP)))
-#define STACK_REG_P(xop) (REG_P (xop) && \
- REGNO (xop) >= FIRST_STACK_REG && \
- REGNO (xop) <= LAST_STACK_REG)
+#define STACK_REG_P(XOP) \
+ (REG_P (XOP) && \
+ REGNO (XOP) >= FIRST_STACK_REG && \
+ REGNO (XOP) <= LAST_STACK_REG)
-#define NON_STACK_REG_P(xop) (REG_P (xop) && ! STACK_REG_P (xop))
+#define NON_STACK_REG_P(XOP) (REG_P (XOP) && ! STACK_REG_P (XOP))
-#define STACK_TOP_P(xop) (REG_P (xop) && REGNO (xop) == FIRST_STACK_REG)
+#define STACK_TOP_P(XOP) (REG_P (XOP) && REGNO (XOP) == FIRST_STACK_REG)
-/* 1 if register REGNO can magically overlap other regs.
- Note that nonzero values work only in very special circumstances. */
+#define CC_REG_P(X) (REG_P (X) && CC_REGNO_P (REGNO (X)))
+#define CC_REGNO_P(X) ((X) == FLAGS_REG || (X) == FPSR_REG)
-/* #define OVERLAPPING_REGNO_P(REGNO) FP_REGNO_P (REGNO) */
+/* Indicate whether hard register numbered REG_NO should be converted
+ to SSA form. */
+#define CONVERT_HARD_REGISTER_TO_SSA_P(REG_NO) \
+ ((REG_NO) == FLAGS_REG || (REG_NO) == ARG_POINTER_REGNUM)
/* The class value for index registers, and the one for base regs. */
@@ -895,7 +1382,9 @@ enum reg_class
#define REG_CLASS_FROM_LETTER(C) \
((C) == 'r' ? GENERAL_REGS : \
- (C) == 'q' ? Q_REGS : \
+ (C) == 'R' ? LEGACY_REGS : \
+ (C) == 'q' ? TARGET_64BIT ? GENERAL_REGS : Q_REGS : \
+ (C) == 'Q' ? Q_REGS : \
(C) == 'f' ? (TARGET_80387 || TARGET_FLOAT_RETURNS_IN_80387 \
? FLOAT_REGS \
: NO_REGS) : \
@@ -909,6 +1398,9 @@ enum reg_class
(C) == 'b' ? BREG : \
(C) == 'c' ? CREG : \
(C) == 'd' ? DREG : \
+ (C) == 'x' ? TARGET_SSE ? SSE_REGS : NO_REGS : \
+ (C) == 'Y' ? TARGET_SSE2? SSE_REGS : NO_REGS : \
+ (C) == 'y' ? TARGET_MMX ? MMX_REGS : NO_REGS : \
(C) == 'A' ? AD_REGS : \
(C) == 'D' ? DIREG : \
(C) == 'S' ? SIREG : NO_REGS)
@@ -921,19 +1413,20 @@ enum reg_class
I is for non-DImode shifts.
J is for DImode shifts.
- K and L are for an `andsi' optimization.
+ K is for signed imm8 operands.
+ L is for andsi as zero-extending move.
M is for shifts that can be executed by the "lea" opcode.
+ N is for immedaite operands for out/in instructions (0-255)
*/
-#define CONST_OK_FOR_LETTER_P(VALUE, C) \
- ((C) == 'I' ? (VALUE) >= 0 && (VALUE) <= 31 : \
- (C) == 'J' ? (VALUE) >= 0 && (VALUE) <= 63 : \
- (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)
+#define CONST_OK_FOR_LETTER_P(VALUE, C) \
+ ((C) == 'I' ? (VALUE) >= 0 && (VALUE) <= 31 \
+ : (C) == 'J' ? (VALUE) >= 0 && (VALUE) <= 63 \
+ : (C) == 'K' ? (VALUE) >= -128 && (VALUE) <= 127 \
+ : (C) == 'L' ? (VALUE) == 0xff || (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.
Here VALUE is the CONST_DOUBLE rtx itself. We allow constants even if
@@ -941,14 +1434,34 @@ enum reg_class
load 0.0 into the function value register. */
#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) \
- ((C) == 'G' ? standard_80387_constant_p (VALUE) : 0)
+ ((C) == 'G' ? standard_80387_constant_p (VALUE) \
+ : ((C) == 'H' ? standard_sse_constant_p (VALUE) : 0))
+
+/* A C expression that defines the optional machine-dependent
+ constraint letters that can be used to segregate specific types of
+ operands, usually memory references, for the target machine. Any
+ letter that is not elsewhere defined and not matched by
+ `REG_CLASS_FROM_LETTER' may be used. Normally this macro will not
+ be defined.
+
+ If it is required for a particular target machine, it should
+ return 1 if VALUE corresponds to the operand type represented by
+ the constraint letter C. If C is not defined as an extra
+ constraint, the value returned should be 0 regardless of VALUE. */
+
+#define EXTRA_CONSTRAINT(VALUE, C) \
+ ((C) == 'e' ? x86_64_sign_extended_value (VALUE) \
+ : (C) == 'Z' ? x86_64_zero_extended_value (VALUE) \
+ : 0)
/* Place additional restrictions on the register class to use when it
is necessary to be able to hold a value of mode MODE in a reload
- register for which class CLASS would ordinarily be used. */
+ register for which class CLASS would ordinarily be used. */
-#define LIMIT_RELOAD_CLASS(MODE, CLASS) \
- ((MODE) == QImode && ((CLASS) == ALL_REGS || (CLASS) == GENERAL_REGS) \
+#define LIMIT_RELOAD_CLASS(MODE, CLASS) \
+ ((MODE) == QImode && !TARGET_64BIT \
+ && ((CLASS) == ALL_REGS || (CLASS) == GENERAL_REGS \
+ || (CLASS) == LEGACY_REGS || (CLASS) == INDEX_REGS) \
? Q_REGS : (CLASS))
/* Given an rtx X being reloaded into a reg required to be
@@ -962,32 +1475,37 @@ enum reg_class
/* Put float CONST_DOUBLE in the constant pool instead of fp regs.
QImode must go into class Q_REGS.
Narrow ALL_REGS to GENERAL_REGS. This supports allowing movsf and
- movdf to do mem-to-mem moves through integer regs. */
-
-#define PREFERRED_RELOAD_CLASS(X,CLASS) \
- (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) != VOIDmode \
- ? (standard_80387_constant_p (X) \
- ? reg_class_subset_p (CLASS, FLOAT_REGS) ? CLASS : FLOAT_REGS \
- : NO_REGS) \
- : GET_MODE (X) == QImode && ! reg_class_subset_p (CLASS, Q_REGS) ? Q_REGS \
- : ((CLASS) == ALL_REGS \
- && GET_MODE_CLASS (GET_MODE (X)) == MODE_FLOAT) ? GENERAL_REGS \
- : (CLASS))
+ movdf to do mem-to-mem moves through integer regs. */
+
+#define PREFERRED_RELOAD_CLASS(X, CLASS) \
+ ix86_preferred_reload_class ((X), (CLASS))
/* If we are copying between general and FP registers, we need a memory
- location. */
+ location. The same is true for SSE and MMX registers. */
+#define SECONDARY_MEMORY_NEEDED(CLASS1, CLASS2, MODE) \
+ ix86_secondary_memory_needed ((CLASS1), (CLASS2), (MODE), 1)
+
+/* QImode spills from non-QI registers need a scratch. This does not
+ happen often -- the only example so far requires an uninitialized
+ pseudo. */
-#define SECONDARY_MEMORY_NEEDED(CLASS1,CLASS2,MODE) \
- ((FLOAT_CLASS_P (CLASS1) && ! FLOAT_CLASS_P (CLASS2)) \
- || (! FLOAT_CLASS_P (CLASS1) && FLOAT_CLASS_P (CLASS2)))
+#define SECONDARY_OUTPUT_RELOAD_CLASS(CLASS, MODE, OUT) \
+ (((CLASS) == GENERAL_REGS || (CLASS) == LEGACY_REGS \
+ || (CLASS) == INDEX_REGS) && !TARGET_64BIT && (MODE) == QImode \
+ ? Q_REGS : NO_REGS)
/* Return the maximum number of consecutive registers
needed to represent mode MODE in a register of class CLASS. */
/* On the 80386, this is the size of MODE in words,
- except in the FP regs, where a single reg is always enough. */
-#define CLASS_MAX_NREGS(CLASS, MODE) \
- (FLOAT_CLASS_P (CLASS) ? 1 : \
- ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD))
+ except in the FP regs, where a single reg is always enough.
+ The TFmodes are really just 80bit values, so we use only 3 registers
+ to hold them, instead of 4, as the size would suggest.
+ */
+#define CLASS_MAX_NREGS(CLASS, MODE) \
+ (!MAYBE_INTEGER_CLASS_P (CLASS) \
+ ? (COMPLEX_MODE_P (MODE) ? 2 : 1) \
+ : ((GET_MODE_SIZE ((MODE) == TFmode ? XFmode : (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
@@ -1014,6 +1532,21 @@ enum reg_class
|| ((CLASS) == SIREG) \
|| ((CLASS) == DIREG))
+/* A C statement that adds to CLOBBERS any hard regs the port wishes
+ to automatically clobber for all asms.
+
+ We do this in the new i386 backend to maintain source compatibility
+ with the old cc0-based compiler. */
+
+#define MD_ASM_CLOBBERS(CLOBBERS) \
+ do { \
+ (CLOBBERS) = tree_cons (NULL_TREE, build_string (5, "flags"), \
+ (CLOBBERS)); \
+ (CLOBBERS) = tree_cons (NULL_TREE, build_string (4, "fpsr"), \
+ (CLOBBERS)); \
+ (CLOBBERS) = tree_cons (NULL_TREE, build_string (7, "dirflag"), \
+ (CLOBBERS)); \
+ } while (0)
/* Stack layout; function entry, exit and calling. */
@@ -1037,13 +1570,61 @@ enum reg_class
this says how many the stack pointer really advances by.
On 386 pushw decrements by exactly 2 no matter what the position was.
On the 386 there is no pushb; we use pushw instead, and this
- has the effect of rounding up to 2. */
+ has the effect of rounding up to 2.
+
+ For 64bit ABI we round up to 8 bytes.
+ */
+
+#define PUSH_ROUNDING(BYTES) \
+ (TARGET_64BIT \
+ ? (((BYTES) + 7) & (-8)) \
+ : (((BYTES) + 1) & (-2)))
-#define PUSH_ROUNDING(BYTES) (((BYTES) + 1) & (-2))
+/* If defined, the maximum amount of space required for outgoing arguments will
+ be computed and placed into the variable
+ `current_function_outgoing_args_size'. No space will be pushed onto the
+ stack for each call; instead, the function prologue should increase the stack
+ frame size by this amount. */
+
+#define ACCUMULATE_OUTGOING_ARGS TARGET_ACCUMULATE_OUTGOING_ARGS
+
+/* If defined, a C expression whose value is nonzero when we want to use PUSH
+ instructions to pass outgoing arguments. */
+
+#define PUSH_ARGS (TARGET_PUSH_ARGS && !ACCUMULATE_OUTGOING_ARGS)
/* Offset of first parameter from the argument pointer register value. */
#define FIRST_PARM_OFFSET(FNDECL) 0
+/* Define this macro if functions should assume that stack space has been
+ allocated for arguments even when their values are passed in registers.
+
+ The value of this macro is the size, in bytes, of the area reserved for
+ arguments passed in registers for the function represented by FNDECL.
+
+ This space can be allocated by the caller, or be a part of the
+ machine-dependent stack frame: `OUTGOING_REG_PARM_STACK_SPACE' says
+ which. */
+#define REG_PARM_STACK_SPACE(FNDECL) 0
+
+/* Define as a C expression that evaluates to nonzero if we do not know how
+ to pass TYPE solely in registers. The file expr.h defines a
+ definition that is usually appropriate, refer to expr.h for additional
+ documentation. If `REG_PARM_STACK_SPACE' is defined, the argument will be
+ computed in the stack and then loaded into a register. */
+#define MUST_PASS_IN_STACK(MODE, TYPE) \
+ ((TYPE) != 0 \
+ && (TREE_CODE (TYPE_SIZE (TYPE)) != INTEGER_CST \
+ || TREE_ADDRESSABLE (TYPE) \
+ || ((MODE) == TImode) \
+ || ((MODE) == BLKmode \
+ && ! ((TYPE) != 0 \
+ && TREE_CODE (TYPE_SIZE (TYPE)) == INTEGER_CST \
+ && 0 == (int_size_in_bytes (TYPE) \
+ % (PARM_BOUNDARY / BITS_PER_UNIT))) \
+ && (FUNCTION_ARG_PADDING (MODE, TYPE) \
+ == (BYTES_BIG_ENDIAN ? upward : downward)))))
+
/* 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),
@@ -1061,22 +1642,24 @@ enum reg_class
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 RETURN_POPS_ARGS(FUNDECL, FUNTYPE, SIZE) \
+ ix86_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), \
- VALUE_REGNO (TYPE_MODE (VALTYPE)))
+ ix86_function_value (VALTYPE)
+
+#define FUNCTION_VALUE_REGNO_P(N) \
+ ix86_function_value_regno_p (N)
/* 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))
+ ix86_libcall_value (MODE)
/* Define the size of the result block used for communication between
untyped_call and untyped_return. The block contains a DImode value
@@ -1085,7 +1668,7 @@ enum reg_class
#define APPLY_RESULT_SIZE (8+108)
/* 1 if N is a possible register number for function argument passing. */
-#define FUNCTION_ARG_REGNO_P(N) ((N) >= 0 && (N) < REGPARM_MAX)
+#define FUNCTION_ARG_REGNO_P(N) ix86_function_arg_regno_p (N)
/* Define a data type for recording info about an argument list
during the scan of that argument list. This data type should
@@ -1093,25 +1676,29 @@ enum reg_class
and about the args processed so far, enough to enable macros
such as FUNCTION_ARG to determine where the next arg should go. */
-typedef struct i386_args {
+typedef struct ix86_args {
int words; /* # words passed so far */
int nregs; /* # registers available for passing */
int regno; /* next available register number */
+ int sse_words; /* # sse words passed so far */
+ int sse_nregs; /* # sse registers available for passing */
+ int sse_regno; /* next available sse register number */
+ int maybe_vaarg; /* true for calls to possibly vardic fncts. */
} 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. */
-#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE,LIBNAME,INDIRECT) \
- (init_cumulative_args (&CUM, FNTYPE, LIBNAME))
+#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) \
- (function_arg_advance (&CUM, MODE, TYPE, NAMED))
+#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \
+ 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,
@@ -1127,404 +1714,79 @@ typedef struct i386_args {
(otherwise it is an extra parameter matching an ellipsis). */
#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \
- (function_arg (&CUM, MODE, TYPE, NAMED))
+ 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) \
- (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. */
+#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) 0
-#undef ASM_OUTPUT_FUNCTION_PREFIX
-#define ASM_OUTPUT_FUNCTION_PREFIX(FILE, FNNAME) \
- asm_output_function_prefix (FILE, FNNAME)
+/* If PIC, we cannot make sibling calls to global functions
+ because the PLT requires %ebx live.
+ If we are returning floats on the register stack, we cannot make
+ sibling calls to functions that return floats. (The stack adjust
+ instruction will wind up after the sibcall jump, and not be executed.) */
+#define FUNCTION_OK_FOR_SIBCALL(DECL) \
+ ((DECL) \
+ && (! flag_pic || ! TREE_PUBLIC (DECL)) \
+ && (! TARGET_FLOAT_RETURNS_IN_80387 \
+ || ! FLOAT_MODE_P (TYPE_MODE (TREE_TYPE (TREE_TYPE (DECL)))) \
+ || FLOAT_MODE_P (TYPE_MODE (TREE_TYPE (TREE_TYPE (cfun->decl))))))
-/* This macro generates the assembly code for function entry.
- FILE is a stdio stream to output the code to.
- SIZE is an int: how many units of temporary storage to allocate.
- Refer to the array `regs_ever_live' to determine which registers
- to save; `regs_ever_live[I]' is nonzero if register number I
- is ever used in the function. This macro is responsible for
- knowing which registers should not be saved even if used. */
+/* Perform any needed actions needed for a function that is receiving a
+ variable number of arguments.
-#define FUNCTION_PROLOGUE(FILE, SIZE) \
- function_prologue (FILE, SIZE)
+ CUM is as above.
-/* Output assembler code to FILE to increment profiler label # LABELNO
- for profiling a function entry. */
+ MODE and TYPE are the mode and type of the current parameter.
-#define FUNCTION_PROFILER(FILE, LABELNO) \
-{ \
- if (flag_pic) \
- { \
- fprintf (FILE, "\tleal %sP%d@GOTOFF(%%ebx),%%edx\n", \
- LPREFIX, (LABELNO)); \
- fprintf (FILE, "\tcall *_mcount@GOT(%%ebx)\n"); \
- } \
- else \
- { \
- fprintf (FILE, "\tmovl $%sP%d,%%edx\n", LPREFIX, (LABELNO)); \
- fprintf (FILE, "\tcall _mcount\n"); \
- } \
-}
+ PRETEND_SIZE is a variable that should be set to the amount of stack
+ that must be pushed by the prolog to pretend that our caller pushed
+ it.
+ Normally, this macro will push all remaining incoming registers on the
+ stack and set PRETEND_SIZE to the length of the registers pushed. */
-/* 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.
+#define SETUP_INCOMING_VARARGS(CUM, MODE, TYPE, PRETEND_SIZE, NO_RTL) \
+ ix86_setup_incoming_varargs (&(CUM), (MODE), (TYPE), &(PRETEND_SIZE), \
+ (NO_RTL))
- profile_block_flag == 0, no option used:
+/* Define the `__builtin_va_list' type for the ABI. */
+#define BUILD_VA_LIST_TYPE(VALIST) \
+ ((VALIST) = ix86_build_va_list ())
- No profiling done.
+/* Implement `va_start' for varargs and stdarg. */
+#define EXPAND_BUILTIN_VA_START(STDARG, VALIST, NEXTARG) \
+ ix86_va_start ((STDARG), (VALIST), (NEXTARG))
- profile_block_flag == 1, -a option used.
+/* Implement `va_arg'. */
+#define EXPAND_BUILTIN_VA_ARG(VALIST, TYPE) \
+ ix86_va_arg ((VALIST), (TYPE))
- Count frequency of execution of every basic block.
+/* This macro is invoked at the end of compilation. It is used here to
+ output code for -fpic that will load the return address into %ebx. */
- profile_block_flag == 2, -ax option used.
+#undef ASM_FILE_END
+#define ASM_FILE_END(FILE) ix86_asm_file_end (FILE)
- 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:
-
-*/
+/* Output assembler code to FILE to increment profiler label # LABELNO
+ for profiling a function entry. */
-#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; \
- \
+#define FUNCTION_PROFILER(FILE, LABELNO) \
+do { \
+ if (flag_pic) \
+ { \
+ fprintf ((FILE), "\tleal\t%sP%d@GOTOFF(%%ebx),%%edx\n", \
+ LPREFIX, (LABELNO)); \
+ fprintf ((FILE), "\tcall\t*_mcount@GOT(%%ebx)\n"); \
} \
- } \
-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; \
- \
+ else \
+ { \
+ fprintf ((FILE), "\tmovl\t$%sP%d,%%edx\n", LPREFIX, (LABELNO)); \
+ fprintf ((FILE), "\tcall\t_mcount\n"); \
} \
- } \
-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");
+} 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
@@ -1536,35 +1798,6 @@ while (0)
#define EXIT_IGNORE_STACK 1
-/* This macro generates the assembly code for function exit,
- on machines that need it. If FUNCTION_EPILOGUE is not defined
- then individual return instructions are generated for each
- return statement. Args are same as for FUNCTION_PROLOGUE.
-
- The function epilogue should not depend on the current stack pointer!
- It should use the frame pointer only. This is mandatory because
- of alloca; we also take advantage of it to omit stack adjustments
- before returning.
-
- If the last non-note insn in the function is a BARRIER, then there
- is no need to emit a function prologue, because control does not fall
- off the end. This happens if the function ends in an "exit" call, or
- if a `return' insn is emitted directly into the function. */
-
-#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);*/ \
-} 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. */
@@ -1577,23 +1810,14 @@ do { \
/* Length in units of the trampoline for entering a nested function. */
-#define TRAMPOLINE_SIZE 10
+#define TRAMPOLINE_SIZE (TARGET_64BIT ? 23 : 10)
/* Emit RTL insns to initialize the variable parts of a trampoline.
FNADDR is an RTX for the address of the function's pure code.
CXT is an RTX for the static chain value for the function. */
-#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT) \
-{ \
- /* Compute offset from the end of the jmp to the target function. */ \
- rtx disp = expand_binop (SImode, sub_optab, FNADDR, \
- plus_constant (TRAMP, 10), \
- NULL_RTX, 1, OPTAB_DIRECT); \
- emit_move_insn (gen_rtx_MEM (QImode, TRAMP), GEN_INT (0xb9)); \
- emit_move_insn (gen_rtx_MEM (SImode, plus_constant (TRAMP, 1)), CXT); \
- emit_move_insn (gen_rtx_MEM (QImode, plus_constant (TRAMP, 5)), GEN_INT (0xe9));\
- emit_move_insn (gen_rtx_MEM (SImode, plus_constant (TRAMP, 6)), disp); \
-}
+#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT) \
+ x86_initialize_trampoline ((TRAMP), (FNADDR), (CXT))
/* Definitions for register eliminations.
@@ -1602,57 +1826,31 @@ do { \
followed by "to". Eliminations of the same "from" register are listed
in order of preference.
- We have two registers that can be eliminated on the i386. First, the
- frame pointer register can often be eliminated in favor of the stack
- pointer register. Secondly, the argument pointer register can always be
- eliminated; it is replaced with either the stack or frame pointer. */
-
-#define ELIMINABLE_REGS \
-{{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
- { ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM}, \
- { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}}
+ There are two registers that can always be eliminated on the i386.
+ The frame pointer and the arg pointer can be replaced by either the
+ hard frame pointer or to the stack pointer, depending upon the
+ circumstances. The hard frame pointer is not used before reload and
+ so it is not eligible for elimination. */
-/* Given FROM and TO register numbers, say whether this elimination is allowed.
- Frame pointer elimination is automatically handled.
+#define ELIMINABLE_REGS \
+{{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
+ { ARG_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}, \
+ { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
+ { FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}} \
- For the i386, if frame pointer elimination is being done, we would like to
- convert ap into sp, not fp.
+/* Given FROM and TO register numbers, say whether this elimination is
+ allowed. Frame pointer elimination is automatically handled.
All other eliminations are valid. */
-#define CAN_ELIMINATE(FROM, TO) \
- ((FROM) == ARG_POINTER_REGNUM && (TO) == STACK_POINTER_REGNUM \
- ? ! frame_pointer_needed \
- : 1)
+#define CAN_ELIMINATE(FROM, TO) \
+ ((TO) == STACK_POINTER_REGNUM ? ! frame_pointer_needed : 1)
/* Define the offset between two registers, one to be eliminated, and the other
its replacement, at the start of a routine. */
-#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
-{ \
- if ((FROM) == ARG_POINTER_REGNUM && (TO) == FRAME_POINTER_REGNUM) \
- (OFFSET) = 8; /* Skip saved PC and previous frame pointer */ \
- else \
- { \
- int nregs; \
- int offset; \
- int preferred_alignment = PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT; \
- HOST_WIDE_INT tsize = ix86_compute_frame_size (get_frame_size (), \
- &nregs); \
- \
- (OFFSET) = (tsize + nregs * UNITS_PER_WORD); \
- \
- offset = 4; \
- if (frame_pointer_needed) \
- offset += UNITS_PER_WORD; \
- \
- if ((FROM) == ARG_POINTER_REGNUM) \
- (OFFSET) += offset; \
- else \
- (OFFSET) -= ((offset + preferred_alignment - 1) \
- & -preferred_alignment) - offset; \
- } \
-}
+#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
+ ((OFFSET) = ix86_initial_elimination_offset ((FROM), (TO)))
/* Addressing modes, and classification of registers for them. */
@@ -1670,17 +1868,28 @@ do { \
Since they use reg_renumber, they are safe only once reg_renumber
has been allocated, which happens in local-alloc.c. */
-#define REGNO_OK_FOR_INDEX_P(REGNO) \
- ((REGNO) < STACK_POINTER_REGNUM \
- || (unsigned) reg_renumber[REGNO] < STACK_POINTER_REGNUM)
-
-#define REGNO_OK_FOR_BASE_P(REGNO) \
- ((REGNO) <= STACK_POINTER_REGNUM \
- || (REGNO) == ARG_POINTER_REGNUM \
- || (unsigned) reg_renumber[REGNO] <= STACK_POINTER_REGNUM)
-
-#define REGNO_OK_FOR_SIREG_P(REGNO) ((REGNO) == 4 || reg_renumber[REGNO] == 4)
-#define REGNO_OK_FOR_DIREG_P(REGNO) ((REGNO) == 5 || reg_renumber[REGNO] == 5)
+#define REGNO_OK_FOR_INDEX_P(REGNO) \
+ ((REGNO) < STACK_POINTER_REGNUM \
+ || (REGNO >= FIRST_REX_INT_REG \
+ && (REGNO) <= LAST_REX_INT_REG) \
+ || ((unsigned) reg_renumber[(REGNO)] >= FIRST_REX_INT_REG \
+ && (unsigned) reg_renumber[(REGNO)] <= LAST_REX_INT_REG) \
+ || (unsigned) reg_renumber[(REGNO)] < STACK_POINTER_REGNUM)
+
+#define REGNO_OK_FOR_BASE_P(REGNO) \
+ ((REGNO) <= STACK_POINTER_REGNUM \
+ || (REGNO) == ARG_POINTER_REGNUM \
+ || (REGNO) == FRAME_POINTER_REGNUM \
+ || (REGNO >= FIRST_REX_INT_REG \
+ && (REGNO) <= LAST_REX_INT_REG) \
+ || ((unsigned) reg_renumber[(REGNO)] >= FIRST_REX_INT_REG \
+ && (unsigned) reg_renumber[(REGNO)] <= LAST_REX_INT_REG) \
+ || (unsigned) reg_renumber[(REGNO)] <= STACK_POINTER_REGNUM)
+
+#define REGNO_OK_FOR_SIREG_P(REGNO) \
+ ((REGNO) == 4 || reg_renumber[(REGNO)] == 4)
+#define REGNO_OK_FOR_DIREG_P(REGNO) \
+ ((REGNO) == 5 || reg_renumber[(REGNO)] == 5)
/* The macros REG_OK_FOR..._P assume that the arg is a REG rtx
and check its validity for a certain class.
@@ -1699,31 +1908,29 @@ do { \
/* Non strict versions, pseudos are ok */
#define REG_OK_FOR_INDEX_NONSTRICT_P(X) \
(REGNO (X) < STACK_POINTER_REGNUM \
+ || (REGNO (X) >= FIRST_REX_INT_REG \
+ && REGNO (X) <= LAST_REX_INT_REG) \
|| 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) == FRAME_POINTER_REGNUM \
+ || (REGNO (X) >= FIRST_REX_INT_REG \
+ && REGNO (X) <= LAST_REX_INT_REG) \
|| REGNO (X) >= FIRST_PSEUDO_REGISTER)
-#define REG_OK_FOR_STRREG_NONSTRICT_P(X) \
- (REGNO (X) == 4 || REGNO (X) == 5 || REGNO (X) >= FIRST_PSEUDO_REGISTER)
-
/* 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)
+#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)
#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)
+#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)
#endif
/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression
@@ -1741,30 +1948,41 @@ do { \
#define CONSTANT_ADDRESS_P(X) \
(GET_CODE (X) == LABEL_REF || GET_CODE (X) == SYMBOL_REF \
- || GET_CODE (X) == CONST_INT || GET_CODE (X) == CONST)
+ || GET_CODE (X) == CONST_INT || GET_CODE (X) == CONST \
+ || GET_CODE (X) == CONST_DOUBLE)
/* Nonzero if the constant value X is a legitimate general operand.
It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. */
-#define LEGITIMATE_CONSTANT_P(X) \
- (GET_CODE (X) == CONST_DOUBLE ? standard_80387_constant_p (X) : 1)
+#define LEGITIMATE_CONSTANT_P(X) 1
#ifdef REG_OK_STRICT
#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \
-{ \
- if (legitimate_address_p (MODE, X, 1)) \
+do { \
+ if (legitimate_address_p ((MODE), (X), 1)) \
goto ADDR; \
-}
+} while (0)
#else
#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \
-{ \
- if (legitimate_address_p (MODE, X, 0)) \
+do { \
+ if (legitimate_address_p ((MODE), (X), 0)) \
goto ADDR; \
-}
+} while (0)
#endif
+/* If defined, a C expression to determine the base term of address X.
+ This macro is used in only one place: `find_base_term' in alias.c.
+
+ It is always safe for this macro to not be defined. It exists so
+ that alias analysis can understand machine-dependent addresses.
+
+ The typical use of this macro is to handle addresses containing
+ a label_ref or symbol_ref within an UNSPEC. */
+
+#define FIND_BASE_TERM(X) ix86_find_base_term (X)
+
/* 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.
@@ -1787,32 +2005,256 @@ do { \
See comments by legitimize_pic_address in i386.c for details. */
#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) \
-{ \
- (X) = legitimize_address (X, OLDX, MODE); \
- if (memory_address_p (MODE, X)) \
+do { \
+ (X) = legitimize_address ((X), (OLDX), (MODE)); \
+ if (memory_address_p ((MODE), (X))) \
goto WIN; \
-}
+} while (0)
-#define REWRITE_ADDRESS(x) rewrite_address(x)
+#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
that X satisfies CONSTANT_P or is a CONST_DOUBLE. */
-#define LEGITIMATE_PIC_OPERAND_P(X) \
- (! SYMBOLIC_CONST (X) || legitimate_pic_address_disp_p (X))
+#define LEGITIMATE_PIC_OPERAND_P(X) \
+ (! SYMBOLIC_CONST (X) \
+ || legitimate_pic_address_disp_p (X))
#define SYMBOLIC_CONST(X) \
-(GET_CODE (X) == SYMBOL_REF \
- || GET_CODE (X) == LABEL_REF \
- || (GET_CODE (X) == CONST && symbolic_reference_mentioned_p (X)))
+ (GET_CODE (X) == SYMBOL_REF \
+ || GET_CODE (X) == LABEL_REF \
+ || (GET_CODE (X) == CONST && symbolic_reference_mentioned_p (X)))
/* Go to LABEL if ADDR (a legitimate address expression)
has an effect that depends on the machine mode it is used for.
On the 80386, only postdecrement and postincrement address depend thus
(the amount of decrement or increment being the length of the operand). */
-#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) \
- if (GET_CODE (ADDR) == POST_INC || GET_CODE (ADDR) == POST_DEC) goto LABEL
+#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR, LABEL) \
+do { \
+ if (GET_CODE (ADDR) == POST_INC \
+ || GET_CODE (ADDR) == POST_DEC) \
+ goto LABEL; \
+} while (0)
+
+/* Codes for all the SSE/MMX builtins. */
+enum ix86_builtins
+{
+ IX86_BUILTIN_ADDPS,
+ IX86_BUILTIN_ADDSS,
+ IX86_BUILTIN_DIVPS,
+ IX86_BUILTIN_DIVSS,
+ IX86_BUILTIN_MULPS,
+ IX86_BUILTIN_MULSS,
+ IX86_BUILTIN_SUBPS,
+ IX86_BUILTIN_SUBSS,
+
+ IX86_BUILTIN_CMPEQPS,
+ IX86_BUILTIN_CMPLTPS,
+ IX86_BUILTIN_CMPLEPS,
+ IX86_BUILTIN_CMPGTPS,
+ IX86_BUILTIN_CMPGEPS,
+ IX86_BUILTIN_CMPNEQPS,
+ IX86_BUILTIN_CMPNLTPS,
+ IX86_BUILTIN_CMPNLEPS,
+ IX86_BUILTIN_CMPNGTPS,
+ IX86_BUILTIN_CMPNGEPS,
+ IX86_BUILTIN_CMPORDPS,
+ IX86_BUILTIN_CMPUNORDPS,
+ IX86_BUILTIN_CMPNEPS,
+ IX86_BUILTIN_CMPEQSS,
+ IX86_BUILTIN_CMPLTSS,
+ IX86_BUILTIN_CMPLESS,
+ IX86_BUILTIN_CMPGTSS,
+ IX86_BUILTIN_CMPGESS,
+ IX86_BUILTIN_CMPNEQSS,
+ IX86_BUILTIN_CMPNLTSS,
+ IX86_BUILTIN_CMPNLESS,
+ IX86_BUILTIN_CMPNGTSS,
+ IX86_BUILTIN_CMPNGESS,
+ IX86_BUILTIN_CMPORDSS,
+ IX86_BUILTIN_CMPUNORDSS,
+ IX86_BUILTIN_CMPNESS,
+
+ IX86_BUILTIN_COMIEQSS,
+ IX86_BUILTIN_COMILTSS,
+ IX86_BUILTIN_COMILESS,
+ IX86_BUILTIN_COMIGTSS,
+ IX86_BUILTIN_COMIGESS,
+ IX86_BUILTIN_COMINEQSS,
+ IX86_BUILTIN_UCOMIEQSS,
+ IX86_BUILTIN_UCOMILTSS,
+ IX86_BUILTIN_UCOMILESS,
+ IX86_BUILTIN_UCOMIGTSS,
+ IX86_BUILTIN_UCOMIGESS,
+ IX86_BUILTIN_UCOMINEQSS,
+
+ IX86_BUILTIN_CVTPI2PS,
+ IX86_BUILTIN_CVTPS2PI,
+ IX86_BUILTIN_CVTSI2SS,
+ IX86_BUILTIN_CVTSS2SI,
+ IX86_BUILTIN_CVTTPS2PI,
+ IX86_BUILTIN_CVTTSS2SI,
+
+ IX86_BUILTIN_MAXPS,
+ IX86_BUILTIN_MAXSS,
+ IX86_BUILTIN_MINPS,
+ IX86_BUILTIN_MINSS,
+
+ IX86_BUILTIN_LOADAPS,
+ IX86_BUILTIN_LOADUPS,
+ IX86_BUILTIN_STOREAPS,
+ IX86_BUILTIN_STOREUPS,
+ IX86_BUILTIN_LOADSS,
+ IX86_BUILTIN_STORESS,
+ IX86_BUILTIN_MOVSS,
+
+ IX86_BUILTIN_MOVHLPS,
+ IX86_BUILTIN_MOVLHPS,
+ IX86_BUILTIN_LOADHPS,
+ IX86_BUILTIN_LOADLPS,
+ IX86_BUILTIN_STOREHPS,
+ IX86_BUILTIN_STORELPS,
+
+ IX86_BUILTIN_MASKMOVQ,
+ IX86_BUILTIN_MOVMSKPS,
+ IX86_BUILTIN_PMOVMSKB,
+
+ IX86_BUILTIN_MOVNTPS,
+ IX86_BUILTIN_MOVNTQ,
+
+ IX86_BUILTIN_PACKSSWB,
+ IX86_BUILTIN_PACKSSDW,
+ IX86_BUILTIN_PACKUSWB,
+
+ IX86_BUILTIN_PADDB,
+ IX86_BUILTIN_PADDW,
+ IX86_BUILTIN_PADDD,
+ IX86_BUILTIN_PADDSB,
+ IX86_BUILTIN_PADDSW,
+ IX86_BUILTIN_PADDUSB,
+ IX86_BUILTIN_PADDUSW,
+ IX86_BUILTIN_PSUBB,
+ IX86_BUILTIN_PSUBW,
+ IX86_BUILTIN_PSUBD,
+ IX86_BUILTIN_PSUBSB,
+ IX86_BUILTIN_PSUBSW,
+ IX86_BUILTIN_PSUBUSB,
+ IX86_BUILTIN_PSUBUSW,
+
+ IX86_BUILTIN_PAND,
+ IX86_BUILTIN_PANDN,
+ IX86_BUILTIN_POR,
+ IX86_BUILTIN_PXOR,
+
+ IX86_BUILTIN_PAVGB,
+ IX86_BUILTIN_PAVGW,
+
+ IX86_BUILTIN_PCMPEQB,
+ IX86_BUILTIN_PCMPEQW,
+ IX86_BUILTIN_PCMPEQD,
+ IX86_BUILTIN_PCMPGTB,
+ IX86_BUILTIN_PCMPGTW,
+ IX86_BUILTIN_PCMPGTD,
+
+ IX86_BUILTIN_PEXTRW,
+ IX86_BUILTIN_PINSRW,
+
+ IX86_BUILTIN_PMADDWD,
+
+ IX86_BUILTIN_PMAXSW,
+ IX86_BUILTIN_PMAXUB,
+ IX86_BUILTIN_PMINSW,
+ IX86_BUILTIN_PMINUB,
+
+ IX86_BUILTIN_PMULHUW,
+ IX86_BUILTIN_PMULHW,
+ IX86_BUILTIN_PMULLW,
+
+ IX86_BUILTIN_PSADBW,
+ IX86_BUILTIN_PSHUFW,
+
+ IX86_BUILTIN_PSLLW,
+ IX86_BUILTIN_PSLLD,
+ IX86_BUILTIN_PSLLQ,
+ IX86_BUILTIN_PSRAW,
+ IX86_BUILTIN_PSRAD,
+ IX86_BUILTIN_PSRLW,
+ IX86_BUILTIN_PSRLD,
+ IX86_BUILTIN_PSRLQ,
+ IX86_BUILTIN_PSLLWI,
+ IX86_BUILTIN_PSLLDI,
+ IX86_BUILTIN_PSLLQI,
+ IX86_BUILTIN_PSRAWI,
+ IX86_BUILTIN_PSRADI,
+ IX86_BUILTIN_PSRLWI,
+ IX86_BUILTIN_PSRLDI,
+ IX86_BUILTIN_PSRLQI,
+
+ IX86_BUILTIN_PUNPCKHBW,
+ IX86_BUILTIN_PUNPCKHWD,
+ IX86_BUILTIN_PUNPCKHDQ,
+ IX86_BUILTIN_PUNPCKLBW,
+ IX86_BUILTIN_PUNPCKLWD,
+ IX86_BUILTIN_PUNPCKLDQ,
+
+ IX86_BUILTIN_SHUFPS,
+
+ IX86_BUILTIN_RCPPS,
+ IX86_BUILTIN_RCPSS,
+ IX86_BUILTIN_RSQRTPS,
+ IX86_BUILTIN_RSQRTSS,
+ IX86_BUILTIN_SQRTPS,
+ IX86_BUILTIN_SQRTSS,
+
+ IX86_BUILTIN_UNPCKHPS,
+ IX86_BUILTIN_UNPCKLPS,
+
+ IX86_BUILTIN_ANDPS,
+ IX86_BUILTIN_ANDNPS,
+ IX86_BUILTIN_ORPS,
+ IX86_BUILTIN_XORPS,
+
+ IX86_BUILTIN_EMMS,
+ IX86_BUILTIN_LDMXCSR,
+ IX86_BUILTIN_STMXCSR,
+ IX86_BUILTIN_SFENCE,
+
+ /* 3DNow! Original */
+ IX86_BUILTIN_FEMMS,
+ IX86_BUILTIN_PAVGUSB,
+ IX86_BUILTIN_PF2ID,
+ IX86_BUILTIN_PFACC,
+ IX86_BUILTIN_PFADD,
+ IX86_BUILTIN_PFCMPEQ,
+ IX86_BUILTIN_PFCMPGE,
+ IX86_BUILTIN_PFCMPGT,
+ IX86_BUILTIN_PFMAX,
+ IX86_BUILTIN_PFMIN,
+ IX86_BUILTIN_PFMUL,
+ IX86_BUILTIN_PFRCP,
+ IX86_BUILTIN_PFRCPIT1,
+ IX86_BUILTIN_PFRCPIT2,
+ IX86_BUILTIN_PFRSQIT1,
+ IX86_BUILTIN_PFRSQRT,
+ IX86_BUILTIN_PFSUB,
+ IX86_BUILTIN_PFSUBR,
+ IX86_BUILTIN_PI2FD,
+ IX86_BUILTIN_PMULHRW,
+
+ /* 3DNow! Athlon Extensions */
+ IX86_BUILTIN_PF2IW,
+ IX86_BUILTIN_PFNACC,
+ IX86_BUILTIN_PFPNACC,
+ IX86_BUILTIN_PI2FW,
+ IX86_BUILTIN_PSWAPDSI,
+ IX86_BUILTIN_PSWAPDSF,
+
+ IX86_BUILTIN_SSE_ZERO,
+ IX86_BUILTIN_MMX_ZERO,
+
+ IX86_BUILTIN_MAX
+};
/* Define this macro if references to a symbol must be treated
differently depending on something about the variable or
@@ -1821,35 +2263,29 @@ do { \
On i386, if using PIC, mark a SYMBOL_REF for a non-global symbol
so that we may access it directly in the GOT. */
-#define ENCODE_SECTION_INFO(DECL) \
-do \
- { \
- if (flag_pic) \
- { \
- 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)
-
-/* Initialize data used by insn expanders. This is called from
- init_emit, once for each function, before code is generated.
- For 386, clear stack slot assignments remembered from previous
- functions. */
-
-#define INIT_EXPANDERS clear_386_stack_locals ()
+#define ENCODE_SECTION_INFO(DECL) \
+do { \
+ if (flag_pic) \
+ { \
+ rtx rtl = (TREE_CODE_CLASS (TREE_CODE (DECL)) != 'd' \
+ ? TREE_CST_RTL (DECL) : DECL_RTL (DECL)); \
+ \
+ if (GET_CODE (rtl) == MEM) \
+ { \
+ 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)
/* The `FINALIZE_PIC' macro serves as a hook to emit these special
codes once the function is being compiled into assembly code, but
@@ -1858,93 +2294,61 @@ while (0)
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)
+#define FINALIZE_PIC \
+ (current_function_uses_pic_offset_table |= current_function_profile)
-/* 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
+#define REGPARM_MAX (TARGET_64BIT ? 6 : 3)
+
+#define SSE_REGPARM_MAX (TARGET_64BIT ? 8 : 0)
/* Specify the machine mode that this machine uses
for the index in the tablejump instruction. */
-#define CASE_VECTOR_MODE Pmode
+#define CASE_VECTOR_MODE (!TARGET_64BIT || flag_pic ? SImode : DImode)
/* 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. */
+ 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 ??
- */
-#define IMPLICIT_FIX_EXPR FIX_ROUND_EXPR
-
-/* This is the kind of divide that is easiest to do in the general case. */
-#define EASY_DIV_EXPR TRUNC_DIV_EXPR
-
/* Define this as 1 if `char' should by default be signed; else as 0. */
#define DEFAULT_SIGNED_CHAR 1
+/* Number of bytes moved into a data cache for a single prefetch operation. */
+#define PREFETCH_BLOCK ix86_cost->prefetch_block
+
+/* Number of prefetch operations that can be done in parallel. */
+#define SIMULTANEOUS_PREFETCHES ix86_cost->simultaneous_prefetches
+
/* Max number of bytes we can move from memory to memory
in one reasonably fast instruction. */
-#define MOVE_MAX 4
+#define MOVE_MAX 16
+
+/* MOVE_MAX_PIECES is the number of bytes at a time which we can
+ move efficiently, as opposed to MOVE_MAX which is the maximum
+ number of bytes we can move with a single instruction. */
+#define MOVE_MAX_PIECES (TARGET_64BIT ? 8 : 4)
/* If a memory-to-memory move would take MOVE_RATIO or more simple
move-instruction pairs, we will do a movstr or libcall instead.
Increasing the value will always make code faster, but eventually
incurs high cost in increased code size.
- If you don't define this, a reasonable default is used.
-
- 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. */
+ If you don't define this, a reasonable default is used. */
-#define MOVE_RATIO 5
+#define MOVE_RATIO (optimize_size ? 3 : ix86_cost->move_ratio)
/* Define if shifts truncate the shift count
which implies one can omit a sign-extension or zero-extension
of a shift count. */
-/* On 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 */
@@ -1960,12 +2364,27 @@ while (0)
/* When a prototype says `char' or `short', really pass an `int'.
(The 386 can't easily push less than an int.) */
-#define PROMOTE_PROTOTYPES
+#define PROMOTE_PROTOTYPES 1
+
+/* A macro to update M and UNSIGNEDP when an object whose type is
+ TYPE and which has the specified mode and signedness is to be
+ stored in a register. This macro is only called when TYPE is a
+ scalar type.
+
+ On i386 it is sometimes useful to promote HImode and QImode
+ quantities to SImode. The choice depends on target type. */
+
+#define PROMOTE_MODE(MODE, UNSIGNEDP, TYPE) \
+do { \
+ if (((MODE) == HImode && TARGET_PROMOTE_HI_REGS) \
+ || ((MODE) == QImode && TARGET_PROMOTE_QI_REGS)) \
+ (MODE) = SImode; \
+} while (0)
/* Specify the machine mode that pointers have.
After generation of rtl, the compiler makes no further distinction
between pointers and any other objects of this machine mode. */
-#define Pmode SImode
+#define Pmode (TARGET_64BIT ? DImode : SImode)
/* A function address in a call instruction
is a byte address (for indexing purposes)
@@ -1985,28 +2404,32 @@ while (0)
CODE is the expression code--redundant, since it can be obtained
with `GET_CODE (X)'. */
-#define CONST_COSTS(RTX,CODE,OUTER_CODE) \
+#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 : 1; \
+ if (TARGET_64BIT && !x86_64_sign_extended_value (RTX)) \
+ return 3; \
+ if (TARGET_64BIT && !x86_64_zero_extended_value (RTX)) \
+ return 2; \
+ return flag_pic && SYMBOLIC_CONST (RTX) ? 1 : 0; \
\
case CONST_DOUBLE: \
{ \
int code; \
if (GET_MODE (RTX) == VOIDmode) \
- return 2; \
+ return 0; \
\
code = standard_80387_constant_p (RTX); \
- return code == 1 ? 0 : \
- code == 2 ? 1 : \
- 2; \
+ return code == 1 ? 1 : \
+ code == 2 ? 2 : \
+ 3; \
}
/* 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;}
+#define TOPLEVEL_COSTS_N_INSNS(N) \
+ do { total = COSTS_N_INSNS (N); goto egress_rtx_costs; } while (0)
/* Like `CONST_COSTS' but applies to nonconstant RTL expressions.
This can be used, for example, to indicate how costly a multiply
@@ -2018,20 +2441,33 @@ while (0)
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) \
+#define RTX_COSTS(X, CODE, OUTER_CODE) \
+ case ZERO_EXTEND: \
+ /* The zero extensions is often completely free on x86_64, so make \
+ it as cheap as possible. */ \
+ if (TARGET_64BIT && GET_MODE (X) == DImode \
+ && GET_MODE (XEXP (X, 0)) == SImode) \
+ { \
+ total = 1; goto egress_rtx_costs; \
+ } \
+ else \
+ TOPLEVEL_COSTS_N_INSNS (TARGET_ZERO_EXTEND_WITH_AND ? \
+ ix86_cost->add : ix86_cost->movzx); \
+ break; \
+ case SIGN_EXTEND: \
+ TOPLEVEL_COSTS_N_INSNS (ix86_cost->movsx); \
+ break; \
case ASHIFT: \
if (GET_CODE (XEXP (X, 1)) == CONST_INT \
- && GET_MODE (XEXP (X, 0)) == SImode) \
+ && (GET_MODE (XEXP (X, 0)) != DImode || TARGET_64BIT)) \
{ \
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); \
+ TOPLEVEL_COSTS_N_INSNS (ix86_cost->add); \
+ if ((value == 2 || value == 3) \
+ && !TARGET_DECOMPOSE_LEA \
+ && ix86_cost->lea <= ix86_cost->shift_const) \
+ TOPLEVEL_COSTS_N_INSNS (ix86_cost->lea); \
} \
/* fall through */ \
\
@@ -2039,23 +2475,31 @@ while (0)
case ASHIFTRT: \
case LSHIFTRT: \
case ROTATERT: \
- if (GET_MODE (XEXP (X, 0)) == DImode) \
+ if (!TARGET_64BIT && 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); \
+ TOPLEVEL_COSTS_N_INSNS(ix86_cost->shift_const + 2); \
+ else \
+ TOPLEVEL_COSTS_N_INSNS(ix86_cost->shift_const * 2); \
+ } \
+ else \
+ { \
+ if (GET_CODE (XEXP (X, 1)) == AND) \
+ TOPLEVEL_COSTS_N_INSNS(ix86_cost->shift_var * 2); \
+ else \
+ TOPLEVEL_COSTS_N_INSNS(ix86_cost->shift_var * 6 + 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); \
+ else \
+ { \
+ if (GET_CODE (XEXP (X, 1)) == CONST_INT) \
+ TOPLEVEL_COSTS_N_INSNS (ix86_cost->shift_const); \
+ else \
+ TOPLEVEL_COSTS_N_INSNS (ix86_cost->shift_var); \
+ } \
+ break; \
\
case MULT: \
if (GET_CODE (XEXP (X, 1)) == CONST_INT) \
@@ -2063,28 +2507,15 @@ while (0)
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); \
+ TOPLEVEL_COSTS_N_INSNS (ix86_cost->mult_init \
+ + nbits * ix86_cost->mult_bit); \
} \
- \
else /* This is arbitrary */ \
TOPLEVEL_COSTS_N_INSNS (ix86_cost->mult_init \
+ 7 * ix86_cost->mult_bit); \
@@ -2096,27 +2527,68 @@ while (0)
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); \
+ if (!TARGET_DECOMPOSE_LEA \
+ && INTEGRAL_MODE_P (GET_MODE (X)) \
+ && GET_MODE_BITSIZE (GET_MODE (X)) <= GET_MODE_BITSIZE (Pmode)) \
+ { \
+ if (GET_CODE (XEXP (X, 0)) == PLUS \
+ && GET_CODE (XEXP (XEXP (X, 0), 0)) == MULT \
+ && GET_CODE (XEXP (XEXP (XEXP (X, 0), 0), 1)) == CONST_INT \
+ && CONSTANT_P (XEXP (X, 1))) \
+ { \
+ HOST_WIDE_INT val = INTVAL (XEXP (XEXP (XEXP (X, 0), 0), 1));\
+ if (val == 2 || val == 4 || val == 8) \
+ { \
+ return (COSTS_N_INSNS (ix86_cost->lea) \
+ + rtx_cost (XEXP (XEXP (X, 0), 1), \
+ (OUTER_CODE)) \
+ + rtx_cost (XEXP (XEXP (XEXP (X, 0), 0), 0), \
+ (OUTER_CODE)) \
+ + rtx_cost (XEXP (X, 1), (OUTER_CODE))); \
+ } \
+ } \
+ else if (GET_CODE (XEXP (X, 0)) == MULT \
+ && GET_CODE (XEXP (XEXP (X, 0), 1)) == CONST_INT) \
+ { \
+ HOST_WIDE_INT val = INTVAL (XEXP (XEXP (X, 0), 1)); \
+ if (val == 2 || val == 4 || val == 8) \
+ { \
+ return (COSTS_N_INSNS (ix86_cost->lea) \
+ + rtx_cost (XEXP (XEXP (X, 0), 0), \
+ (OUTER_CODE)) \
+ + rtx_cost (XEXP (X, 1), (OUTER_CODE))); \
+ } \
+ } \
+ else if (GET_CODE (XEXP (X, 0)) == PLUS) \
+ { \
+ return (COSTS_N_INSNS (ix86_cost->lea) \
+ + rtx_cost (XEXP (XEXP (X, 0), 0), (OUTER_CODE)) \
+ + rtx_cost (XEXP (XEXP (X, 0), 1), (OUTER_CODE)) \
+ + rtx_cost (XEXP (X, 1), (OUTER_CODE))); \
+ } \
+ } \
\
/* 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)); \
+ if (!TARGET_64BIT && 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))); \
+ \
+ /* fall through */ \
case NEG: \
case NOT: \
- if (GET_MODE (X) == DImode) \
- TOPLEVEL_COSTS_N_INSNS (ix86_cost->add * 2) \
- TOPLEVEL_COSTS_N_INSNS (ix86_cost->add)
+ if (!TARGET_64BIT && GET_MODE (X) == DImode) \
+ TOPLEVEL_COSTS_N_INSNS (ix86_cost->add * 2); \
+ TOPLEVEL_COSTS_N_INSNS (ix86_cost->add); \
+ \
+ egress_rtx_costs: \
+ break;
/* An expression giving the cost of an addressing mode that contains
@@ -2166,28 +2638,19 @@ while (0)
lifetimes. */
#define ADDRESS_COST(RTX) \
- ((CONSTANT_P (RTX) \
- || (GET_CODE (RTX) == PLUS && CONSTANT_P (XEXP (RTX, 1)) \
- && REG_P (XEXP (RTX, 0)))) ? 0 \
- : REG_P (RTX) ? 1 \
- : 2)
+ ix86_address_cost (RTX)
-/* 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'.
+/* A C expression for the cost of moving data from a register in class FROM to
+ one in class TO. The classes are expressed using the enumeration values
+ such as `GENERAL_REGS'. A value of 2 is the default; other values are
+ interpreted relative to that.
- 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)
+ It is not required that the cost always equal 2 when FROM is the same as TO;
+ on some machines it is expensive to move between registers if they are not
+ general registers. */
+#define REGISTER_MOVE_COST(MODE, CLASS1, CLASS2) \
+ ix86_register_move_cost ((MODE), (CLASS1), (CLASS2))
/* 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
@@ -2197,12 +2660,13 @@ while (0)
between two registers, you should define this macro to express the
relative cost. */
-/* #define MEMORY_MOVE_COST(M,C,I) 2 */
+#define MEMORY_MOVE_COST(MODE, CLASS, IN) \
+ ix86_memory_move_cost ((MODE), (CLASS), (IN))
/* 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 BRANCH_COST ix86_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
@@ -2223,19 +2687,6 @@ while (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.
@@ -2248,7 +2699,7 @@ while (0)
If the value of this macro is always zero, it need not be defined. */
-/* #define SLOW_UNALIGNED_ACCESS 0 */
+/* #define SLOW_UNALIGNED_ACCESS(MODE, ALIGN) 0 */
/* Define this macro to inhibit strength reduction of memory
addresses. (On some machines, such strength reduction seems to do
@@ -2269,111 +2720,63 @@ while (0)
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) \
- (cost) = x86_adjust_cost(insn, link, dep_insn, cost)
-
-#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; \
- } \
-}
-
-#define ISSUE_RATE ((int)ix86_cpu > (int)PROCESSOR_I486 ? 2 : 1)
-
/* Add any extra modes needed to represent the condition code.
- For the i386, we need separate modes when floating-point equality
- comparisons are being done. */
+ For the i386, we need separate modes when floating-point
+ equality comparisons are being done.
+
+ Add CCNO to indicate comparisons against zero that requires
+ Overflow flag to be unset. Sign bit test is used instead and
+ thus can be used to form "a&b>0" type of tests.
-#define EXTRA_CC_MODES CCFPEQmode
+ Add CCGC to indicate comparisons agains zero that allows
+ unspecified garbage in the Carry flag. This mode is used
+ by inc/dec instructions.
-/* Define the names for the modes specified above. */
-#define EXTRA_CC_NAMES "CCFPEQ"
+ Add CCGOC to indicate comparisons agains zero that allows
+ unspecified garbage in the Carry and Overflow flag. This
+ mode is used to simulate comparisons of (a-b) and (a+b)
+ against zero using sub/cmp/add operations.
+
+ Add CCZ to indicate that only the Zero flag is valid. */
+
+#define EXTRA_CC_MODES \
+ CC (CCGCmode, "CCGC") \
+ CC (CCGOCmode, "CCGOC") \
+ CC (CCNOmode, "CCNO") \
+ CC (CCZmode, "CCZ") \
+ CC (CCFPmode, "CCFP") \
+ CC (CCFPUmode, "CCFPU")
/* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE,
return the mode to be used for the comparison.
For floating-point equality comparisons, CCFPEQmode should be used.
- VOIDmode should be used in all other cases. */
-
-#define SELECT_CC_MODE(OP,X,Y) \
- (GET_MODE_CLASS (GET_MODE (X)) == MODE_FLOAT \
- && ((OP) == EQ || (OP) == NE) ? CCFPEQmode : VOIDmode)
-
-/* Define the information needed to generate branch and scc insns. This is
- 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_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
+ VOIDmode should be used in all other cases.
-/* Set if the CC value was stored in a nonstandard way, so that
- the state of equality is indicated by zero in the carry bit. */
-#define CC_Z_IN_NOT_C 010000
+ For integer comparisons against zero, reduce to CCNOmode or CCZmode if
+ possible, to allow for more combinations. */
-/* 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
+#define SELECT_CC_MODE(OP, X, Y) ix86_cc_mode ((OP), (X), (Y))
-/* Store in cc_status the expressions
- that the condition codes will describe
- after execution of an instruction whose pattern is EXP.
- Do not alter them if the instruction would not alter the cc's. */
+/* Return non-zero if MODE implies a floating point inequality can be
+ reversed. */
-#define NOTICE_UPDATE_CC(EXP, INSN) \
- notice_update_cc((EXP))
+#define REVERSIBLE_CC_MODE(MODE) 1
-/* Output a signed jump insn. Use template NORMAL ordinarily, or
- FLOAT following a floating point comparison.
- Use NO_OV following an arithmetic insn that set the cc's
- before a test insn that was deleted.
- NO_OV may be zero, meaning final should reinsert the test insn
- because the jump cannot be handled properly without it. */
+/* A C expression whose value is reversed condition code of the CODE for
+ comparison done in CC_MODE mode. */
+#define REVERSE_CONDITION(CODE, MODE) \
+ ((MODE) != CCFPmode && (MODE) != CCFPUmode ? reverse_condition (CODE) \
+ : reverse_condition_maybe_unordered (CODE))
-#define OUTPUT_JUMP(NORMAL, FLOAT, NO_OV) \
-{ \
- if (cc_prev_status.flags & CC_IN_80387) \
- return FLOAT; \
- if (cc_prev_status.flags & CC_NO_OVERFLOW) \
- return NO_OV; \
- return NORMAL; \
-}
/* Control the assembler format that we output, to the extent
this does not vary between assemblers. */
/* How to refer to registers in assembler output.
- This sequence is indexed by compiler's hard-register-number (see above). */
+ This sequence is indexed by compiler's hard-register-number (see above). */
/* In order to refer to the first 8 regs as 32 bit regs prefix an "e"
For non floating point regs, the following are the HImode names.
@@ -2381,9 +2784,15 @@ extern struct rtx_def *(*i386_compare_gen)(), *(*i386_compare_gen_eq)();
For float regs, the stack top is sometimes referred to as "%st(0)"
instead of just "%st". PRINT_REG handles this with the "y" code. */
-#define HI_REGISTER_NAMES \
-{"ax","dx","cx","bx","si","di","bp","sp", \
- "st","st(1)","st(2)","st(3)","st(4)","st(5)","st(6)","st(7)","" }
+#undef HI_REGISTER_NAMES
+#define HI_REGISTER_NAMES \
+{"ax","dx","cx","bx","si","di","bp","sp", \
+ "st","st(1)","st(2)","st(3)","st(4)","st(5)","st(6)","st(7)","", \
+ "flags","fpsr", "dirflag", "frame", \
+ "xmm0","xmm1","xmm2","xmm3","xmm4","xmm5","xmm6","xmm7", \
+ "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7" , \
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", \
+ "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15"}
#define REGISTER_NAMES HI_REGISTER_NAMES
@@ -2392,87 +2801,75 @@ extern struct rtx_def *(*i386_compare_gen)(), *(*i386_compare_gen_eq)();
#define ADDITIONAL_REGISTER_NAMES \
{ { "eax", 0 }, { "edx", 1 }, { "ecx", 2 }, { "ebx", 3 }, \
{ "esi", 4 }, { "edi", 5 }, { "ebp", 6 }, { "esp", 7 }, \
+ { "rax", 0 }, { "rdx", 1 }, { "rcx", 2 }, { "rbx", 3 }, \
+ { "rsi", 4 }, { "rdi", 5 }, { "rbp", 6 }, { "rsp", 7 }, \
{ "al", 0 }, { "dl", 1 }, { "cl", 2 }, { "bl", 3 }, \
- { "ah", 0 }, { "dh", 1 }, { "ch", 2 }, { "bh", 3 } }
+ { "ah", 0 }, { "dh", 1 }, { "ch", 2 }, { "bh", 3 }, \
+ { "mm0", 8}, { "mm1", 9}, { "mm2", 10}, { "mm3", 11}, \
+ { "mm4", 12}, { "mm5", 13}, { "mm6", 14}, { "mm7", 15} }
/* 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
number as al, and ax.
*/
-/* note the last four are not really qi_registers, but
- the md will have to never output movb into one of them
- only a movw . There is no movb into the last four regs */
-
#define QI_REGISTER_NAMES \
-{"al", "dl", "cl", "bl", "si", "di", "bp", "sp",}
+{"al", "dl", "cl", "bl", "sil", "dil", "bpl", "spl",}
/* These parallel the array above, and can be used to access bits 8:15
- of regs 0 through 3. */
+ of regs 0 through 3. */
#define QI_HIGH_REGISTER_NAMES \
{"ah", "dh", "ch", "bh", }
/* How to renumber registers for dbx and gdb. */
-/* {0,2,1,3,6,7,4,5,12,13,14,15,16,17} */
-#define DBX_REGISTER_NUMBER(n) \
-((n) == 0 ? 0 : \
- (n) == 1 ? 2 : \
- (n) == 2 ? 1 : \
- (n) == 3 ? 3 : \
- (n) == 4 ? 6 : \
- (n) == 5 ? 7 : \
- (n) == 6 ? 4 : \
- (n) == 7 ? 5 : \
- (n) + 4)
+#define DBX_REGISTER_NUMBER(N) \
+ (TARGET_64BIT ? dbx64_register_map[(N)] : dbx_register_map[(N)])
+
+extern int const dbx_register_map[FIRST_PSEUDO_REGISTER];
+extern int const dbx64_register_map[FIRST_PSEUDO_REGISTER];
+extern int const svr4_dbx_register_map[FIRST_PSEUDO_REGISTER];
/* 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))))
+#define RETURN_ADDR_RTX(COUNT, FRAME) \
+ ((COUNT) == 0 \
+ ? gen_rtx_MEM (Pmode, plus_constant (arg_pointer_rtx, -UNITS_PER_WORD)) \
+ : gen_rtx_MEM (Pmode, plus_constant (FRAME, UNITS_PER_WORD)))
-/* PC is dbx register 8; let's use that column for RA. */
-#define DWARF_FRAME_RETURN_COLUMN 8
+/* PC is dbx register 8; let's use that column for RA. */
+#define DWARF_FRAME_RETURN_COLUMN (TARGET_64BIT ? 16 : 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 INCOMING_FRAME_SP_OFFSET UNITS_PER_WORD
-#define ASM_OUTPUT_LABEL(FILE,NAME) \
- (assemble_name (FILE, NAME), fputs (":\n", FILE))
+/* Describe how we implement __builtin_eh_return. */
+#define EH_RETURN_DATA_REGNO(N) ((N) < 2 ? (N) : INVALID_REGNUM)
+#define EH_RETURN_STACKADJ_RTX gen_rtx_REG (Pmode, 2)
-/* This is how to output an assembler line defining a `double' constant. */
-#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \
-do { long l[2]; \
- REAL_VALUE_TO_TARGET_DOUBLE (VALUE, l); \
- fprintf (FILE, "%s 0x%lx,0x%lx\n", ASM_LONG, l[0], l[1]); \
- } while (0)
+/* Select a format to encode pointers in exception handling data. CODE
+ is 0 for data, 1 for code labels, 2 for function pointers. GLOBAL is
+ true if the symbol may be affected by dynamic relocations.
-/* This is how to output a `long double' extended real constant. */
+ ??? All x86 object file formats are capable of representing this.
+ After all, the relocation needed is the same as for the call insn.
+ Whether or not a particular assembler allows us to enter such, I
+ guess we'll have to see. */
+#define ASM_PREFERRED_EH_DATA_FORMAT(CODE, GLOBAL) \
+ (flag_pic \
+ ? ((GLOBAL) ? DW_EH_PE_indirect : 0) | DW_EH_PE_pcrel | DW_EH_PE_sdata4\
+ : DW_EH_PE_absptr)
-#undef ASM_OUTPUT_LONG_DOUBLE
-#define ASM_OUTPUT_LONG_DOUBLE(FILE,VALUE) \
-do { long l[3]; \
- REAL_VALUE_TO_TARGET_LONG_DOUBLE (VALUE, l); \
- 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. */
+/* 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_FLOAT(FILE,VALUE) \
-do { long l; \
- REAL_VALUE_TO_TARGET_SINGLE (VALUE, l); \
- fprintf ((FILE), "%s 0x%lx\n", ASM_LONG, l); \
- } while (0)
+#define ASM_OUTPUT_LABEL(FILE, NAME) \
+ (assemble_name ((FILE), (NAME)), fputs (":\n", (FILE)))
/* Store in OUTPUT a string (made with alloca) containing
an assembler-name for a local static variable named NAME.
@@ -2482,327 +2879,339 @@ do { long l; \
( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 10), \
sprintf ((OUTPUT), "%s.%d", (NAME), (LABELNO)))
+/* This is how to output an insn to push a register on the stack.
+ It need not be very fast code. */
+#define ASM_OUTPUT_REG_PUSH(FILE, REGNO) \
+ asm_fprintf ((FILE), "\tpush{l}\t%%e%s\n", reg_names[(REGNO)])
-/* This is how to output an assembler line defining an `int' constant. */
-
-#define ASM_OUTPUT_INT(FILE,VALUE) \
-( fprintf (FILE, "%s ", ASM_LONG), \
- output_addr_const (FILE,(VALUE)), \
- putc('\n',FILE))
-
-/* Likewise for `char' and `short' constants. */
-/* is this supposed to do align too?? */
+/* This is how to output an insn to pop a register from the stack.
+ It need not be very fast code. */
-#define ASM_OUTPUT_SHORT(FILE,VALUE) \
-( fprintf (FILE, "%s ", ASM_SHORT), \
- output_addr_const (FILE,(VALUE)), \
- putc('\n',FILE))
+#define ASM_OUTPUT_REG_POP(FILE, REGNO) \
+ asm_fprintf ((FILE), "\tpop{l}\t%%e%s\n", reg_names[(REGNO)])
-/*
-#define ASM_OUTPUT_SHORT(FILE,VALUE) \
-( fprintf (FILE, "%s ", ASM_BYTE_OP), \
- output_addr_const (FILE,(VALUE)), \
- fputs (",", FILE), \
- output_addr_const (FILE,(VALUE)), \
- fputs (" >> 8\n",FILE))
-*/
+/* This is how to output an element of a case-vector that is absolute. */
+#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \
+ ix86_output_addr_vec_elt ((FILE), (VALUE))
-#define ASM_OUTPUT_CHAR(FILE,VALUE) \
-( fprintf (FILE, "%s ", ASM_BYTE_OP), \
- output_addr_const (FILE, (VALUE)), \
- putc ('\n', FILE))
+/* This is how to output an element of a case-vector that is relative. */
-/* This is how to output an assembler line for a numeric constant byte. */
+#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \
+ ix86_output_addr_diff_elt ((FILE), (VALUE), (REL))
-#define ASM_OUTPUT_BYTE(FILE,VALUE) \
- fprintf ((FILE), "%s 0x%x\n", ASM_BYTE_OP, (VALUE))
+/* Under some conditions we need jump tables in the text section, because
+ the assembler cannot handle label differences between sections. */
-/* This is how to output an insn to push a register on the stack.
- It need not be very fast code. */
+#define JUMP_TABLES_IN_TEXT_SECTION \
+ (!TARGET_64BIT && flag_pic && !HAVE_AS_GOTOFF_IN_DATA)
-#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \
- fprintf (FILE, "\tpushl %%e%s\n", reg_names[REGNO])
+/* A C statement that outputs an address constant appropriate to
+ for DWARF debugging. */
-/* This is how to output an insn to pop a register from the stack.
- It need not be very fast code. */
+#define ASM_OUTPUT_DWARF_ADDR_CONST(FILE, X) \
+ i386_dwarf_output_addr_const ((FILE), (X))
-#define ASM_OUTPUT_REG_POP(FILE,REGNO) \
- fprintf (FILE, "\tpopl %%e%s\n", reg_names[REGNO])
+/* Either simplify a location expression, or return the original. */
-/* This is how to output an element of a case-vector that is absolute.
- */
+#define ASM_SIMPLIFY_DWARF_ADDR(X) \
+ i386_simplify_dwarf_addr (X)
-#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \
- fprintf (FILE, "%s %s%d\n", ASM_LONG, LPREFIX, VALUE)
-
-/* This is how to output an element of a case-vector that is relative.
- We don't use these on the 386 yet, because the ATT assembler can't do
- forward reference the differences.
- */
-
-#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
- in assembler code. */
-
-#define ASM_OPEN_PAREN ""
-#define ASM_CLOSE_PAREN ""
-
-/* Define results of standard character escape sequences. */
-#define TARGET_BELL 007
-#define TARGET_BS 010
-#define TARGET_TAB 011
-#define TARGET_NEWLINE 012
-#define TARGET_VT 013
-#define TARGET_FF 014
-#define TARGET_CR 015
+/* Switch to init or fini section via SECTION_OP, emit a call to FUNC,
+ and switch back. For x86 we do this only to save a few bytes that
+ would otherwise be unused in the text section. */
+#define CRT_CALL_STATIC_FUNCTION(SECTION_OP, FUNC) \
+ asm (SECTION_OP "\n\t" \
+ "call " USER_LABEL_PREFIX #FUNC "\n" \
+ TEXT_SECTION_ASM_OP);
/* Print operand X (an rtx) in assembler syntax to file FILE.
CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified.
- The CODE z takes the size of operand from the following digit, and
- outputs b,w,or l respectively.
-
- 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,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)
- 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) == '*' || (CODE) == '_')
+ Effect of various CODE letters is described in i386.c near
+ print_operand function. */
+
+#define PRINT_OPERAND_PUNCT_VALID_P(CODE) \
+ ((CODE) == '*' || (CODE) == '+')
/* Print the name of a register based on its machine mode and number.
If CODE is 'w', pretend the mode is HImode.
If CODE is 'b', pretend the mode is QImode.
If CODE is 'k', pretend the mode is SImode.
+ If CODE is 'q', pretend the mode is DImode.
If CODE is 'h', pretend the reg is the `high' byte register.
- If CODE is 'y', print "st(0)" instead of "st", if the reg is stack op. */
-
-extern char *hi_reg_name[];
-extern char *qi_reg_name[];
-extern char *qi_high_reg_name[];
-
-#define PRINT_REG(X, CODE, FILE) \
- do { if (REGNO (X) == ARG_POINTER_REGNUM) \
- abort (); \
- fprintf (FILE, "%s", RP); \
- switch ((CODE == 'w' ? 2 \
- : CODE == 'b' ? 1 \
- : CODE == 'k' ? 4 \
- : CODE == 'y' ? 3 \
- : CODE == 'h' ? 0 \
- : GET_MODE_SIZE (GET_MODE (X)))) \
- { \
- case 3: \
- if (STACK_TOP_P (X)) \
- { \
- fputs ("st(0)", FILE); \
- break; \
- } \
- case 4: \
- case 8: \
- case 12: \
- if (! FP_REG_P (X)) fputs ("e", FILE); \
- case 2: \
- fputs (hi_reg_name[REGNO (X)], FILE); \
- break; \
- case 1: \
- fputs (qi_reg_name[REGNO (X)], FILE); \
- break; \
- case 0: \
- fputs (qi_high_reg_name[REGNO (X)], FILE); \
- break; \
- } \
- } while (0)
+ If CODE is 'y', print "st(0)" instead of "st", if the reg is stack op. */
+
+#define PRINT_REG(X, CODE, FILE) \
+ print_reg ((X), (CODE), (FILE))
#define PRINT_OPERAND(FILE, X, CODE) \
- print_operand (FILE, X, CODE)
+ print_operand ((FILE), (X), (CODE))
#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \
- print_operand_address (FILE, ADDR)
+ print_operand_address ((FILE), (ADDR))
/* Print the name of a register for based on its machine mode and number.
This macro is used to print debugging output.
This macro is different from PRINT_REG in that it may be used in
programs that are not linked with aux-output.o. */
-#define DEBUG_PRINT_REG(X, CODE, FILE) \
- do { static char *hi_name[] = HI_REGISTER_NAMES; \
- static char *qi_name[] = QI_REGISTER_NAMES; \
- fprintf (FILE, "%d %s", REGNO (X), RP); \
+#define DEBUG_PRINT_REG(X, CODE, FILE) \
+ do { static const char * const hi_name[] = HI_REGISTER_NAMES; \
+ static const char * const qi_name[] = QI_REGISTER_NAMES; \
+ fprintf ((FILE), "%d ", REGNO (X)); \
+ if (REGNO (X) == FLAGS_REG) \
+ { fputs ("flags", (FILE)); break; } \
+ if (REGNO (X) == DIRFLAG_REG) \
+ { fputs ("dirflag", (FILE)); break; } \
+ if (REGNO (X) == FPSR_REG) \
+ { fputs ("fpsr", (FILE)); break; } \
if (REGNO (X) == ARG_POINTER_REGNUM) \
- { fputs ("argp", FILE); break; } \
+ { fputs ("argp", (FILE)); break; } \
+ if (REGNO (X) == FRAME_POINTER_REGNUM) \
+ { fputs ("frame", (FILE)); break; } \
if (STACK_TOP_P (X)) \
- { fputs ("st(0)", FILE); break; } \
+ { fputs ("st(0)", (FILE)); break; } \
if (FP_REG_P (X)) \
- { fputs (hi_name[REGNO(X)], FILE); break; } \
+ { fputs (hi_name[REGNO(X)], (FILE)); break; } \
+ if (REX_INT_REG_P (X)) \
+ { \
+ switch (GET_MODE_SIZE (GET_MODE (X))) \
+ { \
+ default: \
+ case 8: \
+ fprintf ((FILE), "r%i", REGNO (X) \
+ - FIRST_REX_INT_REG + 8); \
+ break; \
+ case 4: \
+ fprintf ((FILE), "r%id", REGNO (X) \
+ - FIRST_REX_INT_REG + 8); \
+ break; \
+ case 2: \
+ fprintf ((FILE), "r%iw", REGNO (X) \
+ - FIRST_REX_INT_REG + 8); \
+ break; \
+ case 1: \
+ fprintf ((FILE), "r%ib", REGNO (X) \
+ - FIRST_REX_INT_REG + 8); \
+ break; \
+ } \
+ break; \
+ } \
switch (GET_MODE_SIZE (GET_MODE (X))) \
{ \
+ case 8: \
+ fputs ("r", (FILE)); \
+ fputs (hi_name[REGNO (X)], (FILE)); \
+ break; \
default: \
- fputs ("e", FILE); \
+ fputs ("e", (FILE)); \
case 2: \
- fputs (hi_name[REGNO (X)], FILE); \
+ fputs (hi_name[REGNO (X)], (FILE)); \
break; \
case 1: \
- fputs (qi_name[REGNO (X)], FILE); \
+ fputs (qi_name[REGNO (X)], (FILE)); \
break; \
} \
} while (0)
-/* Output the prefix for an immediate operand, or for an offset operand. */
-#define PRINT_IMMED_PREFIX(FILE) fputs (IP, (FILE))
-#define PRINT_OFFSET_PREFIX(FILE) fputs (IP, (FILE))
-
-/* Routines in libgcc that return floats must return them in an fp reg,
- just as other functions do which return such values.
- These macros make that happen. */
-
-#define FLOAT_VALUE_TYPE float
-#define INTIFY(FLOATVAL) FLOATVAL
-
-/* Nonzero if INSN magically clobbers register REGNO. */
-
-/* #define INSN_CLOBBERS_REGNO_P(INSN, REGNO) \
- (FP_REGNO_P (REGNO) \
- && (GET_CODE (INSN) == JUMP_INSN || GET_CODE (INSN) == BARRIER))
-*/
-
/* a letter which is not needed by the normal asm syntax, which
we can use for operand syntax in the extended asm */
#define ASM_OPERAND_LETTER '#'
#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))
-/* 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 the codes that are matched by predicates in i386.c. */
+
+#define PREDICATE_CODES \
+ {"x86_64_immediate_operand", {CONST_INT, SUBREG, REG, \
+ SYMBOL_REF, LABEL_REF, CONST}}, \
+ {"x86_64_nonmemory_operand", {CONST_INT, SUBREG, REG, \
+ SYMBOL_REF, LABEL_REF, CONST}}, \
+ {"x86_64_movabs_operand", {CONST_INT, SUBREG, REG, \
+ SYMBOL_REF, LABEL_REF, CONST}}, \
+ {"x86_64_szext_nonmemory_operand", {CONST_INT, SUBREG, REG, \
+ SYMBOL_REF, LABEL_REF, CONST}}, \
+ {"x86_64_general_operand", {CONST_INT, SUBREG, REG, MEM, \
+ SYMBOL_REF, LABEL_REF, CONST}}, \
+ {"x86_64_szext_general_operand", {CONST_INT, SUBREG, REG, MEM, \
+ SYMBOL_REF, LABEL_REF, CONST}}, \
+ {"x86_64_zext_immediate_operand", {CONST_INT, CONST_DOUBLE, CONST, \
+ SYMBOL_REF, LABEL_REF}}, \
+ {"shiftdi_operand", {SUBREG, REG, MEM}}, \
+ {"const_int_1_operand", {CONST_INT}}, \
+ {"symbolic_operand", {SYMBOL_REF, LABEL_REF, CONST}}, \
+ {"aligned_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF, \
+ LABEL_REF, SUBREG, REG, MEM}}, \
+ {"pic_symbolic_operand", {CONST}}, \
+ {"call_insn_operand", {REG, SUBREG, MEM, SYMBOL_REF}}, \
+ {"constant_call_address_operand", {SYMBOL_REF, CONST}}, \
+ {"const0_operand", {CONST_INT, CONST_DOUBLE}}, \
+ {"const1_operand", {CONST_INT}}, \
+ {"const248_operand", {CONST_INT}}, \
+ {"incdec_operand", {CONST_INT}}, \
+ {"mmx_reg_operand", {REG}}, \
+ {"reg_no_sp_operand", {SUBREG, REG}}, \
+ {"general_no_elim_operand", {CONST_INT, CONST_DOUBLE, CONST, \
+ SYMBOL_REF, LABEL_REF, SUBREG, REG, MEM}}, \
+ {"nonmemory_no_elim_operand", {CONST_INT, REG, SUBREG}}, \
+ {"q_regs_operand", {SUBREG, REG}}, \
+ {"non_q_regs_operand", {SUBREG, REG}}, \
+ {"fcmov_comparison_operator", {EQ, NE, LTU, GTU, LEU, GEU, UNORDERED, \
+ ORDERED, LT, UNLT, GT, UNGT, LE, UNLE, \
+ GE, UNGE, LTGT, UNEQ}}, \
+ {"sse_comparison_operator", {EQ, LT, LE, UNORDERED, NE, UNGE, UNGT, \
+ ORDERED, UNEQ, UNLT, UNLE, LTGT, GE, GT \
+ }}, \
+ {"ix86_comparison_operator", {EQ, NE, LE, LT, GE, GT, LEU, LTU, GEU, \
+ GTU, UNORDERED, ORDERED, UNLE, UNLT, \
+ UNGE, UNGT, LTGT, UNEQ }}, \
+ {"cmp_fp_expander_operand", {CONST_DOUBLE, SUBREG, REG, MEM}}, \
+ {"ext_register_operand", {SUBREG, REG}}, \
+ {"binary_fp_operator", {PLUS, MINUS, MULT, DIV}}, \
+ {"mult_operator", {MULT}}, \
+ {"div_operator", {DIV}}, \
+ {"arith_or_logical_operator", {PLUS, MULT, AND, IOR, XOR, SMIN, SMAX, \
+ UMIN, UMAX, COMPARE, MINUS, DIV, MOD, \
+ UDIV, UMOD, ASHIFT, ROTATE, ASHIFTRT, \
+ LSHIFTRT, ROTATERT}}, \
+ {"promotable_binary_operator", {PLUS, MULT, AND, IOR, XOR, ASHIFT}}, \
+ {"memory_displacement_operand", {MEM}}, \
+ {"cmpsi_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF, \
+ LABEL_REF, SUBREG, REG, MEM, AND}}, \
+ {"long_memory_operand", {MEM}},
+
+/* A list of predicates that do special things with modes, and so
+ should not elicit warnings for VOIDmode match_operand. */
+
+#define SPECIAL_MODE_PREDICATES \
+ "ext_register_operand",
+
+/* CM_32 is used by 32bit ABI
+ CM_SMALL is small model assuming that all code and data fits in the first
+ 31bits of address space.
+ CM_KERNEL is model assuming that all code and data fits in the negative
+ 31bits of address space.
+ CM_MEDIUM is model assuming that code fits in the first 31bits of address
+ space. Size of data is unlimited.
+ CM_LARGE is model making no assumptions about size of particular sections.
+
+ CM_SMALL_PIC is model for PIC libraries assuming that code+data+got/plt
+ tables first in 31bits of address space.
+ */
+enum cmodel {
+ CM_32,
+ CM_SMALL,
+ CM_KERNEL,
+ CM_MEDIUM,
+ CM_LARGE,
+ CM_SMALL_PIC
+};
-#define IX86_EXPAND_UNARY_OPERATOR(OP, MODE, OPERANDS) \
-do { \
- if (!ix86_expand_unary_operator (OP, MODE, OPERANDS,)) \
- FAIL; \
-} while (0)
+/* Size of the RED_ZONE area. */
+#define RED_ZONE_SIZE 128
+/* Reserved area of the red zone for temporaries. */
+#define RED_ZONE_RESERVE 8
+extern const char *ix86_debug_arg_string, *ix86_debug_addr_string;
+enum asm_dialect {
+ ASM_ATT,
+ ASM_INTEL
+};
+extern const char *ix86_asm_string;
+extern enum asm_dialect ix86_asm_dialect;
+/* Value of -mcmodel specified by user. */
+extern const char *ix86_cmodel_string;
+extern enum cmodel ix86_cmodel;
-/* 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 char *singlemove_string ();
-extern char *output_move_double ();
-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 void output_float_extend ();
-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 ();
-extern char *output_int_conditional_move ();
-extern char *output_fp_conditional_move ();
-extern int ix86_can_use_return_insn_p ();
-extern int small_shift_operand ();
-extern char *output_ashl ();
-extern int memory_address_info ();
-
-#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_preferred_stack_boundary_string;/* power of two alignment for stack boundary */
-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_preferred_stack_boundary; /* preferred stack boundary alignment in bits */
-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 ();
+extern const char *ix86_cpu_string; /* for -mcpu=<xxx> */
+extern const char *ix86_arch_string; /* for -march=<xxx> */
+extern const char *ix86_fpmath_string; /* for -mfpmath=<xxx> */
+extern const char *ix86_regparm_string; /* # registers to use to pass args */
+extern const char *ix86_align_loops_string; /* power of two alignment for loops */
+extern const char *ix86_align_jumps_string; /* power of two alignment for non-loop jumps */
+extern const char *ix86_align_funcs_string; /* power of two alignment for functions */
+extern const char *ix86_preferred_stack_boundary_string;/* power of two alignment for stack boundary */
+extern const char *ix86_branch_cost_string; /* values 1-5: see jump.c */
+extern int ix86_regparm; /* ix86_regparm_string as a number */
+extern int ix86_preferred_stack_boundary; /* preferred stack boundary alignment in bits */
+extern int ix86_branch_cost; /* values 1-5: see jump.c */
+extern enum reg_class const regclass_map[FIRST_PSEUDO_REGISTER]; /* smalled class containing REGNO */
+extern rtx ix86_compare_op0; /* operand 0 for comparisons */
+extern rtx ix86_compare_op1; /* operand 1 for comparisons */
+
+/* To properly truncate FP values into integers, we need to set i387 control
+ word. We can't emit proper mode switching code before reload, as spills
+ generated by reload may truncate values incorrectly, but we still can avoid
+ redundant computation of new control word by the mode switching pass.
+ The fldcw instructions are still emitted redundantly, but this is probably
+ not going to be noticeable problem, as most CPUs do have fast path for
+ the sequence.
+
+ The machinery is to emit simple truncation instructions and split them
+ before reload to instructions having USEs of two memory locations that
+ are filled by this code to old and new control word.
+
+ Post-reload pass may be later used to eliminate the redundant fildcw if
+ needed. */
+
+enum fp_cw_mode {FP_CW_STORED, FP_CW_UNINITIALIZED, FP_CW_ANY};
+
+/* Define this macro if the port needs extra instructions inserted
+ for mode switching in an optimizing compilation. */
+
+#define OPTIMIZE_MODE_SWITCHING(ENTITY) 1
+
+/* If you define `OPTIMIZE_MODE_SWITCHING', you have to define this as
+ initializer for an array of integers. Each initializer element N
+ refers to an entity that needs mode switching, and specifies the
+ number of different modes that might need to be set for this
+ entity. The position of the initializer in the initializer -
+ starting counting at zero - determines the integer that is used to
+ refer to the mode-switched entity in question. */
+
+#define NUM_MODES_FOR_MODE_SWITCHING { FP_CW_ANY }
+
+/* ENTITY is an integer specifying a mode-switched entity. If
+ `OPTIMIZE_MODE_SWITCHING' is defined, you must define this macro to
+ return an integer value not larger than the corresponding element
+ in `NUM_MODES_FOR_MODE_SWITCHING', to denote the mode that ENTITY
+ must be switched into prior to the execution of INSN. */
+
+#define MODE_NEEDED(ENTITY, I) \
+ (GET_CODE (I) == CALL_INSN \
+ || (GET_CODE (I) == INSN && (asm_noperands (PATTERN (I)) >= 0 \
+ || GET_CODE (PATTERN (I)) == ASM_INPUT))\
+ ? FP_CW_UNINITIALIZED \
+ : recog_memoized (I) < 0 || get_attr_type (I) != TYPE_FISTP \
+ ? FP_CW_ANY \
+ : FP_CW_STORED)
+
+/* This macro specifies the order in which modes for ENTITY are
+ processed. 0 is the highest priority. */
+
+#define MODE_PRIORITY_TO_MODE(ENTITY, N) (N)
+
+/* Generate one or more insns to set ENTITY to MODE. HARD_REG_LIVE
+ is the set of hard registers live at the point where the insn(s)
+ are to be inserted. */
+
+#define EMIT_MODE_SET(ENTITY, MODE, HARD_REGS_LIVE) \
+ ((MODE) == FP_CW_STORED \
+ ? emit_i387_cw_initialization (assign_386_stack_local (HImode, 1), \
+ assign_386_stack_local (HImode, 2)), 0\
+ : 0)
+
+/* Avoid renaming of stack registers, as doing so in combination with
+ scheduling just increases amount of live registers at time and in
+ the turn amount of fxch instructions needed.
+
+ ??? Maybe Pentium chips benefits from renaming, someone can try... */
+
+#define HARD_REGNO_RENAME_OK(SRC, TARGET) \
+ ((SRC) < FIRST_STACK_REG || (SRC) > LAST_STACK_REG)
/*
diff --git a/contrib/gcc/print-tree.c b/contrib/gcc/print-tree.c
index 7b29454..33236cf 100644
--- a/contrib/gcc/print-tree.c
+++ b/contrib/gcc/print-tree.c
@@ -1,22 +1,23 @@
/* Prints out tree in human readable form - GNU C-compiler
- Copyright (C) 1990, 91, 93-97, 1998 Free Software Foundation, Inc.
+ Copyright (C) 1990, 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+ 2001, 2002 Free Software Foundation, Inc.
-This file is part of GNU CC.
+This file is part of GCC.
-GNU CC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
-GNU CC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
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, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+along with GCC; see the file COPYING. If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
/* $FreeBSD$ */
@@ -24,11 +25,8 @@ Boston, MA 02111-1307, USA. */
#include "config.h"
#include "system.h"
#include "tree.h"
-
-extern char *mode_name[];
-
-void print_node ();
-void indent_to ();
+#include "ggc.h"
+#include "langhooks.h"
/* Define the hash table of nodes already seen.
Such nodes are not repeated; brief cross-references are used. */
@@ -51,13 +49,10 @@ void
debug_tree (node)
tree node;
{
- char *object = (char *) oballoc (0);
-
- table = (struct bucket **) oballoc (HASH_SIZE * sizeof (struct bucket *));
- bzero ((char *) table, HASH_SIZE * sizeof (struct bucket *));
+ table = (struct bucket **) permalloc (HASH_SIZE * sizeof (struct bucket *));
+ memset ((char *) table, 0, HASH_SIZE * sizeof (struct bucket *));
print_node (stderr, "", node, 0);
table = 0;
- obfree (object);
fprintf (stderr, "\n");
}
@@ -103,7 +98,8 @@ print_node_brief (file, prefix, node, indent)
}
if (TREE_CODE (node) == IDENTIFIER_NODE)
fprintf (file, " %s", IDENTIFIER_POINTER (node));
- /* We might as well always print the value of an integer. */
+
+ /* We might as well always print the value of an integer or real. */
if (TREE_CODE (node) == INTEGER_CST)
{
if (TREE_CONSTANT_OVERFLOW (node))
@@ -117,7 +113,7 @@ print_node_brief (file, prefix, node, indent)
{
fprintf (file, "-");
fprintf (file, HOST_WIDE_INT_PRINT_UNSIGNED,
- -TREE_INT_CST_LOW (node));
+ -TREE_INT_CST_LOW (node));
}
else
fprintf (file, HOST_WIDE_INT_PRINT_DOUBLE_HEX,
@@ -229,7 +225,7 @@ print_node (file, prefix, node, indent)
}
/* Add this node to the table. */
- b = (struct bucket *) oballoc (sizeof (struct bucket));
+ b = (struct bucket *) permalloc (sizeof (struct bucket));
b->node = node;
b->next = table[hash];
table[hash] = b;
@@ -272,19 +268,6 @@ print_node (file, prefix, node, indent)
print_node (file, "type", TREE_TYPE (node), indent + 4);
if (TREE_TYPE (node))
indent_to (file, indent + 3);
-
- print_obstack_name ((char *) node, file, "");
- indent_to (file, indent + 3);
- }
-
- /* If a permanent object is in the wrong obstack, or the reverse, warn. */
- if (object_permanent_p (node) != TREE_PERMANENT (node))
- {
- if (TREE_PERMANENT (node))
- fputs (" !!permanent object in non-permanent obstack!!", file);
- else
- fputs (" !!non-permanent object in permanent obstack!!", file);
- indent_to (file, indent + 3);
}
if (TREE_SIDE_EFFECTS (node))
@@ -303,14 +286,18 @@ print_node (file, prefix, node, indent)
fputs (" asm_written", file);
if (TREE_USED (node))
fputs (" used", file);
- if (TREE_RAISES (node))
- fputs (" raises", file);
- if (TREE_PERMANENT (node))
- fputs (" permanent", file);
+ if (TREE_NOTHROW (node))
+ fputs (" nothrow", file);
if (TREE_PUBLIC (node))
fputs (" public", file);
+ if (TREE_PRIVATE (node))
+ fputs (" private", file);
+ if (TREE_PROTECTED (node))
+ fputs (" protected", file);
if (TREE_STATIC (node))
fputs (" static", file);
+ if (TREE_DEPRECATED (node))
+ fputs (" deprecated", file);
if (TREE_LANG_FLAG_0 (node))
fputs (" tree_0", file);
if (TREE_LANG_FLAG_1 (node))
@@ -343,36 +330,47 @@ print_node (file, prefix, node, indent)
fputs (" common", file);
if (DECL_EXTERNAL (node))
fputs (" external", file);
- if (DECL_REGISTER (node))
+ if (DECL_REGISTER (node) && TREE_CODE (node) != FIELD_DECL
+ && TREE_CODE (node) != FUNCTION_DECL
+ && TREE_CODE (node) != LABEL_DECL)
fputs (" regdecl", file);
- if (DECL_PACKED (node))
- fputs (" packed", file);
if (DECL_NONLOCAL (node))
fputs (" nonlocal", file);
- if (DECL_INLINE (node))
- fputs (" inline", file);
if (TREE_CODE (node) == TYPE_DECL && TYPE_DECL_SUPPRESS_DEBUG (node))
fputs (" suppress-debug", file);
+ if (TREE_CODE (node) == FUNCTION_DECL && DECL_INLINE (node))
+ fputs (" inline", file);
if (TREE_CODE (node) == FUNCTION_DECL && DECL_BUILT_IN (node))
fputs (" built-in", file);
if (TREE_CODE (node) == FUNCTION_DECL && DECL_BUILT_IN_NONANSI (node))
fputs (" built-in-nonansi", file);
+ if (TREE_CODE (node) == FUNCTION_DECL && DECL_NO_STATIC_CHAIN (node))
+ fputs (" no-static-chain", file);
+ if (TREE_CODE (node) == FIELD_DECL && DECL_PACKED (node))
+ fputs (" packed", file);
if (TREE_CODE (node) == FIELD_DECL && DECL_BIT_FIELD (node))
fputs (" bit-field", file);
+ if (TREE_CODE (node) == FIELD_DECL && DECL_NONADDRESSABLE_P (node))
+ fputs (" nonaddressable", file);
+
if (TREE_CODE (node) == LABEL_DECL && DECL_TOO_LATE (node))
fputs (" too-late", file);
+ if (TREE_CODE (node) == LABEL_DECL && DECL_ERROR_ISSUED (node))
+ fputs (" error-issued", file);
+
if (TREE_CODE (node) == VAR_DECL && DECL_IN_TEXT_SECTION (node))
fputs (" in-text-section", file);
+ if (TREE_CODE (node) == PARM_DECL && DECL_TRANSPARENT_UNION (node))
+ fputs (" transparent-union", file);
+
if (DECL_VIRTUAL_P (node))
fputs (" virtual", file);
if (DECL_DEFER_OUTPUT (node))
fputs (" defer-output", file);
- if (DECL_TRANSPARENT_UNION (node))
- fputs (" transparent-union", file);
if (DECL_LANG_FLAG_0 (node))
fputs (" decl_0", file);
@@ -391,54 +389,91 @@ print_node (file, prefix, node, indent)
if (DECL_LANG_FLAG_7 (node))
fputs (" decl_7", file);
- fprintf (file, " %s", mode_name[(int) mode]);
-
+ fprintf (file, " %s", GET_MODE_NAME (mode));
fprintf (file, " file %s line %d",
DECL_SOURCE_FILE (node), DECL_SOURCE_LINE (node));
print_node (file, "size", DECL_SIZE (node), indent + 4);
- indent_to (file, indent + 3);
+ print_node (file, "unit size", DECL_SIZE_UNIT (node), indent + 4);
+
+ if (TREE_CODE (node) != FUNCTION_DECL
+ || DECL_INLINE (node) || DECL_BUILT_IN (node))
+ indent_to (file, indent + 3);
+
if (TREE_CODE (node) != FUNCTION_DECL)
- fprintf (file, " align %d", DECL_ALIGN (node));
- else if (DECL_INLINE (node))
- fprintf (file, " frame_size %d", DECL_FRAME_SIZE (node));
+ {
+ if (DECL_USER_ALIGN (node))
+ fprintf (file, " user");
+
+ fprintf (file, " align %d", DECL_ALIGN (node));
+ if (TREE_CODE (node) == FIELD_DECL)
+ {
+ fprintf (file, " offset_align ");
+ fprintf (file, HOST_WIDE_INT_PRINT_UNSIGNED,
+ DECL_OFFSET_ALIGN (node));
+ }
+ }
else if (DECL_BUILT_IN (node))
- fprintf (file, " built-in code %d", DECL_FUNCTION_CODE (node));
- if (TREE_CODE (node) == FIELD_DECL)
- print_node (file, "bitpos", DECL_FIELD_BITPOS (node), indent + 4);
+ {
+ if (DECL_BUILT_IN_CLASS (node) == BUILT_IN_MD)
+ fprintf (file, " built-in BUILT_IN_MD %d", DECL_FUNCTION_CODE (node));
+ else
+ fprintf (file, " built-in %s:%s",
+ built_in_class_names[(int) DECL_BUILT_IN_CLASS (node)],
+ built_in_names[(int) DECL_FUNCTION_CODE (node)]);
+ }
+
if (DECL_POINTER_ALIAS_SET_KNOWN_P (node))
- fprintf (file, " alias set %d", DECL_POINTER_ALIAS_SET (node));
+ {
+ fprintf (file, " alias set ");
+ fprintf (file, HOST_WIDE_INT_PRINT_DEC,
+ DECL_POINTER_ALIAS_SET (node));
+ }
+
+ if (TREE_CODE (node) == FIELD_DECL)
+ {
+ print_node (file, "offset", DECL_FIELD_OFFSET (node), indent + 4);
+ print_node (file, "bit offset", DECL_FIELD_BIT_OFFSET (node),
+ indent + 4);
+ }
+
print_node_brief (file, "context", DECL_CONTEXT (node), indent + 4);
- print_node_brief (file, "machine_attributes", DECL_MACHINE_ATTRIBUTES (node), indent + 4);
+ print_node_brief (file, "attributes",
+ DECL_ATTRIBUTES (node), indent + 4);
print_node_brief (file, "abstract_origin",
DECL_ABSTRACT_ORIGIN (node), indent + 4);
print_node (file, "arguments", DECL_ARGUMENTS (node), indent + 4);
- print_node (file, "result", DECL_RESULT (node), indent + 4);
+ print_node (file, "result", DECL_RESULT_FLD (node), indent + 4);
print_node_brief (file, "initial", DECL_INITIAL (node), indent + 4);
- print_lang_decl (file, node, indent);
+ (*lang_hooks.print_decl) (file, node, indent);
- if (DECL_RTL (node) != 0)
+ if (DECL_RTL_SET_P (node))
{
indent_to (file, indent + 4);
print_rtl (file, DECL_RTL (node));
}
- if (DECL_SAVED_INSNS (node) != 0)
+ if (TREE_CODE (node) == PARM_DECL)
{
- indent_to (file, indent + 4);
- if (TREE_CODE (node) == PARM_DECL)
+ print_node (file, "arg-type", DECL_ARG_TYPE (node), indent + 4);
+ print_node (file, "arg-type-as-written",
+ DECL_ARG_TYPE_AS_WRITTEN (node), indent + 4);
+
+ if (DECL_INCOMING_RTL (node) != 0)
{
+ indent_to (file, indent + 4);
fprintf (file, "incoming-rtl ");
print_rtl (file, DECL_INCOMING_RTL (node));
}
- else if (TREE_CODE (node) == FUNCTION_DECL)
- {
- fprintf (file, "saved-insns ");
- fprintf (file, HOST_PTR_PRINTF,
- (char *) DECL_SAVED_INSNS (node));
- }
+ }
+ else if (TREE_CODE (node) == FUNCTION_DECL
+ && DECL_SAVED_INSNS (node) != 0)
+ {
+ indent_to (file, indent + 4);
+ fprintf (file, "saved-insns ");
+ fprintf (file, HOST_PTR_PRINTF, (char *) DECL_SAVED_INSNS (node));
}
/* Print the decl chain only if decl is at second level. */
@@ -449,14 +484,36 @@ print_node (file, prefix, node, indent)
break;
case 't':
- if (TYPE_NO_FORCE_BLK (node))
+ /* The no-force-blk flag is used for different things in
+ different types. */
+ if ((TREE_CODE (node) == RECORD_TYPE
+ || TREE_CODE (node) == UNION_TYPE
+ || TREE_CODE (node) == QUAL_UNION_TYPE)
+ && TYPE_NO_FORCE_BLK (node))
fputs (" no-force-blk", file);
+ else if (TREE_CODE (node) == INTEGER_TYPE
+ && TYPE_IS_SIZETYPE (node))
+ fputs (" sizetype", file);
+ else if (TREE_CODE (node) == FUNCTION_TYPE
+ && TYPE_RETURNS_STACK_DEPRESSED (node))
+ fputs (" returns-stack-depressed", file);
+
if (TYPE_STRING_FLAG (node))
fputs (" string-flag", file);
if (TYPE_NEEDS_CONSTRUCTING (node))
fputs (" needs-constructing", file);
- if (TYPE_TRANSPARENT_UNION (node))
+
+ /* The transparent-union flag is used for different things in
+ different nodes. */
+ if (TREE_CODE (node) == UNION_TYPE && TYPE_TRANSPARENT_UNION (node))
fputs (" transparent-union", file);
+ else if (TREE_CODE (node) == ARRAY_TYPE
+ && TYPE_NONALIASED_COMPONENT (node))
+ fputs (" nonaliased-component", file);
+ else if (TREE_CODE (node) == FUNCTION_TYPE
+ && TYPE_AMBIENT_BOUNDEDNESS (node))
+ fputs (" ambient-boundedness", file);
+
if (TYPE_PACKED (node))
fputs (" packed", file);
@@ -476,61 +533,66 @@ print_node (file, prefix, node, indent)
fputs (" type_6", file);
mode = TYPE_MODE (node);
- fprintf (file, " %s", mode_name[(int) mode]);
+ fprintf (file, " %s", GET_MODE_NAME (mode));
print_node (file, "size", TYPE_SIZE (node), indent + 4);
+ print_node (file, "unit size", TYPE_SIZE_UNIT (node), indent + 4);
indent_to (file, indent + 3);
+ if (TYPE_USER_ALIGN (node))
+ fprintf (file, " user");
+
fprintf (file, " align %d", TYPE_ALIGN (node));
fprintf (file, " symtab %d", TYPE_SYMTAB_ADDRESS (node));
- fprintf (file, " alias set %d", TYPE_ALIAS_SET (node));
+ fprintf (file, " alias set ");
+ fprintf (file, HOST_WIDE_INT_PRINT_DEC, TYPE_ALIAS_SET (node));
print_node (file, "attributes", TYPE_ATTRIBUTES (node), indent + 4);
- if (TREE_CODE (node) == ARRAY_TYPE || TREE_CODE (node) == SET_TYPE)
- print_node (file, "domain", TYPE_DOMAIN (node), indent + 4);
- else if (TREE_CODE (node) == INTEGER_TYPE
- || TREE_CODE (node) == BOOLEAN_TYPE
- || TREE_CODE (node) == CHAR_TYPE)
- {
- fprintf (file, " precision %d", TYPE_PRECISION (node));
- print_node (file, "min", TYPE_MIN_VALUE (node), indent + 4);
- print_node (file, "max", TYPE_MAX_VALUE (node), indent + 4);
- }
- else if (TREE_CODE (node) == ENUMERAL_TYPE)
+ if (INTEGRAL_TYPE_P (node) || TREE_CODE (node) == REAL_TYPE)
{
fprintf (file, " precision %d", TYPE_PRECISION (node));
- print_node (file, "min", TYPE_MIN_VALUE (node), indent + 4);
- print_node (file, "max", TYPE_MAX_VALUE (node), indent + 4);
- print_node (file, "values", TYPE_VALUES (node), indent + 4);
+ print_node_brief (file, "min", TYPE_MIN_VALUE (node), indent + 4);
+ print_node_brief (file, "max", TYPE_MAX_VALUE (node), indent + 4);
}
- else if (TREE_CODE (node) == REAL_TYPE)
- fprintf (file, " precision %d", TYPE_PRECISION (node));
+
+ if (TREE_CODE (node) == ENUMERAL_TYPE)
+ print_node (file, "values", TYPE_VALUES (node), indent + 4);
+ else if (TREE_CODE (node) == ARRAY_TYPE || TREE_CODE (node) == SET_TYPE)
+ print_node (file, "domain", TYPE_DOMAIN (node), indent + 4);
else if (TREE_CODE (node) == RECORD_TYPE
|| TREE_CODE (node) == UNION_TYPE
|| TREE_CODE (node) == QUAL_UNION_TYPE)
print_node (file, "fields", TYPE_FIELDS (node), indent + 4);
- else if (TREE_CODE (node) == FUNCTION_TYPE || TREE_CODE (node) == METHOD_TYPE)
+ else if (TREE_CODE (node) == FUNCTION_TYPE
+ || TREE_CODE (node) == METHOD_TYPE)
{
if (TYPE_METHOD_BASETYPE (node))
- print_node_brief (file, "method basetype", TYPE_METHOD_BASETYPE (node), indent + 4);
+ print_node_brief (file, "method basetype",
+ TYPE_METHOD_BASETYPE (node), indent + 4);
print_node (file, "arg-types", TYPE_ARG_TYPES (node), indent + 4);
}
+ else if (TREE_CODE (node) == OFFSET_TYPE)
+ print_node_brief (file, "basetype", TYPE_OFFSET_BASETYPE (node),
+ indent + 4);
+
if (TYPE_CONTEXT (node))
print_node_brief (file, "context", TYPE_CONTEXT (node), indent + 4);
- print_lang_type (file, node, indent);
+ (*lang_hooks.print_type) (file, node, indent);
if (TYPE_POINTER_TO (node) || TREE_CHAIN (node))
indent_to (file, indent + 3);
- print_node_brief (file, "pointer_to_this", TYPE_POINTER_TO (node), indent + 4);
- print_node_brief (file, "reference_to_this", TYPE_REFERENCE_TO (node), indent + 4);
+
+ print_node_brief (file, "pointer_to_this", TYPE_POINTER_TO (node),
+ indent + 4);
+ print_node_brief (file, "reference_to_this", TYPE_REFERENCE_TO (node),
+ indent + 4);
print_node_brief (file, "chain", TREE_CHAIN (node), indent + 4);
break;
case 'b':
print_node (file, "vars", BLOCK_VARS (node), indent + 4);
- print_node (file, "tags", BLOCK_TYPE_TAGS (node), indent + 4);
print_node (file, "supercontext", BLOCK_SUPERCONTEXT (node), indent + 4);
print_node (file, "subblocks", BLOCK_SUBBLOCKS (node), indent + 4);
print_node (file, "chain", BLOCK_CHAIN (node), indent + 4);
@@ -552,10 +614,12 @@ print_node (file, prefix, node, indent)
break;
}
- len = tree_code_length[(int) TREE_CODE (node)];
+ len = TREE_CODE_LENGTH (TREE_CODE (node));
+
/* Some nodes contain rtx's, not trees,
after a certain point. Print the rtx's as rtx's. */
first_rtl = first_rtl_op (TREE_CODE (node));
+
for (i = 0; i < len; i++)
{
if (i >= first_rtl)
@@ -585,6 +649,7 @@ print_node (file, prefix, node, indent)
EXPR_WFL_FILENAME (node) : "(no file info)"),
EXPR_WFL_LINENO (node), EXPR_WFL_COLNO (node));
}
+ print_node (file, "chain", TREE_CHAIN (node), indent + 4);
break;
case 'c':
@@ -659,7 +724,7 @@ print_node (file, prefix, node, indent)
break;
case IDENTIFIER_NODE:
- print_lang_identifier (file, node, indent);
+ (*lang_hooks.print_identifier) (file, node, indent);
break;
case TREE_LIST:
@@ -680,14 +745,9 @@ print_node (file, prefix, node, indent)
}
break;
- case OP_IDENTIFIER:
- print_node (file, "op1", TREE_PURPOSE (node), indent + 4);
- print_node (file, "op2", TREE_VALUE (node), indent + 4);
- break;
-
default:
if (TREE_CODE_CLASS (TREE_CODE (node)) == 'x')
- lang_print_xnode (file, node, indent);
+ (*lang_hooks.print_xnode) (file, node, indent);
break;
}
diff --git a/contrib/gcc/reload.c b/contrib/gcc/reload.c
index e96e431..672c631 100644
--- a/contrib/gcc/reload.c
+++ b/contrib/gcc/reload.c
@@ -1,23 +1,24 @@
/* Search an insn for pseudo regs that must be in hard regs and are not.
- Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997,
- 1998, 1999, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+ 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
-This file is part of GNU CC.
+This file is part of GCC.
-GNU CC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
-GNU CC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
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, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+along with GCC; see the file COPYING. If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
/* $FreeBSD$ */
@@ -73,7 +74,6 @@ NOTE SIDE EFFECTS:
2 happens only when REPLACE is 1, which is only when
actually doing the reloads, not when just counting them.
-
Using a reload register for several reloads in one insn:
When an insn has reloads, it is considered as having three parts:
@@ -93,8 +93,10 @@ a register with any other reload. */
#include "config.h"
#include "system.h"
#include "rtl.h"
+#include "tm_p.h"
#include "insn-config.h"
-#include "insn-codes.h"
+#include "expr.h"
+#include "optabs.h"
#include "recog.h"
#include "reload.h"
#include "regs.h"
@@ -102,11 +104,11 @@ a register with any other reload. */
#include "flags.h"
#include "real.h"
#include "output.h"
-#include "expr.h"
+#include "function.h"
#include "toplev.h"
#ifndef REGISTER_MOVE_COST
-#define REGISTER_MOVE_COST(x, y) 2
+#define REGISTER_MOVE_COST(m, x, y) 2
#endif
#ifndef REGNO_MODE_OK_FOR_BASE_P
@@ -117,82 +119,10 @@ a register with any other reload. */
#define REG_MODE_OK_FOR_BASE_P(REGNO, MODE) REG_OK_FOR_BASE_P (REGNO)
#endif
-/* The variables set up by `find_reloads' are:
-
- n_reloads number of distinct reloads needed; max reload # + 1
- tables indexed by reload number
- reload_in rtx for value to reload from
- reload_out rtx for where to store reload-reg afterward if nec
- (often the same as reload_in)
- reload_reg_class enum reg_class, saying what regs to reload into
- reload_inmode enum machine_mode; mode this operand should have
- when reloaded, on input.
- reload_outmode enum machine_mode; mode this operand should have
- when reloaded, on output.
- reload_optional char, nonzero for an optional reload.
- Optional reloads are ignored unless the
- value is already sitting in a register.
- reload_nongroup char, nonzero when a reload must use a register
- not already allocated to a group.
- reload_inc int, positive amount to increment or decrement by if
- reload_in is a PRE_DEC, PRE_INC, POST_DEC, POST_INC.
- Ignored otherwise (don't assume it is zero).
- reload_in_reg rtx. A reg for which reload_in is the equivalent.
- If reload_in is a symbol_ref which came from
- reg_equiv_constant, then this is the pseudo
- which has that symbol_ref as equivalent.
- reload_reg_rtx rtx. This is the register to reload into.
- If it is zero when `find_reloads' returns,
- you must find a suitable register in the class
- specified by reload_reg_class, and store here
- an rtx for that register with mode from
- reload_inmode or reload_outmode.
- reload_nocombine char, nonzero if this reload shouldn't be
- combined with another reload.
- reload_opnum int, operand number being reloaded. This is
- used to group related reloads and need not always
- be equal to the actual operand number in the insn,
- though it current will be; for in-out operands, it
- is one of the two operand numbers.
- reload_when_needed enum, classifies reload as needed either for
- addressing an input reload, addressing an output,
- for addressing a non-reloaded mem ref,
- or for unspecified purposes (i.e., more than one
- of the above).
- reload_secondary_p int, 1 if this is a secondary register for one
- or more reloads.
- reload_secondary_in_reload
- reload_secondary_out_reload
- int, gives the reload number of a secondary
- reload, when needed; otherwise -1
- reload_secondary_in_icode
- reload_secondary_out_icode
- enum insn_code, if a secondary reload is required,
- gives the INSN_CODE that uses the secondary
- reload as a scratch register, or CODE_FOR_nothing
- if the secondary reload register is to be an
- intermediate register. */
+/* All reloads of the current insn are recorded here. See reload.h for
+ comments. */
int n_reloads;
-
-rtx reload_in[MAX_RELOADS];
-rtx reload_out[MAX_RELOADS];
-enum reg_class reload_reg_class[MAX_RELOADS];
-enum machine_mode reload_inmode[MAX_RELOADS];
-enum machine_mode reload_outmode[MAX_RELOADS];
-rtx reload_reg_rtx[MAX_RELOADS];
-char reload_optional[MAX_RELOADS];
-char reload_nongroup[MAX_RELOADS];
-int reload_inc[MAX_RELOADS];
-rtx reload_in_reg[MAX_RELOADS];
-rtx reload_out_reg[MAX_RELOADS];
-char reload_nocombine[MAX_RELOADS];
-int reload_opnum[MAX_RELOADS];
-enum reload_type reload_when_needed[MAX_RELOADS];
-int reload_secondary_p[MAX_RELOADS];
-int reload_secondary_in_reload[MAX_RELOADS];
-int reload_secondary_out_reload[MAX_RELOADS];
-enum insn_code reload_secondary_in_icode[MAX_RELOADS];
-enum insn_code reload_secondary_out_icode[MAX_RELOADS];
+struct reload rld[MAX_RELOADS];
/* All the "earlyclobber" operands of the current insn
are recorded here. */
@@ -239,9 +169,9 @@ struct decomposition
#ifdef SECONDARY_MEMORY_NEEDED
/* Save MEMs needed to copy from one class of registers to another. One MEM
- is used per mode, but normally only one or two modes are ever used.
+ is used per mode, but normally only one or two modes are ever used.
- We keep two versions, before and after register elimination. The one
+ We keep two versions, before and after register elimination. The one
after register elimination is record separately for each operand. This
is done in case the address is not valid to be sure that we separately
reload each. */
@@ -310,40 +240,39 @@ static int output_reloadnum;
: (type)))
#ifdef HAVE_SECONDARY_RELOADS
-static int push_secondary_reload PROTO((int, rtx, int, int, enum reg_class,
+static int push_secondary_reload PARAMS ((int, rtx, int, int, enum reg_class,
enum machine_mode, enum reload_type,
enum insn_code *));
#endif
-static enum reg_class find_valid_class PROTO((enum machine_mode, int));
-static int push_reload PROTO((rtx, rtx, rtx *, rtx *, enum reg_class,
- enum machine_mode, enum machine_mode,
- int, int, int, enum reload_type));
-static void push_replacement PROTO((rtx *, int, enum machine_mode));
-static void combine_reloads PROTO((void));
-static int find_reusable_reload PROTO((rtx *, rtx, enum reg_class,
+static enum reg_class find_valid_class PARAMS ((enum machine_mode, int));
+static int reload_inner_reg_of_subreg PARAMS ((rtx, enum machine_mode));
+static void push_replacement PARAMS ((rtx *, int, enum machine_mode));
+static void combine_reloads PARAMS ((void));
+static int find_reusable_reload PARAMS ((rtx *, rtx, enum reg_class,
enum reload_type, int, int));
-static rtx find_dummy_reload PROTO((rtx, rtx, rtx *, rtx *,
+static rtx find_dummy_reload PARAMS ((rtx, rtx, rtx *, rtx *,
enum machine_mode, enum machine_mode,
enum reg_class, int, int));
-static int hard_reg_set_here_p PROTO((int, int, rtx));
-static struct decomposition decompose PROTO((rtx));
-static int immune_p PROTO((rtx, rtx, struct decomposition));
-static int alternative_allows_memconst PROTO((const char *, int));
-static rtx find_reloads_toplev PROTO((rtx, int, enum reload_type, int, int, rtx));
-static rtx make_memloc PROTO((rtx, int));
-static int find_reloads_address PROTO((enum machine_mode, rtx *, rtx, rtx *,
+static int hard_reg_set_here_p PARAMS ((unsigned int, unsigned int, rtx));
+static struct decomposition decompose PARAMS ((rtx));
+static int immune_p PARAMS ((rtx, rtx, struct decomposition));
+static int alternative_allows_memconst PARAMS ((const char *, int));
+static rtx find_reloads_toplev PARAMS ((rtx, int, enum reload_type, int,
+ int, rtx, int *));
+static rtx make_memloc PARAMS ((rtx, int));
+static int find_reloads_address PARAMS ((enum machine_mode, rtx *, rtx, rtx *,
int, enum reload_type, int, rtx));
-static rtx subst_reg_equivs PROTO((rtx, rtx));
-static rtx subst_indexed_address PROTO((rtx));
-static int find_reloads_address_1 PROTO((enum machine_mode, rtx, int, rtx *,
+static rtx subst_reg_equivs PARAMS ((rtx, rtx));
+static rtx subst_indexed_address PARAMS ((rtx));
+static void update_auto_inc_notes PARAMS ((rtx, int, int));
+static int find_reloads_address_1 PARAMS ((enum machine_mode, rtx, int, rtx *,
int, enum reload_type,int, rtx));
-static void find_reloads_address_part PROTO((rtx, rtx *, enum reg_class,
+static void find_reloads_address_part PARAMS ((rtx, rtx *, enum reg_class,
enum machine_mode, int,
enum reload_type, int));
-static rtx find_reloads_subreg_address PROTO((rtx, int, int, enum reload_type,
+static rtx find_reloads_subreg_address PARAMS ((rtx, int, int, enum reload_type,
int, rtx));
-static int find_inc_amount PROTO((rtx, rtx));
-static int loc_mentioned_in_p PROTO((rtx *, rtx));
+static int find_inc_amount PARAMS ((rtx, rtx));
#ifdef HAVE_SECONDARY_RELOADS
@@ -428,8 +357,8 @@ push_secondary_reload (in_p, x, opnum, optional, reload_class, reload_mode,
: reload_out_optab[(int) reload_mode]);
if (icode != CODE_FOR_nothing
- && insn_operand_predicate[(int) icode][in_p]
- && (! (insn_operand_predicate[(int) icode][in_p]) (x, reload_mode)))
+ && insn_data[(int) icode].operand[in_p].predicate
+ && (! (insn_data[(int) icode].operand[in_p].predicate) (x, reload_mode)))
icode = CODE_FOR_nothing;
/* If we will be using an insn, see if it can directly handle the reload
@@ -440,30 +369,42 @@ push_secondary_reload (in_p, x, opnum, optional, reload_class, reload_mode,
if (icode != CODE_FOR_nothing)
{
- /* If IN_P is non-zero, the reload register will be the output in
+ /* If IN_P is non-zero, the reload register will be the output in
operand 0. If IN_P is zero, the reload register will be the input
in operand 1. Outputs should have an initial "=", which we must
skip. */
- char insn_letter = insn_operand_constraint[(int) icode][!in_p][in_p];
- enum reg_class insn_class
- = (insn_letter == 'r' ? GENERAL_REGS
- : REG_CLASS_FROM_LETTER ((unsigned char) insn_letter));
+ enum reg_class insn_class;
- if (insn_class == NO_REGS
- || (in_p && insn_operand_constraint[(int) icode][!in_p][0] != '=')
- /* The scratch register's constraint must start with "=&". */
- || insn_operand_constraint[(int) icode][2][0] != '='
- || insn_operand_constraint[(int) icode][2][1] != '&')
+ if (insn_data[(int) icode].operand[!in_p].constraint[0] == 0)
+ insn_class = ALL_REGS;
+ else
+ {
+ char insn_letter
+ = insn_data[(int) icode].operand[!in_p].constraint[in_p];
+ insn_class
+ = (insn_letter == 'r' ? GENERAL_REGS
+ : REG_CLASS_FROM_LETTER ((unsigned char) insn_letter));
+
+ if (insn_class == NO_REGS)
+ abort ();
+ if (in_p
+ && insn_data[(int) icode].operand[!in_p].constraint[0] != '=')
+ abort ();
+ }
+
+ /* The scratch register's constraint must start with "=&". */
+ if (insn_data[(int) icode].operand[2].constraint[0] != '='
+ || insn_data[(int) icode].operand[2].constraint[1] != '&')
abort ();
if (reg_class_subset_p (reload_class, insn_class))
- mode = insn_operand_mode[(int) icode][2];
+ mode = insn_data[(int) icode].operand[2].mode;
else
{
- char t_letter = insn_operand_constraint[(int) icode][2][2];
+ char t_letter = insn_data[(int) icode].operand[2].constraint[2];
class = insn_class;
- t_mode = insn_operand_mode[(int) icode][2];
+ t_mode = insn_data[(int) icode].operand[2].mode;
t_class = (t_letter == 'r' ? GENERAL_REGS
: REG_CLASS_FROM_LETTER ((unsigned char) t_letter));
t_icode = icode;
@@ -482,11 +423,11 @@ push_secondary_reload (in_p, x, opnum, optional, reload_class, reload_mode,
can not use secondary reloads, you must work around the problem some
other way.
- Allow this when MODE is not reload_mode and assume that the generated
- code handles this case (it does on the Alpha, which is the only place
- this currently happens). */
+ Allow this when a reload_in/out pattern is being used. I.e. assume
+ that the generated code handles this case. */
- if (in_p && class == reload_class && mode == reload_mode)
+ if (in_p && class == reload_class && icode == CODE_FOR_nothing
+ && t_icode == CODE_FOR_nothing)
abort ();
/* If we need a tertiary reload, see if we have one we can reuse or else
@@ -495,58 +436,57 @@ push_secondary_reload (in_p, x, opnum, optional, reload_class, reload_mode,
if (t_class != NO_REGS)
{
for (t_reload = 0; t_reload < n_reloads; t_reload++)
- if (reload_secondary_p[t_reload]
- && (reg_class_subset_p (t_class, reload_reg_class[t_reload])
- || reg_class_subset_p (reload_reg_class[t_reload], t_class))
- && ((in_p && reload_inmode[t_reload] == t_mode)
- || (! in_p && reload_outmode[t_reload] == t_mode))
- && ((in_p && (reload_secondary_in_icode[t_reload]
+ if (rld[t_reload].secondary_p
+ && (reg_class_subset_p (t_class, rld[t_reload].class)
+ || reg_class_subset_p (rld[t_reload].class, t_class))
+ && ((in_p && rld[t_reload].inmode == t_mode)
+ || (! in_p && rld[t_reload].outmode == t_mode))
+ && ((in_p && (rld[t_reload].secondary_in_icode
== CODE_FOR_nothing))
- || (! in_p &&(reload_secondary_out_icode[t_reload]
+ || (! in_p &&(rld[t_reload].secondary_out_icode
== CODE_FOR_nothing)))
&& (reg_class_size[(int) t_class] == 1 || SMALL_REGISTER_CLASSES)
&& MERGABLE_RELOADS (secondary_type,
- reload_when_needed[t_reload],
- opnum, reload_opnum[t_reload]))
+ rld[t_reload].when_needed,
+ opnum, rld[t_reload].opnum))
{
if (in_p)
- reload_inmode[t_reload] = t_mode;
+ rld[t_reload].inmode = t_mode;
if (! in_p)
- reload_outmode[t_reload] = t_mode;
+ rld[t_reload].outmode = t_mode;
- if (reg_class_subset_p (t_class, reload_reg_class[t_reload]))
- reload_reg_class[t_reload] = t_class;
+ if (reg_class_subset_p (t_class, rld[t_reload].class))
+ rld[t_reload].class = t_class;
- reload_opnum[t_reload] = MIN (reload_opnum[t_reload], opnum);
- reload_optional[t_reload] &= optional;
- reload_secondary_p[t_reload] = 1;
- if (MERGE_TO_OTHER (secondary_type, reload_when_needed[t_reload],
- opnum, reload_opnum[t_reload]))
- reload_when_needed[t_reload] = RELOAD_OTHER;
+ rld[t_reload].opnum = MIN (rld[t_reload].opnum, opnum);
+ rld[t_reload].optional &= optional;
+ rld[t_reload].secondary_p = 1;
+ if (MERGE_TO_OTHER (secondary_type, rld[t_reload].when_needed,
+ opnum, rld[t_reload].opnum))
+ rld[t_reload].when_needed = RELOAD_OTHER;
}
if (t_reload == n_reloads)
{
/* We need to make a new tertiary reload for this register class. */
- reload_in[t_reload] = reload_out[t_reload] = 0;
- reload_reg_class[t_reload] = t_class;
- reload_inmode[t_reload] = in_p ? t_mode : VOIDmode;
- reload_outmode[t_reload] = ! in_p ? t_mode : VOIDmode;
- reload_reg_rtx[t_reload] = 0;
- reload_optional[t_reload] = optional;
- reload_nongroup[t_reload] = 0;
- reload_inc[t_reload] = 0;
+ rld[t_reload].in = rld[t_reload].out = 0;
+ rld[t_reload].class = t_class;
+ rld[t_reload].inmode = in_p ? t_mode : VOIDmode;
+ rld[t_reload].outmode = ! in_p ? t_mode : VOIDmode;
+ rld[t_reload].reg_rtx = 0;
+ rld[t_reload].optional = optional;
+ rld[t_reload].inc = 0;
/* Maybe we could combine these, but it seems too tricky. */
- reload_nocombine[t_reload] = 1;
- reload_in_reg[t_reload] = 0;
- reload_out_reg[t_reload] = 0;
- reload_opnum[t_reload] = opnum;
- reload_when_needed[t_reload] = secondary_type;
- reload_secondary_in_reload[t_reload] = -1;
- reload_secondary_out_reload[t_reload] = -1;
- reload_secondary_in_icode[t_reload] = CODE_FOR_nothing;
- reload_secondary_out_icode[t_reload] = CODE_FOR_nothing;
- reload_secondary_p[t_reload] = 1;
+ rld[t_reload].nocombine = 1;
+ rld[t_reload].in_reg = 0;
+ rld[t_reload].out_reg = 0;
+ rld[t_reload].opnum = opnum;
+ rld[t_reload].when_needed = secondary_type;
+ rld[t_reload].secondary_in_reload = -1;
+ rld[t_reload].secondary_out_reload = -1;
+ rld[t_reload].secondary_in_icode = CODE_FOR_nothing;
+ rld[t_reload].secondary_out_icode = CODE_FOR_nothing;
+ rld[t_reload].secondary_p = 1;
n_reloads++;
}
@@ -554,33 +494,33 @@ push_secondary_reload (in_p, x, opnum, optional, reload_class, reload_mode,
/* See if we can reuse an existing secondary reload. */
for (s_reload = 0; s_reload < n_reloads; s_reload++)
- if (reload_secondary_p[s_reload]
- && (reg_class_subset_p (class, reload_reg_class[s_reload])
- || reg_class_subset_p (reload_reg_class[s_reload], class))
- && ((in_p && reload_inmode[s_reload] == mode)
- || (! in_p && reload_outmode[s_reload] == mode))
- && ((in_p && reload_secondary_in_reload[s_reload] == t_reload)
- || (! in_p && reload_secondary_out_reload[s_reload] == t_reload))
- && ((in_p && reload_secondary_in_icode[s_reload] == t_icode)
- || (! in_p && reload_secondary_out_icode[s_reload] == t_icode))
+ if (rld[s_reload].secondary_p
+ && (reg_class_subset_p (class, rld[s_reload].class)
+ || reg_class_subset_p (rld[s_reload].class, class))
+ && ((in_p && rld[s_reload].inmode == mode)
+ || (! in_p && rld[s_reload].outmode == mode))
+ && ((in_p && rld[s_reload].secondary_in_reload == t_reload)
+ || (! in_p && rld[s_reload].secondary_out_reload == t_reload))
+ && ((in_p && rld[s_reload].secondary_in_icode == t_icode)
+ || (! in_p && rld[s_reload].secondary_out_icode == t_icode))
&& (reg_class_size[(int) class] == 1 || SMALL_REGISTER_CLASSES)
- && MERGABLE_RELOADS (secondary_type, reload_when_needed[s_reload],
- opnum, reload_opnum[s_reload]))
+ && MERGABLE_RELOADS (secondary_type, rld[s_reload].when_needed,
+ opnum, rld[s_reload].opnum))
{
if (in_p)
- reload_inmode[s_reload] = mode;
+ rld[s_reload].inmode = mode;
if (! in_p)
- reload_outmode[s_reload] = mode;
+ rld[s_reload].outmode = mode;
- if (reg_class_subset_p (class, reload_reg_class[s_reload]))
- reload_reg_class[s_reload] = class;
+ if (reg_class_subset_p (class, rld[s_reload].class))
+ rld[s_reload].class = class;
- reload_opnum[s_reload] = MIN (reload_opnum[s_reload], opnum);
- reload_optional[s_reload] &= optional;
- reload_secondary_p[s_reload] = 1;
- if (MERGE_TO_OTHER (secondary_type, reload_when_needed[s_reload],
- opnum, reload_opnum[s_reload]))
- reload_when_needed[s_reload] = RELOAD_OTHER;
+ rld[s_reload].opnum = MIN (rld[s_reload].opnum, opnum);
+ rld[s_reload].optional &= optional;
+ rld[s_reload].secondary_p = 1;
+ if (MERGE_TO_OTHER (secondary_type, rld[s_reload].when_needed,
+ opnum, rld[s_reload].opnum))
+ rld[s_reload].when_needed = RELOAD_OTHER;
}
if (s_reload == n_reloads)
@@ -588,7 +528,7 @@ push_secondary_reload (in_p, x, opnum, optional, reload_class, reload_mode,
#ifdef SECONDARY_MEMORY_NEEDED
/* If we need a memory location to copy between the two reload regs,
set it up now. Note that we do the input case before making
- the reload and the output case after. This is due to the
+ the reload and the output case after. This is due to the
way reloads are output. */
if (in_p && icode == CODE_FOR_nothing
@@ -603,27 +543,26 @@ push_secondary_reload (in_p, x, opnum, optional, reload_class, reload_mode,
#endif
/* We need to make a new secondary reload for this register class. */
- reload_in[s_reload] = reload_out[s_reload] = 0;
- reload_reg_class[s_reload] = class;
-
- reload_inmode[s_reload] = in_p ? mode : VOIDmode;
- reload_outmode[s_reload] = ! in_p ? mode : VOIDmode;
- reload_reg_rtx[s_reload] = 0;
- reload_optional[s_reload] = optional;
- reload_nongroup[s_reload] = 0;
- reload_inc[s_reload] = 0;
+ rld[s_reload].in = rld[s_reload].out = 0;
+ rld[s_reload].class = class;
+
+ rld[s_reload].inmode = in_p ? mode : VOIDmode;
+ rld[s_reload].outmode = ! in_p ? mode : VOIDmode;
+ rld[s_reload].reg_rtx = 0;
+ rld[s_reload].optional = optional;
+ rld[s_reload].inc = 0;
/* Maybe we could combine these, but it seems too tricky. */
- reload_nocombine[s_reload] = 1;
- reload_in_reg[s_reload] = 0;
- reload_out_reg[s_reload] = 0;
- reload_opnum[s_reload] = opnum;
- reload_when_needed[s_reload] = secondary_type;
- reload_secondary_in_reload[s_reload] = in_p ? t_reload : -1;
- reload_secondary_out_reload[s_reload] = ! in_p ? t_reload : -1;
- reload_secondary_in_icode[s_reload] = in_p ? t_icode : CODE_FOR_nothing;
- reload_secondary_out_icode[s_reload]
+ rld[s_reload].nocombine = 1;
+ rld[s_reload].in_reg = 0;
+ rld[s_reload].out_reg = 0;
+ rld[s_reload].opnum = opnum;
+ rld[s_reload].when_needed = secondary_type;
+ rld[s_reload].secondary_in_reload = in_p ? t_reload : -1;
+ rld[s_reload].secondary_out_reload = ! in_p ? t_reload : -1;
+ rld[s_reload].secondary_in_icode = in_p ? t_icode : CODE_FOR_nothing;
+ rld[s_reload].secondary_out_icode
= ! in_p ? t_icode : CODE_FOR_nothing;
- reload_secondary_p[s_reload] = 1;
+ rld[s_reload].secondary_p = 1;
n_reloads++;
@@ -641,13 +580,13 @@ push_secondary_reload (in_p, x, opnum, optional, reload_class, reload_mode,
#ifdef SECONDARY_MEMORY_NEEDED
-/* Return a memory location that will be used to copy X in mode MODE.
+/* Return a memory location that will be used to copy X in mode MODE.
If we haven't already made a location for this mode in this insn,
call find_reloads_address on the location being returned. */
rtx
get_secondary_mem (x, mode, opnum, type)
- rtx x;
+ rtx x ATTRIBUTE_UNUSED;
enum machine_mode mode;
int opnum;
enum reload_type type;
@@ -663,7 +602,7 @@ get_secondary_mem (x, mode, opnum, type)
#ifdef SECONDARY_MEMORY_NEEDED_MODE
mode = SECONDARY_MEMORY_NEEDED_MODE (mode);
#else
- if (GET_MODE_BITSIZE (mode) < BITS_PER_WORD)
+ if (GET_MODE_BITSIZE (mode) < BITS_PER_WORD && INTEGRAL_MODE_P (mode))
mode = mode_for_size (BITS_PER_WORD, GET_MODE_CLASS (mode), 0);
#endif
@@ -671,7 +610,7 @@ get_secondary_mem (x, mode, opnum, type)
if (secondary_memlocs_elim[(int) mode][opnum] != 0)
return secondary_memlocs_elim[(int) mode][opnum];
- /* If this is the first time we've tried to get a MEM for this mode,
+ /* If this is the first time we've tried to get a MEM for this mode,
allocate a new one. `something_changed' in reload will get set
by noticing that the frame size has changed. */
@@ -707,7 +646,7 @@ get_secondary_mem (x, mode, opnum, type)
: type == RELOAD_FOR_OUTPUT ? RELOAD_FOR_OUTPUT_ADDRESS
: RELOAD_OTHER);
- find_reloads_address (mode, NULL_PTR, XEXP (loc, 0), &XEXP (loc, 0),
+ find_reloads_address (mode, (rtx*) 0, XEXP (loc, 0), &XEXP (loc, 0),
opnum, type, 0, 0);
}
@@ -720,7 +659,7 @@ get_secondary_mem (x, mode, opnum, type)
void
clear_secondary_mem ()
{
- bzero ((char *) secondary_memlocs, sizeof secondary_memlocs);
+ memset ((char *) secondary_memlocs, 0, sizeof secondary_memlocs);
}
#endif /* SECONDARY_MEMORY_NEEDED */
@@ -729,13 +668,13 @@ clear_secondary_mem ()
static enum reg_class
find_valid_class (m1, n)
- enum machine_mode m1;
+ enum machine_mode m1 ATTRIBUTE_UNUSED;
int n;
{
int class;
int regno;
- enum reg_class best_class;
- int best_size = 0;
+ enum reg_class best_class = NO_REGS;
+ unsigned int best_size = 0;
for (class = 1; class < N_REG_CLASSES; class++)
{
@@ -763,6 +702,7 @@ find_valid_class (m1, n)
combine. P_IN points to the corresponding value of IN, which can be
modified by this function.
DONT_SHARE is nonzero if we can't share any input-only reload for IN. */
+
static int
find_reusable_reload (p_in, out, class, type, opnum, dont_share)
rtx *p_in, out;
@@ -781,28 +721,26 @@ find_reusable_reload (p_in, out, class, type, opnum, dont_share)
/* We can use an existing reload if the class is right
and at least one of IN and OUT is a match
and the other is at worst neutral.
- (A zero compared against anything is neutral.)
+ (A zero compared against anything is neutral.)
If SMALL_REGISTER_CLASSES, don't use existing reloads unless they are
for the same thing since that can cause us to need more reload registers
than we otherwise would. */
-
+
for (i = 0; i < n_reloads; i++)
- if ((reg_class_subset_p (class, reload_reg_class[i])
- || reg_class_subset_p (reload_reg_class[i], class))
+ if ((reg_class_subset_p (class, rld[i].class)
+ || reg_class_subset_p (rld[i].class, class))
/* If the existing reload has a register, it must fit our class. */
- && (reload_reg_rtx[i] == 0
+ && (rld[i].reg_rtx == 0
|| TEST_HARD_REG_BIT (reg_class_contents[(int) class],
- true_regnum (reload_reg_rtx[i])))
- && ((in != 0 && MATCHES (reload_in[i], in) && ! dont_share
- && (out == 0 || reload_out[i] == 0 || MATCHES (reload_out[i], out)))
- ||
- (out != 0 && MATCHES (reload_out[i], out)
- && (in == 0 || reload_in[i] == 0 || MATCHES (reload_in[i], in))))
- && (reload_out[i] == 0 || ! earlyclobber_operand_p (reload_out[i]))
+ true_regnum (rld[i].reg_rtx)))
+ && ((in != 0 && MATCHES (rld[i].in, in) && ! dont_share
+ && (out == 0 || rld[i].out == 0 || MATCHES (rld[i].out, out)))
+ || (out != 0 && MATCHES (rld[i].out, out)
+ && (in == 0 || rld[i].in == 0 || MATCHES (rld[i].in, in))))
+ && (rld[i].out == 0 || ! earlyclobber_operand_p (rld[i].out))
&& (reg_class_size[(int) class] == 1 || SMALL_REGISTER_CLASSES)
- && MERGABLE_RELOADS (type, reload_when_needed[i],
- opnum, reload_opnum[i]))
+ && MERGABLE_RELOADS (type, rld[i].when_needed, opnum, rld[i].opnum))
return i;
/* Reloading a plain reg for input can match a reload to postincrement
@@ -811,41 +749,73 @@ find_reusable_reload (p_in, out, class, type, opnum, dont_share)
the preincrementation as happening before any ref in this insn
to that register. */
for (i = 0; i < n_reloads; i++)
- if ((reg_class_subset_p (class, reload_reg_class[i])
- || reg_class_subset_p (reload_reg_class[i], class))
+ if ((reg_class_subset_p (class, rld[i].class)
+ || reg_class_subset_p (rld[i].class, class))
/* If the existing reload has a register, it must fit our
class. */
- && (reload_reg_rtx[i] == 0
+ && (rld[i].reg_rtx == 0
|| TEST_HARD_REG_BIT (reg_class_contents[(int) class],
- true_regnum (reload_reg_rtx[i])))
- && out == 0 && reload_out[i] == 0 && reload_in[i] != 0
+ true_regnum (rld[i].reg_rtx)))
+ && out == 0 && rld[i].out == 0 && rld[i].in != 0
&& ((GET_CODE (in) == REG
- && (GET_CODE (reload_in[i]) == POST_INC
- || GET_CODE (reload_in[i]) == POST_DEC
- || GET_CODE (reload_in[i]) == PRE_INC
- || GET_CODE (reload_in[i]) == PRE_DEC)
- && MATCHES (XEXP (reload_in[i], 0), in))
- ||
- (GET_CODE (reload_in[i]) == REG
- && (GET_CODE (in) == POST_INC
- || GET_CODE (in) == POST_DEC
- || GET_CODE (in) == PRE_INC
- || GET_CODE (in) == PRE_DEC)
- && MATCHES (XEXP (in, 0), reload_in[i])))
- && (reload_out[i] == 0 || ! earlyclobber_operand_p (reload_out[i]))
+ && GET_RTX_CLASS (GET_CODE (rld[i].in)) == 'a'
+ && MATCHES (XEXP (rld[i].in, 0), in))
+ || (GET_CODE (rld[i].in) == REG
+ && GET_RTX_CLASS (GET_CODE (in)) == 'a'
+ && MATCHES (XEXP (in, 0), rld[i].in)))
+ && (rld[i].out == 0 || ! earlyclobber_operand_p (rld[i].out))
&& (reg_class_size[(int) class] == 1 || SMALL_REGISTER_CLASSES)
- && MERGABLE_RELOADS (type, reload_when_needed[i],
- opnum, reload_opnum[i]))
+ && MERGABLE_RELOADS (type, rld[i].when_needed,
+ opnum, rld[i].opnum))
{
/* Make sure reload_in ultimately has the increment,
not the plain register. */
if (GET_CODE (in) == REG)
- *p_in = reload_in[i];
+ *p_in = rld[i].in;
return i;
}
return n_reloads;
}
+/* Return nonzero if X is a SUBREG which will require reloading of its
+ SUBREG_REG expression. */
+
+static int
+reload_inner_reg_of_subreg (x, mode)
+ rtx x;
+ enum machine_mode mode;
+{
+ rtx inner;
+
+ /* Only SUBREGs are problematical. */
+ if (GET_CODE (x) != SUBREG)
+ return 0;
+
+ inner = SUBREG_REG (x);
+
+ /* If INNER is a constant or PLUS, then INNER must be reloaded. */
+ if (CONSTANT_P (inner) || GET_CODE (inner) == PLUS)
+ return 1;
+
+ /* If INNER is not a hard register, then INNER will not need to
+ be reloaded. */
+ if (GET_CODE (inner) != REG
+ || REGNO (inner) >= FIRST_PSEUDO_REGISTER)
+ return 0;
+
+ /* If INNER is not ok for MODE, then INNER will need reloading. */
+ if (! HARD_REGNO_MODE_OK (subreg_regno (x), mode))
+ return 1;
+
+ /* If the outer part is a word or smaller, INNER larger than a
+ word and the number of regs for INNER is not the same as the
+ number of words in INNER, then INNER will need reloading. */
+ return (GET_MODE_SIZE (mode) <= UNITS_PER_WORD
+ && GET_MODE_SIZE (GET_MODE (inner)) > UNITS_PER_WORD
+ && ((GET_MODE_SIZE (GET_MODE (inner)) / UNITS_PER_WORD)
+ != HARD_REGNO_NREGS (REGNO (inner), GET_MODE (inner))));
+}
+
/* Record one reload that needs to be performed.
IN is an rtx saying where the data are to be found before this instruction.
OUT says where they must be stored after the instruction.
@@ -879,7 +849,7 @@ find_reusable_reload (p_in, out, class, type, opnum, dont_share)
the two reload-numbers are equal, but the caller should be careful to
distinguish them. */
-static int
+int
push_reload (in, out, inloc, outloc, class,
inmode, outmode, strict_low, optional, opnum, type)
rtx in, out;
@@ -891,7 +861,7 @@ push_reload (in, out, inloc, outloc, class,
int opnum;
enum reload_type type;
{
- register int i;
+ int i;
int dont_share = 0;
int dont_remove_subreg = 0;
rtx *in_subreg_loc = 0, *out_subreg_loc = 0;
@@ -907,13 +877,13 @@ push_reload (in, out, inloc, outloc, class,
if (outmode == VOIDmode && out != 0)
outmode = GET_MODE (out);
- /* If IN is a pseudo register everywhere-equivalent to a constant, and
+ /* If IN is a pseudo register everywhere-equivalent to a constant, and
it is not in a hard register, reload straight from the constant,
since we want to get rid of such pseudo registers.
Often this is done earlier, but not always in find_reloads_address. */
if (in != 0 && GET_CODE (in) == REG)
{
- register int regno = REGNO (in);
+ int regno = REGNO (in);
if (regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] < 0
&& reg_equiv_constant[regno] != 0)
@@ -925,7 +895,7 @@ push_reload (in, out, inloc, outloc, class,
(in the case of a parameter). */
if (out != 0 && GET_CODE (out) == REG)
{
- register int regno = REGNO (out);
+ int regno = REGNO (out);
if (regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] < 0
&& reg_equiv_constant[regno] != 0)
@@ -935,14 +905,19 @@ push_reload (in, out, inloc, outloc, class,
/* If we have a read-write operand with an address side-effect,
change either IN or OUT so the side-effect happens only once. */
if (in != 0 && out != 0 && GET_CODE (in) == MEM && rtx_equal_p (in, out))
- {
- if (GET_CODE (XEXP (in, 0)) == POST_INC
- || GET_CODE (XEXP (in, 0)) == POST_DEC)
- in = gen_rtx_MEM (GET_MODE (in), XEXP (XEXP (in, 0), 0));
- if (GET_CODE (XEXP (in, 0)) == PRE_INC
- || GET_CODE (XEXP (in, 0)) == PRE_DEC)
- out = gen_rtx_MEM (GET_MODE (out), XEXP (XEXP (out, 0), 0));
- }
+ switch (GET_CODE (XEXP (in, 0)))
+ {
+ case POST_INC: case POST_DEC: case POST_MODIFY:
+ in = replace_equiv_address_nv (in, XEXP (XEXP (in, 0), 0));
+ break;
+
+ case PRE_INC: case PRE_DEC: case PRE_MODIFY:
+ out = replace_equiv_address_nv (out, XEXP (XEXP (out, 0), 0));
+ break;
+
+ default:
+ break;
+ }
/* If we are reloading a (SUBREG constant ...), really reload just the
inside expression in its own mode. Similarly for (SUBREG (PLUS ...)).
@@ -969,15 +944,16 @@ push_reload (in, out, inloc, outloc, class,
Finally, reload the inner expression if it is a register that is in
the class whose registers cannot be referenced in a different size
- and M1 is not the same size as M2. If SUBREG_WORD is nonzero, we
+ and M1 is not the same size as M2. If subreg_lowpart_p is false, we
cannot reload just the inside since we might end up with the wrong
register class. But if it is inside a STRICT_LOW_PART, we have
no choice, so we hope we do get the right register class there. */
if (in != 0 && GET_CODE (in) == SUBREG
- && (SUBREG_WORD (in) == 0 || strict_low)
-#ifdef CLASS_CANNOT_CHANGE_SIZE
- && class != CLASS_CANNOT_CHANGE_SIZE
+ && (subreg_lowpart_p (in) || strict_low)
+#ifdef CLASS_CANNOT_CHANGE_MODE
+ && (class != CLASS_CANNOT_CHANGE_MODE
+ || ! CLASS_CANNOT_CHANGE_MODE_P (GET_MODE (SUBREG_REG (in)), inmode))
#endif
&& (CONSTANT_P (SUBREG_REG (in))
|| GET_CODE (SUBREG_REG (in)) == PLUS
@@ -1008,7 +984,7 @@ push_reload (in, out, inloc, outloc, class,
&& REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER
/* The case where out is nonzero
is handled differently in the following statement. */
- && (out == 0 || SUBREG_WORD (in) == 0)
+ && (out == 0 || subreg_lowpart_p (in))
&& ((GET_MODE_SIZE (inmode) <= UNITS_PER_WORD
&& (GET_MODE_SIZE (GET_MODE (SUBREG_REG (in)))
> UNITS_PER_WORD)
@@ -1016,9 +992,7 @@ push_reload (in, out, inloc, outloc, class,
/ UNITS_PER_WORD)
!= HARD_REGNO_NREGS (REGNO (SUBREG_REG (in)),
GET_MODE (SUBREG_REG (in)))))
- || ! HARD_REGNO_MODE_OK ((REGNO (SUBREG_REG (in))
- + SUBREG_WORD (in)),
- inmode)))
+ || ! HARD_REGNO_MODE_OK (subreg_regno (in), inmode)))
#ifdef SECONDARY_INPUT_RELOAD_CLASS
|| (SECONDARY_INPUT_RELOAD_CLASS (class, inmode, in) != NO_REGS
&& (SECONDARY_INPUT_RELOAD_CLASS (class,
@@ -1026,14 +1000,14 @@ push_reload (in, out, inloc, outloc, class,
SUBREG_REG (in))
== NO_REGS))
#endif
-#ifdef CLASS_CANNOT_CHANGE_SIZE
+#ifdef CLASS_CANNOT_CHANGE_MODE
|| (GET_CODE (SUBREG_REG (in)) == REG
&& REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER
&& (TEST_HARD_REG_BIT
- (reg_class_contents[(int) CLASS_CANNOT_CHANGE_SIZE],
+ (reg_class_contents[(int) CLASS_CANNOT_CHANGE_MODE],
REGNO (SUBREG_REG (in))))
- && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (in)))
- != GET_MODE_SIZE (inmode)))
+ && CLASS_CANNOT_CHANGE_MODE_P (GET_MODE (SUBREG_REG (in)),
+ inmode))
#endif
))
{
@@ -1058,31 +1032,27 @@ push_reload (in, out, inloc, outloc, class,
that case. */
/* Similar issue for (SUBREG constant ...) if it was not handled by the
- code above. This can happen if SUBREG_WORD != 0. */
+ code above. This can happen if SUBREG_BYTE != 0. */
- if (in != 0 && GET_CODE (in) == SUBREG
- && (CONSTANT_P (SUBREG_REG (in))
- || (GET_CODE (SUBREG_REG (in)) == REG
- && REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER
- && (! HARD_REGNO_MODE_OK (REGNO (SUBREG_REG (in))
- + SUBREG_WORD (in),
- inmode)
- || (GET_MODE_SIZE (inmode) <= UNITS_PER_WORD
- && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (in)))
- > UNITS_PER_WORD)
- && ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (in)))
- / UNITS_PER_WORD)
- != HARD_REGNO_NREGS (REGNO (SUBREG_REG (in)),
- GET_MODE (SUBREG_REG (in)))))))))
+ if (in != 0 && reload_inner_reg_of_subreg (in, inmode))
{
+ enum reg_class in_class = class;
+
+ if (GET_CODE (SUBREG_REG (in)) == REG)
+ in_class
+ = find_valid_class (inmode,
+ subreg_regno_offset (REGNO (SUBREG_REG (in)),
+ GET_MODE (SUBREG_REG (in)),
+ SUBREG_BYTE (in),
+ GET_MODE (in)));
+
/* This relies on the fact that emit_reload_insns outputs the
instructions for input reloads of type RELOAD_OTHER in the same
order as the reloads. Thus if the outer reload is also of type
RELOAD_OTHER, we are guaranteed that this inner reload will be
output before the outer reload. */
- push_reload (SUBREG_REG (in), NULL_RTX, &SUBREG_REG (in), NULL_PTR,
- find_valid_class (inmode, SUBREG_WORD (in)),
- VOIDmode, VOIDmode, 0, 0, opnum, type);
+ push_reload (SUBREG_REG (in), NULL_RTX, &SUBREG_REG (in), (rtx *) 0,
+ in_class, VOIDmode, VOIDmode, 0, 0, opnum, type);
dont_remove_subreg = 1;
}
@@ -1093,9 +1063,11 @@ push_reload (in, out, inloc, outloc, class,
(except in the case of STRICT_LOW_PART,
and in that case the constraint should label it input-output.) */
if (out != 0 && GET_CODE (out) == SUBREG
- && (SUBREG_WORD (out) == 0 || strict_low)
-#ifdef CLASS_CANNOT_CHANGE_SIZE
- && class != CLASS_CANNOT_CHANGE_SIZE
+ && (subreg_lowpart_p (out) || strict_low)
+#ifdef CLASS_CANNOT_CHANGE_MODE
+ && (class != CLASS_CANNOT_CHANGE_MODE
+ || ! CLASS_CANNOT_CHANGE_MODE_P (GET_MODE (SUBREG_REG (out)),
+ outmode))
#endif
&& (CONSTANT_P (SUBREG_REG (out))
|| strict_low
@@ -1111,7 +1083,7 @@ push_reload (in, out, inloc, outloc, class,
((GET_MODE_SIZE (GET_MODE (SUBREG_REG (out))) - 1)
/ UNITS_PER_WORD)))
#endif
- ))
+ ))
|| (GET_CODE (SUBREG_REG (out)) == REG
&& REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER
&& ((GET_MODE_SIZE (outmode) <= UNITS_PER_WORD
@@ -1121,9 +1093,7 @@ push_reload (in, out, inloc, outloc, class,
/ UNITS_PER_WORD)
!= HARD_REGNO_NREGS (REGNO (SUBREG_REG (out)),
GET_MODE (SUBREG_REG (out)))))
- || ! HARD_REGNO_MODE_OK ((REGNO (SUBREG_REG (out))
- + SUBREG_WORD (out)),
- outmode)))
+ || ! HARD_REGNO_MODE_OK (subreg_regno (out), outmode)))
#ifdef SECONDARY_OUTPUT_RELOAD_CLASS
|| (SECONDARY_OUTPUT_RELOAD_CLASS (class, outmode, out) != NO_REGS
&& (SECONDARY_OUTPUT_RELOAD_CLASS (class,
@@ -1131,22 +1101,22 @@ push_reload (in, out, inloc, outloc, class,
SUBREG_REG (out))
== NO_REGS))
#endif
-#ifdef CLASS_CANNOT_CHANGE_SIZE
+#ifdef CLASS_CANNOT_CHANGE_MODE
|| (GET_CODE (SUBREG_REG (out)) == REG
&& REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER
&& (TEST_HARD_REG_BIT
- (reg_class_contents[(int) CLASS_CANNOT_CHANGE_SIZE],
+ (reg_class_contents[(int) CLASS_CANNOT_CHANGE_MODE],
REGNO (SUBREG_REG (out))))
- && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (out)))
- != GET_MODE_SIZE (outmode)))
+ && CLASS_CANNOT_CHANGE_MODE_P (GET_MODE (SUBREG_REG (out)),
+ outmode))
#endif
))
{
out_subreg_loc = outloc;
outloc = &SUBREG_REG (out);
- out = *outloc;
+ out = *outloc;
#if ! defined (LOAD_EXTEND_OP) && ! defined (WORD_REGISTER_OPERATIONS)
- if (GET_CODE (out) == MEM
+ if (GET_CODE (out) == MEM
&& GET_MODE_SIZE (GET_MODE (out)) > GET_MODE_SIZE (outmode))
abort ();
#endif
@@ -1160,18 +1130,7 @@ push_reload (in, out, inloc, outloc, class,
However, we must reload the inner reg *as well as* the subreg in
that case. In this case, the inner reg is an in-out reload. */
- if (out != 0 && GET_CODE (out) == SUBREG
- && GET_CODE (SUBREG_REG (out)) == REG
- && REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER
- && (! HARD_REGNO_MODE_OK (REGNO (SUBREG_REG (out)) + SUBREG_WORD (out),
- outmode)
- || (GET_MODE_SIZE (outmode) <= UNITS_PER_WORD
- && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (out)))
- > UNITS_PER_WORD)
- && ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (out)))
- / UNITS_PER_WORD)
- != HARD_REGNO_NREGS (REGNO (SUBREG_REG (out)),
- GET_MODE (SUBREG_REG (out)))))))
+ if (out != 0 && reload_inner_reg_of_subreg (out, outmode))
{
/* This relies on the fact that emit_reload_insns outputs the
instructions for output reloads of type RELOAD_OTHER in reverse
@@ -1181,7 +1140,11 @@ push_reload (in, out, inloc, outloc, class,
dont_remove_subreg = 1;
push_reload (SUBREG_REG (out), SUBREG_REG (out), &SUBREG_REG (out),
&SUBREG_REG (out),
- find_valid_class (outmode, SUBREG_WORD (out)),
+ find_valid_class (outmode,
+ subreg_regno_offset (REGNO (SUBREG_REG (out)),
+ GET_MODE (SUBREG_REG (out)),
+ SUBREG_BYTE (out),
+ GET_MODE (out))),
VOIDmode, VOIDmode, 0, 0,
opnum, RELOAD_OTHER);
}
@@ -1198,16 +1161,14 @@ push_reload (in, out, inloc, outloc, class,
if (in != 0 && GET_CODE (in) == SUBREG && GET_CODE (SUBREG_REG (in)) == REG
&& REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER
&& ! dont_remove_subreg)
- in = gen_rtx_REG (GET_MODE (in),
- REGNO (SUBREG_REG (in)) + SUBREG_WORD (in));
+ in = gen_rtx_REG (GET_MODE (in), subreg_regno (in));
/* Similarly for OUT. */
if (out != 0 && GET_CODE (out) == SUBREG
&& GET_CODE (SUBREG_REG (out)) == REG
&& REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER
&& ! dont_remove_subreg)
- out = gen_rtx_REG (GET_MODE (out),
- REGNO (SUBREG_REG (out)) + SUBREG_WORD (out));
+ out = gen_rtx_REG (GET_MODE (out), subreg_regno (out));
/* Narrow down the class of register wanted if that is
desirable on this machine for efficiency. */
@@ -1311,30 +1272,29 @@ push_reload (in, out, inloc, outloc, class,
if (in != 0 && GET_CODE (in) == REG
&& REGNO (in) < FIRST_PSEUDO_REGISTER
&& SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (REGNO (in)),
- class, inmode))
+ class, inmode))
get_secondary_mem (in, inmode, opnum, type);
#endif
i = n_reloads;
- reload_in[i] = in;
- reload_out[i] = out;
- reload_reg_class[i] = class;
- reload_inmode[i] = inmode;
- reload_outmode[i] = outmode;
- reload_reg_rtx[i] = 0;
- reload_optional[i] = optional;
- reload_nongroup[i] = 0;
- reload_inc[i] = 0;
- reload_nocombine[i] = 0;
- reload_in_reg[i] = inloc ? *inloc : 0;
- reload_out_reg[i] = outloc ? *outloc : 0;
- reload_opnum[i] = opnum;
- reload_when_needed[i] = type;
- reload_secondary_in_reload[i] = secondary_in_reload;
- reload_secondary_out_reload[i] = secondary_out_reload;
- reload_secondary_in_icode[i] = secondary_in_icode;
- reload_secondary_out_icode[i] = secondary_out_icode;
- reload_secondary_p[i] = 0;
+ rld[i].in = in;
+ rld[i].out = out;
+ rld[i].class = class;
+ rld[i].inmode = inmode;
+ rld[i].outmode = outmode;
+ rld[i].reg_rtx = 0;
+ rld[i].optional = optional;
+ rld[i].inc = 0;
+ rld[i].nocombine = 0;
+ rld[i].in_reg = inloc ? *inloc : 0;
+ rld[i].out_reg = outloc ? *outloc : 0;
+ rld[i].opnum = opnum;
+ rld[i].when_needed = type;
+ rld[i].secondary_in_reload = secondary_in_reload;
+ rld[i].secondary_out_reload = secondary_out_reload;
+ rld[i].secondary_in_icode = secondary_in_icode;
+ rld[i].secondary_out_icode = secondary_out_icode;
+ rld[i].secondary_p = 0;
n_reloads++;
@@ -1356,11 +1316,11 @@ push_reload (in, out, inloc, outloc, class,
/* The modes can be different. If they are, we want to reload in
the larger mode, so that the value is valid for both modes. */
if (inmode != VOIDmode
- && GET_MODE_SIZE (inmode) > GET_MODE_SIZE (reload_inmode[i]))
- reload_inmode[i] = inmode;
+ && GET_MODE_SIZE (inmode) > GET_MODE_SIZE (rld[i].inmode))
+ rld[i].inmode = inmode;
if (outmode != VOIDmode
- && GET_MODE_SIZE (outmode) > GET_MODE_SIZE (reload_outmode[i]))
- reload_outmode[i] = outmode;
+ && GET_MODE_SIZE (outmode) > GET_MODE_SIZE (rld[i].outmode))
+ rld[i].outmode = outmode;
if (in != 0)
{
rtx in_reg = inloc ? *inloc : 0;
@@ -1378,43 +1338,43 @@ push_reload (in, out, inloc, outloc, class,
choose_reload_regs will remove the replacements for address
reloads of inherited reloads which results in the same
problem. */
- if (reload_in[i] != in && rtx_equal_p (in, reload_in[i])
- && ! (reload_optional[i] && optional))
+ if (rld[i].in != in && rtx_equal_p (in, rld[i].in)
+ && ! (rld[i].optional && optional))
{
/* We must keep the address reload with the lower operand
number alive. */
- if (opnum > reload_opnum[i])
+ if (opnum > rld[i].opnum)
{
remove_address_replacements (in);
- in = reload_in[i];
- in_reg = reload_in_reg[i];
+ in = rld[i].in;
+ in_reg = rld[i].in_reg;
}
else
- remove_address_replacements (reload_in[i]);
+ remove_address_replacements (rld[i].in);
}
- reload_in[i] = in;
- reload_in_reg[i] = in_reg;
+ rld[i].in = in;
+ rld[i].in_reg = in_reg;
}
if (out != 0)
{
- reload_out[i] = out;
- reload_out_reg[i] = outloc ? *outloc : 0;
+ rld[i].out = out;
+ rld[i].out_reg = outloc ? *outloc : 0;
}
- if (reg_class_subset_p (class, reload_reg_class[i]))
- reload_reg_class[i] = class;
- reload_optional[i] &= optional;
- if (MERGE_TO_OTHER (type, reload_when_needed[i],
- opnum, reload_opnum[i]))
- reload_when_needed[i] = RELOAD_OTHER;
- reload_opnum[i] = MIN (reload_opnum[i], opnum);
+ if (reg_class_subset_p (class, rld[i].class))
+ rld[i].class = class;
+ rld[i].optional &= optional;
+ if (MERGE_TO_OTHER (type, rld[i].when_needed,
+ opnum, rld[i].opnum))
+ rld[i].when_needed = RELOAD_OTHER;
+ rld[i].opnum = MIN (rld[i].opnum, opnum);
}
- /* If the ostensible rtx being reload differs from the rtx found
+ /* If the ostensible rtx being reloaded differs from the rtx found
in the location to substitute, this reload is not safe to combine
because we cannot reliably tell whether it appears in the insn. */
if (in != 0 && in != *inloc)
- reload_nocombine[i] = 1;
+ rld[i].nocombine = 1;
#if 0
/* This was replaced by changes in find_reloads_address_1 and the new
@@ -1428,12 +1388,12 @@ push_reload (in, out, inloc, outloc, class,
if (out != 0 && sets_cc0_p (PATTERN (this_insn)))
{
out = 0;
- reload_out[i] = 0;
- reload_inc[i] = find_inc_amount (PATTERN (this_insn), in);
+ rld[i].out = 0;
+ rld[i].inc = find_inc_amount (PATTERN (this_insn), in);
/* If we did not find a nonzero amount-to-increment-by,
that contradicts the belief that IN is being incremented
in an address in this insn. */
- if (reload_inc[i] == 0)
+ if (rld[i].inc == 0)
abort ();
}
#endif
@@ -1446,7 +1406,7 @@ push_reload (in, out, inloc, outloc, class,
{
if (inloc != 0)
{
- register struct replacement *r = &replacements[n_replacements++];
+ struct replacement *r = &replacements[n_replacements++];
r->what = i;
r->subreg_loc = in_subreg_loc;
r->where = inloc;
@@ -1454,7 +1414,7 @@ push_reload (in, out, inloc, outloc, class,
}
if (outloc != 0 && outloc != inloc)
{
- register struct replacement *r = &replacements[n_replacements++];
+ struct replacement *r = &replacements[n_replacements++];
r->what = i;
r->where = outloc;
r->subreg_loc = out_subreg_loc;
@@ -1467,25 +1427,25 @@ push_reload (in, out, inloc, outloc, class,
supposed to be made to match, see if either one of the two
can serve as the place to reload into.
- If one of them is acceptable, set reload_reg_rtx[i]
+ If one of them is acceptable, set rld[i].reg_rtx
to that one. */
- if (in != 0 && out != 0 && in != out && reload_reg_rtx[i] == 0)
+ if (in != 0 && out != 0 && in != out && rld[i].reg_rtx == 0)
{
- reload_reg_rtx[i] = find_dummy_reload (in, out, inloc, outloc,
- inmode, outmode,
- reload_reg_class[i], i,
- earlyclobber_operand_p (out));
+ rld[i].reg_rtx = find_dummy_reload (in, out, inloc, outloc,
+ inmode, outmode,
+ rld[i].class, i,
+ earlyclobber_operand_p (out));
/* If the outgoing register already contains the same value
as the incoming one, we can dispense with loading it.
The easiest way to tell the caller that is to give a phony
value for the incoming operand (same as outgoing one). */
- if (reload_reg_rtx[i] == out
+ if (rld[i].reg_rtx == out
&& (GET_CODE (in) == REG || CONSTANT_P (in))
&& 0 != find_equiv_reg (in, this_insn, 0, REGNO (out),
static_reload_reg_p, i, inmode))
- reload_in[i] = out;
+ rld[i].in = out;
}
/* If this is an input reload and the operand contains a register that
@@ -1500,10 +1460,14 @@ push_reload (in, out, inloc, outloc, class,
But if there is no spilling in this block, that is OK.
An explicitly used hard reg cannot be a spill reg. */
- if (reload_reg_rtx[i] == 0 && in != 0)
+ if (rld[i].reg_rtx == 0 && in != 0)
{
rtx note;
int regno;
+ enum machine_mode rel_mode = inmode;
+
+ if (out && GET_MODE_SIZE (outmode) > GET_MODE_SIZE (inmode))
+ rel_mode = outmode;
for (note = REG_NOTES (this_insn); note; note = XEXP (note, 1))
if (REG_NOTE_KIND (note) == REG_DEAD
@@ -1513,7 +1477,7 @@ push_reload (in, out, inloc, outloc, class,
&& ! refers_to_regno_for_reload_p (regno,
(regno
+ HARD_REGNO_NREGS (regno,
- inmode)),
+ rel_mode)),
PATTERN (this_insn), inloc)
/* If this is also an output reload, IN cannot be used as
the reload register if it is set in this insn unless IN
@@ -1522,7 +1486,7 @@ push_reload (in, out, inloc, outloc, class,
|| ! hard_reg_set_here_p (regno,
(regno
+ HARD_REGNO_NREGS (regno,
- inmode)),
+ rel_mode)),
PATTERN (this_insn)))
/* ??? Why is this code so different from the previous?
Is there any simple coherent way to describe the two together?
@@ -1534,9 +1498,9 @@ push_reload (in, out, inloc, outloc, class,
== ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (in)))
+ (UNITS_PER_WORD - 1)) / UNITS_PER_WORD))))
/* Make sure the operand fits in the reg that dies. */
- && GET_MODE_SIZE (inmode) <= GET_MODE_SIZE (GET_MODE (XEXP (note, 0)))
+ && (GET_MODE_SIZE (rel_mode)
+ <= GET_MODE_SIZE (GET_MODE (XEXP (note, 0))))
&& HARD_REGNO_MODE_OK (regno, inmode)
- && GET_MODE_SIZE (outmode) <= GET_MODE_SIZE (GET_MODE (XEXP (note, 0)))
&& HARD_REGNO_MODE_OK (regno, outmode))
{
unsigned int offs;
@@ -1551,7 +1515,7 @@ push_reload (in, out, inloc, outloc, class,
if (offs == nregs)
{
- reload_reg_rtx[i] = gen_rtx_REG (inmode, regno);
+ rld[i].reg_rtx = gen_rtx_REG (rel_mode, regno);
break;
}
}
@@ -1577,7 +1541,7 @@ push_replacement (loc, reloadnum, mode)
{
if (replace_reloads)
{
- register struct replacement *r = &replacements[n_replacements++];
+ struct replacement *r = &replacements[n_replacements++];
r->what = reloadnum;
r->where = loc;
r->subreg_loc = 0;
@@ -1611,7 +1575,7 @@ remove_address_replacements (in_rtx)
char reload_flags[MAX_RELOADS];
int something_changed = 0;
- bzero (reload_flags, sizeof reload_flags);
+ memset (reload_flags, 0, sizeof reload_flags);
for (i = 0, j = 0; i < n_replacements; i++)
{
if (loc_mentioned_in_p (replacements[i].where, in_rtx))
@@ -1630,39 +1594,13 @@ remove_address_replacements (in_rtx)
if (reload_flags[i] == 1)
{
deallocate_reload_reg (i);
- remove_address_replacements (reload_in[i]);
- reload_in[i] = 0;
+ remove_address_replacements (rld[i].in);
+ rld[i].in = 0;
something_changed = 1;
}
}
return something_changed;
}
-
-/* Return non-zero if IN contains a piece of rtl that has the address LOC */
-static int
-loc_mentioned_in_p (loc, in)
- rtx *loc, in;
-{
- enum rtx_code code = GET_CODE (in);
- char *fmt = GET_RTX_FORMAT (code);
- int i, j;
-
- for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
- {
- if (loc == &XEXP (in, i))
- return 1;
- if (fmt[i] == 'e')
- {
- if (loc_mentioned_in_p (loc, XEXP (in, i)))
- return 1;
- }
- else if (fmt[i] == 'E')
- for (j = XVECLEN (in, i) - 1; i >= 0; i--)
- if (loc_mentioned_in_p (loc, XVECEXP (in, i, j)))
- return 1;
- }
- return 0;
-}
/* If there is only one output reload, and it is not for an earlyclobber
operand, try to combine it with a (logically unrelated) input reload
@@ -1688,103 +1626,114 @@ combine_reloads ()
and that one is mandatory. */
for (i = 0; i < n_reloads; i++)
- if (reload_out[i] != 0)
+ if (rld[i].out != 0)
{
if (output_reload >= 0)
return;
output_reload = i;
}
- if (output_reload < 0 || reload_optional[output_reload])
+ if (output_reload < 0 || rld[output_reload].optional)
return;
/* An input-output reload isn't combinable. */
- if (reload_in[output_reload] != 0)
+ if (rld[output_reload].in != 0)
return;
/* If this reload is for an earlyclobber operand, we can't do anything. */
- if (earlyclobber_operand_p (reload_out[output_reload]))
+ if (earlyclobber_operand_p (rld[output_reload].out))
return;
+ /* If there is a reload for part of the address of this operand, we would
+ need to chnage it to RELOAD_FOR_OTHER_ADDRESS. But that would extend
+ its life to the point where doing this combine would not lower the
+ number of spill registers needed. */
+ for (i = 0; i < n_reloads; i++)
+ if ((rld[i].when_needed == RELOAD_FOR_OUTPUT_ADDRESS
+ || rld[i].when_needed == RELOAD_FOR_OUTADDR_ADDRESS)
+ && rld[i].opnum == rld[output_reload].opnum)
+ return;
+
/* Check each input reload; can we combine it? */
for (i = 0; i < n_reloads; i++)
- if (reload_in[i] && ! reload_optional[i] && ! reload_nocombine[i]
+ if (rld[i].in && ! rld[i].optional && ! rld[i].nocombine
/* Life span of this reload must not extend past main insn. */
- && reload_when_needed[i] != RELOAD_FOR_OUTPUT_ADDRESS
- && reload_when_needed[i] != RELOAD_FOR_OUTADDR_ADDRESS
- && reload_when_needed[i] != RELOAD_OTHER
- && (CLASS_MAX_NREGS (reload_reg_class[i], reload_inmode[i])
- == CLASS_MAX_NREGS (reload_reg_class[output_reload],
- reload_outmode[output_reload]))
- && reload_inc[i] == 0
- && reload_reg_rtx[i] == 0
+ && rld[i].when_needed != RELOAD_FOR_OUTPUT_ADDRESS
+ && rld[i].when_needed != RELOAD_FOR_OUTADDR_ADDRESS
+ && rld[i].when_needed != RELOAD_OTHER
+ && (CLASS_MAX_NREGS (rld[i].class, rld[i].inmode)
+ == CLASS_MAX_NREGS (rld[output_reload].class,
+ rld[output_reload].outmode))
+ && rld[i].inc == 0
+ && rld[i].reg_rtx == 0
#ifdef SECONDARY_MEMORY_NEEDED
/* Don't combine two reloads with different secondary
memory locations. */
- && (secondary_memlocs_elim[(int) reload_outmode[output_reload]][reload_opnum[i]] == 0
- || secondary_memlocs_elim[(int) reload_outmode[output_reload]][reload_opnum[output_reload]] == 0
- || rtx_equal_p (secondary_memlocs_elim[(int) reload_outmode[output_reload]][reload_opnum[i]],
- secondary_memlocs_elim[(int) reload_outmode[output_reload]][reload_opnum[output_reload]]))
+ && (secondary_memlocs_elim[(int) rld[output_reload].outmode][rld[i].opnum] == 0
+ || secondary_memlocs_elim[(int) rld[output_reload].outmode][rld[output_reload].opnum] == 0
+ || rtx_equal_p (secondary_memlocs_elim[(int) rld[output_reload].outmode][rld[i].opnum],
+ secondary_memlocs_elim[(int) rld[output_reload].outmode][rld[output_reload].opnum]))
#endif
&& (SMALL_REGISTER_CLASSES
- ? (reload_reg_class[i] == reload_reg_class[output_reload])
- : (reg_class_subset_p (reload_reg_class[i],
- reload_reg_class[output_reload])
- || reg_class_subset_p (reload_reg_class[output_reload],
- reload_reg_class[i])))
- && (MATCHES (reload_in[i], reload_out[output_reload])
+ ? (rld[i].class == rld[output_reload].class)
+ : (reg_class_subset_p (rld[i].class,
+ rld[output_reload].class)
+ || reg_class_subset_p (rld[output_reload].class,
+ rld[i].class)))
+ && (MATCHES (rld[i].in, rld[output_reload].out)
/* Args reversed because the first arg seems to be
the one that we imagine being modified
while the second is the one that might be affected. */
- || (! reg_overlap_mentioned_for_reload_p (reload_out[output_reload],
- reload_in[i])
+ || (! reg_overlap_mentioned_for_reload_p (rld[output_reload].out,
+ rld[i].in)
/* However, if the input is a register that appears inside
the output, then we also can't share.
Imagine (set (mem (reg 69)) (plus (reg 69) ...)).
If the same reload reg is used for both reg 69 and the
result to be stored in memory, then that result
will clobber the address of the memory ref. */
- && ! (GET_CODE (reload_in[i]) == REG
- && reg_overlap_mentioned_for_reload_p (reload_in[i],
- reload_out[output_reload]))))
- && (reg_class_size[(int) reload_reg_class[i]]
+ && ! (GET_CODE (rld[i].in) == REG
+ && reg_overlap_mentioned_for_reload_p (rld[i].in,
+ rld[output_reload].out))))
+ && ! reload_inner_reg_of_subreg (rld[i].in, rld[i].inmode)
+ && (reg_class_size[(int) rld[i].class]
|| SMALL_REGISTER_CLASSES)
/* We will allow making things slightly worse by combining an
input and an output, but no worse than that. */
- && (reload_when_needed[i] == RELOAD_FOR_INPUT
- || reload_when_needed[i] == RELOAD_FOR_OUTPUT))
+ && (rld[i].when_needed == RELOAD_FOR_INPUT
+ || rld[i].when_needed == RELOAD_FOR_OUTPUT))
{
int j;
/* We have found a reload to combine with! */
- reload_out[i] = reload_out[output_reload];
- reload_out_reg[i] = reload_out_reg[output_reload];
- reload_outmode[i] = reload_outmode[output_reload];
+ rld[i].out = rld[output_reload].out;
+ rld[i].out_reg = rld[output_reload].out_reg;
+ rld[i].outmode = rld[output_reload].outmode;
/* Mark the old output reload as inoperative. */
- reload_out[output_reload] = 0;
+ rld[output_reload].out = 0;
/* The combined reload is needed for the entire insn. */
- reload_when_needed[i] = RELOAD_OTHER;
+ rld[i].when_needed = RELOAD_OTHER;
/* If the output reload had a secondary reload, copy it. */
- if (reload_secondary_out_reload[output_reload] != -1)
+ if (rld[output_reload].secondary_out_reload != -1)
{
- reload_secondary_out_reload[i]
- = reload_secondary_out_reload[output_reload];
- reload_secondary_out_icode[i]
- = reload_secondary_out_icode[output_reload];
+ rld[i].secondary_out_reload
+ = rld[output_reload].secondary_out_reload;
+ rld[i].secondary_out_icode
+ = rld[output_reload].secondary_out_icode;
}
#ifdef SECONDARY_MEMORY_NEEDED
/* Copy any secondary MEM. */
- if (secondary_memlocs_elim[(int) reload_outmode[output_reload]][reload_opnum[output_reload]] != 0)
- secondary_memlocs_elim[(int) reload_outmode[output_reload]][reload_opnum[i]]
- = secondary_memlocs_elim[(int) reload_outmode[output_reload]][reload_opnum[output_reload]];
+ if (secondary_memlocs_elim[(int) rld[output_reload].outmode][rld[output_reload].opnum] != 0)
+ secondary_memlocs_elim[(int) rld[output_reload].outmode][rld[i].opnum]
+ = secondary_memlocs_elim[(int) rld[output_reload].outmode][rld[output_reload].opnum];
#endif
/* If required, minimize the register class. */
- if (reg_class_subset_p (reload_reg_class[output_reload],
- reload_reg_class[i]))
- reload_reg_class[i] = reload_reg_class[output_reload];
+ if (reg_class_subset_p (rld[output_reload].class,
+ rld[i].class))
+ rld[i].class = rld[output_reload].class;
/* Transfer all replacements from the old reload to the combined. */
for (j = 0; j < n_replacements; j++)
@@ -1803,9 +1752,9 @@ combine_reloads ()
if (INSN_CODE (this_insn) == -1)
return;
- for (i = 1; i < insn_n_operands[INSN_CODE (this_insn)]; i++)
- if (insn_operand_constraint[INSN_CODE (this_insn)][i][0] == '='
- || insn_operand_constraint[INSN_CODE (this_insn)][i][0] == '+')
+ for (i = 1; i < insn_data[INSN_CODE (this_insn)].n_operands; i++)
+ if (insn_data[INSN_CODE (this_insn)].operand[i].constraint[0] == '='
+ || insn_data[INSN_CODE (this_insn)].operand[i].constraint[0] == '+')
return;
/* See if some hard register that dies in this insn and is not used in
@@ -1815,27 +1764,27 @@ combine_reloads ()
if (REG_NOTE_KIND (note) == REG_DEAD
&& GET_CODE (XEXP (note, 0)) == REG
&& ! reg_overlap_mentioned_for_reload_p (XEXP (note, 0),
- reload_out[output_reload])
+ rld[output_reload].out)
&& REGNO (XEXP (note, 0)) < FIRST_PSEUDO_REGISTER
- && HARD_REGNO_MODE_OK (REGNO (XEXP (note, 0)), reload_outmode[output_reload])
- && TEST_HARD_REG_BIT (reg_class_contents[(int) reload_reg_class[output_reload]],
+ && HARD_REGNO_MODE_OK (REGNO (XEXP (note, 0)), rld[output_reload].outmode)
+ && TEST_HARD_REG_BIT (reg_class_contents[(int) rld[output_reload].class],
REGNO (XEXP (note, 0)))
- && (HARD_REGNO_NREGS (REGNO (XEXP (note, 0)), reload_outmode[output_reload])
+ && (HARD_REGNO_NREGS (REGNO (XEXP (note, 0)), rld[output_reload].outmode)
<= HARD_REGNO_NREGS (REGNO (XEXP (note, 0)), GET_MODE (XEXP (note, 0))))
/* Ensure that a secondary or tertiary reload for this output
won't want this register. */
- && ((secondary_out = reload_secondary_out_reload[output_reload]) == -1
- || (! (TEST_HARD_REG_BIT
- (reg_class_contents[(int) reload_reg_class[secondary_out]],
- REGNO (XEXP (note, 0))))
- && ((secondary_out = reload_secondary_out_reload[secondary_out]) == -1
+ && ((secondary_out = rld[output_reload].secondary_out_reload) == -1
+ || (! (TEST_HARD_REG_BIT
+ (reg_class_contents[(int) rld[secondary_out].class],
+ REGNO (XEXP (note, 0))))
+ && ((secondary_out = rld[secondary_out].secondary_out_reload) == -1
|| ! (TEST_HARD_REG_BIT
- (reg_class_contents[(int) reload_reg_class[secondary_out]],
+ (reg_class_contents[(int) rld[secondary_out].class],
REGNO (XEXP (note, 0)))))))
&& ! fixed_regs[REGNO (XEXP (note, 0))])
{
- reload_reg_rtx[output_reload]
- = gen_rtx_REG (reload_outmode[output_reload],
+ rld[output_reload].reg_rtx
+ = gen_rtx_REG (rld[output_reload].outmode,
REGNO (XEXP (note, 0)));
return;
}
@@ -1851,7 +1800,7 @@ combine_reloads ()
If FOR_REAL is >= 0, it is the number of the reload,
and in some cases when it can be discovered that OUT doesn't need
- to be computed, clear out reload_out[FOR_REAL].
+ to be computed, clear out rld[FOR_REAL].out.
If FOR_REAL is -1, this should not be done, because this call
is just to see if a register can be found, not to find and install it.
@@ -1884,15 +1833,28 @@ find_dummy_reload (real_in, real_out, inloc, outloc,
|| GET_MODE_SIZE (inmode) > UNITS_PER_WORD))
return 0;
+ /* Note that {in,out}_offset are needed only when 'in' or 'out'
+ respectively refers to a hard register. */
+
/* Find the inside of any subregs. */
while (GET_CODE (out) == SUBREG)
{
- out_offset = SUBREG_WORD (out);
+ if (GET_CODE (SUBREG_REG (out)) == REG
+ && REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER)
+ out_offset += subreg_regno_offset (REGNO (SUBREG_REG (out)),
+ GET_MODE (SUBREG_REG (out)),
+ SUBREG_BYTE (out),
+ GET_MODE (out));
out = SUBREG_REG (out);
}
while (GET_CODE (in) == SUBREG)
{
- in_offset = SUBREG_WORD (in);
+ if (GET_CODE (SUBREG_REG (in)) == REG
+ && REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER)
+ in_offset += subreg_regno_offset (REGNO (SUBREG_REG (in)),
+ GET_MODE (SUBREG_REG (in)),
+ SUBREG_BYTE (in),
+ GET_MODE (in));
in = SUBREG_REG (in);
}
@@ -1904,8 +1866,8 @@ find_dummy_reload (real_in, real_out, inloc, outloc,
if (GET_CODE (out) == REG
&& REGNO (out) < FIRST_PSEUDO_REGISTER)
{
- register int regno = REGNO (out) + out_offset;
- int nwords = HARD_REGNO_NREGS (regno, outmode);
+ unsigned int regno = REGNO (out) + out_offset;
+ unsigned int nwords = HARD_REGNO_NREGS (regno, outmode);
rtx saved_rtx;
/* When we consider whether the insn uses OUT,
@@ -1921,15 +1883,11 @@ find_dummy_reload (real_in, real_out, inloc, outloc,
*inloc = const0_rtx;
if (regno < FIRST_PSEUDO_REGISTER
- /* A fixed reg that can overlap other regs better not be used
- for reloading in any way. */
-#ifdef OVERLAPPING_REGNO_P
- && ! (fixed_regs[regno] && OVERLAPPING_REGNO_P (regno))
-#endif
&& ! refers_to_regno_for_reload_p (regno, regno + nwords,
PATTERN (this_insn), outloc))
{
- int i;
+ unsigned int i;
+
for (i = 0; i < nwords; i++)
if (! TEST_HARD_REG_BIT (reg_class_contents[(int) class],
regno + i))
@@ -1968,17 +1926,18 @@ find_dummy_reload (real_in, real_out, inloc, outloc,
(GET_MODE (out) != VOIDmode
? GET_MODE (out) : outmode)))
{
- register int regno = REGNO (in) + in_offset;
- int nwords = HARD_REGNO_NREGS (regno, inmode);
+ unsigned int regno = REGNO (in) + in_offset;
+ unsigned int nwords = HARD_REGNO_NREGS (regno, inmode);
- if (! refers_to_regno_for_reload_p (regno, regno + nwords, out, NULL_PTR)
+ if (! refers_to_regno_for_reload_p (regno, regno + nwords, out, (rtx*) 0)
&& ! hard_reg_set_here_p (regno, regno + nwords,
PATTERN (this_insn))
&& (! earlyclobber
|| ! refers_to_regno_for_reload_p (regno, regno + nwords,
PATTERN (this_insn), inloc)))
{
- int i;
+ unsigned int i;
+
for (i = 0; i < nwords; i++)
if (! TEST_HARD_REG_BIT (reg_class_contents[(int) class],
regno + i))
@@ -1990,7 +1949,7 @@ find_dummy_reload (real_in, real_out, inloc, outloc,
and changed our mind, it means OUT is a dummy that
dies here. So don't bother copying value to it. */
if (for_real >= 0 && value == real_out)
- reload_out[for_real] = 0;
+ rld[for_real].out = 0;
if (GET_CODE (real_in) == REG)
value = real_in;
else
@@ -2028,17 +1987,19 @@ earlyclobber_operand_p (x)
static int
hard_reg_set_here_p (beg_regno, end_regno, x)
- register int beg_regno, end_regno;
+ unsigned int beg_regno, end_regno;
rtx x;
{
if (GET_CODE (x) == SET || GET_CODE (x) == CLOBBER)
{
- register rtx op0 = SET_DEST (x);
+ rtx op0 = SET_DEST (x);
+
while (GET_CODE (op0) == SUBREG)
op0 = SUBREG_REG (op0);
if (GET_CODE (op0) == REG)
{
- register int r = REGNO (op0);
+ unsigned int r = REGNO (op0);
+
/* See if this reg overlaps range under consideration. */
if (r < end_regno
&& r + HARD_REGNO_NREGS (r, GET_MODE (op0)) > beg_regno)
@@ -2047,7 +2008,8 @@ hard_reg_set_here_p (beg_regno, end_regno, x)
}
else if (GET_CODE (x) == PARALLEL)
{
- register int i = XVECLEN (x, 0) - 1;
+ int i = XVECLEN (x, 0) - 1;
+
for (; i >= 0; i--)
if (hard_reg_set_here_p (beg_regno, end_regno, XVECEXP (x, 0, i)))
return 1;
@@ -2062,8 +2024,8 @@ hard_reg_set_here_p (beg_regno, end_regno, x)
int
strict_memory_address_p (mode, addr)
- enum machine_mode mode;
- register rtx addr;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+ rtx addr;
{
GO_IF_LEGITIMATE_ADDRESS (mode, addr, win);
return 0;
@@ -2089,27 +2051,30 @@ strict_memory_address_p (mode, addr)
int
operands_match_p (x, y)
- register rtx x, y;
+ rtx x, y;
{
- register int i;
- register RTX_CODE code = GET_CODE (x);
- register char *fmt;
+ int i;
+ RTX_CODE code = GET_CODE (x);
+ const char *fmt;
int success_2;
-
+
if (x == y)
return 1;
if ((code == REG || (code == SUBREG && GET_CODE (SUBREG_REG (x)) == REG))
&& (GET_CODE (y) == REG || (GET_CODE (y) == SUBREG
&& GET_CODE (SUBREG_REG (y)) == REG)))
{
- register int j;
+ int j;
if (code == SUBREG)
{
i = REGNO (SUBREG_REG (x));
if (i >= FIRST_PSEUDO_REGISTER)
goto slow;
- i += SUBREG_WORD (x);
+ i += subreg_regno_offset (REGNO (SUBREG_REG (x)),
+ GET_MODE (SUBREG_REG (x)),
+ SUBREG_BYTE (x),
+ GET_MODE (x));
}
else
i = REGNO (x);
@@ -2119,7 +2084,10 @@ operands_match_p (x, y)
j = REGNO (SUBREG_REG (y));
if (j >= FIRST_PSEUDO_REGISTER)
goto slow;
- j += SUBREG_WORD (y);
+ j += subreg_regno_offset (REGNO (SUBREG_REG (y)),
+ GET_MODE (SUBREG_REG (y)),
+ SUBREG_BYTE (y),
+ GET_MODE (y));
}
else
j = REGNO (y);
@@ -2141,7 +2109,7 @@ operands_match_p (x, y)
because the assembler insn would increment only once.
On the other hand, an postincrement matches ordinary indexing
if the postincrement is the output operand. */
- if (code == POST_DEC || code == POST_INC)
+ if (code == POST_DEC || code == POST_INC || code == POST_MODIFY)
return operands_match_p (XEXP (x, 0), y);
/* Two preincrements are invalid
because the assembler insn would increment only once.
@@ -2149,12 +2117,13 @@ operands_match_p (x, y)
if the preincrement is the input operand.
In this case, return 2, since some callers need to do special
things when this happens. */
- if (GET_CODE (y) == PRE_DEC || GET_CODE (y) == PRE_INC)
+ if (GET_CODE (y) == PRE_DEC || GET_CODE (y) == PRE_INC
+ || GET_CODE (y) == PRE_MODIFY)
return operands_match_p (x, XEXP (y, 0)) ? 2 : 0;
slow:
- /* Now we have disposed of all the cases
+ /* Now we have disposed of all the cases
in which different rtx codes can match. */
if (code != GET_CODE (y))
return 0;
@@ -2225,11 +2194,11 @@ operands_match_p (x, y)
}
/* Describe the range of registers or memory referenced by X.
- If X is a register, set REG_FLAG and put the first register
+ If X is a register, set REG_FLAG and put the first register
number into START and the last plus one into END.
- If X is a memory reference, put a base address into BASE
+ If X is a memory reference, put a base address into BASE
and a range of integer offsets into START and END.
- If X is pushing on the stack, we can assume it causes no trouble,
+ If X is pushing on the stack, we can assume it causes no trouble,
so we set the SAFE field. */
static struct decomposition
@@ -2244,19 +2213,33 @@ decompose (x)
val.base = 0;
if (GET_CODE (x) == MEM)
{
- rtx base, offset = 0;
+ rtx base = NULL_RTX, offset = 0;
rtx addr = XEXP (x, 0);
if (GET_CODE (addr) == PRE_DEC || GET_CODE (addr) == PRE_INC
|| GET_CODE (addr) == POST_DEC || GET_CODE (addr) == POST_INC)
{
val.base = XEXP (addr, 0);
- val.start = - GET_MODE_SIZE (GET_MODE (x));
+ val.start = -GET_MODE_SIZE (GET_MODE (x));
val.end = GET_MODE_SIZE (GET_MODE (x));
val.safe = REGNO (val.base) == STACK_POINTER_REGNUM;
return val;
}
+ if (GET_CODE (addr) == PRE_MODIFY || GET_CODE (addr) == POST_MODIFY)
+ {
+ if (GET_CODE (XEXP (addr, 1)) == PLUS
+ && XEXP (addr, 0) == XEXP (XEXP (addr, 1), 0)
+ && CONSTANT_P (XEXP (XEXP (addr, 1), 1)))
+ {
+ val.base = XEXP (addr, 0);
+ val.start = -INTVAL (XEXP (XEXP (addr, 1), 1));
+ val.end = INTVAL (XEXP (XEXP (addr, 1), 1));
+ val.safe = REGNO (val.base) == STACK_POINTER_REGNUM;
+ return val;
+ }
+ }
+
if (GET_CODE (addr) == CONST)
{
addr = XEXP (addr, 0);
@@ -2280,7 +2263,7 @@ decompose (x)
{
base = addr;
offset = const0_rtx;
- }
+ }
if (GET_CODE (offset) == CONST)
offset = XEXP (offset, 0);
if (GET_CODE (offset) == PLUS)
@@ -2321,7 +2304,7 @@ decompose (x)
else if (GET_CODE (x) == REG)
{
val.reg_flag = 1;
- val.start = true_regnum (x);
+ val.start = true_regnum (x);
if (val.start < 0)
{
/* A pseudo with no hard reg. */
@@ -2338,7 +2321,7 @@ decompose (x)
/* This could be more precise, but it's good enough. */
return decompose (SUBREG_REG (x));
val.reg_flag = 1;
- val.start = true_regnum (x);
+ val.start = true_regnum (x);
if (val.start < 0)
return decompose (SUBREG_REG (x));
else
@@ -2365,7 +2348,7 @@ immune_p (x, y, ydata)
struct decomposition xdata;
if (ydata.reg_flag)
- return !refers_to_regno_for_reload_p (ydata.start, ydata.end, x, NULL_PTR);
+ return !refers_to_regno_for_reload_p (ydata.start, ydata.end, x, (rtx*) 0);
if (ydata.safe)
return 1;
@@ -2375,7 +2358,7 @@ immune_p (x, y, ydata)
if (GET_CODE (x) != MEM)
return 1;
- xdata = decompose (x);
+ xdata = decompose (x);
if (! rtx_equal_p (xdata.base, ydata.base))
{
@@ -2397,7 +2380,6 @@ immune_p (x, y, ydata)
return 0;
}
-
return (xdata.start >= ydata.end || ydata.start >= xdata.end);
}
@@ -2442,10 +2424,8 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
int live_known;
short *reload_reg_p;
{
-#ifdef REGISTER_CONSTRAINTS
-
- register int insn_code_number;
- register int i, j;
+ int insn_code_number;
+ int i, j;
int noperands;
/* These start out as the constraints for the insn
and they are chewed up as we consider alternatives. */
@@ -2465,6 +2445,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
int no_input_reloads = 0, no_output_reloads = 0;
int n_alternatives;
int this_alternative[MAX_RECOG_OPERANDS];
+ char this_alternative_match_win[MAX_RECOG_OPERANDS];
char this_alternative_win[MAX_RECOG_OPERANDS];
char this_alternative_offmemok[MAX_RECOG_OPERANDS];
char this_alternative_earlyclobber[MAX_RECOG_OPERANDS];
@@ -2472,27 +2453,24 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
int swapped;
int goal_alternative[MAX_RECOG_OPERANDS];
int this_alternative_number;
- int goal_alternative_number;
+ int goal_alternative_number = 0;
int operand_reloadnum[MAX_RECOG_OPERANDS];
int goal_alternative_matches[MAX_RECOG_OPERANDS];
int goal_alternative_matched[MAX_RECOG_OPERANDS];
+ char goal_alternative_match_win[MAX_RECOG_OPERANDS];
char goal_alternative_win[MAX_RECOG_OPERANDS];
char goal_alternative_offmemok[MAX_RECOG_OPERANDS];
char goal_alternative_earlyclobber[MAX_RECOG_OPERANDS];
int goal_alternative_swapped;
int best;
int commutative;
- int changed;
char operands_match[MAX_RECOG_OPERANDS][MAX_RECOG_OPERANDS];
rtx substed_operand[MAX_RECOG_OPERANDS];
rtx body = PATTERN (insn);
rtx set = single_set (insn);
- int goal_earlyclobber, this_earlyclobber;
+ int goal_earlyclobber = 0, this_earlyclobber;
enum machine_mode operand_mode[MAX_RECOG_OPERANDS];
int retval = 0;
- /* Cache the last regno for the last pseudo we did an output reload
- for in case the next insn uses it. */
- static int last_output_reload_regno = -1;
this_insn = insn;
n_reloads = 0;
@@ -2514,12 +2492,12 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
if (reg_set_p (cc0_rtx, PATTERN (insn)))
no_output_reloads = 1;
#endif
-
+
#ifdef SECONDARY_MEMORY_NEEDED
/* The eliminated forms of any secondary memory locations are per-insn, so
clear them out here. */
- bzero ((char *) secondary_memlocs_elim, sizeof secondary_memlocs_elim);
+ memset ((char *) secondary_memlocs_elim, 0, sizeof secondary_memlocs_elim);
#endif
/* Dispose quickly of (set (reg..) (reg..)) if both have hard regs and it
@@ -2530,14 +2508,15 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
&& REGNO (SET_DEST (body)) < FIRST_PSEUDO_REGISTER
&& GET_CODE (SET_SRC (body)) == REG
&& REGNO (SET_SRC (body)) < FIRST_PSEUDO_REGISTER
- && REGISTER_MOVE_COST (REGNO_REG_CLASS (REGNO (SET_SRC (body))),
+ && REGISTER_MOVE_COST (GET_MODE (SET_SRC (body)),
+ REGNO_REG_CLASS (REGNO (SET_SRC (body))),
REGNO_REG_CLASS (REGNO (SET_DEST (body)))) == 2)
return 0;
extract_insn (insn);
- noperands = reload_n_operands = recog_n_operands;
- n_alternatives = recog_n_alternatives;
+ noperands = reload_n_operands = recog_data.n_operands;
+ n_alternatives = recog_data.n_alternatives;
/* Just return "no reloads" if insn has no operands with constraints. */
if (noperands == 0 || n_alternatives == 0)
@@ -2546,10 +2525,9 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
insn_code_number = INSN_CODE (insn);
this_insn_is_asm = insn_code_number < 0;
- bcopy ((char *) recog_operand_mode, (char *) operand_mode,
- noperands * sizeof (enum machine_mode));
- bcopy ((char *) recog_constraints, (char *) constraints,
- noperands * sizeof (char *));
+ memcpy (operand_mode, recog_data.operand_mode,
+ noperands * sizeof (enum machine_mode));
+ memcpy (constraints, recog_data.constraints, noperands * sizeof (char *));
commutative = -1;
@@ -2560,15 +2538,15 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
for (i = 0; i < noperands; i++)
{
- register char *p;
- register int c;
+ char *p;
+ int c;
- substed_operand[i] = recog_operand[i];
+ substed_operand[i] = recog_data.operand[i];
p = constraints[i];
modified[i] = RELOAD_READ;
- /* Scan this operand's constraint to see if it is an output operand,
+ /* Scan this operand's constraint to see if it is an output operand,
an in-out operand, is commutative, or should match another. */
while ((c = *p++))
@@ -2585,11 +2563,13 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
commutative = i;
}
- else if (c >= '0' && c <= '9')
+ else if (ISDIGIT (c))
{
- c -= '0';
+ c = strtoul (p - 1, &p, 10);
+
operands_match[c][i]
- = operands_match_p (recog_operand[c], recog_operand[i]);
+ = operands_match_p (recog_data.operand[c],
+ recog_data.operand[i]);
/* An operand may not match itself. */
if (c == i)
@@ -2603,13 +2583,15 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
{
int other = c + (c == commutative ? 1 : -1);
operands_match[other][i]
- = operands_match_p (recog_operand[other], recog_operand[i]);
+ = operands_match_p (recog_data.operand[other],
+ recog_data.operand[i]);
}
if (i == commutative || i == commutative + 1)
{
int other = i + (i == commutative ? 1 : -1);
operands_match[c][other]
- = operands_match_p (recog_operand[c], recog_operand[other]);
+ = operands_match_p (recog_data.operand[c],
+ recog_data.operand[other]);
}
/* Note that C is supposed to be less than I.
No need to consider altering both C and I because in
@@ -2623,13 +2605,13 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
and reload parts of the addresses into index registers.
Also here any references to pseudo regs that didn't get hard regs
but are equivalent to constants get replaced in the insn itself
- with those constants. Nobody will ever see them again.
+ with those constants. Nobody will ever see them again.
Finally, set up the preferred classes of each operand. */
for (i = 0; i < noperands; i++)
{
- register RTX_CODE code = GET_CODE (recog_operand[i]);
+ RTX_CODE code = GET_CODE (recog_data.operand[i]);
address_reloaded[i] = 0;
operand_type[i] = (modified[i] == RELOAD_READ ? RELOAD_FOR_INPUT
@@ -2645,16 +2627,17 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
;
else if (constraints[i][0] == 'p')
{
- find_reloads_address (VOIDmode, NULL_PTR,
- recog_operand[i], recog_operand_loc[i],
+ find_reloads_address (VOIDmode, (rtx*) 0,
+ recog_data.operand[i],
+ recog_data.operand_loc[i],
i, operand_type[i], ind_levels, insn);
- /* If we now have a simple operand where we used to have a
+ /* If we now have a simple operand where we used to have a
PLUS or MULT, re-recognize and try again. */
- if ((GET_RTX_CLASS (GET_CODE (*recog_operand_loc[i])) == 'o'
- || GET_CODE (*recog_operand_loc[i]) == SUBREG)
- && (GET_CODE (recog_operand[i]) == MULT
- || GET_CODE (recog_operand[i]) == PLUS))
+ if ((GET_RTX_CLASS (GET_CODE (*recog_data.operand_loc[i])) == 'o'
+ || GET_CODE (*recog_data.operand_loc[i]) == SUBREG)
+ && (GET_CODE (recog_data.operand[i]) == MULT
+ || GET_CODE (recog_data.operand[i]) == PLUS))
{
INSN_CODE (insn) = -1;
retval = find_reloads (insn, replace, ind_levels, live_known,
@@ -2662,51 +2645,55 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
return retval;
}
- substed_operand[i] = recog_operand[i] = *recog_operand_loc[i];
+ recog_data.operand[i] = *recog_data.operand_loc[i];
+ substed_operand[i] = recog_data.operand[i];
}
else if (code == MEM)
{
address_reloaded[i]
- = find_reloads_address (GET_MODE (recog_operand[i]),
- recog_operand_loc[i],
- XEXP (recog_operand[i], 0),
- &XEXP (recog_operand[i], 0),
+ = find_reloads_address (GET_MODE (recog_data.operand[i]),
+ recog_data.operand_loc[i],
+ XEXP (recog_data.operand[i], 0),
+ &XEXP (recog_data.operand[i], 0),
i, address_type[i], ind_levels, insn);
- substed_operand[i] = recog_operand[i] = *recog_operand_loc[i];
+ recog_data.operand[i] = *recog_data.operand_loc[i];
+ substed_operand[i] = recog_data.operand[i];
}
else if (code == SUBREG)
{
- rtx reg = SUBREG_REG (recog_operand[i]);
+ rtx reg = SUBREG_REG (recog_data.operand[i]);
rtx op
- = find_reloads_toplev (recog_operand[i], i, address_type[i],
+ = find_reloads_toplev (recog_data.operand[i], i, address_type[i],
ind_levels,
set != 0
- && &SET_DEST (set) == recog_operand_loc[i],
- insn);
+ && &SET_DEST (set) == recog_data.operand_loc[i],
+ insn,
+ &address_reloaded[i]);
/* If we made a MEM to load (a part of) the stackslot of a pseudo
that didn't get a hard register, emit a USE with a REG_EQUAL
note in front so that we might inherit a previous, possibly
wider reload. */
-
+
if (replace
&& GET_CODE (op) == MEM
&& GET_CODE (reg) == REG
&& (GET_MODE_SIZE (GET_MODE (reg))
>= GET_MODE_SIZE (GET_MODE (op))))
- REG_NOTES (emit_insn_before (gen_rtx_USE (VOIDmode, reg), insn))
- = gen_rtx_EXPR_LIST (REG_EQUAL,
- reg_equiv_memory_loc[REGNO (reg)], NULL_RTX);
+ set_unique_reg_note (emit_insn_before (gen_rtx_USE (VOIDmode, reg),
+ insn),
+ REG_EQUAL, reg_equiv_memory_loc[REGNO (reg)]);
- substed_operand[i] = recog_operand[i] = op;
+ substed_operand[i] = recog_data.operand[i] = op;
}
else if (code == PLUS || GET_RTX_CLASS (code) == '1')
/* We can get a PLUS as an "operand" as a result of register
elimination. See eliminate_regs and gen_reload. We handle
a unary operator by reloading the operand. */
- substed_operand[i] = recog_operand[i]
- = find_reloads_toplev (recog_operand[i], i, address_type[i],
- ind_levels, 0, insn);
+ substed_operand[i] = recog_data.operand[i]
+ = find_reloads_toplev (recog_data.operand[i], i, address_type[i],
+ ind_levels, 0, insn,
+ &address_reloaded[i]);
else if (code == REG)
{
/* This is equivalent to calling find_reloads_toplev.
@@ -2714,52 +2701,47 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
When we find a pseudo always equivalent to a constant,
we replace it by the constant. We must be sure, however,
that we don't try to replace it in the insn in which it
- is being set. */
- register int regno = REGNO (recog_operand[i]);
+ is being set. */
+ int regno = REGNO (recog_data.operand[i]);
if (reg_equiv_constant[regno] != 0
- && (set == 0 || &SET_DEST (set) != recog_operand_loc[i]))
+ && (set == 0 || &SET_DEST (set) != recog_data.operand_loc[i]))
{
/* Record the existing mode so that the check if constants are
- allowed will work when operand_mode isn't specified. */
+ allowed will work when operand_mode isn't specified. */
if (operand_mode[i] == VOIDmode)
- operand_mode[i] = GET_MODE (recog_operand[i]);
+ operand_mode[i] = GET_MODE (recog_data.operand[i]);
- substed_operand[i] = recog_operand[i]
- = reg_equiv_constant[regno];
+ substed_operand[i] = recog_data.operand[i]
+ = reg_equiv_constant[regno];
}
if (reg_equiv_memory_loc[regno] != 0
&& (reg_equiv_address[regno] != 0 || num_not_at_initial_offset))
/* We need not give a valid is_set_dest argument since the case
of a constant equivalence was checked above. */
- substed_operand[i] = recog_operand[i]
- = find_reloads_toplev (recog_operand[i], i, address_type[i],
- ind_levels, 0, insn);
+ substed_operand[i] = recog_data.operand[i]
+ = find_reloads_toplev (recog_data.operand[i], i, address_type[i],
+ ind_levels, 0, insn,
+ &address_reloaded[i]);
}
/* If the operand is still a register (we didn't replace it with an
equivalent), get the preferred class to reload it into. */
- code = GET_CODE (recog_operand[i]);
+ code = GET_CODE (recog_data.operand[i]);
preferred_class[i]
- = ((code == REG && REGNO (recog_operand[i]) >= FIRST_PSEUDO_REGISTER)
- ? reg_preferred_class (REGNO (recog_operand[i])) : NO_REGS);
+ = ((code == REG && REGNO (recog_data.operand[i])
+ >= FIRST_PSEUDO_REGISTER)
+ ? reg_preferred_class (REGNO (recog_data.operand[i]))
+ : NO_REGS);
pref_or_nothing[i]
- = (code == REG && REGNO (recog_operand[i]) >= FIRST_PSEUDO_REGISTER
- && reg_alternate_class (REGNO (recog_operand[i])) == NO_REGS);
+ = (code == REG
+ && REGNO (recog_data.operand[i]) >= FIRST_PSEUDO_REGISTER
+ && reg_alternate_class (REGNO (recog_data.operand[i])) == NO_REGS);
}
-#ifdef HAVE_cc0
- /* If we made any reloads for addresses, see if they violate a
- "no input reloads" requirement for this insn. */
- if (no_input_reloads)
- for (i = 0; i < n_reloads; i++)
- if (reload_in[i] != 0)
- abort ();
-#endif
-
/* If this is simply a copy from operand 1 to operand 0, merge the
preferred classes for the operands. */
- if (set != 0 && noperands >= 2 && recog_operand[0] == SET_DEST (set)
- && recog_operand[1] == SET_SRC (set))
+ if (set != 0 && noperands >= 2 && recog_data.operand[0] == SET_DEST (set)
+ && recog_data.operand[1] == SET_SRC (set))
{
preferred_class[0] = preferred_class[1]
= reg_class_subunion[(int) preferred_class[0]][(int) preferred_class[1]];
@@ -2798,7 +2780,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
/* REJECT is a count of how undesirable this alternative says it is
if any reloading is required. If the alternative matches exactly
then REJECT is ignored, but otherwise it gets this much
- counted against it in addition to the reloading needed. Each
+ counted against it in addition to the reloading needed. Each
? counts three times here since we want the disparaging caused by
a bad register class to only count 1/3 as much. */
int reject = 0;
@@ -2807,14 +2789,15 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
for (i = 0; i < noperands; i++)
{
- register char *p = constraints[i];
- register int win = 0;
- /* 0 => this operand can be reloaded somehow for this alternative */
+ char *p = constraints[i];
+ int win = 0;
+ int did_match = 0;
+ /* 0 => this operand can be reloaded somehow for this alternative. */
int badop = 1;
/* 0 => this operand can be reloaded if the alternative allows regs. */
int winreg = 0;
int c;
- register rtx operand = recog_operand[i];
+ rtx operand = recog_data.operand[i];
int offset = 0;
/* Nonzero means this is a MEM that must be reloaded into a reg
regardless of what the constraint says. */
@@ -2826,7 +2809,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
int earlyclobber = 0;
/* If the predicate accepts a unary operator, it means that
- we need to reload the operand, but do not do this for
+ we need to reload the operand, but do not do this for
match_operator and friends. */
if (GET_RTX_CLASS (GET_CODE (operand)) == '1' && *p != 0)
operand = XEXP (operand, 0);
@@ -2837,7 +2820,18 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
while (GET_CODE (operand) == SUBREG)
{
- offset += SUBREG_WORD (operand);
+ /* Offset only matters when operand is a REG and
+ it is a hard reg. This is because it is passed
+ to reg_fits_class_p if it is a REG and all pseudos
+ return 0 from that function. */
+ if (GET_CODE (SUBREG_REG (operand)) == REG
+ && REGNO (SUBREG_REG (operand)) < FIRST_PSEUDO_REGISTER)
+ {
+ offset += subreg_regno_offset (REGNO (SUBREG_REG (operand)),
+ GET_MODE (SUBREG_REG (operand)),
+ SUBREG_BYTE (operand),
+ GET_MODE (operand));
+ }
operand = SUBREG_REG (operand);
/* Force reload if this is a constant or PLUS or if there may
be a problem accessing OPERAND in the outer mode. */
@@ -2856,10 +2850,10 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
made assumptions about the behavior of the machine in such
register access. If the data is, in fact, in memory we
must always load using the size assumed to be in the
- register and let the insn do the different-sized
+ register and let the insn do the different-sized
accesses.
- This is doubly true if WORD_REGISTER_OPERATIONS. In
+ This is doubly true if WORD_REGISTER_OPERATIONS. In
this case eliminate_regs has left non-paradoxical
subregs for push_reloads to see. Make sure it does
by forcing the reload.
@@ -2888,6 +2882,11 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
)
#endif
)
+ /* This following hunk of code should no longer be
+ needed at all with SUBREG_BYTE. If you need this
+ code back, please explain to me why so I can
+ fix the real problem. -DaveM */
+#if 0
/* Subreg of a hard reg which can't handle the subreg's mode
or which would handle that mode in the wrong number of
registers for subregging to work. */
@@ -2901,12 +2900,15 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
!= HARD_REGNO_NREGS (REGNO (operand),
GET_MODE (operand))))
|| ! HARD_REGNO_MODE_OK (REGNO (operand) + offset,
- operand_mode[i]))))
+ operand_mode[i])))
+#endif
+ )
force_reload = 1;
}
this_alternative[i] = (int) NO_REGS;
this_alternative_win[i] = 0;
+ this_alternative_match_win[i] = 0;
this_alternative_offmemok[i] = 0;
this_alternative_earlyclobber[i] = 0;
this_alternative_matches[i] = -1;
@@ -2926,9 +2928,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
while (*p && (c = *p++) != ',')
switch (c)
{
- case '=':
- case '+':
- case '*':
+ case '=': case '+': case '*':
break;
case '%':
@@ -2948,15 +2948,14 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
case '#':
/* Ignore rest of this alternative as far as
reloading is concerned. */
- while (*p && *p != ',') p++;
+ while (*p && *p != ',')
+ p++;
break;
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- c -= '0';
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ c = strtoul (p - 1, &p, 10);
+
this_alternative_matches[i] = c;
/* We are supposed to match a previous operand.
If we do, we win if that one did.
@@ -2973,22 +2972,22 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
don't exchange them, because operands_match is valid
only on one side of its diagonal. */
? (operands_match
- [(c == commutative || c == commutative + 1)
- ? 2*commutative + 1 - c : c]
- [(i == commutative || i == commutative + 1)
- ? 2*commutative + 1 - i : i])
+ [(c == commutative || c == commutative + 1)
+ ? 2 * commutative + 1 - c : c]
+ [(i == commutative || i == commutative + 1)
+ ? 2 * commutative + 1 - i : i])
: operands_match[c][i])
{
/* If we are matching a non-offsettable address where an
offsettable address was expected, then we must reject
this combination, because we can't reload it. */
if (this_alternative_offmemok[c]
- && GET_CODE (recog_operand[c]) == MEM
+ && GET_CODE (recog_data.operand[c]) == MEM
&& this_alternative[c] == (int) NO_REGS
&& ! this_alternative_win[c])
bad = 1;
- win = this_alternative_win[c];
+ did_match = this_alternative_win[c];
}
else
{
@@ -3004,8 +3003,10 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
/* But count the pair only once in the total badness of
this alternative, if the pair can be a dummy reload. */
value
- = find_dummy_reload (recog_operand[i], recog_operand[c],
- recog_operand_loc[i], recog_operand_loc[c],
+ = find_dummy_reload (recog_data.operand[i],
+ recog_data.operand[c],
+ recog_data.operand_loc[i],
+ recog_data.operand_loc[c],
operand_mode[i], operand_mode[c],
this_alternative[c], -1,
this_alternative_earlyclobber[c]);
@@ -3022,18 +3023,17 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
operand also had to match the same thing as this
operand, we don't know how to do that. So reject this
alternative. */
- if (! win || force_reload)
+ if (! did_match || force_reload)
for (j = 0; j < i; j++)
if (this_alternative_matches[j]
== this_alternative_matches[i])
badop = 1;
-
break;
case 'p':
/* All necessary reloads for an address_operand
were handled in find_reloads_address. */
- this_alternative[i] = (int) BASE_REG_CLASS;
+ this_alternative[i] = (int) MODE_BASE_REG_CLASS (VOIDmode);
win = 1;
break;
@@ -3194,8 +3194,8 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
/* A SCRATCH is not a valid operand. */
&& GET_CODE (operand) != SCRATCH
#ifdef LEGITIMATE_PIC_OPERAND_P
- && (! CONSTANT_P (operand)
- || ! flag_pic
+ && (! CONSTANT_P (operand)
+ || ! flag_pic
|| LEGITIMATE_PIC_OPERAND_P (operand))
#endif
&& (GENERAL_REGS == ALL_REGS
@@ -3203,35 +3203,32 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
|| (REGNO (operand) >= FIRST_PSEUDO_REGISTER
&& reg_renumber[REGNO (operand)] < 0)))
win = 1;
- /* Drop through into 'r' case */
+ /* Drop through into 'r' case. */
case 'r':
this_alternative[i]
= (int) reg_class_subunion[this_alternative[i]][(int) GENERAL_REGS];
goto reg;
+ default:
+ if (REG_CLASS_FROM_LETTER (c) == NO_REGS)
+ {
#ifdef EXTRA_CONSTRAINT
- case 'Q':
- case 'R':
- case 'S':
- case 'T':
- case 'U':
- if (EXTRA_CONSTRAINT (operand, c))
- win = 1;
- break;
+ if (EXTRA_CONSTRAINT (operand, c))
+ win = 1;
#endif
-
- default:
+ break;
+ }
+
this_alternative[i]
= (int) reg_class_subunion[this_alternative[i]][(int) REG_CLASS_FROM_LETTER (c)];
-
reg:
if (GET_MODE (operand) == BLKmode)
break;
winreg = 1;
if (GET_CODE (operand) == REG
&& reg_fits_class_p (operand, this_alternative[i],
- offset, GET_MODE (recog_operand[i])))
+ offset, GET_MODE (recog_data.operand[i])))
win = 1;
break;
}
@@ -3247,6 +3244,8 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
this_alternative_earlyclobber[i] = earlyclobber;
if (win && ! force_reload)
this_alternative_win[i] = 1;
+ else if (did_match && ! force_reload)
+ this_alternative_match_win[i] = 1;
else
{
int const_to_mem = 0;
@@ -3261,34 +3260,19 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
&& this_alternative_matches[i] < 0)
bad = 1;
-#if 0
- /* If this is a pseudo-register that is set in the previous
- insns, there's a good chance that it will already be in a
- spill register and we can use that spill register. So
- make this case cheaper.
-
- Disabled for egcs. egcs has better inheritance code and
- this change causes problems with the improved reload
- inheritance code. */
- if (GET_CODE (operand) == REG
- && REGNO (operand) >= FIRST_PSEUDO_REGISTER
- && REGNO (operand) == last_output_reload_regno)
- reject--;
-#endif
-
/* If this is a constant that is reloaded into the desired
class by copying it to memory first, count that as another
reload. This is consistent with other code and is
required to avoid choosing another alternative when
the constant is moved into memory by this function on
- an early reload pass. Note that the test here is
+ an early reload pass. Note that the test here is
precisely the same as in the code below that calls
force_const_mem. */
if (CONSTANT_P (operand)
/* force_const_mem does not accept HIGH. */
&& GET_CODE (operand) != HIGH
&& ((PREFERRED_RELOAD_CLASS (operand,
- (enum reg_class) this_alternative[i])
+ (enum reg_class) this_alternative[i])
== NO_REGS)
|| no_input_reloads)
&& operand_mode[i] != VOIDmode)
@@ -3314,18 +3298,17 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
permitted for this insn. We can always reload SCRATCH
and objects with a REG_UNUSED note. */
else if (GET_CODE (operand) != SCRATCH
- && modified[i] != RELOAD_READ && no_output_reloads
- && ! find_reg_note (insn, REG_UNUSED, operand))
+ && modified[i] != RELOAD_READ && no_output_reloads
+ && ! find_reg_note (insn, REG_UNUSED, operand))
bad = 1;
else if (modified[i] != RELOAD_WRITE && no_input_reloads
&& ! const_to_mem)
bad = 1;
-
/* We prefer to reload pseudos over reloading other things,
since such reloads may be able to be eliminated later.
If we are reloading a SCRATCH, we won't be generating any
- insns, just using a register, so it is also preferred.
+ insns, just using a register, so it is also preferred.
So bump REJECT in other cases. Don't do this in the
case where we are forcing a constant into memory and
it will then win since we don't want to have a different
@@ -3343,7 +3326,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
reject++;
}
- /* If this operand is a pseudo register that didn't get a hard
+ /* If this operand is a pseudo register that didn't get a hard
reg and this alternative accepts some register, see if the
class that we want is a subset of the preferred class for this
register. If not, but it intersects that class, use the
@@ -3364,8 +3347,8 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
Don't do this if the preferred class has only one register
because we might otherwise exhaust the class. */
-
- if (! win && this_alternative[i] != (int) NO_REGS
+ if (! win && ! did_match
+ && this_alternative[i] != (int) NO_REGS
&& GET_MODE_SIZE (operand_mode[i]) <= UNITS_PER_WORD
&& reg_class_size[(int) preferred_class[i]] > 1)
{
@@ -3374,7 +3357,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
{
/* Since we don't have a way of forming the intersection,
we just do something special if the preferred class
- is a subset of the class we have; that's the most
+ is a subset of the class we have; that's the most
common case anyway. */
if (reg_class_subset_p (preferred_class[i],
this_alternative[i]))
@@ -3391,15 +3374,15 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
for (i = 0; i < noperands; i++)
if (this_alternative_earlyclobber[i]
- && this_alternative_win[i])
+ && (this_alternative_win[i] || this_alternative_match_win[i]))
{
- struct decomposition early_data;
+ struct decomposition early_data;
- early_data = decompose (recog_operand[i]);
+ early_data = decompose (recog_data.operand[i]);
if (modified[i] == RELOAD_READ)
abort ();
-
+
if (this_alternative[i] == NO_REGS)
{
this_alternative_earlyclobber[i] = 0;
@@ -3412,26 +3395,29 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
for (j = 0; j < noperands; j++)
/* Is this an input operand or a memory ref? */
- if ((GET_CODE (recog_operand[j]) == MEM
+ if ((GET_CODE (recog_data.operand[j]) == MEM
|| modified[j] != RELOAD_WRITE)
&& j != i
/* Ignore things like match_operator operands. */
- && *recog_constraints[j] != 0
+ && *recog_data.constraints[j] != 0
/* Don't count an input operand that is constrained to match
the early clobber operand. */
&& ! (this_alternative_matches[j] == i
- && rtx_equal_p (recog_operand[i], recog_operand[j]))
+ && rtx_equal_p (recog_data.operand[i],
+ recog_data.operand[j]))
/* Is it altered by storing the earlyclobber operand? */
- && !immune_p (recog_operand[j], recog_operand[i], early_data))
+ && !immune_p (recog_data.operand[j], recog_data.operand[i],
+ early_data))
{
/* If the output is in a single-reg class,
it's costly to reload it, so reload the input instead. */
if (reg_class_size[this_alternative[i]] == 1
- && (GET_CODE (recog_operand[j]) == REG
- || GET_CODE (recog_operand[j]) == SUBREG))
+ && (GET_CODE (recog_data.operand[j]) == REG
+ || GET_CODE (recog_data.operand[j]) == SUBREG))
{
losers++;
this_alternative_win[j] = 0;
+ this_alternative_match_win[j] = 0;
}
else
break;
@@ -3442,11 +3428,13 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
{
losers++;
this_alternative_win[i] = 0;
+ this_alternative_match_win[j] = 0;
for (j = 0; j < noperands; j++)
if (this_alternative_matches[j] == i
- && this_alternative_win[j])
+ && this_alternative_match_win[j])
{
this_alternative_win[j] = 0;
+ this_alternative_match_win[j] = 0;
losers++;
}
}
@@ -3459,13 +3447,14 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
/* Unswap these so that they are never swapped at `finish'. */
if (commutative >= 0)
{
- recog_operand[commutative] = substed_operand[commutative];
- recog_operand[commutative + 1]
+ recog_data.operand[commutative] = substed_operand[commutative];
+ recog_data.operand[commutative + 1]
= substed_operand[commutative + 1];
}
for (i = 0; i < noperands; i++)
{
- goal_alternative_win[i] = 1;
+ goal_alternative_win[i] = this_alternative_win[i];
+ goal_alternative_match_win[i] = this_alternative_match_win[i];
goal_alternative[i] = this_alternative[i];
goal_alternative_offmemok[i] = this_alternative_offmemok[i];
goal_alternative_matches[i] = this_alternative_matches[i];
@@ -3493,6 +3482,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
{
goal_alternative[i] = this_alternative[i];
goal_alternative_win[i] = this_alternative_win[i];
+ goal_alternative_match_win[i] = this_alternative_match_win[i];
goal_alternative_offmemok[i] = this_alternative_offmemok[i];
goal_alternative_matches[i] = this_alternative_matches[i];
goal_alternative_earlyclobber[i]
@@ -3519,11 +3509,17 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
swapped = !swapped;
if (swapped)
{
- register enum reg_class tclass;
- register int t;
-
- recog_operand[commutative] = substed_operand[commutative + 1];
- recog_operand[commutative + 1] = substed_operand[commutative];
+ enum reg_class tclass;
+ int t;
+
+ recog_data.operand[commutative] = substed_operand[commutative + 1];
+ recog_data.operand[commutative + 1] = substed_operand[commutative];
+ /* Swap the duplicates too. */
+ for (i = 0; i < recog_data.n_dups; i++)
+ if (recog_data.dup_num[i] == commutative
+ || recog_data.dup_num[i] == commutative + 1)
+ *recog_data.dup_loc[i]
+ = recog_data.operand[(int) recog_data.dup_num[i]];
tclass = preferred_class[commutative];
preferred_class[commutative] = preferred_class[commutative + 1];
@@ -3533,14 +3529,21 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
pref_or_nothing[commutative] = pref_or_nothing[commutative + 1];
pref_or_nothing[commutative + 1] = t;
- bcopy ((char *) recog_constraints, (char *) constraints,
- noperands * sizeof (char *));
+ memcpy (constraints, recog_data.constraints,
+ noperands * sizeof (char *));
goto try_swapped;
}
else
{
- recog_operand[commutative] = substed_operand[commutative];
- recog_operand[commutative + 1] = substed_operand[commutative + 1];
+ recog_data.operand[commutative] = substed_operand[commutative];
+ recog_data.operand[commutative + 1]
+ = substed_operand[commutative + 1];
+ /* Unswap the duplicates too. */
+ for (i = 0; i < recog_data.n_dups; i++)
+ if (recog_data.dup_num[i] == commutative
+ || recog_data.dup_num[i] == commutative + 1)
+ *recog_data.dup_loc[i]
+ = recog_data.operand[(int) recog_data.dup_num[i]];
}
}
@@ -3553,7 +3556,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
{
/* No alternative works with reloads?? */
if (insn_code_number >= 0)
- fatal_insn ("Unable to generate reloads for:", insn);
+ fatal_insn ("unable to generate reloads for:", insn);
error_for_asm (insn, "inconsistent operand constraints in an `asm'");
/* Avoid further trouble with this insn. */
PATTERN (insn) = gen_rtx_USE (VOIDmode, const0_rtx);
@@ -3573,36 +3576,40 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
for (i = 0; i < noperands; i++)
goal_alternative_matched[i] = -1;
-
+
for (i = 0; i < noperands; i++)
if (! goal_alternative_win[i]
&& goal_alternative_matches[i] >= 0)
goal_alternative_matched[goal_alternative_matches[i]] = i;
+ for (i = 0; i < noperands; i++)
+ goal_alternative_win[i] |= goal_alternative_match_win[i];
+
/* If the best alternative is with operands 1 and 2 swapped,
consider them swapped before reporting the reloads. Update the
operand numbers of any reloads already pushed. */
if (goal_alternative_swapped)
{
- register rtx tem;
+ rtx tem;
tem = substed_operand[commutative];
substed_operand[commutative] = substed_operand[commutative + 1];
substed_operand[commutative + 1] = tem;
- tem = recog_operand[commutative];
- recog_operand[commutative] = recog_operand[commutative + 1];
- recog_operand[commutative + 1] = tem;
- tem = *recog_operand_loc[commutative];
- *recog_operand_loc[commutative] = *recog_operand_loc[commutative+1];
- *recog_operand_loc[commutative+1] = tem;
+ tem = recog_data.operand[commutative];
+ recog_data.operand[commutative] = recog_data.operand[commutative + 1];
+ recog_data.operand[commutative + 1] = tem;
+ tem = *recog_data.operand_loc[commutative];
+ *recog_data.operand_loc[commutative]
+ = *recog_data.operand_loc[commutative + 1];
+ *recog_data.operand_loc[commutative + 1] = tem;
for (i = 0; i < n_reloads; i++)
{
- if (reload_opnum[i] == commutative)
- reload_opnum[i] = commutative + 1;
- else if (reload_opnum[i] == commutative + 1)
- reload_opnum[i] = commutative;
+ if (rld[i].opnum == commutative)
+ rld[i].opnum = commutative + 1;
+ else if (rld[i].opnum == commutative + 1)
+ rld[i].opnum = commutative;
}
}
@@ -3618,9 +3625,9 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
One special case that is worth checking is when we have an
output that is earlyclobber but isn't used past the insn (typically
- a SCRATCH). In this case, we only need have the reload live
+ a SCRATCH). In this case, we only need have the reload live
through the insn itself, but not for any of our input or output
- reloads.
+ reloads.
But we must not accidentally narrow the scope of an existing
RELOAD_OTHER reload - leave these alone.
@@ -3629,7 +3636,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
if (goal_alternative_earlyclobber[i] && operand_type[i] != RELOAD_OTHER)
operand_type[i]
- = (find_reg_note (insn, REG_UNUSED, recog_operand[i])
+ = (find_reg_note (insn, REG_UNUSED, recog_data.operand[i])
? RELOAD_FOR_INSN : RELOAD_OTHER);
}
@@ -3637,20 +3644,21 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
into registers are here changed into memory references. */
for (i = 0; i < noperands; i++)
if (! goal_alternative_win[i]
- && CONSTANT_P (recog_operand[i])
+ && CONSTANT_P (recog_data.operand[i])
/* force_const_mem does not accept HIGH. */
- && GET_CODE (recog_operand[i]) != HIGH
- && ((PREFERRED_RELOAD_CLASS (recog_operand[i],
- (enum reg_class) goal_alternative[i])
+ && GET_CODE (recog_data.operand[i]) != HIGH
+ && ((PREFERRED_RELOAD_CLASS (recog_data.operand[i],
+ (enum reg_class) goal_alternative[i])
== NO_REGS)
|| no_input_reloads)
&& operand_mode[i] != VOIDmode)
{
- substed_operand[i] = recog_operand[i]
+ substed_operand[i] = recog_data.operand[i]
= find_reloads_toplev (force_const_mem (operand_mode[i],
- recog_operand[i]),
- i, address_type[i], ind_levels, 0, insn);
- if (alternative_allows_memconst (recog_constraints[i],
+ recog_data.operand[i]),
+ i, address_type[i], ind_levels, 0, insn,
+ NULL);
+ if (alternative_allows_memconst (recog_data.constraints[i],
goal_alternative_number))
goal_alternative_win[i] = 1;
}
@@ -3659,10 +3667,9 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
if (goal_earlyclobber)
for (i = 0; i < noperands; i++)
if (goal_alternative_earlyclobber[i])
- reload_earlyclobbers[n_earlyclobbers++] = recog_operand[i];
+ reload_earlyclobbers[n_earlyclobbers++] = recog_data.operand[i];
/* Now record reloads for all the operands that need them. */
- last_output_reload_regno = -1;
for (i = 0; i < noperands; i++)
if (! goal_alternative_win[i])
{
@@ -3678,15 +3685,16 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
so we don't bother with it. It may not be worth doing. */
else if (goal_alternative_matched[i] == -1
&& goal_alternative_offmemok[i]
- && GET_CODE (recog_operand[i]) == MEM)
+ && GET_CODE (recog_data.operand[i]) == MEM)
{
operand_reloadnum[i]
- = push_reload (XEXP (recog_operand[i], 0), NULL_RTX,
- &XEXP (recog_operand[i], 0), NULL_PTR,
- BASE_REG_CLASS, GET_MODE (XEXP (recog_operand[i], 0)),
+ = push_reload (XEXP (recog_data.operand[i], 0), NULL_RTX,
+ &XEXP (recog_data.operand[i], 0), (rtx*) 0,
+ MODE_BASE_REG_CLASS (VOIDmode),
+ GET_MODE (XEXP (recog_data.operand[i], 0)),
VOIDmode, 0, 0, i, RELOAD_FOR_INPUT);
- reload_inc[operand_reloadnum[i]]
- = GET_MODE_SIZE (GET_MODE (recog_operand[i]));
+ rld[operand_reloadnum[i]].inc
+ = GET_MODE_SIZE (GET_MODE (recog_data.operand[i]));
/* If this operand is an output, we will have made any
reloads for its address as RELOAD_FOR_OUTPUT_ADDRESS, but
@@ -3697,13 +3705,13 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
{
for (j = 0; j < n_reloads; j++)
{
- if (reload_opnum[j] == i)
+ if (rld[j].opnum == i)
{
- if (reload_when_needed[j] == RELOAD_FOR_OUTPUT_ADDRESS)
- reload_when_needed[j] = RELOAD_FOR_INPUT_ADDRESS;
- else if (reload_when_needed[j]
+ if (rld[j].when_needed == RELOAD_FOR_OUTPUT_ADDRESS)
+ rld[j].when_needed = RELOAD_FOR_INPUT_ADDRESS;
+ else if (rld[j].when_needed
== RELOAD_FOR_OUTADDR_ADDRESS)
- reload_when_needed[j] = RELOAD_FOR_INPADDR_ADDRESS;
+ rld[j].when_needed = RELOAD_FOR_INPADDR_ADDRESS;
}
}
}
@@ -3712,23 +3720,21 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
{
operand_reloadnum[i]
= push_reload ((modified[i] != RELOAD_WRITE
- ? recog_operand[i] : 0),
- modified[i] != RELOAD_READ ? recog_operand[i] : 0,
+ ? recog_data.operand[i] : 0),
+ (modified[i] != RELOAD_READ
+ ? recog_data.operand[i] : 0),
(modified[i] != RELOAD_WRITE
- ? recog_operand_loc[i] : 0),
+ ? recog_data.operand_loc[i] : 0),
(modified[i] != RELOAD_READ
- ? recog_operand_loc[i] : 0),
+ ? recog_data.operand_loc[i] : 0),
(enum reg_class) goal_alternative[i],
(modified[i] == RELOAD_WRITE
? VOIDmode : operand_mode[i]),
(modified[i] == RELOAD_READ
? VOIDmode : operand_mode[i]),
(insn_code_number < 0 ? 0
- : insn_operand_strict_low[insn_code_number][i]),
+ : insn_data[insn_code_number].operand[i].strict_low),
0, i, operand_type[i]);
- if (modified[i] != RELOAD_READ
- && GET_CODE (recog_operand[i]) == REG)
- last_output_reload_regno = REGNO (recog_operand[i]);
}
/* In a matching pair of operands, one must be input only
and the other must be output only.
@@ -3737,34 +3743,29 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
&& modified[goal_alternative_matched[i]] == RELOAD_WRITE)
{
operand_reloadnum[i]
- = push_reload (recog_operand[i],
- recog_operand[goal_alternative_matched[i]],
- recog_operand_loc[i],
- recog_operand_loc[goal_alternative_matched[i]],
+ = push_reload (recog_data.operand[i],
+ recog_data.operand[goal_alternative_matched[i]],
+ recog_data.operand_loc[i],
+ recog_data.operand_loc[goal_alternative_matched[i]],
(enum reg_class) goal_alternative[i],
operand_mode[i],
operand_mode[goal_alternative_matched[i]],
0, 0, i, RELOAD_OTHER);
operand_reloadnum[goal_alternative_matched[i]] = output_reloadnum;
- if (GET_CODE (recog_operand[goal_alternative_matched[i]]) == REG)
- last_output_reload_regno
- = REGNO (recog_operand[goal_alternative_matched[i]]);
}
else if (modified[i] == RELOAD_WRITE
&& modified[goal_alternative_matched[i]] == RELOAD_READ)
{
operand_reloadnum[goal_alternative_matched[i]]
- = push_reload (recog_operand[goal_alternative_matched[i]],
- recog_operand[i],
- recog_operand_loc[goal_alternative_matched[i]],
- recog_operand_loc[i],
+ = push_reload (recog_data.operand[goal_alternative_matched[i]],
+ recog_data.operand[i],
+ recog_data.operand_loc[goal_alternative_matched[i]],
+ recog_data.operand_loc[i],
(enum reg_class) goal_alternative[i],
operand_mode[goal_alternative_matched[i]],
operand_mode[i],
0, 0, i, RELOAD_OTHER);
operand_reloadnum[i] = output_reloadnum;
- if (GET_CODE (recog_operand[i]) == REG)
- last_output_reload_regno = REGNO (recog_operand[i]);
}
else if (insn_code_number >= 0)
abort ();
@@ -3781,14 +3782,14 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
&& goal_alternative_matches[i] < 0
&& optimize)
{
- /* For each non-matching operand that's a MEM or a pseudo-register
+ /* For each non-matching operand that's a MEM or a pseudo-register
that didn't get a hard register, make an optional reload.
This may get done even if the insn needs no reloads otherwise. */
- rtx operand = recog_operand[i];
+ rtx operand = recog_data.operand[i];
while (GET_CODE (operand) == SUBREG)
- operand = XEXP (operand, 0);
+ operand = SUBREG_REG (operand);
if ((GET_CODE (operand) == MEM
|| (GET_CODE (operand) == REG
&& REGNO (operand) >= FIRST_PSEUDO_REGISTER))
@@ -3808,19 +3809,21 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
&& (modified[i] == RELOAD_READ
|| (! no_output_reloads && ! this_insn_is_asm)))
operand_reloadnum[i]
- = push_reload (modified[i] != RELOAD_WRITE ? recog_operand[i] : 0,
- modified[i] != RELOAD_READ ? recog_operand[i] : 0,
+ = push_reload ((modified[i] != RELOAD_WRITE
+ ? recog_data.operand[i] : 0),
+ (modified[i] != RELOAD_READ
+ ? recog_data.operand[i] : 0),
(modified[i] != RELOAD_WRITE
- ? recog_operand_loc[i] : 0),
+ ? recog_data.operand_loc[i] : 0),
(modified[i] != RELOAD_READ
- ? recog_operand_loc[i] : 0),
+ ? recog_data.operand_loc[i] : 0),
(enum reg_class) goal_alternative[i],
(modified[i] == RELOAD_WRITE
? VOIDmode : operand_mode[i]),
(modified[i] == RELOAD_READ
? VOIDmode : operand_mode[i]),
(insn_code_number < 0 ? 0
- : insn_operand_strict_low[insn_code_number][i]),
+ : insn_data[insn_code_number].operand[i].strict_low),
1, i, operand_type[i]);
/* If a memory reference remains (either as a MEM or a pseudo that
did not get a hard register), yet we can't make an optional
@@ -3833,14 +3836,18 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
&& REGNO (operand) >= FIRST_PSEUDO_REGISTER
&& reg_renumber [REGNO (operand)] < 0)))
{
- operand = *recog_operand_loc[i];
+ operand = *recog_data.operand_loc[i];
while (GET_CODE (operand) == SUBREG)
- operand = XEXP (operand, 0);
+ operand = SUBREG_REG (operand);
if (GET_CODE (operand) == REG)
{
if (modified[i] != RELOAD_WRITE)
- emit_insn_before (gen_rtx_USE (VOIDmode, operand), insn);
+ /* We mark the USE with QImode so that we recognize
+ it as one that can be safely deleted at the end
+ of reload. */
+ PUT_MODE (emit_insn_before (gen_rtx_USE (VOIDmode, operand),
+ insn), QImode);
if (modified[i] != RELOAD_READ)
emit_insn_after (gen_rtx_CLOBBER (VOIDmode, operand), insn);
}
@@ -3856,26 +3863,26 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
/* Similarly, make an optional reload for a pair of matching
objects that are in MEM or a pseudo that didn't get a hard reg. */
- rtx operand = recog_operand[i];
+ rtx operand = recog_data.operand[i];
while (GET_CODE (operand) == SUBREG)
- operand = XEXP (operand, 0);
+ operand = SUBREG_REG (operand);
if ((GET_CODE (operand) == MEM
|| (GET_CODE (operand) == REG
&& REGNO (operand) >= FIRST_PSEUDO_REGISTER))
&& ((enum reg_class) goal_alternative[goal_alternative_matches[i]]
!= NO_REGS))
operand_reloadnum[i] = operand_reloadnum[goal_alternative_matches[i]]
- = push_reload (recog_operand[goal_alternative_matches[i]],
- recog_operand[i],
- recog_operand_loc[goal_alternative_matches[i]],
- recog_operand_loc[i],
+ = push_reload (recog_data.operand[goal_alternative_matches[i]],
+ recog_data.operand[i],
+ recog_data.operand_loc[goal_alternative_matches[i]],
+ recog_data.operand_loc[i],
(enum reg_class) goal_alternative[goal_alternative_matches[i]],
operand_mode[goal_alternative_matches[i]],
operand_mode[i],
0, 1, goal_alternative_matches[i], RELOAD_OTHER);
}
-
+
/* Perform whatever substitutions on the operands we are supposed
to make due to commutativity or replacement of registers
with equivalent constants or memory slots. */
@@ -3883,15 +3890,15 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
for (i = 0; i < noperands; i++)
{
/* We only do this on the last pass through reload, because it is
- possible for some data (like reg_equiv_address) to be changed during
- later passes. Moreover, we loose the opportunity to get a useful
- reload_{in,out}_reg when we do these replacements. */
+ possible for some data (like reg_equiv_address) to be changed during
+ later passes. Moreover, we loose the opportunity to get a useful
+ reload_{in,out}_reg when we do these replacements. */
if (replace)
{
rtx substitution = substed_operand[i];
- *recog_operand_loc[i] = substitution;
+ *recog_data.operand_loc[i] = substitution;
/* If we're replacing an operand with a LABEL_REF, we need
to make sure that there's a REG_LABEL note attached to
@@ -3899,12 +3906,12 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
if (GET_CODE (insn) != JUMP_INSN
&& GET_CODE (substitution) == LABEL_REF
&& !find_reg_note (insn, REG_LABEL, XEXP (substitution, 0)))
- REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_LABEL,
+ REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL,
XEXP (substitution, 0),
REG_NOTES (insn));
}
else
- retval |= (substed_operand[i] != *recog_operand_loc[i]);
+ retval |= (substed_operand[i] != *recog_data.operand_loc[i]);
}
/* If this insn pattern contains any MATCH_DUP's, make sure that
@@ -3916,13 +3923,13 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
it doesn't expect. */
if (insn_code_number >= 0 && replace)
- for (i = insn_n_dups[insn_code_number] - 1; i >= 0; i--)
+ for (i = insn_data[insn_code_number].n_dups - 1; i >= 0; i--)
{
- int opno = recog_dup_num[i];
- *recog_dup_loc[i] = *recog_operand_loc[opno];
+ int opno = recog_data.dup_num[i];
+ *recog_data.dup_loc[i] = *recog_data.operand_loc[opno];
if (operand_reloadnum[opno] >= 0)
- push_replacement (recog_dup_loc[i], operand_reloadnum[opno],
- insn_operand_mode[insn_code_number][opno]);
+ push_replacement (recog_data.dup_loc[i], operand_reloadnum[opno],
+ insn_data[insn_code_number].operand[opno].mode);
}
#if 0
@@ -3936,18 +3943,18 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
search for an existing equivalent reg (same value now) in the right class.
We can use it as long as we don't need to change its contents. */
for (i = 0; i < n_reloads; i++)
- if (reload_reg_rtx[i] == 0
- && reload_in[i] != 0
- && GET_CODE (reload_in[i]) == REG
- && reload_out[i] == 0)
+ if (rld[i].reg_rtx == 0
+ && rld[i].in != 0
+ && GET_CODE (rld[i].in) == REG
+ && rld[i].out == 0)
{
- reload_reg_rtx[i]
- = find_equiv_reg (reload_in[i], insn, reload_reg_class[i], -1,
- static_reload_reg_p, 0, reload_inmode[i]);
+ rld[i].reg_rtx
+ = find_equiv_reg (rld[i].in, insn, rld[i].class, -1,
+ static_reload_reg_p, 0, rld[i].inmode);
/* Prevent generation of insn to load the value
because the one we found already has the value. */
- if (reload_reg_rtx[i])
- reload_in[i] = reload_reg_rtx[i];
+ if (rld[i].reg_rtx)
+ rld[i].in = rld[i].reg_rtx;
}
#endif
@@ -3966,37 +3973,37 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
int k;
for (j = i + 1; j < n_reloads; j++)
- if ((reload_when_needed[i] == RELOAD_FOR_INPUT_ADDRESS
- || reload_when_needed[i] == RELOAD_FOR_OUTPUT_ADDRESS
- || reload_when_needed[i] == RELOAD_FOR_INPADDR_ADDRESS
- || reload_when_needed[i] == RELOAD_FOR_OUTADDR_ADDRESS)
- && (reload_when_needed[j] == RELOAD_FOR_INPUT_ADDRESS
- || reload_when_needed[j] == RELOAD_FOR_OUTPUT_ADDRESS
- || reload_when_needed[j] == RELOAD_FOR_INPADDR_ADDRESS
- || reload_when_needed[j] == RELOAD_FOR_OUTADDR_ADDRESS)
- && rtx_equal_p (reload_in[i], reload_in[j])
- && (operand_reloadnum[reload_opnum[i]] < 0
- || reload_optional[operand_reloadnum[reload_opnum[i]]])
- && (operand_reloadnum[reload_opnum[j]] < 0
- || reload_optional[operand_reloadnum[reload_opnum[j]]])
- && (goal_alternative_matches[reload_opnum[i]] == reload_opnum[j]
- || (goal_alternative_matches[reload_opnum[j]]
- == reload_opnum[i])))
+ if ((rld[i].when_needed == RELOAD_FOR_INPUT_ADDRESS
+ || rld[i].when_needed == RELOAD_FOR_OUTPUT_ADDRESS
+ || rld[i].when_needed == RELOAD_FOR_INPADDR_ADDRESS
+ || rld[i].when_needed == RELOAD_FOR_OUTADDR_ADDRESS)
+ && (rld[j].when_needed == RELOAD_FOR_INPUT_ADDRESS
+ || rld[j].when_needed == RELOAD_FOR_OUTPUT_ADDRESS
+ || rld[j].when_needed == RELOAD_FOR_INPADDR_ADDRESS
+ || rld[j].when_needed == RELOAD_FOR_OUTADDR_ADDRESS)
+ && rtx_equal_p (rld[i].in, rld[j].in)
+ && (operand_reloadnum[rld[i].opnum] < 0
+ || rld[operand_reloadnum[rld[i].opnum]].optional)
+ && (operand_reloadnum[rld[j].opnum] < 0
+ || rld[operand_reloadnum[rld[j].opnum]].optional)
+ && (goal_alternative_matches[rld[i].opnum] == rld[j].opnum
+ || (goal_alternative_matches[rld[j].opnum]
+ == rld[i].opnum)))
{
for (k = 0; k < n_replacements; k++)
if (replacements[k].what == j)
replacements[k].what = i;
- if (reload_when_needed[i] == RELOAD_FOR_INPADDR_ADDRESS
- || reload_when_needed[i] == RELOAD_FOR_OUTADDR_ADDRESS)
- reload_when_needed[i] = RELOAD_FOR_OPADDR_ADDR;
+ if (rld[i].when_needed == RELOAD_FOR_INPADDR_ADDRESS
+ || rld[i].when_needed == RELOAD_FOR_OUTADDR_ADDRESS)
+ rld[i].when_needed = RELOAD_FOR_OPADDR_ADDR;
else
- reload_when_needed[i] = RELOAD_FOR_OPERAND_ADDRESS;
- reload_in[j] = 0;
+ rld[i].when_needed = RELOAD_FOR_OPERAND_ADDRESS;
+ rld[j].in = 0;
}
}
- /* Scan all the reloads and update their type.
+ /* Scan all the reloads and update their type.
If a reload is for the address of an operand and we didn't reload
that operand, change the type. Similarly, change the operand number
of a reload when two operands match. If a reload is optional, treat it
@@ -4015,68 +4022,66 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
for (i = 0; i < n_reloads; i++)
{
- if (reload_secondary_p[i]
- && reload_when_needed[i] == operand_type[reload_opnum[i]])
- reload_when_needed[i] = address_type[reload_opnum[i]];
-
- if ((reload_when_needed[i] == RELOAD_FOR_INPUT_ADDRESS
- || reload_when_needed[i] == RELOAD_FOR_OUTPUT_ADDRESS
- || reload_when_needed[i] == RELOAD_FOR_INPADDR_ADDRESS
- || reload_when_needed[i] == RELOAD_FOR_OUTADDR_ADDRESS)
- && (operand_reloadnum[reload_opnum[i]] < 0
- || reload_optional[operand_reloadnum[reload_opnum[i]]]))
+ if (rld[i].secondary_p
+ && rld[i].when_needed == operand_type[rld[i].opnum])
+ rld[i].when_needed = address_type[rld[i].opnum];
+
+ if ((rld[i].when_needed == RELOAD_FOR_INPUT_ADDRESS
+ || rld[i].when_needed == RELOAD_FOR_OUTPUT_ADDRESS
+ || rld[i].when_needed == RELOAD_FOR_INPADDR_ADDRESS
+ || rld[i].when_needed == RELOAD_FOR_OUTADDR_ADDRESS)
+ && (operand_reloadnum[rld[i].opnum] < 0
+ || rld[operand_reloadnum[rld[i].opnum]].optional))
{
/* If we have a secondary reload to go along with this reload,
change its type to RELOAD_FOR_OPADDR_ADDR. */
- if ((reload_when_needed[i] == RELOAD_FOR_INPUT_ADDRESS
- || reload_when_needed[i] == RELOAD_FOR_INPADDR_ADDRESS)
- && reload_secondary_in_reload[i] != -1)
+ if ((rld[i].when_needed == RELOAD_FOR_INPUT_ADDRESS
+ || rld[i].when_needed == RELOAD_FOR_INPADDR_ADDRESS)
+ && rld[i].secondary_in_reload != -1)
{
- int secondary_in_reload = reload_secondary_in_reload[i];
+ int secondary_in_reload = rld[i].secondary_in_reload;
- reload_when_needed[secondary_in_reload]
- = RELOAD_FOR_OPADDR_ADDR;
+ rld[secondary_in_reload].when_needed = RELOAD_FOR_OPADDR_ADDR;
/* If there's a tertiary reload we have to change it also. */
if (secondary_in_reload > 0
- && reload_secondary_in_reload[secondary_in_reload] != -1)
- reload_when_needed[reload_secondary_in_reload[secondary_in_reload]]
+ && rld[secondary_in_reload].secondary_in_reload != -1)
+ rld[rld[secondary_in_reload].secondary_in_reload].when_needed
= RELOAD_FOR_OPADDR_ADDR;
}
- if ((reload_when_needed[i] == RELOAD_FOR_OUTPUT_ADDRESS
- || reload_when_needed[i] == RELOAD_FOR_OUTADDR_ADDRESS)
- && reload_secondary_out_reload[i] != -1)
+ if ((rld[i].when_needed == RELOAD_FOR_OUTPUT_ADDRESS
+ || rld[i].when_needed == RELOAD_FOR_OUTADDR_ADDRESS)
+ && rld[i].secondary_out_reload != -1)
{
- int secondary_out_reload = reload_secondary_out_reload[i];
+ int secondary_out_reload = rld[i].secondary_out_reload;
- reload_when_needed[secondary_out_reload]
- = RELOAD_FOR_OPADDR_ADDR;
+ rld[secondary_out_reload].when_needed = RELOAD_FOR_OPADDR_ADDR;
/* If there's a tertiary reload we have to change it also. */
if (secondary_out_reload
- && reload_secondary_out_reload[secondary_out_reload] != -1)
- reload_when_needed[reload_secondary_out_reload[secondary_out_reload]]
+ && rld[secondary_out_reload].secondary_out_reload != -1)
+ rld[rld[secondary_out_reload].secondary_out_reload].when_needed
= RELOAD_FOR_OPADDR_ADDR;
}
- if (reload_when_needed[i] == RELOAD_FOR_INPADDR_ADDRESS
- || reload_when_needed[i] == RELOAD_FOR_OUTADDR_ADDRESS)
- reload_when_needed[i] = RELOAD_FOR_OPADDR_ADDR;
+ if (rld[i].when_needed == RELOAD_FOR_INPADDR_ADDRESS
+ || rld[i].when_needed == RELOAD_FOR_OUTADDR_ADDRESS)
+ rld[i].when_needed = RELOAD_FOR_OPADDR_ADDR;
else
- reload_when_needed[i] = RELOAD_FOR_OPERAND_ADDRESS;
+ rld[i].when_needed = RELOAD_FOR_OPERAND_ADDRESS;
}
- if ((reload_when_needed[i] == RELOAD_FOR_INPUT_ADDRESS
- || reload_when_needed[i] == RELOAD_FOR_INPADDR_ADDRESS)
- && operand_reloadnum[reload_opnum[i]] >= 0
- && (reload_when_needed[operand_reloadnum[reload_opnum[i]]]
+ if ((rld[i].when_needed == RELOAD_FOR_INPUT_ADDRESS
+ || rld[i].when_needed == RELOAD_FOR_INPADDR_ADDRESS)
+ && operand_reloadnum[rld[i].opnum] >= 0
+ && (rld[operand_reloadnum[rld[i].opnum]].when_needed
== RELOAD_OTHER))
- reload_when_needed[i] = RELOAD_FOR_OTHER_ADDRESS;
+ rld[i].when_needed = RELOAD_FOR_OTHER_ADDRESS;
- if (goal_alternative_matches[reload_opnum[i]] >= 0)
- reload_opnum[i] = goal_alternative_matches[reload_opnum[i]];
+ if (goal_alternative_matches[rld[i].opnum] >= 0)
+ rld[i].opnum = goal_alternative_matches[rld[i].opnum];
}
/* Scan all the reloads, and check for RELOAD_FOR_OPERAND_ADDRESS reloads.
@@ -4106,7 +4111,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
int first_op_addr_num = -2;
int first_inpaddr_num[MAX_RECOG_OPERANDS];
int first_outpaddr_num[MAX_RECOG_OPERANDS];
- int need_change= 0;
+ int need_change = 0;
/* We use last_op_addr_reload and the contents of the above arrays
first as flags - -2 means no instance encountered, -1 means exactly
one instance encountered.
@@ -4117,7 +4122,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
first_inpaddr_num[i] = first_outpaddr_num[i] = -2;
for (i = n_reloads - 1; i >= 0; i--)
{
- switch (reload_when_needed[i])
+ switch (rld[i].when_needed)
{
case RELOAD_FOR_OPERAND_ADDRESS:
if (++first_op_addr_num >= 0)
@@ -4127,16 +4132,16 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
}
break;
case RELOAD_FOR_INPUT_ADDRESS:
- if (++first_inpaddr_num[reload_opnum[i]] >= 0)
+ if (++first_inpaddr_num[rld[i].opnum] >= 0)
{
- first_inpaddr_num[reload_opnum[i]] = i;
+ first_inpaddr_num[rld[i].opnum] = i;
need_change = 1;
}
break;
case RELOAD_FOR_OUTPUT_ADDRESS:
- if (++first_outpaddr_num[reload_opnum[i]] >= 0)
+ if (++first_outpaddr_num[rld[i].opnum] >= 0)
{
- first_outpaddr_num[reload_opnum[i]] = i;
+ first_outpaddr_num[rld[i].opnum] = i;
need_change = 1;
}
break;
@@ -4149,20 +4154,21 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
{
for (i = 0; i < n_reloads; i++)
{
- int first_num, type;
+ int first_num;
+ enum reload_type type;
- switch (reload_when_needed[i])
+ switch (rld[i].when_needed)
{
case RELOAD_FOR_OPADDR_ADDR:
first_num = first_op_addr_num;
type = RELOAD_FOR_OPERAND_ADDRESS;
break;
case RELOAD_FOR_INPADDR_ADDRESS:
- first_num = first_inpaddr_num[reload_opnum[i]];
+ first_num = first_inpaddr_num[rld[i].opnum];
type = RELOAD_FOR_INPUT_ADDRESS;
break;
case RELOAD_FOR_OUTADDR_ADDRESS:
- first_num = first_outpaddr_num[reload_opnum[i]];
+ first_num = first_outpaddr_num[rld[i].opnum];
type = RELOAD_FOR_OUTPUT_ADDRESS;
break;
default:
@@ -4171,19 +4177,19 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
if (first_num < 0)
continue;
else if (i > first_num)
- reload_when_needed[i] = type;
+ rld[i].when_needed = type;
else
{
/* Check if the only TYPE reload that uses reload I is
reload FIRST_NUM. */
for (j = n_reloads - 1; j > first_num; j--)
{
- if (reload_when_needed[j] == type
- && (reload_secondary_p[i]
- ? reload_secondary_in_reload[j] == i
- : reg_mentioned_p (reload_in[i], reload_in[j])))
+ if (rld[j].when_needed == type
+ && (rld[i].secondary_p
+ ? rld[j].secondary_in_reload == i
+ : reg_mentioned_p (rld[i].in, rld[j].in)))
{
- reload_when_needed[i] = type;
+ rld[i].when_needed = type;
break;
}
}
@@ -4198,151 +4204,64 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
check for the most common cases. */
for (i = 0; i < n_reloads; i++)
- if (reload_in[i] != 0 && reload_out[i] == 0
- && (reload_when_needed[i] == RELOAD_FOR_OPERAND_ADDRESS
- || reload_when_needed[i] == RELOAD_FOR_OPADDR_ADDR
- || reload_when_needed[i] == RELOAD_FOR_OTHER_ADDRESS))
+ if (rld[i].in != 0 && rld[i].out == 0
+ && (rld[i].when_needed == RELOAD_FOR_OPERAND_ADDRESS
+ || rld[i].when_needed == RELOAD_FOR_OPADDR_ADDR
+ || rld[i].when_needed == RELOAD_FOR_OTHER_ADDRESS))
for (j = 0; j < n_reloads; j++)
- if (i != j && reload_in[j] != 0 && reload_out[j] == 0
- && reload_when_needed[j] == reload_when_needed[i]
- && MATCHES (reload_in[i], reload_in[j])
- && reload_reg_class[i] == reload_reg_class[j]
- && !reload_nocombine[i] && !reload_nocombine[j]
- && reload_reg_rtx[i] == reload_reg_rtx[j])
+ if (i != j && rld[j].in != 0 && rld[j].out == 0
+ && rld[j].when_needed == rld[i].when_needed
+ && MATCHES (rld[i].in, rld[j].in)
+ && rld[i].class == rld[j].class
+ && !rld[i].nocombine && !rld[j].nocombine
+ && rld[i].reg_rtx == rld[j].reg_rtx)
{
- reload_opnum[i] = MIN (reload_opnum[i], reload_opnum[j]);
+ rld[i].opnum = MIN (rld[i].opnum, rld[j].opnum);
transfer_replacements (i, j);
- reload_in[j] = 0;
+ rld[j].in = 0;
}
- /* Set which reloads must use registers not used in any group. Start
- with those that conflict with a group and then include ones that
- conflict with ones that are already known to conflict with a group. */
+#ifdef HAVE_cc0
+ /* If we made any reloads for addresses, see if they violate a
+ "no input reloads" requirement for this insn. But loads that we
+ do after the insn (such as for output addresses) are fine. */
+ if (no_input_reloads)
+ for (i = 0; i < n_reloads; i++)
+ if (rld[i].in != 0
+ && rld[i].when_needed != RELOAD_FOR_OUTADDR_ADDRESS
+ && rld[i].when_needed != RELOAD_FOR_OUTPUT_ADDRESS)
+ abort ();
+#endif
- changed = 0;
+ /* Compute reload_mode and reload_nregs. */
for (i = 0; i < n_reloads; i++)
{
- enum machine_mode mode = reload_inmode[i];
- enum reg_class class = reload_reg_class[i];
- int size;
-
- if (GET_MODE_SIZE (reload_outmode[i]) > GET_MODE_SIZE (mode))
- mode = reload_outmode[i];
- size = CLASS_MAX_NREGS (class, mode);
-
- if (size == 1)
- for (j = 0; j < n_reloads; j++)
- if ((CLASS_MAX_NREGS (reload_reg_class[j],
- (GET_MODE_SIZE (reload_outmode[j])
- > GET_MODE_SIZE (reload_inmode[j]))
- ? reload_outmode[j] : reload_inmode[j])
- > 1)
- && !reload_optional[j]
- && (reload_in[j] != 0 || reload_out[j] != 0
- || reload_secondary_p[j])
- && reloads_conflict (i, j)
- && reg_classes_intersect_p (class, reload_reg_class[j]))
- {
- reload_nongroup[i] = 1;
- changed = 1;
- break;
- }
- }
-
- while (changed)
- {
- changed = 0;
+ rld[i].mode
+ = (rld[i].inmode == VOIDmode
+ || (GET_MODE_SIZE (rld[i].outmode)
+ > GET_MODE_SIZE (rld[i].inmode)))
+ ? rld[i].outmode : rld[i].inmode;
- for (i = 0; i < n_reloads; i++)
- {
- enum machine_mode mode = reload_inmode[i];
- enum reg_class class = reload_reg_class[i];
- int size;
-
- if (GET_MODE_SIZE (reload_outmode[i]) > GET_MODE_SIZE (mode))
- mode = reload_outmode[i];
- size = CLASS_MAX_NREGS (class, mode);
-
- if (! reload_nongroup[i] && size == 1)
- for (j = 0; j < n_reloads; j++)
- if (reload_nongroup[j]
- && reloads_conflict (i, j)
- && reg_classes_intersect_p (class, reload_reg_class[j]))
- {
- reload_nongroup[i] = 1;
- changed = 1;
- break;
- }
- }
+ rld[i].nregs = CLASS_MAX_NREGS (rld[i].class, rld[i].mode);
}
-#else /* no REGISTER_CONSTRAINTS */
- int noperands;
- int insn_code_number;
- int goal_earlyclobber = 0; /* Always 0, to make combine_reloads happen. */
- register int i;
- rtx body = PATTERN (insn);
- int retval = 0;
-
- n_reloads = 0;
- n_replacements = 0;
- n_earlyclobbers = 0;
- replace_reloads = replace;
- this_insn = insn;
-
- extract_insn (insn);
-
- noperands = reload_n_operands = recog_n_operands;
-
- /* Return if the insn needs no reload processing. */
- if (noperands == 0)
- return;
-
- for (i = 0; i < noperands; i++)
- {
- register RTX_CODE code = GET_CODE (recog_operand[i]);
- int is_set_dest = GET_CODE (body) == SET && (i == 0);
+ /* Special case a simple move with an input reload and a
+ destination of a hard reg, if the hard reg is ok, use it. */
+ for (i = 0; i < n_reloads; i++)
+ if (rld[i].when_needed == RELOAD_FOR_INPUT
+ && GET_CODE (PATTERN (insn)) == SET
+ && GET_CODE (SET_DEST (PATTERN (insn))) == REG
+ && SET_SRC (PATTERN (insn)) == rld[i].in)
+ {
+ rtx dest = SET_DEST (PATTERN (insn));
+ unsigned int regno = REGNO (dest);
- if (insn_code_number >= 0)
- if (insn_operand_address_p[insn_code_number][i])
- find_reloads_address (VOIDmode, NULL_PTR,
- recog_operand[i], recog_operand_loc[i],
- i, RELOAD_FOR_INPUT, ind_levels, insn);
-
- /* In these cases, we can't tell if the operand is an input
- or an output, so be conservative. In practice it won't be
- problem. */
-
- if (code == MEM)
- find_reloads_address (GET_MODE (recog_operand[i]),
- recog_operand_loc[i],
- XEXP (recog_operand[i], 0),
- &XEXP (recog_operand[i], 0),
- i, RELOAD_OTHER, ind_levels, insn);
- if (code == SUBREG)
- recog_operand[i] = *recog_operand_loc[i]
- = find_reloads_toplev (recog_operand[i], i, RELOAD_OTHER,
- ind_levels, is_set_dest);
- if (code == REG)
- {
- register int regno = REGNO (recog_operand[i]);
- if (reg_equiv_constant[regno] != 0 && !is_set_dest)
- recog_operand[i] = *recog_operand_loc[i]
- = reg_equiv_constant[regno];
-#if 0 /* This might screw code in reload1.c to delete prior output-reload
- that feeds this insn. */
- if (reg_equiv_mem[regno] != 0)
- recog_operand[i] = *recog_operand_loc[i]
- = reg_equiv_mem[regno];
-#endif
- }
- }
+ if (regno < FIRST_PSEUDO_REGISTER
+ && TEST_HARD_REG_BIT (reg_class_contents[rld[i].class], regno)
+ && HARD_REGNO_MODE_OK (regno, rld[i].mode))
+ rld[i].reg_rtx = dest;
+ }
- /* Perhaps an output reload can be combined with another
- to reduce needs by one. */
- if (!goal_earlyclobber)
- combine_reloads ();
-#endif /* no REGISTER_CONSTRAINTS */
return retval;
}
@@ -4354,7 +4273,7 @@ alternative_allows_memconst (constraint, altnum)
const char *constraint;
int altnum;
{
- register int c;
+ int c;
/* Skip alternatives before the one requested. */
while (altnum > 0)
{
@@ -4386,32 +4305,37 @@ alternative_allows_memconst (constraint, altnum)
INSN, if nonzero, is the insn in which we do the reload. It is used
to determine if we may generate output reloads, and where to put USEs
- for pseudos that we have to replace with stack slots. */
+ for pseudos that we have to replace with stack slots.
+
+ ADDRESS_RELOADED. If nonzero, is a pointer to where we put the
+ result of find_reloads_address. */
static rtx
-find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest, insn)
+find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest, insn,
+ address_reloaded)
rtx x;
int opnum;
enum reload_type type;
int ind_levels;
int is_set_dest;
rtx insn;
+ int *address_reloaded;
{
- register RTX_CODE code = GET_CODE (x);
+ RTX_CODE code = GET_CODE (x);
- register char *fmt = GET_RTX_FORMAT (code);
- register int i;
+ const char *fmt = GET_RTX_FORMAT (code);
+ int i;
int copied;
if (code == REG)
{
/* This code is duplicated for speed in find_reloads. */
- register int regno = REGNO (x);
+ int regno = REGNO (x);
if (reg_equiv_constant[regno] != 0 && !is_set_dest)
x = reg_equiv_constant[regno];
#if 0
-/* This creates (subreg (mem...)) which would cause an unnecessary
- reload of the mem. */
+ /* This creates (subreg (mem...)) which would cause an unnecessary
+ reload of the mem. */
else if (reg_equiv_mem[regno] != 0)
x = reg_equiv_mem[regno];
#endif
@@ -4425,11 +4349,17 @@ find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest, insn)
/* If this is not a toplevel operand, find_reloads doesn't see
this substitution. We have to emit a USE of the pseudo so
that delete_output_reload can see it. */
- if (replace_reloads && recog_operand[opnum] != x)
- emit_insn_before (gen_rtx_USE (VOIDmode, x), insn);
+ if (replace_reloads && recog_data.operand[opnum] != x)
+ /* We mark the USE with QImode so that we recognize it
+ as one that can be safely deleted at the end of
+ reload. */
+ PUT_MODE (emit_insn_before (gen_rtx_USE (VOIDmode, x), insn),
+ QImode);
x = mem;
- find_reloads_address (GET_MODE (x), &x, XEXP (x, 0), &XEXP (x, 0),
- opnum, type, ind_levels, insn);
+ i = find_reloads_address (GET_MODE (x), &x, XEXP (x, 0), &XEXP (x, 0),
+ opnum, type, ind_levels, insn);
+ if (address_reloaded)
+ *address_reloaded = i;
}
}
return x;
@@ -4437,14 +4367,18 @@ find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest, insn)
if (code == MEM)
{
rtx tem = x;
- find_reloads_address (GET_MODE (x), &tem, XEXP (x, 0), &XEXP (x, 0),
- opnum, type, ind_levels, insn);
+
+ i = find_reloads_address (GET_MODE (x), &tem, XEXP (x, 0), &XEXP (x, 0),
+ opnum, type, ind_levels, insn);
+ if (address_reloaded)
+ *address_reloaded = i;
+
return tem;
}
if (code == SUBREG && GET_CODE (SUBREG_REG (x)) == REG)
{
- /* Check for SUBREG containing a REG that's equivalent to a constant.
+ /* Check for SUBREG containing a REG that's equivalent to a constant.
If the constant has a known value, truncate it right now.
Similarly if we are extracting a single-word of a multi-word
constant. If the constant is symbolic, allow it to be substituted
@@ -4453,7 +4387,7 @@ find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest, insn)
the register (this should never happen because one of the cases
above should handle it). */
- register int regno = REGNO (SUBREG_REG (x));
+ int regno = REGNO (SUBREG_REG (x));
rtx tem;
if (subreg_lowpart_p (x)
@@ -4467,7 +4401,7 @@ find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest, insn)
&& regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] < 0
&& reg_equiv_constant[regno] != 0
&& (tem = operand_subword (reg_equiv_constant[regno],
- SUBREG_WORD (x), 0,
+ SUBREG_BYTE (x) / UNITS_PER_WORD, 0,
GET_MODE (SUBREG_REG (x)))) != 0)
{
/* TEM is now a word sized constant for the bits from X that
@@ -4492,18 +4426,18 @@ find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest, insn)
&& GET_CODE (reg_equiv_constant[regno]) == CONST_INT
&& (GET_MODE_SIZE (GET_MODE (x))
< GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))))
- {
- int shift = SUBREG_WORD (x) * BITS_PER_WORD;
- if (WORDS_BIG_ENDIAN)
- shift = (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x)))
- - GET_MODE_BITSIZE (GET_MODE (x))
- - shift);
- /* Here we use the knowledge that CONST_INTs have a
- HOST_WIDE_INT field. */
- if (shift >= HOST_BITS_PER_WIDE_INT)
- shift = HOST_BITS_PER_WIDE_INT - 1;
- return GEN_INT (INTVAL (reg_equiv_constant[regno]) >> shift);
- }
+ {
+ int shift = SUBREG_BYTE (x) * BITS_PER_UNIT;
+ if (WORDS_BIG_ENDIAN)
+ shift = (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x)))
+ - GET_MODE_BITSIZE (GET_MODE (x))
+ - shift);
+ /* Here we use the knowledge that CONST_INTs have a
+ HOST_WIDE_INT field. */
+ if (shift >= HOST_BITS_PER_WIDE_INT)
+ shift = HOST_BITS_PER_WIDE_INT - 1;
+ return GEN_INT (INTVAL (reg_equiv_constant[regno]) >> shift);
+ }
if (regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] < 0
&& reg_equiv_constant[regno] != 0
@@ -4530,7 +4464,7 @@ find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest, insn)
#endif
&& (reg_equiv_address[regno] != 0
|| (reg_equiv_mem[regno] != 0
- && (! strict_memory_address_p (GET_MODE (x),
+ && (! strict_memory_address_p (GET_MODE (x),
XEXP (reg_equiv_mem[regno], 0))
|| ! offsettable_memref_p (reg_equiv_mem[regno])
|| num_not_at_initial_offset))))
@@ -4543,7 +4477,8 @@ find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest, insn)
if (fmt[i] == 'e')
{
rtx new_part = find_reloads_toplev (XEXP (x, i), opnum, type,
- ind_levels, is_set_dest, insn);
+ ind_levels, is_set_dest, insn,
+ address_reloaded);
/* If we have replaced a reg with it's equivalent memory loc -
that can still be handled here e.g. if it's in a paradoxical
subreg - we must make the change in a copy, rather than using
@@ -4575,11 +4510,16 @@ make_memloc (ad, regno)
/* If TEM might contain a pseudo, we must copy it to avoid
modifying it when we do the substitution for the reload. */
- if (rtx_varies_p (tem))
+ if (rtx_varies_p (tem, 0))
tem = copy_rtx (tem);
- tem = gen_rtx_MEM (GET_MODE (ad), tem);
- RTX_UNCHANGING_P (tem) = RTX_UNCHANGING_P (regno_reg_rtx[regno]);
+ tem = replace_equiv_address_nv (reg_equiv_memory_loc[regno], tem);
+ tem = adjust_address_nv (tem, GET_MODE (ad), 0);
+
+ /* Copy the result if it's still the same as the equivalence, to avoid
+ modifying it when we do the substitution for the reload. */
+ if (tem == reg_equiv_memory_loc[regno])
+ tem = copy_rtx (tem);
return tem;
}
@@ -4618,7 +4558,7 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels, insn)
int ind_levels;
rtx insn;
{
- register int regno;
+ int regno;
int removed_and = 0;
rtx tem;
@@ -4630,10 +4570,14 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels, insn)
{
regno = REGNO (ad);
- if (reg_equiv_constant[regno] != 0
- && strict_memory_address_p (mode, reg_equiv_constant[regno]))
+ /* If the register is equivalent to an invariant expression, substitute
+ the invariant, and eliminate any eliminable register references. */
+ tem = reg_equiv_constant[regno];
+ if (tem != 0
+ && (tem = eliminate_regs (tem, mode, insn))
+ && strict_memory_address_p (mode, tem))
{
- *loc = ad = reg_equiv_constant[regno];
+ *loc = ad = tem;
return 0;
}
@@ -4645,7 +4589,7 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels, insn)
tem = make_memloc (ad, regno);
if (! strict_memory_address_p (GET_MODE (tem), XEXP (tem, 0)))
{
- find_reloads_address (GET_MODE (tem), NULL_PTR, XEXP (tem, 0),
+ find_reloads_address (GET_MODE (tem), (rtx*) 0, XEXP (tem, 0),
&XEXP (tem, 0), opnum, ADDR_TYPE (type),
ind_levels, insn);
}
@@ -4669,7 +4613,12 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels, insn)
&& ! rtx_equal_p (tem, reg_equiv_mem[regno]))
{
*loc = tem;
- emit_insn_before (gen_rtx_USE (VOIDmode, ad), insn);
+ /* We mark the USE with QImode so that we
+ recognize it as one that can be safely
+ deleted at the end of reload. */
+ PUT_MODE (emit_insn_before (gen_rtx_USE (VOIDmode, ad),
+ insn), QImode);
+
/* This doesn't really count as replacing the address
as a whole, since it is still a memory access. */
}
@@ -4685,11 +4634,11 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels, insn)
else if (regno < FIRST_PSEUDO_REGISTER
&& REGNO_MODE_OK_FOR_BASE_P (regno, mode)
- && ! regno_clobbered_p (regno, this_insn, GET_MODE (ad), 0))
+ && ! regno_clobbered_p (regno, this_insn, mode, 0))
return 0;
/* If we do not have one of the cases above, we must do the reload. */
- push_reload (ad, NULL_RTX, loc, NULL_PTR, BASE_REG_CLASS,
+ push_reload (ad, NULL_RTX, loc, (rtx*) 0, MODE_BASE_REG_CLASS (mode),
GET_MODE (ad), VOIDmode, 0, 0, opnum, type);
return 1;
}
@@ -4789,8 +4738,8 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels, insn)
{
/* Must use TEM here, not AD, since it is the one that will
have any subexpressions reloaded, if needed. */
- push_reload (tem, NULL_RTX, loc, NULL_PTR,
- BASE_REG_CLASS, GET_MODE (tem),
+ push_reload (tem, NULL_RTX, loc, (rtx*) 0,
+ MODE_BASE_REG_CLASS (mode), GET_MODE (tem),
VOIDmode, 0,
0, opnum, type);
return ! removed_and;
@@ -4836,7 +4785,7 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels, insn)
/* If the sum of two regs is not necessarily valid,
reload the sum into a base reg.
That will at least work. */
- find_reloads_address_part (ad, loc, BASE_REG_CLASS,
+ find_reloads_address_part (ad, loc, MODE_BASE_REG_CLASS (mode),
Pmode, opnum, type, ind_levels);
}
return ! removed_and;
@@ -4845,7 +4794,7 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels, insn)
/* If we have an indexed stack slot, there are three possible reasons why
it might be invalid: The index might need to be reloaded, the address
might have been made by frame pointer elimination and hence have a
- constant out of range, or both reasons might apply.
+ constant out of range, or both reasons might apply.
We can easily check for an index needing reload, but even if that is the
case, we might also have an invalid constant. To avoid making the
@@ -4854,14 +4803,6 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels, insn)
that the index needs a reload and find_reloads_address_1 will take care
of it.
- There is still a case when we might generate an extra reload,
- however. In certain cases eliminate_regs will return a MEM for a REG
- (see the code there for details). In those cases, memory_address_p
- applied to our address will return 0 so we will think that our offset
- must be too large. But it might indeed be valid and the only problem
- is that a MEM is present where a REG should be. This case should be
- very rare and there doesn't seem to be any way to avoid it.
-
If we decide to do something here, it must be that
`double_reg_address_ok' is true and that this address rtl was made by
eliminate_regs. We generate a reload of the fp/sp/ap + constant and
@@ -4886,15 +4827,16 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels, insn)
*loc = ad = gen_rtx_PLUS (GET_MODE (ad),
plus_constant (XEXP (XEXP (ad, 0), 0),
INTVAL (XEXP (ad, 1))),
- XEXP (XEXP (ad, 0), 1));
- find_reloads_address_part (XEXP (ad, 0), &XEXP (ad, 0), BASE_REG_CLASS,
+ XEXP (XEXP (ad, 0), 1));
+ find_reloads_address_part (XEXP (ad, 0), &XEXP (ad, 0),
+ MODE_BASE_REG_CLASS (mode),
GET_MODE (ad), opnum, type, ind_levels);
find_reloads_address_1 (mode, XEXP (ad, 1), 1, &XEXP (ad, 1), opnum,
type, 0, insn);
return 0;
}
-
+
else if (GET_CODE (ad) == PLUS && GET_CODE (XEXP (ad, 1)) == CONST_INT
&& GET_CODE (XEXP (ad, 0)) == PLUS
&& (XEXP (XEXP (ad, 0), 1) == frame_pointer_rtx
@@ -4911,14 +4853,15 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels, insn)
XEXP (XEXP (ad, 0), 0),
plus_constant (XEXP (XEXP (ad, 0), 1),
INTVAL (XEXP (ad, 1))));
- find_reloads_address_part (XEXP (ad, 1), &XEXP (ad, 1), BASE_REG_CLASS,
+ find_reloads_address_part (XEXP (ad, 1), &XEXP (ad, 1),
+ MODE_BASE_REG_CLASS (mode),
GET_MODE (ad), opnum, type, ind_levels);
find_reloads_address_1 (mode, XEXP (ad, 0), 1, &XEXP (ad, 0), opnum,
type, 0, insn);
return 0;
}
-
+
/* See if address becomes valid when an eliminable register
in a sum is replaced. */
@@ -4946,7 +4889,7 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels, insn)
into a register. */
if (CONSTANT_P (ad) && ! strict_memory_address_p (mode, ad))
{
- /* If AD is in address in the constant pool, the MEM rtx may be shared.
+ /* If AD is an address in the constant pool, the MEM rtx may be shared.
Unshare it so we can safely alter it. */
if (memrefloc && GET_CODE (ad) == SYMBOL_REF
&& CONSTANT_POOL_ADDRESS_P (ad))
@@ -4957,8 +4900,8 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels, insn)
loc = &XEXP (*loc, 0);
}
- find_reloads_address_part (ad, loc, BASE_REG_CLASS, Pmode, opnum, type,
- ind_levels);
+ find_reloads_address_part (ad, loc, MODE_BASE_REG_CLASS (mode),
+ Pmode, opnum, type, ind_levels);
return ! removed_and;
}
@@ -4977,9 +4920,9 @@ subst_reg_equivs (ad, insn)
rtx ad;
rtx insn;
{
- register RTX_CODE code = GET_CODE (ad);
- register int i;
- register char *fmt;
+ RTX_CODE code = GET_CODE (ad);
+ int i;
+ const char *fmt;
switch (code)
{
@@ -4995,7 +4938,7 @@ subst_reg_equivs (ad, insn)
case REG:
{
- register int regno = REGNO (ad);
+ int regno = REGNO (ad);
if (reg_equiv_constant[regno] != 0)
{
@@ -5008,7 +4951,11 @@ subst_reg_equivs (ad, insn)
if (! rtx_equal_p (mem, reg_equiv_mem[regno]))
{
subst_reg_equivs_changed = 1;
- emit_insn_before (gen_rtx_USE (VOIDmode, ad), insn);
+ /* We mark the USE with QImode so that we recognize it
+ as one that can be safely deleted at the end of
+ reload. */
+ PUT_MODE (emit_insn_before (gen_rtx_USE (VOIDmode, ad), insn),
+ QImode);
return mem;
}
}
@@ -5021,7 +4968,7 @@ subst_reg_equivs (ad, insn)
&& GET_CODE (XEXP (ad, 1)) == CONST_INT)
return ad;
break;
-
+
default:
break;
}
@@ -5113,9 +5060,9 @@ subst_indexed_address (addr)
&& reg_equiv_constant[regno] != 0)
op0 = reg_equiv_constant[regno];
else if (GET_CODE (op1) == REG
- && (regno = REGNO (op1)) >= FIRST_PSEUDO_REGISTER
- && reg_renumber[regno] < 0
- && reg_equiv_constant[regno] != 0)
+ && (regno = REGNO (op1)) >= FIRST_PSEUDO_REGISTER
+ && reg_renumber[regno] < 0
+ && reg_equiv_constant[regno] != 0)
op1 = reg_equiv_constant[regno];
else if (GET_CODE (op0) == PLUS
&& (tem = subst_indexed_address (op0)) != op0)
@@ -5143,6 +5090,32 @@ subst_indexed_address (addr)
return addr;
}
+/* Update the REG_INC notes for an insn. It updates all REG_INC
+ notes for the instruction which refer to REGNO the to refer
+ to the reload number.
+
+ INSN is the insn for which any REG_INC notes need updating.
+
+ REGNO is the register number which has been reloaded.
+
+ RELOADNUM is the reload number. */
+
+static void
+update_auto_inc_notes (insn, regno, reloadnum)
+ rtx insn ATTRIBUTE_UNUSED;
+ int regno ATTRIBUTE_UNUSED;
+ int reloadnum ATTRIBUTE_UNUSED;
+{
+#ifdef AUTO_INC_DEC
+ rtx link;
+
+ for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
+ if (REG_NOTE_KIND (link) == REG_INC
+ && REGNO (XEXP (link, 0)) == regno)
+ push_replacement (&XEXP (link, 0), reloadnum, VOIDmode);
+#endif
+}
+
/* Record the pseudo registers we must reload into hard registers in a
subexpression of a would-be memory address, X referring to a value
in mode MODE. (This function is not called if the address we find
@@ -5164,7 +5137,7 @@ subst_indexed_address (addr)
/* Note that we take shortcuts assuming that no multi-reg machine mode
occurs as part of an address.
Also, this is not fully machine-customizable; it works for machines
- such as vaxes and 68000's and 32000's, but other possible machines
+ such as VAXen and 68000's and 32000's, but other possible machines
could have addressing modes that this does not handle right. */
static int
@@ -5178,18 +5151,18 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn)
int ind_levels;
rtx insn;
{
- register RTX_CODE code = GET_CODE (x);
+ RTX_CODE code = GET_CODE (x);
switch (code)
{
case PLUS:
{
- register rtx orig_op0 = XEXP (x, 0);
- register rtx orig_op1 = XEXP (x, 1);
- register RTX_CODE code0 = GET_CODE (orig_op0);
- register RTX_CODE code1 = GET_CODE (orig_op1);
- register rtx op0 = orig_op0;
- register rtx op1 = orig_op1;
+ rtx orig_op0 = XEXP (x, 0);
+ rtx orig_op1 = XEXP (x, 1);
+ RTX_CODE code0 = GET_CODE (orig_op0);
+ RTX_CODE code1 = GET_CODE (orig_op1);
+ rtx op0 = orig_op0;
+ rtx op1 = orig_op1;
if (GET_CODE (op0) == SUBREG)
{
@@ -5197,7 +5170,11 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn)
code0 = GET_CODE (op0);
if (code0 == REG && REGNO (op0) < FIRST_PSEUDO_REGISTER)
op0 = gen_rtx_REG (word_mode,
- REGNO (op0) + SUBREG_WORD (orig_op0));
+ (REGNO (op0) +
+ subreg_regno_offset (REGNO (SUBREG_REG (orig_op0)),
+ GET_MODE (SUBREG_REG (orig_op0)),
+ SUBREG_BYTE (orig_op0),
+ GET_MODE (orig_op0))));
}
if (GET_CODE (op1) == SUBREG)
@@ -5205,11 +5182,17 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn)
op1 = SUBREG_REG (op1);
code1 = GET_CODE (op1);
if (code1 == REG && REGNO (op1) < FIRST_PSEUDO_REGISTER)
+ /* ??? Why is this given op1's mode and above for
+ ??? op0 SUBREGs we use word_mode? */
op1 = gen_rtx_REG (GET_MODE (op1),
- REGNO (op1) + SUBREG_WORD (orig_op1));
+ (REGNO (op1) +
+ subreg_regno_offset (REGNO (SUBREG_REG (orig_op1)),
+ GET_MODE (SUBREG_REG (orig_op1)),
+ SUBREG_BYTE (orig_op1),
+ GET_MODE (orig_op1))));
}
- if (code0 == MULT || code0 == SIGN_EXTEND || code0 == TRUNCATE
+ if (code0 == MULT || code0 == SIGN_EXTEND || code0 == TRUNCATE
|| code0 == ZERO_EXTEND || code1 == MEM)
{
find_reloads_address_1 (mode, orig_op0, 1, &XEXP (x, 0), opnum,
@@ -5285,13 +5268,102 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn)
return 0;
+ case POST_MODIFY:
+ case PRE_MODIFY:
+ {
+ rtx op0 = XEXP (x, 0);
+ rtx op1 = XEXP (x, 1);
+
+ if (GET_CODE (op1) != PLUS && GET_CODE (op1) != MINUS)
+ return 0;
+
+ /* Currently, we only support {PRE,POST}_MODIFY constructs
+ where a base register is {inc,dec}remented by the contents
+ of another register or by a constant value. Thus, these
+ operands must match. */
+ if (op0 != XEXP (op1, 0))
+ abort ();
+
+ /* Require index register (or constant). Let's just handle the
+ register case in the meantime... If the target allows
+ auto-modify by a constant then we could try replacing a pseudo
+ register with its equivalent constant where applicable. */
+ if (REG_P (XEXP (op1, 1)))
+ if (!REGNO_OK_FOR_INDEX_P (REGNO (XEXP (op1, 1))))
+ find_reloads_address_1 (mode, XEXP (op1, 1), 1, &XEXP (op1, 1),
+ opnum, type, ind_levels, insn);
+
+ if (REG_P (XEXP (op1, 0)))
+ {
+ int regno = REGNO (XEXP (op1, 0));
+ int reloadnum;
+
+ /* A register that is incremented cannot be constant! */
+ if (regno >= FIRST_PSEUDO_REGISTER
+ && reg_equiv_constant[regno] != 0)
+ abort ();
+
+ /* Handle a register that is equivalent to a memory location
+ which cannot be addressed directly. */
+ if (reg_equiv_memory_loc[regno] != 0
+ && (reg_equiv_address[regno] != 0
+ || num_not_at_initial_offset))
+ {
+ rtx tem = make_memloc (XEXP (x, 0), regno);
+
+ if (reg_equiv_address[regno]
+ || ! rtx_equal_p (tem, reg_equiv_mem[regno]))
+ {
+ /* First reload the memory location's address.
+ We can't use ADDR_TYPE (type) here, because we need to
+ write back the value after reading it, hence we actually
+ need two registers. */
+ find_reloads_address (GET_MODE (tem), 0, XEXP (tem, 0),
+ &XEXP (tem, 0), opnum,
+ RELOAD_OTHER,
+ ind_levels, insn);
+
+ /* Then reload the memory location into a base
+ register. */
+ reloadnum = push_reload (tem, tem, &XEXP (x, 0),
+ &XEXP (op1, 0),
+ MODE_BASE_REG_CLASS (mode),
+ GET_MODE (x), GET_MODE (x), 0,
+ 0, opnum, RELOAD_OTHER);
+
+ update_auto_inc_notes (this_insn, regno, reloadnum);
+ return 0;
+ }
+ }
+
+ if (reg_renumber[regno] >= 0)
+ regno = reg_renumber[regno];
+
+ /* We require a base register here... */
+ if (!REGNO_MODE_OK_FOR_BASE_P (regno, GET_MODE (x)))
+ {
+ reloadnum = push_reload (XEXP (op1, 0), XEXP (x, 0),
+ &XEXP (op1, 0), &XEXP (x, 0),
+ MODE_BASE_REG_CLASS (mode),
+ GET_MODE (x), GET_MODE (x), 0, 0,
+ opnum, RELOAD_OTHER);
+
+ update_auto_inc_notes (this_insn, regno, reloadnum);
+ return 0;
+ }
+ }
+ else
+ abort ();
+ }
+ return 0;
+
case POST_INC:
case POST_DEC:
case PRE_INC:
case PRE_DEC:
if (GET_CODE (XEXP (x, 0)) == REG)
{
- register int regno = REGNO (XEXP (x, 0));
+ int regno = REGNO (XEXP (x, 0));
int value = 0;
rtx x_orig = x;
@@ -5339,9 +5411,6 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn)
|| !(context ? REGNO_OK_FOR_INDEX_P (regno)
: REGNO_MODE_OK_FOR_BASE_P (regno, mode))))
{
-#ifdef AUTO_INC_DEC
- register rtx link;
-#endif
int reloadnum;
/* If we can output the register afterwards, do so, this
@@ -5362,8 +5431,10 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn)
&& ! sets_cc0_p (PATTERN (insn))
#endif
&& ! (icode != CODE_FOR_nothing
- && (*insn_operand_predicate[icode][0]) (equiv, Pmode)
- && (*insn_operand_predicate[icode][1]) (equiv, Pmode)))
+ && ((*insn_data[icode].operand[0].predicate)
+ (equiv, Pmode))
+ && ((*insn_data[icode].operand[1].predicate)
+ (equiv, Pmode))))
{
/* We use the original pseudo for loc, so that
emit_reload_insns() knows which pseudo this
@@ -5374,33 +5445,27 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn)
x = XEXP (x, 0);
reloadnum
= push_reload (x, x, loc, loc,
- (context ? INDEX_REG_CLASS : BASE_REG_CLASS),
- GET_MODE (x), GET_MODE (x), 0, 0,
- opnum, RELOAD_OTHER);
-
+ (context ? INDEX_REG_CLASS :
+ MODE_BASE_REG_CLASS (mode)),
+ GET_MODE (x), GET_MODE (x), 0, 0,
+ opnum, RELOAD_OTHER);
}
else
{
reloadnum
- = push_reload (x, NULL_RTX, loc, NULL_PTR,
- (context ? INDEX_REG_CLASS : BASE_REG_CLASS),
+ = push_reload (x, NULL_RTX, loc, (rtx*) 0,
+ (context ? INDEX_REG_CLASS :
+ MODE_BASE_REG_CLASS (mode)),
GET_MODE (x), GET_MODE (x), 0, 0,
opnum, type);
- reload_inc[reloadnum]
+ rld[reloadnum].inc
= find_inc_amount (PATTERN (this_insn), XEXP (x_orig, 0));
-
+
value = 1;
}
-#ifdef AUTO_INC_DEC
- /* Update the REG_INC notes. */
-
- for (link = REG_NOTES (this_insn);
- link; link = XEXP (link, 1))
- if (REG_NOTE_KIND (link) == REG_INC
- && REGNO (XEXP (link, 0)) == REGNO (XEXP (x_orig, 0)))
- push_replacement (&XEXP (link, 0), reloadnum, VOIDmode);
-#endif
+ update_auto_inc_notes (this_insn, REGNO (XEXP (x_orig, 0)),
+ reloadnum);
}
return value;
}
@@ -5411,9 +5476,9 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn)
of an equivalent address for a pseudo that was not allocated to a
hard register. Verify that the specified address is valid and
reload it into a register. */
- /* Variable `tem' might or might not be used in FIND_REG_INC_NOTE. */
+ /* Variable `tem' might or might not be used in FIND_REG_INC_NOTE. */
rtx tem ATTRIBUTE_UNUSED = XEXP (x, 0);
- register rtx link;
+ rtx link;
int reloadnum;
/* Since we know we are going to reload this item, don't decrement
@@ -5429,10 +5494,11 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn)
XEXP (XEXP (x, 0), 0), &XEXP (XEXP (x, 0), 0),
opnum, type, ind_levels, insn);
- reloadnum = push_reload (x, NULL_RTX, loc, NULL_PTR,
- (context ? INDEX_REG_CLASS : BASE_REG_CLASS),
+ reloadnum = push_reload (x, NULL_RTX, loc, (rtx*) 0,
+ (context ? INDEX_REG_CLASS :
+ MODE_BASE_REG_CLASS (mode)),
GET_MODE (x), VOIDmode, 0, 0, opnum, type);
- reload_inc[reloadnum]
+ rld[reloadnum].inc
= find_inc_amount (PATTERN (this_insn), XEXP (x, 0));
link = FIND_REG_INC_NOTE (this_insn, tem);
@@ -5458,19 +5524,20 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn)
find_reloads_address (GET_MODE (x), loc, XEXP (x, 0), &XEXP (x, 0),
opnum, ADDR_TYPE (type), ind_levels, insn);
- push_reload (*loc, NULL_RTX, loc, NULL_PTR,
- (context ? INDEX_REG_CLASS : BASE_REG_CLASS),
+ push_reload (*loc, NULL_RTX, loc, (rtx*) 0,
+ (context ? INDEX_REG_CLASS : MODE_BASE_REG_CLASS (mode)),
GET_MODE (x), VOIDmode, 0, 0, opnum, type);
return 1;
case REG:
{
- register int regno = REGNO (x);
+ int regno = REGNO (x);
if (reg_equiv_constant[regno] != 0)
{
find_reloads_address_part (reg_equiv_constant[regno], loc,
- (context ? INDEX_REG_CLASS : BASE_REG_CLASS),
+ (context ? INDEX_REG_CLASS :
+ MODE_BASE_REG_CLASS (mode)),
GET_MODE (x), opnum, type, ind_levels);
return 1;
}
@@ -5479,8 +5546,9 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn)
that feeds this insn. */
if (reg_equiv_mem[regno] != 0)
{
- push_reload (reg_equiv_mem[regno], NULL_RTX, loc, NULL_PTR,
- (context ? INDEX_REG_CLASS : BASE_REG_CLASS),
+ push_reload (reg_equiv_mem[regno], NULL_RTX, loc, (rtx*) 0,
+ (context ? INDEX_REG_CLASS :
+ MODE_BASE_REG_CLASS (mode)),
GET_MODE (x), VOIDmode, 0, 0, opnum, type);
return 1;
}
@@ -5507,8 +5575,8 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn)
|| !(context ? REGNO_OK_FOR_INDEX_P (regno)
: REGNO_MODE_OK_FOR_BASE_P (regno, mode))))
{
- push_reload (x, NULL_RTX, loc, NULL_PTR,
- (context ? INDEX_REG_CLASS : BASE_REG_CLASS),
+ push_reload (x, NULL_RTX, loc, (rtx*) 0,
+ (context ? INDEX_REG_CLASS : MODE_BASE_REG_CLASS (mode)),
GET_MODE (x), VOIDmode, 0, 0, opnum, type);
return 1;
}
@@ -5519,8 +5587,8 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn)
from before this insn to after it. */
if (regno_clobbered_p (regno, this_insn, GET_MODE (x), 0))
{
- push_reload (x, NULL_RTX, loc, NULL_PTR,
- (context ? INDEX_REG_CLASS : BASE_REG_CLASS),
+ push_reload (x, NULL_RTX, loc, (rtx*) 0,
+ (context ? INDEX_REG_CLASS : MODE_BASE_REG_CLASS (mode)),
GET_MODE (x), VOIDmode, 0, 0, opnum, type);
return 1;
}
@@ -5535,13 +5603,14 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn)
needless copies if SUBREG_REG is multi-word. */
if (REGNO (SUBREG_REG (x)) < FIRST_PSEUDO_REGISTER)
{
- int regno = REGNO (SUBREG_REG (x)) + SUBREG_WORD (x);
+ int regno = subreg_regno (x);
if (! (context ? REGNO_OK_FOR_INDEX_P (regno)
: REGNO_MODE_OK_FOR_BASE_P (regno, mode)))
{
- push_reload (x, NULL_RTX, loc, NULL_PTR,
- (context ? INDEX_REG_CLASS : BASE_REG_CLASS),
+ push_reload (x, NULL_RTX, loc, (rtx*) 0,
+ (context ? INDEX_REG_CLASS :
+ MODE_BASE_REG_CLASS (mode)),
GET_MODE (x), VOIDmode, 0, 0, opnum, type);
return 1;
}
@@ -5551,27 +5620,27 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn)
else
{
enum reg_class class = (context ? INDEX_REG_CLASS
- : BASE_REG_CLASS);
+ : MODE_BASE_REG_CLASS (mode));
if (CLASS_MAX_NREGS (class, GET_MODE (SUBREG_REG (x)))
> reg_class_size[class])
{
x = find_reloads_subreg_address (x, 0, opnum, type,
ind_levels, insn);
- push_reload (x, NULL_RTX, loc, NULL_PTR, class,
+ push_reload (x, NULL_RTX, loc, (rtx*) 0, class,
GET_MODE (x), VOIDmode, 0, 0, opnum, type);
return 1;
}
}
}
break;
-
+
default:
break;
}
{
- register char *fmt = GET_RTX_FORMAT (code);
- register int i;
+ const char *fmt = GET_RTX_FORMAT (code);
+ int i;
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
@@ -5615,18 +5684,7 @@ find_reloads_address_part (x, loc, class, mode, opnum, type, ind_levels)
{
rtx tem;
- /* If this is a CONST_INT, it could have been created by a
- plus_constant call in eliminate_regs, which means it may be
- on the reload_obstack. reload_obstack will be freed later, so
- we can't allow such RTL to be put in the constant pool. There
- is code in force_const_mem to check for this case, but it doesn't
- work because we have already popped off the reload_obstack, so
- rtl_obstack == saveable_obstack is true at this point. */
- if (GET_CODE (x) == CONST_INT)
- tem = x = force_const_mem (mode, GEN_INT (INTVAL (x)));
- else
- tem = x = force_const_mem (mode, x);
-
+ tem = x = force_const_mem (mode, x);
find_reloads_address (mode, &tem, XEXP (tem, 0), &XEXP (tem, 0),
opnum, type, ind_levels, 0);
}
@@ -5638,18 +5696,13 @@ find_reloads_address_part (x, loc, class, mode, opnum, type, ind_levels)
{
rtx tem;
- /* See comment above. */
- if (GET_CODE (XEXP (x, 1)) == CONST_INT)
- tem = force_const_mem (GET_MODE (x), GEN_INT (INTVAL (XEXP (x, 1))));
- else
- tem = force_const_mem (GET_MODE (x), XEXP (x, 1));
-
+ tem = force_const_mem (GET_MODE (x), XEXP (x, 1));
x = gen_rtx_PLUS (GET_MODE (x), XEXP (x, 0), tem);
find_reloads_address (mode, &tem, XEXP (tem, 0), &XEXP (tem, 0),
opnum, type, ind_levels, 0);
}
- push_reload (x, NULL_RTX, loc, NULL_PTR, class,
+ push_reload (x, NULL_RTX, loc, (rtx*) 0, class,
mode, VOIDmode, 0, 0, opnum, type);
}
@@ -5705,27 +5758,48 @@ find_reloads_subreg_address (x, force_replace, opnum, type,
if (force_replace
|| ! rtx_equal_p (tem, reg_equiv_mem[regno]))
{
- int offset = SUBREG_WORD (x) * UNITS_PER_WORD;
+ int offset = SUBREG_BYTE (x);
+ unsigned outer_size = GET_MODE_SIZE (GET_MODE (x));
+ unsigned inner_size = GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)));
+
+ XEXP (tem, 0) = plus_constant (XEXP (tem, 0), offset);
+ PUT_MODE (tem, GET_MODE (x));
- if (BYTES_BIG_ENDIAN)
+ /* If this was a paradoxical subreg that we replaced, the
+ resulting memory must be sufficiently aligned to allow
+ us to widen the mode of the memory. */
+ if (outer_size > inner_size && STRICT_ALIGNMENT)
{
- int size;
+ rtx base;
- size = GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)));
- offset += MIN (size, UNITS_PER_WORD);
- size = GET_MODE_SIZE (GET_MODE (x));
- offset -= MIN (size, UNITS_PER_WORD);
+ base = XEXP (tem, 0);
+ if (GET_CODE (base) == PLUS)
+ {
+ if (GET_CODE (XEXP (base, 1)) == CONST_INT
+ && INTVAL (XEXP (base, 1)) % outer_size != 0)
+ return x;
+ base = XEXP (base, 0);
+ }
+ if (GET_CODE (base) != REG
+ || (REGNO_POINTER_ALIGN (REGNO (base))
+ < outer_size * BITS_PER_UNIT))
+ return x;
}
- XEXP (tem, 0) = plus_constant (XEXP (tem, 0), offset);
- PUT_MODE (tem, GET_MODE (x));
+
find_reloads_address (GET_MODE (tem), &tem, XEXP (tem, 0),
&XEXP (tem, 0), opnum, ADDR_TYPE (type),
ind_levels, insn);
+
/* If this is not a toplevel operand, find_reloads doesn't see
this substitution. We have to emit a USE of the pseudo so
that delete_output_reload can see it. */
- if (replace_reloads && recog_operand[opnum] != x)
- emit_insn_before (gen_rtx_USE (VOIDmode, SUBREG_REG (x)), insn);
+ if (replace_reloads && recog_data.operand[opnum] != x)
+ /* We mark the USE with QImode so that we recognize it
+ as one that can be safely deleted at the end of
+ reload. */
+ PUT_MODE (emit_insn_before (gen_rtx_USE (VOIDmode,
+ SUBREG_REG (x)),
+ insn), QImode);
x = tem;
}
}
@@ -5735,22 +5809,58 @@ find_reloads_subreg_address (x, force_replace, opnum, type,
/* Substitute into the current INSN the registers into which we have reloaded
the things that need reloading. The array `replacements'
- says contains the locations of all pointers that must be changed
+ contains the locations of all pointers that must be changed
and says what to replace them with.
Return the rtx that X translates into; usually X, but modified. */
void
-subst_reloads ()
+subst_reloads (insn)
+ rtx insn;
{
- register int i;
+ int i;
for (i = 0; i < n_replacements; i++)
{
- register struct replacement *r = &replacements[i];
- register rtx reloadreg = reload_reg_rtx[r->what];
+ struct replacement *r = &replacements[i];
+ rtx reloadreg = rld[r->what].reg_rtx;
if (reloadreg)
{
+#ifdef ENABLE_CHECKING
+ /* Internal consistency test. Check that we don't modify
+ anything in the equivalence arrays. Whenever something from
+ those arrays needs to be reloaded, it must be unshared before
+ being substituted into; the equivalence must not be modified.
+ Otherwise, if the equivalence is used after that, it will
+ have been modified, and the thing substituted (probably a
+ register) is likely overwritten and not a usable equivalence. */
+ int check_regno;
+
+ for (check_regno = 0; check_regno < max_regno; check_regno++)
+ {
+#define CHECK_MODF(ARRAY) \
+ if (ARRAY[check_regno] \
+ && loc_mentioned_in_p (r->where, \
+ ARRAY[check_regno])) \
+ abort ()
+
+ CHECK_MODF (reg_equiv_constant);
+ CHECK_MODF (reg_equiv_memory_loc);
+ CHECK_MODF (reg_equiv_address);
+ CHECK_MODF (reg_equiv_mem);
+#undef CHECK_MODF
+ }
+#endif /* ENABLE_CHECKING */
+
+ /* If we're replacing a LABEL_REF with a register, add a
+ REG_LABEL note to indicate to flow which label this
+ register refers to. */
+ if (GET_CODE (*r->where) == LABEL_REF
+ && GET_CODE (insn) == JUMP_INSN)
+ REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL,
+ XEXP (*r->where, 0),
+ REG_NOTES (insn));
+
/* Encapsulate RELOADREG so its machine mode matches what
used to be there. Note that gen_lowpart_common will
do the wrong thing if RELOADREG is multi-word. RELOADREG
@@ -5769,15 +5879,25 @@ subst_reloads ()
*r->subreg_loc = SUBREG_REG (reloadreg);
else
{
+ int final_offset =
+ SUBREG_BYTE (*r->subreg_loc) + SUBREG_BYTE (reloadreg);
+
+ /* When working with SUBREGs the rule is that the byte
+ offset must be a multiple of the SUBREG's mode. */
+ final_offset = (final_offset /
+ GET_MODE_SIZE (GET_MODE (*r->subreg_loc)));
+ final_offset = (final_offset *
+ GET_MODE_SIZE (GET_MODE (*r->subreg_loc)));
+
*r->where = SUBREG_REG (reloadreg);
- SUBREG_WORD (*r->subreg_loc) += SUBREG_WORD (reloadreg);
+ SUBREG_BYTE (*r->subreg_loc) = final_offset;
}
}
else
*r->where = reloadreg;
}
/* If reload got no reg and isn't optional, something's wrong. */
- else if (! reload_optional[r->what])
+ else if (! rld[r->what].optional)
abort ();
}
}
@@ -5793,7 +5913,7 @@ copy_replacements (x, y)
{
int i, j;
enum rtx_code code = GET_CODE (x);
- char *fmt = GET_RTX_FORMAT (code);
+ const char *fmt = GET_RTX_FORMAT (code);
struct replacement *r;
/* We can't support X being a SUBREG because we might then need to know its
@@ -5854,7 +5974,7 @@ find_replacement (loc)
for (r = &replacements[0]; r < &replacements[n_replacements]; r++)
{
- rtx reloadreg = reload_reg_rtx[r->what];
+ rtx reloadreg = rld[r->what].reg_rtx;
if (reloadreg && r->where == loc)
{
@@ -5871,12 +5991,24 @@ find_replacement (loc)
if (GET_CODE (reloadreg) == REG)
return gen_rtx_REG (GET_MODE (*loc),
- REGNO (reloadreg) + SUBREG_WORD (*loc));
+ (REGNO (reloadreg) +
+ subreg_regno_offset (REGNO (SUBREG_REG (*loc)),
+ GET_MODE (SUBREG_REG (*loc)),
+ SUBREG_BYTE (*loc),
+ GET_MODE (*loc))));
else if (GET_MODE (reloadreg) == GET_MODE (*loc))
return reloadreg;
else
- return gen_rtx_SUBREG (GET_MODE (*loc), SUBREG_REG (reloadreg),
- SUBREG_WORD (reloadreg) + SUBREG_WORD (*loc));
+ {
+ int final_offset = SUBREG_BYTE (reloadreg) + SUBREG_BYTE (*loc);
+
+ /* When working with SUBREGs the rule is that the byte
+ offset must be a multiple of the SUBREG's mode. */
+ final_offset = (final_offset / GET_MODE_SIZE (GET_MODE (*loc)));
+ final_offset = (final_offset * GET_MODE_SIZE (GET_MODE (*loc)));
+ return gen_rtx_SUBREG (GET_MODE (*loc), SUBREG_REG (reloadreg),
+ final_offset);
+ }
}
}
@@ -5907,13 +6039,14 @@ find_replacement (loc)
int
refers_to_regno_for_reload_p (regno, endregno, x, loc)
- int regno, endregno;
+ unsigned int regno, endregno;
rtx x;
rtx *loc;
{
- register int i;
- register RTX_CODE code;
- register char *fmt;
+ int i;
+ unsigned int r;
+ RTX_CODE code;
+ const char *fmt;
if (x == 0)
return 0;
@@ -5924,26 +6057,26 @@ refers_to_regno_for_reload_p (regno, endregno, x, loc)
switch (code)
{
case REG:
- i = REGNO (x);
+ r = REGNO (x);
/* If this is a pseudo, a hard register must not have been allocated.
X must therefore either be a constant or be in memory. */
- if (i >= FIRST_PSEUDO_REGISTER)
+ if (r >= FIRST_PSEUDO_REGISTER)
{
- if (reg_equiv_memory_loc[i])
+ if (reg_equiv_memory_loc[r])
return refers_to_regno_for_reload_p (regno, endregno,
- reg_equiv_memory_loc[i],
- NULL_PTR);
+ reg_equiv_memory_loc[r],
+ (rtx*) 0);
- if (reg_equiv_constant[i])
+ if (reg_equiv_constant[r])
return 0;
abort ();
}
- return (endregno > i
- && regno < i + (i < FIRST_PSEUDO_REGISTER
- ? HARD_REGNO_NREGS (i, GET_MODE (x))
+ return (endregno > r
+ && regno < r + (r < FIRST_PSEUDO_REGISTER
+ ? HARD_REGNO_NREGS (r, GET_MODE (x))
: 1));
case SUBREG:
@@ -5952,8 +6085,8 @@ refers_to_regno_for_reload_p (regno, endregno, x, loc)
if (GET_CODE (SUBREG_REG (x)) == REG
&& REGNO (SUBREG_REG (x)) < FIRST_PSEUDO_REGISTER)
{
- int inner_regno = REGNO (SUBREG_REG (x)) + SUBREG_WORD (x);
- int inner_endregno
+ unsigned int inner_regno = subreg_regno (x);
+ unsigned int inner_endregno
= inner_regno + (inner_regno < FIRST_PSEUDO_REGISTER
? HARD_REGNO_NREGS (regno, GET_MODE (x)) : 1);
@@ -5986,7 +6119,7 @@ refers_to_regno_for_reload_p (regno, endregno, x, loc)
return 0;
x = SET_SRC (x);
goto repeat;
-
+
default:
break;
}
@@ -6010,8 +6143,8 @@ refers_to_regno_for_reload_p (regno, endregno, x, loc)
}
else if (fmt[i] == 'E')
{
- register int j;
- for (j = XVECLEN (x, i) - 1; j >=0; j--)
+ int j;
+ for (j = XVECLEN (x, i) - 1; j >= 0; j--)
if (loc != &XVECEXP (x, i, j)
&& refers_to_regno_for_reload_p (regno, endregno,
XVECEXP (x, i, j), loc))
@@ -6025,9 +6158,9 @@ refers_to_regno_for_reload_p (regno, endregno, x, loc)
we check if any register number in X conflicts with the relevant register
numbers. If X is a constant, return 0. If X is a MEM, return 1 iff IN
contains a MEM (we don't bother checking for memory addresses that can't
- conflict because we expect this to be a rare case.
+ conflict because we expect this to be a rare case.
- This function is similar to reg_overlap_mention_p in rtlanal.c except
+ This function is similar to reg_overlap_mentioned_p in rtlanal.c except
that we look at equivalences for pseudos that didn't get hard registers. */
int
@@ -6037,7 +6170,8 @@ reg_overlap_mentioned_for_reload_p (x, in)
int regno, endregno;
/* Overly conservative. */
- if (GET_CODE (x) == STRICT_LOW_PART)
+ if (GET_CODE (x) == STRICT_LOW_PART
+ || GET_RTX_CLASS (GET_CODE (x)) == 'a')
x = XEXP (x, 0);
/* If either argument is a constant, then modifying X can not affect IN. */
@@ -6047,7 +6181,10 @@ reg_overlap_mentioned_for_reload_p (x, in)
{
regno = REGNO (SUBREG_REG (x));
if (regno < FIRST_PSEUDO_REGISTER)
- regno += SUBREG_WORD (x);
+ regno += subreg_regno_offset (REGNO (SUBREG_REG (x)),
+ GET_MODE (SUBREG_REG (x)),
+ SUBREG_BYTE (x),
+ GET_MODE (x));
}
else if (GET_CODE (x) == REG)
{
@@ -6070,13 +6207,16 @@ reg_overlap_mentioned_for_reload_p (x, in)
else if (GET_CODE (x) == SCRATCH || GET_CODE (x) == PC
|| GET_CODE (x) == CC0)
return reg_mentioned_p (x, in);
+ else if (GET_CODE (x) == PLUS)
+ return (reg_overlap_mentioned_for_reload_p (XEXP (x, 0), in)
+ || reg_overlap_mentioned_for_reload_p (XEXP (x, 1), in));
else
abort ();
endregno = regno + (regno < FIRST_PSEUDO_REGISTER
? HARD_REGNO_NREGS (regno, GET_MODE (x)) : 1);
- return refers_to_regno_for_reload_p (regno, endregno, in, NULL_PTR);
+ return refers_to_regno_for_reload_p (regno, endregno, in, (rtx*) 0);
}
/* Return nonzero if anything in X contains a MEM. Look also for pseudo
@@ -6086,7 +6226,7 @@ int
refers_to_mem_for_reload_p (x)
rtx x;
{
- char *fmt;
+ const char *fmt;
int i;
if (GET_CODE (x) == MEM)
@@ -6095,14 +6235,14 @@ refers_to_mem_for_reload_p (x)
if (GET_CODE (x) == REG)
return (REGNO (x) >= FIRST_PSEUDO_REGISTER
&& reg_equiv_memory_loc[REGNO (x)]);
-
+
fmt = GET_RTX_FORMAT (GET_CODE (x));
for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
if (fmt[i] == 'e'
&& (GET_CODE (XEXP (x, i)) == MEM
|| refers_to_mem_for_reload_p (XEXP (x, i))))
return 1;
-
+
return 0;
}
@@ -6135,18 +6275,18 @@ refers_to_mem_for_reload_p (x)
rtx
find_equiv_reg (goal, insn, class, other, reload_reg_p, goalreg, mode)
- register rtx goal;
+ rtx goal;
rtx insn;
enum reg_class class;
- register int other;
+ int other;
short *reload_reg_p;
int goalreg;
enum machine_mode mode;
{
- register rtx p = insn;
+ rtx p = insn;
rtx goaltry, valtry, value, where;
- register rtx pat;
- register int regno = -1;
+ rtx pat;
+ int regno = -1;
int valueno;
int goal_mem = 0;
int goal_const = 0;
@@ -6173,6 +6313,8 @@ find_equiv_reg (goal, insn, class, other, reload_reg_p, goalreg, mode)
case PRE_INC:
case POST_DEC:
case PRE_DEC:
+ case POST_MODIFY:
+ case PRE_MODIFY:
return 0;
default:
break;
@@ -6192,15 +6334,6 @@ find_equiv_reg (goal, insn, class, other, reload_reg_p, goalreg, mode)
else
return 0;
- /* On some machines, certain regs must always be rejected
- because they don't behave the way ordinary registers do. */
-
-#ifdef OVERLAPPING_REGNO_P
- if (regno >= 0 && regno < FIRST_PSEUDO_REGISTER
- && OVERLAPPING_REGNO_P (regno))
- return 0;
-#endif
-
/* Scan insns back from INSN, looking for one that copies
a value into or out of GOAL.
Stop and give up if we reach a label. */
@@ -6210,21 +6343,24 @@ find_equiv_reg (goal, insn, class, other, reload_reg_p, goalreg, mode)
p = PREV_INSN (p);
if (p == 0 || GET_CODE (p) == CODE_LABEL)
return 0;
+
if (GET_CODE (p) == INSN
/* If we don't want spill regs ... */
&& (! (reload_reg_p != 0
&& reload_reg_p != (short *) (HOST_WIDE_INT) 1)
- /* ... then ignore insns introduced by reload; they aren't useful
- and can cause results in reload_as_needed to be different
- from what they were when calculating the need for spills.
- If we notice an input-reload insn here, we will reject it below,
- but it might hide a usable equivalent. That makes bad code.
- It may even abort: perhaps no reg was spilled for this insn
- because it was assumed we would find that equivalent. */
+ /* ... then ignore insns introduced by reload; they aren't
+ useful and can cause results in reload_as_needed to be
+ different from what they were when calculating the need for
+ spills. If we notice an input-reload insn here, we will
+ reject it below, but it might hide a usable equivalent.
+ That makes bad code. It may even abort: perhaps no reg was
+ spilled for this insn because it was assumed we would find
+ that equivalent. */
|| INSN_UID (p) < reload_first_uid))
{
rtx tem;
pat = single_set (p);
+
/* First check for something that sets some reg equal to GOAL. */
if (pat != 0
&& ((regno >= 0
@@ -6249,27 +6385,30 @@ find_equiv_reg (goal, insn, class, other, reload_reg_p, goalreg, mode)
/* If we are looking for a constant,
and something equivalent to that constant was copied
into a reg, we can use that reg. */
- || (goal_const && (tem = find_reg_note (p, REG_EQUIV,
- NULL_RTX))
- && rtx_equal_p (XEXP (tem, 0), goal)
- && (valueno = true_regnum (valtry = SET_DEST (pat))) >= 0)
- || (goal_const && (tem = find_reg_note (p, REG_EQUIV,
- NULL_RTX))
- && GET_CODE (SET_DEST (pat)) == REG
- && GET_CODE (XEXP (tem, 0)) == CONST_DOUBLE
- && GET_MODE_CLASS (GET_MODE (XEXP (tem, 0))) == MODE_FLOAT
- && GET_CODE (goal) == CONST_INT
- && 0 != (goaltry = operand_subword (XEXP (tem, 0), 0, 0,
+ || (goal_const && REG_NOTES (p) != 0
+ && (tem = find_reg_note (p, REG_EQUIV, NULL_RTX))
+ && ((rtx_equal_p (XEXP (tem, 0), goal)
+ && (valueno
+ = true_regnum (valtry = SET_DEST (pat))) >= 0)
+ || (GET_CODE (SET_DEST (pat)) == REG
+ && GET_CODE (XEXP (tem, 0)) == CONST_DOUBLE
+ && (GET_MODE_CLASS (GET_MODE (XEXP (tem, 0)))
+ == MODE_FLOAT)
+ && GET_CODE (goal) == CONST_INT
+ && 0 != (goaltry
+ = operand_subword (XEXP (tem, 0), 0, 0,
VOIDmode))
- && rtx_equal_p (goal, goaltry)
- && (valtry = operand_subword (SET_DEST (pat), 0, 0,
- VOIDmode))
- && (valueno = true_regnum (valtry)) >= 0)
+ && rtx_equal_p (goal, goaltry)
+ && (valtry
+ = operand_subword (SET_DEST (pat), 0, 0,
+ VOIDmode))
+ && (valueno = true_regnum (valtry)) >= 0)))
|| (goal_const && (tem = find_reg_note (p, REG_EQUIV,
NULL_RTX))
&& GET_CODE (SET_DEST (pat)) == REG
&& GET_CODE (XEXP (tem, 0)) == CONST_DOUBLE
- && GET_MODE_CLASS (GET_MODE (XEXP (tem, 0))) == MODE_FLOAT
+ && (GET_MODE_CLASS (GET_MODE (XEXP (tem, 0)))
+ == MODE_FLOAT)
&& GET_CODE (goal) == CONST_INT
&& 0 != (goaltry = operand_subword (XEXP (tem, 0), 1, 0,
VOIDmode))
@@ -6311,7 +6450,7 @@ find_equiv_reg (goal, insn, class, other, reload_reg_p, goalreg, mode)
/* Don't try to re-use something that is killed in this insn. We want
to be able to trust REG_UNUSED notes. */
- if (find_reg_note (where, REG_UNUSED, value))
+ if (REG_NOTES (where) != 0 && find_reg_note (where, REG_UNUSED, value))
return 0;
/* If we propose to get the value from the stack pointer or if GOAL is
@@ -6332,14 +6471,14 @@ find_equiv_reg (goal, insn, class, other, reload_reg_p, goalreg, mode)
&& refers_to_regno_for_reload_p (valueno,
(valueno
+ HARD_REGNO_NREGS (valueno, mode)),
- goal, NULL_PTR))
+ goal, (rtx*) 0))
return 0;
/* Reject registers that overlap GOAL. */
if (!goal_mem && !goal_const
- && regno + HARD_REGNO_NREGS (regno, mode) > valueno
- && regno < valueno + HARD_REGNO_NREGS (valueno, mode))
+ && regno + (int) HARD_REGNO_NREGS (regno, mode) > valueno
+ && regno < valueno + (int) HARD_REGNO_NREGS (valueno, mode))
return 0;
nregs = HARD_REGNO_NREGS (regno, mode);
@@ -6359,14 +6498,6 @@ find_equiv_reg (goal, insn, class, other, reload_reg_p, goalreg, mode)
return 0;
}
- /* On some machines, certain regs must always be rejected
- because they don't behave the way ordinary registers do. */
-
-#ifdef OVERLAPPING_REGNO_P
- if (OVERLAPPING_REGNO_P (valueno))
- return 0;
-#endif
-
/* Reject VALUE if it is a register being used for an input reload
even if it is not one of those reserved. */
@@ -6374,11 +6505,11 @@ find_equiv_reg (goal, insn, class, other, reload_reg_p, goalreg, mode)
{
int i;
for (i = 0; i < n_reloads; i++)
- if (reload_reg_rtx[i] != 0 && reload_in[i])
+ if (rld[i].reg_rtx != 0 && rld[i].in)
{
- int regno1 = REGNO (reload_reg_rtx[i]);
+ int regno1 = REGNO (rld[i].reg_rtx);
int nregs1 = HARD_REGNO_NREGS (regno1,
- GET_MODE (reload_reg_rtx[i]));
+ GET_MODE (rld[i].reg_rtx));
if (regno1 < valueno + valuenregs
&& regno1 + nregs1 > valueno)
return 0;
@@ -6418,28 +6549,18 @@ find_equiv_reg (goal, insn, class, other, reload_reg_p, goalreg, mode)
for (i = 0; i < valuenregs; ++i)
if (call_used_regs[valueno + i])
return 0;
- }
-
-#ifdef NON_SAVING_SETJMP
- if (NON_SAVING_SETJMP && GET_CODE (p) == NOTE
- && NOTE_LINE_NUMBER (p) == NOTE_INSN_SETJMP)
- return 0;
-#endif
-
-#ifdef INSN_CLOBBERS_REGNO_P
- if ((valueno >= 0 && valueno < FIRST_PSEUDO_REGISTER
- && INSN_CLOBBERS_REGNO_P (p, valueno))
- || (regno >= 0 && regno < FIRST_PSEUDO_REGISTER
- && INSN_CLOBBERS_REGNO_P (p, regno)))
- return 0;
+#ifdef NON_SAVING_SETJMP
+ if (NON_SAVING_SETJMP && find_reg_note (p, REG_SETJMP, NULL))
+ return 0;
#endif
+ }
- if (GET_RTX_CLASS (GET_CODE (p)) == 'i')
+ if (INSN_P (p))
{
pat = PATTERN (p);
- /* Watch out for unspec_volatile, and volatile asms. */
- if (volatile_insn_p (pat))
+ /* Watch out for unspec_volatile, and volatile asms. */
+ if (volatile_insn_p (pat))
return 0;
/* If this insn P stores in either GOAL or VALUE, return 0.
@@ -6447,9 +6568,11 @@ find_equiv_reg (goal, insn, class, other, reload_reg_p, goalreg, mode)
If GOAL is a memory ref and its address is not constant,
and this insn P changes a register used in GOAL, return 0. */
+ if (GET_CODE (pat) == COND_EXEC)
+ pat = COND_EXEC_CODE (pat);
if (GET_CODE (pat) == SET || GET_CODE (pat) == CLOBBER)
{
- register rtx dest = SET_DEST (pat);
+ rtx dest = SET_DEST (pat);
while (GET_CODE (dest) == SUBREG
|| GET_CODE (dest) == ZERO_EXTRACT
|| GET_CODE (dest) == SIGN_EXTRACT
@@ -6457,7 +6580,7 @@ find_equiv_reg (goal, insn, class, other, reload_reg_p, goalreg, mode)
dest = XEXP (dest, 0);
if (GET_CODE (dest) == REG)
{
- register int xregno = REGNO (dest);
+ int xregno = REGNO (dest);
int xnregs;
if (REGNO (dest) < FIRST_PSEUDO_REGISTER)
xnregs = HARD_REGNO_NREGS (xregno, GET_MODE (dest));
@@ -6485,13 +6608,15 @@ find_equiv_reg (goal, insn, class, other, reload_reg_p, goalreg, mode)
}
else if (GET_CODE (pat) == PARALLEL)
{
- register int i;
+ int i;
for (i = XVECLEN (pat, 0) - 1; i >= 0; i--)
{
- register rtx v1 = XVECEXP (pat, 0, i);
+ rtx v1 = XVECEXP (pat, 0, i);
+ if (GET_CODE (v1) == COND_EXEC)
+ v1 = COND_EXEC_CODE (v1);
if (GET_CODE (v1) == SET || GET_CODE (v1) == CLOBBER)
{
- register rtx dest = SET_DEST (v1);
+ rtx dest = SET_DEST (v1);
while (GET_CODE (dest) == SUBREG
|| GET_CODE (dest) == ZERO_EXTRACT
|| GET_CODE (dest) == SIGN_EXTRACT
@@ -6499,7 +6624,7 @@ find_equiv_reg (goal, insn, class, other, reload_reg_p, goalreg, mode)
dest = XEXP (dest, 0);
if (GET_CODE (dest) == REG)
{
- register int xregno = REGNO (dest);
+ int xregno = REGNO (dest);
int xnregs;
if (REGNO (dest) < FIRST_PSEUDO_REGISTER)
xnregs = HARD_REGNO_NREGS (xregno, GET_MODE (dest));
@@ -6541,31 +6666,26 @@ find_equiv_reg (goal, insn, class, other, reload_reg_p, goalreg, mode)
pat = XEXP (link, 0);
if (GET_CODE (pat) == CLOBBER)
{
- register rtx dest = SET_DEST (pat);
- while (GET_CODE (dest) == SUBREG
- || GET_CODE (dest) == ZERO_EXTRACT
- || GET_CODE (dest) == SIGN_EXTRACT
- || GET_CODE (dest) == STRICT_LOW_PART)
- dest = XEXP (dest, 0);
+ rtx dest = SET_DEST (pat);
+
if (GET_CODE (dest) == REG)
{
- register int xregno = REGNO (dest);
- int xnregs;
- if (REGNO (dest) < FIRST_PSEUDO_REGISTER)
- xnregs = HARD_REGNO_NREGS (xregno, GET_MODE (dest));
- else
- xnregs = 1;
+ int xregno = REGNO (dest);
+ int xnregs
+ = HARD_REGNO_NREGS (xregno, GET_MODE (dest));
+
if (xregno < regno + nregs
&& xregno + xnregs > regno)
return 0;
- if (xregno < valueno + valuenregs
- && xregno + xnregs > valueno)
+ else if (xregno < valueno + valuenregs
+ && xregno + xnregs > valueno)
return 0;
- if (goal_mem_addr_varies
- && reg_overlap_mentioned_for_reload_p (dest,
+ else if (goal_mem_addr_varies
+ && reg_overlap_mentioned_for_reload_p (dest,
goal))
return 0;
}
+
else if (goal_mem && GET_CODE (dest) == MEM
&& ! push_operand (dest, GET_MODE (dest)))
return 0;
@@ -6582,13 +6702,13 @@ find_equiv_reg (goal, insn, class, other, reload_reg_p, goalreg, mode)
If GOAL is a memory ref and its address is not constant,
and this insn P increments a register used in GOAL, return 0. */
{
- register rtx link;
+ rtx link;
for (link = REG_NOTES (p); link; link = XEXP (link, 1))
if (REG_NOTE_KIND (link) == REG_INC
&& GET_CODE (XEXP (link, 0)) == REG)
{
- register int incno = REGNO (XEXP (link, 0));
+ int incno = REGNO (XEXP (link, 0));
if (incno < regno + nregs && incno >= regno)
return 0;
if (incno < valueno + valuenregs && incno >= valueno)
@@ -6612,19 +6732,29 @@ static int
find_inc_amount (x, inced)
rtx x, inced;
{
- register enum rtx_code code = GET_CODE (x);
- register char *fmt;
- register int i;
+ enum rtx_code code = GET_CODE (x);
+ const char *fmt;
+ int i;
if (code == MEM)
{
- register rtx addr = XEXP (x, 0);
+ rtx addr = XEXP (x, 0);
if ((GET_CODE (addr) == PRE_DEC
|| GET_CODE (addr) == POST_DEC
|| GET_CODE (addr) == PRE_INC
|| GET_CODE (addr) == POST_INC)
&& XEXP (addr, 0) == inced)
return GET_MODE_SIZE (GET_MODE (x));
+ else if ((GET_CODE (addr) == PRE_MODIFY
+ || GET_CODE (addr) == POST_MODIFY)
+ && GET_CODE (XEXP (addr, 1)) == PLUS
+ && XEXP (addr, 0) == XEXP (XEXP (addr, 1), 0)
+ && XEXP (addr, 0) == inced
+ && GET_CODE (XEXP (XEXP (addr, 1), 1)) == CONST_INT)
+ {
+ i = INTVAL (XEXP (XEXP (addr, 1), 1));
+ return i < 0 ? -i : i;
+ }
}
fmt = GET_RTX_FORMAT (code);
@@ -6632,16 +6762,16 @@ find_inc_amount (x, inced)
{
if (fmt[i] == 'e')
{
- register int tem = find_inc_amount (XEXP (x, i), inced);
+ int tem = find_inc_amount (XEXP (x, i), inced);
if (tem != 0)
return tem;
}
if (fmt[i] == 'E')
{
- register int j;
+ int j;
for (j = XVECLEN (x, i) - 1; j >= 0; j--)
{
- register int tem = find_inc_amount (XVECEXP (x, i, j), inced);
+ int tem = find_inc_amount (XVECEXP (x, i, j), inced);
if (tem != 0)
return tem;
}
@@ -6651,23 +6781,24 @@ find_inc_amount (x, inced)
return 0;
}
-/* Return 1 if register REGNO is the subject of a clobber in insn INSN. */
+/* Return 1 if register REGNO is the subject of a clobber in insn INSN.
+ If SETS is nonzero, also consider SETs. */
int
regno_clobbered_p (regno, insn, mode, sets)
- int regno;
+ unsigned int regno;
rtx insn;
enum machine_mode mode;
int sets;
{
- int nregs = HARD_REGNO_NREGS (regno, mode);
- int endregno = regno + nregs;
+ unsigned int nregs = HARD_REGNO_NREGS (regno, mode);
+ unsigned int endregno = regno + nregs;
if ((GET_CODE (PATTERN (insn)) == CLOBBER
|| (sets && GET_CODE (PATTERN (insn)) == SET))
&& GET_CODE (XEXP (PATTERN (insn), 0)) == REG)
{
- int test = REGNO (XEXP (PATTERN (insn), 0));
+ unsigned int test = REGNO (XEXP (PATTERN (insn), 0));
return test >= regno && test < endregno;
}
@@ -6683,7 +6814,7 @@ regno_clobbered_p (regno, insn, mode, sets)
|| (sets && GET_CODE (PATTERN (insn)) == SET))
&& GET_CODE (XEXP (elt, 0)) == REG)
{
- int test = REGNO (XEXP (elt, 0));
+ unsigned int test = REGNO (XEXP (elt, 0));
if (test >= regno && test < endregno)
return 1;
@@ -6694,22 +6825,22 @@ regno_clobbered_p (regno, insn, mode, sets)
return 0;
}
-static char *reload_when_needed_name[] =
+static const char *const reload_when_needed_name[] =
{
- "RELOAD_FOR_INPUT",
- "RELOAD_FOR_OUTPUT",
+ "RELOAD_FOR_INPUT",
+ "RELOAD_FOR_OUTPUT",
"RELOAD_FOR_INSN",
"RELOAD_FOR_INPUT_ADDRESS",
"RELOAD_FOR_INPADDR_ADDRESS",
"RELOAD_FOR_OUTPUT_ADDRESS",
"RELOAD_FOR_OUTADDR_ADDRESS",
- "RELOAD_FOR_OPERAND_ADDRESS",
+ "RELOAD_FOR_OPERAND_ADDRESS",
"RELOAD_FOR_OPADDR_ADDR",
- "RELOAD_OTHER",
+ "RELOAD_OTHER",
"RELOAD_FOR_OTHER_ADDRESS"
};
-static char *reg_class_names[] = REG_CLASS_NAMES;
+static const char * const reg_class_names[] = REG_CLASS_NAMES;
/* These functions are used to print the variables set by 'find_reloads' */
@@ -6718,7 +6849,7 @@ debug_reload_to_stream (f)
FILE *f;
{
int r;
- char *prefix;
+ const char *prefix;
if (! f)
f = stderr;
@@ -6726,84 +6857,84 @@ debug_reload_to_stream (f)
{
fprintf (f, "Reload %d: ", r);
- if (reload_in[r] != 0)
+ if (rld[r].in != 0)
{
fprintf (f, "reload_in (%s) = ",
- GET_MODE_NAME (reload_inmode[r]));
- print_inline_rtx (f, reload_in[r], 24);
+ GET_MODE_NAME (rld[r].inmode));
+ print_inline_rtx (f, rld[r].in, 24);
fprintf (f, "\n\t");
}
- if (reload_out[r] != 0)
+ if (rld[r].out != 0)
{
fprintf (f, "reload_out (%s) = ",
- GET_MODE_NAME (reload_outmode[r]));
- print_inline_rtx (f, reload_out[r], 24);
+ GET_MODE_NAME (rld[r].outmode));
+ print_inline_rtx (f, rld[r].out, 24);
fprintf (f, "\n\t");
}
- fprintf (f, "%s, ", reg_class_names[(int) reload_reg_class[r]]);
+ fprintf (f, "%s, ", reg_class_names[(int) rld[r].class]);
fprintf (f, "%s (opnum = %d)",
- reload_when_needed_name[(int) reload_when_needed[r]],
- reload_opnum[r]);
+ reload_when_needed_name[(int) rld[r].when_needed],
+ rld[r].opnum);
- if (reload_optional[r])
+ if (rld[r].optional)
fprintf (f, ", optional");
- if (reload_nongroup[r])
- fprintf (stderr, ", nongroup");
+ if (rld[r].nongroup)
+ fprintf (f, ", nongroup");
- if (reload_inc[r] != 0)
- fprintf (f, ", inc by %d", reload_inc[r]);
+ if (rld[r].inc != 0)
+ fprintf (f, ", inc by %d", rld[r].inc);
- if (reload_nocombine[r])
+ if (rld[r].nocombine)
fprintf (f, ", can't combine");
- if (reload_secondary_p[r])
+ if (rld[r].secondary_p)
fprintf (f, ", secondary_reload_p");
- if (reload_in_reg[r] != 0)
+ if (rld[r].in_reg != 0)
{
fprintf (f, "\n\treload_in_reg: ");
- print_inline_rtx (f, reload_in_reg[r], 24);
+ print_inline_rtx (f, rld[r].in_reg, 24);
}
- if (reload_out_reg[r] != 0)
+ if (rld[r].out_reg != 0)
{
fprintf (f, "\n\treload_out_reg: ");
- print_inline_rtx (f, reload_out_reg[r], 24);
+ print_inline_rtx (f, rld[r].out_reg, 24);
}
- if (reload_reg_rtx[r] != 0)
+ if (rld[r].reg_rtx != 0)
{
fprintf (f, "\n\treload_reg_rtx: ");
- print_inline_rtx (f, reload_reg_rtx[r], 24);
+ print_inline_rtx (f, rld[r].reg_rtx, 24);
}
prefix = "\n\t";
- if (reload_secondary_in_reload[r] != -1)
+ if (rld[r].secondary_in_reload != -1)
{
fprintf (f, "%ssecondary_in_reload = %d",
- prefix, reload_secondary_in_reload[r]);
+ prefix, rld[r].secondary_in_reload);
prefix = ", ";
}
- if (reload_secondary_out_reload[r] != -1)
+ if (rld[r].secondary_out_reload != -1)
fprintf (f, "%ssecondary_out_reload = %d\n",
- prefix, reload_secondary_out_reload[r]);
+ prefix, rld[r].secondary_out_reload);
prefix = "\n\t";
- if (reload_secondary_in_icode[r] != CODE_FOR_nothing)
+ if (rld[r].secondary_in_icode != CODE_FOR_nothing)
{
- fprintf (stderr, "%ssecondary_in_icode = %s", prefix,
- insn_name[reload_secondary_in_icode[r]]);
+ fprintf (f, "%ssecondary_in_icode = %s", prefix,
+ insn_data[rld[r].secondary_in_icode].name);
prefix = ", ";
}
- if (reload_secondary_out_icode[r] != CODE_FOR_nothing)
- fprintf (stderr, "%ssecondary_out_icode = %s", prefix,
- insn_name[reload_secondary_out_icode[r]]);
+ if (rld[r].secondary_out_icode != CODE_FOR_nothing)
+ fprintf (f, "%ssecondary_out_icode = %s", prefix,
+ insn_data[rld[r].secondary_out_icode].name);
fprintf (f, "\n");
}
OpenPOWER on IntegriCloud