2016-11-12 6 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命令を生成します。しかし、私の意見では、pcmpistrmpcmistriと同じ方法でプロセッサのフラグレジスタにフラグを設定するので、2番目の命令は冗長です。

私の質問に戻るには、フラグレジスタを直接読み込む方法と、pcmpistrm命令だけを生成するようにコンパイラに指示する方法がありますか?

+1

どのコンパイラでどのオプションを使用できますか?これは、コンパイラがCSEを成功させることの問題であるように思われる。 ISAマニュアルには、[PCMPISTRI](http://www.felixcloutier.com/x86/PCMPISTRI.html)と[PCMPISTRM](http://www.felixcloutier.com/x86)の両方の組み込み関数の1つとして '_mm_cmpistrz'がリストされています/PCMPISTRM.html)、インテルによれば、コンパイラは '_mm_cmpistrz'のいずれかの命令を発行することができます。 –

+0

また、これをコンパイルする関数にラップすることができるので、人々はhttp://gcc.godbolt.org/にコピーできますか?または、Godboltのsource + asm出力にリンクしてください。 –

+0

@Peter Cordesすべての最適化を有効にしてMSVCコンパイラを使用します(/ O2) – Philinator

答えて

1

MSVCの最適化されていないバグのように見えますが、それは固有のものではありません。

#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、および用途に失敗します。

gcc6.2とicc17が正常にテスト関数に1 PCMPISTRMからの両方の結果を使用するには、私はzero結果の枝(on the Godbolt compiler explorer)と書きました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が良いスループットが、高遅延を持っているので、待ち時間がボトルネックになっている場合は、並列に2を行うには、部屋の多くがあります注意してください。 __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

私は真剣に最適化がPUSHFからPCMPISTRMを分離し、整数の加算/減算などからフラグを読み取ることになると心配していました。これが信頼できる場合、スタックにフラグを書き込んだ後にそれらをテストする〜5サイクルのストア転送レイテンシは、少なくともスループットに関して、ほとんどのCPU上の別のPCMPISTRIよりも優れている可能性があります。 PCMPISTRMのスループットは高いものの、レイテンシが高いため、レイテンシが悪くなる可能性があるため、同じ結果を2回生成するために2つを並列に実行すると、余分な5cよりも優れている可能性があります。 –

+0

あなたは正しいです!私は両方のベンチマークを行い、 'pushf 'を使った方が' pcmpistrm'と 'pcmpistri'を並行して使うよりも実際に約1ns遅いです。 – Philinator

+0

ベンチマークが実際のユースケースを反映するように注意してください。待ち時間とスループットは大したことです。 –

関連する問題