# FMA (set di istruzioni)

Il set di istruzioni FMA è un'estensione delle istruzioni a 128 e 256 bit per le estensioni Streaming SIMD Extensions dell'Instruction set dei microprocessori x86 per eseguire operazioni FMA (Fused Multily-add). Ci sono due varianti:
* FMA4 è supportato nei processori AMD a partire dall'architettura Bulldozer. FMA4 è stato realizzato in hardware prima di FMA3.
* FMA3 è supportato nei processori AMD a partire dall'architettura Piledriver e Intel a partire dai processori Haswell e Broadwell dal 2014.

## Nuove istruzioni

Le istruzioni FMA3 e FMA4 hanno funzionalità quasi identiche ma non sono compatibili. Entrambe contengono istruzioni fused multiply–add (FMA) per operazioni SIMD e scalari in virgola mobile, ma le istruzioni FMA3 hanno tre operandi mentre quelle FMA4 ne hanno quattro. L'operazione FMA ha la forma d = round (a · b + c) dove la funzione round esegue un arrotondamento per consentire al risultato di adattarsi al registro di destinazione se ci sono troppi bit significativi per adattarsi alla destinazione.
La forma a quattro operandi (FMA4) permette a, b, c e d di essere quattro diversi registri, mentre la forma a tre operandi (FMA3) richiede che d sia lo stesso registro di a, b o c. La forma a tre operandi rende il codice più breve e l'implementazione hardware leggermente più semplice, mentre la forma a quattro operandi fornisce maggiore flessibilità di programmazione.
Si veda il set di istruzioni XOP per ulteriori discussioni sui problemi di compatibilità tra Intel e AMD.

## Set di istruzioni FMA3
### CPU con FMA3

* AMD
** AMD ha introdotto il supporto FMA3 nei processori a partire con l'architettura Piledriver per motivi di compatibilità. I processori APU di seconda generazione basati su istruzioni FMA3 "Trinity" (32 nm) sono stati lanciati il 15 maggio 2012. I processori Bulldozer di seconda generazione con core Piledriver che supportano le istruzioni FMA3 sono stati lanciati il 23 ottobre 2012.
* Intel
** Intel ha introdotto l'hardware FMA3 nei processori basati su Haswell nel corso del 2013.

### Estratto da FMA3

| Mnemonico (AT&T) | Operandi | Operazione |
| VFMADD132PDy | ymm, ymm, ymm/m256 | a = a·c + b |
| VFMADD132PSy | ymm, ymm, ymm/m256 | a = a·c + b |
| VFMADD132PDx | xmm, xmm, xmm/m128 | a = a·c + b |
| VFMADD132PSx | xmm, xmm, xmm/m128 | a = a·c + b |
| VFMADD132SD | xmm, xmm, xmm/m64 | a = a·c + b |
| VFMADD132SS | xmm, xmm, xmm/m32 | a = a·c + b |
| VFMADD213PDy | ymm, ymm, ymm/m256 | a = b·a + c |
| VFMADD213PSy | ymm, ymm, ymm/m256 | a = b·a + c |
| VFMADD213PDx | xmm, xmm, xmm/m128 | a = b·a + c |
| VFMADD213PSx | xmm, xmm, xmm/m128 | a = b·a + c |
| VFMADD213SD | xmm, xmm, xmm/m64 | a = b·a + c |
| VFMADD213SS | xmm, xmm, xmm/m32 | a = b·a + c |
| VFMADD231PDy | ymm, ymm, ymm/m256 | a = b·c + a |
| VFMADD231PSy | ymm, ymm, ymm/m256 | a = b·c + a |
| VFMADD231PDx | xmm, xmm, xmm/m128 | a = b·c + a |
| VFMADD231PSx | xmm, xmm, xmm/m128 | a = b·c + a |
| VFMADD231SD | xmm, xmm, xmm/m64 | a = b·c + a |
| VFMADD231SS | xmm, xmm, xmm/m32 | a = b·c + a |

## Set di istruzioni FMA4
### CPU con FMA4

* AMD
** Processori per "lavori pesanti"
*** Bulldozer, processore base, è stato lanciato il 12 ottobre 2011
*** Piledriver, processore base
*** Steamroller, processore base
*** Excavator, processore base (incluso "v2")
** Zen: i test di WikiChip mostrano che FMA4 sembra ancora funzionare (alle condizioni dei test) nonostante non sia ufficialmente supportato e nemmeno riportato da CPUID. Questo è stato confermato anche da Agner, ma altri test hanno dato risultati errati. Il sito web ufficiale AMD ha pubblicato una nota di supporto per FMA4 indicando come processori compatibili gli ZEN= AMD ThreadRipper 1900x, R7 Pro 1800, 1700, R5 Pro 1600, 1500, R3 Pro 1300, 1200, R3 2200G, R5 2400G
* Intel
** Non è certo che i futuri processori Intel supporteranno FMA4, a causa dell'annunciato cambiamento di Intel in FMA3.

