双和ffast数学的自动矢量化

时间:2010-05-17 20:54:20

标签: gcc g++ double vectorization fast-math

为什么必须使用-ffast-math和g ++来实现使用double s的循环矢量化?我不喜欢-ffast-math,因为我不想失去精确度。

3 个答案:

答案 0 :(得分:8)

使用-ffast-math不一定会失去精确度。它只影响NaNInf等的处理以及执行操作的顺序。

如果您有一段特定的代码,您不希望GCC重新排序或简化计算,您可以使用asm语句将变量标记为正在使用。

例如,以下代码对f执行舍入操作。但是,两个f += gf -= g操作可能会被gcc优化掉:

static double moo(double f, double g)                                      
{                                                                          
    g *= 4503599627370496.0; // 2 ** 52                                    
    f += g;                                                                
    f -= g;                                                                
    return f;                                                            
}                                                                     

在x86_64上,您可以使用此asm语句指示GCC不执行该优化:

static double moo(double f, double g)                                      
{                                                                          
    g *= 4503599627370496.0; // 2 ** 52                                    
    f += g;                                                                
    __asm__("" : "+x" (f));
    f -= g;
    return f;
}

不幸的是,您需要为每个架构调整此选项。在PowerPC上,使用+f代替+x

答案 1 :(得分:2)

很可能因为矢量化意味着您可能会有不同的结果,或者可能意味着您错过了浮点信号/异常。

如果您正在编译32位x86,那么gcc和g ++默认使用x87进行浮点数学计算,在64位时它们默认为sse,但x87可以并且将为相同的计算生成不同的值,因此不太可能如果g ++不能保证你会得到相同的结果,除非你使用-ffast-math或它打开的一些标志,否则g ++会考虑向量化。

基本上归结为浮点环境,矢量化代码可能与非矢量化代码的环境不同,有时候重要的方式,如果差异对你不重要,比如

-fno-math-errno -fno-trapping-math -fno-signaling-nans -fno-rounding-math

但首先要查看这些选项并确保它们不会影响程序的正确性。 -ffinite-math-only也可能有所帮助

答案 2 :(得分:0)

因为-ffast-math启用操作数重新排序,这允许许多代码被矢量化。

例如计算这个

sum = a[0] + a[1] + a[2] + a[3] + a[4] + a[5] + … a[99]

编译器必需在没有-ffast-math的情况下顺序执行 的添加,因为浮点数学既不是可交换的也不是关联的。

why compilers can't optimize a*a*a*a*a*a to (a*a*a)*(a*a*a)没有-ffast-math

的原因相同

这意味着除非你有非常有效的水平向量加法,否则没有矢量化可用。

但是,如果启用-ffast-math,则可以计算表达式like this(查看A7. Auto-Vectorization

sum0 = a[0] + a[4] + a[ 8] + … a[96]
sum1 = a[1] + a[5] + a[ 9] + … a[97]
sum2 = a[2] + a[6] + a[10] + … a[98]
sum3 = a[3] + a[7] + a[11] + … a[99]
sum’ = sum0 + sum1 + sum2 + sum3

现在编译器可以通过并行添加每个列来轻松地向量化它,然后在末尾执行水平添加

  

sum’ == sum吗?只有在(a[0]+a[4]+…) + (a[1]+a[5]+…) + (a[2]+a[6]+…) + ([a[3]+a[7]+…) == a[0] + a[1] + a[2] + …这种情况下,才能保持相关性,浮动不遵守。对于这个简单的计算,指定/fp:fast可让编译器将代码转换为运行速度更快 - 速度提高4倍。

     

Do You Prefer Fast or Precise? - A7。自动矢量

可以通过gcc

中的-fassociative-math标志启用它

进一步阅读