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.