Floating point 为什么不';LLVM通过优化浮点指令?
见上文。我写了一些示例函数: LH: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 %
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
这是第一行不能合法地转换为常数*x4*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
,这可能是误导。