50.054 - Liveness Analysis¶
Learning Outcomes¶
- Define the liveness analysis problem
- Apply lattice and fixed point algorithm to solve the liveness analysis problem
Recall¶
t = s
is redundant as t
is not used.
It can be statically detected by a liveness analysis.
Liveness Analysis¶
A variable is consideredd live at a program location \(v\) if it may be used in another program location \(u\) if we follow the execution order, i.e. in the control flow graph there exists a path from \(v\) to \(u\). Otherwise, the variable is considered not live or dead. Note that from this analysis a variable is detected to be live, it is actually "maybe-live" since we are using a conservative approximation via lattice theory. On the hand, the negation, i.e. dead is definite.
By applying this analysis to the above program, we can find out at the program locations where variables must be dead.
Defining the Lattice for Livenesss Analysis¶
Recall from the previous lesson, we learned that if \(A\) be a set, then \(({\cal P}(A), \subseteq)\) forms a complete lattice, where \({\cal P}(A)\) the power set of \(A\).
Applying this approach the liveness analysis, we consider the powerset the set of all variables in the program.
Let's recast the SIMP1
program into pseudo assembly, let's label it as PA1
In PA1
we find the set of variables \(V = \{input, x, y, s, t, b\}\), if we construct a powerset lattice \(({\cal P(V)}, \subseteq)\), we see the following hasse diagram
graph TD;
N58["{b}"] --- N64["{}"]
N59["{t}"] --- N64["{}"]
N60["{s}"] --- N64["{}"]
N61["{y}"] --- N64["{}"]
N62["{x}"] --- N64["{}"]
N63["{input}"] --- N64["{}"]
N43["{t,b}"] --- N58["{b}"]
N44["{s,b}"] --- N58["{b}"]
N46["{y,b}"] --- N58["{b}"]
N49["{x,b}"] --- N58["{b}"]
N53["{input,b}"] --- N58["{b}"]
N43["{t,b}"] --- N59["{t}"]
N45["{s,t}"] --- N59["{t}"]
N47["{y,t}"] --- N59["{t}"]
N50["{x,t}"] --- N59["{t}"]
N54["{input,t}"] --- N59["{t}"]
N44["{s,b}"] --- N60["{s}"]
N45["{s,t}"] --- N60["{s}"]
N48["{y,s}"] --- N60["{s}"]
N51["{x,s}"] --- N60["{s}"]
N55["{input,s}"] --- N60["{s}"]
N46["{y,b}"] --- N61["{y}"]
N47["{y,t}"] --- N61["{y}"]
N48["{y,s}"] --- N61["{y}"]
N52["{x,y}"] --- N61["{y}"]
N56["{input,y}"] --- N61["{y}"]
N49["{x,b}"] --- N62["{x}"]
N50["{x,t}"] --- N62["{x}"]
N51["{x,s}"] --- N62["{x}"]
N52["{x,y}"] --- N62["{x}"]
N57["{input,x}"] --- N62["{x}"]
N53["{input,b}"] --- N63["{input}"]
N54["{input,t}"] --- N63["{input}"]
N55["{input,s}"] --- N63["{input}"]
N56["{input,y}"] --- N63["{input}"]
N57["{input,x}"] --- N63["{input}"]
N23["{s,t,b}"] --- N43["{t,b}"]
N24["{y,t,b}"] --- N43["{t,b}"]
N27["{x,t,b}"] --- N43["{t,b}"]
N33["{input,t,b}"] --- N43["{t,b}"]
N23["{s,t,b}"] --- N44["{s,b}"]
N25["{y,s,b}"] --- N44["{s,b}"]
N28["{x,s,b}"] --- N44["{s,b}"]
N34["{input,s,b}"] --- N44["{s,b}"]
N23["{s,t,b}"] --- N45["{s,t}"]
N26["{y,s,t}"] --- N45["{s,t}"]
N29["{x,s,t}"] --- N45["{s,t}"]
N35["{input,s,t}"] --- N45["{s,t}"]
N24["{y,t,b}"] --- N46["{y,b}"]
N25["{y,s,b}"] --- N46["{y,b}"]
N30["{x,y,b}"] --- N46["{y,b}"]
N36["{input,y,b}"] --- N46["{y,b}"]
N24["{y,t,b}"] --- N47["{y,t}"]
N26["{y,s,t}"] --- N47["{y,t}"]
N31["{x,y,t}"] --- N47["{y,t}"]
N37["{input,y,t}"] --- N47["{y,t}"]
N25["{y,s,b}"] --- N48["{y,s}"]
N26["{y,s,t}"] --- N48["{y,s}"]
N32["{x,y,s}"] --- N48["{y,s}"]
N38["{input,y,s}"] --- N48["{y,s}"]
N27["{x,t,b}"] --- N49["{x,b}"]
N28["{x,s,b}"] --- N49["{x,b}"]
N30["{x,y,b}"] --- N49["{x,b}"]
N39["{input,x,b}"] --- N49["{x,b}"]
N27["{x,t,b}"] --- N50["{x,t}"]
N29["{x,s,t}"] --- N50["{x,t}"]
N31["{x,y,t}"] --- N50["{x,t}"]
N40["{input,x,t}"] --- N50["{x,t}"]
N28["{x,s,b}"] --- N51["{x,s}"]
N29["{x,s,t}"] --- N51["{x,s}"]
N32["{x,y,s}"] --- N51["{x,s}"]
N41["{input,x,s}"] --- N51["{x,s}"]
N30["{x,y,b}"] --- N52["{x,y}"]
N31["{x,y,t}"] --- N52["{x,y}"]
N32["{x,y,s}"] --- N52["{x,y}"]
N42["{input,x,y}"] --- N52["{x,y}"]
N33["{input,t,b}"] --- N53["{input,b}"]
N34["{input,s,b}"] --- N53["{input,b}"]
N36["{input,y,b}"] --- N53["{input,b}"]
N39["{input,x,b}"] --- N53["{input,b}"]
N33["{input,t,b}"] --- N54["{input,t}"]
N35["{input,s,t}"] --- N54["{input,t}"]
N37["{input,y,t}"] --- N54["{input,t}"]
N40["{input,x,t}"] --- N54["{input,t}"]
N34["{input,s,b}"] --- N55["{input,s}"]
N35["{input,s,t}"] --- N55["{input,s}"]
N38["{input,y,s}"] --- N55["{input,s}"]
N41["{input,x,s}"] --- N55["{input,s}"]
N36["{input,y,b}"] --- N56["{input,y}"]
N37["{input,y,t}"] --- N56["{input,y}"]
N38["{input,y,s}"] --- N56["{input,y}"]
N42["{input,x,y}"] --- N56["{input,y}"]
N39["{input,x,b}"] --- N57["{input,x}"]
N40["{input,x,t}"] --- N57["{input,x}"]
N41["{input,x,s}"] --- N57["{input,x}"]
N42["{input,x,y}"] --- N57["{input,x}"]
N8["{y,s,t,b}"] --- N23["{s,t,b}"]
N9["{x,s,t,b}"] --- N23["{s,t,b}"]
N13["{input,s,t,b}"] --- N23["{s,t,b}"]
N8["{y,s,t,b}"] --- N24["{y,t,b}"]
N10["{x,y,t,b}"] --- N24["{y,t,b}"]
N14["{input,y,t,b}"] --- N24["{y,t,b}"]
N8["{y,s,t,b}"] --- N25["{y,s,b}"]
N11["{x,y,s,b}"] --- N25["{y,s,b}"]
N15["{input,y,s,b}"] --- N25["{y,s,b}"]
N8["{y,s,t,b}"] --- N26["{y,s,t}"]
N12["{x,y,s,t}"] --- N26["{y,s,t}"]
N16["{input,y,s,t}"] --- N26["{y,s,t}"]
N9["{x,s,t,b}"] --- N27["{x,t,b}"]
N10["{x,y,t,b}"] --- N27["{x,t,b}"]
N17["{input,x,t,b}"] --- N27["{x,t,b}"]
N9["{x,s,t,b}"] --- N28["{x,s,b}"]
N11["{x,y,s,b}"] --- N28["{x,s,b}"]
N18["{input,x,s,b}"] --- N28["{x,s,b}"]
N9["{x,s,t,b}"] --- N29["{x,s,t}"]
N12["{x,y,s,t}"] --- N29["{x,s,t}"]
N19["{input,x,s,t}"] --- N29["{x,s,t}"]
N10["{x,y,t,b}"] --- N30["{x,y,b}"]
N11["{x,y,s,b}"] --- N30["{x,y,b}"]
N20["{input,x,y,b}"] --- N30["{x,y,b}"]
N10["{x,y,t,b}"] --- N31["{x,y,t}"]
N12["{x,y,s,t}"] --- N31["{x,y,t}"]
N21["{input,x,y,t}"] --- N31["{x,y,t}"]
N11["{x,y,s,b}"] --- N32["{x,y,s}"]
N12["{x,y,s,t}"] --- N32["{x,y,s}"]
N22["{input,x,y,s}"] --- N32["{x,y,s}"]
N13["{input,s,t,b}"] --- N33["{input,t,b}"]
N14["{input,y,t,b}"] --- N33["{input,t,b}"]
N17["{input,x,t,b}"] --- N33["{input,t,b}"]
N13["{input,s,t,b}"] --- N34["{input,s,b}"]
N15["{input,y,s,b}"] --- N34["{input,s,b}"]
N18["{input,x,s,b}"] --- N34["{input,s,b}"]
N13["{input,s,t,b}"] --- N35["{input,s,t}"]
N16["{input,y,s,t}"] --- N35["{input,s,t}"]
N19["{input,x,s,t}"] --- N35["{input,s,t}"]
N14["{input,y,t,b}"] --- N36["{input,y,b}"]
N15["{input,y,s,b}"] --- N36["{input,y,b}"]
N20["{input,x,y,b}"] --- N36["{input,y,b}"]
N14["{input,y,t,b}"] --- N37["{input,y,t}"]
N16["{input,y,s,t}"] --- N37["{input,y,t}"]
N21["{input,x,y,t}"] --- N37["{input,y,t}"]
N15["{input,y,s,b}"] --- N38["{input,y,s}"]
N16["{input,y,s,t}"] --- N38["{input,y,s}"]
N22["{input,x,y,s}"] --- N38["{input,y,s}"]
N17["{input,x,t,b}"] --- N39["{input,x,b}"]
N18["{input,x,s,b}"] --- N39["{input,x,b}"]
N20["{input,x,y,b}"] --- N39["{input,x,b}"]
N17["{input,x,t,b}"] --- N40["{input,x,t}"]
N19["{input,x,s,t}"] --- N40["{input,x,t}"]
N21["{input,x,y,t}"] --- N40["{input,x,t}"]
N18["{input,x,s,b}"] --- N41["{input,x,s}"]
N19["{input,x,s,t}"] --- N41["{input,x,s}"]
N22["{input,x,y,s}"] --- N41["{input,x,s}"]
N20["{input,x,y,b}"] --- N42["{input,x,y}"]
N21["{input,x,y,t}"] --- N42["{input,x,y}"]
N22["{input,x,y,s}"] --- N42["{input,x,y}"]
N2["{x,y,s,t,b}"] --- N8["{y,s,t,b}"]
N3["{input,y,s,t,b}"] --- N8["{y,s,t,b}"]
N2["{x,y,s,t,b}"] --- N9["{x,s,t,b}"]
N4["{input,x,s,t,b}"] --- N9["{x,s,t,b}"]
N2["{x,y,s,t,b}"] --- N10["{x,y,t,b}"]
N5["{input,x,y,t,b}"] --- N10["{x,y,t,b}"]
N2["{x,y,s,t,b}"] --- N11["{x,y,s,b}"]
N6["{input,x,y,s,b}"] --- N11["{x,y,s,b}"]
N2["{x,y,s,t,b}"] --- N12["{x,y,s,t}"]
N7["{input,x,y,s,t}"] --- N12["{x,y,s,t}"]
N3["{input,y,s,t,b}"] --- N13["{input,s,t,b}"]
N4["{input,x,s,t,b}"] --- N13["{input,s,t,b}"]
N3["{input,y,s,t,b}"] --- N14["{input,y,t,b}"]
N5["{input,x,y,t,b}"] --- N14["{input,y,t,b}"]
N3["{input,y,s,t,b}"] --- N15["{input,y,s,b}"]
N6["{input,x,y,s,b}"] --- N15["{input,y,s,b}"]
N3["{input,y,s,t,b}"] --- N16["{input,y,s,t}"]
N7["{input,x,y,s,t}"] --- N16["{input,y,s,t}"]
N4["{input,x,s,t,b}"] --- N17["{input,x,t,b}"]
N5["{input,x,y,t,b}"] --- N17["{input,x,t,b}"]
N4["{input,x,s,t,b}"] --- N18["{input,x,s,b}"]
N6["{input,x,y,s,b}"] --- N18["{input,x,s,b}"]
N4["{input,x,s,t,b}"] --- N19["{input,x,s,t}"]
N7["{input,x,y,s,t}"] --- N19["{input,x,s,t}"]
N5["{input,x,y,t,b}"] --- N20["{input,x,y,b}"]
N6["{input,x,y,s,b}"] --- N20["{input,x,y,b}"]
N5["{input,x,y,t,b}"] --- N21["{input,x,y,t}"]
N7["{input,x,y,s,t}"] --- N21["{input,x,y,t}"]
N6["{input,x,y,s,b}"] --- N22["{input,x,y,s}"]
N7["{input,x,y,s,t}"] --- N22["{input,x,y,s}"]
N1["{input,x,y,s,t,b}"] --- N2["{x,y,s,t,b}"]
N1["{input,x,y,s,t,b}"] --- N3["{input,y,s,t,b}"]
N1["{input,x,y,s,t,b}"] --- N4["{input,x,s,t,b}"]
N1["{input,x,y,s,t,b}"] --- N5["{input,x,y,t,b}"]
N1["{input,x,y,s,t,b}"] --- N6["{input,x,y,s,b}"]
N1["{input,x,y,s,t,b}"] --- N7["{input,x,y,s,t}"]
In the above lattice, the \(\top\) is the full set of \(V\) and the \(\bot\) is the empty set \(\{\}\). The order \(\subseteq\) is the subset relation \(\sqsubseteq\).
Defining the Monotone Constraint for Liveness Analysis¶
In Sign Analysis the state variable \(s_i\) denotes the mapping of the variables to the sign abstract values after the instruction \(i\) is executed.
In Liveness Analysis, we define the state variable \(s_i\) as the set of variables may live before the execution of the instruction \(i\).
In Sign Analysis the \(join(s_i)\) function is defined as the least upper bound of all the states that are preceding \(s_i\) in the control flow.
In Liveness Analysis, we define the \(join(s_i)\) function as follows
where \(succ(s_i)\) returns the set of successors of \(s_i\) according to the control flow graph.
The monotonic functions can be defined by the following cases.
- case \(l:ret\), \(s_l = \{\}\)
- case \(l: t \leftarrow src\), \(s_l = join(s_l) - \{ t \} \cup var(src)\)
- case \(l: t \leftarrow src_1\ op\ src_2\), \(s_l = join(s_l) - \{t\} \cup var(src_1) \cup var(src_2)\)
- case \(l: r \leftarrow src\), \(s_l = join(s_l) \cup var(src)\)
- case \(l: r \leftarrow src_1\ op\ src_2\), \(s_l = join(s_l) \cup var(src_1) \cup var(src_2)\)
- case \(l: ifn\ t\ goto\ l'\), \(s_l = join(s_l) \cup \{ t \}\)
- other cases: \(s_l = join(s_l)\)
The helper function \(var(src)\) returns the set of variables (either empty or singleton) from operand \(src\).
By applying the PA
program above we have
By turning the above equation system to a monotonic function
Question, can you show that \(f_1\) is a monotonic function?
By applying the naive fixed point algorithm (or its optimized version) with starting states s1 = ... = s11 = {}
, we solve the above constraints and find
From which we can identify at least two possible optimization opportunities.
t
is must be dead throughout the entire program. Hence instruction7
is redundant.input
only lives at instruction 1. If it is not holding any heap references, it can be freed.x,y,b
lives until instruction 9. If they are not holding any heap references, they can be freed.
Forward vs Backward Analysis¶
Given an analysis in which the monotone equations are defined by deriving the current state based on the predecessors's states, we call this analysis a forward analysis.
Given an analysis in which the monotone equations are defined by deriving the current state based on the successor's states, we call this analysis a backward analysis.
For instance, the sign analysis is a forward analysis and the liveness analysis is a backward analysis.
May Analysis vs Must Analysis¶
Given an analysis that makes use of powerset lattice, it is a may analysis if it gives an over-approximation. For example, liveness analysis analyses the set of variables that may be "live" at a program point.
Given an analysis that makes use of powerset lattice, it is a must analysis if it gives an under-approximation. For example, if we negate the result of a liveness analysis to analyse the set of variables that must be "dead" at a program point. In this analysis we can keep track of the set of variables must be dead and use \(\sqcap\) (which is \(\cap\)) instead of \(\sqcup\) (which is \(\cup\)).