为什么矢量化在几乎相同的代码中表现不同?

13

这里有些免费的函数,它们在第一种情况下没有向量化循环,但在其他情况下则是向量化的。为什么会这样呢?

#include <vector>

typedef std::vector<double> Vec;

void update(Vec& a, const Vec& b, double gamma) {
    const size_t K = a.size();
    for (size_t i = 0; i < K; ++i) { // not vectorized
        a[i] = b[i] * gamma - a[i];
    }
}

void update2(Vec& a, const Vec& b, double gamma) {
    for (size_t i = 0; i < a.size(); ++i) { // vectorized
        a[i] = b[i] * gamma - a[i];
    }
}

void update3(Vec& a, size_t K, const Vec& b, double gamma) {
    for (size_t i = 0; i < K; ++i) { // vectorized
        a[i] = b[i] * gamma - a[i];
    }
}

int main(int argc, const char* argv[]) {
    Vec a(argc), b;
    update(a, b, 0.5);
    update2(a, b, 0.5);
    update3(a, a.size(), b, 0.5);
    return 0;
}

编译器(VS2013)的相关提示信息:

1>  c:\home\dima\trws\trw_s-v1.3\trws\test\vector.cpp(7) : info C5002: loop not vectorized due to reason '1200'
1>  c:\home\dima\trws\trw_s-v1.3\trws\test\vector.cpp(13) : info C5001: loop vectorized
1>  c:\home\dima\trws\trw_s-v1.3\trws\test\vector.cpp(19) : info C5001: loop vectorized

来自@tony的评论

原因1200:"循环包含循环传递的数据依赖关系,防止向量化。循环的不同迭代互相干扰,使得向量化循环会产生错误的答案,并且自动向量化器无法证明不存在这样的数据依赖关系。" 来源


2
尝试使用不同的编译器?其他编译器(如gcc和clang)可以对这3个函数进行向量化处理。 - Marc Glisse
1
“Reason 1200”被记录为什么? - Alan Stokes
1
原因1200:“循环包含循环传递的数据依赖关系,这些依赖关系阻止了矢量化。循环的不同迭代相互干扰,使得矢量化循环会产生错误的答案,并且自动向量化程序无法证明不存在这样的数据依赖关系。” 来源 - Tony
1
我很惊讶任何编译器都能够向量化它们中的任何一个。编译器需要证明要么ab不是别名,要么&a[0] < &b[0] - Mysticial
1
@Mysticial 或者更容易的方法是,编译器可以生成顺序和向量化版本,并进行运行时测试以检查 a 和 b 是否重叠,以便分派到任一版本。 - Marc Glisse
显示剩余4条评论
1个回答

2
我猜这是一些深层次的编译器实现问题,比如自动向量化器“启动”的阶段以及此时代码的内部表示状态。当我在MSVC2017上尝试时,它更符合人们的预期。它自动向量化了update()update3(),但没有向量化update2(),原因是第14行给出了501,文档中记录为:

归纳变量不是本地的;或者上界不是循环不变量。


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