我目前正在尝试对大量 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 关于自动矢量化的说明清楚地指出应该正确检测到这个函数:
我试过的:
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 跟随)。