解压缩位域(movmskb 的逆)
Posted
技术标签:
【中文标题】解压缩位域(movmskb 的逆)【英文标题】:Unpacking a bitfield (Inverse of movmskb) 【发布时间】:2016-02-23 22:05:27 【问题描述】: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 regs,因为 pshufw 不允许这样做。
我知道我可以使用PSHUFB
,但那是 SSSE3,我想要 SSE2 代码,因为它需要在任何 AMD64 系统上工作。
有没有办法做到这一点是纯 SSE2 代码?请不要使用内在函数,只需纯 intel x64 代码。
【问题讨论】:
对于那些对具有内在函数here it is 的 SSSE3(和 32 位的 AVX2)解决方案感兴趣的人。 @Zboson,SSSE3 只是一个简单的SHUFB
。
【参考方案1】:
幸运的是pshufd
是 SSE2,你只需要再次解压它。我相信这应该可行:
movd xmm0, eax
punpcklbw xmm0, xmm0
punpcklbw xmm0, xmm0
pshufd xmm0, xmm0, 0x50
pand xmm0, [mask]
pcmpeqb xmm0, [mask]
约翰说:
如果你从一个单词开始,第一个解包会给你一个 dword,让你可以像这样缩短它:
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 个。
【讨论】:
是的,它可以用SHUFPS
短接,但我不确定整数和浮点 sse 指令的混合是否不会引起惩罚。 (我隐约记得在处理这些问题的 SSE 指令中生成非标准化单项会受到惩罚。
不,您的SHUFPS
版本错误。 SHUFPS
也像 PSHUFD
一样对双字进行洗牌,因此需要额外的解包。
嗯,第一个和第二个版本在我的机器上工作(TM)。我从一个单词开始,所以第一个解包给了我一个 dword。
@Johan 查看更新。你不同意吗?另外,SHUFPS
的意义何在,它的功能与PSHUFD
的功能完全相同,因此您可以离开PSHUFD
。
笨蛋,错过了,但是简短的版本可能仍然有用,如果您能够处理位的混合,完全同意SHUFPS
的无用性。它确实为您提供了一种您可以使用的结果 - 咳嗽类型 - 以额外的复杂性为代价。以上是关于解压缩位域(movmskb 的逆)的主要内容,如果未能解决你的问题,请参考以下文章