当前位置:  开发笔记 > 编程语言 > 正文

在GNU C inline asm中,对于单个操作数,xmm/ymm/zmm的修饰符是什么?

如何解决《在GNUCinlineasm中,对于单个操作数,xmm/ymm/zmm的修饰符是什么?》经验,为你挑选了1个好方法。

在尝试使用内在函数和汇编来回答嵌入式广播时,我试图做这样的事情:

__m512 mul_broad(__m512 a, float b) {
    int scratch = 0;
    asm(
        "vbroadcastss  %k[scalar], %q[scalar]\n\t"  // want  vbr..  %xmm0, %zmm0
        "vmulps        %q[scalar], %[vec], %[vec]\n\t"

        // how it's done for integer registers
        "movw         symbol(%q[inttmp]), %w[inttmp]\n\t"  // movw symbol(%rax), %ax
        "movsbl        %h[inttmp], %k[inttmp]\n\t"  // movsx %ah, %eax
        : [vec] "+x" (a), [scalar] "+x" (b),  [inttmp] "=r" (scratch)
        :
        :
    );
    return a;
}

的GNU C 86操作数修饰符文档仅指定到改性剂q(DI(DoubleInt)尺寸,64位).使用q一个向量寄存器总会带给它归结为xmm(从ymmzmm).

问题:

在向量寄存器的大小之间改变的修饰符是什么?

此外,是否有任何特定大小的约束用于输入或输出操作数?除通用之外的其他东西x,最终可能是xmm,ymm或zmm,具体取决于放在括号中的表达式的类型.


偏离主题:clang似乎有一些Yi/ Yt约束(不是修饰符),但我也找不到文档.clang甚至不会编译它,即使注释掉了向量指令,因为它不喜欢+x作为__m512向量的约束.


背景/动机

我可以通过传入标量作为输入操作数来获得我想要的结果,被限制为与更宽的输出操作数在同一个寄存器中,但它更笨拙.(这个用例的最大缺点是AFAIK必须使用操作数 - 而不是[symbolic_name],因此在添加/删除输出约束时它很容易破损.)

// does what I want, by using a paired output and input constraint
__m512 mul_broad(__m512 a, float b) {
    __m512 tmpvec;
    asm(
        "vbroadcastss  %[scalar], %[tmpvec]\n\t"
        "vmulps        %[tmpvec], %[vec], %[vec]\n\t"
        : [vec] "+x" (a), [tmpvec] "=x" (tmpvec)
        : [scalar] "1" (b)
        :
    );

  return a;
}

godbolt链接


此外,我认为我试图解决的问题的整个方法将是一个死胡同,因为多替代约束不允许您为不同的约束模式给出不同的asm.我希望有xr约束最终vbroadcastss从寄存器发出一个,而m约束最终发出vmulps (mem_src){1to16}, %zmm_src2, %zmm_dst(折叠的广播负载).使用内联asm执行此操作的目的是gcc还不知道如何将set1()内存操作数折叠到广播加载中(但是clang确实如此).

无论如何,这个具体问题是关于向量寄存器的操作数修饰符和约束.请关注这一点,但欢迎在另一个问题上提出意见和答案.(或者更好,只是对Z Boson关于嵌入式广播的问题发表评论/回答.)



1> Ross Ridge..:

从GCC来源的文件gcc/config/i386/i386.c:

       b -- print the QImode name of the register for the indicated operand.
        %b0 would print %al if operands[0] is reg 0.
       w --  likewise, print the HImode name of the register.
       k --  likewise, print the SImode name of the register.
       q --  likewise, print the DImode name of the register.
       x --  likewise, print the V4SFmode name of the register.
       t --  likewise, print the V8SFmode name of the register.
       g --  likewise, print the V16SFmode name of the register.
       h -- print the QImode name for a "high" register, either ah, bh, ch or dh.

同样来自gcc/config/i386/contraints.md:

    ;; We use the Y prefix to denote any number of conditional register sets:
    ;;  z   First SSE register.
    ;;  i   SSE2 inter-unit moves to SSE register enabled
    ;;  j   SSE2 inter-unit moves from SSE register enabled
    ;;  m   MMX inter-unit moves to MMX register enabled
    ;;  n   MMX inter-unit moves from MMX register enabled
    ;;  a   Integer register when zero extensions with AND are disabled
    ;;  p   Integer register when TARGET_PARTIAL_REG_STALL is disabled
    ;;  f   x87 register when 80387 floating point arithmetic is enabled
    ;;  r   SSE regs not requiring REX prefix when prefixes avoidance is enabled
    ;;  and all SSE regs otherwise

此文件还定义了"Yk"约束,但我不知道它在asm语句中的工作效果如何:

    (define_register_constraint "Yk" "TARGET_AVX512F ? MASK_EVEX_REGS : NO_REGS"
    "@internal Any mask register that can be used as predicate, i.e. k1-k7.")

请注意,这是从最新的SVN版本复制的.我不知道GCC的哪个版本,如果有的话,你添加了你感兴趣的特定修饰符和约束.

推荐阅读
wangtao
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有