0% found this document useful (0 votes)
18 views54 pages

13-Issues in The Design of A Code Generator - 22!10!2024

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

13-Issues in The Design of A Code Generator - 22!10!2024

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

BCSE307L – Compiler Design

Module 6 – Code Generation

Dr. M.Bhuvaneswari
Assistant Professor Senior Grade 2
School of Computer Science and
Engineering,
Vellore Institute of Technology,
Vellore – 632014
Code Generation
• The final phase in our compiler model is the code generator.
• It takes as input the intermediate representation (IR)
produced by the front end of the compiler, along with
relevant symbol table information, and produces as output a
semantically equivalent target program
• The target program must preserve the semantic meaning of
the source program and must make effective use of the
available resources of the target machine (Eg. Register
Allocation)

Position of code
Code Generation
A code generator has three primary tasks:
1. Instruction Selection
• Instruction selection involves choosing appropriate target-machine
instructions to implement the IR statements.

2. Register Allocation and Assignment


• Register allocation and assignment involves deciding what values
to keep in which registers.

3. Instruction Ordering
• Instruction ordering involves deciding in what order to schedule
the execution of instructions.
Issues in Code
Generation
Issues in Code Generation
• Issues in Code Generation are:
1. Input to code generator

2. Target program

3. Memory management

4. Instruction selection

5. Register allocation

6. Order of evaluation
1. Input to code generator
• Input to the code generator consists of the intermediate
representation of the source program.
• Types of intermediate language are:
1. Linear representation - Postfix notation
2. 3AC representation – Quadruples, triples & indirect triples
3. Graphical representation - Syntax trees or DAGs
4. VM representation – bytecode and stack-machine code
• The detection of semantic error should be done before
submitting the input to the code generator.
• The code generation phase requires complete error free
intermediate code as an input. [necessary type checking has
taken place, and that type conversion operators have been
inserted wherever necessary]
2. Target program
• The instruction-set architecture of the target machine has a significant
impact on the difficulty of constructing a good code generator that produces
high-quality machine code.
• The most common target-machine architectures are RISC (reduced
instruction set computer), CISC (complex instruction set computer), and
stack based.

1. A RISC machine typically has many registers, three-address instructions,


simple addressing modes, and a relatively simple instruction-set
architecture.

2. In contrast, a CISC machine typically has few registers, two-address


instructions, a variety of addressing modes, several register classes,
variable-length instructions, and instructions with side effects.

3. In a stack-based machine, operations are done by pushing operands onto a


stack and then performing the operations on the operands at the top of the
2. Target program
• The output/target may be in form of:
1. Absolute machine language:
• Absolute machine language program can be placed in a fixed
memory location and immediately executed.
• Small/simple programs.
2. Relocatable machine language (Object module):
• Program can be placed in a dynamic memory location
• The subroutine can be compiled separately. A set of relocatable
object modules can be linked together (linker) and loaded for
execution (loader).
3. Assembly language:
• Producing an assembly language program as output makes the
process of code generation easier, then assembler is require to
convert code in binary form.
3. Memory management
• Mapping names in the source program to addresses of data
objects in run time memory is done cooperatively by the front
end and the code generator using the symbol table.

• We assume that a name in a three-address statement refers to


a symbol table entry for the name.

• From the symbol table information, a relative address can be


