<table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Issue</th>
<td>
<a href=https://github.com/llvm/llvm-project/issues/116092>116092</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>
LLVM is unable to fully optimize out `std::vector` allocation with libc++
</td>
</tr>
<tr>
<th>Labels</th>
<td>
libc++
</td>
</tr>
<tr>
<th>Assignees</th>
<td>
</td>
</tr>
<tr>
<th>Reporter</th>
<td>
zygoloid
</td>
</tr>
</table>
<pre>
[Testcase](https://godbolt.org/z/GGjW199nn):
```c++
#include <vector>
void f(std::vector<char> v) {
std::vector<char> v2 = v;
}
```
With `clang -stdlib=libstdc++`, we get this:
```asm
f(std::vector<char, std::allocator<char>>):
mov rax, qword ptr [rdi + 8]
cmp rax, qword ptr [rdi]
sete al
setns cl
or cl, al
je .LBB0_2
ret
.LBB0_2:
push rax
call std::__throw_bad_alloc()@PLT
```
(The branch and throw is a bit sad, but I suppose LLVM has no way to know that `v`'s existing size doesn't exceed `vector::max_size()`.)
GCC gives a similar result:
```asm
f(std::vector<char, std::allocator<char> >):
mov rax, QWORD PTR [rdi]
cmp QWORD PTR [rdi+8], rax
je .L1
js .L10
.L1:
ret
.L10:
sub rsp, 8
call std::__throw_bad_alloc()
```
But with `clang -stdlib=libc++`, we get this instead:
```asm
f(std::__1::vector<char, std::__1::allocator<char>>):
push rbx
sub rsp, 32
xorps xmm0, xmm0
movaps xmmword ptr [rsp], xmm0
mov qword ptr [rsp + 16], 0
mov rax, qword ptr [rdi + 8]
cmp rax, qword ptr [rdi]
sete al
setns cl
or cl, al
je .LBB0_1
add rsp, 32
pop rbx
ret
.LBB0_1:
mov rdi, rsp
call std::__1::vector<char, std::__1::allocator<char>>::__throw_length_error[abi:ne200000]() const
mov rbx, rax
mov rdi, qword ptr [rsp]
test rdi, rdi
je .LBB0_5
mov qword ptr [rsp + 8], rdi
mov rsi, qword ptr [rsp + 16]
sub rsi, rdi
call operator delete(void*, unsigned long)@PLT
.LBB0_5:
mov rdi, rbx
call _Unwind_Resume@PLT
.L.str:
.asciz "vector"
DW.ref.__gxx_personality_v0:
.quad __gxx_personality_v0
```
The extra code here is attempting to deallocate the data pointer within `v2` along the exception path. But that code is all unreachable -- we first branch on whether the pointer is null, which it is, because the only store to it is the `memset`-to-zero at the start of the function. But LLVM doesn't seem to notice that.
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJy0V01v47wR_jX0ZRBDomzHPvgQ282iQIq-XaTNUaDEscWUIrXkyHby6wvS8pecZLftu4EQweTMcD4ePjMS3quNQZyz8YKNVwPRUmXd_P1tY7VVclBY-Rb2ntFTKTyy8YrxaUXUeJY9MP7I-OPGysJqGlq3YfzxnfHHb99eX9LZzBjGZ0EsWbHkgU2Sw1MyvgjPYZVnypS6lQgsW26xJOtY9pfD5tYqCWvGp55ksJM9HAWWZSWCHGwZnwG776wBAHwhy4FlK9iy7Hj4_arnW_cz_n9RVEHwVwuzgTtPUquCZSutCk_yGMUkYXwJO4QNElCl_G3AwteHlS9C4cuz40JrW4or38NzkUvo_mq7BSf2QfvHzjoJDTlg44WTChhfwDTU60qjrJv4_kTrLO-RMAgKfW3AIxkfDPXWresO0MFuX-sVYfi0WCQ5v153SIeF424_wqb11dHf60CE1ueU5TlVzu7yQsg8po_xaUjYKPnj6fnjGvPpc4VQOGHKCoSREC2A8iCgUAReyBBJ0RL8FXzbNNYjPD39629QCQ_Gwk68AVn4t7E7oEpQwMo24uHeA-6VJ2U24NU7grToDeP3BLgvEWUU7eof3K_FPg-CndeTZBheF1j8tlzCRm0xOOdVrbRw4NC3mn4L3KCPtwC0C9j84-Xv31fwx_P3G9j0YHYjyBcRk3x5UdFXPCgNn9IeavxpIznCJL2ByAWG0uS869visO2bcNz0f4HP5-SwaAl2nxPEp-wAynhCIX-1bHme_qx-J5Ff543TrSp6t6qXtKx3XffWNaEm-7qOgcV3n5FEENnX9RW1-KYr-4cq8f2jpxAZLJ10ep8o_Sb2O5Md_tkM2MO4kPKrjDe28_hUqR5l3t6HU2rCdVtGw19C__8G2NUV0mg2VOXonHVsvBCFYtmDQZ6Ev8P4EFp2aY2nPrkU-2ti-DigPk5uqkbo6RS9VDd16DglZG_8X0DxRFx9kyf__If-XeD4k7v2saexTgFXDbqQdJCokUKPCHMR4w9BqzVxgJOgrdn0Ot4xxJ8BpE8C8eD8n2anjMy_o29rvGqknfGhJ3djeyh8qd6Bcd7hifNLrdXL0OF6mOeb_T5v0HlrhFb0lm-TW1M_WiHhQ9GPeDl0c9yTE1BaiVChw9jMibBuYismCxI7DCNQhSAFCWisMoQu0rkysTVzNklAhJRGsdC0G1LWQCOoGkIg_9jx40nhEK2hNQ5FWYlCI9zdBc5fK-fpOGFYA7sKqUIXTR4PVR5MqyNj7CpVVqAIlI-DB5ai9Qc_rdFv4Mk6DEFEkbjOJkmNtUdik-SO7N07OguC4p4n4QjsOv5Yt6YMARx8j1PMeSbxiHWwayypEmNkw4GcZ3KWzcQA5-l9lo75KB3zQTXPpsVoNhOY8TTJZCKn48mEi2xSYiZwWiYDNecJH6VpmqXT8XjMh5PRWkzXxXo8u8-mo6xgowRrofRQ620dvhoGyvsW52k6SWZ8oEWB2scPEs4vWinn4QPFzYPWXdFuPBslWnnyZzukSOM8Rqc8tCbWgiysW63fwDak6jCN2TbOav3RKJY8giNUOjb38_GD1ul577tHUdUWw9LWjD8GH7rXXePsK5bE-GMMzDP-2MW2nfP_BAAA__94_8mf">