C++ AVX-512-如何使用汇编指令从内存中收集数据?
我试图使用汇编指令从内存中收集64位整数。下面您可以看到我如何从C调用汇编代码。请注意,汇编代码使用NASM语法 nasm_gather.asm文件 main.cpp文件 包括 包括 使用名称空间std; 外部C内部nasm_聚集; 常数int N=32; int64*base\u addr/*\u属性对齐64*/=int64\u t*mallocsizeofind64\u t*N; int64_t*vindex=int64_t*mallocsizeofind64_t*8; int main{ /*初始化索引*/ vindex[0]=2;vindex[1]=5;vindex[2]=1;vindex[3]=3; vindex[4]=0;vindex[5]=4;vindex[6]=7;vindex[7]=6; // ... int64_t结果=nasm_聚集; ... 返回0; } vm64z汇编指令对应于C中的固有函数 就在程序达到这一点时:C++ AVX-512-如何使用汇编指令从内存中收集数据?,c++,assembly,nasm,simd,avx512,C++,Assembly,Nasm,Simd,Avx512,我试图使用汇编指令从内存中收集64位整数。下面您可以看到我如何从C调用汇编代码。请注意,汇编代码使用NASM语法 nasm_gather.asm文件 main.cpp文件 包括 包括 使用名称空间std; 外部C内部nasm_聚集; 常数int N=32; int64*base\u addr/*\u属性对齐64*/=int64\u t*mallocsizeofind64\u t*N; int64_t*vindex=int64_t*mallocsizeofind64_t*8; int main{
vpgatherqq zmm2 ,[r12 + zmm1*8]
我得到非法指令错误:
地址=4011f0:62 d2 fd 48 91 14 cc 62 f1 7e处的非法指令
48 6f c2 e8 10
如果您认为您的申请应该尝试
执行此非法指令和可能存在的其他指令,
然后使用此旋钮:-发出非法指令0,将显示此错误消息
必须避免
有什么问题吗?采集需要一个掩码,以便在中断或一个元素出现故障时记录进度。NASM通常不允许您在没有警告的情况下汇编非法指令;这是一个NASM错误,它不能帮助您发现这个错误
另外,您使用全局变量而不是函数参数的整个方法对可维护性和性能都是有害的。如果您已经愿意告诉GCC它可以发出AVX-512指令-march=skylake-avx512并包含在源代码中,请像普通人一样使用内部函数。e、 g._mm512_mask_i64 gather_epi64。调用任何函数而不是内联GARGE指令的成本将相当于GARGE成本的一小部分,如果用这种方式编写的函数笨重且效率低下,则成本会更高。如果索引不在SIMD向量中,则聚集是非常有问题的,并且使用存储在全局变量中的指针作为索引,而不是为聚集函数传递指针arg以从某处加载索引向量肯定没有帮助
以下代码在SDE 8.33.0和NASM 2.15.05中运行良好。您声称添加{k1}并不能解决问题。要么你的SDE版本坏了,要么你做错了什么。或者您忘记从更新的源代码重建可执行文件
default rel
global _start
_start:
lea rax, [rel buf] ; dummy base = static array. In a function, use RDI (first int/pointer arg)
vpxor xmm1, xmm1,xmm1 ; ZMM1 = dummy index = all zeros, efficiently done with a VEX-coded AVX instruction
kxnorb k1, k0,k0 ; mask = -1
vpxor xmm0, xmm0,xmm0 ; optional: dependency-breaking before merge-masking. GCC will do this for the intrinsic.
vpgatherqq zmm0{k1}, [rax + zmm1*8]
mov eax, 231
syscall ; exit_group(RDI)
section .bss
buf: resd 1024
如果我删除{k1},让它像你原来的问题一样被揭穿,我就可以重现SDE错误消息。NASM 2.15.05错误如果您尝试使用{k1}{z}-聚集仅支持再次合并屏蔽,以便在部分执行被PF中断或可能中断后恢复。但是有了正确的源代码,它就可以在静态可执行文件中正常构建和运行。主机CPU是不支持AVX-512的i7-6700k Skylake客户端,因此由SDE来实现
$ nasm -felf64 avx512-gather.asm
$ ld -o avx512-gather avx512-gather.o
$ /opt/sde-external-8.33.0-2019-02-07-lin/sde64 -- ./avx512-gather
$ echo $?
0
当然,sde64-icl也有效
将同一机器代码链接到C++调用的函数将以相同的方式运行,但同样,当使用ObjDIP-DRWC-Munel.AUT来查看GCC如何使用指令时,这将是毫无意义的。
集合需要一个掩码,以便如果中断,或者如果一个元素出错,则可以记录进程。NASM通常不允许您在没有警告的情况下汇编非法指令;这是一个NASM错误,它不能帮助您发现这个错误
另外,您使用全局变量而不是函数参数的整个方法对可维护性和性能都是有害的。如果您已经愿意告诉GCC它可以发出AVX-512指令-march=skylake-avx512并包含在源代码中,请像普通人一样使用内部函数。e、 g._mm512_mask_i64 gather_epi64。调用任何函数而不是内联GARGE指令的成本将相当于GARGE成本的一小部分,如果用这种方式编写的函数笨重且效率低下,则成本会更高。如果索引不在SIMD向量中,则聚集是非常有问题的,并且使用存储在全局变量中的指针作为索引,而不是为聚集函数传递指针arg以从某处加载索引向量肯定没有帮助 以下代码在SDE 8.33.0和NASM 2.15.05中运行良好。您声称添加{k1}并不能解决问题。要么你的SDE版本坏了,要么你做错了什么。或者您忘记从更新的源代码重建可执行文件default rel
global _start
_start:
lea rax, [rel buf] ; dummy base = static array. In a function, use RDI (first int/pointer arg)
vpxor xmm1, xmm1,xmm1 ; ZMM1 = dummy index = all zeros, efficiently done with a VEX-coded AVX instruction
kxnorb k1, k0,k0 ; mask = -1
vpxor xmm0, xmm0,xmm0 ; optional: dependency-breaking before merge-masking. GCC will do this for the intrinsic.
vpgatherqq zmm0{k1}, [rax + zmm1*8]
mov eax, 231
syscall ; exit_group(RDI)
section .bss
buf: resd 1024
如果我删除{k1},让它像你原来的问题一样被揭穿,我就可以重现SDE错误消息。NASM 2.15.05错误如果您尝试使用{k1}{z}-聚集仅支持再次合并屏蔽,以便在部分执行被PF中断或可能中断后恢复。但是有了正确的源代码,它就可以在sta中正常构建和运行
tic可执行文件。主机CPU是不支持AVX-512的i7-6700k Skylake客户端,因此由SDE来实现
$ nasm -felf64 avx512-gather.asm
$ ld -o avx512-gather avx512-gather.o
$ /opt/sde-external-8.33.0-2019-02-07-lin/sde64 -- ./avx512-gather
$ echo $?
0
当然,sde64-icl也有效
将相同的机器代码链接到C++调用的函数将运行相同的方法,但同样,当您可以使用ObjDIP-DRWC-Munel.AUT来使用内含子并拆解GCC如何使用该指令时,这将是毫无意义的。< /P> MOV R12,[RelBaseAdDR]将加载RaseBaseAdDr(0)的值,然而,我认为您只希望它包含base_addr的地址。所以我想你想要lea r12,[rel base_addr]来代替。下一行也是如此。虽然我仍然希望出现分段错误,而不是非法指令。@NateEldredge我在地址=4011dc:62 d2 fd 48 91 14 cc 62 f1 7e 48 6f c2 e8 07处收到相同的错误消息“非法指令”。但说真的,如果您只想从C使用vpgatherqq,请使用imintrin.h中的_mm512_mask_i64gather_epi64。不要使用全局变量来传递参数!我希望你不是真的打算用它来提高性能。你告诉你的模拟器启用AVX-512了吗?是哪个模拟器?还要注意你的评论是错误的;kxnorW将生产65535。或者像大多数人写的那样,-1或0xFFFF@him您并没有回答Peter关于您正在使用的模拟器或向其传递的参数的问题。在您的情况下,这将是实际编译的以及代码的一部分,即,除去…mov r12,[rel base_addr]将使用base_addr[0]中的值加载r12,而我认为您只希望它包含base_addr的地址。所以我想你想要lea r12,[rel base_addr]来代替。下一行也是如此。虽然我仍然希望出现分段错误,而不是非法指令。@NateEldredge我在地址=4011dc:62 d2 fd 48 91 14 cc 62 f1 7e 48 6f c2 e8 07处收到相同的错误消息“非法指令”。但说真的,如果您只想从C使用vpgatherqq,请使用imintrin.h中的_mm512_mask_i64gather_epi64。不要使用全局变量来传递参数!我希望你不是真的打算用它来提高性能。你告诉你的模拟器启用AVX-512了吗?是哪个模拟器?还要注意你的评论是错误的;kxnorW将生产65535。或者像大多数人写的那样,-1或0xFFFF@him您并没有回答Peter关于您正在使用的模拟器或向其传递的参数的问题。在您的情况下,这将是实际编译的代码的一部分,也就是说,摆脱…谢谢!我来看看,你为什么要把zmm0归零?zmm0的单独加载是否依赖于寄存器的其余部分或其他内容?@Noah:collects仅在合并掩蔽时可用,因此是的,false dep。尽管您提到了它,值并不重要,只是dep中断,所以我应该修复注释。当我写这个答案的时候,我脑子里放了一个屁,我认为这个值对正确性很重要,就像是在对它进行修改一样。当然不是。GCC也使用xor归零,但那是因为它喜欢dep-breaking。谢谢!我来看看,你为什么要把zmm0归零?zmm0的单独加载是否依赖于寄存器的其余部分或其他内容?@Noah:collects仅在合并掩蔽时可用,因此是的,false dep。尽管您提到了它,值并不重要,只是dep中断,所以我应该修复注释。当我写这个答案的时候,我脑子里放了一个屁,我认为这个值对正确性很重要,就像是在对它进行修改一样。当然不是。GCC也使用xor归零,但那是因为它喜欢dep中断。