決定とループ

決定とループ

デフォルトでは、CPUは命令を上から下へと現れる順に実行します。その順序だけでは、選択を行ったり作業を繰り返したりすることはできません。分岐とは、プログラムがその一直線の道から外れる方法です。条件をテストし、条件が成立したとき、CPUを次の行ではなく別の場所から続行するように導きます。すべての決定とすべてのループは、この一つの仕組みから生まれます。

if や for はありません。それらはラベル(名前付きの位置)と分岐(条件が成立したときに位置へジャンプする)から構築します。ラベルは名前の後に : が続くものです。

分岐がどのように実行されるかを理解するには、プログラムカウンタ(PC)について知る必要があります。PCは、コードからは見えない特別なレジスタで、実行中の命令のメモリアドレスを保持します。分岐命令はPCに新しい値を書き込むため、CPUは次の命令をコードの次の行ではなく、ターゲットラベルからフェッチします。

分岐ファミリー

すべての分岐は2つのレジスタを比較し、テストが成立したときだけラベルにジャンプします。テストが失敗したときは、実行は次の行に続きます。6つのテストが核心を形成します:

6つの実際のブランチ
beq a, b, label # a == bなら分岐
bne a, b, label # a != bなら分岐
blt a, b, label # a < bなら分岐 (符号あり)
bge a, b, label # a >= bなら分岐 (符号あり)
bltu a, b, label # a < bなら分岐 (符号なし)
bgeu a, b, label # a >= bなら分岐 (符号なし)

と は等価性をテストし、符号を無視します。 と は順序のペア、より小さいとより大きいか等しいを形成し、レジスタを符号付き数として比較します。 と は同じ比較を行いますが、値を符号なしとして扱います。これは負にならないアドレスやカウントに適しています。

符号付きと符号なしとはどういう意味でしょうか?レジスタは32ビットを保持し、同じビットを2通りに読むことができます。符号なしとして読むと、0から約40億までの単純な整数を形成します。符号付きとして読むと、最上位ビットがマイナス記号として数えられるため、ビットパターンの半分は負の数を表します。ビット自体は変わりません。変わるのは読み方だけです。だからこそ2組の比較があるのです。負になる可能性のある通常の数には符号付き(、)を使い、メモリアドレスのように決して負にならない値には符号なし(、)を使います。

直接の「より大きいなら分岐」や「より小さいか等しいなら分岐」はありません。それらは2つのレジスタを交換することで得られ、アセンブラは交換を代行する疑似分岐として と を提供します。したがって は になります。さらに2つのショートカット: と は1つのレジスタをゼロと比較し、 は条件なしでジャンプします。

ループで1から5までの合計を計算
li t0, 0 # 合計 = 0
li t1, 1 # i = 1
li t2, 6 # 上限 = 6 (i < 6の間ループ)
loop:
bge t1, t2, done # i >= 6でループを抜ける
add t0, t0, t1 # 合計 += i
addi t1, t1, 1 # i++
j loop # 再びチェックしに戻る
done:
mv a0, t0 # 合計を出力 (15になるはず)
li a7, 1
ecall
li a7, 10
ecall

追跡してみましょう。t0 は実行中の合計を保持し(0から開始)、t1 はカウンタ i を保持し(1から開始)、t2 は上限6を保持します。loop を通過するたびに: は i が6に達するとループを抜けます。そうでなければ が i を合計に加え、 が i を1増やし、 が再びテストするためにジャンプします。ループは1、2、3、4、5を加え、done が合計15を出力します。

分岐のあるループ
loop:
bge t1, t2, done
add t0, t0, t1
addi t1, t1, 1
j loop
i (t1)1
sum (t0)0
yesnot1 < 6?sum += t1t1 += 1done

bge は t1 と t2 を比較して、ループを継続するかどうかを決定します。

以下の図は、カウンタを更新する命令と実行中の合計を更新する命令を示し、ループの残りから区別しています。 はカウンタを進め、それに続く は新しいカウンタ値を合計に加えます。最後のフレームはループを終了させるテストを示しています。t1 が6になると、 は本体を再び実行させるのではなく、制御を done に移します。そのテストが、繰り返すパスと停止するパスを分けるものです。
💡
RunではなくStepでプログラムを進めてください。進むにつれて t1 が増加し、プログラムカウンタ(pc)が loop にジャンプして戻ります。pc が loop に戻るたびに、分岐条件は偽だったので、ループは再び実行されます。
⚠
終了条件が間違っていると、ループは決して終わりません。シミュレータは暴走ループを停止しますが、分岐ロジックはあなたが正しくするものです。