在优化编译器中,冗余代码可以被多次检测并通过不同的算法消除,例如值编号,稀疏条件常数传播等。在这种情况下,我对检测冗余分支感兴趣。假设目标代码是
block1:
cmp r1, r2
jne block3
block2:
cmp r1, r2
je block4
block3:
...
block4:
...
...
在这种情况下,如果控件达到block2
,则表示r1
和r2
相等,因此je block4
可以替换为jmp block4
。此外,如果在block2中说jne block4
,那么我们可以完全删除je
。
然后我的问题是,什么优化传递捕获这种代码?我想可以扩展价值编号以解决这个问题,但从未在参考书目中看到它,所以也许有更好的方法。
修改:更正了第一次跳转,其中说je block3
它应该说jne block3
答案 0 :(得分:1)
好吧,假设在其他地方没有其他分支到block2中,编译器的布尔传播应该捕获它。当然,根据编译器的不同,还有其他各种阶段也可以做优化。
取决于bool prop算法,可能发生的情况是块3保持数据流值为" R1!= R2"它将传播到它下面的所有块。块2同样具有值" R1 == R2"它也会传播到后续的块(根据数据流),从而在途中移除死枝。
希望这有帮助。
答案 1 :(得分:0)
我不确定优化通行证的名称是否完全标准化,我现在无法找到Muchnick的副本,但在我上次编写的编译器中,您描述的情况会在两个阶段中检测 - 一个优化过程将检测到二次比较是多余的,并将其删除,后续传递将检测到相等跳转不需要是有条件的。
但并非每个编译器都进行此类优化。
答案 2 :(得分:0)
优化通常在您进行装配之前很久就会发生,而是某种形式的中间表示。
不同形式的IR会有所不同,但一个典型的方面是它们在无限的寄存器集上运行,而不是在机器寄存器上运行,并且每个寄存器都不能更改,只能初始化一次。 (如果你需要可变变量,你需要在堆栈上alloca
指针,然后通过它load
/ store
。优化的第一个也是最困难的阶段是从分配转换基于SSA,以便所有其他优化,如此,可以完成)
此示例使用LLVM IR。
define void @func2(i32 %r1, i32 %r2) {
block1:
%0 = icmp ne i32 %r1, %r2
br i1 %0, label %block3, label %block2
block2: ; preds = %block1
%1 = icmp eq i32 %r1, %r2
br i1 %1, label %block4, label %block3
block3: ; preds = %block2, %block1
unreachable
block4: ; preds = %block2
unreachable
}
现在应该相当直观%1
的定义可以用%1 = xor i1 %1, true
替换(这是布尔not
看起来像),然后可以传播常量通往block2
的唯一边缘。