Skip to content

Commit

Permalink
Merge pull request #917 from wurstscript/propagation-improvements
Browse files Browse the repository at this point in the history
improved constant/copy-propagation performance
  • Loading branch information
peq committed Jan 3, 2020
2 parents a9db329 + 901f71b commit ba8322f
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 31 deletions.
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
package de.peeeq.wurstscript.intermediatelang.optimizer;

import de.peeeq.datastructures.Worklist;
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.ImTranslator;
import io.vavr.Tuple2;
import io.vavr.collection.HashMap;
import org.eclipse.jdt.annotation.Nullable;

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

public class ConstantAndCopyPropagation implements OptimizerPass {
private int totalPropagated = 0;
Expand All @@ -32,8 +31,10 @@ public String getName() {

static class Value {
// one of the two is null
final @Nullable ImVar copyVar;
final @Nullable ImConst constantValue;
final @Nullable
ImVar copyVar;
final @Nullable
ImConst constantValue;

public Value(ImVar copyVar) {
this.copyVar = copyVar;
Expand Down Expand Up @@ -74,9 +75,8 @@ public String toString() {
}

static class Knowledge {

Map<ImVar, Value> varKnowledge = new HashMap<>();
Map<ImVar, Value> varKnowledgeOut = new HashMap<>();
HashMap<ImVar, Value> varKnowledge = HashMap.empty();
HashMap<ImVar, Value> varKnowledgeOut = HashMap.empty();

@Override
public String toString() {
Expand Down Expand Up @@ -121,7 +121,7 @@ public void visit(ImVarAccess va) {
if (va.isUsedAsLValue()) {
return;
}
Value val = kn.varKnowledge.get(va.getVar());
Value val = kn.varKnowledge.get(va.getVar()).getOrNull();
if (val == null) {
return;
}
Expand All @@ -141,45 +141,50 @@ public void visit(ImVarAccess va) {
}

private Map<Node, Knowledge> calculateKnowledge(ControlFlowGraph cfg) {
Map<Node, Knowledge> knowledge = new HashMap<>();
Map<Node, Knowledge> knowledge = new java.util.HashMap<>();

// initialize with empty knowledge:
for (Node n : cfg.getNodes()) {
knowledge.put(n, new Knowledge());
}

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

while (!todo.isEmpty()) {
Node n = todo.poll();

Knowledge kn = knowledge.get(n);

// get knowledge from predecessor out
HashMap<ImVar, Value> newKnowledge = new HashMap<>();
HashMap<ImVar, Value> newKnowledge = HashMap.empty();
if (!n.getPredecessors().isEmpty()) {
Node pred1 = n.getPredecessors().get(0);
Map<ImVar, Value> predKnowledgeOut = knowledge.get(pred1).varKnowledgeOut;
for (Entry<ImVar, Value> e : predKnowledgeOut.entrySet()) {
ImVar var = e.getKey();
Value val = e.getValue();
boolean allSame = true;
for (int i = 1; i < n.getPredecessors().size(); i++) {
Node predi = n.getPredecessors().get(i);
Value predi_val = knowledge.get(predi).varKnowledgeOut.get(var);
if (predi_val == null || !predi_val.equalValue(val)) {
allSame = false;
break;
HashMap<ImVar, Value> predKnowledgeOut = knowledge.get(pred1).varKnowledgeOut;

// only keep knowledge that is the same for all predecessors:
newKnowledge = predKnowledgeOut;
if (n.getPredecessors().size() > 1) {
for (Tuple2<ImVar, Value> e : predKnowledgeOut) {
ImVar var = e._1();
Value val = e._2();
boolean allSame = true;
for (int i = 1; i < n.getPredecessors().size(); i++) {
Node predi = n.getPredecessors().get(i);
Value predi_val = knowledge.get(predi).varKnowledgeOut.get(var).getOrNull();
if (predi_val == null || !predi_val.equalValue(val)) {
allSame = false;
break;
}
}
if (!allSame) {
newKnowledge = newKnowledge.remove(var);
}
}
if (allSame) {
newKnowledge.put(var, val);
}
}
}

// at the output get all from the input knowledge
HashMap<ImVar, Value> newOut = new HashMap<>(newKnowledge);
HashMap<ImVar, Value> newOut = newKnowledge;

ImStmt stmt = n.getStmt();
if (stmt instanceof ImSet) {
Expand All @@ -199,16 +204,21 @@ private Map<Node, Knowledge> calculateKnowledge(ControlFlowGraph cfg) {
}
if (newValue == null) {
// invalidate old value
newOut.remove(var);
newOut = newOut.remove(var);
} else {
newOut.put(var, newValue);
newOut = newOut.put(var, newValue);
}
// invalidate copies of the lhs
// for example:
// x = a; [x->a]
// y = b; [x->a, y->b]
// a = 5; [y->b, a->5] // here [x->a] has been invalidated
newOut.entrySet().removeIf(entry -> entry.getValue().equalValue(new Value(var)));
Value varAsValue = new Value(var);
for (Tuple2<ImVar, Value> p : newOut) {
if (p._2().equalValue(varAsValue)) {
newOut = newOut.remove(p._1());
}
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -955,4 +955,61 @@ public void multiArrayNoInline2() {
" testSuccess()"
);
}


@Test
public void copyPropagation() throws IOException {
testAssertOkLines(true,
"package Test",
"native testSuccess()",
"@extern native S2I(string s) returns int",
"init",
" let a = S2I(\"7\")",
" let b = a",
" let c = b",
" if c == 7",
" testSuccess()"
);
String compiled = Files.toString(new File("test-output/OptimizerTests_copyPropagation_opt.j"), Charsets.UTF_8);
System.out.println(compiled);
assertTrue(compiled.contains("if a == 7 then"));
}

@Test
public void copyPropagation2() throws IOException {
testAssertOkLines(true,
"package Test",
"native testSuccess()",
"@extern native S2I(string s) returns int",
"integer test_x=0",
"integer array B_nextFree",
"integer B_firstFree=0",
"integer B_maxIndex=0",
"integer array B_typeId",
"integer array B_y",
"function destroyA(int this0)",
" let this_1 = this0",
" integer this_2",
" integer obj",
" test_x = test_x + B_y[this_1]",
" this_2 = this_1",
" test_x = test_x * B_y[this_2]",
" obj = this0",
" if B_typeId[obj] == 0",
" else",
" B_nextFree[B_firstFree] = obj",
" B_firstFree = B_firstFree + 1",
" B_typeId[obj] = 0",
" if B_nextFree[B_firstFree - 1] == 42",
" testSuccess()",
"init",
" B_typeId[42] = 1",
" destroyA(42)"
);
String compiled = Files.toString(new File("test-output/OptimizerTests_copyPropagation2_opt.j"), Charsets.UTF_8);
System.out.println(compiled);
// copy propagation obj -> this0
assertTrue(compiled.contains("set Test_B_nextFree[Test_B_firstFree] = this0"));
}

}

0 comments on commit ba8322f

Please sign in to comment.