Vous êtes sur la page 1sur 46

MIPS Procedures

CS270
Max Luttrell, Fall 2016
procedures
• high level language: procedure, function,
method, subroutine
procedure needs
1. put parameters in a place where procedure can
access them

2. transfer control to the procedure

3. acquire storage resources the procedure needs (if


necessary)

4. perform the task

5. put the result somewhere the calling program can


access it

6. return control to point of origin in the calling program


MIPS procedure support
• Registers
register(s) name purpose

$a0-$a3 pass parameters to


argument register
procedures
$v0-$v1 return values from
value register
procedures
$ra return address register store return address

• Instructions
instru name purpose example
ction jump jump to location and store jal ProcedureAddress
jal
and link return address in $ra
jump jump to address in
jr jr $ra
register register
simple procedure
example
main
- put parameter(s) in $a0-$a3
- jal ProcedureAddress # puts PC+4 in $ra and
# jumps to ProcedureAddress

- use return values in $v0, $v1 to do something

ProcedureAddress:
- use parameters in $a0-$a3 to compute result
- put result in $v0, $v1
- jr $ra # jumps back to $ra, origin point in main
stack
• to save variables, we
use a stack
$sp high memory
• the $sp register points address
to the top of stack

• push -- subtract 4
from $sp, then add a
word to the stack

• pop -- remove a word


from the stack and low memory
add 4 to $sp address
stack example
• push (7)

value addr
$sp
$sp 0x10 0x10

0xC

0x8

0x4
stack example
• push (7) - done

• push (3) value addr


$sp
0x10 0xC

$sp 7 0xC

0x8

0x4
stack example
• push (7) - done

• push (3) - done value addr


$sp
• pop () 0x10 0x8

7 0xC

$sp 3 0x8

0x4
stack example
• push (7) - done

• push (3) - done value addr


$sp
• pop () - done 0x10 0xC

$sp 7 0xC

0x8

0x4
MIPS procedure
• previously, we wrote MIPS code for the following
C statement, assuming the f,g,h,i,j variables are
assigned to registers $s0, $s1, $s2, $s3, and
$s4:

f = (g+h) - (i+j);
add $t0, $s1, $s2 # put g+h in $t0
add $t1, $s3, $s4 # put i+j in $t1
sub $s0, $t0, $t1 # put $t0-$t1 in f
# note $t0 is now g+h; $t1 is i+j

• let's make a procedure out of it


MIPS procedure
int leaf_example(int g, int h, int i, int j)
{
int f;
f = (g+h) - (i+j);
return f;
}

leaf_example:
addi $sp, $sp, -12 # adjust stack to make room for 3 words
sw $t1, 8($sp) # save $t1 to stack
sw $t0, 4($sp) # save $t0 to stack
sw $s0, 0($sp) # save $s0 to stack
...

• first, let's save all the registers we will use to the stack
MIPS procedure
int leaf_example(int g, int h, int i, int j)
{
int f;
f = (g+h) - (i+j);
return f;
}

...
add $t0, $a0, $a1 # $t0 gets g+h
add $t1, $a2, $a3 # $t1 gets i+j
sub $s0, $t0, $t1 # $s0 gets (g+h) - (i+j)
...

• now, let's do our computation


MIPS procedure
int leaf_example(int g, int h, int i, int j)
{
int f;
f = (g+h) - (i+j);
return f;
}

...
add $v0, $s0, $zero # put result in $v0 for return
...

• now, let's put the result into return register $v0


MIPS procedure
int leaf_example(int g, int h, int i, int j)
{
int f;
f = (g+h) - (i+j);
return f;
}

...
lw $s0, 0($sp) # restore $s0 for caller
lw $t0, 4($sp) # restore $t0 for caller
lw $t1, 8($sp) # restore $t1 for caller
addi $sp, $sp, 12 # adjust stack to pop 3 items
...

• now, let's restore the registers we saved to the stack


MIPS procedure
int leaf_example(int g, int h, int i, int j)
{
int f;
f = (g+h) - (i+j);
return f;
}

...
jr $ra

• finally, let's jump back to the caller. done!


