如何用 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 ymmvmovdqu ymm 更短, 完全 做同样的事情,。如果编译器想要加载到 ymm16..31,它总是可以使用 vmovdqu3264,否则你希望它使用更短的 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 位加载内在函数并不重要(对齐与未对齐除外)。

相关: