[go: up one dir, main page]

0% found this document useful (0 votes)
105 views16 pages

Position of Code Generator: Principles of Compiler Design Lecture Notes

The document discusses code generation in compiler design. It describes the code generator as the final phase that takes an intermediate representation of the source program and produces an equivalent target program. It outlines several issues in designing a code generator including the input, target program format, memory management, instruction selection, register allocation, and evaluation order. It then provides details about the target machine, including its instruction set and addressing modes. It concludes by covering run-time storage management and examples of implementing call and return statements for static allocation.

Uploaded by

fiker123
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOC, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
105 views16 pages

Position of Code Generator: Principles of Compiler Design Lecture Notes

The document discusses code generation in compiler design. It describes the code generator as the final phase that takes an intermediate representation of the source program and produces an equivalent target program. It outlines several issues in designing a code generator including the input, target program format, memory management, instruction selection, register allocation, and evaluation order. It then provides details about the target machine, including its instruction set and addressing modes. It concludes by covering run-time storage management and examples of implementing call and return statements for static allocation.

Uploaded by

fiker123
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOC, PDF, TXT or read online on Scribd
You are on page 1/ 16

Principles of Compiler Design lecture Notes

Chapter 6 CODE GENERATION

The final phase in compiler model is the code generator. It takes as input an intermediate
representation of the source program and produces as output an equivalent target program. The
code generation techniques presented below can be used whether or not an optimizing phase
occurs before code generation.

Position of code generator

source front end intermediate code intermediate code target


program optimizer generator program

symbol
table

ISSUES IN THE DESIGN OF A CODE GENERATOR

The following issues arise during the code generation phase :

1. Input to code generator


2. Target program
3. Memory management
4. Instruction selection
5. Register allocation
6. Evaluation order

1. Input to code generator:


 The input to the code generation consists of the intermediate representation of the source
program produced by front end , together with information in the symbol table to
determine run-time addresses of the data objects denoted by the names in the
intermediate representation.

 Intermediate representation can be :


a. Linear representation such as postfix notation
b. Three address representation such as quadruples
c. Virtual machine representation such as stack machine code
d. Graphical representations such as syntax trees and dags.

 Prior to code generation, the front end must be scanned, parsed and translated into
intermediate representation along with necessary type checking. Therefore, input to code
generation is assumed to be error-free.

2. Target program:

Compiled and Prepared by Dr.Anusuya


Principles of Compiler Design lecture Notes
 The output of the code generator is the target program. The output may be :
a. Absolute machine language
- It can be placed in a fixed memory location and can be executed immediately.
b. Relocatable machine language
- It allows subprograms to be compiled separately.

c. Assembly language
- Code generation is made easier.

3. Memory management:
 Names in the source program are mapped to addresses of data objects in run-time
memory by the front end and code generator.

 It makes use of symbol table, that is, a name in a three-address statement refers to a
symbol-table entry for the name.

 Labels in three-address statements have to be converted to addresses of


instructions. For example,
j : goto i generates jump instruction as follows :
 if i < j, a backward jump instruction with target address equal to location of
code for quadruple i is generated.
 if i > j, the jump is forward. We must store on a list for quadruple i the
location of the first machine instruction generated for quadruple j. When i
is processed, the machine locations for all instructions that forward jumps
to i are filled.

4. Instruction selection:
 The instructions of target machine should be complete and uniform.

 Instruction speeds and machine idioms are important factors when efficiency of target
program is considered.

 The quality of the generated code is determined by its speed and size.

 The former statement can be translated into the latter statement as shown below:

5. Register allocation
 Instructions involving register operands are shorter and faster than those involving
operands in memory.

 The use of registers is subdivided into two subproblems :


 Register allocation – the set of variables that will reside in registers at a point in
Compiled and Prepared by Dr.Anusuya
Principles of Compiler Design lecture Notes
the program is selected.

 Register assignment – the specific register that a variable will reside in is picked.

 Certain machine requires even-odd register pairs for some operands and
results. For example , consider the division instruction of the form :
D x, y

where, x – dividend even register in even/odd register


pair y – divisor
even register holds the
remainder odd register holds the
quotient
6. Evaluation order
 The order in which the computations are performed can affect the efficiency of the
target code. Some computation orders require fewer registers to hold intermediate
results than others.

TARGET MACHINE

 Familiarity with the target machine and its instruction set is a prerequisite for designing a
