我目前正在尝试对程序进行矢量化,并且我观察到了一种奇怪的行为
使用
时,似乎for循环被矢量化#pragma simd
(262):(第3栏)评论:SIMD LOOP已被矢量化。
但是当我使用
时它不会#pragma vector始终
#pragma ivdep
(262):( col.3)备注:循环没有矢量化:存在向量依赖性。
我一直以为两个句子都做同样的矢量化
答案 0 :(得分:4)
pragma simd强制执行循环矢量化,无论成本或安全性如何。
pragma vector总是告诉编译器在决定是否进行向量化时忽略效率启发式算法。仅在添加此pragma时进行矢量化的代码可能会更慢。
pragma ivdep告诉编译器忽略禁止向量化的假设数据依赖性(例如循环携带的依赖性),但不是已证实的依赖性。例如,它可能假设指针不指向相同的内存和矢量化。但是,它不会忽略已证明的循环携带依赖性(a [i] = a [i - 1] * c),但是pragma simd可能会。
您的代码可能仅使用编译指示simd进行向量化的原因是已被证实的依赖性被忽略。您可能希望验证程序输出是否正确。
来源:英特尔特定的pragma文档(http://software.intel.com/en-us/node/462880)
答案 1 :(得分:4)
Pragma SIMD是一个显式的矢量化工具,允许开发人员执行https://software.intel.com/en-us/node/514582中提到的矢量化,而pragma vector是一个工具,用于指示编译器应该根据参数对矢量进行矢量化。这里的论点总是意味着“它应该忽略编译器的成本/效率启发式并继续进行矢量化”。有关Pragma向量的更多信息,请访问https://software.intel.com/en-us/node/514586。这并不意味着当编译指示向量总是无法向量化时,编译指示simd将产生错误的结果。当#pragma simd与右边的子句一起使用时,它可以向量化并仍然产生正确的结果。下面是一个小代码片段,演示了:
void foo(float *a, float *b, float *c, int N){
#pragma vector always
#pragma ivdep
//#pragma simd vectorlength(2)
for(int i = 2; i < N; i++)
a[i] = a[i-2] + b[i] + c[i];
return;
}
使用ICC编译此代码将生成以下矢量化报告:
$ icc -c -vec-report2 test11.cc
test11.cc(5): (col. 1) remark: loop was not vectorized: existence of vector dependence
默认情况下,ICC以SSE2为目标,使用128位XMM寄存器。可以在一个XMM寄存器中容纳4个浮点数,但是当您尝试容纳4个浮点数的向量时,存在向量依赖性。那么#pragma vector始终发出的是正确的。但是,如果我们只考虑2个浮点数,而不是4,我们可以在不破坏结果的情况下对此循环进行矢量化。相同的矢量化报告如下所示:
void foo(float *a, float *b, float *c, int N){
//#pragma vector always
//#pragma ivdep
#pragma simd vectorlength(2)
for(int i = 2; i < N; i++)
a[i] = a[i-2] + b[i] + c[i];
return;
}
$ icc -c -vec-report2 test11.cc
test11.cc(5): (col. 1) remark: SIMD LOOP WAS VECTORIZED
但是#pragma vector没有子句可以明确指定在引导循环时要考虑的向量长度。这是pragma simd真的可以派上用场。当与右子句一起使用时,它最能以向量方式解释计算,编译器将生成请求的向量,该向量不会产生错误的结果。在https://software.intel.com/sites/default/files/article/402486/intel-cilk-plus-white-paper.pdf发布的英特尔(R)Cilk(TM)Plus白皮书中有一节“使用$ pragma simd vectorlength子句”和“使用$ pragma simd reduction and private clause”,其中解释了如何使用pragma simd带有权利条款的条款。这些子句帮助开发人员向编译器表达他想要实现的内容,并且编译器相应地生成向量代码。强烈建议在需要的地方使用带有相关子句的#pragma simd来最好地表达编译器的循环逻辑。
传统上,内部循环的目标是矢量化,但是pragma simd也可以用于矢量化外部循环。有关此问题的更多信息,请访问https://software.intel.com/en-us/articles/outer-loop-vectorization。