将带有 args 的 C 函数转换为 MIPS:循环遍历 int 数组并计算负数 [英] Translating C function with args to MIPS: loop over an int array and count negatives

查看:49
本文介绍了将带有 args 的 C 函数转换为 MIPS:循环遍历 int 数组并计算负数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的问题是关于 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保留,所以a0a1被用作临时.

Note that under the mips ABI, only the s* regs must be preserved by callee, so a0 and a1 are used as temporaries.

另请注意,在添加地址/指针时,作为一种好的做法,我们希望使用 add 指令的未签名版本(即 adduaddiu) 以防止 [不太可能发生的] 溢出异常.

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