在英特尔架构指令集扩展编程参考的第 2.5.3 节“广播”中,我们了解到 AVX512(和 Knights Corner)有
为某些加载操作指令编码数据广播的位字段,即从内存加载数据并执行某些计算或数据移动操作的指令。
例如,使用 Intel 汇编语法,我们可以在存储的地址广播标量,rax
然后乘以 16 个浮点数zmm2
并将结果写成zmm1
这样
vmulps zmm1, zmm2, [rax] {1to16}
但是,没有内在函数可以做到这一点。因此,使用内在函数,编译器应该能够折叠
__m512 bb = _mm512_set1_ps(b);
__m512 ab = _mm512_mul_ps(a,bb);
单条指令
vmulps zmm1, zmm2, [rax] {1to16}
但我没有观察到 GCC 这样做。我发现了一个关于这个的 GCC 错误报告。
我观察到与 GCC 的 FMA 类似的东西。例如,GCC 4.9 不会崩溃_mm256_add_ps(_mm256_mul_ps(areg0,breg0)
为带有-Ofast
. 但是,GCC 5.1 现在确实将其折叠为单个 fma。至少有内在函数可以使用 FMA 执行此操作,例如_mm256_fmadd_ps
. 但是没有例如_mm512_mulbroad_ps(vector,scalar)
内在的。
GCC 可能会在某个时候解决这个问题,但在那之前,汇编是唯一的解决方案。
所以我的问题是如何在 GCC 中使用内联汇编来做到这一点?
对于上面的示例,我想我可能已经为 GCC 内联汇编提出了正确的语法(但我不确定)。
"vmulps (%%rax)%{1to16}, %%zmm1, %%zmm2\n\t"
我真的在寻找这样的功能
static inline __m512 mul_broad(__m512 a, float b) {
return a*b;
}
如果b
在内存中指向rax
它产生
vmulps (%rax){1to16}, %zmm0, %zmm0
ret
如果b
在xmm1
其中产生
vbroadcastss %xmm1, %zmm1
vmulps %zmm1, %zmm0, %zmm0
ret
GCC 已经vbroadcastss
使用内部函数执行 -from-register 案例,但如果b
在内存中,则将其编译为vbroadcastss
来自内存。
__m512 mul_broad(__m512 a, float b) {
__m512 bb = _mm512_set1_ps(b);
__m512 ab = _mm512_mul_ps(a,bb);
return ab;
}
如果b
在内存中,clang 将使用广播内存操作数。