我试图找到Xeon Phi平台的KNC广播指令 . 但我找不到任何指示 . 相反,我试图在程序集中使用此AVX _mm512_set1_epi32内在函数 . 我有两个问题:首先是有任何KNC广播指令吗?其次,当我编译下面的代码时,我得到了'vpbroadcastd'错误的操作数类型不匹配 .
int op = 2;
__asm__("vmovdqa32 %0,%%zmm0\n\t"
"mov %1, %%eax\n\t"
"vpbroadcastd %%eax, %%zmm1\n\t"
"vpsravd %%zmm1,%%zmm0,%%zmm1\n\t"
"vmovdqa32 %%zmm1,%0;"
: "=m" (tt[0]): "m" (op));
哪个tt使用下面的代码定义,我使用k1om-mpss-linux-gcc编译器来编译这段代码
int * tt = (int *) aligned_malloc(16 * sizeof(int),64);
2 回答
我看了AVX2如何用内在函数做到这一点,并注意到广播从内存读取就像使用KNC一样 . 从AVX2内在函数看组件,我写了内联汇编,它做了同样的事情 .
这是我对KNC的猜测(使用对齐的加载):
使用KNC和AVX512似乎有一种更有效的方法 .
Intel says关于AVX12的"2.5.3 Broadcast"部分:
然后举例说明
哪里
我之前从未使用过他的语法,但你可以试试
}
这会产生
他说,Agner Fog偶然在_2877026中有一个 Headers 为"8.4 Assembly syntax for AVX-512 and Knights Corner instructions"的部分
根据他的文档,NASM支持AVX-512和KNC语法,因此您可以在NASM中尝试这种语法 .
这个答案的早期版本是错误的 . 根据An Intels PDF of the KNC insn from Sep 2012, which I hope is current/up-to-date,512b
vpsrad
仅适用于即时计数 . 当你在GP寄存器(而不是内存)中计数时,它看起来相当不方便 .似乎变量计数移位(
vpsravd
)是在KNC上进行非立即计数移位的唯一方法,即使每个元素的计数相同 . 由于它可以使用广播负载进行移位计数,因此这不是一个大问题 . KNC似乎也有一个来自寄存器源的"swizzle" shuffle或广播(zmm1 {aaaa}
),但我不确定该广播的宽度是多少 .这不能在普通的编译器上编译:{1to16}被忽略,并且你得到一个错误,“对于`vpsravd',这种类型的操作数需要广播” . IDK,如果这只是一个语法问题,使用intel-syntax而不是AT&T .
仍然使用完整的“内存”代码,因为我们只告诉编译器使用第一个整数作为输入/输出内存操作数,而不是下一个16 .
If you can keep the zmm value in memory, instead of storing/reloading between tiny fragments of inline asm, that will perform much better.
根据Xeon Phi Knights Corner intrinsics with GCC,gcc不支持KNC的内在函数 .
我认为我的PDF版本适用于AVX512(KNL / Skylake-E) . IDK关于KNC;它可能没有这个 . (特别是:英特尔®架构指令集扩展编程参考,自2014年10月起 . )
有一个GP-register源形式
VPBROADCASTD
,只需要AVX512F .VPBROADCASTD zmm1 {k1}{z}, r32
. 内在的是没有面具没有列出,但也许只能试试
_mm512_set1_epi32(int)
.顺便说一句,你的内联汇编compiles ok with a normal compiler on godbolt . ("binary"复选框使它实际组装然后反汇编,所以我确定说明已被接受 . )
如果您仍然使用内联asm而不是内在函数,请确保整理代码:如果您要求编译器将
op
放入内存,请使用广播加载,而不是mov
到GP寄存器中从那里播放 . 更好的是,为vpsravd
:VPSRAVD zmm1 {k1}{z}, zmm2, zmm3/m512/m32bcst
使用广播加载内存操作数 . 然后你根本不需要VPBROADCAST指令 . (我假设编译器会使用内在函数执行此操作 . )