Fix bugs in irreducible flowgraph node splitting

This commit is contained in:
Alexey Andreev 2015-03-02 19:10:26 +04:00
parent f106afb034
commit b6df37115f
4 changed files with 52 additions and 41 deletions

View File

@ -71,7 +71,7 @@ class DefaultDominatorTree implements DominatorTree {
@Override @Override
public int levelOf(int a) { public int levelOf(int a) {
int index = indexes[a]; int index = indexes[a + 1];
return lcaTree.depthOf(index); return lcaTree.depthOf(index);
} }
} }

View File

@ -48,6 +48,7 @@ public class DJGraph {
domTree = GraphUtils.buildDominatorTree(src); domTree = GraphUtils.buildDominatorTree(src);
buildGraph(src); buildGraph(src);
buildLevels(); buildLevels();
spanningTree = new LCATree(src.size());
dfs(); dfs();
mergeRoot = new int[src.size()]; mergeRoot = new int[src.size()];
mergeClasses = new IntegerArray[src.size()]; mergeClasses = new IntegerArray[src.size()];
@ -55,7 +56,7 @@ public class DJGraph {
mergeRoot[i] = i; mergeRoot[i] = i;
mergeClasses[i] = IntegerArray.of(i); mergeClasses[i] = IntegerArray.of(i);
} }
weight = Arrays.copyOf(weight, weight.length); this.weight = Arrays.copyOf(weight, weight.length);
} }
private void buildGraph(Graph src) { private void buildGraph(Graph src) {
@ -84,9 +85,9 @@ public class DJGraph {
} }
builder.get(level).add(i); builder.get(level).add(i);
} }
levelContent = new int[builder.size()][]; levelContent = new int[builder.size() - 1][];
for (int i = 0; i < builder.size(); ++i) { for (int i = 1; i < builder.size(); ++i) {
levelContent[i] = builder.get(i).getAll(); levelContent[i - 1] = builder.get(i).getAll();
} }
} }
@ -97,15 +98,15 @@ public class DJGraph {
Arrays.fill(spanningTreeNode, -1); Arrays.fill(spanningTreeNode, -1);
boolean[] visited = new boolean[graph.size()]; boolean[] visited = new boolean[graph.size()];
IntegerStack stack = new IntegerStack(graph.size() * 2); IntegerStack stack = new IntegerStack(graph.size() * 2);
stack.push(0);
stack.push(-1); stack.push(-1);
stack.push(0);
while (!stack.isEmpty()) { while (!stack.isEmpty()) {
int node = stack.pop(); int node = stack.pop();
int source = stack.pop(); int source = stack.pop();
if (visited[node]) { if (visited[node]) {
continue; continue;
} }
int index = spanningTree.addNode(spanningTreeIndex[source]); int index = source >= 0 ? spanningTree.addNode(spanningTreeIndex[source]) : 0;
spanningTreeNode[index] = node; spanningTreeNode[index] = node;
spanningTreeIndex[node] = index; spanningTreeIndex[node] = index;
visited[node] = true; visited[node] = true;
@ -179,7 +180,7 @@ public class DJGraph {
} }
public int levelOf(int node) { public int levelOf(int node) {
return domTree.levelOf(mergeRoot[node]); return domTree.levelOf(mergeRoot[node]) - 1;
} }
public int[] level(int level) { public int[] level(int level) {

View File

@ -20,5 +20,5 @@ package org.teavm.common.irreducible;
* @author Alexey Andreev <konsoletyper@gmail.com> * @author Alexey Andreev <konsoletyper@gmail.com>
*/ */
public interface GraphSplittingBackend { public interface GraphSplittingBackend {
int[] split(int[] domain, int[] nodes); int[][] split(int[][] domain, int[][] nodes);
} }

View File

@ -15,11 +15,11 @@
*/ */
package org.teavm.common.irreducible; package org.teavm.common.irreducible;
import java.util.Arrays;
import org.teavm.common.*;
import com.carrotsearch.hppc.IntOpenHashSet; import com.carrotsearch.hppc.IntOpenHashSet;
import com.carrotsearch.hppc.IntSet; import com.carrotsearch.hppc.IntSet;
import com.carrotsearch.hppc.cursors.IntCursor; import com.carrotsearch.hppc.cursors.IntCursor;
import java.util.Arrays;
import org.teavm.common.*;
/** /**
* <p>Converts irreducible graph to reducible one using node splitting algorithm described at * <p>Converts irreducible graph to reducible one using node splitting algorithm described at
@ -30,22 +30,20 @@ import com.carrotsearch.hppc.cursors.IntCursor;
*/ */
public class IrreducibleGraphConverter { public class IrreducibleGraphConverter {
private Graph cfg; private Graph cfg;
private int[] cfgWeight;
private GraphSplittingBackend backend; private GraphSplittingBackend backend;
public void convertToReducible(Graph cfg, int[] weight, GraphSplittingBackend backend) { public void convertToReducible(Graph cfg, int[] weight, GraphSplittingBackend backend) {
this.backend = backend; this.backend = backend;
int[] identityNodeMap = new int[cfg.size()]; int[][] identityNodeMap = new int[cfg.size()][];
for (int i = 0; i < identityNodeMap.length; ++i) { for (int i = 0; i < identityNodeMap.length; ++i) {
identityNodeMap[i] = i; identityNodeMap[i] = new int[] { i };
} }
this.cfg = cfg; this.cfg = cfg;
this.cfgWeight = weight;
handleLoops(new DJGraph(cfg, weight), identityNodeMap); handleLoops(new DJGraph(cfg, weight), identityNodeMap);
this.backend = null; this.backend = null;
} }
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;
for (int node : djGraph.level(level)) { for (int node : djGraph.level(level)) {
@ -59,14 +57,16 @@ public class IrreducibleGraphConverter {
} }
} }
} }
DJGraphNodeFilter filter = new DJGraphNodeFilter(djGraph, level, null); DJGraphNodeFilter filter = new DJGraphNodeFilter(djGraph, level);
int[][] sccs = GraphUtils.findStronglyConnectedComponents(djGraph.getGraph(), djGraph.level(level), filter); int[][] sccs = GraphUtils.findStronglyConnectedComponents(djGraph.getGraph(), djGraph.level(level), filter);
for (int[] scc : sccs) { for (int[] scc : sccs) {
if (scc.length > 1) {
handleStronglyConnectedComponent(djGraph, scc, nodeMap); handleStronglyConnectedComponent(djGraph, scc, nodeMap);
djGraph.collapse(scc); djGraph.collapse(scc);
} }
} }
} }
}
private int[] reachUnder(DJGraph djGraph, int back, int header) { private int[] reachUnder(DJGraph djGraph, int back, int header) {
IntSet naturalLoop = IntOpenHashSet.from(header); IntSet naturalLoop = IntOpenHashSet.from(header);
@ -84,7 +84,7 @@ public class IrreducibleGraphConverter {
return naturalLoop.toArray(); return naturalLoop.toArray();
} }
private void handleStronglyConnectedComponent(DJGraph djGraph, int[] scc, int[] nodeMap) { private void handleStronglyConnectedComponent(DJGraph djGraph, int[] scc, int[][] nodeMap) {
// Find shared dominator // Find shared dominator
int sharedDom = scc[0]; int sharedDom = scc[0];
for (int i = 1; i < scc.length; ++i) { for (int i = 1; i < scc.length; ++i) {
@ -136,52 +136,66 @@ public class IrreducibleGraphConverter {
} }
// Split // Split
splitStronglyConnectedComponent(domainNodes, sharedDom, scc, nodeMap); splitStronglyConnectedComponent(djGraph, domainNodes, sharedDom, scc, nodeMap);
// Collapse // Collapse
djGraph.collapse(scc); djGraph.collapse(scc);
} }
private void splitStronglyConnectedComponent(IntSet domain, int sharedDom, int[] scc, int[] nodeMap) { private void splitStronglyConnectedComponent(DJGraph djGraph, IntSet domain, int sharedDom,
int[] scc, int[][] nodeMap) {
// 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[] nonDomainNodes = new int[mappedNonDomain.length];
int index = 0; int index = 0;
for (int node : scc) { for (int node : scc) {
if (!domain.contains(node)) { if (!domain.contains(node)) {
mappedNonDomain[index++] = nodeMap[node]; mappedNonDomain[index] = nodeMap[node];
nonDomainNodes[index] = node;
++index;
} }
} }
int[] mappedDomain = new int[domain.size()]; int[][] mappedDomain = new int[domain.size()][];
index = 0; index = 0;
for (IntCursor cursor : domain) { for (IntCursor cursor : domain) {
mappedDomain[index++] = cursor.value; mappedDomain[index] = nodeMap[cursor.value];
domainNodes[index] = cursor.value;
++index;
} }
// Delegate splitting to domain // Delegate splitting to domain
int[] newNodes = backend.split(mappedDomain, mappedNonDomain); int[][] newNodes = backend.split(mappedDomain, mappedNonDomain);
// 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[cfg.size()];
int[] mappedWeight = new int[newNodeMap.length];
Arrays.fill(newNodeBackMap, -1); Arrays.fill(newNodeBackMap, -1);
newNodeMap[0] = nodeMap[sharedDom]; newNodeMap[0] = nodeMap[sharedDom];
newNodeBackMap[sharedDom] = 0; newNodeBackMap[sharedDom] = 0;
mappedWeight[0] = djGraph.weightOf(sharedDom);
index = 1; index = 1;
for (int i = 0; i < mappedDomain.length; ++i) { for (int i = 0; i < mappedDomain.length; ++i) {
newNodeMap[index] = mappedDomain[i]; newNodeMap[index] = mappedDomain[i];
newNodeBackMap[mappedDomain[i]] = index; newNodeBackMap[domainNodes[i]] = index;
mappedWeight[index] = djGraph.weightOf(domainNodes[i]);
++index; ++index;
} }
for (int i = 0; i < mappedNonDomain.length; ++i) { for (int i = 0; i < mappedNonDomain.length; ++i) {
newNodeMap[index] = mappedNonDomain[i]; newNodeMap[index] = mappedNonDomain[i];
newNodeBackMap[mappedNonDomain[i]] = index; newNodeBackMap[nonDomainNodes[i]] = index;
mappedWeight[index] = djGraph.weightOf(nonDomainNodes[i]);
++index;
}
for (int i = 0; i < mappedNonDomain.length; ++i) {
newNodeMap[index] = newNodes[i];
mappedWeight[index] = djGraph.weightOf(nonDomainNodes[i]);
++index; ++index;
} }
// Build subgraph with new nodes // Build subgraph with new nodes
GraphBuilder builder = new GraphBuilder(newNodeMap.length); GraphBuilder builder = new GraphBuilder(newNodeMap.length);
int[] mappedWeight = new int[newNodeMap.length];
mappedWeight[0] = cfgWeight[newNodeMap[0]];
for (int succ : cfg.outgoingEdges(sharedDom)) { for (int succ : cfg.outgoingEdges(sharedDom)) {
int j = newNodeBackMap[succ]; int j = newNodeBackMap[succ];
if (j >= 0) { if (j >= 0) {
@ -189,8 +203,7 @@ public class IrreducibleGraphConverter {
} }
} }
for (int i = 1; i <= mappedDomain.length; ++i) { for (int i = 1; i <= mappedDomain.length; ++i) {
mappedWeight[i] = cfgWeight[newNodeMap[i]]; for (int succ : djGraph.getCfg().outgoingEdges(domainNodes[i])) {
for (int succ : cfg.outgoingEdges(mappedDomain[i])) {
int j = newNodeBackMap[succ]; int j = newNodeBackMap[succ];
if (j > mappedDomain.length) { if (j > mappedDomain.length) {
builder.addEdge(i, j); builder.addEdge(i, j);
@ -199,10 +212,9 @@ public class IrreducibleGraphConverter {
} }
} }
} }
index = 0;
for (int i = mappedDomain.length + 1; i <= scc.length; ++i) { for (int i = mappedDomain.length + 1; i <= scc.length; ++i) {
mappedWeight[i] = cfgWeight[newNodeMap[i]]; for (int succ : djGraph.getCfg().outgoingEdges(nonDomainNodes[index++])) {
mappedWeight[i + mappedNonDomain.length] = cfgWeight[newNodeMap[i]];
for (int succ : cfg.outgoingEdges(mappedNonDomain[i])) {
int j = newNodeBackMap[succ]; int j = newNodeBackMap[succ];
if (j >= 0) { if (j >= 0) {
builder.addEdge(i, j); builder.addEdge(i, j);
@ -221,17 +233,15 @@ public class IrreducibleGraphConverter {
static class DJGraphNodeFilter implements GraphNodeFilter { static class DJGraphNodeFilter implements GraphNodeFilter {
private DJGraph graph; private DJGraph graph;
private int level; private int level;
private IntSet nodes;
public DJGraphNodeFilter(DJGraph graph, int level, IntSet nodes) { public DJGraphNodeFilter(DJGraph graph, int level) {
this.graph = graph; this.graph = graph;
this.level = level; this.level = level;
this.nodes = nodes;
} }
@Override @Override
public boolean match(int node) { public boolean match(int node) {
return nodes.contains(node) && graph.levelOf(node) >= level; return graph.levelOf(node) >= level;
} }
} }
} }