MIPS procedure
• Note: unlike the previous example, typically we
wouldn't save $t registers during function calls
since they are temporary; but need to save $s
registers (and some others…)

• We will discuss what needs to be saved, and


who needs to save it, in detail later
parameter passing - general
• On many systems,
parameters are all passed on other data higher memory
for caller address
the stack, there aren't
arg d
dedicated registers like MIPS' 12($sp)
$a0-$a3. Consider this
arg c
function: 8($sp)
int foo(int a, int b, int c, int d) arg b
4($sp)

$sp at entry to foo() arg a lower memory


0($sp) address
parameter passing - MIPS
• On MIPS, space is in fact allocated on stack
for four argument registers $a0-$a3 when a
function is called.

• However, by default, the values are not put on


the stack, since they are in $a0-$a3.

• For a function with >4 arguments, the


additional arguments are put on the stack
parameter passing
- MIPS example
arg e
higher memory
• MIPS: first 4 arguments go in 16($sp)
address
$a0-$a3, additional arguments reserved for
callee $a3
go on stack. 12($sp)
reserved for
• Consider this function: callee $a2
8($sp)
int foo(int a, int b, int c, int d, int e)
reserved for
{
callee $a1
a += b;
4($sp)
a += c;
reserved for lower memory
a += d;
$sp callee $a0
address
a += e; 0($sp)
return a;
} arg a arg b arg c arg d

$a0 $a1 $a2 $a3


MIPS parameters example
int foo(int a, int b, int c, int d, int e) {
a += b;
a += c;
a += d;
a += e;
return (a);
}
# int foo(int a, int b, int c, int d, int e) {
foo:
# a += b;
add $a0,$a0,$a1
# a += c;
add $a0,$a0,$a2
# a += d;
add $a0,$a0,$a3
# a += e;
lw $t0,16($sp)
add $a0,$a0,$t0
# return (a);
# now our result is in $a0. put in $v0 to return
move $v0,$a0
jr $ra
}
procedure use of registers
• There is only one set of registers on the machine

• Whichever function is executing "owns" the $a


registers, $t registers, $v registers, and $ra.

• If you call a procedure, you must assume that all


of these registers have been destroyed!
who saves registers?
• Traditionally, either the caller or the callee had to
save all registers the callee uses.

• MIPS convention:

• caller saves t-registers, a-registers, v-registers


if necessary, i.e. if they are in use and used
after procedure call

• callee saves s-registers, $ra (return address),


$gp (global pointer) if necessary
local variables
• We have now seen storing arguments, and $ra/
$gp on the stack

• we also need somewhere to store local variables

int proc2(int);
int proc1(void) {
int a=10, b=40;
a = a + proc2(b);
return (a);
}
order of items on stack
int proc2(int);
int proc1(void) {
• Inside of a call to proc1, looking int a=10, b=40;
"up" the stack, here is what you a = a + proc2(b);
return (a);
should see, in order: }

• argument area ($a0-$a3) Stack during proc1


• any additional arguments (if data item address
more than 4)
$ra 24($sp)
• local variables (in any order
you want, we chose b 20($sp)
alphabetical)
a 16($sp)
• saved registers (in increasing
$sp -> argument 0($sp)
register number order) area
proc1
# int proc1(void) { int proc2(int);
proc1: addiu $sp,$sp,-28 int proc1(void) {
sw $ra,24($sp) int a=10, b=40;
# int a=10, b=40; a = a + proc2(b);
li $t0,10 return (a);
sw $t0, 16($sp) }
li $t0, 40
sw $t0, 20($sp)
# a = a + proc2(b);
lw $a0, 20($sp) data item address
jal proc2
lw $t0, 16($sp) $ra 24($sp)
add $t0,$t0,$v0
sw $t0,16($sp)
# return (a); b 20($sp)
lw $v0,16($sp)
# } a 16($sp)
lw $ra,24($sp)
addiu $sp,$sp,28 argument 0($sp)
jr $ra area
proc1: first try proc1: optimized
# int proc1(void) { # int proc1(void) {
proc1: addiu $sp,$sp,-28 proc1: addiu $sp,$sp,-24
sw $ra,24($sp) sw $ra,20($sp)
# int a=10, b=40; # int a=10, b=40;
li $t0,10 li $t0,10
sw $t0, 16($sp) sw $t0, 16($sp)
li $t0, 40 li $t1, 40 # use $t1 for b
sw $t0, 20($sp)
# a = a + proc2(b); # a = a + proc2(b);
lw $a0, 20($sp) move $a0, $t1
jal proc2 jal proc2
lw $t0, 16($sp) lw $t0, 16($sp)
add $t0,$t0,$v0 # don't store final value
sw $t0,16($sp) # for a, just return it
# return (a); add $v0, $t0, $v0
lw $v0,16($sp) # return (a);
# }
lw $ra,24($sp) # }
addiu $sp,$sp,28 lw $ra,20($sp)
jr $ra addiu $sp,$sp,24 data address
data address jr $ra item
$ra 24($sp) $ra 20($sp)
b 20($sp) a 16($sp)
a 16($sp)
arg 0($sp) arg area 0($sp)
proc1 with parameter
• Let's change proc1 so that a is a parameter instead of a
local variable:

