将C语言的for循环转换为MIPS指令

5

我正在尝试将这段C代码直接翻译成MIPS代码,而不修改任何指令,以使其运行更加高效:

for(i = 0; i != j; i += 2)
    b[i] = a[i] - a[i + 1]

我并不是真的要使用MIPS编写代码,只是想了解一些东西。目前我的进展并不大:

#t5 = i
$t6 = j
#t1 = a
#t2 = b
#t3 = c
#t10, t11, t12 = free

add $t5, $zero, $zero # initialize i = 0 

loop:
    bne $t5, $t6        # check if i is not equal to j
    addi $t5, $t5, 2    # i += 2
    add $t10, $t5, $t11 # temp reg $t10 = address of b[i]
    lw $t2, 0($t10)     # temp reg $t2 = b[i]
    add $t10, $t5, $t12 # temp reg $t10 = address of a[i]
    lw $t1, 0($t10)     # temp reg $t1 = a[i]

我不确定bne是否正确,因为我没有指定要跳转到哪里。我已经阅读了有关MIPS中数组的内容,但这让我感到困惑。我知道当将数组放入寄存器时,需要使用正确的字节地址偏移量。如果数组中是一个变量而不是一个数字,那么情况会相同吗?任何指导或提示都将很好。谢谢!


应该是 beq 吧?因为当条件为假时,也就是当 (i==j) 时,我们将退出。如果条件为真(i!=j),则我们会继续执行循环而不会退出。 - Alex Nosenko
2个回答

1

不要忘记,内存寻址在读取字时会偏移4位。 根据《计算机组成与体系结构》一书的内容,按照正确的方式移动索引为i的数组应该是:

sll $t10,$t5,2     #$t10=i*4
add $t10,$t10,$t1  #$t10 = i*4 + addr(a)
lw $t11,4($t10)    #temp reg $t11 = a[i + 1]
lw $t12,0($t10)    #temp reg $t12 = a[i]

注意,i 必须乘以 4,lw 的偏移量应该是 4 的倍数。如果不这样做,寻址将无法正确进行,因为寻址是按字节进行的,但我们正在使用按字进行数据操作。正确的实现应该像这样。
#t5 = i
#t6 = j
#t1 = address of a
#t2 = address of b
#t10, t11, t12 = free

#START
move $t5,$0               #set $t5 to zero

loop:
       bne $t5,$t6,exit   #if $t5 not equal to $t6 branch to exit
       sll $t10,$t5,2     #temp reg $t10 = i*4
       add $t10,$t10,$t1 #temp reg $t10 = address of a[i]
       lw $t11,4($t10)    #temp reg $t11 = a[i + 1]
       lw $t12,0($t10)    #temp reg $t12 = a[i]
       sub $t10,$t12,$t11 #temp reg $t10 = a[i] - a[i + 1]
       sll $t11,$t5,2     #temp reg $t11 = i*4
       add $t11,$t11,$t2  #temp reg $t11 = address of b[i]
       sw $t10,0($t11)    #store word b[i] = a[i] - a[i + 2]
       addi $t5,$t5,2     #i+=2
       j loop             #jump to start of loop
exit

1

你猜对了,bne需要一个跳转位置。因此,您的程序中至少需要一个标签。在下面的示例中,新标签称为“exit”。

至于加载和存储中的寻址,我同意你的观点;一开始可能会有点混淆(特别是如果你习惯了C风格的数组索引)。如果您的偏移量不是常量,则必须执行加法(或减法)操作以获取地址。让我们以a [i + 1]的地址为例:首先,您需要将a的地址与i相加并将其存储在某个地方,然后您可以使用恒定的偏移量来加载(或存储)真实地址。我重新编写了您的示例,以便您可以看到我正在谈论的内容;这是其中一件通过示例比解释更容易理解的事情 :)

#t5 = i
#t6 = j
#t1 = address of a
#t2 = address of b
#t10, t11, t12 = free

#START
move $t5,$0               #set $t5 to zero

loop:
       bne $t5,$t6,exit   #if $t5 not equal to $t6 branch to exit
       addi $t10,$t1,$t5  #temp reg $t10 = address of a[i]
       lw $t11,1($t10)    #temp reg $t11 = a[i + 1]
       lw $t12,0($t10)    #temp reg $t12 = a[i]
       sub $t10,$t12,$t11 #temp reg $t10 = a[i] - a[i + 1]
       addi $t11,$t2,$t5  #temp reg $t11 = address of b[i]
       sw $t10,0($t11)    #store word b[i] = a[i] - a[i + 2]
       addi $t5,$t5,2     #i+=2
       j loop             #jump to start of loop
exit:

非常感谢!所以我不需要执行move $t5,$zero,$zero吗?只用$0就可以了吗?感谢您告诉我如何处理不是常量的偏移量。这解决了一些问题。 - pfinferno
1
没错,你可以使用move代替addi。Move是MIPS伪指令;基本上是经常使用的指令组合的快捷方式。搜索“MIPS伪指令”以了解更多信息。 - 8tracklover

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接