CS61C Homework 3 - C to MIPS Practice Problems
TA: Sagar Karandikar
Spring 2015
This homework is an ungraded assignment designed to familiarize you with translating C code to MIPS.
We will release solutions on Sunday, Feb 22nd, so that you may use them to study for the exam.
Problem 1 - Useful Snippets
In this section, we’ll take the same problem (that of printing a string) and approach it using different C
constructs. This should allow you to see how various C constructs are translated into MIPS.
Suppose that we have a print function, but that this function only takes one character and prints it to
the screen. It expects the character to be in the lower 8 bits of $a0.
A) Translate into MIPS, while preserving the while loop structure:
void string_print(char *print_me) {
while (*print_me != ’\0’) {
print(*print_me);
print_me++;
}
}
Solution:
stringprint :
# p r o l o g u e , backup ra , backup s 0
addiu $sp , $sp , −8
sw $ra , 0 ( $sp )
sw $s0 , 4 ( $sp )
addiu $s0 , $a0 , 0 # copy a0 t o s 0 s o we don ’ t have t o back i t up
l b u $a0 , 0 ( $ s 0 ) # l o a d c h a r a c t e r f o r f i r s t i t e r a t i o n
Loop :
beq $a0 , $0 , Ret # break out o f l o o p i f l o a d e d c h a r a c t e r i s n u l l t e r m i n a t o r
j a l p r i n t # c a l l p r i n t ( t h i s i s why we l o a d e d t o a0 )
1
addiu $s0 , $s0 , 1 # i n c r e m e n t p o i n t e r
l b u $a0 , 0 ( $ s 0 ) # l o a d next c h a r a c t e r
j Loop
Ret :
# e p i l o g u e , r e s t o r e ra , r e s t o r e s 0
lw $s0 , 4 ( $sp )
lw $ra , 0 ( $sp )
addiu $sp , $sp , 8
j r $ra
B) Translate into MIPS, while preserving the for loop structure (your function is given the string length):
void string_print(char *print_me, int slen) {
for (int i = 0; i < slen; i++) {
print(*(print_me+i));
}
}
Solution:
stringprint :
# p r o l o g u e , backup ra , backup s0 , s1 , s 2
addiu $sp , $sp , −16
sw $ra , 0 ( $sp )
sw $s0 , 4 ( $sp )
sw $s1 , 8 ( $sp )
sw $s2 , 1 2 ( $sp )
addiu $s0 , $a0 , 0 # copy a0 t o s 0 s o we don ’ t have t o back i t up
addiu $s1 , $a1 , 0 # copy a1 t o s 1 s o we don ’ t have t o back i t up
addiu $s2 , $0 , 0 # i n i t i a l i z e l o o p c o u n t e r
Loop :
beq $s2 , $s1 , Ret # break out o f l o o p i f i == s l e n
addu $a0 , $s2 , $ s 0
l b u $a0 , 0 ( $a0 ) # g e t f i r s t c h a r
j a l p r i n t # c a l l p r i n t ( t h i s i s why we l o a d e d t o a0 )
addiu $s2 , $s2 , 1 # i n c r e m e n t l o o p var
j Loop
Ret :
2
# e p i l o g u e , r e s t o r e ra , r e s t o r e s0 , s1 , s 2
lw $s2 , 1 2 ( $sp )
lw $s1 , 8 ( $sp )
lw $s0 , 4 ( $sp )
lw $ra , 0 ( $sp )
addiu $sp , $sp , 16
j r $ra
C) Translate into MIPS, while preserving the do while loop structure:
void string_print(char *print_me) {
if (!(*print_me)) {
return;
}
do {
print(*print_me);
print_me++;
} while (*print_me);
}
Solution:
stringprint :
# p r o l o g u e , backup ra , backup s 0
addiu $sp , $sp , −8
sw $ra , 0 ( $sp )
sw $s0 , 4 ( $sp )
addiu $s0 , $a0 , 0 # copy a0 t o s 0 s o we don ’ t have t o back i t up
l b u $a0 , 0 ( $ s 0 ) # l o a d c h a r a c t e r f o r f i r s t i t e r a t i o n
beq $a0 , $0 , Ret # do n o t h i n g i f l o a d e d c h a r a c t e r i s n u l l t e r m i n a t o r
Loop :
j a l p r i n t # c a l l p r i n t ( t h i s i s why we l o a d e d t o a0 )
addiu $s0 , $s0 , 1 # i n c r e m e n t p o i n t e r
l b u $a0 , 0 ( $ s 0 ) # l o a d next c h a r a c t e r
bne $a0 , $0 , Loop # c o n t i n u e l o o p i f l o a d e d c h a r a c t e r i s not n u l l t e r m i n a t o r
Ret :
# e p i l o g u e , r e s t o r e ra , r e s t o r e s 0
lw $s0 , 4 ( $sp )
lw $ra , 0 ( $sp )
addiu $sp , $sp , 8
3
j r $ra
Problem 2 - Recursive Fibonacci
Convert the following recursive implementation of Fibonacci to MIPS. Do not convert it to an iterative
solution.
int fib(int n) {
if (n == 0) {
return 0;
} else if (n == 1) {
return 1;
}
return fib(n-1) + fib(n-2);
}
Solution:
# n o t e : t h i s s o l u t i o n i s i n s t r u c t i o n a l and not n e c e s s a r i l y o p t i m i z e d
fib :
addiu $sp , $sp , −12
sw $ra , 0 ( $sp ) #backup r a f o r r e c u r s i v e c a l l s
sw $a0 , 4 ( $sp ) #backup a0 f o r r e c u r s i v e c a l l s
sw $s0 , 8 ( $sp ) #backup s 0 s i n c e we u s e i t
beq $a0 , $0 , ReturnZero
addiu $t0 , $0 , 0
s l t i $t0 , $a0 , 2 # you can a l s o beq with one
bne $t0 , $0 , ReturnOne
addiu $a0 , $a0 , −1
jal fib
move $s0 , $v0
lw $a0 , 4 ( $sp )
addiu $a0 , $a0 , −2
jal fib
add $v0 , $v0 , $ s 0
lw $s0 , 8 ( $sp )
lw $ra , 0 ( $sp )
addiu $sp , $sp , 12
4
j r $ra
ReturnZero :
# e p i l o g u e j u s t t o make our r e t u r n s c o n s i s t e n t
lw $s0 , 8 ( $sp )
lw $ra , 0 ( $sp )
addiu $sp , $sp , 12
l i $v0 , 0
j r $ra
ReturnOne :
# e p i l o g u e j u s t t o make our r e t u r n s c o n s i s t e n t
lw $s0 , 8 ( $sp )
lw $ra , 0 ( $sp )
addiu $sp , $sp , 12
l i $v0 , 1
j r $ra
Problem 3 - Memoized Fibonacci
Now, modify your recursive Fibonacci implementation to memoize results. For the sake of simplicity, you
can assume that the array given to you (memolist) is at least n elements long for any n. Additionally, the
array is initialized to all zeros.
int fib(int n, int* memolist) {
if (n == 0) {
return 0;
} else if (n == 1) {
return 1;
}
if (memolist[n]) {
return memolist[n];
}
memolist[n] = fib(n-1, memolist) + fib(n-2, memolist);
return memolist[n];
}
Solution:
# n o t e : t h i s s o l u t i o n i s i n s t r u c t i o n a l and not n e c e s s a r i l y o p t i m i z e d
fib :
5
addiu $sp , $sp , −12
sw $ra , 0 ( $sp ) #backup r a f o r r e c u r s i v e c a l l s
sw $a0 , 4 ( $sp ) #backup a0 f o r r e c u r s i v e c a l l s
sw $s0 , 8 ( $sp ) #backup s 0 s i n c e we u s e i t
beq $a0 , $0 , ReturnZero
addiu $t0 , $0 , 0
s l t i $t0 , $a0 , 2 # you can a l s o beq with one
bne $t0 , $0 , ReturnOne
# not t h e n = 1 o r n = 0 c a s e s , check memoized t a b l e
s l l $t0 , $a0 , 2 # c o n v e r t n t o o f f s e t ( i n t s a r e 4 b y t e s )
addiu $t0 , $t0 , $a1 # add o f f s e t t o b a s e p o i n t e r ( $a1 )
lw $v0 , 0 ( $ t 0 )
bne $v0 , $0 , RetMemo
# not i n t a b l e , compute i t t h e old−f a s h i o n e d way
addiu $a0 , $a0 , −1
jal fib
move $s0 , $v0
lw $a0 , 4 ( $sp )
addiu $a0 , $a0 , −2
jal fib
add $v0 , $v0 , $ s 0
# s t o r e copy i n t h e memoize t a b l e
lw $a0 , 4 ( $sp ) # f i r s t , r e s t o r e a0
s l l $t0 , $a0 , 2 # c o n v e r t n t o o f f s e t ( i n t s a r e 4 b y t e s )
addiu $t0 , $t0 , $a1 # add o f f s e t t o b a s e p o i n t e r ( $a1 )
sw $v0 , 0 ( $ t 0 )
# epilogue
lw $s0 , 8 ( $sp )
lw $ra , 0 ( $sp )
addiu $sp , $sp , 12
j r $ra
ReturnZero :
# e p i l o g u e j u s t t o make our r e t u r n s c o n s i s t e n t
lw $s0 , 8 ( $sp )
lw $ra , 0 ( $sp )
6
addiu $sp , $sp , 12
l i $v0 , 0
j r $ra
ReturnOne :
# e p i l o g u e j u s t t o make our r e t u r n s c o n s i s t e n t
lw $s0 , 8 ( $sp )
lw $ra , 0 ( $sp )
addiu $sp , $sp , 12
l i $v0 , 1
j r $ra
RetMemo : # r e t u r n s v a l u e a l r e a d y i n v0
# epilogue
lw $s0 , 8 ( $sp )
lw $ra , 0 ( $ s 0 )
addiu $sp , $sp , 12
j r $ra
Problem 4 - Self-Modifying MIPS
Write a MIPS function that performs identically to this code when called many times in a row, but does not
store the static variable in the static segment (or even the heap or stack):
short nextshort() {
static short a = 0;
return a++;
}
Tips/Hints:
• You can assume that the short type is 16 bits wide. shorts represent signed numbers.
• You can assume that your MIPS code is allowed to modify any part of memory.
• See the title of this question.
Solution:
nextshort :
addiu $v0 , $0 , 0
l a $t0 , n e x t s h o r t
lw $t1 , 0 ( $ t 0 )
addiu $t3 , $0 , 0xFFFF
7
and $t2 , $t1 , $ t 3
beq $t2 , $t3 , H a n d l e S p e c i a l
addiu $t1 , $t1 , 1
sw $t1 , 0 ( $ t 0 ) # s t o r e i n c r e m e n t e d i n s t r u c t i o n
j r $ r a # r e t v a l u e i s a l r e a d y i n v0
H a n d l e S p e c i a l : # here , h a n d l e t h e o v e r f l o w c a s e
l a $t6 , b a c k u p i n s t
lw $t1 , 0 ( $ t 6 )
sw $t1 , 0 ( $ t 0 )
j r $ r a # r e t v a l u e i s a l r e a d y i n v0
backupinst :
addiu $v0 , $0 , 0