从 C 到 MIPS 的快速排序 - 如何传递参数和维护堆栈帧的变量?

Quicksort from C to MIPS - How to pass parameters and maintaining variables for stack frame?

我正在对整数数组创建快速排序算法。我正在使用这个 C 算法并将其转换为 MIPS。然而,MIPS和递归确实非常难。

我不确定如何将参数发送到递归调用 QS。我最近发现我可以通过将堆栈指针移动 4 个字节来更改调用堆栈中每个帧的 $s 寄存器。这将允许我更改每个堆栈帧的 $s 寄存器,这样我就不需要每个 QS 帧的一百万个变量。

我的问题是我不太明白在递归过程中如何以及何时设置和获取这些 $sx 值。

递归是通过移动堆栈指针寄存器($sp)实现的。

首先我们来了解一下移动栈指针的意义: 当您在高级语言中使用递归时,它所做的基本上是 "save" "stack memory" 中当前函数调用的 状态 。 为此,您必须:

  1. 保存程序的当前状态(所有 variables/registers 你在"function")的范围内使用,在栈内存中;
  2. 调用函数"recursively"(这可能会修改您使用的所有寄存器);
  3. 函数完成后,您必须恢复之前的状态和 "free" 您分配的 space。

但除此之外,我们还必须保存 $ra 的值,以跟踪上层函数结束时我们应该去哪里。

下面是一个递归计算阶乘 (n) 的简单程序示例:

.text
main:
  # Calls Fact with Input ($a0) N = 10
  li $a0, 10
  jal fact
  # prints the Output ($v0) Factorial(N)
  move $a0, $v0
  li $v0, 1
  syscall
  # exit
  li $v0, 10
  syscall

# Input: $a0 - N
# Output: $v0 - Factorial(N)
fact:
  # Fact(0) = 1
  beq $a0, 0, r_one
  # Fact(N) = N * Fact(N-1) use recursion
  # allocate 8 bytes in the stack for storing N, and $ra
  addi $sp, $sp, -8
  # stores N in the first, and $ra in the last position
  sw $a0, 4($sp)
  sw $ra, 0($sp)
  # call Fact(N-1)
  addi $a0, $a0, -1
  jal fact
  # Restore the values of N and $ra
  lw $a0, 4($sp)
  lw $ra, 0($sp)
  # Free the 8 bytes used
  addi $sp, $sp, 8
  # Set the return value to be N * Fact(N-1) and return
  mul $v0, $a0, $v0
  jr $ra
  # return 1;
  r_one:
    li $v0, 1
    jr $ra

这基本上是您在实施代码时应该牢记的。 只需关注:

  • 堆栈指针递减;
  • 您需要分配多少字节。在这个例子中我使用了 2 个 32 位整数,总共 8 个字节。这将取决于您需要存储多少变量及其大小。
  • 如何使用正确的索引通过 lwsw 访问它们。另外,请注意内存对齐;
  • 这不仅适用于递归。您可以使用堆栈内存来调用另一个使用正在使用的寄存器的函数(与递归基本相同,只是您不需要保存 $ra)。并且还存储一个数组,一个结构等

编辑:

一些注意事项:

  • 执行此操作的正确位置是您的代码调用函数的位置(分配和保存),以及在此调用之后(恢复和释放)。
  • 了解您的代码以了解需要保存哪些变量(可能会被使用)。