Androidに従ってARM v 8 aの世界に入る(1)-例から言えば

3937 ワード

Androidに従ってARM v 8 aの世界に入る
例から言えば
現在Androidで動作しているARMチップには、6セットの命令セット、32ビットのARM v 5命令セット、16ビットのthumb命令セット、32ビットのARM v 7 a命令セット、16ビットと32ビットが混在するthumb 2命令セット、32ビットのARM v 7 aにNeon付き命令セット、64ビットのARM v 8 a命令セットがあります.16ビットのThumb命令セットは不完全な命令セットであり,ARM命令と混成しなければすべての機能を完成できない.
まず古典に敬意を表し、最大公約数を求めるコードを見てみましょう.
Cコードはこうです.
unsigned int gcd(unsigned int a, unsigned int b){
    while(a!=b){
        if(a>b){
            a-=b;
        }else{
            b-=a;
        }
    }
    return a;
}

手書きのアセンブリはこうです.
.global gcd_asm
.func gcd_asm

gcd_asm:
    cmp r0,r1
    subgt r0,r0,r1
    sublt r1,r1,r0
    bne gcd_asm
    bx lr
.endfunc
.end

上記のコマンドを説明します:cmp r 0,r 1:r 0-r 1の減算を1回行い、結果に応じてCPSRの値を設定します.r 0-r 1が0である場合、CPSRにおいて0と示すZ位置1、そうでない場合は0とする.r 0-r 1>0の場合、負数を表すNビットlは0に、r 0-r 1<0の場合、その位置1となる.SUBは減算命令、GTとLTは条件実行命令です.SUBGTはGT、すなわちそれ以上の条件で減算を実行し、同様に、SUBLTはそれ以下の場合に減算を実行する.BNEはZマークがセットされていない状態でジャンプします.BXは、関数の戻りに使用される切り替えジャンプです.
次にgccが私たちのためにどのようなアセンブリコードを編成したかを見てみましょう.ARM v 5のARMモードの指令は、
00000fd8 :
     fd8:   e1500001    cmp r0, r1
     fdc:   012fff1e    bxeq    lr
     fe0:   e1500001    cmp r0, r1
     fe4:   80610000    rsbhi   r0, r1, r0
     fe8:   90601001    rsbls   r1, r0, r1
     fec:   e1510000    cmp r1, r0
     ff0:   1afffffa    bne fe0 
     ff4:   e12fff1e    bx  lr

各命令は32ビット長であることがわかります.BXEQ LR、前節で説明したBXですが、EQは条件実行です.r 0とr 1が等しい場合に返される.そしてもう一度cmpを作ります.RSBは逆減算であり,RSB a b cはa=c−bに相当する.一方、SUB a b cは、a=b−c HIに相当し、LSは符号なし数よりも大きい.だからRSBHIとRSBLSは以前のSUBGTとSUBLTと本質的に違いはありません.BNEとBXは前と同じで、あまり説明しません.
ARM v 7 aのARMモードの指令は、
00000c7c :
     c7c:   e1500001    cmp r0, r1
     c80:   012fff1e    bxeq    lr
     c84:   e1500001    cmp r0, r1
     c88:   80610000    rsbhi   r0, r1, r0
     c8c:   90601001    rsbls   r1, r0, r1
     c90:   e1510000    cmp r1, r0
     c94:   1afffffa    bne c84 
     c98:   e12fff1e    bx  lr

論理が単純すぎてARM v 7 a命令セットの優位性が発揮できないため、ARM v 5と同じである.
Thumb命令はこうです.
00000fd0 :
     fd0:   b500        push    {lr}
     fd2:   4288        cmp r0, r1
     fd4:   d004        beq.n   fe0 
     fd6:   d901        bls.n   fdc 
     fd8:   1a40        subs    r0, r0, r1
     fda:   e7fa        b.n fd2 
     fdc:   1a09        subs    r1, r1, r0
     fde:   e7f8        b.n fd2 
     fe0:   bd00        pop {pc}

命令は全16ビットであることがわかります.16ビット長指令の制限でSUB指令はこれ以上条件が作れないので、追加の比較とジャンプ指令が必要です.Thumb 2命令はこうです.
00000c6c :
     c6c:   4288        cmp r0, r1
     c6e:   d005        beq.n   c7c 
     c70:   bf8c        ite hi
     c72:   ebc1 0000   rsbhi   r0, r1, r0
     c76:   ebc0 0101   rsbls   r1, r0, r1
     c7a:   e7f7        b.n c6c 
     c7c:   4770        bx  lr

16位と32位が混在していることがわかります.比較して、ジャンプなどは16ビット命令で、減算はまたARM 32命令を運び出しました.
最後に、ARM 64 v 8-aが出馬した.まず手書きがどんなものか見てみましょう.
.global gcd_asm
.func gcd_asm

gcd_asm:
    subs w2, w0, w1
    csel w0, w2, w0, gt
    csneg w1, w1, w2, gt
    bne gcd_asm
    ret
.endfunc
.end

cselは後の条件に基づいてどのように値を割り当てるかを決定し,GTであればw 0=w 2,そうでなければw 0=w 0である.Csnegはcselに基づいて,条件が合わなければ3番目のパラメータの逆をとる.Csneg w 1,w 1,w 2,gtは,GTであればw 1=w 1,そうでなければw 1=−w 2に相当する.
注意、オペランドは64ビットになりましたが、指令長は32ビットですね.
0000000000000504 :
 504:   6b01001f    cmp w0, w1
 508:   2a0003e2    mov w2, w0
 50c:   54000140    b.eq    534 
 510:   6b01005f    cmp w2, w1
 514:   4b010040    sub w0, w2, w1
 518:   1a828000    csel    w0, w0, w2, hi
 51c:   4b020023    sub w3, w1, w2
 520:   6b01005f    cmp w2, w1
 524:   2a0003e2    mov w2, w0
 528:   1a838021    csel    w1, w1, w3, hi
 52c:   6b00003f    cmp w1, w0
 530:   54ffff01    b.ne    510 
 534:   d65f03c0    ret