4
4
5
5
/**
6
6
* 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.
8
9
* pages 446-447.
9
10
*
10
- * It turns out that this dataflow implementation cannot correctly handle
11
+ * It turned out that this dataflow implementation cannot correctly handle
11
12
* phis, because with phis, the inputs are live at the predecessor blocks.
12
13
* We have to look at alternative approaches when input is SSA form.
13
14
* 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.
15
25
*/
16
26
public class Liveness {
17
27
18
28
public Liveness (CompiledFunction function ) {
19
29
List <BasicBlock > blocks = BBHelper .findAllBlocks (function .entry );
20
30
RegisterPool regPool = function .registerPool ;
21
- init (regPool , blocks );
31
+ initBlocks (regPool , blocks );
32
+ init (blocks );
22
33
computeLiveness (blocks );
23
34
function .hasLiveness = true ;
24
35
}
25
36
26
- private void init (RegisterPool regPool , List <BasicBlock > blocks ) {
37
+ private void initBlocks (RegisterPool regPool , List <BasicBlock > blocks ) {
27
38
int numRegisters = regPool .numRegisters ();
28
39
for (BasicBlock block : blocks ) {
29
40
block .UEVar = new LiveSet (numRegisters );
30
41
block .varKill = new LiveSet (numRegisters );
31
42
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
+ }
32
60
for (Instruction instruction : block .instructions ) {
33
61
for (Register use : instruction .uses ()) {
34
62
if (!block .varKill .isMember (use ))
35
63
block .UEVar .add (use );
36
64
}
37
- if (instruction .definesVar ()) {
65
+ if (instruction .definesVar () && !( instruction instanceof Instruction . Phi ) ) {
38
66
Register def = instruction .def ();
39
67
block .varKill .add (def );
40
68
}
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
+ }
41
82
}
42
83
}
43
84
}
@@ -53,17 +94,19 @@ private void computeLiveness(List<BasicBlock> blocks) {
53
94
}
54
95
}
55
96
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)
56
100
private boolean recomputeLiveOut (BasicBlock block ) {
57
101
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 );
66
108
}
109
+ block .liveOut .union (block .phiUses );
67
110
return !oldLiveOut .equals (block .liveOut );
68
111
}
69
112
}
0 commit comments