当英特尔编译器成功时,GCC无法对一个简单的2级嵌套循环进行矢量化

时间:2016-12-26 11:13:19

标签: gcc vectorization icc

我有相同循环的以下两个版本:

// version 1
for(int x = 0; x < size_x; ++x)
{
    for(int y = 0; y < size_y; ++y)
    {
        data[y*size_x + x] = value;
    }
}

// version 2
for(int y = 0; y < size_y; ++y)
{
    for(int x = 0; x < size_x; ++x)
    {
        data[y*size_x + x] = value;
    }
}

我使用两个编译器编译上述代码:

  • Intel(17.0.1):我使用以下代码编译代码:icc -qopenmp -O3 -qopt-report main.cpp。两者都成功地进行了矢量化。

  • GCC(5.1):我使用:g++ -fopenmp -ftree-vectorize -fopt-info-vec -O3 main.cpp编译代码。只有版本2被矢量化。

以下是我的问题:

  • 为什么GCC无法对版本1进行矢量化?是因为版本1中的内部循环不能访问连续的内存吗?
  • 如果上述答案为“是”:GCC是否无法对其进行矢量化或选择不这样做,因为它不具有任何性能优势?如果是后者,我可以以某种方式迫使GCC对其进行矢量化吗?
  • 显然,在版本1中,英特尔编译器的矢量化报告包括以下行:Loopnest Interchanged: ( 1 2 ) --> ( 2 1 )PERMUTED LOOP WAS VECTORIZED;在第二版中,我得到了这个:LOOP WAS VECTORIZED。那么看起来英特尔编译器会重新排列循环的顺序以便对其进行矢量化?我明白这是对的吗?
  • 我可以通过GCC实现与上述类似的功能吗?

编辑1:

感谢MarcGlisse,我通过创建代码的简化示例进一步调查,并意识到我的data大小和GCC上的编译标志的不同组合将实现不同的矢量化。此时我更加困惑,我认为最好先创建一个新帖子,以便首先了解GCC向量化的工作原理。如果有人好奇,您可以查看下面的代码并尝试size_xsize_y的值1,2,3,4,5,6,7。还可以使用MarcGlisse的编译标志尝试一次,一次不使用。不同的组合可能会给出不同的矢量化结果。

void foo1(int size_x, int size_y, float value, float* data)
{
    for(int x = 0; x < size_x; ++x)
    {
        for(int y = 0; y < size_y; ++y)
        {
            data[y*size_x + x] = value;
        }
    }
}

void foo2(int size_x, int size_y, float value, float* data)
{
    for(int y = 0; y < size_y; ++y)
    {
        for(int x = 0; x < size_x; ++x)
        {
            data[y*size_x + x] = value;
        }
    }
}

int main(int argc, char** argv)
{
    int size_x = 7;
    int size_y = 7;
    int size = size_x*size_y;
    float* data1 = new float[size];
    float* data2 = new float[size];

    foo1(size_x, size_y, 1, data1);
    foo2(size_x, size_y, 1, data2);

    delete [] data1;
    delete [] data2;

    return 0;
}

0 个答案:

没有答案