Ist es meine Einbildung, oder fehlt eine Anweisung PNOT
von SSE und AVX? Das heißt, eine Anweisung, die jedes Bit im Vektor umlegt.
Wenn ja, gibt es eine bessere Möglichkeit, es als PXOR
mit einem Vektor aller 1s zu emulieren? Ziemlich nervig, da ich einen Vektor aller 1s einrichten muss, um diesen Ansatz zu verwenden.
In solchen Fällen kann es hilfreich sein zu sehen, was ein Compiler erzeugen würde.
z. für die folgende Funktion:
%Vor%Sowohl gcc als auch clang scheinen viel denselben Code zu generieren :
%Vor% Sie können dafür den PANDN
OpCode verwenden.
PANDN
implementiert die Operation
oder
%Vor%Die Kombination dieser Operation mit einem All-Einsen-Vektor führt effektiv zu einer PNOT -Operation.
Einige x86 (SSEx) Assembly-Code würde wie folgt aussehen:
%Vor%Einige x86 (AVXx) Assembly-Code würde wie folgt aussehen:
%Vor%Beide können (natürlich) leicht in intrinsisch übersetzt werden.
AVX512F vpternlogd
/ _mm512_ternarylogic_epi32(__m512i a, __m512i b, __m512i c, int imm8)
bietet schließlich eine Möglichkeit, NOT ohne zusätzliche Konstanten zu implementieren, indem eine einzige Anweisung verwendet wird (mit 2 pro Takt Durchsatz auf Skylake-avx512 und KNL, also ist es nicht so gut wie PXOR / XORPS für 256b und kleinere Vektoren. )
vpternlogd zmm,zmm,zmm, imm8
hat 3 Eingabevektoren und einen Ausgang, um das Ziel an Ort und Stelle zu ändern. Mit der richtigen sofortigen, können Sie immer noch eine Kopie-und-NOT in ein anderes Register implementieren, aber es wird eine "falsche" Abhängigkeit von der Ausgabe-Register (die vpxord dst, src, all-ones
hätte nicht).
TL: DR: benutze wahrscheinlich immer noch xor mit All-Einsen als Teil einer Schleife, außer wenn dir die Register ausgehen. vpternlog
kann einen zusätzlichen vmovdqa
register-copy-Befehl kosten, wenn seine Eingabe später benötigt wird. Außerhalb von Schleifen ist vpternlogd zmm,zmm,zmm, 0xff
Compiler beste Option für die Erstellung eines 512b All-One-Vektors an erster Stelle , da AVX512-Vergleiche Anweisungen in Masken vergleichen ( k0-k7
), so dass XOR mit All-Einsen möglicherweise bereits einen vpternlogd
oder vielleicht ein Broadcast-Konstante aus dem Speicher.
Für jede Bitposition i
ist das Ausgabe-Bit imm[ (DEST[i]<<2) + (SRC1[i]<<1) + SRC2[i]]
, wobei imm8
als Bitmap mit 8 Elementen behandelt wird.
Wenn wir also wollen, dass das Ergebnis nur von SRC2 abhängt (was der zmm/m512/m32bcst
-Operand ist), sollten wir eine Bitmap wählen, die 1,0 wiederholt, mit 1
an den geraden Positionen (ausgewählt von src2=0
).
Wenn Sie Glück haben, wird ein Compiler _mm512_xor_epi32(v, set1(-1))
auf vpternlogd
für Sie optimieren, wenn es profitabel ist.
Wenn Sie nicht sicher sind, ob das eine gute Idee ist, halten Sie es einfach und verwenden Sie die gleiche Variable für alle 3 Eingaben:
%Vor%