From d4824ff9d2965d2f6080b1d69222ff38b6235677 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Wed, 4 Mar 2015 18:28:26 +0400 Subject: [PATCH] Improve node splitting --- .../common/{irreducible => }/DJGraph.java | 3 +- .../common/DefaultGraphSplittingBackend.java | 97 +++++++++++++++++++ .../java/org/teavm/common/GraphBuilder.java | 10 ++ .../GraphSplittingBackend.java | 4 +- .../java/org/teavm/common/GraphUtils.java | 4 + .../IrreducibleGraphConverter.java | 36 ++++++- .../teavm/common/MutableDirectedGraph.java | 18 ++++ 7 files changed, 164 insertions(+), 8 deletions(-) rename teavm-core/src/main/java/org/teavm/common/{irreducible => }/DJGraph.java (99%) create mode 100644 teavm-core/src/main/java/org/teavm/common/DefaultGraphSplittingBackend.java rename teavm-core/src/main/java/org/teavm/common/{irreducible => }/GraphSplittingBackend.java (89%) rename teavm-core/src/main/java/org/teavm/common/{irreducible => }/IrreducibleGraphConverter.java (90%) diff --git a/teavm-core/src/main/java/org/teavm/common/irreducible/DJGraph.java b/teavm-core/src/main/java/org/teavm/common/DJGraph.java similarity index 99% rename from teavm-core/src/main/java/org/teavm/common/irreducible/DJGraph.java rename to teavm-core/src/main/java/org/teavm/common/DJGraph.java index 73eec1dd7..d59ad5320 100644 --- a/teavm-core/src/main/java/org/teavm/common/irreducible/DJGraph.java +++ b/teavm-core/src/main/java/org/teavm/common/DJGraph.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.teavm.common.irreducible; +package org.teavm.common; import com.carrotsearch.hppc.IntOpenHashSet; import com.carrotsearch.hppc.IntSet; @@ -21,7 +21,6 @@ import com.carrotsearch.hppc.cursors.IntCursor; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import org.teavm.common.*; /** * diff --git a/teavm-core/src/main/java/org/teavm/common/DefaultGraphSplittingBackend.java b/teavm-core/src/main/java/org/teavm/common/DefaultGraphSplittingBackend.java new file mode 100644 index 000000000..b3aea9210 --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/common/DefaultGraphSplittingBackend.java @@ -0,0 +1,97 @@ +/* + * Copyright 2015 Alexey Andreev. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.teavm.common; + +import com.carrotsearch.hppc.IntIntMap; +import com.carrotsearch.hppc.IntIntOpenHashMap; + +/** + * + * @author Alexey Andreev + */ +public class DefaultGraphSplittingBackend implements GraphSplittingBackend { + private MutableDirectedGraph graph; + private int index; + private IntegerArray prototypeNodes; + private IntegerArray copyIndexes; + private int[] copyCount; + + public DefaultGraphSplittingBackend(Graph graph) { + this.graph = new MutableDirectedGraph(graph); + prototypeNodes = new IntegerArray(graph.size()); + copyIndexes = new IntegerArray(graph.size()); + copyCount = new int[graph.size()]; + index = graph.size(); + for (int i = 0; i < graph.size(); ++i) { + prototypeNodes.add(i); + copyIndexes.add(i); + } + } + + public Graph getGraph() { + return graph.copyToImmutable(); + } + + public int prototype(int index) { + return prototypeNodes.get(index); + } + + public int copyIndex(int index) { + return copyIndexes.get(index); + } + + @Override + public int[] split(int[] domain, int[] nodes) { + int[] copies = new int[nodes.length]; + IntIntMap map = new IntIntOpenHashMap(); + for (int i = 0; i < nodes.length; ++i) { + copies[i] = index++; + map.put(nodes[i], copies[i]); + int proto = prototypeNodes.get(nodes[i]); + prototypeNodes.add(proto); + copyIndexes.add(++copyCount[proto]); + } + + for (int i = 0; i < domain.length; ++i) { + int node = domain[i]; + for (int succ : graph.outgoingEdges(node)) { + int succCopy = map.get(succ); + if (succCopy == 0) { + continue; + } + --succCopy; + graph.deleteEdge(node, succ); + graph.addEdge(node, succCopy); + } + } + + for (int i = 0; i < nodes.length; ++i) { + int node = nodes[i]; + int nodeCopy = copies[i]; + for (int succ : graph.outgoingEdges(node)) { + int succCopy = map.get(succ); + if (succCopy != 0) { + graph.addEdge(nodeCopy, succCopy - 1); + } else { + graph.addEdge(nodeCopy, succ); + } + } + } + + return copies; + } +} + diff --git a/teavm-core/src/main/java/org/teavm/common/GraphBuilder.java b/teavm-core/src/main/java/org/teavm/common/GraphBuilder.java index 1306006c2..7228fc23d 100644 --- a/teavm-core/src/main/java/org/teavm/common/GraphBuilder.java +++ b/teavm-core/src/main/java/org/teavm/common/GraphBuilder.java @@ -65,6 +65,16 @@ public class GraphBuilder { } } + public void removeEdge(int from, int to) { + if (to < 0 || from < 0) { + throw new IllegalArgumentException(); + } + if (from >= addedEdges.size() || to >= addedEdges.size()) { + return; + } + addedEdges.get(from).removeAllOccurrences(to); + } + public Graph build() { if (builtGraph == null) { IntSet[] incomingEdges = new IntSet[sz]; diff --git a/teavm-core/src/main/java/org/teavm/common/irreducible/GraphSplittingBackend.java b/teavm-core/src/main/java/org/teavm/common/GraphSplittingBackend.java similarity index 89% rename from teavm-core/src/main/java/org/teavm/common/irreducible/GraphSplittingBackend.java rename to teavm-core/src/main/java/org/teavm/common/GraphSplittingBackend.java index 16f14fb0b..5dd859ff3 100644 --- a/teavm-core/src/main/java/org/teavm/common/irreducible/GraphSplittingBackend.java +++ b/teavm-core/src/main/java/org/teavm/common/GraphSplittingBackend.java @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.teavm.common.irreducible; +package org.teavm.common; /** * * @author Alexey Andreev */ public interface GraphSplittingBackend { - int[][] split(int[][] domain, int[][] nodes); + int[] split(int[] domain, int[] nodes); } diff --git a/teavm-core/src/main/java/org/teavm/common/GraphUtils.java b/teavm-core/src/main/java/org/teavm/common/GraphUtils.java index d9a8d55fb..d181d8e98 100644 --- a/teavm-core/src/main/java/org/teavm/common/GraphUtils.java +++ b/teavm-core/src/main/java/org/teavm/common/GraphUtils.java @@ -179,6 +179,10 @@ public final class GraphUtils { return graph.build(); } + public static void splitIrreducibleGraph(Graph graph, int[] weights, GraphSplittingBackend backend) { + new IrreducibleGraphConverter().convertToReducible(graph, weights, backend); + } + public static int[][] findDominanceFrontiers(Graph cfg, DominatorTree domTree) { IntegerArray[] tmpFrontiers = new IntegerArray[cfg.size()]; int[][] domFrontiers = new int[cfg.size()][]; diff --git a/teavm-core/src/main/java/org/teavm/common/irreducible/IrreducibleGraphConverter.java b/teavm-core/src/main/java/org/teavm/common/IrreducibleGraphConverter.java similarity index 90% rename from teavm-core/src/main/java/org/teavm/common/irreducible/IrreducibleGraphConverter.java rename to teavm-core/src/main/java/org/teavm/common/IrreducibleGraphConverter.java index b5e06125b..594db8992 100644 --- a/teavm-core/src/main/java/org/teavm/common/irreducible/IrreducibleGraphConverter.java +++ b/teavm-core/src/main/java/org/teavm/common/IrreducibleGraphConverter.java @@ -13,13 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.teavm.common.irreducible; +package org.teavm.common; import com.carrotsearch.hppc.IntOpenHashSet; import com.carrotsearch.hppc.IntSet; import com.carrotsearch.hppc.cursors.IntCursor; import java.util.Arrays; -import org.teavm.common.*; /** *

Converts irreducible graph to reducible one using node splitting algorithm described at @@ -28,7 +27,7 @@ import org.teavm.common.*; * * @author Alexey Andreev */ -public class IrreducibleGraphConverter { +class IrreducibleGraphConverter { private Graph cfg; private int totalNodeCount; private GraphSplittingBackend backend; @@ -174,7 +173,7 @@ public class IrreducibleGraphConverter { } // Delegate splitting to domain - int[][] newNodes = backend.split(mappedDomain, mappedNonDomain); + int[][] newNodes = unflatten(backend.split(flatten(mappedDomain), flatten(mappedNonDomain)), mappedNonDomain); for (int[] nodes : newNodes) { totalNodeCount += nodes.length; } @@ -242,6 +241,35 @@ public class IrreducibleGraphConverter { handleLoops(new DJGraph(builder.build(), mappedWeight), newNodeMap); } + private static int[] flatten(int[][] array) { + int count = 0; + for (int i = 0; i < array.length; ++i) { + count += array[i].length; + } + int[] flat = new int[count]; + int index = 0; + for (int i = 0; i < array.length; ++i) { + int[] part = array[i]; + for (int j = 0; j < part.length; ++j) { + flat[index++] = part[j]; + } + } + return flat; + } + + private static int[][] unflatten(int[] flat, int[][] pattern) { + int[][] rough = new int[pattern.length][]; + int index = 0; + for (int i = 0; i < rough.length; ++i) { + int[] part = new int[pattern[i].length]; + for (int j = 0; j < part.length; ++j) { + part[j] = flat[index++]; + } + rough[i] = part; + } + return rough; + } + static class DJGraphNodeFilter implements GraphNodeFilter { private DJGraph graph; private int level; diff --git a/teavm-core/src/main/java/org/teavm/common/MutableDirectedGraph.java b/teavm-core/src/main/java/org/teavm/common/MutableDirectedGraph.java index 8036e16ae..91fb6a851 100644 --- a/teavm-core/src/main/java/org/teavm/common/MutableDirectedGraph.java +++ b/teavm-core/src/main/java/org/teavm/common/MutableDirectedGraph.java @@ -42,6 +42,16 @@ public class MutableDirectedGraph implements Graph { } } + public Graph copyToImmutable() { + GraphBuilder builder = new GraphBuilder(successors.size()); + for (int i = 0; i < successors.size(); ++i) { + for (IntCursor cursor : successors.get(i)) { + builder.addEdge(i, cursor.value); + } + } + return builder.build(); + } + @Override public int size() { return successors.size(); @@ -57,6 +67,14 @@ public class MutableDirectedGraph implements Graph { predecessors.get(to).add(from); } + public void deleteEdge(int from, int to) { + if (from >= successors.size() || to >= successors.size()) { + return; + } + successors.get(from).removeAllOccurrences(to); + predecessors.get(to).removeAllOccurrences(from); + } + public void detachNode(int node) { for (IntCursor succ : successors.get(node)) { predecessors.get(succ.value).removeAllOccurrences(node);