当我在ICC中使用-opt report或-vec report选项编译给定文件时,我会收到以下消息:
foo.c(226:7-226:7):VEC:function_foo: loop was not vectorized: subscript too complex
foo.c(226): (col. 7) warning #13379: loop was not vectorized with "simd"
vectorization support: call to function absorbing_apply cannot be vectorized
loop was not vectorized: not inner loop
loop was not vectorized: unsupported loop structure
loop was not vectorized: subscript too complex
我知道这些信息的含义。我担心的是,在foo.c:226
中根本没有任何循环。事实上,存在的是对另一个函数的调用。该函数确实包含一些循环,这些循环通过卷进行操作,并且在icc报告它时确实正确地向量化了。然而,对该函数的所有调用都给出了与我粘贴的消息相同的消息。
icc会不会因为在完全没有循环的地方显示矢量化消息而陷入混乱?或者是我误解了什么?
编辑:我已经半复制了这个问题。这一次,编译器告诉,它对一行代码进行了向量化,其中有对另一个函数的调用(在最初的情况下,只是相反,它说不能)。这是代码:
1
2
3 void foo(float *a, float *b, float *c, int n1, int n2, int n3, int ini3, int end3 ) {
4 int i, j, k;
5
6 for( i = ini3; i < end3; i++ ) {
7 for( j = 0; j < n2; j++ ) {
8 #pragma simd
9 #pragma ivdep
10 for( k = 0; k < 4; k ++ ) {
11 int index = k + j*n1 + i*n1*n2;
12 a[index] = b[index] + 2* c[index];
13 }
14 }
15 }
16
17 for( i = ini3; i < end3; i++ ) {
18 for( j = 0; j < n2; j++ ) {
19 #pragma simd
20 #pragma ivdep
21 for( k = n1-4; k < n1; k ++ ) {
22 int index = k + j*n1 + i*n1*n2;
23 a[index] = b[index] + 2* c[index];
24 }
25 }
26 }
27
28 return;
29 }
30 int main(void){
31 int n1, n2, n3;
32 int ini3 = 20;
33 int end3 = 30;
34 n1 = n2 = n3 = 200;
35
36 float *a = malloc( n1 * n2 * n3 * sizeof(float ));
37 float *b = malloc( n1 * n2 * n3 * sizeof(float ));
38 float *c = malloc( n1 * n2 * n3 * sizeof(float ));
39
40 foo( a,b,c, n1, n2, n3, ini3, end3 );
41
42 ini3 += 50;
43 end3 += 50;
44
45 foo( a,b,c, n1, n2, n3, ini3, end3 );
46
47 free(a); free(b); free(c);
48
49 return 0;
50 }
51
在优化报告中,ICC称其对第40行和第45行进行了矢量化:
foo.c(40:4-40:4):VEC:main: LOOP WAS VECTORIZED
loop was not vectorized: not inner loop
loop was not vectorized: not inner loop
LOOP WAS VECTORIZED
loop was not vectorized: not inner loop
loop was not vectorized: not inner loop
foo.c(45:4-45:4):VEC:main: LOOP WAS VECTORIZED
loop was not vectorized: not inner loop
loop was not vectorized: not inner loop
这正常吗?
在您发布的示例中,对foo()
的函数调用是内联的。foo()
中的循环在内联之后被矢量化。
结果是,所有的代码都被"折叠"到第40行和第45行。当vectorzor接触到代码时,它不知道它最初来自不同的函数。
在最初的例子中,你说它没有矢量化,同样的情况也适用。函数调用是内联的,但它包含不可向量化的循环。
也许,ICC可以通过函数调用保留线路信息。但是,每次内联函数时,都会得到一个重复的矢量化报告。此外,它们都指向同一条线。这可能会更加令人困惑。
一个简单的编码提示-不要使用像这样的结构
for( i = ini3; i < end3; i++ ) {
for( j = 0; j < n2; j++ ) {
#pragma simd
#pragma ivdep
for( k = 0; k < 4; k ++ ) {
int index = k + j*n1 + i*n1*n2;
a[index] = b[index] + 2* c[index];
}
}
}
您可能很清楚,在最内部循环的每次迭代中,index
都会以1
的步长递增,但编译器矢量器可能很难弄清楚这一点。更好的用途:
for( i = ini3; i < end3; i++ ) {
for( j = 0; j < n2; j++ ) {
int base = (j + i*n2)*n1;
for( k = base; k < base+4; k++ ) {
a[k] = b[k] + 2* c[k];
}
}
}
现在很明显发生了什么,即使是最愚蠢的矢量器也应该能够弄清楚(代码看起来更干净)。与其使用#pragma ivdep
,不如使用C99restrict
限定符向编译器保证a
、b
和c
指向不重叠的内存区域
void foo(float *restrict a, float *restrict b, float *restrict c,
int n1, int n2, int n3, int ini3, int end3) {