0% found this document useful (0 votes)
330 views61 pages

Principles of Compiler Design: Run Time Environments

The document discusses run-time environments and activation records. It explains that a program requires a run-time environment with memory resources and mapping of names to locations to execute. Activation records are used to manage information for each procedure execution, containing return values, parameters, local data, and more. Activation records are allocated on the stack when a procedure starts and deallocated when it finishes.

Uploaded by

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

Principles of Compiler Design: Run Time Environments

The document discusses run-time environments and activation records. It explains that a program requires a run-time environment with memory resources and mapping of names to locations to execute. Activation records are used to manage information for each procedure execution, containing return values, parameters, local data, and more. Activation records are allocated on the stack when a procedure starts and deallocated when it finishes.

Uploaded by

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

Principles of Compiler Design

Chapter 6
Run Time Environments

1
Run-Time Environments
 A program as a source code is merely a collection of text (code,
statements etc.) and to make it alive, it requires actions to be performed
on the target machine.
 A program needs memory resources to execute instructions.
 A program contains names for procedures, identifiers etc., that require
mapping with the actual memory location at runtime.
 By runtime, we mean a program in execution.
 Runtime environment is a state of the target machine, which may
include software libraries, environment variables, etc., to provide
services to the processes running in the system.
 Runtime support system is a package, mostly generated with the
executable program itself and It facilitates the process communication
between the process and the runtime environment.
 It takes care of memory allocation and de-allocation while the program
is being executed
2
Cont..
• How do we allocate the space for the generated target code and the data
object of our source programs?
• The places of the data objects that can be determined at compile time will
be allocated statically.
• But the places for the some of data objects will be allocated at run-time.
• The allocation of de-allocation of the data objects is managed by the run-
time support package.
– run-time support package is loaded together with the generate
target code.
– the structure of the run-time support package depends on the
semantics of the programming language (especially the
semantics of procedures in that language).
• Each execution of a procedure is called as activation of that procedure.
3
Procedure Activations
• An execution of a procedure starts at the beginning of the procedure
body;
• When the procedure is completed, it returns the control to the point
immediately after the place where that procedure is called.
• Each execution of a procedure is called as its activation.
• Lifetime of an activation of a procedure is the sequence of the steps
between the first and the last steps in the execution of that procedure
(including the other procedures called by that procedure).
• If a and b are procedure activations, then their lifetimes are either non-
overlapping or are nested.
• If a procedure is recursive, a new activation can begin before an earlier
activation of the same procedure has ended.

4
Activation Tree
• We can use a tree (called activation tree) to show the way control
enters and leaves activations.

• In an activation tree:
– Each node represents an activation of a procedure.
– The root represents the activation of the main program.
– The node a is a parent of the node b iff the control flows from a to b.
– The node a is left to to the node b iff the lifetime of a occurs before
the lifetime of b.

5
Activation Tree (cont.)
program main; enter main
procedure s; enter p
begin ... end; enter q
procedure p; exit q
procedure q; enter s
begin ... end; exit s
begin q; s; end; exit p
begin p; s; end; enter s
exit s
exit main

A Nested Structure

6
Activation Tree (cont.)

main

p s

q s

7
Control Stack
• The flow of the control in a program corresponds to a depth-first
traversal of the activation tree that:
– starts at the root,
– visits a node before its children, and
– recursively visits children at each node an a left-to-right order.
• A stack (called control stack) can be used to keep track of live
procedure activations.
– An activation record is pushed onto the control stack as the
activation starts.
– That activation record is popped when that activation ends.
• When node n is at the top of the control stack, the stack contains the
nodes along the path from n to the root.
8
Variable Scopes
• The same variable name can be used in the different parts of the
program.
• The scope rules of the language determine which declaration of a name
applies when the name appears in the program.
• An occurrence of a variable (a name) is:
– local: If that occurrence is in the same procedure in which that name is declared.
– non-local: Otherwise (ie. it is declared outside of that procedure)

procedure p;
var b:real;
procedure p;
var a: integer; a is local
begin a := 1; b := 2; end; b is non-local
begin ... end;

9
Run-Time Storage Organization
Code
Memory locations for code are
determined at compile time.

Static Data Locations of static data can also be


determined at compile time.
Stack
Data objects allocated at run-time.
(Activation Records)

Other dynamically allocated data


Heap
objects at run-time. (For example,
malloc area in C).

