Parametric Shape Analysis via 3

Liveness Analysis
Mooly Sagiv
Schrierber 317
03-640-7606
Wed 10:00-12:00
html://www.math.tau.ac.il/~msagiv/courses/wcc02.html
Basic Compiler Phases
Source program (string)
lexical analysis
Tokens
syntax analysis
Abstract syntax tree
semantic analysis
Frame
Translate
Intermediate representation
Instruction selection
Assembly
Register Allocation
Fin. Assembly
Register Allocation
• Input:
– Sequence of machine code instructions
(assembly)
• Unbounded number of temporary registers
• Output
– Sequence of machine code instructions
(assembly)
– Machine registers
– Some MOVE instructions removed
– Missing prologue and epilogue
LABEL(l3)
CJUMP(EQ, TEMP t128, CONST 0, l0, l1)
LABEL( l1)
MOVE(TEMP t131, TEMP t128)
MOVE(TEMP t130, CALL(nfactor, BINOP(MINUS, TEMP t128, CONST 1)))
MOVE(TEMP t129, BINOP(TIMES, TEMP t131, TEMP t130))
LABEL(l2)
MOVE(TEMP t103, TEMP t129)
JUMP(NAME lend)
LABEL(l0)
MOVE(TEMP t129, CONST 1)
JUMP(NAME l2)
Missing updates for static link
l3:
beq t128, $0, l0
l3:
beq $25, $0, l0
l1:
or t131, $0, t128
l1:
or $30, $0, $25
addi t132, t128, -1
or $4, $0, t132
jal nfactor
or t130, $0, $2
or t133, $0, t131
mult t133, t130
mflo t133
or t129, $0, t133
l2:
or t103, $0, t129
addi $4, $25, -1
t128
t129
t130
t131
t132
t133
t103
$25
$30
$2
$30
$4
$30
$2
/*
jal nfactor
/*
or $2, $0, $2 */
/*
or $30, $0, $30 */
mult $30, $2
mflo $30
/*
or $30, $0, $30 */
l2:
or $2, $0, $30
b lend
l0:
addi t129, $0, 1
b l2
or $4, $0, $4 */
b lend
l0:
addi $30, $0, 1
b l2
.global nfactor
.ent
nfactor
factor_framesize=40
.frame
nfactor: addiu
$sp,nfactor_framesize,$31
$sp,$sp,-nfactor_framesize
l3:
beq $25, $0, l0
l1:
or $30, $0, $25
sw
$2,0+nfactor_framesize($sp)
or
$25, $0, $4
addi $4, $25, -1
sw
$31,-4+nfactor_framesize($sp)
jal nfactor
sw
$30,-8+nfactor_framesize($sp)
mult $30, $2
mflo $30
lend:
lw
$30,-8+nfactor_framesize($sp)
lw
$31,-4+nfactor_framesize($sp)
addiu
$sp,$sp,nfactor_framesize
j
.end
$31
nfactor
l2:
or $2, $0, $30
b lend
l0:
addi $30, $0, 1
b l2
The need for “spilling”
• The number of registers may not be enough
– Spill the content of some registers into memory
– Load when needed
• Increase the number of instructions
• Increase CPU time
The Challenge
• Minimize the number of spills
• Minimize the number of MOVEs
• Minimize CPU time
Outline
• Liveness Analysis
–
–
–
–
–
–
Motivation
Static Liveness
Dataflow Equations
Solutions
An Iterative Algorithm
Liveness in Tiger (Targil)
• Actual Allocation
– Next week
Liveness Analysis
• The same register may be assigned (at
compile-time) to two temporaries if their
“life-times” do not overlap
• A variable is live a given
program point
– its current is used after this point prior to a
definition (assignment)
• v is live at a given program point
• There exists an execution sequence from this point to
a use of v that does not assign to v
• Two variables interfere at a given point
– they are simultaneously live at this point
A Simple Example
/* c */
L0:
a := 0
/* ac */
L1:
a
b
b := a + 1
/* bc */
c := c + b
/* bc */
c
a := b * 2
/* ac */
if c < N goto L1
/* c */
return c
Liveness Interference Graph
• For every compiled function
• Nodes
– Pre-colored machine registers
– Temporaries
• Undirected-Edges
– Temporaries that are simultaneously alive
– Different machine registers
• Undirected MOVE edges
– “Correlated” temporaries and registers
Other usages of Livness
A Simple Example
/* c */
L0:
a := 0
/* ac */
L1:
a
b
b := a + 1
/* bc */
c := c + b
/* bc */
c
a := b * 2
/* ac */
if c < N goto L1
/* c */
return c
l3:
beq t128, $0, l0 /* $0, t128 */
l1:
or t131, $0, t128 /* $0, t128, t131 */
addi t132, t128, -1 /* $0, t131, t132 */
t132
or $4, $0, t132 /* $0, $4, t131 */
jal nfactor
t130
/* $0, $2, t131 */
or t130, $0, $2 /* $0, t130, t131 */
t131
t133
or t133, $0, t131 /* $0, t130, t133 */
mult t133, t130 /* $0, t133 */
mflo t133 /* $0, t133 */
t128
t129
$0
or t129, $0, t133 /* $0, t129 */
l2:
or t103, $0, t129 /* $0, t103 */
$2
$4
b lend /* $0, t103 */
l0:
addi t129, $0, 1 /* $0, t129 */
b l2 /* $0, t129 */
t103
Undecidabily
• A variable is live at a given
point in the program
– if its current value is used after this point prior to
a definition in some execution path
• It is undecidable if a variable is live at a
given program location
Proof Sketch
Pr
L: x := y
Is y live at L?
Conservative
• The compiler need not generate the optimal
code
• Can use more registers (“spill code”) than
necessary
• Find an upper approximation of the live
variables
• A superset of edges in the interference graph
• Not too many superfluous live variables
Control Flow Graph
• Nodes
– Assembly instructions
• Directed-Edges
– If an instruction x can be immediately followed
by an instruction y
• A directed edge xy
Static Liveness
• A variable v is statically live at control flow
node n
– there exists a directed path p from n to a use of v
such that
• p does not include an assignment to v
• Every live variable is statically live
• Some statically live variables are not live
– since some control flow paths are nonexecutable
Example
a := b * b ;
a := b * b ;
c := a + b ;
c := a + b ;
if (c >= b)
then return c;
else return a;
c >= b
return c;
return a;
a := 0 ;
/* c */
L0:
a := 0
b := a +1 ;
b := a + 1
c := c +b ;
/* ac */
L1:
/* bc */
c := c + b
/* bc */
a := b*2 ;
a := b * 2
/* ac */
if c < N goto L1
c <N goto L1
/* c */
return c
return c ;
Computing Static Liveness
• Generate a system of equations for every
function
– define the set of live variables recursively
• Iteratively compute a minimal solution
The System of Equations
• For every instruction n
– def[n]
• The temporary and physical register(s) assigned by n
– use[n]
• The temporary and physical register used in n
• System of equations
– LiveOut[ex] = 
– LiveOut[n] =  (n, m)  Edges Live[m]
– Live[n] = (LiveOut[n] – def[n])  use[n]
a := 0 ;
b := a +1 ;
c := c +b ;
1
2
3
ins
def[n]
use[n]
1
{a}

