https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89924
Bug ID: 89924 Summary: [missed-optimization] Function not de-virtualized within the same TU Product: gcc Version: 9.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: tree-optimization Assignee: unassigned at gcc dot gnu.org Reporter: eyalroz at technion dot ac.il Target Milestone: --- Related StackOverflow question: https://stackoverflow.com/q/55464578/1593077 GodBolt example: https://godbolt.org/z/l0vdFG In the following code: struct A { virtual A& operator+=(const A& other) noexcept = 0; }; void foo_inner(int *p) noexcept { *p += *p; } void foo_virtual_inner(A *p) noexcept { *p += *p; } void foo(int *p) noexcept { return foo_inner(p); } struct Aint : public A { int i; A& operator+=(const A& other) noexcept override final { i += dynamic_cast<const Aint&>(other).i; // i += reinterpret_cast<const Aint&>(other).i; return *this; } }; void foo_virtual(Aint *p) noexcept { return foo_virtual_inner(p); } Both functions, `foo()` and `foo_virtual()`, should compile to the same thing. But g++ 8.3 (on x86_64) with -O3 produces: ``` foo(int*): sal DWORD PTR [rdi] ret foo_virtual(Aint*): mov rax, QWORD PTR [rdi] mov rax, QWORD PTR [rax] cmp rax, OFFSET FLAT:Aint::operator+=(A const&) jne .L19 push rbx xor ecx, ecx mov edx, OFFSET FLAT:typeinfo for Aint mov esi, OFFSET FLAT:typeinfo for A mov rbx, rdi call __dynamic_cast test rax, rax je .L20 mov eax, DWORD PTR [rax+8] add DWORD PTR [rbx+8], eax pop rbx ret .L19: mov rsi, rdi jmp rax foo_virtual(Aint*) [clone .cold.1]: .L20: call __cxa_bad_cast ``` i.e. it doesn't manage to de-virtualize `Aint::operator+=` - although it really should. It has all the necessary information, as far as I can tell. As a side note, even regardless of de-virtualization, there's a whole lot of code there, while with with clang 8, we only get: ``` foo_virtual(Aint*): # @foo_virtual(Aint*) mov rax, qword ptr [rdi] mov rax, qword ptr [rax] mov rsi, rdi jmp rax ``` which at least doesn't need the type info.