determined for the name in a data area.
4. Instruction selection
• The code generator must map the IR program into a code
sequence that can be executed by the target machine.
• The complexity of performing this mapping is determined by
factors such as
1. The level of the IR (High / Low)
2. The nature of the instruction-set architecture
3. The desired quality of the generated code
4. Instruction selection
• Example: the sequence of statements
a := b + c
d := a + e
• would be translated into
MOV b, R0
ADD c, R0
MOV R0, a
MOV a, R0
ADD e, R0
MOV R0, d
• Here, the third and fourth statement is redundant, which can
be eliminated.
Cont…
5. Register allocation
• The use of registers is often subdivided into two sub
problems:
1. During register allocation, we select the set of variables that
will reside in registers at a point in the program.
2. During a subsequent register assignment phase, we pick the
specific register that a variable will reside in.
• Finding an optimal assignment of registers to variables is
difficult, even with single register value.
• Mathematically, the problem is NP-complete.
• Example
6. Order of evaluation
• The order in which computations are performed can
affect the efficiency of the target code.
• Some computation orders require fewer registers to hold
intermediate results than others.
• Picking a best order is another difficult issue, NP-
complete problem.
Approaches to code generation
• The most important criterion for a code generator is that it
produces correct code.
• The design of code generator should be in such a way so it can
be implemented, tested, and maintained easily.
The Target Machine
Target machine
• We will assume our target computer models a three-address
machine with load and store operations, computation
operations, jump operations, and conditional jumps.

• Assume, the underlying computer is a byte-addressable


machine with general-purpose registers,

• Consider only a very limited set of instructions and assume


that all operands are integers.

• Most instructions consists of an operator, followed by a


target, followed by a list of source operands. A label may
precede an instruction.
Cont…
• We assume the following kinds of instructions are
available:
1. Load operations:
• The instruction LD dst, addr loads the value in location addr
into location dst. This instruction denotes the assignment dst
= addr.
• Eg. LD r, x which loads the value in location x into register r.
• Eg. LD r1, r2 is a register-to-register copy in which the
contents of register r2 are copied into register r1.

2. Store operations:
• The instruction ST x, r stores the value in register r into the
location x. This instruction denotes the assignment x = r.
Cont…
• We assume the following kinds of instructions are available:
3. Computation operations
• Form: OP dst, src1, src2, where OP is a operator like ADD or SUB, and dst, src1,
and src2 are locations, not necessarily distinct.
• Eg. SUB r1, r2, r3 computes r1 = r2 - r3. Any value formerly stored in r1 is lost,
but if r1 is r2 or r3, the old value is read first.
• Unary operators that take only one operand do not have a src2.
4. Unconditional jumps:
• Form: BR L causes control to branch to the machine instruction with label L. (BR
stands for branch.)
5. Conditional jumps:
• Form: Bcond r, L, where r is a register, L is a label, and cond stands for any of the
common tests on values in the register r.
• Eg. BLTZ r, L causes a jump to label L if the value in register r is less than zero,
and allows control to pass to the next machine instruction if not.
Instruction Cost
• The address modes (to find the effective address) together with
the assembly language forms and associated cost are as
follows:
Mode Form Address Extra cost
Absolute M M 1
Register R R 0
Indexed k(R) k +contents(R) 1
Indirect *R contents(R) 0
register
Indirect *k(R) contents(k + 1
indexed contents(R))
Immediate or #C NA 1
literal

• The instruction cost can be computed as one plus cost


Example
Instruction Cost
Mode Form Address Extra
cost
Absolute M M 1
Register R R 0
Indexed k(R) k +contents(R) 1
Indirect *R contents(R) 0
register
• Calculate cost for following:
Indirect *k(R) contents(k + 1
indexed contents(R))
MOV B,R0 MOV B,R0 cost = 1+1+0=2
ADD C,R0 ADD C,R0 cost = 1+1+0=2
MOV R0,A
MOV R0,A cost = 1+0+1=2

Total Cost=6
Example
Instruction Cost – Cont…
Mode Form Address Extra
cost
Absolute M M 1
Register R R 0
Indexed k(R) k +contents(R) 1
Indirect *R contents(R) 0
register
Indirect *k(R) contents(k + 1
• Calculate cost for following:
indexed contents(R))
MOV *R1 ,*R0 MOV *R1 ,*R0  cost = 1+0+0=1
ADD *R2 ,*R0 ADD *R2 ,*R0  cost = 1+0+0=1

