Lecture 19

Problem:

You cannot know the offsets until all declarations have been processed, because $30 changes with each new declaration.

int wain(int a, int b) { 
    int c = 0;
    return a; 
}
Name Type Offset from $30
a int 8
b int 4
c int 0

Introdue two conventions:

  1. $4 always contains 4
  2. $29 points to the bottom of the stack frame
int wain(int a, int b) {
    int c = 0;
    return a;
}
lis $4
.word 4
sub $29, $30, $4
sw  $1, -4($30)
sw  $2, -8($30)
sw  $0, -12($30)
lis $5
.word 12
sub $30, $30, $12
lw  $3, 0($29)
add $30, $30, $5
jr  $31
Name Type Offset from $29
a int 0
b int -4
c int -8

$29 is called the frame pointer.

What about more complicated programs?

int wain(int a, int b) {
    return a + b;
}

In general: for every grammar rule \(A\rightarrow\gamma\) build code(\(A\)) from code(\(gamma\)).

Extend previous convention: use $3 as "output" for all expressions.

a + b
$3<-eval(a)
$3<-eval(a) -- value of a is lost!
$3<-$3 + $3

Need a place to store pending computation could use a reg:

code(a+b)=code(a)           ($3<-a)
          add $5, $3, $0    ($5<-a)
          code(b)           ($3<-b)
          add $3, $5, $3    ($3<-a+b)

What about \(a+(b+c)\)?

code(a+(b+c)) = code(a)           ($3<-a)
                add $5, $3, $0    ($5<-a)
                code(b)           ($3<-b)
                add $6, $3, $0    ($3<-b)
                code(c)           ($3<-c)
                add $3, $6, $3    ($3<-(b+c))
                add $3, $5, $3    ($3<-a+(b+c))

Similarly \(a+(b+(c+d))\) would need \(3\) extra registers. Eventually run out of registers

More general solution: use the stack

code(a) ($3<-a)
push($3)
code(b) ($3<-b)
push($3)
code(c) ($3<-c)
push($3)
code(d) ($3<-d)
pop($5) ($5<-c)
add $3, $5, $3  ($3<-c+d)
pop($5) ($5<-b)
add $3, $5, $3  ($3<-b+(c+d))
pop($5) ($5<-a)
add $3, $5, $3  ($3<-a+(b+(c+d)))

Only one extra register!

In general: \(expr_1->expr_2+term\)

code(expr_1) = code(expr_2)
             + push($3)
             + code($term$)
             + pop($5)
             + add $3, $5, $3

Singleton Rules: easy -- \(expr->term\)

code(\(expr\))=code(\(term\))

println(expr)

print expr, followed by newline

You did this already! A2P6, A2P7a

Runtime environment: set of procedures supplied by the complier (or the OS) to assist programs in their execution

Procedure print will be part of the runtime environment. We will provide print.merl

./wlp4gen < prog.wlp4i > prog.asm
java cs241.linkasm < prog.asm > prog.merl
linker prog.merl print.merl > exec.mips

So assume "print" is available -- takes input int $1

code(println(expr)) = code(expr)
                    + add $1, $3, $0
                    + call print

remember to save and restore $31

Assignment

statement->lvalue=expr

For now: assume lvalue is ID (no pointers yet)

statement->lvalue=expr
code(statement)=code(expr) ($3<-expr)
sw $3, offset in symbol table($29)

If and While

code so far

Prologue

.import print
lis     $4
.word   4
lis     $10
.word   print
lis     $11
.word   1
sub     $29, $30, $4

Epilogue

add $30, $29, $4
jr  $31
test->expr1<expr2
code(test) = code(expr1)    ($3<-expr1)
           + add $6, $3, $0 ($6<-expr2)
           + code(expr2)    ($3<-expr2)
           + slt $3, $6, $0 ($3<-expr1<expr2)
test->expr1>expr2
    treat as expr2<expr1, as above