这个矢量化代码如何不覆盖内存?
How does this vectorized code not overwrite memory?
接受这个代码。
#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。
注意所有条件 b运行 在到达那个大的(过度激进的)展开块之前的所有条件,特别是 jmp .LBB0_12
在 cmp ebx, 7
/ [=12= 的下降路径中].
另请注意 .LBB0_10 处的较小循环,它由 2 个向量展开。 (根本没有 16 字节的汇总循环似乎是不明智的,只有 256、32 和标量,但这就是 clang 所做的。)
有一些逻辑运行(或没有)循环的自动矢量化版本是 100% 标准的,并且当在编译时无法证明循环甚至 运行 为一个完整的向量。找到最大的代码块是您需要做的所有事情,以查看 large 输入可能会发生什么,但是如果您想检查正确性,您显然必须考虑哪些循环可能 运行 0 次迭代。
接受这个代码。
#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。
注意所有条件 b运行 在到达那个大的(过度激进的)展开块之前的所有条件,特别是 jmp .LBB0_12
在 cmp ebx, 7
/ [=12= 的下降路径中].
另请注意 .LBB0_10 处的较小循环,它由 2 个向量展开。 (根本没有 16 字节的汇总循环似乎是不明智的,只有 256、32 和标量,但这就是 clang 所做的。)
有一些逻辑运行(或没有)循环的自动矢量化版本是 100% 标准的,并且当在编译时无法证明循环甚至 运行 为一个完整的向量。找到最大的代码块是您需要做的所有事情,以查看 large 输入可能会发生什么,但是如果您想检查正确性,您显然必须考虑哪些循环可能 运行 0 次迭代。