Добавлена оптимизация: распространение констант

This commit is contained in:
Victor 2016-06-26 01:28:47 +03:00
parent 6dbc045b93
commit 357813ee76
3 changed files with 177 additions and 3 deletions

View File

@ -2,6 +2,7 @@ package com.annimon.ownlang.parser;
import com.annimon.ownlang.parser.ast.Statement; import com.annimon.ownlang.parser.ast.Statement;
import com.annimon.ownlang.parser.visitors.ConstantFolding; 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.DeadCodeElimination;
import com.annimon.ownlang.parser.visitors.ExpressionSimplification; import com.annimon.ownlang.parser.visitors.ExpressionSimplification;
@ -18,16 +19,19 @@ public final class Optimizer {
if (level == 0) return statement; if (level == 0) return statement;
final ConstantFolding constantFolding = new ConstantFolding(); final ConstantFolding constantFolding = new ConstantFolding();
final ConstantPropagation constantPropagation = new ConstantPropagation();
final DeadCodeElimination deadCodeElimination = new DeadCodeElimination(); final DeadCodeElimination deadCodeElimination = new DeadCodeElimination();
final ExpressionSimplification expressionSimplification = new ExpressionSimplification(); final ExpressionSimplification expressionSimplification = new ExpressionSimplification();
Statement result = statement; Statement result = statement;
for (int i = 0; i < level; i++) { for (int i = 0; i < level; i++) {
result = (Statement) result.accept(constantFolding, null); result = (Statement) result.accept(constantFolding, null);
result = (Statement) constantPropagation.visit(result);
result = (Statement) result.accept(deadCodeElimination, null); result = (Statement) result.accept(deadCodeElimination, null);
result = (Statement) result.accept(expressionSimplification, null); result = (Statement) result.accept(expressionSimplification, null);
} }
System.out.print(constantFolding.summaryInfo()); System.out.print(constantFolding.summaryInfo());
System.out.print(constantPropagation.summaryInfo());
System.out.print(deadCodeElimination.summaryInfo()); System.out.print(deadCodeElimination.summaryInfo());
System.out.print(expressionSimplification.summaryInfo()); System.out.print(expressionSimplification.summaryInfo());
System.out.println(); System.out.println();

View File

@ -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<String, Integer> 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<String, Integer> e : propagatedVariables.entrySet()) {
sb.append("\n ").append(e.getKey()).append(": ").append(e.getValue());
}
}
return sb.toString();
}
public Node visit(Statement s) {
final Map<String, VariableInfo> variables = new HashMap<>();
// Find variables
s.accept(new VariablesGrabber(), variables);
// Filter only string/number values with 1 modification
final Map<String, Value> candidates = new HashMap<>();
for (Map.Entry<String, VariableInfo> 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<Map<String, VariableInfo>> {
@Override
public Node visit(AssignmentExpression s, Map<String, VariableInfo> 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<String, VariableInfo> 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<String, VariableInfo> 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<String, VariableInfo> t) {
// no visit match expression
return s;
}
}
private class VariablesPropagator extends OptimizationVisitor<Map<String, Value>> {
@Override
public Node visit(VariableExpression s, Map<String, Value> 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)";
}
}
}

View File

@ -17,8 +17,16 @@ import java.util.Set;
public final class VisitorUtils { 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) { public static Statement includeProgram(IncludeStatement s) {
if (!(s.expression instanceof ValueExpression)) return null; if (!isValue(s)) return null;
try { try {
return s.loadProgram(s.expression.eval().asString()); return s.loadProgram(s.expression.eval().asString());
} catch (IOException ex) { } catch (IOException ex) {
@ -27,7 +35,7 @@ public final class VisitorUtils {
} }
public static boolean isIntegerValue(Node node, int valueToCheck) { 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; final Value value = ((ValueExpression) node).value;
if (value.type() != Types.NUMBER) return false; if (value.type() != Types.NUMBER) return false;
@ -40,7 +48,7 @@ public final class VisitorUtils {
} }
public static boolean isSameVariables(Node n1, Node n2) { 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 v1 = (VariableExpression) n1;
final VariableExpression v2 = (VariableExpression) n2; final VariableExpression v2 = (VariableExpression) n2;
return v1.name.equals(v2.name); return v1.name.equals(v2.name);