OLD | NEW |
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 import '../../io/source_information.dart'; | 9 import '../../io/source_information.dart'; |
10 | 10 |
(...skipping 369 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
380 node = node.next; | 380 node = node.next; |
381 } | 381 } |
382 Statement result = visitStatement(node); | 382 Statement result = visitStatement(node); |
383 for (Function fun in stack.reversed) { | 383 for (Function fun in stack.reversed) { |
384 result = fun(result); | 384 result = fun(result); |
385 } | 385 } |
386 return result; | 386 return result; |
387 } | 387 } |
388 | 388 |
389 /// Attempts to propagate an assignment in an expression statement. | 389 /// Attempts to propagate an assignment in an expression statement. |
390 /// | 390 /// |
391 /// Returns a callback to be invoked after the sucessor statement has | 391 /// Returns a callback to be invoked after the sucessor statement has |
392 /// been processed. | 392 /// been processed. |
393 Function processExpressionStatement(ExpressionStatement stmt) { | 393 Function processExpressionStatement(ExpressionStatement stmt) { |
394 Variable leftHand = getLeftHand(stmt.expression); | 394 Variable leftHand = getLeftHand(stmt.expression); |
395 pushDominatingAssignment(leftHand); | 395 pushDominatingAssignment(leftHand); |
396 if (isEffectivelyConstantAssignment(stmt.expression) && | 396 if (isEffectivelyConstantAssignment(stmt.expression) && |
397 !usesRecentlyAssignedVariable(stmt.expression)) { | 397 !usesRecentlyAssignedVariable(stmt.expression)) { |
398 Assign assign = stmt.expression; | 398 Assign assign = stmt.expression; |
399 // Handle constant assignments specially. | 399 // Handle constant assignments specially. |
400 // They are always safe to propagate (though we should avoid duplication). | 400 // They are always safe to propagate (though we should avoid duplication). |
401 // Moreover, they should not prevent other expressions from propagating. | 401 // Moreover, they should not prevent other expressions from propagating. |
402 if (assign.variable.readCount == 1) { | 402 if (assign.variable.readCount == 1) { |
403 // A single-use constant should always be propagated to its use site. | 403 // A single-use constant should always be propagated to its use site. |
404 constantEnvironment[assign.variable] = assign.value; | 404 constantEnvironment[assign.variable] = assign.value; |
405 return (Statement next) { | 405 return (Statement next) { |
406 popDominatingAssignment(leftHand); | 406 popDominatingAssignment(leftHand); |
407 if (assign.variable.readCount > 0) { | 407 if (assign.variable.readCount > 0) { |
408 // The assignment could not be propagated into the successor, | 408 // The assignment could not be propagated into the successor, |
409 // either because it [hasUnsafeVariableUse] or because the | 409 // either because it [hasUnsafeVariableUse] or because the |
410 // use is outside the current try block, and we do not currently | 410 // use is outside the current try block, and we do not currently |
411 // support constant propagation out of a try block. | 411 // support constant propagation out of a try block. |
412 constantEnvironment.remove(assign.variable); | 412 constantEnvironment.remove(assign.variable); |
413 assign.value = visitExpression(assign.value); | 413 assign.value = visitExpression(assign.value); |
414 stmt.next = next; | 414 stmt.next = next; |
415 return stmt; | 415 return stmt; |
416 } else { | 416 } else { |
417 --assign.variable.writeCount; | 417 --assign.variable.writeCount; |
418 return next; | 418 return next; |
(...skipping 415 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
834 if (environment.isEmpty || getLeftHand(environment.last) == null) { | 834 if (environment.isEmpty || getLeftHand(environment.last) == null) { |
835 // If there is no recent assignment that might propagate, so there is no | 835 // If there is no recent assignment that might propagate, so there is no |
836 // opportunity for optimization here. | 836 // opportunity for optimization here. |
837 _rewriteList(node.arguments); | 837 _rewriteList(node.arguments); |
838 return node; | 838 return node; |
839 } | 839 } |
840 Variable propagatableVariable = getLeftHand(environment.last); | 840 Variable propagatableVariable = getLeftHand(environment.last); |
841 BuiltinOperator commuted = commuteBinaryOperator(node.operator); | 841 BuiltinOperator commuted = commuteBinaryOperator(node.operator); |
842 if (commuted != null) { | 842 if (commuted != null) { |
843 assert(node.arguments.length == 2); // Only binary operators can commute. | 843 assert(node.arguments.length == 2); // Only binary operators can commute. |
844 VariableUse arg1 = node.arguments[0]; | 844 Expression left = node.arguments[0]; |
845 VariableUse arg2 = node.arguments[1]; | 845 if (left is VariableUse && propagatableVariable == left.variable) { |
846 if (propagatableVariable == arg1.variable && | 846 Expression right = node.arguments[1]; |
847 propagatableVariable != arg2.variable && | 847 if (right is This || |
848 !constantEnvironment.containsKey(arg2.variable)) { | 848 (right is VariableUse && |
849 // An assignment can be propagated if we commute the operator. | 849 propagatableVariable != right.variable && |
850 node.operator = commuted; | 850 !constantEnvironment.containsKey(right.variable))) { |
851 node.arguments[0] = arg2; | 851 // An assignment can be propagated if we commute the operator. |
852 node.arguments[1] = arg1; | 852 node.operator = commuted; |
| 853 node.arguments[0] = right; |
| 854 node.arguments[1] = left; |
| 855 } |
853 } | 856 } |
854 } | 857 } |
855 _rewriteList(node.arguments); | 858 _rewriteList(node.arguments); |
856 return node; | 859 return node; |
857 } | 860 } |
858 | 861 |
859 /// If [s] and [t] are similar statements we extract their subexpressions | 862 /// If [s] and [t] are similar statements we extract their subexpressions |
860 /// and returns a new statement of the same type using expressions combined | 863 /// and returns a new statement of the same type using expressions combined |
861 /// with the [combine] callback. For example: | 864 /// with the [combine] callback. For example: |
862 /// | 865 /// |
(...skipping 354 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1217 VariableUseVisitor(this.callback); | 1220 VariableUseVisitor(this.callback); |
1218 | 1221 |
1219 visitVariableUse(VariableUse use) => callback(use); | 1222 visitVariableUse(VariableUse use) => callback(use); |
1220 | 1223 |
1221 visitInnerFunction(FunctionDefinition node) {} | 1224 visitInnerFunction(FunctionDefinition node) {} |
1222 | 1225 |
1223 static void visit(Expression node, VariableUseCallback callback) { | 1226 static void visit(Expression node, VariableUseCallback callback) { |
1224 new VariableUseVisitor(callback).visitExpression(node); | 1227 new VariableUseVisitor(callback).visitExpression(node); |
1225 } | 1228 } |
1226 } | 1229 } |
OLD | NEW |