Để thực hiện  được đệ quy trong MIPS, điều quan tâm của chúng ta là các kết quả trung  gian và thanh ghi địa chỉ $ra. MIPS cung cấp cho  chúng ta một stack  pointer (thanh ghi $sp). Theo cơ chế stack thì cứ trước mỗi lần gọi thì  ta giảm giá trị của thanh $sp, sau đó Push vào các kết quả trung gian  cần nhớ và thanh ghi $ra. Sau lời gọi đệ quy thì ta lấy lại các kết quả  trung gian xử lí tính toán và phục hồi lại thanh $ra, sau đó jr $ra là  OK!
Nguyên nhân tại sao lại lưu thanh ghi $ra: Khi ta gọi thủ tục jal [ten-thu-tuc],  thì lúc đó thanh ghi $ra tự động cập nhật lại địa chỉ phái sau lệnh  jal, để chương trình sau khi thực hiện xong thủ tục thì chạy về thủ tục  gọi hàm và thực hiện tiếp những lệnh sau nó. Khi đệ quy, tức là gọi lại  thủ tục đó nhiều lần, nếu như ta không lưu lại thanh ghi $ra thì $ra sẽ  được cập nhật mới sau mỗi lần gọi đệ quy. Vì thế nó sẽ không nhớ được  đường về những lần gọi thủ tục trước lần gọi cuối cùng.
Và sau đây là một bài code mẫu tính giai thừa bằng đệ quy:
.data
  st_Nhap: .asciiz "Nhap vao so n: "
.text
main:
  addi $v0 $0, 5
  syscall
  addi $a0, $v0, 0
  jal giaithua
  addi $a0, $v0, 0
  addi $v0 $0, 1
  syscall
  addi $v0 $0, 10
  syscall
giaithua: # <=> $v0 = giaithua($a0)
  bne $a0, $0 , dequy 
  addi $v0, $0, 1
  jr $ra
  dequy:
    addi $sp, $sp, -8
    sw $a0, 0($sp)
    sw $ra, 4($sp)
    addi $a0, $a0, -1
    jal giaithua
        
    lw $a0, 0($sp)
    addi $a1, $v0, 0
    jal Nhan
    
    lw $ra, 4($sp)
    addi $sp, $sp, 8
  jr $ra 
Nhan:
  addi $sp, $sp, -4
  sw $ra, 0($sp)
  addi $v0, $0, 0
  LapNhan:
    slt $t0, $0, $a1
    beq $t0, $0, KTLapNhan
    add $v0, $v0, $a0
    addi $a1, $a1, -1
    j LapNhan
  KTLapNhan:
  lw $ra, 0($sp)
  addi $sp, $sp, 4
  jr $ra
Nhận xét
Đăng nhận xét