0% found this document useful (0 votes)
70 views40 pages

Optimization PDF

The document discusses 3 compiler optimization techniques: 1) statement-by-statement code generation, 2) peephole optimization which replaces short sequences of instructions with shorter/faster sequences through several passes, and 3) "global" optimization which analyzes data flow across the entire program to collect information for optimizations like common subexpression elimination.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
70 views40 pages

Optimization PDF

The document discusses 3 compiler optimization techniques: 1) statement-by-statement code generation, 2) peephole optimization which replaces short sequences of instructions with shorter/faster sequences through several passes, and 3) "global" optimization which analyzes data flow across the entire program to collect information for optimizations like common subexpression elimination.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 40

1.

statement-by-statement code generation


2. peephole optimization
3. “global” optimization

0-0
Peephole optimization

Peephole: a short sequence of target instructions that may be


replaced by a shorter/faster sequence
One optimization may make further optimizations possible
⇒ several passes may be required

1. Redundant load/store elimination:


Section 9.9

MOV R0 a
MOV a R0 ← delete if in same B.B.
2. Algebraic simplification: eliminate instructions like the
following:
x = x + 0 x = x * 1
3. Strength reduction: replace expensive operations by
equivalent cheaper operations, e.g.
x2 → x * x
fixed-point multiplication/division by power of 2 → shift

Compiler Construction: Code Optimization – p. 1/35


Peephole optimization

4. Jumps:
goto L1 if a < b goto L1
... ...
L1: goto L2 L1: goto L2
⇓ ⇓
goto L2 if a < b goto L2
... ...
L1: goto L2 L1: goto L2

If there are no other jumps to L1, and it is preceded by an


unconditional jump, it may be eliminated.
If there is only jump to L1 and it is preceded by an
unconditional goto
goto L1 if a < b goto L2
... goto L3
L1: if a < b goto L2 ⇒ ...
L3: L3:
Compiler Construction: Code Optimization – p. 2/35
Peephole optimization

5. Unreachable code: unlabeled instruction following an


unconditional jump may be eliminated

#define DEBUG 0 if debug = 1 goto L1


... goto L2
if (debug) { ⇒ L1: /* print */
/* print stmts */ L2:
}

if 0 != 1 goto L2 if debug != 1 goto L2


/* print stmts */ ⇐ /* print stmts */
L2: L2:

eliminate

Compiler Construction: Code Optimization – p. 3/35


Example

i = m-1; j = n; v = a[n];
while (1) {
do i = i+1; while (a[i] < v);
do j = j-1; while (a[j] > v);
if (i >= j) break;
x = a[i]; a[i] = a[j]; a[j] = x;
Section 10.1

}
x = a[i]; a[i] = a[n]; a[n] = x;

Compiler Construction: Code Optimization – p. 4/35


Intermediate code

1 i = m-1 16 t7 = 4*i
2 j = n 17 t8 = 4*j
3 t1 = 4*n 18 t9 = a[t8]
4 v = a[t1] 19 a[t7] = t9
5 i = i+1 20 t10 = 4*j
6 t2 = 4*i 21 a[t10] = x
7 t3 = a[t2] 22 goto 5
8 if t3 < v goto 5 23 t11 = 4*i
9 j = j-1 24 x = a[t11]
10 t4 = 4*j 25 t12 = 4*i
11 t5 = a[t4] 26 t13 = 4*n
12 if t5 > v goto 9 27 t14 = a[t13]
13 if i>=j goto 23 28 a[t12] = t14
14 t6 = 4*i 29 t15 = 4*n
15 x = a[t6] 30 a[t15] = x
Compiler Construction: Code Optimization – p. 5/35
Basic blocks

1 i = m-1 16 t7 = 4*i
2 j = n 17 t8 = 4*j
3 t1 = 4*n 18 t9 = a[t8]
4 v = a[t1] 19 a[t7] = t9
5 i = i+1 20 t10 = 4*j
6 t2 = 4*i 21 a[t10] = x
7 t3 = a[t2] 22 goto 5
8 if t3 < v goto 5 23 t11 = 4*i
9 j = j-1 24 x = a[t11]
10 t4 = 4*j 25 t12 = 4*i
11 t5 = a[t4] 26 t13 = 4*n
12 if t5 > v goto 9 27 t14 = a[t13]
13 if i>=j goto 23 28 a[t12] = t14
14 t6 = 4*i 29 t15 = 4*n
15 x = a[t6] 30 a[t15] = x
Compiler Construction: Code Optimization – p. 6/35
Flow graph

