raeburn@athena.mit.edu (Ken Raeburn) (01/05/90)
(I apologize if this issue has already been raised, but I haven't been reading these newsgroups.) How does one properly implement <stdarg.h> for a PMAX? (Or any MIPS-based system, for that matter.) According to "MIPS RISC Architecture" by Kane, the first few arguments to a function are passed in registers, if their types fit certain constraints. If the first argument to a function is assumed to be some floating point type, the possibilities for the argument locations boil down to: arguments registers (f1->$f12 always) f1, f2, ... f2->$f14, remainder on stack f1, n1, ... n1->$6, remainder [elsewhere] (Arguments following N1 don't really matter, I think.) If a function is declared as: void foo (double d, ...); then where does it find the next argument? Is it in $6 or $f14? Even the simplest mechanisms I can imagine that conform to the description above involve a fair amount of compiler support, which isn't being provided so far as I can see. The best working alternative I see is that arguments which may have different types get treated as type 'N' arguments in the table above, even if they are floating-point values. This isn't what is described in Kane's book, but I don't see any other way to make it work. (This also is not what the MIPS compiler does, but a simple test file shows that the stdarg use simply fails, so....) (Before someone points it out, I am aware that the compiler on the PMAX does not claim to be ANSI compliant.) Anybody know any "official" answers? -- Ken
grunwald@foobar.colorado.edu (Dirk Grunwald) (01/06/90)
You might want to check the documentation for the Gnu C compiler; it documents a little state machine that implements the MIPS convention. Also, check stdarg.h & the version of varargs for the mips (va-mips.h). recall that the mips calling convention always allocates 4 words on the frame. In general, if you're going to pass varidic args to something like printf, the ``varargs'' package flushs the registers to memory. I think this also happens if you take the address of an argument.
raeburn@athena.mit.edu (Ken Raeburn) (01/06/90)
In article <15370@boulder.Colorado.EDU> grunwald@foobar.colorado.edu writes: >You might want to check the documentation for the Gnu C compiler; it >documents a little state machine that implements the MIPS convention. I didn't mention it in my previous posting, but in my test file (using stdarg.h and a function taking "(double, ...)"), gcc botches it even worse than the standard compiler. At least with /bin/cc I can read integer arguments following the double; with gcc I get zeros for integers as well as doubles (following the explicitly declared double argument, that is). The MIPS configuration files are fairly conservative about following the rules about passing arguments and writing back all the interesting registers to the stack for functions that are even suspected of using varargs, but they don't do much about retrieving the information. >Also, check stdarg.h & the version of varargs for the mips (va-mips.h). These macros assume that the compiler will write back the registers to the stack, or that (in the case of the GNU version, on some architectures) there's a __builtin_saveregs available that can be called to do that. That doesn't tell you where you are in the argument list. I.e., if the first argument you try to retrieve is a double, will it be on the stack or in registers? The varargs version seems to make use of the idea that you're supposed to use "va_alist" as the only thing(s) in the argument list, so you know where you're starting from, and you know when to switch from gee-which-registers-do-I-use-for-this-one to now-I-look-on-the-stack. With stdarg.h, you don't have this; the state machine doesn't help if you don't know what state to start in. And as I think I mentioned in my previous posting, I don't think stdarg.h works as provided. (In fact, a large part of my reason for posting is that I'd like to get a stdarg.h that works with gcc on the pmax.) > In general, if you're going to pass varidic args to >something like printf, the ``varargs'' package flushs the registers to >memory. Yes, but varargs is in better control in this respect. It may be less efficient than letting the programmer specify the types of leading arguments, but the same constraints make it easier to locate the arguments -- e.g., by forcing all registers that could be used as arguments to be written out to memory in a known format, with a known variable located at a known position within that block. Maybe I should point it out again: The troublesome case is a function declared: foo (double d, ...) How does it know, when you ask for a "double", that it should look at the second FP reg save slot? All that's available to the macros is the address of d; but since the macros can't tell the difference between foo's declaration above and foo2 (double d1, double d2, ...) (for which it should start with the first stack argument) how does it know when to switch from FP reg save slots to regular stack arguments? It needs to know, if they aren't contiguous in memory. I should rephrase that: How _should_ it know? My claim is that (lacking more information from the compiler) it does not. -- Ken
lai@mips.COM (David Lai) (01/07/90)
In article <1990Jan6.062805.23863@athena.mit.edu> raeburn@athena.mit.edu (Ken Raeburn) writes: > >Maybe I should point it out again: The troublesome case is a function >declared: > foo (double d, ...) > >How does it know, when you ask for a "double", that it should look at >the second FP reg save slot? All that's available to the macros is >the address of d; but since the macros can't tell the difference >between foo's declaration above and > foo2 (double d1, double d2, ...) >(for which it should start with the first stack argument) how does it >know when to switch from FP reg save slots to regular stack arguments? >It needs to know, if they aren't contiguous in memory. > >I should rephrase that: How _should_ it know? My claim is that >(lacking more information from the compiler) it does not. > >-- Ken The MIPS compiler does support full stdarg.h type calls, even if the first argument is a float (or double). The secret is that the prototype must be *visible* at the caller side (see ANSI section 4.8.1.3). The compiler knows where the beginning of the variable part of the argument list is (the position of the '...' in the prototype), and hence forces arguments to be passed in the integer registers (even arguments that are float or double). The actual function must also be *defined* with the same prototype form, including the '...'. Example: main() { extern foo(double,...); foo(2.0,3.0); /* passes 2.0 in fp reg, 3.0 in regular registers */ foo2(2.0,3.0); /* passes 2.0, 3.0 in fp regs */ } We are aware of limitations of the old style varargs.h type calls when the first argument is a float or double. -- "What is a DJ if he can't scratch?" - Uncle Jamms Army David Lai (lai@mips.com || {ames,prls,pyramid,decwrl}!mips!lai)
raeburn@athena.mit.edu (Ken Raeburn) (01/08/90)
In article <34218@mips.mips.COM> lai@mips.COM (David Lai) writes: > extern foo(double,...); > foo(2.0,3.0); /* passes 2.0 in fp reg, 3.0 in regular registers */ Ah, excellent. Thank you for the confirmation. I had thought this was the solution, but it doesn't match Kane's book (well, maybe if you interpret variadic-function arguments as coming under "anything else", regardless of type -- but that should be explicitly stated) or the behavior I saw from the PMAX (excuse me, DECstation) compiler. (I did have my definition -- with ellipsis -- before the call; that should be enough.) Could the Ultrix version be an older compiler, that didn't have this fixed? Theirs is 1.31, and puts 3.0 (from the example above) in $f14, as does the current gcc port. If it is outdated, I'll complain at them.... What's the current one supposed to be? Thanks again... -- Ken
jg@max.crl.dec.com (Jim Gettys) (01/08/90)
The MIPS based systems we (Digital) sells right now are using 1.31 compilers. As you might expect, later compilers are in field test.... - Jim
lai@mips.COM (David Lai) (01/10/90)
In article <1990Jan8.041547.18259@athena.mit.edu> raeburn@athena.mit.edu (Ken Raeburn) writes: >In article <34218@mips.mips.COM> lai@mips.COM (David Lai) writes: >> extern foo(double,...); >> foo(2.0,3.0); /* passes 2.0 in fp reg, 3.0 in regular registers */ > >Ah, excellent. Thank you for the confirmation. I had thought this >was the solution, but it doesn't match Kane's book (well, maybe if you A new update to Kanes book is in the works. There is also updates to the Languages Programmers Guide to reflect stdarg style functions. >interpret variadic-function arguments as coming under "anything else", >regardless of type -- but that should be explicitly stated) or the >behavior I saw from the PMAX (excuse me, DECstation) compiler. (I did >have my definition -- with ellipsis -- before the call; that should be >enough.) Could the Ultrix version be an older compiler, that didn't >have this fixed? Theirs is 1.31, and puts 3.0 (from the example >above) in $f14, as does the current gcc port. If it is outdated, I'll >complain at them.... What's the current one supposed to be? The latest released compiler is 2.0. 2.10 is in beta test, which has the stdarg fully working. -- "What is a DJ if he can't scratch?" - Uncle Jamms Army David Lai (lai@mips.com || {ames,prls,pyramid,decwrl}!mips!lai)