在试图回答时 具有内在和装配的嵌入式广播,我试图做这样的事情:
__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 x86操作数修饰符 doc仅指定最多的修饰符 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;
}
此外,我认为我试图解决的问题的整个方法将是一个死胡同,因为 多方替代约束 不要让你为不同的约束模式赋予不同的asm。我希望有 x
和 r
约束最终散发出来 vbroadcastss
从寄存器,而 m
约束最终会发出 vmulps (mem_src){1to16}, %zmm_src2, %zmm_dst
(折叠的广播负载)。使用内联asm执行此操作的目的是gcc还不知道如何折叠 set1()
内存操作数转换为广播负载(但是clang确实如此)。
无论如何,这个具体问题是关于向量寄存器的操作数修饰符和约束。请关注这一点,但欢迎在另一个问题上给出答案中的评论和旁白。 (或者更好的是,只评论/答复Z Boson关于嵌入式广播的问题。)