diff --git a/src/dk/camelot64/kickc/Compiler.java b/src/dk/camelot64/kickc/Compiler.java
index 31dca207c..da7242566 100644
--- a/src/dk/camelot64/kickc/Compiler.java
+++ b/src/dk/camelot64/kickc/Compiler.java
@@ -101,22 +101,29 @@ public class Compiler {
Pass3BlockSequencePlanner pass3BlockSequencePlanner = new Pass3BlockSequencePlanner(program, log);
pass3BlockSequencePlanner.plan();
- //Pass3PhiLifting pass3PhiLifting = new Pass3PhiLifting(program, log);
- //pass3PhiLifting.perform();
- //pass3BlockSequencePlanner.plan();
-
- //log.append("CONTROL FLOW GRAPH - PHI LIFTED");
- //log.append(program.getGraph().toString(program.getScope()));
- //pass2AssertSSA(program, log);
+ Pass3PhiLifting pass3PhiLifting = new Pass3PhiLifting(program, log);
+ pass3PhiLifting.perform();
+ pass3BlockSequencePlanner.plan();
+ log.append("CONTROL FLOW GRAPH - PHI LIFTED");
+ log.append(program.getGraph().toString(program.getScope()));
+ pass2AssertSSA(program, log);
Pass3IdentifyAliveRanges pass3IdentifyAliveRanges = new Pass3IdentifyAliveRanges(program, log);
pass3IdentifyAliveRanges.findLiveRanges();
-
-
log.append("CONTROL FLOW GRAPH - LIVE RANGES");
log.append(program.getGraph().toString(program.getScope()));
pass2AssertSSA(program, log);
+ Pass3PhiMemCoalesce pass3PhiMemCoalesce = new Pass3PhiMemCoalesce(program, log);
+ pass3PhiMemCoalesce.optimize();
+ Pass2CullEmptyBlocks cullEmptyBlocks = new Pass2CullEmptyBlocks(program, log);
+ cullEmptyBlocks.optimize();
+ pass3BlockSequencePlanner.plan();
+ pass3IdentifyAliveRanges.findLiveRanges();
+ log.append("CONTROL FLOW GRAPH - PHI MEM COALESCED");
+ log.append(program.getGraph().toString(program.getScope()));
+ pass2AssertSSA(program, log);
+
}
public void pass2OptimizeSSA(Program program, CompileLog log) {
diff --git a/src/dk/camelot64/kickc/icl/LiveRange.java b/src/dk/camelot64/kickc/icl/LiveRange.java
index 1b5f48bc7..4702d1f31 100644
--- a/src/dk/camelot64/kickc/icl/LiveRange.java
+++ b/src/dk/camelot64/kickc/icl/LiveRange.java
@@ -109,6 +109,37 @@ public class LiveRange {
return true;
}
+ /**
+ * Determines if this live range overlaps another live range
+ * @param other The other live range
+ * @return true if there is an overlap
+ */
+ public boolean overlaps(LiveRange other) {
+ if(this.getMaxIndex()==-1 || other.getMaxIndex()==-1) {
+ return false;
+ }
+ int maxIdx = getMaxIndex();
+ for(int i=0;i<=maxIdx; i++) {
+ if(contains(i) && other.contains(i)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Adds another live range to this one - extending this live range to include the other one.
+ * @param other The live range to add
+ */
+ public void add(LiveRange other) {
+ int otherMaxIndex = other.getMaxIndex();
+ for(int i=0;i<=otherMaxIndex; i++) {
+ if(other.contains(i)) {
+ add(i);
+ }
+ }
+ }
+
/**
* Determines if the live range contains a statement
* @param statement The statement to examine
@@ -136,5 +167,16 @@ public class LiveRange {
return false;
}
+ /**
+ * Get the maximal index contained in the live range
+ * @return The max index. -1 if the range is empty.
+ */
+ int getMaxIndex() {
+ if(intervals.isEmpty()) {
+ return -1;
+ }
+ return intervals.get(intervals.size()-1).lastStatementIdx;
+ }
+
}
diff --git a/src/dk/camelot64/kickc/icl/VariableLiveRanges.java b/src/dk/camelot64/kickc/icl/VariableLiveRanges.java
index ecce3ab84..788394844 100644
--- a/src/dk/camelot64/kickc/icl/VariableLiveRanges.java
+++ b/src/dk/camelot64/kickc/icl/VariableLiveRanges.java
@@ -44,4 +44,13 @@ public class VariableLiveRanges {
return aliveVars;
}
+ /**
+ * Get the alive range of a variable
+ * @param variable The variable reference
+ * @return The alive range for the variable
+ */
+ public LiveRange getLiveRange(VariableRef variable) {
+ return liveRanges.get(variable);
+ }
+
}
diff --git a/src/dk/camelot64/kickc/passes/Pass3PhiMemCoalesce.java b/src/dk/camelot64/kickc/passes/Pass3PhiMemCoalesce.java
new file mode 100644
index 000000000..86e42df91
--- /dev/null
+++ b/src/dk/camelot64/kickc/passes/Pass3PhiMemCoalesce.java
@@ -0,0 +1,239 @@
+package dk.camelot64.kickc.passes;
+
+import dk.camelot64.kickc.CompileLog;
+import dk.camelot64.kickc.icl.*;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Eliminate virtual variables introduced by PhiLifting if they do not have overlapping live ranges with other phi equivalent variables.
+ * (This pass requires variable alive ranges).
+ *
+ * See http://compilers.cs.ucla.edu/fernando/projects/soc/reports/short_tech.pdf
+ */
+public class Pass3PhiMemCoalesce extends Pass2SsaOptimization {
+
+ public Pass3PhiMemCoalesce(Program program, CompileLog log) {
+ super(program, log);
+ }
+
+ @Override
+ public boolean optimize() {
+ PhiEquivalenceClassInitializer phiEquivalenceClassInitializer = new PhiEquivalenceClassInitializer();
+ phiEquivalenceClassInitializer.visitGraph(getGraph());
+ ProgramPhiEquivalenceClasses phiEquivalenceClasses = phiEquivalenceClassInitializer.getPhiEquivalenceClasses();
+ log.append("Created " +phiEquivalenceClasses.size()+ " initial phi equivalence classes");
+ PhiMemCoalescer phiMemCoalescer = new PhiMemCoalescer(phiEquivalenceClasses);
+ phiMemCoalescer.visitGraph(getGraph());
+ removeAssignments(phiMemCoalescer.getRemove());
+ replaceVariables(phiMemCoalescer.getReplace());
+ deleteVariables(phiMemCoalescer.getRemove());
+ log.append("Coalesced down to " +phiEquivalenceClasses.size()+ " phi equivalence classes");
+ return false;
+ }
+
+ /** Coalesces phi equivalence classes when they do not overlap based on assignments to variables in phi statements. */
+ private class PhiMemCoalescer extends ControlFlowGraphBaseVisitor {
+
+ private ProgramPhiEquivalenceClasses phiEquivalenceClasses;
+ private List remove;
+ private Map replace;
+
+ public PhiMemCoalescer(ProgramPhiEquivalenceClasses phiEquivalenceClasses) {
+ this.phiEquivalenceClasses = phiEquivalenceClasses;
+ this.remove = new ArrayList<>();
+ this.replace = new HashMap<>();
+ }
+
+ public List getRemove() {
+ return remove;
+ }
+
+ public Map getReplace() {
+ return replace;
+ }
+
+ @Override
+ public Void visitAssignment(StatementAssignment assignment) {
+ if (assignment.getlValue() instanceof VariableRef) {
+ PhiEquivalenceClass lValEquivalenceClass =
+ phiEquivalenceClasses.getPhiEquivalenceClass((VariableRef) assignment.getlValue());
+ if (lValEquivalenceClass != null && assignment.getOperator() == null && assignment.getrValue1() == null && assignment.getrValue2() instanceof VariableRef) {
+ // Found copy assignment to a variable in an equivalence class - attempt to coalesce
+ VariableRef assignVar = (VariableRef) assignment.getrValue2();
+ PhiEquivalenceClass assignVarEquivalenceClass = phiEquivalenceClasses.getOrCreateEquivalenceClass(assignVar);
+ if(lValEquivalenceClass.equals(assignVarEquivalenceClass)) {
+ remove.add((VariableRef) assignment.getlValue());
+ replace.put((VariableRef) assignment.getlValue(), assignVar);
+ log.append("Coalesced (already) "+assignment);
+ } else if (!lValEquivalenceClass.getLiveRange().overlaps(assignVarEquivalenceClass.getLiveRange())) {
+ lValEquivalenceClass.addAll(assignVarEquivalenceClass);
+ phiEquivalenceClasses.remove(assignVarEquivalenceClass);
+ remove.add((VariableRef) assignment.getlValue());
+ replace.put((VariableRef) assignment.getlValue(), assignVar);
+ log.append("Coalesced "+assignment);
+ } else {
+ log.append("Not coalescing "+assignment);
+ }
+ }
+ }
+ return null;
+ }
+
+ }
+
+
+ /** Creates initial phi equivalence classes from program phi statements.*/
+ private class PhiEquivalenceClassInitializer extends ControlFlowGraphBaseVisitor {
+
+ private ProgramPhiEquivalenceClasses phiEquivalenceClasses;
+
+ public PhiEquivalenceClassInitializer() {
+ this.phiEquivalenceClasses = new ProgramPhiEquivalenceClasses();
+ }
+
+ @Override
+ public Void visitPhiBlock(StatementPhiBlock phi) {
+ for (StatementPhiBlock.PhiVariable phiVariable : phi.getPhiVariables()) {
+ VariableRef variable = phiVariable.getVariable();
+ PhiEquivalenceClass equivalenceClass = phiEquivalenceClasses.getOrCreateEquivalenceClass(variable);
+ for (StatementPhiBlock.PhiRValue phiRValue : phiVariable.getValues()) {
+ if(!(phiRValue.getrValue() instanceof Constant)) {
+ VariableRef phiRVar = (VariableRef) phiRValue.getrValue();
+ equivalenceClass.addVariable(phiRVar);
+ }
+ }
+ }
+ return null;
+ }
+
+ public ProgramPhiEquivalenceClasses getPhiEquivalenceClasses() {
+ return phiEquivalenceClasses;
+ }
+ }
+
+ /** The entire set of phi equivalence classes in the pgogram. */
+ public class ProgramPhiEquivalenceClasses {
+
+ List equivalenceClasses;
+
+ public ProgramPhiEquivalenceClasses() {
+ this.equivalenceClasses = new ArrayList<>();
+ }
+
+ /**
+ * Get the phi equivalence class for a specific variable.
+ * If the equivalence class does not exist it is created.
+ *
+ * @param variable The variable
+ * @return The existing or new phi equivalence class
+ */
+ public PhiEquivalenceClass getOrCreateEquivalenceClass(VariableRef variable) {
+ PhiEquivalenceClass equivalenceClass1 = getPhiEquivalenceClass(variable);
+ if (equivalenceClass1 != null) return equivalenceClass1;
+ // Not found - create it
+ PhiEquivalenceClass equivalenceClass = new PhiEquivalenceClass();
+ equivalenceClasses.add(equivalenceClass);
+ equivalenceClass.addVariable(variable);
+ return equivalenceClass;
+ }
+
+ /**
+ * Get the phi equivalence class for a specific variable.
+ *
+ * @param variable The variable
+ * @return The existing phi equivalence class. null if no equivalence class contains the variable.
+ */
+ private PhiEquivalenceClass getPhiEquivalenceClass(VariableRef variable) {
+ for (PhiEquivalenceClass equivalenceClass : equivalenceClasses) {
+ if(equivalenceClass.contains(variable)) {
+ return equivalenceClass;
+ }
+ }
+ return null;
+ }
+
+
+ public int size() {
+ return equivalenceClasses.size();
+ }
+
+ public void remove(PhiEquivalenceClass equivalenceClass) {
+ equivalenceClasses.remove(equivalenceClass);
+ }
+ }
+
+ /**
+ * A phi equivalence class contains all varialbes connected in by phi statements.
+ * In the phi statement va = phi(vb, vc)
all 3 variables are in the same equivalence class.
+ * The equivalence class is the closure over all phi statements in the program.
+ * The set of equivalence classes is a disjoint partition of all variables uses in phi statements
+ * (ie. those variables crossing non-trivial block transitions).
+ *
+ * See http://compilers.cs.ucla.edu/fernando/projects/soc/reports/short_tech.pdf
+ **/
+ public class PhiEquivalenceClass {
+
+ /** The variables of the equivalence class. */
+ List variables;
+
+ /** The combined live range of the variables. */
+ LiveRange classLiveRange;
+
+ public PhiEquivalenceClass() {
+ this.variables = new ArrayList<>();
+ this.classLiveRange = new LiveRange();
+ }
+
+ /**
+ * Add a variable to the equivalence class
+ * @param variable The variable to add
+ */
+ public void addVariable(VariableRef variable) {
+ VariableLiveRanges liveRanges = getSymbols().getLiveRanges();
+ LiveRange varLiveRange = liveRanges.getLiveRange(variable);
+ if(classLiveRange.overlaps(varLiveRange)) {
+ throw new RuntimeException("Compilation error! Variable live range overlaps phi equivalence class live range. "+variable);
+ }
+ classLiveRange.add(varLiveRange);
+ variables.add(variable);
+ }
+
+ /**
+ * Determines if the phi equivalence class contains a variable
+ * @param variable The variable to look for
+ * @return true if the equivalence class contains the variable
+ */
+ public boolean contains(VariableRef variable) {
+ return variables.contains(variable);
+ }
+
+ public LiveRange getLiveRange() {
+ return classLiveRange;
+ }
+
+ public void addAll(PhiEquivalenceClass other) {
+ variables.addAll(other.variables);
+ classLiveRange.add(other.classLiveRange);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ PhiEquivalenceClass that = (PhiEquivalenceClass) o;
+
+ return variables.equals(that.variables);
+ }
+
+ @Override
+ public int hashCode() {
+ return variables.hashCode();
+ }
+ }
+
+}
diff --git a/src/dk/camelot64/kickc/test/ref/bresenham.log b/src/dk/camelot64/kickc/test/ref/bresenham.log
index bec4dc83b..a3e2fa7b8 100644
--- a/src/dk/camelot64/kickc/test/ref/bresenham.log
+++ b/src/dk/camelot64/kickc/test/ref/bresenham.log
@@ -844,6 +844,52 @@ Multiple usages for variable. Not optimizing sub-constant (byte*) cursor#1
Multiple usages for variable. Not optimizing sub-constant (byte) y#2
Multiple usages for variable. Not optimizing sub-constant (byte*) cursor#1
Block Sequence Planned @BEGIN @1 @3 @END @2
+Added new block during phi lifting @7(between @3 and @1)
+Added new block during phi lifting @8(between @1 and @3)
+Block Sequence Planned @BEGIN @1 @8 @3 @END @7 @2
+CONTROL FLOW GRAPH - PHI LIFTED
+@BEGIN: from
+ to:@1
+@1: from @7 @BEGIN
+ (byte) y#2 ← phi( @7/(byte~) y#5 @BEGIN/(byte) 0 )
+ (byte) e#3 ← phi( @7/(byte~) e#6 @BEGIN/(byte) 12 )
+ (byte) x#2 ← phi( @7/(byte~) x#5 @BEGIN/(byte) 0 )
+ (byte*) cursor#3 ← phi( @7/(byte*~) cursor#6 @BEGIN/(word) 1024 )
+ *((byte*) cursor#3) ← (byte) 81
+ (byte) x#1 ← (byte) x#2 + (byte) 1
+ (byte*) cursor#1 ← (byte*) cursor#3 + (byte) 1
+ (byte) e#1 ← (byte) e#3 + (byte) 24
+ if((byte) 39<(byte) e#1) goto @2
+ to:@8
+@8: from @1
+ (byte*~) cursor#7 ← (byte*) cursor#1
+ (byte~) e#7 ← (byte) e#1
+ (byte~) y#6 ← (byte) y#2
+ to:@3
+@3: from @2 @8
+ (byte) y#4 ← phi( @8/(byte~) y#6 @2/(byte~) y#7 )
+ (byte) e#5 ← phi( @8/(byte~) e#7 @2/(byte~) e#8 )
+ (byte*) cursor#5 ← phi( @8/(byte*~) cursor#7 @2/(byte*~) cursor#8 )
+ if((byte) x#1<(byte) 40) goto @7
+ to:@END
+@END: from @3
+@7: from @3
+ (byte*~) cursor#6 ← (byte*) cursor#5
+ (byte~) x#5 ← (byte) x#1
+ (byte~) e#6 ← (byte) e#5
+ (byte~) y#5 ← (byte) y#4
+ to:@1
+@2: from @1
+ (byte) y#1 ← (byte) y#2 + (byte) 1
+ (byte*) cursor#2 ← (byte*) cursor#1 + (byte) 40
+ (byte) e#2 ← (byte) e#1 - (byte) 39
+ (byte*~) cursor#8 ← (byte*) cursor#2
+ (byte~) e#8 ← (byte) e#2
+ (byte~) y#7 ← (byte) y#1
+ to:@3
+
+Propagating live ranges...
+Propagating live ranges...
Propagating live ranges...
Propagating live ranges...
Propagating live ranges...
@@ -851,6 +897,68 @@ Propagating live ranges...
Propagating live ranges...
Propagating live ranges...
CONTROL FLOW GRAPH - LIVE RANGES
+@BEGIN: from
+ to:@1
+@1: from @7 @BEGIN
+ [0] (byte) y#2 ← phi( @7/(byte~) y#5 @BEGIN/(byte) 0 ) [ cursor#3 x#2 e#3 y#2 ]
+ [0] (byte) e#3 ← phi( @7/(byte~) e#6 @BEGIN/(byte) 12 ) [ cursor#3 x#2 e#3 y#2 ]
+ [0] (byte) x#2 ← phi( @7/(byte~) x#5 @BEGIN/(byte) 0 ) [ cursor#3 x#2 e#3 y#2 ]
+ [0] (byte*) cursor#3 ← phi( @7/(byte*~) cursor#6 @BEGIN/(word) 1024 ) [ cursor#3 x#2 e#3 y#2 ]
+ [1] *((byte*) cursor#3) ← (byte) 81 [ cursor#3 x#2 e#3 y#2 ]
+ [2] (byte) x#1 ← (byte) x#2 + (byte) 1 [ cursor#3 e#3 y#2 x#1 ]
+ [3] (byte*) cursor#1 ← (byte*) cursor#3 + (byte) 1 [ e#3 cursor#1 y#2 x#1 ]
+ [4] (byte) e#1 ← (byte) e#3 + (byte) 24 [ e#1 cursor#1 y#2 x#1 ]
+ [5] if((byte) 39<(byte) e#1) goto @2 [ e#1 cursor#1 y#2 x#1 ]
+ to:@8
+@8: from @1
+ [6] (byte*~) cursor#7 ← (byte*) cursor#1 [ e#1 y#2 cursor#7 x#1 ]
+ [7] (byte~) e#7 ← (byte) e#1 [ y#2 cursor#7 e#7 x#1 ]
+ [8] (byte~) y#6 ← (byte) y#2 [ cursor#7 e#7 y#6 x#1 ]
+ to:@3
+@3: from @2 @8
+ [9] (byte) y#4 ← phi( @8/(byte~) y#6 @2/(byte~) y#7 ) [ x#1 cursor#5 e#5 y#4 ]
+ [9] (byte) e#5 ← phi( @8/(byte~) e#7 @2/(byte~) e#8 ) [ x#1 cursor#5 e#5 y#4 ]
+ [9] (byte*) cursor#5 ← phi( @8/(byte*~) cursor#7 @2/(byte*~) cursor#8 ) [ x#1 cursor#5 e#5 y#4 ]
+ [10] if((byte) x#1<(byte) 40) goto @7 [ x#1 cursor#5 e#5 y#4 ]
+ to:@END
+@END: from @3
+@7: from @3
+ [11] (byte*~) cursor#6 ← (byte*) cursor#5 [ cursor#6 x#1 e#5 y#4 ]
+ [12] (byte~) x#5 ← (byte) x#1 [ cursor#6 x#5 e#5 y#4 ]
+ [13] (byte~) e#6 ← (byte) e#5 [ cursor#6 x#5 e#6 y#4 ]
+ [14] (byte~) y#5 ← (byte) y#4 [ cursor#6 x#5 e#6 y#5 ]
+ to:@1
+@2: from @1
+ [15] (byte) y#1 ← (byte) y#2 + (byte) 1 [ e#1 cursor#1 x#1 y#1 ]
+ [16] (byte*) cursor#2 ← (byte*) cursor#1 + (byte) 40 [ e#1 x#1 cursor#2 y#1 ]
+ [17] (byte) e#2 ← (byte) e#1 - (byte) 39 [ x#1 cursor#2 e#2 y#1 ]
+ [18] (byte*~) cursor#8 ← (byte*) cursor#2 [ cursor#8 x#1 e#2 y#1 ]
+ [19] (byte~) e#8 ← (byte) e#2 [ cursor#8 e#8 x#1 y#1 ]
+ [20] (byte~) y#7 ← (byte) y#1 [ cursor#8 e#8 y#7 x#1 ]
+ to:@3
+
+Created 7 initial phi equivalence classes
+Coalesced [6] cursor#7 ← cursor#1
+Coalesced [7] e#7 ← e#1
+Coalesced [8] y#6 ← y#2
+Coalesced [11] cursor#6 ← cursor#5
+Coalesced [12] x#5 ← x#1
+Coalesced [13] e#6 ← e#5
+Coalesced (already) [14] y#5 ← y#4
+Coalesced [18] cursor#8 ← cursor#2
+Coalesced [19] e#8 ← e#2
+Coalesced [20] y#7 ← y#1
+Coalesced down to 4 phi equivalence classes
+Culled Empty Block (label) @8
+Culled Empty Block (label) @7
+Block Sequence Planned @BEGIN @1 @3 @END @2
+Propagating live ranges...
+Propagating live ranges...
+Propagating live ranges...
+Propagating live ranges...
+Propagating live ranges...
+Propagating live ranges...
+CONTROL FLOW GRAPH - PHI MEM COALESCED
@BEGIN: from
to:@1
@1: from @3 @BEGIN
diff --git a/src/dk/camelot64/kickc/test/ref/flipper-rex2.log b/src/dk/camelot64/kickc/test/ref/flipper-rex2.log
index 7479f40db..d2e115943 100644
--- a/src/dk/camelot64/kickc/test/ref/flipper-rex2.log
+++ b/src/dk/camelot64/kickc/test/ref/flipper-rex2.log
@@ -3310,6 +3310,149 @@ Multiple usages for variable. Not optimizing sub-constant (byte) flip::i#2
Multiple usages for variable. Not optimizing sub-constant (byte) flip::i#2
Multiple usages for variable. Not optimizing sub-constant (byte) plot::i#2
Block Sequence Planned @BEGIN @END main main::@3 main::@4 main::@6 main::@7 main::@10 main::@11 main::@return plot plot::@1 plot::@2 plot::@3 plot::@return flip flip::@1 flip::@2 flip::@4 flip::@3 flip::@return prepare prepare::@1 prepare::@return
+Added new block during phi lifting main::@12(between main::@6 and main::@3)
+Added new block during phi lifting plot::@5(between plot::@3 and plot::@1)
+Added new block during phi lifting plot::@6(between plot::@2 and plot::@2)
+Added new block during phi lifting flip::@7(between flip::@4 and flip::@1)
+Added new block during phi lifting flip::@8(between flip::@2 and flip::@2)
+Added new block during phi lifting flip::@9(between flip::@3 and flip::@3)
+Added new block during phi lifting prepare::@3(between prepare::@1 and prepare::@1)
+Block Sequence Planned @BEGIN @END main main::@3 main::@4 main::@6 main::@7 main::@10 main::@11 main::@return main::@12 plot plot::@1 plot::@2 plot::@3 plot::@return plot::@5 plot::@6 flip flip::@1 flip::@2 flip::@4 flip::@3 flip::@return flip::@9 flip::@7 flip::@8 prepare prepare::@1 prepare::@return prepare::@3
+CONTROL FLOW GRAPH - PHI LIFTED
+@BEGIN: from
+ call main param-assignment
+ to:@END
+@END: from @BEGIN
+main: from @BEGIN
+ call prepare param-assignment
+ to:main::@3
+main::@3: from main main::@11 main::@12 main::@3
+ (byte) main::c#2 ← phi( main/(byte) 25 main::@12/(byte~) main::c#6 main::@11/(byte) 25 )
+ (byte~) main::$1 ← * (word) 53266
+ if((byte~) main::$1!=(byte) 254) goto main::@3
+ to:main::@4
+main::@4: from main::@3 main::@4
+ (byte~) main::$3 ← * (word) 53266
+ if((byte~) main::$3!=(byte) 255) goto main::@4
+ to:main::@6
+main::@6: from main::@4
+ (byte) main::c#1 ← -- (byte) main::c#2
+ if((byte) main::c#1!=(byte) 0) goto main::@12
+ to:main::@7
+main::@7: from main::@6
+ call flip param-assignment
+ to:main::@10
+main::@10: from main::@7
+ call plot param-assignment
+ to:main::@11
+main::@11: from main::@10
+ if(true) goto main::@3
+ to:main::@return
+main::@return: from main::@11
+ return
+ to:@RETURN
+main::@12: from main::@6
+ (byte~) main::c#6 ← (byte) main::c#1
+ to:main::@3
+plot: from main::@10
+ to:plot::@1
+plot::@1: from plot plot::@5
+ (byte) plot::y#2 ← phi( plot/(byte) 16 plot::@5/(byte~) plot::y#5 )
+ (byte*) plot::line#2 ← phi( plot/(word) 1236 plot::@5/(byte*~) plot::line#5 )
+ (byte) plot::i#3 ← phi( plot/(byte) 0 plot::@5/(byte~) plot::i#5 )
+ (byte~) plot::i#6 ← (byte) plot::i#3
+ to:plot::@2
+plot::@2: from plot::@1 plot::@6
+ (byte) plot::x#2 ← phi( plot::@1/(byte) 0 plot::@6/(byte~) plot::x#3 )
+ (byte) plot::i#2 ← phi( plot::@1/(byte~) plot::i#6 plot::@6/(byte~) plot::i#7 )
+ (byte~) plot::$3 ← (word) 4096 *idx (byte) plot::i#2
+ *((byte*) plot::line#2 + (byte) plot::x#2) ← (byte~) plot::$3
+ (byte) plot::i#1 ← ++ (byte) plot::i#2
+ (byte) plot::x#1 ← ++ (byte) plot::x#2
+ if((byte) plot::x#1<(byte) 16) goto plot::@6
+ to:plot::@3
+plot::@3: from plot::@2
+ (byte*) plot::line#1 ← (byte*) plot::line#2 + (byte) 40
+ (byte) plot::y#1 ← -- (byte) plot::y#2
+ if((byte) plot::y#1!=(byte) 0) goto plot::@5
+ to:plot::@return
+plot::@return: from plot::@3
+ return
+ to:@RETURN
+plot::@5: from plot::@3
+ (byte~) plot::i#5 ← (byte) plot::i#1
+ (byte*~) plot::line#5 ← (byte*) plot::line#1
+ (byte~) plot::y#5 ← (byte) plot::y#1
+ to:plot::@1
+plot::@6: from plot::@2
+ (byte~) plot::i#7 ← (byte) plot::i#1
+ (byte~) plot::x#3 ← (byte) plot::x#1
+ to:plot::@2
+flip: from main::@7
+ to:flip::@1
+flip::@1: from flip flip::@7
+ (byte) flip::r#2 ← phi( flip/(byte) 16 flip::@7/(byte~) flip::r#5 )
+ (byte) flip::dstIdx#5 ← phi( flip/(byte) 15 flip::@7/(byte~) flip::dstIdx#6 )
+ (byte) flip::srcIdx#3 ← phi( flip/(byte) 0 flip::@7/(byte~) flip::srcIdx#5 )
+ (byte~) flip::srcIdx#6 ← (byte) flip::srcIdx#3
+ (byte~) flip::dstIdx#7 ← (byte) flip::dstIdx#5
+ to:flip::@2
+flip::@2: from flip::@1 flip::@8
+ (byte) flip::c#2 ← phi( flip::@1/(byte) 16 flip::@8/(byte~) flip::c#3 )
+ (byte) flip::dstIdx#3 ← phi( flip::@1/(byte~) flip::dstIdx#7 flip::@8/(byte~) flip::dstIdx#8 )
+ (byte) flip::srcIdx#2 ← phi( flip::@1/(byte~) flip::srcIdx#6 flip::@8/(byte~) flip::srcIdx#7 )
+ (byte~) flip::$0 ← (word) 4096 *idx (byte) flip::srcIdx#2
+ *((word) 4352 + (byte) flip::dstIdx#3) ← (byte~) flip::$0
+ (byte) flip::srcIdx#1 ← ++ (byte) flip::srcIdx#2
+ (byte) flip::dstIdx#1 ← (byte) flip::dstIdx#3 + (byte) 16
+ (byte) flip::c#1 ← -- (byte) flip::c#2
+ if((byte) flip::c#1!=(byte) 0) goto flip::@8
+ to:flip::@4
+flip::@4: from flip::@2
+ (byte) flip::dstIdx#2 ← -- (byte) flip::dstIdx#1
+ (byte) flip::r#1 ← -- (byte) flip::r#2
+ if((byte) flip::r#1!=(byte) 0) goto flip::@7
+ to:flip::@3
+flip::@3: from flip::@4 flip::@9
+ (byte) flip::i#2 ← phi( flip::@9/(byte~) flip::i#3 flip::@4/(byte) 0 )
+ (byte~) flip::$4 ← (word) 4352 *idx (byte) flip::i#2
+ *((word) 4096 + (byte) flip::i#2) ← (byte~) flip::$4
+ (byte) flip::i#1 ← ++ (byte) flip::i#2
+ if((byte) flip::i#1!=(byte) 0) goto flip::@9
+ to:flip::@return
+flip::@return: from flip::@3
+ return
+ to:@RETURN
+flip::@9: from flip::@3
+ (byte~) flip::i#3 ← (byte) flip::i#1
+ to:flip::@3
+flip::@7: from flip::@4
+ (byte~) flip::srcIdx#5 ← (byte) flip::srcIdx#1
+ (byte~) flip::dstIdx#6 ← (byte) flip::dstIdx#2
+ (byte~) flip::r#5 ← (byte) flip::r#1
+ to:flip::@1
+flip::@8: from flip::@2
+ (byte~) flip::srcIdx#7 ← (byte) flip::srcIdx#1
+ (byte~) flip::dstIdx#8 ← (byte) flip::dstIdx#1
+ (byte~) flip::c#3 ← (byte) flip::c#1
+ to:flip::@2
+prepare: from main
+ to:prepare::@1
+prepare::@1: from prepare prepare::@3
+ (byte) prepare::i#2 ← phi( prepare/(byte) 0 prepare::@3/(byte~) prepare::i#3 )
+ *((word) 4096 + (byte) prepare::i#2) ← (byte) prepare::i#2
+ (byte) prepare::i#1 ← ++ (byte) prepare::i#2
+ if((byte) prepare::i#1!=(byte) 0) goto prepare::@3
+ to:prepare::@return
+prepare::@return: from prepare::@1
+ return
+ to:@RETURN
+prepare::@3: from prepare::@1
+ (byte~) prepare::i#3 ← (byte) prepare::i#1
+ to:prepare::@1
+
+Propagating live ranges...
+Propagating live ranges...
Propagating live ranges...
Propagating live ranges...
Propagating live ranges...
@@ -3324,6 +3467,175 @@ CONTROL FLOW GRAPH - LIVE RANGES
[0] call main param-assignment [ ]
to:@END
@END: from @BEGIN
+main: from @BEGIN
+ [1] call prepare param-assignment [ ]
+ to:main::@3
+main::@3: from main main::@11 main::@12 main::@3
+ [2] (byte) main::c#2 ← phi( main/(byte) 25 main::@12/(byte~) main::c#6 main::@11/(byte) 25 ) [ main::c#2 ]
+ [3] (byte~) main::$1 ← * (word) 53266 [ main::$1 main::c#2 ]
+ [4] if((byte~) main::$1!=(byte) 254) goto main::@3 [ main::c#2 ]
+ to:main::@4
+main::@4: from main::@3 main::@4
+ [5] (byte~) main::$3 ← * (word) 53266 [ main::$3 main::c#2 ]
+ [6] if((byte~) main::$3!=(byte) 255) goto main::@4 [ main::c#2 ]
+ to:main::@6
+main::@6: from main::@4
+ [7] (byte) main::c#1 ← -- (byte) main::c#2 [ main::c#1 ]
+ [8] if((byte) main::c#1!=(byte) 0) goto main::@12 [ main::c#1 ]
+ to:main::@7
+main::@7: from main::@6
+ [9] call flip param-assignment [ ]
+ to:main::@10
+main::@10: from main::@7
+ [10] call plot param-assignment [ ]
+ to:main::@11
+main::@11: from main::@10
+ [11] if(true) goto main::@3 [ ]
+ to:main::@return
+main::@return: from main::@11
+ [12] return [ ]
+ to:@RETURN
+main::@12: from main::@6
+ [13] (byte~) main::c#6 ← (byte) main::c#1 [ main::c#6 ]
+ to:main::@3
+plot: from main::@10
+ to:plot::@1
+plot::@1: from plot plot::@5
+ [14] (byte) plot::y#2 ← phi( plot/(byte) 16 plot::@5/(byte~) plot::y#5 ) [ plot::i#3 plot::line#2 plot::y#2 ]
+ [14] (byte*) plot::line#2 ← phi( plot/(word) 1236 plot::@5/(byte*~) plot::line#5 ) [ plot::i#3 plot::line#2 plot::y#2 ]
+ [14] (byte) plot::i#3 ← phi( plot/(byte) 0 plot::@5/(byte~) plot::i#5 ) [ plot::i#3 plot::line#2 plot::y#2 ]
+ [15] (byte~) plot::i#6 ← (byte) plot::i#3 [ plot::i#6 plot::line#2 plot::y#2 ]
+ to:plot::@2
+plot::@2: from plot::@1 plot::@6
+ [16] (byte) plot::x#2 ← phi( plot::@1/(byte) 0 plot::@6/(byte~) plot::x#3 ) [ plot::i#2 plot::line#2 plot::x#2 plot::y#2 ]
+ [16] (byte) plot::i#2 ← phi( plot::@1/(byte~) plot::i#6 plot::@6/(byte~) plot::i#7 ) [ plot::i#2 plot::line#2 plot::x#2 plot::y#2 ]
+ [17] (byte~) plot::$3 ← (word) 4096 *idx (byte) plot::i#2 [ plot::i#2 plot::line#2 plot::x#2 plot::$3 plot::y#2 ]
+ [18] *((byte*) plot::line#2 + (byte) plot::x#2) ← (byte~) plot::$3 [ plot::i#2 plot::line#2 plot::x#2 plot::y#2 ]
+ [19] (byte) plot::i#1 ← ++ (byte) plot::i#2 [ plot::line#2 plot::x#2 plot::y#2 plot::i#1 ]
+ [20] (byte) plot::x#1 ← ++ (byte) plot::x#2 [ plot::line#2 plot::x#1 plot::y#2 plot::i#1 ]
+ [21] if((byte) plot::x#1<(byte) 16) goto plot::@6 [ plot::line#2 plot::x#1 plot::y#2 plot::i#1 ]
+ to:plot::@3
+plot::@3: from plot::@2
+ [22] (byte*) plot::line#1 ← (byte*) plot::line#2 + (byte) 40 [ plot::y#2 plot::i#1 plot::line#1 ]
+ [23] (byte) plot::y#1 ← -- (byte) plot::y#2 [ plot::y#1 plot::i#1 plot::line#1 ]
+ [24] if((byte) plot::y#1!=(byte) 0) goto plot::@5 [ plot::y#1 plot::i#1 plot::line#1 ]
+ to:plot::@return
+plot::@return: from plot::@3
+ [25] return [ ]
+ to:@RETURN
+plot::@5: from plot::@3
+ [26] (byte~) plot::i#5 ← (byte) plot::i#1 [ plot::i#5 plot::y#1 plot::line#1 ]
+ [27] (byte*~) plot::line#5 ← (byte*) plot::line#1 [ plot::i#5 plot::line#5 plot::y#1 ]
+ [28] (byte~) plot::y#5 ← (byte) plot::y#1 [ plot::i#5 plot::line#5 plot::y#5 ]
+ to:plot::@1
+plot::@6: from plot::@2
+ [29] (byte~) plot::i#7 ← (byte) plot::i#1 [ plot::i#7 plot::line#2 plot::x#1 plot::y#2 ]
+ [30] (byte~) plot::x#3 ← (byte) plot::x#1 [ plot::i#7 plot::x#3 plot::line#2 plot::y#2 ]
+ to:plot::@2
+flip: from main::@7
+ to:flip::@1
+flip::@1: from flip flip::@7
+ [31] (byte) flip::r#2 ← phi( flip/(byte) 16 flip::@7/(byte~) flip::r#5 ) [ flip::srcIdx#3 flip::dstIdx#5 flip::r#2 ]
+ [31] (byte) flip::dstIdx#5 ← phi( flip/(byte) 15 flip::@7/(byte~) flip::dstIdx#6 ) [ flip::srcIdx#3 flip::dstIdx#5 flip::r#2 ]
+ [31] (byte) flip::srcIdx#3 ← phi( flip/(byte) 0 flip::@7/(byte~) flip::srcIdx#5 ) [ flip::srcIdx#3 flip::dstIdx#5 flip::r#2 ]
+ [32] (byte~) flip::srcIdx#6 ← (byte) flip::srcIdx#3 [ flip::dstIdx#5 flip::srcIdx#6 flip::r#2 ]
+ [33] (byte~) flip::dstIdx#7 ← (byte) flip::dstIdx#5 [ flip::srcIdx#6 flip::dstIdx#7 flip::r#2 ]
+ to:flip::@2
+flip::@2: from flip::@1 flip::@8
+ [34] (byte) flip::c#2 ← phi( flip::@1/(byte) 16 flip::@8/(byte~) flip::c#3 ) [ flip::srcIdx#2 flip::dstIdx#3 flip::c#2 flip::r#2 ]
+ [34] (byte) flip::dstIdx#3 ← phi( flip::@1/(byte~) flip::dstIdx#7 flip::@8/(byte~) flip::dstIdx#8 ) [ flip::srcIdx#2 flip::dstIdx#3 flip::c#2 flip::r#2 ]
+ [34] (byte) flip::srcIdx#2 ← phi( flip::@1/(byte~) flip::srcIdx#6 flip::@8/(byte~) flip::srcIdx#7 ) [ flip::srcIdx#2 flip::dstIdx#3 flip::c#2 flip::r#2 ]
+ [35] (byte~) flip::$0 ← (word) 4096 *idx (byte) flip::srcIdx#2 [ flip::srcIdx#2 flip::dstIdx#3 flip::$0 flip::c#2 flip::r#2 ]
+ [36] *((word) 4352 + (byte) flip::dstIdx#3) ← (byte~) flip::$0 [ flip::srcIdx#2 flip::dstIdx#3 flip::c#2 flip::r#2 ]
+ [37] (byte) flip::srcIdx#1 ← ++ (byte) flip::srcIdx#2 [ flip::dstIdx#3 flip::c#2 flip::r#2 flip::srcIdx#1 ]
+ [38] (byte) flip::dstIdx#1 ← (byte) flip::dstIdx#3 + (byte) 16 [ flip::c#2 flip::dstIdx#1 flip::r#2 flip::srcIdx#1 ]
+ [39] (byte) flip::c#1 ← -- (byte) flip::c#2 [ flip::c#1 flip::dstIdx#1 flip::r#2 flip::srcIdx#1 ]
+ [40] if((byte) flip::c#1!=(byte) 0) goto flip::@8 [ flip::c#1 flip::dstIdx#1 flip::r#2 flip::srcIdx#1 ]
+ to:flip::@4
+flip::@4: from flip::@2
+ [41] (byte) flip::dstIdx#2 ← -- (byte) flip::dstIdx#1 [ flip::r#2 flip::srcIdx#1 flip::dstIdx#2 ]
+ [42] (byte) flip::r#1 ← -- (byte) flip::r#2 [ flip::r#1 flip::srcIdx#1 flip::dstIdx#2 ]
+ [43] if((byte) flip::r#1!=(byte) 0) goto flip::@7 [ flip::r#1 flip::srcIdx#1 flip::dstIdx#2 ]
+ to:flip::@3
+flip::@3: from flip::@4 flip::@9
+ [44] (byte) flip::i#2 ← phi( flip::@9/(byte~) flip::i#3 flip::@4/(byte) 0 ) [ flip::i#2 ]
+ [45] (byte~) flip::$4 ← (word) 4352 *idx (byte) flip::i#2 [ flip::i#2 flip::$4 ]
+ [46] *((word) 4096 + (byte) flip::i#2) ← (byte~) flip::$4 [ flip::i#2 ]
+ [47] (byte) flip::i#1 ← ++ (byte) flip::i#2 [ flip::i#1 ]
+ [48] if((byte) flip::i#1!=(byte) 0) goto flip::@9 [ flip::i#1 ]
+ to:flip::@return
+flip::@return: from flip::@3
+ [49] return [ ]
+ to:@RETURN
+flip::@9: from flip::@3
+ [50] (byte~) flip::i#3 ← (byte) flip::i#1 [ flip::i#3 ]
+ to:flip::@3
+flip::@7: from flip::@4
+ [51] (byte~) flip::srcIdx#5 ← (byte) flip::srcIdx#1 [ flip::srcIdx#5 flip::r#1 flip::dstIdx#2 ]
+ [52] (byte~) flip::dstIdx#6 ← (byte) flip::dstIdx#2 [ flip::srcIdx#5 flip::dstIdx#6 flip::r#1 ]
+ [53] (byte~) flip::r#5 ← (byte) flip::r#1 [ flip::srcIdx#5 flip::dstIdx#6 flip::r#5 ]
+ to:flip::@1
+flip::@8: from flip::@2
+ [54] (byte~) flip::srcIdx#7 ← (byte) flip::srcIdx#1 [ flip::srcIdx#7 flip::c#1 flip::dstIdx#1 flip::r#2 ]
+ [55] (byte~) flip::dstIdx#8 ← (byte) flip::dstIdx#1 [ flip::srcIdx#7 flip::dstIdx#8 flip::c#1 flip::r#2 ]
+ [56] (byte~) flip::c#3 ← (byte) flip::c#1 [ flip::srcIdx#7 flip::dstIdx#8 flip::c#3 flip::r#2 ]
+ to:flip::@2
+prepare: from main
+ to:prepare::@1
+prepare::@1: from prepare prepare::@3
+ [57] (byte) prepare::i#2 ← phi( prepare/(byte) 0 prepare::@3/(byte~) prepare::i#3 ) [ prepare::i#2 ]
+ [58] *((word) 4096 + (byte) prepare::i#2) ← (byte) prepare::i#2 [ prepare::i#2 ]
+ [59] (byte) prepare::i#1 ← ++ (byte) prepare::i#2 [ prepare::i#1 ]
+ [60] if((byte) prepare::i#1!=(byte) 0) goto prepare::@3 [ prepare::i#1 ]
+ to:prepare::@return
+prepare::@return: from prepare::@1
+ [61] return [ ]
+ to:@RETURN
+prepare::@3: from prepare::@1
+ [62] (byte~) prepare::i#3 ← (byte) prepare::i#1 [ prepare::i#3 ]
+ to:prepare::@1
+
+Created 14 initial phi equivalence classes
+Coalesced [13] main::c#6 ← main::c#1
+Coalesced [15] plot::i#6 ← plot::i#3
+Coalesced [26] plot::i#5 ← plot::i#1
+Coalesced [27] plot::line#5 ← plot::line#1
+Coalesced [28] plot::y#5 ← plot::y#1
+Coalesced (already) [29] plot::i#7 ← plot::i#1
+Coalesced [30] plot::x#3 ← plot::x#1
+Coalesced [32] flip::srcIdx#6 ← flip::srcIdx#3
+Coalesced [33] flip::dstIdx#7 ← flip::dstIdx#5
+Coalesced [50] flip::i#3 ← flip::i#1
+Coalesced [51] flip::srcIdx#5 ← flip::srcIdx#1
+Coalesced [52] flip::dstIdx#6 ← flip::dstIdx#2
+Coalesced [53] flip::r#5 ← flip::r#1
+Coalesced (already) [54] flip::srcIdx#7 ← flip::srcIdx#1
+Coalesced [55] flip::dstIdx#8 ← flip::dstIdx#1
+Coalesced [56] flip::c#3 ← flip::c#1
+Coalesced [62] prepare::i#3 ← prepare::i#1
+Coalesced down to 11 phi equivalence classes
+Culled Empty Block (label) main::@12
+Culled Empty Block (label) plot::@5
+Culled Empty Block (label) plot::@6
+Culled Empty Block (label) flip::@9
+Culled Empty Block (label) flip::@7
+Culled Empty Block (label) flip::@8
+Culled Empty Block (label) prepare::@3
+Block Sequence Planned @BEGIN @END main main::@3 main::@4 main::@6 main::@7 main::@10 main::@11 main::@return plot plot::@1 plot::@2 plot::@3 plot::@return flip flip::@1 flip::@2 flip::@4 flip::@3 flip::@return prepare prepare::@1 prepare::@return
+Propagating live ranges...
+Propagating live ranges...
+Propagating live ranges...
+Propagating live ranges...
+Propagating live ranges...
+Propagating live ranges...
+Propagating live ranges...
+Propagating live ranges...
+Propagating live ranges...
+CONTROL FLOW GRAPH - PHI MEM COALESCED
+@BEGIN: from
+ [0] call main param-assignment [ ]
+ to:@END
+@END: from @BEGIN
main: from @BEGIN
[1] call prepare param-assignment [ ]
to:main::@3
diff --git a/src/dk/camelot64/kickc/test/ref/loopmin.log b/src/dk/camelot64/kickc/test/ref/loopmin.log
index 79b0c21dc..58eb5af3e 100644
--- a/src/dk/camelot64/kickc/test/ref/loopmin.log
+++ b/src/dk/camelot64/kickc/test/ref/loopmin.log
@@ -252,10 +252,78 @@ CONTROL FLOW GRAPH
@END: from @3
Block Sequence Planned @BEGIN @1 @3 @END @2
+Added new block during phi lifting @7(between @3 and @1)
+Added new block during phi lifting @8(between @1 and @3)
+Block Sequence Planned @BEGIN @1 @8 @3 @END @7 @2
+CONTROL FLOW GRAPH - PHI LIFTED
+@BEGIN: from
+ to:@1
+@1: from @7 @BEGIN
+ (byte) s#2 ← phi( @7/(byte~) s#5 @BEGIN/(byte) 0 )
+ (byte) i#2 ← phi( @7/(byte~) i#5 @BEGIN/(byte) 10 )
+ if((byte) i#2>(byte) 5) goto @2
+ to:@8
+@8: from @1
+ (byte~) s#6 ← (byte) s#2
+ to:@3
+@3: from @2 @8
+ (byte) s#4 ← phi( @8/(byte~) s#6 @2/(byte~) s#7 )
+ (byte) i#1 ← -- (byte) i#2
+ if((byte) i#1>(byte) 0) goto @7
+ to:@END
+@END: from @3
+@7: from @3
+ (byte~) i#5 ← (byte) i#1
+ (byte~) s#5 ← (byte) s#4
+ to:@1
+@2: from @1
+ (byte) s#1 ← (byte) s#2 + (byte) i#2
+ (byte~) s#7 ← (byte) s#1
+ to:@3
+
+Propagating live ranges...
Propagating live ranges...
Propagating live ranges...
Propagating live ranges...
CONTROL FLOW GRAPH - LIVE RANGES
+@BEGIN: from
+ to:@1
+@1: from @7 @BEGIN
+ [0] (byte) s#2 ← phi( @7/(byte~) s#5 @BEGIN/(byte) 0 ) [ i#2 s#2 ]
+ [0] (byte) i#2 ← phi( @7/(byte~) i#5 @BEGIN/(byte) 10 ) [ i#2 s#2 ]
+ [1] if((byte) i#2>(byte) 5) goto @2 [ i#2 s#2 ]
+ to:@8
+@8: from @1
+ [2] (byte~) s#6 ← (byte) s#2 [ i#2 s#6 ]
+ to:@3
+@3: from @2 @8
+ [3] (byte) s#4 ← phi( @8/(byte~) s#6 @2/(byte~) s#7 ) [ i#2 s#4 ]
+ [4] (byte) i#1 ← -- (byte) i#2 [ i#1 s#4 ]
+ [5] if((byte) i#1>(byte) 0) goto @7 [ i#1 s#4 ]
+ to:@END
+@END: from @3
+@7: from @3
+ [6] (byte~) i#5 ← (byte) i#1 [ i#5 s#4 ]
+ [7] (byte~) s#5 ← (byte) s#4 [ i#5 s#5 ]
+ to:@1
+@2: from @1
+ [8] (byte) s#1 ← (byte) s#2 + (byte) i#2 [ i#2 s#1 ]
+ [9] (byte~) s#7 ← (byte) s#1 [ i#2 s#7 ]
+ to:@3
+
+Created 3 initial phi equivalence classes
+Coalesced [2] s#6 ← s#2
+Coalesced [6] i#5 ← i#1
+Coalesced (already) [7] s#5 ← s#4
+Coalesced [9] s#7 ← s#1
+Coalesced down to 2 phi equivalence classes
+Culled Empty Block (label) @8
+Culled Empty Block (label) @7
+Block Sequence Planned @BEGIN @1 @3 @END @2
+Propagating live ranges...
+Propagating live ranges...
+Propagating live ranges...
+CONTROL FLOW GRAPH - PHI MEM COALESCED
@BEGIN: from
to:@1
@1: from @3 @BEGIN
diff --git a/src/dk/camelot64/kickc/test/ref/minus.log b/src/dk/camelot64/kickc/test/ref/minus.log
index c5fb88bdb..37445250e 100644
--- a/src/dk/camelot64/kickc/test/ref/minus.log
+++ b/src/dk/camelot64/kickc/test/ref/minus.log
@@ -207,9 +207,50 @@ Multiple usages for variable. Not optimizing sub-constant (byte) i#2
Multiple usages for variable. Not optimizing sub-constant (byte) i#2
Multiple usages for variable. Not optimizing sub-constant (byte) i#2
Block Sequence Planned @BEGIN @1 @END
+Added new block during phi lifting @3(between @1 and @1)
+Block Sequence Planned @BEGIN @1 @END @3
+CONTROL FLOW GRAPH - PHI LIFTED
+@BEGIN: from
+ to:@1
+@1: from @3 @BEGIN
+ (byte) i#2 ← phi( @3/(byte~) i#3 @BEGIN/(byte) 5 )
+ (byte~) $0 ← (byte) 2 + (byte) i#2
+ (byte~) $1 ← (byte~) $0 + (byte) 2
+ *((word) 4352 + (byte) i#2) ← (byte~) $1
+ (byte) i#1 ← (byte) i#2 + (byte) 1
+ if((byte) i#1<(byte) 10) goto @3
+ to:@END
+@END: from @1
+@3: from @1
+ (byte~) i#3 ← (byte) i#1
+ to:@1
+
Propagating live ranges...
Propagating live ranges...
CONTROL FLOW GRAPH - LIVE RANGES
+@BEGIN: from
+ to:@1
+@1: from @3 @BEGIN
+ [0] (byte) i#2 ← phi( @3/(byte~) i#3 @BEGIN/(byte) 5 ) [ i#2 ]
+ [1] (byte~) $0 ← (byte) 2 + (byte) i#2 [ i#2 $0 ]
+ [2] (byte~) $1 ← (byte~) $0 + (byte) 2 [ i#2 $1 ]
+ [3] *((word) 4352 + (byte) i#2) ← (byte~) $1 [ i#2 ]
+ [4] (byte) i#1 ← (byte) i#2 + (byte) 1 [ i#1 ]
+ [5] if((byte) i#1<(byte) 10) goto @3 [ i#1 ]
+ to:@END
+@END: from @1
+@3: from @1
+ [6] (byte~) i#3 ← (byte) i#1 [ i#3 ]
+ to:@1
+
+Created 1 initial phi equivalence classes
+Coalesced [6] i#3 ← i#1
+Coalesced down to 1 phi equivalence classes
+Culled Empty Block (label) @3
+Block Sequence Planned @BEGIN @1 @END
+Propagating live ranges...
+Propagating live ranges...
+CONTROL FLOW GRAPH - PHI MEM COALESCED
@BEGIN: from
to:@1
@1: from @1 @BEGIN
diff --git a/src/dk/camelot64/kickc/test/ref/summin.log b/src/dk/camelot64/kickc/test/ref/summin.log
index a4f6e6f8d..783b0f132 100644
--- a/src/dk/camelot64/kickc/test/ref/summin.log
+++ b/src/dk/camelot64/kickc/test/ref/summin.log
@@ -241,6 +241,24 @@ sum::@return: from sum
@END: from @2
Block Sequence Planned @BEGIN @2 @END sum sum::@return
+Block Sequence Planned @BEGIN @2 @END sum sum::@return
+CONTROL FLOW GRAPH - PHI LIFTED
+@BEGIN: from
+ call sum param-assignment
+ to:@2
+@2: from @BEGIN
+ call sum param-assignment
+ to:@END
+@END: from @2
+sum: from @2 @BEGIN
+ (byte) sum::b#2 ← phi( @2/(byte) 13 @BEGIN/(byte) 2 )
+ (byte) sum::a#2 ← phi( @2/(byte) 9 @BEGIN/(byte) 1 )
+ (byte) s1#0 ← (byte) sum::a#2 + (byte) sum::b#2
+ to:sum::@return
+sum::@return: from sum
+ return (byte) s1#0
+ to:@RETURN
+
Propagating live ranges...
CONTROL FLOW GRAPH - LIVE RANGES
@BEGIN: from
@@ -259,6 +277,27 @@ sum::@return: from sum
[4] return (byte) s1#0 [ ]
to:@RETURN
+Created 2 initial phi equivalence classes
+Coalesced down to 2 phi equivalence classes
+Block Sequence Planned @BEGIN @2 @END sum sum::@return
+Propagating live ranges...
+CONTROL FLOW GRAPH - PHI MEM COALESCED
+@BEGIN: from
+ [0] call sum param-assignment [ ]
+ to:@2
+@2: from @BEGIN
+ [1] call sum param-assignment [ ]
+ to:@END
+@END: from @2
+sum: from @2 @BEGIN
+ [2] (byte) sum::b#2 ← phi( @2/(byte) 13 @BEGIN/(byte) 2 ) [ sum::a#2 sum::b#2 ]
+ [2] (byte) sum::a#2 ← phi( @2/(byte) 9 @BEGIN/(byte) 1 ) [ sum::a#2 sum::b#2 ]
+ [3] (byte) s1#0 ← (byte) sum::a#2 + (byte) sum::b#2 [ s1#0 ]
+ to:sum::@return
+sum::@return: from sum
+ [4] return (byte) s1#0 [ ]
+ to:@RETURN
+
INITIAL ASM
BBEGIN:
sum_from_BBEGIN: