thn*_*ghh 0 c intrinsics avx avx512
我正在寻找将压缩的 64 位整数饱和为 8 位整数的解决方案。看着_mm256_cvtepi64_epi8但不是饱和,它截断了导致不需要的输出。
我的程序如下:
int main()
{
__m256i a, b, c;
__m128i d;
a = _mm256_set1_epi64x(127);
b = _mm256_set1_epi64x(1);
c = _mm256_add_epi64x(a, b);
d = _mm256_cvtepi64_epi8(c);
}
Run Code Online (Sandbox Code Playgroud)
我希望输出 (d) 包含四个127(饱和),但是程序产生四个-128元素(从 截断128)。
_mm256_cvtepi64_epi8是AVX512。(特别是 AVX512VL;512 位版本是 AVX512F)。你标记了它,但你的(原始)标题只说 AVX。
无论如何,您的选择包括首先进行饱和加法,_mm256_adds_epi8因此每个向量可以拥有 8 倍的元素。
(正如在评论中讨论的,8×8 => 8位乘法饱和,你可能只是想在通道解压缩饲料_mm256_mullo_epi16,和结果的包对在车道退缩与_mm256_packs_epi16(vpacksswb)。虽然符号扩展在通道解压缩不方便,因此您可以考虑vpmovsx。无论哪种方式,您绝对不需要加宽超过 16 位的元素;int16_t可以保存两个的完整乘积而int8_t不会溢出。)
或者按照您的要求进行操作,AVX512 确实具有下转换指令的有符号和无符号饱和版本,以及您找到的截断版本。VPMOVQB, VPMOVSQB, 和VPMOVUSQB都记录在一起。
__m128i _mm256_cvtsepi64_epi8(__m256i a);是否有符号饱和。它在带有__m512i源的版本和直接存储到内存的版本中可用(可选地作为掩码存储)。
(存储版本在主流 CPU 上效率不高,但它确实允许 KNL / KNM(缺少 AVX512BW)进行窄字节掩码存储。)
除非万不得已,否则不要将数据扩展到 64 位元素。与 8 位元素相比,这是每个向量工作量的 1/8,自 Haswell 以来,32x32 => 32 位和 64x64 => 64 位 SIMD 乘法在 Intel 上每条指令需要 2 uop。
另一种选择是打包 2 个向量 -> 1 个与 2 个输入具有相同宽度的向量,但它们仅适用于车道内打包指令。例如_mm256_packs_epi16如上所述。它们仅适用于 2:1 的元素大小比率,而不是一步从 64 或 32 到 8。(这是避免扩大太多的另一个原因)。
但是如果你看看产生 N 字节输出数据的 shuffle 总数,它往往会稍微领先一些。例如,对于 4 个输入向量,您需要 2 + 1 次 shuffle 而不是 4 次以从 32 位缩小到 8 位。(如果您需要修复通道内,如果您无法向它们提供具有 128 位通道中交错奇数/偶数数据的指令,则可能是第 4 次洗牌)。您必须查看解包和重新打包需要多少次洗牌(或可能的其他指令,如 AND 或 AVX512 字节掩码)的大图。
如果您甚至存储结果,2:1 包装的优势在于可以扩大存储空间。如果不是,那么这比新的 AVX512 1->1 向量缩小指令有更大的优势,在新的 AVX512 1->1 向量缩小指令中,您需要将它们重新组合成 256 位向量。