2015-12-23 20 views
9

mit GCC 5.3 der folgende Code mit compield -O3 -fmaFused multiply hinzufügen und Standard Rundungsmodi

float mul_add(float a, float b, float c) { 
    return a*b + c; 
} 

erzeugt die folgende Montage

vfmadd132ss  %xmm1, %xmm2, %xmm0 
ret 

I noticed GCC doing this with -O3 already in GCC 4.8.

Clang 3.7 mit -O3 -mfma produziert

vmulss %xmm1, %xmm0, %xmm0 
vaddss %xmm2, %xmm0, %xmm0 
retq 

aber Clang 3.7 mit -Ofast -mfma mit -O3 fast den gleichen Code wie GCC produziert.

Ich bin überrascht, dass GCC mit -O3 tut, weil von this answer sagt es

Der Compiler ist nicht erlaubt eine getrennte Zusatz zu verschmelzen und sich vermehren, wenn Sie für einen entspannten Modell Gleitkommazahlen ermöglichen.

Dies ist, weil ein FMA nur eine Rundung hat, während ein ADD + MUL zwei hat. Der Compiler wird also das strikte IEEE-Fließkomma-Verhalten durch Verschmelzen verletzen.

jedoch aus this link sagt

Unabhängig von dem Wert von FLT_EVAL_METHOD jede Gleitkommaausdruck kontrahiert werden kann, das heißt, berechnet, als ob alle Zwischenergebnisse unendlichen Bereich und Präzision aufweisen.

So jetzt bin ich verwirrt und besorgt.

  1. Ist GCC gerechtfertigt in der Verwendung von FMA mit -O3?
  2. Verletzt die Fusion das strikte IEEE-Fließkommaverhalten?
  3. Wenn Fusing IEEE Fließkommazahl verletzt und GCC returns __STDC_IEC_559__ ist dies nicht ein Widerspruch?

Da FMA can be emulated in software es scheint, dort zu sein, sollten zwei Compiler-Schalter für FMA sein: man den Compiler sagen FMA in Berechnungen verwendet werden und man den Compiler zu sagen, dass die Hardware FMA hat.


apprently kann dies mit der Option -ffp-contract gesteuert werden. Mit GCC ist der Standard -ffp-contract=fast und mit Clang ist es nicht. Andere Optionen wie -ffp-contract=on und -ffp-contract=off erzeugen keine FMA-Anweisung. Beispiel: Clang 3.7 mit -O3 -mfma -ffp-contract=fast produziert vfmadd132ss.


Ich habe einige Permutationen von #pragma STDC FP_CONTRACT Set ON und OFF mit -ffp-contract Set on, off und fast.In allen Fällen habe ich auch -O3 -mfma verwendet.

Mit GCC ist die Antwort einfach. #pragma STDC FP_CONTRACT ON oder OFF macht keinen Unterschied. Nur -ffp-contract zählt.

GCC verwendet es fma mit

  1. -ffp-contract=fast (Standard).

mit Clang verwendet es fma

  1. mit -ffp-contract=fast.
  2. mit -ffp-contract=on (Standard) und #pragma STDC FP_CONTRACT ON (Standard ist OFF).

Mit anderen Worten mit Clang können Sie fma mit #pragma STDC FP_CONTRACT ON bekommen oder mit -ffp-contract=fast (seit -ffp-contract=on der Standard ist). -ffast-math (und damit -Ofast) Set -ffp-contract=fast.


Ich schaute in MSVC und ICC.

Mit MSVC verwendet es die Fma-Anweisung mit /O2 /arch:AVX2 /fp:fast. Mit MSVC /fp:precise ist der Standardwert.

Mit ICC verwendet es fma mit -O3 -march=core-avx2 (actually -O1 ist ausreichend). Dies liegt daran, dass ICC standardmäßig -fp-model fast verwendet. Aber ICC verwendet fma sogar mit -fp-model precise. Um FMA mit ICC zu deaktivieren, verwenden Sie oder .

Standardmäßig verwenden GCC und ICC fma, wenn fma aktiviert ist (mit -mfma für GCC/Clang oder -march=core-avx2 mit ICC), aber Clang und MSVC nicht.

+0

Könnte ein Compiler-Fehler sein. Überlegen Sie, es zu melden. – fuz

+0

Ich bin mir ziemlich sicher, was GCC macht, ist in Ordnung. Nachdem ich den FLT_EVAL_METHOD-Doc über Contracting-FP-Ausdrücke gelesen habe, bin ich überrascht, dass 'clang' * das nicht tut. Ich poste das nicht als Antwort, da es nicht auf einer echten Standarddokumentation basiert, nur mein Verständnis davon, wie * ich * denke, dass die Dinge angesichts des Materials in der Frage funktionieren sollten/sollten. –

