https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120894
Bug ID: 120894 Summary: Usage of std::pmr::polymorphic_allocator<T> is not optimized out Product: gcc Version: 16.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: m.cencora at gmail dot com Target Milestone: --- Following program is not fully optimized (to 16-byte stack allocation + zeroing and a call to 'use'). $ cat pmr.cpp #include <vector> #include <memory_resource> #ifdef WORKAROUND namespace std::pmr { [[gnu::pure]] memory_resource* get_default_resource() noexcept; memory_resource::~memory_resource() {} } #endif void use(const std::byte*) noexcept; namespace { struct StaticResource final : public std::pmr::memory_resource { constexpr StaticResource(void* buffer, std::size_t buffer_size, std::pmr::memory_resource* upstream = std::pmr::get_default_resource()) noexcept : buffer{buffer}, buffer_left{buffer_size}, upstream{upstream} { } void* do_allocate(std::size_t bytes, std::size_t alignment = alignof(std::max_align_t)) override { if (auto ret = static_cast<std::byte*>(std::align(alignment, bytes, buffer, buffer_left))) { buffer_left -= bytes; buffer = &ret[bytes]; return ret; } else { return upstream->allocate(bytes, alignment); } } void do_deallocate(void*, std::size_t, std::size_t = alignof(std::max_align_t)) override {} bool do_is_equal(const memory_resource& other) const noexcept override { return &other == this; } private: void* buffer; std::size_t buffer_left; std::pmr::memory_resource* upstream; }; } void test() { std::byte buf[16]; StaticResource res(&buf[0], sizeof(buf)); std::pmr::vector<std::byte> vec{16, &res}; use(vec.data()); } $ g++ -std=c++20 -O3 pmr.cpp Resulting assembly still have non-inlined calls to StaticResource::do_allocate, unused call std::pmr::get_default_resource and invocation of no-op destructor of std::pmr::memory_resource. See here: https://godbolt.org/z/br57EaGhn This can be improved somewhat by compilation with additional -DWORKAROUND flag, but the calls to std::pmr::get_default_resource and StaticResource::do_allocate are still there. "test()": sub rsp, 72 movq xmm0, QWORD PTR .LC0[rip] lea rax, [rsp+16] movq xmm1, rax punpcklqdq xmm0, xmm1 movaps XMMWORD PTR [rsp], xmm0 call "std::pmr::get_default_resource()" movdqa xmm0, XMMWORD PTR [rsp] lea rdi, [rsp+32] mov edx, 1 mov esi, 16 mov QWORD PTR [rsp+56], rax movaps XMMWORD PTR [rsp+32], xmm0 mov QWORD PTR [rsp+48], 16 call "(anonymous namespace)::StaticResource::do_allocate(unsigned long, unsigned long)" pxor xmm0, xmm0 movups XMMWORD PTR [rax], xmm0 mov rdi, rax call "use(std::byte const*)" add rsp, 72 ret clang with -O2 -DWORKAROUND does pretty good job: test(): sub rsp, 24 xorps xmm0, xmm0 movaps xmmword ptr [rsp], xmm0 mov rdi, rsp call use(std::byte const*)@PLT add rsp, 24 ret Obviously marking the std::pmr::get_default_resource as 'pure' function is wrong, so it would be great if we had an attribute that indicates functions does not modify program state, but cannot be reordered or CSE-d. Also not sure why but ~memory_resource is not-defined inline, and most likely we cannot change it due to ABI so we would need another attribute that states the function is a no-op.