10
Activation Records
• Information needed by a single execution of a procedure is managed
using a contiguous block of storage called activation record.
• An activation record is allocated when a procedure is entered, and it is
de-allocated when that procedure exited.
• Size of each field can be determined at compile time (Although actual
location of the activation record is determined at run-time).
– Except that if the procedure has a local variable and its size depends
on a parameter, its size is determined at the run time.

11
Activation Records (cont.)
The returned value of the called procedure is returned
return value in this field to the calling procedure. In practice, we may
use a machine register for the return value.
actual parameters The field for actual parameters is used by the calling
procedure to supply parameters to the called procedure.
optional control link The optional control link points to the activation record
of the caller.
optional access link
The optional access link is used to refer to nonlocal data
held in other activation records.
saved machine status
The field for saved machine status holds information about
the state of the machine before the procedure is called.
local data
The field of local data holds data that local to an execution
temporaries of a procedure..
Temporay variables is stored in the field of temporaries.

12
Activation Records (Ex1)
stack
main
program main;
procedure p;
var a:real;
procedure q;
var b:integer;
begin ... end; p
begin q; end;
procedure s; a:
var c:integer;
begin ... end; main
begin p; s; end; q

p s b:

13
Activation Records for Recursive Procedures
program main;
main
procedure p;
function q(a:integer):integer;
begin
if (a=1) then q:=1; p
else q:=a-1;
end;
begin q(3); end; q(3)
begin p; end; a: 3

q(2)
a:2

q(1)
a:1

14
Creation of An Activation Record
• Who allocates an activation record of a procedure?
– Some part of the activation record of a procedure is created by that
procedure immediately after that procedure is entered.
– Some part is created by the caller of that procedure before that
procedure is entered.

• Who deallocates?
– Callee de-allocates the part allocated by Callee.
– Caller de-allocates the part allocated by Caller.

15
Creation of An Activation Record (cont.)
return value Caller’s Activation Record
actual parameters
optional control link
optional access link
saved machine status
local data
Caller’s Responsibility
temporaries
return value
Callee’s Activation Record
actual parameters
optional control link
optional access link
saved machine status
local data
Callee’s Responsibility
temporaries

16
Variable Length Data
return value
actual parameters
Variable length data is allocated after
optional control link
temporaries, and there is a link to from
optional access link
local data to that array.
saved machine status
local data
pointer a
pointer b

temporaries

array a

array b

17
Dangling Reference
• Whenever a storage is de-allocated, the problem of dangling references
may accur.

main () {
int *p;
p = dangle();
}
int *dangle*() {
int i=2;
return &i;
}

18
Access to Nonlocal Names
• Scope rules of a language determine the treatment of references to
nonlocal names.
• Scope Rules:
– Lexical Scope (Static Scope)
• Determines the declaration that applies to a name by examining
the program text alone at compile-time.
• Most-closely nested rule is used.
• Pascal, C, ..
– Dynamic Scope
• Determines the declaration that applies to a name at run-time.
• Lisp, APL, ...

19
Lexical Scope
• The scope of a declaration in a block-structured language is given by
the mostly closed rule.
• Each procedure (block) will have its own activation record.
– procedure
– begin-end blocks
• (treated same as procedure without creating most part of its activation record)
• A procedure may access to a nonlocal name using:
– access links in activation records, or
– displays (an efficient way to access to nonlocal names)

20
Access Links
main
program main; access link
var a:int; a:
procedure p;
q(1)
var d:int;
access link
begin a:=1; end;
procedure q(i:int); Access i,b:
var b:int; Links q(0)
procedure s; access link
var c:int; i,b:
begin p; end; s
begin access link
if (i<>0) then q(i-1) c:
else s;
p
end;
begin q(1); end; access link
d:
21
Procedure Parameters
main
program main; access link
procedure p(procedure a);
begin a; end;
procedure q; q
procedure s; access link
begin ... end;
begin p(s) end; p
begin q; end;
access link

Access links must be passed with s


procedure parameters. access link

22
Displays

• An array of pointers to activation records can be used to access


activation records.
• This array is called as displays.
• For each level, there will be an array entry.

1: Current activation record at level 1


2: Current activation record at level 2
3: Current activation record at level 3

23
Accessing Nonlocal Variables
main addrC := offsetC(currAR)
program main; access link t := *currAR
var a:int;
a: addrB := offsetB(t)
procedure p;
t := *t
var b:int;
p addrA := offsetA(t)
begin q; end;
ADD addrA,addrB,addrC
procedure q(); access link
var c:int; b:
begin
c:=a+b;
end; q
begin p; end; access link
c:

24
Accessing Nonlocal Variables using Display
main
program main; D[1] addrC := offsetC(D[3])
access link addrB := offsetB(D[2])
var a:int;
a: addrA := offsetA(D[1])
procedure p;
var b:int; ADD addrA,addrB,addrC
begin q; end; p
procedure q(); D[2]
access link
var c:int; b:
begin
c:=a+b;
end; q
D[3]
begin p; end; access link
c:

25
Parameter Passing Methods
• Call-by-value
• Call-by-reference
• Call-by-name (used by Algol)

26
SOME OTHER ISSUES
• Symbol Tables hold scope information.

• Dynamic Scope:
– uses control link (similar to access links)

• Dynamic Storage Allocation (Heap Management)


– different allocation techniques

27
Principles of Compiler Design

Chapter 7
Code Generation

28
Code Generation
 The final phase of the 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

 A code generator has three primary tasks: instruction selection,


register allocation and assignment, and instruction ordering.
 Instruction selection involves choosing appropriate target-machine instructions
to implement the IR statements.
 Register allocation and assignment involves deciding what values to keep in
which registers.
 Instruction ordering involves deciding in what order to schedule the execution
of instructions.
29
Issues in the Design of Code Generator
 The most important criterion is that it produces correct code.
 Input to the code generator
 IR + Symbol table
 We assume front end produces low-level IR, i.e. values of names in it can be
directly manipulated by the machine instructions.
 Syntactic and semantic errors have been already detected.
 The target program
 Common target architectures are:
 RISC(Reduced Instruction Set Computer),

 CISC(complex instruction set computer) and

 Stack based machines

30
Contd…
 A RISC machine typically has many registers, three-address
instructions, simple addressing modes, and a relatively simple
instruction-set architecture.
 In contrast, a ClSC machine typically has few registers, two-address
instructions, a variety of addressing modes , several register classes,
variable-length instructions, and instructions with side effects.
 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 stack.
 To achieve high performance the top of the stack is typically kept in
registers.
 Stack-based machines almost disappeared because it was felt that the
stack organization was too limiting and required too many swap and
copy operations.
 In this chapter we use a very simple RISC-like computer with
addition of some CISC-like addressing modes.

31
Instruction selection
 The code generator must map the lR program into a code sequence
that can be executed by the target machine.
 The complexity of performing this mapping is determined by a
factors such as
 the level of the IR
 the nature of the instruction-set architecture
 the desired quality of the generated code.
 For example, every three-address statement of the form x = y + z,
where x, y, and z are statically allocated, can be translated into the
code sequence

32
Contd…
 This strategy often produces redundant loads and stores. For
example, the sequence of three-address statements

 Here, the fourth statement is redundant since it loads a value that has
just been stored, and so is the third if a is not subsequently used.
 The quality of the generated code is usually determined by its speed
and size.

33
Register Allocation
 A key problem in code generation is deciding what values to hold in
what registers.
 Registers are the fastest computational unit on the target machine, but
we usually do not have enough of them to hold all values. Values not
held in registers need to reside in memory.
 Instructions involving register operands are invariably shorter and faster
than those involving operands in memory, so efficient utilization of
registers is particularly important.
 The use of registers is often subdivided into two sub problems:
1. Register allocation, during which we select the set of variables that will reside in
registers at each point in the program.
2. Register assignment, during which 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 machines.
34
Contd…
 The problem is further complicated because the hardware and/or the
operating system of the target machine may require that certain
register-usage conventions be observed.
 Example: Certain machines require register-pairs (an even and next
odd numbered register) for some operands and results. For example,
on some machines, integer multiplication and integer division involve
register pairs.
 The multiplication instruction is of the form M x, y
where x, the multiplicand, is the even register of an even/odd register pair and y,
the multiplier, is the odd register. The product occupies the entire even/odd
register pair.
 The division instruction is of the form D x, y
where the dividend occupies an even/odd register pair whose even register is X;

the divisor is After division, the even register holds the remainder and the odd
y.

register the quotient


35
Contd…
 Consider the two three-address code sequences in which the only
difference in (a) and (b) is the operator in the second statement.

 The shortest assembly-code sequences for (a) and (b) are given as

36
A Simple Target Machine Model
 Our target computer models a three-address machine with load and store