int proc2(int);
int proc1(int a) {
int b=40;
a = a + proc2(b);
return (a);
}

• Note: we will continue to use a t-register for local


variable b.

• Note: we still need a after our function call to proc2. So


we need to save a somewhere.
proc1 with parameter
# int proc1(int a) { int proc2(int);
proc1: addiu $sp,$sp,-20 int proc1(int a) {
sw $ra,16($sp) int b=40;
# int b=40; a = a + proc2(b);
li $t1, 40 # use $t1 for b return (a);
# a = a + proc2(b); }
sw $a0,20($sp) # home a
move $a0,$t1
jal proc2 Stack
lw $t0, 20($sp) # restore a
# no need to store the final data item address
# value of a, just return it
# plus return value from proc2. c
add $v0,$t0,$v0 a ...
l
# return (a); l
# } e arg area reserved
20($sp)
lw $ra,16($sp) r for callee (proc1)
addiu $sp,$sp,20 p $ra 16($sp)
jr $ra r
o
c arg area reserved
1 0($sp)
for callee (proc2)
procedure call steps - 1
1. At call, caller:

• allocates room on stack for any caller save


registers (if not done at entry)

• saves caller-save registers (t-registers, v-


registers) and homes its a-registers (if needed)

• loads argument registers and places additional


arguments on the stack if more than 4
arguments (room for arguments should have
been allocated at procedure entry)
procedure call steps - 2
2. At entry, unless it is a leaf, callee:

• creates stack frame to allocate space for (in this order


from top (high address) to bottom (low address)):

• return address ($ra)

• any s-registers it uses

• local variables (including room to save t-registers if


necessary)

• room for arguments for any procedures it calls

• saves $ra and any s-registers it uses


procedure call steps - 3, 4
3. At exit from procedure, callee:

• restores s-registers and $ra

• deallocates stack frame

• returns to caller

4. Upon returning, caller:

• restores t-registers and a-registers (if necessary)

• deallocates room it added to stack frame before call


(if any)
stack example
• an example with no code: data item address

$ra 20($sp)
• main() calls f1(), which m
a
calls f2() $s0 16($sp) i
n
• main() $sp arg area 0($sp)

• called by system with no


arguments

• uses $s0

• calls f1(), which has 2


arguments
stack example
• f1() data item address

• calls f2() with 5 arguments: $ra 56($sp)


m
a, b, c, d, e a
$s0 52($sp) i
n
• uses $s3 and $s1 arg area 36($sp)
$ra 32($sp)
• modifies its arg regs as it
calculates, and needs $s3 28($sp)
them after it calls f2()
$s1 24($sp) f
1
• uses temporary register $t0 20($sp)
$t0 for a value that it wants
e 16($sp)
to preserve across call to
f2()
$sp arg area 0($sp)
stack example
• f2() data item address

$ra 56($sp)
m
• is a leaf (does not call a
$s0 52($sp) i
any other procedures) n
arg area 36($sp)
• only uses t-registers $ra 32($sp)

$s3 28($sp)

$s1 24($sp) f
1
$t0 20($sp)
e 16($sp)
arg area
$sp 0($sp)
(a,b,c,d)
nmatches
• Let's look at a slightly more complicated
example
int equiv (char, char);

int nmatches(char *str, char comp) {


char c;
int n=0;
while ((c = *str) != 0) {
if (equiv(c,comp) != 0) n++;
str++;
}
return (n);
}
nmatches
• Here's the ugly C version:
int equiv (char, char);
int nmatches(char *str, char comp) {
char c;
int n=0;
Lnmatchesloop:
c = *str;
if (c == 0) goto Lnmatchesloopend;
if (equiv(c,comp) == 0) goto Lnmatchesskip;
n++;
Lnmatchesskip:
str++;
goto Lnmatchesloop;
Lnmatchesloopend:
return (n);
}

• Note: you can find this at:


/pub/cs/mluttrel/cs270/examples/mips
nmatches variable analysis

value int equiv (char, char);


int nmatches(char *str, char comp) {
needed
variable char c;
after call to int n=0;
equiv? Lnmatchesloop:
c = *str;
c no if (c == 0)
goto Lnmatchesloopend;
if (equiv(c,comp) == 0)
n yes goto Lnmatchesskip;
n++;
Lnmatchesskip:
str yes str++;
goto Lnmatchesloop;
Lnmatchesloopend:
comp yes return (n);
}
nmatches variables
saved on stack
• Approach: save variables on stack

• c: don't need to save, use t-reg. nice!

• n: local variable - allocate a word on stack

• str, comp: parameters - home them in caller's


reserved argument area

• Code:
/pub/cs/mluttrel/cs270/examples/mips/nmatches1.s
nmatches variables
stored in s-registers
• Alternate pproach: save variables in s-registers

• c: don't need to save, use t-reg. nice!

• n: local variable - put it in an s-register

• str, comp: parameters - put them both in s-


registers

• Code:
/pub/cs/mluttrel/cs270/examples/mips/nmatches1_sregs.s
global variables
• In addition to the stack, which holds arguments, registers, and
locals, we need memory for global/static variables and dynamically
allocated memory (i.e. "malloc" in C, "new" in C++/java)

$sp starts here, stack memory higher memory


grows down address

lowest stack address


highest static address static memory

dynamically
allocated
pre-allocated lower memory
(globals) address
Exercise 5A
• In this exercise, we will call a procedure, but we will not use the
stack to save and restore registers this time. This is not correct
behavior, but is a good starting point to introduce us to
procedures.

• You can get a starting file from hills by using the following scp
command (all one line; replace uname with your username):

scp uname@hills.ccsf.edu:/pub/cs/mluttrel/cs270/exercises/
procedures/first_proc.s .

• There are four missing parts to this program (2 in main, 2 in the


procedure). Follow the instructions to add code in parts 1-4.
• If you are running MARS on your own laptop, you will need to
save the file util.s on your local drive, and modify the last line of
first_proc.s to indicate the directory where you saved it. If you are
on a Linux box, this file is in the right place; don’t modify this line.
scp uname@hills.ccsf.edu:/pub/cs/mluttrel/cs270/util.s .
Exercise 5B
1. Get the file add6.s:
scp uname@hills.ccsf.edu:/pub/cs/mluttrel/cs270/
exercises/procedures/add6.s .

2. Review the code in main() and make sure you


understand how the function call to add6 works
3. This function must add together 6 integer arguments
and return the result. The first four arguments are in the
$a0-$a3 registers, you need to figure out where the other
two are! Once you determine this, write the function.
4. If you’re running on your laptop, don’t forget to save
util.s locally update the line including util.s at the bottom
of add6.s with the correct location
scp uname@hills.ccsf.edu:/pub/cs/mluttrel/cs270/util.s .
Exercise 5C

fog.ccsf.edu/~mluttrel/cs270/exercises/ex5c.html
Exercise 5D

fog.ccsf.edu/~mluttrel/cs270/exercises/ex5d.html
Exercise 5E

fog.ccsf.edu/~mluttrel/cs270/exercises/ex5e.html

Vous aimerez peut-être aussi