+0

@FUZxxl, meinst du, das Gleitkomma-Tag wäre passender als ieee-754? (Wenn es so ist, kannst du es ändern). Ich denke, ich sollte auch das Fließkomma-Tag verwenden. –

Antwort

3

Es verstößt nicht IEEE-754, da IEEE-754 in diesem Punkt Sprachen aufschiebt:

Ein Sprachstandard sollte auch festgelegt werden, und Implementierungen benötigen Attribute bereitzustellen, die ermöglichen, und nicht zulassen wert- Ändern von Optimierungen, einzeln oder zusammen für einen Block.Diese Optimierungen können beinhalten, sind aber nicht beschränkt auf:

...

- Synthese eines fusedMultiplyAdd Betrieb aus einer Multiplikation und einer Addition.

Im Standard C bietet das Pragma STDC FP_CONTRACT die Möglichkeit, diese wertverändernde Optimierung zu steuern. Daher ist GCC lizensiert, um die Fusion standardmäßig durchzuführen, solange es Ihnen ermöglicht, die Optimierung durch Setzen von STDC FP_CONTRACT OFF zu deaktivieren. Wenn man das nicht unterstützt, bedeutet das nicht, sich an den C-Standard zu halten.

+0

Was meinen Sie mit "Nicht unterstützen heißt nicht den C-Standard einhalten"? Übrigens scheint GCC "STDC FP_CONTRACT" zu ignorieren. Stattdessen verwendet es nur "-ffp-contract". Clang erkennt beides. –

+0

Ich meine, dass FP_CONTRACT Teil des C-Standards ist. Es zu ignorieren ist nicht konform. –

+0

Oh, ich habe bemerkt, dass Sie sich darauf beziehen, dass GCC 'FP_CONTRACT' nicht unterstützt (oder einen Compiler, der es nicht unterstützt). Jetzt verstehe ich. –

4

Wenn Sie zitiert, dass fusionierte Multiply-Add erlaubt ist, haben Sie die wichtige Bedingung "außer Pragma FP_CONTRACT ist aus" weggelassen. Was ist ein neues Feature in C (ich denke, in C99 eingeführt) und wurde von PowerPC, die alle hatte fusioniert Multiply-Add von Anfang an zwingend erforderlich gemacht - eigentlich, x * y war äquivalent zu fma (x, y, 0) und x + y war äquivalent zu fma (1.0, x, y).

FP_CONTRACT ist was steuert, fusioniert multiplizieren/hinzufügen, nicht FLT_EVAL_METHOD. Obwohl, wenn FLT_EVAL_METHOD eine höhere Genauigkeit erlaubt, ist Contracting immer legal; tue nur so, als ob die Operationen mit sehr hoher Präzision ausgeführt und dann abgerundet würden.

Die fma-Funktion ist nützlich, wenn Sie nicht die Geschwindigkeit, sondern die Präzision wünschen. Es berechnet das kontrahierte Ergebnis langsam, aber korrekt, auch wenn es in der Hardware nicht verfügbar ist. Und sollte inline sein, wenn es in Hardware verfügbar ist.

+0

Ich denke, dass dies zu einem gewissen Grad meine erste Frage beantwortet, ob GCC nur in fma mit "-O3" gerechtfertigt ist. Aber es ist immer noch nicht klar, ob es IEEE-konform ist. Und da GCC "__STDC_IEC_559__" definiert, kann ich annehmen, dass es IEEE-konform ist, aber andere Leute behaupten, dass fma dies bricht (was argumentieren würde, dass GCC nicht gerechtfertigt ist, wenn "__STDC_IEC_559__" definiert ist). Also bin ich immer noch verwirrt. –

+0

@Zboson: Ich bemerkte, dass Zeug über das Pragma in dem Dokument, das ich Ihnen verlinkt habe, aber nicht wusste, wie neu oder weit verbreitet das war. Deshalb habe ich es vorher nicht erwähnt. –

+1

@PeterCordes, das ist in Ordnung, GCC scheint sich nicht um dieses Pragma zu kümmern, also ist es ein strittiges Problem. Und auf jeden Fall sagt es nichts darüber, dass es IEEE-konform ist. GCC gibt '__STDC_IEC_559__' zurück und verwendet gleichzeitig -ffp-contract = fast, also möchte ich immer noch wissen, ob das ein Widerspruch ist. –