我被自动矢量化结果搞糊涂了。以下代码addtest.c
#include <stdio.h>
#include <stdlib.h>
#define ELEMS 1024
int
main()
{
float data1[ELEMS], data2[ELEMS];
for (int i = 0; i < ELEMS; i++) {
data1[i] = drand48();
data2[i] = drand48();
}
for (int i = 0; i < ELEMS; i++)
data1[i] += data2[i];
printf("%g\n", data1[ELEMS-1]);
return 0;
}是用gcc 11.1.0编译的
gcc-11 -O3 -march=haswell -masm=intel -save-temps -o addtest addtest.c而加法循环被自动矢量化为
.L3:
vmovaps ymm1, YMMWORD PTR [r12]
vaddps ymm0, ymm1, YMMWORD PTR [rax]
add r12, 32
add rax, 32
vmovaps YMMWORD PTR -32[r12], ymm0
cmp r12, r13
jne .L3这一点很清楚:从data1加载,从data2加载和添加,存储到data1,在中间提前索引。
如果我将相同的代码传递给https://godbolt.org,选择x86-64 gcc-11.1和options -O3 -march=haswell,我将得到以下汇编代码:
.L3:
vmovaps ymm1, YMMWORD PTR [rbp-4112+rax]
vaddps ymm0, ymm1, YMMWORD PTR [rbp-8208+rax]
vmovaps YMMWORD PTR [rbp-8240], ymm1
vmovaps YMMWORD PTR [rbp-8208+rax], ymm0
add rax, 32
cmp rax, 4096
jne .L3一个令人惊讶的事情是不同的地址处理,但让我完全困惑的是[rbp-8240]的附加存储。据我所知,这个位置再也不用了。
如果我选择了gcc 7.5,多余的商店消失了(但从8.1以上,它就产生了)。
所以我的问题是:
非常感谢你的帮助!
发布于 2022-04-14 02:17:01
差异制造者是-fpie**,,默认情况下,大多数发行版都是,而不是哥德波特。**这没有多大意义,但编译器是复杂的机器,不是“智能”的。
它也不特定于-march=haswell或AVX;同样的区别只发生在-O3上。
与发行版相比,天栓为GCC配置了比发行版更简单的选项,例如,没有默认饼,也没有-fstack-protector-strong。若要在本地匹配“天栓”,请至少使用-fno-pie -no-pie -fno-stack-protector。也许还有其他我忘了的。
IDK为什么这会触发或避免漏掉的优化,但我可以确认它是在我的Arch /Linux系统上使用GCC 11.1实现的。
带gcc -O3 -march=haswell -fno-stack-protector -fno-pie的局部
(和-masm=intel -S -o- vec.c | less)它与哥德波特相匹配:
.L3:
vmovaps ymm1, YMMWORD PTR [rbp-4112+rax]
vaddps ymm0, ymm1, YMMWORD PTR [rbp-8208+rax]
vmovaps YMMWORD PTR [rbp-8240], ymm1
vmovaps YMMWORD PTR [rbp-8208+rax], ymm0
add rax, 32
cmp rax, 4096
jne .L3但是使用-O3 -march=haswell中配置发行版的GCC默认设置
.L3:
vmovaps ymm1, YMMWORD PTR [r12]
vaddps ymm0, ymm1, YMMWORD PTR [rax]
add r12, 32
add rax, 32
vmovaps YMMWORD PTR -32[r12], ymm0
cmp r12, r13
jne .L3在没有-march=haswell的情况下,也会发生同样的丢失-opt;我们在循环中将movaps XMMWORD PTR [rsp], xmm1存储到一个固定地址。(由于GCC不需要对齐堆栈来溢出32字节的向量,所以它没有使用RBP作为帧指针。)
没有明显的原因,使用-fpie 关于戈德波特编译器浏览器 的让GCC使用两个指针增量,而不是索引寻址模式,同时也避免了冗余存储。(在本地制作相同的asm )。-fpie强迫GCC对静态存储中的数组执行此操作(因为[arr + rax]将要求符号地址作为32位绝对值:在x86-64 Linux中不再允许32位绝对地址?)。
您可以并且应该在 GCC的布奇拉 上使用关键字“错过优化”.报告这一点。
https://stackoverflow.com/questions/71858658
复制相似问题