我可以将 returns __m128i 的内在结果分配给类型 __m128i_u 的变量吗?

can I assign the result of intrinsic that returns __m128i to variable of the type__m128i_u?

如标题所示-我想做如下:

__m128i_u* avxVar = (__m128i_u*)Var;  // Var allocated with alloc
*avxVar = _mm_set_epi64(...);         // is that ok to assign __m128i to __m128i_u ?

是的,但请注意 __m128i_u 不可移植(例如到 MSVC); GCC/clang 在内部使用它来实现未对齐的 loadu/storeu 内在函数。 完全 等同于以正常方式进行:

_mm_storeu_si128((__m128i*)Var, vec);

(其中 vec 是任何 __m128i。例如,它可以是 _mm_set_epi64x 或一个变量。)

GCC 11 的 emmintrin.h 实现 _mm_storeu_si128 是这样定义的,采用 __m128i_u* 指针 arg,因此取消引用执行未对齐访问(如果未优化)。

// GCC internals, quoted for reference only.
// Just use #include <immintrin.h> in your own code
extern __inline void __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_storeu_si128 (__m128i_u *__P, __m128i __B)
{
  *__P = __B;
}

所以是的,GCC 的 headers 依赖于 __m128i*__m128i_u* 的兼容和隐式转换。

正如 _mm_storeu_si128movdqu 的固有函数一样,__m128i_u* 取消引用也是如此。但实际上这些内在函数的存在只是为了向编译器传达对齐信息,由编译器决定何时实际加载和存储,就像 char*.

的 deref 一样

(有趣的事实:__m128i* 是一个 may_alias 类型,就像 char*,所以你可以将它指向任何东西而不会违反 strict-aliasing。Is `reinterpret_cast`ing between hardware SIMD vector pointer and the corresponding type an undefined behavior? )


另请注意,_mm_set_epi64 采用 __m64 参数:它用于从两个 MMX 向量而非标量 int64_t 构建 SSE2 向量。你可能想要 _mm_set_epi64x


它们的编译方式相同

void foo(void *Var) {
    __m128i_u* avxVar = (__m128i_u*)Var;
    *avxVar = _mm_set_epi64x(1, 2); 
}

void bar(void *Var) {
    _mm_storeu_si128((__m128i*)Var, _mm_set_epi64x(1, 2) );
}

两个函数在 gcc/clang/MSVC 中的编译方式相同(并且在语义上是等效的,因此内联后将始终相同)。 但是只有第二个可以用 MSVC 编译,正如您在 Godbolt 编译器资源管理器上看到的那样: https://godbolt.org/z/Y8Wq96Pqs 。如果禁用 #ifdef __GNUC__,则会在 MSVC 上出现编译器错误。

## GCC -O3
foo:
        movdqa  xmm0, XMMWORD PTR .LC0[rip]
        movups  XMMWORD PTR [rdi], xmm0
        ret
bar:
        movdqa  xmm0, XMMWORD PTR .LC0[rip]
        movups  XMMWORD PTR [rdi], xmm0
        ret
.LC0:
        .quad   2
        .quad   1

随着周围代码的复杂化,_mm_loadu_si128 可以折叠到仅使用 AVX 的 ALU 的内存源操作数(例如 vpaddb xmm0, xmm1, [rdi],但 _mm_load_si128 对齐的加载可以折叠到 SSE 内存源像 paddb xmm0, [rdi].