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.