This question already has answers here:
Why doesn't GCC optimize a*a*a*a*a*a to (a*a*a)*(a*a*a)?

(12个答案)


7年前关闭。




看上面。我写了一些示例函数:
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。

最佳答案

说没有优化是不可能的。我将浏览前几行,以显示在何处和不允许进行转换:

  %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已经存在于其他位置,因此优化器可以轻松地选择不采用此转换(因为如果不这样做,则可以利用现有的部分结果)。

关于floating-point - LLVM为什么不通过优化浮点指令?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/11942527/

10-11 22:07
查看更多