在将数组的地址传递给 MIP 中的函数后,我是否应该将数组的值保存到堆栈中?

After passing the address of an array into a function in MIPs, am I supposed to save the values of the array into a stack?

我必须将这个 C++ 函数翻译成 MIPS。

void updatePoint(int *arg)
    {
      int distance;

      distance = findDistance(arg[0],arg[1],0,-1);
      if ((distance < 1) && (arg[2] < 0))
        arg[2] = - arg[2];
      distance = findDistance(arg[0],arg[1],10,-1);
      if ((distance < 1) && (arg[2] > 0))
        arg[2] = - arg[2];
      distance = findDistance(arg[0],arg[1],-1,0);
      if ((distance < 1) && (arg[3] < 0))
        arg[3] = - arg[3];
      distance = findDistance(arg[0],arg[1],-1,10);
      if ((distance < 1) && (arg[3] > 0))
        arg[3] = - arg[3];
       arg[0] = arg[0] + arg[2];
      arg[1] = arg[1] + arg[3];
      return;
}

这是导致函数调用的 MIPS 代码。

        .data
redData:    .word   0:4
greenData:      .word   0:4
prmpt1:  .asciiz "Enter x-coordinate for red particle (0 to 10):"
prmpt2:  .asciiz "Enter y-coordinate for red particle (0 to 10):"
prmpt3:  .asciiz "Enter x-coordinate for green particle (0 to 10):"
prmpt4:  .asciiz "Enter y-coordinate for green particle (0 to 10):"
prmpt5:  .asciiz "cycle "
prmpt6:  .asciiz "red particle (x,y,xVel,yVel): "
prmpt7:  .asciiz "green particle (x,y,xVel,yVel): "
prmpt8:  .asciiz "Collison: oops, end of simulation!\n"
space:   .asciiz " "
endl:    .asciiz "\n"

# i     $s0
# cycle $s1 = 0
# dist  $s2

.text

main:   li      $s1,0

la      $s3,redData     #  redData[2] = 1 ;
li      $s4,1
sw      $s4,8($s3)
sw      $s4,12($s3)     #  redData[3] = 1 ;
la      $s3,greenData   #  greenData[2] = -1 ;
li      $s4,-1
sw      $s4,8($s3)
sw      $s4,12($s3)     #  greenData[3] = -1 ;

la      $a0,prmpt1      #  cout << prmpt1 ;
li      $v0,4
syscall
la      $s3,redData
li      $v0,5           #  cin >> redData[0] ;
syscall
sw      $v0,($s3)
la      $a0,prmpt2      #  cout << prmpt2 ;
li      $v0,4
syscall
li      $v0,5           #  cin >> redData[1] ;
syscall
sw      $v0,4($s3)
la      $a0,prmpt3      #  cout << prmpt3 ;
li      $v0,4
syscall
la      $s3,greenData   #  cin >> greenData[0] ;
li      $v0,5
syscall
sw      $v0,($s3)
la      $a0,prmpt4      #  cout << prmpt4 ;
li      $v0,4
syscall
li      $v0,5           #  cin >> greenData[1] ;
syscall
sw      $v0,4($s3)

loop:                           #  do {
la      $a0,prmpt5      #    cout << "cycle " << cycle << endl ;
li      $v0,4
syscall
move    $a0,$s1
li      $v0,1
syscall
la      $a0,endl
li      $v0,4
syscall
la      $a0,prmpt6      #    cout << "red particle (x,y,xVel,yVel): "
li      $v0,4
syscall
la      $s3, redData
lw      $a0,($s3)       #       << redData[0]
li      $v0,1
syscall
la      $a0,space       #       << " "
li      $v0,4
syscall
lw      $a0,4($s3)      #       << redData[1]
li      $v0,1
syscall
la      $a0,space       #       << " "
li      $v0,4
syscall
lw      $a0,8($s3)      #       << redData[2]
li      $v0,1
syscall
la      $a0,space       #       << " "
li      $v0,4
syscall
lw      $a0,12($s3)     #       << redData[3]
li      $v0,1
syscall
la      $a0,endl        #       << endl ;
li      $v0,4
syscall
la      $a0,prmpt7      #    cout << "green particle (x,y,xVel,yVel): "
li      $v0,4
syscall
la      $s3, greenData
lw      $a0,($s3)       #       << greenData[0]
li      $v0,1
syscall
la      $a0,space       #       << " "
li      $v0,4
syscall
lw      $a0,4($s3)      #       << greenData[1]
li      $v0,1
syscall
la      $a0,space       #       << " "
li      $v0,4
syscall
lw      $a0,8($s3)      #       << greenData[2]
li      $v0,1
syscall
la      $a0,space       #       << " "
li      $v0,4
syscall
lw      $a0,12($s3)     #       << greenData[3]
li      $v0,1
syscall
la      $a0,endl        #       << endl ;
li      $v0,4
syscall
la      $a0,endl        #       << endl ;
li      $v0,4
syscall

la      $a0,redData     #    updatePoint(redData) ;
jal     updatePoint

对于 updatePoint,我应该将 arg[0] - arg[2] 的值存储到堆栈上吗?为此,我应该做

lw      $s0, 0($a0) 
lw      $s1, 4($a0)
lw      $s2, 8($a0)
lw      $s3, 12($a0)
addi    $sp, $sp, -20
lw      $s0, 0($sp) 
lw      $s1, 4($sp)
lw      $s2, 8($sp)
lw      $s3, 12($sp)
lw      $ra, 16($sp)

