在尝试使用内在函数和汇编来回答嵌入式广播时,我试图做这样的事情:
__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
(从ymm
或zmm
).
在向量寄存器的大小之间改变的修饰符是什么?
此外,是否有任何特定大小的约束用于输入或输出操作数?除通用之外的其他东西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.我希望有x
和r
约束最终vbroadcastss
从寄存器发出一个,而m
约束最终发出vmulps (mem_src){1to16}, %zmm_src2, %zmm_dst
(折叠的广播负载).使用内联asm执行此操作的目的是gcc还不知道如何将set1()
内存操作数折叠到广播加载中(但是clang确实如此).
无论如何,这个具体问题是关于向量寄存器的操作数修饰符和约束.请关注这一点,但欢迎在另一个问题上提出意见和答案.(或者更好,只是对Z Boson关于嵌入式广播的问题发表评论/回答.)
从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的哪个版本,如果有的话,你添加了你感兴趣的特定修饰符和约束.