2016-07-30 26 views
2

ARM-Intrinsics enthalten Funktionen zum Extrahieren von Skalaren unterschiedlicher Größe. Die Funktionen sind dokumentiert die meisten vollständig im ARM® C Language Extensions:vgetq_lane_u64 (x, 0) versus vget_low_u64 (x)

ET vgetQ_lane_ST(T vec, const int lane); 

erhält den Wert aus der angegebenen Spur eines Eingangsvektors. Es gibt 24 intrinsics.

Und:

T vget_high_ST(T2 a); 
T vget_low_ST(T2 a); 

erhält die hoch oder niedrig ist, die Hälfte eines 128-Bit-Vektor. Es gibt 24 intrinsics.

Ich weiß, dass unter bestimmten Umständen eine Gleichwertigkeit existiert. Zum Beispiel auf einer Little-Endian-Maschine gilt die folgende gilt für 64-Bit-Werte:

uint64x2_t x = ...; 
vgetq_lane_u64(x, 0) == vget_low_u64(x); 

Eine ähnliche Äquivalenz ist für die hohe Spur:

uint64x2_t x = ...; 
vgetq_lane_u64(x, 1) == vget_high_u64(x); 

Meine Frage ist, was sind die praktische Unterschiede, da beide Funktionen einen Skalar liefern? Sollte man dem anderen vorgezogen werden?

+0

'auf einer Little-Endian-Maschine' ist wahrscheinlich nicht relevant, da Sie zu keinem Zeitpunkt ein Array indizieren. Indexelemente in einem Vektorregister sind eher Links/Rechts-Verschiebungen einer Ganzzahl in einem Skalarregister. Ich habe nicht geschaut, aber ich gehe davon aus, dass Architekturen, die in beiden Endianen laufen können, nicht das Verhalten von Anweisungen ändern, die Vektoren mischen oder einen Skalar in einen Vektor einfügen oder aus ihm extrahieren. (Natürlich, wenn der Skalar aus dem Speicher kommt, ist die Endianess für die Reihenfolge der Bytes innerhalb des Skalars wichtig, aber nicht die Elementposition innerhalb des Vektors.) –

Antwort

4

Ich würde die Überlappung ein Implementierungsdetail betrachten. "... da beide Funktionen einen Skalar zurückgeben" ist nicht einmal richtig, für Starter: vgetq_lane_u64() gibt einen uint64_t zurück, der ein Skalar ist; vget_low_u64() gibt einen uint64x1_t zurück, der ein Einheitslängenvektor ist. Bedenken Sie, dass dieser Typ existiert auch:

uint64_t vget_lane_u64(uint64x1_t v, const int lane) 

Semantisch vget_{high,low} verwenden, wo immer Sie eine Q-Register Ausgabe von einer Vektoroperation haben, und muß es spalten, die Daten in weitere Vektoroperationen auf D-Register zu übergeben. Verwenden Sie vget{,q}_lane, wenn Sie tatsächlich einen einzelnen Wert extrahieren, der an Skalarkode übergeben wird. Ich bin mir ziemlich sicher, dass die implizite Konvertierung zwischen Vektortypen der Einheitslänge und skalaren Typen nirgends wirklich garantiert ist, also würde ich mich nicht darauf verlassen.

+0

* "... da beide Funktionen einen Skalar zurückgeben" ist nicht gleich Wahr ... "- Oh, du hast recht; Ich habe dieses Detail vermisst. Es scheint, dass GCC und Clang meist entgegenkommend sind, weil sie zwischen den 'uint64_t' und' uint64x1_t 'ohne Warnung konvertieren. – jww

+0

Ursprünglich dachte ich, der Unterschied liege in der Leichtigkeit der Bewegung zwischen Big-Endian und Little-Endian. Das heißt, ich könnte # die Lane-Nummer definieren und die Definition je nach Big- oder Little-Endian ändern. – jww

+2

@jww Vorsicht [die GCC-Vektorerweiterungen] (https://gcc.gnu.org/onlinedocs/gcc/Vector-Extensions.html#Vector-Extensions) ([ähnlich für Clang]) (http: //clang.llvm. org/docs/LanguageExtensions.html #vectors and-extended-vectors)) - Dank dieser können Sie mit NEON-Typen eine Menge schlampiger Sachen durchgehen. – Notlikethat