我希望对zmm 0-31寄存器组的四字字元素执行整数运算操作,并保留这些操作产生的进位。只有在通用寄存器集中处理数据时才会出现这种情况。
因此,我想将一个zmm 0-31寄存器中的信息复制到一个通用寄存器中。在处理通用寄存器中的64位数据之后,我想将数据返回到它来自的相同QuadWord位置的原始zmm 0-31寄存器。我知道我可以使用命令将数据从通用寄存器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源的广播命令。
我很高兴知道我的命令选项是从zmm 0-31寄存器到rax寄存器的特定QuadWord。此外,除了英特尔手册之外,AVX512指令集还有其他任何描述性信息来源吗?
答案 0 :(得分:3)
与某些早期的SIMD扩展不同,它们具有"提取"诸如pextrq
这样的指令可以直接执行此操作,我不知道在AVX-512中使用任何方法(在带有ymm寄存器的AVX中),除了:
将您想要的元素置换/混洗到较低阶四字,然后使用vmovq
按照您的注意将其放入通用寄存器。
将整个矢量存储到临时存储位置loc
,例如堆栈,然后使用mov register,[loc + offset]
指令读取您感兴趣的qword。
这两种方法看起来都很丑陋,哪种更好取决于您的具体情况。尽管使用内存作为中介,如果您计划从每个向量中提取多个值,第二种方法可能会更快,因为您可以在最近的CPU上使用两个加载端口,这些加载端口具有一个负载/周期的吞吐量,而置换/混洗方法可能会阻塞permute / shuffle所需的端口。
请参阅下面的彼得的答案,以获得更全面的治疗,包括使用带有面具的vcompress
说明作为一种穷人的提取物。
答案 1 :(得分:1)
vpbroadcastq zmm26{k5}{z},rax
是一个有趣的黑客;如果它有效运行可能会有用。特别是使用合并屏蔽作为vmovq
/ vpinsrq
的替代方法。
{(1}}的此(ab)使用没有单指令反转,除了元素0或1:vmovq rax, xmm26
或vpextrq rax, xmm26, 1
。是的,对于那些让他们分别在AVX512F和AVX512DQ中访问xmm16-31的指令,有EVEX编码。如果您的数据是xmm0-15,则可以使用较短的VEX编码版本。
然而,您可以滥用VPCOMPRESSQ zmm1/m512 {k5}{z}, zmm26
来使用您用于{{1}的同一个设置位掩码寄存器来执行内存或zmm目标所需的操作}。但它没有其他选项那么快,所以唯一的优势是使用相同的掩码寄存器作为随机控制,如果你不能将设置提升到循环中,就可以节省工作。
在KNL上,vpbroadcastq
(带寄存器目的地)每3个周期有一个吞吐量(根据Agner Fog的测试)。 On Skylake-AVX512,每2个周期一个,有3c延迟。这两个CPU每个周期运行vpbroadcast
1,因此它可能对其他指令的干扰较小。我还没有找到VPCOMPRESSQ
的内存目标版本的时间安排。
在没有存储/重新加载的情况下转向另一个方向需要至少一个shuffle uop,以及一个单独的uop从向量复制到GP寄存器(如vpermq
)。 (如果你最终需要所有的元素,那么存储/重新加载可能比纯ALU策略更好。前一个或两个的ALU可能是好的,所以你让它们具有低延迟,因此一些相关的操作可以开始)。 / p>
如果您的值位于128b" lane" (即偶数元素)的低64b,则vextracti64x2 xmm1, zmm26, 3
/ vpcompressq
对于单个元素而言尽可能高效。奇怪的名称是因为vmovq
的AVX512版本有两种掩盖粒度。如果你想要的元素在zmm0-15的第二个128b通道中,你可以使用vmovq rax, xmm1
来保存代码大小(AVX2指令只有一个3字节的VEX前缀,而不是4字节的EVEX)。 / p>
但是如果你的值在一个通道的高64b(即一个奇数元素,从0开始计算),你需要,vextracti128
而不是vextracti128 xmm1, ymm6, 1
,它解码(在Skylake上)到一个shuffle uop和一个vpextrq rax, xmm, 1
uop。 (永远不要使用vmovq
,因为它会浪费一个随机的uop。这就是编译器将vmovq
优化为vpextrq rax, xmm, 0
的原因。)
对于奇数编号的元素,您仍可以使用_mm_extract_epi64(v, 0)
+ vmovq
进行一次随机播放。如果需要在循环中提取,请在循环外设置一个随机向量常量。或者如果你还需要其他常量(因此你的函数已经是常量的热缓存行),如果不在循环中,广播加载内存操作数应该没问题。
vpermq zmm1, zmm2, zmm3/m512/m64bcst
+ vmovq
也可以工作,因为在shuffle控制向量中你需要的只是在元素中有索引例如vpermq
为vmovq
/ vmovd xmm7, ecx
正如@Bee所说,如果您需要多个元素,则存储/重新加载是一个不错的选择。如果需要运行时变量元素,也可以使用它,因为从对齐的512b存储到对齐的64b重新加载的存储转发可能无需停顿。 (仍然比vpermq zmm1, zmm2, zmm7
解决方案的延迟更高,但仅使用内存uops,而不是ALU。在Skylake-AVX512中,ALU uop可能非常有价值,其中port1不会运行任何向量uops,而有512b uops运行。)
如果您的元素编号是编译时常量,则可以使用vmovq rax, zxm1
仅将ZMM向量的所需128b通道存储到内存中。 (或vpermq
如果是它的通道1.)如果你最终想要内存中的值,你可以使用一个只有第二位设置的掩码寄存器来存储高元素。 (但IDK如果额外的屏蔽部分进入未映射的页面,它的性能如何.IIRC,它实际上并不是错误的,但是在体系结构上它可能很慢处理它。甚至跨越缓存线边界与128b全宽可能很慢。)
AVX2 vextracti64x2 [rsp-16], zmm26, 3
指令在Skylake上运行,只是一个(非微融合)商店,没有随机端口(http://agner.org/optimize/)。 AVX512提取到内存有望相同,仍然没有使用shuffle uop。 (Throughput / latency Instlatx64 numbers are available,但我们不知道与哪些吞吐量资源有什么竞争,因此它比Agner Fog的指令表更有用。)
对于KNL,vextracti128
是4 uops,吞吐量不佳,AVX2 VEXTRACTI128 [mem], ymm, 1
是相同的。所以(假设存储转发工作正常)只需将整个512b向量存储在KNL上。