19

我一直被告知编译器足够聪明,可以消除死代码。我正在编写的大部分代码在编译时都有很多已知信息,但代码必须以最通用的形式编写。我不知道任何程序集,所以我无法检查生成的程序集。在最终的可执行文件中可以有效地消除什么样的代码?

几个例子但不限于

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)在主代码中怎么办?链接时间优化会有效消除死代码吗?促进死代码消除的编码风格/编译器选项/技巧是什么?

4

3 回答 3

27

通常,如果您使用标志进行编译,则会-O打开以下标志:

      -fauto-inc-dec 
      -fcompare-elim 
      -fcprop-registers 
      -fdce  
      [...]

-fdce代表死代码消除。我建议您编译您的二进制文件时使用或不使用(即通过明确关闭)此选项,以确保您的二进制文件是否按照您希望的那样优化。

阅读编译器的不同阶段:

  • SSA 积极的死代码消除。由 `-fssa-dce' 选项打开。这个过程执行消除被认为是不必要的代码,因为它对程序没有外部可见的影响。它以线性时间运行。

至于帮助链接器消除死代码,请通过此演示文稿。两个主要的收获是:

使用 -ffunction-sections -fdata-sections 编译您的模块——它没有任何缺点!

  • 这包括静态库,而不仅仅是二进制文件——使您的库的用户可以从更有效的死代码删除中受益。
  • 用 --gc-sections 链接你的二进制文件,除非你必须链接到使用魔法部分的讨厌的第三方静态库。

您可能还想查看这个 GCC 错误(了解可能会错过哪些优化机会以及原因)。

于 2012-05-30T03:13:58.807 回答
3

您的示例侧重于函数内部的死代码消除。

另一种类型的死代码消除是删除整个未使用的符号(函数或变量),可以通过以下方式实现:

-fdata-sections -ffunction-sections -Wl,--gc-sections

如前所述:如何使用 GCC 和 ld 删除未使用的 C/C++ 符号?

默认情况下,这些标志在各种 GCC -O 级别(-O1、-O2 等)中未启用。

于 2015-11-11T09:59:44.687 回答
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
}
于 2013-10-14T16:21:37.307 回答