2015-06-11 32 views
3

我有這樣的結構:使用最多SSE 4.2比較兩個16字節的值是否相等?

struct { 
    uint32_t a; 
    uint16_t b; 
    uint16_t c; 
    uint16_t d; 
    uint8_t e; 
} s; 

,我想比較兩個平等上述結構的,儘可能以最快的方式。我查看了「英特爾內核指南」,但無法找到整數的比較結果,可用的選項主要是雙精度和單浮點向量輸入。

請問有人請告知最好的方法?我可以在我的結構中添加一個聯合以使處理更容易。

我受限於(現在)使用SSE4.2,但任何AVX答案也會受到歡迎,如果他們明顯更快。我使用GCC 4.8.2

+2

你可以使用'PCMPEQ'系列的任何整數比較,我沒有看到你的問題。 – Jester

+3

這個結構本質上是打包的。你能假定永遠是真的嗎?它看起來像一個'memcmp(&s1,&s2,sizeof(struct s))'可能是最少的投資時間。利用'memcmp'提供的任何優化。 –

+0

@JonathonReinhart是可以假設包裝。 – user997112

回答

0

簡單的解決辦法是隻減去兩個結構明智字節屏蔽等以後你只有在所有壓縮字節是相同的全零值。此代碼是MASM格式,但你一定能適應,爲GCC AT & T語法或intrinsicals:

.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字節,256位/ 32字節-AVX(X)將沒有意義。

+0

......或者,你可以使用'pxor'而不是'psub',並且只使用'pand'一次。 – EOF

+0

你根本不需要'pand'。使用掩碼作爲「ptest」的一個操作數;這就是它的目的!你可以在'psubb'(逐字節減法)或'pxor'後面屏蔽,但'pxor'可以在一個'psubb'不能(SnB端口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個uops,所以ptest版本總共是4個uops(包括jcc或其他指令)。所述pmovmskb版本也4個微指令具有test/jcc宏稠合分支,但5 cmovcc/setcc。 (4 andn,與任何setcc/cmovcc/jcc,因爲它不能宏觀fuse`。)

(昂納霧的桌子說:ptest承擔的SandyBridge,2:1融合域UOP上的所有其它英特爾CPU,這些CPU支持它,但我不確定我是否相信。)

延遲上的Haswell(重要的,如果該分支不預測井):

  • pxor:1 + ptest:2 = 3個週期
  • pcmpeqb:1 + pmovmskb:3 + not:1 + test:1 = 6個週期
  • pcmpeqb:1 + pmovmskb:3 + andn:1 = 5個週期(?但不是宏稠合的,所以有可能更多的循環等待時間的)

因此,ptest版本具有顯着縮短的延遲:jcc可以更快執行,以更快地檢測分支預測失誤。

Agner Fog的測試顯示ptest在Nehalem上的延遲= 3,在SnB/IvB上是1,在Haswell上是2。

相關問題