CD Unit 4
CD Unit 4
CD Unit 4
UNIT- IV
Run time Environment
Storage organization:
• From compiler writer perspective, executing program runs in its own logical address space
in which each program value has location
• Management and organization of logical address space is shared between compiler,
operating system and target machine. Os maps logical address to physical address.
• Run time representation of object program in logical address space consist of data and
program area.
Code
Static
heap
Free memory
Stack
• Run time storage comes in block of memory (continuous bytes).byte is 8 bits and 4 bytes
form a machine word multi byte objects are stored in consecutive bytes.
• Storage layout for data objects is strongly influenced by addressing constraints of target
machine.
• Size of generated target code is fixed at compile time. So compiler can place target code in
statically determined area code usually in low end of memory.
• Global constants and information supported to garbage collection may be known at
compile time, and these are placed in statically determined area static.
• Addresses of code and static area objects are compiled in to target code.
• To maximum utilization of space at runtime, other 2 areas are stack and heap. these are
dynamic, their size can change as program executes.
Activation trees:
• Stack allocation would not be feasible if procedure calls or activations of procedures did
not nest in time.
Example: program that reads 9 integers into array ‘a’ and sort them using recursive quick sort
algorithm.
int a[11];
void readArray()
{
/*read 9 integers into a[1]_ _ _ _ _a[9]*/
Int i;
______
}
int partition(int m, int n)
{
/*pick separator value v1 and partitions a[m_ _ _ _ _n] to a[m_ _ _ _ _p-1] are less than v
and a[p+1_ _ _ _ n] are greater than v */
______
}
Void Quick sort(int m, int n)
{
Int i;
• Stack will enabled several relationships between tree and behavior of program.
1. Sequence of procedure calls corresponds to pre order traversal of tree.
2. Sequence of returns corresponds to post order traversal of tree.
3. Order in which activations called is order they appear along path to N and returns
should be reverse order.
Activation records:
• Procedure calls and returns are usually managed by runtime stack called control stack.
• Each live activation has activation record on control stack with root of activation tree at
bottom.
• We draw control stacks with bottom of stack than top. Elements appear at lowest are
closest to top.
• Here is a list of kinds of data that might appear in an activation record. These are vary with
language implemented it.
1. Temporary values, such as those rising from evaluation of expression.
2. Local data belongs to procedure which activation record this is.
3. Saved machine states, information about state of machine before call procedure.
Information includes return address and registers used by calling procedure.
4. Access link may be needed to locate data needed by called procedure in other
activation record.
Actual Parameters
Returned Values
Control Link
Access Link
Saved Machine Status
Local Data
Temporaries
Example: Below picture shows run time, stacks as control slow through the activation tree
here a is global .so, space is allocated for it before execution starts.
• How caller and callee might cooperate in managing stack should be shown in the above.
• The calling sequence and it’s division between caller and callee are as follows:
1. Caller evaluates actual parameters.
2. Caller stores return address and old value of top_sp into activation record of callee.
3. Callee saves register value and other status information.
4. Callee initializes it’s local data and begin execution.
• Suitable, corresponding return sequence is
1. Callee place return value next to parameters.
• In the above diagram, procedure p has 3 local arrays whose sizes can’t be determined at
compile time.
• Storage allocation of these arrays is not part of activation record for p, although it does
appear on stack.
• Only a pointer to beginning of each array appears in activation record itself. When p
executing array elements accessed through these pointers.
• Activation record of q, called by p begins after array of p. Any variable length array of q is
after activation record of q.
• Access to data on stack is through two pointers top and top_sp.
Top marks actual top of stack. it points at which next activation record begins.
Top_sp is used to find local, fixed length fields of top activation record
• Code to reposition top and top-sp can generated at compile time,in terms of size that is
known at runtime
• When q returns, top_sp can restore from save control link in activation record for q.new
value of top is top_sp minus the length of fields in q’s activation record.
Nesting depth:
• Give nesting depth 1to procedures that are not nesting with in any other Procedure.
• All C functions are at nesting depth 1. If Procedure p is defined with in Procedure at nesting
i then nesting depth of p is i+1
Example:
fun sort(inputFile, outputFile) =
let
val a = array( 11,0 );
fun readArray(inputFile) = -------- ;
------- a -------- ;
fun exchange( i, j ) =
------- a -------- ;
fun quicksort( m, n )
let
val v = -------- ;
fun partition( y, z ) =
------- a -------- v -------- exchange --------
in
------- a -------- v -------- partition ---------- quicksort
end
in
------- a -------- readArray ---------- quicksort
End ;
• In above ML program, only function at nesting depth 1 is outermost function, sort which
reads array as a 9 integers and sort them using quicksort algorithm.
• In an array a, first argument says array 11 elements and second arguments says array a
holds value 0.
• Sort consist several functions: readArray, exchange and quick sort. readArray and
exchange each access array a.
• Each of the above function immediately within the function is at nesting depth 1, their
nesting depths are all 2.
Access links:
• Direct implementation of normal static scope rule for nested functions is obtained by
access links of each activation record.
• If Procedure p is nested immediately within the Procedure q then access links in any
activation of p points to most recent activation of q.
• Access links form a chain from activation record at top of the stack to sequence of
activation at lower nesting depth.
Example: Sequence of stacks will show result of function sort. Here function name represent
first letters, show some data and access links for each activation.
We see situation after sort called read Array to load input in to array a then called
Quicksort(1,9).The access link from Quicksort(1,9) points to activation record sort.l
In successive steps we see recursive call to Quicksort(1,3) followed by partition which calls
exchange. Quicksort(1,3) points to sort for same array of Quicksort (1,9).
Exchange access link by passes activation records for Quicksort and partition , since exchange
is nested immediately with in sort.
Displays:
• One problem with the access link approach to non local data is that if the nesting depth gets
large, we may have to follow long chain of links to reach data.
• Efficient implementation uses auxiliary array d called display, which consists of one pointer
for each nesting depth.
• d[i] is pointer to highest activation record on stack for any procedure at nesting depth i.
Heap Management:
• Heap is portion of data store that is used for data that lives indefinitely, or until program
explicitly deletes it.
• Local variables becomes inaccessible when procedure end, many languages enable us to
creates objects or other data whose existence not tied with procedure that creates them
example new in java and C++.
• In this memory manager is subsystem that allocates and deallocates space within heap. It
serves interface between application programs and OS.
• Garbage collection is the process of finding spaces within heap that are no longer used by
program and reallocates it to other data items.
• Languages like java; it is garbage collection that deallocates memory. It is important
subsystem of memory manager.
Memory Manager:
• It keeps track of all free spaces in heap storage at all times it performs basically two
functions.
1. Allocation:
• When program requests memory for variable or object memory manager
processes contiguous heap memory of fixed size.
• If memory or space satisfies with free space in heap. If no space of needed size
available it increases space by getting virtual memory from OS.
• If space exhausted then memory manager passes information to application
program.
2. Deallocation:
• Memory manager returns deallocation space to pool of free spaces, so it can reuse
space to others.
• Memory manager do not return memory to OS even if program’s heap usage drops.
• Memory management is simpler if
(a) All allocation request, were for chunks of same size.
(b) Storage released predictably, the first allocated first deallocated.
• Lisp holds (a) but in some conditions supports (b) also generally most of languages holds
neither (a) nor (b).
• Properties of Memory Managers are:
1. Space Efficiency:
• Memory manager minimizes total heap space needed by a program.
• It allows large programs to run in fixed virtual address space.
Locality in programs:
• Most programs exhibit high degree of locality, they spend most of time executing small
fraction of code and only data.
• Program has temporal locality if memory locations it accesses are likely to be accessed
again with in short time.
• Program has spatial locality if memory locations close to location accessed are likely
accessed with in short time
• most programs spend 90% of their executing is 10% of code because
1. Program contains many instructions that never execute programs built with
components and libraries use only small fraction of provided functionality.
2. Only small fraction of code invoked is actually executed in typical run of program.
3. A typical program spends most of its time executing innermost loops are recursive
cycles in program.
• In modern computers locality, placing most common instructions and data in fast but small
storage by the lower average memory access time of program.
• If we know which instructions are executed heavily fastest caches is not enough then
adjusts storage dynamically.
Reducing fragmentation:
• At beginning of program, heap is contiguous unit of free space. at program allocation and
de allocation of memory, this space is broken into free and used chunks of memory.
• We refer to free chunks of memory as holes .At each allocation request, memory manager
place requested chunk memory into large enough hole.
• Unless a hole of exactly right size is found, we need to split some hole for creating small
hole.
• At each de allocation request, freed chunks are added back to pool of free space. we
coalesce contiguous holes into larger , as hole can be smaller.
• If we are not careful, free memory is fragmented to large number of small holes, because of
this, no hole is large enough to satisfy request even though space is there.
UNIT- IV
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.
Symbol
Table
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:
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 are data 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.
Absolute M M 1
Register R R 0
contents(c+
indirect indexed *c(R) 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.
GEETHANJALI INSTITUTE OF SCIENCE AND TECHNOLOGY, NELLORE Y.v.R 23
III BTECH II-SEM, CSE: COMPILER DESIGN
• Consider the following source code for dot 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
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:
• 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:
B1
prod : = 0
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
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
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:
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.
MOV a , R1
u:=a-c R0 contains t R1 contains u t in R0 u in R1
SUB c , R1
ADD R1, R0 d in R0
d:=v+u R0 contains d
MOV R0, d d in R0 and memory
x : = y +z MOV y, R0
if x < 0 goto z ADD z, R0
MOV R0,x
CJ < z
4. Algebraic Simplification:
• Few algebraic identifiers that occur frequently enough and are worth considering like
x=x+0
x=x*1
• They do not alter value of x. If we keep them as it is, it produces 6 statements that are
no use in 3 address code. So we removed these statements.
5. Reduction in Strength:
• Optimization deals with replacing expensive operations by cheaper one. example is
given below:
1. x2 ⇒ x * x
2. Division by constant ⇒ multiplication by constants