2014-07-18 4 views
7

Diese Frage bezieht sich auf gcc (4.6.3 Ubuntu) und sein Verhalten in Unrolling-Schleifen für SSE-Intrinsics mit unmittelbaren Operanden.Welche gcc-Option ermöglicht Schleifen-Abrollung für SSE-Intrinsics mit unmittelbaren Operanden?

Ein Beispiel für eine intrinsische mit unmittelbarer Operand ist _mm_blend_ps. Es erwartet eine direkte 4-Bit-Ganzzahl, die nur eine Konstante sein kann. Bei Verwendung der Option -O3 löst der Compiler jedoch scheinbar automatisch Schleifen aus (wenn die Schleifenzählerwerte zur Kompilierungszeit bestimmt werden können) und erzeugt mehrere Instanzen der entsprechenden Mischanweisung mit unterschiedlichen unmittelbaren Werten.

Dies ist ein einfacher Testcode (blendsimple.c), welche die 16 möglichen Werte des unmittelbaren Operanden der Mischung läuft durch:

#include <stdio.h> 
#include <x86intrin.h> 

#define PRINT(V)    \ 
    printf("%s: ", #V);    \ 
    for (i = 3; i >= 0; i--) printf("%3g ", V[i]); \ 
    printf("\n"); 

int 
main() 
{ 
    __m128 a = _mm_set_ps(1, 2, 3, 4); 
    __m128 b = _mm_set_ps(5, 6, 7, 8); 
    int i; 
    PRINT(a); 
    PRINT(b); 
    unsigned mask; 
    __m128 r; 
    for (mask = 0; mask < 16; mask++) { 
    r = _mm_blend_ps(a, b, mask); 
    PRINT(r); 
    } 
    return 0; 
} 

Es ist möglich, diesen Code kompilieren mit

gcc -Wall -march=native -O3 -o blendsimple blendsimple.c 

und der Code funktioniert. Offensichtlich entrollt der Compiler die Schleife und fügt Konstanten für den unmittelbaren Operanden ein.

Wenn Sie jedoch den Code mit

gcc -Wall -march=native -O2 -o blendsimple blendsimple.c 

Sie folgende Fehlereigen für die Mischung erhalten kompilieren:

error: the last argument must be a 4-bit immediate 

Jetzt habe ich versucht, die spezifischen Compiler-Flag in aktiv ist, um herauszufinden - O3, aber nicht in -O2, wodurch der Compiler die Schleife auflösen kann, aber fehlgeschlagen ist. Im Anschluss an die gcc Online-Dokumentation bei

https://gcc.gnu.org/onlinedocs/gcc-4.8.2/gcc/Overall-Options.html

ausgeführt ich die folgenden Befehle:

gcc -c -Q -O3 --help=optimizers > /tmp/O3-opts 
gcc -c -Q -O2 --help=optimizers > /tmp/O2-opts 
diff /tmp/O2-opts /tmp/O3-opts | grep enabled 

, die alle Optionen von O3, aber nicht von -O2 aktiviert auflistet. Wenn ich alle der 7 aufgeführten Flags zusätzlich hinzufügen

gcc -Wall -march=native -O2 -fgcse-after-reload -finline-functions -fipa-cp-clone -fpredictive-commoning -ftree-loop-distribute-patterns -ftree-vectorize -funswitch-loops blendsimple blendsimple.c 

-O2 würde ich erwarten, dass das Verhalten genau wie bei O3 gleich ist. Der Compiler beklagt sich jedoch, dass "das letzte Argument ein 4-Bit-Immediate sein muss".

Hat jemand eine Idee, was das Problem ist? Ich denke, es wäre gut zu wissen, welches Flag erforderlich ist, um diese Art des Schleifenabwickelns zu aktivieren, so dass es selektiv mit #pragma GCC optimize oder durch ein Funktionsattribut aktiviert werden kann.

(Ich war auch überrascht, dass -O3 offenbar nicht einmal die Unroll-Loops-Option aktiviert).

Ich wäre dankbar für jede Hilfe. Dies ist für einen Vortrag über SSE-Programmierung ich gebe.

Bearbeiten: Vielen Dank für Ihre Kommentare. Jtaylor scheint recht zu haben. Ich habe meine Hand auf zwei neuere Versionen von gcc (4.7.3, 4.8.2), und 4.8.2 klagt über das unmittelbare Problem, unabhängig von der Optimierungsstufe. Moverover habe ich später bemerkt, dass gcc 4.6.3 den Code mit -O2 -funroll-loops kompiliert, was aber auch in 4.8.2 fehlschlägt. Offensichtlich kann man diesem Feature nicht vertrauen und sollte immer "manuell" mit Hilfe von cpp oder Templates ausrollen, wie Jason R darauf hingewiesen hat.

+0

ich den Fehler 'das letzte Argument muss ein 4-Bit-immediate' sogar mit O3 . –

+0

Sie können das Abrollen immer manuell mithilfe von Präprozessor-Trickserei oder Template-Metaprogrammierung implementieren (wenn Sie in C++ schreiben). –

+1

Dieses Verhalten sieht eher wie ein Compiler-Fehler aus (der in 4.8 behoben wird). Compiler sollen keine Fehler auf verschiedenen Optimierungsebenen geben. gcc sollte entweder immer sofort (z. B. über Bedingungen) oder nie unterstützen. Es scheint, dass sie die späteren Versionen auswählten. Was sinnvoll ist, intrinsics sollen sehr dünne Wrapper um Maschinenanweisungen sein – jtaylor

Antwort

1

Ich bin nicht sicher, ob dies für Ihre Situation gilt, da ich SSE-Intrinsics nicht kenne.Aber im Allgemeinen, können Sie den Compiler sagen, speziell einen Abschnitt von Code zu optimieren mit:

#pragma GCC push_options 
#pragma GCC optimize ("unroll-loops") 

do your stuff 

#pragma GCC pop_options 

Quelle: Tell gcc to specifically unroll a loop

Verwandte Themen