加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c – std :: vector sum ASM的解释

发布时间:2020-12-16 10:00:43 所属栏目:百科 来源:网络整理
导读:我正在玩 Compiler Explorer,我正在努力理解一个简单的std :: vector int的ASM输出(x86 Clang 3.7 -O3).和函数: #include vector#include numericint sum(const std::vectorint v){ return std::accumulate(v.begin(),v.end(),0);} 此代码的ASM是: sum(std
我正在玩 Compiler Explorer,我正在努力理解一个简单的std :: vector< int>的ASM输出(x86 Clang 3.7 -O3).和函数:

#include <vector>
#include <numeric>

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

此代码的ASM是:

sum(std::vector<int,std::allocator<int> > const&):              # @sum(std::vector<int,std::allocator<int> > 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,%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,%rdx
        cmpq    $24,%r9
        jb      .LBB0_10
        subq    %rdi,%rax
        leaq    112(%rsi,%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,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 const*,std::vector<int,std::allocator<int> > >,int>(__gnu_cxx::__normal_iterator<int const*,__gnu_cxx::__normal_iterator<int const*,int) [clone .exit]
        req

为了比较,ASM具有相同的功能,但使用std :: vector< double>是:

sum(std::vector<double,std::allocator<double> > 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

std :: vector< double>的ASM看起来相当简单,而std :: vector< int>的ASM显得更加复杂.我假设有一些聪明的优化正在进行std :: vector< int>,但我有点亏本来解释发生了什么.有人可以开导我吗?

解决方法

简短回答 – 编译器已经向量化并展开了用于添加整数的循环.比较矢量< double>有这些行的版本:

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

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

向量< int>的主循环中的相同代码版本:

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显示它一次执行16个字节(4个整数)和subq $-128,%rsi显示它在8个负载的单个循环中执行128个字节(或32个int).循环的每次迭代的最终结果将接下来的32个整数添加到xmm0:xmm1中的8个插槽之一

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

然后LBB0_12完成向量末尾的任何整数,主循环无法使用(因为主循环同时在32个整数上运行)

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

矢量化说明:What does vectorization mean?

循环展开的说明:When,if ever,is loop unrolling still useful?

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

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读