2
{b}
{a}
3
{c}
{c, b}
4
{a}
{b}
5

{c}
6

{c}
LiveOut[6] = 
a := b*2 ;
4
Live[6] = (LiveOut[6] – )  {c}
LiveOut[5] = Live[6]  Live[2]
Live[5] = (LiveOut[5] – )  {c}
LiveOut[4] = Live[5]
c <N goto L1
return c ;
5 LiveOut[3] = Live[4]
6
Live[4] = (LiveOut[4] – {a})  {b}
Live[3] = (LiveOut[3] – {c})  {c, b}
LiveOut[2] = Live[3]
Live[2] = (LiveOut[2] – {b})  {a}
LiveOut[1] = Live[2]
Live[1] = (LiveOut[1] – {a})  
a := 0 ;
b := a +1 ;
c := c +b ;
1
2
3
ins
def[n]
use[n]
1
{a}

2
{b}
{a}
3
{c}
{c, b}
4
{a}
{b}
5

{c}
6

{c}
LiveOut[6] = 
a := b*2 ;
4
Live[6] = LiveOut[6]  {c}
LiveOut[5] = Live[6]  Live[2]
Live[5] = LiveOut[5]  {c}
LiveOut[4] = Live[5]
c <N goto L1
return c ;
5 LiveOut[3] = Live[4]
6
Live[4] = (LiveOut[4] – {a})  {b}
Live[3] = (LiveOut[3] – {c})  {c, b}
LiveOut[2] = Live[3]
Live[2] = (LiveOut[2] – {b})  {a}
LiveOut[1] = Live[2]
Live[1] = (LiveOut[1] – {a})
Fixed Points
• A fixed point is a vector solution Live and LiveOut
– for every instruction n
• LiveOut[ex] = 
• LiveOut[n] =  (n, m)  Edges Live[m]
• Live[n] = (LiveOut[n] – def[n])  use[n]
• There more than one fixed point
• Every fixed point contains at least the statically live
variables
• The least fixed point (in terms of set inclusion)
uniquely exists
– it contains exactly the statically live variables
LiveOut[6] = 
a := 0 ;
1
Live[6] = LiveOut[6]  {c}
LiveOut[5] = Live[6]  Live[2]
Live[5] = LiveOut[5]  {c}
b := a +1 ;
2 LiveOut[4] = Live[5]
c := c +b ;
3
a := b*2 ;
4
c <N goto L1
return c ;
5
6
Live[4] = (LiveOut[4] – {a})  {b}
LiveOut[3] = Live[4]
Live[3] = (LiveOut[3] – {c})  {c, b}
LiveOut[2] = Live[3]
Live[2] = (LiveOut[2] – {b})  {a}
LiveOut[1] = Live[2]
Live[1] = (LiveOut[1] – {a})
ins
LiveOut
Live
1
{c, a}
{c}
2
{c, b}
{c, a}
3
{c, b}
{c, b}
4
{c, a}
{c, b}
5
{c,a}
{c, a}
6

