Wie man GCC sagen, dass ein Zeiger-argument ist immer double-word-aligned?
In meinem Programm habe ich eine Funktion, welche eine einfache addition c[0:15] = a[0:15] + b[0:15]
. Der Funktionsprototyp lautet:
void vecadd(float * restrict a, float * restrict b, float * restrict c);
Auf unsere 32-bit-embedded-Architektur gibt es eine load/store-option laden/speichern von doppelten Worte, wie:
r16 = 0x4000 ;
strd r0,[r16] ; stores r0 in [0x4000] and r1 in [0x4004]
Den GCC-optimizer erkennt die vector Art der Schleife und erzeugt zwei Zweige der code - eine für den Fall, wo die 3 arrays double-word-aligned (so verwendet er das double load/store-Anweisungen) und die andere für den Fall, dass die arrays sind Wort-ausgerichtet (wobei es nutzt die single-load/store-option).
Das problem ist, dass die Adresse, die Ausrichtung zu überprüfen ist teuer, relativ zu der neben der Teil und das möchte ich beseitigen, indem hinting der compiler, dass a, b und c sind immer 8-ausgerichtet. Gibt es einen Modifikator hinzufügen, um die pointer-Erklärung zu sagen, das der compiler nicht?
Den arrays, die sind verwendet für den Aufruf dieser Funktion haben ausgerichtet(8) Attribut, aber es spiegelt sich nicht in der Funktion code selbst. ist es möglich dieses Attribut hinzufügen, um die Parameter für die Funktion?
- Auch wenn mein code unten nicht helfen können (wegen C++), möchten Sie vielleicht printf("%p") &array[0] und &array[1] in deinem code, nur um sicherzugehen, dass das ausrichten wird gehorcht, und pro element - nicht nur auf die array-Startadresse.
- ist es eigentlich erforderlich, dass es NICHT richten pro array-element. Es muss schon eine zusammenhängende Reihe von Schwimmern, deren Herkunft 8-ausgerichtet.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Wenn die Attribute nicht funktionieren, oder die nicht eine option ....
Ich bin mir nicht sicher, aber versuchen Sie dies:
Sollte GCC sagen, dass der Zeiger ausgerichtet sind. Aus, dass, ob es das macht, was Sie wollen, hängt davon ab, ob der compiler kann diese information effektiv ist, ist es möglicherweise nicht schlau genug: diese Optimierungen sind nicht einfach.
Weitere option könnte sein, wickeln Sie den Schwimmer innerhalb der union müssen auf 8 byte ausgerichtet:
Ich denke, dass sollte Durchsetzung der 8-byte-Ausrichtung, aber wieder, ich weiß nicht, ob der compiler schlau genug ist, es zu benutzen.
__builtin_assume_aligned
. Ich werde Bearbeiten Sie die Antwort.union {float f[100]; long long dummy}
aber 🙂gcc -std=c99 test.c -S -masm=intel -O3 -march=native
bekomme ichtestGood
zu verwenden AVX-Vektorisierung, währendtestBad
mit__builtin_assume_aligned
nur verwendet x87 Instruktionen.aligned_float
union hat Größe=8, und ein array hätte es Polsterung. Sie haben zu werfen die Zeiger auffloat*
bevor Sie es verwenden können normalerweise.typedef __attribute__((aligned(8))) float aligned_float;
arbeitet mit gcc (z.B. als eine Funktion arg), aber die klappern nicht ableiten Ausrichtung ab. godbolt.org/z/tCLkfp (immer Noch auto-vectorizes mitmovups
, nichtmovaps
auf x86 zum Beispiel.)Folgenden ein Stück Beispiel-code habe ich gefunden auf meinem system, ich habe versucht, die folgende Lösung, die auch Ideen von ein paar der Antworten, die früher gegeben: im Grunde erstellen Sie eine union von einer kleinen Reihe von Schwimmern, die mit einer 64-bit-Typ, in diesem Fall eine SIMD Vektor von floats - und rufen Sie die Funktion mit einer Form der Operanden float-arrays:
Nun der compiler erzeugt nicht das 4-ausgerichtet Zweig.
Jedoch die
__builtin_assume_aligned()
wäre die bessere Lösung, die Verhinderung der Besetzung und möglichen Nebenwirkungen, wenn es nur funktioniert.EDIT: ich habe bemerkt, dass die builtin-Funktion ist tatsächlich buggy auf unsere Umsetzung (ich.e, nicht nur es funktioniert nicht, aber es bewirkt, dass die Berechnung Fehler später im code.
Sieht es aus wie neuere Versionen von GCC haben
__builtin_übernehmen_ausgerichtet
:Basierend auf einige andere Fragen und Antworten auf Stack Overflow circa 2010, scheint es, dass die built-in war nicht verfügbar in GCC 3 und Anfang der GCC-4. Aber ich weiß nicht, wo der cut-off-Punkt ist.
gcc-Versionen wurden dodgy über align() auf einfache Typdefinitionen und arrays. In der Regel tun, was Sie wollen, hätten Sie wickeln Sie die Schwimmer in einem struct, und die darin enthaltenen Schwimmer haben die Ausrichtung Beschränkung.
Mit operator-überladung kann man fast machen diese schmerzlos, es wird jedoch vorausgesetzt du kannst c++ - syntax.
Ausrichtung Spezifikationen in der Regel nur Arbeit für Ausrichtungen, die kleiner sind als der Basis-Typ des Zeigers, nicht größer.
Ich denke, am einfachsten ist es, zu erklären, Ihre ganze array mit einem alignment-Spezifikation, so etwas wie
(Die syntax nicht richtig sein könnte, habe ich immer Schwierigkeiten haben, zu wissen, wo man diese
__attribute__
s)Verwenden und diese Art in Ihrem gesamten code. Für Ihre Funktion, definition, ich würde versuchen,
Dies gibt Ihnen eine zusätzliche Dereferenzierung aber das ist nur syntax. So etwas wie
*a
ist nur ein noop und nur eine moderne Neuinterpretation der Zeiger als Zeiger auf das erste element.Ich es nie benutzt, aber es ist _Attribut_((aligned (8)))
Wenn ich Lesen Sie die Dokumentation, Recht, dann ist es so genutzt:
sehen http://ohse.de/uwe/articles/gcc-attributes.html#type-aligned
error: alignment may not be specified for