gpt4 book ai didi

c++ - 为什么这个简单的功能没有去虚拟化?

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:46:28 27 4
gpt4 key购买 nike

考虑以下代码:

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
{
// No devirtualization of foo_virtual with:
i += dynamic_cast<const Aint&>(other).i;
// ... nor with:
// i += reinterpret_cast<const Aint&>(other).i;
return *this;
}
};

void foo_virtual(Aint *p) noexcept
{
return foo_virtual_inner(p);
}

据我所知,foo()foo_virtual() 应该编译成相同的目标代码。当从 foo_virtual 调用时,编译器拥有在 foo_virtual_inner() 中对 operator+= 的调用去虚拟化所需的所有信息。但是 - neither GCC 8.3, nor MSVC 19.10, nor clang 8 do this .当然,我使用了最大优化标志(-O3/Ox)。

为什么?这是一个错误,还是我遗漏了什么?


clang 8 输出:

foo(int*):                               # @foo(int*)
shl dword ptr [rdi]
ret
foo_virtual(Aint*): # @foo_virtual(Aint*)
mov rax, qword ptr [rdi]
mov rax, qword ptr [rax]
mov rsi, rdi
jmp rax # TAILCALL

GCC 8.3 输出:

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

MSVC 19.10 输出:

p$ = 8
void foo(int * __ptr64) PROC ; foo
mov eax, DWORD PTR [rcx]
add eax, eax
mov DWORD PTR [rcx], eax
ret 0
void foo(int * __ptr64) ENDP ; foo

p$ = 8
void foo_virtual(Aint * __ptr64) PROC ; foo_virtual
mov rax, QWORD PTR [rcx]
mov rdx, rcx
rex_jmp QWORD PTR [rax]
void foo_virtual(Aint * __ptr64) ENDP

PS - GCC 下编译代码中所有类型信息业务的解释是什么?

最佳答案

GCC 猜测 Aint *p 指向 Aint *p 的实例(但不认为这一定会发生)因此它推测性地去虚拟化了对 operator+= 的调用并且类型信息检查是它的内联拷贝。-fno-devirtualize-speculatively 导致与 Clang 和 MSVC 生成的代码相同。

_Z11foo_virtualP4Aint:
.LFB4:
.cfi_startproc
movq (%rdi), %rax
movq %rdi, %rsi
movq (%rax), %rax
jmp *%rax

关于c++ - 为什么这个简单的功能没有去虚拟化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55464578/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com