Floating point 为什么不';LLVM通过优化浮点指令?

Floating point 为什么不';LLVM通过优化浮点指令?,floating-point,llvm,compiler-optimization,Floating Point,Llvm,Compiler Optimization,见上文。我写了一些示例函数: LH: 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 %

见上文。我写了一些示例函数:

LH:

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
}
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
}
source fp.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
}
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
one得到优化,而
double
one没有得到优化?我希望
fadd
组合成一个
fmul
。相反,它看起来完全一样

这是因为标志设置不同吗?我知道对于
i32
可能进行的某些优化对于
double
是不可行的。但我无法理解为什么没有简单的不断折叠


我使用的是LLVM 3.1。

说不可能进行优化并不完全正确。我将通过前几行来说明哪些地方允许进行转换,哪些地方不允许进行转换:

  %addtmp = fadd double %x, %x
这第一行可以安全地转换为
fmul double%x2.0e+0
,但在大多数体系结构上,这实际上不是一个优化(
fadd
通常与
fmul
一样快,并且不需要生成常量
2.0
)。请注意,除非溢出,否则此操作是精确的(就像所有按二的幂进行缩放一样)

该行可以转换为
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
可能会第二次舍入

  %addtmp3 = fadd double %addtmp2, %x
这里也一样
5*x
将导致一次四舍五入<代码>x+x+x+x+x会导致三个错误


唯一可能进行有益转换的行是将
x+x+x
替换为
3*x
。但是,子表达式
x+x
已经存在于其他地方,因此优化器很容易选择不使用此转换(因为如果不使用,它可以利用现有的部分结果)。

高度相关,尽管我不确定它是否重复:@delan this,就像大量类似的浮点问题一样,这确实是一个复制品。即使问题的细节不同,答案也是一样的。这个问题的任何好答案都会指出浮点运算的非关联性,并提及-ffast math,就像这个问题的公认答案一样。谢谢你们。这是对相关问题的回答,强调了其中关于歧义的部分。谢谢你的详细回答。因此,执行
fmul double%x2.0e+0
并不断传播结果仍然比重复
fadd
s慢?还是我缺少舍入问题?
2*x
x+x
在数字上是等效的;但是,在常见的体系结构上,
x+x
并不比
2*x
慢(有时甚至快),因此优化器通常没有理由使用
2*x
。但是计算
x+x
两次(然后添加
x
)似乎比执行
%y1=fadd double%x,%x
之类的操作要慢,
%y2=fadd-double%y1,%y1
%res=fadd-double%y2,%x
。我不想强调
fmul
,这可能是误导。