使用4个单独的双倍加载x64 ymm寄存器的有效方法是什么?

时间:2016-02-12 06:54:01

标签: assembly x86 64-bit x86-64 simd

使用

加载x64 ymm寄存器的最有效方法是什么
  1. 4个均匀间隔的双倍,即一组连续的双打

    0  1  2  3  4  5  6  7  8  9 10 .. 100
    And i want to load for example 0, 10, 20, 30
    
  2. 在任何位置加倍4次

    i.e. i want to load for example 1, 6, 22, 43
    

2 个答案:

答案 0 :(得分:5)

最简单的方法是VGATHERQPD,它是Haswell及以上的AVX2指令。

VGATHERQPD ymm1, [rsi+xmm7*8], ymm2
  

使用vm32x中指定的双向索引,从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包含4个双打0,10,20,30。 虽然,我还没有测试过。另外需要提及的是,这不一定是每种情况下最快的选择。这些值都是单独收集的,也就是说,每个值都需要一次内存访问,请参阅How are the gather instructions in AVX2 implemented

所以根据Mysticial's comment

  

我最近不得不做一些需要真正聚集负载的事情。 (即数据[index [i]])。在Haswell上,4 index loads + 2x movsd + 2x movhpd + vinsertf128仍然明显快于ymm load + vgatherqpd。所以即使在最好的情况下,4路聚集仍然会失败。我没有试过8路聚会。

最快的方法是使用这种方法。

OpCode方式中的“高效”将使用VGATHER,与执行时间相关的“高效”将是最后一个(到目前为止,让我们看看未来的架构将如何执行)。

编辑:根据评论,VGATHER指令在Broadwell和Skylake上的速度更快。

答案 1 :(得分:1)

我认为您必须寻找像VGATHERQPD这样的GATHER操作。

该指令有条件地从内存操作数(第二个操作数)指定的内存地址加载最多2或4个双精度浮点值,并使用qword索引。内存操作数使用SIB字节的VSIB形式指定通用寄存器操作数作为公共基数,相对于基数的索引数组的向量寄存器和常量比例因子。

请注意,这需要AVX2,因此不适用于具有AVX但不支持AVX2的Sandy Bridge / Ivy Bridge。