如何克服icc中的“存在向量依赖”
Posted
技术标签:
【中文标题】如何克服icc中的“存在向量依赖”【英文标题】:How to overcome "existence of vector dependence" in icc 【发布时间】:2013-07-26 05:12:42 【问题描述】:我想在 C 中矢量化以下循环:
for(k = 0; k < SysData->numOfClaGen; k++)
A[k] = B[k] * cos(x1[2 * k] - x1[ind0 + k]);
其中,变量之间没有别名,ind0
是一个常量。没有其他指针(A
或 B
)指向 ind0,因此,ind0
在整个循环中保持不变。
当我用 icc 编译代码时,它说这个循环不能被矢量化,因为可能存在矢量依赖性。这是消息:
loop was not vectorized: existence of vector dependence.
我缩小了问题范围,发现用常数替换 ind0 可以解决问题。所以,我假设 icc 认为A
可能指向ind0
,因此ind0
可能会改变。
我想知道如何帮助编译器知道向量化这样的循环是安全的。
提前感谢您的帮助。
【问题讨论】:
【参考方案1】:在 for 循环前面添加#pragma ivdep
,它指示编译器忽略假定的向量依赖关系。
#pragma ivdep
for(k = 0; k < SysData->numOfClaGen; k++)
A[k] = B[k] * cos(x1[2 * k] - x1[ind0 + k]);
有关 ivdep 的更多信息,请参阅icc doc
【讨论】:
【参考方案2】:对指针使用restrict
修饰符向编译器断言没有别名。这个关键字是在 C99 中引入的。 C++ 不支持它,但许多 C++ 编译器支持 __restrict
作为等效的专有扩展。对于英特尔编译器,必须通过添加命令行标志-restrict
(Linux) 或/Qrestrict
(Windows) 来启用restrict
。在您的代码的以下版本中,当使用英特尔编译器版本 13.1.3.198 时,循环会根据需要进行矢量化:
#include <math.h>
struct bar
int numOfClaGen;
;
void foo (double * restrict A,
const double * restrict B,
const double * restrict x1,
const struct bar * restrict SysData,
const int ind0)
int k;
for (k = 0; k < SysData->numOfClaGen; k++)
A[k] = B[k] * cos(x1[2 * k] - x1[ind0 + k]);
如下调用编译器(在 64 位 Windows 系统上)
icl /c /Ox /QxHost /Qrestrict /Qvec-report2 vectorize.c
编译器报告
vectorize.c(14): (col. 5) remark: LOOP WAS VECTORIZED.
【讨论】:
【参考方案3】:icc 在一年前更改为将 -ansi-alias 设置为 linux 和 Mac 的默认值。对于 Windows,不能指望此默认设置,因为它与 Microsoft 的使用相冲突。此选项等效于 gcc -fstrict-aliasing,自 gcc 3.0 以来一直是默认选项。我认为对于这样一个有限的问题,设置此选项比设置 ivdep restrict 或 simd 要好得多。 尽管没有很好的文档记录,但 icc 将 __restrict 视为与 gcc 相同,并且不需要限制或 C99 选项来接受它。原则上,它应该只对正在修改的对象起作用(上例中的 A[])。 奇怪的是,__restrict 对于 MSVC++ 的含义略有不同。它允许非向量优化,否则可能会被可能的依赖项阻止,但不能启用向量化(但它可能适用于当前情况)。
【讨论】:
以上是关于如何克服icc中的“存在向量依赖”的主要内容,如果未能解决你的问题,请参考以下文章