Jan*_*tke 8 c++ clang compiler-optimization devirtualization
struct base {
virtual void vcall() = 0;
};
struct foo final : base {
void vcall() final;
};
void call_base(base& b) {
b.vcall();
}
void call_foo(foo& f) {
call_base(f);
}
void call_foo_directly(foo& f) {
f.vcall();
}
Run Code Online (Sandbox Code Playgroud)
clang 16 产生:
call_base(base&):
mov rax, qword ptr [rdi]
jmp qword ptr [rax]
call_foo(foo&):
mov rax, qword ptr [rdi]
jmp qword ptr [rax]
call_foo_directly(foo&):
jmp foo::vcall()@PLT
Run Code Online (Sandbox Code Playgroud)
GCC 和 MSVC 产生相同的结果,因此这不是仅限于 clang 的问题。是否也应该call_foo包含非虚拟调用foo::vcall()?这是错过的优化,还是调用有可能是虚拟的?
SrP*_*nda -1
编译器确实会尝试,但需要内联一些东西,如果一个函数没有实现,它只是一个空调用,这就是编译的内容;添加final只会阻止以后的使用override。volatile需要通过优化来编译它,这样一切都不会被优化掉。
在bodbolt中运行它。
struct base {
volatile int num = 111;
virtual void vcall() = 0;
};
struct foo final : base {
void vcall() {
num += 222;
};
};
void call_base(base& b) {
b.vcall();
}
void call_foo(foo& f) {
call_base(f);
}
void call_foo_directly(foo& f) {
f.vcall();
}
void main_func(void) {
foo val;
call_foo(val);
call_foo_directly(val);
}
Run Code Online (Sandbox Code Playgroud)
这是带有-O3部分反汇编的clang-15(与-O2相同);vs 无法内联call_foo。
main_func(): # @main_func()
mov dword ptr [rsp - 8], 111
add dword ptr [rsp - 8], 222
add dword ptr [rsp - 8], 222
ret
Run Code Online (Sandbox Code Playgroud)