0% found this document useful (0 votes)
34 views

Lecture 8- Code Generation

Copyright
© © All Rights Reserved
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
34 views

Lecture 8- Code Generation

Copyright
© © All Rights Reserved
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 19

Code Generation

Compiler construction
Code Generation
 Code generation can be considered as the final
phase of the compilation.
 In post code generation phase, optimization process
can be applied on the code, but that can be seen as a
part of code generation phase itself.
 The code generated by the compiler is an object
code of some lower-level programming language,
for example, assembly language.
 Lower-level object code should have the following
minimum properties:
 It should carry the exact meaning of source
code.
It should be efficient in terms of CPU
usage and memory management.
Compiler Design
1
Directed Acyclic Graph (DAG)
 Directed Acyclic Graph (DAG) is a tool that depicts the
structure of basic blocks, helps to see the flow of values
flowing among the basic blocks and offers optimization too.

 DAG provides easy transformation on basic blocks.

 The nodes of a DAG can be described as:


 Leaf nodes represent identifiers, names or constants.
 Interior nodes represent operators.
Interior nodes also represent the results of
expressions or the identifiers/name where the values are
to be stored or assigned.

Compiler Design
1
Directed Acyclic Graph (DAG)..
Example:

t0=a+b t1=t0+c d=t0+t1

Compiler Design
1
Peephole Optimization
 This optimization technique works locally on the source
code to transform it into an optimized code. By locally, it
means a small portion of the code block at hand.
 These methods can be applied on intermediate codes as
well as on target codes.
 A bunch of statements are analyzed and checked for
the following possible optimizations:
1. Redundant instruction elimination
2. Unreachable code
3. Flow of control optimization
4. Algebraic expression simplification
5. Strength reduction
6. Accessing machine instructions

Compiler Design
1
Peephole Optimization..
1. Redundant instruction elimination
At compilation level, the compiler searches for
redundant instructions. Multiple loading and storing of
instructions may carry the redundancy as shown below:
MOV x,
R0 MOV
R0, R1
Can be re-written as:
MOV x,
R1

Compiler Design
1
Peephole Optimization..
2. Unreachable Code
Unreachable code is a part of the program code that is
never accessed during the program execution.
void add_ten(int x)
{
x=x+10;
return x;
printf(“value of x is %d”, x);
}
In this code segment, the printf statement will never
be executed as the program control returns back
before it can execute. Hence printf can be removed.

Compiler Design
1
Peephole Optimization..
3. Flow of Control Optimization
There are instances in a code where the program control
jumps back and forth without performing any significant task.
These jumps can be removed.
Consider the following chunk of code:
... ...
MOV R1, R2 MOV R1, R2
GOTO L1
...
=> GOTO L2
...
L1 : GOTO L2 : INC R1
L2 L2 :INC R1

Compiler Design
1
Peephole Optimization..
4. Algebraic Expression Simplification
There are several cases when algebraic expressions can be
made simple.
Example:
a = a + 0 can be replaced by a
Or a = a * 1 can be replaced by a

Compiler Design
1
Peephole Optimization..
5. Strength Reduction
There are some operations that consume more time and
space. Their ‘strength’ can be reduced by replacing them with
other operations that consume less time and space, but
produce the same result.
Example:
x2 can be replaced by x << 1
Or 2x can be replaced by x+x

Compiler Design
10
Peephole Optimization..
6. Accessing Machine Instructions
The target machine can deploy more sophisticated
instructions, which can have the capability to perform specific
operations much efficiently. If the target code can
accommodate those instructions directly, that will not only
improve the quality of code, but also yield more efficient
results.
Example:
x=x+1 can be replaced by INC x
Or, y=y-1 can be replaced by DCR
y

Compiler Design
10
Code Generator
A code generator is expected to have an understanding
of the target machine’s runtime environment and its
instruction set.
The code generator should take the following
things into consideration to generate the code:
1.Target language : The code generator has to be
aware of the nature of the target language for which
the code is to be transformed. That language may
facilitate some machine- specific instructions to help
the compiler generate the code in a more convenient
way. The target machine can have either CISC or RISC
processor architecture.
2.IR Type : Intermediate representation has various
forms. It can be in Abstract Syntax Tree (AST)
structure, Reverse Polish Notation, or 3-address code.
Compiler Design
10
Code Generator..
3.Selection of instruction : The code generator
takes Intermediate Representation as input and
converts (maps) it into target machine’s instruction set.
One representation can have many ways (instructions)
to convert it, so it becomes the responsibility of the
code generator to choose the appropriate instructions
wisely.
4.Register allocation : A program has a number of
values to be maintained during the execution. The
target machine’s architecture may not allow all of the
values to be kept in the CPU memory or registers.
Code generator decides what values to keep in the
registers. Also, it decides the registers to be used to
keep these values.
Compiler Design
10
Code Generator..
5. Ordering of instructions : At last, the code generator
decides the order in which the instruction will be executed. It
creates schedules for instructions to execute them.

Compiler Design
10
Descriptors
The code generator has to track both the registers
(for availability) and addresses (location of
values) while generating the code. For both of
them, the following two descriptors are used:
1. Register descriptor : Register descriptor is used to
inform the code generator about the availability of
registers. Register descriptor keeps track of values
stored in each register. Whenever a new register is
required during code generation, this descriptor is
consulted for register availability.

Compiler Design
10
Descriptors..
2.Address descriptor : Values of the names
(identifiers) used in the program might be stored at
different locations while in execution. Address descriptors
are used to keep track of memory locations where the
values of identifiers are stored. These locations may include
CPU registers, heaps, stacks, memory or a combination of
the mentioned locations.

Example:
For a load statement, LD R1, x, the code generator:
(i)updates the Register Descriptor R1 that has
value of x and
(ii)updates the Address Descriptor (x)
to show that one instance of x is in R1.
Compiler Design
10
Code Generation
Basic blocks comprise of a sequence of three-address
instructions. Code generator takes these sequence of
instructions as input.
Note : If the value of a name is found at more than one place
(register, cache, or memory), the register’s value will be
preferred over the cache and main memory. Likewise cache’s
value will be preferred over the main memory. Main memory
is barely given any preference.

Compiler Design
10
Code Generation
getReg : Code generator uses getReg function to
determine the status of available registers and the
location of name values.getReg works as follows:
If variable Y is already in register R, it
uses that register.
Else if some register R is available, it
uses that register.
Else if both the above options are not possible, it
chooses a register that requires minimal number of load
and store instructions.

Compiler Design
10
Code Generation
For an instruction x = y OP z, the code generator may
perform the following actions. Let us assume that L is the
location (preferably register) where the output of y OP z is to
be saved:
Call function getReg, to decide the location of L.
Determine the present location (register or memory)
of yby consulting the Address Descriptor of y. If y is
not presently in register L, then generate the following
instruction to copy the value of y to L:
MOV y’, L
where y’ represents the copied value of y.

Compiler Design
10

You might also like