COMS W4115
Programming Languages and Translators
Lecture 22: Code Generation
April 15, 2015
Lecture Outline
- Issues in code generation
- Categories of target machines
- Primary tasks of a code generator
- Basic blocks and flow graphs
- Our model target machine
- Optimal code generation for expression trees
1. Issues in Code Generation
- The role of the code generator is to translate the IR produced
by the font end of the compiler into good target machine code.
- Challenges of code generation
- The target program must preserve the semantic meaning of the
source program.
- The target program should make efficient use of the target
machine's resources.
- The code generator itself should be efficient.
- The problem of optimal code generation is undecidable.
- Many subproblems in code generation, such as optimal register
allocation, are computationally intractable.
- The design of a good code generator often reverts to the problem of
designing good heuristics.
2. Categories of Target Machines
- Reduced instruction set machines (RISC)
- many registers
- three-address instructions
- simple addressing modes
- simple instruction set architecture
- Complex instruction set machines (CISC)
- few registers
- two-address instructions
- variety of addressing modes
- several register classes
- variable-length instructions
- instructions with side effects
- Stack-based machines
- push operands onto stack
- perform operations on operands at top of stack
- stack kept in registers
- model for Java Virtual Machine
- Multicore machines
3. Primary Tasks of a Code Generator
- Instruction selection
- Determining factors:
- level of IR
- nature of ISA
- desired quality of generated code
- Register allocation and assignment
- Register allocation determines the set of variables that
will reside in registers at each point in the program.
- Register assignment determines the specific register in which
a variable will reside.
- Evaluation order
- Some computation orders require fewer registers to hold intermediate
results than others.
- Picking an optimal order in the general case is NP-complete.
4. Basic Blocks and Flow Graphs
- A basic block is a maximal sequence of consecutive three-address
instructions such that
- The flow of control can only enter the basic block throught the
first instruction in the block.
- Control will leave the block without halting or branching
except possibly at the last instruction in the block.
- A flow graph for the basic blocks of an intermediate program
can be constructed as follows:
- The basic blocks are the nodes of the flow graph.
- There is an edge from block B to block C iff it is possible
for the first instruction in C to immediately follow the last
instruction in B.
- A set of nodes L in a flow graph is a loop if
- There is a node in L called the loop entry with the property
that no other node in L has a predecessor outside L.
- Every node in L has a nonempty path completely within L to
the entry of L.
5. Our Model Target Machine
- n general-purpose registers
- Instructions: load, store, compute, jump, conditional jump
- Various addressing modes:
- indexed address
- integer indexed by a register
- indirect addressing
- immediate constant
- Example 1: for
x = y + z
we can generate
LD R1, y // R1 = y
LD R2, z // R2 = z
ADD R1, R1, R2 // R1 = R1 + R2
ST x, R1 // x = R1
Example 2: for b = a[i]
where a is an
array of integers we can generate
LD R1, i // R1 = i
MUL R1, R1, #4 // R1 = R1 * 4
LD R2, a(R1) // R2 = contents(a + contents(R1))
ST b, R2 // b = R2
Example 3: for a[j] = c
where a is an
array of integers we can generate
LD R1, c // R1 = c
LD R2, j // R2 = j
MUL R2, R2, #4 // R2 = R2 * 4
ST a(R2), R1 // contents(a + contents(R2)) = R1
Example 4: for x = *p
we can generate
LD R1, p // R1 = p
LD R2, 0(R1) // R2 = contents(0 + contents(R1))
ST x, R2 // x = R2
Example 5: for *p = y
we can generate
LD R1, p // R1 = p
LD R2, y // R2 = y
ST 0(R1), R2 // contents(0 + contents(R1)) = R2
Example 6: for if x < y goto L
we can generate
LD R1, x // R1 = x
LD R2, y // R2 = y
SUB R1, R1, R2 // R1 = R1 - R2
BLTZ R1, M // if R1 < 0 jump to M
Here M
is the label of the first machine instruction
generated from the three-address instruction that has label L
Instruction cost: 1 + cost associated with the addressing modes of the operands
6. Optimal Code Generation for Expression Trees
- In this section we assume we are using an n-register machine with
instructions of the form
LD reg, mem
ST mem, reg
OP reg, reg, reg
- to evaluate expressions.
- Ershov numbers
- An expression tree is a syntax tree for an expression.
- Numbers, called Ershov numbers, can be assigned to label the nodes of an expression
tree. The Ershov number at a node gives the minimum number of registers needed
to evaluate on a register machine the expression generated by that node
with no spills. A spill is a store instruction that gets generated
when there are no empty registers and a register is needed to perform
a computation.
- Algorithm to label the nodes of an expression tree with Ershov numbers
- Label all leaves 1.
- The label of an interior node with one child is the label of its child.
- The label of an interior node with two children is the larger of the
labels of its children if these labels are different; otherwise, it is
one plus the label of the left child.
- Sethi-Ullman algorithm
generates register machine code that minimizes the number of spills to evaluate
an expression tree. Ershov numbers guide the evaluation order.
- Input: an expression tree labeled with Ershov and a k-register machine.
- Output: an optimal sequence of register machine instructions to evaluate
the root of the tree into a register.
- The details of the algorithm are in Section 8.10 of ALSU, pp. 567-573.
7. Practice Problems
- ALSU, Exercise 8.2.5, p. 517.
- ALSU, Exercise 8.4.1, p. 531.
- ALSU, Exercise 8.10.2, p. 573.
8. Reading
- ALSU, Sections 8.1-8.6, 8.10
aho@cs.columbia.edu