问题描述
#include <stdlib.h>
int main(int argc,char **argv) {
int *x = malloc(argc*sizeof(int));
for (int i = 0; i < argc; ++i) {
x[i] = argc;
}
int t = 0;
for (int i = 0; i < argc; ++i) {
t += x[i];
}
free(x);
return t;
这个循环
for (int i = 0; i < argc; ++i) {
x[i] = argc;
}
矢量化为
movdqu xmmword ptr [rax + 4*rdx],xmm0
movdqu xmmword ptr [rax + 4*rdx + 16],xmm0
movdqu xmmword ptr [rax + 4*rdx + 32],xmm0
movdqu xmmword ptr [rax + 4*rdx + 48],xmm0
movdqu xmmword ptr [rax + 4*rdx + 64],xmm0
movdqu xmmword ptr [rax + 4*rdx + 80],xmm0
movdqu xmmword ptr [rax + 4*rdx + 96],xmm0
movdqu xmmword ptr [rax + 4*rdx + 112],xmm0
movdqu xmmword ptr [rax + 4*rdx + 128],xmm0
movdqu xmmword ptr [rax + 4*rdx + 144],xmm0
movdqu xmmword ptr [rax + 4*rdx + 160],xmm0
movdqu xmmword ptr [rax + 4*rdx + 176],xmm0
movdqu xmmword ptr [rax + 4*rdx + 192],xmm0
movdqu xmmword ptr [rax + 4*rdx + 208],xmm0
movdqu xmmword ptr [rax + 4*rdx + 224],xmm0
movdqu xmmword ptr [rax + 4*rdx + 240],xmm0
https://godbolt.org/z/33vvonojd
按照我的阅读方式,它在 256 字节的内存块中进行了矢量化。考虑到我的 malloc
大小为 argc*sizeof(int)
没有那么大,这怎么可能?这不会覆盖过去我分配的内存吗?
解决方法
它会运行,这就是为什么它不会用于小型 argc。
在到达那个大的(过于激进的)展开块之前注意所有条件分支,特别是 jmp .LBB0_12
/ cmp ebx,7
的贯穿路径中的 ja .LBB0_4
。
还要注意 .LBB0_10 处的较小循环,它由 2 个向量展开。 (完全没有 16 字节的循环循环,只有 256、32 和标量,这似乎是不明智的,但这就是 clang 所做的。)
有一些逻辑来运行(或不运行)循环的自动向量化版本是 100% 标准的,并且在编译时无法证明循环甚至可以运行一个完整向量时是必要的。您只需找到最大的代码块即可查看大输入可能会发生什么,但如果您想检查正确性,您显然必须考虑哪些循环可能运行 0 次迭代。