解包位域(movmskb 的逆运算)

Unpacking a bitfield (Inverse of movmskb)

MOVMSKB 在将字节字段打包成位方面做得非常好。
但是我想做相反的事情。
我有一个 16 位的位域,我想将其放入 XMM 寄存器中。
每位 1 字节字段。
最好设置位应该设置每个字节字段的 MSB (0x80),但我可以接受设置位导致字节字段中的 0xFF 结果。

我在 https://software.intel.com/en-us/forums/intel-isa-extensions/topic/298374 上看到了以下选项:

movd mm0, eax
punpcklbw mm0, mm0
pshufw mm0, mm0, 0x00
pand mm0, [mask8040201008040201h]
pcmpeb mm0, [mask8040201008040201h]

然而,此代码仅适用于 MMX 寄存器,不能用于 XMM 寄存器,因为 pshufw 不允许这样做。

我知道我可以使用 PSHUFB,但那是 SSSE3,我想要 SSE2 代码,因为它需要在任何 AMD64 系统上工作。

有没有办法做到这一点是纯 SSE2 代码?
请不要内在函数,只有简单的英特尔 x64 代码。

幸运的是pshufd是SSE2,你只需要再解压一次就可以了。我相信这应该有效:

movd xmm0, eax
punpcklbw xmm0, xmm0
punpcklbw xmm0, xmm0
pshufd xmm0, xmm0, 0x50
pand xmm0, [mask]
pcmpeqb xmm0, [mask]

约翰说:

If you're starting with a word the first unpack will give you a dword, allowing you to shorten it like so:

movd xmm0, eax
punpcklbw xmm0, xmm0
pshufd xmm0, xmm0, 0x00
pand xmm0, [mask]
pcmpeqb xmm0, [mask]

但是这段代码应该不起作用。例子:假设输入是0x00FF(字),即我们要设置低8字节。

punpcklbw xmm0, xmm0    ; 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FF FF
pshufd xmm0, xmm0, 0x00 ; 00 00 FF FF 00 00 FF FF 00 00 FF FF 00 00 FF FF
pand xmm0, [mask]       ; 00 00 02 01 00 00 02 01 00 00 02 01 00 00 02 01
pcmpeqb xmm0, [mask]    ; 00 00 FF FF 00 00 FF FF 00 00 FF FF 00 00 FF FF

这是错误的结果,因为我们想要 00 00 00 00 00 00 00 00 FF FF FF FF FF FF FF FF。当然,它确实给了你 8 个设置字节,而不是对应于位的 8。