From e7ea5fb4ea8888c2c3aaddac1a995c3cf3e82aec Mon Sep 17 00:00:00 2001 From: jespergravgaard Date: Thu, 27 Jul 2017 22:20:50 +0200 Subject: [PATCH] Implemented control flow graph loop analysis. --- src/dk/camelot64/kickc/Compiler.java | 15 +- .../camelot64/kickc/icl/ControlFlowBlock.java | 19 + .../camelot64/kickc/icl/ControlFlowGraph.java | 18 + .../camelot64/kickc/icl/DominatorsBlock.java | 100 ++++ .../camelot64/kickc/icl/DominatorsGraph.java | 69 +++ src/dk/camelot64/kickc/icl/LiveRange.java | 2 +- src/dk/camelot64/kickc/icl/NaturalLoop.java | 129 ++++ .../camelot64/kickc/icl/NaturalLoopSet.java | 80 +++ src/dk/camelot64/kickc/icl/Program.java | 1 + .../kickc/passes/Pass3DominatorsAnalysis.java | 84 +++ ...nges.java => Pass3LiveRangesAnalysis.java} | 4 +- .../kickc/passes/Pass3LoopAnalysis.java | 240 ++------ .../kickc/test/TestCompilationOutput.java | 5 + src/dk/camelot64/kickc/test/TestIclJson.java | 6 +- src/dk/camelot64/kickc/test/loopsplit.kc | 9 + src/dk/camelot64/kickc/test/ref/bresenham.log | 12 + .../camelot64/kickc/test/ref/flipper-rex2.log | 58 ++ src/dk/camelot64/kickc/test/ref/loopmin.log | 12 + src/dk/camelot64/kickc/test/ref/loopsplit.asm | 24 + src/dk/camelot64/kickc/test/ref/loopsplit.cfg | 18 + src/dk/camelot64/kickc/test/ref/loopsplit.log | 564 ++++++++++++++++++ src/dk/camelot64/kickc/test/ref/loopsplit.sym | 13 + src/dk/camelot64/kickc/test/ref/minus.log | 10 + src/dk/camelot64/kickc/test/ref/summin.log | 9 + 24 files changed, 1311 insertions(+), 190 deletions(-) create mode 100644 src/dk/camelot64/kickc/icl/DominatorsBlock.java create mode 100644 src/dk/camelot64/kickc/icl/DominatorsGraph.java create mode 100644 src/dk/camelot64/kickc/icl/NaturalLoop.java create mode 100644 src/dk/camelot64/kickc/icl/NaturalLoopSet.java create mode 100644 src/dk/camelot64/kickc/passes/Pass3DominatorsAnalysis.java rename src/dk/camelot64/kickc/passes/{Pass3IdentifyLiveRanges.java => Pass3LiveRangesAnalysis.java} (99%) create mode 100644 src/dk/camelot64/kickc/test/loopsplit.kc create mode 100644 src/dk/camelot64/kickc/test/ref/loopsplit.asm create mode 100644 src/dk/camelot64/kickc/test/ref/loopsplit.cfg create mode 100644 src/dk/camelot64/kickc/test/ref/loopsplit.log create mode 100644 src/dk/camelot64/kickc/test/ref/loopsplit.sym diff --git a/src/dk/camelot64/kickc/Compiler.java b/src/dk/camelot64/kickc/Compiler.java index a1ddc8e8d..a56b1bc81 100644 --- a/src/dk/camelot64/kickc/Compiler.java +++ b/src/dk/camelot64/kickc/Compiler.java @@ -110,8 +110,8 @@ public class Compiler { log.append(program.getGraph().toString(program.getScope())); pass2AssertSSA(program, log); - Pass3IdentifyLiveRanges pass3IdentifyLiveRanges = new Pass3IdentifyLiveRanges(program, log); - pass3IdentifyLiveRanges.findLiveRanges(); + Pass3LiveRangesAnalysis pass3LiveRangesAnalysis = new Pass3LiveRangesAnalysis(program, log); + pass3LiveRangesAnalysis.findLiveRanges(); log.append("CONTROL FLOW GRAPH - LIVE RANGES"); log.append(program.getGraph().toString(program.getScope())); pass2AssertSSA(program, log); @@ -121,13 +121,20 @@ public class Compiler { Pass2CullEmptyBlocks cullEmptyBlocks = new Pass2CullEmptyBlocks(program, log); cullEmptyBlocks.optimize(); pass3BlockSequencePlanner.plan(); - pass3IdentifyLiveRanges.findLiveRanges(); + pass3LiveRangesAnalysis.findLiveRanges(); log.append("CONTROL FLOW GRAPH - PHI MEM COALESCED"); log.append(program.getGraph().toString(program.getScope())); pass2AssertSSA(program, log); + Pass3DominatorsAnalysis pass3DominatorsAnalysis = new Pass3DominatorsAnalysis(program, log); + pass3DominatorsAnalysis.findDominators(); + log.append("DOMINATORS"); + log.append(program.getGraph().getDominators().toString()); + Pass3LoopAnalysis pass3LoopAnalysis = new Pass3LoopAnalysis(program, log); - pass3LoopAnalysis.detectLoops(); + pass3LoopAnalysis.findLoops(); + log.append("NATURAL LOOPS"); + log.append(program.getGraph().getLoopSet().toString()); } diff --git a/src/dk/camelot64/kickc/icl/ControlFlowBlock.java b/src/dk/camelot64/kickc/icl/ControlFlowBlock.java index bd569843d..524e4c493 100644 --- a/src/dk/camelot64/kickc/icl/ControlFlowBlock.java +++ b/src/dk/camelot64/kickc/icl/ControlFlowBlock.java @@ -5,6 +5,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import java.util.ArrayList; +import java.util.Collection; import java.util.List; /** A named/labelled sequence of SSA statements connected to other basic blocks. @@ -158,4 +159,22 @@ public class ControlFlowBlock { } + /** Get all successors of the block + * + * @return All successors + */ + @JsonIgnore + public Collection getSuccessors() { + List successors = new ArrayList<>(); + if(defaultSuccessor!=null) { + successors.add(defaultSuccessor); + } + if(conditionalSuccessor!=null) { + successors.add(conditionalSuccessor); + } + if(callSuccessor!=null) { + successors.add(callSuccessor); + } + return successors; + } } diff --git a/src/dk/camelot64/kickc/icl/ControlFlowGraph.java b/src/dk/camelot64/kickc/icl/ControlFlowGraph.java index 9355640e1..f3f659d25 100644 --- a/src/dk/camelot64/kickc/icl/ControlFlowGraph.java +++ b/src/dk/camelot64/kickc/icl/ControlFlowGraph.java @@ -13,6 +13,8 @@ public class ControlFlowGraph { private Map blocks; private LabelRef firstBlockRef; private List sequence; + private DominatorsGraph dominators; + private NaturalLoopSet loopSet; public ControlFlowGraph(Map blocks, LabelRef firstBlockRef) { this.blocks = blocks; @@ -175,4 +177,20 @@ public class ControlFlowGraph { return result; } + public void setDominators(DominatorsGraph dominators) { + this.dominators = dominators; + } + + public DominatorsGraph getDominators() { + return dominators; + } + + public void setLoops(NaturalLoopSet loopSet) { + this.loopSet = loopSet; + } + + public NaturalLoopSet getLoopSet() { + return loopSet; + } + } diff --git a/src/dk/camelot64/kickc/icl/DominatorsBlock.java b/src/dk/camelot64/kickc/icl/DominatorsBlock.java new file mode 100644 index 000000000..55fa0cf68 --- /dev/null +++ b/src/dk/camelot64/kickc/icl/DominatorsBlock.java @@ -0,0 +1,100 @@ +package dk.camelot64.kickc.icl; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +/** The Dominators for a specific block. + *

+ * Definition: Block d dominates block i if all paths from entry to block i includes block d + *

+ * See http://www.cs.colostate.edu/~cs553/ClassNotes/lecture09-control-dominators.ppt.pdf + * */ +public class DominatorsBlock { + + /** + * Set containing the labels of all blocks that are dominators of the block. + */ + Set dominators; + + public DominatorsBlock() { + this.dominators = new HashSet<>(); + } + + /** + * Add a single dominator + * + * @param dominator The dominator to add + */ + public void add(LabelRef dominator) { + dominators.add(dominator); + } + + /** + * Adds a bunch of dominators + * + * @param dominators The dominators to add + */ + public void addAll(Collection dominators) { + for (LabelRef dominator : dominators) { + add(dominator); + } + + } + + /** + * Modifies this set of dominators to be the intersection between this set and the passed set. + * Effectively removes all labels from this set that is not also present in the passed set. + * + * @param other The dominator set to intersect with + */ + public void intersect(DominatorsBlock other) { + Iterator iterator = dominators.iterator(); + while (iterator.hasNext()) { + LabelRef dominator = iterator.next(); + if (!other.contains(dominator)) { + iterator.remove(); + } + } + } + + /** + * Determines if the dominator set contains a specific block + * + * @param block The block to look for + * @return true if the dominator set contains the block + */ + public boolean contains(LabelRef block) { + return dominators.contains(block); + } + + public Set getDominators() { + return dominators; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + DominatorsBlock that = (DominatorsBlock) o; + + return dominators != null ? dominators.equals(that.dominators) : that.dominators == null; + } + + @Override + public int hashCode() { + return dominators != null ? dominators.hashCode() : 0; + } + + @Override + public String toString() { + StringBuilder out = new StringBuilder(); + for (LabelRef dominator : dominators) { + out.append(dominator); + out.append(" "); + } + return out.toString(); + } +} diff --git a/src/dk/camelot64/kickc/icl/DominatorsGraph.java b/src/dk/camelot64/kickc/icl/DominatorsGraph.java new file mode 100644 index 000000000..17680223b --- /dev/null +++ b/src/dk/camelot64/kickc/icl/DominatorsGraph.java @@ -0,0 +1,69 @@ +package dk.camelot64.kickc.icl; + +import java.util.LinkedHashMap; +import java.util.Map; + +/** Dominators for a control flow graph. + *

+ * Definition: Block d dominates block i if all paths from entry to block i includes block d + *

+ * See http://www.cs.colostate.edu/~cs553/ClassNotes/lecture09-control-dominators.ppt.pdf + * + * */ +public class DominatorsGraph { + + /** + * Maps block label to the dominators of the block. + */ + Map blockDominators; + + public DominatorsGraph() { + this.blockDominators = new LinkedHashMap<>(); + } + + /** + * Get the dominators for a specific block. + * + * @param block Label of the block + * @return The block dominators + */ + public DominatorsBlock getDominators(LabelRef block) { + return blockDominators.get(block); + } + + /** + * Creates dominators for a specific block + * + * @param block Label of the block + * @return The newly created block dominators + */ + public DominatorsBlock addDominators(LabelRef block) { + DominatorsBlock dominatorsBlock = new DominatorsBlock(); + this.blockDominators.put(block, dominatorsBlock); + return dominatorsBlock; + } + + + /** + * Set the dominators for a specific block + * + * @param block The block + * @param dominators The new dominators + */ + public void setDominators(LabelRef block, DominatorsBlock dominators) { + blockDominators.put(block, dominators); + } + + @Override + public String toString() { + StringBuilder out = new StringBuilder(); + for (LabelRef block : blockDominators.keySet()) { + DominatorsBlock dominators = getDominators(block); + out.append(block); + out.append(" dominated by "); + out.append(dominators.toString()); + out.append("\n"); + } + return out.toString(); + } +} diff --git a/src/dk/camelot64/kickc/icl/LiveRange.java b/src/dk/camelot64/kickc/icl/LiveRange.java index 41e506780..4c2bd8685 100644 --- a/src/dk/camelot64/kickc/icl/LiveRange.java +++ b/src/dk/camelot64/kickc/icl/LiveRange.java @@ -66,7 +66,7 @@ public class LiveRange { private Integer getIndex(Statement statement) { Integer index = statement.getIndex(); if (index == null) { - throw new RuntimeException("Statement index not defined! Live Ranges only work after defining statement indexes (Pass3IdentifyLiveRanges.generateStatementIndexes)."); + throw new RuntimeException("Statement index not defined! Live Ranges only work after defining statement indexes (Pass3LiveRangesAnalysis.generateStatementIndexes)."); } return index; } diff --git a/src/dk/camelot64/kickc/icl/NaturalLoop.java b/src/dk/camelot64/kickc/icl/NaturalLoop.java new file mode 100644 index 000000000..58c4e60bd --- /dev/null +++ b/src/dk/camelot64/kickc/icl/NaturalLoop.java @@ -0,0 +1,129 @@ +package dk.camelot64.kickc.icl; + +import java.util.LinkedHashSet; +import java.util.Set; + +/** + * A single natural loop in a control flow graph. + */ +public class NaturalLoop { + + /** + * The head of the natural loop. The block where control enters the loop and the block where the back edge returns to. Dominates all nodes in the loop. + */ + private LabelRef head; + + /** + * The tail(s) of the natural loop. The source(s) of the back edge. + * Normally there is only one tail in a loop - but loops with multiple tails occur when the loop body is split. An example + * while(i!=0) { if(i<5) { tail1; } else { tail2; }} + */ + private Set tails; + + /** + * The blocks of the natural loop (including head and tail) + */ + private Set blocks; + + /** + * Create a new natural loop. + * The loop is not filled with all blocks from the start, but only holds the head & tail. + * + * @param head The head block, start of the loop. + * @param tail The tail block, source of the back edge + */ + public NaturalLoop(LabelRef head, LabelRef tail) { + this.head = head; + this.tails = new LinkedHashSet<>(); + tails.add(tail); + this.blocks = null; + } + + public LabelRef getHead() { + return head; + } + + public Set getTails() { + return tails; + } + + public Set getBlocks() { + return blocks; + } + + public void setBlocks(Set blocks) { + this.blocks = blocks; + } + + @Override + public String toString() { + StringBuilder out = new StringBuilder(); + out.append("Loop head: ") + .append(head) + .append(" tails: "); + for (LabelRef tail : tails) { + out.append(tail).append(" "); + } + out.append("blocks: "); + if (blocks != null) { + for (LabelRef block : blocks) { + out.append(block.toString()).append(" "); + } + } else { + out.append("null"); + } + return out.toString(); + } + + /** + * Determines if this loop contains another loop - ie. if the other loops blocks are all contained in this loops blocks. + * + * @param other The other loop + * @return true if this loop contains the other loop + */ + public boolean nests(NaturalLoop other) { + for (LabelRef otherBlock : other.getBlocks()) { + if (!blocks.contains(otherBlock)) { + return false; + } + } + return true; + } + + /** + * Add more tails to the loop + * @param tails The tails to add + */ + public void addTails(Set tails) { + this.tails.addAll(tails); + } + + /** + * Add more blocks to the loop + * @param blocks The blocks to add + */ + public void addBlocks(Set blocks) { + this.blocks.addAll(blocks); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + NaturalLoop that = (NaturalLoop) o; + + if (head != null ? !head.equals(that.head) : that.head != null) return false; + if (tails != null ? !tails.equals(that.tails) : that.tails != null) return false; + return blocks != null ? blocks.equals(that.blocks) : that.blocks == null; + } + + @Override + public int hashCode() { + int result = head != null ? head.hashCode() : 0; + result = 31 * result + (tails != null ? tails.hashCode() : 0); + result = 31 * result + (blocks != null ? blocks.hashCode() : 0); + return result; + } + +} diff --git a/src/dk/camelot64/kickc/icl/NaturalLoopSet.java b/src/dk/camelot64/kickc/icl/NaturalLoopSet.java new file mode 100644 index 000000000..2130ac8f4 --- /dev/null +++ b/src/dk/camelot64/kickc/icl/NaturalLoopSet.java @@ -0,0 +1,80 @@ +package dk.camelot64.kickc.icl; + +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +/** A set of natural loops in a control flow graph. + *

For definitions and more see http://www.cs.colostate.edu/~cs553/ClassNotes/lecture09-control-dominators.ppt.pdf + * */ +public class NaturalLoopSet { + + private List loops; + + public NaturalLoopSet() { + this.loops = new ArrayList<>(); + } + + /** + * Add a loop to the set + * + * @param loop The loop to add + */ + public void addLoop(NaturalLoop loop) { + loops.add(loop); + } + + /** + * Get all the loops + * @return The loops + */ + public List getLoops() { + return loops; + } + + @Override + public String toString() { + StringBuilder out = new StringBuilder(); + for (NaturalLoop loop : loops) { + out.append(loop.toString()); + out.append("\n"); + } + return out.toString(); + } + + /** + * Get all blocks that are heads of a loop + * @return The labels for all blocks that are head of a loop. + */ + public Set getLoopHeads() { + LinkedHashSet heads = new LinkedHashSet<>(); + for (NaturalLoop loop : loops) { + heads.add(loop.getHead()); + } + return heads; + } + + /** + * Get all loops with a given loop head + * @param loopHead The loop head + * @return Set with all loops that have the given head + */ + public Set getLoopsFromHead(LabelRef loopHead) { + LinkedHashSet result = new LinkedHashSet<>(); + for (NaturalLoop loop : loops) { + if(loopHead.equals(loop.getHead())) { + result.add(loop); + } + } + return result; + } + + /** + * Remove a loop from the set + * @param loop The loop to remove + */ + public void remove(NaturalLoop loop) { + this.loops.remove(loop); + } +} diff --git a/src/dk/camelot64/kickc/icl/Program.java b/src/dk/camelot64/kickc/icl/Program.java index 237b1d321..9fdf323e8 100644 --- a/src/dk/camelot64/kickc/icl/Program.java +++ b/src/dk/camelot64/kickc/icl/Program.java @@ -5,6 +5,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; /** A KickC Intermediate Compiler Language (ICL) Program */ public class Program { + /** The main scope. */ private ProgramScope scope; /** The control flow graph. */ diff --git a/src/dk/camelot64/kickc/passes/Pass3DominatorsAnalysis.java b/src/dk/camelot64/kickc/passes/Pass3DominatorsAnalysis.java new file mode 100644 index 000000000..406ea7782 --- /dev/null +++ b/src/dk/camelot64/kickc/passes/Pass3DominatorsAnalysis.java @@ -0,0 +1,84 @@ +package dk.camelot64.kickc.passes; + +import dk.camelot64.kickc.CompileLog; +import dk.camelot64.kickc.icl.*; + +import java.util.ArrayList; +import java.util.List; + +/** Finds the dominators for the control flow graph. */ +public class Pass3DominatorsAnalysis { + + private Program program; + private CompileLog log; + + public Pass3DominatorsAnalysis(Program program, CompileLog log) { + this.program = program; + this.log = log; + } + + public Program getProgram() { + return program; + } + + public CompileLog getLog() { + return log; + } + + /** + * Analyse the control flow graph to find dominators for all blocks. + *

+ * Definition: d dom i if all paths from entry to node i include d + *

+ * See http://www.cs.colostate.edu/~cs553/ClassNotes/lecture09-control-dominators.ppt.pdf + * + * @return The graph dominators + */ + public void findDominators() { + DominatorsGraph dominatorsGraph = new DominatorsGraph(); + + // Initialize dominators: Dom[first]={first}, Dom[block]={all} + LabelRef firstBlock = program.getGraph().getFirstBlock().getLabel(); + DominatorsBlock firstDominators = dominatorsGraph.addDominators(firstBlock); + firstDominators.add(firstBlock); + List allBlocks = new ArrayList<>(); + for (ControlFlowBlock block : program.getGraph().getAllBlocks()) { + allBlocks.add(block.getLabel()); + } + for (ControlFlowBlock block : program.getGraph().getAllBlocks()) { + if (!block.getLabel().equals(firstBlock)) { + DominatorsBlock dominatorsBlock = dominatorsGraph.addDominators(block.getLabel()); + dominatorsBlock.addAll(allBlocks); + } + } + + // Iteratively refine dominators until they do not change + // For all nodes: + // Dom[n] = {n} UNION ( INTERSECT Dom[p] for all p that are predecessors of n) + boolean change = false; + do { + change = false; + for (ControlFlowBlock block : program.getGraph().getAllBlocks()) { + if (!block.getLabel().equals(firstBlock)) { + List predecessors = program.getGraph().getPredecessors(block); + DominatorsBlock newDominators = new DominatorsBlock(); + newDominators.addAll(allBlocks); + for (ControlFlowBlock predecessor : predecessors) { + DominatorsBlock predecessorDominators = dominatorsGraph.getDominators(predecessor.getLabel()); + newDominators.intersect(predecessorDominators); + } + newDominators.add(block.getLabel()); + DominatorsBlock currentDominators = dominatorsGraph.getDominators(block.getLabel()); + if (!currentDominators.equals(newDominators)) { + change = true; + dominatorsGraph.setDominators(block.getLabel(), newDominators); + } + } + } + + } while (change); + program.getGraph().setDominators(dominatorsGraph); + } + + +} diff --git a/src/dk/camelot64/kickc/passes/Pass3IdentifyLiveRanges.java b/src/dk/camelot64/kickc/passes/Pass3LiveRangesAnalysis.java similarity index 99% rename from src/dk/camelot64/kickc/passes/Pass3IdentifyLiveRanges.java rename to src/dk/camelot64/kickc/passes/Pass3LiveRangesAnalysis.java index b873bada2..83262d276 100644 --- a/src/dk/camelot64/kickc/passes/Pass3IdentifyLiveRanges.java +++ b/src/dk/camelot64/kickc/passes/Pass3LiveRangesAnalysis.java @@ -11,12 +11,12 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -public class Pass3IdentifyLiveRanges { +public class Pass3LiveRangesAnalysis { private final Program program; private final CompileLog log; - public Pass3IdentifyLiveRanges(Program program, CompileLog log) { + public Pass3LiveRangesAnalysis(Program program, CompileLog log) { this.program = program; this.log = log; } diff --git a/src/dk/camelot64/kickc/passes/Pass3LoopAnalysis.java b/src/dk/camelot64/kickc/passes/Pass3LoopAnalysis.java index 8feb5346f..eed857161 100644 --- a/src/dk/camelot64/kickc/passes/Pass3LoopAnalysis.java +++ b/src/dk/camelot64/kickc/passes/Pass3LoopAnalysis.java @@ -1,14 +1,15 @@ package dk.camelot64.kickc.passes; import dk.camelot64.kickc.CompileLog; -import dk.camelot64.kickc.icl.ControlFlowBlock; -import dk.camelot64.kickc.icl.LabelRef; -import dk.camelot64.kickc.icl.Program; +import dk.camelot64.kickc.icl.*; import java.util.*; /** - * Finds loops and nested loops in the control flow graph + * Finds loops and nested loops in the control flow graph. + * Uses the dominators of the graph to find loops. + *

+ * See http://www.cs.colostate.edu/~cs553/ClassNotes/lecture09-control-dominators.ppt.pdf */ public class Pass3LoopAnalysis { @@ -28,194 +29,73 @@ public class Pass3LoopAnalysis { return log; } - public void detectLoops() { - - GraphDominators graphDominators = analyseDominators(); - - - } - /** - * Analyse the control flow graph to find dominators for all blocks. - *

- * Definition: d dom i if all paths from entry to node i include d + * Finds loops and nested loops in the control flow graph. + * Uses the dominators of the graph to find loops. *

* See http://www.cs.colostate.edu/~cs553/ClassNotes/lecture09-control-dominators.ppt.pdf - * - * @return The graph dominators */ - private GraphDominators analyseDominators() { - GraphDominators graphDominators = new GraphDominators(); + public void findLoops() { + DominatorsGraph dominators = program.getGraph().getDominators(); + Collection blocks = program.getGraph().getAllBlocks(); - // Initialize dominators: Dom[first]={first}, Dom[block]={all} - LabelRef firstBlock = program.getGraph().getFirstBlock().getLabel(); - BlockDominators firstDominators = graphDominators.addDominators(firstBlock); - firstDominators.add(firstBlock); - List allBlocks = new ArrayList<>(); - for (ControlFlowBlock block : program.getGraph().getAllBlocks()) { - allBlocks.add(block.getLabel()); - } - for (ControlFlowBlock block : program.getGraph().getAllBlocks()) { - if (!block.getLabel().equals(firstBlock)) { - BlockDominators blockDominators = graphDominators.addDominators(block.getLabel()); - blockDominators.addAll(allBlocks); - } - } - - // Iteratively refine dominators until they do not change - // For all nodes: - // Dom[n] = {n} UNION ( INTERSECT Dom[p] for all p that are predecessors of n) - boolean change = false; - do { - change = false; - for (ControlFlowBlock block : program.getGraph().getAllBlocks()) { - if (!block.getLabel().equals(firstBlock)) { - List predecessors = program.getGraph().getPredecessors(block); - BlockDominators newDominators = new BlockDominators(); - newDominators.addAll(allBlocks); - for (ControlFlowBlock predecessor : predecessors) { - BlockDominators predecessorDominators = graphDominators.getDominators(predecessor.getLabel()); - newDominators.intersect(predecessorDominators); - } - newDominators.add(block.getLabel()); - BlockDominators currentDominators = graphDominators.getDominators(block.getLabel()); - if (!currentDominators.equals(newDominators)) { - change = true; - graphDominators.setDominators(block.getLabel(), newDominators); - } - } - } - - } while (change); - - return graphDominators; - } - - - public static class GraphDominators { - - /** - * Maps block label to the dominators of the block. - */ - Map blockDominators; - - public GraphDominators() { - this.blockDominators = new LinkedHashMap<>(); - } - - /** - * Get the dominators for a specific block. - * - * @param block Label of the block - * @return The block dominators - */ - public BlockDominators getDominators(LabelRef block) { - return blockDominators.get(block); - } - - /** - * Creates dominators for a specific block - * - * @param block Label of the block - * @return The newly created block dominators - */ - public BlockDominators addDominators(LabelRef block) { - BlockDominators blockDominators = new BlockDominators(); - this.blockDominators.put(block, blockDominators); - return blockDominators; - } - - - /** - * Set the dominators for a specific block - * - * @param block The block - * @param dominators The new dominators - */ - public void setDominators(LabelRef block, BlockDominators dominators) { - blockDominators.put(block, dominators); - } - } - - /** - * The Dominators for a specific block. - */ - public static class BlockDominators { - - /** - * Set containing the labels of all blocks that are dominators of the block. - */ - Set dominators; - - public BlockDominators() { - this.dominators = new HashSet<>(); - } - - /** - * Add a single dominator - * - * @param dominator The dominator to add - */ - public void add(LabelRef dominator) { - dominators.add(dominator); - } - - /** - * Adds a bunch of dominators - * - * @param dominators The dominators to add - */ - public void addAll(Collection dominators) { - for (LabelRef dominator : dominators) { - add(dominator); - } - - } - - /** - * Modifies this set of dominators to be the intersection between this set and the passed set. - * Effectively removes all labels from this set that is not also present in the passed set. - * - * @param other The dominator set to intersect with - */ - public void intersect(BlockDominators other) { - Iterator iterator = dominators.iterator(); - while (iterator.hasNext()) { - LabelRef dominator = iterator.next(); - if (!other.contains(dominator)) { - iterator.remove(); + // Look through graph for natural loop back edges + NaturalLoopSet loopSet = new NaturalLoopSet(); + for (ControlFlowBlock block : blocks) { + DominatorsBlock blockDominators = dominators.getDominators(block.getLabel()); + for (LabelRef successor : block.getSuccessors()) { + if (blockDominators.contains(successor)) { + // Found a loop back edge! + NaturalLoop loop = new NaturalLoop(successor, block.getLabel()); + log.append("Found back edge: "+loop.toString()); + loopSet.addLoop(loop); } } } - /** - * Determines if the dominator set contains a specific block - * - * @param block The block to look for - * @return true if the dominator set contains the block - */ - private boolean contains(LabelRef block) { - return dominators.contains(block); + // Find all blocks for each loop + for (NaturalLoop loop : loopSet.getLoops()) { + Deque todo = new ArrayDeque<>(); + Set loopBlocks = new LinkedHashSet<>(); + todo.addAll(loop.getTails()); + while(!todo.isEmpty()) { + LabelRef block = todo.pop(); + loopBlocks.add(block); + if(block.equals(loop.getHead())) { + continue; + } + ControlFlowBlock controlFlowBlock = program.getGraph().getBlock(block); + List predecessors = program.getGraph().getPredecessors(controlFlowBlock); + for (ControlFlowBlock predecessor : predecessors) { + if(!loopBlocks.contains(predecessor.getLabel()) && !todo.contains(predecessor.getLabel())) { + todo.add(predecessor.getLabel()); + } + } + } + loop.setBlocks(loopBlocks); + log.append("Populated: "+loop.toString()); } - public Set getDominators() { - return dominators; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - BlockDominators that = (BlockDominators) o; - - return dominators != null ? dominators.equals(that.dominators) : that.dominators == null; - } - - @Override - public int hashCode() { - return dominators != null ? dominators.hashCode() : 0; + // Coalesce loops that are neither nested, nor disjoint + for (NaturalLoop loop : loopSet.getLoops()) { + Set headLoops = loopSet.getLoopsFromHead(loop.getHead()); + for (NaturalLoop other : headLoops) { + if(other.equals(loop)) { + // Same loop - do not process + continue; + } else if(loop.nests(other) || other.nests(loop)) { + // One of the loops nest the other loop + continue; + } else { + // Two non-nested loops with a shared head - collect them to one loop + loop.addTails(other.getTails()); + loop.addBlocks(other.getBlocks()); + loopSet.remove(other); + log.append("Coalesced: "+loop.toString()) ; + } + } } + program.getGraph().setLoops(loopSet); } diff --git a/src/dk/camelot64/kickc/test/TestCompilationOutput.java b/src/dk/camelot64/kickc/test/TestCompilationOutput.java index 709212fab..f6ad635fc 100644 --- a/src/dk/camelot64/kickc/test/TestCompilationOutput.java +++ b/src/dk/camelot64/kickc/test/TestCompilationOutput.java @@ -48,6 +48,11 @@ public class TestCompilationOutput extends TestCase { tester.testFile("summin"); } + public void testLoopSplit() throws IOException, URISyntaxException { + TestCompilationOutput tester = new TestCompilationOutput(); + tester.testFile("loopsplit"); + } + private void testFile(String fileName) throws IOException, URISyntaxException { String inputPath = testPath + fileName + ".kc"; System.out.println("Testing output for " + inputPath); diff --git a/src/dk/camelot64/kickc/test/TestIclJson.java b/src/dk/camelot64/kickc/test/TestIclJson.java index 18b281c98..6937f1d8b 100644 --- a/src/dk/camelot64/kickc/test/TestIclJson.java +++ b/src/dk/camelot64/kickc/test/TestIclJson.java @@ -87,7 +87,7 @@ public class TestIclJson extends TestCase { CompileLog log = new CompileLog(); KickCParser.FileContext file = compiler.pass0ParseInput(new ANTLRInputStream(minProgram), log); Program program = compiler.pass1GenerateSSA(file, log); - String json = "{\"scope\":{\"@type\":\"program\",\"name\":\"\",\"symbols\":{\"b\":{\"@type\":\"variable_unversioned\",\"name\":\"b\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"nextVersionNumber\":1,\"inferredType\":false},\"c\":{\"@type\":\"variable_unversioned\",\"name\":\"c\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"nextVersionNumber\":1,\"inferredType\":false},\"@BEGIN\":{\"@type\":\"label\",\"name\":\"@BEGIN\",\"intermediate\":false},\"@END\":{\"@type\":\"label\",\"name\":\"@END\",\"intermediate\":false},\"b#0\":{\"@type\":\"variable_versioned\",\"name\":\"b#0\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"b\",\"inferredType\":false},\"c#0\":{\"@type\":\"variable_versioned\",\"name\":\"c#0\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"c\",\"inferredType\":false}},\"intermediateVarCount\":0,\"intermediateLabelCount\":1,\"allocation\":null,\"liveRanges\":null},\"graph\":{\"blocks\":{\"@BEGIN\":{\"label\":{\"@type\":\"labelref\",\"fullName\":\"@BEGIN\"},\"statements\":[{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"b#0\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"integer\",\"number\":0},\"index\":null},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"c#0\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"varref\",\"fullName\":\"b#0\"},\"index\":null}],\"defaultSuccessor\":{\"@type\":\"labelref\",\"fullName\":\"@END\"},\"conditionalSuccessor\":null,\"callSuccessor\":null},\"@END\":{\"label\":{\"@type\":\"labelref\",\"fullName\":\"@END\"},\"statements\":[],\"defaultSuccessor\":null,\"conditionalSuccessor\":null,\"callSuccessor\":null}},\"firstBlockRef\":{\"@type\":\"labelref\",\"fullName\":\"@BEGIN\"},\"sequence\":null}}"; + String json = "{\"scope\":{\"@type\":\"program\",\"name\":\"\",\"symbols\":{\"b\":{\"@type\":\"variable_unversioned\",\"name\":\"b\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"nextVersionNumber\":1,\"inferredType\":false},\"c\":{\"@type\":\"variable_unversioned\",\"name\":\"c\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"nextVersionNumber\":1,\"inferredType\":false},\"@BEGIN\":{\"@type\":\"label\",\"name\":\"@BEGIN\",\"intermediate\":false},\"@END\":{\"@type\":\"label\",\"name\":\"@END\",\"intermediate\":false},\"b#0\":{\"@type\":\"variable_versioned\",\"name\":\"b#0\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"b\",\"inferredType\":false},\"c#0\":{\"@type\":\"variable_versioned\",\"name\":\"c#0\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"c\",\"inferredType\":false}},\"intermediateVarCount\":0,\"intermediateLabelCount\":1,\"allocation\":null,\"liveRanges\":null},\"graph\":{\"blocks\":{\"@BEGIN\":{\"label\":{\"@type\":\"labelref\",\"fullName\":\"@BEGIN\"},\"statements\":[{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"b#0\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"integer\",\"number\":0},\"index\":null},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"c#0\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"varref\",\"fullName\":\"b#0\"},\"index\":null}],\"defaultSuccessor\":{\"@type\":\"labelref\",\"fullName\":\"@END\"},\"conditionalSuccessor\":null,\"callSuccessor\":null},\"@END\":{\"label\":{\"@type\":\"labelref\",\"fullName\":\"@END\"},\"statements\":[],\"defaultSuccessor\":null,\"conditionalSuccessor\":null,\"callSuccessor\":null}},\"firstBlockRef\":{\"@type\":\"labelref\",\"fullName\":\"@BEGIN\"},\"sequence\":null,\"dominators\":null,\"loopSet\":null}}"; assertJsonSerialization(program, json, Program.class); } @@ -101,7 +101,7 @@ public class TestIclJson extends TestCase { CompileLog log = new CompileLog(); KickCParser.FileContext file = compiler.pass0ParseInput(new ANTLRInputStream(minProgram), log); Program program = compiler.pass1GenerateSSA(file, log); - String json = "{\"scope\":{\"@type\":\"program\",\"name\":\"\",\"symbols\":{\"s1\":{\"@type\":\"variable_unversioned\",\"name\":\"s1\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"nextVersionNumber\":1,\"inferredType\":false},\"$0\":{\"@type\":\"variable_intermediate\",\"name\":\"$0\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"inferredType\":true},\"s2\":{\"@type\":\"variable_unversioned\",\"name\":\"s2\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"nextVersionNumber\":1,\"inferredType\":false},\"$1\":{\"@type\":\"variable_intermediate\",\"name\":\"$1\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"inferredType\":true},\"sum\":{\"@type\":\"procedure\",\"name\":\"sum\",\"parameterNames\":[\"a\",\"b\"],\"symbols\":{\"@return\":{\"@type\":\"label\",\"name\":\"@return\",\"intermediate\":false},\"return\":{\"@type\":\"variable_unversioned\",\"name\":\"return\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"nextVersionNumber\":7,\"inferredType\":false},\"a\":{\"@type\":\"variable_unversioned\",\"name\":\"a\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"nextVersionNumber\":3,\"inferredType\":false},\"b\":{\"@type\":\"variable_unversioned\",\"name\":\"b\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"nextVersionNumber\":3,\"inferredType\":false},\"$0\":{\"@type\":\"variable_intermediate\",\"name\":\"$0\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"inferredType\":true},\"a#0\":{\"@type\":\"variable_versioned\",\"name\":\"a#0\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"a\",\"inferredType\":false},\"b#0\":{\"@type\":\"variable_versioned\",\"name\":\"b#0\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"b\",\"inferredType\":false},\"return#0\":{\"@type\":\"variable_versioned\",\"name\":\"return#0\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"return\",\"inferredType\":false},\"a#1\":{\"@type\":\"variable_versioned\",\"name\":\"a#1\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"a\",\"inferredType\":false},\"b#1\":{\"@type\":\"variable_versioned\",\"name\":\"b#1\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"b\",\"inferredType\":false},\"return#1\":{\"@type\":\"variable_versioned\",\"name\":\"return#1\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"return\",\"inferredType\":false},\"return#2\":{\"@type\":\"variable_versioned\",\"name\":\"return#2\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"return\",\"inferredType\":false},\"return#3\":{\"@type\":\"variable_versioned\",\"name\":\"return#3\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"return\",\"inferredType\":false},\"return#4\":{\"@type\":\"variable_versioned\",\"name\":\"return#4\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"return\",\"inferredType\":false},\"return#5\":{\"@type\":\"variable_versioned\",\"name\":\"return#5\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"return\",\"inferredType\":false},\"a#2\":{\"@type\":\"variable_versioned\",\"name\":\"a#2\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"a\",\"inferredType\":false},\"b#2\":{\"@type\":\"variable_versioned\",\"name\":\"b#2\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"b\",\"inferredType\":false},\"return#6\":{\"@type\":\"variable_versioned\",\"name\":\"return#6\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"return\",\"inferredType\":false}},\"intermediateVarCount\":1,\"intermediateLabelCount\":2,\"returnType\":{\"@type\":\"basic\",\"typeName\":\"byte\"}},\"@BEGIN\":{\"@type\":\"label\",\"name\":\"@BEGIN\",\"intermediate\":false},\"@END\":{\"@type\":\"label\",\"name\":\"@END\",\"intermediate\":false},\"@2\":{\"@type\":\"label\",\"name\":\"@2\",\"intermediate\":true},\"@3\":{\"@type\":\"label\",\"name\":\"@3\",\"intermediate\":true},\"s1#0\":{\"@type\":\"variable_versioned\",\"name\":\"s1#0\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"s1\",\"inferredType\":false},\"s2#0\":{\"@type\":\"variable_versioned\",\"name\":\"s2#0\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"s2\",\"inferredType\":false}},\"intermediateVarCount\":2,\"intermediateLabelCount\":4,\"allocation\":null,\"liveRanges\":null},\"graph\":{\"blocks\":{\"@BEGIN\":{\"label\":{\"@type\":\"labelref\",\"fullName\":\"@BEGIN\"},\"statements\":[{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"sum::a#0\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"integer\",\"number\":1},\"index\":null},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"sum::b#0\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"integer\",\"number\":2},\"index\":null},{\"@type\":\"call\",\"lValue\":null,\"procedureName\":\"sum\",\"procedure\":{\"@type\":\"procref\",\"fullName\":\"sum\"},\"parameters\":null,\"parametersByAssignment\":true,\"index\":null},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"sum::return#0\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"varref\",\"fullName\":\"sum::return#3\"},\"index\":null}],\"defaultSuccessor\":{\"@type\":\"labelref\",\"fullName\":\"@2\"},\"conditionalSuccessor\":null,\"callSuccessor\":{\"@type\":\"labelref\",\"fullName\":\"sum\"}},\"@2\":{\"label\":{\"@type\":\"labelref\",\"fullName\":\"@2\"},\"statements\":[{\"@type\":\"phiblock\",\"phiVariables\":[{\"variable\":{\"@type\":\"varref\",\"fullName\":\"sum::return#4\"},\"values\":[{\"predecessor\":{\"@type\":\"labelref\",\"fullName\":\"@BEGIN\"},\"rValue\":{\"@type\":\"varref\",\"fullName\":\"sum::return#0\"}}]}],\"index\":null},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"$0\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"varref\",\"fullName\":\"sum::return#4\"},\"index\":null},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"s1#0\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"varref\",\"fullName\":\"$0\"},\"index\":null},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"sum::a#1\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"integer\",\"number\":9},\"index\":null},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"sum::b#1\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"integer\",\"number\":13},\"index\":null},{\"@type\":\"call\",\"lValue\":null,\"procedureName\":\"sum\",\"procedure\":{\"@type\":\"procref\",\"fullName\":\"sum\"},\"parameters\":null,\"parametersByAssignment\":true,\"index\":null},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"sum::return#1\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"varref\",\"fullName\":\"sum::return#3\"},\"index\":null}],\"defaultSuccessor\":{\"@type\":\"labelref\",\"fullName\":\"@3\"},\"conditionalSuccessor\":null,\"callSuccessor\":{\"@type\":\"labelref\",\"fullName\":\"sum\"}},\"@3\":{\"label\":{\"@type\":\"labelref\",\"fullName\":\"@3\"},\"statements\":[{\"@type\":\"phiblock\",\"phiVariables\":[{\"variable\":{\"@type\":\"varref\",\"fullName\":\"sum::return#5\"},\"values\":[{\"predecessor\":{\"@type\":\"labelref\",\"fullName\":\"@2\"},\"rValue\":{\"@type\":\"varref\",\"fullName\":\"sum::return#1\"}}]}],\"index\":null},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"$1\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"varref\",\"fullName\":\"sum::return#5\"},\"index\":null},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"s2#0\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"varref\",\"fullName\":\"$1\"},\"index\":null}],\"defaultSuccessor\":{\"@type\":\"labelref\",\"fullName\":\"@END\"},\"conditionalSuccessor\":null,\"callSuccessor\":null},\"sum\":{\"label\":{\"@type\":\"labelref\",\"fullName\":\"sum\"},\"statements\":[{\"@type\":\"phiblock\",\"phiVariables\":[{\"variable\":{\"@type\":\"varref\",\"fullName\":\"sum::a#2\"},\"values\":[{\"predecessor\":{\"@type\":\"labelref\",\"fullName\":\"@2\"},\"rValue\":{\"@type\":\"varref\",\"fullName\":\"sum::a#1\"}},{\"predecessor\":{\"@type\":\"labelref\",\"fullName\":\"@BEGIN\"},\"rValue\":{\"@type\":\"varref\",\"fullName\":\"sum::a#0\"}}]},{\"variable\":{\"@type\":\"varref\",\"fullName\":\"sum::b#2\"},\"values\":[{\"predecessor\":{\"@type\":\"labelref\",\"fullName\":\"@2\"},\"rValue\":{\"@type\":\"varref\",\"fullName\":\"sum::b#1\"}},{\"predecessor\":{\"@type\":\"labelref\",\"fullName\":\"@BEGIN\"},\"rValue\":{\"@type\":\"varref\",\"fullName\":\"sum::b#0\"}}]}],\"index\":null},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"sum::$0\"},\"rValue1\":{\"@type\":\"varref\",\"fullName\":\"sum::a#2\"},\"operator\":{\"operator\":\"+\"},\"rValue2\":{\"@type\":\"varref\",\"fullName\":\"sum::b#2\"},\"index\":null},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"sum::return#2\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"varref\",\"fullName\":\"sum::$0\"},\"index\":null}],\"defaultSuccessor\":{\"@type\":\"labelref\",\"fullName\":\"sum::@return\"},\"conditionalSuccessor\":null,\"callSuccessor\":null},\"sum::@return\":{\"label\":{\"@type\":\"labelref\",\"fullName\":\"sum::@return\"},\"statements\":[{\"@type\":\"phiblock\",\"phiVariables\":[{\"variable\":{\"@type\":\"varref\",\"fullName\":\"sum::return#6\"},\"values\":[{\"predecessor\":{\"@type\":\"labelref\",\"fullName\":\"sum\"},\"rValue\":{\"@type\":\"varref\",\"fullName\":\"sum::return#2\"}}]}],\"index\":null},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"sum::return#3\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"varref\",\"fullName\":\"sum::return#6\"},\"index\":null},{\"@type\":\"return\",\"value\":{\"@type\":\"varref\",\"fullName\":\"sum::return#3\"},\"index\":null}],\"defaultSuccessor\":{\"@type\":\"labelref\",\"fullName\":\"@RETURN\"},\"conditionalSuccessor\":null,\"callSuccessor\":null},\"@END\":{\"label\":{\"@type\":\"labelref\",\"fullName\":\"@END\"},\"statements\":[],\"defaultSuccessor\":null,\"conditionalSuccessor\":null,\"callSuccessor\":null}},\"firstBlockRef\":{\"@type\":\"labelref\",\"fullName\":\"@BEGIN\"},\"sequence\":null}}"; + String json = "{\"scope\":{\"@type\":\"program\",\"name\":\"\",\"symbols\":{\"s1\":{\"@type\":\"variable_unversioned\",\"name\":\"s1\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"nextVersionNumber\":1,\"inferredType\":false},\"$0\":{\"@type\":\"variable_intermediate\",\"name\":\"$0\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"inferredType\":true},\"s2\":{\"@type\":\"variable_unversioned\",\"name\":\"s2\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"nextVersionNumber\":1,\"inferredType\":false},\"$1\":{\"@type\":\"variable_intermediate\",\"name\":\"$1\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"inferredType\":true},\"sum\":{\"@type\":\"procedure\",\"name\":\"sum\",\"parameterNames\":[\"a\",\"b\"],\"symbols\":{\"@return\":{\"@type\":\"label\",\"name\":\"@return\",\"intermediate\":false},\"return\":{\"@type\":\"variable_unversioned\",\"name\":\"return\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"nextVersionNumber\":7,\"inferredType\":false},\"a\":{\"@type\":\"variable_unversioned\",\"name\":\"a\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"nextVersionNumber\":3,\"inferredType\":false},\"b\":{\"@type\":\"variable_unversioned\",\"name\":\"b\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"nextVersionNumber\":3,\"inferredType\":false},\"$0\":{\"@type\":\"variable_intermediate\",\"name\":\"$0\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"inferredType\":true},\"a#0\":{\"@type\":\"variable_versioned\",\"name\":\"a#0\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"a\",\"inferredType\":false},\"b#0\":{\"@type\":\"variable_versioned\",\"name\":\"b#0\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"b\",\"inferredType\":false},\"return#0\":{\"@type\":\"variable_versioned\",\"name\":\"return#0\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"return\",\"inferredType\":false},\"a#1\":{\"@type\":\"variable_versioned\",\"name\":\"a#1\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"a\",\"inferredType\":false},\"b#1\":{\"@type\":\"variable_versioned\",\"name\":\"b#1\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"b\",\"inferredType\":false},\"return#1\":{\"@type\":\"variable_versioned\",\"name\":\"return#1\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"return\",\"inferredType\":false},\"return#2\":{\"@type\":\"variable_versioned\",\"name\":\"return#2\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"return\",\"inferredType\":false},\"return#3\":{\"@type\":\"variable_versioned\",\"name\":\"return#3\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"return\",\"inferredType\":false},\"return#4\":{\"@type\":\"variable_versioned\",\"name\":\"return#4\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"return\",\"inferredType\":false},\"return#5\":{\"@type\":\"variable_versioned\",\"name\":\"return#5\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"return\",\"inferredType\":false},\"a#2\":{\"@type\":\"variable_versioned\",\"name\":\"a#2\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"a\",\"inferredType\":false},\"b#2\":{\"@type\":\"variable_versioned\",\"name\":\"b#2\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"b\",\"inferredType\":false},\"return#6\":{\"@type\":\"variable_versioned\",\"name\":\"return#6\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"return\",\"inferredType\":false}},\"intermediateVarCount\":1,\"intermediateLabelCount\":2,\"returnType\":{\"@type\":\"basic\",\"typeName\":\"byte\"}},\"@BEGIN\":{\"@type\":\"label\",\"name\":\"@BEGIN\",\"intermediate\":false},\"@END\":{\"@type\":\"label\",\"name\":\"@END\",\"intermediate\":false},\"@2\":{\"@type\":\"label\",\"name\":\"@2\",\"intermediate\":true},\"@3\":{\"@type\":\"label\",\"name\":\"@3\",\"intermediate\":true},\"s1#0\":{\"@type\":\"variable_versioned\",\"name\":\"s1#0\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"s1\",\"inferredType\":false},\"s2#0\":{\"@type\":\"variable_versioned\",\"name\":\"s2#0\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"s2\",\"inferredType\":false}},\"intermediateVarCount\":2,\"intermediateLabelCount\":4,\"allocation\":null,\"liveRanges\":null},\"graph\":{\"blocks\":{\"@BEGIN\":{\"label\":{\"@type\":\"labelref\",\"fullName\":\"@BEGIN\"},\"statements\":[{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"sum::a#0\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"integer\",\"number\":1},\"index\":null},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"sum::b#0\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"integer\",\"number\":2},\"index\":null},{\"@type\":\"call\",\"lValue\":null,\"procedureName\":\"sum\",\"procedure\":{\"@type\":\"procref\",\"fullName\":\"sum\"},\"parameters\":null,\"parametersByAssignment\":true,\"index\":null},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"sum::return#0\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"varref\",\"fullName\":\"sum::return#3\"},\"index\":null}],\"defaultSuccessor\":{\"@type\":\"labelref\",\"fullName\":\"@2\"},\"conditionalSuccessor\":null,\"callSuccessor\":{\"@type\":\"labelref\",\"fullName\":\"sum\"}},\"@2\":{\"label\":{\"@type\":\"labelref\",\"fullName\":\"@2\"},\"statements\":[{\"@type\":\"phiblock\",\"phiVariables\":[{\"variable\":{\"@type\":\"varref\",\"fullName\":\"sum::return#4\"},\"values\":[{\"predecessor\":{\"@type\":\"labelref\",\"fullName\":\"@BEGIN\"},\"rValue\":{\"@type\":\"varref\",\"fullName\":\"sum::return#0\"}}]}],\"index\":null},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"$0\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"varref\",\"fullName\":\"sum::return#4\"},\"index\":null},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"s1#0\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"varref\",\"fullName\":\"$0\"},\"index\":null},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"sum::a#1\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"integer\",\"number\":9},\"index\":null},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"sum::b#1\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"integer\",\"number\":13},\"index\":null},{\"@type\":\"call\",\"lValue\":null,\"procedureName\":\"sum\",\"procedure\":{\"@type\":\"procref\",\"fullName\":\"sum\"},\"parameters\":null,\"parametersByAssignment\":true,\"index\":null},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"sum::return#1\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"varref\",\"fullName\":\"sum::return#3\"},\"index\":null}],\"defaultSuccessor\":{\"@type\":\"labelref\",\"fullName\":\"@3\"},\"conditionalSuccessor\":null,\"callSuccessor\":{\"@type\":\"labelref\",\"fullName\":\"sum\"}},\"@3\":{\"label\":{\"@type\":\"labelref\",\"fullName\":\"@3\"},\"statements\":[{\"@type\":\"phiblock\",\"phiVariables\":[{\"variable\":{\"@type\":\"varref\",\"fullName\":\"sum::return#5\"},\"values\":[{\"predecessor\":{\"@type\":\"labelref\",\"fullName\":\"@2\"},\"rValue\":{\"@type\":\"varref\",\"fullName\":\"sum::return#1\"}}]}],\"index\":null},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"$1\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"varref\",\"fullName\":\"sum::return#5\"},\"index\":null},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"s2#0\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"varref\",\"fullName\":\"$1\"},\"index\":null}],\"defaultSuccessor\":{\"@type\":\"labelref\",\"fullName\":\"@END\"},\"conditionalSuccessor\":null,\"callSuccessor\":null},\"sum\":{\"label\":{\"@type\":\"labelref\",\"fullName\":\"sum\"},\"statements\":[{\"@type\":\"phiblock\",\"phiVariables\":[{\"variable\":{\"@type\":\"varref\",\"fullName\":\"sum::a#2\"},\"values\":[{\"predecessor\":{\"@type\":\"labelref\",\"fullName\":\"@2\"},\"rValue\":{\"@type\":\"varref\",\"fullName\":\"sum::a#1\"}},{\"predecessor\":{\"@type\":\"labelref\",\"fullName\":\"@BEGIN\"},\"rValue\":{\"@type\":\"varref\",\"fullName\":\"sum::a#0\"}}]},{\"variable\":{\"@type\":\"varref\",\"fullName\":\"sum::b#2\"},\"values\":[{\"predecessor\":{\"@type\":\"labelref\",\"fullName\":\"@2\"},\"rValue\":{\"@type\":\"varref\",\"fullName\":\"sum::b#1\"}},{\"predecessor\":{\"@type\":\"labelref\",\"fullName\":\"@BEGIN\"},\"rValue\":{\"@type\":\"varref\",\"fullName\":\"sum::b#0\"}}]}],\"index\":null},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"sum::$0\"},\"rValue1\":{\"@type\":\"varref\",\"fullName\":\"sum::a#2\"},\"operator\":{\"operator\":\"+\"},\"rValue2\":{\"@type\":\"varref\",\"fullName\":\"sum::b#2\"},\"index\":null},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"sum::return#2\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"varref\",\"fullName\":\"sum::$0\"},\"index\":null}],\"defaultSuccessor\":{\"@type\":\"labelref\",\"fullName\":\"sum::@return\"},\"conditionalSuccessor\":null,\"callSuccessor\":null},\"sum::@return\":{\"label\":{\"@type\":\"labelref\",\"fullName\":\"sum::@return\"},\"statements\":[{\"@type\":\"phiblock\",\"phiVariables\":[{\"variable\":{\"@type\":\"varref\",\"fullName\":\"sum::return#6\"},\"values\":[{\"predecessor\":{\"@type\":\"labelref\",\"fullName\":\"sum\"},\"rValue\":{\"@type\":\"varref\",\"fullName\":\"sum::return#2\"}}]}],\"index\":null},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"sum::return#3\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"varref\",\"fullName\":\"sum::return#6\"},\"index\":null},{\"@type\":\"return\",\"value\":{\"@type\":\"varref\",\"fullName\":\"sum::return#3\"},\"index\":null}],\"defaultSuccessor\":{\"@type\":\"labelref\",\"fullName\":\"@RETURN\"},\"conditionalSuccessor\":null,\"callSuccessor\":null},\"@END\":{\"label\":{\"@type\":\"labelref\",\"fullName\":\"@END\"},\"statements\":[],\"defaultSuccessor\":null,\"conditionalSuccessor\":null,\"callSuccessor\":null}},\"firstBlockRef\":{\"@type\":\"labelref\",\"fullName\":\"@BEGIN\"},\"sequence\":null,\"dominators\":null,\"loopSet\":null}}"; assertJsonSerialization(program, json, Program.class); } @@ -112,7 +112,7 @@ public class TestIclJson extends TestCase { CompileLog log = new CompileLog(); KickCParser.FileContext file = compiler.pass0ParseInput(new ANTLRInputStream(minProgram), log); Program program = compiler.pass1GenerateSSA(file, log); - String json = "{\"scope\":{\"@type\":\"program\",\"name\":\"\",\"symbols\":{\"n1\":{\"@type\":\"variable_unversioned\",\"name\":\"n1\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"nextVersionNumber\":4,\"inferredType\":false},\"n2\":{\"@type\":\"variable_unversioned\",\"name\":\"n2\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"nextVersionNumber\":4,\"inferredType\":false},\"i\":{\"@type\":\"variable_unversioned\",\"name\":\"i\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"nextVersionNumber\":4,\"inferredType\":false},\"fib\":{\"@type\":\"variable_unversioned\",\"name\":\"fib\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"nextVersionNumber\":2,\"inferredType\":false},\"@1\":{\"@type\":\"label\",\"name\":\"@1\",\"intermediate\":true},\"@2\":{\"@type\":\"label\",\"name\":\"@2\",\"intermediate\":true},\"$0\":{\"@type\":\"variable_intermediate\",\"name\":\"$0\",\"type\":{\"@type\":\"basic\",\"typeName\":\"boolean\"},\"inferredType\":true},\"$1\":{\"@type\":\"variable_intermediate\",\"name\":\"$1\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"inferredType\":true},\"$2\":{\"@type\":\"variable_intermediate\",\"name\":\"$2\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"inferredType\":true},\"@BEGIN\":{\"@type\":\"label\",\"name\":\"@BEGIN\",\"intermediate\":false},\"@END\":{\"@type\":\"label\",\"name\":\"@END\",\"intermediate\":false},\"n1#0\":{\"@type\":\"variable_versioned\",\"name\":\"n1#0\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"n1\",\"inferredType\":false},\"n2#0\":{\"@type\":\"variable_versioned\",\"name\":\"n2#0\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"n2\",\"inferredType\":false},\"i#0\":{\"@type\":\"variable_versioned\",\"name\":\"i#0\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"i\",\"inferredType\":false},\"fib#0\":{\"@type\":\"variable_versioned\",\"name\":\"fib#0\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"fib\",\"inferredType\":false},\"fib#1\":{\"@type\":\"variable_versioned\",\"name\":\"fib#1\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"fib\",\"inferredType\":false},\"n1#1\":{\"@type\":\"variable_versioned\",\"name\":\"n1#1\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"n1\",\"inferredType\":false},\"n2#1\":{\"@type\":\"variable_versioned\",\"name\":\"n2#1\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"n2\",\"inferredType\":false},\"i#1\":{\"@type\":\"variable_versioned\",\"name\":\"i#1\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"i\",\"inferredType\":false},\"i#2\":{\"@type\":\"variable_versioned\",\"name\":\"i#2\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"i\",\"inferredType\":false},\"n1#2\":{\"@type\":\"variable_versioned\",\"name\":\"n1#2\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"n1\",\"inferredType\":false},\"n2#2\":{\"@type\":\"variable_versioned\",\"name\":\"n2#2\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"n2\",\"inferredType\":false},\"i#3\":{\"@type\":\"variable_versioned\",\"name\":\"i#3\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"i\",\"inferredType\":false},\"n1#3\":{\"@type\":\"variable_versioned\",\"name\":\"n1#3\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"n1\",\"inferredType\":false},\"n2#3\":{\"@type\":\"variable_versioned\",\"name\":\"n2#3\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"n2\",\"inferredType\":false}},\"intermediateVarCount\":3,\"intermediateLabelCount\":7,\"allocation\":null,\"liveRanges\":null},\"graph\":{\"blocks\":{\"@BEGIN\":{\"label\":{\"@type\":\"labelref\",\"fullName\":\"@BEGIN\"},\"statements\":[{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"n1#0\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"integer\",\"number\":0},\"index\":null},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"n2#0\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"integer\",\"number\":1},\"index\":null},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"i#0\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"integer\",\"number\":12},\"index\":null},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"fib#0\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"integer\",\"number\":0},\"index\":null}],\"defaultSuccessor\":{\"@type\":\"labelref\",\"fullName\":\"@1\"},\"conditionalSuccessor\":null,\"callSuccessor\":null},\"@1\":{\"label\":{\"@type\":\"labelref\",\"fullName\":\"@1\"},\"statements\":[{\"@type\":\"phiblock\",\"phiVariables\":[{\"variable\":{\"@type\":\"varref\",\"fullName\":\"i#2\"},\"values\":[{\"predecessor\":{\"@type\":\"labelref\",\"fullName\":\"@2\"},\"rValue\":{\"@type\":\"varref\",\"fullName\":\"i#1\"}},{\"predecessor\":{\"@type\":\"labelref\",\"fullName\":\"@BEGIN\"},\"rValue\":{\"@type\":\"varref\",\"fullName\":\"i#0\"}}]},{\"variable\":{\"@type\":\"varref\",\"fullName\":\"n1#3\"},\"values\":[{\"predecessor\":{\"@type\":\"labelref\",\"fullName\":\"@2\"},\"rValue\":{\"@type\":\"varref\",\"fullName\":\"n1#1\"}},{\"predecessor\":{\"@type\":\"labelref\",\"fullName\":\"@BEGIN\"},\"rValue\":{\"@type\":\"varref\",\"fullName\":\"n1#0\"}}]},{\"variable\":{\"@type\":\"varref\",\"fullName\":\"n2#3\"},\"values\":[{\"predecessor\":{\"@type\":\"labelref\",\"fullName\":\"@2\"},\"rValue\":{\"@type\":\"varref\",\"fullName\":\"n2#1\"}},{\"predecessor\":{\"@type\":\"labelref\",\"fullName\":\"@BEGIN\"},\"rValue\":{\"@type\":\"varref\",\"fullName\":\"n2#0\"}}]}],\"index\":null},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"$0\"},\"rValue1\":{\"@type\":\"varref\",\"fullName\":\"i#2\"},\"operator\":{\"operator\":\">\"},\"rValue2\":{\"@type\":\"integer\",\"number\":0},\"index\":null},{\"@type\":\"cond\",\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"varref\",\"fullName\":\"$0\"},\"destination\":{\"@type\":\"labelref\",\"fullName\":\"@2\"},\"index\":null}],\"defaultSuccessor\":{\"@type\":\"labelref\",\"fullName\":\"@END\"},\"conditionalSuccessor\":{\"@type\":\"labelref\",\"fullName\":\"@2\"},\"callSuccessor\":null},\"@2\":{\"label\":{\"@type\":\"labelref\",\"fullName\":\"@2\"},\"statements\":[{\"@type\":\"phiblock\",\"phiVariables\":[{\"variable\":{\"@type\":\"varref\",\"fullName\":\"n1#2\"},\"values\":[{\"predecessor\":{\"@type\":\"labelref\",\"fullName\":\"@1\"},\"rValue\":{\"@type\":\"varref\",\"fullName\":\"n1#3\"}}]},{\"variable\":{\"@type\":\"varref\",\"fullName\":\"n2#2\"},\"values\":[{\"predecessor\":{\"@type\":\"labelref\",\"fullName\":\"@1\"},\"rValue\":{\"@type\":\"varref\",\"fullName\":\"n2#3\"}}]},{\"variable\":{\"@type\":\"varref\",\"fullName\":\"i#3\"},\"values\":[{\"predecessor\":{\"@type\":\"labelref\",\"fullName\":\"@1\"},\"rValue\":{\"@type\":\"varref\",\"fullName\":\"i#2\"}}]}],\"index\":null},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"$1\"},\"rValue1\":{\"@type\":\"varref\",\"fullName\":\"n1#2\"},\"operator\":{\"operator\":\"+\"},\"rValue2\":{\"@type\":\"varref\",\"fullName\":\"n2#2\"},\"index\":null},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"fib#1\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"varref\",\"fullName\":\"$1\"},\"index\":null},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"n1#1\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"varref\",\"fullName\":\"n2#2\"},\"index\":null},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"n2#1\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"varref\",\"fullName\":\"fib#1\"},\"index\":null},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"$2\"},\"rValue1\":{\"@type\":\"varref\",\"fullName\":\"i#3\"},\"operator\":{\"operator\":\"-\"},\"rValue2\":{\"@type\":\"integer\",\"number\":1},\"index\":null},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"i#1\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"varref\",\"fullName\":\"$2\"},\"index\":null}],\"defaultSuccessor\":{\"@type\":\"labelref\",\"fullName\":\"@1\"},\"conditionalSuccessor\":null,\"callSuccessor\":null},\"@END\":{\"label\":{\"@type\":\"labelref\",\"fullName\":\"@END\"},\"statements\":[],\"defaultSuccessor\":null,\"conditionalSuccessor\":null,\"callSuccessor\":null}},\"firstBlockRef\":{\"@type\":\"labelref\",\"fullName\":\"@BEGIN\"},\"sequence\":null}}"; + String json = "{\"scope\":{\"@type\":\"program\",\"name\":\"\",\"symbols\":{\"n1\":{\"@type\":\"variable_unversioned\",\"name\":\"n1\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"nextVersionNumber\":4,\"inferredType\":false},\"n2\":{\"@type\":\"variable_unversioned\",\"name\":\"n2\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"nextVersionNumber\":4,\"inferredType\":false},\"i\":{\"@type\":\"variable_unversioned\",\"name\":\"i\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"nextVersionNumber\":4,\"inferredType\":false},\"fib\":{\"@type\":\"variable_unversioned\",\"name\":\"fib\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"nextVersionNumber\":2,\"inferredType\":false},\"@1\":{\"@type\":\"label\",\"name\":\"@1\",\"intermediate\":true},\"@2\":{\"@type\":\"label\",\"name\":\"@2\",\"intermediate\":true},\"$0\":{\"@type\":\"variable_intermediate\",\"name\":\"$0\",\"type\":{\"@type\":\"basic\",\"typeName\":\"boolean\"},\"inferredType\":true},\"$1\":{\"@type\":\"variable_intermediate\",\"name\":\"$1\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"inferredType\":true},\"$2\":{\"@type\":\"variable_intermediate\",\"name\":\"$2\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"inferredType\":true},\"@BEGIN\":{\"@type\":\"label\",\"name\":\"@BEGIN\",\"intermediate\":false},\"@END\":{\"@type\":\"label\",\"name\":\"@END\",\"intermediate\":false},\"n1#0\":{\"@type\":\"variable_versioned\",\"name\":\"n1#0\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"n1\",\"inferredType\":false},\"n2#0\":{\"@type\":\"variable_versioned\",\"name\":\"n2#0\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"n2\",\"inferredType\":false},\"i#0\":{\"@type\":\"variable_versioned\",\"name\":\"i#0\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"i\",\"inferredType\":false},\"fib#0\":{\"@type\":\"variable_versioned\",\"name\":\"fib#0\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"fib\",\"inferredType\":false},\"fib#1\":{\"@type\":\"variable_versioned\",\"name\":\"fib#1\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"fib\",\"inferredType\":false},\"n1#1\":{\"@type\":\"variable_versioned\",\"name\":\"n1#1\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"n1\",\"inferredType\":false},\"n2#1\":{\"@type\":\"variable_versioned\",\"name\":\"n2#1\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"n2\",\"inferredType\":false},\"i#1\":{\"@type\":\"variable_versioned\",\"name\":\"i#1\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"i\",\"inferredType\":false},\"i#2\":{\"@type\":\"variable_versioned\",\"name\":\"i#2\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"i\",\"inferredType\":false},\"n1#2\":{\"@type\":\"variable_versioned\",\"name\":\"n1#2\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"n1\",\"inferredType\":false},\"n2#2\":{\"@type\":\"variable_versioned\",\"name\":\"n2#2\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"n2\",\"inferredType\":false},\"i#3\":{\"@type\":\"variable_versioned\",\"name\":\"i#3\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"i\",\"inferredType\":false},\"n1#3\":{\"@type\":\"variable_versioned\",\"name\":\"n1#3\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"n1\",\"inferredType\":false},\"n2#3\":{\"@type\":\"variable_versioned\",\"name\":\"n2#3\",\"type\":{\"@type\":\"basic\",\"typeName\":\"byte\"},\"versionOfName\":\"n2\",\"inferredType\":false}},\"intermediateVarCount\":3,\"intermediateLabelCount\":7,\"allocation\":null,\"liveRanges\":null},\"graph\":{\"blocks\":{\"@BEGIN\":{\"label\":{\"@type\":\"labelref\",\"fullName\":\"@BEGIN\"},\"statements\":[{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"n1#0\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"integer\",\"number\":0},\"index\":null},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"n2#0\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"integer\",\"number\":1},\"index\":null},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"i#0\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"integer\",\"number\":12},\"index\":null},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"fib#0\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"integer\",\"number\":0},\"index\":null}],\"defaultSuccessor\":{\"@type\":\"labelref\",\"fullName\":\"@1\"},\"conditionalSuccessor\":null,\"callSuccessor\":null},\"@1\":{\"label\":{\"@type\":\"labelref\",\"fullName\":\"@1\"},\"statements\":[{\"@type\":\"phiblock\",\"phiVariables\":[{\"variable\":{\"@type\":\"varref\",\"fullName\":\"i#2\"},\"values\":[{\"predecessor\":{\"@type\":\"labelref\",\"fullName\":\"@2\"},\"rValue\":{\"@type\":\"varref\",\"fullName\":\"i#1\"}},{\"predecessor\":{\"@type\":\"labelref\",\"fullName\":\"@BEGIN\"},\"rValue\":{\"@type\":\"varref\",\"fullName\":\"i#0\"}}]},{\"variable\":{\"@type\":\"varref\",\"fullName\":\"n1#3\"},\"values\":[{\"predecessor\":{\"@type\":\"labelref\",\"fullName\":\"@2\"},\"rValue\":{\"@type\":\"varref\",\"fullName\":\"n1#1\"}},{\"predecessor\":{\"@type\":\"labelref\",\"fullName\":\"@BEGIN\"},\"rValue\":{\"@type\":\"varref\",\"fullName\":\"n1#0\"}}]},{\"variable\":{\"@type\":\"varref\",\"fullName\":\"n2#3\"},\"values\":[{\"predecessor\":{\"@type\":\"labelref\",\"fullName\":\"@2\"},\"rValue\":{\"@type\":\"varref\",\"fullName\":\"n2#1\"}},{\"predecessor\":{\"@type\":\"labelref\",\"fullName\":\"@BEGIN\"},\"rValue\":{\"@type\":\"varref\",\"fullName\":\"n2#0\"}}]}],\"index\":null},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"$0\"},\"rValue1\":{\"@type\":\"varref\",\"fullName\":\"i#2\"},\"operator\":{\"operator\":\">\"},\"rValue2\":{\"@type\":\"integer\",\"number\":0},\"index\":null},{\"@type\":\"cond\",\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"varref\",\"fullName\":\"$0\"},\"destination\":{\"@type\":\"labelref\",\"fullName\":\"@2\"},\"index\":null}],\"defaultSuccessor\":{\"@type\":\"labelref\",\"fullName\":\"@END\"},\"conditionalSuccessor\":{\"@type\":\"labelref\",\"fullName\":\"@2\"},\"callSuccessor\":null},\"@2\":{\"label\":{\"@type\":\"labelref\",\"fullName\":\"@2\"},\"statements\":[{\"@type\":\"phiblock\",\"phiVariables\":[{\"variable\":{\"@type\":\"varref\",\"fullName\":\"n1#2\"},\"values\":[{\"predecessor\":{\"@type\":\"labelref\",\"fullName\":\"@1\"},\"rValue\":{\"@type\":\"varref\",\"fullName\":\"n1#3\"}}]},{\"variable\":{\"@type\":\"varref\",\"fullName\":\"n2#2\"},\"values\":[{\"predecessor\":{\"@type\":\"labelref\",\"fullName\":\"@1\"},\"rValue\":{\"@type\":\"varref\",\"fullName\":\"n2#3\"}}]},{\"variable\":{\"@type\":\"varref\",\"fullName\":\"i#3\"},\"values\":[{\"predecessor\":{\"@type\":\"labelref\",\"fullName\":\"@1\"},\"rValue\":{\"@type\":\"varref\",\"fullName\":\"i#2\"}}]}],\"index\":null},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"$1\"},\"rValue1\":{\"@type\":\"varref\",\"fullName\":\"n1#2\"},\"operator\":{\"operator\":\"+\"},\"rValue2\":{\"@type\":\"varref\",\"fullName\":\"n2#2\"},\"index\":null},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"fib#1\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"varref\",\"fullName\":\"$1\"},\"index\":null},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"n1#1\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"varref\",\"fullName\":\"n2#2\"},\"index\":null},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"n2#1\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"varref\",\"fullName\":\"fib#1\"},\"index\":null},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"$2\"},\"rValue1\":{\"@type\":\"varref\",\"fullName\":\"i#3\"},\"operator\":{\"operator\":\"-\"},\"rValue2\":{\"@type\":\"integer\",\"number\":1},\"index\":null},{\"@type\":\"assign\",\"lValue\":{\"@type\":\"varref\",\"fullName\":\"i#1\"},\"rValue1\":null,\"operator\":null,\"rValue2\":{\"@type\":\"varref\",\"fullName\":\"$2\"},\"index\":null}],\"defaultSuccessor\":{\"@type\":\"labelref\",\"fullName\":\"@1\"},\"conditionalSuccessor\":null,\"callSuccessor\":null},\"@END\":{\"label\":{\"@type\":\"labelref\",\"fullName\":\"@END\"},\"statements\":[],\"defaultSuccessor\":null,\"conditionalSuccessor\":null,\"callSuccessor\":null}},\"firstBlockRef\":{\"@type\":\"labelref\",\"fullName\":\"@BEGIN\"},\"sequence\":null,\"dominators\":null,\"loopSet\":null}}"; assertJsonSerialization(program, json, Program.class); } diff --git a/src/dk/camelot64/kickc/test/loopsplit.kc b/src/dk/camelot64/kickc/test/loopsplit.kc new file mode 100644 index 000000000..60cdeccc6 --- /dev/null +++ b/src/dk/camelot64/kickc/test/loopsplit.kc @@ -0,0 +1,9 @@ +byte i=100; +byte s=0; +while(--i>0) { + if(i>50) { + s++; + } else { + s--; + } +} diff --git a/src/dk/camelot64/kickc/test/ref/bresenham.log b/src/dk/camelot64/kickc/test/ref/bresenham.log index f871e3b4c..7c2db8aff 100644 --- a/src/dk/camelot64/kickc/test/ref/bresenham.log +++ b/src/dk/camelot64/kickc/test/ref/bresenham.log @@ -985,6 +985,18 @@ CONTROL FLOW GRAPH - PHI MEM COALESCED [10] (byte) e#2 ← (byte) e#1 - (byte) 39 [ x#1 cursor#2 e#2 y#1 ] to:@3 +DOMINATORS +@BEGIN dominated by @BEGIN +@1 dominated by @1 @BEGIN +@3 dominated by @1 @BEGIN @3 +@END dominated by @1 @BEGIN @3 @END +@2 dominated by @1 @BEGIN @2 + +Found back edge: Loop head: @1 tails: @3 blocks: null +Populated: Loop head: @1 tails: @3 blocks: @3 @1 @2 +NATURAL LOOPS +Loop head: @1 tails: @3 blocks: @3 @1 @2 + Initial phi equivalence classes [ cursor#3 cursor#5 cursor#1 cursor#2 ] [ x#2 x#1 ] diff --git a/src/dk/camelot64/kickc/test/ref/flipper-rex2.log b/src/dk/camelot64/kickc/test/ref/flipper-rex2.log index 0efc447ff..164f9eb81 100644 --- a/src/dk/camelot64/kickc/test/ref/flipper-rex2.log +++ b/src/dk/camelot64/kickc/test/ref/flipper-rex2.log @@ -3733,6 +3733,64 @@ prepare::@return: from prepare::@1 [45] return [ ] to:@RETURN +DOMINATORS +@BEGIN dominated by @BEGIN +@END dominated by @BEGIN @END +main dominated by @BEGIN main +main::@3 dominated by @BEGIN main::@3 main +main::@4 dominated by @BEGIN main::@4 main::@3 main +main::@6 dominated by @BEGIN main::@4 main::@3 main::@6 main +main::@7 dominated by @BEGIN main::@4 main::@3 main::@6 main main::@7 +main::@10 dominated by @BEGIN main::@4 main::@3 main::@6 main main::@7 main::@10 +main::@11 dominated by @BEGIN main::@4 main::@3 main::@6 main main::@7 main::@10 main::@11 +main::@return dominated by @BEGIN main::@4 main::@3 main::@6 main main::@7 main::@return main::@10 main::@11 +plot dominated by @BEGIN main::@4 main::@3 main::@6 plot main main::@7 main::@10 +plot::@1 dominated by @BEGIN main::@4 main::@3 main::@6 main plot main::@7 plot::@1 main::@10 +plot::@2 dominated by @BEGIN main::@4 main::@3 main::@6 main plot main::@7 plot::@2 plot::@1 main::@10 +plot::@3 dominated by @BEGIN main::@4 main::@3 main::@6 main plot main::@7 plot::@2 plot::@1 main::@10 plot::@3 +plot::@return dominated by @BEGIN main::@4 main::@3 plot::@return main::@6 main plot main::@7 plot::@2 plot::@1 main::@10 plot::@3 +flip dominated by @BEGIN main::@4 main::@3 main::@6 main main::@7 flip +flip::@1 dominated by @BEGIN main::@4 main::@3 main::@6 main main::@7 flip::@1 flip +flip::@2 dominated by @BEGIN main::@4 main::@3 main::@6 main main::@7 flip::@1 flip::@2 flip +flip::@4 dominated by flip::@4 @BEGIN main::@4 main::@3 main::@6 main main::@7 flip::@1 flip::@2 flip +flip::@3 dominated by flip::@4 flip::@3 @BEGIN main::@4 main::@3 main::@6 main main::@7 flip::@1 flip::@2 flip +flip::@return dominated by flip::@4 flip::@3 @BEGIN main::@4 main::@3 main::@6 main main::@7 flip::@return flip::@1 flip::@2 flip +prepare dominated by @BEGIN prepare main +prepare::@1 dominated by @BEGIN prepare main prepare::@1 +prepare::@return dominated by @BEGIN prepare::@return prepare main prepare::@1 + +Found back edge: Loop head: main::@3 tails: main::@3 blocks: null +Found back edge: Loop head: main::@4 tails: main::@4 blocks: null +Found back edge: Loop head: main::@3 tails: main::@6 blocks: null +Found back edge: Loop head: main::@3 tails: main::@11 blocks: null +Found back edge: Loop head: plot::@2 tails: plot::@2 blocks: null +Found back edge: Loop head: plot::@1 tails: plot::@3 blocks: null +Found back edge: Loop head: flip::@2 tails: flip::@2 blocks: null +Found back edge: Loop head: flip::@1 tails: flip::@4 blocks: null +Found back edge: Loop head: flip::@3 tails: flip::@3 blocks: null +Found back edge: Loop head: prepare::@1 tails: prepare::@1 blocks: null +Populated: Loop head: main::@3 tails: main::@3 blocks: main::@3 +Populated: Loop head: main::@4 tails: main::@4 blocks: main::@4 +Populated: Loop head: main::@3 tails: main::@6 blocks: main::@6 main::@4 main::@3 +Populated: Loop head: main::@3 tails: main::@11 blocks: main::@11 main::@10 main::@7 main::@6 main::@4 main::@3 +Populated: Loop head: plot::@2 tails: plot::@2 blocks: plot::@2 +Populated: Loop head: plot::@1 tails: plot::@3 blocks: plot::@3 plot::@2 plot::@1 +Populated: Loop head: flip::@2 tails: flip::@2 blocks: flip::@2 +Populated: Loop head: flip::@1 tails: flip::@4 blocks: flip::@4 flip::@2 flip::@1 +Populated: Loop head: flip::@3 tails: flip::@3 blocks: flip::@3 +Populated: Loop head: prepare::@1 tails: prepare::@1 blocks: prepare::@1 +NATURAL LOOPS +Loop head: main::@3 tails: main::@3 blocks: main::@3 +Loop head: main::@4 tails: main::@4 blocks: main::@4 +Loop head: main::@3 tails: main::@6 blocks: main::@6 main::@4 main::@3 +Loop head: main::@3 tails: main::@11 blocks: main::@11 main::@10 main::@7 main::@6 main::@4 main::@3 +Loop head: plot::@2 tails: plot::@2 blocks: plot::@2 +Loop head: plot::@1 tails: plot::@3 blocks: plot::@3 plot::@2 plot::@1 +Loop head: flip::@2 tails: flip::@2 blocks: flip::@2 +Loop head: flip::@1 tails: flip::@4 blocks: flip::@4 flip::@2 flip::@1 +Loop head: flip::@3 tails: flip::@3 blocks: flip::@3 +Loop head: prepare::@1 tails: prepare::@1 blocks: prepare::@1 + Initial phi equivalence classes [ main::c#2 main::c#1 ] [ plot::line#2 plot::line#1 ] diff --git a/src/dk/camelot64/kickc/test/ref/loopmin.log b/src/dk/camelot64/kickc/test/ref/loopmin.log index 86ff0ea4e..11057691d 100644 --- a/src/dk/camelot64/kickc/test/ref/loopmin.log +++ b/src/dk/camelot64/kickc/test/ref/loopmin.log @@ -341,6 +341,18 @@ CONTROL FLOW GRAPH - PHI MEM COALESCED [5] (byte) s#1 ← (byte) s#2 + (byte) i#2 [ i#2 s#1 ] to:@3 +DOMINATORS +@BEGIN dominated by @BEGIN +@1 dominated by @1 @BEGIN +@3 dominated by @1 @BEGIN @3 +@END dominated by @1 @BEGIN @3 @END +@2 dominated by @1 @BEGIN @2 + +Found back edge: Loop head: @1 tails: @3 blocks: null +Populated: Loop head: @1 tails: @3 blocks: @3 @1 @2 +NATURAL LOOPS +Loop head: @1 tails: @3 blocks: @3 @1 @2 + Initial phi equivalence classes [ i#2 i#1 ] [ s#2 s#4 s#1 ] diff --git a/src/dk/camelot64/kickc/test/ref/loopsplit.asm b/src/dk/camelot64/kickc/test/ref/loopsplit.asm new file mode 100644 index 000000000..6011d8315 --- /dev/null +++ b/src/dk/camelot64/kickc/test/ref/loopsplit.asm @@ -0,0 +1,24 @@ +BBEGIN: +B1_from_BBEGIN: + lda #0 + sta 3 + lda #100 + sta 2 +B1: + dec 2 + lda 2 +BEND: +B2: + lda 2 + cmp #50 + beq !+ + bcs B4 +!: +B5: + dec 3 +B1_from_B5: + jmp B1 +B4: + inc 3 +B1_from_B4: + jmp B1 diff --git a/src/dk/camelot64/kickc/test/ref/loopsplit.cfg b/src/dk/camelot64/kickc/test/ref/loopsplit.cfg new file mode 100644 index 000000000..bdb7d9649 --- /dev/null +++ b/src/dk/camelot64/kickc/test/ref/loopsplit.cfg @@ -0,0 +1,18 @@ +@BEGIN: from + to:@1 +@1: from @4 @5 @BEGIN + [0] (byte) s#3 ← phi( @4/(byte) s#1 @5/(byte) s#2 @BEGIN/(byte) 0 ) [ i#2 s#3 ] + [0] (byte) i#2 ← phi( @4/(byte) i#1 @5/(byte) i#1 @BEGIN/(byte) 100 ) [ i#2 s#3 ] + [1] (byte) i#1 ← -- (byte) i#2 [ i#1 s#3 ] + [2] if((byte) i#1>(byte) 0) goto @2 [ i#1 s#3 ] + to:@END +@END: from @1 +@2: from @1 + [3] if((byte) i#1>(byte) 50) goto @4 [ i#1 s#3 ] + to:@5 +@5: from @2 + [4] (byte) s#2 ← -- (byte) s#3 [ i#1 s#2 ] + to:@1 +@4: from @2 + [5] (byte) s#1 ← ++ (byte) s#3 [ i#1 s#1 ] + to:@1 diff --git a/src/dk/camelot64/kickc/test/ref/loopsplit.log b/src/dk/camelot64/kickc/test/ref/loopsplit.log new file mode 100644 index 000000000..94e0fc122 --- /dev/null +++ b/src/dk/camelot64/kickc/test/ref/loopsplit.log @@ -0,0 +1,564 @@ +byte i=100; +byte s=0; +while(--i>0) { + if(i>50) { + s++; + } else { + s--; + } +} + +Adding pre/post-modifier (byte) i ← -- (byte) i +Adding pre/post-modifier (byte) s ← ++ (byte) s +Adding pre/post-modifier (byte) s ← -- (byte) s +PROGRAM + (byte) i ← (byte) 100 + (byte) s ← (byte) 0 +@1: + (byte) i ← -- (byte) i + (boolean~) $0 ← (byte) i > (byte) 0 + if((boolean~) $0) goto @2 + goto @3 +@2: + (boolean~) $1 ← (byte) i > (byte) 50 + if((boolean~) $1) goto @4 + goto @5 +@4: + (byte) s ← ++ (byte) s + goto @6 +@5: + (byte) s ← -- (byte) s +@6: + goto @1 +@3: + +SYMBOLS +(boolean~) $0 +(boolean~) $1 +(label) @1 +(label) @2 +(label) @3 +(label) @4 +(label) @5 +(label) @6 +(byte) i +(byte) s + +INITIAL CONTROL FLOW GRAPH +@BEGIN: from + (byte) i ← (byte) 100 + (byte) s ← (byte) 0 + to:@1 +@1: from @6 @BEGIN + (byte) i ← -- (byte) i + (boolean~) $0 ← (byte) i > (byte) 0 + if((boolean~) $0) goto @2 + to:@7 +@2: from @1 @8 + (boolean~) $1 ← (byte) i > (byte) 50 + if((boolean~) $1) goto @4 + to:@9 +@7: from @1 + to:@3 +@3: from @12 @7 + to:@END +@8: from + to:@2 +@4: from @10 @2 + (byte) s ← ++ (byte) s + to:@6 +@9: from @2 + to:@5 +@5: from @11 @9 + (byte) s ← -- (byte) s + to:@6 +@10: from + to:@4 +@6: from @4 @5 + to:@1 +@11: from + to:@5 +@12: from + to:@3 +@END: from @3 + +Removing empty block @7 +Removing empty block @3 +Removing empty block @8 +Removing empty block @9 +Removing empty block @10 +Removing empty block @6 +Removing empty block @11 +Removing empty block @12 +CONTROL FLOW GRAPH +@BEGIN: from + (byte) i ← (byte) 100 + (byte) s ← (byte) 0 + to:@1 +@1: from @4 @5 @BEGIN + (byte) i ← -- (byte) i + (boolean~) $0 ← (byte) i > (byte) 0 + if((boolean~) $0) goto @2 + to:@END +@2: from @1 + (boolean~) $1 ← (byte) i > (byte) 50 + if((boolean~) $1) goto @4 + to:@5 +@4: from @2 + (byte) s ← ++ (byte) s + to:@1 +@5: from @2 + (byte) s ← -- (byte) s + to:@1 +@END: from @1 + +CONTROL FLOW GRAPH WITH ASSIGNMENT CALL +@BEGIN: from + (byte) i ← (byte) 100 + (byte) s ← (byte) 0 + to:@1 +@1: from @4 @5 @BEGIN + (byte) i ← -- (byte) i + (boolean~) $0 ← (byte) i > (byte) 0 + if((boolean~) $0) goto @2 + to:@END +@2: from @1 + (boolean~) $1 ← (byte) i > (byte) 50 + if((boolean~) $1) goto @4 + to:@5 +@4: from @2 + (byte) s ← ++ (byte) s + to:@1 +@5: from @2 + (byte) s ← -- (byte) s + to:@1 +@END: from @1 + +Completing Phi functions... +Completing Phi functions... +Completing Phi functions... +CONTROL FLOW GRAPH SSA +@BEGIN: from + (byte) i#0 ← (byte) 100 + (byte) s#0 ← (byte) 0 + to:@1 +@1: from @4 @5 @BEGIN + (byte) s#6 ← phi( @4/(byte) s#1 @5/(byte) s#2 @BEGIN/(byte) s#0 ) + (byte) i#2 ← phi( @4/(byte) i#4 @5/(byte) i#5 @BEGIN/(byte) i#0 ) + (byte) i#1 ← -- (byte) i#2 + (boolean~) $0 ← (byte) i#1 > (byte) 0 + if((boolean~) $0) goto @2 + to:@END +@2: from @1 + (byte) s#5 ← phi( @1/(byte) s#6 ) + (byte) i#3 ← phi( @1/(byte) i#1 ) + (boolean~) $1 ← (byte) i#3 > (byte) 50 + if((boolean~) $1) goto @4 + to:@5 +@4: from @2 + (byte) i#4 ← phi( @2/(byte) i#3 ) + (byte) s#3 ← phi( @2/(byte) s#5 ) + (byte) s#1 ← ++ (byte) s#3 + to:@1 +@5: from @2 + (byte) i#5 ← phi( @2/(byte) i#3 ) + (byte) s#4 ← phi( @2/(byte) s#5 ) + (byte) s#2 ← -- (byte) s#4 + to:@1 +@END: from @1 + +CONTROL FLOW GRAPH WITH ASSIGNMENT CALL & RETURN +@BEGIN: from + (byte) i#0 ← (byte) 100 + (byte) s#0 ← (byte) 0 + to:@1 +@1: from @4 @5 @BEGIN + (byte) s#6 ← phi( @4/(byte) s#1 @5/(byte) s#2 @BEGIN/(byte) s#0 ) + (byte) i#2 ← phi( @4/(byte) i#4 @5/(byte) i#5 @BEGIN/(byte) i#0 ) + (byte) i#1 ← -- (byte) i#2 + (boolean~) $0 ← (byte) i#1 > (byte) 0 + if((boolean~) $0) goto @2 + to:@END +@2: from @1 + (byte) s#5 ← phi( @1/(byte) s#6 ) + (byte) i#3 ← phi( @1/(byte) i#1 ) + (boolean~) $1 ← (byte) i#3 > (byte) 50 + if((boolean~) $1) goto @4 + to:@5 +@4: from @2 + (byte) i#4 ← phi( @2/(byte) i#3 ) + (byte) s#3 ← phi( @2/(byte) s#5 ) + (byte) s#1 ← ++ (byte) s#3 + to:@1 +@5: from @2 + (byte) i#5 ← phi( @2/(byte) i#3 ) + (byte) s#4 ← phi( @2/(byte) s#5 ) + (byte) s#2 ← -- (byte) s#4 + to:@1 +@END: from @1 + +Constant (byte) i#0 (byte) 100 +Constant (byte) s#0 (byte) 0 +Succesful SSA optimization Pass2ConstantPropagation +CONTROL FLOW GRAPH +@BEGIN: from + to:@1 +@1: from @4 @5 @BEGIN + (byte) s#6 ← phi( @4/(byte) s#1 @5/(byte) s#2 @BEGIN/(byte) 0 ) + (byte) i#2 ← phi( @4/(byte) i#4 @5/(byte) i#5 @BEGIN/(byte) 100 ) + (byte) i#1 ← -- (byte) i#2 + (boolean~) $0 ← (byte) i#1 > (byte) 0 + if((boolean~) $0) goto @2 + to:@END +@2: from @1 + (byte) s#5 ← phi( @1/(byte) s#6 ) + (byte) i#3 ← phi( @1/(byte) i#1 ) + (boolean~) $1 ← (byte) i#3 > (byte) 50 + if((boolean~) $1) goto @4 + to:@5 +@4: from @2 + (byte) i#4 ← phi( @2/(byte) i#3 ) + (byte) s#3 ← phi( @2/(byte) s#5 ) + (byte) s#1 ← ++ (byte) s#3 + to:@1 +@5: from @2 + (byte) i#5 ← phi( @2/(byte) i#3 ) + (byte) s#4 ← phi( @2/(byte) s#5 ) + (byte) s#2 ← -- (byte) s#4 + to:@1 +@END: from @1 + +Alias (byte) i#1 = (byte) i#3 (byte) i#4 (byte) i#5 +Alias (byte) s#3 = (byte) s#5 (byte) s#6 (byte) s#4 +Succesful SSA optimization Pass2AliasElimination +CONTROL FLOW GRAPH +@BEGIN: from + to:@1 +@1: from @4 @5 @BEGIN + (byte) s#3 ← phi( @4/(byte) s#1 @5/(byte) s#2 @BEGIN/(byte) 0 ) + (byte) i#2 ← phi( @4/(byte) i#1 @5/(byte) i#1 @BEGIN/(byte) 100 ) + (byte) i#1 ← -- (byte) i#2 + (boolean~) $0 ← (byte) i#1 > (byte) 0 + if((boolean~) $0) goto @2 + to:@END +@2: from @1 + (boolean~) $1 ← (byte) i#1 > (byte) 50 + if((boolean~) $1) goto @4 + to:@5 +@4: from @2 + (byte) s#1 ← ++ (byte) s#3 + to:@1 +@5: from @2 + (byte) s#2 ← -- (byte) s#3 + to:@1 +@END: from @1 + +Simple Condition (boolean~) $0 if((byte) i#1>(byte) 0) goto @2 +Simple Condition (boolean~) $1 if((byte) i#1>(byte) 50) goto @4 +Succesful SSA optimization Pass2ConditionalJumpSimplification +CONTROL FLOW GRAPH +@BEGIN: from + to:@1 +@1: from @4 @5 @BEGIN + (byte) s#3 ← phi( @4/(byte) s#1 @5/(byte) s#2 @BEGIN/(byte) 0 ) + (byte) i#2 ← phi( @4/(byte) i#1 @5/(byte) i#1 @BEGIN/(byte) 100 ) + (byte) i#1 ← -- (byte) i#2 + if((byte) i#1>(byte) 0) goto @2 + to:@END +@2: from @1 + if((byte) i#1>(byte) 50) goto @4 + to:@5 +@4: from @2 + (byte) s#1 ← ++ (byte) s#3 + to:@1 +@5: from @2 + (byte) s#2 ← -- (byte) s#3 + to:@1 +@END: from @1 + +Block Sequence Planned @BEGIN @1 @END @2 @5 @4 +Block Sequence Planned @BEGIN @1 @END @2 @5 @4 +CONTROL FLOW GRAPH - PHI LIFTED +@BEGIN: from + to:@1 +@1: from @4 @5 @BEGIN + (byte) s#3 ← phi( @4/(byte~) s#7 @5/(byte~) s#8 @BEGIN/(byte) 0 ) + (byte) i#2 ← phi( @4/(byte~) i#6 @5/(byte~) i#7 @BEGIN/(byte) 100 ) + (byte) i#1 ← -- (byte) i#2 + if((byte) i#1>(byte) 0) goto @2 + to:@END +@END: from @1 +@2: from @1 + if((byte) i#1>(byte) 50) goto @4 + to:@5 +@5: from @2 + (byte) s#2 ← -- (byte) s#3 + (byte~) i#7 ← (byte) i#1 + (byte~) s#8 ← (byte) s#2 + to:@1 +@4: from @2 + (byte) s#1 ← ++ (byte) s#3 + (byte~) i#6 ← (byte) i#1 + (byte~) s#7 ← (byte) s#1 + to:@1 + +Propagating live ranges... +Propagating live ranges... +Propagating live ranges... +Propagating live ranges... +CONTROL FLOW GRAPH - LIVE RANGES +@BEGIN: from + to:@1 +@1: from @4 @5 @BEGIN + [0] (byte) s#3 ← phi( @4/(byte~) s#7 @5/(byte~) s#8 @BEGIN/(byte) 0 ) [ i#2 s#3 ] + [0] (byte) i#2 ← phi( @4/(byte~) i#6 @5/(byte~) i#7 @BEGIN/(byte) 100 ) [ i#2 s#3 ] + [1] (byte) i#1 ← -- (byte) i#2 [ i#1 s#3 ] + [2] if((byte) i#1>(byte) 0) goto @2 [ i#1 s#3 ] + to:@END +@END: from @1 +@2: from @1 + [3] if((byte) i#1>(byte) 50) goto @4 [ i#1 s#3 ] + to:@5 +@5: from @2 + [4] (byte) s#2 ← -- (byte) s#3 [ i#1 s#2 ] + [5] (byte~) i#7 ← (byte) i#1 [ i#7 s#2 ] + [6] (byte~) s#8 ← (byte) s#2 [ i#7 s#8 ] + to:@1 +@4: from @2 + [7] (byte) s#1 ← ++ (byte) s#3 [ i#1 s#1 ] + [8] (byte~) i#6 ← (byte) i#1 [ i#6 s#1 ] + [9] (byte~) s#7 ← (byte) s#1 [ i#6 s#7 ] + to:@1 + +Created 2 initial phi equivalence classes +Coalesced [5] i#7 ← i#1 +Coalesced [6] s#8 ← s#2 +Coalesced (already) [8] i#6 ← i#1 +Coalesced [9] s#7 ← s#1 +Coalesced down to 2 phi equivalence classes +Block Sequence Planned @BEGIN @1 @END @2 @5 @4 +Propagating live ranges... +Propagating live ranges... +Propagating live ranges... +Propagating live ranges... +CONTROL FLOW GRAPH - PHI MEM COALESCED +@BEGIN: from + to:@1 +@1: from @4 @5 @BEGIN + [0] (byte) s#3 ← phi( @4/(byte) s#1 @5/(byte) s#2 @BEGIN/(byte) 0 ) [ i#2 s#3 ] + [0] (byte) i#2 ← phi( @4/(byte) i#1 @5/(byte) i#1 @BEGIN/(byte) 100 ) [ i#2 s#3 ] + [1] (byte) i#1 ← -- (byte) i#2 [ i#1 s#3 ] + [2] if((byte) i#1>(byte) 0) goto @2 [ i#1 s#3 ] + to:@END +@END: from @1 +@2: from @1 + [3] if((byte) i#1>(byte) 50) goto @4 [ i#1 s#3 ] + to:@5 +@5: from @2 + [4] (byte) s#2 ← -- (byte) s#3 [ i#1 s#2 ] + to:@1 +@4: from @2 + [5] (byte) s#1 ← ++ (byte) s#3 [ i#1 s#1 ] + to:@1 + +DOMINATORS +@BEGIN dominated by @BEGIN +@1 dominated by @1 @BEGIN +@END dominated by @1 @BEGIN @END +@2 dominated by @1 @BEGIN @2 +@5 dominated by @1 @BEGIN @2 @5 +@4 dominated by @1 @BEGIN @2 @4 + +Found back edge: Loop head: @1 tails: @5 blocks: null +Found back edge: Loop head: @1 tails: @4 blocks: null +Populated: Loop head: @1 tails: @5 blocks: @5 @2 @1 +Populated: Loop head: @1 tails: @4 blocks: @4 @2 @1 +Coalesced: Loop head: @1 tails: @5 @4 blocks: @5 @2 @1 @4 +NATURAL LOOPS +Loop head: @1 tails: @5 @4 blocks: @5 @2 @1 @4 + +Initial phi equivalence classes +[ i#2 i#1 ] +[ s#3 s#1 s#2 ] +Copy Coalesced equivalence classes +[ i#2 i#1 ] +[ s#3 s#1 s#2 ] +Complete equivalence classes +[ i#2 i#1 ] +[ s#3 s#1 s#2 ] +Allocated zp byte:2 to [ i#2 i#1 ] +Allocated zp byte:3 to [ s#3 s#1 s#2 ] +INITIAL ASM +BBEGIN: +B1_from_BBEGIN: + // (byte) s#3 = (byte) 0 // zpby1=coby1 + lda #0 + sta 3 + // (byte) i#2 = (byte) 100 // zpby1=coby1 + lda #100 + sta 2 + jmp B1 +B1: + // [1] (byte) i#1 ← -- (byte) i#2 [ i#1 s#3 ] // zpby1=_dec_zpby1 + dec 2 + // [2] if((byte) i#1>(byte) 0) goto @2 [ i#1 s#3 ] // zpby1_gt_0_then_la1 + lda 2 + bne B2 + jmp BEND +BEND: +B2: + // [3] if((byte) i#1>(byte) 50) goto @4 [ i#1 s#3 ] // zpby1_gt_coby1_then_la1 + lda 2 + cmp #50 + beq !+ + bcs B4 +!: + jmp B5 +B5: + // [4] (byte) s#2 ← -- (byte) s#3 [ i#1 s#2 ] // zpby1=_dec_zpby1 + dec 3 +B1_from_B5: + // (byte) s#3 = (byte) s#2 // register copy + // (byte) i#2 = (byte) i#1 // register copy + jmp B1 +B4: + // [5] (byte) s#1 ← ++ (byte) s#3 [ i#1 s#1 ] // zpby1=_inc_zpby1 + inc 3 +B1_from_B4: + // (byte) s#3 = (byte) s#1 // register copy + // (byte) i#2 = (byte) i#1 // register copy + jmp B1 + +Removing instruction jmp B1 +Removing instruction jmp BEND +Removing instruction jmp B5 +Succesful ASM optimization Pass5NextJumpElimination +ASSEMBLER +BBEGIN: +B1_from_BBEGIN: + // (byte) s#3 = (byte) 0 // zpby1=coby1 + lda #0 + sta 3 + // (byte) i#2 = (byte) 100 // zpby1=coby1 + lda #100 + sta 2 +B1: + // [1] (byte) i#1 ← -- (byte) i#2 [ i#1 s#3 ] // zpby1=_dec_zpby1 + dec 2 + // [2] if((byte) i#1>(byte) 0) goto @2 [ i#1 s#3 ] // zpby1_gt_0_then_la1 + lda 2 + bne B2 +BEND: +B2: + // [3] if((byte) i#1>(byte) 50) goto @4 [ i#1 s#3 ] // zpby1_gt_coby1_then_la1 + lda 2 + cmp #50 + beq !+ + bcs B4 +!: +B5: + // [4] (byte) s#2 ← -- (byte) s#3 [ i#1 s#2 ] // zpby1=_dec_zpby1 + dec 3 +B1_from_B5: + // (byte) s#3 = (byte) s#2 // register copy + // (byte) i#2 = (byte) i#1 // register copy + jmp B1 +B4: + // [5] (byte) s#1 ← ++ (byte) s#3 [ i#1 s#1 ] // zpby1=_inc_zpby1 + inc 3 +B1_from_B4: + // (byte) s#3 = (byte) s#1 // register copy + // (byte) i#2 = (byte) i#1 // register copy + jmp B1 + +Removing instruction bne B2 +Succesful ASM optimization Pass5NextJumpElimination +ASSEMBLER +BBEGIN: +B1_from_BBEGIN: + // (byte) s#3 = (byte) 0 // zpby1=coby1 + lda #0 + sta 3 + // (byte) i#2 = (byte) 100 // zpby1=coby1 + lda #100 + sta 2 +B1: + // [1] (byte) i#1 ← -- (byte) i#2 [ i#1 s#3 ] // zpby1=_dec_zpby1 + dec 2 + // [2] if((byte) i#1>(byte) 0) goto @2 [ i#1 s#3 ] // zpby1_gt_0_then_la1 + lda 2 +BEND: +B2: + // [3] if((byte) i#1>(byte) 50) goto @4 [ i#1 s#3 ] // zpby1_gt_coby1_then_la1 + lda 2 + cmp #50 + beq !+ + bcs B4 +!: +B5: + // [4] (byte) s#2 ← -- (byte) s#3 [ i#1 s#2 ] // zpby1=_dec_zpby1 + dec 3 +B1_from_B5: + // (byte) s#3 = (byte) s#2 // register copy + // (byte) i#2 = (byte) i#1 // register copy + jmp B1 +B4: + // [5] (byte) s#1 ← ++ (byte) s#3 [ i#1 s#1 ] // zpby1=_inc_zpby1 + inc 3 +B1_from_B4: + // (byte) s#3 = (byte) s#1 // register copy + // (byte) i#2 = (byte) i#1 // register copy + jmp B1 + +FINAL SYMBOL TABLE +(label) @1 +(label) @2 +(label) @4 +(label) @5 +(label) @BEGIN +(label) @END +(byte) i +(byte) i#1 zp byte:2 +(byte) i#2 zp byte:2 +(byte) s +(byte) s#1 zp byte:3 +(byte) s#2 zp byte:3 +(byte) s#3 zp byte:3 + +FINAL CODE +BBEGIN: +B1_from_BBEGIN: + // (byte) s#3 = (byte) 0 // zpby1=coby1 + lda #0 + sta 3 + // (byte) i#2 = (byte) 100 // zpby1=coby1 + lda #100 + sta 2 +B1: + // [1] (byte) i#1 ← -- (byte) i#2 [ i#1 s#3 ] // zpby1=_dec_zpby1 + dec 2 + // [2] if((byte) i#1>(byte) 0) goto @2 [ i#1 s#3 ] // zpby1_gt_0_then_la1 + lda 2 +BEND: +B2: + // [3] if((byte) i#1>(byte) 50) goto @4 [ i#1 s#3 ] // zpby1_gt_coby1_then_la1 + lda 2 + cmp #50 + beq !+ + bcs B4 +!: +B5: + // [4] (byte) s#2 ← -- (byte) s#3 [ i#1 s#2 ] // zpby1=_dec_zpby1 + dec 3 +B1_from_B5: + // (byte) s#3 = (byte) s#2 // register copy + // (byte) i#2 = (byte) i#1 // register copy + jmp B1 +B4: + // [5] (byte) s#1 ← ++ (byte) s#3 [ i#1 s#1 ] // zpby1=_inc_zpby1 + inc 3 +B1_from_B4: + // (byte) s#3 = (byte) s#1 // register copy + // (byte) i#2 = (byte) i#1 // register copy + jmp B1 + diff --git a/src/dk/camelot64/kickc/test/ref/loopsplit.sym b/src/dk/camelot64/kickc/test/ref/loopsplit.sym new file mode 100644 index 000000000..e5ab7c897 --- /dev/null +++ b/src/dk/camelot64/kickc/test/ref/loopsplit.sym @@ -0,0 +1,13 @@ +(label) @1 +(label) @2 +(label) @4 +(label) @5 +(label) @BEGIN +(label) @END +(byte) i +(byte) i#1 zp byte:2 +(byte) i#2 zp byte:2 +(byte) s +(byte) s#1 zp byte:3 +(byte) s#2 zp byte:3 +(byte) s#3 zp byte:3 diff --git a/src/dk/camelot64/kickc/test/ref/minus.log b/src/dk/camelot64/kickc/test/ref/minus.log index 5ffc04bc1..322fdb4c0 100644 --- a/src/dk/camelot64/kickc/test/ref/minus.log +++ b/src/dk/camelot64/kickc/test/ref/minus.log @@ -263,6 +263,16 @@ CONTROL FLOW GRAPH - PHI MEM COALESCED to:@END @END: from @1 +DOMINATORS +@BEGIN dominated by @BEGIN +@1 dominated by @1 @BEGIN +@END dominated by @1 @BEGIN @END + +Found back edge: Loop head: @1 tails: @1 blocks: null +Populated: Loop head: @1 tails: @1 blocks: @1 +NATURAL LOOPS +Loop head: @1 tails: @1 blocks: @1 + Initial phi equivalence classes [ i#2 i#1 ] Copy Coalesced equivalence classes diff --git a/src/dk/camelot64/kickc/test/ref/summin.log b/src/dk/camelot64/kickc/test/ref/summin.log index 6beb42a2c..e7cec26ab 100644 --- a/src/dk/camelot64/kickc/test/ref/summin.log +++ b/src/dk/camelot64/kickc/test/ref/summin.log @@ -298,6 +298,15 @@ sum::@return: from sum [4] return (byte) s1#0 [ ] to:@RETURN +DOMINATORS +@BEGIN dominated by @BEGIN +@2 dominated by @BEGIN @2 +@END dominated by @BEGIN @2 @END +sum dominated by @BEGIN sum +sum::@return dominated by @BEGIN sum::@return sum + +NATURAL LOOPS + Initial phi equivalence classes [ sum::a#2 ] [ sum::b#2 ]