44
55/**
66 * Compute LiveOut for each Basic Block
7- * Implementation is based on description in 'Engineering a Compiler' 2nd ed.
7+ *
8+ * Original Implementation was based on description in 'Engineering a Compiler' 2nd ed.
89 * pages 446-447.
910 *
10- * It turns out that this dataflow implementation cannot correctly handle
11+ * It turned out that this dataflow implementation cannot correctly handle
1112 * phis, because with phis, the inputs are live at the predecessor blocks.
1213 * We have to look at alternative approaches when input is SSA form.
1314 * Surprisingly even with this approach, the lost copy and swap problems
14- * appear to work correctly.
15+ * appeared to work correctly.
16+ *
17+ * The new approach is based on formula described in
18+ * Computing Liveness Sets for SSA-Form Programs
19+ * Florian Brandner, Benoit Boissinot, Alain Darte, Benoît Dupont de Dinechin, Fabrice Rastello
20+ *
21+ * The implementation is the unoptimized simple one.
22+ * However, we have a modification to ensure that if we see a block
23+ * which loops to itself and has Phi cycles, then the Phi is only added to
24+ * PhiDefs.
1525 */
1626public class Liveness {
1727
1828 public Liveness (CompiledFunction function ) {
1929 List <BasicBlock > blocks = BBHelper .findAllBlocks (function .entry );
2030 RegisterPool regPool = function .registerPool ;
21- init (regPool , blocks );
31+ initBlocks (regPool , blocks );
32+ init (blocks );
2233 computeLiveness (blocks );
2334 function .hasLiveness = true ;
2435 }
2536
26- private void init (RegisterPool regPool , List <BasicBlock > blocks ) {
37+ private void initBlocks (RegisterPool regPool , List <BasicBlock > blocks ) {
2738 int numRegisters = regPool .numRegisters ();
2839 for (BasicBlock block : blocks ) {
2940 block .UEVar = new LiveSet (numRegisters );
3041 block .varKill = new LiveSet (numRegisters );
3142 block .liveOut = new LiveSet (numRegisters );
43+ block .liveIn = new LiveSet (numRegisters );
44+ block .phiUses = new LiveSet (numRegisters );
45+ block .phiDefs = new LiveSet (numRegisters );
46+ }
47+ }
48+
49+ private void init (List <BasicBlock > blocks ) {
50+ for (BasicBlock block : blocks ) {
51+ // We st up phiDefs first because when we
52+ // look at phi uses we need to refer back here
53+ // see comments on phi cycles below
54+ for (Instruction instruction : block .instructions ) {
55+ if (instruction instanceof Instruction .Phi phi ) {
56+ block .phiDefs .add (phi .value ());
57+ }
58+ else break ;
59+ }
3260 for (Instruction instruction : block .instructions ) {
3361 for (Register use : instruction .uses ()) {
3462 if (!block .varKill .isMember (use ))
3563 block .UEVar .add (use );
3664 }
37- if (instruction .definesVar ()) {
65+ if (instruction .definesVar () && !( instruction instanceof Instruction . Phi ) ) {
3866 Register def = instruction .def ();
3967 block .varKill .add (def );
4068 }
69+ if (instruction instanceof Instruction .Phi phi ) {
70+ for (int i = 0 ; i < block .predecessors .size (); i ++) {
71+ BasicBlock pred = block .predecessors .get (i );
72+ Register use = phi .input (i );
73+ // We can have a block referring it its own phis
74+ // if there is loop back and there are cycles
75+ // such as e.g. the swap copy problem
76+ if (pred == block &&
77+ block .phiDefs .isMember (use ))
78+ continue ;
79+ pred .phiUses .add (use );
80+ }
81+ }
4182 }
4283 }
4384 }
@@ -53,17 +94,19 @@ private void computeLiveness(List<BasicBlock> blocks) {
5394 }
5495 }
5596
97+ // See 'Computing Liveness Sets for SSA-Form Programs'
98+ // LiveIn(B) = PhiDefs(B) U UpwardExposed(B) U (LiveOut(B) \ Defs(B))
99+ // LiveOut(B) = U all S (LiveIn(S) \ PhiDefs(S)) U PhiUses(B)
56100 private boolean recomputeLiveOut (BasicBlock block ) {
57101 LiveSet oldLiveOut = block .liveOut .dup ();
58- for (BasicBlock m : block .successors ) {
59- LiveSet mLiveIn = m .liveOut .dup ();
60- // LiveOut(m) intersect not VarKill(m)
61- mLiveIn .intersectNot (m .varKill );
62- // UEVar(m) union (LiveOut(m) intersect not VarKill(m))
63- mLiveIn .union (m .UEVar );
64- // LiveOut(block) =union (UEVar(m) union (LiveOut(m) intersect not VarKill(m)))
65- block .liveOut .union (mLiveIn );
102+ LiveSet t = block .liveOut .dup ().intersectNot (block .varKill );
103+ block .liveIn .union (block .phiDefs ).union (block .UEVar ).union (t );
104+ block .liveOut .clear ();
105+ for (BasicBlock s : block .successors ) {
106+ t = s .liveIn .dup ().intersectNot (s .phiDefs );
107+ block .liveOut .union (t );
66108 }
109+ block .liveOut .union (block .phiUses );
67110 return !oldLiveOut .equals (block .liveOut );
68111 }
69112}
0 commit comments