如何将 AVX512 寄存器 zmm26 中的 QuadWord 写入 rax 寄存器?

Posted

技术标签:

【中文标题】如何将 AVX512 寄存器 zmm26 中的 QuadWord 写入 rax 寄存器?【英文标题】:How can I write a QuadWord from AVX512 register zmm26 to the rax register? 【发布时间】:2015-08-08 13:16:56 【问题描述】:

我希望对 zmm 0-31 寄存器集的四字元素执行整数算术运算,并保留这些运算产生的进位位。看来只有在通用寄存器集中处理数据时才有可能。

因此,我想将信息从 zmm 0-31 寄存器之一复制到通用寄存器之一。在处理通用寄存器中的 64 位数据后,我想将数据返回到原始 zmm 0-31 寄存器中的相同 QuadWord 位置。我知道我可以使用命令将数据从通用寄存器 rax 移动到 AVX512 寄存器 zmm26 QuadWord 位置 5

    vpbroadcastq zmm26k5z,rax 

其中 8 位掩码 k5 = 十进制 32,允许将数据广播到 zmm26 的第 5 个 QuadWord,z=1 表示 zmm26 中没有其他 QWord 受到影响,而 rax 是数据的来源。

但我找不到将数据从寄存器 zmm26,四字 5 写入 rax 寄存器的反向命令。看来我只能使用 vmovq rax, xmm1 命令将最不重要的 QuadWord 从 AVX 寄存器复制到通用寄存器。并且没有使用掩码 zmm 0-31 源的广播命令。

我希望知道我的命令选项是什么,以便将特定的 QuadWord 从 zmm 0-31 寄存器获取到 rax 寄存器。另外,目前除了英特尔手册之外,还有其他关于 AVX512 指令集的描述性信息来源吗?

【问题讨论】:

您可以通过之后进行比较来模拟向量 reg 中的进位处理。 (例如,无符号 a+b < a 表示发生了进位,而 AVX512F 有一个无符号小于谓词用于整数比较指令,如 vcmpq)。有时这比解包为整数要好。特别是如果您需要对 ZMM 向量中的所有元素执行此操作。 相关:使用 AVX512 或 AVX2 How to move double in %rax into particular qword position on %ymm or %zmm? (Kaby Lake or later) 走向另一个方向。 Move an int64_t to the high quadwords of an AVX2 __m256i vector 用于 AVX2 的 C 内在函数。 【参考方案1】:

与早期的一些具有“提取”指令的 SIMD 扩展不同,例如 pextrq 可以直接执行此操作,我不知道在 AVX-512 中执行此操作的任何方法(也不知道在带有 ymm 寄存器的 AVX 中) ) 以外:

    将您想要的元素排列/改组到低位四字中,然后使用vmovq 将其放入通用寄存器中。

    将整个向量存储到临时内存位置loc,例如堆栈,然后使用mov register,[loc + offset] 指令读取您感兴趣的任何qword。

这两种方法看起来都很难看,哪种更好取决于您的具体情况。尽管使用内存作为中介,但如果您计划从每个向量中提取多个值,则第二种方法可能会更快,因为您可以利用最近 CPU 上的两个负载端口,这些 CPU 具有一个负载/周期的吞吐量,而 permute/shuffle 方法可能会在置换/洗牌所需的端口上成为瓶颈。

请参阅下面彼得的回答以获得更全面的治疗,包括使用带有面具的 vcompress 说明作为一种穷人的提取物。

【讨论】:

虽然很难猜测未来处理器的性能,但我还是会尝试并建议vextracti32x4,然后是vpextrq。这个不需要置换向量。 这是有道理的。我经常使用 PSHUFB 作为我的锤子,因为它有效地提供了大多数其他置换和广播指令的超集,以及 1 个周期的最佳延迟,因此在某种程度上它几乎淘汰了其他更受限制的指令。但是,当它起作用时,使用其中一个受约束的指令通常会更好,因为您不必设置 shuffle 掩码,您可以保存一个寄存器,并且在某些情况下您的指令可以执行一个更广泛的端口。 vpcompressq zmm1k5, zmm26 几乎与 OP 的 hack 相反,但具有向量或内存目标。不过,不如单次随机播放快。,【参考方案2】:

vpbroadcastq zmm26k5z,rax 是一个有趣的 hack;如果它有效运行,可能会很有用。特别是使用合并屏蔽作为vmovq / vpinsrq 的替代方案。

除了元素 0 或 1:vmovq rax, xmm26vpextrq rax, xmm26, 1 之外,没有与 vpbroadcastq 的这种(ab)使用相反的单指令。是的,在 AVX512F 和 AVX512DQ 中,这些指令有 EVEX 编码,可以分别访问 xmm16-31。如果您的数据在 xmm0-15 中,则可以使用较短的 VEX 编码版本。

但是,您可以滥用VPCOMPRESSQ zmm1/m512 k5z, zmm26,使用与vpbroadcast 相同的单组位掩码寄存器对内存或zmm 目标执行您想要的操作。但它不如其他选项快,因此唯一的优点是使用相同的掩码寄存器作为随机播放控件,如果您无法将设置提升到循环之外,可以节省工作。

