Re: C aggregate passing (Rust kernel policy)

H. Peter Anvin
2025-02-20T20:34:16Z

On February 20, 2025 7:17:07 AM PST, Jan Engelhardt <ej@inai.de> wrote:
>
>On Thursday 2025-02-20 14:23, H. Peter Anvin wrote:
>>
>>People writing C seem to have a real aversion for using structures
>>as values (arguments, return values or assignments) even though that
>>has been valid since at least C90 and can genuinely produce better
>>code in some cases.
>
>The aversion stems from compilers producing "worse" ASM to this
>date, as in this case for example:
>
>```c
>#include <sys/stat.h>
>extern struct stat fff();
>struct stat __attribute__((noinline)) fff()
>{
> struct stat sb = {};
> stat(".", &sb);
> return sb;
>}
>```
>
>Build as C++ and C and compare.
>
>$ g++-15 -std=c++23 -O2 -x c++ -c x.c && objdump -Mintel -d x.o
>$ gcc-15 -std=c23 -O2 -c x.c && objdump -Mintel -d x.o
>
>Returning aggregates in C++ is often implemented with a secret extra
>pointer argument passed to the function. The C backend does not
>perform that kind of transformation automatically. I surmise ABI reasons.

The ABI is exactly the same for C and C++ in that case (hidden pointer), so that would be a code quality bug.

But I expect that that is a classic case of "no one is using it, so no one is optimizing it, so no one is using it." ... and so it has been stuck for 35 years.

But as Linus pointed out, even the C backend does quite well if the aggregate fits in two registers; pretty much every ABI I have seen pass two-machine-word return values in registers (even the ones that pass arguments on the stack.)