4 ms·
Amd64 and va_arg
- tptacek 16y agoWow. Gross. On x86-64, caller args hit callee functions via registers, not the stack like they do on i386. This is a performance win. But functions like printf that take variable numbers of arguments need to go through contortions, saving copies of register arguments and painstakingly calculating which args would be on the stack versus registers (and their offset into the register save area) to work the same way on x86-64 than i386.
- koenigdavidmj 16y agoI think that the MIPS does this quite well. There exist four (of 32) registers to hold the first four arguments to a function, and then any more go on the stack. However, most calling conventions require that you leave enough space in the stack frame to copy the argument registers into it (although you do not actually need to do the copy). That way, you can get the speed benefits of register-passed arguments while making it easy to do array indexing off the stack pointer if you really need to.
- paulbaumgart 16y agoSPARC (V8 at least) is the same, just with 6 instead of 4 argument registers: %i0 to %i5.
- tptacek 16y agoI think SPARC has always had register argument passing; it's practically the design thesis for the processor.
- pmjordan 16y agoIt's not that arguments are passed in registers that makes it so complicated, but the fact that there are separate register files for integer/pointer and floating-point types. Most classic RISC architectures have only one register file.
- aidenn0 16y agoshrug va_args has to be written once, and once you get it right, the performance penalty should be much smaller than a memory access. Also note that Power based architectures have been doing this for a long time.
- paulbaumgart 16y agoSeems like the right trade-off to make. Variadic functions are so rarely used in performance-critical code that a couple of extra hoops for making printf and company work is probably worth it It sounds like structs (at least the small ones?) get passed in registers also. I don't really understand that. Isn't it kinda a rule of C-programming that if you want your code to be fast, don't pass around structs? If structs just always went onto the stack, you wouldn't have to mess around figuring out whether its members are on the integer or floating point registers.
- tptacek 16y agoWhat's the performance sensitivity of variadic functions? I've never seen a varargs function hit the top of my profile. On i386, there's almost no performance difference between a va_arg and a positional arg. It's actually not a rule of performant C programming that you shouldn't pass structures by value. The contortions you end up going through to avoid it (decomposing the struct into arguments, creating temp structs to pass addresses instead of values, filling structs in from return-args) often cost more than just passing the damn thing to begin with.
- paulbaumgart 16y agoYeah, my point was it's OK to make variadic functions have a little extra logic and in some cases potentially be slower than the ix86 equivalent, because regular functions are definitely sped-up and those are much more common. On the subject of passing structs by value: it really comes down to whether you plan on copying the struct anyway or not, doesn't it?
- andrewf 16y agoI wonder if this is more for the sake of C++ than C, where primitive values are more likely to be 'boxed' into a struct/class along with some methods. For instance, with a typical non-debug standard library, vector<int>::iterator has one member - an int*. It'd be a shame if that couldn't go in a register.
- 16y ago
- CamperBob 16y agoI've never heard of variadic functions not being declared cdecl (_cdecl, __cdecl, whatever). This is also the first time I've ever heard that "C requires that code be able to call functions even if their prototype is not visible, which means the compiler doesn’t necessarily know if it’s calling a variadic function at any given call site." Can someone point to an authoritative reference for this? On Win32 (and presumably most other systems as well) it's perfectly kosher to require variadic functions to be declared cdecl. This all sounds like a giant nonissue to me. Add support for cdecl functions and move on.
- caf 16y agoThe comment about C requiring functions to be able to be called without a prototype in scope is not true, in the case of variadic functions. Calling a variadic function without a correct prototype in scope is undefined behaviour - so it's open to an ABI to specify a different calling convention for them. (The relevant part of C99 is §6.5.2.2 Function Calls, p6).