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