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

std :: vector <int>和ASM的解释

如何解决《std::vector<int>和ASM的解释》经验,为你挑选了1个好方法。

我正在玩Compiler Explorer,我很难理解简单std::vector求和函数的ASM输出(x86 Clang 3.7 -O3):

#include 
#include 

int sum(const std::vector& v)
{
    return std::accumulate(v.begin(), v.end(), 0);
}

此代码的ASM是:

sum(std::vector > const&):              # @sum(std::vector > const&)
        movq    (%rdi), %rsi
        movq    8(%rdi), %r11
        xorl    %eax, %eax
        cmpq    %r11, %rsi
        je      .LBB0_13
        movabsq $9223372036854775800, %rax # imm = 0x7FFFFFFFFFFFFFF8
        leaq    -4(%r11), %rdx
        movq    %rdx, %r10
        subq    %rsi, %r10
        shrq    $2, %r10
        incq    %r10
        xorl    %edi, %edi
        movq    %r10, %r8
        andq    %rax, %r8
        pxor    %xmm0, %xmm0
        je      .LBB0_2
        andq    %r10, %rax
        leaq    -8(%rax), %r9
        movl    %r9d, %ecx
        shrl    $3, %ecx
        incl    %ecx
        xorl    %edi, %edi
        testb   $3, %cl
        je      .LBB0_4
        subl    %esi, %edx
        shrl    $2, %edx
        incl    %edx
        andl    $24, %edx
        addl    $-8, %edx
        shrl    $3, %edx
        incl    %edx
        andl    $3, %edx
        negq    %rdx
        pxor    %xmm0, %xmm0
        xorl    %edi, %edi
        pxor    %xmm1, %xmm1
.LBB0_6:                                # %vector.body.prol
        movdqu  (%rsi,%rdi,4), %xmm2
        movdqu  16(%rsi,%rdi,4), %xmm3
        paddd   %xmm2, %xmm0
        paddd   %xmm3, %xmm1
        addq    $8, %rdi
        incq    %rdx
        jne     .LBB0_6
        jmp     .LBB0_7
.LBB0_2:
        pxor    %xmm1, %xmm1
        jmp     .LBB0_11
.LBB0_4:
        pxor    %xmm0, %xmm0
        pxor    %xmm1, %xmm1
.LBB0_7:                                # %vector.body.preheader.split
        leaq    (%rsi,%r8,4), %rdx
        cmpq    $24, %r9
        jb      .LBB0_10
        subq    %rdi, %rax
        leaq    112(%rsi,%rdi,4), %rsi
.LBB0_9:                                # %vector.body
        movdqu  -112(%rsi), %xmm2
        movdqu  -96(%rsi), %xmm3
        movdqu  -80(%rsi), %xmm4
        movdqu  -64(%rsi), %xmm5
        paddd   %xmm0, %xmm2
        paddd   %xmm1, %xmm3
        paddd   %xmm4, %xmm2
        paddd   %xmm5, %xmm3
        movdqu  -48(%rsi), %xmm4
        movdqu  -32(%rsi), %xmm5
        paddd   %xmm2, %xmm4
        paddd   %xmm3, %xmm5
        movdqu  -16(%rsi), %xmm0
        movdqu  (%rsi), %xmm1
        paddd   %xmm4, %xmm0
        paddd   %xmm5, %xmm1
        subq    $-128, %rsi
        addq    $-32, %rax
        jne     .LBB0_9
.LBB0_10:
        movq    %rdx, %rsi
        movq    %r8, %rdi
.LBB0_11:                               # %middle.block
        paddd   %xmm1, %xmm0
        pshufd  $78, %xmm0, %xmm1       # xmm1 = xmm0[2,3,0,1]
        paddd   %xmm0, %xmm1
        pshufd  $229, %xmm1, %xmm0      # xmm0 = xmm1[1,1,2,3]
        paddd   %xmm1, %xmm0
        movd    %xmm0, %eax
        cmpq    %rdi, %r10
        je      .LBB0_13
.LBB0_12:                               # %.lr.ph.i
        addl    (%rsi), %eax
        addq    $4, %rsi
        cmpq    %rsi, %r11
        jne     .LBB0_12
.LBB0_13:                               # %int std::accumulate<__gnu_cxx::__normal_iterator > >, int>(__gnu_cxx::__normal_iterator > >, __gnu_cxx::__normal_iterator > >, int) [clone .exit]
        req

为了比较,使用相同功能的ASM std::vector是:

sum(std::vector > const&):
        movq    8(%rdi), %rdx
        movq    (%rdi), %rax
        pxor    %xmm0, %xmm0
        cmpq    %rax, %rdx
        je      .L4
.L3:
        addsd   (%rax), %xmm0
        addq    $8, %rax
        cmpq    %rax, %rdx
        jne     .L3
        rep ret
.L4:
        rep ret

ASM std::vector似乎相当微不足道,而ASM std::vector似乎显得更加复杂.我假设有一些聪明的优化正在进行std::vector,但我有点不知道解释发生了什么.有人可以开导我吗?



1> Mike Vine..:

简短的回答 - 编译器已经向量化并展开了用于添加整数的循环.比较vector具有以下行的版本:

addsd   (%rax), %xmm0
addq    $8, %rax

这意味着它在总和中添加一个double,然后在8个字节上移动并循环.

vector版本主循环中的相同代码可以:

movdqu  -112(%rsi), %xmm2
movdqu  -96(%rsi), %xmm3
movdqu  -80(%rsi), %xmm4
movdqu  -64(%rsi), %xmm5
...
movdqu  -48(%rsi), %xmm4
movdqu  -32(%rsi), %xmm5
...
movdqu  -16(%rsi), %xmm0
...
movdqu  (%rsi), %xmm1
...
subq    $-128, %rsi

所述movdq显示其在一次(4个整数)做16个字节和subq $-128, %rsi显示其在跨越8个负载单个环路做128个字节(或32个整数).循环的每次迭代的最终结果将接下来的32个整数添加到xmm0:xmm1中的8个插槽之一

LBB0_11 然后获取主循环的输出(跨越xmm0和xmm1的8个整数)并找到它们的总和.

LBB0_12 然后在向量的末尾完成任何不能被主循环消耗的整数(因为主循环同时在32个整数上工作)

它会对添加进行矢量化,因此它可以同时处理4个整数,这通常比一次执行一个整数更快.它还会展开循环,以便每循环添加多次迭代.

矢量化的解释:矢量化是什么意思?

循环展开的解释:如果有的话,循环展开仍然有用吗?

我没有分析整数情况的代码的开始,但通常这是通过在启动主循环之前将其对齐到16字节边界来设置循环.


注意,对于`std :: vector `,使用编译器选项`-ffast-math`会发生类似的事情.
推荐阅读
个性2402852463
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有