加载x64 ymm寄存器的最有效方法是什么
-
4 个均匀分布的双打,即一组连续的双打
0 1 2 3 4 5 6 7 8 9 10 .. 100 And i want to load for example 0, 10, 20, 30
-
任何位置4次双打
i.e. i want to load for example 1, 6, 22, 43
最简单的方法是VGATHERQPD,它是Haswell及更高版本可用的AVX2指令。
VGATHERQPD ymm1, [rsi+xmm7*8], ymm2
使用 vm32x 中指定的 dword 索引,从以 ymm2 指定的掩码为条件的内存中收集双倍预置 FP 值。有条件收集的元素合并到 ymm1 中。
这可以通过一个指令来实现这一点。这里ymm2
是掩码寄存器,最高位指示是否应将值复制到ymm1
(保持不变(。 ymm7
包含具有比例因子的元素的索引。
因此,应用于您的示例,它在 MASM 语法中可能如下所示:
4 个均匀分布的双打,即一组连续的双打
0 1 2 3 4 5 6 7 8 9 10 .. 100 --- 我想加载例如 0、10、20、30
.data
.align 16
qqIndices dq 0,10,20,30
dpValues REAL8 0,1,2,3, ... 100
.code
lea rsi, dpValues
movapd ymm7, qqIndices
vpcmpeqw ymm1, ymm1 ; set to all ones
vgatherqpd ymm0, [rsi+xmm7*8], ymm1
现在ymm0
包含四个双打 0、10、20、30。不过,我还没有测试过这个。另一件值得一提的事情是,这不一定是每种情况下最快的选择。这些值都是单独收集的,这意味着每个值都需要一次内存访问,请参阅 AVX2 中的收集指令是如何实现
所以根据神秘客的评论
我最近不得不做一些需要真正收集负载的事情。(即数据[索引[i]](。在哈斯韦尔,
4 index loads + 2x movsd + 2x movhpd + vinsertf128
仍然比ymm load + vgatherqpd
快得多。因此,即使在最好的情况下,4 向聚集仍然会失败。不过我还没有尝试过 8 向收集。
最快的方法是使用这种方法。
因此,OpCode方式的"高效"将使用VGATHER
,而与执行时间相关的"高效"将是最后一个(到目前为止,让我们看看未来的架构将如何表现(。
编辑:根据评论,VGATHER
指令在布罗德韦尔和Skylake上变得更快。
我认为你必须寻找像VGATHERQPD这样的GATHER操作。
该指令有条件地从内存操作数(第二个操作数(指定的内存地址并使用 qword 索引加载最多 2 或 4 个双精度浮点值。内存操作数使用 SIB 字节的 VSIB 形式将通用寄存器操作数指定为公共基数、相对于基数的索引数组的向量寄存器和恒定比例因子。
请注意,这需要 AVX2,因此不适用于具有 AVX 但不是 AVX2 的桑迪桥/常春藤桥。