* calls.c (store_one_arg): Set default alignment for BLKmode arguments
authordanglin <danglin@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 17 Sep 2002 03:30:37 +0000 (03:30 +0000)
committerdanglin <danglin@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 17 Sep 2002 03:30:37 +0000 (03:30 +0000)
to BITS_PER_UNIT when ARGS_GROW_DOWNWARD and the padding direction is
downward.
* function.c (pad_below):  Always compile.
(locate_and_pad_parm): If defined ARGS_GROW_DOWNWARD, pad argument to
alignment when it is not in a register or REG_PARM_STACK_SPACE is true.
Pad below when the argument is not in a register and the padding
direction is downward.
* pa-64.h (MUST_PASS_IN_STACK): Move define to pa.h.
(PAD_VARARGS_DOWN): Define.
* pa.c (function_arg_padding): Revise padding directions to make them
compatible with the 32 and 64-bit runtime architecture documentation.
(hppa_va_arg):  Add code to handle variable and size zero arguments
passed by reference on TARGET_64BIT.  Reformat.
(function_arg): Use a PARALLEL for BLKmode and aggregates args on
TARGET_64BIT.  Use a DImode PARALLEL for BLKmode args 5 to 8 bytes
wide when !TARGET_64BIT.  Move forward check for mode==VOIDmode.
Add comments.
* pa.h (MAX_PARM_BOUNDARY): Correct define for TARGET_64BIT.
(RETURN_IN_MEMORY): Return size zero types in memory.
(FUNCTION_VALUE): Return TFmode in general registers.
(MUST_PASS_IN_STACK): Define.
(FUNCTION_ARG_BOUNDARY): Simplify.
(FUNCTION_ARG_PASS_BY_REFERENCE): Pass variable and zero sized types
by reference.
(FUNCTION_ARG_CALLEE_COPIES): Define to FUNCTION_ARG_PASS_BY_REFERENCE.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@57226 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/calls.c
gcc/config/pa/pa-64.h
gcc/config/pa/pa.c
gcc/config/pa/pa.h
gcc/function.c

index 06a2ff9..abaa25a 100644 (file)
@@ -1,3 +1,33 @@
+2002-09-16  John David Anglin  <dave@hiauly1.hia.nrc.ca>
+
+       * calls.c (store_one_arg): Set default alignment for BLKmode arguments
+       to BITS_PER_UNIT when ARGS_GROW_DOWNWARD and the padding direction is
+       downward.
+       * function.c (pad_below):  Always compile.
+       (locate_and_pad_parm): If defined ARGS_GROW_DOWNWARD, pad argument to
+       alignment when it is not in a register or REG_PARM_STACK_SPACE is true.
+       Pad below when the argument is not in a register and the padding
+       direction is downward.
+
+       * pa-64.h (MUST_PASS_IN_STACK): Move define to pa.h.
+       (PAD_VARARGS_DOWN): Define.
+       * pa.c (function_arg_padding): Revise padding directions to make them
+       compatible with the 32 and 64-bit runtime architecture documentation.
+       (hppa_va_arg):  Add code to handle variable and size zero arguments
+       passed by reference on TARGET_64BIT.  Reformat.
+       (function_arg): Use a PARALLEL for BLKmode and aggregates args on
+       TARGET_64BIT.  Use a DImode PARALLEL for BLKmode args 5 to 8 bytes
+       wide when !TARGET_64BIT.  Move forward check for mode==VOIDmode.
+       Add comments.
+       * pa.h (MAX_PARM_BOUNDARY): Correct define for TARGET_64BIT.
+       (RETURN_IN_MEMORY): Return size zero types in memory.
+       (FUNCTION_VALUE): Return TFmode in general registers.
+       (MUST_PASS_IN_STACK): Define.
+       (FUNCTION_ARG_BOUNDARY): Simplify.
+       (FUNCTION_ARG_PASS_BY_REFERENCE): Pass variable and zero sized types
+       by reference.
+       (FUNCTION_ARG_CALLEE_COPIES): Define to FUNCTION_ARG_PASS_BY_REFERENCE.
+
 2002-09-16  Richard Henderson  <rth@redhat.com>
 
        * real.c (do_fix_trunc): New.
