5

看上面。我写了示例函数:

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。

4

1 回答 1

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

于 2012-08-13T21:56:30.060 回答