+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.
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));
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));
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);
+ }
+}
+
\f
#define REG_OR_SUBREG_REG(X) \
&& 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); \
|| (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) \
#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. */
/* 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; \
- }
-#else
-#define ARM_GO_IF_LEGITIMATE_ADDRESS(MODE,X,WIN) \
- { \
- if (arm_legitimate_address_p (MODE, X, 0)) \
- goto WIN; \
+#define ARM_GO_IF_LEGITIMATE_ADDRESS(MODE,X,WIN) \
+ { \
+ if (arm_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 THUMB_GO_IF_LEGITIMATE_ADDRESS(MODE,X,WIN) \
+ { \
+ if (thumb_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_THUMB) */ \
THUMB_GO_IF_LEGITIMATE_ADDRESS (MODE, X, WIN)
-/* ------------------------------------------------------------------- */
+
\f
/* Try machine-dependent ways of modifying an illegitimate address
to be legitimate. If we find one, return the new, valid address.