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()) { while (!stack.isEmpty()) {
int node = stack.pop(); int node = stack.pop();
if (visitIndex[node] > 0) { if (visitIndex[node] > 0) {
if (headerIndex[node] > 0) {
continue;
}
currentComponent.add(node); currentComponent.add(node);
int hdr = visitIndex[node]; int hdr = visitIndex[node];
for (int successor : graph.outgoingEdges(node)) { for (int successor : graph.outgoingEdges(node)) {

View File

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

View File

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