为什么LLVM不通过优化浮点指令?

时间:2012-08-13 21:23:05

标签: floating-point llvm compiler-optimization

见上文。我写信给示例函数:

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。

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已经存在于其他地方,因此优化器很容易选择不使用此转换(因为如果没有,它可以利用现有的部分结果)。