C语言 如何在每32位数据通道avx512中存储低8位?

tcomlyy6  于 2022-12-29  发布在  其他
关注(0)|答案(1)|浏览(211)

如何在每32位数据通道中存储低8位,例如,一个zmm寄存器存储16个32位整数,我只需要将低8位数据存储到内存中,内存是int8_t数组?

5anewei6

5anewei61#

有一条指令vpmovdbhttps://www.felixcloutier.com/x86/vpmovdb:vpmovsdb:vpmovusdb),但不幸的是,Intel CPU将其作为2个微指令运行,都是针对端口5的。https://uops.info/https://agner.org/optimize/)。C内部函数

VPMOVDB __m128i _mm512_cvtepi32_epi8( __m512i a);
VPMOVDB __m128i _mm512_mask_cvtepi32_epi8(__m128i s, __mmask16 k, __m512i a);
VPMOVDB __m128i _mm512_maskz_cvtepi32_epi8( __mmask16 k, __m512i a);
VPMOVDB void _mm512_mask_cvtepi32_storeu_epi8(void * d, __mmask16 k, __m512i a);

有趣的事实:它允许内存 * 目的地 *,并且只需要AVX 512 F,而不是AVX 512 BW,所以这就是KNL至强融核可以进行字节粒度掩码存储的方式。有符号和无符号饱和形式,但您需要截断形式。
截断和跨道填充都是AVX-512中的新技术;在AVX 2中,通常必须使用2x vpackssdw来馈送vpackuswbvpermq修复,还需要在打包之前屏蔽32位数据,使其位于0..255无符号范围内,这将为每个 input 向量额外消耗vpand

带有多个向量

如果您有多个数据矢量,使用AVX-512 VBMI(Ice Lake / Zen 4)vpermt2b从两个矢量中获取字节可能是值得的。在支持它的Intel CPU上,这将运行3个uop(2 p5 + p015),因此每个256位矢量2个周期,而不是每个128位矢量2个周期。
它在Zen 4上是1 uop,和vpmovdb一样,所以vpermt2b是理想的,每个时钟允许一个256位存储,速度是Intel的两倍,前端uop更少。
vpack...通道内压缩指令是Intel上的单个uop,它将2个寄存器以2:1的比例压缩为一个相同宽度的寄存器。如果在末尾执行vpermt2d混洗,它可能会领先于多个向量。
因此,给定4个ZMM寄存器,4x vpmovdb在英特尔上将占用8个吞吐周期。4x vpand + 2x vpackssdw + 1x vpackuswb + vpermq将在Skylake/Cascade Lake或更高版本上每4个时钟周期生成一个准备存储的ZMM。
vpermt2w在Skylake-avx 512上可用,因此可以代替vpackuswb + vpermq使用,但不幸的是,在那里和更高版本的英特尔上,vpermt2w是3 uops。)
AVX 2指令的另一个想法:* how to convert uint32 to uint8 using simd but not avx512? * -vpshufb_mm256_shuffle_epi8)用于压缩和清零,以更宽的粒度设置2输入混洗,但每个输入向量需要一个port 5微操作。
Intel的C/C++ intrinsic指南(https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html)有一个对asm助记符起作用的搜索;它们更短,更便于打字和谈论。

相关问题