错误:“_mm512_loadu_epi64”未在此范围内声明
Posted
技术标签:
【中文标题】错误:“_mm512_loadu_epi64”未在此范围内声明【英文标题】:error: '_mm512_loadu_epi64' was not declared in this scope 【发布时间】:2018-12-04 02:47:01 【问题描述】:我正在尝试为this issue report 创建一个最小的复制器。 AVX-512 似乎存在一些问题,它在配备 Skylake 处理器的最新 Apple 机器上提供。
根据GCC6 release notes,应该可以使用 AVX-512 设备。根据Intel Intrinsics Guidevmovdqu64
可与AVX-512VL
和AVX-512F
:
$ cat test.cxx
#include <cstdint>
#include <immintrin.h>
int main(int argc, char* argv[])
uint64_t x[8];
__m512i y = _mm512_loadu_epi64(x);
return 0;
然后:
$ /opt/local/bin/g++-mp-6 -mavx512f -Wa,-q test.cxx -o test.exe
test.cxx: In function 'int main(int, char**)':
test.cxx:6:37: error: '_mm512_loadu_epi64' was not declared in this scope
__m512i y = _mm512_loadu_epi64(x);
^
$ /opt/local/bin/g++-mp-6 -mavx -mavx2 -mavx512f -Wa,-q test.cxx -o test.exe
test.cxx: In function 'int main(int, char**)':
test.cxx:6:37: error: '_mm512_loadu_epi64' was not declared in this scope
__m512i y = _mm512_loadu_epi64(x);
^
$ /opt/local/bin/g++-mp-6 -msse4.1 -msse4.2 -mavx -mavx2 -mavx512f -Wa,-q test.cxx -o test.exe
test.cxx: In function 'int main(int, char**)':
test.cxx:6:37: error: '_mm512_loadu_epi64' was not declared in this scope
__m512i y = _mm512_loadu_epi64(x);
^
我将选项带回-msse2
,但没有成功。我好像漏掉了什么。
为现代 GCC 使用 AVX-512 需要什么?
根据/opt/local/bin/g++-mp-6 -v
,这些是标题搜索路径:
#include "..." search starts here:
#include <...> search starts here:
/opt/local/include/gcc6/c++/
/opt/local/include/gcc6/c++//x86_64-apple-darwin13
/opt/local/include/gcc6/c++//backward
/opt/local/lib/gcc6/gcc/x86_64-apple-darwin13/6.5.0/include
/opt/local/include
/opt/local/lib/gcc6/gcc/x86_64-apple-darwin13/6.5.0/include-fixed
/usr/include
/System/Library/Frameworks
/Library/Frameworks
然后:
$ grep -R '_mm512_' /opt/local/lib/gcc6/ | grep avx512f | head -n 8
/opt/local/lib/gcc6//gcc/x86_64-apple-darwin13/6.5.0/include/avx512fintrin.h:_mm512_set_epi64 (long long __A, long long __B, long long __C,
/opt/local/lib/gcc6//gcc/x86_64-apple-darwin13/6.5.0/include/avx512fintrin.h:_mm512_set_epi32 (int __A, int __B, int __C, int __D,
/opt/local/lib/gcc6//gcc/x86_64-apple-darwin13/6.5.0/include/avx512fintrin.h:_mm512_set_pd (double __A, double __B, double __C, double __D,
/opt/local/lib/gcc6//gcc/x86_64-apple-darwin13/6.5.0/include/avx512fintrin.h:_mm512_set_ps (float __A, float __B, float __C, float __D,
/opt/local/lib/gcc6//gcc/x86_64-apple-darwin13/6.5.0/include/avx512fintrin.h:#define _mm512_setr_epi64(e0,e1,e2,e3,e4,e5,e6,e7) \
/opt/local/lib/gcc6//gcc/x86_64-apple-darwin13/6.5.0/include/avx512fintrin.h: _mm512_set_epi64(e7,e6,e5,e4,e3,e2,e1,e0)
/opt/local/lib/gcc6//gcc/x86_64-apple-darwin13/6.5.0/include/avx512fintrin.h:#define _mm512_setr_epi32(e0,e1,e2,e3,e4,e5,e6,e7, \
/opt/local/lib/gcc6//gcc/x86_64-apple-darwin13/6.5.0/include/avx512fintrin.h: _mm512_set_epi32(e15,e14,e13,e12,e11,e10,e9,e8,e7,e6,e5,e4,e3,e2,e1,e0)
...
【问题讨论】:
在clang with-mavx512f
上工作。尝试在标题中搜索相关的内在函数,看看是否可以找到该函数。如果你找不到它,你要么需要更新版本的 gcc,要么可能它还没有实现。
没有掩码,没有理由让这个内在函数存在或永远使用它。与_mm512_loadu_si512
相比,这只是令人困惑。英特尔的指南确实指定它存在(software.intel.com/sites/landingpage/IntrinsicsGuide/…),但也许 gcc 没有定义它。 SSE* 和 AVX1/2 选项与 GCC 标头是否根据 gcc 内置函数定义此内在函数无关; -mavx512f
已经暗示了 AVX512 之前的所有英特尔 SSE/AVX 扩展。
@user2176127 在 Godbolt 的 gcc 主干上不存在,在 clang 中它只存在于主干中,而不是 7.0。但是,两者都存在对齐的版本:_mm512_load_epi64
。他们都有maskz
版本。很奇怪,但就像我说的那样,只需使用 si512 版本就可以轻松避免。
是的,grepping GCC 包含目录不会返回 $ grep -R '_mm512_' /opt/local/lib/gcc6/ | grep _mm512_loadu_epi64
的命中。
@Peter - 我认为_mm512_load_epi64
已经足够接近了。我可以使用它来获取汇编程序错误消息。 (我正在尝试重现集成的汇编器错误)。
【参考方案1】:
没有掩码,没有理由存在或使用它来代替等效的_mm512_loadu_si512
。这只是令人困惑,并且可能会诱使人类读者认为这是单个 epi64
的 vmovq
零扩展负载。
Intel's intrinsics finder does specify that it exists,但即使是当前的主干 gcc(在 Godbolt 上)也没有定义它。
几乎所有 AVX512 指令都支持合并屏蔽和零屏蔽。过去纯粹是按位/全寄存器且没有有意义的元素边界的指令现在有 32 位和 64 位元素风格,例如 vpxord
和 vpxorq
。或vmovdqa32
and vmovdqa64
。但是使用任何一个没有掩码的版本仍然只是一个正常的向量加载/存储/寄存器复制,并且在具有内在函数的 C++ 源代码中为它们指定任何关于元素大小的任何内容都是没有意义的,只有总向量宽度。
另见What is the difference between _mm512_load_epi32 and _mm512_load_si512?
SSE* 和 AVX1/2 选项与 GCC 头文件是否根据 gcc 内置函数定义此内在函数无关; -mavx512f
已经暗示了 AVX512 之前的所有英特尔 SSE/AVX 扩展。
它存在于 clang trunk 中(但不是 7.0,所以它是最近才添加的)。
unaligned_mm512_loadu_si512
- 到处都支持,使用这个
未对齐的_mm512_loadu_epi64
- clang 主干,而不是 gcc。
对齐_mm512_load_si512
- 到处都支持,使用这个
对齐_mm512_load_epi64
- 令人惊讶的是,它也支持所有地方。
unaligned _mm512_maskz_loadu_epi64
- 随处支持,将其用于零掩码加载
unaligned _mm512_mask_loadu_epi64
- 到处都支持,将它用于合并掩码加载。
此代码早在 4.9.0 就在 gcc 上编译,而 mainline (Linux) 早在 3.9 就可以编译,两者都使用-march=avx512f
。或者,如果他们支持它,-march=skylake-avx512
或 -march=knl
。我没有用 Apple Clang 测试过。
#include <immintrin.h>
__m512i loadu_si512(void *x) return _mm512_loadu_si512(x);
__m512i load_epi64(void *x) return _mm512_load_epi64(x);
//__m512i loadu_epi64(void *x) return _mm512_loadu_epi64(x);
__m512i loadu_maskz(void *x) return _mm512_maskz_loadu_epi64(0xf0, x);
__m512i loadu_mask(void *x) return _mm512_mask_loadu_epi64(_mm512_setzero_si512(), 0xf0, x);
Godbolt link;您可以取消注释 _mm512_loadu_epi64
并将编译器翻转到 clang trunk 以查看它在那里工作。
【讨论】:
原谅我的无知...当你说“不加掩饰”时,你是什么意思? 没有 AVX512 掩码参数。具有不同元素大小版本的向量加载的全部意义在于与掩码寄存器一起使用,例如_mm512_maskz_loadu_epi64(0x55, x);
,它在加载时免费将奇数元素归零。喜欢vmovdqu64 (%rdi), %zmm0%k1z
。当元素不变地加载到目标时,元素边界是没有意义的。这就是为什么 AVX2 和更早版本没有它们用于按位布尔值(如 _mm_xor_si128
)和加载/存储如 _mm_load_si128
)。
这就是为什么存在像 vmovdqu64/32/16/8
这样的 asm 指令的原因。 felixcloutier.com/x86/… 请注意上述 AT&T 语法 asm 指令中的 %k1z
装饰。这意味着使用 EVEX 前缀编码 mask-register = k1 和零屏蔽(不是合并屏蔽)进行组装。对于大多数指令,无掩码编码意味着k0
,因此有一个额外的掩码寄存器可以用作比较掩码或kshift
/kunpack
/ktest
/@ 的目标987654355@/等说明。
谢谢。我不知道需要掩码才能从 AVX-512 下的内存中加载具有值的寄存器。
@jww:不需要。 (刚刚编辑完我的最后一条评论,提到在这些情况下意味着k0
的编码实际上意味着“无掩码”)。所以你可以说机器代码中总是有掩码,但是有一个架构零寄存器可用于无掩码。但是在 asm 文本语法和 C++ 内在函数中,您可以使用指令或内在函数的无掩码版本。如果您没有在纯粹按位的内在函数中使用掩码,则无需关心它的不同元素大小版本。在 asm 中你只需要选择一个,在 C++ 中编译器可以【参考方案2】:
_mm512_loadu_epi64 在 32 位模式下不可用。您需要针对 64 位模式进行编译。一般来说,AVX512 在 64 位模式下效果最好。
【讨论】:
哪个编译器是这样的?这听起来像是一个错误,因为vmovdqu64
在任何一种模式下都可用。 (同意使用 64 位模式,因此您有 32 个而不是 8 个寄存器!因此整数寄存器可以保存 AVX512BW 的 64 元素掩码。)以上是关于错误:“_mm512_loadu_epi64”未在此范围内声明的主要内容,如果未能解决你的问题,请参考以下文章