我有这样的结构:
struct {
uint32_t a;
uint16_t b;
uint16_t c;
uint16_t d;
uint8_t e;
} s;
我想以最快的方式比较上述两个结构的平等性。我查看了英特尔内部指南但无法找到整数的比较,可用的选项主要是双精度和单浮点矢量输入。
有人可以建议最好的方法吗?我可以在我的struct中添加一个union来使处理更容易。
我受限于(目前)使用SSE4.2,但如果它们明显更快,任何AVX答案都会受到欢迎。我正在使用GCC 4.8.2
答案 0 :(得分:2)
@ zx485应该写的是:
.data
mask11byte db 0ffh,0ffh,0ffh,0ffh,0ffh,0ffh,0ffh,0ffh,0ffh,0ffh,0ffh,0,0,0,0,0
.code
pxor xmm1, xmm2 ; equiv to psubb, but runs on all 3 vector execution ports
ptest xmm1, xmmword ptr [mask11byte] ; SSE 4.1
setz al ; AL=TRUE for equal
只要没有发生任何不良事件(浮点异常),您就不需要在计算之前屏蔽操作数,即使它们存在垃圾。由于PTEST
执行按位AND作为其操作的一部分,因此您根本不需要单独的PAND
。
有一段时间,我认为我的版本可以使用更少的空间和更少的微量,但我最终需要额外的指令,因为没有pcmpneq
(所以我需要一个逻辑not
) 。所以它更小,相同数量的uops,但延迟明显更差。
.code
PCMPEQB xmm1, xmm2 ; bytes of xmm1 = 0xFF on equal
PMOVMSKB eax, xmm1 ; ax = high bit of each byte of xmm1
NOT eax
TEST eax, 0x7FF ; zero flag set if all the low 11 bits are zero
SETZ al ; 17 bytes
; Or one fewer insn with BMI1's ANDN. One fewer uop if test can't macro-fuse
ANDN eax, eax, [mask11bits] ; only test the low 11 bits.
; ANDN version takes 20 bytes, plus 2B of data
.data
mask11bits dw 07ffh
test
可以与jcc
进行宏观融合,因此,如果您将其用作跳转条件而不是实际执行setz
,那么您的尺寸就会提前。 (因为你不需要16B掩模常量。)
ptest
需要2 uop,因此ptest
版本总计为4 uops(包括jcc
或其他指令)。 pmovmskb
版本也是4 uops,test
/ jcc
宏融合分支,但cmovcc
/ setcc
5。 (4 andn
,setcc
/ cmovcc
/ jcc
,因为它无法宏观融合。)
(Agner Fog的表格说ptest
在Sandybridge上占用1个融合域uop,在支持它的所有其他Intel CPU上占2个。但我不确定我是否相信。)
Haswell的延迟(如果分支不能很好地预测,则很重要):
pxor
:1 + ptest
:2 = 3个周期pcmpeqb
:1 + pmovmskb
:3 + not
:1 + test
:1 = 6个周期pcmpeqb
:1 + pmovmskb
:3 + andn
:1 = 5个周期(但不是宏融合,可能还有1个延迟周期?)因此ptest
版本的延迟时间明显缩短:jcc
可以更快地执行,以便更快地检测到分支错误预测。
Agner Fog的测试显示ptest
在Nehalem上有延迟= 3,在SnB / IvB上有1,在Haswell上有2。
答案 1 :(得分:0)
一个简单的解决方案是在屏蔽后以字节方式减去两个结构,因此只有当所有压缩字节相同时才能获得全零值。此代码采用MASM格式,但您肯定可以将其改编为gcc AT& T语法或内在函数:
.data
mask11byte db 0ffh,0ffh,0ffh,0ffh,0ffh,0ffh,0ffh,0ffh,0ffh,0ffh,0ffh,0,0,0,0,0
.code
pand xmm1, xmmword ptr [mask11byte]
pand xmm2, xmmword ptr [mask11byte]
psubb xmm1, xmm2
ptest xmm1, xmm1 ; SSE 4.1
setz al ; AL=TRUE for equal
添加:因为结构的大小是11字节,256bit / 32byte-AVX(x)是没有意义的。