0

我在模块编译器中为我的课程创建了一个代码生成器。它以 MIPS 汇编代码生成代码,并且似乎工作正常(我测试了非常简单的程序和表达式)。我测试了递归斐波那契程序,它目前永远循环。基本情况 0 和 1 工作正常。但是当我尝试 fib(2) 或更多时,它会一直循环。不知道是什么问题,谁能帮我找出来?

这是代码:

main: 
move $fp $sp 
sw $ra 0($sp)
addiu $sp $sp -4 
sw $fp 0($sp) 
addiu $sp $sp -4 
li $a0 2 #testing comment
sw $a0 0($sp) 
addiu $sp $sp -4 
jal fib_entry 
lw $ra 4($sp) 
addiu $sp $sp 8 
lw $fp 0($sp) 
li $v0, 10 
syscall 
fib_entry: 
move $fp $sp 
sw $ra 0($sp)
addiu $sp $sp -4 
lw $a0 4($fp) 
sw $a0 0($sp) 
addiu $sp $sp -4 
li $a0 0 
lw $t1 4($sp) 
addiu $sp $sp 4 
beq $a0 $t1 thenBranch1
elseBranch1: 
lw $a0 4($fp) 
sw $a0 0($sp) 
addiu $sp $sp -4 
li $a0 1 
lw $t1 4($sp) 
addiu $sp $sp 4 
beq $a0 $t1 thenBranch2
elseBranch2: 
sw $fp 0($sp) 
addiu $sp $sp -4 
lw $a0 4($fp) 
sw $a0 0($sp) 
addiu $sp $sp -4 
li $a0 1 
lw $t1 4($sp) 
sub $a0 $t1 $a0 
addiu $sp $sp 4 
sw $a0 0($sp) 
addiu $sp $sp -4 
jal fib_entry 
sw $a0 0($sp) 
addiu $sp $sp -4 
sw $fp 0($sp) 
addiu $sp $sp -4 
lw $a0 4($fp) 
sw $a0 0($sp) 
addiu $sp $sp -4 
li $a0 2 
lw $t1 4($sp) 
sub $a0 $t1 $a0 
addiu $sp $sp 4 
sw $a0 0($sp) 
addiu $sp $sp -4 
jal fib_entry 
lw $t1 4($sp) 
add $a0 $a0 $t1 
addiu $sp $sp 4 
b endIf2 
thenBranch2: 
li $a0 1 
endIf2: 
b endIf1 
thenBranch1: 
li $a0 0 
endIf1: 
lw $ra 4($sp) 
addiu $sp $sp 12 
lw $fp 0($sp) 
jr $ra 
4

1 回答 1

2

该代码的各种问题。

  1. 你应该在写信$sp 之前($sp)递减(尽管这只是惯例)
  2. 您应该在修改$fp 之前保存(这是常识;))
  3. MIPS 通常使用寄存器来传递参数(但您当然可以制定自己的约定)
  4. 你的堆栈处理非常复杂,至少在main它是不平衡的
  5. 建议从而main不使用exit系统调用返回

在尝试生成一些 asm 代码之前,您当然应该能够编写和调试 asm 代码。

给定一个输入结构类似于这个 C 实现:

unsigned fib_entry(unsigned n) {
    unsigned ret;
    unsigned n1;
    unsigned f1;
    unsigned n2;
    unsigned f2;

    if (n <= 1) goto fib_small;

    n1 = n - 1;
    f1 = fib_entry(n1);
    n2 = n - 2;
    f2 = fib_entry(n2);
    ret = f1 + f2;
    goto fib_done;

fib_small:
    ret = n;

fib_done:
    return ret;
}

我希望一个不太聪明的编译器生成这样的代码:

fib_entry:
    addiu $sp $sp -28   # we need room for $ra, n, ret, n1, n2, f1, f2
    sw $ra, 24($sp)     # store $ra since not leaf function
    sw $a0, 20($sp)     # store n

    lw $t0, 20($sp)     # load n
    ble $t0 1 fib_small

    lw $t0, 20($sp)     # load n
    addi $t0 $t0 -1     # n - 1
    sw $t0, 12($sp)     # store as n1

    lw $a0, 12($sp)     # pass n1 as argument
    jal fib_entry
    sw $v0 4($sp)       # store into f1

    lw $t0, 20($sp)     # load n
    addi $t0 $t0 -2     # n - 2
    sw $t0, 8($sp)      # store as n2

    lw $a0, 8($sp)      # pass n2 as argument
    jal fib_entry
    sw $v0 ($sp)        # store into f2

    lw $t0 4($sp)       # f1
    lw $t1 ($sp)        # f2
    addu $t0 $t0 $t1    # f1 + f2
    sw $t0 16($sp)      # store into ret

    b fib_done

fib_small:
    lw $t0, 20($sp)     # load n
    sw $t0 16($sp)      # store into ret

fib_done:
    lw $v0 16($sp)      # load return value
    lw $ra 24($sp)      # restore $ra
    addiu $sp $sp 28    # restore stack
    jr $ra              # return

注意我故意让它未优化。这种代码应该足够简单以生成。

于 2012-11-19T18:34:26.523 回答