SPRAC71B February 2019 – October 2023
Structures (including classes) and unions larger than 32 bits are passed and returned by reference. See Section 2.6 for additional cases where structures and unions are passed by value when using FPU32 or FPU64.
To pass a structure or union by reference, the caller places its address in the appropriate location: either in a register or on the stack, according to its position in the argument list. To preserve pass-by-value semantics (required for C and C++), the callee may need to make its own copy of the pointed-to object. In some cases, the callee need not make a copy, such as if the callee is a leaf and it does not modify the pointed-to object.
If the called function returns a structure or union larger than 32 bits, the caller must pass an additional argument containing a destination address for the returned value, or NULL if the returned value is not used.
This additional argument is passed in the first argument register as an implicit first argument. The callee returns the object by copying it to the given address. The caller is responsible for allocating memory if required. Typically this involves reserving space on the stack, but in some cases the address of an already-existing object can be passed and no allocation is required. For example, if f returns a structure, the assignment s = f() can be compiled by passing &s in the first argument register.
Examples
C source code:
struct S { char big[100]; } g;
struct S accepts_and_returns_struct(struct S s)
{
s.big[0] = 1;
return s;
}
void caller(void)
{
struct S w;
w.big[0] = 0;
g = accepts_and_returns_struct(w);
}
"Lowered" C code: (higher-level C code converted to lower-level C code)
struct S { char big[100]; } g;
void accepts_and_returns_struct(struct S *dst, struct S *sptr)
{
struct S s;
s = *sptr;
s.big[0] = 1;
if (dst) *dst = s;
}
void caller(void)
{
struct S w;
w.big[0] = 0;
accepts_and_returns_struct(&g, &w);
}