#pragma simd reduction(<operator>:<variable>)如何在引擎盖下工作?

时间:2016-05-19 21:47:54

标签: vectorization intel simd avx

我想更详细地了解英特尔编译器使用的simd减少条款是如何工作的。

特别是对于形式

的循环
double x = x_initial;
#pragma simd reduction(<operator1>:x)
for( int i = 0; i < N; i++ )
  x <operator2> some_value;

我天真的猜测如下: 编译器为每个向量通道初始化x的私有副本,然后一次遍历循环一个向量宽度。例如,如果矢量宽度是4倍,则这将对应于N / 4次迭代加上最后的剥离循环。在迭代的每个步骤中,使用operator2更新每个通道的x的私有副本,然后在最后,使用4个向量通道&#39}。私人副本使用operator1合并。 auto-vectorization guide似乎没有直接解决此问题。

我做了一些实验,发现一些结果符合我的期望,有些结果不符合我的预期。例如,我尝试了这个案例

double x = 1;
#pragma simd reduction(*:x) assert
for( int i = 0; i < 16; i++ )
  x += a[i];  // All elements of a are equal to 3.0
cout << "x after (*:x), x += a[i] loop:  " << x << endl; 

其中operator1为*且operator2为+ =。当我为avx2编译时,其矢量宽度为4倍,输出为28561 =(1 + 4 * a [i])^ 4。这意味着代码首先将x的4个通道专用副本初始化为1,然后将4个双宽矢量通道迭代跨越16个行程计数,每个副本增加3个4次。每个通道专用副本x现在等于13.最后,使用operator2组合(减少)车道 - 私人副本,即*,产生13 * 13 * 13 * 13 = 28561.

但是,当我切换*和+运算符时,就像这样

x = 1;
#pragma simd reduction(+:x) assert
for( int i = 0; i < 16; i++ )
  x *= a[i];
cout << "x after (+:x), x *= a[i] loop:  " << x << endl;

再次为avx2编译,输出为1.0。如果我的理论是正确的,那么每个向量通道最终应该包含1 * 3 ^ 4的值,然后使用+组合得到4 * 3 ^ 4 = 324.显然情况并非如此。我错过了什么?

0 个答案:

没有答案