将带有 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 约定,以及我是否在程序中使用了参数正确的方式。

如果有人可以检查代码并查看是否有问题,请提前致谢。

我认为看看像样的编译器做什么并不难:

https://godbolt.org/g/PiR8Ds

您将拥有所有调用约定和其他内容。

 #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 必须由被调用方保留,因此 a0a1 用作临时值。

另请注意,在添加 addresses/pointers 时,我们希望使用 add 指令的无符号版本(即 adduaddiu)作为良好做法防止[不太可能发生]溢出异常。

    .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;
}