如何解决是否有更好的AVX指令从3个ymm寄存器中移出数据?
我有三个ymm寄存器-ymm4,ymm5和ymm6-装有双精度(qword)浮点数:
ymm4: 73 144 168 41
ymm5: 144 348 26 144
ymm6: 732 83 144 852
我想写上面矩阵的每一列。例如:
-- extract ymm4[63:0] and insert it at ymm0[63:0]
-- extract ymm5[63:0] and insert it at ymm0[127:64]
-- extract ymm6[63:0] and insert it at ymm0[191:128]
以便ymm0读取73、144、732。
到目前为止,我已经使用过:
mov rax,4
kmovq k6,rax
vpxor ymm1,ymm1
VEXPANDPD ymm1{k6}{z},ymm6
这导致ymm1读取[0 0 732],所以我完成了第一步,因为732是ymm6中[63:0]处的元素。
对于ymm4和ymm5,我使用vblendpd:
vblendpd ymm0,ymm1,ymm4,1
这导致ymm0读取[73 0 732],所以我完成了第二步,因为73是ymm4中[63:0]处的元素。
现在我需要将ymm5 [63:0]放在ymm0 [127:64]:
vblendpd ymm0,ymm0,ymm5,2
这导致ymm0读取[73 144 732],所以现在我完成了第一列[63:0]。
但是现在我需要对ymm寄存器中的第2、3和4列执行相同的操作。在添加更多说明之前,这是执行我描述的最有效的方法吗?还有另一种更有效的方法吗?
我研究了unpckhpd(https://www.felixcloutier.com/x86/unpckhpd),vblendpd(https://www.felixcloutier.com/x86/blendpd和vshufpd(https://www.felixcloutier.com/x86/shufpd),上面显示的内容似乎是最好的解决方案,但其中有很多说明,并且文档中显示的imm8值的编码有些不透明。是否有更好的方法来提取三个ymm寄存器的对应列?
解决方法
让矩阵元素这样命名:
YMM0 = [A,B,C,D]
YMM1 = [E,F,G,H]
YMM2 = [I,J,K,L]
最终,您需要这样的结果,其中*
表示“无关”。
YMM0 = [A,E,I,*]
YMM1 = [B,*]
YMM2 = [C,*]
YMM3 = [D,H,*]
要实现此目的,我们将矩阵扩展为4×4(想象[*,*,*]
的另一行),然后转置矩阵。这分两个步骤完成:首先,对每个2×2子矩阵进行转置。然后,交换左上和右下矩阵:
[A,D] [A,G] [A,*]
[E,H] --\ [B,D,*]
[I,L] --/ [I,*] --/ [C,*]
[*,*] [J,L,*] [D,*]
对于ymm0
和ymm1
中的第一步,我们使用一对解压缩指令:
vunpcklpd %ymm1,%ymm0,%ymm4 // YMM4 = [A,G]
vunpckhpd %ymm1,%ymm5 // YMM5 = [B,H]
第3行暂时停留在ymm2
中,因为不需要更改。第4行是通过将ymm2
与自身解包而获得的:
vunpckhpd %ymm2,%ymm2,%ymm6 // YMM5 = [J,*]
第二步是通过混合和交换通道两次来实现的:
vblendpd $0xa,%ymm4,%ymm0 // YMM0 = [A,*]
vblendpd $0xa,%ymm6,%ymm5,%ymm1 // YMM1 = [B,*]
vperm2f128 $0x31,%ymm2 // YMM2 = [C,%ymm3 // YMM3 = [D,*]
这可以通过7条指令实现所需的排列。
请注意,由于这些指令均不需要AVX2,因此该代码将在仅具有AVX的Sandy Bridge处理器上运行。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。