index 665868f..578bd98 100644 (file)
@@ -4491,6 +4491,7 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space)
     {
       /* BLKmode, at least partly to be pushed.  */
 
+      unsigned int default_align = PARM_BOUNDARY;
       int excess;
       rtx size_rtx;
 
@@ -4498,6 +4499,13 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space)
         If part is passed in registers, PARTIAL says how much
         and emit_push_insn will take care of putting it there.  */
 
+#ifdef ARGS_GROW_DOWNWARD
+      /* When an argument is padded down, the block is not aligned to
+        PARM_BOUNDARY.  */
+      if (FUNCTION_ARG_PADDING (arg->mode, TREE_TYPE (pval)) == downward)
+       default_align = BITS_PER_UNIT;
+#endif
+
       /* Round its size up to a multiple
         of the allocation unit for arguments.  */
 
@@ -4573,7 +4581,7 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space)
           {
            rtx size_rtx1 = GEN_INT (reg_parm_stack_space - arg->offset.constant);
            emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), size_rtx1,
-                           MAX (PARM_BOUNDARY, TYPE_ALIGN (TREE_TYPE (pval))),
+                           MAX (default_align, TYPE_ALIGN (TREE_TYPE (pval))),
                            partial, reg, excess, argblock,
                            ARGS_SIZE_RTX (arg->offset), reg_parm_stack_space,
                            ARGS_SIZE_RTX (arg->alignment_pad));
@@ -4582,7 +4590,7 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space)
        
 
       emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), size_rtx,
-                     MAX (PARM_BOUNDARY, TYPE_ALIGN (TREE_TYPE (pval))),
+                     MAX (default_align, TYPE_ALIGN (TREE_TYPE (pval))),
                      partial, reg, excess, argblock,
                      ARGS_SIZE_RTX (arg->offset), reg_parm_stack_space,
                      ARGS_SIZE_RTX (arg->alignment_pad));
index 82ce3ef..646f5f1 100644 (file)
@@ -88,8 +88,11 @@ Boston, MA 02111-1307, USA.  */
 #undef STATIC_CHAIN_REGNUM
 #define STATIC_CHAIN_REGNUM 31
 
