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