什么是打包、解包和扩展打包数据

Oma*_*lid 12 sse simd cpu-architecture avx avx2

我一直在研究英特尔内部函数,每个函数都处理打包或解包或扩展打包的整数、浮点数或双精度数。

似乎这个问题应该在互联网上的某个地方得到回答,但我根本找不到答案。

那个包装物是什么?

zko*_*oza 8

好吧,我一直在寻找同一问题的答案,但也没有成功。所以我只能猜测。

Intel 在其 MMX 技术中引入了打包指令和标量指令。例如,他们引入了一个功能

__m64 _mm_add_pi8 (__m64 a, __m64 b)
Run Code Online (Sandbox Code Playgroud)

那时还没有“扩展包装”这样的东西。唯一的数据类型是整数,__m64并且所有操作都适用于整数。SSE 带来了 128 位寄存器和浮点数运算。但是,SSE2 包含对 128 位寄存器中执行的整数进行 MMX 操作的超集。例如,

__m128i _mm_add_epi8 (__m128i a, __m128i b)
Run Code Online (Sandbox Code Playgroud)

这里我们第一次看到函数名中的“ep”(扩展打包)部分。为什么要引入它?我相信这是为了解决_mm_add_pi8上面列出的 MMX 指令已使用该名称的问题。 SSE/AVX的接口是C语言的,没有函数名的多态性。

对于 AVX,英特尔选择了不同的策略,并开始在开头的“_mm”字母之后添加寄存器长度,参见:

__m256i _mm256_add_epi8 (__m256i a, __m256i b)
__m512i _mm512_add_epi8 (__m512i a, __m512i b)
Run Code Online (Sandbox Code Playgroud)

为什么他们在这里选择“ep”而不是“p”是一个谜,与程序员无关。实际上,他们似乎使用“p”进行浮点数和双精度运算,使用“ep”进行整数运算。

__m128d _mm_add_pd (__m128d a, __m128d b); // "d": function operates on doubles
__m256 _mm256_add_ps (__m256 a, __m256 b); // "s": function operates on floats
Run Code Online (Sandbox Code Playgroud)

也许这可以追溯到从 MMX 到 SSE 的过渡,其中引入了“ep”用于整数操作(MMX 不处理浮点数),并尝试使 AVX 助记符尽可能接近 SSE 助记符

因此,基本上,从程序员的角度来看,“ep”(“扩展打包”)和“p”(“打包”)之间没有区别,因为我们已经知道代码中目标的寄存器长度。


至于问题的下一部分,“拆包”属于与“标量”和“打包”完全不同的概念类别。这是特定数据重新排列或洗牌的通俗术语,例如旋转或移位。

在类似内在函数的名称中使用“epi”的原因_mm256_unpackhi_epi16 是,它是 16 位整数元素向量上的真正向量(而不是标量)函数。请注意,此处“unpack”属于函数名称中描述其操作的部分(如 mul、add 或 permute),而“s”/“p”/“ep”(标量、打包、扩展打包)属于描述操作模式的部分(“s”为标量,“p”或“ep”为向量)。

(没有在两个 XMM 寄存器之间进行操作的标量整数指令,但“si”确实出现在movd eax, xmm0:的内在名称中_mm_cvtsi128_si32。有一些类似的内在函数。)