矢量:按位置索引
向量就是一个数组:在内存中彼此相邻存储的一串数字。在上一课中,你通过为每个元素将指针向前移动 4 个字节来求和。同样的方法在这里也适用。还有一种常见的访问元素的方式:通过索引。索引是从开头数起的元素位置,第一个元素的索引为 0,第二个为 1,依此类推。
通过移动指针求向量之和
.dataa: .word 5, 10, 15, 20 # 四个元素.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 # 剩余数减一j loopdone:mv a0, t2 # 打印总和:5+10+15+20 = 50li a7, 1ecallli a7, 10ecall
循环的运行如下。t0 保存 a 的地址,t1 保存剩余元素的数量,从 4 开始。每一轮中, 在计数变为零时结束循环。 加载 t0 中地址处的元素。 将该值加到累计总和中。 将指针推进到下一个字。 减少计数。经过四轮(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 x 2),也就是一个字的大小。将结果加到基址指针上就得到 element[index] 的地址。这个移位与算术课中的二的幂方法相同,也是按字的大小缩放索引的标准方式。
a[0]:索引 0,偏移 0。
i 作为位置,以及该位置在 将其缩放 4 倍并加到基址后产生的地址。十六进制数字是模拟器运行此程序时 a 实际占用的地址。目标是预测下一个地址,在它出现之前。这样你就能读懂递增循环中的 ,或类 C 语言中的 a[i],并想象它触及的内存地址,而不是把这种表示法当作黑箱。按索引求向量之和
.dataa: .word 5, 10, 15, 20 # 四个元素.textla t0, a # t0 = a 的基地址li t1, 4 # t1 = 元素个数li t2, 0 # t2 = 索引,起始于 0li 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 开始。每一轮中, 在索引达到 4(即 t1 中保存的元素数量)时结束循环。 将索引转换为字节偏移量。 将该偏移量加到 t0 中的基址上,产生 a[index] 的地址。 加载存储在那里的值。该值被加到 t3 中的累计总和中, 前进到下一个索引。经过四轮(5 + 10 + 15 + 20)后,done 打印 50。
逐元素相加两个向量
.dataa: .word 3, 6, 9, 12 # 第一个向量b: .word 1, 2, 3, 4 # 第二个向量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 中的累计总和中。 前进到下一个索引,循环重复,直到所有四个元素都被处理完。
