向量化源码修改建议
向量化建议 |
无法向量化原因 |
修改方案 |
修改样例 |
---|---|---|---|
提取循环控制变量 |
for循环的循环控制变量为结构体的成员,编译器无法确定循环结束条件,导致无法自动向量化循环。 |
将循环控制变量提取到循环外。 |
代码样例如下: for (i = 0; i < data->len; i++) { vecC[i] = vecA[i] + vecB[i]; } 修改方式样例如下: int len = data->len; // 将循环控制变量提取到循环外. for (i = 0; i < len; i++) { vecC[i] = vecA[i] + vecB[i]; |
修改循环控制条件 |
clang 15支持向量化,clang 15版本以下无法支持自动向量化实现。 |
循环条件从<=改成<,循环长度从len改成len+1。 |
代码样例如下: for (i = 0; i <= data->len; i++) { vecC[i] = vecA[i] + vecB[i]; } 修改方式样例如下: // 循环条件从"<="改成"<",循环长度从len改成len+1 for (i = 0; i < data->len + 1; i++) { vecC[i] = vecA[i] + vecB[i]; } |
增加自动向量化编译指示 |
编译器评估向量化收益后采用保守策略,不进行自动向量化。 |
添加pragma编译指示强行对代码进行自动向量化。 |
代码样例如下: for (i = 0; i < data->len; i++) { vecC[i] = vecA[i] + vecB[i]; } 修改方式样例如下: // 添加pragma编译指示强行对代码进行自动向量化 #pragma clang loop vectorize(enable) for (i = 0; i < data->len; i++) { vecC[i] = vecA[i] + vecB[i]; } |
明确指针指向的内存不会被其他指针引用 |
无法确定指针指向的内存是否被其他指针引用,编译器将放弃自动向量化。 |
添加restrict关键字修饰指针变量。 |
代码样例如下: void func(int *A, struct Data *data) { data->a = A[0]; data->b = A[1]; } 修改方式样例如下: // Add restrict to the argument <A>. void func(int *restrict A, struct Data *data) { data->a = A[0]; data->b = A[1]; } |
保持数据类型长度一致 |
类型不匹配,编译器无法进行自动向量化。 |
改变变量的类型,从long型变为int型。 |
代码样例如下: void func(int *vec) { long b = 1; int i; for (i = 0; i < 64; i++) { vec[i] = (b << i); } } 修改方式样例如下: void func(int *vec) { // 改变变量的类型,从long型变为int型 int b = 1; int i; for (i = 0; i < 64; i++) { vec[i] = (b << i); } } |
循环拆分 |
循环中的运算左值空间为固定空间,存在循环依赖关系,编译器无法进行向量化。 |
拆分循环,将每一轮循环运算左值独立存储再归并。 |
代码样例如下: for( int i = 0; i < 4; i++ ) { ...... sum += a0 + a1 + a2 + a3; } 修改方式样例如下: // Declare an array, // and assign element in each iteration, // and finally accumulate elements in the array. uint32_t sumTmp[4]; for( int i = 0; i < 4; i++ ) { ...... sumTmp[i] = a0 + a1 + a2 + a3; } sum = sumTmp[0] + sumTmp[1] + sumTmp[2] + sumTmp[3]; |
简化条件分支内的代码逻辑 |
在条件分支语句中存在较复杂的运算,导致无法自动向量化。 |
将运算语句提取到条件分支之外。 |
代码样例如下: for( int i = 0; i < len; i++ ) { if (flag[i]) vecC[i] = vecA[i] + vecB[i]; else vecC[i] = vecA[i] - vecB[i]; sum += vecC[i]; } 修改方式样例如下: for( int i = 0; i < len; i++ ) { // Extract all expressions outside the branch. int ifTrue = vecA[i] + vecB[i]; int ifFalse = vecA[i] - vecB[i]; if (flag[i]) vecC[i] = ifTrue; else vecC[i] = ifFalse; sum += vecC[i]; } |
数据类型改为无符号类型 |
数据类型不一致,编译器无法向量化。 |
改变数据的类型,从signed型变为unsigned型。 |
代码样例如下: int sum; for( int i = 0; i < len; i++ ){ b0 = abs2(a0 + a4) + abs2(a0 - a4); sum += (uint16_t)b0; } return sum; 修改方式样例如下: "// Change the type of <sum> from signed to unsigned. unsigned int sum; for( int i = 0; i < len; i++ ){ b0 = abs2(a0 + a4) + abs2(a0 - a4); sum += (uint16_t)b0; } return sum; |
降低计算精度 |
计算精度高,编译器为保障计算精度不进行自动向量化。 |
降低计算结果的精度。 |
代码样例如下: DO K = 1,KM veC(k)= (vecA(K) + vecB(K + 1))*0.5D0 END DO 修改方式样例如下: DO K = 1,KM veC(k)= (vecA(K) + vecB(K + 1))*0.5 END DO |
循环拆分 |
循环内的语句较多,编译器无法判断变量的依赖关系,不进行向量化。 |
将循环内容的多个语句拆分到多个循环中。 |
代码样例如下: DO A = 1,AM DO K = 1,KM DO J = 3,JMT DO I = 3,IMT V1 (I,J,K,A)= V2 (I,J,K,A) + V3 (I,J,K,A)* D U1 (I,J,K,A)= U2 (I,J,K,A) + U3 (I,J,K,A)* D END DO END DO END DO END DO 修改方式样例如下: DO A = 1,N DO K = 1,KM DO J = 3,JMT DO I = 3,IMT V1 (I,J,K,A)= V2 (I,J,K,A) + V3 (I,J,K,A)* D END DO DO I = 3,IMT U1 (I,J,K,A)= U2 (I,J,K,A) + U3 (I,J,K,A)* D END DO END DO END DO END DO |
减少循环内的函数调用 |
循环内的存在函数调用,编译器无法进行向量化。 |
将函数调用相关的计算提取到循环外。 |
代码样例如下: for( int i = 0; i < len; i++ ) { delta = -0.5 + (2*m+1)/(2.0*n); vecA[k].dx = delta*length*cos(theta); vecA[k].dy = delta*length*sin(theta); k++; } 修改方式样例如下: // Extract math lib call outside the loop. double cosNum = cos(theta); double sinNum = sin(theta); for( int i = 0; i < len; i++ ) { delta = -0.5 + (2*m+1)/(2.0*n); vecA[k].dx = delta*length*cosNum; vecA[k].dy = delta*length*sinNum; k++; } |
利用Fortran关键字 |
未充分利用fortran语言特性。 |
使用数组赋值代替循环来实现多个数据的操作。 |
代码样例如下: do i = 1, maxI type1%array1(i)=array3(type1%array2(i)) enddo 修改方式样例如下: type1%array1=array3(type1%array2) |
明确指针指向的内存不会被其他指针引用,同时增加编译标识 |
无法确定指针指向的内存是否被其他指针引用,编译器将放弃自动向量化。 |
添加restrict关键字修饰指针变量。 |
代码样例如下: for (int i=0;i<len;++i) { a[i] = b[index[i]]; } 修改方式样例如下: void func(int *a, int *__restrict__ b, int *index, int len) { #pragma clang loop vectorize(enable) for (int i=0;i<len;++i) { a[i] = b[index[i]]; } } |