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.