在 KNL 上,VPCOMPRESSQ(带有寄存器目标)每 3 个周期有一个吞吐量(根据Agner Fog 的测试)。 On Skylake-AVX512,每 2 个周期一个,延迟为 3c。这两个 CPU 都以每个周期 1 次运行 vpermq,因此它可能会减少对其他指令的干扰。我还没有找到vpcompressq 的内存目标版本的时间安排。


在没有存储/重新加载的情况下转到另一个方向需要至少一个 shuffle uop,以及一个单独的 uop 从向量复制到 GP 寄存器(如vmovq)。 (如果您最终想要所有元素,存储/重新加载可能比纯 ALU 策略更好。前一个或两个 ALU 可能很好,因此您拥有它们具有低延迟,因此可以开始一些相关操作)。

如果您的值在 128b“通道”的低 64b 中(即偶数元素),那么 vextracti64x2 xmm1, zmm26, 3 / vmovq rax, xmm1 对于单个元素。奇怪的名字是因为vextracti128 的 AVX512 版本有两种掩码粒度。如果您想要的元素在 zmm0-15 的第 2 个 128b 通道中,您可以使用 vextracti128 xmm1, ymm6, 1 来节省代码大小(AVX2 指令只有 3 字节的 VEX 前缀,而不是 4 字节的 EVEX)。

但是,如果您的值位于车道的上 64b 位(即奇数元素,从 0 开始计数),您需要 vpextrq rax, xmm, 1 而不是 vmovq,它会(在 Skylake 上)解码为随机播放 uop 和 vmovq uop。 (永远不要使用vpextrq rax, xmm, 0,因为它会浪费一个shuffle uop。这就是编译器将_mm_extract_epi64(v, 0)优化为vmovq的原因。)

对于奇数元素,您仍然可以使用vpermq zmm1, zmm2, zmm3/m512/m64bcst + vmovq 一次性完成。如果您需要在循环中提取,请在循环外设置一个随机播放向量常量。或者,如果您仍然需要其他常量(因此您的函数已经有一个常量的热缓存行),如果不在循环中,广播加载内存操作数应该没问题。

vpermq + vmovq 在索引不是编译时常量时也可以使用,因为在随机播放控制向量中所需的只是将索引放在元素 0 中。例如vmovd xmm7, ecx 为您设置 vpermq zmm1, zmm2, zmm7 / vmovq rax, zxm1


正如@Bee 所说,如果您需要多个元素,存储/重新加载是一个不错的选择。如果您需要一个运行时变量元素,您也可以使用它,因为从对齐的 512b 存储到对齐的 64b 重新加载的存储转发可能不会停止。 (仍然比vpermq 解决方案更高的延迟,但仅使用内存微指令,而不是 ALU。ALU 微指令在 Skylake-AVX512 中可能非常重要,其中端口 1 不会运行任何向量微指令,而有 512b 微指令正在运行。)

如果您的元素编号是编译时常量,您可以使用vextracti64x2 [rsp-16], zmm26, 3 仅将所需的 ZMM 向量的 128b 通道存储到内存中。 (或者vextracti128,如果它是通道1。)如果你最终想要内存中的值,你可以使用一个只设置第二位的掩码寄存器来存储高元素。 (但是 IDK 如果额外的屏蔽部分进入未映射的页面,它的性能如何。IIRC,它实际上并没有故障,但从微架构上来说,处理它可能会很慢。即使跨越 128b 完整的缓存线边界宽度可能很慢。)

AVX2 VEXTRACTI128 [mem], ymm, 1 指令在 Skylake 上作为(非微融合)存储运行,没有随机播放端口 (http://agner.org/optimize/)。 AVX512 extract-to-memory 希望是一样的,仍然没有使用 shuffle uop。 (Throughput / latency Instlatx64 numbers are available,但我们不知道什么与什么竞争哪些吞吐量资源,所以它的用处远不如 Agner Fog 的指令表。)

对于 KNL,VEXTRACTF32X4 [mem], zmm 是 4 uop,吞吐量很差,而 AVX2 vextracti128 [mem], ymm, imm8 也是一样。所以(假设存储转发运行良好)只需将整个 512b 向量存储在 KNL 上。

【讨论】:

以上是关于如何将 AVX512 寄存器 zmm26 中的 QuadWord 写入 rax 寄存器?的主要内容,如果未能解决你的问题,请参考以下文章

AVX512BW:使用bsf / tzcnt处理32位代码中的64位掩码?

LLVM学习笔记(50)

当使用带有 AVX-512 加载和存储的屏蔽寄存器时,是不是会因对屏蔽元素的无效访问而引发错误?

缺少掩码的 AVX-512 内在函数?

如何编译 TensorFlow 二进制文件以使用 AVX2、AVX512F、FMA?

随机播放 AVX 寄存器中的元素