当前位置:  开发笔记 > 编程语言 > 正文

使用SIMD内在函数时,这些额外的反汇编指令是什么?

如何解决《使用SIMD内在函数时,这些额外的反汇编指令是什么?》经验,为你挑选了1个好方法。

我正在测试使用SIMU指令和RyuJIT可以得到什么样的加速,我看到了一些我不期望的反汇编指令.我立足代码这个博客帖子从RyuJIT队的凯文·弗雷,以及相关的帖子在这里.这是功能:

static void AddPointwiseSimd(float[] a, float[] b) {
    int simdLength = Vector.Count;
    int i = 0;
    for (i = 0; i < a.Length - simdLength; i += simdLength) {
        Vector va = new Vector(a, i);
        Vector vb = new Vector(b, i);
        va += vb;
        va.CopyTo(a, i);
    }
}

我正在查询的反汇编部分将数组值复制到Vector.大部分的反汇编与Kevin和Sasha的帖子类似,但我强调了一些额外的指令(以及我的混淆注释),这些指令没有出现在他们的反汇编中:

;// Vector va = new Vector(a, i);
  cmp eax,r8d              ; <-- Unexpected - Compare a.Length to i?
  jae 00007FFB17DB6D5F     ; <-- Unexpected - Jump to range check failure
  lea r10d,[rax+3] 
  cmp r10d,r8d 
  jae 00007FFB17DB6D5F 
  mov r11,rcx              ; <-- Unexpected - Extra register copy?
  movups xmm0,xmmword ptr [r11+rax*4+10h  ]

;// Vector vb = new Vector(b, i);
  cmp eax,r9d              ; <-- Unexpected - Compare b.Length to i?
  jae 00007FFB17DB6D5F     ; <-- Unexpected - Jump to range check failure
  cmp r10d,r9d 
  jae 00007FFB17DB6D5F 
  movups xmm1,xmmword ptr [rdx+rax*4+10h]

请注意,循环范围检查符合预期:

;// for (i = 0; i < a.Length - simdLength; i += simdLength) {
  add eax,4  
  cmp r9d,eax  
  jg loop

所以我不知道为什么还有额外的比较eax.任何人都可以解释为什么我看到这些额外的指令,如果有可能摆脱它们.

如果它与项目设置有关,我有一个非常相似的项目,在github上显示相同的问题(请参阅FloatSimdProcessor.HwAcceleratedSumInPlace()UShortSimdProcessor.HwAcceleratedSumInPlaceUnchecked()).



1> Hans Passant..:

我会注释我看到的代码生成,对于支持像Haswell这样的AVX2的处理器,它一次可以移动8个浮点数:

00007FFA1ECD4E20  push        rsi
00007FFA1ECD4E21  sub         rsp,20h  

00007FFA1ECD4E25  xor         eax,eax                       ; i = 0
00007FFA1ECD4E27  mov         r8d,dword ptr [rcx+8]         ; a.Length
00007FFA1ECD4E2B  lea         r9d,[r8-8]                    ; a.Length - simdLength
00007FFA1ECD4E2F  test        r9d,r9d                       ; if (i >= a.Length - simdLength)
00007FFA1ECD4E32  jle         00007FFA1ECD4E75              ; then skip loop 

00007FFA1ECD4E34  mov         r10d,dword ptr [rdx+8]        ; b.Length
00007FFA1ECD4E38  cmp         eax,r8d                       ; if (i >= a.Length)
00007FFA1ECD4E3B  jae         00007FFA1ECD4E7B              ; then OutOfRangeException
00007FFA1ECD4E3D  lea         r11d,[rax+7]                  ; i+7
00007FFA1ECD4E41  cmp         r11d,r8d                      ; if (i+7 >= a.Length)
00007FFA1ECD4E44  jae         00007FFA1ECD4E7B              ; then OutOfRangeException

00007FFA1ECD4E46  mov         rsi,rcx                       ; move a[i..i+7]
00007FFA1ECD4E49  vmovupd     ymm0,ymmword ptr [rsi+rax*4+10h]  

00007FFA1ECD4E50  cmp         eax,r10d                      ; same as above 
00007FFA1ECD4E53  jae         00007FFA1ECD4E7B              ; but for b
00007FFA1ECD4E55  cmp         r11d,r10d  
00007FFA1ECD4E58  jae         00007FFA1ECD4E7B  
00007FFA1ECD4E5A  vmovupd     ymm1,ymmword ptr [rdx+rax*4+10h]  

00007FFA1ECD4E61  vaddps      ymm0,ymm0,ymm1                ; a[i..] + b[i...]
00007FFA1ECD4E66  vmovupd     ymmword ptr [rsi+rax*4+10h],ymm0  

00007FFA1ECD4E6D  add         eax,8                         ; i += 8
00007FFA1ECD4E70  cmp         r9d,eax                       ; if (i < a.Length)
00007FFA1ECD4E73  jg          00007FFA1ECD4E38              ; then loop

00007FFA1ECD4E75  add         rsp,20h  
00007FFA1ECD4E79  pop         rsi  
00007FFA1ECD4E7A  ret  

所以eax比较是博客文章谈到的那些"讨厌的约束检查".博客文章给出了一个尚未实际实现的优化版本,实际代码现在检查同时移动的8个浮点数的第一个和最后一个索引.博客文章的评论"希望,我们将获得足够强大的边界检查淘汰工作"是一项未完成的任务:)

mov rsi,rcx指令也出现在博客文章中,并且似乎是寄存器分配器中的限制.可能受到RCX作为重要寄存器的影响,它通常会存储.我认为,寄存器到寄存器的移动只需要0个周期,因为它们只会影响寄存器重命名,因此不够重要.

注意SSE2和AVX2之间的区别是如何丑陋的,而代码移动并一次添加8个浮点数,它实际上只使用了4个浮点数. Vector.Count无论处理器的味道如何都是4,在桌面上留下2倍的性能.我猜,很难隐藏实现细节.

推荐阅读
mobiledu2402851373
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有