分区函数错误(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
所以不能肯定地说)。
您还在序言中保留(并在结尾中恢复)不值得保留的寄存器,这是浪费但无害。
这是我为了在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
所以不能肯定地说)。
您还在序言中保留(并在结尾中恢复)不值得保留的寄存器,这是浪费但无害。