首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >循环携带的依赖项在哪里?

循环携带的依赖项在哪里?
EN

Stack Overflow用户
提问于 2012-12-23 00:43:51
回答 2查看 2.4K关注 0票数 12

有人看到下面的循环代码有什么明显的地方吗?我没有看到为什么as 2012的C++编译器不能自动向量化循环代码?

当我使用info C5002: loop not vectorized due to reason '1200'命令行开关时,编译器给我的全部是/Qvec-report:2

原因1200在MSDN中记录为:

循环包含循环携带的数据依赖项,以防止矢量化。循环的不同迭代相互干扰,从而使循环矢量化会产生错误的答案,而自动向量器无法向自己证明不存在这种数据依赖。

我知道(或者我很确定)没有任何循环携带的数据依赖项,但我不确定是什么阻止了编译器实现这一点。

这些sourcedest指针不会重叠,也不会别名相同的内存,我试图通过__restrict向编译器提供这个提示。

pitch总是一个正整数值,类似于4096,这取决于屏幕分辨率,因为这是一个8bpp->32bpp呈现/转换函数,逐列操作。

代码语言:javascript
复制
byte  * __restrict source;
DWORD * __restrict dest;
int pitch;

for (int i = 0; i < count; ++i) {
    dest[(i*2*pitch)+0] = (source[(i*8)+0]);
    dest[(i*2*pitch)+1] = (source[(i*8)+1]);
    dest[(i*2*pitch)+2] = (source[(i*8)+2]);
    dest[(i*2*pitch)+3] = (source[(i*8)+3]);

    dest[((i*2+1)*pitch)+0] = (source[(i*8)+4]);
    dest[((i*2+1)*pitch)+1] = (source[(i*8)+5]);
    dest[((i*2+1)*pitch)+2] = (source[(i*8)+6]);
    dest[((i*2+1)*pitch)+3] = (source[(i*8)+7]);
}

每个source[]周围的父类都是函数调用的残余,我在这里省略了这个函数调用,因为如果没有函数调用(最简单的形式),循环仍然无法自动向量化。

编辑:

我已经将循环简化为它的最简单的形式:

代码语言:javascript
复制
for (int i = 0; i < 200; ++i) {
    dest[(i*2*4096)+0] = (source[(i*8)+0]);
}

这仍然会产生相同的1200原因代码。

编辑(2):

这种具有本地分配和相同指针类型的最小测试用例仍然无法自动矢量化。我只是对此感到困惑。

代码语言:javascript
复制
const byte * __restrict source;
byte * __restrict dest;
source = (const byte * __restrict ) new byte[1600];
dest = (byte * __restrict ) new byte[1600];
for (int i = 0; i < 200; ++i) {
    dest[(i*2*4096)+0] = (source[(i*8)+0]);
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-12-23 01:12:13

我们只想说有几件事能阻止这个循环的矢量化.

考虑到这一点:

代码语言:javascript
复制
int main(){
    byte  *source = new byte[1000];
    DWORD *dest   = new DWORD[1000];

    for (int i = 0; i < 200; ++i) {
        dest[(i*2*4096)+0] = (source[(i*8)+0]);
    }
    for (int i = 0; i < 200; ++i) {
        dest[i*2*4096] = source[i*8];
    }
    for (int i = 0; i < 200; ++i) {
        dest[i*8192] = source[i*8];
    }
    for (int i = 0; i < 200; ++i) {
        dest[i] = source[i];
    }
}

编译器输出:

代码语言:javascript
复制
main.cpp(10) : info C5002: loop not vectorized due to reason '1200'
main.cpp(13) : info C5002: loop not vectorized due to reason '1200'
main.cpp(16) : info C5002: loop not vectorized due to reason '1203'
main.cpp(19) : info C5002: loop not vectorized due to reason '1101'

让我们把这个分解一下:

  1. 前两个循环是相同的。因此,他们给出了最初的理由1200,即循环携带的依赖项。
  2. 第三圈与第二圈相同。然而,编译器给出了一个不同的理由:1203: 循环体包括对数组的非连续访问。

好吧..。为什么有不同的原因?我不知道。但这一次,原因是正确的。

  1. 第四个循环给出了1101: 循环包含不可向量化的转换操作(可能是隐式的)。

因此,VC++不够聪明,无法发出SSE4.1 pmovzxbd指令。

这是一个相当利基的案例,我不会期望任何现代编译器能够做到这一点。如果可以,则需要指定SSE4.1。

所以唯一不寻常的是,为什么初始循环报告一个循环携带的依赖项。

嗯,这是个艰难的决定.我要说的是,编译器只是没有发出正确的理由。(当它真的应该是非连续访问时)

回到重点,我不希望MSVC或任何编译器能够矢量化您的原始循环。您的原始循环将访问分组为4块--这使得它足够连续,足以向量化。但期望编译器能够识别这一点是遥不可及的。

因此,如果这很重要,我建议手动向量化这个循环。您需要的内在特性是_mm_cvtepu8_epi32()

您的原始循环:

代码语言:javascript
复制
for (int i = 0; i < count; ++i) {
    dest[(i*2*pitch)+0] = (source[(i*8)+0]);
    dest[(i*2*pitch)+1] = (source[(i*8)+1]);
    dest[(i*2*pitch)+2] = (source[(i*8)+2]);
    dest[(i*2*pitch)+3] = (source[(i*8)+3]);

    dest[((i*2+1)*pitch)+0] = (source[(i*8)+4]);
    dest[((i*2+1)*pitch)+1] = (source[(i*8)+5]);
    dest[((i*2+1)*pitch)+2] = (source[(i*8)+6]);
    dest[((i*2+1)*pitch)+3] = (source[(i*8)+7]);
}

按以下方式矢量化:

代码语言:javascript
复制
for (int i = 0; i < count; ++i) {
    __m128i s0 = _mm_loadl_epi64((__m128i*)(source + i*8));
    __m128i s1 = _mm_unpackhi_epi64(s0,s0);

    *(__m128i*)(dest + (i*2 + 0)*pitch) = _mm_cvtepu8_epi32(s0);
    *(__m128i*)(dest + (i*2 + 1)*pitch) = _mm_cvtepu8_epi32(s1);
}

免责声明:这是未经测试和忽略对齐。

票数 11
EN

Stack Overflow用户

发布于 2012-12-23 01:11:57

从MSDN文档中,将报告错误1203的情况。

代码语言:javascript
复制
void code_1203(int *A)
{
    // Code 1203 is emitted when non-vectorizable memory references
    // are present in the loop body. Vectorization of some non-contiguous 
    // memory access is supported - for example, the gather/scatter pattern.

    for (int i=0; i<1000; ++i)
    {
        A[i] += A[0] + 1;       // constant memory access not vectorized
        A[i] += A[i*2+2] + 2;  // non-contiguous memory access not vectorized
    }
}

它真的可以是在索引的计算,这扰乱了自动向量器。有趣的是,显示的错误代码不是1203。

MSDN参数化器和向量器消息

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14007805

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档