Erzwingen / Überzeugen / Trick GCC in entrollen _Long_Loop?

8

Wie überzeuge ich GCC, eine Schleife aufzulösen, in der die Anzahl der Iterationen bekannt ist, aber groß?

Ich kompiliere mit -O3 .

Der fragliche echte Code ist natürlich komplexer, aber hier ist ein heruntergekommenes Beispiel, das dasselbe Verhalten hat:

%Vor%

... Wenn CONSTANT_COUNT als 8 (oder weniger) definiert ist, dann wird GCC die Schleife ausrollen, die Konstanten propagieren und die gesamte Funktion auf ein einfaches return <value>; reduzieren. Wenn andererseits CONSTANT_COUNT 9 (oder größer) ist, wird die Schleife nicht abgerollt, und GCC erzeugt eine Binärdatei, die Schleifen ausführt, die Konstanten liest und sie zur Laufzeit hinzufügt - obwohl theoretisch die Funktion könnte noch optimiert werden, um nur eine Konstante zurückzugeben. (Ja, ich habe mir die Dekompilierung der Binärdatei angesehen.)

Wenn ich manuell die Schleife abrollte, wie folgt:

%Vor%

Oder das:

%Vor%

... dann ist die Funktion bis zur Rückgabe einer Konstante optimiert. Daher scheint GCC in der Lage zu sein, die konstante Ausbreitung für größere Schleifen zu handhaben, sobald sie einmal ausgerollt sind; Das Auflegen scheint GCC nur dazu zu bringen, in Betracht zu ziehen, die längere Schleife überhaupt abzurollen.

Allerdings sind weder Hand-entrolling noch BOOST_PP_REPEAT praktikable Optionen, da es einige -Fällen gibt, in denen CONSTANT_COUNT ein Laufzeitausdruck und gleich ist Code muss für diese Fälle immer noch ordnungsgemäß funktionieren. (In diesen Fällen ist die Leistung nicht so kritisch.)

Ich arbeite in C (nicht in C ++), also sind weder Template-Metaprogrammierung noch constexpr für mich verfügbar.

Ich habe -funroll-loops , -funroll-all-loops , -fpeel-loops versucht und große Werte für max-unrolled-insns , max-average-unrolled-insns , max-unroll-times , max-peeled-insns , max-peel-times , max-completely-peeled-insns und% festgelegt. co_de%, von denen keine zu unterscheiden scheint.

Ich verwende GCC 4.8.2, unter Linux, x86_64.

Irgendwelche Ideen? Gibt es eine Flagge oder einen Parameter, der mir fehlt ...?

    
jgustafson 16.09.2014, 21:35
quelle

2 Antworten

3

Ich bin mir nicht sicher, ob diese Problemumgehung auf Ihr tatsächliches Problem anwendbar ist, aber ich habe festgestellt, dass GCC 4.9.0 20140604 (Vorabversion) auf einem x86_64 mit Parabola GNU / Linux die folgende Schleife bis einschließlich CONSTANT_COUNT == 33 / p> %Vor%

Ich habe nur das -O3 -Flag übergeben. Der Assemblierungscode für get_sum ist wirklich nur

%Vor%

Ich habe es nicht versucht, aber vielleicht kann das Muster noch weiter ausgedehnt werden.

Es scheint mir merkwürdig, dass das funktioniert - zumindest für meine menschlichen Augen - sieht der Code jetzt viel komplexer aus. Leider ist es eine eher aufdringliche Art, das Abrollen zu erzwingen. Ein Compiler-Flag wäre viel schöner gewesen.

    
5gon12eder 17.09.2014, 02:20
quelle
0

GCC hat eine große Menge an obskuren Parametern und Programmargumenten bezüglich Schleifen-Abrollung (und Optimierungen) ). Du könntest mit -funroll-loops , -funroll-all-loops , --param name = wert spielen (zB mit name ist max-unroll-times ....) usw.

Die Reihenfolge der Argumente für gcc ist sehr wichtig. Wahrscheinlich möchtest du zuerst -O3 und danach die seltsamen Optionen setzen.

Die Erhöhung des Abrollens verbessert jedoch nicht immer die Leistung.

Zu guter Letzt könnten Sie Ihr eigenes GCC-Plugin programmieren, das die Abwicklungskriterien ändern würde.

Clever mit __builtin_prefetch könnte die Leistung verbessern, siehe diese Antwort (aber verwenden Sie sie sorglos wird die Leistung beeinträchtigen

Sie müssen einen Benchmark erstellen. Mein Gefühl ist, dass vorzeitige Mikro-Optimierung ein großer Verlust Ihrer Zeit ist.

    
Basile Starynkevitch 18.09.2014 19:37
quelle

Tags und Links