Total Cost=2
Instruction Cost – Cont…
Mode Form Address Extra
cost
Absolute M M 1
Register R R 0
Indexed k(R) k +contents(R) 1
Indirect *R contents(R) 0
register
Indirect *k(R) contents(k + 1
• Calculate cost for following:
indexed contents(R))
ADD R2 ,R1 ADD R2 ,R1  cost = 1+0+0=1
MOV R1, a MOV R1, a  cost = 1+0+1=2

Total Cost=3
Next Use Information
Computing Next Uses
• The next-use information is a collection of all the names that
are useful for next subsequent statement in a block.
• Knowing when the value of a variable will be used next is essential for
generating good code.
• If the value of a variable that is currently in a register will never be
referenced subsequently, then that register can be assigned to another
variable.

• The use of a name is defined as follows,


• Consider a statement,
x := i
j := x op y
• That means the statement j uses value of x.
• The next-use information can be collected by making the
Storage for Temporary Names
• For the distinct names each time a temporary is needed. And
each time a space gets allocated for each temporary.
• To have optimization in the process of code generation we pack
two temporaries into the same location if they are not live
simultaneously.
• Consider three address code as,
t1=a*a t1=a*a
t2=a*b t2=a*b
t3=4*t2 t2=4*t2
t4=t1+t3 t1=t1+t2
t5=b*b t2=b*b
t6=t4+t5 t1=t1+t2
Register and Address Descriptors
• The code generator algorithm uses descriptors to keep track of
register contents and addresses for names.
• Address descriptor stores the location where the current
value of the name can be found at run time. The information
about locations can be stored in the symbol table and is used to
access the variables.
• Register descriptor is used to keep track of what is currently
in each register. The register descriptor shows that initially all
the registers are empty. As the generation for the block
progresses the registers will hold the values of computation.
Algorithm: Determining the liveness and
next-use information for each statement in
a basic block.
• INPUT: A basic block B of three-address statements.
We assume that the symbol table initially shows all
non-temporary variables in B as being live and
temporary variables are dead.

• OUTPUT: At each statement i: x = y + z in B, we


attach to i the liveness and next-use information of x, y,
Cont…
• METHOD: We start at the last statement in B and scan
backwards to the beginning of B. At each statement i: x = y
+ z in B, we do the following:
1. Attach to statement i the information currently found in the
symbol table regarding the next use and liveness 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 the next uses of y and
z to i.

• Here we have used + as a symbol representing any operator.


Cont…

• If the three-address statement i is of the form x = +y or x = y,


the steps are the same as above, ignoring z.
• Note that the order of steps (2) and (3) may not be interchanged
because x may be y or z.
Example
Example – What are the live variables in
both B2 and B3?
Answer is r and u

