2015-12-23 23 views
9

Con GCC 5.3 il codice seguente compield con -O3 -fmafusi moltiplicano aggiungere e arrotondamento predefinite Modalità

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

produce il seguente complesso

vfmadd132ss  %xmm1, %xmm2, %xmm0 
ret 

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

Clang 3.7 con -O3 -mfma produce

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

ma Clang 3.7 con -Ofast -mfma produce lo stesso codice di GCC con -O3 fast.

Mi sorprende che GCC fa con -O3 perché da this answer dice

Il compilatore non è consentito di fondere un separato aggiuntivo e moltiplicare a meno che non si consente per un modello in virgola mobile rilassato.

Questo perché un FMA ha un solo arrotondamento, mentre un ADD + MUL ne ha due. Quindi il compilatore violerà il comportamento in virgola mobile IEEE mediante fusione.

Tuttavia, da this link dice

Indipendentemente dal valore di FLT_EVAL_METHOD, qualsiasi espressione in virgola mobile può essere contratto, cioè, calcolata come se i risultati intermedi hanno portata e precisione infinita.

Quindi ora sono confuso e preoccupato.

  1. GCC è giustificato nell'uso di FMA con -O3?
  2. Il fusing viola il comportamento in virgola mobile IEEE?
  3. Se la fusione viola il punto di virgola mobile IEEE e poiché GCC returns __STDC_IEC_559__ non è una contraddizione?

Poiché FMA can be emulated in software sembra esserci dovrebbero essere due interruttori compilatore per FMA: uno a dire al compilatore di utilizzare FMA nei calcoli e uno a dire al compilatore che l'hardware ha FMA.


apprently questo può essere controllato con l'opzione -ffp-contract. Con GCC il valore predefinito è -ffp-contract=fast e con Clang non lo è. Altre opzioni come -ffp-contract=on e -ffp-contract=off non producono l'istruzione FMA.

Ad esempio Clang 3.7 con -O3 -mfma -ffp-contract=fast produce vfmadd132ss.


ho controllato alcune permutazioni di #pragma STDC FP_CONTRACT set per ON e OFF con -ffp-contract set per on, off e fast.In tutti i casi ho anche utilizzato -O3 -mfma.

Con GCC la risposta è semplice. #pragma STDC FP_CONTRACT ON o OFF non fa differenza. Solo gli argomenti -ffp-contract.

GCC utilizza fma con

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

Con Clang utilizza fma

  1. con -ffp-contract=fast.
  2. con -ffp-contract=on (predefinito) e #pragma STDC FP_CONTRACT ON (il valore predefinito è OFF).

In altre parole con Clang è possibile ottenere fma con #pragma STDC FP_CONTRACT ON (dal -ffp-contract=on è l'impostazione predefinita) o con -ffp-contract=fast. -ffast-math (e quindi -Ofast) impostato -ffp-contract=fast.


Ho esaminato MSVC e ICC.

Con MSVC utilizza l'istruzione fma con /O2 /arch:AVX2 /fp:fast. Con MSVC /fp:precise è l'impostazione predefinita.

Con ICC utilizza fma con -O3 -march=core-avx2 (è sufficiente -O1). Questo perché di default ICC usa -fp-model fast. Ma ICC usa fma anche con -fp-model precise. Per disabilitare fma con ICC utilizzare -fp-model strict o -no-fma.

Quindi, per impostazione predefinita, GCC e ICC utilizzano fma quando fma è abilitato (con -mfma per GCC/Clang o -march=core-avx2 con ICC) ma Clang e MSVC no.

+0

Potrebbe essere un errore del compilatore. Considera di segnalarlo. – fuz

+0

Sono abbastanza sicuro di quello che gcc sta facendo è ok. Dopo aver letto il documento FLT_EVAL_METHOD sulla contrazione delle espressioni FP, sono sorpreso che 'clang' * non lo faccia *. Non sto postando questo come una risposta, dal momento che non si basa su alcuna documentazione di standard reali, solo la mia comprensione di come * I * penso che le cose dovrebbero funzionare/dovrebbero essere state progettate, dato il materiale nella domanda. –

