2015-12-08 4 views
10

Ich muss überprüfen, dass alle Vektorelemente nicht Null sind. Bisher habe ich folgende Lösung gefunden. Gibt es einen besseren Weg, dies zu tun? Ich verwende gcc 4.8.2 unter Linux/x86_64, Anweisungen bis zu SSE4.2.SIMD/SSE: Wie überprüft man, dass alle Vektorelemente nicht Null sind

typedef char ChrVect __attribute__((vector_size(16), aligned(16))); 

inline bool testNonzero(ChrVect vect) 
{ 
    const ChrVect vzero = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; 
    return (0 == (__int128_t)(vzero == vect)); 
} 

Update: Code über folgende Assembler-Code kompiliert wird (wenn sie als nicht-Inline-Funktion kompiliert):

movdqa %xmm0, -24(%rsp) 
pxor %xmm0, %xmm0 
pcmpeqb -24(%rsp), %xmm0 
movdqa %xmm0, -24(%rsp) 
movq -24(%rsp), %rax 
orq -16(%rsp), %rax 
sete %al 
ret 
+0

Für welche Architektur interessieren Sie sich? x86? LEISTUNG? ARM? ...? –

+0

x86_64, Anweisungen bis SSE4.2 –

+0

Warum nicht? Return ((__int128_t) (vzero == vect) == 0) 'aber' return (0 == (__int128_t) (vzero == vect)) '? Vielleicht ist es "modern"? – i486

Antwort

7

Mit gerade SSE intrinsics könnten Sie es wie folgt tun:

inline bool testNonzero(__m128i v) 
{ 
    __m128i vcmp = _mm_cmpeq_epi8(v, _mm_setzero_si128()); 
#if __SSE4_1__ // for SSE 4.1 and later use PTEST 
    return _mm_testz_si128(vcmp, vcmp); 
#else   // for older SSE use PMOVMSKB 
    uint32_t mask = _mm_movemask_epi8(vcmp); 
    return (mask == 0); 
#endif 
} 

Ich schlage vor, zu sehen, was Ihr Compiler derzeit für Ihren vorhandenen Code generiert und vergleichen Sie es dann mit dieser Version mit intrinsics und siehe i f gibt es einen signifikanten Unterschied.

Mit SSE3 (clang -O3 -msse3) erhalte ich die folgende für die obige Funktion:

pxor %xmm1, %xmm1 
pcmpeqb %xmm1, %xmm0 
pmovmskb %xmm0, %ecx 
testl %ecx, %ecx 

Die SSE4-Version (clang -O3 -msse4.1) produziert:

pxor %xmm1, %xmm1 
pcmpeqb %xmm1, %xmm0 
ptest %xmm0, %xmm0 

Beachten Sie, dass die Nullpunkteinstellung von xmm1 wird in der Regel hochgezogen werden, Aus jeder Schleife, die diese Funktion enthält, sollten die obigen Sequenzen um eine Anweisung reduziert werden, wenn sie innerhalb einer Schleife verwendet werden.

+1

Danke. Ich habe versucht, es gegen meinen ursprünglichen Code zu benchmarken und es ist schneller. Wenn ich es als Nicht-Inline-Funktion verwendete, war die Geschwindigkeitssteigerung ziemlich gering - etwa 2%. Wenn die Funktion inline war, war deine Version um 26% schneller. –

+0

@ DanielFrużyński: Sie können die aktualisierte Version oben mit Harolds vorgeschlagener Änderung versuchen - ich denke, dass dies einen Zyklus der Latenz auf einigen CPUs speichern kann. –

+1

Würde 'ptest' hier irgendeinen Nutzen haben? – Mysticial

Verwandte Themen