summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog23
-rw-r--r--gcc/calls.c4
-rw-r--r--gcc/config/ia64/hpux.h27
-rw-r--r--gcc/config/ia64/ia64-protos.h5
-rw-r--r--gcc/config/ia64/ia64.c24
-rw-r--r--gcc/defaults.h10
-rw-r--r--gcc/doc/tm.texi8
-rw-r--r--gcc/expr.c21
-rw-r--r--gcc/stmt.c4
-rw-r--r--gcc/stor-layout.c12
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 */
}