Was können Sie mit SSE4.1 ptest
anders machen, als zu testen, ob ein einzelnes Register nur aus Null besteht?
Können Sie eine Kombination aus SF und CF verwenden, um etwas Nützliches über zwei unbekannte Eingangsregister zu testen?
Wofür ist PTEST gut? Sie würden denken, dass es gut wäre, das Ergebnis eines gepackten Vergleichs (wie PCMPEQD oder CMPPS) zu überprüfen, aber zumindest auf Intel-CPUs, es kostet mehr UPs zu vergleichen und verzweigen mit PTEST + JCC als mit PMOVMSK (B / PS / PD) + Makro-fusionierte CMP + JCC.
Siehe auch Überprüfen, ob TWO SSE-Register sind nicht Null, ohne sie zu zerstören
Nein, es sei denn, ich verpasse etwas Schlaues, ptest
mit zwei unbekannten Registern ist normalerweise nicht nützlich, um eine Eigenschaft über beide zu überprüfen. (Abgesehen von offensichtlichen Dingen, die Sie bereits bitweise wollen - UND für Schnittpunkte zwischen zwei Bitmaps).
Um zwei Register zu testen, die beide alle Null sind, OR sie zusammen und PTEST das gegen sich selbst.
ptest xmm0, xmm1
erzeugt zwei Ergebnisse:
xmm0 & xmm1
alles-null? (~xmm0) & xmm1
alle null? Wenn der zweite Vektor nur aus Null besteht, hängen die Flags überhaupt nicht von den Bits im ersten Vektor ab.
Es kann nützlich sein, an die "is-all-zero" Prüfungen als NOT(bitwise horizontal-OR())
der AND- und ANDNOT-Ergebnisse zu denken. Aber wahrscheinlich nicht, weil das zu viele Schritte sind, damit mein Gehirn leicht durchdenken kann. Diese Folge von vertikalem UND und dann horizontalem ODER macht es vielleicht leichter zu verstehen, warum PTEST nicht viel über eine Kombination zweier unbekannter Register erzählt, genau wie die Integer-Anweisung TEST.
Hier ist eine Wahrheitstabelle für eine 2-Bit ptest a,mask
. Hoffentlich hilft dies beim Nachdenken über Mischungen von Nullen und Einsen mit 128b Eingaben.
Beachten Sie, dass CF(a,mask) == ZF(~a,mask)
.
Intels intrinsics guide listet 2 interessante intrinsics dafür auf . Beachten Sie die Benennung der Argumente: a
und mask
sind ein Hinweis darauf, dass sie Ihnen die Teile von a
mitteilen, die von einer bekannten UND-Maske ausgewählt wurden.
_mm_test_mix_ones_zeros (__m128i a, __m128i mask)
: gibt (ZF == 0 && CF == 0)
zurück
_mm_test_all_zeros (__m128i a, __m128i mask)
: gibt ZF
zurück
Es gibt auch die einfacheren Versionen:
int _mm_testc_si128 (__m128i a, __m128i b)
: gibt CF
zurück
int _mm_testnzc_si128 (__m128i a, __m128i b)
: gibt (ZF == 0 && CF == 0)
zurück
int _mm_testz_si128 (__m128i a, __m128i b)
: gibt ZF
zurück
Es gibt AVX2 __m256i
Versionen dieser intrinsics, aber die Anleitung listet nur die Versionen all_zeros und mix_ones_zeros alternativer Namen für __m128i
operands auf.
Wenn Sie eine andere Bedingung aus C oder C ++ testen möchten, sollten Sie testc
und testz
mit denselben Operanden verwenden und hoffen, dass Ihr Compiler erkennt, dass er nur einen PTEST ausführen und hoffentlich sogar verwenden muss ein einzelner JCC, SETCC oder CMOVCC, um Ihre Logik zu implementieren. (Ich würde empfehlen, die ASM zu überprüfen, zumindest für den Compiler, den Sie am meisten interessieren.)
Beachten Sie, dass _mm_testz_si128(v, set1(0xff))
immer gleich _mm_testz_si128(v,v)
ist, denn so funktioniert AND. Aber das stimmt nicht für das CF-Ergebnis.
Mit
können Sie prüfen, ob ein Vektor ein Einsen ist %Vor%Dies ist wahrscheinlich nicht schneller, aber kleinere Code-Größe, als ein PCMPEQB gegen einen Vektor von All-Einsen, dann die übliche Movemask + CMP. Es vermeidet nicht die Notwendigkeit für eine Vektorkonstante.
PTEST hat den Vorteil, dass es auch ohne AVX keinen der Eingangsoperanden zerstört.
Tags und Links assembly x86 sse intrinsics sse4