In section 2.5.3 "Broadcasts" of the Intel Architecture Instruction Set Extensions Programming Reference the we learn than
AVX512 (and Knights Corner) has
a bit-field to encode data broadcast for some load-op instructions, i.e. instructions that
load data from memory and perform some computational
or data movement operation.
For example using Intel assembly syntax we can broadcast the scalar at the address stored in rax
and then multiplying with the 16 floats in zmm2
and write the result to zmm1
like this
vmulps zmm1, zmm2, [rax] {1to16}
However, there are no intrinsics which can do this. Therefore, with intrinsics the compiler should be able to fold
__m512 bb = _mm512_set1_ps(b);
__m512 ab = _mm512_mul_ps(a,bb);
to a single instruction
vmulps zmm1, zmm2, [rax] {1to16}
but I have not observed GCC doing this. I found a GCC bug report about this.
I have observed something similar with FMA with GCC. e.g. GCC 4.9 will not collapse _mm256_add_ps(_mm256_mul_ps(areg0,breg0)
to a single fma instruction with -Ofast
. However, GCC 5.1 does collapse it to a single fma now. At least there are intrinsics to do this with FMA e.g. _mm256_fmadd_ps
. But there is no e.g. _mm512_mulbroad_ps(vector,scalar)
intrinsic.
GCC may fix this at some point but until then assembly is the only solution.
So my question is how to do this with inline assembly in GCC?
I think I may have come up with the correct syntax (but I am not sure) for GCC inline assembly for the example above.
"vmulps (%%rax)%{1to16}, %%zmm1, %%zmm2
"
I am really looking for a function like this
static inline __m512 mul_broad(__m512 a, float b) {
return a*b;
}
where if b
is in memory point to in rax
it produces
vmulps (%rax){1to16}, %zmm0, %zmm0
ret
and if b
is in xmm1
it produces
vbroadcastss %xmm1, %zmm1
vmulps %zmm1, %zmm0, %zmm0
ret
GCC will already do the vbroadcastss
-from-register case with intrinsics, but if b
is in memory, compiles this to a vbroadcastss
from memory.
__m512 mul_broad(__m512 a, float b) {
__m512 bb = _mm512_set1_ps(b);
__m512 ab = _mm512_mul_ps(a,bb);
return ab;
}
clang will use a broadcast memory operand if b
is in memory.
See Question&Answers more detail:
os