通过例子学习汇编(二)

        话不多说,接着干!!!

案例二;

        实现一个函数进行前n项和计算。

#include <stdio.h>
#include <stdlib.h>

int sum_(const int n){
        int sum=0;
        for(int i=0;i<n;i++){
                sum+=i;
        }
        return sum;
}

int main(){

        const int N=10;

        int sum=sum_(N);

        printf("sum=%d\n",sum);

        return 0;
}

        使用编译命令生成汇编代码

-O0

        gcc -S -O0 sum.c

        .arch armv8-a
        .file   "sum.c"
        .text
        .align  2
        .global sum_
        .type   sum_, %function
sum_:
        sub     sp, sp, #32    //开辟32个字节来保存局部变量
        str     w0, [sp, 12]    //将寄存器w0中的变量(函数传入参数)存储在栈偏移12字节的位置,也就是传入参数n
        str     wzr, [sp, 24]   //将零寄存器中的值(0)存储在栈偏移为24的位置,其实存储的就是c代码中的sum变量的值
        str     wzr, [sp, 28]   //将零寄存器中的值(0)存储在栈偏移28的的位置,存储的是c代码中i的值
        b       .L2   //无条件跳转到.L2
.L3:
        ldr     w1, [sp, 24]
        ldr     w0, [sp, 28]  //这两句是将占中的两个局部变量值sum和i加载到寄存器中
        add     w0, w1, w0    //计算sum+=i
        str     w0, [sp, 24]  //将计算结果保存
        ldr     w0, [sp, 28]  
        add     w0, w0, 1       
        str     w0, [sp, 28]  //这三句是将i+1,然后保存
        //.L3的代码是进行sum+=i
.L2:
        ldr     w1, [sp, 28]
        ldr     w0, [sp, 12]  //加载寄存器中两个局部变量的值i和n
        cmp     w1, w0        //判断比较
        blt     .L3            //blt表示跳转到.L3并返回,然后继续循环
        ldr     w0, [sp, 24]  //循环结束后,从栈中加载计算结果到w0
        add     sp, sp, 32    //然后释放掉当前函数局部变量所占用的占空间
        ret
        .size   sum_, .-sum_
        .section        .rodata
        .align  3
.LC0:
        .string "sum=%d\n"
        .text
        .align  2
        .global main
        .type   main, %function
main:
        stp     x29, x30, [sp, -32]!
        add     x29, sp, 0
        mov     w0, 10
        str     w0, [x29, 24]
        ldr     w0, [x29, 24]
        bl      sum_
        str     w0, [x29, 28]
        adrp    x0, .LC0
        add     x0, x0, :lo12:.LC0
        ldr     w1, [x29, 28]
        bl      printf
        mov     w0, 0
        ldp     x29, x30, [sp], 32
        ret
        .size   main, .-main
        .ident  "GCC: (Ubuntu/Linaro 7.5.0-3ubuntu1~18.04) 7.5.0"
        .section        .note.GNU-stack,"",@progbits

-O3

        gcc -S -O3 sum.c

sum_:
        mov     w2, w0
        cmp     w0, 0
        ble     .L7
        sub     w0, w0, #1
        cmp     w0, 4
        bls     .L8
        adrp    x1, .LC0
        lsr     w0, w2, 2
        movi    v0.4s, 0
        movi    v2.4s, 0x4
        ldr     q1, [x1, #:lo12:.LC0]
        mov     w1, 0
        .p2align 3
.L4:
        add     v0.4s, v0.4s, v1.4s
        add     w1, w1, 1
        add     v1.4s, v1.4s, v2.4s
        cmp     w1, w0
        bcc     .L4
        addv    s0, v0.4s
        and     w1, w2, -4
        cmp     w2, w1
        umov    w0, v0.s[0]
        beq     .L1
.L3:
        add     w3, w1, 1
        add     w0, w0, w1
        cmp     w2, w3
        ble     .L1
        add     w4, w1, 2
        add     w0, w0, w3
        cmp     w4, w2
        bge     .L1
        add     w3, w1, 3
        add     w0, w0, w4
        cmp     w2, w3
        ble     .L1
        add     w0, w0, w3
        add     w1, w1, 4
        add     w3, w0, w1
        cmp     w2, w1
        csel    w0, w3, w0, gt
.L1:
        ret
        .p2align 2
.L7:
        mov     w0, 0
        ret
        .p2align 2
.L8:
        mov     w1, 0
        mov     w0, 0
        b       .L3
        .size   sum_, .-sum_
        .section        .rodata.cst16,"aM",@progbits,16
        .align  4

        老实说,开了O3优化后的汇编好多都看不明白呜呜呜。

        但有一个地方可以看出来,因为学了一点点neon intrinsic编程哈哈哈哈哈哈。

        add     v0.4s, v0.4s, v1.4s
        add     w1, w1, 1
        add     v1.4s, v1.4s, v2.4s

        这里很肯定的说使用了neon寄存器。一个neon寄存器是128位,处理的数据时int类型,所以一个neon寄存器可以同时处理4个int型数据。所以很明显,开了O3级别优化,编译器自动的使用了neon实现SIMD并行处理数据了。

另外,我以为对for循环进行4个一组的循环展开可能会使编译器自动使用neon进行优化,但不开O3的时候编译器并没有自动优化。而是他也直接展开(裂开。。)

.L3:
        ldr     w1, [sp, 24]
        ldr     w0, [sp, 28]
        add     w0, w1, w0
        str     w0, [sp, 24]
        ldr     w0, [sp, 28]
        add     w0, w0, 1
        ldr     w1, [sp, 24]
        add     w0, w1, w0
        str     w0, [sp, 24]
        ldr     w0, [sp, 28]
        add     w0, w0, 2
        ldr     w1, [sp, 24]
        add     w0, w1, w0
        str     w0, [sp, 24]
        ldr     w0, [sp, 28]
        add     w0, w0, 3
        ldr     w1, [sp, 24]
        add     w0, w1, w0
        str     w0, [sp, 24]
        ldr     w0, [sp, 28]
        add     w0, w0, 4
        str     w0, [sp, 28]

        感觉学习的不多,希望有对这方面了解的大佬和小伙伴可以评论交流啊,互相学习鸭!

  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值