---
title: 向量化源码修改建议
description: "**表1 向量化源码修改建议**"
url: https://www.hikunpeng.com/document/detail/zh/kunpengdevkithistory/devkit_24/usermanual/DevKit_Affinity_0021.html
sourcePath: /source/zh/kunpengdevkithistory/devkit_24/usermanual/DevKit_Affinity_0021.html
indexId: 8d0f8228b1e29afe31895e0429afbbf203f156ffed329680713d77508093935b78
---
# 向量化源码修改建议


**表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]]; } } |
