gpt4 book ai didi

gcc 4.8 AVX 优化错误 : extra code insertion?

转载 作者:行者123 更新时间:2023-12-03 17:16:43 24 4
gpt4 key购买 nike

gcc 编译器 4.8 附带带有 -Ofast 选项的 AVX 优化,这真是太棒了。然而,我发现了一个有趣但愚蠢的错误,它增加了不必要的额外计算。也许我错了,有人可以给我解释吗?

原始C++源代码如下:

#define N 1000007

float a[N],b[N],c[N],d[N],e[N];

int main(int argc, char *argv[]){
cout << a << ' ' << b << ' ' << c << endl;
for(int x=0; x<N; ++x){
c[x] = 1/sqrt((a[x]+b[x]-c[x])*d[x]/e[x]);
}
return 0;
}

代码在 Ubuntu 14.04.3 x86_64 中使用 g++ 4.8.4 编译:g++ -mavx avx.cpp -masm=intel -c -g -Wa,-ahl=avx.asm -Ofast

汇编源代码如下:

  90                    .LVL10:
91 006b C5FC2825 vmovaps ymm4, YMMWORD PTR .LC0[rip]
91 00000000
92 0073 31C0 xor eax, eax
93 0075 C5FC281D vmovaps ymm3, YMMWORD PTR .LC1[rip]
25:avx.cpp **** for(int x=0; x<N; ++x){
26:avx.cpp **** c[x] = 1/sqrt((a[x]+b[x]-c[x])*d[x]/e[x]);
101 .loc 1 26 0 discriminator 2
102 0080 C5FC2890 vmovaps ymm2, YMMWORD PTR b[rax]
102 00000000
103 0088 4883C020 add rax, 32
104 008c C5FC2888 vmovaps ymm1, YMMWORD PTR e[rax-32]
104 00000000
105 0094 C5EC5890 vaddps ymm2, ymm2, YMMWORD PTR a[rax-32]
105 00000000
106 009c C5FC53C1 vrcpps ymm0, ymm1
107 00a0 C5FC59C9 vmulps ymm1, ymm0, ymm1
108 00a4 C5FC59C9 vmulps ymm1, ymm0, ymm1
109 00a8 C5EC5C90 vsubps ymm2, ymm2, YMMWORD PTR c[rax-32]
109 00000000
110 00b0 C5FC58C0 vaddps ymm0, ymm0, ymm0
111 00b4 C5EC5990 vmulps ymm2, ymm2, YMMWORD PTR d[rax-32]
111 00000000
112 00bc C5FC5CC9 vsubps ymm1, ymm0, ymm1
113 00c0 C5EC59C1 vmulps ymm0, ymm2, ymm1
118 00c4 C5FC52C8 vrsqrtps ymm1, ymm0
119 00c8 C5F459C0 vmulps ymm0, ymm1, ymm0
120 00cc C5FC59C1 vmulps ymm0, ymm0, ymm1
121 00d0 C5F459CB vmulps ymm1, ymm1, ymm3
122 00d4 C5FC58C4 vaddps ymm0, ymm0, ymm4
^LGAS LISTING /tmp/ccJtIFtg.s page 21


123 00d8 C5FC59C9 vmulps ymm1, ymm0, ymm1
124 .LBE45:
125 .LBE44:
126 .loc 1 26 0 discriminator 2
127 00dc C5FC2988 vmovaps YMMWORD PTR c[rax-32], ymm1
127 00000000
128 00e4 483D0009 cmp rax, 4000000
128 3D00
129 00ea 7594 jne .L3

现在看第 106、107、108、110、112 和 113 行。

编译器使用 e[x] 的逆乘法来计算除法。因此第 106 行计算出 1/e[x],这是正确的。之后,它可以直接将其与 (a[x]+b[x]-c[x])*d[x] 的最终乘积相乘,该乘积存储在 ymm2 第 111 行中。但是,不这样做,编译器做了一些有趣而荒谬的事情:

  1. 它首先将计算出的倒数 1/e[x] 与 e[x] 相乘,得到获取 1(第 107 行)

  2. 然后将此 1 与 1/e[x] 相乘,得到 1/e[x](第 108 行)

  3. 然后将 1/e[x] 与自身相加,得到 2/e[x](第 110 行)

  4. 然后用 1/e[x] 减去 2/e[x] 得到 1/e[x](第 112 行)

之后,编译器巧妙地使用vrsqrtps指令来计算1/sqrt()。然而,在那之后,会发生什么呢?它没有提取 ymm1 中的输出(第 118 行),而是再次做了一些更奇特的事情:

  1. 它首先将 1/sqrt(x) 乘以 x 以获得 sqrt(x),(第 119 行)

  2. 然后将 sqrt(x) 乘以 1/sqrt(x) 以获得 1,(第 120 行)

  3. 然后将 1/sqrt(x) 乘以 1(预先存储在 ymm3 中)以获得相同的 1/sqrt(x)(第 121 行)

  4. 然后将获得的 1 加 0(预先存储在 ymm4 中)以获得 1,(第 122 行)

  5. 然后将 1/sqrt(x) 与获得的 1 相乘,得到相同的 1/sqrt(x)(第 123 行)

以上两个冗余表明,每当需要 1/x 时,编译器倾向于将已获得的输出与原始数字相乘以获得回 1,然后将此 1 与已获得的输出相乘以获得相同的输出。这样做有什么理由吗?或者这只是一个错误?

最佳答案

我认为您在生成的代码中看到的是 Newton-Raphson 的附加迭代完善由 vrcpps 提供的初始估计。 (有关 vrcpps 提供的初始估计准确度的详细信息,请参阅 Intel Intrinsics Guide。)

关于gcc 4.8 AVX 优化错误 : extra code insertion?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34585770/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com