相关疑难解决方法(0)

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

我正在对科学应用进行一些数值优化.我注意到的一件事是GCC会pow(a,2)通过编译来优化调用a*a,但调用pow(a,6)没有优化,实际上会调用库函数pow,这会大大降低性能.(相比之下,英特尔C++编译器,可执行文件icc,将消除库调用pow(a,6).)

我很好奇的是,当我更换pow(a,6)a*a*a*a*a*a使用GCC 4.5.1和选项" -O3 -lm -funroll-loops -msse4",它采用5分mulsd的说明:

movapd  %xmm14, %xmm13
mulsd   %xmm14, %xmm13
mulsd   %xmm14, %xmm13
mulsd   %xmm14, %xmm13
mulsd   %xmm14, %xmm13
mulsd   %xmm14, %xmm13
Run Code Online (Sandbox Code Playgroud)

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

movapd  %xmm14, %xmm13
mulsd   %xmm14, %xmm13
mulsd   %xmm14, %xmm13
mulsd   %xmm13, %xmm13
Run Code Online (Sandbox Code Playgroud)

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

为什么编译器不能识别这种优化技巧?

floating-point assembly gcc compiler-optimization fast-math

2083
推荐指数
12
解决办法
20万
查看次数

gcc的ffast-math实际上做了什么?

我理解gcc的--ffast-math标志可以大大提高浮动操作的速度,并超出IEEE标准,但我似乎无法找到有关它正在发生的事情的信息.任何人都可以解释一些细节,并可能给出一个明确的例子,说明如果标志开启或关闭会有什么变化?

我确实尝试过挖掘SO以寻找类似的问题,但却找不到任何解释ffast-math工作原理的东西.

math floating-point performance gcc fast-math

138
推荐指数
2
解决办法
5万
查看次数

C++中的浮点加法是否可交换?

对于浮点值,是否保证a + b == b + a

我相信这在IEEE754中是有保证的,但是C++标准没有规定必须使用IEEE754.唯一相关的文本似乎来自[expr.add]#3:

binary +运算符的结果是操作数的总和.

数学运算"和"是可交换的.然而,数学运算"sum"也是关联的,而浮点加法肯定不是关联的.所以,在我看来,我们不能断定数学中"和"的交换性意味着这个引用指的是C++中的交换性.

c++ floating-point language-lawyer

36
推荐指数
3
解决办法
5705
查看次数

为什么 gcc 在条件乘法的 std::vector<float> 向量化方面比 clang 差得多?

考虑使用以下 float 循环,使用 -O3 -mavx2 -mfma 编译

for (auto i = 0; i < a.size(); ++i) {
    a[i] = (b[i] > c[i]) ? (b[i] * c[i]) : 0;
}
Run Code Online (Sandbox Code Playgroud)

Clang 在矢量化方面做得非常出色。它使用 256 位 ymm 寄存器,并了解 vblendps/vandps 之间的差异,以获得尽可能最佳的性能。

.LBB0_7:
        vcmpltps        ymm2, ymm1, ymm0
        vmulps  ymm0, ymm0, ymm1
        vandps  ymm0, ymm2, ymm0
Run Code Online (Sandbox Code Playgroud)

然而,海湾合作委员会的情况要糟糕得多。由于某种原因,它并没有比 SSE 128 位向量更好(-mprefer-vector-width=256 不会改变任何东西)。

.L6:
        vcomiss xmm0, xmm1
        vmulss  xmm0, xmm0, xmm1
        vmovss  DWORD PTR [rcx+rax*4], xmm0
Run Code Online (Sandbox Code Playgroud)

如果将其替换为普通数组(如指南中所示),gcc 会将其矢量化为 AVX ymm。

int a[256], b[256], c[256];
auto foo …
Run Code Online (Sandbox Code Playgroud)

c++ gcc vectorization avx compiler-optimization

30
推荐指数
2
解决办法
3498
查看次数

C中的浮点运算是关联的吗?

添加在数学上保持关联属性:

(a + b) + c = a + (b + c)
Run Code Online (Sandbox Code Playgroud)

在一般情况下,此属性不适用于浮点数,因为它们表示有限精度的值.

作为优化的一部分,是否允许编译器在从C程序生成机器代码时进行上述替换?它在C标准中的确切位置在哪里?

c math floating-point compiler-optimization

22
推荐指数
2
解决办法
3712
查看次数

浮点加法和乘法是否相关?

当我添加三个浮点值并将它们与1进行比较时,我遇到了问题.

cout << ((0.7 + 0.2 + 0.1)==1)<<endl;     //output is 0
cout << ((0.7 + 0.1 + 0.2)==1)<<endl;     //output is 1
Run Code Online (Sandbox Code Playgroud)

为什么这些价值观会有所不同?

c++ floating-point

10
推荐指数
3
解决办法
5310
查看次数

矢量化:什么时候值得手动展开循环?

我想大致了解何时可以期望编译器对循环进行矢量化,以及何时值得我展开循环以帮助它决定使用矢量化。

我知道细节非常重要(什么编译器,什么编译选项,什么架构,如何在循环中编写代码等),但我想知道是否有一些针对现代编译器的通用指南。

我将更具体地给出一个简单循环的示例(代码不应该计算任何有用的东西):

    double *A,*B; // two arrays
    int delay = something
    [...]


    double numer = 0, denomB = 0, denomA = 0;
    for (int idxA = 0; idxA < Asize; idxA++)
    {
        int idxB = idxA + (Bsize-Asize)/2 + delay;
        numer  += A[idxA] * B[idxB];
        denomA += A[idxA] * A[idxA];
        denomB += B[idxB] * B[idxB];
    }
Run Code Online (Sandbox Code Playgroud)

我可以期望编译器对循环进行矢量化吗?或者重写如下代码是否有用?

    for ( int idxA = 0; idxA < Asize; idxA+=4 )
    {
        int idxB = idxA + (Bsize-Asize)/2 …
Run Code Online (Sandbox Code Playgroud)

c c++ vectorization loop-unrolling

5
推荐指数
1
解决办法
1072
查看次数

矩阵/向量运算的GCC优化标志

我正在使用C执行矩阵运算.我想知道什么是各种编译器优化标志,以提高双和int64数据的这些矩阵运算的执行速度 - 如乘法,反向等.我不是在寻找手动优化的代码,我只想使用编译器标志更快地生成本机代码,并了解有关这些标志的更多信息.

到目前为止我发现的标志改进了矩阵码.

-O3/O4
-funroll-loops
-ffast-math
Run Code Online (Sandbox Code Playgroud)

optimization gcc matrix linear-algebra compiler-flags

4
推荐指数
1
解决办法
5313
查看次数