diff options
-rw-r--r-- | gcc/ChangeLog | 23 | ||||
-rw-r--r-- | gcc/calls.c | 4 | ||||
-rw-r--r-- | gcc/config/ia64/hpux.h | 27 | ||||
-rw-r--r-- | gcc/config/ia64/ia64-protos.h | 5 | ||||
-rw-r--r-- | gcc/config/ia64/ia64.c | 24 | ||||
-rw-r--r-- | gcc/defaults.h | 10 | ||||
-rw-r--r-- | gcc/doc/tm.texi | 8 | ||||
-rw-r--r-- | gcc/expr.c | 21 | ||||
-rw-r--r-- | gcc/stmt.c | 4 | ||||
-rw-r--r-- | gcc/stor-layout.c | 12 |
10 files changed, 131 insertions, 7 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index acd76f34710..919f9559a08 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,26 @@ +2001-12-11 Steve Ellcey <sje@cup.hp.com> + + * doc/tm.texi (FUNCTION_ARG_REG_LITTLE_ENDIAN): New. + * defaults.h (FUNCTION_ARG_REG_LITTLE_ENDIAN): New. + * calls.c (store_unaligned_arguments_into_pseudos): Check + FUNCTION_ARG_REG_LITTLE_ENDIAN to see how structures + are passed/returned. + * expr.c (move_block_from_reg): Ditto. + (move_block_from_reg): Ditto. + (copy_blkmode_from_reg): Ditto. + * stmt.c (expand_return): Ditto. + * stor-layout.c (compute_record_mode): If + FUNCTION_ARG_REG_LITTLE_ENDIAN is set then check + MEMBER_TYPE_FORCES_BLK even if mode == VOIDmode. + * config/ia64/hpux.h (MEMBER_TYPE_FORCES_BLK): Set to true + so that Structures of one field are still treated as structures. + (FUNCTION_ARG_REG_LITTLE_ENDIAN): New, set it to true. + (FUNCTION_ARG_PADDING): Set to ia64_hpux_function_arg_padding(). + (PAD_VARARGS_DOWN): Modify from default to not pad structures down. + * config/ia64/ia64-protos.h (ia64_hpux_function_arg_padding): New. + * config/ia64/ia64.c (ia64_hpux_function_arg_padding): New function + to special case handling of structure padding. + 2001-12-11 Daniel Berlin <dan@cgsoftware.com> * sched-rgn.c (CONST_BASED_ADDRESS_P): CONST_INT -> CONSTANT_P. diff --git a/gcc/calls.c b/gcc/calls.c index 2ab670bb32b..c7f5d994cab 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -1029,7 +1029,9 @@ store_unaligned_arguments_into_pseudos (args, num_actuals) significant byte (to the right). On a BYTES_BIG_ENDIAN machine, this means we must skip the empty high order bytes when calculating the bit offset. */ - if (BYTES_BIG_ENDIAN && bytes < UNITS_PER_WORD) + if (BYTES_BIG_ENDIAN + && !FUNCTION_ARG_REG_LITTLE_ENDIAN + && bytes < UNITS_PER_WORD) big_endian_correction = (BITS_PER_WORD - (bytes * BITS_PER_UNIT)); for (j = 0; j < args[i].n_aligned_regs; j++) diff --git a/gcc/config/ia64/hpux.h b/gcc/config/ia64/hpux.h index 6fb8f87f33e..89b2902bf85 100644 --- a/gcc/config/ia64/hpux.h +++ b/gcc/config/ia64/hpux.h @@ -95,3 +95,30 @@ Boston, MA 02111-1307, USA. */ #undef TARGET_DEFAULT #define TARGET_DEFAULT (MASK_DWARF2_ASM | MASK_BIG_ENDIAN) + +/* This needs to be set to force structure arguments with a single + field to be treated as structures and not as the type of their + field. Without this a structure with a single char will be + returned just like a char variable and that is wrong on HP-UX + IA64. TARGET_STRUCT_ARG_REG_LITTLE_ENDIAN triggers the special + structure handling, this macro simply ensures that single field + structures are always treated like structures. */ + +#define MEMBER_TYPE_FORCES_BLK(FIELD) 1 + +/* Override the setting of FUNCTION_ARG_REG_LITTLE_ENDIAN in + defaults.h. Setting this to true means that we are not passing + structures in registers in the "normal" big-endian way. See + See section 8.5 of the "Itanium Software Conventions and Runtime + Architecture", specifically Table 8-1 and the explanation of Byte 0 + alignment and LSB alignment and a description of how structures + are passed. */ + +#define FUNCTION_ARG_REG_LITTLE_ENDIAN 1 + +#undef FUNCTION_ARG_PADDING +#define FUNCTION_ARG_PADDING(MODE, TYPE) \ + ia64_hpux_function_arg_padding ((MODE), (TYPE)) + +#undef PAD_VARARGS_DOWN +#define PAD_VARARGS_DOWN (!AGGREGATE_TYPE_P (type)) diff --git a/gcc/config/ia64/ia64-protos.h b/gcc/config/ia64/ia64-protos.h index fca7f35551a..c543a538c5f 100644 --- a/gcc/config/ia64/ia64-protos.h +++ b/gcc/config/ia64/ia64-protos.h @@ -134,3 +134,8 @@ extern void sdata_section PARAMS ((void)); #ifdef SBSS_SECTION_ASM_OP extern void sbss_section PARAMS ((void)); #endif + +#ifdef ARGS_SIZE_RTX +/* expr.h defines ARGS_SIZE_RTX and `enum direction'. */ +extern enum direction ia64_hpux_function_arg_padding PARAMS ((enum machine_mode, tree)); +#endif /* ARGS_SIZE_RTX */ diff --git a/gcc/config/ia64/ia64.c b/gcc/config/ia64/ia64.c index d282b70aebc..b70f038390a 100644 --- a/gcc/config/ia64/ia64.c +++ b/gcc/config/ia64/ia64.c @@ -7724,3 +7724,27 @@ ia64_expand_builtin (exp, target, subtarget, mode, ignore) return NULL_RTX; } + +/* For the HP-UX IA64 aggregate parameters are passed stored in the + most significant bits of the stack slot. */ + +enum direction +ia64_hpux_function_arg_padding (mode, type) + enum machine_mode mode; + tree type; +{ + /* Exception to normal case for structures/unions/etc. */ + + if (type && AGGREGATE_TYPE_P (type) + && int_size_in_bytes (type) < UNITS_PER_WORD) + return upward; + + /* This is the standard FUNCTION_ARG_PADDING with !BYTES_BIG_ENDIAN + hardwired to be true. */ + + return((mode == BLKmode + ? (type && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST + && int_size_in_bytes (type) < (PARM_BOUNDARY / BITS_PER_UNIT)) + : GET_MODE_BITSIZE (mode) < PARM_BOUNDARY) + ? downward : upward); +} diff --git a/gcc/defaults.h b/gcc/defaults.h index f23b0ab8a43..ecfcedaaae2 100644 --- a/gcc/defaults.h +++ b/gcc/defaults.h @@ -457,4 +457,14 @@ You Lose! You must define PREFERRED_DEBUGGING_TYPE! #define PREFERRED_DEBUGGING_TYPE NO_DEBUG #endif +/* This is set to 1 if BYTES_BIG_ENDIAN is defined but the target uses a + little-endian method of passing and returning structures in registers. + On the HP-UX IA64 and PA64 platforms structures are aligned differently + then integral values and setting this value to 1 will allow for the + special handling of structure arguments and return values in regs. */ + +#ifndef FUNCTION_ARG_REG_LITTLE_ENDIAN +#define FUNCTION_ARG_REG_LITTLE_ENDIAN 0 +#endif + #endif /* ! GCC_DEFAULTS_H */ diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index beae6e5f259..5e97e914926 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -3435,6 +3435,14 @@ nonzero, the caller does not make a copy. Instead, it passes a pointer to the determined that the value won't be modified, it need not make a copy; otherwise a copy must be made. +@findex FUNCTION_ARG_REG_LITTLE_ENDIAN +@item FUNCTION_ARG_REG_LITTLE_ENDIAN +If defined TRUE on a big-endian system then structure arguments passed +(and returned) in registers are passed in a little-endian manner instead of +the big-endian manner. On the HP-UX IA64 and PA64 platforms structures are +aligned differently then integral values and setting this value to true will +allow for the special handling of structure arguments and return values. + @findex CUMULATIVE_ARGS @item CUMULATIVE_ARGS A C type for declaring a variable that is used as the first argument of diff --git a/gcc/expr.c b/gcc/expr.c index 051dc20a71b..53208057eb7 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -1868,7 +1868,8 @@ move_block_from_reg (regno, x, nregs, size) /* If SIZE is that of a mode no bigger than a word, just use that mode's store operation. */ if (size <= UNITS_PER_WORD - && (mode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0)) != BLKmode) + && (mode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0)) != BLKmode + && !FUNCTION_ARG_REG_LITTLE_ENDIAN) { emit_move_insn (adjust_address (x, mode, 0), gen_rtx_REG (mode, regno)); return; @@ -1877,7 +1878,9 @@ move_block_from_reg (regno, x, nregs, size) /* Blocks smaller than a word on a BYTES_BIG_ENDIAN machine must be aligned to the left before storing to memory. Note that the previous test doesn't handle all cases (e.g. SIZE == 3). */ - if (size < UNITS_PER_WORD && BYTES_BIG_ENDIAN) + if (size < UNITS_PER_WORD + && BYTES_BIG_ENDIAN + && !FUNCTION_ARG_REG_LITTLE_ENDIAN) { rtx tem = operand_subword (x, 0, 1, BLKmode); rtx shift; @@ -2162,15 +2165,25 @@ copy_blkmode_from_reg (tgtblk, srcreg, type) /* This code assumes srcreg is at least a full word. If it isn't, copy it into a new pseudo which is a full word. */ + + /* If FUNCTION_ARG_REG_LITTLE_ENDIAN is set and convert_to_mode does + a copy, the wrong part of the register gets copied so we fake + a type conversion in place. */ + if (GET_MODE (srcreg) != BLKmode && GET_MODE_SIZE (GET_MODE (srcreg)) < UNITS_PER_WORD) - srcreg = convert_to_mode (word_mode, srcreg, TREE_UNSIGNED (type)); + if (FUNCTION_ARG_REG_LITTLE_ENDIAN) + srcreg = simplify_gen_subreg (word_mode, srcreg, GET_MODE (srcreg), 0); + else + srcreg = convert_to_mode (word_mode, srcreg, TREE_UNSIGNED (type)); /* Structures whose size is not a multiple of a word are aligned to the least significant byte (to the right). On a BYTES_BIG_ENDIAN machine, this means we must skip the empty high order bytes when calculating the bit offset. */ - if (BYTES_BIG_ENDIAN && bytes % UNITS_PER_WORD) + if (BYTES_BIG_ENDIAN + && !FUNCTION_ARG_REG_LITTLE_ENDIAN + && bytes % UNITS_PER_WORD) big_endian_correction = (BITS_PER_WORD - ((bytes % UNITS_PER_WORD) * BITS_PER_UNIT)); diff --git a/gcc/stmt.c b/gcc/stmt.c index 8d51a2c04bb..3c4ccd11573 100644 --- a/gcc/stmt.c +++ b/gcc/stmt.c @@ -3197,7 +3197,9 @@ expand_return (retval) to the least significant byte (to the right). On a BYTES_BIG_ENDIAN machine, this means we must skip the empty high order bytes when calculating the bit offset. */ - if (BYTES_BIG_ENDIAN && bytes % UNITS_PER_WORD) + if (BYTES_BIG_ENDIAN + && !FUNCTION_ARG_REG_LITTLE_ENDIAN + && bytes % UNITS_PER_WORD) big_endian_correction = (BITS_PER_WORD - ((bytes % UNITS_PER_WORD) * BITS_PER_UNIT)); diff --git a/gcc/stor-layout.c b/gcc/stor-layout.c index 05eaf247f39..f657463bfd0 100644 --- a/gcc/stor-layout.c +++ b/gcc/stor-layout.c @@ -1149,7 +1149,17 @@ compute_record_mode (type) #ifdef MEMBER_TYPE_FORCES_BLK /* With some targets, eg. c4x, it is sub-optimal to access an aligned BLKmode structure as a scalar. */ - if (mode == VOIDmode && MEMBER_TYPE_FORCES_BLK (field)) + + /* On ia64-*-hpux we need to ensure that we don't change the + mode of a structure containing a single field or else we + will pass it incorrectly. Since a structure with a single + field causes mode to get set above we can't allow the + check for mode == VOIDmode in this case. Perhaps + MEMBER_TYPE_FORCES_BLK should be extended to include mode + as an argument and the check could be put in there for c4x. */ + + if ((mode == VOIDmode || FUNCTION_ARG_REG_LITTLE_ENDIAN) + && MEMBER_TYPE_FORCES_BLK (field)) return; #endif /* MEMBER_TYPE_FORCES_BLK */ } |