Kann PTEST verwendet werden, um zu testen, ob zwei Register entweder Null oder eine andere Bedingung sind?

8

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

    
Peter Cordes 30.04.2017, 23:03
quelle

1 Antwort

5

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:

  • ZF = ist xmm0 & xmm1 alles-null?
  • CF = ist (~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) .

%Vor%

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.

    
Peter Cordes 30.04.2017, 23:03
quelle

Tags und Links