我一直被告知编译器足以聪明地消除死代码。我编写的大部分代码在编译时都知道很多信息,但代码必须以最通用的形式编写。我不知道任何装配,所以我无法检查生成的装配。什么样的代码可以在最终的可执行文件中有效消除?
几个例子,但不限于
f(bool b){
if(b){
//some code
}else{
//some code
}
}
f(true);
//////////////////////////
template<bool b>
f(){
if(b){
//some code
}else{
//some code
}
}
f<true>();
///////////////////////////
如果f
的定义在其他客观代码中且被调用的f(true)
在主要内容,该怎么办?链接时间优化会有效消除死代码吗?什么是编码样式/编译器选项/技巧,以促进死代码消除?
答案 0 :(得分:25)
通常,如果您使用the -O
flag进行编译,则会打开以下标志:
-fauto-inc-dec
-fcompare-elim
-fcprop-registers
-fdce
[...]
-fdce
代表死法消除。我建议您使用和不使用(即通过明确关闭)此选项来编译您的二进制文件,以确保您的二进制文件是否像您希望的那样进行了优化。
阅读编译器的different passes:
- SSA积极的死代码消除。由`-fssa-dce'打开 选项。此过程执行消除被认为不必要的代码 因为它对程序没有外部可见的影响。它 在线性时间内运作。
至于帮助链接器消除死代码,请通过this presentation。两个主要的要点是:
使用-ffunction-sections -fdata-sections编译模块 没有缺点!
- 这包括静态库,而不仅仅是 二进制文件 - 使您的图书馆用户可以从中受益 更有效的死代码删除。
- 将您的二进制文件链接到 --gc-sections,除非你必须链接使用魔法部分的令人讨厌的第三方静态库。
您可能还想查看this GCC bug(了解可能遗漏优化的可能性以及原因)。
答案 1 :(得分:1)
您的示例主要关注函数内的死代码消除。
另一种类型的死代码消除,是删除整个未使用的符号(函数或变量),可以通过以下方式实现:
-fdata-sections -ffunction-sections -Wl,--gc-sections
如上所述:How to remove unused C/C++ symbols with GCC and ld?
在各种GCC -O级别(-O1,-O2等)by default中未启用这些标志。
答案 2 :(得分:0)
当我在这样的if表达式中使用模板参数常量时,dce(死代码消除)编译器(Linux上的GCC 4.8.1)标志没有帮助和O2,O3优化也没有帮助。 我不得不使用模板专业化包装器:
template<bool b>
f();
template<>
f<true>(){
//some code on true condition
}
template<>
f<false>(){
//some code on false condition
}
此外,还可以使用宏来避免编译未使用的代码分支,但这取决于编译器(无论是在代码中还是在预编译阶段都处理宏):
template<bool b>
f(){
#if b
//some code
#elif
//some code
#endif // b
}