MIPS——遞歸調用


嵌套過程

不調用其他過程的過程稱為葉過程(leaf procedure)。如果所有過程都是葉過程,那么情況就很簡單。但是某個過程可以調用其他過程,甚至調用的是自身的“克隆”。在調用非葉過程時使用寄存器需要十分小心。

例如,假設主程序將參數3存入寄存器a0,然后使用jal A調用過程A。再假設過程A通過jal B調用過程B,參數為7,同樣存入a0。由於A尚未結束任務,所以在寄存器a0的使用上存在沖突。同樣,在寄存器ra保存的返回地址也存在沖突,因為它現在保存着B的返回值。

我們必須采取措施阻止這類問題發生:

一個解決方法是將其他所有必須保存的寄存器壓棧,就像將保存寄存器壓棧一樣。調用者將所有調用后還需的參數寄存器(a1~a3)或臨時寄存器(t0~t9)壓棧。被調用者將返回地址寄存器(ra)和被調用者使用的保存寄存器(a0~a7)都壓棧。棧指針 sp 隨這棧中的寄存器個數調整。到返回時,寄存器會從存儲器中恢復,棧指針也會隨着重新調整。

有關指令

1     jal  function   #set $ra to Program Counter(PC),then jump to statement at target addres

C語言代碼

 1 #include<stdio.h>
 2 
 3 int factorial(int n);
 4 
 5 int main()
 6 {
 7     int n;
 8     scanf("%d", &n);
 9     int res = factorial(n);
10     printf("%d\n",res);
11     return 0;
12 }
13 
14 int factorial(int n)
15 {
16     if (n < 1)  return 1;
17     else  return n * factorial(n - 1);
18 }

雖然在C語言中函數定義可以在main函數前,也可以在main函數后,但定義在main函數后似乎更接近MIPS風格(看下面的代碼你就知道了)

MIPS代碼

 1 .data
 2     prompt1: .asciiz "Enter the number\n"
 3     prompt2: .asciiz "The factorial of n is:\n"
 4 
 5 .text
 6     # Print prompt1
 7     li $v0, 4
 8     la $a0, prompt1
 9     syscall
10 
11     # Read integer
12     li $v0, 5
13     syscall
14 
15     # Call factorial
16     move $a0, $v0
17     jal factorial
18     move $a1, $v0 # save return value to a1
19 
20     # Print prompt2
21     li $v0, 4
22     la $a0, prompt2
23     syscall
24 
25     # Print result
26     li $v0, 1
27     move $a0, $a1
28     syscall
29 
30     # Exit
31     li $v0, 10
32     syscall
33 
34     ## Function int factorial(int n)
35     factorial:
36         ## YOUR CODE HERE
37         addi $sp,$sp,-8            #adjust stack for 2 items
38         sw   $ra,4($sp)            #save return address
39         sw   $a0,0($sp)            #save the argument n
40     
41         slti $t0,$a0,1             #if n < 1,then set $t0 as 1
42         beq  $t0,$zero,L1          #if equal,then jump L1
43                                    #above all,if n >= 1,then jump L1
44         #if(n < 1)
45         addi $v0,$zero,1            #return 1
46         addi $sp,$sp,8              #pop 2 items off stack
47         jr   $ra                    #return to caller
48         #else
49         L1:
50             add $a0,$a0,-1          #argument :n - 1
51             jal factorial           #call factorial with (n-1)
52         
53            lw   $a0,0($sp)          #restore argument n
54            lw   $ra,4($sp)          #restore address
55            addi $sp,$sp,8           #adjust stack pionter
56            mul  $v0,$a0,$v0         #return n * factorial(n-1)
57            jr   $ra                  return to caller
58     ## END OF YOUR CODE
59   #jr $ra  

 手繪調用棧:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM