5 ms·
A compiler related question: A often recurring C idiom is passing a pointer to a struct as function argument where passing the plain struct by copy would do. A
by yvdriess 7y ago
A compiler related question:
A often recurring C idiom is passing a pointer to a struct as function argument where passing the plain struct by copy would do. A big reason is the good old 'passing by pointer is faster', which I thought to be no longer relevant with modern optimizing compilers. Of course I found out the hard way that even on modern compilers object copies are not elided on call. I had performance sensitive parts of my (non-x86) code that were dominated by the compiler's builtin memcpy, due to my struct-happy coding style (e.g. rolling my own range struct and passing it by value everywhere).
I understand mostly why eliding argument copy is so much harder than eliding a return object copy, there are so many ways to observe its effect, and you have to obey the calling convention. Another aspect is the lack of programmer-communicated immutability in C, which you have addressed with D.
Does the D compiler help in this situation? Can it guarantee that (immutable) argument copies will be elided in certain circumstances? (e.g. in file-scope static functions)
- WalterBright 7y ago> Can it guarantee that (immutable) argument copies will be elided in certain circumstances? No, but it's an interesting idea I never thought of. By the way, passing by 'ref' works handily and avoids icky pointer passing, while being efficient. I recommend as a "best practices" coding style using 'ref' parameters instead of pointers where possible.
- SAI_Peregrinus 7y ago> A big reason is the good old 'passing by pointer is faster' Not even with old compilers, necessarily, this is more about the CPU architecture. If you've got an architecture with no cache (eg 386 and below for Intel) you'll not care about cache miss vs cache hit, but once you have cache you'll often find that the pointer dereference will hit main memory, and thus be slower than just passing by value. Not always, of course, but sometimes, so since 1989 (for Intel) you've needed to profile that to be sure.
- dfawcus 7y agoThe proposed NUBI ABI[1] for MIPS was interesting here in that for call by value if a struct was register sized, it would be passed in a register, but if larger it would be implicitly passed by reference. See section 3.4, Arguments. It was then up to the callee to make a copy if necessary, say if it modified the struct contents. Hence it would have been possible to elide the copies, on a per function basis, depending upon how the function used the structure. [1] ftp://ftp.linux-mips.org//pub/linux/mips/doc/NUBI/MD00438-2C-NUBIDESC-SPC-00.20.pdf
- yvdriess 7y agoThanks for the interesting pointer. I was also thinking in the direction of the compiler transforming the call-by-value struct object argument into a call-by-ref one at specific call sites. e.g. when the object is clearly on the caller's stack, is not mutated by the function and the function is not taking its address. As Walter pointed out, you can use refs in BetterC (and of course C++) directly, but I don't see why it cannot be automatically applied to C in general.
- saagarjha 7y agoAnother complication to the normal "pass structs by pointer" is that small structs are actually split up and passed in registers depending on the platform ABI, which can be more efficient in certain cases.