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

Dav*_*ice 1 64-bit x86 assembly 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
    
    Run Code Online (Sandbox Code Playgroud)
  2. 在任何位置都有4次加倍

    i.e. i want to load for example 1, 6, 22, 43
    
    Run Code Online (Sandbox Code Playgroud)

zx4*_*485 5

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

VGATHERQPD ymm1, [rsi+xmm7*8], ymm2
Run Code Online (Sandbox Code Playgroud)

使用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
Run Code Online (Sandbox Code Playgroud)

现在ymm0包含4个双打0,10,20,30.虽然,我还没有测试过.另外需要提及的是,这不一定是每种情况下最快的选择.这些值都是单独收集的,也就是说,每个值都需要一次内存访问,请参阅如何实现AVX2中的收集指令

所以根据Mysticial的评论

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

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

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

编辑:根据评论VGATHER,Broadwell和Skylake 的指令变得更快.