CSCE 434 Lecture 33
« previous | Wednesday, November 13, 2013 | next »
Register Allocation
- Virtual Registers: map "enough" into reality
- Targeting: Prioritize by some "good" metric
Lots of "fuzzy" terms
Intermediate Representation
We will be targeting RISC-like processors
We will abstract RISC as a:
- load-store architecture
- register-transfer language (RTL)
- three-address code
- explicit loads and stores
Examples:
load r1, <addr> # r1 = value at <addr> loadi r1, <const> # r1 = value of <const> store r1, <addr> # <addr> = r1 move r1, r2 # r1 = r2 add r1, r2, r3 # r1 = r2 + r3 sub r1, r2, r3 # r1 = r2 - r3 mult r1, r2, r3 # r1 = r2 * r3 jmp <addr> # jump to <addr>
Storage Layout
Local:
- stack frames
- offsets from frame pointer
Global: offset from known global label
Static: offset from procedure's static data section
Varied size storage
- local, non-static: top of stack frame
- other: allocate on heap
Assign variables to virtual registers
Treat those that can't be in a register carefully.
- depends on register allocator
Simple Expressions
- Represent as simple tree
- assign virtual register to each operator
- emit code in postorder walk
Routines:
base(str)
- name of virtual register that contains base address forstr
.offset(str)
- name of virtual register that contains offset ofstr
newtemp()
- return new virtual register name
Assumptions:
- tree represents correct precedence and associativity
- all operands are integers
int expr(Node *node)
{
int result, t1, t2, t3;
switch (node.type) {
case PLUS:
t1 = expr(node.left);
t2 = expr(node.right);
result = newtemp();
emit(ADD, result, t1, t2);
break;
case ID:
t1 = base(node.val);
t2 = offset(node.val);
t3 = newtemp();
emit(ADD, t3, t1, t2);
break;
case NUM:
result = newtemp();
emit(LOADI, result, node.val);
break;
}
return result;
}
Control Structures
Assignment
Strategy:
- Evaluate RHS to value
- Evaluate LHS to an address
- if LHS is a register, move it
- if LHS is an address, store it
Registers vs. Memory
- non-aliased scalars can go in registers
- aggregate or potentially aliased: put in memory
Aliased values can belong to multiple processes/threads, so the correct value of that variable must be accessible in memory.
Basic Blocks
Defined as:
- A sequence of straight line code
- If the first instruction executes, they all execute
- A maximal sequence of instructions without branches/jumps
- A label starts a new basic block.
Early optimization work focused on basic blocks.
- common subexpression elimination
- constant folding (realizing that
int i = 3 + 7;
is the same asint i = 10;
- "optimal" code generation
- list scheduling
If-Then-Else
- evaluate expression to
true
orfalse
- If
true
, fall through tothen
part; branch aroundelse
part - if
false
, jump toelse
part; fall through to next statement
Example:
r1 = expr if not(r1) br L1 ... then section ... br L2 L1: ... else section ... L2: ... following statement ...
While/Do Loops
- evaluate control expression
- if
false
, branch beyond end of loop - if
true
, fall through into loop body - At end, re-evaluate control expression
- If
true
, branch to top of loop body - If
false
, fall through
Example:
r1 = expr if not(r1) br L2 L1: ... loop body ... r1 = expr if r1 br L1 L2: ... following statement ...
Since the test is at the end, the simple loop is one block
Case Statements
- evaluate control expression
- branch to selected case
- execute its code
- branch to the following statement
How to find the right case?
- linear search (few cases)
- binary search (sparse cases)
- jump table (dense cases)
Procedure Calls
Prolog
- save registers
- extend basic frame
- find static data area (if needed)
- initialize locals
Start of call
:
- allocate child's frame
- evaluate and store params
- store frame pointer and return address
- set frame pointer for child
- jump to child
Post-Call code:
- copy return value
- restore params (if needed)
- free up child's frame
Epilog Code
- store return value
- unextend basic frame
- restore registers
- restore parent's frame pointer
- jump to return address.