### Estratto da FMA4

| Mnemonico (AT&T) | Operandi | Operazione |
| VFMADDPDx | xmm, xmm, xmm/m128, xmm/m128 | a = b·c + d |
| VFMADDPDy | ymm, ymm, ymm/m256, ymm/m256 | a = b·c + d |
| VFMADDPSx | xmm, xmm, xmm/m128, xmm/m128 | a = b·c + d |
| VFMADDPSy | ymm, ymm, ymm/m256, ymm/m256 | a = b·c + d |
| VFMADDSD | xmm, xmm, xmm/m64, xmm/m64 | a = b·c + d |
| VFMADDSS | xmm, xmm, xmm/m32, xmm/m32 | a = b·c + d |

## Storia

L'incompatibilità tra FMA3 di Intel e FMA4 di AMD è dovuta al fatto che entrambe le aziende cambiano i piani senza coordinare tra loro i dettagli di codifica. AMD ha cambiato i suoi piani da FMA3 a FMA4 mentre Intel ha cambiato i suoi da FMA4 a FMA3 quasi contemporaneamente. La storia può essere riassunta come segue:
* Agosto 2007: AMD annuncia il set di istruzioni SSE5, che include istruzioni per 3 operandi e FMA. Viene introdotto un nuovo schema di codifica (DREX) per consentire alle istruzioni di avere tre operandi
* Aprile 2008: Intel annuncia i set di istruzioni AVX e FMA, comprese le istruzioni per l'uso a 4 operandi e FMA. La codifica di queste istruzioni utilizza il nuovo schema di codifica VEX, che è più flessibile dello schema DREX di AMD
* Dicembre 2008: Intel cambia le specifiche per le istruzioni FMA da 4 operandi a 3 operandi. Lo schema di codifica VEX è ancora in uso
* Maggio 2009: AMD cambia le specifiche delle istruzioni FMA dal modulo 3-operandi DREX al modulo 4-operandi VEX, compatibile con le specifiche Intel dell'aprile 2008 piuttosto che con le specifiche Intel del dicembre 2008
* Ottobre 2011: il processore AMD Bulldozer supporta FMA4
* Gennaio 2012: AMD annuncia il supporto di FMA3 nei futuri processori Trinity e Vishera, che si basano sull'architettura Piledriver
* Maggio 2012: il processore AMD Piledriver supporta sia FMA3 che FMA4
* Giugno 2013: il processore Intel Haswell supporta FMA3
* Febbraio 2017: la prima generazione di processori AMD Ryzen supporta ufficialmente FMA3, ma non FMA4 secondo le istruzioni della CPUID. C'è stata confusione riguardo al fatto che FMA4 sia stato implementato o meno su questo processore a causa di errori nella patch iniziale del pacchetto GNU Binutils che da allora è stato corretto. Secondo alcuni test le istruzioni di FMA4 sembrano funzionare, anche se possono dare risultati errati. Inoltre, le CPU Ryzen iniziali potrebbero andare in crash a causa di una particolare sequenza di istruzioni FMA3. Da allora è stato risolto con un aggiornamento del mcrocode della CPU.

## Compilatori e assemblatori supportati

Diversi compilatori forniscono diversi livelli di supporto per FMA4:
* GCC supporta FMA4 con -mfma4 dalla versione 4.5.0 e FMA3 con -mfma dalla versione 4.7.0
* Microsoft Visual C++ 2010 SP1 supporta l'istruzione FMA4
* Microsoft Visual C++ 2012 supporta le istruzioni FMA3 (se il processore supporta anche l'estensione del set di istruzioni AVX2)
* Microsoft Visual C++ 2013
* Microsoft Visual C++ 2015
* Microsoft Visual C++ 2017
* PathScale supporta FMA4 con -mfma
* LLVM 3.1 aggiunge il supporto FMA4, insieme al supporto preliminare FMA3
* Open64 5.0 aggiunge "supporto limitato"
* I compilatori Intel supportano solo le istruzioni FMA3
* NASM supporta le istruzioni FMA3 dalla versione 2.03 e le istruzioni FMA4 dalla versione 2.06
* Yasm supporta le istruzioni FMA3 dalla versione 0.8.0 e le istruzioni FMA4 dalla versione 1.0.0.0
* FASM supporta sia le istruzioni FMA3 che FMA4