将带有 args 的 C 函数转换为 MIPS:遍历 int 数组并计算负数
Translating C function with args to MIPS: loop over an int array and count negatives
我的问题是关于 MIPS 中的过程和使用参数。
我正在尝试将这个小的 C 函数转换为 MIPS,但我不确定我是否在正确的轨道上。这是 C 函数:
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 上的表现
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 约定,以及我是否在程序中使用了参数正确的方式。
如果有人可以检查代码并查看是否有问题,请提前致谢。
我认为看看像样的编译器做什么并不难:
您将拥有所有调用约定和其他内容。
#include <stdio.h>
int __attribute__((noinline)) countNegatives(int table[] , int n) {
int count = 0;
int i;
for (i=0; i<n; i++) {
if (table[i] <0) {
count++;
}
}
return count;
}
volatile int x[] = {454,-3,-5343,-3434,4534};
int main(void)
{
printf("%d\n",countNegatives((int *)x, sizeof(x)/sizeof(x[0])));
}
countNegatives:
blez ,$L6
sll ,,2
addu ,,
move ,[=10=]
$L5:
lw ,0()
addiu ,,4
slt ,,0
bne ,,$L5
addu ,,
j
nop
$L6:
j
move ,[=10=]
$LC0:
.ascii "%d2[=10=]0"
main:
lui ,%hi(x)
addiu $sp,$sp,-32
li ,5 # 0x5
sw ,28($sp)
jal countNegatives
addiu ,,%lo(x)
lui ,%hi($LC0)
move ,
jal printf
addiu ,,%lo($LC0)
lw ,28($sp)
move ,[=10=]
j
addiu $sp,$sp,32
x:
.word 454
.word -3
.word -5343
.word -3434
.word 4534
除了一些遗漏的样板文件,你们非常接近。这是一个带有错误注释的版本:
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
这是一个工作版本[添加了样板]:
.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
而不是条件分支 [并消除了循环内的额外跳转]:
.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
这是另一个使用指针运算而不是索引变量的版本。
请注意,在 mips ABI 下,只有 s*
regs 必须由被调用方保留,因此 a0
和 a1
用作临时值。
另请注意,在添加 addresses/pointers 时,我们希望使用 add
指令的无符号版本(即 addu
和 addiu
)作为良好做法防止[不太可能发生]溢出异常。
.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 看起来像这样:
int
countNegatives(int *table, int n)
{
int *endp;
int count = 0;
endp = &table[n];
for (; table != endp; ++table)
count += (*table < 0);
return count;
}
我的问题是关于 MIPS 中的过程和使用参数。
我正在尝试将这个小的 C 函数转换为 MIPS,但我不确定我是否在正确的轨道上。这是 C 函数:
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 上的表现
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 约定,以及我是否在程序中使用了参数正确的方式。
如果有人可以检查代码并查看是否有问题,请提前致谢。
我认为看看像样的编译器做什么并不难:
您将拥有所有调用约定和其他内容。
#include <stdio.h>
int __attribute__((noinline)) countNegatives(int table[] , int n) {
int count = 0;
int i;
for (i=0; i<n; i++) {
if (table[i] <0) {
count++;
}
}
return count;
}
volatile int x[] = {454,-3,-5343,-3434,4534};
int main(void)
{
printf("%d\n",countNegatives((int *)x, sizeof(x)/sizeof(x[0])));
}
countNegatives:
blez ,$L6
sll ,,2
addu ,,
move ,[=10=]
$L5:
lw ,0()
addiu ,,4
slt ,,0
bne ,,$L5
addu ,,
j
nop
$L6:
j
move ,[=10=]
$LC0:
.ascii "%d2[=10=]0"
main:
lui ,%hi(x)
addiu $sp,$sp,-32
li ,5 # 0x5
sw ,28($sp)
jal countNegatives
addiu ,,%lo(x)
lui ,%hi($LC0)
move ,
jal printf
addiu ,,%lo($LC0)
lw ,28($sp)
move ,[=10=]
j
addiu $sp,$sp,32
x:
.word 454
.word -3
.word -5343
.word -3434
.word 4534
除了一些遗漏的样板文件,你们非常接近。这是一个带有错误注释的版本:
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
这是一个工作版本[添加了样板]:
.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
而不是条件分支 [并消除了循环内的额外跳转]:
.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
这是另一个使用指针运算而不是索引变量的版本。
请注意,在 mips ABI 下,只有 s*
regs 必须由被调用方保留,因此 a0
和 a1
用作临时值。
另请注意,在添加 addresses/pointers 时,我们希望使用 add
指令的无符号版本(即 addu
和 addiu
)作为良好做法防止[不太可能发生]溢出异常。
.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 看起来像这样:
int
countNegatives(int *table, int n)
{
int *endp;
int count = 0;
endp = &table[n];
for (; table != endp; ++table)
count += (*table < 0);
return count;
}