llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
28.06k stars 11.59k forks source link

std::deque/std::stack construction is more expensive than GCC #53267

Open firewave opened 2 years ago

firewave commented 2 years ago

I came across this while working on https://github.com/danmar/cppcheck/pull/3716.

Using std::stack in Clang with the default std::deque backend is more expensive than doing so in GCC. It's about 10% slower. In the case I came across this I was able to speed this up using std::vector instead. That actually helped both compilers but Clang profited more from that.

The problem is the std::_Deque_base<void*, std::allocator<void*> >::_M_initialize_map(unsigned long) which GCC does not generate in the code - see https://godbolt.org/z/v1d9GsGnW.

Here's some sample code I used for profiling with -O2 and callgrind:

#include <stack>

extern void f()
{
        std::stack<void*> stk;
        stk.push(nullptr);
}

int main()
{
        for (int i = 0; i < 100000; ++i)
        {
                f();
        }

        return 0;
}

Total Ir: Clang 43,790,737 GCC 39,794,842

EugeneZelenko commented 2 years ago

Could you please clarify which standard C++ library was used?

firewave commented 2 years ago

I am using libstdc++.

fhahn commented 2 years ago

From a first glance, it seems like the std::vector case is optimized away because LLVM is able the inline the full std::vector constructor and the ::push calls. That appears to not be the case for the std::deque case

fhahn commented 2 years ago

I am confused, how is this different to #53268?

llvmbot commented 2 years ago

@llvm/issue-subscribers-clang-codegen

firewave commented 2 years ago

I am confused, how is this different to #53268?

This is about the std::deque constructor being more expensive than GCC. The other one is about dead code elimination with std::deque which neither compiler does. So it seems like two different things possibly depending on the same underlying behavior.

fhahn commented 2 years ago

This is about the std::deque constructor being more expensive than GCC. The other one is about dead code elimination with std::deque which neither compiler does. So it seems like two different things possibly depending on the same underlying behavior.

Right, but the reason it is more expensive (_M_initialize_map call not eliminated) is also the reason the code cannot be eliminated.

firewave commented 2 years ago

Right, but the reason it is more expensive (_M_initialize_map call not eliminated) is also the reason the code cannot be eliminated.

If that is the case feel free to close one of them as a duplicate.