说我有一个功能
void do_something() {
//....
#ifdef FEATURE_X
feature_x();
#endif
//....
}
字符串
我可以编译和运行这个没有问题;如果我想要这个特性,我可以传递-D FEATURE_X
,它可以工作。
但是,如果我想将do_something
放入另一个文件中(并且每次决定更改选项时都不必重新编译该文件),该怎么办?如果是在同一个文件里我想
const int FEATURE_X=0;
void do_something() {
//....
if(FEATURE_X) {
feature_x();
}
//....
}
型
将正确使用死代码消除,消除调用。如果我把这个放到另一个文件里,不带LTO,
extern const int FEATURE_X;
void do_something() {
//....
if(FEATURE_X) {
feature_x();
}
//....
}
型
它不会删除代码(它没有办法知道)。因此,启用链接时优化后,编译器是否可以在链接时检测FEATURE_X
的值,确定是否使用了该代码,并在适当的情况下删除它?
2条答案
按热度按时间yxyvkwin1#
GCC确实可以跨模块删除不可访问的函数,但它将无法在您的最后一个测试用例中确定代码已经死亡,因为FEATURE_X的常量值将被确定得太晚。
如果你将使用-D方式或将你的
const int FEATURE_X=0;
放入每个模块中,那么是的,代码将被消除。ou6hu8tu2#
LTO导致死代码消除的示例
测试设置:
notmain.c
字符串
main.c
型
无LTO的对照实验
不使用LTO编译和反汇编:
型
输出包含:
型
所以没有删除无用的
notmain2
。我们也可以看看对象的大小:
型
其输出:
型
此外,作为奖励,我们注意到函数调用不是内联的:
型
观察LTO执行DCE
型
输出不包含
notmain
和notmain2
符号。所有内容都完全内联到main
中,它在一条指令中将第一个参数rdi加1,并将其放入返回寄存器eax中:型
Inlining还提到:链接时间优化和内联
漂亮。检查尺寸:
型
产出:
型
并且我们看到由于内联和死代码消除,文本大小如所期望的那样更小。
LTO执行DCE,即使没有发生内联
在上面的示例中,不清楚是否只有在涉及内联时才会消除函数DCE。让我们用以下代码来测试一下:
型
编译和反汇编:
型
输出包含:
型
没有
notmain2
。因此,即使notmain
没有被删除,无用的notmain2
也被删除了。使用
-O0
编译notmain.c
时不会删除函数我不明白为什么:Why GCC does not do function dead code elimination with LTO when compiling the object file with -O0?
在Ubuntu 23.04 amd64,GCC 12.2.0上测试。