vpbroadcastq zmm26{k5}{z},rax 是一个有趣的 hack;如果它有效运行,可能会很有用。特别是使用合并屏蔽作为vmovq / vpinsrq 的替代方案。
除了元素 0 或 1:vmovq rax, xmm26 或 vpextrq rax, xmm26, 1 之外,没有与 vpbroadcastq 的这种(ab)使用相反的单指令。是的,在 AVX512F 和 AVX512DQ 中,这些指令有 EVEX 编码,可以分别访问 xmm16-31。如果您的数据在 xmm0-15 中,则可以使用较短的 VEX 编码版本。
但是,您可以滥用VPCOMPRESSQ zmm1/m512 {k5}{z}, 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 上。