Visual studio无法矢量化

Visual studio fails to vectorise

本文关键字:矢量化 studio Visual      更新时间:2023-10-16

我尝试在VS2013中编译以下代码

template <class T>
void assignment(T* result, size_t sz, const T x)
{
  for (size_t i = 0; i < sz; i++)
    result[i] = x;
}

和编译器无法用以下消息向量化代码。

info C5002: loop not vectorized due to reason '1104'

,而下面的代码可以

void discountFactor(double* result, const double* r, double t, size_t sz)
{
  for (size_t i = 0; i < sz; i++)
    result[i] = -r[i] * t;
  for (size_t i = 0; i < sz; i++)
    result[i] = exp(result[i]);
}
谁能给我解释一下1104的原因是什么?

正如其他人所说,这些类型的优化在MSDN上有很好的文档记录。事实上,这里有一个很好的例子。下面是代码片段:

int code_1104(int *A, int *B)
{
    // When it vectorizes a loop, the compiler must 'expand' scalar
    // variables to a vector size such that they can fit in
    // vector registers. Code 1104 is emitted when the compiler
    // cannot 'expand' such scalars.
    // In this example, we try to 'expand' x to be used in the 
    // vectorized loop. However, there is a use of 'x' 
    // beyond the loop body, which prohibits this expansion.
    // To resolve this, try to limit scalars to be used only in
    // the loop body and not beyond, and try to keep their types
    // consistent with the loop types.
    int x;
    for (int i=0; i<1000; ++i)
    {
        x = B[i];
        A[i] = A[i] + x;
    }
    return x;
}
我的解释(老实说,他们只是猜测):第二个例子之所以有效,是因为result是原始数据类型(double *),即使它在循环的作用域之外,也可以很容易地修改。

示例在其注释中告诉…

// When it vectorizes a loop, the compiler must 'expand' scalar
// variables to a vector size such that they can fit in
// vector registers.

取决于你如何调用你的模板函数assignment,你的T在第一个例子中可能是任何。包含了一个不适合寄存器的类型。因此,我假设编译器不能自动向量化您的for -循环。

编译器不能很好地确定哪些变量被用作只读。您必须确保向量化循环使用局部变量的const副本。考虑下面的代码:

#include <iostream>
using std::cout;
using std::endl;
using std::cin;
void doIt(double* src, double* dst, double factor, int sz) {
    for (int i = 0; i < sz; ++i) { // loop vectorized
        dst[i] += src[i] * factor;
    }
}
int main() {
    static const int SZ = 1024;
    double sum = 0.0;
    double factor;
    double initial;
    double source[SZ];
    double destination[SZ];
    cin >> factor;
    for (int i = 0; i < SZ; ++i) { // 22, reason 1200, data dependency expected
        cin >> source[i];
    }
    cin >> initial;
    for (int i = 0; i < SZ; ++i) {  // 27, reason 1104
        destination[i] += source[i] * factor;
    }
    doIt(source, destination, factor, SZ); // 31, no problem
    return 0;
}

这里doIt中的循环是由编译器向量化的,而main中的循环则不是。

为什么?

因为factor不是const变量,并且在从第27行开始的循环中,它可以被修改(尽管它显然不是)。

为什么doIt不引起问题?

因为factor是按值传递的,而不是按引用传递的。

修复吗?

使因子为const变量

#include <iostream>
using std::cout;
using std::endl;
using std::cin;
void doIt(double* src, double* dst, double factor, int sz) {
    for (int i = 0; i < sz; ++i) { // loop vectorized
        dst[i] += src[i] * factor;
    }
}
double GetFactor() {
    double ret;
    cin >> ret;
    return ret;
}
int main() {
    static const int SZ = 1024;
    double sum = 0.0;
    const double factor = GetFactor();
    double initial;
    double source[SZ];
    double destination[SZ];
    for (int i = 0; i < SZ; ++i) { // 22, reason 1200, data dependency expected
        cin >> source[i];
    }
    cin >> initial;
    for (int i = 0, mysz=SZ; i < mysz; ++i) {  // no problem
        destination[i] += source[i] * factor;
    }
    doIt(source, destination, factor, SZ); // no problem
    return 0;
}

很好,但这和我有什么关系?

我怀疑你的模板函数被内联了,本质上与第一个例子中第27行的循环相同。尝试更改传递给模板函数的变量x,如下所示:

:

assignment(bob, sz, x);
新:

const double copyx = x;
assignment(bob, sz, copyx);