gpt4 book ai didi

assembly - 从通用寄存器加载/存储到 xmm/ymm 寄存器/从 xmm/ymm 寄存器加载/存储的最佳方式

转载 作者:行者123 更新时间:2023-12-02 22:15:10 27 4
gpt4 key购买 nike

从 SIMD 寄存器加载和存储生成用途寄存器的最佳方式是什么?到目前为止,我一直使用堆栈作为临时的。例如,

mov [rsp + 0x00], r8
mov [rsp + 0x08], r9
mov [rsp + 0x10], r10
mov [rsp + 0x18], r11
vmovdqa ymm0, [rsp] ; stack is properly aligned first.

我认为没有任何指令可以直接(或其他方向)执行此操作,因为这意味着具有五个操作数的指令。然而,上面的代码对我来说似乎很愚蠢。有更好的方法吗?我只能想到一种替代方案,使用 pinsrd 和相关指令。但似乎并没有好转。

动机是,有时在 AVX2 中执行某些操作会更快,而其他操作则使用通用寄存器执行。例如,在一小段代码中,有四个 64 位无符号整数,我需要 BMI2 中的四个 xor、两个 mulx。使用 vpxor 执行xor 会更快,但是,mulx 没有 AVX2 等效项。 vpxor 与 4 xor 相比,任何性能增益都会因打包和解包过程而丢失。

最佳答案

您的瓶颈是延迟、吞吐量还是融合域微指令?如果是延迟,那么存储/重新加载就会很糟糕,因为从窄存储到宽负载的存储转发停滞。

对于吞吐量和融合域微指令,这并不可怕:只有 5 个融合域微指令,在存储端口上形成瓶颈。如果周围的代码主要是ALU uops,那么值得考虑。

<小时/>

对于您建议的用例:

花费大量指令/微指令在整数和向量寄存器之间移动数据通常是一个坏主意。 PMULUDQ确实为您提供了相当于 32 位 mulx 的功能,但您是对的,64 位乘法在 AVX2 中不能直接使用。 (AVX512 有它们)。

您可以使用 PMULUDQ 的常用扩展精度技术进行 64 位向量乘法。我对Fastest way to multiply an array of int64_t?的回答发现使用 AVX2 256b 向量对 64 x 64 => 64b 乘法进行向量化是值得的,但对于 128b 向量则不值得。但这是内存中的数据,而不是向量寄存器中开始和结束的数据。

在这种情况下,可能值得从多个 32x32 => 64 位向量乘法中构建一个 64x64 => 128b 完全乘法,但可能需要太多指令,因此不值得它。如果您确实需要上半部分结果,则解包为标量(或执行整个标量操作)可能是最好的选择。

整数 XOR 非常便宜,具有出色的 ILP(延迟 = 1,吞吐量 = 每个时钟 4)。如果您没有其他矢量友好的操作,那么将数据移动到矢量寄存器中只是为了进行异或它绝对不值得。请参阅 tag wiki用于性能链接。

<小时/>

延迟的最佳方法可能是:

vmovq   xmm0, r8
vmovq xmm1, r10 # 1uop for p5 (SKL), 1c latency
vpinsrq xmm0, r9, 1 # 2uops for p5 (SKL), 3c latency
vpinsrq xmm1, r11, 1
vinserti128 ymm0, ymm0, ymm1, 1 # 1uop for p5 (SKL), 3c latency

总计:p5 为 7 uops,有足够的 ILP 来几乎所有背靠背运行它们。无论如何,r8 可能会比 r10 早一两个周期准备就绪,因此您不会损失太多。

<小时/>

还值得考虑:无论您做什么来生成 r8..r11,都使用向量整数指令来执行,以便您的数据已经在 XMM 寄存器中。不过,您仍然需要使用 2x PUNPCKLQDQ 和 VINSERTI128 将它们混在一起。

关于assembly - 从通用寄存器加载/存储到 xmm/ymm 寄存器/从 xmm/ymm 寄存器加载/存储的最佳方式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40623773/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com