Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(156)

Side by Side Diff: pkg/compiler/lib/src/tree_ir/optimization/statement_rewriter.dart

Issue 1175973005: dart2js cps: Introduce some built-in operators in type propagation. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Status files Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library tree_ir.optimization.statement_rewriter; 5 library tree_ir.optimization.statement_rewriter;
6 6
7 import 'optimization.dart' show Pass; 7 import 'optimization.dart' show Pass;
8 import '../tree_ir_nodes.dart'; 8 import '../tree_ir_nodes.dart';
9 9
10 /** 10 /**
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
109 * separated two ifs. 109 * separated two ifs.
110 */ 110 */
111 class StatementRewriter extends Transformer implements Pass { 111 class StatementRewriter extends Transformer implements Pass {
112 String get passName => 'Statement rewriter'; 112 String get passName => 'Statement rewriter';
113 113
114 @override 114 @override
115 void rewrite(FunctionDefinition node) { 115 void rewrite(FunctionDefinition node) {
116 node.body = visitStatement(node.body); 116 node.body = visitStatement(node.body);
117 } 117 }
118 118
119 /// True if targeting Dart.
120 final bool isDartMode;
121
122 /// The most recently evaluated impure expressions, with the most recent 119 /// The most recently evaluated impure expressions, with the most recent
123 /// expression being last. 120 /// expression being last.
124 /// 121 ///
125 /// Most importantly, this contains [Assign] expressions that we attempt to 122 /// Most importantly, this contains [Assign] expressions that we attempt to
126 /// inline at their use site. It also contains other impure expressions that 123 /// inline at their use site. It also contains other impure expressions that
127 /// we can propagate to a variable use if they are known to return the value 124 /// we can propagate to a variable use if they are known to return the value
128 /// of that variable. 125 /// of that variable.
129 /// 126 ///
127 /// Assignments with constant right-hand sides (see [isEffectivelyConstant])
128 /// are not considered impure and are put in [constantEnvironment] instead.
129 ///
130 /// Except for [Conditional]s, expressions in the environment have 130 /// Except for [Conditional]s, expressions in the environment have
131 /// not been processed, and all their subexpressions must therefore be 131 /// not been processed, and all their subexpressions must therefore be
132 /// variables uses. 132 /// variables uses.
133 List<Expression> environment = <Expression>[]; 133 List<Expression> environment = <Expression>[];
134 134
135 /// Binding environment for variables that are assigned to effectively 135 /// Binding environment for variables that are assigned to effectively
136 /// constant expressions (see [isEffectivelyConstant]). 136 /// constant expressions (see [isEffectivelyConstant]).
137 final Map<Variable, Expression> constantEnvironment; 137 final Map<Variable, Expression> constantEnvironment;
138 138
139 /// Substitution map for labels. Any break to a label L should be substituted 139 /// Substitution map for labels. Any break to a label L should be substituted
140 /// for a break to L' if L maps to L'. 140 /// for a break to L' if L maps to L'.
141 Map<Label, Jump> labelRedirects = <Label, Jump>{}; 141 Map<Label, Jump> labelRedirects = <Label, Jump>{};
142 142
143 /// Number of uses of the given variable that are still unseen. 143 /// Number of uses of the given variable that are still unseen.
144 /// Used to detect the first use of a variable (since we do backwards 144 /// Used to detect the first use of a variable (since we do backwards
145 /// traversal, the first use is the last one seen). 145 /// traversal, the first use is the last one seen).
146 Map<Variable, int> unseenUses = <Variable, int>{}; 146 Map<Variable, int> unseenUses = <Variable, int>{};
147 147
148 /// Rewriter for methods. 148 /// Rewriter for methods.
149 StatementRewriter({this.isDartMode}) 149 StatementRewriter() : constantEnvironment = <Variable, Expression>{};
150 : constantEnvironment = <Variable, Expression>{} {
151 assert(isDartMode != null);
152 }
153 150
154 /// Rewriter for nested functions. 151 /// Rewriter for nested functions.
155 StatementRewriter.nested(StatementRewriter parent) 152 StatementRewriter.nested(StatementRewriter parent)
156 : constantEnvironment = parent.constantEnvironment, 153 : constantEnvironment = parent.constantEnvironment,
157 unseenUses = parent.unseenUses, 154 unseenUses = parent.unseenUses;
158 isDartMode = parent.isDartMode;
159 155
160 /// A set of labels that can be safely inlined at their use. 156 /// A set of labels that can be safely inlined at their use.
161 /// 157 ///
162 /// The successor statements for labeled statements that have only one break 158 /// The successor statements for labeled statements that have only one break
163 /// from them are normally rewritten inline at the site of the break. This 159 /// from them are normally rewritten inline at the site of the break. This
164 /// is not safe if the code would be moved inside the scope of an exception 160 /// is not safe if the code would be moved inside the scope of an exception
165 /// handler (i.e., if the code would be moved into a try from outside it). 161 /// handler (i.e., if the code would be moved into a try from outside it).
166 Set<Label> safeForInlining = new Set<Label>(); 162 Set<Label> safeForInlining = new Set<Label>();
167 163
168 /// Returns the redirect target of [jump] or [jump] itself if it should not 164 /// Returns the redirect target of [jump] or [jump] itself if it should not
(...skipping 12 matching lines...) Expand all
181 } 177 }
182 178
183 /// Left-hand side of the given assignment, or `null` if not an assignment. 179 /// Left-hand side of the given assignment, or `null` if not an assignment.
184 Variable getLeftHand(Expression e) { 180 Variable getLeftHand(Expression e) {
185 return e is Assign ? e.variable : null; 181 return e is Assign ? e.variable : null;
186 } 182 }
187 183
188 /// If the given expression always returns the value of one of its 184 /// If the given expression always returns the value of one of its
189 /// subexpressions, returns that subexpression, otherwise `null`. 185 /// subexpressions, returns that subexpression, otherwise `null`.
190 Expression getValueSubexpression(Expression e) { 186 Expression getValueSubexpression(Expression e) {
191 if (isDartMode &&
192 e is InvokeMethod &&
193 (e.selector.isSetter || e.selector.isIndexSet)) {
194 return e.arguments.last;
195 }
196 if (e is SetField) return e.value; 187 if (e is SetField) return e.value;
197 return null; 188 return null;
198 } 189 }
199 190
200 /// If the given expression always returns the value of one of its 191 /// If the given expression always returns the value of one of its
201 /// subexpressions, and that subexpression is a variable use, returns that 192 /// subexpressions, and that subexpression is a variable use, returns that
202 /// variable. Otherwise `null`. 193 /// variable. Otherwise `null`.
203 Variable getRightHand(Expression e) { 194 Variable getRightHand(Expression e) {
204 Expression value = getValueSubexpression(e); 195 Expression value = getValueSubexpression(e);
205 return value is VariableUse ? value.variable : null; 196 return value is VariableUse ? value.variable : null;
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
257 environment.removeLast(); 248 environment.removeLast();
258 --node.variable.readCount; 249 --node.variable.readCount;
259 return visitExpression(binding); 250 return visitExpression(binding);
260 } 251 }
261 } 252 }
262 253
263 // If the definition could not be propagated, leave the variable use. 254 // If the definition could not be propagated, leave the variable use.
264 return node; 255 return node;
265 } 256 }
266 257
258 /// True if [exp] contains a use of a variable that was assigned to by the
259 /// most recently evaluated impure expression (constant assignments are not
260 /// considered impure).
261 ///
262 /// This implies that the assignment can be propagated into this use unless
263 /// the use is moved further away.
264 ///
265 /// In this case, we will refrain from moving [exp] across other impure
266 /// expressions, even when this is safe, because doing so would immediately
267 /// prevent the previous expression from propagating, canceling out the
268 /// benefit we might otherwise gain from propagating [exp].
269 ///
270 /// [exp] must be an unprocessed expression, i.e. either a [Conditional] or
271 /// an expression whose subexpressions are all variable uses.
272 bool usesRecentlyAssignedVariable(Expression exp) {
273 if (environment.isEmpty) return false;
274 Variable variable = getLeftHand(environment.last);
275 if (variable == null) return false;
276 IsVariableUsedVisitor visitor = new IsVariableUsedVisitor(variable);
277 visitor.visitExpression(exp);
278 return visitor.wasFound;
279 }
280
267 /// Returns true if [exp] has no side effects and has a constant value within 281 /// Returns true if [exp] has no side effects and has a constant value within
268 /// any given activation of the enclosing method. 282 /// any given activation of the enclosing method.
269 bool isEffectivelyConstant(Expression exp) { 283 bool isEffectivelyConstant(Expression exp) {
270 // TODO(asgerf): Can be made more aggressive e.g. by checking conditional 284 // TODO(asgerf): Can be made more aggressive e.g. by checking conditional
271 // expressions recursively. Determine if that is a valuable optimization 285 // expressions recursively. Determine if that is a valuable optimization
272 // and/or if it is better handled at the CPS level. 286 // and/or if it is better handled at the CPS level.
273 return exp is Constant || 287 return exp is Constant ||
274 exp is This || 288 exp is This ||
275 exp is CreateInvocationMirror || 289 exp is CreateInvocationMirror ||
276 exp is InvokeStatic && exp.isEffectivelyConstant || 290 exp is InvokeStatic && exp.isEffectivelyConstant ||
291 exp is ApplyBuiltinOperator ||
277 exp is VariableUse && constantEnvironment.containsKey(exp.variable); 292 exp is VariableUse && constantEnvironment.containsKey(exp.variable);
278 } 293 }
279 294
280 /// True if [node] is an assignment that can be propagated as a constant. 295 /// True if [node] is an assignment that can be propagated as a constant.
281 bool isEffectivelyConstantAssignment(Expression node) { 296 bool isEffectivelyConstantAssignment(Expression node) {
282 return node is Assign && 297 return node is Assign &&
283 node.variable.writeCount == 1 && 298 node.variable.writeCount == 1 &&
284 isEffectivelyConstant(node.value); 299 isEffectivelyConstant(node.value);
285 } 300 }
286 301
287 Statement visitExpressionStatement(ExpressionStatement stmt) { 302 Statement visitExpressionStatement(ExpressionStatement stmt) {
288 if (isEffectivelyConstantAssignment(stmt.expression)) { 303 if (isEffectivelyConstantAssignment(stmt.expression) &&
304 !usesRecentlyAssignedVariable(stmt.expression)) {
289 Assign assign = stmt.expression; 305 Assign assign = stmt.expression;
290 // Handle constant assignments specially. 306 // Handle constant assignments specially.
291 // They are always safe to propagate (though we should avoid duplication). 307 // They are always safe to propagate (though we should avoid duplication).
292 // Moreover, they should not prevent other expressions from propagating. 308 // Moreover, they should not prevent other expressions from propagating.
293 if (assign.variable.readCount <= 1) { 309 if (assign.variable.readCount <= 1) {
294 // A single-use constant should always be propagted to its use site. 310 // A single-use constant should always be propagted to its use site.
295 constantEnvironment[assign.variable] = assign.value; 311 constantEnvironment[assign.variable] = assign.value;
296 --assign.variable.writeCount; 312 --assign.variable.writeCount;
297 return visitStatement(stmt.next); 313 return visitStatement(stmt.next);
298 } else { 314 } else {
(...skipping 313 matching lines...) Expand 10 before | Expand all | Expand 10 after
612 Expression visitTypeExpression(TypeExpression node) { 628 Expression visitTypeExpression(TypeExpression node) {
613 _rewriteList(node.arguments); 629 _rewriteList(node.arguments);
614 return node; 630 return node;
615 } 631 }
616 632
617 Expression visitCreateInvocationMirror(CreateInvocationMirror node) { 633 Expression visitCreateInvocationMirror(CreateInvocationMirror node) {
618 _rewriteList(node.arguments); 634 _rewriteList(node.arguments);
619 return node; 635 return node;
620 } 636 }
621 637
638 /// True if [operator] is a binary operator that always has the same value
639 /// if its arguments are swapped.
640 bool isSymmetricOperator(BuiltinOperator operator) {
641 switch (operator) {
642 case BuiltinOperator.StrictEq:
643 case BuiltinOperator.StrictNeq:
644 case BuiltinOperator.LooseEq:
645 case BuiltinOperator.LooseNeq:
646 case BuiltinOperator.NumAnd:
647 case BuiltinOperator.NumOr:
648 case BuiltinOperator.NumXor:
649 case BuiltinOperator.NumAdd:
650 case BuiltinOperator.NumMultiply:
651 return true;
652 default:
653 return false;
654 }
655 }
656
657 /// If [operator] is a commutable binary operator, returns the commuted
658 /// operator, possibly the operator itself, otherwise returns `null`.
659 BuiltinOperator commuteBinaryOperator(BuiltinOperator operator) {
660 if (isSymmetricOperator(operator)) {
661 // Symmetric operators are their own commutes.
662 return operator;
663 }
664 switch(operator) {
665 case BuiltinOperator.NumLt: return BuiltinOperator.NumGt;
666 case BuiltinOperator.NumLe: return BuiltinOperator.NumGe;
667 case BuiltinOperator.NumGt: return BuiltinOperator.NumLt;
668 case BuiltinOperator.NumGe: return BuiltinOperator.NumLe;
669 default: return null;
670 }
671 }
672
673 /// Built-in binary operators are commuted when it is safe and can enable an
674 /// assignment propagation. For example:
675 ///
676 /// var x = foo();
677 /// var y = bar();
678 /// var z = y < x;
679 ///
680 /// ==>
681 ///
682 /// var z = foo() > bar();
683 ///
684 /// foo() must be evaluated before bar(), so the propagation is only possible
685 /// by commuting the operator.
686 Expression visitApplyBuiltinOperator(ApplyBuiltinOperator node) {
687 if (environment.isEmpty || getLeftHand(environment.last) == null) {
688 // If there is no recent assignment that might propagate, so there is no
689 // opportunity for optimization here.
690 _rewriteList(node.arguments);
691 return node;
692 }
693 Variable propagatableVariable = getLeftHand(environment.last);
694 BuiltinOperator commuted = commuteBinaryOperator(node.operator);
695 if (commuted != null) {
696 assert(node.arguments.length == 2); // Only binary operators can commute.
697 VariableUse arg1 = node.arguments[0];
698 VariableUse arg2 = node.arguments[1];
699 if (propagatableVariable == arg1.variable &&
700 propagatableVariable != arg2.variable &&
701 !constantEnvironment.containsKey(arg2.variable)) {
702 // An assignment can be propagated if we commute the operator.
703 node.operator = commuted;
704 node.arguments[0] = arg2;
705 node.arguments[1] = arg1;
706 }
707 }
708 _rewriteList(node.arguments);
709 return node;
710 }
711
622 /// If [s] and [t] are similar statements we extract their subexpressions 712 /// If [s] and [t] are similar statements we extract their subexpressions
623 /// and returns a new statement of the same type using expressions combined 713 /// and returns a new statement of the same type using expressions combined
624 /// with the [combine] callback. For example: 714 /// with the [combine] callback. For example:
625 /// 715 ///
626 /// combineStatements(Return E1, Return E2) = Return combine(E1, E2) 716 /// combineStatements(Return E1, Return E2) = Return combine(E1, E2)
627 /// 717 ///
628 /// If [combine] returns E1 then the unified statement is equivalent to [s], 718 /// If [combine] returns E1 then the unified statement is equivalent to [s],
629 /// and if [combine] returns E2 the unified statement is equivalence to [t]. 719 /// and if [combine] returns E2 the unified statement is equivalence to [t].
630 /// 720 ///
631 /// It is guaranteed that no side effects occur between the beginning of the 721 /// It is guaranteed that no side effects occur between the beginning of the
(...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after
916 } 1006 }
917 1007
918 /// Result of combining two expressions that do not affect reference counting. 1008 /// Result of combining two expressions that do not affect reference counting.
919 class GenericCombinedExpressions implements CombinedExpressions { 1009 class GenericCombinedExpressions implements CombinedExpressions {
920 Expression combined; 1010 Expression combined;
921 1011
922 GenericCombinedExpressions(this.combined); 1012 GenericCombinedExpressions(this.combined);
923 1013
924 void uncombine() {} 1014 void uncombine() {}
925 } 1015 }
1016
1017 /// Looks for uses of a specific variable.
1018 ///
1019 /// Note that this visitor is only applied to expressions where all
1020 /// sub-expressions are known to be variable uses, so there is no risk of
1021 /// explosive reprocessing.
1022 class IsVariableUsedVisitor extends RecursiveVisitor {
1023 Variable variable;
1024 bool wasFound = false;
1025
1026 IsVariableUsedVisitor(this.variable);
1027
1028 visitVariableUse(VariableUse node) {
1029 if (node.variable == variable) {
1030 wasFound = true;
1031 }
1032 }
1033
1034 visitInnerFunction(FunctionDefinition node) {}
1035 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698