operations, computation operations, jump operations, and conditional
jumps.
 We assume the following kinds of instructions are available:
 Load operations:
 LD dst, addr loads the value in location addr into location dst.

 LD r, x which loads the value in location x into register r.

 LD r1 , r2 is a register-to-register copy in which the contents of register r2 are

copied into register r1 .


 Store operations: S1 x, r stores the value in register r into the location x.
 Computation operations: OP dst, srcl , src2 , where OP is a operator like ADD or
SUB, and dst, srcl , and src2 are locations, not necessarily distinct.
 Unconditional jumps: BR L causes control to branch to the machine instruction
with label L. (BR stands for branch.)
 Conditional jumps: 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.
37
Contd…
We assume our target machine has a variety of addressing modes:
 In instructions, a location can be a variable name x referring to the

memory location that is reserved for x.


 A location can also be an indexed address of the form a (r), where a is

a variable and r is a register.


 The memory location denoted by a(r) is computed by taking the l-value of a
and adding to it the value in register r.
 For example, the instruction LD Rl , a (R2 ) has the effect of setting Rl =
contents ( a + contents (R2) ) , where contents(x) denotes the contents of the
register or memory location represented by x.
 This addressing mode is useful for accessing arrays, where a is the base address
of the array (that is, the address of the first element), and r holds the number of
bytes past that address we wish to go to reach one of the elements of array a.

38
Contd…
 A memory location can be an integer indexed by a register.
 For example, LD Rl , 100 (R2 ) has the effect of setting R l = contents (100 +
contents (R2) ) , that is, of loading into R l the value in the memory location obtained
by adding 100 to the contents of register R2.
 We also allow two indirect addressing modes: *r means the memory
location found in the location represented by the contents of register r and
* 100 (r) means the memory location found in the location obtained by
adding 100 to the contents of r.
 For example, LD Rl , * 100 (R2) has the effect of setting Rl = contents (contents
(100 + contents (R2) ) ) , that is, of loading into Rl the value in the memory location
stored in the memory location obtained by adding 100 to the contents of register R2.
 Finally, we allow an immediate constant addressing mode. The constant is
prefixed by #. The instruction LD Rl , # 100 loads the integer 100 into
register Rl , and ADD Rl , Rl , # 100 adds the integer 100 into register R1.

39
Contd…
 Example1: We may execute the three-address instruction b = a [i] by
the machine instructions(a is an array whose elements are 8-byte
values) :

 Example2: a [j ] = c is implemented by:

40
Contd…
 Example3: To implement a simple pointer indirection, such as the
three-address statement x = *p, we can use machine instructions like:

 Example4: Consider a conditional-jump three-address instruction


like if x < y goto L
The machine-code equivalent would be something like:

41
Basic Blocks and Flow Graphs
 Partition the intermediate code into basic blocks, with the properties
that
 The flow of control can only enter the basic block through the first instruction
in the block. That is, there are no jumps into the middle of the block.
 Control will leave the block without halting or branching, except possibly at the
last instruction in the block.

 The basic blocks become the nodes of a flow graph, whose edges
indicate which blocks can follow which other blocks.

42
Basic Blocks
 We begin a new basic block with the first instruction and keep
adding instructions until we meet either a jump, a conditional
jump, or a label on the following instruction.
 In the absence of jumps and labels, control proceeds sequentially

from one instruction to the next.


 This idea is formalized in the following algorithm.

Algorithm : Partitioning three-address instructions into basic


blocks
INPUT: A sequence of three-address instructions.
OUTPUT: A list of the basic blocks for that sequence in which each
instruction is assigned to exactly one basic block.

43
Contd…
 METHOD: First, we determine those instructions in the intermediate
code that are leaders, that is, the first instructions in some basic
block. The instruction just past the end of the intermediate program is
not included as a leader. The rules for finding leaders are:
1. The first three-address instruction in the intermediate code is a leader.
2. Any instruction that is the target of a conditional or unconditional jump is a
leader.
3. Any instruction that immediately follows a conditional or unconditional jump
is a leader.
 Then, for each leader, its basic block consists of itself and all
instructions up to but not including the next leader or the end of the
intermediate program.

44
Contd..
Example: Intermediate code to set a 10 x 10 matrix to an identity
matrix

First, instruction 1 is a leader by rule (1) of Algorithm.


