From 866af8a90915d8ed191ab7af616b3a186c28cae4 Mon Sep 17 00:00:00 2001 From: Julian Brown Date: Tue, 26 Apr 2005 16:30:37 +0000 Subject: [PATCH] arm.c (arm_return_in_msb): New function. * config/arm/arm.c (arm_return_in_msb): New function. (arm_must_pass_in_stack): New function. (TARGET_RETURN_IN_MSB): Define target hook. (TARGET_MUST_PASS_IN_STACK): Define target hook. (arm_function_value): Pad small aggregate return. (arm_pad_arg_upward): New function. (arm_pad_reg_upward): New function. * config/arm/arm.h (PROMOTE_FUNCTION_MODE): Include complex values. (FUNCTION_ARG_PADDING): Define macro. (BLOCK_REG_PADDING): Define macro. (PAD_VARARGS_DOWN): Correct padding for AAPCS. * config/arm/arm-protos.h (arm_pad_arg_upward): Declare function. (arm_pad_reg_upward): Declare function. From-SVN: r98774 --- gcc/ChangeLog | 16 +++++++ gcc/config/arm/arm-protos.h | 2 + gcc/config/arm/arm.c | 86 ++++++++++++++++++++++++++++++++++++- gcc/config/arm/arm.h | 18 ++++++-- 4 files changed, 118 insertions(+), 4 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 2d441c43cab..07c96a5372f 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,19 @@ +2005-04-26 Julian Brown + + * config/arm/arm.c (arm_return_in_msb): New function. + (arm_must_pass_in_stack): New function. + (TARGET_RETURN_IN_MSB): Define target hook. + (TARGET_MUST_PASS_IN_STACK): Define target hook. + (arm_function_value): Pad small aggregate return. + (arm_pad_arg_upward): New function. + (arm_pad_reg_upward): New function. + * config/arm/arm.h (PROMOTE_FUNCTION_MODE): Include complex values. + (FUNCTION_ARG_PADDING): Define macro. + (BLOCK_REG_PADDING): Define macro. + (PAD_VARARGS_DOWN): Correct padding for AAPCS. + * config/arm/arm-protos.h (arm_pad_arg_upward): Declare function. + (arm_pad_reg_upward): Declare function. + 2005-04-26 Kazu Hirata * basic-block.h (ei_cond): New. diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h index 087b475a96b..0d20eb8fd44 100644 --- a/gcc/config/arm/arm-protos.h +++ b/gcc/config/arm/arm-protos.h @@ -121,6 +121,8 @@ extern int arm_eliminable_register (rtx); #if defined TREE_CODE extern rtx arm_function_arg (CUMULATIVE_ARGS *, enum machine_mode, tree, int); extern void arm_init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, tree); +extern bool arm_pad_arg_upward (enum machine_mode, tree); +extern bool arm_pad_reg_upward (enum machine_mode, tree, int); extern bool arm_needs_doubleword_align (enum machine_mode, tree); extern rtx arm_function_value(tree, tree); #endif diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index 8189909f2eb..cd529365c2f 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -165,6 +165,8 @@ static bool arm_pass_by_reference (CUMULATIVE_ARGS *, static bool arm_promote_prototypes (tree); static bool arm_default_short_enums (void); static bool arm_align_anon_bitfield (void); +static bool arm_return_in_msb (tree); +static bool arm_must_pass_in_stack (enum machine_mode, tree); static tree arm_cxx_guard_type (void); static bool arm_cxx_guard_mask_bit (void); @@ -319,6 +321,12 @@ static unsigned HOST_WIDE_INT arm_shift_truncation_mask (enum machine_mode); #undef TARGET_CXX_CLASS_DATA_ALWAYS_COMDAT #define TARGET_CXX_CLASS_DATA_ALWAYS_COMDAT arm_cxx_class_data_always_comdat +#undef TARGET_RETURN_IN_MSB +#define TARGET_RETURN_IN_MSB arm_return_in_msb + +#undef TARGET_MUST_PASS_IN_STACK +#define TARGET_MUST_PASS_IN_STACK arm_must_pass_in_stack + struct gcc_target targetm = TARGET_INITIALIZER; /* Obstack for minipool constant handling. */ @@ -2302,11 +2310,23 @@ arm_function_value(tree type, tree func ATTRIBUTE_UNUSED) int unsignedp ATTRIBUTE_UNUSED; rtx r ATTRIBUTE_UNUSED; - mode = TYPE_MODE (type); /* Promote integer types. */ if (INTEGRAL_TYPE_P (type)) PROMOTE_FUNCTION_MODE (mode, unsignedp, type); + + /* Promotes small structs returned in a register to full-word size + for big-endian AAPCS. */ + if (arm_return_in_msb (type)) + { + HOST_WIDE_INT size = int_size_in_bytes (type); + if (size % UNITS_PER_WORD != 0) + { + size += UNITS_PER_WORD - size % UNITS_PER_WORD; + mode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0); + } + } + return LIBCALL_VALUE(mode); } @@ -4905,6 +4925,17 @@ vfp_secondary_reload_class (enum machine_mode mode, rtx x) return GENERAL_REGS; } +/* Values which must be returned in the most-significant end of the return + register. */ + +static bool +arm_return_in_msb (tree valtype) +{ + return (TARGET_AAPCS_BASED + && BYTES_BIG_ENDIAN + && (AGGREGATE_TYPE_P (valtype) + || TREE_CODE (valtype) == COMPLEX_TYPE)); +} /* Returns TRUE if INSN is an "LDR REG, ADDR" instruction. Use by the Cirrus Maverick code which has to workaround @@ -6503,6 +6534,59 @@ arm_reload_out_hi (rtx *operands) gen_lowpart (QImode, scratch))); } } + +/* Return true if a type must be passed in memory. For AAPCS, small aggregates + (padded to the size of a word) should be passed in a register. */ + +static bool +arm_must_pass_in_stack (enum machine_mode mode, tree type) +{ + if (TARGET_AAPCS_BASED) + return must_pass_in_stack_var_size (mode, type); + else + return must_pass_in_stack_var_size_or_pad (mode, type); +} + + +/* For use by FUNCTION_ARG_PADDING (MODE, TYPE). + Return true if an argument passed on the stack should be padded upwards, + i.e. if the least-significant byte has useful data. */ + +bool +arm_pad_arg_upward (enum machine_mode mode, tree type) +{ + if (!TARGET_AAPCS_BASED) + return DEFAULT_FUNCTION_ARG_PADDING(mode, type); + + if (type && BYTES_BIG_ENDIAN && INTEGRAL_TYPE_P (type)) + return false; + + return true; +} + + +/* Similarly, for use by BLOCK_REG_PADDING (MODE, TYPE, FIRST). + For non-AAPCS, return !BYTES_BIG_ENDIAN if the least significant + byte of the register has useful data, and return the opposite if the + most significant byte does. + For AAPCS, small aggregates and small complex types are always padded + upwards. */ + +bool +arm_pad_reg_upward (enum machine_mode mode ATTRIBUTE_UNUSED, + tree type, int first ATTRIBUTE_UNUSED) +{ + if (TARGET_AAPCS_BASED + && BYTES_BIG_ENDIAN + && (AGGREGATE_TYPE_P (type) || TREE_CODE (type) == COMPLEX_TYPE) + && int_size_in_bytes (type) <= 4) + return true; + + /* Otherwise, use default padding. */ + return !BYTES_BIG_ENDIAN; +} + + /* Print a symbolic form of X to the debug file, F. */ static void diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h index 5955a52ad85..61ff2133c5f 100644 --- a/gcc/config/arm/arm.h +++ b/gcc/config/arm/arm.h @@ -607,9 +607,10 @@ extern int arm_cpp_interwork; } #define PROMOTE_FUNCTION_MODE(MODE, UNSIGNEDP, TYPE) \ - if (GET_MODE_CLASS (MODE) == MODE_INT \ - && GET_MODE_SIZE (MODE) < 4) \ - (MODE) = SImode; \ + 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. */ @@ -1761,6 +1762,17 @@ typedef struct #define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ arm_function_arg (&(CUM), (MODE), (TYPE), (NAMED)) +#define FUNCTION_ARG_PADDING(MODE, TYPE) \ + (arm_pad_arg_upward (MODE, TYPE) ? upward : downward) + +#define BLOCK_REG_PADDING(MODE, TYPE, FIRST) \ + (arm_pad_reg_upward (MODE, TYPE, FIRST) ? upward : downward) + +/* For AAPCS, padding should never be below the argument. For other ABIs, + * mimic the default. */ +#define PAD_VARARGS_DOWN \ + ((TARGET_AAPCS_BASED) ? 0 : BYTES_BIG_ENDIAN) + /* 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.