Programming Languages and Translators

Lecture 23: Code Generation

April 16, 2014

- 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

- 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.

- 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

- 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.

- 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.

*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
```

`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
```

`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
```

`x = *p`

we can generate```
LD R1, p // R1 = p
LD R2, 0(R1) // R2 = contents(0 + contents(R1))
ST x, R2 // x = R2
```

`*p = y`

we can generate```
LD R1, p // R1 = p
LD R2, y // R2 = y
ST 0(R1), R2 // contents(0 + contents(R1)) = R2
```

`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
```

`M`

is the label of the first machine instruction
generated from the three-address instruction that has label `L`

- 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.

- ALSU, Exercise 8.2.5, p. 517.
- ALSU, Exercise 8.4.1, p. 531.
- ALSU, Exercise 8.10.2, p. 573.

- ALSU, Sections 8.1-8.6, 8.10

aho@cs.columbia.edu