<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/151288>151288</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            Missing optimizations involving byval arguments passing on x86_64
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            new issue
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          akhvoshch
      </td>
    </tr>
</table>

<pre>
    In System V x86_64 ABI large arguments are passed in stack. In IR code `byval` attribute is used for them.
Calling a function with `byval` argument requires making intermediate copy of argument bytes. But it seems like this copying is implemented in a target-specific way, somewhere in code generation. This results in poor generated code quality, since no IR optimizations can be done for `byval` arguments, including unnecessary loads/stores elimination.

Consider this example:
```cpp
#include <cstdint>

struct S
{
    int64_t arr[12];

 S()
    {
        for( int64_t i= 0; i < 12; ++i )
                        arr[i]= i * i * 3 + i * 7 + 13;
    }
};

void Bar(S s);

void Foo()
{
 Bar(S());
}
```

clang 20.1 produces following assembly:

```asm
Foo():
        sub     rsp, 200
        mov     qword ptr [rsp + 104], 13
        mov     qword ptr [rsp + 112], 23
        mov qword ptr [rsp + 120], 39
        mov     qword ptr [rsp + 128], 61
 mov     qword ptr [rsp + 136], 89
        mov     qword ptr [rsp + 144], 123
        mov     qword ptr [rsp + 152], 163
        mov     qword ptr [rsp + 160], 209
        mov     qword ptr [rsp + 168], 261
        mov qword ptr [rsp + 176], 319
        mov     qword ptr [rsp + 184], 383
 mov     qword ptr [rsp + 192], 453
        movups  xmm0, xmmword ptr [rsp + 184]
        movups  xmmword ptr [rsp + 80], xmm0
        movups  xmm0, xmmword ptr [rsp + 168]
        movups  xmmword ptr [rsp + 64], xmm0
 movups  xmm0, xmmword ptr [rsp + 104]
        movups  xmm1, xmmword ptr [rsp + 120]
        movups  xmm2, xmmword ptr [rsp + 136]
        movups xmm3, xmmword ptr [rsp + 152]
        movups  xmmword ptr [rsp + 48], xmm3
 movups  xmmword ptr [rsp + 32], xmm2
        movups  xmmword ptr [rsp + 16], xmm1
        movups  xmmword ptr [rsp], xmm0
        call Bar(S)@PLT
        add     rsp, 200
 ret
```

https://godbolt.org/z/rzEzn18v9

It can be seen, that memory for a local variable is initialized first (first 12 `mov` instructions), then this memory is read and pushed to a new stack location in order to pass this variable to function `Bar`. Targeting a newer CPU (with `-march=skylake` option) only results in newer memory move instructions usage, but overall pattern remains the same.

I expect that LLVM can optimize such cases and move necessary values directly to the stack region of the argument. A lot of existing C++ code may benefit from such optimization, since it's nowadays pretty common to pass arguments by value (sine move-semantics was introduced).
</pre>
<img width="1" height="1" alt="" src="http://email.email.llvm.org/o/eJyUV99v6rgS_mvMy6gocUiABx6gXaRKZ6XVPefu68pxBvCtf-R4HCj9669sh9L2dLtshZoQzzffzGfH_hBEam8RV6zesPphIoZwcH4lng5HRwd5mLSuO68eLXw_U0ADf8LzovmrmcF68wha-D2C8PvBoA0EwiP0ggg7UBYoCPk0hUcLj_8B6ToE1hTt-Sg0awoQIXjVDgFBEQwRsnMewgHNlBXre6G1snsQsBusDMpZOKlweJ9h5AWPPwflkcCIpwhSNqA32CkREKTrz-B21-j2HJCmsBkCqACEaAi0ekIIB0UpPOUgUKbXGCG5HQEhthvuqEepdkrCSZwZvwdyBk8H9BijUp97tOhFrHoKP2JWjzToQDGgd85fArDL8T8HoVXIyZSVCNZFzVwflFEvKRGBFBZahM5ZTFJ9JgXFFMpKPXSxicFalEgk_Bm0Ex0xvqXgolSolVE218iKdZTcWVId-qwDPovYPqviEGuK_JF9H7_yKnMgsOpeUuiUDaz6Leeh4AcZ4Hv8Nt-wYg0AcUqa2V8BhPes3pSc1Q-s2mQAfGd8wfhyDL2C4t_OecYXr3jFqgcoWLUBFbmh5PGe8Q3jGwU5CSuW-ZPJVOJ6iAC-Hv9XETLez9N9WeV6cgUPqfhriUenOtiIWMp3oEjzbmTr3GsLY_lj8Pj4FZAzX-TMKaQWdg-8mJbQe9cNEgl2Tmt3Sm8AEZpWn8eZeIMWZFixvnKngItuNLTp6qmPa4IXxZtB447p-vPkfAd98MDqjac-K1HMomL8PmpyKybPaCT6iPk8nhdjfLW8mYMvRkxTRszXwVUzBi9uJ5i9Nv5LF38Pqi-dl83toObSPi9uL6-59M-zAP8o8vyiQVXezrK4iFAtqn-WeXnpflZ_6H7oCeDZmCKOPhvzBdmnuM_iFxfZUt5_T5cVvJmumX2gu5Wn-Pu2yq9w-a34FMe_wuXF_gvu2ZjqK1heujfLMVtc5ag-yPFZfMWv8fx2mrK5wsqbYJ8vCim0vm7DSzYr_vj248246Lp0fb9Degy_7tCHEHqK-yvfMr7du651Okyd3zO-fWF8619-e7Hl4phPn_VjuBzWhGhj8nAQAQwa58_p7BagnRQajsIr0erkgZRVQQmtXqIVUp4CML7INyWPp71xx3jWK5tP2GgK0tkS06PNx_bIkSyH6EDYDvqBDthBcCDA4inbssSfbJWy4Hw69l3ybjnPa2HBXR0Ya4qoZ1NM4UeyQtmhWTyhh_s__hsLvri0OyO8PLDqgZ7OWjxhrDz6GWcZX4Kz-vzWFOUUY_HGHfFdlzCQ2GNstB0CuCP6OLW9CAG9BY9GKBvrRiBhcLQzj4DPPcqQtf_27c_f06SMngqBBnkAKQgpqZRIr27pKPSABJ3yKIM-RxlS_qSdx32Uw-3Ss4v3msIatAvxMT4rSuLcZ2eSXZ4RZ2jR4k4F2HlncglvTd7VAKrA-JzAupPoxJmg9xjCGaQzxtnXqbo673YsOU4BKYupnztCI2xQkuAkos4h24uO8eV00q2qblktxQRX5byuFvVyyfnksKp5Uc2XbdOVhdx1hdzNq3lbtV1ZdCWKWTVRK17wuphXRTEvFzM-rbuyLupa1qJainkp2ayIc6KnWh9NfE0mimjAVVmXfLGYaNGipvSDg_O4ItMo43G7mPhVBN21w57YrNCKAl3TBBU0rn5XRFHc9_ZY2aPTx_g8ueI32kSpUrwdf7tMBq9XH95pFQ5DO5XOML6NfOPlrvfufygD49tUZXTQYxvHFf9_AAAA__-cYwXu">