ベクトル:位置によるインデックス付け
ベクトルとは配列のことです。メモリ上で隣り合って格納された数値の並びです。前のレッスンでは、各要素ごとにポインタを4バイト進めながら合計を求めました。同じ方法がここでも使えます。要素に到達するもう一つの一般的な方法があります。それはインデックスによる方法です。インデックスとは、先頭から数えた要素の位置であり、最初の要素のインデックスは0、2番目は1、というように続きます。
ポインタを進めてベクトルを合計する
.dataa: .word 5, 10, 15, 20 # 4要素.textla t0, a # t0 = aのアドレスli t1, 4 # t1 = 残りの要素数li t2, 0 # t2 = 累計loop:beq t1, zero, donelw t3, 0(t0) # 現在の要素を読み込むadd t2, t2, t3 # 合計に加えるaddi t0, t0, 4 # 次のワードへ進む (4バイト)addi t1, t1, -1 # 残り1つ減るj loopdone:mv a0, t2 # 合計を出力: 5+10+15+20 = 50li a7, 1ecallli a7, 10ecall
ループは次のように動作します。t0はaのアドレスを保持し、t1は残りの要素数を保持し、4から始まります。各パスで、はカウントがゼロになったときにループを終了します。はt0のアドレスにある要素をロードします。はその値を累計に加算します。はポインタを次のワードに進めます。はカウントを減らします。4回のパスの後(5 + 10 + 15 + 20)、doneは50を出力します。これはメモリのレッスンで使われたのと同じパターンであり、今度はベクトルに適用されています。
インデックスからアドレスへ
インデックス計算は、ベースポインタと位置からアドレスを計算します。address = base + index * 4。この4はワードのサイズ(バイト単位)です。コンパイラは、Cなどの言語におけるa[i]に対して、これと同じ計算を生成します。インデックス自体はメモリにアクセスしません。それから計算されたアドレスのみがアクセスします。
slli t5, t3, 2 # t5 = インデックス * 4 (ワードサイズ)add t6, t0, t5 # t6 = element[index]のアドレスlw t6, 0(t6) # t6 = element[index]
はt3のインデックスを2ビット左にシフトし、それを4倍します(2回の倍化:2 x 2)。これは1ワードのサイズです。その結果をベースポインタに加算すると、element[index]のアドレスが得られます。このシフトは算術のレッスンで扱った2の累乗の方法と同じであり、インデックスをワードのサイズでスケーリングする標準的な方法です。
a[0]: インデックス0、オフセット0。
iは位置として、そしてその位置がによって4倍にスケーリングされベースに加算された後に生成するアドレスです。16進数の数値は、シミュレータがこのプログラムを実行するときにaが占める実際のアドレスです。目的は、次のアドレスが現れる前にそれを予測することです。そうすれば、インクリメントするループ内のや、Cライクな言語のa[i]を読み、表記をブラックボックスとして扱うのではなく、それが触れるメモリアドレスを思い描くことができます。インデックスでベクトルを合計する
.dataa: .word 5, 10, 15, 20 # 4要素.textla t0, a # t0 = aのベースアドレスli t1, 4 # t1 = 要素数li t2, 0 # t2 = インデックス、0から開始li t3, 0 # t3 = 累積合計loop:beq t2, t1, doneslli t4, t2, 2 # t4 = インデックス * 4 (バイトオフセット)add t5, t0, t4 # t5 = a[index] のアドレスlw t5, 0(t5) # t5 = a[index]add t3, t3, t5 # total += a[index]addi t2, t2, 1 # 次のインデックスへ進むj loopdone:mv a0, t3 # 合計を出力: 5+10+15+20 = 50li a7, 1ecallli a7, 10ecall
ループは次のように動作します。t2はインデックスで、0から始まります。各パスで、はインデックスがt1に保持された要素数である4に達したときにループを終了します。はインデックスをバイトオフセットに変換します。はそのオフセットをt0のベースアドレスに加算して、a[index]のアドレスを生成します。はそこに格納された値をロードします。その値はt3の累計に加算され、は次のインデックスに進みます。4回のパスの後(5 + 10 + 15 + 20)、doneは50を出力します。
2つのベクトルを要素ごとに加算する
.dataa: .word 3, 6, 9, 12 # 1つ目のベクトルb: .word 1, 2, 3, 4 # 2つ目のベクトルc: .space 16 # 結果用の4ワード分の場所.textla t0, a # aのベースアドレスla t1, b # bのベースアドレスla t2, c # cのベースアドレスli t3, 0 # インデックス、0から始まるli t4, 4 # 要素数li s0, 0 # 累計loop:beq t3, t4, doneslli t5, t3, 2 # バイトオフセット = インデックス * 4add t6, t0, t5 # a[index]のアドレスlw t6, 0(t6) # a[index]の値add a0, t1, t5 # b[index]のアドレスlw a0, 0(a0) # b[index]の値add t6, t6, a0 # a[index] + b[index]add a0, t2, t5 # c[index]のアドレスsw t6, 0(a0) # c[index] = a[index] + b[index]add s0, s0, t6 # 合計 += c[index]addi t3, t3, 1 # 次のインデックスへ進むj loopdone:mv a0, s0 # 合計を出力: 4+8+12+16 = 40li a7, 1ecallli a7, 10ecall
ループは次のように動作します。はインデックスt3をバイトオフセットに変換します。それを各ベースポインタ(t0、t1、t2)に加算すると、a[i]、b[i]、c[i]のアドレスが得られます。各パスで、両方の要素がロードされ、加算され、cに格納され、s0の累計に加算されます。は次のインデックスに進み、4つの要素すべてが処理されるまでループが繰り返されます。
