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

    <tr>
        <th>Summary</th>
        <td>
            [clang] Missed optimization: Failure to remove useless allocations / deallocations
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            clang
      </td>
    </tr>

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

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

<pre>
    The following translation unit:

```c++
#include <memory>

struct Container {
        ~Container() {
                if (m_pointer) {
                        std::allocator<int>().deallocate(m_pointer, 1);
                }
        }

        int * m_pointer = nullptr;
};

Container bad() {
        auto container = Container{};
        auto const original_pointer = std::allocator<int>().allocate(1);
        container.m_pointer = original_pointer;
        container.m_pointer = std::allocator<int>().allocate(1);

        std::allocator<int>().deallocate(
                original_pointer,
                1
        );

        return container;
}
```

when compiled with `-O3` generates the following output:

```
%struct.Container = type { ptr }

define dso_local void @bad()(ptr dead_on_unwind noalias nocapture writable writeonly sret(%struct.Container) align 8 initializes((0, 8)) %agg.result) local_unnamed_addr #0 personality ptr @__gxx_personality_v0 !dbg !394 {
entry:
    #dbg_value(ptr undef, !401, !DIExpression(DW_OP_LLVM_fragment, 0, 8), !407)
    #dbg_value(ptr undef, !401, !DIExpression(DW_OP_LLVM_fragment, 0, 8), !409)
    #dbg_value(ptr undef, !411, !DIExpression(DW_OP_LLVM_fragment, 0, 8), !416)
    #dbg_value(ptr %agg.result, !398, !DIExpression(DW_OP_deref), !418)
    #dbg_value(ptr undef, !401, !DIExpression(), !407)
    #dbg_value(i64 1, !404, !DIExpression(), !407)
    #dbg_value(ptr null, !405, !DIExpression(), !407)
  %call5.i14 = tail call noalias noundef nonnull dereferenceable(4) ptr @operator new(unsigned long)(i64 noundef 4) #3, !dbg !419
 #dbg_value(ptr %call5.i14, !399, !DIExpression(), !418)
  store ptr %call5.i14, ptr %agg.result, align 8, !dbg !420
    #dbg_value(ptr undef, !401, !DIExpression(), !409)
    #dbg_value(i64 1, !404, !DIExpression(), !409)
    #dbg_value(ptr null, !405, !DIExpression(), !409)
  %call5.i15 = invoke noalias noundef nonnull dereferenceable(4) ptr @operator new(unsigned long)(i64 noundef 4) #3
          to label %invoke.cont4 unwind label %if.then.i, !dbg !427

invoke.cont4:
  store ptr %call5.i15, ptr %agg.result, align 8, !dbg !428
    #dbg_value(ptr undef, !411, !DIExpression(), !416)
    #dbg_value(ptr %call5.i14, !414, !DIExpression(), !416)
    #dbg_value(i64 1, !415, !DIExpression(), !416)
  tail call void @operator delete(void*, unsigned long)(ptr noundef nonnull %call5.i14, i64 noundef 4) #4, !dbg !429
  ret void, !dbg !430

if.then.i:
  %0 = landingpad { ptr, i32 }
          cleanup, !dbg !430
    #dbg_value(ptr undef, !411, !DIExpression(DW_OP_LLVM_fragment, 0, 8), !431)
 #dbg_value(ptr %agg.result, !438, !DIExpression(), !441)
    #dbg_value(ptr undef, !411, !DIExpression(), !431)
    #dbg_value(ptr %call5.i14, !414, !DIExpression(), !431)
    #dbg_value(i64 1, !415, !DIExpression(), !431)
 tail call void @operator delete(void*, unsigned long)(ptr noundef nonnull %call5.i14, i64 noundef 4) #4, !dbg !442
  resume { ptr, i32 } %0, !dbg !430
}

declare i32 @__gxx_personality_v0(...)

declare void @operator delete(void*, unsigned long)(ptr noundef, i64 noundef) local_unnamed_addr #1

declare noundef nonnull ptr @operator new(unsigned long)(i64 noundef) local_unnamed_addr #2

attributes #0 = { mustprogress uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #1 = { nobuiltin nounwind "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #2 = { nobuiltin allocsize(0) "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #3 = { builtin allocsize(0) }
attributes #4 = { builtin nounwind }
```

which corresponds to the assembly

