Skip to content

Commit

Permalink
improved performance for liveness calculation in LocalMerger
Browse files Browse the repository at this point in the history
- using immutable collections to share data between nodes in the graph
- better strategy for calculating fixed point
  • Loading branch information
peq committed Jan 3, 2020
1 parent ac19a7d commit c05a8a8
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 27 deletions.
3 changes: 3 additions & 0 deletions de.peeeq.wurstscript/build.gradle
Expand Up @@ -86,6 +86,9 @@ dependencies {
// Functional data structures:
compile group: 'org.functionaljava', name: 'functionaljava', version: '4.8.1'

// Better functional data structures:
compile 'io.vavr:vavr:1.0.0-alpha-3'

// Support for the vscode language server protocol
compile group: 'org.eclipse.lsp4j', name: 'org.eclipse.lsp4j', version: '0.7.0'

Expand Down
@@ -0,0 +1,60 @@
package de.peeeq.datastructures;

import java.util.ArrayDeque;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;

/**
* A queue with efficient lookup using a hashset.
* <p>
* No element is added to the queue more than once.
*/
public class Worklist<T> {
private ArrayDeque<T> queue = new ArrayDeque<>();
private HashSet<T> set = new HashSet<>();

public Worklist() {
}

public Worklist(Iterable<? extends T> nodes) {
for (T node : nodes) {
addLast(node);
}
}

public boolean isEmpty() {
return queue.isEmpty();
}


public void addFirst(T node) {
if (set.add(node)) {
queue.addFirst(node);
}
}

public void addLast(T node) {
if (set.add(node)) {
queue.addLast(node);
}
}

public T poll() {
T result = queue.poll();
if (result != null) {
set.remove(result);
}
return result;
}

public int size() {
return queue.size();
}

public void addAll(Collection<? extends T> elems) {
for (T elem : elems) {
addLast(elem);
}
}
}
Expand Up @@ -3,12 +3,25 @@
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap;
import de.peeeq.datastructures.Worklist;
import de.peeeq.wurstscript.attributes.CompileError;
import de.peeeq.wurstscript.intermediatelang.optimizer.ControlFlowGraph.Node;
import de.peeeq.wurstscript.jassIm.*;
import de.peeeq.wurstscript.translation.imoptimizer.OptimizerPass;
import de.peeeq.wurstscript.translation.imtranslation.GetAForB;
import de.peeeq.wurstscript.translation.imtranslation.ImPrinter;
import de.peeeq.wurstscript.translation.imtranslation.ImTranslator;
import io.vavr.collection.HashSet;
import io.vavr.collection.Set;

import java.util.*;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.PriorityQueue;
import java.util.concurrent.atomic.AtomicInteger;

/**
* merges local variable, if they have disjoint live-spans
Expand Down Expand Up @@ -109,7 +122,7 @@ public void visit(ImSet set) {
private Multimap<ImVar, ImVar> calculateInferenceGraph(Map<ImStmt, Set<ImVar>> livenessInfo) {
Multimap<ImVar, ImVar> inferenceGraph = HashMultimap.create();
for (ImStmt s : livenessInfo.keySet()) {
Collection<ImVar> live = livenessInfo.get(s);
Set<ImVar> live = livenessInfo.get(s);
for (ImVar v1 : live) {
for (ImVar v2 : live) {
if (v1.getType().equalsType(v2.getType())) {
Expand Down Expand Up @@ -151,32 +164,35 @@ private Map<ImStmt, Set<ImVar>> calculateLiveness(ImFunction func) {
Map<Node, Set<ImVar>> in = new HashMap<>();
Map<Node, Set<ImVar>> out = new HashMap<>();

Deque<Node> todo = new ArrayDeque<>();
Worklist<Node> todo = new Worklist<>();

Map<Node, Integer> index = new HashMap<>();

// init in and out with empty sets
for (Node node : cfg.getNodes()) {
in.put(node, Collections.emptySet());
out.put(node, Collections.emptySet());
in.put(node, HashSet.empty());
out.put(node, HashSet.empty());
todo.addFirst(node);
index.put(node, 1+ index.size());
}

// calculate def- and use- sets for each node
Multimap<Node, ImVar> def = calculateDefs(cfg.getNodes());
Multimap<Node, ImVar> use = calculateUses(cfg.getNodes());
// boolean changes = true;
// int iterations = 0;
Map<Node, Set<ImVar>> def = calculateDefs(cfg.getNodes());
Map<Node, Set<ImVar>> use = calculateUses(cfg.getNodes());
while (!todo.isEmpty()) {
Node node = todo.poll();
// iterations++;
// in[n] = use[n] + (out[n] - def[n])
Set<ImVar> newIn = new HashSet<>(out.get(node));
newIn.removeAll(def.get(node));
newIn.addAll(use.get(node));

// out[n] = union s in succ[n]: in[s]
Set<ImVar> newOut = new HashSet<>();
for (Node s : node.getSuccessors()) {
newOut.addAll(in.get(s));
}
Set<ImVar> newOut = node.getSuccessors()
.stream()
.map(in::get)
.reduce(HashSet.empty(), Set::union);

// in[n] = use[n] + (out[n] - def[n])
Set<ImVar> newIn = newOut;
newIn = newIn.diff(def.get(node));
newIn = newIn.union(use.get(node));


if (!newIn.equals(in.get(node))) {
in.put(node, newIn);
Expand All @@ -187,8 +203,6 @@ private Map<ImStmt, Set<ImVar>> calculateLiveness(ImFunction func) {
}
if (!newOut.equals(out.get(node))) {
out.put(node, newOut);
// if out changes, then this node has to be recalculated
todo.addLast(node);
}
}
// System.out.println("result after " + iterations + " iterations in func " + func.getName());
Expand All @@ -204,41 +218,44 @@ private Map<ImStmt, Set<ImVar>> calculateLiveness(ImFunction func) {
for (Node node : cfg.getNodes()) {
ImStmt stmt = node.getStmt();
if (stmt != null) {
result.put(stmt, ImmutableSet.copyOf(out.get(node)));
result.put(stmt, out.get(node));
}
}
return result;
}

private Multimap<Node, ImVar> calculateUses(List<Node> nodes) {
Multimap<Node, ImVar> result = HashMultimap.create();
private Map<Node, Set<ImVar>> calculateUses(List<Node> nodes) {
Map<Node, Set<ImVar>> result = new HashMap<>();
for (Node node : nodes) {
List<ImVar> uses = new ArrayList<>();
ImStmt stmt = node.getStmt();
if (stmt != null) {
stmt.accept(new ImStmt.DefaultVisitor() {
@Override
public void visit(ImVarAccess va) {
super.visit(va);
if (!va.getVar().isGlobal()) {
result.put(node, va.getVar());
uses.add(va.getVar());
}
}
});
}
result.put(node, HashSet.ofAll(uses));
}
return result;
}

private Multimap<Node, ImVar> calculateDefs(List<Node> nodes) {
Multimap<Node, ImVar> result = HashMultimap.create();
private Map<Node, Set<ImVar>> calculateDefs(List<Node> nodes) {
Map<Node, Set<ImVar>>result = new HashMap<>();
for (Node node : nodes) {
result.put(node, HashSet.empty());
ImStmt stmt = node.getStmt();
if (stmt instanceof ImSet) {
ImSet imSet = (ImSet) stmt;
if (imSet.getLeft() instanceof ImVarAccess) {
ImVar v = ((ImVarAccess) imSet.getLeft()).getVar();
if (!v.isGlobal()) {
result.put(node, v);
result.put(node, HashSet.of(v));
}
}
}
Expand Down

0 comments on commit c05a8a8

Please sign in to comment.