C++向量化双循环

Posted

技术标签:

【中文标题】C++向量化双循环【英文标题】:C++ vectorize double loop 【发布时间】:2018-02-12 17:07:58 【问题描述】:

我想用omp simd 向量化一个双循环。我的问题是以下形式:

#include <vector>

using namespace std;

#define N 8000

int main() 
  vector<int> a;
  vector<int> b;
  vector<int> c;

  a.resize(N);
  b.resize(N);
  c.resize(N);

#pragma omp simd collapse(2)
  for (unsigned int i = 0; i < c.size(); ++i) 
    for (unsigned int j = 0; j < c.size(); ++j) 
      c[i] += a[i] + b[j];
    
  

当我用g++ -O2 -fopenmp-simd -fopt-info-vec-all 编译它时,矢量化报告指出:

note: not vectorized: not suitable for gather load _14 = *_42;

如何转换代码以供编译器自动矢量化?

(编译器:g++ 5.4.0,CPU 支持AVX2

更新

主要问题是,如下所述,c 的数据依赖关系似乎只有内部循环是可向量化的。解决依赖关系,可以通过切换循环来实现,如下所示。编译器现在为我自动向量化了它。

  for (unsigned int j = 0; j < c.size(); ++j) 
  #pragma omp simd
    for (unsigned int i = 0; i < c.size(); ++i) 
      c[i] += a[i] + b[j];
    
  

【问题讨论】:

您是否有理由不使用-O3 运行?您是否查看过反汇编以表明编译器没有已经矢量化您的循环? (它应该在-O3 之下。) 第一步:丢失j 循环。最后一次迭代覆盖了由较低值 j 完成的所有工作。实现的操作是,AFAICT,我的伪代码采用 Matlab 语法:c(1:end) = a(1:end) + b(end) 你的代码的目的是什么?内部循环缩小到c[i] = a[i] + b[N-1]; 是的,抱歉应该是+= 而不是=(更新) 给出的总和真的是你想要的吗?由于它等价于(模舍入误差):foreach i c[i] += N*a[i] + B,其中 B = Sum j | b[j] 【参考方案1】:

您的代码的主要问题是在执行循环之前无法计算循环迭代计数。您需要将 c.size() 替换为 N

第二个问题是如果你想矢量化外循环,c[i] = a[i] + b[j] 的语句会导致 Flow依赖。为了克服这些问题,我尝试对内部循环进行矢量化,并且我的代码成功地被矢量化。

您可以在下面的页面中阅读有关 Anti 和 Flow Dependencies 的更多信息: https://en.wikipedia.org/wiki/Data_dependency

矢量化后我实现了 6.3 的加速。 最后我的代码如下所示:

for (unsigned int i = 0; i < N; ++i) 

        #pragma simd
        for (unsigned int j = 0; j < N; ++j) 
        
            c[i] = a[i] + b[j];
        
    

【讨论】:

感谢您向我指出 RAW 依赖项。我不得不不同意循环计数。查看更新后的帖子。

以上是关于C++向量化双循环的主要内容,如果未能解决你的问题,请参考以下文章

在python中为依赖于索引的函数向量化嵌套的for循环

向量化numpy追加循环

为啥在一定数量的元素之后循环不向量化?

向量化这个循环

向量化嵌套循环,其中一个循环变量依赖于另一个

如何向量化嵌套循环