good code generator.
 The target computer is a byte-addressable machine with 4 bytes to a word.
 It has n general-purpose registers, R0, R1, . . . , Rn-1.
 It has two-address instructions of the form:
op source, destination
where, op is an op-code, and source and destination aredata fields.
 It has the following op-codes :
MOV (move source to destination)
ADD (add source to destination)
SUB (subtract source from destination)

 The source and destination of an instruction are specified by combining registers


and memory locations with address modes.

Address modes with their assembly-language forms

MODE FORM ADDRESS ADDED COST

Absolute M M 1

Register R R 0

Indexed c(R) c+contents(R) 1

Compiled and Prepared by Dr.Anusuya


Principles of Compiler Design lecture Notes
indirect register *R contents (R) 0

indirect indexed *c(R) contents(c+ 1


contents(R))

Literal #c c 1

 For example : MOV R0, M stores contents of Register R0 into memory location M ;
MOV 4(R0), M stores the value contents(4+contents(R0)) into M.

Instruction costs :

 Instruction cost = 1+cost for source and destination address modes. This cost corresponds
to the length of the instruction.
 Address modes involving registers have cost zero.
 Address modes involving memory location or literal have cost one.
 Instruction length should be minimized if space is important. Doing so also minimizes
the time taken to fetch and perform the instruction.
For example : MOV R0, R1 copies the contents of register R0 into R1. It has cost one,
since it occupies only one word of memory.
 The three-address statement a : = b + c can be implemented by many different
instruction sequences :

i) MOV b, R0
ADD c, R0 cost = 6
MOV R0, a

ii) MOV b, a
ADD c, a cost = 6

iii) Assuming R0, R1 and R2 contain the addresses of a, b, and c :


MOV *R1, *R0
ADD *R2, *R0 cost = 2

 In order to generate good code for target machine, we must utilize its
addressing capabilities efficiently.
RUN-TIME STORAGE MANAGEMENT

 Information needed during an execution of a procedure is kept in a block of storage


called an activation record, which includes storage for names local to the procedure.
 The two standard storage allocation strategies are:
1. Static allocation
2. Stack allocation
 In static allocation, the position of an activation record in memory is fixed at compile
time.
 In stack allocation, a new activation record is pushed onto the stack for each execution of
a procedure. The record is popped when the activation ends.
 The following three-address statements are associated with the run-time allocation and
Compiled and Prepared by Dr.Anusuya
Principles of Compiler Design lecture Notes
deallocation of activation records:
1. Call,
2. Return,
3. Halt, and
4. Action, a placeholder for other statements.
 We assume that the run-time memory is divided into areas for:
1. Code
2. Static data
3. Stack

Static allocation

Implementation of call statement:

The codes needed to implement static allocation are as follows:

MOV #here +20, callee.static_area /*It saves return address*/

GOTO callee.code_area /*It transfers control to the target code for the called procedure */

where,
callee.static_area – Address of the activation record callee.code_area
– Address of the first instruction for called procedure
#here +20 – Literal return address which is the address of the instruction following GOTO.

Implementation of return statement:

A return from procedure callee is implemented by :

GOTO *callee.static_area

This transfers control to the address saved at the beginning of the activation record.

Implementation of action statement:

The instruction ACTION is used to implement action statement.

Implementation of halt statement:

The statement HALT is the final instruction that returns control to the operating system.

Stack allocation

Static allocation can become stack allocation by using relative addresses for storage in
activation records. In stack allocation, the position of activation record is stored in register so
words in activation records can be accessed as offsets from the value in this register.
The codes needed to implement stack allocation are as follows:

Initialization of stack:

Compiled and Prepared by Dr.Anusuya


Principles of Compiler Design lecture Notes
MOV #stackstart , SP /* initializes stack */

Code for the first procedure

HALT /* terminate execution */

Implementation of Call statement:

ADD #caller.recordsize, SP /* increment stack pointer */

MOV #here +16, *SP /*Save return address */

GOTO callee.code_area

where,
caller.recordsize – size of the activation record
#here +16 – address of the instruction following the GOTO

Implementation of Return statement:

GOTO *0 (SP ) /*return to the caller */

SUB #caller.recordsize, SP /* decrement SP and restore to previous value */

BASIC BLOCKS AND FLOW GRAPHS

Basic Blocks

 A basic block is a sequence of consecutive statements in which flow of control enters at