i = m-1 t6 = 4*i
j = n x = a[t6]
B1
t1 = 4*n t7 = 4*i
v = a[t1] t8 = 4*j
t9 = a[t8] B5
i = i+1 a[t7] = t9
t2 = 4*i t10 = 4*j
B2
t3 = a[t2] a[t10] = x
if t3 < v goto B2 goto B2
t11 = 4*i
x = a[t11]
j = j-1
t12 = 4*i
t4 = 4*j
B3 t13 = 4*n
t5 = a[t4] B6
t14 = a[t13]
if t5 > v goto B3
a[t12] = t14
t15 = 4*n
B4 if i>=j goto B6 a[t15] = x
Compiler Construction: Code Optimization – p. 7/35
Optimization methods

Common subexpression elimination:


Def. E is a common subexpression at some point in the
program if it has been previously computed and the values of
variables in E have not changed since the last computation
NOTE : local vs. global C.S.E.
array expressions
Section 10.2

Compiler Construction: Code Optimization – p. 8/35


Optimization methods

Common subexpression elimination:


Def. E is a common subexpression at some point in the
program if it has been previously computed and the values of
variables in E have not changed since the last computation
NOTE : local vs. global C.S.E.
array expressions
Section 10.2

Copy propagation: after the copy statement x = y, use y


wherever possible in place of x

Compiler Construction: Code Optimization – p. 8/35


Optimization methods

Common subexpression elimination:


Def. E is a common subexpression at some point in the
program if it has been previously computed and the values of
variables in E have not changed since the last computation
NOTE : local vs. global C.S.E.
array expressions
Section 10.2

Copy propagation: after the copy statement x = y, use y


wherever possible in place of x
Dead code elimination:
Dead variable: v is dead at a point if its value is not used
after that point
Dead code: statements which compute values that are
never used

Compiler Construction: Code Optimization – p. 8/35


Loop optimizations

Code motion: if a statement is independent of the number


of times a loop is executed (≡ loop invariant computation),
move it outside the loop
Example:
t = N-1
while (i <= N-1) ... ⇒
while (i <= t) ...
Induction variable elimination:
Induction variable: variable whose value has a simple
relation with no. of loop iterations
Strength reduction: replacing expensive operation by
cheaper one (e.g. multiplication by addition)

Compiler Construction: Code Optimization – p. 9/35


Data flow analysis

Motivation: collect information like live variables, common


subexpressions, etc. about entire program for optimization (and
code generation)

Plan:
Structured programs
Section 10.5

reaching definitions
Flow graphs / Iterative solutions
reaching definitions
available expressions
live variables

Compiler Construction: Code Optimization – p. 10/35


Structured programs

Control-flow changes only via if and while stmts (no arbitrary


gotos)
Source-level grammar:
S → id = E
| S; S
| if E then S else S
| do S while E

Compiler Construction: Code Optimization – p. 11/35


Reaching definitions

Point: position between 2 adjacent stmts within a BB, before the


1st stmt in a BB, and after the last stmt in a BB
Path: sequence of points p1 , p2 , . . . , pn s.t. pi immediately
precedes and pi+1 immediately follows an instruction, or pi ends
a block, and pi+1 begins a successor block

Definition of a variable x is a stmt that assigns or may assign a


value to x
Unambiguous defn. – stmt that definitely assigns a value to
x, e.g. direct assignments, I/O
Ambiguous defn. – stmt that may change the value of x, e.g.
indirect assignment, procedure call
Kill: a definition of a variable is killed on a path, if there is a
(unambiguous) definition of the variable along that path

Compiler Construction: Code Optimization – p. 12/35


Reaching definitions

Reaching Definition: A definition d reaches point p if there is a


path from the point immediately following d to p, and d is not
killed along that path
Applications: used for constant folding, code motion, induction
variable elimination, dead code elimination, etc.

Compiler Construction: Code Optimization – p. 13/35


Reaching definitions

Reaching Definition: A definition d reaches point p if there is a


path from the point immediately following d to p, and d is not
killed along that path
Applications: used for constant folding, code motion, induction
variable elimination, dead code elimination, etc.

in(S) – set of definitions reaching the beginning of stmt S


out(S) – set of definitions reaching the end of stmt S
gen(S) – set of definitions that reach the end of S , irrespec-
tive of whether they reach the beginning of S
kill (S) – set of definitions that never reach the end of S ,
even if they reach the beginning of S

Compiler Construction: Code Optimization – p. 13/35


Data flow equations

gen(S) = {d}
d: a=b+c kill (S) = Da − {d}

gen(S) = gen(S2 ) ∪ (gen(S1 ) − kill (S2 ))


S1 kill (S) = kill (S2 ) ∪ (kill (S1 ) − gen(S2 ))

in(S1 ) = in(S)
S2 in(S2 ) = out(S1 )
out(S) = out(S2 )

Compiler Construction: Code Optimization – p. 14/35


Data flow equations

gen(S) = gen(S1 ) ∪ gen(S2 )


