Unit 6 and 7- Code Optimization and Code Generation
Unit 6 and 7- Code Optimization and Code Generation
Unit-6 & 7
Unit-6 & 7
Storage Organization
Unit-6 & 7
Static vs. Dynamic Allocation
• Static: Compile time, Dynamic: Runtime allocation
• Many compilers use some combination of
following
– Stack storage: for local variables, parameters and so on
– Heap storage: Data that may outlive the call to the
procedure that created it
• Stack allocation is a valid allocation for procedures
since procedure calls are nested
Unit-6 & 7
Sketch of a quicksort program
Unit-6 & 7
Activation for Quicksort
Unit-6 & 7
Activation tree representing calls during an
execution of quicksort
Unit-6 & 7
Activation records
• Procedure calls and returns are usaully managed
by a run-time stack called the control stack.
• Each live activation has an activation record
(sometimes called a frame)
• The root of activation tree is at the bottom of
the stack
• The current execution path specifies the content
of the stack with the last activation has record in
the top of the stack.
Unit-6 & 7
A General Activation Record
Unit-6 & 7
Downward-growing stack of activation records
Unit-6 & 7
Designing Calling Sequences
• Values communicated between caller and callee are
generally placed at the beginning of callee’s
activation record
• Fixed-length items: are generally placed at the
middle
• Items whose size may not be known early enough:
are placed at the end of activation record
• We must locate the top-of-stack pointer judiciously:
a common approach is to have it point to the end of
fixed length fields.
Unit-6 & 7
Division of tasks between caller and callee
Unit-6 & 7
calling sequence
• The caller evaluates the actual parameters
• The caller stores a return address and the old
value of top-sp into the callee's activation
record.
• The callee saves the register values and other
status information.
• The callee initializes its local data and begins
execution.
Unit-6 & 7
corresponding return sequence
• The callee places the return value next to the
parameters
• Using information in the machine-status field, the
callee restores top-sp and other registers, and then
branches to the return address that the caller
placed in the status field.
• Although top-sp has been decremented, the caller
knows where the return value is, relative to the
current value of top-sp; the caller therefore may
use that value.
Unit-6 & 7
Access to dynamically allocated arrays
Unit-6 & 7
ML
• ML is a functional language
• Variables are defined, and have their
unchangeable values initialized, by a statement
of the form:
val (name) = (expression)
Unit-6 & 7
A version of quicksort, in ML style, using
nested functions
Unit-6 & 7
Access links for finding nonlocal data
Unit-6 & 7
Sketch of ML program that uses function-
parameters
Unit-6 & 7
Actual parameters carry their access link
with them
Unit-6 & 7
Maintaining the Display
Unit-6 & 7
Maintaining the Display (Cont.)
Unit-6 & 7
Memory Manager
• Two basic functions:
– Allocation
– Deallocation
• Properties of memory managers:
– Space efficiency
– Program efficiency
– Low overhead
Unit-6 & 7
Typical Memory Hierarchy Configurations
Unit-6 & 7
Locality in Programs
The conventional wisdom is that programs spend 90%
of their time executing 10% of the code:
• Programs often contain many instructions that are
never executed.
• Only a small fraction of the code that could be
invoked is actually executed in a typical run of the
program.
• The typical program spends most of its time
executing innermost loops and tight recursive cycles
in a program.
Unit-6 & 7
Part of a Heap
Unit-6 & 7
Basic blocks and flow graphs
• Partition the intermediate code into basic blocks
– 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
Rules for finding leaders
• The first three-address instruction in the
intermediate code is a leader.
• Any instruction that is the target of a
conditional or unconditional jump is a leader.
• Any instruction that immediately follows a
conditional or unconditional jump is a leader.
Intermediate code to set a 10*10 matrix to
an identity matrix
Flow graph based on Basic Blocks
liveness and next-use information
• We wish to determine for each three address
statement x=y+z what the next uses of x, y and z are.
• Algorithm:
– Attach to statement i the information currently found in
the symbol table regarding the next use and liveness of x,
y, and z.
– In the symbol table, set x to "not live" and "no next use.“
– In the symbol table, set y and z to "live" and the next uses
of y and z to i.
DAG representation of basic blocks
• There is a node in the DAG for each of the initial values
of the variables appearing in the basic block.
• 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.
• 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.
• Certain nodes are designated output nodes. These are
the nodes whose variables are live on exit from the
block.
Code improving transformations
• We can eliminate local common subexpressions, that
is, instructions that compute a value that has already
been computed.
• We can eliminate dead code, that is, instructions that
compute a value that is never used.
• 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.
• We can apply algebraic laws to reorder operands of
three-address instructions, and sometimes t hereby
simplify t he computation.
DAG for basic block
DAG for basic block
array accesses in a DAG
• An assignment from an array, like x = a [i], is represented by creating
a node with operator =[] and two children representing the initial
value of the array, a0 in this case, and the index i. Variable x
becomes a label of this new node.
• An assignment to an array, like a [j] = y, is represented by a new
node with operator []= and three children representing a0, j and y.
There is no variable labeling this node. What is different is that the
creation of this node kills all currently constructed nodes whose
value depends on a0. A node that has been killed cannot receive
any more labels; that is, it cannot become a common
subexpression.
DAG for a sequence of array assignments
Rules for reconstructing the basic block
•
from a DAG
The order of instructions must respect the order of nodes in the DAG. That
is, we cannot compute a node's value until we have computed a value for
each of its children.
• Assignments to an array must follow all previous assignments to, or
evaluations from, the same array, according to the order of these
instructions in the original basic block.
• Evaluations of array elements must follow any previous (according to the
original block) assignments to the same array. The only permutation
allowed is that two evaluations from the same array may be done in either
order, as long as neither crosses over an assignment to that array.
• Any use of a variable must follow all previous (according to the original
block) procedure calls or indirect assignments through a pointer.
• Any procedure call or indirect assignment through a pointer must follow
all previous (according to the original block) evaluations of any variable.
Characteristic of peephole optimizations
• Redundant-instruction elimination
• Flow-of-control optimizations
• Algebraic simplifications
• Use of machine idioms
Redundant-instruction elimination
• LD a, R0
ST R0, a
• if debug == 1 goto L1
goto L2
L I : print debugging information
L2:
Flow-of-control optimizations
• x=x+0
• x=x*1
Register Allocation and Assignment