the beginning and leaves at the end without any halt or possibility of branching except at
the end.
 The following sequence of three-address statements forms a basic
block:

t1 : = a * a
t2 : = a * b
t3 : = 2 * t 2
t4 : = t1 + t3
t5 : = b * b
Compiled and Prepared by Dr.Anusuya
Principles of Compiler Design lecture Notes
t6 : = t4 + t5

Basic Block Construction:

Algorithm: Partition into basic blocks

Input: A sequence of three-address statements

Output: A list of basic blocks with each three-address statement in exactly one block

Method:

1. We first determine the set of leaders, the first statements of basic blocks. The rules
we use are of the following:
a. The first statement is a leader.
b. Any statement that is the target of a conditional or unconditional goto is a
leader.
c. Any statement that immediately follows a goto or conditional goto statement
is a leader.
2. For each leader, its basic block consists of the leader and all statements up to but not
including the next leader or the end of the program.

Compiled and Prepared by Dr.Anusuya


Principles of Compiler Design lecture Notes

 Consider the following source code fordot product of two vectors a and b of length 20

begin

prod :=0;

i:=1; do

begin

prod :=prod+ a[i]* b[i];

i :=i+1;

end

while i <= 20

end

 The -three-address code for the above source program is


given as
: :
(1) prod := 0

(2) i := 1

(3) t1 := 4* i

(4) t2 := a[t1] /*compute a[i] */

(5) t3 := 4*i

(6) t4 := b[t3] /*compute b[i] */

(7) t5 := t2*t4

(8) t6 := prod+t5

(9) prod := t6

(10) t7 := i+1

(11) i := t7

(12) if i<=20 goto (3)

Basic block 1: Statement (1) to (2)

Basic block 2: Statement (3) to (12)


Compiled and Prepared by
Dr.Anusuya
Principles of Compiler Design lecture Notes
Transformations on Basic Blocks:

A number of transformations can be applied to a basic block without changing the set of
expressions computed by the block. Two important classes of transformation are :

 Structure-preserving transformations

 Algebraic transformations

1. Structure preserving transformations:

a) Common subexpression elimination:

Compiled and Prepared by Dr.Anusuya


Principles of Compiler Design
lecture Notes

a:=b+c a:=b+c
b:=a–d b:=a-d
c:=b+c c:=b+c
d:=a–d d:=a-d

Compiled and Prepared by Dr.Anusuya


Principles of Compiler Design lecture Notes
Since the second and fourth expressions compute the same expression, the basic block can be
transformed as above.

b) Dead-code elimination:

Suppose x is dead, that is, never subsequently used, at the point where the statement x : =
y + z appears in a basic block. Then this statement may be safely removed without changing
the value of the basic block.

c) Renaming temporary variables:

A statement t : = b + c ( t is a temporary ) can be changed to u : = b + c (u is a new


temporary) and all uses of this instance of t can be changed to u without changing the value of
the basic block.
Such a block is called a normal-form block.

d) Interchange of statements:

Suppose a block has the following two adjacent statements:

t1 : = b + c
t2 : = x + y

We can interchange the two statements without affecting the value of the block if and
only if neither x nor y is t1 and neither b nor c is t2.
2. Algebraic transformations:

Algebraic transformations can be used to change the set of expressions computed by a basic
block into an algebraically equivalent set.
Examples:
i) x : = x + 0 or x : = x * 1 can be eliminated from a basic block without changing the set of
expressions it computes.
ii) The exponential statement x : = y * * 2 can be replaced by x : = y * y.

Flow Graphs
Compiled and Prepared by Dr.Anusuya
Principles of Compiler Design lecture Notes

 Flow graph is a directed graph containing the flow-of-control information for the set of
basic blocks making up a program.
 The nodes of the flow graph are basic blocks. It has a distinguished initial node.
 E.g.: Flow graph for the vector dot product is given as follows:

prod : = 0 B1
i:=1

t1 : = 4 * i
t2 : = a [ t1 ]
t3 : = 4 * i B2
t4 : = b [ t3 ]
t5 : = t2 * t4
t6 : = prod +
t5 prod : = t6
t7 : = i + 1
i : = t7
if i <= 20 goto B2

 B1 is the initial node. B2 immediately follows B1, so there is an edge from B 1 to B2. The
target of jump from last statement of B 1 is the first statement B2, so there is an edge from
B1 (last statement) to B2 (first statement).
 B1 is the predecessor of B2, and B2 is a successor of B1.

