Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/155.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 使用SSE 4.2比较两个16字节的值是否相等?_C++_Assembly_Vectorization_Sse_Avx - Fatal编程技术网

C++ 使用SSE 4.2比较两个16字节的值是否相等?

C++ 使用SSE 4.2比较两个16字节的值是否相等?,c++,assembly,vectorization,sse,avx,C++,Assembly,Vectorization,Sse,Avx,我有一个这样的结构: struct { uint32_t a; uint16_t b; uint16_t c; uint16_t d; uint8_t e; } s; 我想以最快的方式比较上面两种结构的相等性。我看了《英特尔Intrinsics指南》,但找不到整数的比较,可用的选项主要是双精度和单浮点向量输入 有人能告诉我最好的方法吗?我可以向我的结构中添加一个并集,以简化处理 我(目前)仅限于使用SSE4.2,但如果AVX的回答速度明显更快,我也欢迎

我有一个这样的结构:

struct {
    uint32_t a;
    uint16_t b;
    uint16_t c;
    uint16_t d;
    uint8_t  e;
} s;
我想以最快的方式比较上面两种结构的相等性。我看了《英特尔Intrinsics指南》,但找不到整数的比较,可用的选项主要是双精度和单浮点向量输入

有人能告诉我最好的方法吗?我可以向我的结构中添加一个并集,以简化处理


我(目前)仅限于使用SSE4.2,但如果AVX的回答速度明显更快,我也欢迎。我使用的是GCC4.8.2

一个简单的解决方案是在屏蔽后按字节减去两个结构,这样只有当所有压缩字节都相同时,才能得到一个全零值。这段代码是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/32字节的AVX(x)没有意义。

@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
执行按位和作为其操作的一部分,因此根本不需要单独的
PAND

有一段时间,我认为我有一个版本可以使用更少的空间和更少的UOP,但我最终需要一个额外的指令,因为没有
pcmpneq
(所以我需要一个逻辑
而不是
)。因此它更小,UOP的数量相同,但延迟明显更差

.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个计量单位,因此
ptest
版本总共是4个计量单位(包括
jcc
或其他指令)。
pmovskb
版本也是4个UOP,带有
test
/
jcc
宏融合分支,但5个UOP带有
cmovcc
/
setcc
。(4带有
和n
,带有任何
setcc
/
cmovcc
/
jcc
,因为它不能进行宏融合`。)

(Agner Fog的表格显示,
ptest
在Sandybridge上取1个融合域uop,在所有支持它的英特尔CPU上取2个。不过,我不确定我是否相信这一点。)

Haswell上的延迟(如果分支不能很好地预测,则很重要):

  • pxor
    :1+
    ptest
    :2=3个周期
  • pcmpeqb
    :1+
    pmovmskb
    :3+
    :1+
    测试
    :1=6个周期
  • pcmpeqb
    :1+
    pmovmskb
    :3+
    和n
    :1=5个周期(但不是宏融合,因此可能还有1个周期的延迟?)
因此,
ptest
版本的延迟显著缩短:
jcc
可以更快地执行,以更快地检测分支预测失误


Agner Fog的测试显示,
ptest
在Nehalem上的延迟为3,在SnB/IvB上的延迟为1,在Haswell上的延迟为2。

您可以使用
PCMPEQ
系列中的任何整数比较,我看不出您的问题。此结构基本上是打包的。你能假设这永远是真的吗?似乎
memcmp(&s1,&s2,sizeof(struct s))
可能是最少的时间投资。利用memcmp提供的任何优化功能。@JonathonReinhart yes可以假设压缩。@Jester\u mm\u cmpeq\u epi64只接受64位输入?该结构只有11个字节;因此,在进行比较之前,您需要屏蔽掉未使用的5个字节(以防它们包含垃圾);或者比较压缩字节并屏蔽未使用的5个字节的结果。在现代64位计算机上,使用
uint16\u t e
将其设置为12个字节,并使用枯燥的老式“非SIMD”整数比较进行64位比较和32位比较可能会更快(特别是如果您没有处理这些结构的数组)……或者,您可以使用
pxor
而不是
psub
,而且只需
pand
一次。您根本不需要
pand
。将掩码用作一个操作数,以
ptest
;这就是它的目的!您可以在
psubb
(字节减法)或
pxor
之后进行掩码,但是
pxor
可以在
psubb
无法运行的一个端口(SnB端口0)上运行,这是一个很好的调用。