中文
注册

向量化源码修改建议

表1 向量化源码修改建议

向量化建议

无法向量化原因

修改方案

修改样例

提取循环控制变量

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]];                         
     }                                                 
 } 
搜索结果
找到“0”个结果

当前产品无相关内容

未找到相关内容,请尝试其他搜索词