| Index: gcc/gcc/config/arm/arm.h
|
| diff --git a/gcc/gcc/config/arm/arm.h b/gcc/gcc/config/arm/arm.h
|
| index f894d37fe7ec4c67def99d532e2612be896a51c7..26ffaf8dff80276e1b2eefd8c83aeee87c1baf14 100644
|
| --- a/gcc/gcc/config/arm/arm.h
|
| +++ b/gcc/gcc/config/arm/arm.h
|
| @@ -26,6 +26,16 @@
|
| #ifndef GCC_ARM_H
|
| #define GCC_ARM_H
|
|
|
| +/* We can't use enum machine_mode inside a generator file because it
|
| + hasn't been created yet; we shouldn't be using any code that
|
| + needs the real definition though, so this ought to be safe. */
|
| +#ifdef GENERATOR_FILE
|
| +#define MACHMODE int
|
| +#else
|
| +#include "insn-modes.h"
|
| +#define MACHMODE enum machine_mode
|
| +#endif
|
| +
|
| #include "config/vxworks-dummy.h"
|
|
|
| /* The architecture define. */
|
| @@ -124,10 +134,6 @@ extern arm_cc arm_current_cc;
|
| extern int arm_target_label;
|
| extern int arm_ccfsm_state;
|
| extern GTY(()) rtx arm_target_insn;
|
| -/* Define the information needed to generate branch insns. This is
|
| - stored from the compare operation. */
|
| -extern GTY(()) rtx arm_compare_op0;
|
| -extern GTY(()) rtx arm_compare_op1;
|
| /* The label of the current constant pool. */
|
| extern rtx pool_vector_label;
|
| /* Set to 1 when a return insn is output, this means that the epilogue
|
| @@ -184,9 +190,9 @@ extern void (*arm_lang_output_object_attributes_hook)(void);
|
| #define TARGET_HARD_FLOAT (arm_float_abi != ARM_FLOAT_ABI_SOFT)
|
| /* Use hardware floating point calling convention. */
|
| #define TARGET_HARD_FLOAT_ABI (arm_float_abi == ARM_FLOAT_ABI_HARD)
|
| -#define TARGET_FPA (arm_fp_model == ARM_FP_MODEL_FPA)
|
| -#define TARGET_MAVERICK (arm_fp_model == ARM_FP_MODEL_MAVERICK)
|
| -#define TARGET_VFP (arm_fp_model == ARM_FP_MODEL_VFP)
|
| +#define TARGET_FPA (arm_fpu_desc->model == ARM_FP_MODEL_FPA)
|
| +#define TARGET_MAVERICK (arm_fpu_desc->model == ARM_FP_MODEL_MAVERICK)
|
| +#define TARGET_VFP (arm_fpu_desc->model == ARM_FP_MODEL_VFP)
|
| #define TARGET_IWMMXT (arm_arch_iwmmxt)
|
| #define TARGET_REALLY_IWMMXT (TARGET_IWMMXT && TARGET_32BIT)
|
| #define TARGET_IWMMXT_ABI (TARGET_32BIT && arm_abi == ARM_ABI_IWMMXT)
|
| @@ -210,6 +216,8 @@ extern void (*arm_lang_output_object_attributes_hook)(void);
|
| #define TARGET_THUMB2 (TARGET_THUMB && arm_arch_thumb2)
|
| /* Thumb-1 only. */
|
| #define TARGET_THUMB1_ONLY (TARGET_THUMB1 && !arm_arch_notm)
|
| +/* FPA emulator without LFM. */
|
| +#define TARGET_FPA_EMU2 (TARGET_FPA && arm_fpu_desc->rev == 2)
|
|
|
| /* The following two macros concern the ability to execute coprocessor
|
| instructions for VFPv3 or NEON. TARGET_VFP3/TARGET_VFPD32 are currently
|
| @@ -217,29 +225,37 @@ extern void (*arm_lang_output_object_attributes_hook)(void);
|
| to be more careful with TARGET_NEON as noted below. */
|
|
|
| /* FPU is has the full VFPv3/NEON register file of 32 D registers. */
|
| -#define TARGET_VFPD32 (arm_fp_model == ARM_FP_MODEL_VFP \
|
| - && (arm_fpu_arch == FPUTYPE_VFP3 \
|
| - || arm_fpu_arch == FPUTYPE_NEON))
|
| +#define TARGET_VFPD32 (TARGET_VFP && arm_fpu_desc->regs == VFP_REG_D32)
|
|
|
| /* FPU supports VFPv3 instructions. */
|
| -#define TARGET_VFP3 (arm_fp_model == ARM_FP_MODEL_VFP \
|
| - && (arm_fpu_arch == FPUTYPE_VFP3D16 \
|
| - || TARGET_VFPD32))
|
| +#define TARGET_VFP3 (TARGET_VFP && arm_fpu_desc->rev >= 3)
|
| +
|
| +/* FPU only supports VFP single-precision instructions. */
|
| +#define TARGET_VFP_SINGLE (TARGET_VFP && arm_fpu_desc->regs == VFP_REG_SINGLE)
|
| +
|
| +/* FPU supports VFP double-precision instructions. */
|
| +#define TARGET_VFP_DOUBLE (TARGET_VFP && arm_fpu_desc->regs != VFP_REG_SINGLE)
|
| +
|
| +/* FPU supports half-precision floating-point with NEON element load/store. */
|
| +#define TARGET_NEON_FP16 \
|
| + (TARGET_VFP && arm_fpu_desc->neon && arm_fpu_desc->fp16)
|
| +
|
| +/* FPU supports VFP half-precision floating-point. */
|
| +#define TARGET_FP16 (TARGET_VFP && arm_fpu_desc->fp16)
|
|
|
| /* FPU supports Neon instructions. The setting of this macro gets
|
| revealed via __ARM_NEON__ so we add extra guards upon TARGET_32BIT
|
| and TARGET_HARD_FLOAT to ensure that NEON instructions are
|
| available. */
|
| #define TARGET_NEON (TARGET_32BIT && TARGET_HARD_FLOAT \
|
| - && arm_fp_model == ARM_FP_MODEL_VFP \
|
| - && arm_fpu_arch == FPUTYPE_NEON)
|
| + && TARGET_VFP && arm_fpu_desc->neon)
|
|
|
| /* "DSP" multiply instructions, eg. SMULxy. */
|
| #define TARGET_DSP_MULTIPLY \
|
| - (TARGET_32BIT && arm_arch5e && arm_arch_notm)
|
| + (TARGET_32BIT && arm_arch5e && (arm_arch_notm || arm_arch7em))
|
| /* Integer SIMD instructions, and extend-accumulate instructions. */
|
| #define TARGET_INT_SIMD \
|
| - (TARGET_32BIT && arm_arch6 && arm_arch_notm)
|
| + (TARGET_32BIT && arm_arch6 && (arm_arch_notm || arm_arch7em))
|
|
|
| /* Should MOVW/MOVT be used in preference to a constant pool. */
|
| #define TARGET_USE_MOVT (arm_arch_thumb2 && !optimize_size)
|
| @@ -289,40 +305,26 @@ enum arm_fp_model
|
| ARM_FP_MODEL_VFP
|
| };
|
|
|
| -extern enum arm_fp_model arm_fp_model;
|
| -
|
| -/* Which floating point hardware is available. Also update
|
| - fp_model_for_fpu in arm.c when adding entries to this list. */
|
| -enum fputype
|
| +enum vfp_reg_type
|
| {
|
| - /* No FP hardware. */
|
| - FPUTYPE_NONE,
|
| - /* Full FPA support. */
|
| - FPUTYPE_FPA,
|
| - /* Emulated FPA hardware, Issue 2 emulator (no LFM/SFM). */
|
| - FPUTYPE_FPA_EMU2,
|
| - /* Emulated FPA hardware, Issue 3 emulator. */
|
| - FPUTYPE_FPA_EMU3,
|
| - /* Cirrus Maverick floating point co-processor. */
|
| - FPUTYPE_MAVERICK,
|
| - /* VFP. */
|
| - FPUTYPE_VFP,
|
| - /* VFPv3-D16. */
|
| - FPUTYPE_VFP3D16,
|
| - /* VFPv3. */
|
| - FPUTYPE_VFP3,
|
| - /* Neon. */
|
| - FPUTYPE_NEON
|
| + VFP_NONE = 0,
|
| + VFP_REG_D16,
|
| + VFP_REG_D32,
|
| + VFP_REG_SINGLE
|
| };
|
|
|
| -/* Recast the floating point class to be the floating point attribute. */
|
| -#define arm_fpu_attr ((enum attr_fpu) arm_fpu_tune)
|
| -
|
| -/* What type of floating point to tune for */
|
| -extern enum fputype arm_fpu_tune;
|
| +extern const struct arm_fpu_desc
|
| +{
|
| + const char *name;
|
| + enum arm_fp_model model;
|
| + int rev;
|
| + enum vfp_reg_type regs;
|
| + int neon;
|
| + int fp16;
|
| +} *arm_fpu_desc;
|
|
|
| -/* What type of floating point instructions are available */
|
| -extern enum fputype arm_fpu_arch;
|
| +/* Which floating point hardware to schedule for. */
|
| +extern int arm_fpu_attr;
|
|
|
| enum float_abi_type
|
| {
|
| @@ -337,6 +339,21 @@ extern enum float_abi_type arm_float_abi;
|
| #define TARGET_DEFAULT_FLOAT_ABI ARM_FLOAT_ABI_SOFT
|
| #endif
|
|
|
| +/* Which __fp16 format to use.
|
| + The enumeration values correspond to the numbering for the
|
| + Tag_ABI_FP_16bit_format attribute.
|
| + */
|
| +enum arm_fp16_format_type
|
| +{
|
| + ARM_FP16_FORMAT_NONE = 0,
|
| + ARM_FP16_FORMAT_IEEE = 1,
|
| + ARM_FP16_FORMAT_ALTERNATIVE = 2
|
| +};
|
| +
|
| +extern enum arm_fp16_format_type arm_fp16_format;
|
| +#define LARGEST_EXPONENT_IS_NORMAL(bits) \
|
| + ((bits) == 16 && arm_fp16_format == ARM_FP16_FORMAT_ALTERNATIVE)
|
| +
|
| /* Which ABI to use. */
|
| enum arm_abi_type
|
| {
|
| @@ -383,6 +400,9 @@ extern int arm_arch6;
|
| /* Nonzero if instructions not present in the 'M' profile can be used. */
|
| extern int arm_arch_notm;
|
|
|
| +/* Nonzero if instructions present in ARMv7E-M can be used. */
|
| +extern int arm_arch7em;
|
| +
|
| /* Nonzero if this chip can benefit from load scheduling. */
|
| extern int arm_ld_sched;
|
|
|
| @@ -483,12 +503,6 @@ extern int arm_arch_hwdiv;
|
| (MODE) = SImode; \
|
| }
|
|
|
| -#define PROMOTE_FUNCTION_MODE(MODE, UNSIGNEDP, TYPE) \
|
| - if ((GET_MODE_CLASS (MODE) == MODE_INT \
|
| - || GET_MODE_CLASS (MODE) == MODE_COMPLEX_INT) \
|
| - && GET_MODE_SIZE (MODE) < 4) \
|
| - (MODE) = SImode; \
|
| -
|
| /* Define this if most significant bit is lowest numbered
|
| in instructions that operate on numbered bit-fields. */
|
| #define BITS_BIG_ENDIAN 0
|
| @@ -537,7 +551,7 @@ extern int arm_arch_hwdiv;
|
| #define PREFERRED_STACK_BOUNDARY \
|
| (arm_abi == ARM_ABI_ATPCS ? 64 : STACK_BOUNDARY)
|
|
|
| -#define FUNCTION_BOUNDARY 32
|
| +#define FUNCTION_BOUNDARY ((TARGET_THUMB && optimize_size) ? 16 : 32)
|
|
|
| /* The lowest bit is used to indicate Thumb-mode functions, so the
|
| vbit must go into the delta field of pointers to member
|
| @@ -881,6 +895,9 @@ extern int arm_structure_size_boundary;
|
| /* The number of (integer) argument register available. */
|
| #define NUM_ARG_REGS 4
|
|
|
| +/* And similarly for the VFP. */
|
| +#define NUM_VFP_ARG_REGS 16
|
| +
|
| /* Return the register number of the N'th (integer) argument. */
|
| #define ARG_REGISTER(N) (N - 1)
|
|
|
| @@ -1027,11 +1044,6 @@ extern int arm_structure_size_boundary;
|
| #define SUBTARGET_FRAME_POINTER_REQUIRED 0
|
| #endif
|
|
|
| -#define FRAME_POINTER_REQUIRED \
|
| - (cfun->has_nonlocal_label \
|
| - || SUBTARGET_FRAME_POINTER_REQUIRED \
|
| - || (TARGET_ARM && TARGET_APCS_FRAME && ! leaf_function_p ()))
|
| -
|
| /* Return number of consecutive hard regs needed starting at reg REGNO
|
| to hold something of mode MODE.
|
| This is ordinarily the length in words of a value of mode MODE
|
| @@ -1263,7 +1275,7 @@ enum reg_class
|
| In general this is just CLASS, but for the Thumb core registers and
|
| immediate constants we prefer a LO_REGS class or a subset. */
|
| #define PREFERRED_RELOAD_CLASS(X, CLASS) \
|
| - (TARGET_ARM ? (CLASS) : \
|
| + (TARGET_32BIT ? (CLASS) : \
|
| ((CLASS) == GENERAL_REGS || (CLASS) == HI_REGS \
|
| || (CLASS) == NO_REGS || (CLASS) == STACK_REG \
|
| ? LO_REGS : (CLASS)))
|
| @@ -1416,13 +1428,17 @@ do { \
|
| /* If defined, gives a class of registers that cannot be used as the
|
| operand of a SUBREG that changes the mode of the object illegally. */
|
|
|
| -/* Moves between FPA_REGS and GENERAL_REGS are two memory insns. */
|
| +/* Moves between FPA_REGS and GENERAL_REGS are two memory insns.
|
| + Moves between VFP_REGS and GENERAL_REGS are a single insn, but
|
| + it is typically more expensive than a single memory access. We set
|
| + the cost to less than two memory accesses so that floating
|
| + point to integer conversion does not go through memory. */
|
| #define REGISTER_MOVE_COST(MODE, FROM, TO) \
|
| (TARGET_32BIT ? \
|
| ((FROM) == FPA_REGS && (TO) != FPA_REGS ? 20 : \
|
| (FROM) != FPA_REGS && (TO) == FPA_REGS ? 20 : \
|
| - IS_VFP_CLASS (FROM) && !IS_VFP_CLASS (TO) ? 10 : \
|
| - !IS_VFP_CLASS (FROM) && IS_VFP_CLASS (TO) ? 10 : \
|
| + IS_VFP_CLASS (FROM) && !IS_VFP_CLASS (TO) ? 15 : \
|
| + !IS_VFP_CLASS (FROM) && IS_VFP_CLASS (TO) ? 15 : \
|
| (FROM) == IWMMXT_REGS && (TO) != IWMMXT_REGS ? 4 : \
|
| (FROM) != IWMMXT_REGS && (TO) == IWMMXT_REGS ? 4 : \
|
| (FROM) == IWMMXT_GR_REGS || (TO) == IWMMXT_GR_REGS ? 20 : \
|
| @@ -1491,9 +1507,10 @@ do { \
|
|
|
| /* Define how to find the value returned by a library function
|
| assuming the value has mode MODE. */
|
| -#define LIBCALL_VALUE(MODE) \
|
| - (TARGET_32BIT && TARGET_HARD_FLOAT_ABI && TARGET_FPA \
|
| - && GET_MODE_CLASS (MODE) == MODE_FLOAT \
|
| +#define LIBCALL_VALUE(MODE) \
|
| + (TARGET_AAPCS_BASED ? aapcs_libcall_value (MODE) \
|
| + : (TARGET_32BIT && TARGET_HARD_FLOAT_ABI && TARGET_FPA \
|
| + && GET_MODE_CLASS (MODE) == MODE_FLOAT) \
|
| ? gen_rtx_REG (MODE, FIRST_FPA_REGNUM) \
|
| : TARGET_32BIT && TARGET_HARD_FLOAT_ABI && TARGET_MAVERICK \
|
| && GET_MODE_CLASS (MODE) == MODE_FLOAT \
|
| @@ -1502,22 +1519,16 @@ do { \
|
| ? gen_rtx_REG (MODE, FIRST_IWMMXT_REGNUM) \
|
| : gen_rtx_REG (MODE, ARG_REGISTER (1)))
|
|
|
| -/* 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) \
|
| - arm_function_value (VALTYPE, FUNC);
|
| -
|
| -/* 1 if N is a possible register number for a function value.
|
| - On the ARM, only r0 and f0 can return results. */
|
| -/* On a Cirrus chip, mvf0 can return results. */
|
| -#define FUNCTION_VALUE_REGNO_P(REGNO) \
|
| - ((REGNO) == ARG_REGISTER (1) \
|
| - || (TARGET_32BIT && ((REGNO) == FIRST_CIRRUS_FP_REGNUM) \
|
| - && TARGET_HARD_FLOAT_ABI && TARGET_MAVERICK) \
|
| - || ((REGNO) == FIRST_IWMMXT_REGNUM && TARGET_IWMMXT_ABI) \
|
| - || (TARGET_32BIT && ((REGNO) == FIRST_FPA_REGNUM) \
|
| +/* 1 if REGNO is a possible register number for a function value. */
|
| +#define FUNCTION_VALUE_REGNO_P(REGNO) \
|
| + ((REGNO) == ARG_REGISTER (1) \
|
| + || (TARGET_AAPCS_BASED && TARGET_32BIT \
|
| + && TARGET_VFP && TARGET_HARD_FLOAT \
|
| + && (REGNO) == FIRST_VFP_REGNUM) \
|
| + || (TARGET_32BIT && ((REGNO) == FIRST_CIRRUS_FP_REGNUM) \
|
| + && TARGET_HARD_FLOAT_ABI && TARGET_MAVERICK) \
|
| + || ((REGNO) == FIRST_IWMMXT_REGNUM && TARGET_IWMMXT_ABI) \
|
| + || (TARGET_32BIT && ((REGNO) == FIRST_FPA_REGNUM) \
|
| && TARGET_HARD_FLOAT_ABI && TARGET_FPA))
|
|
|
| /* Amount of memory needed for an untyped call to save all possible return
|
| @@ -1571,7 +1582,7 @@ do { \
|
| in the direction of stack growth.
|
| Only soft_frame is used in thumb mode. */
|
|
|
| -typedef struct arm_stack_offsets GTY(())
|
| +typedef struct GTY(()) arm_stack_offsets
|
| {
|
| int saved_args; /* ARG_POINTER_REGNUM. */
|
| int frame; /* ARM_HARD_FRAME_POINTER_REGNUM. */
|
| @@ -1585,7 +1596,7 @@ arm_stack_offsets;
|
|
|
| /* A C structure for machine-specific, per-function data.
|
| This is added to the cfun structure. */
|
| -typedef struct machine_function GTY(())
|
| +typedef struct GTY(()) machine_function
|
| {
|
| /* Additional stack adjustment in __builtin_eh_throw. */
|
| rtx eh_epilogue_sp_ofs;
|
| @@ -1610,6 +1621,9 @@ typedef struct machine_function GTY(())
|
| register. We can never call via LR or PC. We can call via SP if a
|
| trampoline happens to be on the top of the stack. */
|
| rtx call_via[14];
|
| + /* Set to 1 when a return insn is output, this means that the epilogue
|
| + is not needed. */
|
| + int return_used_this_function;
|
| }
|
| machine_function;
|
|
|
| @@ -1617,9 +1631,25 @@ machine_function;
|
| that is in text_section. */
|
| extern GTY(()) rtx thumb_call_via_label[14];
|
|
|
| +/* The number of potential ways of assigning to a co-processor. */
|
| +#define ARM_NUM_COPROC_SLOTS 1
|
| +
|
| +/* Enumeration of procedure calling standard variants. We don't really
|
| + support all of these yet. */
|
| +enum arm_pcs
|
| +{
|
| + ARM_PCS_AAPCS, /* Base standard AAPCS. */
|
| + ARM_PCS_AAPCS_VFP, /* Use VFP registers for floating point values. */
|
| + ARM_PCS_AAPCS_IWMMXT, /* Use iWMMXT registers for vectors. */
|
| + /* This must be the last AAPCS variant. */
|
| + ARM_PCS_AAPCS_LOCAL, /* Private call within this compilation unit. */
|
| + ARM_PCS_ATPCS, /* ATPCS. */
|
| + ARM_PCS_APCS, /* APCS (legacy Linux etc). */
|
| + ARM_PCS_UNKNOWN
|
| +};
|
| +
|
| /* A C type for declaring a variable that is used as the first argument of
|
| - `FUNCTION_ARG' and other related values. For some target machines, the
|
| - type `int' suffices and can hold the number of bytes of argument so far. */
|
| + `FUNCTION_ARG' and other related values. */
|
| typedef struct
|
| {
|
| /* This is the number of registers of arguments scanned so far. */
|
| @@ -1628,7 +1658,28 @@ typedef struct
|
| int iwmmxt_nregs;
|
| int named_count;
|
| int nargs;
|
| - int can_split;
|
| + /* Which procedure call variant to use for this call. */
|
| + enum arm_pcs pcs_variant;
|
| +
|
| + /* AAPCS related state tracking. */
|
| + int aapcs_arg_processed; /* No need to lay out this argument again. */
|
| + int aapcs_cprc_slot; /* Index of co-processor rules to handle
|
| + this argument, or -1 if using core
|
| + registers. */
|
| + int aapcs_ncrn;
|
| + int aapcs_next_ncrn;
|
| + rtx aapcs_reg; /* Register assigned to this argument. */
|
| + int aapcs_partial; /* How many bytes are passed in regs (if
|
| + split between core regs and stack.
|
| + Zero otherwise. */
|
| + int aapcs_cprc_failed[ARM_NUM_COPROC_SLOTS];
|
| + int can_split; /* Argument can be split between core regs
|
| + and the stack. */
|
| + /* Private data for tracking VFP register allocation */
|
| + unsigned aapcs_vfp_regs_free;
|
| + unsigned aapcs_vfp_reg_alloc;
|
| + int aapcs_vfp_rcount;
|
| + MACHMODE aapcs_vfp_rmode;
|
| } CUMULATIVE_ARGS;
|
|
|
| /* Define where to put the arguments to a function.
|
| @@ -1674,13 +1725,7 @@ typedef struct
|
| of mode MODE and data type TYPE.
|
| (TYPE is null for libcalls where that information may not be available.) */
|
| #define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \
|
| - (CUM).nargs += 1; \
|
| - if (arm_vector_mode_supported_p (MODE) \
|
| - && (CUM).named_count > (CUM).nargs \
|
| - && TARGET_IWMMXT_ABI) \
|
| - (CUM).iwmmxt_nregs += 1; \
|
| - else \
|
| - (CUM).nregs += ARM_NUM_REGS2 (MODE, TYPE)
|
| + arm_function_arg_advance (&(CUM), (MODE), (TYPE), (NAMED))
|
|
|
| /* 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,
|
| @@ -1692,9 +1737,11 @@ typedef struct
|
|
|
| /* 1 if N is a possible register number for function argument passing.
|
| On the ARM, r0-r3 are used to pass args. */
|
| -#define FUNCTION_ARG_REGNO_P(REGNO) \
|
| - (IN_RANGE ((REGNO), 0, 3) \
|
| - || (TARGET_IWMMXT_ABI \
|
| +#define FUNCTION_ARG_REGNO_P(REGNO) \
|
| + (IN_RANGE ((REGNO), 0, 3) \
|
| + || (TARGET_AAPCS_BASED && TARGET_VFP && TARGET_HARD_FLOAT \
|
| + && IN_RANGE ((REGNO), FIRST_VFP_REGNUM, FIRST_VFP_REGNUM + 15)) \
|
| + || (TARGET_IWMMXT_ABI \
|
| && IN_RANGE ((REGNO), FIRST_IWMMXT_REGNUM, FIRST_IWMMXT_REGNUM + 9)))
|
|
|
|
|
| @@ -1791,21 +1838,6 @@ typedef struct
|
| { FRAME_POINTER_REGNUM, ARM_HARD_FRAME_POINTER_REGNUM },\
|
| { FRAME_POINTER_REGNUM, THUMB_HARD_FRAME_POINTER_REGNUM }}
|
|
|
| -/* Given FROM and TO register numbers, say whether this elimination is
|
| - allowed. Frame pointer elimination is automatically handled.
|
| -
|
| - All eliminations are permissible. Note that ARG_POINTER_REGNUM and
|
| - HARD_FRAME_POINTER_REGNUM are in fact the same thing. If we need a frame
|
| - pointer, we must eliminate FRAME_POINTER_REGNUM into
|
| - HARD_FRAME_POINTER_REGNUM and not into STACK_POINTER_REGNUM or
|
| - ARG_POINTER_REGNUM. */
|
| -#define CAN_ELIMINATE(FROM, TO) \
|
| - (((TO) == FRAME_POINTER_REGNUM && (FROM) == ARG_POINTER_REGNUM) ? 0 : \
|
| - ((TO) == STACK_POINTER_REGNUM && frame_pointer_needed) ? 0 : \
|
| - ((TO) == ARM_HARD_FRAME_POINTER_REGNUM && TARGET_THUMB) ? 0 : \
|
| - ((TO) == THUMB_HARD_FRAME_POINTER_REGNUM && TARGET_ARM) ? 0 : \
|
| - 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) \
|
| @@ -1821,102 +1853,11 @@ typedef struct
|
| once for every function before code is generated. */
|
| #define INIT_EXPANDERS arm_init_expanders ()
|
|
|
| -/* Output assembler code for a block containing the constant parts
|
| - of a trampoline, leaving space for the variable parts.
|
| -
|
| - On the ARM, (if r8 is the static chain regnum, and remembering that
|
| - referencing pc adds an offset of 8) the trampoline looks like:
|
| - ldr r8, [pc, #0]
|
| - ldr pc, [pc]
|
| - .word static chain value
|
| - .word function's address
|
| - XXX FIXME: When the trampoline returns, r8 will be clobbered. */
|
| -#define ARM_TRAMPOLINE_TEMPLATE(FILE) \
|
| -{ \
|
| - asm_fprintf (FILE, "\tldr\t%r, [%r, #0]\n", \
|
| - STATIC_CHAIN_REGNUM, PC_REGNUM); \
|
| - asm_fprintf (FILE, "\tldr\t%r, [%r, #0]\n", \
|
| - PC_REGNUM, PC_REGNUM); \
|
| - assemble_aligned_integer (UNITS_PER_WORD, const0_rtx); \
|
| - assemble_aligned_integer (UNITS_PER_WORD, const0_rtx); \
|
| -}
|
| -
|
| -/* The Thumb-2 trampoline is similar to the arm implementation.
|
| - Unlike 16-bit Thumb, we enter the stub in thumb mode. */
|
| -#define THUMB2_TRAMPOLINE_TEMPLATE(FILE) \
|
| -{ \
|
| - asm_fprintf (FILE, "\tldr.w\t%r, [%r, #4]\n", \
|
| - STATIC_CHAIN_REGNUM, PC_REGNUM); \
|
| - asm_fprintf (FILE, "\tldr.w\t%r, [%r, #4]\n", \
|
| - PC_REGNUM, PC_REGNUM); \
|
| - assemble_aligned_integer (UNITS_PER_WORD, const0_rtx); \
|
| - assemble_aligned_integer (UNITS_PER_WORD, const0_rtx); \
|
| -}
|
| -
|
| -#define THUMB1_TRAMPOLINE_TEMPLATE(FILE) \
|
| -{ \
|
| - ASM_OUTPUT_ALIGN(FILE, 2); \
|
| - fprintf (FILE, "\t.code\t16\n"); \
|
| - fprintf (FILE, ".Ltrampoline_start:\n"); \
|
| - asm_fprintf (FILE, "\tpush\t{r0, r1}\n"); \
|
| - asm_fprintf (FILE, "\tldr\tr0, [%r, #8]\n", \
|
| - PC_REGNUM); \
|
| - asm_fprintf (FILE, "\tmov\t%r, r0\n", \
|
| - STATIC_CHAIN_REGNUM); \
|
| - asm_fprintf (FILE, "\tldr\tr0, [%r, #8]\n", \
|
| - PC_REGNUM); \
|
| - asm_fprintf (FILE, "\tstr\tr0, [%r, #4]\n", \
|
| - SP_REGNUM); \
|
| - asm_fprintf (FILE, "\tpop\t{r0, %r}\n", \
|
| - PC_REGNUM); \
|
| - assemble_aligned_integer (UNITS_PER_WORD, const0_rtx); \
|
| - assemble_aligned_integer (UNITS_PER_WORD, const0_rtx); \
|
| -}
|
| -
|
| -#define TRAMPOLINE_TEMPLATE(FILE) \
|
| - if (TARGET_ARM) \
|
| - ARM_TRAMPOLINE_TEMPLATE (FILE) \
|
| - else if (TARGET_THUMB2) \
|
| - THUMB2_TRAMPOLINE_TEMPLATE (FILE) \
|
| - else \
|
| - THUMB1_TRAMPOLINE_TEMPLATE (FILE)
|
| -
|
| -/* Thumb trampolines should be entered in thumb mode, so set the bottom bit
|
| - of the address. */
|
| -#define TRAMPOLINE_ADJUST_ADDRESS(ADDR) do \
|
| -{ \
|
| - if (TARGET_THUMB) \
|
| - (ADDR) = expand_simple_binop (Pmode, IOR, (ADDR), GEN_INT(1), \
|
| - gen_reg_rtx (Pmode), 0, OPTAB_LIB_WIDEN); \
|
| -} while(0)
|
| -
|
| /* Length in units of the trampoline for entering a nested function. */
|
| #define TRAMPOLINE_SIZE (TARGET_32BIT ? 16 : 20)
|
|
|
| /* Alignment required for a trampoline in bits. */
|
| #define TRAMPOLINE_ALIGNMENT 32
|
| -
|
| -
|
| -/* 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. */
|
| -#ifndef INITIALIZE_TRAMPOLINE
|
| -#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT) \
|
| -{ \
|
| - emit_move_insn (gen_rtx_MEM (SImode, \
|
| - plus_constant (TRAMP, \
|
| - TARGET_32BIT ? 8 : 12)), \
|
| - CXT); \
|
| - emit_move_insn (gen_rtx_MEM (SImode, \
|
| - plus_constant (TRAMP, \
|
| - TARGET_32BIT ? 12 : 16)), \
|
| - FNADDR); \
|
| - emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__clear_cache"), \
|
| - 0, VOIDmode, 2, TRAMP, Pmode, \
|
| - plus_constant (TRAMP, TRAMPOLINE_SIZE), Pmode); \
|
| -}
|
| -#endif
|
| -
|
|
|
| /* Addressing modes, and classification of registers for them. */
|
| #define HAVE_POST_INCREMENT 1
|
| @@ -2163,88 +2104,12 @@ typedef struct
|
| #define REG_MODE_OK_FOR_REG_BASE_P(X, MODE) \
|
| REG_OK_FOR_INDEX_P (X)
|
|
|
| -/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression
|
| - that is a valid memory address for an instruction.
|
| - The MODE argument is the machine mode for the MEM expression
|
| - that wants to use this address. */
|
| -
|
| #define ARM_BASE_REGISTER_RTX_P(X) \
|
| (GET_CODE (X) == REG && ARM_REG_OK_FOR_BASE_P (X))
|
|
|
| #define ARM_INDEX_REGISTER_RTX_P(X) \
|
| (GET_CODE (X) == REG && ARM_REG_OK_FOR_INDEX_P (X))
|
| -
|
| -#define ARM_GO_IF_LEGITIMATE_ADDRESS(MODE,X,WIN) \
|
| - { \
|
| - if (arm_legitimate_address_p (MODE, X, SET, REG_STRICT_P)) \
|
| - goto WIN; \
|
| - }
|
| -
|
| -#define THUMB2_GO_IF_LEGITIMATE_ADDRESS(MODE,X,WIN) \
|
| - { \
|
| - if (thumb2_legitimate_address_p (MODE, X, REG_STRICT_P)) \
|
| - goto WIN; \
|
| - }
|
| -
|
| -#define THUMB1_GO_IF_LEGITIMATE_ADDRESS(MODE,X,WIN) \
|
| - { \
|
| - if (thumb1_legitimate_address_p (MODE, X, REG_STRICT_P)) \
|
| - goto WIN; \
|
| - }
|
| -
|
| -#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, WIN) \
|
| - if (TARGET_ARM) \
|
| - ARM_GO_IF_LEGITIMATE_ADDRESS (MODE, X, WIN) \
|
| - else if (TARGET_THUMB2) \
|
| - THUMB2_GO_IF_LEGITIMATE_ADDRESS (MODE, X, WIN) \
|
| - else /* if (TARGET_THUMB1) */ \
|
| - THUMB1_GO_IF_LEGITIMATE_ADDRESS (MODE, X, WIN)
|
| -
|
|
|
| -/* Try machine-dependent ways of modifying an illegitimate address
|
| - to be legitimate. If we find one, return the new, valid address. */
|
| -#define ARM_LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) \
|
| -do { \
|
| - X = arm_legitimize_address (X, OLDX, MODE); \
|
| -} while (0)
|
| -
|
| -/* ??? Implement LEGITIMIZE_ADDRESS for thumb2. */
|
| -#define THUMB2_LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) \
|
| -do { \
|
| -} while (0)
|
| -
|
| -#define THUMB1_LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) \
|
| -do { \
|
| - X = thumb_legitimize_address (X, OLDX, MODE); \
|
| -} while (0)
|
| -
|
| -#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) \
|
| -do { \
|
| - if (TARGET_ARM) \
|
| - ARM_LEGITIMIZE_ADDRESS (X, OLDX, MODE, WIN); \
|
| - else if (TARGET_THUMB2) \
|
| - THUMB2_LEGITIMIZE_ADDRESS (X, OLDX, MODE, WIN); \
|
| - else \
|
| - THUMB1_LEGITIMIZE_ADDRESS (X, OLDX, MODE, WIN); \
|
| - \
|
| - if (memory_address_p (MODE, X)) \
|
| - goto WIN; \
|
| -} while (0)
|
| -
|
| -/* Go to LABEL if ADDR (a legitimate address expression)
|
| - has an effect that depends on the machine mode it is used for. */
|
| -#define ARM_GO_IF_MODE_DEPENDENT_ADDRESS(ADDR, LABEL) \
|
| -{ \
|
| - if ( GET_CODE (ADDR) == PRE_DEC || GET_CODE (ADDR) == POST_DEC \
|
| - || GET_CODE (ADDR) == PRE_INC || GET_CODE (ADDR) == POST_INC) \
|
| - goto LABEL; \
|
| -}
|
| -
|
| -/* Nothing helpful to do for the Thumb */
|
| -#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR, LABEL) \
|
| - if (TARGET_32BIT) \
|
| - ARM_GO_IF_MODE_DEPENDENT_ADDRESS (ADDR, LABEL)
|
| -
|
| /* Define this for compatibility reasons. */
|
| #define HANDLE_PRAGMA_PACK_PUSH_POP
|
|
|
| @@ -2252,12 +2117,24 @@ do { \
|
| for the index in the tablejump instruction. */
|
| #define CASE_VECTOR_MODE Pmode
|
|
|
| -#define CASE_VECTOR_PC_RELATIVE TARGET_THUMB2
|
| -
|
| -#define CASE_VECTOR_SHORTEN_MODE(min, max, body) \
|
| - ((min < 0 || max >= 0x2000 || !TARGET_THUMB2) ? SImode \
|
| - : (max >= 0x200) ? HImode \
|
| - : QImode)
|
| +#define CASE_VECTOR_PC_RELATIVE (TARGET_THUMB2 \
|
| + || (TARGET_THUMB1 \
|
| + && (optimize_size || flag_pic)))
|
| +
|
| +#define CASE_VECTOR_SHORTEN_MODE(min, max, body) \
|
| + (TARGET_THUMB1 \
|
| + ? (min >= 0 && max < 512 \
|
| + ? (ADDR_DIFF_VEC_FLAGS (body).offset_unsigned = 1, QImode) \
|
| + : min >= -256 && max < 256 \
|
| + ? (ADDR_DIFF_VEC_FLAGS (body).offset_unsigned = 0, QImode) \
|
| + : min >= 0 && max < 8192 \
|
| + ? (ADDR_DIFF_VEC_FLAGS (body).offset_unsigned = 1, HImode) \
|
| + : min >= -4096 && max < 4096 \
|
| + ? (ADDR_DIFF_VEC_FLAGS (body).offset_unsigned = 0, HImode) \
|
| + : SImode) \
|
| + : ((min < 0 || max >= 0x2000 || !TARGET_THUMB2) ? SImode \
|
| + : (max >= 0x200) ? HImode \
|
| + : QImode))
|
|
|
| /* signed 'char' is most compatible, but RISC OS wants it unsigned.
|
| unsigned is probably best, but may break some code. */
|
| @@ -2392,29 +2269,50 @@ extern int making_const_table;
|
|
|
| /* The arm5 clz instruction returns 32. */
|
| #define CLZ_DEFINED_VALUE_AT_ZERO(MODE, VALUE) ((VALUE) = 32, 1)
|
| +#define CTZ_DEFINED_VALUE_AT_ZERO(MODE, VALUE) ((VALUE) = 32, 1)
|
|
|
| #undef ASM_APP_OFF
|
| #define ASM_APP_OFF (TARGET_THUMB1 ? "\t.code\t16\n" : \
|
| TARGET_THUMB2 ? "\t.thumb\n" : "")
|
|
|
| -/* Output a push or a pop instruction (only used when profiling). */
|
| +/* Output a push or a pop instruction (only used when profiling).
|
| + We can't push STATIC_CHAIN_REGNUM (r12) directly with Thumb-1. We know
|
| + that ASM_OUTPUT_REG_PUSH will be matched with ASM_OUTPUT_REG_POP, and
|
| + that r7 isn't used by the function profiler, so we can use it as a
|
| + scratch reg. WARNING: This isn't safe in the general case! It may be
|
| + sensitive to future changes in final.c:profile_function. */
|
| #define ASM_OUTPUT_REG_PUSH(STREAM, REGNO) \
|
| do \
|
| { \
|
| if (TARGET_ARM) \
|
| asm_fprintf (STREAM,"\tstmfd\t%r!,{%r}\n", \
|
| STACK_POINTER_REGNUM, REGNO); \
|
| + else if (TARGET_THUMB1 \
|
| + && (REGNO) == STATIC_CHAIN_REGNUM) \
|
| + { \
|
| + asm_fprintf (STREAM, "\tpush\t{r7}\n"); \
|
| + asm_fprintf (STREAM, "\tmov\tr7, %r\n", REGNO);\
|
| + asm_fprintf (STREAM, "\tpush\t{r7}\n"); \
|
| + } \
|
| else \
|
| asm_fprintf (STREAM, "\tpush {%r}\n", REGNO); \
|
| } while (0)
|
|
|
|
|
| +/* See comment for ASM_OUTPUT_REG_PUSH concerning Thumb-1 issue. */
|
| #define ASM_OUTPUT_REG_POP(STREAM, REGNO) \
|
| do \
|
| { \
|
| if (TARGET_ARM) \
|
| asm_fprintf (STREAM, "\tldmfd\t%r!,{%r}\n", \
|
| STACK_POINTER_REGNUM, REGNO); \
|
| + else if (TARGET_THUMB1 \
|
| + && (REGNO) == STATIC_CHAIN_REGNUM) \
|
| + { \
|
| + asm_fprintf (STREAM, "\tpop\t{r7}\n"); \
|
| + asm_fprintf (STREAM, "\tmov\t%r, r7\n", REGNO);\
|
| + asm_fprintf (STREAM, "\tpop\t{r7}\n"); \
|
| + } \
|
| else \
|
| asm_fprintf (STREAM, "\tpop {%r}\n", REGNO); \
|
| } while (0)
|
|
|