前言
无效代码删除(DCE)是一种广泛使用的编译优化技术。数据流分析技术的发展,许多传统优化问题有了成熟的解决方案,无效代码删除优化也越发高效稳定。
对于以下示例:
#include<stdio.h>
void func();
void a() {
int i = 0;
for (; i < 1000; ++i);
func();
return;
}
static void b() {
int i = 0;
for (; i < 1000; ++i);
return;
}
int main()
{
int i = 0;
for (; i < 0xfffff; ++i);
a();
b();
return 0;
}
不采用gcc中任何无效代码删除优化编译(gcc test.c -S -o t1.s
),生成的汇编码包含了所有代码结构,如图所示:
使用-O3
编译之后的汇编码如下:
如上所示,采用-O3
编译优化了程序中的无效代码,极大地缩小了代码体积。虽然O3中包含了众多的优化操作,但对于上述示例代码的优化处理,无效代码删除有着重要的作用。
主要的dce文件
GCC中如果使用-O
编译程序,它会自动启用-fdce
、-fauto-inc-dec
等一系列的优化。但对于一些删除操作可能处理在编译器中启用优化选项外,还需要在链接器中添加一些标记,例如:
# keep every function in separate section. This will allow linker to dump unused functions
CFLAGS += -ffunction-sections -fdata-sections
# let linker to dump unused sections
LDFLAGS := -Wl,--gc-sections
很多的优化工作其实也是依赖-flto
实现的。若想禁用相关的优化可以使用-fno-xx
来实现,或使用关键字volatile
。
GCC编译器中的无效的代码删除优化主要在SSA(Static Single Assignment)
和RTL(Register Transfer Language)
中间表示上进行,从打印出来的中间表示可以看出,该优化是被多次调用执行的。GCC8.2.0版本中无效代码删除相关的文件主要有:tree-ssa-dce.c、dce.c
两个文件,分别代表SSA
上的优化和RTL
上的优化。
1. tree-ssa-dce.c
该文件中的无效代码删除算法主要包含以下三个方面:
- 标记所有已知的必要语句,例如:大多数函数调用,将值写入内存等
- 传播必要的语句,例如:为操作数赋值的语句等
- 删除无效语句
主要方法有:标记语句和操作是否是必要的,处理必要的操作数,删除或替换无效的语句和phi。具体函数和说明如下:
mark_stmt_if_obviously_necessary
方法根据GIMPLE_CODE
调用mark_stmt_necessary
函数,判断一条语句,如果ADD_TO_WORKLIST值为true,并且该语句没有被标记为必要的话,把它添加到worklist
gimple_set_plf (stmt, STMT_NECESSARY, true);
if (add_to_worklist)
worklist.safe_push (stmt);
if