[comp.arch] varargs and register windows

kak@allegra.UUCP (04/06/87)

How do machines with register windows, e.g. RISC I/II,
handle variable length argument lists?  RISC I has
6 registers for incoming arguments (R26 - R31).  What happens
if the caller has more than 6 arguments?

Also, in C, its common practice to treat the passed arguments
as memory, i.e. pointing at them with an (int *) and then using
(++) to walk through them as an array.
How does this work if the arguments are in registers?

Do MIPS, Clipper, and the new AMD micro have the same problems?

Thanks,
Keith Kelleman
allegra!kak

sjc@mips.UUCP (04/07/87)

In article <6575@allegra.UUCP>, kak@allegra.UUCP (Keith Kelleman) writes:
> How do machines with register windows, e.g. RISC I/II,
> handle variable length argument lists?...
> Also, in C, its common practice to treat the passed arguments
> as memory, i.e. pointing at them with an (int *) and then using
> (++) to walk through them as an array.
> How does this work if the arguments are in registers?
> 
> Do MIPS, Clipper, and the new AMD micro have the same problems?

I can answer regarding MIPS: variable-length argument lists work fine if you
use the familiar "varargs.h" macro package (say "man varargs", or see the
draft ANSI C standard), but not if you step through the arguments with "++".
Our compiler tries fairly hard to warn you if it suspects your code uses the
latter method.

The issue is not really the use of registers (we store an argument into its
"home" in stackframe memory anyway if you take its address), but is more a
matter of alignment within the stackframe. In any case, "varargs.h" takes
care of everything.

The "++" method causes trouble on numerous machines, quite apart from the use
of registers; imagine, for example, what happens if the machine merely grows
the stack in the "wrong" direction.
-- 
...decwrl!mips!sjc						Steve Correll

csg@pyramid.UUCP (04/09/87)

In article <6575@allegra.UUCP> kak@allegra.UUCP (Keith Kelleman) writes:
>How do machines with register windows, e.g. RISC I/II,
>handle variable length argument lists?

There are actually two problems: what to do when you run out of registers, and
what to do with objects that don't fit in registers (like structs). Pyramid
puts the first 13 scalars into the register stack; structs and parameters past
the 13th go onto the data stack. The <varargs.h> macros only permit sequential
scanning of the argument list, and are always passed the type of the argument
when an argument is extracted; hence it is easy for <varargs.h> to both count
the number of arguments and to determine whether a given argument is located
on the stack or in a register.

>...its common practice to treat the passed arguments as memory, i.e. pointing
>at them with an (int *) and then using (++) to walk through them as an array.
>How does this work if the arguments are in registers?

It doesn't. Nor does work on machines that grow the stack from the bottom up,
or that push the arguments the "wrong" way (including many 8086 compilers).
Actually, you may be able to get away with it on machines that have memory-
addressable registers, if all the arguments are scalars or pointers. (I have
to do this on the Pyramid all the time. Meanwhile, we keep getting flames from
customers about "varargs being broken." No, <varargs.h> works fine. User code
that assumes how the machine passes parameters is what's broken. *SIGH*)

<csg>

howard@cpocd2.UUCP (04/09/87)

In article <6575@allegra.UUCP> kak@allegra.UUCP (Keith Kelleman) writes:
>How do machines with register windows, e.g. RISC I/II,
>handle variable length argument lists?  RISC I has
>6 registers for incoming arguments (R26 - R31).  What happens
>if the caller has more than 6 arguments?

You put them on a stack in main memory, just like with any other machine,
and they're about the speed you would expect.  But this happens rarely,
so your average speed is close to pure register.

>Also, in C, its common practice to treat the passed arguments
>as memory, i.e. pointing at them with an (int *) and then using
>(++) to walk through them as an array.
>How does this work if the arguments are in registers?

All in all, the practice you refer to is unwise and very machine-dependent.
How do you know the arguments are stored in *ascending* order?  But it is
possible to make a register-window machine behave exactly the same as a
non-register-window machine for this case.  Here are some ways:
(1) Don't let it happen.  The compiler can check whether an address of an
    argument has been taken, and disallow putting any of them in registers.
    Note that you can still put any argument marked "register" into a register,
    because it is illegal to take the address of a register variable.
    For separate compilation, the caller might not know that the callee is
    doing this, so it might be up to the callee to take the register
    args and copy them out to memory (yuck).
(2) Make the registers part of the memory address space, so that references
    to certain addresses (those currently on-chip) are intercepted and
    converted to register references.  Then you can use pointers to write into
    the callee's window (making sure it's free first!).  A little unwieldy,
    but probably faster than keeping the arguments off-chip (assuming you can
    afford the hardware overhead).  This is only slightly more difficult than
    catching references in instruction n to a register that was written to by
    instruction n-1 (and whose value in fact, due to your pipeline, hasn't
    reached the destination register yet but is sitting somewhere else on the
    chip) and forwarding the correct value as an operand.
-- 
Copyright (c) 1987 by Howard A. Landman.  You may copy this material for any
non-commercial purpose as long as this notice is retained.  You may also
transmit this material to others and charge for such transmission, as long
as you place no additional restrictions on retransmission of the material
by the recipients.