P q r s u v
2 D L L D L D
3 D D L L L L
Example
Initial condition
Solution
Register Allocation &
Assignment
Register Allocation & Assignment
• Efficient utilization of registers is important in generating good
code.
• Assign specific values in target program to certain registers
such as base address, arithmetic computations and top of
stack.
• There are four strategies for deciding what values in a program
should reside in a registers and which register each value
should reside.
• Strategies are:
1. Global Register Allocation
2. Usage Count
3. Register assignment for outer loop
4. Register allocation using graph coloring
1. Global Register Allocation
• Global register allocation strategies are:
• The global register allocation has a strategy of storing the most
frequently used variables in fixed registers throughout the
loop.
• Another strategy is to assign some fixed number of global
registers to hold the most active values in each inner loop.
(Register Assignment)
• The registers are not already allocated may be used to hold
values local to one block.
• In certain languages like C or Bliss programmer can do the
register allocation by using register declaration to keep certain
values in register for the duration of the procedure.
• Example:
{
2. Usage count
• The usage count is the count for the use of some variable x in
some register used in any basic block.

• The usage count gives the idea about how many units of cost
can be saved by selecting a specific variable for global register
allocation.

• The approximate formula for usage count can be given as,

• Where is number of times x used in block prior to any definition of


• if is live on exit from and is assigned a value in B; otherwise .
Example Note: Assume here some of the statements (conditional statements) in the
basic blocks are not specified in detail. Hence assume the liveness of
variables as per the given CFG to find usage count.

B1 B2 B3 B4 Usage count /
units of cost
a (0+ (1+ (1+ (0+ 4
2) 0) 0) 0)
b (2+ (0+ (0+ (0+ 6
0) 0) 2) 2)
c (1+ (0+ (1+ (1+ 3
0) 0) 0) 0)
d (1+ (1+ (1+ (1+ 6
2) 0) 0) 0)
e (0+ (0+ (0+ (0+ 4
2) 0) 2) 0)
f (1+ (0+ (1+ (0+ 4
0) 2) 0) 0)
R0 R1 R2
a or e or b d
f
3. Register assignment for outer loop
• Consider that there are two loops is outer loop and is an inner
loop, and register allocation of variable ‘a’ is to be done to
some register. Loop
L1
Loop L1-L2
L2

• Following criteria should be adopted for register assignment


for outer loop,
• If is allocated in loop then it should not be allocated in .
• If is allocated in and it is not allocated in then store 'a' on entrance
to and load 'a' while leaving .
• If is allocated in and not in then load 'a' on entrance of and store 'a'
on exit from .
4. Register allocation for graph coloring
• The graph coloring works in two passes. The working is as
given below:
• In the first pass, the specific machine instruction is selected for
register allocation. For each variable a symbolic register is allocated.
• Goal – Find an assignment that minimizes the cost of spills.
• In the second pass, the register inference graph is prepared.
• In register inference graph each node is a symbolic registers
and an edge connects two nodes where one is live at a point
where other is defined.
• Then a graph coloring technique is applied for this register
inference graph using k-color.
• The k-colors can be assumed to be number of assignable
registers.
• In graph coloring technique no two adjacent nodes can have
Example
Example

Register Interference Graph


Cont…
• Start graph coloring
• Write nodes according to the descending order of degree:
{c,f,e,b,d,a}
Cont…
4 colors required = 4 registers
required
Storage Organization
• Storage organization in symbol table

• The executing target program runs in its own logical address


space in which each program value has a location.

• The management and organization of this logical address space


is shared between the compiler, operating system and target
machine

• The operating system maps the logical address into physical


addresses, which one usually spread throughout memory
Sub-division of runtime memory
How memory is utilized

• Where program is loaded for execution (Text


Section)
• Fixed location, holds Global variable
• Eg.: static keyword in C language (preserves its value
during the repeated call)
• Control Stack: Runtime memory allocation for
activation of procedure
• Local data is stored in stack

Grows in runtime

• Dynamic Memory Allocation


• Eg. malloc function in C
Stack allocation of space
• Compilers uses functions or methods as units of user-
defined actions
• Example:

• All local variable names of the


functions will be stored in the
stack
• Each time when a function is
called, the space for its local
variable is pushed onto the stack
• Each time when a function is
terminated, the local variable is
popped from the stack
Activation record
• Activation – execution flow of the function
• Activation record – contain all necessary information required to call a
function
• Activation tree – Whenever a function is executed, its activation record
is stored on the stack, known as control stack
• Example:
(100) (110)Abc( (120)
Main() ) Xyz()
(101) { (111){ (121) { STACK
(102) -- (112) -- (122) --
(103) -- (113) -- (123) --
(104) (114) (124) --
Abc(); Xyz() (125)}
(105) --- (115) --
(106) --- (116) -- TOP
} (117)}
Example – Activation tree
Activation record
• Temporaries – stores temporary values (intermediate
values of expression)
• Local data – local data of the function
• Saved machine status – status of register and
program counters
• Access link – information of data outside the local
scope of the function
• Control link – address of activation record
• Returned values – all return values of function
• Actual parameters – actual params in the calling
function

You might also like