+0

@FUZxxl, pensi che il tag floating point sarebbe più appropriato di ieee-754? (se è così sentitevi liberi di cambiarlo). Sento che dovrei usare anche il tag floating point. –

risposta

3

Essa non viola IEEE-754, perché IEEE-754 si rimette alle lingue su questo punto:

Un linguaggio standard dovrebbero anche definire, e richiedono implementazioni di fornire, attributi che permettere e impedire a valore cambiare le ottimizzazioni, separatamente o collettivamente, per un blocco.Queste ottimizzazioni possono includere, ma non sono limitati a:

...

- Sintesi di un'operazione fusedMultiplyAdd da una moltiplicazione e un'aggiunta.

In standard C, il pragma STDC FP_CONTRACT fornisce i mezzi per controllare questa ottimizzazione che modifica il valore. Pertanto, GCC è autorizzato a eseguire la fusione per impostazione predefinita, purché consenta di disabilitare l'ottimizzazione impostando STDC FP_CONTRACT OFF. Non supportare ciò significa non aderire allo standard C.

+0

Cosa intendi con "Non supportare ciò significa non aderire allo standard C"? Per inciso, GCC sembra ignorare 'STDC FP_CONTRACT'. Invece usa solo '-ffp-contract'. Clang riconosce entrambi. –

+0

Voglio dire che FP_CONTRACT fa parte dello standard C. Ignorarlo è non conformarsi. –

+0

Oh, ti sei reso conto che ti riferivi a GCC che non supporta 'FP_CONTRACT' (o qualsiasi compilatore che non lo supporta). Ora capisco. –

4

Quando hai indicato che l'aggiunta multipla fusa è consentita, hai escluso la condizione importante "a meno che pragma FP_CONTRACT non sia attivo". Che è una caratteristica nuova di C (credo introdotta in C99) e che è stata resa assolutamente necessaria da PowerPC, che ha fuso tutte le moltiplicate dall'inizio - in realtà x * y era equivalente a fma (x, y, 0) e x + y era equivalente a fma (1.0, x, y).

FP_CONTRACT è ciò che controlla il fuso moltiplicato/aggiunto, non FLT_EVAL_METHOD. Sebbene se FLT_EVAL_METHOD consente una maggiore precisione, la contrazione è sempre legale; fai finta che le operazioni siano state eseguite con altissima precisione e poi arrotondate.

La funzione fma è utile se non si desidera la velocità, ma la precisione. Calcolerà il risultato contratto lentamente ma correttamente anche se non è disponibile nell'hardware. E dovrebbe essere inline se è disponibile nell'hardware.

+0

Penso che questo in qualche modo risponda alla mia prima domanda su se GCC è giustificato solo in fma con '-O3'. Ma non è ancora chiaro se è conforme allo standard IEEE. E dal momento che GCC definisce '__STDC_IEC_559__', allora posso supporre che sia conforme allo standard IEEE ma altre persone sostengono che fma rompe questo (il che indicherebbe che GCC non è giustificato nel fare ciò quando viene definito' __STDC_IEC_559__'). Quindi sono ancora confuso. –

+0

@Zboson: Ho notato quella roba sul pragma nel documento che ti ho collegato, ma non sapevo quanto fosse nuovo o ampiamente supportato. Ecco perché non l'ho menzionato prima. –

+1

@PeterCordes, va bene, GCC non sembra preoccuparsi di tale pragma comunque, quindi è un problema controverso. E in ogni caso non dice nulla sul fatto che sia conforme allo standard IEEE. GCC restituisce '__STDC_IEC_559__' e allo stesso usa' -ffp-contract = fast' quindi voglio ancora sapere se questa è una contraddizione. –