<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">