在尝试用内在函数和汇编回答嵌入式广播时,我试图做这样的事情:
__m512 mul_bcast(__m512 a, float b) {
asm(
"vbroadcastss %k[scalar], %q[scalar]\n\t" // want vbcast.. %xmm0, %zmm0
"vmulps %q[scalar], %[vec], %[vec]\n\t"
: [vec] "+x" (a), [scalar] "+&x" (b)
: :
);
return a;
}
GNU C x86 Operand Modifiers文档仅指定最大为q
(DI (DoubleInt) size, 64bits) 的修饰符。在向量寄存器上使用q
将始终将其降低到xmm
(from ymm
or zmm
)。例如标量寄存器:
long scratch = 0; // not useful instructions, just syntax demo
asm(
"movw symbol(%q[inttmp]), %w[inttmp]\n\t" // movw symbol(%rax), %ax
"movsbl %h[inttmp], %k[inttmp]\n\t" // movsx %ah, %eax
: [inttmp] "+r" (scratch)
:: "memory" // we read some index in symbol[]
);
问题:
在向量寄存器大小之间更改的修饰符是什么?
此外,是否有任何特定大小的限制可用于输入或输出操作数?除了泛型之外的其他东西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_bcast(__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;
}
另外,我认为解决我试图解决的问题的整个方法将是一条死胡同,因为Multi-Alternative 约束不允许您为不同的约束模式提供不同的 asm。我希望约束最终会从寄存器发出 a ,而x
约束最终会发出(折叠的广播负载)。使用内联 asm 执行此操作的目的是 gcc 还不知道如何将内存操作数折叠到广播加载中(但 clang 知道)。r
vbroadcastss
m
vmulps (mem_src){1to16}, %zmm_src2, %zmm_dst
set1()
无论如何,这个特定的问题是关于向量寄存器的操作数修饰符和约束。请关注这一点,但欢迎就其他问题发表评论和回答。(或者更好,只是评论/回答 Z Boson 关于嵌入式广播的问题。)