见上文。我写信给示例函数:
source.ll:
define i32 @bleh(i32 %x) {
entry:
%addtmp = add i32 %x, %x
%addtmp1 = add i32 %addtmp, %x
%addtmp2 = add i32 %addtmp1, %x
%addtmp3 = add i32 %addtmp2, %x
%addtmp4 = add i32 %addtmp3, 1
%addtmp5 = add i32 %addtmp4, 2
%addtmp6 = add i32 %addtmp5, 3
%multmp = mul i32 %x, 3
%addtmp7 = add i32 %addtmp6, %multmp
ret i32 %addtmp7
}
source-fp.ll:
define double @bleh(double %x) {
entry:
%addtmp = fadd double %x, %x
%addtmp1 = fadd double %addtmp, %x
%addtmp2 = fadd double %addtmp1, %x
%addtmp3 = fadd double %addtmp2, %x
%addtmp4 = fadd double %addtmp3, 1.000000e+00
%addtmp5 = fadd double %addtmp4, 2.000000e+00
%addtmp6 = fadd double %addtmp5, 3.000000e+00
%multmp = fmul double %x, 3.000000e+00
%addtmp7 = fadd double %addtmp6, %multmp
ret double %addtmp7
}
为什么当我使用
优化两个函数时 opt -O3 source[-fp].ll -o opt.source[-fp].ll -S
i32
一个得到优化但double
一个没有优化?我希望fadd
合并为一个fmul
。相反,它看起来完全一样。
是否由于标志设置不同?我知道某些i32
可能无法对double
执行的优化。但缺乏简单的恒定折叠是我无法理解的。
我正在使用LLVM 3.1。
答案 0 :(得分:7)
说没有优化是可能的,这是不正确的。我将通过前几行来显示转换的位置和不允许的位置:
%addtmp = fadd double %x, %x
第一行可以安全地转换为fmul double %x 2.0e+0
,但这实际上并不是大多数体系结构的优化(fadd
通常比fmul
快或快,并且不需要产生常数2.0
)。请注意,除非溢出,否则此操作是精确的(就像所有按2的幂缩放一样)。
%addtmp1 = fadd double %addtmp, %x
此行可以转换为fmul double %x 3.0e+0
。为什么这是法律转型?因为生成%addtmp
的计算是精确的,所以只计算了一个舍入,无论是x * 3
还是x + x + x
。因为这些是IEEE-754基本操作,因此正确舍入,结果是相同的。溢出怎么样?除非对方也这样做,否则两者都不会溢出。
%addtmp2 = fadd double %addtmp1, %x
这是第一行无法合法转换为常数* x的行。 4 * x
会精确计算而不进行任何舍入,而x + x + x + x
会产生两次舍入:x + x + x
舍入一次,然后添加x
可能会再次舍入。
%addtmp3 = fadd double %addtmp2, %x
同上; 5 * x
会产生一个四舍五入; x + x + x + x + x
会产生三个。
可能有益转换的唯一一条线就是将x + x + x
替换为3 * x
。但是,子表达式x + x
已经存在于其他地方,因此优化器很容易选择不使用此转换(因为如果没有,它可以利用现有的部分结果)。