5 Stimmen

Wie kann man mit NEON SIMD die Elemente von 2 Reihen zusammenführen?

Ich habe eine

A = a1 a2 a3 a4
    b1 b2 b3 b4
    c1 c2 c3 c4
    d1 d2 d3 d4

Ich habe 2 Reihen mit mir,

float32x2_t a = a1 a2
float32x2_t b = b1 b2

Wie kann ich daraus eine -

float32x4_t result = b1 a1 b2 a2

Gibt es irgendwelche einzelner NEON SIMD-Befehl die diese beiden Zeilen zusammenführen kann? Oder wie kann ich dies in möglichst wenigen Schritten mit Hilfe von Intrinsics erreichen?

Ich dachte an die Verwendung des zip/unzip Intrinsics, sondern der Datentyp der Zip-Funktion zurück, was float32x2x2_t ist für mich nicht geeignet, ich brauche eine float32x4_t Datentyp.

float32x2x2_t vzip_f32 (float32x2_t, float32x2_t)

5voto

Nils Pipenbrinck Punkte 80152

Das ist schwierig Es gibt nicht eine einzige Anweisung, die dies tun kann, und die beste Lösung hängt davon ab, ob sich Ihre Daten im Speicher befinden oder ob sie bereits in Registern gespeichert sind.

Für die Umwandlung sind mindestens zwei Vorgänge erforderlich. Erstens eine Vektorumkehr, die Ihre Argumente wie folgt umwandelt:

a = a1 a2
b = b1 b2

vtrn.32  a, b

a = a1 b1 
b = a2 b2

Und dann müssen Sie die Argumente jeder Operation vertauschen. Entweder, indem man jeden Vektor für sich umkehrt oder indem man die beiden Vektoren als einen Vierfachvektor behandelt und eine lange Umkehrung durchführt.

temp = {a, b} 
temp = a1 b1 a2 b2

vrev64.32 temp, temp

temp = b1 a1 b2 a2    <-- this is what you want.

Wenn Sie Ihre Daten aus dem Speicher laden, können Sie die erste Anweisung vtrn.32 überspringen, da NEON dies tun kann, während es die Daten mit der Anweisung vld2.32 lädt. Hier ist eine kleine Assembler-Funktion, die genau das tut:

.globl asmtest

asmtest:
        vld2.32     {d0-d1}, [r0]   # load two vectors and transose
        vrev64.32   q0, q0          # reverse within d0 and d1
        vst1.32     {d0-d1}, [r0]   # store result
        mov pc, lr                  # return from subroutine..

Übrigens, eine kleine Anmerkung: Die Anweisungen vtrn.32, vzip.32 und vuzp.32 sind identisch (aber nur, wenn Sie mit 32-Bit-Entitäten arbeiten)

Und mit NEON intrinsics? Nun - einfach gesagt, Sie sind aufgeschmissen. Wie du bereits herausgefunden hast, kannst du nicht direkt von einem Typ auf einen anderen casten und du kannst nicht direkt Quad- und Double-Vektoren mischen.

Dies ist das Beste, was mir unter Verwendung von Intrinsics eingefallen ist (es verwendet nicht den vld2.32-Trick für die Lesbarkeit):

int main (int argc, char **args)
{
  const float32_t data[4] =
  {
    1, 2, 3, 4
  };

  float32_t     output[4];

  /* load test vectors */
  float32x2_t   a = vld1_f32 (data + 0);
  float32x2_t   b = vld1_f32 (data + 2);

  /* transpose and convert to float32x4_t */
  float32x2x2_t temp   = vzip_f32 (b,a);
  float32x4_t   result = vcombine_f32 (temp.val[0], temp.val[1]);

  /* store for printing */
  vst1q_f32 (output, result);

  /* print out the original and transposed result */
  printf ("%f %f %f %f\n", data[0],   data[1],   data[2],   data[3]);
  printf ("%f %f %f %f\n", output[0], output[1], output[2], output[3]);
}

Wenn Sie GCC verwenden, wird dies funktionieren, aber der von GCC erzeugte Code wird schrecklich und langsam sein. NEON intrinsische Unterstützung ist noch sehr jung. Sie werden wahrscheinlich eine bessere Leistung mit einem geraden C-Code hier erhalten.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X