我试图对我的一些代码进行向量化,但我总是遇到info C5002: loop not vectorized due to reason '1305'
。根据this page:
//当编译器无法识别此循环的正确可向量化类型信息时,将发出代码1305。
(Visual Studio Community 2022)
我决定尝试一些非功能性的代码,以更好地理解为什么会发生这种情况,但这个错误似乎出现在应该明显类型化的代码中,并且易于矢量化。这是我的代码:
int vecTest() {
int v0[128] alignas(16);
int v1[128] alignas(16);
int v2[128] alignas(16);
int sum = 0;
for (int i = 0; i < 128; i++) {
v0[i] = i-1;
v1[i] = i*2;
}
for (int i = 0; i < 128; i++) {
v2[i] = v0[i] + v2[i];
}
#ifdef CASE_TWO
int* pv0 = &v0[0];
int* pv1 = &v1[0];
int* pv2 = &v2[0];
for (int i = 0; i < 128; i++) {
pv2[i] = pv0[i] + pv2[i];
}
#endif
sum += v2[0];
return sum;
}
int main(int argc, char* argv[])
{
int sum = vecTest();
sum = sum + 1;
}
字符串
如果CASE_TWO不存在,第一个(初始化)循环将进行向量化,但第二个循环将返回代码1305。然而,添加CASE_TWO的内容会导致所有三个循环都正确进行向量化!此外,包括CASE_TWO代码并排除第二个循环会导致CASE_TWO返回1305。
在我看来,这些循环在矢量化时应该没有问题,它们也不应该相互影响。我错过了什么?
代码1305和“适当的可向量化类型信息”的实际含义是什么,编译器实际上是否按照文档建议的方式运行?
我使用默认的编译器设置,除了/O2
和/Qvec-report:2
。
1条答案
按热度按时间ujv3wf0j1#
如果你看一下asm(在Godbolt上),我们可以看到MSVC将两个循环合并在一起,所以没有单独的init循环。它只是在运行中计算
v0[i]
,添加到未初始化的v2[i]
中(从它分配但从未写入的空间中进行向量加载和存储)。它报告第一个循环被向量化,第二个没有,但实际上它将它们融合到一个asm循环中。这些循环中的工作都被向量化,所以这可以说是它报告中的一个bug。(除了优化掉没有任何东西读取的未使用的
v1[i] = i*2;
。)字符串
相比之下,GCC并不那么聪明,它会为v2和v1分配空间(
sub rsp, 928
加上128字节的红色区域,刚好超过1024 = 2x128 * sizeof(int)
)。MSVC为v2
分配了空间,不是v0
(sub rsp, 536
刚好超过128 * sizeof(int)= 512)。两个编译器都没有为未使用的v1
分配空间,IDK为什么这会让你的例子变得混乱。Clang优化了一切(包括返回值,因为阅读未初始化的
v2[]
在C++中是UB,或者至少是不确定的,所以它可以在EAX中留下任何它想要的垃圾作为返回值)。使用alignas(16) int v2[128] = {};
,clang仍然优化了数组,只是返回-1
。https://godbolt.org/z/E9v1evE94- clang需要标准的alignas(128) int v0[];
语法,不允许alignas
在声明之后。GCC和MSVC允许这样做。对于
v2
的init,MSVC确实为此调用了memset
,但随后仍然进行了相同的单个循环,即动态实现v0[i]
以添加到v2[i]
中。