2013-03-23 6 views
13

Ich werde meine Frage mit einem Beispiel stellen. Jetzt habe ich eine Funktion namens do_something().Was ist der richtige Weg, um verschiedene Versionen von SSE-Intrinsics in GCC zu verwenden?

Es hat drei Versionen: do_something(), do_something_sse3() und do_something_sse4(). Wenn mein Programm läuft, erkennt es die CPU-Funktion (siehe SSE3 oder SSE4) und ruft eine der drei Versionen entsprechend auf.

Das Problem ist: Wenn ich mein Programm mit GCC bauen, ich habe -msse4 für do_something_sse4() einstellen zu kompilieren (zum Beispiel für die Header-Datei <smmintrin.h> aufgenommen werden).

Wenn ich jedoch -msse4 einstelle, dann kann gcc SSE4-Anweisungen verwenden, und einige interne Elemente in do_something_sse3() werden auch in einige SSE4-Anweisungen übersetzt. Also, wenn mein Programm auf CPU läuft, die nur SSE3 (aber keine SSE4) Unterstützung hat, verursacht es "illegale Anweisung" wenn Anrufe do_something_sse3().

Vielleicht habe ich ein paar schlechte Praxis. Könntest du ein paar Vorschläge machen? Vielen Dank.

+5

Ich denke, der Standardansatz besteht darin, die verschiedenen Versionen in separaten Kompilierungseinheiten zu kompilieren. – Mysticial

+0

@Mysticial, zuerst danke, dass Sie meine Frage bearbeitet haben. Wie ich es verstehe, bedeutet "kompiliere die verschiedenen Versionen in separaten Kompilierungseinheiten": setze alle "do_things_sse4" in eine Datei "functios_sse4.c" und kompiliere sie mit der Option "-msse4"; und kompiliere 'functions_sse3.c' mit' -msse3'. Ich werde es versuchen. (Ich muss vielleicht meine Codes rekonstruieren, die ursprünglich für MSVC geschrieben wurden) – shengbinmeng

+0

Ja, genau das meinte ich. :) – Mysticial

Antwort

9

Ich denke, dass die mystische Tipp ist in Ordnung, aber wenn Sie es wirklich in der eine Datei tun möchten, können Sie die richtige pragmas, zum Beispiel verwenden:

#pragma GCC target("sse4.1") 

GCC 4.4 benötigt wird, AFAIR . Hier

+0

danke für diesen Vorschlag. Ich werde später auch die # Pragma-Anweisung versuchen. – shengbinmeng

+0

Kann smmintrin.h nicht mit #pragma GCC target ("sse4") einschließen – Trass3r

0

ist ein Beispiel für eine separate Objektdatei für jede Optimierungseinstellung Kompilieren: http://notabs.org/lfsr/software/index.htm

Aber auch diese Methode schlägt fehl, wenn gcc Link Zeitoptimierung (-flto) verwendet wird. Wie kann also eine einzelne ausführbare Datei mit vollständiger Optimierung für verschiedene Prozessoren erstellt werden? Die einzige Lösung, die ich finden kann, ist, Include-Direktiven zu verwenden, um die C-Dateien als eine einzige Kompilierungseinheit zu behandeln, so dass -flto nicht benötigt wird. Hier ist ein Beispiel mit dieser Methode: http://notabs.org/blcutil/index.htm

2

Ich denke, Sie wollen, was eine "CPU-Dispatcher" genannt wird. Ich habe eine Arbeit (soweit ich weiß) für GCC, aber nicht mit Visual Studio arbeiten.
cpu dispatcher for visual studio for AVX and SSE

Ich würde überprüfen Agner Fog vectorclass und die Datei dispatch_example.cpp http://www.agner.org/optimize/#vectorclass

g++ -O3 -msse2 -c dispatch_example.cpp -od2.o 
g++ -O3 -msse4.1 -c dispatch_example.cpp -od5.o 
g++ -O3 -mavx -c dispatch_example.cpp -od8.o 
g++ -O3 -msse2  instrset_detect.cpp d2.o d5.o d8.o 
0

Wenn Sie GCC 4.9 oder höher auf einem i686 oder x86_64 Maschine verwenden, dann sollte Sie sein In der Lage, unabhängig von Ihren Optionen -march=XXX und -mXXX Optionen zu verwenden. Sie könnten Ihre do_something() entsprechend schreiben:

void do_something() 
{ 
    byte temp[18]; 

    if (HasSSE2()) 
    { 
     const __m128i i = _mm_loadu_si128((const __m128i*)(ptr)); 
     ... 
    } 
    else if (HasSSSE3()) 
    { 
     const __m128i MASK = _mm_set_epi8(12,13,14,15, 8,9,10,11, 4,5,6,7, 0,1,2,3); 
     _mm_storeu_si128(reinterpret_cast<__m128i*>(temp), 
      _mm_shuffle_epi8(_mm_loadu_si128((const __m128i*)(ptr)), MASK)); 
    } 
    else 
    { 
     // Do the byte swap/endian reversal manually 
     ... 
    } 
} 

Sie haben HasSSE2(), HasSSSE3() und Freunde zu versorgen. Siehe auch Intrinsics for CPUID like informations?.

Siehe auch GCC Issue 57202 - Please make the intrinsics headers like immintrin.h be usable without compiler flags. Aber ich glaube nicht, dass das Feature funktioniert. Ich stoße regelmäßig auf Fehler beim Kompilieren, weil GCC keine intrinsischen Daten zur Verfügung stellt.

Verwandte Themen