相关疑难解决方法(0)

std::min 的参数顺序更改浮点的编译器输出

我在编译器资源管理器中摆弄,我发现传递给 std::min 的参数顺序改变了发出的程序集。

这是 Godbolt Compiler Explorer 上的示例

double std_min_xy(double x, double y) {
    return std::min(x, y);
}

double std_min_yx(double x, double y) {
    return std::min(y, x);
}
Run Code Online (Sandbox Code Playgroud)

这被编译(例如,在 clang 9.0.0 上使用 -O3):

std_min_xy(double, double):                       # @std_min_xy(double, double)
        minsd   xmm1, xmm0
        movapd  xmm0, xmm1
        ret
std_min_yx(double, double):                       # @std_min_yx(double, double)
        minsd   xmm0, xmm1
        ret
Run Code Online (Sandbox Code Playgroud)

如果我将 std::min 更改为老式三元运算符,这种情况仍然存在。它也适用于我尝试过的所有现代编译器(clang、gcc、icc)。

底层指令是minsd. 阅读文档,第一个参数minsd也是答案的目的地。显然 xmm0 是我的函数应该放置其返回值的地方,所以如果 xmm0 用作第一个参数,则movapd不需要。但是如果 xmm0 是第二个参数,那么它必须movapd xmm0, xmm1将值放入 xmm0。(编者注:是的,x86-64 System V在 …

c++ floating-point x86 assembly android

75
推荐指数
3
解决办法
2771
查看次数

比较 Fortran 和 C++ 汇编程序的 int = floor(sqrt(...))

我在 Fortran 和 C++ 中分别实现了一个函数:

#include <math.h>

void dbl_sqrt_c(double *x, double *y){
   *y = sqrt(*x - 1.0);
   return;
}
Run Code Online (Sandbox Code Playgroud)
pure subroutine my_dbl_sqrt(x,y) bind(c, name="dbl_sqrt_fort")
   USE, INTRINSIC :: ISO_C_BINDING
   implicit none
   real(kind=c_double), intent(in)  :: x
   real(kind=c_double), intent(out) :: y

   y = sqrt(x - 1d0)
end subroutine my_dbl_sqrt
Run Code Online (Sandbox Code Playgroud)

我在编译器资源管理器中比较了它们:

Fortran:https : //godbolt.org/z/froz4rx97
C++:https : //godbolt.org/z/45aex99Yz

我阅读汇编程序的方式,它们基本上做相同的事情,但是 C++ 检查 sqrt 的参数是否为负,而 Fortran 则没有。我使用 googles 基准比较了它们的性能,但它们非常匹配:

--------------------------------------------------------
Benchmark              Time             CPU   Iterations
--------------------------------------------------------
bm_dbl_c/8          2.07 ns         2.07 ns    335965892
bm_dbl_fort/8       2.06 ns         2.06 …
Run Code Online (Sandbox Code Playgroud)

c++ performance assembly x86-64

40
推荐指数
2
解决办法
2462
查看次数

为什么 gcc 在条件乘法的 std::vector&lt;float&gt; 向量化方面比 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
查看次数

哪些函数受 -fno-math-errno 影响?

我对这篇文章感到兴奋:/sf/answers/4037224201/,我考虑使用-fno-math-errno. 但我想确保我不会损害我正在开发的软件的行为。

因此,我检查了(相当大的)代码库以查看errno正在使用的位置,并且我想确定这些用法是否会干扰-fno-math-errno. 但如何做到这一点呢?文档说:

-fno-数学错误号

在调用使用单条指令执行的数学函数(例如 sqrt...)后,请勿设置 errno

但我如何知道单条指令执行了哪些数学函数呢?这有记录在某处吗?在哪里?

似乎我使用的代码库errno特别依赖于调用strtol和使用流时。我猜这strtol不是用一条指令执行的。它是否被认为是一个数学函数?我怎样才能确定?

c++ gcc errno compiler-optimization math-functions

9
推荐指数
1
解决办法
901
查看次数

__builtin_unreachable有哪些优化方便?

从gcc的文档来看

如果控制流程到达该点__builtin_unreachable,则程序未定义.

我认为__builtin_unreachable可以用各种创造性的方式暗示优化器.所以我做了一个小实验

void stdswap(int& x, int& y)
{
    std::swap(x, y);
}

void brswap(int& x, int& y)
{
    if(&x == &y)
        __builtin_unreachable();
    x ^= y;
    y ^= x;
    x ^= y;
}

void rswap(int& __restrict x, int& __restrict y)
{
    x ^= y;
    y ^= x;
    x ^= y;
}
Run Code Online (Sandbox Code Playgroud)

被编译为(g ++ -O2)

stdswap(int&, int&):
        mov     eax, DWORD PTR [rdi]
        mov     edx, DWORD PTR [rsi]
        mov     DWORD PTR [rdi], edx
        mov     DWORD PTR [rsi], eax …
Run Code Online (Sandbox Code Playgroud)

c++ optimization gcc

6
推荐指数
1
解决办法
489
查看次数

为什么即使sqrt脱离领域争论也无法将errno设置为EDOM?

Windows中sqrt()函数的域错误未将errno设置为EDOM,在Linux上正确显示,但在Windows上失败(使用GCC 7.4)...

#include <stdio.h>
#include <errno.h>
#include <math.h>

int main () {
double val;

errno = 0;
val = sqrt(-10);

if(errno == EDOM) {
printf("Invalid value \n");
} else {
printf("Valid value\n");
} 

errno = 0;
val = sqrt(10);

if(errno == EDOM) {
printf("Invalid value\n");
} else {
printf("Valid value\n");
}

return(0);
}
Run Code Online (Sandbox Code Playgroud)

预期结果:无效值有效值实际结果:有效值有效值

c errno

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

SIMD for float threshold operation

I would like to make some vector computation faster, and I believe that SIMD instructions for float comparison and manipulation could help, here is the operation:

void func(const double* left, const double* right, double* res, const size_t size, const double th, const double drop) {
        for (size_t i = 0; i < size; ++i) {
            res[i] = right[i] >= th ? left[i] : (left[i] - drop) ;
        }
    }
Run Code Online (Sandbox Code Playgroud)

Mainly, it drops the left value by drop in case right …

c++ double sse simd vectorization

3
推荐指数
1
解决办法
280
查看次数

与-O3相比,gcc -Ofast的汇编代码中计算不精确的来源在哪里?

以下 3 行使用"gcc -Ofast -march=skylake"给出不精确的结果:

int32_t  i = -5;
const double  sqr_N_min_1 = (double)i * i;
1. - ((double)i * i) / sqr_N_min_1
Run Code Online (Sandbox Code Playgroud)

显然,第三行中的sqr_N_min_1gets25.(-5 * -5) / 25应该变为 ,1.因此第三行的整体结果正好是0.。事实上,这对于编译器选项"gcc -O3 -march=skylake"是正确的。

但是使用“-Ofast”,最后一行产生-2.081668e-17而不是0.i除了-5(例如67)之外的其他非常小的正或负随机偏差0.。我的问题是:这种不精确的根源究竟在哪里?

为了调查这个,我用 C 写了一个小测试程序:

#include <stdint.h>      /* int32_t */
#include <stdio.h>
#define MAX_SIZE 10

double W[MAX_SIZE];

int main( …
Run Code Online (Sandbox Code Playgroud)

c assembly gcc x86-64 fast-math

2
推荐指数
1
解决办法
124
查看次数