8

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

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

    vpbroadcastq zmm26{k5}{z},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 指令集的描述性信息来源吗?

4

2 回答 2

4

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

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

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

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

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

于 2015-08-20T20:33:45.527 回答
2

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

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

但是,您可以VPCOMPRESSQ zmm1/m512 {k5}{z}, zmm26使用与用于vpbroadcast. 但它不如其他选项快,因此唯一的优点是使用相同的掩码寄存器作为随机播放控件,如果您不能将设置提升到循环之外,可以节省工作量。

在 KNL 上,VPCOMPRESSQ(带有寄存器目标)每 3 个周期有一个吞吐量(根据Agner Fog的测试)。 在 Skylake-AVX512 上,它是每 2 个周期一个,延迟为 3c。这两个 CPUvpermq每个周期运行 1 次,因此它对其他指令的干扰可能较小。我还没有找到vpcompressq.


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

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

但是,如果您的值在车道的上部 64b 中(即奇数元素,从 0 开始计数),则您需要,vpextrq rax, xmm, 1而不是vmovq,并且它(在 Skylake 上)解码为 shuffle uop 和vmovquop。(永远不要使用vpextrq rax, xmm, 0,因为它浪费了一个 shuffle uop。这就是编译器优化_mm_extract_epi64(v, 0)为 a 的原因vmovq。)

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

vpermq+vmovq也适用于索引不是编译时常量的情况,因为您在 shuffle 控制向量中需要的只是将索引放在元素 0 中。例如vmovd xmm7, ecxvpermq zmm1, zmm2, zmm7/设置vmovq rax, zxm1


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

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

AVX2VEXTRACTI128 [mem], ymm, 1指令在 Skylake 上作为(非微融合)存储运行,没有随机播放端口(http://agner.org/optimize/)。AVX512 extract-to-memory 希望是相同的,仍然没有使用 shuffle uop。(吞吐量/延迟 Instlatx64 数字可用,但我们不知道什么与什么竞争哪些吞吐量资源,所以它比 Agner Fog 的指令表有用得多。)

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

于 2017-08-14T18:18:49.810 回答