So I am trying to convert some C into mips and I am running into a problem. So here is the C and the mips. My question is a few things, 1, all the times I have done a comparasin, > < == in the past there has been an else, in this their is none. So what would my offset be? and secondly how does one return func and set the paramaters like in the C. Thanks for any help

int f(int a, int b, int c, ind d)
{
    if (a+b > c+d)
        return func(a + b, c + d);
    return func(a + b, c + d);
}

The code for C function func is already compiled in another module.
Here is the mips I have so far

//int a,b,c,d will be $a0, $a1, $a2, $a3
f:
    addi $sp, $sp, -4
sw $s0, 0($sp)
    add $t0, $a0, $a1
    add $t1, $a2, $a3
    slt $t2, $t1, $t0
    bgtz $t2, offset

    lw $s0, 0($sp)
    addi $sp, $sp, 4
    jr $ra

1, all the times I have done a comparasin, > < == in the past there has been an else, in this their is none

It's implicit. You can pretend it looks like this if you'd like:

if (a+b > c+d)
    return func(a + b, c + d);
else
    return func(a + b, c + d);

and secondly how does one return func and set the paramaters like in the C.

Typically the caller handles parameters by pushing them onto the stack (in reverse order for the C calling convention) before making the call, and cleans up the stack after the function returns:

; Add the parameters to the stack
push d
push c
push b
push a

; Call the function
call f

; Remove the parameters from the stack
; I know nothing about MIPS, so assuming int is 2 bytes
add sp, 8

So as the function author you don't need to care how it happens as long as it happens with the expected result.

The return value varies, but the most common scheme is a hybrid of using a preselected register (the accumulator register in x86, for example) for smaller values and a hidden parameter for larger values. In your function, a return type of int is simple enough to place in a register, so there's no wasted effort working with the stack. But the hidden parameter would something look like this:

; Add the parameters to the stack
push d
push c
push b
push a
sub sp, [retsize]

; Call the function
call f

; Use the return value...

; Remove the parameters from the stack
add sp, [retsize]
add sp, 8

Note that all code here is pseudo-assembly, but based on Intel x86 syntax.

Edited 4 Years Ago by deceptikon

@Deceptikon: While your suggestions are well thought out, they really don't apply to the MIPS architecture, which works significantly differently from the x86 architecture, especially with regards to using the stack. Among other things, the standard word size is either 32 or 64 bits, depending on the model of the processor, not 16, and all memory access has to be word aligned. Also, it is a (mostly) pure load/store RISC architecure, so direct memory accesses are minimal; OTOH, there are 32 general registers (some of which are used for conventional purposes, such as the stack pointer, but which can in principle be used for anything any other register can be used for).

In MIPS, function calls are usually made using jal (jump and link, which jumps to the location of the function and copies the return value into $ra, the return address register). Arguments are passed using the $a0 through $a3 registers; if there are more than four arguments, you have to pass them on the stack.

The usual stack frame protocol for MIPS is to first decrement $sp by the amount that you need for the entire stack frame. You then save the frame pointer, $fp, from a zero offset with the new value of $sp as the base. You then add $sp by the amount needed for saving the local variables (that is, whichever of the $s0 through $s7 registers are used) save that to $fp, then use $fp as the base from which to save the the arguments (offsets are $a0 == 8, $a1 == 12, $a2 == 16, and $a3 == 20), as well as the $ra (offset 4), and the save registers (offsets going from -4 on down to -32). A simple example of this can be found

If your assembler allows you to have symbolic constants (SPIM does, MARS doesn't), you can use the following for the offsets:

#stack offsets
fp.ra = 4
fp.a0 = 8
fp.a1 = 12
fp.a2 = 16
fp.a3 = 20
fp.s0 = -4
fp.s1 = -8
fp.s2 = -12
fp.s3 = -16
fp.s4 = -20
fp.s5 = -24
fp.s6 = -28
fp.s7 = -32

And here is a (relatively) short example of a function using those offset constants:

###############################
# (char*, object*) read_line(char*)
# Read a line of text into the input buffer and parse it
###############################
read_line:
    addi $sp, $sp, -12
    sw $fp, 0($sp)
    addi $fp, $sp, 0
    sw $ra, fp.ra($fp)
    sw $a0, fp.a0($fp)  # a0 == pointer to current position in input buffer

    li $v0, read_string
    syscall
    lw $a0, fp.a0($fp)

    jal parse_object

    lw $a0, fp.a0($fp)
    lw $ra, fp.ra($fp)
    lw $fp, 0($sp)
    addi $sp, $sp, 12
    jr $ra

Note that you only need do all of this if the function calls other functions; if it doesn't, you usually can use just temporary registers ($t0 through $t9), and not bother with saving anything on the stack. Return values are passed through the $v0 and $v1 registers. The function return itself is done using the jump register (jr) instruction.

Edited 4 Years Ago by Schol-R-LEA

Thanks for enlightening me about MIPS, Schol-R-LEA. But I think you totally missed the point of my example code which was meant to highlight the concept, not provide a real solution to the problem for the target architecture. The assumptions I made are largely (if not totally) irrelevant, unless you can also confirm that C compilers targeting a MIPS system will use a calling convention that's completely different from and incompatible with the one I described.

Edited 4 Years Ago by deceptikon

This article has been dead for over six months. Start a new discussion instead.