Description
Consider a function on RV32 that returns this struct by value:
struct FooStruct {
int a;
int b;
int c[];
};
FooStruct foo() {
FooStruct ret;
ret.a = 0;
ret.b = 0;
ret.c[0] = 0x124512;
ret.c[1] = 0x535;
return ret;
}
Because of guaranteed return copy elision in C++17, the caller of foo
should be allocating space for the return value, and providing a hidden "out" parameter for foo
to write through.
This is complicated in this case because this struct hits the case in the RV ABI where two XLEN-size members are passed in registers rather than on the stack.
What I would expect to happen is that either the flexible array member would force the entire structure to be returned on the stack, or that a
and b
are returned in registers, and an out-pointer is taken as an argument and used to write to c
.
What actually seems to happen is that the writes to c
are entirely elided: https://godbolt.org/z/P7b1TzjTq
foo():
li a0, 0
li a1, 0
ret
If the types of the a
and b
fields are changed to long long
(thereby avoiding the two-XLEN-sized-fields ABI case), then the writes to c
are suddenly preserved!
foo():
sw zero, 0(a0)
sw zero, 4(a0)
sw zero, 8(a0)
sw zero, 12(a0)
lui a1, 292
li a2, 1333
addi a1, a1, 1298
sw a1, 16(a0)
sw a2, 20(a0)
ret