PR61300 shows a need to differentiate between incoming and outgoing REG_PARM_STACK_SPACE for the PowerPC64 ELFv2 ABI, due to code like function.c:assign_parm_is_stack_parm determining that a stack home is available for incoming args if REG_PARM_STACK_SPACE is non-zero.
Background: The ELFv2 ABI requires a parameter save area only when stack is actually used to pass parameters, and since varargs are passed on the stack, unprototyped calls must pass both on the stack and in registers. OK, easy you say, !prototype_p(fun) means a parameter save area is needed. However, a prototype might not be in scope when compiling an old K&R style C function body, but this does *not* mean a parameter save area has necesasrily been allocated. A caller may well have a prototype in scope at the point of the call. So I wrote a patch to define INCOMING_REG_PARM_STACK_SPACE and use this in function.c, as attached. It's just a quick and dirty patch, I know I'll need to document it in tm.texi and it would be better to use INCOMING_REG_PARM_STACK_SPACE throughout function.c. Also I'm happy to rename OUTGOING_REG_PARM_STACK_SPACE to CALLER_ALLOCATES_REG_PARM_STACK everywhere if that seems like a good idea to those with power to approve such a patch. The question I have is whether there's a better way to do this? Years ago it was possible for a backend to determine whether a function body was being compiled by looking at TYPE_ACTUAL_ARG_TYPES(fun), but that's now a C only flag, and it seems like it wouldn't be a good idea to try to use the flag.. Index: gcc/config/rs6000/rs6000.c =================================================================== --- gcc/config/rs6000/rs6000.c (revision 210919) +++ gcc/config/rs6000/rs6000.c (working copy) @@ -10485,7 +10485,7 @@ 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; @@ -10499,7 +10499,7 @@ static bool fun = TREE_TYPE (fun); /* Varargs functions need the parameter save area. */ - if (!prototype_p (fun) || stdarg_p (fun)) + if ((!incoming && !prototype_p (fun)) || stdarg_p (fun)) return true; INIT_CUMULATIVE_INCOMING_ARGS (args_so_far_v, fun, NULL_RTX); @@ -10525,7 +10525,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 +10543,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,7 +1602,10 @@ 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 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. */ 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/function.c =================================================================== --- gcc/function.c (revision 210919) +++ gcc/function.c (working copy) @@ -1348,6 +1348,11 @@ static int cfa_offset; #define STACK_POINTER_OFFSET 0 #endif +#ifdef INCOMING_REG_PARM_STACK_SPACE +#undef REG_PARM_STACK_SPACE +#define REG_PARM_STACK_SPACE INCOMING_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. */ -- Alan Modra Australia Development Lab, IBM