```asm
bad():
        push    r14
        push    rbx
 push    rax
        mov     rbx, rdi
        mov     edi, 4
        call operator new(unsigned long)@PLT
        mov     r14, rax
        mov qword ptr [rbx], rax
        mov     edi, 4
        call    operator new(unsigned long)@PLT
        mov     qword ptr [rbx], rax
        mov esi, 4
        mov     rdi, r14
        call    operator delete(void*, unsigned long)@PLT
        mov     rax, rbx
        add     rsp, 8
 pop     rbx
        pop     r14
        ret
        mov     rbx, rax
 mov     esi, 4
        mov     rdi, r14
        call    operator delete(void*, unsigned long)@PLT
        mov     rdi, rbx
        call _Unwind_Resume@PLT

DW.ref.__gxx_personality_v0:
        .quad __gxx_personality_v0
```

I want it to generate

```
%struct.Container = type { ptr }

define dso_local void @good()(ptr dead_on_unwind noalias nocapture writable writeonly sret(%struct.Container) align 8 initializes((0, 8)) %agg.result) local_unnamed_addr #0 personality ptr @__gxx_personality_v0 !dbg !394 {
entry:
    #dbg_value(ptr undef, !399, !DIExpression(DW_OP_LLVM_fragment, 0, 8), !405)
    #dbg_value(ptr %agg.result, !398, !DIExpression(DW_OP_deref), !407)
    #dbg_value(ptr undef, !399, !DIExpression(), !405)
    #dbg_value(i64 1, !402, !DIExpression(), !405)
    #dbg_value(ptr null, !403, !DIExpression(), !405)
  %call5.i3 = tail call noalias noundef nonnull dereferenceable(4) ptr @operator new(unsigned long)(i64 noundef 4) #2, !dbg !408
  store ptr %call5.i3, ptr %agg.result, align 8, !dbg !409
  ret void, !dbg !416
}

declare i32 @__gxx_personality_v0(...)

declare noundef nonnull ptr @operator new(unsigned long)(i64 noundef) local_unnamed_addr #1

attributes #0 = { mustprogress uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #1 = { nobuiltin allocsize(0) "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #2 = { builtin allocsize(0) }
```

which corresponds to

```asm
good():
        push    rbx
 mov     rbx, rdi
        mov     edi, 4
        call    operator new(unsigned long)@PLT
        mov     qword ptr [rbx], rax
        mov rax, rbx
        pop     rbx
        ret
```

It looks like if an optimization pass implemented https://github.com/llvm/llvm-project/issues/68365 that would be sufficient to solve this problem, but there are other possible optimization paths for this.

See it live: https://godbolt.org/z/r87Ezb8b5

This bug prevents the optimization of the following code with any standard library implementation:

