假设我有这样的伪代码:
main() {
BOOL b = get_bool_from_environment(); //get it from a file, network, registry, whatever
while(true) {
do_stuff(b);
}
}
do_stuff(BOOL b) {
if(b)
path_a();
else
path_b();
}
现在,既然我们知道外部环境可以影响可能get_bool_from_environment()
产生真假结果,那么我们知道真假分支的代码必须包含在二进制文件中。我们不能简单地省略或从代码中删除。if(b)
path_a();
path_b();
但是——我们只设置BOOL b
了一次,并且我们总是在程序初始化后重用相同的值。
如果我要制作这个有效的 C 代码,然后使用 编译它gcc -O0
,if(b)
那么每次do_stuff(b)
调用时都会在处理器上重复评估,在我看来,这会将不必要的指令插入管道中,用于基本上是静态的分支初始化后。
如果我假设我实际上有一个像 一样愚蠢的编译器,我会gcc -O0
重写这段代码以包含一个函数指针和两个单独的函数do_stuff_a()
和执行两条路径之一。然后,在 中,我将根据 的值分配函数指针,并在循环中调用该函数。这消除了分支,尽管它确实为函数指针取消引用添加了内存访问(由于架构实现,我认为我真的不需要担心)。do_stuff_b()
if(b)
main()
b
即使在原则上,编译器是否有可能采用与原始伪代码示例相同样式的代码,并意识到一旦在 中b
分配了一次值,就不需要进行测试main()
?如果是这样,这个编译器优化的理论名称是什么,你能否举一个实际的编译器实现(开源或其他)的例子?
我意识到编译器不能在运行时生成动态代码,原则上唯一可以做到这一点的系统类型是字节码虚拟机或解释器(例如 Java、.NET、Ruby 等)——所以问题仍然存在是否有可能静态地执行此操作并生成包含path_a();
分支和path_b()
分支的代码,但避免为每次调用评估条件测试 。if(b)
do_stuff(b);