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()));
|
||||
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());
|
||||
|
||||
}
|
||||
|
||||
|
@ -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<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 LabelRef firstBlockRef;
|
||||
private List<LabelRef> sequence;
|
||||
private DominatorsGraph dominators;
|
||||
private NaturalLoopSet loopSet;
|
||||
|
||||
public ControlFlowGraph(Map<LabelRef, ControlFlowBlock> 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
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) {
|
||||
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;
|
||||
}
|
||||
|
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 */
|
||||
public class Program {
|
||||
|
||||
/** The main scope. */
|
||||
private ProgramScope scope;
|
||||
/** 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.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;
|
||||
}
|
@ -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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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<ControlFlowBlock> 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<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)) {
|
||||
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();
|
||||
// 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<LabelRef> todo = new ArrayDeque<>();
|
||||
Set<LabelRef> 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<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() {
|
||||
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<NaturalLoop> 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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
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 ]
|
||||
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 ]
|
||||
|
@ -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 ]
|
||||
|
@ -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 ]
|
||||
|
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
|
||||
@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
|
||||
|
@ -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 ]
|
||||
|
Loading…
Reference in New Issue
Block a user