如何有效地将 zmm 寄存器的低 64 位保存到内存中?
Posted
技术标签:
【中文标题】如何有效地将 zmm 寄存器的低 64 位保存到内存中?【英文标题】:How do I efficiently save the lower 64 bits of a zmm register to memory? 【发布时间】:2020-11-18 01:59:50 【问题描述】:我正在使用 AVX512 对函数进行矢量化。这有效,除了需要将结果保存到内存的存储,它只是低 64 位数字。
inline square(double x) return x * x;
v = in[pos];
v0 = v - (a1 * v1 + a2 * v2 + a3 * v3 + a4 * v4);
r = square(b0 * v0 + b1 * v1 + b2 * v2 + b3 * v3 + b4 * v4);
out[idx] = r;
v4 = v3;
v3 = v2;
v2 = v1;
v1 = v0;
其中 a1 到 a4 和 b0 到 b4 是预先计算的因子。 v0 到 v4 首先设置为零,然后设置为输入值,如上所示。然后旋转该矩阵。
square()
计算后,我想将结果双精度保存在输出缓冲区中。该值在位 [63:0] 或寄存器“r”中。
我尝试了这个内在:
_mm512_store_epi64(out + idx, r);
但它需要超过 16 个字节的对齐方式(它的 SEGV 的地址是 16 的倍数),我需要一条使用 8 字节对齐方式的指令。生成的汇编指令是vmovdqa64
,如下所示:
=> 0x0000555555555122 <+290>: vmovdqa64 %zmm0,(%rbx,%rax,8)
【问题讨论】:
这不是MOVQ 所做的吗?该页面将_mm_cvtsi128_si64
列为内在函数。
不过,我找不到合适的内在函数来在压缩双精度类型上使用它。
@NateEldredge 这不正确。 mm 指令是“遗留”的,因为它们使用 SSE,与 AVX 混合使用是一件很糟糕的事情(因为它们将顶部寄存器内容保存在 transitions 之间。)
【参考方案1】:
AVX512 为无掩码 vector 存储引入了愚蠢的误导性固有名称,例如 _mm512_store_epi64
用于 vmovdqa64 [mem], zmm
,即 _mm512_store_si512
。永远不要使用它们,但内在函数指南确实记录了它们的作用:https://software.intel.com/sites/landingpage/IntrinsicsGuide
转换为__m128i
并使用正常的低元素标量内在函数。你想要的asm指令是vmovq %xmm0, (%rbx,%rax,8)
__m512i
的低 128 位是__m128i
,所以_mm512_castsi512_si128
是免费的。
uint64_t extractlow64(__m512i v)
return _mm_cvtsi128_si64(_mm512_castsi512_si128(v));
compiles to this with GCC
extractlow64(long long __vector(8)):
vmovq rax, xmm0
ret # vzeroupper not needed: caller had to use ZMM to pass the arg
同样适用于__m512d
:
double extractlow_double(__m512d v)
return _mm_cvtsd_f64(_mm512_castpd512_pd128(v));
extractlow_double(double __vector(8)):
ret
# the low element of xmm0 (retval) is already the low element of zmm0
如果未优化存储,则在某处分配 double
结果将使编译器发出 vmovsd
存储。
【讨论】:
很有趣,因为文档 here_mm_cvtsd_f64()
说这是一个遗留的 SSE2 指令,these docs 说不要将 AVX 与 SSE 混合......但是,查看指令集参考书, VMOVQ
被明确标记为 AVX
... 这很复杂。
@AlexisWilke:每条旧指令都有一个 AVX 编码,在助记符前面有一个 v
。 AVX 编码与原始指令一起列出。此外,读取带有movq %xmm0, %rax
的向量寄存器可能没有问题;当 reg 的上半部分脏了时,只用旧的 SSE 指令编写 XMM0 将是一个潜在的问题。但无论如何,旧指令没有新的助记符,当您使用 -mavx
(例如,作为 -march=skylake-avx512
的一部分)时,编译器总是会发出 VEX / EVEX 编码。以上是关于如何有效地将 zmm 寄存器的低 64 位保存到内存中?的主要内容,如果未能解决你的问题,请参考以下文章
如何将 AVX512 寄存器 zmm26 中的 QuadWord 写入 rax 寄存器?