Assembly `vpbroadcasted';的操作数类型不匹配;
我试图为Xeon Phi平台找到KNC广播指令。但我找不到任何指示。相反,我尝试在汇编中使用这个AVX mm512 set1 epi32的内在特性。我有两个问题:第一,是否有KNC广播指令?其次,当我编译下面的代码时,我得到了“vpbroadcasted”错误的操作数类型不匹配Assembly `vpbroadcasted';的操作数类型不匹配;,assembly,broadcast,xeon-phi,Assembly,Broadcast,Xeon Phi,我试图为Xeon Phi平台找到KNC广播指令。但我找不到任何指示。相反,我尝试在汇编中使用这个AVX mm512 set1 epi32的内在特性。我有两个问题:第一,是否有KNC广播指令?其次,当我编译下面的代码时,我得到了“vpbroadcasted”错误的操作数类型不匹配 int op = 2; __asm__("vmovdqa32 %0,%%zmm0\n\t" "mov %1, %%eax\n\t" "vpbroadcastd %%eax,
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);
这个答案的早期版本是错误的。根据,512b
vpsrad
仅在立即计数时可用。当您在GP寄存器(而不是内存)中拥有计数时,它确实显得相当不方便
似乎变量计数移位(vpsravd
)是在KNC上进行非即时计数移位的唯一方法,即使每个元素的计数相同。因为它可以使用广播负载进行移位计数,所以这不是一个大问题。KNC似乎还有一个从寄存器源(zmm1{aaaa}
)发出的“swizzle”混洗或广播,但我不确定广播的宽度
这不会在普通编译器上编译:{1to16}被忽略,并且您会得到一个错误,即“对于`vpsravd',这种类型的操作数需要广播”。IDK,如果这只是一个语法问题,使用intel语法而不是AT&T
// compile with -masm=intel
// todo: something clever to use vpsrad when the shift count is a compile-time constant
void shift_KNC(int *A, int n) {
__asm__ volatile(
// ".intel_syntax noprefix\n"
"vmovdqa32 zmm0, %0\n\t"
"vpsravd zmm0, zmm0, %1 {1to16}\n\t"
"vmovdqa32 %0, zmm0\n\t"
: "+m" (*(__m512i*)A)
: "m" (n) /* force it to memory */
: "%zmm0"
);
}
仍然使用完整的“内存”缓冲,因为我们只告诉编译器使用第一个整数作为输入/输出内存操作数,而不是下一个16
如果您可以将zmm值保留在内存中,而不是在内联asm的微小片段之间存储/重新加载,则性能会更好。
根据,gcc不支持KNC的内部函数
我想我的PDF是针对AVX512(KNL/Skylake-E)的。关于KNC的IDK;它可能没有这个。(特别是:英特尔体系结构 指令集扩展编程参考,2014年10月起) 存在
vpbroadcasted
的GP寄存器源格式,只需要AVX512F<代码>VP广播zmm1{k1}{z},r32。内在的是
__m512i _mm512_maskz_set1_epi32( __mmask16 k, int a);
没有列出没有掩码的掩码,但可以尝试使用\u mm512\u set1\u epi32(int)
顺便说一句,你的内联程序集。(在“二进制”复选框中,它实际上是组装然后拆卸的,所以我确信这些说明是可以接受的。)
如果仍然使用内联asm,而不是intrinsic,请确保整理代码:如果需要编译器将
op
放入内存,请使用广播加载,而不是mov
放入GP寄存器并从那里广播。更好的是,为vpsravd
使用广播加载内存操作数:vpsravd zmm1{k1}{z},zmm2,zmm3/m512/m32bcst
。那么你根本就不需要VP广播指令。(我假设编译器会使用intrinsic来实现这一点。)我研究了AVX2如何使用intrinsic来实现这一点,并注意到广播与KNC一样从内存中读取。在AVX2内部函数中查看程序集时,我编写了内联程序集,它也做了同样的事情
#include <stdio.h>
#include <x86intrin.h>
void foo(int *A, int n) {
__m256i a16 = _mm256_loadu_si256((__m256i*)A);
__m256i t = _mm256_set1_epi32(n);
__m256i s16 = _mm256_srav_epi32(a16,t);
_mm256_storeu_si256((__m256i*)A, s16);
}
void foo2(int *A, int n) {
__asm__("vmovdqu (%0),%%ymm0\n"
"vpbroadcastd (%1), %%ymm1\n"
"vpsravd %%ymm1, %%ymm0, %%ymm0\n"
"vmovdqu %%ymm0, (%0)"
:
: "r" (A), "r" (&n)
: "memory"
);
}
int main(void) {
int x[8];
for(int i=0; i<8; i++) x[i] = 1<<i;
for(int i=0; i<8; i++) printf("%8d ", x[i]); puts("");
foo2(x,2);
for(int i=0; i<8; i++) printf("%8d ", x[i]); puts("");
}
使用KNC和AVX512似乎有一种更有效的方法 关于“2.5.3广播”部分中的AVX12: EVEX编码提供一个位字段,用于对某些load op指令的数据广播进行编码 然后给出了实例
vmulps zmm1, zmm2, [rax] {1to16}
在哪里
{1to16}原语加载一个float32(单精度)元素
从内存中复制ent 16次,形成一个
16个32位浮点元素的向量乘以
16浮动32个元素,其中包含
第一个源操作数向量,并将16个结果中的每个结果放入目标操作数
我以前从未使用过他的语法,但你可以试试
void foo2_KNC(int *A, int n) {
__asm__("vmovdqa32 (%0),%%zmm0\n\t"
"vpsravd (%1)%{1to16}, %%zmm0, %%zmm0\n\t"
"vmovdqa32 %%zmm0, (%0)\t"
:
: "r" (A), "r" (&n)
: "memory", "%zmm0"
);
}
这就产生了
vmovdqa32 (%rax),%zmm0
vpsravd (%rdx){1to16}, %zmm0, %zmm0
vmovdqa32 %zmm0, (%rax)
阿格纳·福格(Agner Fog)顺便提到了一个标题为“AVX-512和骑士角指令的8.4汇编语法”的部分,他在其中说
这两个指令集非常相似,但具有不同的可选指令属性。来自这两个指令集的指令在前缀中相差一位,即使对于其他相同的指令也是如此
根据他的文档,NASM支持AVX-512和KNC语法,因此您可以在NASM中尝试这种语法。根据Xeon Phi指令集,手动VPBroadcasted仅将内存位置作为源操作数。AVX 2版本采用内存位置或XMM寄存器。两者都不允许EAX作为源。@RossRidge感谢您的回复。我的问题是,在Xeon Phi指令中使用广播或set指令的正确方式是什么?@RossRidge:常规AVX512F允许从GP寄存器进行广播。Xeon Phi没有这个?这就可以解释问题了。在这种情况下,解决方案就是不首先加载到eax中,因为OP会强制编译器将其放入内存中。@RossRidge:Peter建议使用_mm512_set1_epi32(int)内在函数。我只想知道这个指令的汇编版本。我不知道什么是r32?我怎么能装到r32呢?我想你可能吃得太多了。正如英特尔的文档所述,没有与
\u mm512\u set1\u epi32
相对应的汇编指令。理想情况下,此内在函数不生成指令,广播是使用{1to16}
操作数转换免费完成的。为了有效地利用Xeon Phi的组装,您需要了解类似的内容。你不应该问一些基本的问题,比如r32
的含义。Downvoter(或者理解我为什么被否决的人)你能解释一下你的否决票吗?刚刚注意到,既然asm噪音更小了:广播,然后是可变移位????为什么不vmovd%1、%%zmm1
(带有rm
约束)然后vpsrad%%zmm1、%%zmm0、%%zmm0
?我假设KNC的512b向量
vmovdqa32 (%rax),%zmm0
vpsravd (%rdx){1to16}, %zmm0, %zmm0
vmovdqa32 %zmm0, (%rax)