2016-11-12 64 views
2

我想知道是否可以通過英特爾的SSE內部函數檢查處理器的標誌寄存器嗎?SSE內在函數檢查零標誌

例如:

int idx = _mm_cmpistri(mmrange, mmstr, 0x14); 
int zero = _mm_cmpistrz(mmrange, mmstr, 0x14); 

在該示例中,編譯器能夠這兩個內在優化對單個指令(pcmpistri)並檢查標誌由一個跳轉指令(jz)寄存器。

然而,在下面的示例中,編譯器不管理正確優化的代碼:

__m128i mmmask = _mm_cmpistrm(mmoldchar, mmstr, 0x40); 
int zero = _mm_cmpistrz(mmoldchar, mmstr, 0x40); 

這裏,編譯器會生成一個pcmpistrmpcmpistri指令。但是,在我看來,第二條指令是多餘的,因爲pcmpistrm以與pcmistri相同的方式設置處理器的標誌寄存器中的標誌。

因此,回到我的問題,有沒有辦法直接讀取標誌寄存器或指示編譯器只生成pcmpistrm指令?

+1

哪個編譯器有哪些選項?這看起來更像是編譯器成功CSEing的一個問題。 ISA手冊列出'_mm_cmpistrz'作爲[PCMPISTRI](http://www.felixcloutier.com/x86/PCMPISTRI.html)和[PCMPISTRM](http://www.felixcloutier.com/x86)的內部函數之一/PCMPISTRM.html),所以根據Intel的說法,編譯器可以發出'_mm_cmpistrz'指令。 –

+0

另外,你可以將它包裝在一個編譯的函數中,以便人們可以將它複製到http://gcc.godbolt.org/上?或者更好的是,你自己鏈接到Godbolt上的source + asm輸出。 –

+0

@Peter Cordes我在啓用了所有優化的情況下使用了MSVC編譯器(/ O2) – Philinator

回答

1

看起來只是一個MSVC錯過的優化錯誤,並非任何固有的東西。

gcc6.2和icc17在測試功能成功地使用從一個PCMPISTRM兩個結果我寫的zero結果分支(on the Godbolt compiler explorer):

#include <immintrin.h> 
__m128i foo(__m128i mmoldchar, __m128i mmstr) 
{  
    __m128i mmmask = _mm_cmpistrm(mmoldchar, mmstr, 0x40); 
    int zero = _mm_cmpistrz(mmoldchar, mmstr, 0x40); 
    if(zero) 
    return mmmask; 
    else 
    return _mm_setzero_si128(); 
} 

    ##gcc6.2 -O3 -march=nehalem 
    pcmpistrm  xmm0, xmm1, 64 
    je  .L5 
    pxor xmm0, xmm0 
    ret 
.L5: 
    ret 

OTOH,clang3.9未能CSE,和用途一個PCMPISTRI。

foo: 
    movdqa xmm2, xmm0 
    pcmpistri  xmm2, xmm1, 64 
    pxor xmm0, xmm0 
    jne  .LBB0_2 
    pcmpistrm  xmm2, xmm1, 64 
.LBB0_2: 
    ret 

注意的是,根據Agner Fog's instruction tables,PCMPISTRM具有良好的吞吐量,但高延遲,所以有很大的空間做兩平行,如果延遲是瓶頸。跳過像使用__readflags()箍可能實際上更糟糕。

0

我自己找到了解決方案。

有一個讀取標誌寄存器的函數,稱爲__readeflags()。它包裝了pushf(在x64 plattforms上的pushfq)指令。

現在,該代碼如下所示:

__m128i mmmask = _mm_cmpistrm(mmoldchar, mmstr, 0x40); 
int zero = __readeflags() & 0x40; //0x40 is the mask for the zero flag (bit 6) 

這個解決方案不是最佳的,但它的伎倆。

+1

我真的擔心優化可能會將PCMPISTRM從PUSHF中分離出來,並導致從整數加/減等操作中讀取標誌。如果這是可靠的,那麼將標誌寫入堆棧的〜5個週期的存儲轉發延遲,然後對它們進行測試可能比大多數CPU上的另一個PCMPISTRI更好,至少對於吞吐量來說。對於延遲,可能會更糟糕,因爲PCMPISTRM具有良好的吞吐量,但延遲時間很長,所以並行運行兩次以產生兩次相同的結果可能會比一個額外的5c更好! –

+0

你是對的!我只是對兩種解決方案進行了基準測試,使用'pushf'的測試比使用'pcmpistrm'和'pcmpistri'的測試慢了大約1ns。 – Philinator

+0

小心您的基準測試反映了您的真實使用案例。延遲與吞吐量有很大關係。 –