-/* Nonzero if we do not know how to pass TYPE solely in registers.  */
-#define MUST_PASS_IN_STACK(MODE,TYPE) \
-  ((TYPE) != 0                                                 \
-   && (TREE_CODE (TYPE_SIZE (TYPE)) != INTEGER_CST             \
-       || TREE_ADDRESSABLE (TYPE)))
+/* If defined, a C expression which determines whether the default
+   implementation of va_arg will attempt to pad down before reading the
+   next argument, if that argument is smaller than its aligned space as
+   controlled by PARM_BOUNDARY.  If this macro is not defined, all such
+   arguments are padded down when BYTES_BIG_ENDIAN is true.  We don't
+   want aggregrates padded down.  */
+
+#define PAD_VARARGS_DOWN (!AGGREGATE_TYPE_P (type))
index 2d65539..e9679a7 100644 (file)
@@ -5089,22 +5089,33 @@ function_arg_padding (mode, type)
      enum machine_mode mode;
      tree type;
 {
-  int size;
-
-  if (mode == BLKmode)
-    {
-      if (type && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST)
-       size = int_size_in_bytes (type) * BITS_PER_UNIT;
+  if (mode == BLKmode
+      || (TARGET_64BIT && type && AGGREGATE_TYPE_P (type)))
+    {
+      /* Return none if justification is not required.  */
+      if (type
+         && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
+         && (int_size_in_bytes (type) * BITS_PER_UNIT) % PARM_BOUNDARY == 0)
+       return none;
+
+      /* The directions set here are ignored when a BLKmode argument larger
+        than a word is placed in a register.  Different code is used for
+        the stack and registers.  This makes it difficult to have a
+        consistent data representation for both the stack and registers.
+        For both runtimes, the justification and padding for arguments on
+        the stack and in registers should be identical.  */
+      if (TARGET_64BIT)
+       /* The 64-bit runtime specifies left justification for aggregates.  */
+        return upward;
       else
-       return upward;          /* Don't know if this is right, but */
-                               /* same as old definition.  */
+       /* The 32-bit runtime architecture specifies right justification.
+          When the argument is passed on the stack, the argument is padded
+          with garbage on the left.  The HP compiler pads with zeros.  */
+       return downward;
     }
-  else
-    size = GET_MODE_BITSIZE (mode);
-  if (size < PARM_BOUNDARY)
+
+  if (GET_MODE_BITSIZE (mode) < PARM_BOUNDARY)
     return downward;
-  else if (size % PARM_BOUNDARY)
-    return upward;
   else
     return none;
 }
@@ -5196,15 +5207,23 @@ rtx
 hppa_va_arg (valist, type)
      tree valist, type;
 {
-  HOST_WIDE_INT align, size, ofs;
+  HOST_WIDE_INT size = int_size_in_bytes (type);
+  HOST_WIDE_INT ofs;
   tree t, ptr, pptr;
 
   if (TARGET_64BIT)
     {
-      /* Every argument in PA64 is passed by value (including large structs).
-         Arguments with size greater than 8 must be aligned 0 MOD 16.  */
+      /* Every argument in PA64 is supposed to be passed by value
+        (including large structs).  However, as a GCC extension, we
+        pass zero and variable sized arguments by reference.  Empty
+        structures are a GCC extension not supported by the HP
+        compilers.  Thus, passing them by reference isn't likely
+        to conflict with the ABI.  For variable sized arguments,
+        GCC doesn't have the infrastructure to allocate these to
+        registers.  */
+
+      /* Arguments with a size greater than 8 must be aligned 0 MOD 16.  */
 
-      size = int_size_in_bytes (type);
       if (size > UNITS_PER_WORD)
         {
           t = build (PLUS_EXPR, TREE_TYPE (valist), valist,
@@ -5213,57 +5232,75 @@ hppa_va_arg (valist, type)
                      build_int_2 (-2 * UNITS_PER_WORD, -1));
           t = build (MODIFY_EXPR, TREE_TYPE (valist), valist, t);
           TREE_SIDE_EFFECTS (t) = 1;
-          expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+         expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
         }
-      return std_expand_builtin_va_arg (valist, type);
-    }
-
-  /* Compute the rounded size of the type.  */
-  align = PARM_BOUNDARY / BITS_PER_UNIT;
-  size = int_size_in_bytes (type);
 
-  ptr = build_pointer_type (type);
+      if (size > 0)
+       return std_expand_builtin_va_arg (valist, type);
+      else
+       {
+         ptr = build_pointer_type (type);
 
-  /* "Large" types are passed by reference.  */
-  if (size > 8)
-    {
-      t = build (PREDECREMENT_EXPR, TREE_TYPE (valist), valist,
-                build_int_2 (POINTER_SIZE / BITS_PER_UNIT, 0));
-      TREE_SIDE_EFFECTS (t) = 1;
+         /* Args grow upward.  */
+         t = build (POSTINCREMENT_EXPR, TREE_TYPE (valist), valist,
+                    build_int_2 (POINTER_SIZE / BITS_PER_UNIT, 0));
+         TREE_SIDE_EFFECTS (t) = 1;
 
-      pptr = build_pointer_type (ptr);
-      t = build1 (NOP_EXPR, pptr, t);
-      TREE_SIDE_EFFECTS (t) = 1;
+         pptr = build_pointer_type (ptr);
+         t = build1 (NOP_EXPR, pptr, t);
+         TREE_SIDE_EFFECTS (t) = 1;
 
-      t = build1 (INDIRECT_REF, ptr, t);
-      TREE_SIDE_EFFECTS (t) = 1;
+         t = build1 (INDIRECT_REF, ptr, t);
+         TREE_SIDE_EFFECTS (t) = 1;
+       }
     }
-  else
+  else /* !TARGET_64BIT */
     {
-      t = build (PLUS_EXPR, TREE_TYPE (valist), valist,
-                build_int_2 (-size, -1));
+      ptr = build_pointer_type (type);
 
-      /* Copied from va-pa.h, but we probably don't need to align
-        to word size, since we generate and preserve that invariant.  */
-      t = build (BIT_AND_EXPR, TREE_TYPE (valist), t,
-                build_int_2 ((size > 4 ? -8 : -4), -1));
+      /* "Large" and variable sized types are passed by reference.  */
+      if (size > 8 || size <= 0)
+       {
+         /* Args grow downward.  */
+         t = build (PREDECREMENT_EXPR, TREE_TYPE (valist), valist,
+                    build_int_2 (POINTER_SIZE / BITS_PER_UNIT, 0));
+         TREE_SIDE_EFFECTS (t) = 1;
 
-      t = build (MODIFY_EXPR, TREE_TYPE (valist), valist, t);
-      TREE_SIDE_EFFECTS (t) = 1;
+         pptr = build_pointer_type (ptr);
+         t = build1 (NOP_EXPR, pptr, t);
+         TREE_SIDE_EFFECTS (t) = 1;
 
-      ofs = (8 - size) % 4;
-      if (ofs)
-       {
-         t = build (PLUS_EXPR, TREE_TYPE (valist), t, build_int_2 (ofs, 0));
+         t = build1 (INDIRECT_REF, ptr, t);
          TREE_SIDE_EFFECTS (t) = 1;
        }
+      else
+       {
+         t = build (PLUS_EXPR, TREE_TYPE (valist), valist,
+                    build_int_2 (-size, -1));
+
+         /* Copied from va-pa.h, but we probably don't need to align to
+            word size, since we generate and preserve that invariant.  */
+         t = build (BIT_AND_EXPR, TREE_TYPE (valist), t,
+                    build_int_2 ((size > 4 ? -8 : -4), -1));
+
+         t = build (MODIFY_EXPR, TREE_TYPE (valist), valist, t);
+         TREE_SIDE_EFFECTS (t) = 1;
+
+         ofs = (8 - size) % 4;
+         if (ofs)
+           {
+             t = build (PLUS_EXPR, TREE_TYPE (valist), t,
+                        build_int_2 (ofs, 0));
+             TREE_SIDE_EFFECTS (t) = 1;
+           }
 
-      t = build1 (NOP_EXPR, ptr, t);
-      TREE_SIDE_EFFECTS (t) = 1;
+         t = build1 (NOP_EXPR, ptr, t);
+         TREE_SIDE_EFFECTS (t) = 1;
+       }
     }
 
   /* Calculate!  */
-  return expand_expr (t, NULL_RTX, Pmode, EXPAND_NORMAL);
+  return expand_expr (t, NULL_RTX, VOIDmode, EXPAND_NORMAL);
 }
 
 
@@ -7446,28 +7483,32 @@ function_arg (cum, mode, type, named, incoming)
      int incoming;
 {
   int max_arg_words = (TARGET_64BIT ? 8 : 4);
-  int arg_size = FUNCTION_ARG_SIZE (mode, type);
   int alignment = 0;
+  int arg_size;
   int fpr_reg_base;
   int gpr_reg_base;
   rtx retval;
 
+  if (mode == VOIDmode)
+    return NULL_RTX;
+
+  arg_size = FUNCTION_ARG_SIZE (mode, type);
+
+  /* If this arg would be passed partially or totally on the stack, then
+     this routine should return zero.  FUNCTION_ARG_PARTIAL_NREGS will
+     handle arguments which are split between regs and stack slots if
+     the ABI mandates split arguments.  */
   if (! TARGET_64BIT)
     {
-      /* If this arg would be passed partially or totally on the stack, then
-         this routine should return zero.  FUNCTION_ARG_PARTIAL_NREGS will
-         handle arguments which are split between regs and stack slots if
-         the ABI mandates split arguments.  */
-      if (cum->words + arg_size > max_arg_words
-          || mode == VOIDmode)
+      /* The 32-bit ABI does not split arguments.  */
+      if (cum->words + arg_size > max_arg_words)
        return NULL_RTX;
     }
   else
     {
       if (arg_size > 1)
        alignment = cum->words & 1;
-      if (cum->words + alignment >= max_arg_words
-         || mode == VOIDmode)
+      if (cum->words + alignment >= max_arg_words)
        return NULL_RTX;
     }
 
@@ -7488,8 +7529,11 @@ function_arg (cum, mode, type, named, incoming)
       gpr_reg_base = 26 - cum->words;
       fpr_reg_base = 32 + cum->words;
 
-      /* Arguments wider than one word need special treatment.  */
-      if (arg_size > 1)
+      /* Arguments wider than one word and small aggregates need special
+        treatment.  */
+      if (arg_size > 1
+         || mode == BLKmode
+         || (type && AGGREGATE_TYPE_P (type)))
        {
          /* Double-extended precision (80-bit), quad-precision (128-bit)
             and aggregates including complex numbers are aligned on
@@ -7497,7 +7541,10 @@ function_arg (cum, mode, type, named, incoming)
             are associated one-to-one, with general registers r26
             through r19, and also with floating-point registers fr4
             through fr11.  Arguments larger than one word are always
-            passed in general registers.  */
+            passed in general registers.
+
+            Using a PARALLEL with a word mode register results in left
+            justified data on a big-endian target.  */
 
          rtx loc[8];
          int i, offset = 0, ub = arg_size;
@@ -7517,7 +7564,7 @@ function_arg (cum, mode, type, named, incoming)
 
          return gen_rtx_PARALLEL (mode, gen_rtvec_v (ub, loc));
        }
-    }
+     }
   else
     {
       /* If the argument is larger than a word, then we know precisely
@@ -7534,6 +7581,34 @@ function_arg (cum, mode, type, named, incoming)
              gpr_reg_base = 25;
              fpr_reg_base = 34;
            }
+
+         /* Structures 5 to 8 bytes in size are passed in the general
+            registers in the same manner as other non floating-point
+            objects.  The data is right-justified and zero-extended
+            to 64 bits.
+
+            This is magic.  Normally, using a PARALLEL results in left
+            justified data on a big-endian target.  However, using a
+            single double-word register provides the required right
+            justication for 5 to 8 byte structures.  This has nothing
+            to do with the direction of padding specified for the argument.
+            It has to do with how the data is widened and shifted into
+            and from the register.
+
+            Aside from adding load_multiple and store_multiple patterns,
+            this is the only way that I have found to obtain right
+            justification of BLKmode data when it has a size greater
+            than one word.  Splitting the operation into two SImode loads
+            or returning a DImode REG results in left justified data.  */
+         if (mode == BLKmode)
+           {
+             rtx loc[1];
+
+             loc[0] = gen_rtx_EXPR_LIST (VOIDmode,
+                                         gen_rtx_REG (DImode, gpr_reg_base),
+                                         const0_rtx);
+             return gen_rtx_PARALLEL (mode, gen_rtvec_v (1, loc));
+           }
        }
       else
         {
index 04e417f..aeef60f 100644 (file)
@@ -407,7 +407,7 @@ extern int target_flags;
 
 /* Largest alignment required for any stack parameter, in bits.
    Don't define this if it is equal to PARM_BOUNDARY */
-#define MAX_PARM_BOUNDARY 64
+#define MAX_PARM_BOUNDARY (2 * PARM_BOUNDARY)
 
 /* Boundary (in *bits*) on which stack pointer is always aligned;
    certain optimizations in combine depend on this.
@@ -506,9 +506,13 @@ extern struct rtx_def *hppa_pic_save_rtx PARAMS ((void));
    PA64 ABI says that objects larger than 128 bits are returned in memory.
    Note, int_size_in_bytes can return -1 if the size of the object is
    variable or larger than the maximum value that can be expressed as
-   a HOST_WIDE_INT.  */
+   a HOST_WIDE_INT.   It can also return zero for an empty type.  The
+   simplest way to handle variable and empty types is to pass them in
+   memory.  This avoids problems in defining the boundaries of argument
+   slots, allocating registers, etc.  */
 #define RETURN_IN_MEMORY(TYPE) \
-  ((unsigned HOST_WIDE_INT) int_size_in_bytes (TYPE) > (TARGET_64BIT ? 16 : 8))
+  (int_size_in_bytes (TYPE) > (TARGET_64BIT ? 16 : 8)  \
+   || int_size_in_bytes (TYPE) <= 0)
 
 /* Register in which address to store a structure value
    is passed to a function.  */
@@ -681,16 +685,18 @@ extern struct rtx_def *hppa_pic_save_rtx PARAMS ((void));
    otherwise, FUNC is 0.  */
 
 /* On the HP-PA the value is found in register(s) 28(-29), unless
-   the mode is SF or DF. Then the value is returned in fr4 (32, ) */
+   the mode is SF or DF. Then the value is returned in fr4 (32).  */
 
 /* This must perform the same promotions as PROMOTE_MODE, else
    PROMOTE_FUNCTION_RETURN will not work correctly.  */
-#define FUNCTION_VALUE(VALTYPE, FUNC)                          \
-  gen_rtx_REG (((INTEGRAL_TYPE_P (VALTYPE)                     \
-                && TYPE_PRECISION (VALTYPE) < BITS_PER_WORD)   \
-               || POINTER_TYPE_P (VALTYPE))                    \
-              ? word_mode : TYPE_MODE (VALTYPE),               \
-              TREE_CODE (VALTYPE) == REAL_TYPE && !TARGET_SOFT_FLOAT ? 32 : 28)
+#define FUNCTION_VALUE(VALTYPE, FUNC)                                  \
+  gen_rtx_REG (((INTEGRAL_TYPE_P (VALTYPE)                             \
+                && TYPE_PRECISION (VALTYPE) < BITS_PER_WORD)           \
+               || POINTER_TYPE_P (VALTYPE))                            \
+               ? word_mode : TYPE_MODE (VALTYPE),                      \
+              (TREE_CODE (VALTYPE) == REAL_TYPE                        \
+               && TYPE_MODE (VALTYPE) != TFmode                        \
+               && !TARGET_SOFT_FLOAT) ? 32 : 28)
 
 /* Define how to find the value returned by a library function
    assuming the value has mode MODE.  */
@@ -745,7 +751,9 @@ struct hppa_args {int words, nargs_prototype, indirect; };
   (CUM).indirect = 0,                          \
   (CUM).nargs_prototype = 1000
 
-/* Figure out the size in words of the function argument.  */
+/* Figure out the size in words of the function argument.  The size
+   returned by this macro should always be greater than zero because
+   we pass variable and zero sized objects by reference.  */
 
 #define FUNCTION_ARG_SIZE(MODE, TYPE)  \
   ((((MODE) != BLKmode \
@@ -817,6 +825,12 @@ struct hppa_args {int words, nargs_prototype, indirect; };
 #define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \
   function_arg (&CUM, MODE, TYPE, NAMED, 0)
 
+/* Nonzero if we do not know how to pass TYPE solely in registers.  */
+#define MUST_PASS_IN_STACK(MODE,TYPE) \
+  ((TYPE) != 0                                                 \
+   && (TREE_CODE (TYPE_SIZE (TYPE)) != INTEGER_CST             \
+       || TREE_ADDRESSABLE (TYPE)))
+
 #define FUNCTION_INCOMING_ARG(CUM, MODE, TYPE, NAMED) \
   function_arg (&CUM, MODE, TYPE, NAMED, 1)
 
@@ -833,33 +847,37 @@ struct hppa_args {int words, nargs_prototype, indirect; };
    bits, of an argument with the specified mode and type.  If it is
    not defined,  `PARM_BOUNDARY' is used for all arguments.  */
 
-#define FUNCTION_ARG_BOUNDARY(MODE, TYPE)                      \
-  (((TYPE) != 0)                                               \
-   ? ((integer_zerop (TYPE_SIZE (TYPE))                                \
-       || ! TREE_CONSTANT (TYPE_SIZE (TYPE)))                  \
-      ? BITS_PER_UNIT                                          \
-      : (((int_size_in_bytes (TYPE)) + UNITS_PER_WORD - 1)     \
-        / UNITS_PER_WORD) * BITS_PER_WORD)                     \
-   : ((GET_MODE_ALIGNMENT(MODE) <= PARM_BOUNDARY)              \
-      ? PARM_BOUNDARY : GET_MODE_ALIGNMENT(MODE)))
-
-/* Arguments larger than eight bytes are passed by invisible reference */
-
-/* PA64 does not pass anything by invisible reference.  */
+/* Arguments larger than one word are double word aligned.  */
+
+#define FUNCTION_ARG_BOUNDARY(MODE, TYPE)                              \
+  (((TYPE)                                                             \
+    ? (integer_zerop (TYPE_SIZE (TYPE))                                        \
+       || !TREE_CONSTANT (TYPE_SIZE (TYPE))                            \
+       || int_size_in_bytes (TYPE) <= UNITS_PER_WORD)                  \
+    : GET_MODE_SIZE(MODE) <= UNITS_PER_WORD)                           \
+   ? PARM_BOUNDARY : MAX_PARM_BOUNDARY)
+
+/* In the 32-bit runtime, arguments larger than eight bytes are passed
+   by invisible reference.  As a GCC extension, we also pass anything
+   with a zero or variable size by reference.
+
+   The 64-bit runtime does not describe passing any types by invisible
+   reference.  The internals of GCC can't currently handle passing
+   empty structures, and zero or variable length arrays when they are
+   not passed entirely on the stack or by reference.  Thus, as a GCC
+   extension, we pass these types by reference.  The HP compiler doesn't
+   support these types, so hopefully there shouldn't be any compatibility
+   issues.  This may have to be revisited when HP releases a C99 compiler
+   or updates the ABI.  */
 #define FUNCTION_ARG_PASS_BY_REFERENCE(CUM, MODE, TYPE, NAMED)         \
   (TARGET_64BIT                                                                \
-   ? 0                                                                 \
-   : (((TYPE) && int_size_in_bytes (TYPE) > 8)                         \
+   ? ((TYPE) && int_size_in_bytes (TYPE) <= 0)                         \
+   : (((TYPE) && (int_size_in_bytes (TYPE) > 8                         \
+                 || int_size_in_bytes (TYPE) <= 0))                    \
       || ((MODE) && GET_MODE_SIZE (MODE) > 8)))
  
-/* PA64 does not pass anything by invisible reference.
-   This should be undef'ed for 64bit, but we'll see if this works. The
-   problem is that we can't test TARGET_64BIT from the preprocessor.  */
-#define FUNCTION_ARG_CALLEE_COPIES(CUM, MODE, TYPE, NAMED) \
-  (TARGET_64BIT                                                        \
-   ? 0                                                         \
-   : (((TYPE) && int_size_in_bytes (TYPE) > 8)                 \
-      || ((MODE) && GET_MODE_SIZE (MODE) > 8)))
+#define FUNCTION_ARG_CALLEE_COPIES(CUM, MODE, TYPE, NAMED)             \
+  FUNCTION_ARG_PASS_BY_REFERENCE (CUM, MODE, TYPE, NAMED)
 
 \f
 extern GTY(()) rtx hppa_compare_op0;
index 424f06c..edc1581 100644 (file)
@@ -255,10 +255,8 @@ static int instantiate_virtual_regs_1 PARAMS ((rtx *, rtx, int));
 static void delete_handlers    PARAMS ((void));
 static void pad_to_arg_alignment PARAMS ((struct args_size *, int,
                                          struct args_size *));
-#ifndef ARGS_GROW_DOWNWARD
 static void pad_below          PARAMS ((struct args_size *, enum machine_mode,
                                         tree));
-#endif
 static rtx round_trampoline_addr PARAMS ((rtx));
 static rtx adjust_trampoline_addr PARAMS ((rtx));
 static tree *identify_blocks_1 PARAMS ((rtx, tree *, tree *, tree *));
@@ -5244,6 +5242,9 @@ locate_and_pad_parm (passed_mode, type, in_regs, fndecl,
     = type ? size_in_bytes (type) : size_int (GET_MODE_SIZE (passed_mode));
   enum direction where_pad = FUNCTION_ARG_PADDING (passed_mode, type);
   int boundary = FUNCTION_ARG_BOUNDARY (passed_mode, type);
+#ifdef ARGS_GROW_DOWNWARD
+  tree s2 = sizetree;
+#endif
 
 #ifdef REG_PARM_STACK_SPACE
   /* If we have found a stack parm before we reach the end of the
@@ -5289,13 +5290,20 @@ locate_and_pad_parm (passed_mode, type, in_regs, fndecl,
       offset_ptr->constant = -initial_offset_ptr->constant;
       offset_ptr->var = 0;
     }
+
   if (where_pad != none
       && (!host_integerp (sizetree, 1)
          || (tree_low_cst (sizetree, 1) * BITS_PER_UNIT) % PARM_BOUNDARY))
-    sizetree = round_up (sizetree, PARM_BOUNDARY / BITS_PER_UNIT);
-  SUB_PARM_SIZE (*offset_ptr, sizetree);
-  if (where_pad != downward)
+    s2 = round_up (s2, PARM_BOUNDARY / BITS_PER_UNIT);
+  SUB_PARM_SIZE (*offset_ptr, s2);
+
+  if (!in_regs
+#ifdef REG_PARM_STACK_SPACE
+      || REG_PARM_STACK_SPACE (fndecl) > 0
+#endif
+     )
     pad_to_arg_alignment (offset_ptr, boundary, alignment_pad);
+
   if (initial_offset_ptr->var)
     arg_size_ptr->var = size_binop (MINUS_EXPR,
                                    size_binop (MINUS_EXPR,
@@ -5307,6 +5315,13 @@ locate_and_pad_parm (passed_mode, type, in_regs, fndecl,
     arg_size_ptr->constant = (-initial_offset_ptr->constant
                              - offset_ptr->constant);
 
+  /* Pad_below needs the pre-rounded size to know how much to pad below.
+     We only pad parameters which are not in registers as they have their
+     padding done elsewhere.  */
+  if (where_pad == downward
+      && !in_regs)
+    pad_below (offset_ptr, passed_mode, sizetree);
+
 #else /* !ARGS_GROW_DOWNWARD */
   if (!in_regs
 #ifdef REG_PARM_STACK_SPACE
@@ -5392,7 +5407,6 @@ pad_to_arg_alignment (offset_ptr, boundary, alignment_pad)
     }
 }
 
-#ifndef ARGS_GROW_DOWNWARD
 static void
 pad_below (offset_ptr, passed_mode, sizetree)
      struct args_size *offset_ptr;
@@ -5420,7 +5434,6 @@ pad_below (offset_ptr, passed_mode, sizetree)
        }
     }
 }
-#endif
 \f
 /* Walk the tree of blocks describing the binding levels within a function
    and warn about uninitialized variables.