Further attempts to get node splitting work

This commit is contained in:
Alexey Andreev 2015-03-03 12:55:54 +04:00
parent b6df37115f
commit 043d6f587f
4 changed files with 89 additions and 34 deletions

View File

@ -122,6 +122,9 @@ public final class GraphUtils {
while (!stack.isEmpty()) {
int node = stack.pop();
if (visitIndex[node] > 0) {
if (headerIndex[node] > 0) {
continue;
}
currentComponent.add(node);
int hdr = visitIndex[node];
for (int successor : graph.outgoingEdges(node)) {

View File

@ -147,11 +147,11 @@ public class DJGraph {
}
public boolean isBackJoin(int i, int j) {
return isJoinEdge(i, j) && !domTree.dominates(mergeRoot[j], mergeRoot[i]);
return isJoinEdge(i, j) && domTree.dominates(mergeRoot[j], mergeRoot[i]);
}
public boolean isCrossJoin(int i, int j) {
return isJoinEdge(i, j) && domTree.dominates(mergeRoot[j], mergeRoot[i]);
return isJoinEdge(i, j) && !domTree.dominates(mergeRoot[j], mergeRoot[i]);
}
public boolean isSpanningBack(int i, int j) {
@ -200,7 +200,7 @@ public class DJGraph {
return mergeRoot[node];
}
public void collapse(int[] nodes) {
public int collapse(int[] nodes) {
// Replace nodes with their classes and find common dominator among them
IntSet set = new IntOpenHashSet();
int top = nodes[0];
@ -244,5 +244,6 @@ public class DJGraph {
cfg.detachNode(node.value);
}
}
return top;
}
}

View File

@ -30,6 +30,7 @@ import org.teavm.common.*;
*/
public class IrreducibleGraphConverter {
private Graph cfg;
private int totalNodeCount;
private GraphSplittingBackend backend;
public void convertToReducible(Graph cfg, int[] weight, GraphSplittingBackend backend) {
@ -39,6 +40,7 @@ public class IrreducibleGraphConverter {
identityNodeMap[i] = new int[] { i };
}
this.cfg = cfg;
totalNodeCount = cfg.size();
handleLoops(new DJGraph(cfg, weight), identityNodeMap);
this.backend = null;
}
@ -46,23 +48,34 @@ public class IrreducibleGraphConverter {
private void handleLoops(DJGraph djGraph, int[][] nodeMap) {
for (int level = djGraph.levelCount() - 1; level >= 0; --level) {
boolean irreducible = false;
levelScan:
for (int node : djGraph.level(level)) {
for (int pred : djGraph.getGraph().incomingEdges(node)) {
if (djGraph.isCrossJoin(pred, node)) {
if (!irreducible && djGraph.isSpanningBack(node, pred)) {
irreducible = true;
}
} else if (djGraph.isBackJoin(node, pred)) {
djGraph.collapse(reachUnder(djGraph, pred, node));
if (djGraph.isCrossJoin(pred, node) && djGraph.isSpanningBack(node, pred)) {
irreducible = true;
break levelScan;
}
}
}
DJGraphNodeFilter filter = new DJGraphNodeFilter(djGraph, level);
int[][] sccs = GraphUtils.findStronglyConnectedComponents(djGraph.getGraph(), djGraph.level(level), filter);
for (int[] scc : sccs) {
if (scc.length > 1) {
handleStronglyConnectedComponent(djGraph, scc, nodeMap);
djGraph.collapse(scc);
if (irreducible) {
DJGraphNodeFilter filter = new DJGraphNodeFilter(djGraph, level);
int[][] sccs = GraphUtils.findStronglyConnectedComponents(djGraph.getGraph(),
djGraph.level(level), filter);
for (int[] scc : sccs) {
if (scc.length > 1) {
handleStronglyConnectedComponent(djGraph, scc, nodeMap);
int cls = djGraph.collapse(scc);
IntegerArray nodes = new IntegerArray(djGraph.getGraph().size());
for (int representative : djGraph.classRepresentatives(cls)) {
for (int node : nodeMap[representative]) {
nodes.add(node);
}
}
for (int representative : djGraph.classRepresentatives(cls)) {
nodeMap[representative] = new int[0];
}
nodeMap[cls] = nodes.getAll();
}
}
}
}
@ -93,14 +106,16 @@ public class IrreducibleGraphConverter {
// Partition SCC into domains
DisjointSet partitions = new DisjointSet();
int[] sccBack = new int[djGraph.getGraph().size()];
for (int i = 0; i < scc.length; ++i) {
partitions.create();
sccBack[scc[i]] = i;
}
for (int i = 0; i < scc.length; ++i) {
int node = scc[i];
int idom = djGraph.getDomTree().immediateDominatorOf(node);
if (idom != sharedDom) {
partitions.union(node, idom);
partitions.union(i, sccBack[idom]);
}
}
int[] domains = partitions.pack(scc.length);
@ -110,10 +125,10 @@ public class IrreducibleGraphConverter {
}
// For each domain calculate its weight
int[] domainWeight = new int [domainCount];
int[] domainWeight = new int[domainCount];
for (int i = 0; i < scc.length; ++i) {
int node = scc[i];
domainWeight[domains[node]] += djGraph.weightOf(node);
domainWeight[domains[i]] += djGraph.weightOf(node);
}
// Find domain to split around
@ -130,7 +145,7 @@ public class IrreducibleGraphConverter {
IntSet domainNodes = new IntOpenHashSet(scc.length);
for (int i = 0; i < scc.length; ++i) {
int node = scc[i];
if (domains[node] == domain) {
if (domains[i] == domain) {
domainNodes.add(node);
}
}
@ -144,6 +159,7 @@ public class IrreducibleGraphConverter {
private void splitStronglyConnectedComponent(DJGraph djGraph, IntSet domain, int sharedDom,
int[] scc, int[][] nodeMap) {
Arrays.sort(scc);
// Find SCC \ domain
int[][] mappedNonDomain = new int[scc.length - domain.size()][];
int[] domainNodes = new int[domain.size()];
@ -166,10 +182,13 @@ public class IrreducibleGraphConverter {
// Delegate splitting to domain
int[][] newNodes = backend.split(mappedDomain, mappedNonDomain);
for (int[] nodes : newNodes) {
totalNodeCount += nodes.length;
}
// Calculate mappings
int[][] newNodeMap = new int[1 + scc.length + newNodes.length][];
int[] newNodeBackMap = new int[cfg.size()];
int[] newNodeBackMap = new int[totalNodeCount];
int[] mappedWeight = new int[newNodeMap.length];
Arrays.fill(newNodeBackMap, -1);
newNodeMap[0] = nodeMap[sharedDom];
@ -203,12 +222,12 @@ public class IrreducibleGraphConverter {
}
}
for (int i = 1; i <= mappedDomain.length; ++i) {
for (int succ : djGraph.getCfg().outgoingEdges(domainNodes[i])) {
for (int succ : djGraph.getCfg().outgoingEdges(domainNodes[i - 1])) {
int j = newNodeBackMap[succ];
if (j > mappedDomain.length) {
builder.addEdge(i, j);
} else if (j >= 0) {
builder.addEdge(i, j + mappedNonDomain.length);
} else if (j >= 0) {
builder.addEdge(i, j);
}
}
}
@ -219,9 +238,9 @@ public class IrreducibleGraphConverter {
if (j >= 0) {
builder.addEdge(i, j);
if (j > mappedDomain.length) {
builder.addEdge(i + mappedNonDomain.length, j);
} else {
builder.addEdge(i + mappedNonDomain.length, j + mappedNonDomain.length);
} else {
builder.addEdge(i + mappedNonDomain.length, j);
}
}
}

View File

@ -48,12 +48,51 @@ public class GraphTest {
builder.addEdge(12, 13);
Graph graph = builder.build();
int[][] sccs = GraphUtils.findStronglyConnectedComponents(graph, new int[] { 0 }, new GraphNodeFilter() {
int[][] sccs = GraphUtils.findStronglyConnectedComponents(graph, new int[] { 0 }, filter);
sortSccs(sccs);
assertThat(sccs.length, is(6));
assertThat(sccs[0], is(new int[] { 0 }));
assertThat(sccs[1], is(new int[] { 1, 2, 3, 4, 5, 6, 7, 8 }));
assertThat(sccs[2], is(new int[] { 9 }));
assertThat(sccs[3], is(new int[] { 10 }));
assertThat(sccs[4], is(new int[] { 11, 12 }));
assertThat(sccs[5], is(new int[] { 13 }));
}
@Test
public void stronglyConnectedComponentCalculated2() {
GraphBuilder builder = new GraphBuilder();
builder.addEdge(0, 1);
builder.addEdge(0, 2);
builder.addEdge(0, 3);
builder.addEdge(1, 2);
builder.addEdge(2, 1);
builder.addEdge(3, 2);
builder.addEdge(2, 4);
builder.addEdge(4, 5);
builder.addEdge(4, 1);
builder.addEdge(5, 3);
Graph graph = builder.build();
int[][] sccs = GraphUtils.findStronglyConnectedComponents(graph, new int[] { 1, 2, 3 }, new GraphNodeFilter() {
@Override public boolean match(int node) {
return true;
return node != 0;
}
});
sortSccs(sccs);
assertThat(sccs.length, is(1));
assertThat(sccs[0], is(new int[] { 1, 2, 3, 4, 5 }));
}
private GraphNodeFilter filter = new GraphNodeFilter() {
@Override public boolean match(int node) {
return true;
}
};
private void sortSccs(int[][] sccs) {
for (int i = 0; i < sccs.length; ++i) {
Arrays.sort(sccs[i]);
}
@ -62,12 +101,5 @@ public class GraphTest {
return Integer.compare(o1[0], o2[0]);
}
});
assertThat(sccs[0], is(new int[] { 0 }));
assertThat(sccs[1], is(new int[] { 1, 2, 3, 4, 5, 6, 7, 8 }));
assertThat(sccs[2], is(new int[] { 9 }));
assertThat(sccs[3], is(new int[] { 10 }));
assertThat(sccs[4], is(new int[] { 11, 12 }));
assertThat(sccs[5], is(new int[] { 13 }));
}
}