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

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: Improve propagation heuristic 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 246 matching lines...) Expand 10 before | Expand all | Expand 10 after
257 environment.removeLast(); 257 environment.removeLast();
258 --node.variable.readCount; 258 --node.variable.readCount;
259 return visitExpression(binding); 259 return visitExpression(binding);
260 } 260 }
261 } 261 }
262 262
263 // If the definition could not be propagated, leave the variable use. 263 // If the definition could not be propagated, leave the variable use.
264 return node; 264 return node;
265 } 265 }
266 266
267 /// True if [exp] contains a use of a variable that was assigned to by the
Kevin Millikin (Google) 2015/06/12 12:19:10 "a variable" ==> "the variable" seems more clear.
asgerf 2015/06/15 09:26:18 Not all expressions assign to a variable, so "the"
268 /// most recently evaluated impure expression.
269 ///
270 /// This implies that the assignment can be propagated into this use unless
271 /// the use is moved further away.
272 ///
273 /// In this case, we will refrain from moving [exp] across other impure
274 /// expressions, even when this is safe, because doing so would immediately
275 /// prevent the previous expression from propagating, canceling out the
276 /// benefit we might otherwise gain from propagating [exp].
277 bool usesRecentlyAssignedVariable(Expression exp) {
278 if (environment.isEmpty) return false;
279 Variable variable = getLeftHand(environment.last);
280 if (variable == null) return false;
281 IsVariableUsedVisitor visitor = new IsVariableUsedVisitor(variable);
282 visitor.visitExpression(exp);
283 return visitor.wasFound;
284 }
285
267 /// Returns true if [exp] has no side effects and has a constant value within 286 /// Returns true if [exp] has no side effects and has a constant value within
268 /// any given activation of the enclosing method. 287 /// any given activation of the enclosing method.
269 bool isEffectivelyConstant(Expression exp) { 288 bool isEffectivelyConstant(Expression exp) {
270 // TODO(asgerf): Can be made more aggressive e.g. by checking conditional 289 // TODO(asgerf): Can be made more aggressive e.g. by checking conditional
271 // expressions recursively. Determine if that is a valuable optimization 290 // expressions recursively. Determine if that is a valuable optimization
272 // and/or if it is better handled at the CPS level. 291 // and/or if it is better handled at the CPS level.
273 return exp is Constant || 292 return exp is Constant ||
274 exp is This || 293 exp is This ||
275 exp is CreateInvocationMirror || 294 exp is CreateInvocationMirror ||
276 exp is InvokeStatic && exp.isEffectivelyConstant || 295 exp is InvokeStatic && exp.isEffectivelyConstant ||
296 exp is ApplyBuiltinOperator ||
277 exp is VariableUse && constantEnvironment.containsKey(exp.variable); 297 exp is VariableUse && constantEnvironment.containsKey(exp.variable);
278 } 298 }
279 299
280 /// True if [node] is an assignment that can be propagated as a constant. 300 /// True if [node] is an assignment that can be propagated as a constant.
281 bool isEffectivelyConstantAssignment(Expression node) { 301 bool isEffectivelyConstantAssignment(Expression node) {
282 return node is Assign && 302 return node is Assign &&
283 node.variable.writeCount == 1 && 303 node.variable.writeCount == 1 &&
284 isEffectivelyConstant(node.value); 304 isEffectivelyConstant(node.value);
285 } 305 }
286 306
287 Statement visitExpressionStatement(ExpressionStatement stmt) { 307 Statement visitExpressionStatement(ExpressionStatement stmt) {
288 if (isEffectivelyConstantAssignment(stmt.expression)) { 308 if (isEffectivelyConstantAssignment(stmt.expression) &&
309 !usesRecentlyAssignedVariable(stmt.expression)) {
289 Assign assign = stmt.expression; 310 Assign assign = stmt.expression;
290 // Handle constant assignments specially. 311 // Handle constant assignments specially.
291 // They are always safe to propagate (though we should avoid duplication). 312 // They are always safe to propagate (though we should avoid duplication).
292 // Moreover, they should not prevent other expressions from propagating. 313 // Moreover, they should not prevent other expressions from propagating.
293 if (assign.variable.readCount <= 1) { 314 if (assign.variable.readCount <= 1) {
294 // A single-use constant should always be propagted to its use site. 315 // A single-use constant should always be propagted to its use site.
295 constantEnvironment[assign.variable] = assign.value; 316 constantEnvironment[assign.variable] = assign.value;
296 --assign.variable.writeCount; 317 --assign.variable.writeCount;
297 return visitStatement(stmt.next); 318 return visitStatement(stmt.next);
298 } else { 319 } else {
(...skipping 313 matching lines...) Expand 10 before | Expand all | Expand 10 after
612 Expression visitTypeExpression(TypeExpression node) { 633 Expression visitTypeExpression(TypeExpression node) {
613 _rewriteList(node.arguments); 634 _rewriteList(node.arguments);
614 return node; 635 return node;
615 } 636 }
616 637
617 Expression visitCreateInvocationMirror(CreateInvocationMirror node) { 638 Expression visitCreateInvocationMirror(CreateInvocationMirror node) {
618 _rewriteList(node.arguments); 639 _rewriteList(node.arguments);
619 return node; 640 return node;
620 } 641 }
621 642
643 /// True if [operator] is a binary operator that always has the same value
644 /// if its arguments are swapped.
645 bool isSymmetricOperator(BuiltinOperator operator) {
646 switch (operator) {
647 case BuiltinOperator.StrictEq:
648 case BuiltinOperator.StrictNeq:
649 case BuiltinOperator.LooseEq:
650 case BuiltinOperator.LooseNeq:
651 case BuiltinOperator.NumAnd:
652 case BuiltinOperator.NumOr:
653 case BuiltinOperator.NumXor:
654 case BuiltinOperator.NumAdd:
655 case BuiltinOperator.NumMultiply:
656 return true;
657 default:
658 return false;
659 }
660 }
661
662 /// If [operator] is a commutable binary operator, returns the commuted
663 /// operator, possibly the operator itself, otherwise returns `null`.
664 BuiltinOperator commuteBinaryOperator(BuiltinOperator operator) {
665 if (isSymmetricOperator(operator)) {
666 // Symmetric operators are their own commutes.
667 return operator;
668 }
669 switch(operator) {
670 case BuiltinOperator.NumLt: return BuiltinOperator.NumGt;
671 case BuiltinOperator.NumLe: return BuiltinOperator.NumGe;
672 case BuiltinOperator.NumGt: return BuiltinOperator.NumLt;
673 case BuiltinOperator.NumGe: return BuiltinOperator.NumLe;
674 default: return null;
675 }
676 }
677
678 /// Built-in binary operators are commuted when it is safe and can enable an
679 /// assignment propagation. For example:
680 ///
681 /// var x = foo();
682 /// var y = bar();
683 /// var z = y < x;
684 ///
685 /// ==>
686 ///
687 /// var z = foo() > bar();
688 ///
689 /// foo() must be evaluated before bar(), so the propagation is only possible
690 /// by commuting the operator.
691 Expression visitApplyBuiltinOperator(ApplyBuiltinOperator node) {
692 if (environment.isEmpty || getLeftHand(environment.last) == null) {
693 // If there is no recent assignment that might propagate, so there is no
694 // opportunity for optimization here.
695 _rewriteList(node.arguments);
696 return node;
697 }
698 Variable propagatableVariable = getLeftHand(environment.last);
699 BuiltinOperator commuted = commuteBinaryOperator(node.operator);
700 if (commuted != null) {
701 assert(node.arguments.length == 2); // Only binary operators can commute.
702 VariableUse arg1 = node.arguments[0];
703 VariableUse arg2 = node.arguments[1];
704 if (propagatableVariable == arg1.variable &&
705 propagatableVariable != arg2.variable &&
706 !constantEnvironment.containsKey(arg2.variable)) {
707 // An assignment can be propagated if we commute the operator.
708 node.operator = commuted;
709 node.arguments[0] = arg2;
710 node.arguments[1] = arg1;
711 }
712 }
713 _rewriteList(node.arguments);
714 return node;
715 }
716
622 /// If [s] and [t] are similar statements we extract their subexpressions 717 /// If [s] and [t] are similar statements we extract their subexpressions
623 /// and returns a new statement of the same type using expressions combined 718 /// and returns a new statement of the same type using expressions combined
624 /// with the [combine] callback. For example: 719 /// with the [combine] callback. For example:
625 /// 720 ///
626 /// combineStatements(Return E1, Return E2) = Return combine(E1, E2) 721 /// combineStatements(Return E1, Return E2) = Return combine(E1, E2)
627 /// 722 ///
628 /// If [combine] returns E1 then the unified statement is equivalent to [s], 723 /// 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]. 724 /// and if [combine] returns E2 the unified statement is equivalence to [t].
630 /// 725 ///
631 /// It is guaranteed that no side effects occur between the beginning of the 726 /// 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 } 1011 }
917 1012
918 /// Result of combining two expressions that do not affect reference counting. 1013 /// Result of combining two expressions that do not affect reference counting.
919 class GenericCombinedExpressions implements CombinedExpressions { 1014 class GenericCombinedExpressions implements CombinedExpressions {
920 Expression combined; 1015 Expression combined;
921 1016
922 GenericCombinedExpressions(this.combined); 1017 GenericCombinedExpressions(this.combined);
923 1018
924 void uncombine() {} 1019 void uncombine() {}
925 } 1020 }
1021
1022 /// Looks for uses of a specific variable.
1023 ///
1024 /// Note that this visitor is only applied to expressions where all
Kevin Millikin (Google) 2015/06/12 12:19:10 You might mention this as well (that it's cheap) a
asgerf 2015/06/15 09:26:18 Added another comment at the use-site to clarify.
1025 /// sub-expressions are known to be variable uses, so there is no risk of
1026 /// explosive reprocessing.
1027 class IsVariableUsedVisitor extends RecursiveVisitor {
1028 Variable variable;
1029 bool wasFound = false;
1030
1031 IsVariableUsedVisitor(this.variable);
1032
1033 visitVariableUse(VariableUse node) {
1034 if (node.variable == variable) {
1035 wasFound = true;
1036 }
1037 }
1038
1039 visitInnerFunction(FunctionDefinition node) {}
1040 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698