#pragma simd和#pragma ivdep指令之间有什么区别?

9

我目前正在尝试将程序向量化,观察到了一种奇怪的行为。

使用以下方式时,for循环会被向量化:

#pragma simd

(262): (col. 3) remark: SIMD LOOP WAS VECTORIZED.

但当我使用以下方式时,它就不会被向量化:

#pragma vector always

#pragma ivdep

(262): (col. 3) remark: loop was not vectorized: existence of vector dependence.

我一直以为这两个句子都是进行相同的向量化。

2个回答

7
#pragma simd是开发人员用来强制执行矢量化的显式矢量化工具,如https://software.intel.com/en-us/node/514582所述,而#pragma vector是一种工具,用于指示编译器基于其参数矢量化循环。这里的参数是always,这意味着“忽略编译器的成本/效率启发式,并继续进行矢量化”。有关#pragma vector的更多信息,请访问https://software.intel.com/en-us/node/514586。这并不意味着#pragma simd会产生错误结果,它成功地将循环矢量化,而#pragma vector always未能矢量化。当#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使用128位的XMM寄存器进行SSE2操作。每个XMM寄存器可以容纳4个浮点数,但是当您尝试容纳一个四个浮点数向量时,会出现向量依赖性。所以#pragma vector总是正确的。但是,如果我们只考虑两个浮点数,就可以将此循环矢量化而不会破坏结果。相同的矢量化报告如下所示:

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真正派上用场的地方。
当使用正确的子句最好地解释了向量计算时,编译器将生成所请求的向量,不会生成错误的结果。Intel(R) Cilk(TM) Plus白皮书发布在https://software.intel.com/sites/default/files/article/402486/intel-cilk-plus-white-paper.pdf中有一节"Usage of $pragma simd vectorlength clause"和"Usage of $pragma simd reduction and private clause",其中讲解了如何使用带有正确子句的pragma simd子句。这些子句帮助开发人员向编译器表达他想要实现的目标,编译器据此生成向量代码。强烈建议在需要最好表达循环逻辑给编译器的地方使用#pragma simd与相关子句。
此外,传统上内部循环是向量化的目标,但pragma simd也可用于向量化外部循环。有关更多信息,请访问https://software.intel.com/en-us/articles/outer-loop-vectorization

7

pragma simd强制循环向量化,无论成本或安全性如何。

pragma vector always告诉编译器在决定是否向量化时忽略效率启发式。仅在添加此pragma时向量化的代码可能会更慢。

pragma ivdep告诉编译器忽略阻止向量化的假定数据依赖关系(例如循环传递的依赖关系),但不忽略已证明的依赖关系。例如,它可能会假定指针没有指向相同的内存并进行向量化。但是,它不会忽略已证明的循环传递依赖关系(a[i] = a[i - 1] * c),但pragma simd可能会忽略。

如果只有pragma simd才能使您的代码向量化,原因可能是已忽略了已证明的依赖关系。您可能需要验证程序输出是否正确。

来源:Intel特定的pragma文档(http://software.intel.com/en-us/node/462880)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接