AVX2:U8绝对差

AVX2: U8 absolute difference

我是 AVX 的新手(来自 ARM NEON),并且对 AVX 缺少许多 U8 算法感到不愉快,其中缺少绝对差异。

因此我不得不求助于 max(a,b)-min(a,b) 内联函数:

static inline __m256i _mm256_abd_epu8(__m256i a, __m256i b)
{
    return _mm256_sub_epi8(_mm256_max_epu8(a, b), _mm256_min_epu8(a, b));
}

我很好奇是否有更有效的方法来处理这个问题。

是的,我知道 _mm256_sad_epu8,但我需要差异本身,而不是总和。

如果有任何意见,我将不胜感激,并且 AVX2 没问题,忽略任何向后兼容性。

提前致谢。

我不知道有什么技巧可以只用 2 条或更少的指令来做到这一点。 (而且这个问题的 SSE 版本也没有什么更好的:Compute the absolute difference between unsigned integers using SSE)。它确实提到了我在这个答案中使用的饱和方法。


稍微 在 Skylake 之前更好:用无符号饱和度减去两种方式,然后对结果进行或运算。 (对于每个元素,a-b 或 b-a 饱和为零。)

_mm256_or_si256(_mm256_subs_epu8(a,b), _mm256_subs_epu8(b,a))

在 Haswell 上,pmin/pmaxpsub 仅 运行 在端口 1 或端口 5 上,但 por 可以 运行在三个矢量执行端口(0、1、5)中的任何一个上。

Skylake 添加了第三个向量整数加法器,因此在 uarch 上没有区别。 (参见 http://agner.org/optimize/ and other links in the 标签 wiki,包括英特尔的优化手册。)

这在Ryzen上也稍微好一点,其中VPOR可以运行任何P0123,但PADD/PMIN只能运行 P013 根据 Agner Fog 的测试。 (Ryzen 将 256b 向量运算拆分为 2 微指令,但它具有有用的吞吐量。它不能仅使用单微指令来填充其 6 微指令宽的管道。)

可以在更多端口上 运行 的 Uops 不太可能被延迟等待其分配的端口(资源冲突),因此您实际上更有可能获得 2 个周期的总延迟(来自两者输入准备好到输出准备好)。如果存在对特定端口的竞争(例如端口 5,它在 Intel Haswell 及更高版本上具有唯一的洗牌单元),它们也不太可能造成吞吐量瓶颈。