For updatePoint, should I be storing the values of arg[0] - arg[2] onto the stack?

不,arg 是一个 数组 。它由 reference 传递(即 arg 的 pointer/address 在 $a0 中)。根据 return,arg 中的值 预计 将被 updatePoint 修改。它 修改 arg[0]arg[1](即见 updatePoint 的最后两行),并且有条件地, 可能 一路修改arg[2]arg[3]

updatePoint中的每一步,它必须使用arg中的更新值,并且, return,updatePointcaller 必须接收回 argmodified 值。

updatePoint 中的任何内容都不允许 findDistance 修改 arg,因为 findDistance 的所有参数都由 value[=96= 传递].

因此,您需要保留 [指针值] $a0 以防止 updatePoint 将此 指针 值丢失到 arg当调用 findDistance 时。

可以 将它保存在 updatePoint 的堆栈帧中,但您必须在每次调用 findDistance 后重新加载它。最好将其保存在 callee 保留的寄存器中(例如 $s0),这样 findDistance 就不会打扰它。


这是第一次调用 findDistance 的示例。填写其他内容以及最后两行 C++ 行对您来说应该很容易。请注意 nothing else 需要保留在 updatePoint 中 [这是一个强烈的提示]。您可以根据需要使用任意数量的其他温度调节器。

# void
# updatePoint(int *arg)
# {
#     int distance;
#
#     distance = findDistance(arg[0], arg[1], 0, -1);
#     if ((distance < 1) && (arg[2] < 0))
#         arg[2] = -arg[2];
#
#     distance = findDistance(arg[0], arg[1], 10, -1);
#     if ((distance < 1) && (arg[2] > 0))
#         arg[2] = -arg[2];
#
#     distance = findDistance(arg[0], arg[1], -1, 0);
#     if ((distance < 1) && (arg[3] < 0))
#         arg[3] = -arg[3];
#
#     distance = findDistance(arg[0], arg[1], -1, 10);
#     if ((distance < 1) && (arg[3] > 0))
#         arg[3] = -arg[3];
#
#     arg[0] = arg[0] + arg[2];
#     arg[1] = arg[1] + arg[3];
# }
updatePoint:
    subu    $sp,$sp,8
    sw      $ra,4($sp)
    sw      $s0,0($sp)

    # NOTE: now that we've preserved $s0 of our caller, we are free to use it
    # for whatever we want -- we use it to preserve the address of 'arg'
    move    $s0,$a0                 # preserve address of 'arg'

    #     distance = findDistance(arg[0], arg[1], 0, -1);
    lw      $a0,0($s0)              # get arg[0]
    lw      $a1,4($s0)              # get arg[1]
    li      $a2,0                   # set 0
    li      $a3,-1                  # set -1
    jal     findDistance

    #     if ((distance < 1) && (arg[2] < 0))
    bge     $v0,1,noset1            # distance < 1? if no, fly
    lw      $v0,8($s0)              # get arg[2]
    bgez    $v0,noset1              # is arg[2] < 0? if no, fly

    #         arg[2] = -arg[2];
    neg     $v0,$v0                 # get -arg[2]
    sw      $v0,8($s0)              # set arg[2] = -arg[2]
noset1:

    # with adjusted parameters repeat the above for all three remaining calls

    # perform last two lines of function ...

    lw      $ra,4($sp)
    lw      $s0,0($sp)
    addu    $sp,$sp,8
    jr      $ra

findDistance:

请注意,被调用的函数只需要保留 $s0-$s7,必须保留它找到它时的 $sp,并且必须保留 $ra 以便它可以执行 jr $ra至 return.

对于 $ra,该函数可以将其保存在(例如)$t3 中,然后再保存 jr $t3。调用者关心$ra是否被保留(即用你想要的任何reg做jr,惯用的是$ra) .只需确保函数 returns 到正确的位置。

在上面的代码中,请注意在调用 findDistance 之后,测试 return 值 [in $v0]。之后,不需要 return 值,代码使用 $v0 作为临时值(对比(例如)$t0))。

同样,被调用的函数可以使用参数寄存器 $a0-$a3 为所欲为(即 它们 可以在计算期间用作临时寄存器)


这是你的 c++ 函数,我称之为 "simple C"。它更像是对 asm:

的直接翻译
void
updatePoint(int *arg)
{
    int distance;

    distance = findDistance(arg[0], arg[1], 0, -1);
    if (distance >= 1)
        goto noset1;
    if (arg[2] >= 0)
        goto noset1;
    arg[2] = -arg[2];
noset1:

    distance = findDistance(arg[0], arg[1], 10, -1);
    if (distance >= 1)
        goto noset2;
    if (arg[2] <= 0)
        goto noset2;
    arg[2] = -arg[2];
noset2:

    distance = findDistance(arg[0], arg[1], -1, 0);
    if (distance >= 1)
        goto noset3;
    if (arg[3] >= 0)
        goto noset3;
    arg[3] = -arg[3];
noset3:

    distance = findDistance(arg[0], arg[1], -1, 10);
    if (distance >= 1)
        goto noset4;
    if (arg[3] <= 0)
        goto noset4;
    arg[3] = -arg[3];
noset4:

    arg[0] = arg[0] + arg[2];
    arg[1] = arg[1] + arg[3];
}