Title: Storage
1Storage
- Storage Layout
- Where to put what
- How much space
- Alignment
Token Stream
Parser
Memory
Intermediate Code
Were going to start making some code with memory
allocations!
2Storage Usage
Code
What do each of these areas get used for?
Static Data
Heap
Heap grows up in memory, stack grows down.
Moving either is very hard to do. So, how do we
know where to place the stack and how much free
space to leave between?
Free Memory
Stack
3Storage Usage
Code
Constants, things that dont change, things that
stay at the same location forever.
Static Data
Heap
Free Memory
Stack
4Storage Usage
Code
Static Data
Heap
Allocations that extend beyond the current block.
new
Free Memory
Your compiler will use this for three address
code temporaries.
Stack
5Storage Usage
Code
Your compiler will put most of its variable
allocations on the stack.
Static Data
Heap
Free Memory
Stack
Allocations that are only valid within the
current block.
6Our goal
We want to create a compiler that generates
reasonable 3-address code. Well need to
create symbols in static memory and symbols on
the stack. Issues?
7Our goal
We want to create a compiler that generates
reasonable 3-address code. Well need to
create symbols in static memory and symbols on
the stack. Issues?
- How do we manage the stack?
- How much memory to allocate for a symbol?
- How to manage a symbol table that changes all of
the time? - Where do we put all of those temporary variables?
- Where does static memory start? After all, we
dont know how big our code will be until weve
compiled.
8How do real machines do this?
MIPS Assembly Language
fib subu sp, sp, 32 frame size 32, just
because... sw ra, 28(sp) preserve the
Return Address. sw fp, 24(sp) preserve the
Frame Pointer. sw s0, 20(sp) preserve
s0. sw s1, 16(sp) preserve s1. sw s2,
12(sp) preserve s2. addu fp, sp, 32
move Frame Pointer to base of frame. move s0,
a0 get n from caller. blt s0, 2,
fib_base_case if n lt 2, then do base case. sub
a0, s0, 1 compute fib (n - 1) jal fib
call subroutine jal move s1, v0 s1 fib (n
- 1). sub a0, s0, 2 compute fib (n -
2) jal fib move s2, v0 s2 fib (n -
2). add v0, s1, s2 v0 fib (n - 1) fib
(n - 2). b fib_return fib_base_case li v0,
1 fib_return lw ra, 28(sp) restore the
Return Address. lw fp, 24(sp) restore the
Frame Pointer. lw s0, 20(sp) restore
s0. lw s1, 16(sp) restore s1. lw s2,
12(sp) restore s2. addu sp, sp, 32
restore the Stack Pointer. jr ra return
fp
sw save word (memory) subu unsigned
subtract addu unsigned add blt branch if less
than jal call subroutine b branch lw load
word jr - return
9Function calling process (most basic)
- Push parameters onto the stack
- Call function (pushes return address on stack)
- Increment the stack to remove parameters
func(a, b) void func(int a, int b) int c
a int d b print(a)
print(d)
What exactly are the operations that get done
here? Could you write something like MIPS code
to do this?
TT
10The functions job
- Push registers onto the stack
- Decrement stack by enough for local variables
- do some work....
- Increment stack to skip over local variables
- Return
func(a, b) void func(int a, int b) int c
a int d b print(a)
print(d)
What exactly are the operations that get done
here? Could you write something like MIPS code
to do this?
11The general idea...
- Local variables are on the stack
- A block creates 0 or more variables on the stack
- End of block we increment the stack pointer
void fob(int n) int i int q 0
for(i0 iltn i) int b
(int)pow(i, 2) q q b
What exactly happens here?
12Before the call
sp
void fob(int n) int i int q 0
for(i0 iltn i) int b
(int)pow(i, 2) q q b
Upon entry to the function
13Outer block allocations
sp
void fob(int n) int i int q 0
for(i0 iltn i) int b
(int)pow(i, 2) q q b
Allocations for the local variables outer block
14Inner block allocations
void fob(int n) int i int q 0
for(i0 iltn i) int b
(int)pow(i, 2) q q b
sp
Allocations for the local variables inner block
Note that i was sp 4 before, now its sp 12.
15Cleanup at the end of the function
sp
void fob(int n) int i int q 0
for(i0 iltn i) int b
(int)pow(i, 2) q q b
At end of function
At end of first block, just increment the stack
pointer by the size of the local allocations.
What to do after the second block?
16How are you going to do this?
void fob(int n) int i int q 0
for(i0 iltn i) int b
(int)pow(i, 2) q q b
sp
Allocations for the local variables inner block
What are the issues involved?
TT
17Some things to watch out for
- We may use the same symbol name.
- We dont know the number of variables (and amount
of needed space) until all variables have been
allocated.
18Linked Symbol Tables
Symbol Table
x foo
int x void foo(int cat, char dog) int
bird int cage for(int j1 jlt10
j) char bug int dog b cat
dog
Symbol Table
cat dog bird cage
Symbol Table
bug dog
If you dont find it in the first one, look in
the next (recursive call)
19What about the sizes?
Symbol Table
0 (heap) x (code) foo
int x void foo(int cat, char dog) int
bird int cage for(int j1 jlt10
j) char bug int dog b cat
dog
Stack space 0
Symbol Table
0 cat 4 dog 8 bird 12 cage
Stack space 16
Symbol Table
0 bug 4 dog
When looking at the first symbol table, whats
the offset to bird?
Stack space 8
TT
20Three Address Code?
- What instructions do we need?
- Do we need a stack pointer?
- How so we push? pop? call? return?
Keep in mind that youre going to execute our
3-address code in project 3.
21Stack pointer
- We dont have registers!
- Well just use a memory location (static
location). - Location zero sounds good to me...
How might you notate this in your code? How do
you do a push?
22Push
sp a sp sp - 4
How would you write this in quad notation?
Call?
Seems reasonable to me...
23Call
call function
Seems like a good idea to have an operation for
this. What should it do?
24Return?
ret
Do we need this or is there another way assuming
only a jump?