{c}
LiveOut[6] = 
a := 0 ;
1
Live[6] = LiveOut[6]  {c}
LiveOut[5] = Live[6]  Live[2]
Live[5] = LiveOut[5]  {c}
b := a +1 ;
2 LiveOut[4] = Live[5]
c := c +b ;
3
a := b*2 ;
4
c <N goto L1
return c ;
5
6
Live[4] = (LiveOut[4] – {a})  {b}
LiveOut[3] = Live[4]
Live[3] = (LiveOut[3] – {c})  {c, b}
LiveOut[2] = Live[3]
Live[2] = (LiveOut[2] – {b})  {a}
LiveOut[1] = Live[2]
Live[1] = (LiveOut[1] – {a})
ins
LiveOut
Live
1
{c, a, d}
{c, d}
2
{c, b, d}
{c, a, d}
3
{c, b, d}
{c, b, d}
4
{c, a, d}
{c, b, d}
5
{c,a, d}
{c, a, d}
6

{c}
LiveOut[6] = 
a := 0 ;
1
Live[6] = LiveOut[6]  {c}
LiveOut[5] = Live[6]  Live[2]
Live[5] = LiveOut[5]  {c}
b := a +1 ;
2 LiveOut[4] = Live[5]
c := c +b ;
3
a := b*2 ;
4
c <N goto L1
return c ;
5
6
Live[4] = (LiveOut[4] – {a})  {b}
LiveOut[3] = Live[4]
Live[3] = (LiveOut[3] – {c})  {c, b}
LiveOut[2] = Live[3]
Live[2] = (LiveOut[2] – {b})  {a}
LiveOut[1] = Live[2]
Live[1] = (LiveOut[1] – {a})
ins
LiveOut
Live
1
{c, a, b}
{c, b}
2
{c, b}
{c, a}
3
{c, b}
{c, b}
4
{c, a}
{c, b}
5
{c, a}
{c, a}
6

{c}
LiveOut[6] = 
a := 0 ;
1
Live[6] = LiveOut[6]  {c}
LiveOut[5] = Live[6]  Live[2]
Live[5] = LiveOut[5]  {c}
b := a +1 ;
2 LiveOut[4] = Live[5]
c := c +b ;
3
a := b*2 ;
4
c <N goto L1
return c ;
5
6
Live[4] = (LiveOut[4] – {a})  {b}
LiveOut[3] = Live[4]
Live[3] = (LiveOut[3] – {c})  {c, b}
LiveOut[2] = Live[3]
Live[2] = (LiveOut[2] – {b})  {a}
LiveOut[1] = Live[2]
Live[1] = (LiveOut[1] – {a})
ins
LiveOut
Live
1
{c, a}
{c}
2
{c, b}
{c, a}
3
{c, b}
{c, b}
4
{c}
{c, b}
5
{c}
{c}
6

