提取循环控制变量
|
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
|
修改方式样例如下:
1
2
3
4
5
6
7
8
9
10
11
12 | 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]];
}
}
|
|