2

我目前正在尝试对大量 uint_32 值运行简单的“最大函数”循环扫描。

使用 AVX2 内在,它相当简单:

const __m256i limit8 = _mm256_set1_epi32(limit);
for (i=0; i<TABLESIZE; i+=8)
{
    __m256i src = _mm256_loadu_si256((const __m256i*)(h+i));
            src = _mm256_max_epu32(src, limit8);
    _mm256_storeu_si256((__m256i*)(h+i), src);
}

唯一重要的操作是 _mm256_max_epu32 (vpmaxud),它有效地完成了请求的工作。表中的所有单元格都与单个常数进行比较。

现在,就可移植性而言,使用内在函数有点限制,我更愿意使用标准 C 编写一个等效版本,编译器会自动对其进行向量化。毕竟,内部循环似乎很简单,可以用廉价的启发式方法找出来。

唉,我没有通过这个简单的练习,即使 VS2012 关于自动矢量化的说明清楚地指出应该正确检测到这个函数:

http://blogs.msdn.com/cfs-filesystemfile.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-04-99/3007.Auto_2D00_Vectorizer_2D00_08_2D00_Cookbook.pdf

我试过的:

for (i=0; i<TABLESIZE; ++i)
{
    if (h[i]>limit) h[i]=limit;
}

不起作用:与说明书语句相比,“if”语句是这里的问题:auto-vectorize在代码 1100 上失败

for (i=0; i<TABLESIZE; ++i)
{
    h[i] = h[i] > limit ? h[i] : limit;
}

没有更好,尽管出于不同的原因:自动矢量化在代码 1304 上失败(循环包括不同大小的分配),这可能是一个错误,因为所有变量都使用相同的类型。

for (i=0; i<TABLESIZE; ++i)
{
    const U32 val = ((limit-h[i]) >> 31);
    h[i]-=limit; h[i]*=val; h[i]+=limit;
}

这个有效,并且是矢量化的。但它更复杂,因此运行速度明显比直接内在版本慢。

我想知道是否有办法让这个简单的“最大”操作由 Visual 自动矢量化(GCC 和 Clang 跟随)。

4

0 回答 0