Code Optimization New
Code Optimization New
Code Optimization New
Introduction
Classifications of Optimization techniques
Factors influencing Optimization
Themes behind Optimization Techniques
Optimizing Transformations
• Example
• Details of Optimization Techniques
Compiler Design 1
Introduction
Concerns with machine-independent code
optimization
90-10 rule: execution spends 90% time in 10% of
the code.
It is moderately easy to achieve 90% optimization. The
rest 10% is very difficult.
Identification of the 10% of the code is not possible for
a compiler – it is the job of a profiler.
In general, loops are the hot-spots
Compiler Design 2
Introduction
Criterion of code optimization
Must preserve the semantic equivalence of the programs
The algorithm should not be modified
Transformation, on average should speed up the execution
of the program
Worth the effort: Intellectual and compilation effort spend
on insignificant improvement.
Transformations are simple enough to have a good effect
Compiler Design 3
Introduction
Optimization can be done in almost all phases
of compilation.
Source Front Inter. Code target
code end code generator code
Compiler Design 4
Introduction
Organization of an optimizing compiler
Control
Data flow
flow Transformation
analysis
analysis
Code optimizer
Compiler Design 5
Classifications of Optimization
techniques
Peephole optimization
Local optimizations
Global Optimizations
Inter-procedural
Intra-procedural
Loop optimization
Compiler Design 6
Factors influencing Optimization
The target machine: machine dependent factors can
be parameterized to compiler for fine tuning
Architecture of Target CPU:
Number of CPU registers
RISC vs CISC
Pipeline Architecture
Number of functional units
Machine Architecture
Cache Size and type
Cache/Memory transfer rate
Compiler Design 7
Themes behind Optimization
Techniques
Avoid redundancy: something already computed need not
be computed again
Smaller code: less work for CPU, cache, and memory!
Less jumps: jumps interfere with code pre-fetch
Code locality: codes executed close together in time is
generated close together in memory – increase locality of
reference
Extract more information about code: More info –
better code generation
Compiler Design 8
Redundancy elimination
Redundancy elimination = determining that two computations
are equivalent and eliminating one.
There are several types of redundancy elimination:
Common subexpression elimination
Identifies expressions that have operands with the same name
Constant/Copy propagation
Identifies variables that have constant/copy values and uses the constants/copies
in place of the variables.
Partial redundancy elimination
Partial redundancy - computation done more than once on some path in the flow-
graph
Combines – global common subexpression elimination and loop invariant code
motion.
Compiler Design 9
Optimizing Transformations
Compile time evaluation
Common sub-expression elimination
Code motion
Strength Reduction
Dead code elimination
Copy propagation
Loop optimization
Induction variables and strength reduction
Compiler Design 10
Compile-Time Evaluation
Expressions whose values can be pre-
computed at the compilation time
Two ways:
Constant folding
Constant propagation
Compiler Design 11
Compile-Time Evaluation
Constant folding: Evaluation of an expression
with constant operands to replace the
expression with single value
Example:
area := (22.0/7.0) * r ** 2
area := 3.14286 * r ** 2
Compiler Design 12
Compile-Time Evaluation
Constant Propagation: Replace a variable with
constant which has been assigned to it earlier.
Example:
pi := 3.14286
area = pi * r ** 2
area = 3.14286 * r ** 2
Compiler Design 13
Constant Propagation
What does it mean?
Given an assignment x = c, where c is a constant, replace later
uses of x with uses of c, provided there are no intervening
assignments to x.
Similar to copy propagation
Extra feature: It can analyze constant-value conditionals to
determine whether a branch should be executed or not.
When is it performed?
Early in the optimization process.
What is the result?
Smaller code
Fewer registers
Compiler Design 14
Common Sub-expression Evaluation
Identify common sub-expression present in different
expression, compute once, and use the result in all the places.
The definition of the variables involved should not change
Example:
a := b * c temp := b * c
… a := temp
… …
x := b * c + 5 x := temp + 5
Compiler Design 15
Common Subexpression Elimination
Local common subexpression elimination
Performed within basic blocks
Algorithm sketch:
Traverse BB from top to bottom
Maintain table of expressions evaluated so far
if any operand of the expression is redefined, remove it from the
table
Modify applicable instructions as you go
generate temporary variable, store the expression in it and use the
variable next time the expression is encountered.
t=a+b
x=a+b x=t
... ...
y=a+b y=t
Compiler Design 16
Common Subexpression Elimination
t1 = a + b
c=a+b c = t1
d=m*n t2 = m * n
e=b+d d = t2
f=a+b t3 = b + d
g=-b e = t3
h=b+a f = t1
a=j+a g = -b
k=m*n h = t1 /* commutative */
j=b+d a=j+a
a=-b k = t2
if m * n go to L j = t3
a = -b
if t2 go to L
Compiler Design 18
Common Sub-expression Evaluation
1 x:=a+b
“a + b” is not a
common sub-
2 a:= b 3 expression in 1 and 4
z : = a + b + 10 4
Compiler Design 19
Code Motion
Moving code from one part of the program to
other without modifying the algorithm
Reduce size of the program
Reduce execution frequency of the code subjected
to movement
Compiler Design 20
Code Motion
1. Code Space reduction: Similar to common sub-
expression elimination but with the objective to
reduce code size.
Example: Code hoisting
temp : = x ** 2
if (a< b) then if (a< b) then
z := x ** 2 z := temp
else else
y := x ** 2 + 10 y := temp + 10
Example:
if (a<b) then if (a<b) then
z=x*2 temp = x * 2
z = temp
else else
y = 10 y = 10
temp = x * 2
g=x*2 g = temp;
Compiler Design 22
Code Motion
Move expression out of a loop if the
evaluation does not change inside the loop.
Example:
while ( i < (max-2) ) …
Equivalent to:
t := max - 2
while ( i < t ) …
Compiler Design 23
Code Motion
Safety of Code movement
Movement of an expression e from a basic block bi to another
block bj, is safe if it does not introduce any new occurrence of
e along any path.
Compiler Design 24
Strength Reduction
Replacement of an operator with a less costly one.
Example:
temp = 5;
for i=1 to 10 do for i=1 to 10 do
… …
x=i*5 x = temp
… …
temp = temp + 5
end end
Compiler Design 26
Dead Code Elimination
• Examples:
DEBUG:=0
if (DEBUG) print Can be
eliminated
Compiler Design 28
Copy Propagation
What does it mean?
Given an assignment x = y, replace later uses of x with
uses of y, provided there are no intervening assignments
to x or y.
When is it performed?
At any level, but usually early in the optimization
process.
What is the result?
Smaller code
Compiler Design 29
Copy Propagation
f := g are called copy statements or copies
Use of g for f, whenever possible after copy
statement
Example:
x[i] = a; x[i] = a;
sum = x[i] + a; sum = a + a;
Compiler Design 30
Local Copy Propagation
Local copy propagation
Performed within basic blocks
Algorithm sketch:
traverseBB from top to bottom
maintain table of copies encountered so far
Compiler Design 31
Loop Optimization
Decrease the number of instruction in the
inner loop
Even if we increase no of instructions in the
outer loop
Techniques:
Code motion
Induction variable elimination
Strength reduction
Compiler Design 32
Peephole Optimization
Compiler Design 33
Redundant instruction elimination
Redundant load/store: see if an obvious replacement is possible
MOV R0, a
MOV a, R0
Can eliminate the second instruction without needing any global knowledge of a
Unreachable code: identify code which will never be executed:
#define DEBUG 0
if( DEBUG) { if (0 != 1) goto L2
print debugging info print debugging info
}
L2:
Compiler Design 34
Algebraic identities
Worth recognizing single instructions with a constant operand:
A * 1 = A
A * 0 = 0
A / 1 = A
A * 2 = A + A
More delicate with floating-point
Strength reduction:
A ^ 2 = A * A
Compiler Design 35
Objective
Why would anyone write X * 1?
Why bother to correct such obvious junk code?
In fact one might write
#define MAX_TASKS 1
...
a = b * MAX_TASKS;
Also, seemingly redundant code can be produced by
other optimizations. This is an important effect.
Compiler Design 36
The right shift problem
Arithmetic Right shift:
shift right and use sign bit to fill most significant bits
-5 111111...1111111011
SAR 111111...1111111101
which is -3, not -2
in most languages -5/2 = -2
Compiler Design 38
Addition chains for multiplication
Compiler Design 39
Folding Jumps to Jumps
Compiler Design 40
Jump to Return
A jump to a return can be replaced by a return
JMP lab1
...
lab1: RET
Can be replaced by
RET
lab1 may become dead code
Compiler Design 41
Usage of Machine idioms
Use machine specific hardware instruction
which may be less costly.
i := i + 1
ADD i, #1 INC i
Compiler Design 42
Local Optimization
Compiler Design 43
Optimization of Basic Blocks
Many structure preserving transformations
can be implemented by construction of DAGs
of basic blocks
Compiler Design 44
DAG representation
of Basic Block (BB)
Leaves are labeled with unique identifier (var name
or const)
Interior nodes are labeled by an operator symbol
Nodes optionally have a list of labels (identifiers)
Edges relates operands to the operator (interior
nodes are operator)
Interior node represents computed value
Identifier in the label are deemed to hold the value
Compiler Design 45
Example: DAG for BB
t1
*
t1 := 4 * i
4 i
t1 := 4 * i
t3 := 4 * i
t2 := t1 + t3 if (i <= 20)goto L1
+ t2 <= (L1)
* t1, t3
i 20
4 i
Compiler Design 46
Construction of DAGs for BB
I/p: Basic block, B
O/p: A DAG for B containing the following
information:
1) A label for each node
2) For leaves the labels are ids or consts
3) For interior nodes the labels are operators
4) For each node a list of attached ids (possible
empty list, no consts)
Compiler Design 47
Construction of DAGs for BB
Data structure and functions:
Node:
1) Label: label of the node
2) Left: pointer to the left child node
3) Right: pointer to the right child node
4) List: list of additional labels (empty for leaves)
Node (id): returns the most recent node created for id.
Else return undef
Create(id,l,r): create a node with label id with l as left
child and r as right child. l and r are optional params.
Compiler Design 48
Construction of DAGs for BB
Method:
For each 3AC, A in B
A if of the following forms:
1. x := y op z
2. x := op y
3. x := y
1. if ((ny = node(y)) == undef)
ny = Create (y);
if (A == type 1)
and ((nz = node(z)) == undef)
nz = Create(z);
Compiler Design 49
Construction of DAGs for BB
1. If (A == type 1)
Find a node labelled ‘op’ with left and right as ny and nz respectively
[determination of common sub-expression]
If (not found) n = Create (op, ny, nz);
If (A == type 2)
Find a node labelled ‘op’ with a single child as ny
If (not found) n = Create (op, ny);
If (A == type 3) n = Node (y);
2. Remove x from Node(x).list
Add x in n.list
Node(x) = n;
Compiler Design 50
Example: DAG construction
from BB
t1 := 4 * i
* t1
4 i
Compiler Design 51
Example: DAG construction
from BB
t1 := 4 * i
t2 := a [ t1 ]
[] t2
* t1
a 4 i
Compiler Design 52
Example: DAG construction
from BB
t1 := 4 * i
t2 := a [ t1 ]
t3 := 4 * i
[] t2
* t1, t3
a 4 i
Compiler Design 53
Example: DAG construction
from BB
t1 := 4 * i
t2 := a [ t1 ]
t3 := 4 * i
t4 := b [ t3 ]
t4 [] [] t2
* t1, t3
b a 4 i
Compiler Design 54
Example: DAG construction
from BB
t1 := 4 * i
t2 := a [ t1 ]
t3 := 4 * i + t5
t4 := b [ t3 ]
t5 := t2 + t4
t4 [] [] t2
* t1, t3
b a 4 i
Compiler Design 55
Example: DAG construction
from BB
t1 := 4 * i
t2 := a [ t1 ]
t3 := 4 * i + t5,i
t4 := b [ t3 ]
t5 := t2 + t4
i := t5 t4 [] [] t2
* t1, t3
b a 4 i
Compiler Design 56
DAG of a Basic Block
Observations:
A leaf node for the initial value of an id
A node n for each statement s
The children of node n are the last definition
(prior to s) of the operands of n
Compiler Design 57
Optimization of Basic Blocks
Common sub-expression elimination: by
construction of DAG
Note: for common sub-expression elimination, we
are actually targeting for expressions that
compute the same value.
a := b + c
b := b – d Common expressions
c := c + d But do not generate the
e := b + c same result
Compiler Design 58
Optimization of Basic Blocks
DAG representation identifies expressions that
yield the same result
+ e
a := b + c
b := b – d
c := c + d
+ a - b + c
e := b + c
b0 c0 d0
Compiler Design 59
Optimization of Basic Blocks
Dead code elimination: Code generation from
DAG eliminates dead code.
c +
a := b + c
a := b + c
b := a – d ×b,d - d := a - d
d := a – d
c := d + c
c := d + c a +
d0
b is not live
b0 c0
Compiler Design 60
Loop Optimization
Compiler Design 61
Loop Optimizations
Most important set of optimizations
Programs are likely to spend more time in loops
Presumption: Loop has been identified
Optimizations:
Loop invariant code removal
Induction variable strength reduction
Induction variable reduction
Compiler Design 62
Loops in Flow Graph
Dominators:
A node d of a flow graph G dominates a node n, if every path in
G from the initial node to n goes through d.
Corollaries:
Every node dominates itself.
The initial node dominates all nodes in G.
The entry node of a loop dominates all nodes in the loop.
Compiler Design 63
Loops in Flow Graph
Each node n has a unique immediate dominator m,
which is the last dominator of n on any path in G
from the initial node to n.
(d ≠ n) && (d dom n) → d dom m
Dominator tree (T):
A representation of dominator information of
flow graph G.
The root node of T is the initial node of G
A node d in T dominates all node in its sub-tree
Compiler Design 64
Example: Loops in Flow Graph
1 1
2 3
2 3
4
4
5 6
5 6 7
7
8 9
8 9
Compiler Design 66
Loop Optimization
Loop interchange: exchange inner loops with outer
loops
Loop splitting: attempts to simplify a loop or
eliminate dependencies by breaking it into multiple
loops which have the same bodies but iterate over
different contiguous portions of the index range.
A useful special case is loop peeling - simplify a loop with a
problematic first iteration by performing that iteration
separately before entering the loop.
Compiler Design 73
Loop Optimization
Loop fusion: two adjacent loops would iterate the
same number of times, their bodies can be combined
as long as they make no reference to each other's
data
Loop fission: break a loop into multiple loops over
the same index range but each taking only a part of
the loop's body.
Loop unrolling: duplicates the body of the loop
multiple times
Compiler Design 74
Loop Optimization
Header
Pre-Header: loop L
Compiler Design 75
Loop Invariant Code Removal
Move out to pre-header the statements
whose source operands do not change within
the loop.
Be careful with the memory operations
Be careful with statements which are executed in
some of the iterations
Compiler Design 77
Loop Invariant Code Removal
Rules: A statement S: x:=y op z is loop invariant:
y and z not modified in loop body
S is the only statement to modify x
For all uses of x, x is in the available def set.
For all exit edge from the loop, S is in the available def set
of the edges.
If S is a load or store (mem ops), then there is no writes to
address(x) in the loop.
Compiler Design 78
Loop Invariant Code Removal
Loop invariant code removal can be done without
available definition information.
Compiler Design 79
Loop Induction Variable
Induction variables are variables such that every time
they change value, they are incremented or
decremented.
Basic induction variable: induction variable whose only
assignments within a loop are of the form:
i = i +/- C, where C is a constant.
Primary induction variable: basic induction variable that
controls the loop execution
(for i=0; i<100; i++)
i (register holding i) is the primary induction variable.
Derived induction variable: variable that is a linear
function of a basic induction variable.
Compiler Design 80
Loop Induction Variable
Basic: r4, r7, r1 r1 = 0
r7 = &A
Primary: r1 Loop: r2 = r1 * 4
r4 = r7 + 3
Derived: r2 r7 = r7 + 1
r10 = *r2
r3 = *r4
r9 = r1 * r3
r10 = r9 >> 4
*r2 = r10
r1 = r1 + 4
If(r1 < 100) goto Loop
Compiler Design 81
Induction Variable Strength Reduction
Create basic induction variables from derived
induction variables.
Rules: (S: x := y op z)
op is *, <<, +, or –
y is a induction variable
z is invariant
No other statement modifies x
x is not y or z
x is a register
Compiler Design 82
Induction Variable Strength Reduction
Transformation:
Insert the following into the bottom of pre-header:
new_reg = expression of target statement S
if (opcode(S)) is not add/sub, insert to the bottom of the preheader
new_inc = inc(y,op,z)
else Function: inc()
new_inc = inc(x)
Calculate the amount of inc
Insert the following at each update of y for 1st param.
new_reg = new_reg + new_inc
Change S: x = new_reg
Compiler Design 83
Example: Induction Variable Strength
Reduction
new_reg = r4 * r9
new_inc = r9
r5 = r4 - 3 r5 = r4 - 3
r4 = r4 + 1 r4 = r4 + 1
new_reg += new_inc
r7 = r4 *r9
r7 = new_reg
r6 = r4 << 2 r6 = r4 << 2
Compiler Design 84
Induction Variable Elimination
Remove unnecessary basic induction variables from the loop
by substituting uses with another basic induction variable.
Rules:
Find two basic induction variables, x and y
x and y in the same family
Incremented at the same place
Increments are equal
Initial values are equal
x is not live at exit of loop
For each BB where x is defined, there is no use of x between the first
and the last definition of y
Compiler Design 85
Example: Induction Variable
Elimination
r1 = 0 r2 = 0
r2 = 0
r1 = r1 - 1 r2 = r2 - 1
r2 = r2 -1
r9 = r2 + r4 r7 = r1 * r9 r9 = r2 + r4 r7 = r2 * r9
r4 = *(r1) r4 = *(r2)
*r2 = r7 *r7 = r2
Compiler Design 86
Induction Variable Elimination
Variants:
Trivial: induction variable that are never used except to increment
Complexity of elimination
1.
themselves and not live at the exit of loop
2. Same increment, same initial value (discussed)
3. Same increment, initial values are a known constant offset from one
another
4. Same increment, nothing known about the relation of initial value
5. Different increments, nothing known about the relation of initial
value
Compiler Design 87
Example: Induction Variable
Elimination
Case 4: Same increment, unknown initial value
For the induction variable that we are eliminating, look at each non-
incremental use, generate the same sequence of values as before. If that
can be done without adding any extra statements in the loop body, then
the transformation can be done.
rx := r2 –r1 + 8
r4 := r2 + 8 r4 := r1 + rx
r3 := r1 + 4 r3 := r1 = 4
. .
. .
r1 := r1 + 4 r1 := r1 + 4
r2 := r2 + 4
Compiler Design 88
Loop Unrolling
Replicate the body of a loop (N-1) times, resulting in
total N copies.
Enable overlap of operations from different iterations
Increase potential of instruction level parallelism (ILP)
Variants:
Unroll multiple of known trip counts
Unroll with remainder loop
While loop unroll
Compiler Design 89
Global Data Flow
Analysis
Compiler Design 90
Global Data Flow Analysis
Collect information about the whole program.
Distribute the information to each block in the flow
graph.
Compiler Design 91
Data flow analysis
IMPORTANT!
Data flow analysis should never tell us that a
transformation is safe when in fact it is not.
When doing data flow analysis we must be
Conservative
Do not consider information that may not preserve the
behavior of the program
Aggressive
Try to collect information that is as exact as possible, so we
can get the greatest benefit from our optimizations.
Compiler Design 92
Global Iterative Data Flow Analysis
Global:
Performed on the flow graph
Goal = to collect information at the beginning
and end of each basic block
Iterative:
Construct data flow equations that describe how
information flows through each basic block and
solve them by iteratively converging on a
solution.
Compiler Design 93
Global Iterative Data Flow Analysis
Components of data flow equations
Sets containing collected information
in set: information coming into the BB from outside (following
flow of data)
gen set: information generated/collected within the BB
kill set: information that, due to action within the BB, will affect
what has been collected outside the BB
out set: information leaving the BB
Functions (operations on these sets)
Transfer functions describe how information changes as it flows
through a basic block
Meet functions describe how information from multiple paths is
combined.
Compiler Design 94
Global Iterative Data Flow Analysis
Algorithm sketch
Typically, a bit vector is used to store the information.
For example, in reaching definitions, each bit position corresponds to
one definition.
We use an iterative fixed-point algorithm.
Depending on the nature of the problem we are solving, we may
need to traverse each basic block in a forward (top-down) or
backward direction.
The order in which we "visit" each BB is not important in terms of
algorithm correctness, but is important in terms of efficiency.
In & Out sets should be initialized in a conservative and aggressive
way.
Compiler Design 95
Global Iterative Data Flow Analysis
Compiler Design 96
Typical problems
Reaching definitions
For each use of a variable, find all definitions that reach it.
Compiler Design 97
Global Data Flow Analysis
A typical data flow equation:
out[ S ] gen[ S ] (in[ S ] kill[ S ])
S: statement
in[S]: Information goes into S
kill[S]: Information get killed by S
gen[S]: New information generated by S
out[S]: Information goes out from S
Compiler Design 98
Global Data Flow Analysis
The notion of gen and kill depends on the desired
information.
In some cases, in may be defined in terms of out -
equation is solved as analysis traverses in the
backward direction.
Data flow analysis follows control flow graph.
Equations are set at the level of basic blocks, or even for a
statement
Compiler Design 99
Points and Paths
Point within a basic block:
A location between two consecutive statements.
A location before the first statement of the basic block.
A location after the last statement of the basic block.
Path: A path from a point p1 to pn is a sequence of
points p1, p2, … pn such that for each i : 1 ≤ i ≤ n,
pi is a point immediately preceding a statement and pi+1 is
the point immediately following that statement in the
same block, or
pi is the last point of some block and pi+1 is first point in the
successor block.
B4
p1 pn
p2
d6: a := u2 B5 B6
Compiler Design 101
Reaching Definition
Definition of a variable x is a statement that assigns or may
assign a value to x.
Unambiguous Definition: The statements that certainly assigns a value
to x
Assignments to x
Read a value from I/O device to x
Ambiguous Definition: Statements that may assign a value to x
Call to a procedure with x as parameter (call by ref)
Call to a procedure which can access x (x being in the scope of the
procedure)
x is an alias for some other variable (aliasing)
Assignment through a pointer that could refer x
d6: a := u2 B5 B6
Compiler Design 104
Reaching Definition
Non-Conservative view: A definition might reach a
point even if it might not.
Only unambiguous definition kills a earlier definition
All edges of flow graph are assumed to be traversed.
if (a == b) then a = 2
else if (a == b) then a = 4
The definition “a=4” is not reachable.
S1
S → S1 ; S2
S2
if E goto S1
S → if E then S1 else S2
S1 S2
S1
S → do S1 while E
if E goto S1
gen[ S ] {d }
kill[ S ] Da {d }
S d: a := b + c
S1
S
S2
S S1 S2
in[ S1 ] in[ S ]
in[ S 2 ] in[ S ]
out[ S ] out[ S1 ] out[ S 2 ]
S S1
Attributes
use = set of variable used in the BB prior to its definition
def = set of variables defined in BB prior to any use of the variable
in = set of variables that are live at the entry point of a BB
out = set of variables that are live at the exit point of a BB
r4 is dead, as it is redefined.
So is r6. r2, r3, r5 are live
r4 = 4
r6 = 8
r6 = r2 + r3
r7 = r4 – r5 What does this mean?
r6 = r4 – r5 is useless,
it produces a dead value !!
Get rid of it!
Compiler Design 128
Computation of use and def sets
change = true;
while (change) do
change = false
for each basic block BB do
old_in = in(BB);
out(BB) = U{in(Y): for all successors Y of BB}
in(X) = use(X) U (out(X) – def(X))
if (old_in != in(X)) then change = true
endfor
endfor
DU Chain of r3:
(3) -> 11
4: r1 = r1 + 5 7: r7 = r6 (5) -> 11
5: r3 = r5 – r1 8: r2 = 0 (12) -> UD Chain of r1:
6: r7 = r3 * 2 9: r7 = r7 + 1 (12) -> 11
UD Chain of r7:
(10) -> 6,9
10: r8 = r7 + 5
11: r1 = r3 – r8
12: r3 = r1 * 2
Compiler Design 132
Some-things to Think About
Liveness and Reaching definitions are basically the same
thing!
All dataflow is basically the same with a few parameters
Meaning of gen/kill (use/def)
Backward / Forward
All paths / some paths (must/may)
So far, we have looked at may analysis algorithms
How do you adjust to do must algorithms?
Dataflow can be slow
How to implement it efficiently?
How to represent the info?
1: r1 = r2 + r3 1,2 reach
2: r6 = r4 – r5 1,2 available
1,2 reach 3: r4 = 4
1,2 available 4: r6 = 8
1,3,4 reach
1,3,4 available
5: r6 = r2 + r3
6: r7 = r4 – r5 1,2,3,4 reach
1 available
Compiler Design 139
Available Definition Analysis (Adefs)
A definition d is available at a point p if along all paths from d
to p, d is not killed
Remember, a definition of a variable is killed between 2 points when there
is another definition of that variable along the path
r1 = r2 + r3 kills previous definitions of r1
Algorithm:
Forward dataflow analysis as propagation occurs from defs downwards
Use the Intersect function as the meet operator to guarantee the all-
path requirement
gen/kill/in/out similar to reaching defs
Initialization of in/out is the tricky part
change = true
while (change) do
change = false
for each basic block BB, do
old_out = out(BB)
in(BB) = out(Y) : for all predecessors Y of BB
out(BB) = GEN(X) + (IN(X) – KILL(X))
if (old_out != out(X)) then change = true
endfor
endfor
Requirements – Efficiency!
Large amount of information to store
Fast access/manipulation
Bitvectors
General strategy used by most compilers
Bit positions represent defs (rdefs)
Efficient set operations: union/intersect/isone
Used for gen, kill, in, out for each BB
dS: r1 := r2 + r3
Benefits:
Reduced computation dT: r4 := r2 + r3
Generates mov statements, which
can get copy propagated
Rules:
dS and dT has the same expression
dS: r1 := r2 + r3
src(dS) == src(dT) for all sources
r100 := r1
For all sources x, x is not redefined
between dS and dT
dT: r4 := r100
Rules:
dS and dT has the same expression
src(dS) == src(dT) for all sources of dS and dT
Expression of dS is available at dT