将 uint64_t 的数组转换为 __m256i

convert array of uint64_t to __m256i

我有四个 uint64_t 号码,我希望将它们合并为一个 __m256i 的一部分,但是,我不知道该怎么做。

这是一次尝试(其中 raxrbxrcxrdxuint64_t):

uint64_t a [4] = {rax,rbx,rcx,rcx};

__m256i t = _mm256_load_si256((__m256i *) &a);

首先,请确保您的 CPU 甚至支持这些 AVX 指令:Performing AVX integer operation

其次,从https://software.intel.com/en-us/node/514151开始,指针参数必须是对齐的位置。通常在堆栈上分配的内存地址是随机的,并且取决于先前调用的堆栈帧的大小,因此可能不会对齐。

相反,只需使用内部类型__m256i强制编译器对齐它; ,根据https://software.intel.com/en-us/node/582952,在你的a数组上使用__declspec(align)

如果你已经有一个数组,那么绝对使用_mm256_loadu_si256(甚至对齐版本,_mm256_load_si256如果你的数组是alignas(32).) 但通常不要创建一个数组只是为了存储到/重新加载。


使用 _mm_set 内在函数,让编译器决定如何做。请注意,他们首先采用编号最高的元素作为参数:例如

__m256i vt = _mm256_set_epi64x(rdx, rcx, rbx, rax);

您通常不希望 asm 看起来像您的标量存储 -> 矢量加载 C 源代码,因为那样会产生存储转发停顿。

gcc 6.1 在这种情况下“看穿”了本地数组(并使用 2x vmovq / 2x vpinsrq / 1x vinserti128),但它仍然生成代码来对齐堆栈到 32B。 (尽管不需要它,因为它最终不需要任何 32B 对齐的局部变量)。

正如你在 Godbolt Compiler Explorer 上看到的那样,两种方式的实际数据移动部分是相同的,但是数组方式有一堆浪费的指令,gcc 在决定避免后未能优化掉消息来源暗示的糟糕方式。

_mm256_set_epi64x 适用于 32 位代码(至少使用 gcc)。你得到 2x vmovq 和 2x vmovhps 来对 xmm 寄存器的上半部分进行 64 位加载。 (将 -m32 添加到 godbolt link 的编译选项中。