{c}
Computing Least Fixed Points
• Start with an empty set of Live and LiveOut
for every instruction
• Repeatedly add new variables according to
the equations
• The sets of LiveOut and Live variables must
monotonically increase
• The process must terminate
• Unique least solution
An Iterative Algorithm
WL := ;
for each instruction n
LiveOut[n] := 
Live[n] := 
WL := WL  {n}
while WL != 
select and remove n from WL
new := (LiveOut[n] –def[n])  use[n]
if new != Live[n] then
Live[n] := new
for all predecessors m of n do
LiveOut[m] := LiveOut[m]  Live[n]
WL := WL {m}
a := 0 ;
1
b := a +1 ;
2
n
Live[n]
LiveOut
WL
{6, 5, 4, 3, 2, 1}
c := c +b ;
a := b*2 ;
c <N goto L1
return c ;
3
4
5
6
6
{c}
LiveOut[5]={c}
{5, 4, 3, 2, 1}
5
{c}
LiveOut[4]={c}
{4, 5, 2, 1}
4
{c, b}
LiveOut[3]={c,b}
{3, 2, 1}
3
{c, b}
LiveOut[2]={c,b}
{2, 1}
2
{c, a}
LiveOut[1]={c,a}
LiveOut[5]={c,a}
{5, 1}
5
{c, a}
LiveOut[4]={c,a}
{4, 1}
4
{c, b}
{1}
1
{c}

Representation of Sets
• Bit-Vectors
– Var bits for every n
– Live[n][v] = 1
• the variable v is live before n
– Cost of set operation is
• O(Vars/word-size)
• Ordered Elements
– Linear time for set operations
Time Complexity
• Parameters
– N
number of nodes (instructions)
– Assume that pred[n] is constant
– V
Number of variables
– d
Number of loop nesting level
• DFS back edges
• Initialization
NV
V
• Inner-Most Iteration
• For-Loop
• Repeat
– Worst-Case
– Worst-Case-DFS
• Total-Worst-Case
• Total-DFS
• Single-variable
N
NV
d+1
(NV)2
NVd
N
An Interference Graph
for every instruction n
for every variable a def[n]
for every variable b  LiveOut[n]
Create an interference edge
b
May introduce too many edges for move instructions
a
Example
t := s
…
x := … s …
…
y := t
An Interference Graph
for every non move instruction n
for every variable a def[n]
for every variable b  LiveOut[n]
Create an interference edge
b
for every move instruction n
a
a:= c
for every variable b  LiveOut[n] – {c}
Create an interference edge
b
a
A Simple Example
/* c */
L0:
a := 0
/* ac */
L1:
a
b
b := a + 1
/* bc */
c := c + b
/* bc */
c
a := b * 2
/* ac */
if c < N goto L1
/* c */
return c
l3:
beq t128, $0, l0 /* $0, t128 */
l1:
or t131, $0, t128 /* $0, t128, t131 */
addi t132, t128, -1 /* $0, t131, t132 */
t132
or $4, $0, t132 /* $0, $4, t131 */
jal nfactor
t130
/* $0, $2, t131 */
or t130, $0, $2 /* $0, t130, t131 */
t131
t133
or t133, $0, t131 /* $0, t130, t133 */
mult t133, t130 /* $0, t133 */
mflo t133 /* $0, t133 */
t128
t129
$0
or t129, $0, t133 /* $0, t129 */
l2:
or t103, $0, t129 /* $0, t103 */
$2
$4
b lend /* $0, t103 */
l0:
addi t129, $0, 1 /* $0, t129 */
b l2 /* $0, t129 */
t103
Summary
• The compiler can statically predict liveness
of variables
– May be expensive
• Other useful static information
– Constant expressions
– Common sub-expression
– Loop invariant
• Liveness inference graph will be colored
next week