MIPS: Translating C code to MIPS problem in function calls and returns

落花浮王杯 提交于 2020-05-15 20:58:10

问题


I need to change C code from below to a MIPS code but I am new to MIPS and stuck with it.

Here is the C code:

int main()
{
    int a, b, result;
    if(a == b)
         result = a*b;
    else
         result = assess(a, b);
    return result;
}

int assess(int a, int b)
{
    if(b<a)
        return upgrade(a, b);
    else
        return demote(a, b);
}

int upgrade(int a, int b)
{
    return 4*(a+b);
}

int demote(int a, int b)
{
    return 4*(b-a);
}

Here is MIPS code that I wrote, which isn't working (I am aware there are major errors and wrongs). Because I am not familiar with the language, my main problems are using stack, return and calling the functions.

.data
    a:.word 8
    b:.word 8
    result:.word 0
main:
    li $s0 a
    li $s1 b
    li $s3 result
    beq $s0,$s1,Resultmul ELSE
    add $s3,$s3,assess

assess:
    blt $s1,$s0,upgrade
    bge $s1,$0,demote
Resultmul :
    mul $s3,$s1,$0

upgrade:
    addi $sp,$sp,-4
    sw $0,0($sp)
    add $t1,$a0,$a1
    mul $t1,$t1,4
    add $v0,$s0,$zero
    lw $s0,0($sp)
    addi $sp,$sp,4
    jr $ra
demote:
    addi $sp,$sp,-4
    sw $0,0($sp)
    sub $t1,$a0,$a1
    mul $t1,$t1,4
    add $v0,$s0,$zero
    lw $s0,0($sp)
    addi $sp,$sp,4
    jr $ra

If someone can help that would be a lifesaver.


回答1:


I'm not going to give you the full solution, so you can learn from the exercise, but I recommend you work from a template, like at this one for example.

I used Visual Studio Code (with MIPS Support and Better MIPS support for highlighting), in which every whitespace or tab, gives me the possibility of collapsing it by these whitespaces, and QtSpim on which I was able to run this and got the output 64.

Also, I'm used to coding with tabs; it's more clear to me, but it might not be to you, so I'm sorry if you have to remove all the tabs and comments.

######################## pseudo ####################################
 #
 #  int main()
 #  {
 #      int a, b, result;
 #      if(a == b)
 #           result = a*b;
 #      else
 #           result = assess(a, b);
 #      return result;
 #  }
 #  
 #  int assess(int a, int b)
 #  {
 #      if(b<a)
 #          return upgrade(a, b);
 #      else
 #          return demote(a, b);
 #  }
 #  
 #  int upgrade(int a, int b)
 #  {
 #      return 4*(a+b);
 #  }
 #  
 #  int demote(int a, int b)
 #  {
 #      return 4*(b-a);
 #  }
 #  
###################### DATA Segment ################################

    .data
 A:
    .word 8
 B:
    .word 8
 result:
    .word 0

###################### CODE Segment ################################

    .text
    .globl main
 main:

Here you made a little mistake: You already stored the words, so you should also load the words. Else, you'll have to type li $t0, 8.

    # int A = A, B = B, result
    lw      $s0, A      # $s0 = A
    lw      $s1, B      # $s1 = B
    lw      $s2, result # $s2 = result    
    # if (a == b)
        bne     $s0, $s1, noteq # if $s0 != $s1 then noteq
        # result = multiply(a,b);
        move    $a0, $s0        # $a0 = $s0
        move    $a1, $s1        # $a1 = $s1
        jal     multiply        # jump to multiply and save position to $ra
        sw      $v0, result     #         
        b       end             # branch to end
    # else
        noteq:
        # result = assess(a,b);
        move    $a0, $s0        # $a0 = $s0
        move    $a1, $s1        # $a1 = $s1
        # jal       assess      # jump to assess and save position to $ra
        sw      $v0, result     #         
        b       end             # branch to end (this rule can be left out)
    end:
    # printf("%i", result)
    li      $v0, 1      # $v0 = 1
    lw      $a0, result #     
    syscall
    # exit()
    li      $v0, 10     # $v0 = 10
    syscall

Since they are functions in your pseudo-code, they should be treated as functions in your assembly as well. Meaning they are being called with j (for non-returning function like exit) or jal (and return with jr).

I made a completely unnecessary function multiply to show you the template, which is pretty handy for larger functions.

###################### FUNC Segment ################################

###################### FUNCTION ####################################
 # multiply(A, B)
 #
 # Purpose: <General description>
######################## i/0 #######################################
 # Input:
  # $a0 = A
  # $a1 = B
 # Output: 
  # $v0 = value
 # Registers being used:
  # $s0 = A
  # $s1 = B
  # $s2 = value
######################## pseudo ####################################
 #  
 #  int multiply(int A, int B)
 #  {
 #      return A * B;
 #  }
 #
######################## <code> ####################################
 multiply:#(A, B)

Always store the content of the registers you are going to overwrite, so you can call other functions without losing any content. Also immediately initialize your parameters stored in $a0-$a3 in new registers, because you might overwrite the parameters when printing something using syscall.

There are two main reasons to store the variables:

  1. The function call want unknowingly change one of your $s0-$s7-registers.
  2. Other functions can be called within the current function, with their own stack handling, so again no need to worry about registers. Might be interesting to know before making an assess-function.

This is how the initialization of a function's parameters would look like:

    # store(&return, parameters that are about overwritten)
    sub     $sp, $sp, 16    # $sp = $sp - 16
    sw      $ra, 0($sp)     #
    sw      $s0, 4($sp)     # 
    sw      $s1, 8($sp)     #
    sw      $s2, 12($sp)    # 
    # int A = A, B = B, value
    move    $s0, $a0        # $s0 = $a0
    move    $s1, $a1        # $s1 = $a1

This is the very short body of the function. As you can tell, storing all these parameters is idiotic, so don't make these overhead functions.

    # value = A * B;
    mul     $s2, $s0, $s1

This is to handle a function's return. In larger functions, you'll need a label most of the time to jump to the return-handling. I always call labels inside a function foo like foo_thisLabel, but that's just my recommendations.

    move    $v0, $s2        # $v0 = $s2
    # restore()
    lw      $ra, 0($sp)     #   
    lw      $s0, 4($sp)     # 
    lw      $s1, 8($sp)     # 
    lw      $s2, 12($sp)    #     
    addi    $sp, $sp, 12    # $sp = $sp + 12
    # return index
    jr      $ra             # jump to $ra
######################## </code> ###################################

Note that I only wait for the function's return segment to move value into the return register, $v0.

Here is an empty template for the other functions.

###################### FUNCTION ####################################
 # <name of function>
 #
 # Purpose: <General description>
######################## i/0 #######################################
 # Input:
  # $a0 = 
  # $a1 = 
  # $a2 = 
  # $a3 = 
 # Output: 
  # $v0 = 
 # Registers being used:
  # $t0 = 
  # $t1 = 
  # $t2 = 
  # $s0 = 
  # $s1 = 
  # $s2 = 
  # $s3 = 
  # $s4 = 
######################## pseudo ####################################
 #  
 #  int assess(int a, int b)
 #  {
 #      if(b<a)
 #          return upgrade(a, b);
 #      else
 #          return demote(a, b);
 #  }
 #
######################## <code> ####################################
 #
######################## </code> ###################################

P.S. I've renamed your variable names, because b might cause an error.



来源:https://stackoverflow.com/questions/61234603/mips-translating-c-code-to-mips-problem-in-function-calls-and-returns

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!