diff --git a/gcc/ChangeLog b/gcc/ChangeLog index abec0a14f32c..4eac1f684052 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,18 @@ +2003-01-23 Richard Earnshaw + + * 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 * unwind.h (_Unwind_GetTextRelBase): Mark parameter as unused. diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h index 83788a0529f4..af0320e0eac0 100644 --- a/gcc/config/arm/arm-protos.h +++ b/gcc/config/arm/arm-protos.h @@ -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)); diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index 4a8d85a2146f..4bffcb525832 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -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) \ diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h index c0708016d167..2b205fc2092d 100644 --- a/gcc/config/arm/arm.h +++ b/gcc/config/arm/arm.h @@ -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.