将带有 args 的 C 函数转换为 MIPS:循环遍历 int 数组并计算负数 [英] Translating C function with args to MIPS: loop over an int array and count negatives
问题描述
我的问题是关于 MIPS 中的过程和使用参数.
My question is about procedures in MIPS and using arguments.
我正在尝试将这个小的 C 函数转换为 MIPS,但我不确定我是否在正确的轨道上.这是 C 函数:
I'm trying to translate this small C Function to MIPS and I wasn't sure if I was in the right track. This is the C function:
0 int countNegatives(int table[] , int n) {
1 int count = 0;
2 int i;
3
4 for (i=0; i<n; i++) {
5 if (table[i] <0) {
6 count++;
7 }
8 }
9
10 return count;
11 }
这就是我对 MIPS 的看法
And this what I have on MIPS
main:
jal countNegatives
countNegatives:
li $t0, 0 #count = 0
li $t1, 0 #i = 0
loop:
bge $t1, $a1, endloop
sll $t2, $t1, 2 #$t2 = 4*i
add $t2, $a0, $t2 #$t2 = &table[i]
lw $t3, 0($t2) #temp = table[i]
bge $t3, $zero, endif
addi $t0, $t0, 1 #counter++
endif:
addi $t1, $t1, 1 #i++
endloop:
jr $ra
我的代码并没有真正在 QTSpim 上运行,所以我还想知道我是否遗漏了任何 MIPS 约定,以及我是否以正确的方式使用了过程中的参数.
My code doesn't really run on QTSpim, and so I'm also trying to know if I'm missing any MIPS convention, and if I'm using the arguments in the procedure in a correct manner.
如果有人可以检查代码并查看是否有问题,请提前致谢.
Thanks in advance if anyone can check the code out and see if something is wrong.
推荐答案
除了一些缺失的样板文件外,您已经非常接近了.这是一个带有错误注释的版本:
Except for some missing boilerplate, you were very close. Here's a version annotated with the bugs:
main:
# NOTE/BUG: a0/a1 are _not_ set up for the call
jal countNegatives
# NOTE/BUG: we just fall through into countNegatives again [which is bad]
countNegatives:
li $t0,0 # count = 0
li $t1,0 # i = 0
loop:
bge $t1,$a1,endloop
sll $t2,$t1,2 # $t2 = 4*i
add $t2,$a0,$t2 # $t2 = &table[i]
lw $t3,0($t2) # temp = table[i]
bge $t3,$zero,endif
addi $t0,$t0,1 # counter++
endif:
addi $t1,$t1,1 # i++
# NOTE/BUG: we need to loop here
endloop:
jr $ra
<小时>
这是一个工作版本[带有添加的样板]:
Here's a working version [with the added boilerplate]:
.data
arr: .word 10 20 -5 7 -6 0 1 -1 37
.text
.globl main
main:
la $a0,arr # point to array
li $a1,9 # array count
jal countNegatives
move $a0,$v0
li $v0,1
syscall
li $v0,10
syscall
# countNegatives -- count number of negatives
#
# RETURNS:
# v0 -- number of negative numbers found
#
# arguments:
# a0 -- pointer to array
# a1 -- array count
#
# temporaries:
# t1 -- index variable "i"
# t2 -- array offset / &table[i]
# t3 -- temp (value of table[i])
countNegatives:
li $v0,0 # count = 0
li $t1,0 # i = 0
loop:
bge $t1,$a1,endloop # i >= count? if yes, fly
sll $t2,$t1,2 # $t2 = 4*i
addu $t2,$a0,$t2 # $t2 = &table[i]
lw $t3,0($t2) # temp = table[i]
bge $t3,$zero,endif
addi $v0,$v0,1 # counter++
endif:
addi $t1,$t1,1 # i++
j loop
endloop:
jr $ra
<小时>
这是一个只是为了好玩的版本,它使用 slt
而不是条件分支[并消除了循环内的额外跳转]:
Here's a just for fun version that uses slt
instead of a conditional branch [and eliminates an extra jump inside the loop]:
.data
arr: .word 10 20 -5 7 -6 0 1 -1 37
.text
.globl main
main:
la $a0,arr # point to array
li $a1,9 # array count
jal countNegatives
move $a0,$v0
li $v0,1
syscall
li $v0,10
syscall
# countNegatives -- count number of negatives
#
# RETURNS:
# v0 -- number of negative numbers found
#
# arguments:
# a0 -- pointer to array
# a1 -- array count
#
# temporaries:
# t1 -- index variable "i"
# t2 -- array offset / &table[i]
# t3 -- temp (value of table[i])
countNegatives:
li $v0,0 # count = 0
li $t1,0 # i = 0
j loop_start # start the loop
loop:
sll $t2,$t1,2 # $t2 = 4*i
addu $t2,$a0,$t2 # $t2 = &table[i]
lw $t3,0($t2) # temp = table[i]
slt $t3,$t3,$zero # temp = (temp < 0)
add $v0,$v0,$t3 # counter += temp
addi $t1,$t1,1 # i++
loop_start:
blt $t1,$a1,loop # i < count? if yes, fly
jr $ra
<小时>
这是另一个使用指针算法而不是索引变量的版本.
Here's another version that uses pointer arithmetic instead of index variables.
注意在mips ABI下,只有s*
regs必须被callee保留,所以a0
和a1
被用作临时.
Note that under the mips ABI, only the s*
regs must be preserved by callee, so a0
and a1
are used as temporaries.
另请注意,在添加地址/指针时,作为一种好的做法,我们希望使用 add
指令的未签名版本(即 addu
和 addiu
) 以防止 [不太可能发生的] 溢出异常.
Also note that when adding addresses/pointers, as good practice, we want to use the unsigned versions of the add
instructions (i.e. addu
and addiu
) to prevent [the unlikely possibility of] an overflow exception.
.data
arr: .word 10 20 -5 7 -6 0 1 -1 37
.text
.globl main
main:
la $a0,arr # point to array
li $a1,9 # array count
jal countNegatives
move $a0,$v0
li $v0,1
syscall
li $v0,10
syscall
# countNegatives -- count number of negatives
#
# RETURNS:
# v0 -- number of negative numbers found
#
# arguments:
# a0 -- pointer to array (ptr)
# a1 -- array count
#
# temporaries:
# a1 -- array limit (endp)
# t3 -- temp (value of table[i])
countNegatives:
li $v0,0 # count = 0
sll $a1,$a1,2 # get byte offset
addu $a1,$a0,$a1 # endp = &arr[count]
j loop_start # start the loop
loop:
lw $t3,0($a0) # temp = *ptr
slt $t3,$t3,$zero # temp = (temp < 0)
add $v0,$v0,$t3 # counter += temp
addiu $a0,$a0,4 # ptr += 4
loop_start:
bne $a0,$a1,loop # ptr != endp? if yes, fly
jr $ra
<小时>
所以,最终的 asm 版本,翻译回 C 看起来像这样:
So, the final asm version, translated back into C would look something like this:
int
countNegatives(int *table, int n)
{
int *endp;
int count = 0;
endp = &table[n];
for (; table != endp; ++table)
count += (*table < 0);
return count;
}
这篇关于将带有 args 的 C 函数转换为 MIPS:循环遍历 int 数组并计算负数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!