为什么在循环中使用 $v0 寄存器 return 错误输出?

Why does using $v0 register in a loop return wrong output?

以下节目

  1. 给定用户输入的下限和上限,确定该范围内的最小值和最小索引

对于测试用例(下限:2 上限:4),我尝试了两种不同的代码,区别如下。

下面的代码没有return预期的输出

findMin:

      addi $t0, $a0, 0        # initialise $t0 (current pointer) to lower bound 
      addi $t1, $a0, 0        # initialise minimum pointer to upper bound 
      lw   $t2, 0($t1)        # initialise min (value) to the lower bound  


Loop: slt $t4, $a1, $t0
      bne $t4, $zero, End     # branch to end if upper < lower

      lw, $t3, 0($t0)         # store the content of the current pointer
      slt $t4, $t3, $t2       # if current ($t3) < min ($t2), store 1 in $t4
      beq $t4, $zero, LoopEnd # if it is 0, go to LoopEnd

      addi $t2, $t3, 0        # store content ($t3) as minimum ($t2)
      addi $v0, $t0, 0        # store the address of min (DIFFERENCE)

LoopEnd: addi $t0, $t0, 4     # increments current pointer lower bound 
         j Loop               # Jump to loop 

End:     jr $ra               # return from this function

但是,以下代码 return 预期值:

findMin:
    addi $t0, $a0, 0  # $t0 is the pointer to the current item
    addi $t1, $a0, 0  # $t1 is the pointer to the minimum item
    lw   $t2, 0($t1)  # $t2 stores the value of minimum item

loop:
    slt $t4, $a1, $t0  # check if last pointer < current pointer
    bne $t4, $zero, exit # if current pointer > last pointer, exit
    lw  $t3, 0($t0)    # $t3 stores the value of current item
    slt $t4, $t3, $t2  # if the current value is lesser than minimum value
    beq $t4, $zero, skip # if current value is not lesser, then skip

    addi $t1, $t0, 0   # minimum pointer = current pointer (DIFFERENCE)
    lw   $t2, 0($t1)   # $t2 stores the value of minimum item

skip:
    addi $t0, $t0, 4   # move to the next item
    j loop
exit:   
    addi $v0, $t1, 0   # $v0 stores the address of the minimum item (DIFFERENCE)
    jr $ra          # return from this function

这背后的原理是什么?

以下为完整代码(可选)


# arrayFunction.asm
       .data 
array: .word 8, 2, 1, 6, 9, 7, 3, 5, 0, 4
newl:  .asciiz "\n"

       .text
main:
    # Print the original content of array
    # setup the parameter(s)
    # call the printArray function
    la $a0, array            # base address of array
    la $a1, 10               # number of elements in array
    jal printArray           # call function 


    # Ask the user for two indices
    li   $v0, 5             # System call code for read_int
    syscall 
    add  $t0, $v0, $zero    # store input in $t0          

    li   $v0, 5             # System call code for read_int
    syscall           
    add  $t1, $v0, $zero    # store input in $t1          

    # Call the findMin function
    # setup the parameter(s) 
    la $a0, array       # load address of array into $a0
    la $a1, array       # load address of array into $a1
    sll $t0, $t0, 2         # calculate offset of lower bound
    sll $t1, $t1, 2         # calculate offset of upper bound
    add $a0, $a0, $t0       # set $a0 to the lower bound
    add $a1, $a1, $t1       # set $a1 to the upper bound 

    # call the function
    jal findMin             # call function 


    # Print the min item
    # place the min item in $t3 for printing
    addi $t3, $t2, 0        # placing min item in $t3 
    addi $t4, $v0, 0        # saving the pointer to the min element

    # Print an integer followed by a newline
    li   $v0, 1             # system call code for print_int
    addi $a0, $t3, 0        # print $t3
    syscall                 # make system call

    li   $v0, 4             # system call code for print_string
    la   $a0, newl      
    syscall                 # print newline

    #Calculate and print the index of min item
    la  $a0, array
    sub $t3, $t4, $a0   
    srl $t3, $t3, 2 

    # Place the min index in $t3 for printing   

    # Print the min index
    # Print an integer followed by a newline
    li   $v0, 1         # system call code for print_int
    addi $a0, $t3, 0    # print $t3
    syscall             # make system call

    li   $v0, 4         # system call code for print_string
    la   $a0, newl      
    syscall             # print newline

    # End of main, make a syscall to "exit"
    li   $v0, 10        # system call code for exit
    syscall             # terminate program


#######################################################################
###   Function printArray   ### 
#Input: Array Address in $a0, Number of elements in $a1
#Output: None
#Purpose: Print array elements
#Registers used: $t0, $t1, $t2, $t3
#Assumption: Array element is word size (4-byte)
printArray:
    addi $t1, $a0, 0    #$t1 is the pointer to the item
    sll  $t2, $a1, 2    #$t2 is the offset beyond the last item
    add  $t2, $a0, $t2  #$t2 is pointing beyond the last item
l1: 
    beq  $t1, $t2, e1
    lw   $t3, 0($t1)    # $t3 is the current item
    li   $v0, 1         # system call code for print_int
    addi $a0, $t3, 0    # integer to print
    syscall             # print it
    addi $t1, $t1, 4
    j l1            # Another iteration
e1:
    li   $v0, 4         # system call code for print_string
    la   $a0, newl      # 
    syscall             # print newline
    jr $ra          # return from this function


#######################################################################
###   Student Function findMin   ### 
#Input: Lower Array Pointer in $a0, Higher Array Pointer in $a1
#Output: $v0 contains the address of min item 
#Purpose: Find and return the minimum item 
#              between $a0 and $a1 (inclusive)
#Registers used: $t0 (counter), $t1 (max add), $t2 (min), $v0 (min pos), $t3 (current item)
#Assumption: Array element is word size (4-byte), $a0 <= $a1
findMin:

      addi $t0, $a0, 0        # initialise $t0 (current pointer) to lower bound 
      addi $t1, $a0, 0        # initialise minimum pointer to upper bound 
      lw   $t2, 0($t1)        # initialise min (value) to the lower bound  


Loop: slt $t4, $a1, $t0
      bne $t4, $zero, End     # branch to end if upper < lower

      lw, $t3, 0($t0)         # store the content of the current pointer
      slt $t4, $t3, $t2       # if current ($t3) < min ($t2), store 1 in $t4
      beq $t4, $zero, LoopEnd # if it is 0, go to LoopEnd

      addi $t2, $t3, 0        # store content ($t3) as minimum ($t2)
      addi $t1, $t0, 0        # store the address of min

LoopEnd: addi $t0, $t0, 4     # increments current pointer lower bound 
         j Loop               # Jump to loop 

End:    addi $v0, $t1, 0       
    jr $ra                # return from this function

在第一种情况下,问题是您最初将最小指针保存到 t1 寄存器,但在 return 上您希望它在 v0 上。现在,在最小值不完全在下限索引上的情况下,这不会成为问题,因为在循环中,您将新找到的最小值指针保存到 v0,因此在 return 一切会如预期的那样。但是如果像 2,4 这样的下限的最小值在索引 2 中,因此在循环中,因为没有找到新的最小点,因此 v0 中不会写入任何内容,因此在 return 中它会有一些垃圾价值。

将开头部分改成这样可以正常工作:

      addi $v0, $a0, 0        # initialise minimum pointer to upper bound 
      lw   $t2, 0($v0)        # initialise min (value) to the lower bound