mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 16:14:10 -08:00
Further attempts to get node splitting work
This commit is contained in:
parent
b6df37115f
commit
043d6f587f
|
@ -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)) {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 }));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user