我是 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 之前稍微好一点:用无符号饱和度减去两种方式,然后对结果进行 OR 运算。 (对于每个元素,a-b 或 b-a 饱和为零。)_mm256_or_si256(_mm256_subs_epu8(a,b), _mm256_subs_epu8(b,a))
在 Haswell 上,pmin
/pmax
和 psub
只运行在端口 1 或端口 5,但 por
可以运行在三个向量执行端口(0、1、5)中的任何一个。
Skylake 添加了第三个向量整数加法器,因此该 uarch 没有区别。 (请参阅 http://agner.org/optimize/ 和 x86 标签维基中的其他链接,包括英特尔的优化手册。)
这在锐龙上也稍微好一些,其中 VPOR
可以在任何 P0123 上运行,但是根据 Agner Fog 的测试,PADD
/PMIN
只能在 P013 上运行。 (Ryzen 将 256b 向量操作拆分为 2 个 uop,但它具有可用的吞吐量。它无法仅使用单 uop 指令填充其 6 uop 宽管道。)
可以在更多端口上运行的 Uop 不太可能在等待分配的端口(资源冲突)时延迟,因此您实际上更有可能因此获得 2 个周期的总延迟(从两个输入准备就绪到输出准备就绪) .如果存在对特定端口的竞争(例如端口 5,它在 Intel Haswell 及更高版本上具有唯一的随机播放单元),它们也不太可能导致吞吐量瓶颈。
关于sse - AVX2:U8绝对差,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/46968847/