我想在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
可能会发生变化。
我想知道如何帮助编译器知道向量化这样的循环是安全的。
提前感谢您的帮助。
答案 0 :(得分:2)
在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
答案 1 :(得分:1)
对指针使用restrict
修饰符断言编译器没有别名。此关键字是在C99中引入的。 C ++不支持它,但许多C ++编译器支持__restrict
作为等效的专有扩展。使用英特尔编译器,必须通过添加命令行标志restrict
(Linux)或-restrict
(Windows)来启用/Qrestrict
。在以下版本的代码中,使用英特尔编译器版本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.
答案 2 :(得分:0)
icc在一年前被更改为将-ansi-alias设置为linux和Mac的默认设置。对于Windows,此默认值无法计入,因为它与Microsoft使用冲突。此选项等同于gcc -fstrict-aliasing,这是自gcc 3.0以来的默认选项。我认为设置此选项要比为这样一个有限的问题设置ivdep restrict或simd要好得多。 虽然没有详细记录,但icc将__restrict视为与gcc相同,并且不需要使用restrict或C99选项来接受它。原则上,它应该只对被修改的对象起作用(上例中的A [])。 奇怪的是,__ restrict对MSVC ++的含义略有不同。它允许非向量优化,否则可能会被可能的依赖性阻止,但不能启用向量化(但它可能适用于当前情况)。