mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-12-22 21:29:50 +00:00
Implemented control flow graph loop analysis.
This commit is contained in:
parent
709cc57a1a
commit
e7ea5fb4ea
@ -110,8 +110,8 @@ public class Compiler {
|
|||||||
log.append(program.getGraph().toString(program.getScope()));
|
log.append(program.getGraph().toString(program.getScope()));
|
||||||
pass2AssertSSA(program, log);
|
pass2AssertSSA(program, log);
|
||||||
|
|
||||||
Pass3IdentifyLiveRanges pass3IdentifyLiveRanges = new Pass3IdentifyLiveRanges(program, log);
|
Pass3LiveRangesAnalysis pass3LiveRangesAnalysis = new Pass3LiveRangesAnalysis(program, log);
|
||||||
pass3IdentifyLiveRanges.findLiveRanges();
|
pass3LiveRangesAnalysis.findLiveRanges();
|
||||||
log.append("CONTROL FLOW GRAPH - LIVE RANGES");
|
log.append("CONTROL FLOW GRAPH - LIVE RANGES");
|
||||||
log.append(program.getGraph().toString(program.getScope()));
|
log.append(program.getGraph().toString(program.getScope()));
|
||||||
pass2AssertSSA(program, log);
|
pass2AssertSSA(program, log);
|
||||||
@ -121,13 +121,20 @@ public class Compiler {
|
|||||||
Pass2CullEmptyBlocks cullEmptyBlocks = new Pass2CullEmptyBlocks(program, log);
|
Pass2CullEmptyBlocks cullEmptyBlocks = new Pass2CullEmptyBlocks(program, log);
|
||||||
cullEmptyBlocks.optimize();
|
cullEmptyBlocks.optimize();
|
||||||
pass3BlockSequencePlanner.plan();
|
pass3BlockSequencePlanner.plan();
|
||||||
pass3IdentifyLiveRanges.findLiveRanges();
|
pass3LiveRangesAnalysis.findLiveRanges();
|
||||||
log.append("CONTROL FLOW GRAPH - PHI MEM COALESCED");
|
log.append("CONTROL FLOW GRAPH - PHI MEM COALESCED");
|
||||||
log.append(program.getGraph().toString(program.getScope()));
|
log.append(program.getGraph().toString(program.getScope()));
|
||||||
pass2AssertSSA(program, log);
|
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 pass3LoopAnalysis = new Pass3LoopAnalysis(program, log);
|
||||||
pass3LoopAnalysis.detectLoops();
|
pass3LoopAnalysis.findLoops();
|
||||||
|
log.append("NATURAL LOOPS");
|
||||||
|
log.append(program.getGraph().getLoopSet().toString());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
|
|||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/** A named/labelled sequence of SSA statements connected to other basic blocks.
|
/** 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<LabelRef> getSuccessors() {
|
||||||
|
List<LabelRef> successors = new ArrayList<>();
|
||||||
|
if(defaultSuccessor!=null) {
|
||||||
|
successors.add(defaultSuccessor);
|
||||||
|
}
|
||||||
|
if(conditionalSuccessor!=null) {
|
||||||
|
successors.add(conditionalSuccessor);
|
||||||
|
}
|
||||||
|
if(callSuccessor!=null) {
|
||||||
|
successors.add(callSuccessor);
|
||||||
|
}
|
||||||
|
return successors;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,8 @@ public class ControlFlowGraph {
|
|||||||
private Map<LabelRef, ControlFlowBlock> blocks;
|
private Map<LabelRef, ControlFlowBlock> blocks;
|
||||||
private LabelRef firstBlockRef;
|
private LabelRef firstBlockRef;
|
||||||
private List<LabelRef> sequence;
|
private List<LabelRef> sequence;
|
||||||
|
private DominatorsGraph dominators;
|
||||||
|
private NaturalLoopSet loopSet;
|
||||||
|
|
||||||
public ControlFlowGraph(Map<LabelRef, ControlFlowBlock> blocks, LabelRef firstBlockRef) {
|
public ControlFlowGraph(Map<LabelRef, ControlFlowBlock> blocks, LabelRef firstBlockRef) {
|
||||||
this.blocks = blocks;
|
this.blocks = blocks;
|
||||||
@ -175,4 +177,20 @@ public class ControlFlowGraph {
|
|||||||
return result;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
100
src/dk/camelot64/kickc/icl/DominatorsBlock.java
Normal file
100
src/dk/camelot64/kickc/icl/DominatorsBlock.java
Normal file
@ -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.
|
||||||
|
* <p>
|
||||||
|
* Definition: Block d dominates block i if all paths from entry to block i includes block d
|
||||||
|
* <p>
|
||||||
|
* 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<LabelRef> 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<LabelRef> 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<LabelRef> 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<LabelRef> 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();
|
||||||
|
}
|
||||||
|
}
|
69
src/dk/camelot64/kickc/icl/DominatorsGraph.java
Normal file
69
src/dk/camelot64/kickc/icl/DominatorsGraph.java
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
package dk.camelot64.kickc.icl;
|
||||||
|
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/** Dominators for a control flow graph.
|
||||||
|
* <p>
|
||||||
|
* Definition: Block d dominates block i if all paths from entry to block i includes block d
|
||||||
|
* <p>
|
||||||
|
* 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<LabelRef, DominatorsBlock> 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();
|
||||||
|
}
|
||||||
|
}
|
@ -66,7 +66,7 @@ public class LiveRange {
|
|||||||
private Integer getIndex(Statement statement) {
|
private Integer getIndex(Statement statement) {
|
||||||
Integer index = statement.getIndex();
|
Integer index = statement.getIndex();
|
||||||
if (index == null) {
|
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;
|
return index;
|
||||||
}
|
}
|
||||||
|
129
src/dk/camelot64/kickc/icl/NaturalLoop.java
Normal file
129
src/dk/camelot64/kickc/icl/NaturalLoop.java
Normal file
@ -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
|
||||||
|
* <code>while(i!=0) { if(i<5) { tail1; } else { tail2; }}</code>
|
||||||
|
*/
|
||||||
|
private Set<LabelRef> tails;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The blocks of the natural loop (including head and tail)
|
||||||
|
*/
|
||||||
|
private Set<LabelRef> 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<LabelRef> getTails() {
|
||||||
|
return tails;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<LabelRef> getBlocks() {
|
||||||
|
return blocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBlocks(Set<LabelRef> 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<LabelRef> tails) {
|
||||||
|
this.tails.addAll(tails);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add more blocks to the loop
|
||||||
|
* @param blocks The blocks to add
|
||||||
|
*/
|
||||||
|
public void addBlocks(Set<LabelRef> 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
80
src/dk/camelot64/kickc/icl/NaturalLoopSet.java
Normal file
80
src/dk/camelot64/kickc/icl/NaturalLoopSet.java
Normal file
@ -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.
|
||||||
|
* <p>For definitions and more see http://www.cs.colostate.edu/~cs553/ClassNotes/lecture09-control-dominators.ppt.pdf
|
||||||
|
* */
|
||||||
|
public class NaturalLoopSet {
|
||||||
|
|
||||||
|
private List<NaturalLoop> 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<NaturalLoop> 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<LabelRef> getLoopHeads() {
|
||||||
|
LinkedHashSet<LabelRef> 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<NaturalLoop> getLoopsFromHead(LabelRef loopHead) {
|
||||||
|
LinkedHashSet<NaturalLoop> 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);
|
||||||
|
}
|
||||||
|
}
|
@ -5,6 +5,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
|||||||
|
|
||||||
/** A KickC Intermediate Compiler Language (ICL) Program */
|
/** A KickC Intermediate Compiler Language (ICL) Program */
|
||||||
public class Program {
|
public class Program {
|
||||||
|
|
||||||
/** The main scope. */
|
/** The main scope. */
|
||||||
private ProgramScope scope;
|
private ProgramScope scope;
|
||||||
/** The control flow graph. */
|
/** The control flow graph. */
|
||||||
|
84
src/dk/camelot64/kickc/passes/Pass3DominatorsAnalysis.java
Normal file
84
src/dk/camelot64/kickc/passes/Pass3DominatorsAnalysis.java
Normal file
@ -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.
|
||||||
|
* <p>
|
||||||
|
* Definition: d dom i if all paths from entry to node i include d
|
||||||
|
* <p>
|
||||||
|
* 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<LabelRef> 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<ControlFlowBlock> 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -11,12 +11,12 @@ import java.util.ArrayList;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class Pass3IdentifyLiveRanges {
|
public class Pass3LiveRangesAnalysis {
|
||||||
|
|
||||||
private final Program program;
|
private final Program program;
|
||||||
private final CompileLog log;
|
private final CompileLog log;
|
||||||
|
|
||||||
public Pass3IdentifyLiveRanges(Program program, CompileLog log) {
|
public Pass3LiveRangesAnalysis(Program program, CompileLog log) {
|
||||||
this.program = program;
|
this.program = program;
|
||||||
this.log = log;
|
this.log = log;
|
||||||
}
|
}
|
@ -1,14 +1,15 @@
|
|||||||
package dk.camelot64.kickc.passes;
|
package dk.camelot64.kickc.passes;
|
||||||
|
|
||||||
import dk.camelot64.kickc.CompileLog;
|
import dk.camelot64.kickc.CompileLog;
|
||||||
import dk.camelot64.kickc.icl.ControlFlowBlock;
|
import dk.camelot64.kickc.icl.*;
|
||||||
import dk.camelot64.kickc.icl.LabelRef;
|
|
||||||
import dk.camelot64.kickc.icl.Program;
|
|
||||||
|
|
||||||
import java.util.*;
|
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.
|
||||||
|
* <p>
|
||||||
|
* See http://www.cs.colostate.edu/~cs553/ClassNotes/lecture09-control-dominators.ppt.pdf
|
||||||
*/
|
*/
|
||||||
public class Pass3LoopAnalysis {
|
public class Pass3LoopAnalysis {
|
||||||
|
|
||||||
@ -28,194 +29,73 @@ public class Pass3LoopAnalysis {
|
|||||||
return log;
|
return log;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void detectLoops() {
|
|
||||||
|
|
||||||
GraphDominators graphDominators = analyseDominators();
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Analyse the control flow graph to find dominators for all blocks.
|
* Finds loops and nested loops in the control flow graph.
|
||||||
* <p>
|
* Uses the dominators of the graph to find loops.
|
||||||
* Definition: d dom i if all paths from entry to node i include d
|
|
||||||
* <p>
|
* <p>
|
||||||
* See http://www.cs.colostate.edu/~cs553/ClassNotes/lecture09-control-dominators.ppt.pdf
|
* See http://www.cs.colostate.edu/~cs553/ClassNotes/lecture09-control-dominators.ppt.pdf
|
||||||
*
|
|
||||||
* @return The graph dominators
|
|
||||||
*/
|
*/
|
||||||
private GraphDominators analyseDominators() {
|
public void findLoops() {
|
||||||
GraphDominators graphDominators = new GraphDominators();
|
DominatorsGraph dominators = program.getGraph().getDominators();
|
||||||
|
Collection<ControlFlowBlock> blocks = program.getGraph().getAllBlocks();
|
||||||
|
|
||||||
// Initialize dominators: Dom[first]={first}, Dom[block]={all}
|
// Look through graph for natural loop back edges
|
||||||
LabelRef firstBlock = program.getGraph().getFirstBlock().getLabel();
|
NaturalLoopSet loopSet = new NaturalLoopSet();
|
||||||
BlockDominators firstDominators = graphDominators.addDominators(firstBlock);
|
for (ControlFlowBlock block : blocks) {
|
||||||
firstDominators.add(firstBlock);
|
DominatorsBlock blockDominators = dominators.getDominators(block.getLabel());
|
||||||
List<LabelRef> allBlocks = new ArrayList<>();
|
for (LabelRef successor : block.getSuccessors()) {
|
||||||
for (ControlFlowBlock block : program.getGraph().getAllBlocks()) {
|
if (blockDominators.contains(successor)) {
|
||||||
allBlocks.add(block.getLabel());
|
// Found a loop back edge!
|
||||||
}
|
NaturalLoop loop = new NaturalLoop(successor, block.getLabel());
|
||||||
for (ControlFlowBlock block : program.getGraph().getAllBlocks()) {
|
log.append("Found back edge: "+loop.toString());
|
||||||
if (!block.getLabel().equals(firstBlock)) {
|
loopSet.addLoop(loop);
|
||||||
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<ControlFlowBlock> 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<LabelRef, BlockDominators> 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<LabelRef> 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<LabelRef> 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<LabelRef> iterator = dominators.iterator();
|
|
||||||
while (iterator.hasNext()) {
|
|
||||||
LabelRef dominator = iterator.next();
|
|
||||||
if (!other.contains(dominator)) {
|
|
||||||
iterator.remove();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// Find all blocks for each loop
|
||||||
* Determines if the dominator set contains a specific block
|
for (NaturalLoop loop : loopSet.getLoops()) {
|
||||||
*
|
Deque<LabelRef> todo = new ArrayDeque<>();
|
||||||
* @param block The block to look for
|
Set<LabelRef> loopBlocks = new LinkedHashSet<>();
|
||||||
* @return true if the dominator set contains the block
|
todo.addAll(loop.getTails());
|
||||||
*/
|
while(!todo.isEmpty()) {
|
||||||
private boolean contains(LabelRef block) {
|
LabelRef block = todo.pop();
|
||||||
return dominators.contains(block);
|
loopBlocks.add(block);
|
||||||
|
if(block.equals(loop.getHead())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ControlFlowBlock controlFlowBlock = program.getGraph().getBlock(block);
|
||||||
|
List<ControlFlowBlock> 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<LabelRef> getDominators() {
|
// Coalesce loops that are neither nested, nor disjoint
|
||||||
return dominators;
|
for (NaturalLoop loop : loopSet.getLoops()) {
|
||||||
}
|
Set<NaturalLoop> headLoops = loopSet.getLoopsFromHead(loop.getHead());
|
||||||
|
for (NaturalLoop other : headLoops) {
|
||||||
@Override
|
if(other.equals(loop)) {
|
||||||
public boolean equals(Object o) {
|
// Same loop - do not process
|
||||||
if (this == o) return true;
|
continue;
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
} else if(loop.nests(other) || other.nests(loop)) {
|
||||||
|
// One of the loops nest the other loop
|
||||||
BlockDominators that = (BlockDominators) o;
|
continue;
|
||||||
|
} else {
|
||||||
return dominators != null ? dominators.equals(that.dominators) : that.dominators == null;
|
// Two non-nested loops with a shared head - collect them to one loop
|
||||||
}
|
loop.addTails(other.getTails());
|
||||||
|
loop.addBlocks(other.getBlocks());
|
||||||
@Override
|
loopSet.remove(other);
|
||||||
public int hashCode() {
|
log.append("Coalesced: "+loop.toString()) ;
|
||||||
return dominators != null ? dominators.hashCode() : 0;
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
program.getGraph().setLoops(loopSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -48,6 +48,11 @@ public class TestCompilationOutput extends TestCase {
|
|||||||
tester.testFile("summin");
|
tester.testFile("summin");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testLoopSplit() throws IOException, URISyntaxException {
|
||||||
|
TestCompilationOutput tester = new TestCompilationOutput();
|
||||||
|
tester.testFile("loopsplit");
|
||||||
|
}
|
||||||
|
|
||||||
private void testFile(String fileName) throws IOException, URISyntaxException {
|
private void testFile(String fileName) throws IOException, URISyntaxException {
|
||||||
String inputPath = testPath + fileName + ".kc";
|
String inputPath = testPath + fileName + ".kc";
|
||||||
System.out.println("Testing output for " + inputPath);
|
System.out.println("Testing output for " + inputPath);
|
||||||
|
File diff suppressed because one or more lines are too long
9
src/dk/camelot64/kickc/test/loopsplit.kc
Normal file
9
src/dk/camelot64/kickc/test/loopsplit.kc
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
byte i=100;
|
||||||
|
byte s=0;
|
||||||
|
while(--i>0) {
|
||||||
|
if(i>50) {
|
||||||
|
s++;
|
||||||
|
} else {
|
||||||
|
s--;
|
||||||
|
}
|
||||||
|
}
|
@ -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 ]
|
[10] (byte) e#2 ← (byte) e#1 - (byte) 39 [ x#1 cursor#2 e#2 y#1 ]
|
||||||
to:@3
|
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
|
Initial phi equivalence classes
|
||||||
[ cursor#3 cursor#5 cursor#1 cursor#2 ]
|
[ cursor#3 cursor#5 cursor#1 cursor#2 ]
|
||||||
[ x#2 x#1 ]
|
[ x#2 x#1 ]
|
||||||
|
@ -3733,6 +3733,64 @@ prepare::@return: from prepare::@1
|
|||||||
[45] return [ ]
|
[45] return [ ]
|
||||||
to:@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
|
Initial phi equivalence classes
|
||||||
[ main::c#2 main::c#1 ]
|
[ main::c#2 main::c#1 ]
|
||||||
[ plot::line#2 plot::line#1 ]
|
[ plot::line#2 plot::line#1 ]
|
||||||
|
@ -341,6 +341,18 @@ CONTROL FLOW GRAPH - PHI MEM COALESCED
|
|||||||
[5] (byte) s#1 ← (byte) s#2 + (byte) i#2 [ i#2 s#1 ]
|
[5] (byte) s#1 ← (byte) s#2 + (byte) i#2 [ i#2 s#1 ]
|
||||||
to:@3
|
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
|
Initial phi equivalence classes
|
||||||
[ i#2 i#1 ]
|
[ i#2 i#1 ]
|
||||||
[ s#2 s#4 s#1 ]
|
[ s#2 s#4 s#1 ]
|
||||||
|
24
src/dk/camelot64/kickc/test/ref/loopsplit.asm
Normal file
24
src/dk/camelot64/kickc/test/ref/loopsplit.asm
Normal file
@ -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
|
18
src/dk/camelot64/kickc/test/ref/loopsplit.cfg
Normal file
18
src/dk/camelot64/kickc/test/ref/loopsplit.cfg
Normal file
@ -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
|
564
src/dk/camelot64/kickc/test/ref/loopsplit.log
Normal file
564
src/dk/camelot64/kickc/test/ref/loopsplit.log
Normal file
@ -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
|
||||||
|
|
13
src/dk/camelot64/kickc/test/ref/loopsplit.sym
Normal file
13
src/dk/camelot64/kickc/test/ref/loopsplit.sym
Normal file
@ -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
|
@ -263,6 +263,16 @@ CONTROL FLOW GRAPH - PHI MEM COALESCED
|
|||||||
to:@END
|
to:@END
|
||||||
@END: from @1
|
@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
|
Initial phi equivalence classes
|
||||||
[ i#2 i#1 ]
|
[ i#2 i#1 ]
|
||||||
Copy Coalesced equivalence classes
|
Copy Coalesced equivalence classes
|
||||||
|
@ -298,6 +298,15 @@ sum::@return: from sum
|
|||||||
[4] return (byte) s1#0 [ ]
|
[4] return (byte) s1#0 [ ]
|
||||||
to:@RETURN
|
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
|
Initial phi equivalence classes
|
||||||
[ sum::a#2 ]
|
[ sum::a#2 ]
|
||||||
[ sum::b#2 ]
|
[ sum::b#2 ]
|
||||||
|
Loading…
Reference in New Issue
Block a user