mirror of
https://gitlab.com/camelot/kickc.git
synced 2025-01-11 04:29:53 +00:00
Implemented loop depth analysis pass.
This commit is contained in:
parent
d1a13402fe
commit
007a5d34b4
@ -47,8 +47,8 @@ public class CallGraph {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CallBlock getFirstCallBlock() {
|
public LabelRef getFirstCallBlock() {
|
||||||
return getOrCreateCallBlock(new LabelRef(""));
|
return new LabelRef("");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -65,6 +65,21 @@ public class CallGraph {
|
|||||||
return called;
|
return called;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all call blocks that call a specific call block
|
||||||
|
* @param scopeLabel The label of scope (the call block)
|
||||||
|
* @return The scope labels of call blocks that call the passed block
|
||||||
|
*/
|
||||||
|
public Collection<LabelRef> getCallingBlocks(LabelRef scopeLabel) {
|
||||||
|
ArrayList<LabelRef> callingBlocks = new ArrayList<>();
|
||||||
|
for (CallBlock callBlock : callBlocks) {
|
||||||
|
if(callBlock.getCalledBlocks().contains(scopeLabel)) {
|
||||||
|
callingBlocks.add(callBlock.getScopeLabel());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return callingBlocks;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder out = new StringBuilder();
|
StringBuilder out = new StringBuilder();
|
||||||
@ -110,7 +125,6 @@ public class CallGraph {
|
|||||||
called.add(call.getProcedure());
|
called.add(call.getProcedure());
|
||||||
}
|
}
|
||||||
return called;
|
return called;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -123,6 +137,29 @@ public class CallGraph {
|
|||||||
return out.toString();
|
return out.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all calls
|
||||||
|
* @return The calls
|
||||||
|
*/
|
||||||
|
public List<Call> getCalls() {
|
||||||
|
return calls;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all calls to a specific call block
|
||||||
|
* @param scope The scope label of the block
|
||||||
|
* @return All calls to the passed scope
|
||||||
|
*/
|
||||||
|
public Collection<Call> getCalls(LabelRef scope) {
|
||||||
|
ArrayList<Call> callsToScope = new ArrayList<>();
|
||||||
|
for (Call call : calls) {
|
||||||
|
if(call.getProcedure().equals(scope)) {
|
||||||
|
callsToScope.add(call);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return callsToScope;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A single call found in the call block.
|
* A single call found in the call block.
|
||||||
*/
|
*/
|
||||||
|
@ -155,6 +155,41 @@ public class ControlFlowGraph {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CallGraph getCallGraph() {
|
||||||
|
return callGraph;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCallGraph(CallGraph callGraph) {
|
||||||
|
this.callGraph = callGraph;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ControlFlowBlock getBlockFromStatementIdx(int statementIdx) {
|
||||||
|
for (ControlFlowBlock block : getAllBlocks()) {
|
||||||
|
for (Statement statement : block.getStatements()) {
|
||||||
|
if(statementIdx==statement.getIndex()) {
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public String toString(ProgramScope scope) {
|
public String toString(ProgramScope scope) {
|
||||||
StringBuffer out = new StringBuffer();
|
StringBuffer out = new StringBuffer();
|
||||||
for (ControlFlowBlock block : getAllBlocks()) {
|
for (ControlFlowBlock block : getAllBlocks()) {
|
||||||
@ -183,28 +218,4 @@ 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CallGraph getCallGraph() {
|
|
||||||
return callGraph;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCallGraph(CallGraph callGraph) {
|
|
||||||
this.callGraph = callGraph;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,9 @@ public class NaturalLoop {
|
|||||||
*/
|
*/
|
||||||
private Set<LabelRef> blocks;
|
private Set<LabelRef> blocks;
|
||||||
|
|
||||||
|
/** The loop nesting depth of the loop. Calculated by {@link dk.camelot64.kickc.passes.Pass3LoopDepthAnalysis}. */
|
||||||
|
private Integer depth;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new natural loop.
|
* Create a new natural loop.
|
||||||
* The loop is not filled with all blocks from the start, but only holds the head & tail.
|
* The loop is not filled with all blocks from the start, but only holds the head & tail.
|
||||||
@ -72,6 +75,9 @@ public class NaturalLoop {
|
|||||||
} else {
|
} else {
|
||||||
out.append("null");
|
out.append("null");
|
||||||
}
|
}
|
||||||
|
if(depth!=null) {
|
||||||
|
out.append(" depth: "+depth);
|
||||||
|
}
|
||||||
return out.toString();
|
return out.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,6 +112,14 @@ public class NaturalLoop {
|
|||||||
this.blocks.addAll(blocks);
|
this.blocks.addAll(blocks);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Integer getDepth() {
|
||||||
|
return depth;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDepth(Integer depth) {
|
||||||
|
this.depth = depth;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
package dk.camelot64.kickc.icl;
|
package dk.camelot64.kickc.icl;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.LinkedHashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/** A set of natural loops in a control flow graph.
|
/** 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
|
* <p>For definitions and more see http://www.cs.colostate.edu/~cs553/ClassNotes/lecture09-control-dominators.ppt.pdf
|
||||||
@ -71,6 +68,26 @@ public class NaturalLoopSet {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all loops containing a specific control flow graph block
|
||||||
|
*
|
||||||
|
* @param block The block to look for
|
||||||
|
* @return All loops containing the block
|
||||||
|
*/
|
||||||
|
public Collection<NaturalLoop> getLoopsContainingBlock(LabelRef block) {
|
||||||
|
ArrayList<NaturalLoop> containing = new ArrayList<>();
|
||||||
|
for (NaturalLoop loop : loops) {
|
||||||
|
for (LabelRef loopBlock : loop.getBlocks()) {
|
||||||
|
if(block.equals(loopBlock)) {
|
||||||
|
containing.add(loop);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return containing;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove a loop from the set
|
* Remove a loop from the set
|
||||||
* @param loop The loop to remove
|
* @param loop The loop to remove
|
||||||
@ -78,4 +95,5 @@ public class NaturalLoopSet {
|
|||||||
public void remove(NaturalLoop loop) {
|
public void remove(NaturalLoop loop) {
|
||||||
this.loops.remove(loop);
|
this.loops.remove(loop);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -35,12 +35,94 @@ public class Pass3LoopDepthAnalysis {
|
|||||||
CallGraph callGraph = program.getGraph().getCallGraph();
|
CallGraph callGraph = program.getGraph().getCallGraph();
|
||||||
NaturalLoopSet loopSet = program.getGraph().getLoopSet();
|
NaturalLoopSet loopSet = program.getGraph().getLoopSet();
|
||||||
|
|
||||||
|
Deque<LabelRef> todo = new ArrayDeque<>();
|
||||||
|
Set<LabelRef> done = new LinkedHashSet<>();
|
||||||
|
todo.push(callGraph.getFirstCallBlock());
|
||||||
|
while(!todo.isEmpty()) {
|
||||||
|
LabelRef currentScope = todo.pop();
|
||||||
|
done.add(currentScope);
|
||||||
|
CallGraph.CallBlock currentCallBlock = callGraph.getOrCreateCallBlock(currentScope);
|
||||||
|
// Add called sub blocks for later processing
|
||||||
|
Collection<LabelRef> subBlocks = currentCallBlock.getCalledBlocks();
|
||||||
|
for (LabelRef subBlock : subBlocks) {
|
||||||
|
if (!done.contains(subBlock) && !todo.contains(subBlock)) {
|
||||||
|
todo.add(subBlock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Find the scope blocks calling the current scope block - and the loop depth of the blocks where the call statement is
|
||||||
|
int callingDepth = 1;
|
||||||
|
Collection<LabelRef> callingScopes = callGraph.getCallingBlocks(currentScope);
|
||||||
|
for (LabelRef callingScope : callingScopes) {
|
||||||
|
CallGraph.CallBlock callingBlock = callGraph.getOrCreateCallBlock(callingScope);
|
||||||
|
Collection<CallGraph.CallBlock.Call> calls = callingBlock.getCalls(currentScope);
|
||||||
|
for (CallGraph.CallBlock.Call call : calls) {
|
||||||
|
int callStatementIdx = call.getCallStatementIdx();
|
||||||
|
ControlFlowBlock callingControlBlock = program.getGraph().getBlockFromStatementIdx(callStatementIdx);
|
||||||
|
Collection<NaturalLoop> callingLoops = loopSet.getLoopsContainingBlock(callingControlBlock.getLabel());
|
||||||
|
for (NaturalLoop callingLoop : callingLoops) {
|
||||||
|
int potentialDepth = callingLoop.getDepth()+1;
|
||||||
|
if(potentialDepth >callingDepth) {
|
||||||
|
callingDepth = potentialDepth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
findLoopDepth(currentScope, callingDepth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void findLoopDepth(LabelRef currentScope, int initialDepth) {
|
||||||
|
NaturalLoopSet loopSet = program.getGraph().getLoopSet();
|
||||||
|
// Find loops in the current scope block
|
||||||
|
List<NaturalLoop> currentScopeLoops = new ArrayList<>();
|
||||||
|
for (NaturalLoop loop : loopSet.getLoops()) {
|
||||||
|
LabelRef loopHead = loop.getHead();
|
||||||
|
ControlFlowBlock loopHeadBlock = program.getGraph().getBlock(loopHead);
|
||||||
|
LabelRef scopeRef = Pass3CallGraphAnalysis.getScopeRef(loopHeadBlock, program);
|
||||||
|
if(scopeRef.equals(currentScope)) {
|
||||||
|
// Loop is inside current scope block!
|
||||||
|
currentScopeLoops.add(loop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.append("Found "+currentScopeLoops.size()+" loops in scope ["+currentScope.toString()+"]");
|
||||||
|
for (NaturalLoop loop : currentScopeLoops) {
|
||||||
|
log.append(" "+loop.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find loop nesting depths in current scope loops
|
||||||
|
Deque<NaturalLoop> todo = new ArrayDeque<>();
|
||||||
|
Set<NaturalLoop> done = new LinkedHashSet<>();
|
||||||
|
todo.addAll(currentScopeLoops);
|
||||||
|
while(!todo.isEmpty()) {
|
||||||
|
NaturalLoop loop = todo.getFirst();
|
||||||
|
todo.removeFirst();
|
||||||
|
// Does any unprocessed loop nest this one?
|
||||||
|
boolean postpone = false;
|
||||||
|
for (NaturalLoop otherLoop : todo) {
|
||||||
|
if(otherLoop.nests(loop)) {
|
||||||
|
// postpone this loop and move on
|
||||||
|
postpone = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(postpone) {
|
||||||
|
todo.addLast(loop);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int depth = initialDepth;
|
||||||
|
// Does any already processed loop nest this one?
|
||||||
|
for (NaturalLoop otherLoop : done) {
|
||||||
|
if(otherLoop.nests(loop)) {
|
||||||
|
int potentialDepth = otherLoop.getDepth()+1;
|
||||||
|
if(potentialDepth>depth) {
|
||||||
|
depth = potentialDepth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loop.setDepth(depth);
|
||||||
|
done.add(loop);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
File diff suppressed because one or more lines are too long
@ -999,6 +999,11 @@ Populated: Loop head: @1 tails: @3 blocks: @3 @1 @2
|
|||||||
NATURAL LOOPS
|
NATURAL LOOPS
|
||||||
Loop head: @1 tails: @3 blocks: @3 @1 @2
|
Loop head: @1 tails: @3 blocks: @3 @1 @2
|
||||||
|
|
||||||
|
Found 1 loops in scope []
|
||||||
|
Loop head: @1 tails: @3 blocks: @3 @1 @2
|
||||||
|
NATURAL LOOPS WITH DEPTH
|
||||||
|
Loop head: @1 tails: @3 blocks: @3 @1 @2 depth: 1
|
||||||
|
|
||||||
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 ]
|
||||||
|
@ -3795,6 +3795,33 @@ 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: flip::@3 tails: flip::@3 blocks: flip::@3
|
||||||
Loop head: prepare::@1 tails: prepare::@1 blocks: prepare::@1
|
Loop head: prepare::@1 tails: prepare::@1 blocks: prepare::@1
|
||||||
|
|
||||||
|
Found 0 loops in scope []
|
||||||
|
Found 4 loops in scope [main]
|
||||||
|
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
|
||||||
|
Found 1 loops in scope [prepare]
|
||||||
|
Loop head: prepare::@1 tails: prepare::@1 blocks: prepare::@1
|
||||||
|
Found 3 loops in scope [flip]
|
||||||
|
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
|
||||||
|
Found 2 loops in scope [plot]
|
||||||
|
Loop head: plot::@2 tails: plot::@2 blocks: plot::@2
|
||||||
|
Loop head: plot::@1 tails: plot::@3 blocks: plot::@3 plot::@2 plot::@1
|
||||||
|
NATURAL LOOPS WITH DEPTH
|
||||||
|
Loop head: main::@3 tails: main::@3 blocks: main::@3 depth: 3
|
||||||
|
Loop head: main::@4 tails: main::@4 blocks: main::@4 depth: 3
|
||||||
|
Loop head: main::@3 tails: main::@6 blocks: main::@6 main::@4 main::@3 depth: 2
|
||||||
|
Loop head: main::@3 tails: main::@11 blocks: main::@11 main::@10 main::@7 main::@6 main::@4 main::@3 depth: 1
|
||||||
|
Loop head: plot::@2 tails: plot::@2 blocks: plot::@2 depth: 3
|
||||||
|
Loop head: plot::@1 tails: plot::@3 blocks: plot::@3 plot::@2 plot::@1 depth: 2
|
||||||
|
Loop head: flip::@2 tails: flip::@2 blocks: flip::@2 depth: 3
|
||||||
|
Loop head: flip::@1 tails: flip::@4 blocks: flip::@4 flip::@2 flip::@1 depth: 2
|
||||||
|
Loop head: flip::@3 tails: flip::@3 blocks: flip::@3 depth: 2
|
||||||
|
Loop head: prepare::@1 tails: prepare::@1 blocks: prepare::@1 depth: 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 ]
|
||||||
|
@ -355,6 +355,11 @@ Populated: Loop head: @1 tails: @3 blocks: @3 @1 @2
|
|||||||
NATURAL LOOPS
|
NATURAL LOOPS
|
||||||
Loop head: @1 tails: @3 blocks: @3 @1 @2
|
Loop head: @1 tails: @3 blocks: @3 @1 @2
|
||||||
|
|
||||||
|
Found 1 loops in scope []
|
||||||
|
Loop head: @1 tails: @3 blocks: @3 @1 @2
|
||||||
|
NATURAL LOOPS WITH DEPTH
|
||||||
|
Loop head: @1 tails: @3 blocks: @3 @1 @2 depth: 1
|
||||||
|
|
||||||
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 ]
|
||||||
|
@ -379,6 +379,11 @@ Coalesced: Loop head: @1 tails: @5 @4 blocks: @5 @2 @1 @4
|
|||||||
NATURAL LOOPS
|
NATURAL LOOPS
|
||||||
Loop head: @1 tails: @5 @4 blocks: @5 @2 @1 @4
|
Loop head: @1 tails: @5 @4 blocks: @5 @2 @1 @4
|
||||||
|
|
||||||
|
Found 1 loops in scope []
|
||||||
|
Loop head: @1 tails: @5 @4 blocks: @5 @2 @1 @4
|
||||||
|
NATURAL LOOPS WITH DEPTH
|
||||||
|
Loop head: @1 tails: @5 @4 blocks: @5 @2 @1 @4 depth: 1
|
||||||
|
|
||||||
Initial phi equivalence classes
|
Initial phi equivalence classes
|
||||||
[ i#2 i#1 ]
|
[ i#2 i#1 ]
|
||||||
[ s#3 s#1 s#2 ]
|
[ s#3 s#1 s#2 ]
|
||||||
|
@ -275,6 +275,11 @@ Populated: Loop head: @1 tails: @1 blocks: @1
|
|||||||
NATURAL LOOPS
|
NATURAL LOOPS
|
||||||
Loop head: @1 tails: @1 blocks: @1
|
Loop head: @1 tails: @1 blocks: @1
|
||||||
|
|
||||||
|
Found 1 loops in scope []
|
||||||
|
Loop head: @1 tails: @1 blocks: @1
|
||||||
|
NATURAL LOOPS WITH DEPTH
|
||||||
|
Loop head: @1 tails: @1 blocks: @1 depth: 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
|
||||||
|
@ -310,6 +310,10 @@ sum::@return dominated by @BEGIN sum::@return sum
|
|||||||
|
|
||||||
NATURAL LOOPS
|
NATURAL LOOPS
|
||||||
|
|
||||||
|
Found 0 loops in scope []
|
||||||
|
Found 0 loops in scope [sum]
|
||||||
|
NATURAL LOOPS WITH DEPTH
|
||||||
|
|
||||||
Initial phi equivalence classes
|
Initial phi equivalence classes
|
||||||
[ sum::a#2 ]
|
[ sum::a#2 ]
|
||||||
[ sum::b#2 ]
|
[ sum::b#2 ]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user