GCC对简单类进行去虚拟化
GCC de-virtualization of simple class
以下代码不会被gcc破坏。我能做些什么来说服gcc放弃机会吗?
struct B /* final */ {
virtual int foo() { return 3; }
};
struct C {
B& b;
__attribute__((noinline))
C( B& b ) : b(b) {
}
int foo() {
return b.foo();
}
};
int main() {
B b;
C c(b);
int res = c.foo();
return res;
}
我天真地认为这将是一种机会化(至少是推测性的)和内联。
在构造函数是另一个编译单元的实际代码中,编译器将无法看到构造函数的主体(因此是noinline属性)。模仿一些现实世界的要求也不是最终的。
当编译器在编译时知道对象的类型时,就会发生虚拟化。在这里,您有C::C的noinline,这使得main无法知道在构造过程中,什么类型的对象最终会变成C::b。
在构造函数是另一个编译单元的实际代码中,编译器将无法看到构造函数的主体(因此是noinline属性)。模仿一些现实世界的要求也不是最终的。
为了去虚拟化,编译器通常需要能够证明类层次结构是密封的。如果对构造函数的调用在单独的翻译单元中,编译器无法证明这一点。然而,使用链接时优化可以在翻译单元之间为优化器提供信息,这可以更容易地证明有关类层次结构和引用的事实。
下面是一个使用clang的例子。
b.hpp
#ifndef B_H
#define B_H
struct B {
virtual int foo();
};
#endif
b.cpp
#include "b.h"
int B::foo() { return 3; };
c.hpp
#ifndef C_H
#define C_H
#include "b.h"
struct C {
B& b;
C(B& b);
int foo();
};
#endif
c.cpp
#include "c.h"
C::C(B& b) : b(b) {}
int C::foo() {
return b.foo();
}
main.cpp
#include <iostream>
#include "b.h"
#include "c.h"
int main(const int argc, const char* argv[argc]) {
B b;
C c(b);
std::cout << c.foo() << std::endl;
return 0;
}
由于优化器对C::C
的调用站点一无所知(构造函数),它对CCD_ 2的运行时类型一无所知。所以,它不能去虚拟化CCD_ 3。
C: :foo
_ZN1C3fooEv: # @_ZN1C3fooEv
.cfi_startproc
# BB#0:
movq (%rdi), %rdi
movq (%rdi), %rax
jmpq *(%rax) # TAILCALL <== pointer call
但是,为优化器提供链接时间信息(-flto
)允许它证明类层次结构与调用站点是密封的。
B: :foo
0000000000400960 <_ZN1B3fooEv>:
400960: b8 03 00 00 00 mov $0x3,%eax
400965: c3 retq
400966: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
40096d: 00 00 00
主要
0000000000400970 <main>:
400970: 41 56 push %r14
400972: 53 push %rbx
400973: 50 push %rax
400974: 48 c7 04 24 78 0a 40 movq $0x400a78,(%rsp)
40097b: 00
40097c: 48 8d 3c 24 lea (%rsp),%rdi
400980: e8 db ff ff ff callq 400960 <_ZN1B3fooEv> # <== direct call
相关文章:
- 在c++中用vector填充一个简单的动态数组
- (C++)分析树以计算返回错误值的简单算术表达式
- 我的简单if-else语句是如何无法访问的代码
- 使用简单类型列表实现的指数编译时间.为什么
- 如何在BST的这个简单递归实现中消除警告
- 一种在C++中读取TXT配置文件的简单方法
- 关于简单C++函数(is_palindrome)的逻辑的问题
- 显示错误输出的简单数组排序程序
- 当无法使用模板和宏时,生成类型变体C++代码的最简单方法是什么?
- 退出简单while循环时出现问题
- 为什么简单的算术减法在"if"条件下不起作用?
- C++-字符串是否包含一个带有简单循环的单词
- 关于 c++ 函数中指针赋值的简单问题
- 从函数返回任意简单类型的数据
- 如何在没有函数的情况下编写此代码并使C++更简单?
- 有没有办法简单地从 GPU 调用多个 cpp 输出文件?
- 在简单示例中,Python3 + ctypes 回调会导致内存泄漏
- 当简单捕获中的标识符显示为参数的声明符 ID 时,没有编译器诊断
- 为什么这个简单的功能没有去虚拟化?
- GCC对简单类进行去虚拟化