From 357813ee76c27e4b335bec47f5be9f74af4b5866 Mon Sep 17 00:00:00 2001 From: Victor Date: Sun, 26 Jun 2016 01:28:47 +0300 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B0=20=D0=BE=D0=BF=D1=82=D0=B8=D0=BC=D0=B8=D0=B7=D0=B0?= =?UTF-8?q?=D1=86=D0=B8=D1=8F:=20=D1=80=D0=B0=D1=81=D0=BF=D1=80=D0=BE?= =?UTF-8?q?=D1=81=D1=82=D1=80=D0=B0=D0=BD=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BA?= =?UTF-8?q?=D0=BE=D0=BD=D1=81=D1=82=D0=B0=D0=BD=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/com/annimon/ownlang/parser/Optimizer.java | 4 + .../parser/visitors/ConstantPropagation.java | 162 ++++++++++++++++++ .../ownlang/parser/visitors/VisitorUtils.java | 14 +- 3 files changed, 177 insertions(+), 3 deletions(-) create mode 100644 src/com/annimon/ownlang/parser/visitors/ConstantPropagation.java diff --git a/src/com/annimon/ownlang/parser/Optimizer.java b/src/com/annimon/ownlang/parser/Optimizer.java index fbe8c99..c753bed 100644 --- a/src/com/annimon/ownlang/parser/Optimizer.java +++ b/src/com/annimon/ownlang/parser/Optimizer.java @@ -2,6 +2,7 @@ package com.annimon.ownlang.parser; import com.annimon.ownlang.parser.ast.Statement; import com.annimon.ownlang.parser.visitors.ConstantFolding; +import com.annimon.ownlang.parser.visitors.ConstantPropagation; import com.annimon.ownlang.parser.visitors.DeadCodeElimination; import com.annimon.ownlang.parser.visitors.ExpressionSimplification; @@ -18,16 +19,19 @@ public final class Optimizer { if (level == 0) return statement; final ConstantFolding constantFolding = new ConstantFolding(); + final ConstantPropagation constantPropagation = new ConstantPropagation(); final DeadCodeElimination deadCodeElimination = new DeadCodeElimination(); final ExpressionSimplification expressionSimplification = new ExpressionSimplification(); Statement result = statement; for (int i = 0; i < level; i++) { result = (Statement) result.accept(constantFolding, null); + result = (Statement) constantPropagation.visit(result); result = (Statement) result.accept(deadCodeElimination, null); result = (Statement) result.accept(expressionSimplification, null); } System.out.print(constantFolding.summaryInfo()); + System.out.print(constantPropagation.summaryInfo()); System.out.print(deadCodeElimination.summaryInfo()); System.out.print(expressionSimplification.summaryInfo()); System.out.println(); diff --git a/src/com/annimon/ownlang/parser/visitors/ConstantPropagation.java b/src/com/annimon/ownlang/parser/visitors/ConstantPropagation.java new file mode 100644 index 0000000..41fa425 --- /dev/null +++ b/src/com/annimon/ownlang/parser/visitors/ConstantPropagation.java @@ -0,0 +1,162 @@ +package com.annimon.ownlang.parser.visitors; + +import com.annimon.ownlang.lib.Types; +import com.annimon.ownlang.lib.Value; +import com.annimon.ownlang.parser.Optimizer; +import com.annimon.ownlang.parser.ast.Argument; +import com.annimon.ownlang.parser.ast.AssignmentExpression; +import com.annimon.ownlang.parser.ast.DestructuringAssignmentStatement; +import com.annimon.ownlang.parser.ast.FunctionDefineStatement; +import com.annimon.ownlang.parser.ast.MatchExpression; +import com.annimon.ownlang.parser.ast.Node; +import com.annimon.ownlang.parser.ast.Statement; +import com.annimon.ownlang.parser.ast.ValueExpression; +import com.annimon.ownlang.parser.ast.VariableExpression; +import static com.annimon.ownlang.parser.visitors.VisitorUtils.isValue; +import static com.annimon.ownlang.parser.visitors.VisitorUtils.isVariable; +import java.util.HashMap; +import java.util.Map; + +/** + * Performs constant propagation. + */ +public class ConstantPropagation implements Optimizer.Info { + + private final Map propagatedVariables; + + public ConstantPropagation() { + propagatedVariables = new HashMap<>(); + } + + @Override + public int optimizationsCount() { + return propagatedVariables.size(); + } + + @Override + public String summaryInfo() { + if (optimizationsCount() == 0) return ""; + final StringBuilder sb = new StringBuilder(); + if (propagatedVariables.size() > 0) { + sb.append("\nConstant propagations: ").append(propagatedVariables.size()); + for (Map.Entry e : propagatedVariables.entrySet()) { + sb.append("\n ").append(e.getKey()).append(": ").append(e.getValue()); + } + } + return sb.toString(); + } + + public Node visit(Statement s) { + final Map variables = new HashMap<>(); + // Find variables + s.accept(new VariablesGrabber(), variables); + // Filter only string/number values with 1 modification + final Map candidates = new HashMap<>(); + for (Map.Entry e : variables.entrySet()) { + final VariableInfo info = e.getValue(); + if (info.modifications != 1) continue; + if (info.value == null) continue; + switch (info.value.type()) { + case Types.NUMBER: + case Types.STRING: + candidates.put(e.getKey(), info.value); + break; + } + } + // Replace VariableExpression with ValueExpression + return s.accept(new VariablesPropagator(), candidates); + } + + private class VariablesGrabber extends OptimizationVisitor> { + + @Override + public Node visit(AssignmentExpression s, Map t) { + if (!isVariable((Node)s.target)) { + return super.visit(s, t); + } + + final String variableName = ((VariableExpression) s.target).name; + final VariableInfo var; + if (t.containsKey(variableName)) { + var = t.get(variableName); + var.modifications++; + } else { + var = new VariableInfo(); + var.modifications = 1; + } + + if (s.operation == null && isValue(s.expression)) { + var.value = ((ValueExpression) s.expression).value; + } + t.put(variableName, var); + return super.visit(s, t); + } + + @Override + public Node visit(DestructuringAssignmentStatement s, Map t) { + for (String variableName : s.variables) { + if (variableName == null) continue; + + final VariableInfo var; + if (t.containsKey(variableName)) { + var = t.get(variableName); + var.modifications++; + } else { + var = new VariableInfo(); + var.modifications = 1; + } + t.put(variableName, var); + } + return super.visit(s, t); + } + + @Override + public Node visit(FunctionDefineStatement s, Map t) { + for (Argument argument : s.arguments) { + final String variableName = argument.getName(); + final VariableInfo var; + if (t.containsKey(variableName)) { + var = t.get(variableName); + var.modifications++; + } else { + var = new VariableInfo(); + var.modifications = 1; + } + t.put(variableName, var); + } + return super.visit(s, t); + } + + @Override + public Node visit(MatchExpression s, Map t) { + // no visit match expression + return s; + } + } + + private class VariablesPropagator extends OptimizationVisitor> { + + @Override + public Node visit(VariableExpression s, Map t) { + if (t.containsKey(s.name)) { + if (!propagatedVariables.containsKey(s.name)) { + propagatedVariables.put(s.name, 1); + } else { + propagatedVariables.put(s.name, 1 + propagatedVariables.get(s.name)); + } + return new ValueExpression(t.get(s.name)); + } + return super.visit(s, t); + } + } + + private static class VariableInfo { + Value value; + int modifications; + + @Override + public String toString() { + return (value == null ? "?" : value) + " (" + modifications + " mods)"; + } + } +} diff --git a/src/com/annimon/ownlang/parser/visitors/VisitorUtils.java b/src/com/annimon/ownlang/parser/visitors/VisitorUtils.java index 21a595a..50cb9f6 100644 --- a/src/com/annimon/ownlang/parser/visitors/VisitorUtils.java +++ b/src/com/annimon/ownlang/parser/visitors/VisitorUtils.java @@ -17,8 +17,16 @@ import java.util.Set; public final class VisitorUtils { + public static boolean isValue(Node node) { + return (node instanceof ValueExpression); + } + + public static boolean isVariable(Node node) { + return (node instanceof VariableExpression); + } + public static Statement includeProgram(IncludeStatement s) { - if (!(s.expression instanceof ValueExpression)) return null; + if (!isValue(s)) return null; try { return s.loadProgram(s.expression.eval().asString()); } catch (IOException ex) { @@ -27,7 +35,7 @@ public final class VisitorUtils { } public static boolean isIntegerValue(Node node, int valueToCheck) { - if (!(node instanceof ValueExpression)) return false; + if (!isValue(node)) return false; final Value value = ((ValueExpression) node).value; if (value.type() != Types.NUMBER) return false; @@ -40,7 +48,7 @@ public final class VisitorUtils { } public static boolean isSameVariables(Node n1, Node n2) { - if ( (n1 instanceof VariableExpression) && (n2 instanceof VariableExpression) ) { + if (isVariable(n1) && isVariable(n2)) { final VariableExpression v1 = (VariableExpression) n1; final VariableExpression v2 = (VariableExpression) n2; return v1.name.equals(v2.name);