Loops

 A loop is a collection of nodes in a flow graph such that


1. All nodes in the collection are strongly connected.
2. The collection of nodes has a unique entry.
 A loop that contains no other loops is called an inner loop.

NEXT-USE INFORMATION

 If the name in a register is no longer needed, then we remove the name from the register
and the register can be used to store some other names.

Compiled and Prepared by Dr.Anusuya


Principles of Compiler Design lecture Notes
Input: Basic block B of three-address statements

Output: At each statement i: x= y op z, we attach to i the liveliness and next-uses of


x, y and z.

Method: We start at the last statement of B and scan backwards.

1. Attach to statement i the information currently found in the symbol table


regarding the next-use and liveliness of x, y and z.
2. In the symbol table, set x to “not live” and “no next use”.
3. In the symbol table, set y and z to “live”,and next-uses of y and z to i.

Symbol Table:

Names Liveliness Next-use

X not live no next-use

Y Live i

Z Live i

A SIMPLE CODE GENERATOR

 A code generator generates target code for a sequence of three- address statements and
effectively uses registers to store operands of the statements.

 For example: consider the three-address statement

a = b+c It can have the following sequence of codes:

ADD Rj, Ri Cost = 1 // if Ri contains b and Rj contains c

(or)

ADD c, Ri Cost = 2 // if c is in a memory location

(or)

MOV c, Rj Cost = 3 // move c from memory to Rj and add

ADD Rj, Ri

Register and Address Descriptors:


Compiled and Prepared by
Dr.Anusuya
Principles of Compiler Design lecture Notes

 A register descriptor is used to keep track of what is currently in each registers. The
register descriptors show that initially all the registers are empty.
 An address descriptor stores the location where the current value of the name can be
found at run time.

A code-generation algorithm:

The algorithm takes as input a sequence of three -address statements constituting a basic
block. For each three-address statement of the form x : = y op z, perform the following
actions:

1. Invoke a function getreg to determine the location L where the result of the computation y
op z should be stored.

2. Consult the address descriptor for y to determine y’, the current location of y. Prefer the
register for y’ if the value of y is currently both in memory and a register. If the value
of y is not already in L, generate the instruction MOV y’ , L to place a copy of y in L.

3. Generate the instruction OP z’ , L where z’ is a current location of z. Prefer a register


to a memory location if z is in both. Update the address descriptor of x to indicate
that x is in location L. If x is in L, update its descriptor and remove x from all other
descriptors.

4. If the current values of y or z have no next uses, are not live on exit from the block, and
are in registers, alter the register descriptor to indicate that, after execution of x : = y op
z , those registers will no longer contain y or z.

Generating Code for Assignment Statements:

 The assignment d : = (a-b) + (a-c) + (a-c) might be translated into the following three-
address code sequence:
t:=a–b
u:=a–c
v:=t+u
d:=v+u
with d live at the end.

Code sequence for the example is:


Compiled and Prepared by
Dr.Anusuya
Principles of Compiler Design lecture Notes

Statements Code Generated Register descriptor Address descriptor

Register empty

t:=a–b MOV a, R0 R0 contains t t in R0


SUB b, R0

u:=a–c MOV a , R1 R0 contains t t in R0


SUB c , R1 R1 contains u u in R1

v : =t + u ADD R1, R0 R0 contains v u in R1


R1 contains u v in R0

d:=v+u ADD R1, R0 R0 contains d d in R0


d in R0 and memory
MOV R0, d

Generating Code for Indexed Assignments

The table shows the code sequences generated for the indexed assignment statements
a : = b [ i ] and a [ i ] : = b

Statements Code Generated Cost

a : = b[i] MOV b(Ri), R 2

a[i] : = b MOV b, a(Ri) 3

Generating Code for Pointer Assignments

The table shows the code sequences generated for the pointer assignments
a : = *p and *p : = a

Statements Code Generated Cost

a : = *p MOV *Rp, a 2

*p : = a MOV a, *Rp 2

Generating Code for Conditional Statements

Compiled and Prepared by


Dr.Anusuya
Principles of Compiler Design lecture Notes

Statements Code Generated

CMP x, y
if x < y goto z CJ< z

MOV y, R0
ADD z, R0
MOV R0,x
x : = y +z if x <0 goto z CJ< z

Compiled and Prepared by


Dr.Anusuya

You might also like