To find the other leaders, we first need to find the jumps.
In this example, there are three jumps, all conditional, at
instructions 9, 11 , and 17.
By rule (2) , the targets of these jumps are leaders; they
are instructions 3, 2, and 13, respectively.
Then, by rule (3) , each instruction following a jump is a
leader; those are instructions 10 and 12. Note that no
instruction follows 17 in this code, but if there were code
following, the 18th instruction would also be a leader.

45
Next Use Information
 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 in a three-address statement is defined as follows.
Suppose three-address statement i assigns a value to x . If statement j
has x as an operand, and control can flow from statement i to j along
a path that has no intervening assignments to x, then we say
statement j uses the value of x computed at statement i . We further
say that x is live at statement i .
Algorithm: Determine 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 nontemporary variables in B as
being live on exit.
OUTPUT: At each statement i : x = y + z in B, we attach to i the
liveness and next-use information of x, y, and z.
46
Contd…
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. 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.

47
Flow Graphs
 Once an intermediate-code program is partitioned into basic blocks,
we represent the flow of control between them by a flow graph.
 The nodes of the flow graph are the basic blocks. There is an edge
from block B to block C if and only if it is possible for the first
instruction in block C to immediately follow the last instruction in
block B .
 There are two ways that such an edge could be justified:
 There is a conditional or unconditional jump from the end of B to the
beginning of C .
 C immediately follows B in the original order of the three-address instructions,
and B does not end in an unconditional jump.
 We say that B is a predecessor of C , and C is a successor of B .

48
Contd…
 Often we add two nodes, called the entry and exit, that do not
correspond to executable intermediate instructions.
 There is an edge from the entry to the first executable node of the
flow graph, that is, to the basic block that comes from the first
instruction of the intermediate code.
 There is an edge to the exit from any basic block that contains an
instruction that could be the last executed instruction of the program.
 If the final instruction of the program is not an unconditional jump,
then the block containing the final instruction of the program is one
predecessor of the exit, but so is any basic block that has a jump to
code that is not part of the program.

49
Contd…
Example: The set of basic blocks constructed
in Example of slide10 yields the below flow
graph. The entry points to basic block B1 ,
since Bl contains the first instruction of the
program. The only successor of Bl is B2 ,
because Bl does not end in an unconditional
jump, and the leader of B2 immediately
follows the end of B1 .
Block B3 has two successors. One is itself,
because the leader of B3 , instruction 3, is the
target of the conditional jump at the end of B3 ,
instruction 9 . The other successor is B4 ,
because control can fall through the conditional
jump at the end of B3 and next enter the leader
of B4 .
Only B6 points to the exit of the flow graph,
since the only way to get to code that follows
the program from which we constructed the
flow graph is to fall through the conditional
jump that ends B6 .

50
DAG Representation of Flow Graphs
We construct a DAG for a basic block as follows:
1. There is a node in the DAG for each of the initial values of the
variables appearing in the basic block.
2. There is a node N associated with each statement s within the block.
The children of N are those nodes corresponding to statements that
are the last definitions, prior to s, of the operands used by s.
3. Node N is labeled by the operator applied at s, and also attached to N
is the list of variables for which it is the last definition within the
block.
4. Certain nodes are designated output nodes. These are the nodes
whose variables are live on exit from the block; that is, their values
may be used later, in another block of the flow graph.

51
Contd…
The DAG representation of a basic block lets us perform several code
improving transformations on the code represented by the block.
a)We can eliminate local common sub expressions, that is , instructions
that compute a value that has already been computed.
b)We can eliminate dead code, that is , instructions that compute a value
that is never used.
c)We can reorder statements that do not depend on one another; such
reordering may reduce the time a temporary value needs to be preserved
in a register.
d)We can apply algebraic laws to reorder operands of three-address
instructions, and sometimes thereby simplify the computation.

52
Contd…
Example: A DAG for the block

53
A Simple Code Generator
 We consider an algorithm that generates code for a single basic block.
 It considers each three-address instruction in turn, and keeps track of what values
are in what registers so it can avoid generating unnecessary loads and stores.
 One of the primary issues during code generation is deciding how to use
registers to best advantage. There are four principal uses of registers:
 In most machine architectures, some or all of the operands of an operation must be
in registers in order to perform the operation .
 Registers make good temporaries - places to hold the result of a sub expression
while a larger expression is being evaluated, or more generally, a place to hold a
variable that is used only within a single basic block.
 Registers are used to hold (global) values that are computed in one basic block and
