diff --git a/teavm-core/src/main/java/org/teavm/common/irreducible/DJGraph.java b/teavm-core/src/main/java/org/teavm/common/irreducible/DJGraph.java index 655c5f765..faefb296a 100644 --- a/teavm-core/src/main/java/org/teavm/common/irreducible/DJGraph.java +++ b/teavm-core/src/main/java/org/teavm/common/irreducible/DJGraph.java @@ -36,9 +36,14 @@ public class DJGraph { private int[] spanningTreeIndex; private int[][] levelContent; private int[] mergeRoot; + private int[] weight; private IntegerArray[] mergeClasses; - public DJGraph(Graph src) { + public DJGraph(Graph src, int[] weight) { + if (src.size() != weight.length) { + throw new IllegalArgumentException("Node count " + src.size() + " is not equal to weight array " + + weight.length); + } this.cfg = new MutableDirectedGraph(src); domTree = GraphUtils.buildDominatorTree(src); buildGraph(src); @@ -50,6 +55,7 @@ public class DJGraph { mergeRoot[i] = i; mergeClasses[i] = IntegerArray.of(i); } + weight = Arrays.copyOf(weight, weight.length); } private void buildGraph(Graph src) { @@ -160,6 +166,18 @@ public class DJGraph { return c != i && c != j; } + public int weightOf(int node) { + return weight[node]; + } + + public int weightOf(int... nodes) { + int result = 0; + for (int node : nodes) { + result += weight[node]; + } + return result; + } + public int levelOf(int node) { return domTree.levelOf(mergeRoot[node]); } @@ -202,6 +220,7 @@ public class DJGraph { cls.addAll(mergeClasses[node.value].getAll()); mergeClasses[node.value].clear(); } + weight[top] += weight[node.value]; } // Alter graphs diff --git a/teavm-core/src/main/java/org/teavm/common/irreducible/IrreducibleGraphConverter.java b/teavm-core/src/main/java/org/teavm/common/irreducible/IrreducibleGraphConverter.java index aa908dba8..84768ef23 100644 --- a/teavm-core/src/main/java/org/teavm/common/irreducible/IrreducibleGraphConverter.java +++ b/teavm-core/src/main/java/org/teavm/common/irreducible/IrreducibleGraphConverter.java @@ -15,10 +15,9 @@ */ package org.teavm.common.irreducible; +import org.teavm.common.*; +import com.carrotsearch.hppc.IntOpenHashSet; import com.carrotsearch.hppc.IntSet; -import org.teavm.common.Graph; -import org.teavm.common.GraphNodeFilter; -import org.teavm.common.GraphUtils; /** *
Converts irreducible graph to reducible one using node splitting algorithm described at @@ -28,15 +27,21 @@ import org.teavm.common.GraphUtils; * @author Alexey Andreev */ public class IrreducibleGraphConverter { + private Graph cfg; private GraphSplittingBackend backend; - public void convertToReducible(Graph cfg, GraphSplittingBackend backend) { + public void convertToReducible(Graph cfg, int[] weight, GraphSplittingBackend backend) { this.backend = backend; - handleLoops(new DJGraph(cfg)); + int[] identityNodeMap = new int[cfg.size()]; + for (int i = 0; i < identityNodeMap.length; ++i) { + identityNodeMap[i] = i; + } + this.cfg = cfg; + handleLoops(new DJGraph(cfg, weight), identityNodeMap); this.backend = null; } - private void handleLoops(DJGraph djGraph) { + private void handleLoops(DJGraph djGraph, int[] nodeMap) { for (int level = djGraph.levelCount() - 1; level >= 0; --level) { boolean irreducible = false; for (int node : djGraph.level(level)) { @@ -52,6 +57,10 @@ public class IrreducibleGraphConverter { } DJGraphNodeFilter filter = new DJGraphNodeFilter(djGraph, level, null); int[][] sccs = GraphUtils.findStronglyConnectedComponents(djGraph.getGraph(), djGraph.level(level), filter); + for (int[] scc : sccs) { + handleStronglyConnectedComponent(djGraph, scc, nodeMap); + djGraph.collapse(scc); + } } } @@ -60,6 +69,89 @@ public class IrreducibleGraphConverter { return null; } + private void handleStronglyConnectedComponent(DJGraph djGraph, int[] scc, int[] nodeMap) { + // Find shared dominator + int sharedDom = scc[0]; + for (int i = 1; i < scc.length; ++i) { + sharedDom = djGraph.getDomTree().commonDominatorOf(sharedDom, scc[i]); + } + + // Partition SCC into domains + DisjointSet partitions = new DisjointSet(); + for (int i = 0; i < scc.length; ++i) { + partitions.create(); + } + 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); + } + } + int[] domains = partitions.pack(scc.length); + int domainCount = 0; + for (int domain : domains) { + domainCount = Math.max(domainCount, domain + 1); + } + + // For each domain calculate its weight + int[] domainWeight = new int [domainCount]; + for (int i = 0; i < scc.length; ++i) { + int node = scc[i]; + domainWeight[domains[node]] += djGraph.weightOf(node); + } + + // Find domain to split around + int domain = 0; + int maxWeight = domainWeight[0]; + for (int i = 1; i < domainWeight.length; ++i) { + if (domainWeight[i] > maxWeight) { + domain = i; + maxWeight = domainWeight[i]; + } + } + + // Find header of this domain + IntSet domainNodes = new IntOpenHashSet(scc.length); + for (int i = 0; i < scc.length; ++i) { + int node = scc[i]; + if (domains[node] == domain) { + domainNodes.add(node); + } + } + + // Split + int[] newNodes = splitStronglyConnectedComponent(domainNodes, scc, nodeMap); + + // Construct DJ-subgraph + int[] newNodeMap = new int[1 + scc.length + newNodes.length]; + for (int i = 0; i < scc.length; ++i) { + newNodeMap[i + 1] = nodeMap[scc[i]]; + } + for (int i = 0; i < newNodes.length; ++i) { + newNodeMap[i + 1 + scc.length] = newNodes[i]; + } + GraphBuilder builder = new GraphBuilder(newNodeMap.length); + + for (int i = 0; i < scc.length; ++i) { + + } + } + + private int[] splitStronglyConnectedComponent(IntSet domain, int[] scc, int[] nodeMap) { + IntegerArray nonDomain = new IntegerArray(scc.length); + for (int node : scc) { + if (!domain.contains(node)) { + nonDomain.add(node); + } + } + int[] mappedNonDomain = new int[nonDomain.size()]; + for (int i = 0; i < nonDomain.size(); ++i) { + mappedNonDomain[i] = nodeMap[nonDomain.get(i)]; + } + return backend.split(mappedNonDomain); + } + static class DJGraphNodeFilter implements GraphNodeFilter { private DJGraph graph; private int level;