我试图找到一种合适的 Material 来清楚地解释编写 C/C++ 源代码的不同方法,这些源代码可以由英特尔编译器使用数组表示法和初等函数进行矢量化。所有在线资料都采用简单的示例:saxpy、reduction 等。但缺乏对如何向量化具有条件分支或包含循环依赖性循环的代码的解释。
举个例子:假设有一个顺序代码我想用不同的数组运行。矩阵以主行格式存储。矩阵的列由 compute_seq() 函数计算:
#define N 256
#define STRIDE 256
__attribute__((vector))
inline void compute_seq(float *sum, float* a) {
int i;
*sum = 0.0f;
for(i=0; i<N; i++)
*sum += a[i*STRIDE];
}
int main() {
// Initialize
float *A = malloc(N*N*sizeof(float));
float sums[N];
// The following line is not going to be valid, but I would like to do somthing like this:
compute_seq(sums[:],*(A[0:N:1]));
}
任何评论表示赞赏。
最佳答案
这是该示例的更正版本。
__attribute__((vector(linear(sum),linear(a))))
inline void compute_seq(float *sum, float* a) {
int i;
*sum = 0.0f;
for(i=0; i<N; i++)
*sum += a[i*STRIDE];
}
int main() {
// Initialize
float *A = malloc(N*N*sizeof(float));
float sums[N];
compute_seq(&sums[:],&A[0:N:N]);
}
重要的变化是在调用站点。表达式 &sums[:] 创建一个数组部分,其中包含 &sums[0]、&sums[1]、&sums[2]、...&sums[N-1]。表达式 &A[0:N:N] 创建一个数组部分,其中包含 &A[0*N]、&A[1*N]、&A[2*N]、...&A[(N-1)*N] .
我向 vector 属性添加了两个线性子句,以告诉编译器生成针对参数为算术序列的情况优化的克隆,如本例中所示。对于这个例子,它们(和 vector 属性)是多余的,因为编译器可以在同一个翻译单元中看到被调用者和调用点,并自己找出细节。但是,如果在另一个翻译单元中定义了 compute_seq,则该属性可能会有所帮助。
数组符号是一项正在进行的工作。 icc 14.0 beta 毫无怨言地为 Intel(R) Xeon Phi(TM) 编译了我的示例。 icc 13.0 update 3 报告它无法向量化函数(“取消引用太复杂”)。相反,关闭 vector 属性会使报告关闭,可能是因为编译器可以在内联后对其进行矢量化。
我在为 Intel(R) Xeon Phi(TM) 编译时使用编译器选项“-opt-assume-safe-padding”。它可以提高 vector 代码质量。它让编译器假设超出任何访问地址的页面可以安全触摸,从而启用某些原本不允许的指令序列。
关于c - 英特尔数组符号和初等函数是否可以通过至强融核 ISA 很好地矢量化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18163179/