具有内在函数和汇编的嵌入式广播

玻色子

在《英特尔架构指令集扩展编程参考》的第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错误报告

我观察到与FCC和GCC相似。例如,GCC 4.9不会折叠_mm256_add_ps(_mm256_mul_ps(areg0,breg0) 为单个fma指令-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

如果bxmm1其中产生

vbroadcastss    %xmm1, %zmm1
vmulps          %zmm1, %zmm0, %zmm0
ret

GCC已经vbroadcastss使用内部函数处理-from-register情况,但是如果b在内存中,则将其编译为vbroadcastssfrom内存。

__m512 mul_broad(__m512 a, float b) {       
    __m512 bb = _mm512_set1_ps(b);
    __m512 ab = _mm512_mul_ps(a,bb);
    return ab;
}

如果内存中有clang,它将使用广播内存操作数b

罗斯里奇

正如Peter Cordes所述,GCC不允许您为不同的约束替代方案指定其他模板。因此,我的解决方案改为让汇编器根据所选的操作数选择正确的指令。

我没有支持ZMM寄存器的GCC版本,因此下面的示例使用XMM寄存器和一些不存在的指令来演示如何实现所需的功能。

typedef __attribute__((vector_size(16))) float v4sf;

v4sf
foo(v4sf a, float b) {
    v4sf ret;
    asm(".ifndef isxmm\n\t"
        ".altmacro\n\t"
        ".macro ifxmm operand, rnum\n\t"
        ".ifc \"\\operand\",\"%%xmm\\rnum\"\n\t"
        ".set isxmm, 1\n\t"
        ".endif\n\t"
        ".endm\n\t"
        ".endif\n\t"
        ".set isxmm, 0\n\t"
        ".set regnum, 0\n\t"
        ".rept 8\n\t"
        "ifxmm <%2>, %%regnum\n\t"
        ".set regnum, regnum + 1\n\t"
        ".endr\n\t"
        ".if isxmm\n\t"
        "alt-1 %1, %2, %0\n\t"
        ".else\n\t"
        "alt-2 %1, %2, %0\n\t"
        ".endif\n\t"
        : "=x,x" (ret)
        : "x,x" (a), "x,m" (b));
    return ret;
}


v4sf
bar(v4sf a, v4sf b) {
    return foo(a, b[0]);
}

此示例应使用编译,gcc -m32 -msse -O3并应生成两个类似于以下内容的汇编器错误消息:

t103.c: Assembler messages:
t103.c:24: Error: no such instruction: `alt-2 %xmm0,4(%esp),%xmm0'
t103.c:22: Error: no such instruction: `alt-1 %xmm0,%xmm1,%xmm0'

此处的基本思想是汇编程序检查第二个操作数(%2)是否为XMM寄存器还是其他(可能是内存位置)。由于GNU汇编器对字符串的操作方式不支持太多,因此第二个操作数在.rept循环中一次与每个可能的XMM寄存器进行比较isxmm宏用于粘贴%xmm和一个寄存器号在一起。

对于您的特定问题,您可能需要像这样重写它:

__m512
mul_broad(__m512 a, float b) {
    __m512 ret;
    __m512 dummy;
    asm(".ifndef isxmm\n\t"
        ".altmacro\n\t"
        ".macro ifxmm operand, rnum\n\t"
        ".ifc \"\\operand\",\"%%zmm\\rnum\"\n\t"
        ".set isxmm, 1\n\t"
        ".endif\n\t"
        ".endm\n\t"
        ".endif\n\t"
        ".set isxmm, 0\n\t"
        ".set regnum, 0\n\t"
        ".rept 32\n\t"
        "ifxmm <%[b]>, %%regnum\n\t"
        ".set regnum, regnum + 1\n\t"
        ".endr\n\t"
        ".if isxmm\n\t"
        "vbroadcastss %x[b], %[b]\n\t"
        "vmulps %[a], %[b], %[ret]\n\t"
        ".else\n\t"
        "vmulps %[b] %{1to16%}, %[a], %[ret]\n\t"
        "# dummy = %[dummy]\n\t"
        ".endif\n\t"
        : [ret] "=x,x" (ret), [dummy] "=xm,x" (dummy)
        : [a] "x,xm" (a), [b] "m,[dummy]" (b));
    return ret;
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

具有嵌入式文档的MongoDB findOne()和updateOne()

具有JSON和嵌入式对象的powershell

具有Aspnet身份和资源所有者的嵌入式IdentityServer 4

使用类型在Go中具有嵌入式类型的参数定义函数

具有NFS引导和SSH的嵌入式Linux板

具有多种消息类型的嵌入式 RTOS 生产者和消费者

具有嵌入式和ng内容子项的不同ChangeDetectionStrategy.OnPush行为

在Java中将$ addToSet和upsert用于具有特定JSON的嵌入式文档

具有多个定义的嵌入式C和AVR GCC编译问题

具有嵌入式 Tomcat 和通用名称 (CN) 的双向 TLS

具有多个嵌入式行的Bootstrap崩溃

具有嵌入式Jetty的异步Servlet

如何编写具有嵌入式ID的JPQL SELECT?

使具有嵌套图像的嵌入式SVG可以访问

具有json / xml响应的嵌入式码头

GraphicsMagick是否具有嵌入式图像裁剪?

具有嵌入式匿名接口的结构的含义?

遍历具有嵌入式结构的结构

具有多个嵌入式结构的 Go MarshalJSON 行为

具有嵌入式hasMay关系的EmberJS RESTSerializer

具有独立应用程序的嵌入式Linux

带有Jersey和嵌入式Jetty的CrossOriginFilter

带有嵌入式HTML和验证的XML模式

RTOS和嵌入式Linux有什么区别?

具有嵌入式ID的实体的带有Spring Boot DDL查询错误的Wix嵌入式mysql

使用聚合查询获取具有总交易数和交易明细的用户列表作为嵌入式文档

MongoDB嵌入式文档数组:仅获取一个具有特定属性的嵌入式文档

为什么要编写嵌入式汇编代码?

通过嵌入式汇编语言递增变量