used in other blocks, for example, a loop index that is incremented going around
the loop and is used several times within the loop .
 Registers are often used to help with run-time storage management, for example, to
manage the run-time stack, including the maintenance of stack pointers and
possibly the top elements of the stack itself.

54
Contd…
Register and Address Descriptors
 In order to make the needed decisions, we require a data structure that tells us what
program variables currently have their value in a register, and which register or
registers, if so.
 We also need to know whether the memory location for a given variable currently has
the proper value for that variable, since a new value for the variable may have been
computed in a register and not yet stored.
The desired data structure has the following descriptors:
1. For each available register, a Register descriptor keeps track of the variable names
whose current value is in that register. Since we shall use only those registers that are
available for local use within a basic block, we assume that initially, all register
descriptors are empty. As the code generation progresses, each register will hold the
value of zero or more names.
2. For each program variable, an address descriptor keeps track of the location or locations
where the current value of that variable can be found. The location might be a register,
a memory address, a stack location, or some set of more than one of these. The
information can be stored in the symbol-table entry for that variable name.
55
Code Generation Algorithm
 An essential part of the algorithm is a function getReg( I), which
selects registers for each memory location associated with the three-
address instruction I.
 Function getReg has access to the register and address descriptors for

all the variables of the basic block, and may also have access to
certain useful data-flow information such as the variables that are live
on exit from the block.
Machine Instructions for Operations
For a three-address instruction such as x = y + z, do the following:
1. Use getReg(x = y + z) to select registers for x, y, and z. Call these Rx , Ry, and Rz .
2. If y is not in Ry , then issue an instruction LD Ry , y' , where y' is one of the
memory locations.
3. Similarly, if z is not in Rz , issue and instruction LD Rz, Zl, where Zl is a location
for z.
4. Issue the instruction ADD Rx , Ry , Rz .
56
Contd…
 Managing Register and Address Descriptors
As the code-generation algorithm issues load, store, and other machine instructions, it
needs to update the register and address descriptors. The rules are as follows:
1. For the instruction LD R, x
 Change the register descriptor for register R so it holds only x.
 Change the address descriptor for x by adding register R as an additional location.
2. For the instruction 8T x, R, change the address descriptor for x to include its own
memory location.
3. For an operation such as ADD Rx , Ry , Rz implementing a three-address instruction
x=y+z
 (a) Change the register descriptor for Rx so that it holds only x.
 (b) Change the address descriptor for x so that its only location is Rx .
 (c) Remove Rx from the address descriptor of any variable other than x.
4. When we process a copy statement x = y , after generating the load for y into register
Ry , if needed, and after managing descriptors as for all load statements (per rule 1 ) :
 (a) Add x to the register descriptor for Ry .
 (b) Change the address descriptor for x so that its only location is Ry .

57
Example

58
Contd…
Design of the Function getReg(I)
Consider instruction x = y + z. First, we must pick a register for y and a
register for z. The rules are as follows:
1 . If y is currently in a register, pick a register already containing y as
Ry. Do not issue a machine instruction to load this register, as none is
needed.
2. If y is not in a register, but there is a register that is currently empty,
pick one such register as Ry.
3. The difficult case occurs when y is not in a register, and there is no
register that is currently empty. We need to pick one of the allowable
registers anyway, and we need to make it safe to reuse.

59
Contd…
Possibilities for the values of R
(a) If the address descriptor for v says that v is somewhere besides R,
then we are OK.
(b) If v is x, the value being computed by instruction I, and x is not also
one of the other operands of instruction I (z in this example) , then we
are OK. The reason is that in this case, we know this value of x is
never again going to be used, so we are free to ignore it.
( c) Otherwise, if v is not used later (that is , after the instruction I, there
are no further uses of v, and if v is live on exit from the block, then v
is recomputed within the block) , then we are OK.
(d) If we are not OK by one of the first two cases, then we need to
generate the store instruction 8T v, R to place a copy of v in its own
memory location. This operation is called a spill.

60
Contd…
Selection of the register Rx
1. Since a new value of x is being computed, a register that holds only x
is always an acceptable choice for Rx; . This statement holds even if
x is one of y and z, since our machine instructions allows two
registers to be the same in one instruction.
2. If y is not used aft er instruction I, in the sense described for variable
v in item (3c) , and Ry holds only y after being loaded, if necessary,
then Ry can also be used as Rx; . A similar option holds regarding z
and Rz.

61

You might also like