Could someone explain to me why there are 3 variants of the fused multiply-accumulate instruction: vfmadd132pd
, vfmadd231pd
and vfmadd213pd
, while there is only one C intrinsics _mm256_fmadd_pd
?
To make things simple, what is the difference between (in AT&T syntax)
vfmadd132pd %ymm0, %ymm1, %ymm2
vfmadd231pd %ymm0, %ymm1, %ymm2
vfmadd213pd %ymm0, %ymm1, %ymm2
I did not get any idea from Intel's intrinsics guide. I ask because I see all of them in the assembler output of a chunk of C code I wrote. Thanks.
A clean answer (re-formating answers below)
For variant ijk
, the meaning of vfmaddijkpd
:
- intel syntax:
op(i) * op(j) + op(k) -> op(1)
- AT&T syntax:
op(4-i) * op(4-j) + op(4-k) -> op(3)
where op(n)
denotes the n-th operand after the instruction. So there is a reverse transform between the two:
n <- 4 - n
The fused multiply-add instructions multiply two (packed) values, add a third value, and then overwrite one of the values with the result. Only one of the three values can be a memory operand rather than a register.
The way it works is that all three instructions overwrite ymm0
and allow only ymm2
to be a memory operand. The choice of instruction determines which two operands are multiplied and which is added.
Assuming that ymm0 is the first operand in Intel syntax (or the last in AT&T syntax):
vfmadd132pd: ymm0 = ymm0 * ymm2/mem + ymm1
vfmadd231pd: ymm0 = ymm1 * ymm2/mem + ymm0
vfmadd213pd: ymm0 = ymm0 * ymm1 + ymm2/mem
When using the C intrinsics, this choice isn't necessary: The intrinsic does not overwrite a value but returns its result instead, and it allows all three values to be read from memory. The compiler will add memory reads/writes if needed, and will allocate a temporary register to store the result if it does not want any of the three values to be overwritten. It will choose one of the three instructions as it sees fit.
This is in the instruction set reference:
VFMADD132PD: Multiplies the two or four packed double-precision
floating-point values from the first source operand to the two or
four packed double-precision floating-point values in the third source
operand, adds the infinite precision intermediate result to the two
or four packed double-precision floating-point values in the second
source operand, performs rounding and stores the resulting two or four
packed double-precision floating-point values to the destination
operand (first source operand).
VFMADD213PD: Multiplies the two or
four packed double-precision floating-point values from the second
source operand to the two or four packed double-precision
floating-point values in the first source operand, adds the infinite
precision intermediate result to the two or four packed
double-precision floating-point values in the third source operand,
performs rounding and stores the resulting two or four packed
double-precision floating-point values to the destination operand
(first source operand).
VFMADD231PD: Multiplies the two or four packed
double-precision floating-point values from the second source to the
two or four packed double-precision floating-point values in the third
source operand, adds the infinite precision intermediate result to
the two or four packed double-precision floating-point values in the
first source operand, performs rounding and stores the resulting two
or four packed double-precision floating-point values to the desti-
nation operand (first source operand).