分区函数错误(mips 程序集)

error in partition function (mips assembly)

这是我为了在mips中实现c分区函数而写的代码。 似乎有一个错误,因为程序不工作,但我找不到它在哪里。 我知道最好调试它,但我不知道如何调试。另外我对存储和恢复寄存器有点困惑,也许问题就出在这里。

我还在 visual studio 中安装了一个 mips 汇编调试器,但应用程序无法识别它,而且似乎没有其他 mips 选项。

partition:

#int partition(int f, int l) {
# int pivot = v[l];
# int i = f;

# for (int j = f; j < l; j++) 
#   if (v[j] < pivot) 
#    swap(i++,j);

# swap(i, l );
# return (i);
#}

addi $sp, $sp, -24 #make room for 6

    sw $a0, 0($sp)  #store f
    sw $a1, 4($sp)  #store l
    sw $ra, 8($sp)      #store return address
    sw $t2, 12($sp) #store i
    #sw $t3, 16($sp) #store j
    sw $t1, 16($sp) #store pivot
    sw $s0, 20($sp) #store s0

    la $s0, v    # s0 = address of v

sll $t0, $a1, 2 # t0 = 4*l
add $t0, $s0, $t0   # t0 = address of v[l]
lw $t1, 0($t0)  # t1 = v[l], t1 = pivot

move $t2, $a0 # t2 = i, t2 is f
move $t3, $a0 # t3 = j, t3 is f

for1:

    slt $t4, $t3, $a1   #if(j<l) t4=1
    beq $t4, $zero, end1 #goto end1 if t4 = 0

    sll $t4, $a0, 2      # t4 = 4*j
    add $t4, $s0, $t4       #t4 = address of v[j]
    lw $t5, 0($t4)      #t5 = v[j]

    slt $t6, $t5, $t1   # if (v[j] < pivot) t6=1 else t6=0


    bne $t6, $zero, else 
    move $a0, $t2 #a0 = i 
    move $a1, $t3 # a1 = j
    jal swap                #    swap(i++,j);
    addi $t2, $t2,1 # i++

    else:
        addi $t3, 1 #j++

        j for1
#here stops the for1 loop

end1: #come here when exiting the for1 loop

    # a0=f & a1=l
    move $a0, $t2 #a0 = i
    lw $a1, 4($sp) #a1= l
    jal swap

    move $v0, $a0 #v0=i / return i 

    lw $ra, 8($sp) #restore ra
    lw $s0, 20($sp) #restore s0
    lw $a0, 0($sp) #restore a0
    lw $a1, 4($sp) #restore a1
    #lw $s1, 4($sp) #restore s1

    addi $sp, $sp, 24 #restore stack
    jr $ra

Also I am kind of confused about storing and restoring registers, perhaps the problem lies there.

是的,您的寄存器用法与标准调用约定不同。我们没有看到您的分区函数的调用者,也没有看到 swap 函数,因此我们无法对它们发表评论。

根据 MIPS 调用约定,$s 寄存器,如果一个函数使用它们中的任何一个,必须在返回给调用者之前保留/恢复它们的原始值。相比之下,其他寄存器($a$t$v)不需要这样保存,所以可以随意使用而不需要进一步考虑。

$s 寄存器用于保存在具有函数调用的循环中使用的变量。这是因为允许函数调用清除非 $s 寄存器,但必须保留 $s 寄存器。因此,存储在 $s 寄存器中的变量将在函数调用后继续存在。

$s 寄存器的替代方案是堆栈内存,因为它也可以在函数调用后继续存在。要使用堆栈内存,我们必须存储和重新加载,这对于 non-looping non-repetitive 代码是可以的,但对于循环代码,这些加载和存储代表开销。

相比之下,$s 寄存器也被存储和加载,但每次函数调用仅一次,而不是在函数体中。因此,如果函数体有循环,那么在 prologue/epilogue 中进行加载和存储比在函数体内进行加载和存储更有效。

因此,经验法则是:如果有函数调用但没有循环,请考虑为需要在函数调用中存活的变量使用堆栈内存。如果没有函数调用,则不要使用 $s 寄存器。如果存在循环或大量函数调用,请考虑 $s 为需要在函数调用中存活的变量注册。

您需要能够分析变量是否在函数调用中存在。分析是:这个值是在函数调用前保存在变量present/existent中,然后在函数调用后使用的吗?如果是这样,该变量必须在函数调用后仍然存在,因此必须使用堆栈内存或 $s 寄存器。

您正在使用 $t 寄存器来存储函数调用循环中使用的变量——这是不正确的并且可能是一个问题(我们没有看到 swap 所以不能肯定地说)。

您还在序言中保留(并在结尾中恢复)不值得保留的寄存器,这是浪费但无害。