On Fri, May 30, 2014 at 11:27:52AM -0600, Jeff Law wrote:
> On 05/26/14 01:38, Alan Modra wrote:
> >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.
> Ugh.  This reminds me a lot of the braindamage we had to deal with
> in the original PA abi's handling of FP values.
> 
> In the general case, how can any function ever be sure as to whether
> or not its prototype was in scope at a call site?  Yea, we can know
> for things with restricted scope, but if it's externally visible, I
> don't see how we're going to know the calling context with absolute
> certainty.
> 
> What am I missing here?

When compiling the function body you don't need to know whether a
prototype was in scope at the call site.  You just need to know the
rules.  :)  For functions with variable argument lists, you'll always
have a parameter save area.  For other functions, whether or not you
have a parameter save area just depends on the number of arguments and
their types (ie. whether you run out of registers for parameter
passing), and you have that whether or not the function is
prototyped.

A simple example might help clear up any confusion.

Given
 void fun1(int a, int b, double c);
 void fun2(int a, ...);
  ...
 fun1 (1, 2, 3.0);
 fun2 (1, 2, 3.0);

A call to fun1 with a prototype in scope won't allocate a parameter
save area, and will pass the first arg in r3, the second in r4, and
the third in f1.

A call to fun2 with a prototype in scope will allocate a parameter
save area of 64 bytes (the minimum size of a parameter save area), and
will pass the first arg in r3, the second in the second slot of the
parameter save area, and the third in the third slot of the parameter
save area.  Now the first eight slots/double-words of the parameter
save area are passed in r3 thru r10, so this means the second arg is
actually passed in r4 and the third in r5, not the stack!

A call to fun1 or fun2 without a prototype in scope will allocate a
parameter save area, and pass the first arg in r3, the second in r4,
and the third in both f1 and r5.

When compiling fun1 body, the first arg is known to be in r3, the
second in r4, and the third in f1, and we don't use the parameter save
area for storing incoming args to a stack slot.  (At least, after
PR61300 is fixed..)  It doesn't matter if the parameter save area was
allocated or not, we just don't use it.

When compiling fun2 body, the first arg is known to be in r3, the
second in r4 and the third in r5.  Since the function has a variable
argument list, registers r4 thru r10 are saved to the parameter
save area stack, and we set up our va_list pointer to the second
double-word of the parameter save area stack.  Of course, code
optimisation might lead to removing the saves and using the args
in their incoming regs, but this is conceptually what happens.

-- 
Alan Modra
Australia Development Lab, IBM

Reply via email to