[仮想コード] 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:
[仮想コード] 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
branch 命令をなしですますための命令がある。
条件selectCSEL 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
入力データをアルファベットデータに限れば、バイト毎に 1101 1111 とAND計算すればよい。 ARM の命令コードだと BIC (BIt Clear) を使う。BIC W3, @3, #0x20
以下、略
NEON Coprocessor で16バイトを同時に操作すればよい。
以下、略