如何解决AVX-512 - 如何使用汇编指令从内存中收集数据?
我正在尝试使用汇编指令从内存中收集 64 位整数。您可以在下面看到我如何从 assembly
调用 C
代码。请注意汇编代码使用 NASM
语法。
nasm_gather.asm
文件
bits 64
section .text
global nasm_gather:function
extern base_addr
extern vindex
nasm_gather:
; prolog
push rbp
push rbx
push r12
push r13
mov r12,[rel base_addr] ; r12 point to base_addr
mov r13,[rel vindex] ; r13 points to vindex
vmovdqu32 zmm1,[r13] ; zmm1 = [2,5,1,3,4,7,6]
vpxorq zmm2,zmm2,zmm2 ; zmm2 = [0,0]
vpgatherqq zmm2,[r12 + zmm1*8] ; ----> Illegal instruction at address = ...
...
; epilog
pop r13
pop r12
pop rbx
pop rbp
ret
main.cpp
文件
#include <iostream>
#include <immintrin.h>
using namespace std;
extern "C" int nasm_gather();
const int N=32;
int64_t* base_addr /*__attribute__ ((aligned (64)))*/ = (int64_t *) malloc(sizeof(int64_t) * N);
int64_t* vindex = (int64_t *) malloc(sizeof(int64_t) * 8);
int main() {
/* initialize indices */
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 result = nasm_gather();
...
return 0;
}
(vpgatherqq zmm,vm64z
汇编指令对应于 C 中的 _mm512_i64gather_epi64 内在函数)
就在程序到达这一点时:
vpgatherqq zmm2,[r12 + zmm1*8]
我收到非法指令错误:
地址 = 4011f0 处的非法指令:62 d2 fd 48 91 14 cc 62 f1 7e
48 6f c2 e8 10
如果您认为您的应用程序应该尝试
执行此非法指令(以及其他可能存在的指令),
然后使用此旋钮:-emit-illegal-insts 0 并且此错误消息将
避免。
有什么问题吗?
解决方法
收集需要一个面具(这样他们可以在被打断或一个元素出现故障时记录进度)。 NASM 通常不会让你在没有警告的情况下组装非法指令;这是一个 NASM 错误,它无法帮助您发现此错误。
此外,您使用全局变量而不是函数 args 的整个方法对于可维护性和性能都是不利的。 使用内在函数,如果您已经愿意告诉 GCC 它可以发出 AVX-512 指令 (-march=skylake-avx512
) 并在您的源代码中 #include <immintrin.h>
。例如_mm512_mask_i64gather_epi64
。完全调用任何函数而不是内联gather 指令将花费gather 成本的很大一部分,而且如果它是一个笨重的低效函数,那么这种方式编写的成本会更高。如果您的索引不在 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}
- Gathers 仅支持合并屏蔽(再次,它可以在被 #PF 或可能中断中断的部分执行后恢复)。但是使用正确的源代码,它在静态可执行文件中构建和运行得很好。主机 CPU 是 i7-6700k Skylake 客户端(不支持 AVX-512,因此由 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++ 调用的函数中会以相同的方式运行,但同样,当您可以使用内部函数(并使用 objdump -drwC -Mintel a.out
反汇编以查看 GCC 如何使用该指令时,这将毫无意义。)
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。