HP-UX IA64 structure passing patch
Steve Ellcey
sje@cup.hp.com
Wed Nov 28 16:26:00 GMT 2001
> > To implement this I added a variable to the target structure as I
> > understand that this is now preferred to creating new macros.
>
> You didn't include documentation, a ChangeLog entry or details of where
> this was tested. Please read and follow the instructions.
>
> Joseph S. Myers
> jsm28@cam.ac.uk
I hate it when I do that. Here is the patch again with documentation
and a ChangeLog entry and a code change recommended by Richard
Henderson. It was tested on IA64 HP-UX with the gcc testsuite and there
were no new failures. I also wrote some specific tests to test
interoperability with HP C and those tests all passed.
Steve Ellcey
sje@cup.hp.com
2001-11-28 Steve Ellcey <sje@cup.hp.com>
* doc/tm.texi (TARGET_STRUCT_ARG_REG_LITTLE_ENDIAN): New.
* target.h (targetm.struct_arg_reg_little_endian): New.
* target-def.h (TARGET_STRUCT_ARG_REG_LITTLE_ENDIAN): New.
* calls.c (store_unaligned_arguments_into_pseudos): Check
targetm.struct_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
targetm.struct_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.
(TARGET_STRUCT_ARG_REG_LITTLE_ENDIAN): New, set it to true.
--- orig/gcc/gcc/doc/tm.texi Wed Nov 28 16:08:32 2001
+++ gcc/gcc/doc/tm.texi Wed Nov 28 16:06:38 2001
@@ -6785,6 +6785,14 @@ collecting constructors and destructors
It is false if we must use @command{collect2}.
@end deftypefn
+@deftypefn {Target Hook} bool TARGET_STRUCT_ARG_REG_LITTLE_ENDIAN
+This value is true if the target is big-endian and uses a non-standard
+(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 true will allow for the
+special handling of structure arguments and return values.
+@end deftypefn
+
@deftypefn {Target Hook} void TARGET_ASM_CONSTRUCTOR (rtx @var{symbol}, int @var{priority})
If defined, a function that outputs assembler code to arrange to call
the function referenced by @var{symbol} at initialization time.
--- orig/gcc/gcc/target.h Wed Nov 28 12:29:17 2001
+++ gcc/gcc/target.h Wed Nov 28 11:19:42 2001
@@ -163,6 +163,10 @@ struct gcc_target
/* True if "native" constructors and destructors are supported,
false if we're using collect2 for the job. */
bool have_ctors_dtors;
+
+ /* True if big-endian system passes/returns structures in a non-standard
+ (little-endian) manner, this is needed for HP-UX IA64 and PA64. */
+ bool struct_arg_reg_little_endian;
};
extern struct gcc_target targetm;
--- orig/gcc/gcc/target-def.h Wed Nov 28 12:29:17 2001
+++ gcc/gcc/target-def.h Wed Nov 28 11:18:56 2001
@@ -136,6 +136,10 @@ Foundation, 59 Temple Place - Suite 330,
#define TARGET_SECTION_TYPE_FLAGS default_section_type_flags
#endif
+#ifndef TARGET_STRUCT_ARG_REG_LITTLE_ENDIAN
+#define TARGET_STRUCT_ARG_REG_LITTLE_ENDIAN false
+#endif
+
/* The whole shebang. */
#define TARGET_INITIALIZER \
{ \
@@ -152,5 +156,6 @@ Foundation, 59 Temple Place - Suite 330,
TARGET_EXPAND_BUILTIN, \
TARGET_SECTION_TYPE_FLAGS, \
TARGET_HAVE_NAMED_SECTIONS, \
- TARGET_HAVE_CTORS_DTORS \
+ TARGET_HAVE_CTORS_DTORS, \
+ TARGET_STRUCT_ARG_REG_LITTLE_ENDIAN \
}
--- orig/gcc/gcc/calls.c Wed Nov 28 12:29:17 2001
+++ gcc/gcc/calls.c Wed Nov 28 11:04:44 2001
@@ -33,6 +33,7 @@ Software Foundation, 59 Temple Place - S
#include "tm_p.h"
#include "timevar.h"
#include "sbitmap.h"
+#include "target.h"
#if !defined FUNCTION_OK_FOR_SIBCALL
#define FUNCTION_OK_FOR_SIBCALL(DECL) 1
@@ -1029,7 +1030,9 @@ store_unaligned_arguments_into_pseudos (
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
+ && !targetm.struct_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++)
--- orig/gcc/gcc/expr.c Wed Nov 28 12:29:17 2001
+++ gcc/gcc/expr.c Wed Nov 28 16:07:43 2001
@@ -45,6 +45,7 @@ Software Foundation, 59 Temple Place - S
#include "langhooks.h"
#include "intl.h"
#include "tm_p.h"
+#include "target.h"
/* Decide whether a function's arguments should be processed
from first to last or from last to first.
@@ -1877,7 +1878,8 @@ move_block_from_reg (regno, x, nregs, si
/* 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
+ && !targetm.struct_arg_reg_little_endian)
{
emit_move_insn (adjust_address (x, mode, 0), gen_rtx_REG (mode, regno));
return;
@@ -1886,7 +1888,9 @@ move_block_from_reg (regno, x, nregs, si
/* 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
+ && !targetm.struct_arg_reg_little_endian)
{
rtx tem = operand_subword (x, 0, 1, BLKmode);
rtx shift;
@@ -2171,15 +2175,25 @@ copy_blkmode_from_reg (tgtblk, srcreg, t
/* 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 struct_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 (targetm.struct_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
+ && !targetm.struct_arg_reg_little_endian
+ && bytes % UNITS_PER_WORD)
big_endian_correction
= (BITS_PER_WORD - ((bytes % UNITS_PER_WORD) * BITS_PER_UNIT));
--- orig/gcc/gcc/stmt.c Wed Nov 28 12:29:17 2001
+++ gcc/gcc/stmt.c Wed Nov 28 11:18:07 2001
@@ -53,6 +53,7 @@ Software Foundation, 59 Temple Place - S
#include "toplev.h"
#include "output.h"
#include "ggc.h"
+#include "target.h"
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
@@ -3214,7 +3215,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
+ && !targetm.struct_arg_reg_little_endian
+ && bytes % UNITS_PER_WORD)
big_endian_correction = (BITS_PER_WORD - ((bytes % UNITS_PER_WORD)
* BITS_PER_UNIT));
--- orig/gcc/gcc/stor-layout.c Wed Nov 28 12:29:17 2001
+++ gcc/gcc/stor-layout.c Wed Nov 28 11:02:59 2001
@@ -30,6 +30,7 @@ Software Foundation, 59 Temple Place - S
#include "expr.h"
#include "toplev.h"
#include "ggc.h"
+#include "target.h"
/* Set to one when set_sizetype has been called. */
static int sizetype_set;
@@ -1145,7 +1146,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 || targetm.struct_arg_reg_little_endian)
+ && MEMBER_TYPE_FORCES_BLK (field))
return;
#endif /* MEMBER_TYPE_FORCES_BLK */
}
--- orig/gcc/gcc/config/ia64/hpux.h Wed Nov 28 12:28:14 2001
+++ gcc/gcc/config/ia64/hpux.h Wed Nov 28 10:59:40 2001
@@ -95,3 +95,23 @@ 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 targetm.struct_arg_reg_little_endian in
+ target-def.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 TARGET_STRUCT_ARG_REG_LITTLE_ENDIAN true
More information about the Gcc-patches
mailing list