2011-11-03 7 views
11

Come si verifica se una variabile __m128i ha un valore diverso da zero su processori SSE-2 e precedenti?È una variabile __m128i zero?

+0

Si intende un elemento non zero o un elemento intero 8/16/32-bit? –

+0

@BrettHale: sto testando per vedere se sono tutti a zero. – Mehrdad

risposta

11

In SSE2 si può fare:

__m128i zero = _mm_setzero_si128(); 
if(_mm_movemask_epi8(_mm_cmpeq_epi32(x,zero)) == 0xFFFF) 
{ 
    //the code... 
} 

questo metterà alla prova quattro int del vs pari a zero per poi tornare una maschera per ogni byte, in modo che i bit-offset di ciascuna delle quali corrisponde int sarebbero a 0, 4, 8 & 12, ma il test sopra riportato verrà catturato se viene impostato un bit qualsiasi, quindi se si conserva la maschera è possibile lavorare direttamente con le parti a grana più fine, se necessario.

+2

+1, è meglio del mio. :) Non ho mai usato l'istruzione movemask, quindi non sapevo che potessi farlo. XD – Mysticial

+0

+1 soluzione più compatta che ho visto, grazie! – Mehrdad

+3

C'è un bug nella risposta altrimenti eccellente - se stai controllando tutti gli zeri, dovrebbe essere 'if (_mm_movemask_epi8 (_mm_cmpeq_epi32 (x, zero)) == 0xFFFF)'. Questo perché '_mm_cmpeq_epi32' imposta l'int a tutti gli 1, non a tutti gli 0, se è uguale a zero, e quindi' _mm_movemask_epi8' imposta i primi 16 bit in base al bit più significativo di ogni byte nell'argomento. Spero che l'autore possa modificare la risposta - ho provato ma è stata respinta. – FarmerBob

1

Per motivi di completezza, con SSE4 è possibile utilizzare _mm_testz_si128.

const bool isAllZero = _mm_testz_si128(a,a); 

noti che questo è vero quando tutti i bit sono uguali a zero.

+1

Questo è in realtà leggermente più veloce, e non ha bisogno di un registro tutto-zero per testare contro. 'ptest' /' jz' è 2 + 1 uop (non macro-fuse). 'pcmpeq' (1uop) /' pmovmsk' (1uop)/'e 0xffff' (1uop) /' cmp 0xffff/je' (1uop). Se stavi testando l'altro caso (* qualsiasi * zero elementi, piuttosto che * tutti * zero elementi), avrebbero approssimativamente le stesse prestazioni sulle attuali CPU Intel e AMD: 'ptest' /' jnz' (3 uops) vs . 'pcmpeq' /' pmovmsk'/'test/jnz' (3 uops). –

+0

@PeterCordes Che dire, in tal caso, avere un registro impostato su tutti e utilizzare '_mm_testc_si128'? Qualcosa come 'const bool atLeastOneZero = _mm_testc_si128 (a, allOnes)' – Antonio

+1

Ancora, 'ptest' è leggermente più veloce. Per farlo senza 'ptest', dovresti' pcmpeq' contro il vettore all-ones, e poi procedi esattamente con la stessa sequenza per verificare che tutti gli elementi corrispondano. Il controllo di tutto-zero o tutto-uno con 'pcmpeq' è lo stesso che per il controllo di == su qualsiasi altro modello, eccetto che le costanti sono più facili da generare al volo (' pxor same, same' o 'pcmpeqw same, same'). –