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