像“_mm256_set1_epi64x”这样的内在函数中后缀 "x" 的含义

Meaning of suffix "x" in intrinsics like "_mm256_set1_epi64x"

在某些内在函数中,他们使用后缀 x ,例如 _mm256_set1_epi64x 。这是什么意思?作为参考,_mm256_set1_epi32 没有此后缀。

TL:DR: MMX->SSE2 转换内在函数使用了非 x _mm_set/set1_epi64 名称。

这都是基于当前函数名称、已知历史和一些编译器行为的猜测:

第一个英特尔 SIMD 内在函数用于 MMX。 __m64 是 SSE2 __m128i 和 AVX2 __m256i 的 MMX 等价物。当时没有 64 位 x86 CPU,所以最宽的 set 内在是 __m64 _mm_set_pi32 (int e1, int e0)。根据 intrinsic-finder,movq mm0, rax 仍然没有任何内在函数。我认为你 can/should 只是将 int64_t 转换为 __m64。 (虽然上次我在去年左右进行了实验,但 gcc 或 clang(我忘了是哪个)在优化 MMX asm 方面做得很差。老化的编译器支持是新项目避免使用 MMX 的另一个原因。)

引入 SSE2 时 in 2001, AMD64 / x86-64 still wasn't released yet, and wouldn't be supported by Intel for a few years. (At that time they were hoping that IA-64 / Itanium 将成为未来并取代 x86)。我没有检查旧手册,但我猜
__m128i _mm_set1_epi64 (__m64 a) 当时可用,
__m128i _mm_set1_epi64x (__int64 a) 可能不是。 (请注意,__int64 不是 <stdint.h> 中的 int64_t。但它是 64 位整数类型,无需担心。)

epi 代表扩展(?)压缩整数。 epi 而不是 pi 告诉您它是 SSE 内在的,而不是 MMX 内在的。对于从一个元素宽度转换为另一个元素宽度的内在函数,如果明确标识操作(至少对于我查看的那些),则内在函数使用源宽度。例如_mm_packs_epi32 (packssdw) 或 _mm_unpackhi_epi16 (punpckhwd)。 PMOVZX 需要两个数字,因为有 _mm_cvtepu8_epi32 (pmovzxbd),_mm_cvtepu8_epi64 (pmovzxbq,等等


编译器当然支持 32 位模式下的 64 位整数,因此英特尔包含与它们一起使用的内在函数是有意义的。但是 IIRC,在某些编译器中,64x 内在函数仅在编译 64 位代码时可用64x 仅与转换 to/from 标量 64 位整数相关,因此您找不到 x 版本的 _mm_add_epi64 或类似的东西。

根据编译器的不同,_mm256_set1_epi64x 可能仍然存在这种仅存在于 64 位中的东西,但无论哪种方式,历史都解释了为什么 64x 而不是 32x.

(抱歉,我很懒惰,没有在 Godbolt 上进行实验以检查当前编译器是否具有 -m32。看看你从铸造中得到什么样的 asm 可能会很有趣 int64_t__m64 并使用 32 位代码中的 _mm_set 内在函数。)