```c++
auto container = vector<int>();
container.push_back(1);
container.push_back(1);
return container;
```
</pre>
<img width="1" height="1" alt="" src="http://email.email.llvm.org/o/eJzsWk-P4ygW_zTUBVVkYztxDjlUV7qkkXo0o93enWOEzbPDNgYP4KSqD_vZVxjHjlNOqtLVXbPSdBQpxDze39-DB4Yaw0sJsELJB5Ssb2hjt0qvGN1xZqyScJMp9rT6vAVcKCHUnssSW02lEdRyJXEjuUXRHQra7zzw3xyRD-4b3CEScZmLhgFG0X0FldJPKPro6Y3VTW7xvZKWcgkao0U7Jlj-t3-GSIrIcuhBwZIXGJG02tSKS-soxt0oWBrLnFLRHRVC5dQqjaJ7Lq2T3PKbMei6YMzqHoeILFF0xG6x7tpdw7W5tBiRO9yPxChaY9kIUVvdjV6sD2zuBgszyk4too1VOB98EK0HjziigU9PaixWmpdcUjFS4GW7j6weGdrLn41NOhXz4oBvVuHu-rj1MXqmJbnv-8KuNZakwTZaDm4fYnYEY0-934IjrGougOE9t1uM5sHtbxGaB7gECZpaMNiOckQ1tm4mMqNNicQDf3Y_Crp9qsGhAtfWZUIHNgYFl4CZURtnt8A7xRlGcdAjCZHUjWBA2UbJTSP3XDIsFRWcGixVTmvbaMB7zS3NhG-AkuIJGw22ZfJMI4dQKngpcYq55JZTwb-CaYnTwOWJF73EiCS0LGcaTCOse9CquWmkpBWwDWVMY0SiANegjZJUcPvkTYyDzaZ8fNwcdWx2AUYkZFnpfqJl3KUJSOvmDecQjLHjx7Jys6Oigc78RjIonF6IhHEQdq31Lx8faw3GcCURSdd_bH77ffPp079_3RSalhVI6wiP7OnGL9yfd5K1fL2s8I2ywvlFWSehvPcxSC_JZKCdeoOE9O2ee10g-DzGYU8Xv4WV08zN3T1pcgU3RJKcCpHMeBj7PKZcYPfoKAdbu7FU0onBrdNAg8zBJSQiaewSp0sKVbsZRWksYY9I2sh2iWZYKFn6dHemH3jGPgejqNOsS504bLWbDnKvbx_j5YsGD4E1VmnAU6wmMdTNIifqkeA7guR8Bl0NksvJeC1IlhMgSVqQcLlTX-CdEeLt8h-rsKAZCKeaV2bmFsMYd-vH0FnM7BbkjJ9GcOEXqOPBhxl6EiLJtRBJ3zgrXjXxneZEHL6MlgtcR8ALX4bKwGqYPg4rfR9uBgLawsf1IHLnBk8Ev0XqCaBOLZwCSHwaAK-QBou9wFFv1JVHAz664COSBC3GBZWMy7Km7FDWtJIj0lU3AxhzAVQ29ZSE91gWo7Bz_ivXxDg6syYe8YzDty_rUyp-VwBf4HotgHtW_z_4jUmHX9NUMAHBFqmTqB6K71xQDX7AdLmKSDqbzbztRyO-g-0nZp4vrcOx6FPXfcuicV4Y8cKotZpnjdv4tMW9y3fn4aoxttaqdBjBzd5vOBAhFZe3AkoqbneQW6Vv95zZLSIERWtESIAIcWRS3VpN65rL8raiRwRWO1S2NMbS_MttrZX1nLKmKEDfGv4VevK0o7VUl2Bv87rpux7T-e08HvcXQN0WyfREiHzIK7Vz-0jyIX9MfaN4NNq3qurRN4yBvkF86zFdHLg3Ekay290iz9vuFmNjN4a9G6XKGi4sl21A2gX5b-8dMuGd9jDA2-Z2pcufXop6L5330cSw-NmwAXjThyI83-JcaQ2mVpIZV1DaLWBqDFSZeDo596CmQsHdcGbRb-Xdp27M1v3qMJ56mj26p_1f-nhEVKkdPhCRe6wZn-gE1havx8zbBeqlKTEOfv_0eUqYX4Oea_LnXmnmJ9zkg1MpWU8TXtIK429W7NXywTyT3Rvn1RrH4plir1rOzvqP-mBlx2pRxnynqX195mKuanwEgQMwDk9HKmqwF3DhPdC7_q81vxMxMqoVsflXm3Kbf7QlS88ABXfrP2YaitlkBTLKpdmfDWV4ku5ZEv-C91RazK1L3sNJ5g87sCyV-nlieWYLcPYE5tWniMmPPtm74kz0NedJFxQeH9qQt7B6dmgTXcFt2HNEf-HBHjnZoQTp2SOW6MoTluDiBj-cf5-t0I_dj4Q_9yPvuh_5WXGf35e8UHG_ooSerJqPFs7psjkbFTffVAq_R9E5WfZNl3i-mDstVywWSn0xWPAvgHmBqcSqtrziX_1lhJoag3lVC3DrJDC8tbY2zmnkAZGHktttk81yVSHyIMTu8ONQ-R_ILSIP3JjGAephnkbzBNsttXivGsFwBtg0RcFzDrKtl4wSO8B2yw2utcoEVM64rLFuG6QBu6lPuSaulTHczTsnytqtwYXSLY-ZN_GfAK4cE3wHKLo71V-xTAk7U7pE5OErIg86XXz8mqVZ4kd_dspkTYlrDTuQ1r-UHklVxcmL6lwx8C-1qXzCxlLJqGZY8ExT_TR4sx1-6abHxDUGP7WevML3b9qH6wMOxZuM5l9G9wFe6j_z_v6g1g1bRWwZLekNrMJFNE_m82hBbrYrUixIzNgyXRYQLFkRByROyTyIchou51lxw1ckIEkQhmEQRSQhM0KCNCcpgzAKwzykKA6golzMHHRcLG5a0KxCQpL54qZ9b2La-zSE5IK63CEoWd_oVYu1rCkNigPBjTUDC8utaC_h-BHJGv_KjQE2Cp5DxAPlwpXGVmENldoBbgwIt7h19yK4km5WesD9TQn35KbRYvXt2dDZtluR_wUAAP__c8qgGg">