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.
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.
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
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.
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)