[clang] [C] Disable use of NRVO (PR #101038)

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Mon Jul 29 14:03:49 PDT 2024


zygoloid wrote:

> Typically, the absence of a statement must be interpreted as a lack of a guarantee. In this case, however, I would argue it is more plausible to infer that the ABI authors did not consider the possibility of passing a pointer to aliased memory for the return value, and therefore we should interpret their silence as an implicit statement that compilers are not permitted to do that.

That seems like a reasonable argument. However, in my testing, a lot of C compilers (including GCC, Clang, ICC) pass a pointer to aliased memory for cases like `struct X x = f(&x);` in practice, and Clang seems to be the only one to do NRVO. A non-aliasing return slot plus NRVO seems to be ABI-conforming (at least for the ABIs that specify a non-aliasing return slot) and probably the best choice for performance, but it also seems to be the choice that is maximally incompatible with everyone else in practice :)

Should we try to convince at least the GCC folks that they're getting this wrong too?

> (1) also requires disabling copy elision in some cases:
> 
> ```c
> struct S { int x, y; char make_it_huge[1024]; };
> struct S foo(struct S *alias) {
>   return (struct S) { .x = 5, .y = (alias->x = 7, 0) };
> }
> void test() {
>   struct S var = foo(&var); // var.x must contain 5
> }
> ```
> 
> I put "when aliasing is possible" in (1), but I can't see any reasonable way to make this decision locally in the callee because essentially any pointer could alias the return value. (1) really has to be done unconditionally.

For what it's worth, (1) appears to be what GCC and ICC do, unconditionally. (And MSVC appears to make an unconditional copy in both the caller and the callee.)

https://github.com/llvm/llvm-project/pull/101038


More information about the cfe-commits mailing list