解包位域(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。
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。