Skip to content

Commit 357813e

Browse files
committed
Добавлена оптимизация: распространение констант
1 parent 6dbc045 commit 357813e

File tree

3 files changed

+177
-3
lines changed

3 files changed

+177
-3
lines changed

src/com/annimon/ownlang/parser/Optimizer.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.annimon.ownlang.parser.ast.Statement;
44
import com.annimon.ownlang.parser.visitors.ConstantFolding;
5+
import com.annimon.ownlang.parser.visitors.ConstantPropagation;
56
import com.annimon.ownlang.parser.visitors.DeadCodeElimination;
67
import com.annimon.ownlang.parser.visitors.ExpressionSimplification;
78

@@ -18,16 +19,19 @@ public static Statement optimize(Statement statement, int level) {
1819
if (level == 0) return statement;
1920

2021
final ConstantFolding constantFolding = new ConstantFolding();
22+
final ConstantPropagation constantPropagation = new ConstantPropagation();
2123
final DeadCodeElimination deadCodeElimination = new DeadCodeElimination();
2224
final ExpressionSimplification expressionSimplification = new ExpressionSimplification();
2325

2426
Statement result = statement;
2527
for (int i = 0; i < level; i++) {
2628
result = (Statement) result.accept(constantFolding, null);
29+
result = (Statement) constantPropagation.visit(result);
2730
result = (Statement) result.accept(deadCodeElimination, null);
2831
result = (Statement) result.accept(expressionSimplification, null);
2932
}
3033
System.out.print(constantFolding.summaryInfo());
34+
System.out.print(constantPropagation.summaryInfo());
3135
System.out.print(deadCodeElimination.summaryInfo());
3236
System.out.print(expressionSimplification.summaryInfo());
3337
System.out.println();
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
package com.annimon.ownlang.parser.visitors;
2+
3+
import com.annimon.ownlang.lib.Types;
4+
import com.annimon.ownlang.lib.Value;
5+
import com.annimon.ownlang.parser.Optimizer;
6+
import com.annimon.ownlang.parser.ast.Argument;
7+
import com.annimon.ownlang.parser.ast.AssignmentExpression;
8+
import com.annimon.ownlang.parser.ast.DestructuringAssignmentStatement;
9+
import com.annimon.ownlang.parser.ast.FunctionDefineStatement;
10+
import com.annimon.ownlang.parser.ast.MatchExpression;
11+
import com.annimon.ownlang.parser.ast.Node;
12+
import com.annimon.ownlang.parser.ast.Statement;
13+
import com.annimon.ownlang.parser.ast.ValueExpression;
14+
import com.annimon.ownlang.parser.ast.VariableExpression;
15+
import static com.annimon.ownlang.parser.visitors.VisitorUtils.isValue;
16+
import static com.annimon.ownlang.parser.visitors.VisitorUtils.isVariable;
17+
import java.util.HashMap;
18+
import java.util.Map;
19+
20+
/**
21+
* Performs constant propagation.
22+
*/
23+
public class ConstantPropagation implements Optimizer.Info {
24+
25+
private final Map<String, Integer> propagatedVariables;
26+
27+
public ConstantPropagation() {
28+
propagatedVariables = new HashMap<>();
29+
}
30+
31+
@Override
32+
public int optimizationsCount() {
33+
return propagatedVariables.size();
34+
}
35+
36+
@Override
37+
public String summaryInfo() {
38+
if (optimizationsCount() == 0) return "";
39+
final StringBuilder sb = new StringBuilder();
40+
if (propagatedVariables.size() > 0) {
41+
sb.append("\nConstant propagations: ").append(propagatedVariables.size());
42+
for (Map.Entry<String, Integer> e : propagatedVariables.entrySet()) {
43+
sb.append("\n ").append(e.getKey()).append(": ").append(e.getValue());
44+
}
45+
}
46+
return sb.toString();
47+
}
48+
49+
public Node visit(Statement s) {
50+
final Map<String, VariableInfo> variables = new HashMap<>();
51+
// Find variables
52+
s.accept(new VariablesGrabber(), variables);
53+
// Filter only string/number values with 1 modification
54+
final Map<String, Value> candidates = new HashMap<>();
55+
for (Map.Entry<String, VariableInfo> e : variables.entrySet()) {
56+
final VariableInfo info = e.getValue();
57+
if (info.modifications != 1) continue;
58+
if (info.value == null) continue;
59+
switch (info.value.type()) {
60+
case Types.NUMBER:
61+
case Types.STRING:
62+
candidates.put(e.getKey(), info.value);
63+
break;
64+
}
65+
}
66+
// Replace VariableExpression with ValueExpression
67+
return s.accept(new VariablesPropagator(), candidates);
68+
}
69+
70+
private class VariablesGrabber extends OptimizationVisitor<Map<String, VariableInfo>> {
71+
72+
@Override
73+
public Node visit(AssignmentExpression s, Map<String, VariableInfo> t) {
74+
if (!isVariable((Node)s.target)) {
75+
return super.visit(s, t);
76+
}
77+
78+
final String variableName = ((VariableExpression) s.target).name;
79+
final VariableInfo var;
80+
if (t.containsKey(variableName)) {
81+
var = t.get(variableName);
82+
var.modifications++;
83+
} else {
84+
var = new VariableInfo();
85+
var.modifications = 1;
86+
}
87+
88+
if (s.operation == null && isValue(s.expression)) {
89+
var.value = ((ValueExpression) s.expression).value;
90+
}
91+
t.put(variableName, var);
92+
return super.visit(s, t);
93+
}
94+
95+
@Override
96+
public Node visit(DestructuringAssignmentStatement s, Map<String, VariableInfo> t) {
97+
for (String variableName : s.variables) {
98+
if (variableName == null) continue;
99+
100+
final VariableInfo var;
101+
if (t.containsKey(variableName)) {
102+
var = t.get(variableName);
103+
var.modifications++;
104+
} else {
105+
var = new VariableInfo();
106+
var.modifications = 1;
107+
}
108+
t.put(variableName, var);
109+
}
110+
return super.visit(s, t);
111+
}
112+
113+
@Override
114+
public Node visit(FunctionDefineStatement s, Map<String, VariableInfo> t) {
115+
for (Argument argument : s.arguments) {
116+
final String variableName = argument.getName();
117+
final VariableInfo var;
118+
if (t.containsKey(variableName)) {
119+
var = t.get(variableName);
120+
var.modifications++;
121+
} else {
122+
var = new VariableInfo();
123+
var.modifications = 1;
124+
}
125+
t.put(variableName, var);
126+
}
127+
return super.visit(s, t);
128+
}
129+
130+
@Override
131+
public Node visit(MatchExpression s, Map<String, VariableInfo> t) {
132+
// no visit match expression
133+
return s;
134+
}
135+
}
136+
137+
private class VariablesPropagator extends OptimizationVisitor<Map<String, Value>> {
138+
139+
@Override
140+
public Node visit(VariableExpression s, Map<String, Value> t) {
141+
if (t.containsKey(s.name)) {
142+
if (!propagatedVariables.containsKey(s.name)) {
143+
propagatedVariables.put(s.name, 1);
144+
} else {
145+
propagatedVariables.put(s.name, 1 + propagatedVariables.get(s.name));
146+
}
147+
return new ValueExpression(t.get(s.name));
148+
}
149+
return super.visit(s, t);
150+
}
151+
}
152+
153+
private static class VariableInfo {
154+
Value value;
155+
int modifications;
156+
157+
@Override
158+
public String toString() {
159+
return (value == null ? "?" : value) + " (" + modifications + " mods)";
160+
}
161+
}
162+
}

src/com/annimon/ownlang/parser/visitors/VisitorUtils.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,16 @@
1717

1818
public final class VisitorUtils {
1919

20+
public static boolean isValue(Node node) {
21+
return (node instanceof ValueExpression);
22+
}
23+
24+
public static boolean isVariable(Node node) {
25+
return (node instanceof VariableExpression);
26+
}
27+
2028
public static Statement includeProgram(IncludeStatement s) {
21-
if (!(s.expression instanceof ValueExpression)) return null;
29+
if (!isValue(s)) return null;
2230
try {
2331
return s.loadProgram(s.expression.eval().asString());
2432
} catch (IOException ex) {
@@ -27,7 +35,7 @@ public static Statement includeProgram(IncludeStatement s) {
2735
}
2836

2937
public static boolean isIntegerValue(Node node, int valueToCheck) {
30-
if (!(node instanceof ValueExpression)) return false;
38+
if (!isValue(node)) return false;
3139

3240
final Value value = ((ValueExpression) node).value;
3341
if (value.type() != Types.NUMBER) return false;
@@ -40,7 +48,7 @@ public static boolean isIntegerValue(Node node, int valueToCheck) {
4048
}
4149

4250
public static boolean isSameVariables(Node n1, Node n2) {
43-
if ( (n1 instanceof VariableExpression) && (n2 instanceof VariableExpression) ) {
51+
if (isVariable(n1) && isVariable(n2)) {
4452
final VariableExpression v1 = (VariableExpression) n1;
4553
final VariableExpression v2 = (VariableExpression) n2;
4654
return v1.name.equals(v2.name);

0 commit comments

Comments
 (0)