<table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Issue</th>
<td>
<a href=https://github.com/llvm/llvm-project/issues/225060>225060</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>
[Windows][AArch64] Returning structures from member functions has wrong ABI
</td>
</tr>
<tr>
<th>Labels</th>
<td>
new issue
</td>
</tr>
<tr>
<th>Assignees</th>
<td>
</td>
</tr>
<tr>
<th>Reporter</th>
<td>
hmelder
</td>
</tr>
</table>
<pre>
When compiling the following C++ code for aarch64-pc-windows-msvc with clang-cl, `struct Big Holder::make(void) const` does not return the sret pointer in x0. This results in a crash when invoked by code in a translation unit compiled with MSVC.
Here is the reproducer:
```c++
#include <cstdint>
#include <cstdio>
struct Big { uintptr_t a, b, c; }; // trivially copyable aggregate, > 16 bytes
struct Holder {
uintptr_t seed;
Big make() const; // non-static member fn
};
Big make_free(uintptr_t seed); // free function, for contrast
Big Holder::make() const { Big r; r.a = seed + 1; r.b = seed + 2; r.c = seed + 3; return r; }
Big make_free(uintptr_t seed) { Big r; r.a = seed + 1; r.b = seed + 2; r.c = seed + 3; return r; }
static bool check(const char* what, const Big& got, uintptr_t seed) {
const bool ok = got.a == seed + 1 && got.b == seed + 2 && got.c == seed + 3;
return ok;
}
int main() {
const uintptr_t seed = 0x1000;
int failures = 0;
Holder h; h.seed = seed;
check("Holder::make()", h.make(), seed);
check("make_free()", make_free(seed), seed);
return 0;
}
```
## Expected Result
I compiled the code above with MSVC v19.51, see https://godbolt.org/z/oYfY63q5E or the listing below.
`Big Holder::make(void)const` copies x1 into x0 just before returning.
<details>
<summary>Assembly listing</summary>
```asm
|Big Holder::make(void)const | PROC ; Holder::make
|$LN3|
stp fp,lr,[sp,#-0x10]!
mov fp,sp
bl __security_push_cookie
sub sp,sp,#0x30
str x0,[sp]
str x1,[sp,#8]
ldr x8,[sp]
ldr x8,[x8]
add x8,x8,#1
str x8,[sp,#0x10]
ldr x8,[sp]
ldr x8,[x8]
add x8,x8,#2
str x8,[sp,#0x18]
ldr x8,[sp]
ldr x8,[x8]
add x8,x8,#3
str x8,[sp,#0x20]
ldr x9,[sp,#8]
ldr q16,[sp,#0x10]
str q16,[x9]
ldr x8,[sp,#0x20]
str x8,[x9,#0x10]
ldr x0,[sp,#8]
add sp,sp,#0x30
bl __security_pop_cookie
ldp fp,lr,[sp],#0x10
ret
```
</details>
On `aarch64-pc-windows-msvc`, a non-static member function returning a class indirectly must
return the hidden result pointer in `x0`. This is according to the ABI convention:
> The caller shall reserve a block of memory of sufficient size and alignment to hold the
> result. The address of the memory block shall be passed as an additional argument to the
> function in x0, or x1 if $this is passed in x0. […] **The callee returns the address of the
> memory block in x0.**
>
> — [Overview of ARM64 ABI conventions, *Return values*](https://learn.microsoft.com/en-us/cpp/build/arm64-windows-abi-conventions?view=msvc-170)
For non-member functions such as `Big make_free(unsigned __int64)`, the callee returns the address of the memory block in x8 instead.
## Actual Result with clang-cl
With clang-cl 22.1.6, does not copy x1 into x0 before returning to the caller, see https://godbolt.org/z/5xWcrMfvM or the listing below.
<details>
<summary>Assembly Listing</summary>
```asm
struct Big Holder::make(void) const: // @"?make@Holder@@QEBA?AUBig@@XZ"
sub sp, sp, #16
mov x8, x1
str x8, [sp, #8]
str x0, [sp]
ldr x8, [sp]
ldr x9, [x8]
add x9, x9, #1
str x9, [x1]
ldr x9, [x8]
add x9, x9, #2
str x9, [x1, #8]
ldr x8, [x8]
add x8, x8, #3
str x8, [x1, #16]
add sp, sp, #16
ret
```
</details>
This becomes a problem when the calling code is compiled with MSVC:
In MSVC
```asm
add x1,sp,#0x60
add x0,sp,#8
bl |Big Holder::make(void)const |
mov x1,x0 // We read garbage here
mov x2,#0x1000
adrp x8,|$SG6520|
add x0,x8,|$SG6520|
bl |bool check(char const *,Big const &,unsigned __int64)|
nop
```
The issue was first discovered here: https://github.com/llvm/llvm-project/issues/47180#issuecomment-5710675591
</pre>
<img width="1" height="1" alt="" src="http://email.email.llvm.org/o/eJy8WF9z47YR_zTwy441IChR0oMeKNlqMpNr2kvaa_riAUFQRAwSCgBKcj59BwApkvpzp3TaaDy2BSx2f7tY7P4AaozY1Zyv0GyNZi9PtLGl0quy4jLn-ilT-cfqS8lrYKraCynqHdiSQ6GkVEf3bYPIGpE1MJW7YQ2UalYm0-c9ez6KOldH81yZA4OjsCUwSevdM5OIbAAl2FjdMAtrsYPvlDOI4hTFaUXfOSKLgxI5IktgqjYWJRhyxQ3UyoLmttG1R2I0t7BXorZcg6jhhCfwcykMaG4aaY0bo8A0NSUcnSOiPqh3nkP2ETD7eatpbSS1QtXQ1MK27vI8wP700z83E4RThNPvuOYgjLet-V6rvGEBN05RgsMPC0FxQyQWNZNNzgHFG2ZsLmqL4tfbU6qdwekgMmi-hkbUdm_1mwXqQpe5XwzFa0DzF_fn_EFki8gWrBYHQaV0Pu4_aCY50N1O8x213Mc-foUogezDcjMyGLbB2UQ4dQp7y4bzHMXduEPW7lO_R0Mko08Lq1b1s7HUCgYVrzKuoaidee9EwNHpfSs0d8ov7JPllZFWt5OHoqmZ20Tno0tGpmqrqbG97ht5dsbvQ-2EtDOiJxRQ_OLtgkvxKIxm41ESRtl4NPajIU11t1EPePf_h-D32m9BppQEVnL2jsgiBICVVCOSwrGk1ueYH12LHSIJ7JQfu4m5zYog7xWrdw9np2xwYuwHIJK0OoM3Y4eG0-xqOu7TsPVPvbcJ1LkoagsVFXW7vZcIxz54oPgUYYx7zU5DQYVsNDdBoJ9rT0npolpOzirGJ6SLLCLkdtIhQlw8y8lwaDPI82tFw9zpNQxHu9W3FLXBwqNYdTUrxA2RGJEYXk97zizP4bOvomHu-74quurnqyfN1IH3RRIO0XIyi1rrUFq7N85tf0R3Ks-UtBOld4hsf0dkq34pfkni32avoLTXKYWxrqtkXKrjJMD7enc4Nwem9oIbOEVu5xScMPzauFzkhdK8dV3Uu7aMo3iTc0uFNG3JjTemqSqqP1D8mhrDq0x-dHBQvEFk28-3KrrIUVP5cG4eQApovoG_ff5xMyxg8fp6mVeIyPSHv8bun7CB7mPs_ryy2COykRqRDZqtjfuCSPzsMhnNXhCJBssqdRgvM_vBbCZ7OG9vhrNGC_vxtm9M-caUehd8iKDJzsKmVeUt41OMR0j1We6EzyBnL_dkorEji7GozAeii9vqbsmcLvTQPB_LBEESR_dwLca4uvj-idDI49D-7KjFD0MjX4va8uG9_y1KvrUfQxxn8dPyocjcAXvLtQD6mwmBv-raMLBfO033jqjaX59Qmd-vEa4wnEH3SzS3l93AV71xlcTpj7Uj7ndIvltINkBvEb2WmfWV2NFySY1j6LnQnFn5AVXjudqA35ciz3ndsvkh0UcJPjmkLd0XBihjSuf-iqL82nTtWlZ94LXnhIGjO8de4WfXwKiUXIMpqZTOANcHDhQyqdg7qMIhV_rD_WeaohBM8NqCEb9zoHUOVIpdXbkhq6BU0jfFVntAO_FWaJ5rboxT4zC1SoORYDrjsKfG8ByoAVq7FcIBphKo3jWdjV79OZb-vuMirrRvfAUgMrVtOFqd7Z3I3e9eCVpglCZo9gKIpIik5zB0HTJcbMaYW6sj5EFrUBLmW6nWyHLqLP544Pog-NEpSj9_SqYXW2L8XYSkn8N-H6hsuHEaXZIuxuxBcqrrSSWYVkYVdsJUhciW18-NQWTL9ntEtlkjZI7IluoqmZ4zk2bieWgz3jpMKH5xKfsczbEjST4ztkr71L3IWQOmYaXbnZaOjCh87W_QOby9idomU6csHAP7SHCvw7oAURvLaT4ZUbKU2YbKlpBd3Ka93JfhEBAyiSau8vW3ZncVHPKjS2rUHZtwLh7lcLPTF6Y_FYdP9znco3Trhz9At_7I00F8rnLdZRFNsePO8dbLT3GrYorRFP_9dZ2ieJv-w117_Mi__u2ErwmQr9Ttb8cfkht8y_cKR22uW0mY6joDXLeGsyDuBW-2maGm2wLLVuBeWw8CrdhtKtTriP43Rm6RmqGRmzG5cvmusRD4RavmFk3pdUT9Ft5U9rWdfrRz-jaVcaYqboDCXqtM8io8SnXHzp2b8CplbjxBnTvY93X4fnUqLnFDR6t7UpHge3J4ILe4wzwev-XcuXt4NCfcHcQvrv7QHHZUZ3THoeSa31tJeuKCx07oM90J1MzfnH76SzIjeIzkyt9vyF-4Pn4xKanu3o1cH_SB6b67ynurM4y012p_fQN3LVkY03A4UgOF0MZCLgxTB655HgIUp5dlWdiyydqeKOWh-_O81-pXziwiW6_TtcrpPFpgRGI_wFTl-MXzbB7hZD6bLd3Jf8pXcb6Ml_SJr6L5YrlcLJLF_KlcxRmN4jjK8JwWPMExK7Iop0seFYwuFtHySawIJglekiiK8HQ6nxSMsdliWfDpghZ4OUdTzCsq5MShc13kycNYETLDCX6SNOPS-MdoQmp-DJFw1Xf28qRX3qWs2Rk0xa7NmF6NFVb6V-wvoeu7czxbp6nnqY7wfD63udA6_LtOoVV1yVANlNTAUat65-jKU6Pl6r-PduvYYUX-EwAA__92zJbs">