GCC为什么不把a*a优化到(a*a)*(a*a)?

GCC为什么不把a*a优化到(a*a)*(a*a)?

我在做一些关于科学应用的数值优化。我注意到的一件事是GCC会优化通话pow(a,2)把它编译成a*a,但是那个电话pow(a,6)没有优化,实际上将调用库函数。pow,这大大降低了表演的速度。(相比之下,Intel C+编译器,可执行icc,将消除图书馆对pow(a,6).)

我好奇的是当我pow(a,6)带着a*a*a*a*a*a使用GCC 4.5.1和选项“-O3 -lm -funroll-loops -msse4“,它使用5mulsd指示:

movapd  %xmm14, %xmm13
mulsd   %xmm14, %xmm13
mulsd   %xmm14, %xmm13
mulsd   %xmm14, %xmm13
mulsd   %xmm14, %xmm13
mulsd   %xmm14, %xmm13

如果我写(a*a*a)*(a*a*a),它会产生

movapd  %xmm14, %xmm13
mulsd   %xmm14, %xmm13
mulsd   %xmm14, %xmm13
mulsd   %xmm13, %xmm13

这将乘法指令的数量减少到3。icc也有类似的行为。

为什么编译器不认识这个优化技巧?


慕桂英4014372
浏览 699回答 3
3回答

慕田峪4524236

因为浮点数学不是相联的..在浮点乘法中将操作数分组的方式对答案的数值精度有影响。因此,大多数编译器对于重新排序浮点计算是非常保守的,除非他们能够确保答案保持不变,或者除非你告诉他们你不在乎数值的准确性。例如:这个-fassociative-math期权GCC的理论,它允许GCC重新使用浮点运算,甚至是-ffast-math该选项允许在准确性和速度上进行更积极的权衡。

桃花长相依

另一种类似的情况:大多数编译器不会优化a + b + c + d到(a + b) + (c + d)(这是一种优化,因为第二个表达式可以更好地流水线化)并按给定(即(((a + b) + c) + d))。这也是因为角落案件:float a = 1e35, b = 1e-5, c = -1e35, d = 1e-5;printf("%e %e\n", a + b + c + d, (a + b) + (c + d));这输出1.000000e-05 0.000000e+00
打开App,查看更多内容
随时随地看视频慕课网APP