99 * pages 446-447.
1010 *
1111 * It turned out that this dataflow implementation cannot correctly handle
12- * phis, because with phis, the inputs are live at the predecessor blocks.
13- * We have to look at alternative approaches when input is SSA form.
14- * Surprisingly even with this approach, the lost copy and swap problems
12+ * phis. Therefore, we have to look at alternative approaches when input is SSA form.
13+ * Surprisingly even with the flawed approach, the lost copy and swap problems
1514 * appeared to work correctly.
1615 *
16+ * Phis need special considerations:
17+ *
18+ * Phi inputs are live out at the predecessor blocks, but not live in for phi block.
19+ * Phi def is live in at phi block but not in live out at predecessor blocks.
20+ *
1721 * The new approach is based on formula described in
1822 * Computing Liveness Sets for SSA-Form Programs
1923 * Florian Brandner, Benoit Boissinot, Alain Darte, Benoît Dupont de Dinechin, Fabrice Rastello
@@ -48,25 +52,29 @@ private void initBlocks(RegisterPool regPool, List<BasicBlock> blocks) {
4852
4953 private void init (List <BasicBlock > blocks ) {
5054 for (BasicBlock block : blocks ) {
51- // We st up phiDefs first because when we
55+ // Any vars created by phi instructions are added to phiDefs
56+ // for this block; these vars will be live on entry to block
57+ // but not live out from predecessor blocks.
58+ //
59+ // We set up phiDefs first because when we
5260 // look at phi uses we need to refer back here
5361 // see comments on phi cycles below
5462 for (Instruction instruction : block .instructions ) {
5563 if (instruction instanceof Instruction .Phi phi ) {
5664 block .phiDefs .add (phi .value ());
5765 }
66+ // There is a scenario where other instructions can appear
67+ // between phi instructions - this happens during the SSA deconstruction
68+ // using Brigg's method. But we don't calculate liveness
69+ // in the middle of that process, so assuming all phis are together
70+ // at the top of the block is okay
5871 else break ;
5972 }
6073 for (Instruction instruction : block .instructions ) {
61- for (Register use : instruction .uses ()) {
62- if (!block .varKill .contains (use ))
63- block .UEVar .add (use );
64- }
65- if (instruction .definesVar () && !(instruction instanceof Instruction .Phi )) {
66- Register def = instruction .def ();
67- block .varKill .add (def );
68- }
6974 if (instruction instanceof Instruction .Phi phi ) {
75+ // Any uses in a Phi are added to the phiUses of predecessor
76+ // block. These uses will be in live out of predecessor block but
77+ // not live in for current block.
7078 for (int i = 0 ; i < block .predecessors .size (); i ++) {
7179 BasicBlock pred = block .predecessors .get (i );
7280 if (!phi .isRegisterInput (i ))
@@ -76,11 +84,24 @@ private void init(List<BasicBlock> blocks) {
7684 // if there is loop back and there are cycles
7785 // such as e.g. the swap copy problem
7886 if (pred == block &&
79- block .phiDefs .contains (use ))
87+ block .phiDefs .contains (use ))
8088 continue ;
8189 pred .phiUses .add (use );
8290 }
8391 }
92+ else {
93+ // Non phi instructions follow regular
94+ // logic. Any var that is used before being defined
95+ // is added to upward expose set.
96+ for (Register use : instruction .uses ()) {
97+ if (!block .varKill .contains (use ))
98+ block .UEVar .add (use );
99+ }
100+ if (instruction .definesVar ()) {
101+ Register def = instruction .def ();
102+ block .varKill .add (def );
103+ }
104+ }
84105 }
85106 }
86107 }
@@ -89,6 +110,7 @@ private void computeLiveness(List<BasicBlock> blocks) {
89110 boolean changed = true ;
90111 while (changed ) {
91112 changed = false ;
113+ // TODO we should process in RPO order
92114 for (BasicBlock block : blocks ) {
93115 if (recomputeLiveOut (block ))
94116 changed = true ;
@@ -97,8 +119,17 @@ private void computeLiveness(List<BasicBlock> blocks) {
97119 }
98120
99121 // See 'Computing Liveness Sets for SSA-Form Programs'
122+ //
100123 // LiveIn(B) = PhiDefs(B) U UpwardExposed(B) U (LiveOut(B) \ Defs(B))
101- // LiveOut(B) = U all S (LiveIn(S) \ PhiDefs(S)) U PhiUses(B)
124+ // LiveOut(B) = U all S (LiveIn(S) \ PhiDefs(S)) U PhiUses
125+ //
126+ // For a phi-function a_0 = phi(a_1, ..., a_n ) in block B_0, where a_i comes from block B_i, then:
127+ // * a_0 is considered to be live-in for B_0, but, with respect to this phi-function, it is
128+ // not live-out for B_i, i > 0.
129+ // * a_i, i > 0, is considered to be live-out of B_i , but, with respect to this phi-function,
130+ // it is not live-in for B_0.
131+ // This corresponds to placing a copy of a_i to a_0 on each edge from B_i to B_0.
132+ //
102133 private boolean recomputeLiveOut (BasicBlock block ) {
103134 LiveSet oldLiveOut = block .liveOut .dup ();
104135 LiveSet t = block .liveOut .dup ().subtract (block .varKill );
0 commit comments