Introduction
A fused multiply-add works out a × b + c and rounds the result once. A separate multiply and add round twice, once after each step. The single rounding makes the result more exact, and it does the work of two instructions in one. Every instruction here works on floating-point values in the vector registers: single precision (the ps and ss forms) or double precision (pd and sd), packed across the whole register or on the low element only.
There are two sets, and they are not compatible:
- FMA3 has three operands. The destination is also one of the sources, and the mnemonic’s digits (132, 213 or 231) say which. Intel brought it with Haswell, in 2013. AMD added it with Piledriver, in 2012, and every AMD processor since has it. A program checks CPUID leaf 01H, ECX bit 12 (FMA).
- FMA4 has four operands, and none of the sources is overwritten. It is AMD’s: it came with Bulldozer, in 2011, beside XOP. A program checks CPUID leaf 80000001H, ECX bit 16 (FMA4). AMD dropped FMA4 from Zen (2017) on: those processors do not report it in CPUID, and programs must not use it there.
Intel’s first AVX specification, in April 2008, described a four-operand fused multiply-add. Intel changed it to the three-operand form in December 2008. AMD moved its own plans to the four-operand form in 2009, shipped it in Bulldozer, and then added Intel’s form in Piledriver. Intel has never made a processor with FMA4.
Both sets are VEX-encoded (see Instruction encoding). They use the xmm registers for 128 bits and the ymm registers for 256 bits: 16 of each in 64-bit mode, 8 elsewhere. Rounding and exception masks come from MXCSR. Like every VEX instruction, they also need the operating system to save the AVX state: CPUID leaf 01H, ECX bit 27 (OSXSAVE) must be set, and XGETBV with ECX = 0 must show bits 1 and 2 of XCR0 set. A 128-bit form clears bits 255:128 of its destination register. The 512-bit EVEX forms of FMA3 are on the AVX-512 Foundation page.
FMA3 operand orders: 132, 213 and 231
Call the three operands a, b and c, in the order they are written. a is the destination and comes from ModRM.reg. b is a register, from VEX.vvvv. c is a register or memory, from ModRM.rm. Only c can be in memory.
The three digits name the operands by number: the first two are multiplied, and the third is added. So vfmadd132ps works out operand 1 × operand 3 + operand 2. The result always goes to operand 1, which the instruction overwrites.
| Order | Result | What it suits | Opcodes |
|---|---|---|---|
132 | a = a × c + b | A multiplier in memory; the destination’s value is a multiplier and is used up | 96–9F |
213 | a = b × a + c | An addend in memory; the destination’s value is a multiplier and is used up | A6–AF |
231 | a = b × c + a | Accumulating: a += b × c, as in a dot product or a polynomial | B6–BF |
The three orders give the same set of operations. A compiler picks the order by which value it may overwrite and which one it wants to read from memory: in 132 the memory operand is a multiplier, in 213 it is the addend, and in 231 it is a multiplier while the addend is the destination itself.
The low four bits of the opcode give the operation, in the same way for each order: 6 multiply with alternating subtract and add, 7 multiply with alternating add and subtract, 8 and 9 multiply-add, A and B multiply-subtract, C and D negated multiply-add, E and F negated multiply-subtract. The even opcode is the packed form, and the odd one the scalar form. VEX.W picks the precision: W0 single, W1 double.
FMA3 instructions
In each row a, b and c are the operands in order, as above. The packed forms work on every element of the register. The scalar forms work on the low element only (see Notes for the rest of the register).
Multiply and add
| Instruction | Forms | Encoding | What it does | Set |
|---|---|---|---|---|
vfmadd132ps | xmm1, xmm2, xmm3/m128ymm1, ymm2, ymm3/m256 | VEX.128.66.0F38.W0 98 /rVEX.256.66.0F38.W0 98 /r | a = a × c + b, on packed single-precision values | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfmadd132pd | xmm1, xmm2, xmm3/m128ymm1, ymm2, ymm3/m256 | VEX.128.66.0F38.W1 98 /rVEX.256.66.0F38.W1 98 /r | a = a × c + b, on packed double-precision values | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfmadd132ss | xmm1, xmm2, xmm3/m32 | VEX.LIG.66.0F38.W0 99 /r | a = a × c + b, on the low single-precision value | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfmadd132sd | xmm1, xmm2, xmm3/m64 | VEX.LIG.66.0F38.W1 99 /r | a = a × c + b, on the low double-precision value | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfmadd213ps | xmm1, xmm2, xmm3/m128ymm1, ymm2, ymm3/m256 | VEX.128.66.0F38.W0 A8 /rVEX.256.66.0F38.W0 A8 /r | a = b × a + c, on packed single-precision values | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfmadd213pd | xmm1, xmm2, xmm3/m128ymm1, ymm2, ymm3/m256 | VEX.128.66.0F38.W1 A8 /rVEX.256.66.0F38.W1 A8 /r | a = b × a + c, on packed double-precision values | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfmadd213ss | xmm1, xmm2, xmm3/m32 | VEX.LIG.66.0F38.W0 A9 /r | a = b × a + c, on the low single-precision value | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfmadd213sd | xmm1, xmm2, xmm3/m64 | VEX.LIG.66.0F38.W1 A9 /r | a = b × a + c, on the low double-precision value | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfmadd231ps | xmm1, xmm2, xmm3/m128ymm1, ymm2, ymm3/m256 | VEX.128.66.0F38.W0 B8 /rVEX.256.66.0F38.W0 B8 /r | a = b × c + a, on packed single-precision values | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfmadd231pd | xmm1, xmm2, xmm3/m128ymm1, ymm2, ymm3/m256 | VEX.128.66.0F38.W1 B8 /rVEX.256.66.0F38.W1 B8 /r | a = b × c + a, on packed double-precision values | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfmadd231ss | xmm1, xmm2, xmm3/m32 | VEX.LIG.66.0F38.W0 B9 /r | a = b × c + a, on the low single-precision value | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfmadd231sd | xmm1, xmm2, xmm3/m64 | VEX.LIG.66.0F38.W1 B9 /r | a = b × c + a, on the low double-precision value | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
Multiply and subtract
| Instruction | Forms | Encoding | What it does | Set |
|---|---|---|---|---|
vfmsub132ps | xmm1, xmm2, xmm3/m128ymm1, ymm2, ymm3/m256 | VEX.128.66.0F38.W0 9A /rVEX.256.66.0F38.W0 9A /r | a = a × c − b, on packed single-precision values | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfmsub132pd | xmm1, xmm2, xmm3/m128ymm1, ymm2, ymm3/m256 | VEX.128.66.0F38.W1 9A /rVEX.256.66.0F38.W1 9A /r | a = a × c − b, on packed double-precision values | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfmsub132ss | xmm1, xmm2, xmm3/m32 | VEX.LIG.66.0F38.W0 9B /r | a = a × c − b, on the low single-precision value | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfmsub132sd | xmm1, xmm2, xmm3/m64 | VEX.LIG.66.0F38.W1 9B /r | a = a × c − b, on the low double-precision value | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfmsub213ps | xmm1, xmm2, xmm3/m128ymm1, ymm2, ymm3/m256 | VEX.128.66.0F38.W0 AA /rVEX.256.66.0F38.W0 AA /r | a = b × a − c, on packed single-precision values | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfmsub213pd | xmm1, xmm2, xmm3/m128ymm1, ymm2, ymm3/m256 | VEX.128.66.0F38.W1 AA /rVEX.256.66.0F38.W1 AA /r | a = b × a − c, on packed double-precision values | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfmsub213ss | xmm1, xmm2, xmm3/m32 | VEX.LIG.66.0F38.W0 AB /r | a = b × a − c, on the low single-precision value | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfmsub213sd | xmm1, xmm2, xmm3/m64 | VEX.LIG.66.0F38.W1 AB /r | a = b × a − c, on the low double-precision value | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfmsub231ps | xmm1, xmm2, xmm3/m128ymm1, ymm2, ymm3/m256 | VEX.128.66.0F38.W0 BA /rVEX.256.66.0F38.W0 BA /r | a = b × c − a, on packed single-precision values | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfmsub231pd | xmm1, xmm2, xmm3/m128ymm1, ymm2, ymm3/m256 | VEX.128.66.0F38.W1 BA /rVEX.256.66.0F38.W1 BA /r | a = b × c − a, on packed double-precision values | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfmsub231ss | xmm1, xmm2, xmm3/m32 | VEX.LIG.66.0F38.W0 BB /r | a = b × c − a, on the low single-precision value | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfmsub231sd | xmm1, xmm2, xmm3/m64 | VEX.LIG.66.0F38.W1 BB /r | a = b × c − a, on the low double-precision value | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
Negated multiply and add
| Instruction | Forms | Encoding | What it does | Set |
|---|---|---|---|---|
vfnmadd132ps | xmm1, xmm2, xmm3/m128ymm1, ymm2, ymm3/m256 | VEX.128.66.0F38.W0 9C /rVEX.256.66.0F38.W0 9C /r | a = −(a × c) + b, on packed single-precision values | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfnmadd132pd | xmm1, xmm2, xmm3/m128ymm1, ymm2, ymm3/m256 | VEX.128.66.0F38.W1 9C /rVEX.256.66.0F38.W1 9C /r | a = −(a × c) + b, on packed double-precision values | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfnmadd132ss | xmm1, xmm2, xmm3/m32 | VEX.LIG.66.0F38.W0 9D /r | a = −(a × c) + b, on the low single-precision value | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfnmadd132sd | xmm1, xmm2, xmm3/m64 | VEX.LIG.66.0F38.W1 9D /r | a = −(a × c) + b, on the low double-precision value | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfnmadd213ps | xmm1, xmm2, xmm3/m128ymm1, ymm2, ymm3/m256 | VEX.128.66.0F38.W0 AC /rVEX.256.66.0F38.W0 AC /r | a = −(b × a) + c, on packed single-precision values | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfnmadd213pd | xmm1, xmm2, xmm3/m128ymm1, ymm2, ymm3/m256 | VEX.128.66.0F38.W1 AC /rVEX.256.66.0F38.W1 AC /r | a = −(b × a) + c, on packed double-precision values | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfnmadd213ss | xmm1, xmm2, xmm3/m32 | VEX.LIG.66.0F38.W0 AD /r | a = −(b × a) + c, on the low single-precision value | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfnmadd213sd | xmm1, xmm2, xmm3/m64 | VEX.LIG.66.0F38.W1 AD /r | a = −(b × a) + c, on the low double-precision value | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfnmadd231ps | xmm1, xmm2, xmm3/m128ymm1, ymm2, ymm3/m256 | VEX.128.66.0F38.W0 BC /rVEX.256.66.0F38.W0 BC /r | a = −(b × c) + a, on packed single-precision values | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfnmadd231pd | xmm1, xmm2, xmm3/m128ymm1, ymm2, ymm3/m256 | VEX.128.66.0F38.W1 BC /rVEX.256.66.0F38.W1 BC /r | a = −(b × c) + a, on packed double-precision values | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfnmadd231ss | xmm1, xmm2, xmm3/m32 | VEX.LIG.66.0F38.W0 BD /r | a = −(b × c) + a, on the low single-precision value | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfnmadd231sd | xmm1, xmm2, xmm3/m64 | VEX.LIG.66.0F38.W1 BD /r | a = −(b × c) + a, on the low double-precision value | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
Negated multiply and subtract
| Instruction | Forms | Encoding | What it does | Set |
|---|---|---|---|---|
vfnmsub132ps | xmm1, xmm2, xmm3/m128ymm1, ymm2, ymm3/m256 | VEX.128.66.0F38.W0 9E /rVEX.256.66.0F38.W0 9E /r | a = −(a × c) − b, on packed single-precision values | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfnmsub132pd | xmm1, xmm2, xmm3/m128ymm1, ymm2, ymm3/m256 | VEX.128.66.0F38.W1 9E /rVEX.256.66.0F38.W1 9E /r | a = −(a × c) − b, on packed double-precision values | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfnmsub132ss | xmm1, xmm2, xmm3/m32 | VEX.LIG.66.0F38.W0 9F /r | a = −(a × c) − b, on the low single-precision value | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfnmsub132sd | xmm1, xmm2, xmm3/m64 | VEX.LIG.66.0F38.W1 9F /r | a = −(a × c) − b, on the low double-precision value | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfnmsub213ps | xmm1, xmm2, xmm3/m128ymm1, ymm2, ymm3/m256 | VEX.128.66.0F38.W0 AE /rVEX.256.66.0F38.W0 AE /r | a = −(b × a) − c, on packed single-precision values | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfnmsub213pd | xmm1, xmm2, xmm3/m128ymm1, ymm2, ymm3/m256 | VEX.128.66.0F38.W1 AE /rVEX.256.66.0F38.W1 AE /r | a = −(b × a) − c, on packed double-precision values | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfnmsub213ss | xmm1, xmm2, xmm3/m32 | VEX.LIG.66.0F38.W0 AF /r | a = −(b × a) − c, on the low single-precision value | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfnmsub213sd | xmm1, xmm2, xmm3/m64 | VEX.LIG.66.0F38.W1 AF /r | a = −(b × a) − c, on the low double-precision value | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfnmsub231ps | xmm1, xmm2, xmm3/m128ymm1, ymm2, ymm3/m256 | VEX.128.66.0F38.W0 BE /rVEX.256.66.0F38.W0 BE /r | a = −(b × c) − a, on packed single-precision values | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfnmsub231pd | xmm1, xmm2, xmm3/m128ymm1, ymm2, ymm3/m256 | VEX.128.66.0F38.W1 BE /rVEX.256.66.0F38.W1 BE /r | a = −(b × c) − a, on packed double-precision values | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfnmsub231ss | xmm1, xmm2, xmm3/m32 | VEX.LIG.66.0F38.W0 BF /r | a = −(b × c) − a, on the low single-precision value | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfnmsub231sd | xmm1, xmm2, xmm3/m64 | VEX.LIG.66.0F38.W1 BF /r | a = −(b × c) − a, on the low double-precision value | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
Alternating add and subtract
These have packed forms only. Elements are numbered from 0 at the low end. vfmaddsub subtracts in the even-numbered elements and adds in the odd-numbered ones; vfmsubadd does the opposite. They suit complex multiplication, where real and imaginary parts alternate.
| Instruction | Forms | Encoding | What it does | Set |
|---|---|---|---|---|
vfmaddsub132ps | xmm1, xmm2, xmm3/m128ymm1, ymm2, ymm3/m256 | VEX.128.66.0F38.W0 96 /rVEX.256.66.0F38.W0 96 /r | a = a × c − b in even elements, a × c + b in odd ones; single precision | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfmaddsub132pd | xmm1, xmm2, xmm3/m128ymm1, ymm2, ymm3/m256 | VEX.128.66.0F38.W1 96 /rVEX.256.66.0F38.W1 96 /r | a = a × c − b in even elements, a × c + b in odd ones; double precision | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfmaddsub213ps | xmm1, xmm2, xmm3/m128ymm1, ymm2, ymm3/m256 | VEX.128.66.0F38.W0 A6 /rVEX.256.66.0F38.W0 A6 /r | a = b × a − c in even elements, b × a + c in odd ones; single precision | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfmaddsub213pd | xmm1, xmm2, xmm3/m128ymm1, ymm2, ymm3/m256 | VEX.128.66.0F38.W1 A6 /rVEX.256.66.0F38.W1 A6 /r | a = b × a − c in even elements, b × a + c in odd ones; double precision | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfmaddsub231ps | xmm1, xmm2, xmm3/m128ymm1, ymm2, ymm3/m256 | VEX.128.66.0F38.W0 B6 /rVEX.256.66.0F38.W0 B6 /r | a = b × c − a in even elements, b × c + a in odd ones; single precision | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfmaddsub231pd | xmm1, xmm2, xmm3/m128ymm1, ymm2, ymm3/m256 | VEX.128.66.0F38.W1 B6 /rVEX.256.66.0F38.W1 B6 /r | a = b × c − a in even elements, b × c + a in odd ones; double precision | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfmsubadd132ps | xmm1, xmm2, xmm3/m128ymm1, ymm2, ymm3/m256 | VEX.128.66.0F38.W0 97 /rVEX.256.66.0F38.W0 97 /r | a = a × c + b in even elements, a × c − b in odd ones; single precision | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfmsubadd132pd | xmm1, xmm2, xmm3/m128ymm1, ymm2, ymm3/m256 | VEX.128.66.0F38.W1 97 /rVEX.256.66.0F38.W1 97 /r | a = a × c + b in even elements, a × c − b in odd ones; double precision | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfmsubadd213ps | xmm1, xmm2, xmm3/m128ymm1, ymm2, ymm3/m256 | VEX.128.66.0F38.W0 A7 /rVEX.256.66.0F38.W0 A7 /r | a = b × a + c in even elements, b × a − c in odd ones; single precision | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfmsubadd213pd | xmm1, xmm2, xmm3/m128ymm1, ymm2, ymm3/m256 | VEX.128.66.0F38.W1 A7 /rVEX.256.66.0F38.W1 A7 /r | a = b × a + c in even elements, b × a − c in odd ones; double precision | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfmsubadd231ps | xmm1, xmm2, xmm3/m128ymm1, ymm2, ymm3/m256 | VEX.128.66.0F38.W0 B7 /rVEX.256.66.0F38.W0 B7 /r | a = b × c + a in even elements, b × c − a in odd ones; single precision | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
vfmsubadd231pd | xmm1, xmm2, xmm3/m128ymm1, ymm2, ymm3/m256 | VEX.128.66.0F38.W1 B7 /rVEX.256.66.0F38.W1 B7 /r | a = b × c + a in even elements, b × c − a in odd ones; double precision | FMA3 (Intel Haswell, 2013; AMD Piledriver, 2012) |
FMA4 instructions
FMA4 sits in VEX map 3 (0F 3A) with the 66 prefix. The four operands are a, b, c and d, in order, and every instruction works out a = b × c ± d. a comes from ModRM.reg and b from VEX.vvvv. The other two come from ModRM.rm and from bits 7:4 of a trailing byte (written /is4), and VEX.W says which is which:
- W0: c is ModRM.rm (a register or memory) and d is the register in imm8[7:4];
- W1: c is the register in imm8[7:4] and d is ModRM.rm.
So either the multiplier or the addend can come from memory. The bits 3:0 of the trailing byte are not used. The names have no digits: the order is always the same.
Multiply and add or subtract
| Instruction | Forms | Encoding | What it does | Set |
|---|---|---|---|---|
vfmaddps | xmm1, xmm2, xmm3/m128, xmm4xmm1, xmm2, xmm3, xmm4/m128ymm1, ymm2, ymm3/m256, ymm4ymm1, ymm2, ymm3, ymm4/m256 | VEX.128.66.0F3A.W0 68 /r /is4VEX.128.66.0F3A.W1 68 /r /is4VEX.256.66.0F3A.W0 68 /r /is4VEX.256.66.0F3A.W1 68 /r /is4 | a = b × c + d, on packed single-precision values | FMA4 (AMD Bulldozer, 2011) |
vfmaddpd | xmm1, xmm2, xmm3/m128, xmm4xmm1, xmm2, xmm3, xmm4/m128ymm1, ymm2, ymm3/m256, ymm4ymm1, ymm2, ymm3, ymm4/m256 | VEX.128.66.0F3A.W0 69 /r /is4VEX.128.66.0F3A.W1 69 /r /is4VEX.256.66.0F3A.W0 69 /r /is4VEX.256.66.0F3A.W1 69 /r /is4 | a = b × c + d, on packed double-precision values | FMA4 (AMD Bulldozer, 2011) |
vfmaddss | xmm1, xmm2, xmm3/m32, xmm4xmm1, xmm2, xmm3, xmm4/m32 | VEX.LIG.66.0F3A.W0 6A /r /is4VEX.LIG.66.0F3A.W1 6A /r /is4 | a = b × c + d, on the low single-precision value | FMA4 (AMD Bulldozer, 2011) |
vfmaddsd | xmm1, xmm2, xmm3/m64, xmm4xmm1, xmm2, xmm3, xmm4/m64 | VEX.LIG.66.0F3A.W0 6B /r /is4VEX.LIG.66.0F3A.W1 6B /r /is4 | a = b × c + d, on the low double-precision value | FMA4 (AMD Bulldozer, 2011) |
vfmsubps | xmm1, xmm2, xmm3/m128, xmm4xmm1, xmm2, xmm3, xmm4/m128ymm1, ymm2, ymm3/m256, ymm4ymm1, ymm2, ymm3, ymm4/m256 | VEX.128.66.0F3A.W0 6C /r /is4VEX.128.66.0F3A.W1 6C /r /is4VEX.256.66.0F3A.W0 6C /r /is4VEX.256.66.0F3A.W1 6C /r /is4 | a = b × c − d, on packed single-precision values | FMA4 (AMD Bulldozer, 2011) |
vfmsubpd | xmm1, xmm2, xmm3/m128, xmm4xmm1, xmm2, xmm3, xmm4/m128ymm1, ymm2, ymm3/m256, ymm4ymm1, ymm2, ymm3, ymm4/m256 | VEX.128.66.0F3A.W0 6D /r /is4VEX.128.66.0F3A.W1 6D /r /is4VEX.256.66.0F3A.W0 6D /r /is4VEX.256.66.0F3A.W1 6D /r /is4 | a = b × c − d, on packed double-precision values | FMA4 (AMD Bulldozer, 2011) |
vfmsubss | xmm1, xmm2, xmm3/m32, xmm4xmm1, xmm2, xmm3, xmm4/m32 | VEX.LIG.66.0F3A.W0 6E /r /is4VEX.LIG.66.0F3A.W1 6E /r /is4 | a = b × c − d, on the low single-precision value | FMA4 (AMD Bulldozer, 2011) |
vfmsubsd | xmm1, xmm2, xmm3/m64, xmm4xmm1, xmm2, xmm3, xmm4/m64 | VEX.LIG.66.0F3A.W0 6F /r /is4VEX.LIG.66.0F3A.W1 6F /r /is4 | a = b × c − d, on the low double-precision value | FMA4 (AMD Bulldozer, 2011) |
vfnmaddps | xmm1, xmm2, xmm3/m128, xmm4xmm1, xmm2, xmm3, xmm4/m128ymm1, ymm2, ymm3/m256, ymm4ymm1, ymm2, ymm3, ymm4/m256 | VEX.128.66.0F3A.W0 78 /r /is4VEX.128.66.0F3A.W1 78 /r /is4VEX.256.66.0F3A.W0 78 /r /is4VEX.256.66.0F3A.W1 78 /r /is4 | a = −(b × c) + d, on packed single-precision values | FMA4 (AMD Bulldozer, 2011) |
vfnmaddpd | xmm1, xmm2, xmm3/m128, xmm4xmm1, xmm2, xmm3, xmm4/m128ymm1, ymm2, ymm3/m256, ymm4ymm1, ymm2, ymm3, ymm4/m256 | VEX.128.66.0F3A.W0 79 /r /is4VEX.128.66.0F3A.W1 79 /r /is4VEX.256.66.0F3A.W0 79 /r /is4VEX.256.66.0F3A.W1 79 /r /is4 | a = −(b × c) + d, on packed double-precision values | FMA4 (AMD Bulldozer, 2011) |
vfnmaddss | xmm1, xmm2, xmm3/m32, xmm4xmm1, xmm2, xmm3, xmm4/m32 | VEX.LIG.66.0F3A.W0 7A /r /is4VEX.LIG.66.0F3A.W1 7A /r /is4 | a = −(b × c) + d, on the low single-precision value | FMA4 (AMD Bulldozer, 2011) |
vfnmaddsd | xmm1, xmm2, xmm3/m64, xmm4xmm1, xmm2, xmm3, xmm4/m64 | VEX.LIG.66.0F3A.W0 7B /r /is4VEX.LIG.66.0F3A.W1 7B /r /is4 | a = −(b × c) + d, on the low double-precision value | FMA4 (AMD Bulldozer, 2011) |
vfnmsubps | xmm1, xmm2, xmm3/m128, xmm4xmm1, xmm2, xmm3, xmm4/m128ymm1, ymm2, ymm3/m256, ymm4ymm1, ymm2, ymm3, ymm4/m256 | VEX.128.66.0F3A.W0 7C /r /is4VEX.128.66.0F3A.W1 7C /r /is4VEX.256.66.0F3A.W0 7C /r /is4VEX.256.66.0F3A.W1 7C /r /is4 | a = −(b × c) − d, on packed single-precision values | FMA4 (AMD Bulldozer, 2011) |
vfnmsubpd | xmm1, xmm2, xmm3/m128, xmm4xmm1, xmm2, xmm3, xmm4/m128ymm1, ymm2, ymm3/m256, ymm4ymm1, ymm2, ymm3, ymm4/m256 | VEX.128.66.0F3A.W0 7D /r /is4VEX.128.66.0F3A.W1 7D /r /is4VEX.256.66.0F3A.W0 7D /r /is4VEX.256.66.0F3A.W1 7D /r /is4 | a = −(b × c) − d, on packed double-precision values | FMA4 (AMD Bulldozer, 2011) |
vfnmsubss | xmm1, xmm2, xmm3/m32, xmm4xmm1, xmm2, xmm3, xmm4/m32 | VEX.LIG.66.0F3A.W0 7E /r /is4VEX.LIG.66.0F3A.W1 7E /r /is4 | a = −(b × c) − d, on the low single-precision value | FMA4 (AMD Bulldozer, 2011) |
vfnmsubsd | xmm1, xmm2, xmm3/m64, xmm4xmm1, xmm2, xmm3, xmm4/m64 | VEX.LIG.66.0F3A.W0 7F /r /is4VEX.LIG.66.0F3A.W1 7F /r /is4 | a = −(b × c) − d, on the low double-precision value | FMA4 (AMD Bulldozer, 2011) |
Alternating add and subtract
| Instruction | Forms | Encoding | What it does | Set |
|---|---|---|---|---|
vfmaddsubps | xmm1, xmm2, xmm3/m128, xmm4xmm1, xmm2, xmm3, xmm4/m128ymm1, ymm2, ymm3/m256, ymm4ymm1, ymm2, ymm3, ymm4/m256 | VEX.128.66.0F3A.W0 5C /r /is4VEX.128.66.0F3A.W1 5C /r /is4VEX.256.66.0F3A.W0 5C /r /is4VEX.256.66.0F3A.W1 5C /r /is4 | a = b × c − d in even elements, b × c + d in odd ones; single precision | FMA4 (AMD Bulldozer, 2011) |
vfmaddsubpd | xmm1, xmm2, xmm3/m128, xmm4xmm1, xmm2, xmm3, xmm4/m128ymm1, ymm2, ymm3/m256, ymm4ymm1, ymm2, ymm3, ymm4/m256 | VEX.128.66.0F3A.W0 5D /r /is4VEX.128.66.0F3A.W1 5D /r /is4VEX.256.66.0F3A.W0 5D /r /is4VEX.256.66.0F3A.W1 5D /r /is4 | a = b × c − d in even elements, b × c + d in odd ones; double precision | FMA4 (AMD Bulldozer, 2011) |
vfmsubaddps | xmm1, xmm2, xmm3/m128, xmm4xmm1, xmm2, xmm3, xmm4/m128ymm1, ymm2, ymm3/m256, ymm4ymm1, ymm2, ymm3, ymm4/m256 | VEX.128.66.0F3A.W0 5E /r /is4VEX.128.66.0F3A.W1 5E /r /is4VEX.256.66.0F3A.W0 5E /r /is4VEX.256.66.0F3A.W1 5E /r /is4 | a = b × c + d in even elements, b × c − d in odd ones; single precision | FMA4 (AMD Bulldozer, 2011) |
vfmsubaddpd | xmm1, xmm2, xmm3/m128, xmm4xmm1, xmm2, xmm3, xmm4/m128ymm1, ymm2, ymm3/m256, ymm4ymm1, ymm2, ymm3, ymm4/m256 | VEX.128.66.0F3A.W0 5F /r /is4VEX.128.66.0F3A.W1 5F /r /is4VEX.256.66.0F3A.W0 5F /r /is4VEX.256.66.0F3A.W1 5F /r /is4 | a = b × c + d in even elements, b × c − d in odd ones; double precision | FMA4 (AMD Bulldozer, 2011) |
Notes
- Rounding and exceptions. The product is not rounded; only the final sum is, by the rounding mode in MXCSR. The instructions raise the usual SIMD floating-point exceptions (invalid, denormal, overflow, underflow and precision), masked or not by MXCSR. They do not change the flags in EFLAGS.
- Alignment. A memory operand need not be aligned.
- The rest of a scalar destination. In FMA3 the destination is also a source, so a scalar form keeps the destination’s own bits above the low element, up to bit 127; bits 255:128 are cleared.
- VEX.L and VEX.W. The scalar forms ignore VEX.L (LIG). In FMA3, VEX.W picks single or double precision. In FMA4 the precision is in the opcode, and VEX.W picks which source may be in memory.
- The fourth register outside 64-bit mode. Only xmm0–xmm7 exist there, so bit 7 of the
/is4byte has no register to name. We ignore it, as GNU binutils does; LLVM does not. - 16-bit code. VEX instructions run in 16-bit protected mode, so we decode them in 16-bit code too, with 16-bit addressing (
[bx + si]). They are not available in real mode or virtual-8086 mode. - Assembler names. GNU and LLVM use the same mnemonics as Intel’s and AMD’s manuals. Intel’s compilers and many libraries reach these instructions through intrinsics such as
_mm256_fmadd_ps(FMA3) and_mm_macc_ps(FMA4).
Links
Reference
- Intel 64 and IA-32 Architectures Software Developer’s Manuals – Intel’s manual; volume 2 describes each FMA3 instruction (VFMADD132PS and the rest)
- AMD64 Architecture Programmer’s Manual, Volume 4 – AMD’s manual of the media instructions, with FMA3 and FMA4
- x86 and amd64 instruction reference – Félix Cloutier’s unofficial HTML copy of volume 2 of Intel’s manual