我试图找到一个合适的材料,清楚地解释了编写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]));
}
任何评论都表示赞赏。
答案 0 :(得分: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]);
}
重要的变化是在呼叫站点。表达式&amp; sums [:]创建一个由&amp; sums [0],&amp; sums [1],&amp; sums [2],...&amp; sums [N-1]组成的数组部分。表达式&amp; A [0:N:N]产生由&amp; A [0 * N],&amp; A [1 * N],&amp; A [2 * N],...&amp; A组成的阵列部分。 A [(N-1)* N]。
我在vector属性中添加了两个线性子句,告诉编译器生成一个针对参数是算术序列的情况优化的克隆,就像在这个例子中一样。对于此示例,它们(和vector属性)是冗余的,因为编译器可以在同一个转换单元中看到被调用者和调用站点,并找出自身的详细信息。但是如果在另一个翻译单元中定义了compute_seq,那么该属性可能会有所帮助。
数组表示法是一项正在进行的工作。 icc 14.0 beta编译了我的英特尔(R)Xeon Phi(TM)的例子而没有任何抱怨。 icc 13.0 update 3报告它无法对该功能进行矢量化(“取消引用太复杂”)。反过来说,关闭vector属性会关闭报告,可能是因为编译器可以在内联后对其进行矢量化。
在编译Intel(R)Xeon Phi(TM)时,我使用编译器选项“-opt-assume-safe-padding”。它可以提高矢量代码质量。它允许编译器假定超出任何访问地址的页面可以安全地触摸,从而启用否则将被禁止的某些指令序列。