mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2025-01-09 00:14:10 -08:00
During node splitting, create copies for previously copied nodes, if necessary. See #219
This commit is contained in:
parent
4b766f7b73
commit
aebfe7d165
|
@ -18,10 +18,6 @@ package org.teavm.common;
|
||||||
import com.carrotsearch.hppc.IntIntMap;
|
import com.carrotsearch.hppc.IntIntMap;
|
||||||
import com.carrotsearch.hppc.IntIntOpenHashMap;
|
import com.carrotsearch.hppc.IntIntOpenHashMap;
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Alexey Andreev
|
|
||||||
*/
|
|
||||||
public class DefaultGraphSplittingBackend implements GraphSplittingBackend {
|
public class DefaultGraphSplittingBackend implements GraphSplittingBackend {
|
||||||
private MutableDirectedGraph graph;
|
private MutableDirectedGraph graph;
|
||||||
private int index;
|
private int index;
|
||||||
|
@ -49,10 +45,6 @@ public class DefaultGraphSplittingBackend implements GraphSplittingBackend {
|
||||||
return prototypeNodes.get(index);
|
return prototypeNodes.get(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int copyIndex(int index) {
|
|
||||||
return copyIndexes.get(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int[] split(int[] domain, int[] nodes) {
|
public int[] split(int[] domain, int[] nodes) {
|
||||||
int[] copies = new int[nodes.length];
|
int[] copies = new int[nodes.length];
|
||||||
|
|
|
@ -15,10 +15,6 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.common;
|
package org.teavm.common;
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Alexey Andreev
|
|
||||||
*/
|
|
||||||
public interface GraphSplittingBackend {
|
public interface GraphSplittingBackend {
|
||||||
int[] split(int[] domain, int[] nodes);
|
int[] split(int[] domain, int[] nodes);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.IntPredicate;
|
import java.util.function.IntPredicate;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -371,4 +372,16 @@ public final class GraphUtils {
|
||||||
}
|
}
|
||||||
return set;
|
return set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String printToDot(Graph graph) {
|
||||||
|
StringBuilder sb = new StringBuilder("digraph G {\n");
|
||||||
|
for (int i = 0; i < graph.size(); ++i) {
|
||||||
|
String successors = Arrays.stream(graph.outgoingEdges(i))
|
||||||
|
.mapToObj(String::valueOf)
|
||||||
|
.collect(Collectors.joining(", "));
|
||||||
|
sb.append(" ").append(i).append(" -> {").append(successors).append("}\n");
|
||||||
|
}
|
||||||
|
sb.append("}");
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,9 +32,19 @@ class IrreducibleGraphConverter {
|
||||||
private Graph cfg;
|
private Graph cfg;
|
||||||
private int totalNodeCount;
|
private int totalNodeCount;
|
||||||
private GraphSplittingBackend backend;
|
private GraphSplittingBackend backend;
|
||||||
|
private IntSet[] nodeCopies;
|
||||||
|
private IntegerArray nodeOriginals;
|
||||||
|
|
||||||
public void convertToReducible(Graph cfg, int[] weight, GraphSplittingBackend backend) {
|
public void convertToReducible(Graph cfg, int[] weight, GraphSplittingBackend backend) {
|
||||||
this.backend = backend;
|
this.backend = backend;
|
||||||
|
|
||||||
|
nodeCopies = new IntOpenHashSet[cfg.size()];
|
||||||
|
nodeOriginals = new IntegerArray(cfg.size());
|
||||||
|
for (int i = 0; i < cfg.size(); ++i) {
|
||||||
|
nodeCopies[i] = new IntOpenHashSet();
|
||||||
|
nodeOriginals.add(i);
|
||||||
|
}
|
||||||
|
|
||||||
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] = new int[] { i };
|
identityNodeMap[i] = new int[] { i };
|
||||||
|
@ -163,7 +173,11 @@ class IrreducibleGraphConverter {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delegate splitting to domain
|
// Delegate splitting to domain
|
||||||
int[][] newNodes = unflatten(backend.split(flatten(mappedDomain), flatten(mappedNonDomain)), mappedNonDomain);
|
int[] nodesToCopy = withCopies(flatten(mappedNonDomain));
|
||||||
|
int[] copies = backend.split(withCopies(flatten(mappedDomain)), nodesToCopy);
|
||||||
|
registerCopies(nodesToCopy, copies);
|
||||||
|
|
||||||
|
int[][] newNodes = unflatten(withoutCopies(copies), mappedNonDomain);
|
||||||
for (int[] nodes : newNodes) {
|
for (int[] nodes : newNodes) {
|
||||||
totalNodeCount += nodes.length;
|
totalNodeCount += nodes.length;
|
||||||
}
|
}
|
||||||
|
@ -231,6 +245,50 @@ class IrreducibleGraphConverter {
|
||||||
handleLoops(new DJGraph(builder.build(), mappedWeight), newNodeMap);
|
handleLoops(new DJGraph(builder.build(), mappedWeight), newNodeMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int[] withCopies(int[] nodes) {
|
||||||
|
IntegerArray nodesWithCopies = new IntegerArray(nodes.length);
|
||||||
|
for (int node : nodes) {
|
||||||
|
nodesWithCopies.add(node);
|
||||||
|
IntSet copies = nodeCopies[node];
|
||||||
|
if (copies != null) {
|
||||||
|
nodesWithCopies.addAll(copies.toArray());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nodesWithCopies.getAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
private int[] withoutCopies(int[] nodesWithCopies) {
|
||||||
|
IntSet visited = new IntOpenHashSet();
|
||||||
|
int[] nodes = new int[nodesWithCopies.length];
|
||||||
|
int sz = 0;
|
||||||
|
for (int node : nodesWithCopies) {
|
||||||
|
node = nodeOriginals.get(node);
|
||||||
|
if (visited.add(node)) {
|
||||||
|
nodes[sz++] = node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Arrays.copyOf(nodes, sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerCopies(int[] originalNodes, int[] copies) {
|
||||||
|
for (int i = 0; i < originalNodes.length; ++i) {
|
||||||
|
int original = nodeOriginals.get(originalNodes[i]);
|
||||||
|
int copy = copies[i];
|
||||||
|
IntSet knownCopies = nodeCopies[original];
|
||||||
|
if (knownCopies == null) {
|
||||||
|
knownCopies = new IntOpenHashSet();
|
||||||
|
nodeCopies[original] = knownCopies;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (knownCopies.add(copy)) {
|
||||||
|
while (nodeOriginals.size() <= copy) {
|
||||||
|
nodeOriginals.add(-1);
|
||||||
|
}
|
||||||
|
nodeOriginals.set(copy, original);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void collapse(DJGraph djGraph, int[] scc, int[][] nodeMap) {
|
private void collapse(DJGraph djGraph, int[] scc, int[][] nodeMap) {
|
||||||
int cls = djGraph.collapse(scc);
|
int cls = djGraph.collapse(scc);
|
||||||
IntegerArray nodes = new IntegerArray(djGraph.getGraph().size());
|
IntegerArray nodes = new IntegerArray(djGraph.getGraph().size());
|
||||||
|
|
|
@ -21,10 +21,6 @@ import org.teavm.common.GraphSplittingBackend;
|
||||||
import org.teavm.model.BasicBlock;
|
import org.teavm.model.BasicBlock;
|
||||||
import org.teavm.model.Program;
|
import org.teavm.model.Program;
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Alexey Andreev
|
|
||||||
*/
|
|
||||||
public class ProgramNodeSplittingBackend implements GraphSplittingBackend {
|
public class ProgramNodeSplittingBackend implements GraphSplittingBackend {
|
||||||
private Program program;
|
private Program program;
|
||||||
|
|
||||||
|
|
|
@ -26,10 +26,6 @@ import java.util.Comparator;
|
||||||
import java.util.function.IntPredicate;
|
import java.util.function.IntPredicate;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Alexey Andreev
|
|
||||||
*/
|
|
||||||
public class GraphTest {
|
public class GraphTest {
|
||||||
@Test
|
@Test
|
||||||
public void stronglyConnectedComponentsCalculated() {
|
public void stronglyConnectedComponentsCalculated() {
|
||||||
|
@ -205,7 +201,6 @@ public class GraphTest {
|
||||||
builder.addEdge(7, 8);
|
builder.addEdge(7, 8);
|
||||||
builder.addEdge(8, 7);
|
builder.addEdge(8, 7);
|
||||||
Graph graph = builder.build();
|
Graph graph = builder.build();
|
||||||
|
|
||||||
DefaultGraphSplittingBackend backend = new DefaultGraphSplittingBackend(graph);
|
DefaultGraphSplittingBackend backend = new DefaultGraphSplittingBackend(graph);
|
||||||
int[] weights = new int[graph.size()];
|
int[] weights = new int[graph.size()];
|
||||||
Arrays.fill(weights, 1);
|
Arrays.fill(weights, 1);
|
||||||
|
@ -214,7 +209,7 @@ public class GraphTest {
|
||||||
|
|
||||||
assertTrue("Should be irreducible", GraphUtils.isIrreducible(graph));
|
assertTrue("Should be irreducible", GraphUtils.isIrreducible(graph));
|
||||||
assertFalse("Should be reducible", GraphUtils.isIrreducible(result));
|
assertFalse("Should be reducible", GraphUtils.isIrreducible(result));
|
||||||
assertTrue("Should be equialent", isEquialent(backend, graph));
|
assertTrue("Should be equivalent", isEquialent(backend, graph));
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isEquialent(DefaultGraphSplittingBackend backend, Graph proto) {
|
private boolean isEquialent(DefaultGraphSplittingBackend backend, Graph proto) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user