計算機按照嚴格的順序執行指令。流控制改變了默認的順序執行方式。前面已
經介紹了強制跳轉到程序中某個非順序位置的無條件分支。以及依據測試結果
進行跳轉的條件分支。這里將介紹子程序調用和返回指令,它們會跳轉到一個
指令塊、執行這些指令,然后返回到子程序調用指令后的一個位置來修改控制
流。
無條件分支
ARM無條件分支指令格式為B target,target指分支目標地址(branch target
address,BTA)。
下面代碼說明了如何使用無條件分支指令:
… do this ; 一些代碼
… then that ; 另一些代碼
B Next ; 跳過下面的指令
… ; …被略過的代碼
… ; …被略過的代碼
Next … ; 分支目標地址,由標號Next表示
在高級語言中,無條件分支叫作goto,它被認為是一種比較糟糕的編程風格。
然而,在匯編語言中,無條件分支是很難避免的。
條件分支
下面給出了高級語言中實現條件行為的典型例子:
IF(X == Y)
THEN Y = Y + 1
ELSE Y = Y + 2
ARM匯編語言表示:
CMP r1,r2 ; 假設r1包括y,r2包括x,將它們比較
BNE plus2 ; 如果不相等則跳轉到ELSE部分
ADD r1,r1,#1 ; 如果相等則繼續,y加1
B leave ; 現在跳過ELSE部分
plus2 ADD r1,r2,#2 ; ELSE部分,y加2
leave … ; 從這里繼續
條件分支指令測試處理器中條件碼寄存器中的標志位,如果測試結果為真則轉移成功
ARM有4條測試與比較指令CMP、CMN、TST、TEQ,這些指令會顯式更新條件
碼標志,因此無需在指令后添加S
相等測試指令TEQ
確定兩個操作數是否相等,如果相等將Z位置1,否則將Z位清0
如,指令TEQ r1,r2完成RTL操作[r1] – [r2],如果r1和r2相等,Z位被置1。
TEQ與CMP指令類似,測試時TEQ不影響溢出標志的狀態而僅修改Z位。相反地,
CMP會更新溢出標志。
比較指令CMP
用第一個源操作數減去第二個,然后更新條件碼。
如,指令CMP r1,r2計算[r1] – [r2],然后設置CPSR中的N、Z、C和V位。
測試指令TST
通過與操作來比較兩個操作數,然后根據結果更新標志位。可以用TST來測試一個字中的每一位。
如,由于小寫ASCII字母的第5位為1,所以通過下面的代碼來判斷r0中的ASCII字母是否為小寫字母:
TST r0,#2_00100000 ; r0與00100000進行與操作,測試第5位的狀態
BEQ LowerCase ; 如果第5位為1則跳轉到小寫字母處理部分
取負并比較指令CMN
在進行比較操作之前先將第二個源操作數取負。
如,指令CMN r1,r2計算[r1] - [-r2],然后設置CPSR。注意[r1] - [-r2]的值與[r1] +
[r2]的相同。
分支與循環結構
用經典的循環結構來介紹流控制概念是最合適的,循環是結構化編程的核心。
下面代碼說明了FOR、WHILE和UNTIL循環的結構
for
MOV r0,#10 ; 設置循環計數器
Loop code … ; 循環體SUBS r0,r0,#1 ; 循環計數器減1并設置狀態標志BNE Loop ; 繼續直到計數值為0——不為0時跳轉Post loop ; 計數值為0的后續代碼
while
Loop CMP r0,#0 ; 循環開始執行測試BEQ WhileExit ; 測試結果為true則退出code … ; 循環體B Loop ; 為true時重復
WhileExit Post loop … ; 退出
until
Loop code … ; 循環體CMP r0,#0 ; 循環末尾進行測試BNE Loop ; 重復直到UNTIL為truePost loop … ; 退出
組合循環
組合循環將上面3中循環的特點結合在一起。
FOR部分指定了最大計數值,限制了循環的執行次數。
WHILE部分測試r1中的初始條件,如果條件不為true則立即退出。
UNTIL部分則在循環體末尾r2為true時退出。
MOV r0,#10 ; 設置循環計數器
LoopStart CMP r1,#0 ; 以WHILE測試開始
BEQ ComboExit ; 為true退出循環
code … ; 循環體
CMP r2,#0 ; 測試UNTIL條件
BEQ ComboExit ; 為true退出循環
SUBS r0,r0,#1 ; 循環計數器減1并設置狀態標志
BNE LoopStart ; 繼續直到計數器為0——不為0則轉移
ComboExit Post loop … ; 退出
條件執行
匯編語言程序員在指令助記符后添加合適的條件以指明條件執行模式
如:ADDEQ r1,r2,r3
指定僅當條件碼中的Z位因為前一個結果為0而被置為1時,加法操作才會被執行。
其RTL形式為:IF Z = 1
THEN [r1] <- [r2] + [r3]
條件執行和移位操作可以組合在一起,因為指令中的分支和移位字段是無關的
如:ADDCC r1,r2,r3 LSL r4
其RTL形式為:IF C = 0
THEN [r1] <- [r2] + [r3] X 2[r4]
ARM的條件執行模式使得在高級語言中實現條件操作更容易。
(1)考慮下面的C代碼段:
If(P == Q)
X = P – Y;
如果r1為P,r2為Q,r3為X,r4為Y,則可以寫為:
CMP r1,r2 ; 比較P == Q
SUBEQ r3,r1,r4 ; 為true則r3 = r1 - r4,為false,減法被轉換為空操作
考慮一個更復雜例子,一個帶有組合條件的C代碼段:
If((a == b) && (c == d))
e++;
可以寫為:
CMP r0,r1 ; 比較a == b
CMPEQ r2,r3 ; 如果a == b,則比較c == d
ADDEQ r4,r4,#1 ; 如果a == b且c == d,則e加1
不使用條件執行,則可寫為:CMP r0,r1 ; 比較a == bBNE Exit ; a !=b則退出CMP r2,r3 ; 比較c == dBNE Exit ; c!=d則退出ADD r4,r4,#1 ; 否則e加1
Exit
處理一些帶有多個條件的C代碼段:
If(a == b) e = e + 4;
If (a < b) e = e + 7;
If(a > b) e = e + 12;
可以寫為:CMP r0,r1 ; 比較a == bADDEQ r4,r4,#4 ; 如果a == b,則e = e + 4ADDLE r4,r4,#7 ; 如果a < b,則e = e + 7ADDGT r4,r4,#12 ; 如果a > b,則e = e + 12
不使用條件執行,則可寫為:
CMP r0,r1 ; 比較a == bBNE Test1 ; 不相等則跳轉到Test1進行下一次測試ADD r4,r4,#4 ; a ==b,則e = e + 4B ExitAll ; 退出
Test1 BLT Test2 ; 如果a < b,則跳轉到Tset2ADD r4,r4,#12 ; 此處a > b,因此e = e + 12B ExitAll ; 退出
Test2 ADD r4,r4,#7 ; 此處a < b,因此e =e + 7
ExitAll