One of the nice features of the ELFv2 ABI is that stack frames are
smaller compared to ELFv1.  We don't allocate a parameter save area
unless we actually use it.  However, for variable argument lists, we
kept the simple va_list type which is a pointer to the memory location
of the next parameter.  This means calls to variable argument list
functions must allocate the parameter save area, and hence calls to
unprototyped functions must also do so.

The wrinkle with K&R style C functions is that function *definitions*
may be unprototyped.  So when compiling a function body we can't use
!prototype_p() to say we have a parameter save area.  A call in some
other compilation unit might be prototyped and so not allocate a
parameter save area.  Another consequence of unprototyped function
definitions is that the return type and argument types may not be
available on the function type node.  Instead you need to look at the
return and arguments on the function decl.

Now, function.c always passes a decl to REG_PARM_STACK_SPACE, but
calls.c sometimes passes a decl and sometimes a type.  This latter
fact makes it necessary, I think, to define an
INCOMING_REG_PARM_STACK_SPACE used by function.c.  You can't blindly
use a decl from calls.c as that falls foul of C++..

The following implements this.  Bootstrapped and regression tested
powerpc64le-linux and powerpc64-linux all langs (except Ada since I
didn't have gnat installed.)  OK to apply?

        PR target/61300
        * doc/tm.texi.in (INCOMING_REG_PARM_STACK_SPACE): Document.
        * doc/tm.texi: Regenerate.
        * function.c (INCOMING_REG_PARM_STACK_SPACE): Provide default.
        Use throughout in place of REG_PARM_STACK_SPACE.
        * config/rs6000/rs6000.c (rs6000_reg_parm_stack_space): Add
        "incoming" param.  Pass to rs6000_function_parms_need_stack.
        (rs6000_function_parms_need_stack): Add "incoming" param, ignore
        prototype_p when incoming.  Use function decl when incoming
        to handle K&R style functions.
        * config/rs6000/rs6000.h (REG_PARM_STACK_SPACE): Adjust.
        (INCOMING_REG_PARM_STACK_SPACE): Define.

Index: gcc/doc/tm.texi.in
===================================================================
--- gcc/doc/tm.texi.in  (revision 210919)
+++ gcc/doc/tm.texi.in  (working copy)
@@ -3499,6 +3499,13 @@ which.
 @c above is overfull.  not sure what to do.  --mew 5feb93  did
 @c something, not sure if it looks good.  --mew 10feb93
 
+@defmac INCOMING_REG_PARM_STACK_SPACE (@var{fndecl})
+Like @code{REG_PARM_STACK_SPACE}, but for incoming register arguments.
+Define this macro if space guaranteed when compiling a function body
+is different to space required when making a call, a situation that
+can arise with unprototyped functions.
+@end defmac
+
 @defmac OUTGOING_REG_PARM_STACK_SPACE (@var{fntype})
 Define this to a nonzero value if it is the responsibility of the
 caller to allocate the area reserved for arguments passed in registers
Index: gcc/doc/tm.texi
===================================================================
--- gcc/doc/tm.texi     (revision 210919)
+++ gcc/doc/tm.texi     (working copy)
@@ -3948,6 +3948,13 @@ which.
 @c above is overfull.  not sure what to do.  --mew 5feb93  did
 @c something, not sure if it looks good.  --mew 10feb93
 
+@defmac INCOMING_REG_PARM_STACK_SPACE (@var{fndecl})
+Like @code{REG_PARM_STACK_SPACE}, but for incoming register arguments.
+Define this macro if space guaranteed when compiling a function body
+is different to space required when making a call, a situation that
+can arise with unprototyped functions.
+@end defmac
+
 @defmac OUTGOING_REG_PARM_STACK_SPACE (@var{fntype})
 Define this to a nonzero value if it is the responsibility of the
 caller to allocate the area reserved for arguments passed in registers
Index: gcc/function.c
===================================================================
--- gcc/function.c      (revision 210919)
+++ gcc/function.c      (working copy)
@@ -1348,9 +1348,13 @@ static int cfa_offset;
 #define STACK_POINTER_OFFSET   0
 #endif
 
+#if defined (REG_PARM_STACK_SPACE) && !defined (INCOMING_REG_PARM_STACK_SPACE)
+#define INCOMING_REG_PARM_STACK_SPACE REG_PARM_STACK_SPACE
+#endif
+
 /* If not defined, pick an appropriate default for the offset of dynamically
    allocated memory depending on the value of ACCUMULATE_OUTGOING_ARGS,
-   REG_PARM_STACK_SPACE, and OUTGOING_REG_PARM_STACK_SPACE.  */
+   INCOMING_REG_PARM_STACK_SPACE, and OUTGOING_REG_PARM_STACK_SPACE.  */
 
 #ifndef STACK_DYNAMIC_OFFSET
 
@@ -1362,12 +1366,12 @@ static int cfa_offset;
    `crtl->outgoing_args_size'.  Nevertheless, we must allow
    for it when allocating stack dynamic objects.  */
 
-#if defined(REG_PARM_STACK_SPACE)
+#ifdef INCOMING_REG_PARM_STACK_SPACE
 #define STACK_DYNAMIC_OFFSET(FNDECL)   \
 ((ACCUMULATE_OUTGOING_ARGS                                                   \
   ? (crtl->outgoing_args_size                                \
      + (OUTGOING_REG_PARM_STACK_SPACE ((!(FNDECL) ? NULL_TREE : TREE_TYPE 
(FNDECL))) ? 0 \
-                                              : REG_PARM_STACK_SPACE 
(FNDECL))) \
+                                              : INCOMING_REG_PARM_STACK_SPACE 
(FNDECL))) \
   : 0) + (STACK_POINTER_OFFSET))
 #else
 #define STACK_DYNAMIC_OFFSET(FNDECL)   \
@@ -2224,8 +2228,9 @@ assign_parms_initialize_all (struct assign_parm_da
 #endif
   all->args_so_far = pack_cumulative_args (&all->args_so_far_v);
 
-#ifdef REG_PARM_STACK_SPACE
-  all->reg_parm_stack_space = REG_PARM_STACK_SPACE (current_function_decl);
+#ifdef INCOMING_REG_PARM_STACK_SPACE
+  all->reg_parm_stack_space
+    = INCOMING_REG_PARM_STACK_SPACE (current_function_decl);
 #endif
 }
 
Index: gcc/config/rs6000/rs6000-protos.h
===================================================================
--- gcc/config/rs6000/rs6000-protos.h   (revision 210919)
+++ gcc/config/rs6000/rs6000-protos.h   (working copy)
@@ -163,7 +163,7 @@ extern tree altivec_resolve_overloaded_builtin (lo
 extern rtx rs6000_libcall_value (enum machine_mode);
 extern rtx rs6000_va_arg (tree, tree);
 extern int function_ok_for_sibcall (tree);
-extern int rs6000_reg_parm_stack_space (tree);
+extern int rs6000_reg_parm_stack_space (tree, bool);
 extern void rs6000_elf_declare_function_name (FILE *, const char *, tree);
 extern bool rs6000_elf_in_small_data_p (const_tree);
 #ifdef ARGS_SIZE_RTX
Index: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c  (revision 210919)
+++ gcc/config/rs6000/rs6000.c  (working copy)
@@ -10485,36 +10485,66 @@ rs6000_parm_needs_stack (cumulative_args_t args_so
    list, or passes any parameter in memory.  */
 
 static bool
-rs6000_function_parms_need_stack (tree fun)
+rs6000_function_parms_need_stack (tree fun, bool incoming)
 {
-  function_args_iterator args_iter;
-  tree arg_type;
+  tree fntype, result;
   CUMULATIVE_ARGS args_so_far_v;
   cumulative_args_t args_so_far;
 
   if (!fun)
     /* Must be a libcall, all of which only use reg parms.  */
     return false;
+
+  fntype = fun;
   if (!TYPE_P (fun))
-    fun = TREE_TYPE (fun);
+    fntype = TREE_TYPE (fun);
 
   /* Varargs functions need the parameter save area.  */
-  if (!prototype_p (fun) || stdarg_p (fun))
+  if ((!incoming && !prototype_p (fntype)) || stdarg_p (fntype))
     return true;
 
-  INIT_CUMULATIVE_INCOMING_ARGS (args_so_far_v, fun, NULL_RTX);
+  INIT_CUMULATIVE_INCOMING_ARGS (args_so_far_v, fntype, NULL_RTX);
   args_so_far = pack_cumulative_args (&args_so_far_v);
 
-  if (aggregate_value_p (TREE_TYPE (fun), fun))
+  /* When incoming, we will have been passed the function decl.
+     It is necessary to use the decl to handle K&R style functions,
+     where TYPE_ARG_TYPES may not be available.  */
+  if (incoming)
     {
-      tree type = build_pointer_type (TREE_TYPE (fun));
-      rs6000_parm_needs_stack (args_so_far, type);
+      gcc_assert (DECL_P (fun));
+      result = DECL_RESULT (fun);
     }
+  else
+    result = TREE_TYPE (fntype);
 
-  FOREACH_FUNCTION_ARGS (fun, arg_type, args_iter)
-    if (rs6000_parm_needs_stack (args_so_far, arg_type))
-      return true;
+  if (result && aggregate_value_p (result, fntype))
+    {
+      if (!TYPE_P (result))
+       result = TREE_TYPE (result);
+      result = build_pointer_type (result);
+      rs6000_parm_needs_stack (args_so_far, result);
+    }
 
+  if (incoming)
+    {
+      tree parm;
+
+      for (parm = DECL_ARGUMENTS (fun);
+          parm && parm != void_list_node;
+          parm = TREE_CHAIN (parm))
+       if (rs6000_parm_needs_stack (args_so_far, TREE_TYPE (parm)))
+         return true;
+    }
+  else
+    {
+      function_args_iterator args_iter;
+      tree arg_type;
+
+      FOREACH_FUNCTION_ARGS (fntype, arg_type, args_iter)
+       if (rs6000_parm_needs_stack (args_so_far, arg_type))
+         return true;
+    }
+
   return false;
 }
 
@@ -10525,7 +10555,7 @@ static bool
    all parameters in registers.  */
 
 int
-rs6000_reg_parm_stack_space (tree fun)
+rs6000_reg_parm_stack_space (tree fun, bool incoming)
 {
   int reg_parm_stack_space;
 
@@ -10543,7 +10573,7 @@ int
     case ABI_ELFv2:
       /* ??? Recomputing this every time is a bit expensive.  Is there
         a place to cache this information?  */
-      if (rs6000_function_parms_need_stack (fun))
+      if (rs6000_function_parms_need_stack (fun, incoming))
        reg_parm_stack_space = TARGET_64BIT ? 64 : 32;
       else
        reg_parm_stack_space = 0;
Index: gcc/config/rs6000/rs6000.h
===================================================================
--- gcc/config/rs6000/rs6000.h  (revision 210919)
+++ gcc/config/rs6000/rs6000.h  (working copy)
@@ -1602,8 +1602,15 @@ extern enum reg_class rs6000_constraints[RS6000_CO
 /* Define this if stack space is still allocated for a parameter passed
    in a register.  The value is the number of bytes allocated to this
    area.  */
-#define REG_PARM_STACK_SPACE(FNDECL) rs6000_reg_parm_stack_space((FNDECL))
+#define REG_PARM_STACK_SPACE(FNDECL) \
+  rs6000_reg_parm_stack_space ((FNDECL), false)
 
+/* Define this macro if space guaranteed when compiling a function body
+   is different to space required when making a call, a situation that
+   can arise with unprototyped functions.  */
+#define INCOMING_REG_PARM_STACK_SPACE(FNDECL) \
+  rs6000_reg_parm_stack_space ((FNDECL), true)
+
 /* Define this if the above stack space is to be considered part of the
    space allocated by the caller.  */
 #define OUTGOING_REG_PARM_STACK_SPACE(FNTYPE) 1

-- 
Alan Modra
Australia Development Lab, IBM

Reply via email to