2015-01-12 8 views
7

Ich bin mit intrinsics SSE, um zu bestimmen, ob ein Rechteck (definiert durch vier int32 Werte) geändert hat:effizienteste Weg, um zu überprüfen, ob alle __m128i Komponenten 0 sind [mit SSE intrinsics]

__m128i oldRect; // contains old left, top, right, bottom packed to 128 bits 
__m128i newRect; // contains new left, top, right, bottom packed to 128 bits 

__m128i xor = _mm_xor_si128(oldRect, newRect); 

An diesem Punkt, Der sich ergebende Wert xor ist nur Nullen, wenn das Rechteck nicht geändert wurde. Was ist dann der effizienteste Weg, das zu bestimmen?

Zur Zeit mache ich so:

if (xor.m128i_u64[0] | xor.m128i_u64[1]) 
{ 
    // rectangle changed 
} 

Aber ich nehme an, es ist ein intelligenter Weg (möglicherweise einige SSE Anweisung verwendet, die ich noch nicht gefunden haben).

I SSE4.1- auf x64 bin Targeting und ich bin Codierung C++ in Visual Studio 2013

+1

Warum beziehen Sie sich auf einen 128-Bit-Ganzzahlwert als 'NULL', was eine Null * -Zeiger * -Konstante ist? –

+0

@KeithThompson 'NULL' ist ein Makro, das auf 0 erweitert wird. C++ hat' nullptr' als Nullzeigerkonstante. – d7samurai

+1

'NULL' wird zu einer Implementierung erweitert, die C++ - Nullzeigerkonstante definiert. Es * könnte * zu "nullptr" erweitern. Selbst wenn es zu "0" expandiert, sollte es nicht als Ganzzahl verwendet werden. –

Antwort

10

Sie die PTEST instuction über die _mm_testz_si128 intrinsische (SSE4.1-) verwenden können, wie folgt aus:

#include "smmintrin.h" // SSE4.1 header 

if (!_mm_testz_si128(xor, xor)) 
{ 
    // rectangle has changed 
} 

Beachten Sie, dass _mm_testz_si128 1 zurückgibt, wenn die bitweise der beiden Argumente Null ist.

5

Ironischerweise ptest Anweisung von SSE 4.1 möglicherweise langsamer als pmovmskb von SSE2 in einigen Fällen. Ich schlage vor, mit einfach:

__m128i cmp = _mm_cmpeq_epi32(oldRect, newRect); 
if (_mm_movemask_epi8(cmp) != 0xFFFF) 
    //registers are different 

Beachten Sie, wenn Sie wirklich brauchen, dass xor Wert, werden Sie es separat berechnen müssen.

Für Intel-Prozessoren wie Ivy Bridge, die Version von paulr mit xor und _mm_testz_si128 in 4 Uops übersetzt, während vorgeschlagene Version ohne xor Berechnung in 3 Uops übersetzt (siehe auch this thread). Dies kann zu einem besseren Durchsatz meiner Version führen.

+0

Sehr interessanter Thread. Vielen Dank! –

+0

Ist diese zusätzliche Latenz immer noch ein Problem bei Haswell? Ich denke, ich sollte etwas Benchmark-Code schreiben und es überprüfen ... –

+0

@PaulR: Ich verstehe nicht, über welche Latenz Sie sprechen. Normalerweise sehe ich nur den Durchsatz, weil Latenz viel schwieriger zu analysieren und zu messen ist = ( Und hier "langsamer" ist auch im Sinne von Durchsatz, nicht Latenz. In einigen Fällen ist der Durchsatz von vektorisiertem Code durch Frontend begrenzt, die nur verarbeiten kann eine begrenzte Anzahl von Ups pro Zyklus, also in diesen Fällen: mehr Ups = langsamerer Durchsatz – stgatilov