mirror of
https://gcc.gnu.org/git/gcc.git
synced 2024-12-12 21:33:54 +08:00
arm.c (thumb_base_register_rtx_p): New function.
* arm.c (thumb_base_register_rtx_p): New function. (thumb_index_register_rtx_p): New function. (thumb_legitimate_address_p): New function. (thumb_legitimate_offset_p): New function. * arm.h (REG_STRICT_P): Define according to setting of REG_OK_STRICT. (ARM_GO_IF_LEGITIMATE_ADDRESS): Use REG_STRICT_P to avoid dumplicate definitions. (THUMB_GO_IF_LEGITIMATE_ADDRESS): Use thumb_legitimate_address_p. (THUMB_LEGITIMATE_OFFSET): Delte. (THUMB_LEGITIMIZE_RELOAD_ADDRESS): Use thumb_legitimate_offset. * arm-protos.h (thumb_legitimate_address_p): Add prototype. (thumb_legitimate_offset_p): Likewise. From-SVN: r61662
This commit is contained in:
parent
0f0ff6ec54
commit
76a318e977
@ -1,3 +1,18 @@
|
||||
2003-01-23 Richard Earnshaw <rearnsha@arm.com>
|
||||
|
||||
* arm.c (thumb_base_register_rtx_p): New function.
|
||||
(thumb_index_register_rtx_p): New function.
|
||||
(thumb_legitimate_address_p): New function.
|
||||
(thumb_legitimate_offset_p): New function.
|
||||
* arm.h (REG_STRICT_P): Define according to setting of REG_OK_STRICT.
|
||||
(ARM_GO_IF_LEGITIMATE_ADDRESS): Use REG_STRICT_P to avoid dumplicate
|
||||
definitions.
|
||||
(THUMB_GO_IF_LEGITIMATE_ADDRESS): Use thumb_legitimate_address_p.
|
||||
(THUMB_LEGITIMATE_OFFSET): Delte.
|
||||
(THUMB_LEGITIMIZE_RELOAD_ADDRESS): Use thumb_legitimate_offset.
|
||||
* arm-protos.h (thumb_legitimate_address_p): Add prototype.
|
||||
(thumb_legitimate_offset_p): Likewise.
|
||||
|
||||
2003-01-23 Andreas Schwab <schwab@suse.de>
|
||||
|
||||
* unwind.h (_Unwind_GetTextRelBase): Mark parameter as unused.
|
||||
|
@ -53,6 +53,10 @@ extern RTX_CODE arm_canonicalize_comparison PARAMS ((RTX_CODE, rtx *));
|
||||
extern int legitimate_pic_operand_p PARAMS ((rtx));
|
||||
extern rtx legitimize_pic_address PARAMS ((rtx, enum machine_mode, rtx));
|
||||
extern int arm_legitimate_address_p PARAMS ((enum machine_mode, rtx, int));
|
||||
extern int thumb_legitimate_address_p PARAMS ((enum machine_mode, rtx,
|
||||
int));
|
||||
extern int thumb_legitimate_offset_p PARAMS ((enum machine_mode,
|
||||
HOST_WIDE_INT));
|
||||
extern int arm_rtx_costs PARAMS ((rtx, RTX_CODE, RTX_CODE));
|
||||
extern int const_double_rtx_ok_for_fpu PARAMS ((rtx));
|
||||
extern int neg_const_double_rtx_ok_for_fpu PARAMS ((rtx));
|
||||
|
@ -71,6 +71,10 @@ static unsigned bit_count PARAMS ((Ulong));
|
||||
static int arm_address_register_rtx_p PARAMS ((rtx, int));
|
||||
static int arm_legitimate_index_p PARAMS ((enum machine_mode,
|
||||
rtx, int));
|
||||
static int thumb_base_register_rtx_p PARAMS ((rtx,
|
||||
enum machine_mode,
|
||||
int));
|
||||
inline static int thumb_index_register_rtx_p PARAMS ((rtx, int));
|
||||
static int const_ok_for_op PARAMS ((Hint, enum rtx_code));
|
||||
static int eliminate_lr2ip PARAMS ((rtx *));
|
||||
static rtx emit_multi_reg_push PARAMS ((int));
|
||||
@ -2717,7 +2721,177 @@ arm_legitimate_index_p (mode, index, strict_p)
|
||||
return (code == CONST_INT
|
||||
&& INTVAL (index) < range
|
||||
&& INTVAL (index) > -range);
|
||||
}
|
||||
}
|
||||
|
||||
/* Return nonzero if X is valid as an ARM state addressing register. */
|
||||
static int
|
||||
thumb_base_register_rtx_p (x, mode, strict_p)
|
||||
rtx x;
|
||||
enum machine_mode mode;
|
||||
int strict_p;
|
||||
{
|
||||
int regno;
|
||||
|
||||
if (GET_CODE (x) != REG)
|
||||
return 0;
|
||||
|
||||
regno = REGNO (x);
|
||||
|
||||
if (strict_p)
|
||||
return THUMB_REGNO_MODE_OK_FOR_BASE_P (regno, mode);
|
||||
|
||||
return (regno <= LAST_LO_REGNUM
|
||||
|| regno >= FIRST_PSEUDO_REGISTER
|
||||
|| regno == FRAME_POINTER_REGNUM
|
||||
|| (GET_MODE_SIZE (mode) >= 4
|
||||
&& (regno == STACK_POINTER_REGNUM
|
||||
|| x == hard_frame_pointer_rtx
|
||||
|| x == arg_pointer_rtx)));
|
||||
}
|
||||
|
||||
/* Return nonzero if x is a legitimate index register. This is the case
|
||||
for any base register that can access a QImode object. */
|
||||
inline static int
|
||||
thumb_index_register_rtx_p (x, strict_p)
|
||||
rtx x;
|
||||
int strict_p;
|
||||
{
|
||||
return thumb_base_register_rtx_p (x, QImode, strict_p);
|
||||
}
|
||||
|
||||
/* Return nonzero if x is a legitimate Thumb-state address.
|
||||
|
||||
The AP may be eliminated to either the SP or the FP, so we use the
|
||||
least common denominator, e.g. SImode, and offsets from 0 to 64.
|
||||
|
||||
??? Verify whether the above is the right approach.
|
||||
|
||||
??? Also, the FP may be eliminated to the SP, so perhaps that
|
||||
needs special handling also.
|
||||
|
||||
??? Look at how the mips16 port solves this problem. It probably uses
|
||||
better ways to solve some of these problems.
|
||||
|
||||
Although it is not incorrect, we don't accept QImode and HImode
|
||||
addresses based on the frame pointer or arg pointer until the
|
||||
reload pass starts. This is so that eliminating such addresses
|
||||
into stack based ones won't produce impossible code. */
|
||||
int
|
||||
thumb_legitimate_address_p (mode, x, strict_p)
|
||||
enum machine_mode mode;
|
||||
rtx x;
|
||||
int strict_p;
|
||||
{
|
||||
/* ??? Not clear if this is right. Experiment. */
|
||||
if (GET_MODE_SIZE (mode) < 4
|
||||
&& !(reload_in_progress || reload_completed)
|
||||
&& (reg_mentioned_p (frame_pointer_rtx, x)
|
||||
|| reg_mentioned_p (arg_pointer_rtx, x)
|
||||
|| reg_mentioned_p (virtual_incoming_args_rtx, x)
|
||||
|| reg_mentioned_p (virtual_outgoing_args_rtx, x)
|
||||
|| reg_mentioned_p (virtual_stack_dynamic_rtx, x)
|
||||
|| reg_mentioned_p (virtual_stack_vars_rtx, x)))
|
||||
return 0;
|
||||
|
||||
/* Accept any base register. SP only in SImode or larger. */
|
||||
else if (thumb_base_register_rtx_p (x, mode, strict_p))
|
||||
return 1;
|
||||
|
||||
/* This is PC relative data before MACHINE_DEPENDENT_REORG runs. */
|
||||
else if (GET_MODE_SIZE (mode) >= 4 && CONSTANT_P (x)
|
||||
&& GET_CODE (x) == SYMBOL_REF
|
||||
&& CONSTANT_POOL_ADDRESS_P (x) && ! flag_pic)
|
||||
return 1;
|
||||
|
||||
/* This is PC relative data after MACHINE_DEPENDENT_REORG runs. */
|
||||
else if (GET_MODE_SIZE (mode) >= 4 && reload_completed
|
||||
&& (GET_CODE (x) == LABEL_REF
|
||||
|| (GET_CODE (x) == CONST
|
||||
&& GET_CODE (XEXP (x, 0)) == PLUS
|
||||
&& GET_CODE (XEXP (XEXP (x, 0), 0)) == LABEL_REF
|
||||
&& GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)))
|
||||
return 1;
|
||||
|
||||
/* Post-inc indexing only supported for SImode and larger. */
|
||||
else if (GET_CODE (x) == POST_INC && GET_MODE_SIZE (mode) >= 4
|
||||
&& thumb_index_register_rtx_p (XEXP (x, 0), strict_p))
|
||||
return 1;
|
||||
|
||||
else if (GET_CODE (x) == PLUS)
|
||||
{
|
||||
/* REG+REG address can be any two index registers. */
|
||||
/* We disallow FRAME+REG addressing since we know that FRAME
|
||||
will be replaced with STACK, and SP relative addressing only
|
||||
permits SP+OFFSET. */
|
||||
if (GET_MODE_SIZE (mode) <= 4
|
||||
&& XEXP (x, 0) != frame_pointer_rtx
|
||||
&& XEXP (x, 1) != frame_pointer_rtx
|
||||
&& XEXP (x, 0) != virtual_stack_vars_rtx
|
||||
&& XEXP (x, 1) != virtual_stack_vars_rtx
|
||||
&& thumb_index_register_rtx_p (XEXP (x, 0), strict_p)
|
||||
&& thumb_index_register_rtx_p (XEXP (x, 1), strict_p))
|
||||
return 1;
|
||||
|
||||
/* REG+const has 5-7 bit offset for non-SP registers. */
|
||||
else if ((thumb_index_register_rtx_p (XEXP (x, 0), strict_p)
|
||||
|| XEXP (x, 0) == arg_pointer_rtx)
|
||||
&& GET_CODE (XEXP (x, 1)) == CONST_INT
|
||||
&& thumb_legitimate_offset_p (mode, INTVAL (XEXP (x, 1))))
|
||||
return 1;
|
||||
|
||||
/* REG+const has 10 bit offset for SP, but only SImode and
|
||||
larger is supported. */
|
||||
/* ??? Should probably check for DI/DFmode overflow here
|
||||
just like GO_IF_LEGITIMATE_OFFSET does. */
|
||||
else if (GET_CODE (XEXP (x, 0)) == REG
|
||||
&& REGNO (XEXP (x, 0)) == STACK_POINTER_REGNUM
|
||||
&& GET_MODE_SIZE (mode) >= 4
|
||||
&& GET_CODE (XEXP (x, 1)) == CONST_INT
|
||||
&& INTVAL (XEXP (x, 1)) >= 0
|
||||
&& INTVAL (XEXP (x, 1)) + GET_MODE_SIZE (mode) <= 1024
|
||||
&& (INTVAL (XEXP (x, 1)) & 3) == 0)
|
||||
return 1;
|
||||
|
||||
else if (GET_CODE (XEXP (x, 0)) == REG
|
||||
&& REGNO (XEXP (x, 0)) == FRAME_POINTER_REGNUM
|
||||
&& GET_MODE_SIZE (mode) >= 4
|
||||
&& GET_CODE (XEXP (x, 1)) == CONST_INT
|
||||
&& (INTVAL (XEXP (x, 1)) & 3) == 0)
|
||||
return 1;
|
||||
}
|
||||
|
||||
else if (GET_MODE_CLASS (mode) != MODE_FLOAT
|
||||
&& GET_CODE (x) == SYMBOL_REF
|
||||
&& CONSTANT_POOL_ADDRESS_P (x)
|
||||
&& !(flag_pic
|
||||
&& symbol_mentioned_p (get_pool_constant (x))))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return nonzero if VAL can be used as an offset in a Thumb-state address
|
||||
instruction of mode MODE. */
|
||||
int
|
||||
thumb_legitimate_offset_p (mode, val)
|
||||
enum machine_mode mode;
|
||||
HOST_WIDE_INT val;
|
||||
{
|
||||
switch (GET_MODE_SIZE (mode))
|
||||
{
|
||||
case 1:
|
||||
return val >= 0 && val < 32;
|
||||
|
||||
case 2:
|
||||
return val >= 0 && val < 64 && (val & 1) == 0;
|
||||
|
||||
default:
|
||||
return (val >= 0
|
||||
&& (val + GET_MODE_SIZE (mode)) <= 128
|
||||
&& (val & 3) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define REG_OR_SUBREG_REG(X) \
|
||||
|
@ -1268,7 +1268,7 @@ enum reg_class
|
||||
&& GET_CODE (XEXP (X, 0)) == REG \
|
||||
&& XEXP (X, 0) == stack_pointer_rtx \
|
||||
&& GET_CODE (XEXP (X, 1)) == CONST_INT \
|
||||
&& ! THUMB_LEGITIMATE_OFFSET (MODE, INTVAL (XEXP (X, 1)))) \
|
||||
&& ! thumb_legitimate_offset_p (MODE, INTVAL (XEXP (X, 1)))) \
|
||||
{ \
|
||||
rtx orig_X = X; \
|
||||
X = copy_rtx (X); \
|
||||
@ -1897,6 +1897,8 @@ typedef struct
|
||||
|| (X) == hard_frame_pointer_rtx \
|
||||
|| (X) == arg_pointer_rtx)))
|
||||
|
||||
#define REG_STRICT_P 0
|
||||
|
||||
#else /* REG_OK_STRICT */
|
||||
|
||||
#define ARM_REG_OK_FOR_BASE_P(X) \
|
||||
@ -1905,6 +1907,8 @@ typedef struct
|
||||
#define THUMB_REG_MODE_OK_FOR_BASE_P(X, MODE) \
|
||||
THUMB_REGNO_MODE_OK_FOR_BASE_P (REGNO (X), MODE)
|
||||
|
||||
#define REG_STRICT_P 1
|
||||
|
||||
#endif /* REG_OK_STRICT */
|
||||
|
||||
/* Now define some helpers in terms of the above. */
|
||||
@ -1932,145 +1936,32 @@ typedef struct
|
||||
/* 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.
|
||||
|
||||
The other macros defined here are used only in GO_IF_LEGITIMATE_ADDRESS. */
|
||||
that wants to use this address. */
|
||||
|
||||
/* --------------------------------arm version----------------------------- */
|
||||
#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))
|
||||
|
||||
#ifdef REG_OK_STRICT
|
||||
#define ARM_GO_IF_LEGITIMATE_ADDRESS(MODE,X,WIN) \
|
||||
{ \
|
||||
if (arm_legitimate_address_p (MODE, X, 1)) \
|
||||
goto WIN; \
|
||||
#define ARM_GO_IF_LEGITIMATE_ADDRESS(MODE,X,WIN) \
|
||||
{ \
|
||||
if (arm_legitimate_address_p (MODE, X, REG_STRICT_P)) \
|
||||
goto WIN; \
|
||||
}
|
||||
#else
|
||||
#define ARM_GO_IF_LEGITIMATE_ADDRESS(MODE,X,WIN) \
|
||||
{ \
|
||||
if (arm_legitimate_address_p (MODE, X, 0)) \
|
||||
goto WIN; \
|
||||
|
||||
#define THUMB_GO_IF_LEGITIMATE_ADDRESS(MODE,X,WIN) \
|
||||
{ \
|
||||
if (thumb_legitimate_address_p (MODE, X, REG_STRICT_P)) \
|
||||
goto WIN; \
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ---------------------thumb version----------------------------------*/
|
||||
#define THUMB_LEGITIMATE_OFFSET(MODE, VAL) \
|
||||
(GET_MODE_SIZE (MODE) == 1 ? ((unsigned HOST_WIDE_INT) (VAL) < 32) \
|
||||
: GET_MODE_SIZE (MODE) == 2 ? ((unsigned HOST_WIDE_INT) (VAL) < 64 \
|
||||
&& ((VAL) & 1) == 0) \
|
||||
: ((VAL) >= 0 && ((VAL) + GET_MODE_SIZE (MODE)) <= 128 \
|
||||
&& ((VAL) & 3) == 0))
|
||||
|
||||
/* The AP may be eliminated to either the SP or the FP, so we use the
|
||||
least common denominator, e.g. SImode, and offsets from 0 to 64. */
|
||||
|
||||
/* ??? Verify whether the above is the right approach. */
|
||||
|
||||
/* ??? Also, the FP may be eliminated to the SP, so perhaps that
|
||||
needs special handling also. */
|
||||
|
||||
/* ??? Look at how the mips16 port solves this problem. It probably uses
|
||||
better ways to solve some of these problems. */
|
||||
|
||||
/* Although it is not incorrect, we don't accept QImode and HImode
|
||||
addresses based on the frame pointer or arg pointer until the
|
||||
reload pass starts. This is so that eliminating such addresses
|
||||
into stack based ones won't produce impossible code. */
|
||||
#define THUMB_GO_IF_LEGITIMATE_ADDRESS(MODE, X, WIN) \
|
||||
{ \
|
||||
/* ??? Not clear if this is right. Experiment. */ \
|
||||
if (GET_MODE_SIZE (MODE) < 4 \
|
||||
&& ! (reload_in_progress || reload_completed) \
|
||||
&& ( reg_mentioned_p (frame_pointer_rtx, X) \
|
||||
|| reg_mentioned_p (arg_pointer_rtx, X) \
|
||||
|| reg_mentioned_p (virtual_incoming_args_rtx, X) \
|
||||
|| reg_mentioned_p (virtual_outgoing_args_rtx, X) \
|
||||
|| reg_mentioned_p (virtual_stack_dynamic_rtx, X) \
|
||||
|| reg_mentioned_p (virtual_stack_vars_rtx, X))) \
|
||||
; \
|
||||
/* Accept any base register. SP only in SImode or larger. */ \
|
||||
else if (GET_CODE (X) == REG \
|
||||
&& THUMB_REG_MODE_OK_FOR_BASE_P (X, MODE)) \
|
||||
goto WIN; \
|
||||
/* This is PC relative data before MACHINE_DEPENDENT_REORG runs. */ \
|
||||
else if (GET_MODE_SIZE (MODE) >= 4 && CONSTANT_P (X) \
|
||||
&& GET_CODE (X) == SYMBOL_REF \
|
||||
&& CONSTANT_POOL_ADDRESS_P (X) && ! flag_pic) \
|
||||
goto WIN; \
|
||||
/* This is PC relative data after MACHINE_DEPENDENT_REORG runs. */ \
|
||||
else if (GET_MODE_SIZE (MODE) >= 4 && reload_completed \
|
||||
&& (GET_CODE (X) == LABEL_REF \
|
||||
|| (GET_CODE (X) == CONST \
|
||||
&& GET_CODE (XEXP (X, 0)) == PLUS \
|
||||
&& GET_CODE (XEXP (XEXP (X, 0), 0)) == LABEL_REF \
|
||||
&& GET_CODE (XEXP (XEXP (X, 0), 1)) == CONST_INT))) \
|
||||
goto WIN; \
|
||||
/* Post-inc indexing only supported for SImode and larger. */ \
|
||||
else if (GET_CODE (X) == POST_INC && GET_MODE_SIZE (MODE) >= 4 \
|
||||
&& GET_CODE (XEXP (X, 0)) == REG \
|
||||
&& THUMB_REG_OK_FOR_INDEX_P (XEXP (X, 0))) \
|
||||
goto WIN; \
|
||||
else if (GET_CODE (X) == PLUS) \
|
||||
{ \
|
||||
/* REG+REG address can be any two index registers. */ \
|
||||
/* We disallow FRAME+REG addressing since we know that FRAME \
|
||||
will be replaced with STACK, and SP relative addressing only \
|
||||
permits SP+OFFSET. */ \
|
||||
if (GET_MODE_SIZE (MODE) <= 4 \
|
||||
&& GET_CODE (XEXP (X, 0)) == REG \
|
||||
&& GET_CODE (XEXP (X, 1)) == REG \
|
||||
&& XEXP (X, 0) != frame_pointer_rtx \
|
||||
&& XEXP (X, 1) != frame_pointer_rtx \
|
||||
&& XEXP (X, 0) != virtual_stack_vars_rtx \
|
||||
&& XEXP (X, 1) != virtual_stack_vars_rtx \
|
||||
&& THUMB_REG_OK_FOR_INDEX_P (XEXP (X, 0)) \
|
||||
&& THUMB_REG_OK_FOR_INDEX_P (XEXP (X, 1))) \
|
||||
goto WIN; \
|
||||
/* REG+const has 5-7 bit offset for non-SP registers. */ \
|
||||
else if (GET_CODE (XEXP (X, 0)) == REG \
|
||||
&& (THUMB_REG_OK_FOR_INDEX_P (XEXP (X, 0)) \
|
||||
|| XEXP (X, 0) == arg_pointer_rtx) \
|
||||
&& GET_CODE (XEXP (X, 1)) == CONST_INT \
|
||||
&& THUMB_LEGITIMATE_OFFSET (MODE, INTVAL (XEXP (X, 1)))) \
|
||||
goto WIN; \
|
||||
/* REG+const has 10 bit offset for SP, but only SImode and \
|
||||
larger is supported. */ \
|
||||
/* ??? Should probably check for DI/DFmode overflow here \
|
||||
just like GO_IF_LEGITIMATE_OFFSET does. */ \
|
||||
else if (GET_CODE (XEXP (X, 0)) == REG \
|
||||
&& REGNO (XEXP (X, 0)) == STACK_POINTER_REGNUM \
|
||||
&& GET_MODE_SIZE (MODE) >= 4 \
|
||||
&& GET_CODE (XEXP (X, 1)) == CONST_INT \
|
||||
&& ((unsigned HOST_WIDE_INT) INTVAL (XEXP (X, 1)) \
|
||||
+ GET_MODE_SIZE (MODE)) <= 1024 \
|
||||
&& (INTVAL (XEXP (X, 1)) & 3) == 0) \
|
||||
goto WIN; \
|
||||
else if (GET_CODE (XEXP (X, 0)) == REG \
|
||||
&& REGNO (XEXP (X, 0)) == FRAME_POINTER_REGNUM \
|
||||
&& GET_MODE_SIZE (MODE) >= 4 \
|
||||
&& GET_CODE (XEXP (X, 1)) == CONST_INT \
|
||||
&& (INTVAL (XEXP (X, 1)) & 3) == 0) \
|
||||
goto WIN; \
|
||||
} \
|
||||
else if (GET_MODE_CLASS (MODE) != MODE_FLOAT \
|
||||
&& GET_CODE (X) == SYMBOL_REF \
|
||||
&& CONSTANT_POOL_ADDRESS_P (X) \
|
||||
&& ! (flag_pic \
|
||||
&& symbol_mentioned_p (get_pool_constant (X)))) \
|
||||
goto WIN; \
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------- */
|
||||
#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, WIN) \
|
||||
if (TARGET_ARM) \
|
||||
ARM_GO_IF_LEGITIMATE_ADDRESS (MODE, X, WIN) \
|
||||
else /* if (TARGET_THUMB) */ \
|
||||
THUMB_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.
|
||||
|
Loading…
Reference in New Issue
Block a user