On 05/31/14 00:30, Alan Modra wrote:
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.
I think the confusion was all mine. I think Ulrich's comments in the BZ
and the paragraph above really help clarify things. This is entirely an
issue on the callee side.
On the callee side, we want to be looking strictly at the number/types
of the arguments. The prototype/lack thereof isn't relevant.
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!
Right, so for a call to fun2 the caller allocates, but the callee
flushes the parameter registers into the allocated space. Right? And
the allocated space would be contiguous with the space used to pass
arguments once you've exhausted the argument registers? FP values get
passed in integer and FP regs to varargs or unprototyped functions.
[ Why, oh why couldn't we have done all this ~10 years ago when all the
aspects of the PA ABIs were will fresh in my head. There's a lot of
similarities, but remembering how it all worked is proving difficult. ]
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.
Right. It's reasonably similar to how certain aspects of the PA ABIs
worked, at least from the callee's viewpoint.
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.
Right. That's also consistent with the old PA32 ABI.
And so the problem you're trying to solve is that when compiling the
callee. You incorrectly assumed that if there was not a prototype for
the callee's definition that the caller had set up the save area and
that you could flush arguments to it. That's not true in the case where
the caller had a prototype for the callee in-scope (and the callee was
not a varargs function).
Right? Just want to make sure I understand the problem.
Jeff