Assembly `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,

我试图为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, %%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)