kill (S) = kill (S1 ) ∩ kill (S2 )
S1 S2
in(S1 ) = in(S2 ) = in(S)
out(S) = out(S1 ) ∪ out(S2 )

gen(S) = gen(S1 )
kill (S) = kill (S1 )
S1

in(S1 ) = in(S) ∪ gen(S1 )


out(S) = out(S1 )

Compiler Construction: Code Optimization – p. 15/35


Data flow equations

1. Compute gen, kill (synthesized attributes) bottom up from


smallest stmt to largest stmt.
2. Let S0 represent the complete program. Then in(S0 ) = ∅.
3. For S1 , a sub-statement of S :
(i) calculate in(S1 ) in terms of in(S);
(ii) calculate out(S1 ) using the equation
out (S) = gen(S) ∪ (in(S) − kill (S))
4. Calculate out(S) in terms of out(S1 ).

Compiler Construction: Code Optimization – p. 16/35


Iterative approach

Reaching definitions
Input: flow graph with gen , kill sets computed for each BB
Output: in , out sets for each block
Method:
P1 P2 ... Pn
Section 10.6

1. For each block, initialize


out(B) ← gen(B)
(assume in(B) = ∅)
B
2. While changes occur:
for each block S
B
in(B) ← P out(P ) where P - predecessor of B
out(B) ← gen(B) ∪ (in(B) − kill (B))

Compiler Construction: Code Optimization – p. 17/35


Reaching definitions

Changes are monotonic ⇒ method converges.


While loop (step 2) simulates all possible alternatives for
control flow during the execution of the program.
If a definition reaches a point, it can do so along a cycle-free
path.
Longest cycle free path in the graph can cover at most all
nodes, at most once.
⇒ Upper bound on # iterations = # of nodes in the flow
graph.
Avg. # of iterations for covergence for real programs = 5

Compiler Construction: Code Optimization – p. 18/35


U-D chains

Definition: for a given use of a variable a, the ud chain is a list


of all definitions of a that reach that use
Method:
Given a use of variable a in block B
1. If the use is not preceded by an unambiguous defn. of a
within B , ud = set of defns of a in in(B).
2. If there is an unambiguous defn of a within B prior to this
use, then ud = { most recent unambiguous defn. }
3. In addition, if there are ambiguous definitions of a, then add
all those for which no unambiguous defn. lies between it and
the current use to the ud chain.

Compiler Construction: Code Optimization – p. 19/35


Available expressions

Definition: x+y is available at point p if every path from the


initial node to p evaluates x+y and there are no subsequent
assignments to x or y after the last evaluation
Kill: x+y is killed if x or y is assigned and x+y is not
subsequently recomputed
Gen: x+y is generated if the value of x+y is computed and x, y
are not subsequently redefined

Compiler Construction: Code Optimization – p. 20/35


Available expressions

Calculating AEs within a block


1. Initialize A ← ∅.
2. Consider each assignment x = y+z within the block in turn:
(i) add y+z to A
(ii) delete any expression involving x from A
3. At the end, gen = A
kill = set of all expressions y+z s.t. y or z is defined within
the block and y+z 6∈ A

Compiler Construction: Code Optimization – p. 21/35


Available expressions

Input: flow graph with e _gen , e _kill sets for each BB


Output: in , out sets for each block
Method:
1. Initialize in(B1 ) ← ∅, out(B1 ) ← e _gen(B1 ) (B1 - initial
node)
2. For each B 6= B1 , initialize out(B) ← U − e _kill (B)
3. While changes occur:
for each B 6= B
T1
in(B) ← P out(P ) where P - predecessor of B
out(B) ← e _gen(B) ∪ (in(B) − e _kill (B))

Compiler Construction: Code Optimization – p. 22/35


Live variables

in(B) – set of variables live at the initial point of B


out(B) – set of variables live at the end point of B
def (B) – set of variables definitely assigned values in B
prior to any use in B
use(B) – set of variables whose values may be used in B
prior to any definition of the variable

Compiler Construction: Code Optimization – p. 23/35


Live variables

Input: flow graph with def , use sets for each BB


Output: in , out sets for each block
Method:
1. For each B , initialize B
in(B) ← use(B)

S1 S2 ... Sn
2. While changes occur:
for each block BS
out(B) ← S in(S) where S - successor of B
in(B) ← use(B) ∪ (out (B) − def (B))

D-U chain: du-chain for a variable x at a given point p is the set


of uses s of the variable s.t. there is a path from p to s that does
not redefine x
Compiler Construction: Code Optimization – p. 24/35
Common subexpression elimination

Input: flow graph with available expression information


Output: revised flow graph
Method:
For each stmt s x = y+z s.t. y+z is available at the beginning
of s’ block and y, z are not defined prior to s within the block:
Section 10.7

1. follow flow graph edges backwards until a block containing


