HP-UX IA64 structure passing patch

Steve Ellcey sje@cup.hp.com
Sun Nov 18 06:02:00 GMT 2001


This patch changes how small structures are passed for HP-UX on the IA64
platform.  This system does not use "standard" big-endian parameter
passing for small structures passed in registers.  Instead, structures
are left-aligned, unlike integral values which are right aligned as one
would expect.  While passing parameters the "normal" way would work for
GCC it would cause problems when interacting with code compiled by the
native HP compiler.

To implement this I added a variable to the target structure as I
understand that this is now preferred to creating new macros.

I do not have write access to CVS so if someone could review it and
check it in that would be great.

Steve Ellcey
sje@cup.hp.com


--- 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 11:16:38 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 = gen_rtx_REG (word_mode, REGNO(srcreg));
+    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