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

查看:44
本文介绍了将带有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 * reg,因此将 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屋!

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