an evaluation w = y+z is found
2. create a new variable u
3. replace w = y+z by u = y+z w = u
4. replace x = y+z by x = u

Compiler Construction: Code Optimization – p. 25/35


Common subexpression elimination

Should be used with copy propagation


May need multiple passes for best effect

Compiler Construction: Code Optimization – p. 26/35


Copy propagation

Principle: Given s: x=y , y can be substituted for x in all uses


u of x if
1. s is the only definition of x reaching u
2. on every path from s to u (including paths that go through u
several times but not more than once through s) there are no
assignments to y

Compiler Construction: Code Optimization – p. 27/35


Copy propagation

in(B) – set of copies s: x=y s.t. every path from initial


node to beginning of B contains s and there are
no assignments to x, y after the last occurrence of
s
out(B) – as above
gen(B) – all copies s: x=y in B s.t. there are no assign-
ments to y within B after s
kill (B) – all copies s: x=y s.t. x or y is assigned in B and
s 6∈ B

Compiler Construction: Code Optimization – p. 28/35


Copy propagation

in(B) – set of copies s: x=y s.t. every path from initial


node to beginning of B contains s and there are
no assignments to x, y after the last occurrence of
s
out(B) – as above
gen(B) – all copies s: x=y in B s.t. there are no assign-
ments to y within B after s
kill (B) – all copies s: x=y s.t. x or y is assigned in B and
s 6∈ B

out = gen ∪ (in − kill )


in(B1 ) = ∅
\
in(B) = out (P ) where P - pred. of B, B 6= B1
P

Compiler Construction: Code Optimization – p. 28/35


Copy propagation

Input: flow graph with ud chains, du chains, in(B)


Output: revised flow graph
Method: For each s: x=y do:
1. Determine the uses of x reached by this definition.
2. Determine whether for every use of x in (1), s ∈ in(B) for the
block containing the use and no definitions of x, y occur prior
to this use within B .
3. If s meets the conditions in (2), remove s and replace all uses
of x found in (1) by y.

Compiler Construction: Code Optimization – p. 29/35


Loops

Dominator: a node d dominates node n if every path from the


initial node to n goes through d
Back edge: an edge a → b in a flow graph is a back edge if b
dominates a
Natural loop: given a back edge n → d, the natural loop for this
Section 10.4

edge consists of d along with all nodes from which we can reach
n without going through d
Header: the node that dominates all other nodes in a loop
Pre-header: Given a loop L with header h:
1. create an empty block p;
2. make h the only successor of p;
3. all edges which entered h from outside L are changed to
point to p (edges to h from inside L are not changed).

Compiler Construction: Code Optimization – p. 30/35


Loop-invariant computations

Input: loop L + ud chains for statements in the loop


Output: statements that perform loop-invariant computations
Method:
1. Mark “invariant” any statement whose operands are all either
constants or have all their reaching definitions outside L.
Section 10.7

2. Repeat until no further changes:


mark “invariant” any statement that is not already marked
and all of whose operands satisfy one of the following
conditions:
(i) the operand is a constant
(ii) the operand has all its reaching definitions outside L
(iii) the operand has exactly one reaching definition, and that
definition is a statement in L that has been marked
invariant

Compiler Construction: Code Optimization – p. 31/35


Conditions for moving x = y+z

B1 i=1

B2 if u<v goto B3

B3
i=2 The block containing s must
u=u+1 dominate all exit nodes of the
loop (i.e. nodes with a succes-
sor not in the loop).
v=v-1
B4
if v<20 goto B5

B5 j=i

Compiler Construction: Code Optimization – p. 32/35


Conditions for moving x = y+z

B1 i=1

B2
i=3
if u<v goto B3
B3 There is no other assignment to
i=2
x in the loop.
u=u+1

(usually satisfied by temporaries)


v=v-1
B4 if v<20 goto B5

B5 j=i

Compiler Construction: Code Optimization – p. 33/35


Conditions for moving x = y+z

B1 i=1

B2
if u<v goto B3

No use of x in the loop is


B3
reached by any definition of x
i=2
u=u+1
other than s.

k=i (usually satisfied by temporaries)


B4 v=v-1
if v<20 goto B5

B5 j=i

Compiler Construction: Code Optimization – p. 34/35


Code motion

Input: loop L with ud chains and dominator information


Output: revised loop with a preheader
Method:
1. Find loop-invariant computations (see above).
2. For each statement s defining x found in (1), check whether:
(i) it is in a block that dominates all exits of L
(ii) x is not defined elsewhere in L
(iii) all uses in L of x can only be reached by the definition of
x in statement s
3. Move all stmts s that satisfy (2) to the preheader in the order
in which they were found in (1) provided any operands of s
that are defined in loop L have also had their definitions
moved to the preheader.

Compiler Construction: Code Optimization – p. 35/35

You might also like