如何用 gcc 或 clang 模拟 _mm256_loadu_epi32?
How to emulate _mm256_loadu_epi32 with gcc or clang?
英特尔的内部指南列出了内部 _mm256_loadu_epi32
:
_m256i _mm256_loadu_epi32 (void const* mem_addr);
/*
Instruction: vmovdqu32 ymm, m256
CPUID Flags: AVX512VL + AVX512F
Description
Load 256-bits (composed of 8 packed 32-bit integers) from memory into dst.
mem_addr does not need to be aligned on any particular boundary.
Operation
a[255:0] := MEM[mem_addr+255:mem_addr]
dst[MAX:256] := 0
*/
但是 clang 和 gcc 不提供这个内在函数。相反,他们(在文件 avx512vlintrin.h
中)仅提供屏蔽版本
_mm256_mask_loadu_epi32 (__m256i, __mmask8, void const *);
_mm256_maskz_loadu_epi32 (__mmask8, void const *);
归结为相同的指令 vmovdqu32
。我的问题:如何模拟 _mm256_loadu_epi32
:
inline _m256i _mm256_loadu_epi32(void const* mem_addr)
{
/* code using vmovdqu32 and compiles with gcc */
}
不编写汇编,即仅使用可用的内部函数?
像正常人一样使用_mm256_loadu_si256
就可以了。 AVX512 intrinsic 唯一给你的是一个更好的原型(const void*
而不是 const __m256i*
)所以你不必写丑陋的转换。
@chtz 建议您可能仍想自己编写一个包装函数来获得 void*
原型。但是不要叫它_mm256_loadu_epi32
;某些未来的 GCC 版本可能会添加它以与 Intel 的文档兼容并破坏您的代码。
从另一个角度来看,不幸的是编译器没有将其视为 AVX1 内在函数,但我想 ,它允许您使用尚未启用的 ISA 扩展中的内在函数,需要这种知道什么时候可以使用 ymm16-31 的线索。
你甚至不希望编译器在你没有屏蔽时发出 vmovdqu32 ymm
; vmovdqu ymm
更短, 完全 做同样的事情,。如果编译器想要加载到 ymm16..31,它总是可以使用 vmovdqu32
或 64
,否则你希望它使用更短的 VEX 编码 AVX1 vmovdqu
.
我很确定 GCC 对待 _mm256_maskz_epi32(0xffu,ptr)
的方式与 _mm256_loadu_si256((const __m256i*)ptr)
完全相同,并且无论您使用哪一个,都会生成相同的 asm。它可以优化掉 0xffu
掩码并简单地使用未掩码的负载,但在您的源代码中不需要额外的复杂性。
但不幸的是,当启用 AVX512VL(例如 -march=skylake-avx512
)时,即使您编写 _mm256_loadu_si256
,GCC9 和更早版本也会悲观化为 vmovdqu32 ymm0, [mem]
。这是一个错误的优化,GCC Bug 89346.
只要没有屏蔽,使用哪个 256 位加载内在函数并不重要(对齐与未对齐除外)。
相关:
英特尔的内部指南列出了内部 _mm256_loadu_epi32
:
_m256i _mm256_loadu_epi32 (void const* mem_addr);
/*
Instruction: vmovdqu32 ymm, m256
CPUID Flags: AVX512VL + AVX512F
Description
Load 256-bits (composed of 8 packed 32-bit integers) from memory into dst.
mem_addr does not need to be aligned on any particular boundary.
Operation
a[255:0] := MEM[mem_addr+255:mem_addr]
dst[MAX:256] := 0
*/
但是 clang 和 gcc 不提供这个内在函数。相反,他们(在文件 avx512vlintrin.h
中)仅提供屏蔽版本
_mm256_mask_loadu_epi32 (__m256i, __mmask8, void const *);
_mm256_maskz_loadu_epi32 (__mmask8, void const *);
归结为相同的指令 vmovdqu32
。我的问题:如何模拟 _mm256_loadu_epi32
:
inline _m256i _mm256_loadu_epi32(void const* mem_addr)
{
/* code using vmovdqu32 and compiles with gcc */
}
不编写汇编,即仅使用可用的内部函数?
像正常人一样使用_mm256_loadu_si256
就可以了。 AVX512 intrinsic 唯一给你的是一个更好的原型(const void*
而不是 const __m256i*
)所以你不必写丑陋的转换。
@chtz 建议您可能仍想自己编写一个包装函数来获得 void*
原型。但是不要叫它_mm256_loadu_epi32
;某些未来的 GCC 版本可能会添加它以与 Intel 的文档兼容并破坏您的代码。
从另一个角度来看,不幸的是编译器没有将其视为 AVX1 内在函数,但我想
你甚至不希望编译器在你没有屏蔽时发出 vmovdqu32 ymm
; vmovdqu ymm
更短, 完全 做同样的事情,vmovdqu32
或 64
,否则你希望它使用更短的 VEX 编码 AVX1 vmovdqu
.
我很确定 GCC 对待 _mm256_maskz_epi32(0xffu,ptr)
的方式与 _mm256_loadu_si256((const __m256i*)ptr)
完全相同,并且无论您使用哪一个,都会生成相同的 asm。它可以优化掉 0xffu
掩码并简单地使用未掩码的负载,但在您的源代码中不需要额外的复杂性。
但不幸的是,当启用 AVX512VL(例如 -march=skylake-avx512
)时,即使您编写 _mm256_loadu_si256
,GCC9 和更早版本也会悲观化为 vmovdqu32 ymm0, [mem]
。这是一个错误的优化,GCC Bug 89346.
只要没有屏蔽,使用哪个 256 位加载内在函数并不重要(对齐与未对齐除外)。
相关: