Programming with 64-Bit ARM Assembly Language: Single Board Computer Development for Raspberry Pi and Mobile Devices

Chapter 14: Optimizing Code


2021.08.12: updated by
アルファベットの小文字を大文字に変換するコードを、効率が良いコードに変更する。

Optimizing the Upper-Case Routine

[仮想コード]
IF (W5 >= 'a') AND (W5 <= 'z') THEN
    W5 = W5 - ( 'a' + 'A' )
ENDIF
[Assembly code]
    CMP    W5, #'z'    // if W5 > 'z' goto cont
    B.GT   cont
    CMP    W5, #'a'    // if W5 < 'z' goto cont
    B.LT   cont
    SUB    W5, W5, #('a' - 'A')
cont:

Simplifying the Range Comparison

[仮想コード]
W6 = W5 - 'a'
IF (W6 >= 0) AND (W6 <= ('z'-'a')) THEN
    W5 = W5 - ( 'a' + 'A' )
ENDIF

W6 を unsingned integer で計算すると W6>=0 はいつも成り立つので、最初の比較は必要なくなる。 機械語で2つのレジスタを使う理由は Exercise 1 を見ること。

[自分へのメモ] いや、たとえば'Z'のときに間違うのでは?
[Assembly code] upper.s
// Convert a string to all upper case.
//
// X1 - address of output string
// X0 - address of input string
// X4 - original output string for length calc.
// X5 - current character being processed
// W6 - minus 'a' to compare < 26
.global toupper
toupper:
    MOV    X4, X1
loop:
    LDRB   W5, [X0], #1    // w5 < *(x0++)
    SUB    W6, W5, #'a'    // W6 = W5 - 'a'
    CMP    W6, #25         // if W6 > 25 goto cont
    B.HI   cont
    SUB    W5, W5, #('a'-'A')
cont:
    STRB   W5, [X1], #1
    CMP    W5, #0
    B.NE   loop
    SUB    X0, X1, X4      //length
    RET

Using a Conditional Instruction

branch 命令をなしですますための命令がある。

条件select
    CSEL   Xd, Xn, Xm, cond   // XでもWでもよい
上の命令は下の意味となる。
IF cond is true then
    Xd = Xn
ELSe
    Xd = Xm
ENDIF
または
Xd = cond ? Xn : Xm
条件select increment
    CSINC  Xd, Xn, Xm, cond
IF cond is true then
    Xd = Xn
ELSE
    Xd = Xm + 1
ENDIF
[自分へのメモ] いや、下のコードはたとえば'Z'のときに間違うのでは?
[Assembly code] upper.s
// Convert a string to all upper case.
//
// X1 - address of output string
// X0 - address of input string
// X4 - original output string for length calc.
// X5 - current character being processed
// W6 - minus 'a' to compare < 26
// W6 - char minus 0x20, potential upper-cased
.global toupper
toupper:
    MOV    X4, X1
loop:
    LDRB   W5, [X0], #1    // w5 < *(x0++)
    SUB    W6, W5, #'a'    // W6 = W5 - 'a'
    CMP    W6, #25         // (W5 - 'a') < 25  範囲内
    SUB    W6, W5, #('a'-'A') // W6 <- 大文字変換した結果
    CSEL   W5, W6, W5, LS  // W5 = (W5 - 'a' < 25) ? W6 : W5
    STRB   W5, [X1], #1
    CMP    W5, #0
    B.NE   loop
    SUB    X0, X1, X4      //length
    RET

Restring the Problem Domain

入力データをアルファベットデータに限れば、バイト毎に 1101 1111 とAND計算すればよい。 ARM の命令コードだと BIC (BIt Clear) を使う。BIC W3, @3, #0x20

以下、略


Using Parallelism with SIMD

NEON Coprocessor で16バイトを同時に操作すればよい。

以下、略



http://karel.tsuda.ac.jp/