| 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 350 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 361 exp is VariableUse && constantEnvironment.containsKey(exp.variable); | 361 exp is VariableUse && constantEnvironment.containsKey(exp.variable); |
| 362 } | 362 } |
| 363 | 363 |
| 364 /// True if [node] is an assignment that can be propagated as a constant. | 364 /// True if [node] is an assignment that can be propagated as a constant. |
| 365 bool isEffectivelyConstantAssignment(Expression node) { | 365 bool isEffectivelyConstantAssignment(Expression node) { |
| 366 return node is Assign && | 366 return node is Assign && |
| 367 node.variable.writeCount == 1 && | 367 node.variable.writeCount == 1 && |
| 368 isEffectivelyConstant(node.value); | 368 isEffectivelyConstant(node.value); |
| 369 } | 369 } |
| 370 | 370 |
| 371 Statement visitExpressionStatement(ExpressionStatement stmt) { | 371 Statement visitExpressionStatement(ExpressionStatement inputNode) { |
| 372 // Analyze chains of expression statements. |
| 373 // To avoid deep recursion, [processExpressionStatement] returns a callback |
| 374 // to invoke after its successor node has been processed. |
| 375 // These callbacks are stored in a list and invoked in reverse at the end. |
| 376 List<Function> stack = []; |
| 377 Statement node = inputNode; |
| 378 while (node is ExpressionStatement) { |
| 379 stack.add(processExpressionStatement(node)); |
| 380 node = node.next; |
| 381 } |
| 382 Statement result = visitStatement(node); |
| 383 for (Function fun in stack.reversed) { |
| 384 result = fun(result); |
| 385 } |
| 386 return result; |
| 387 } |
| 388 |
| 389 /// Attempts to propagate an assignment in an expression statement. |
| 390 /// |
| 391 /// Returns a callback to be invoked after the sucessor statement has |
| 392 /// been processed. |
| 393 Function processExpressionStatement(ExpressionStatement stmt) { |
| 372 Variable leftHand = getLeftHand(stmt.expression); | 394 Variable leftHand = getLeftHand(stmt.expression); |
| 373 pushDominatingAssignment(leftHand); | 395 pushDominatingAssignment(leftHand); |
| 374 if (isEffectivelyConstantAssignment(stmt.expression) && | 396 if (isEffectivelyConstantAssignment(stmt.expression) && |
| 375 !usesRecentlyAssignedVariable(stmt.expression)) { | 397 !usesRecentlyAssignedVariable(stmt.expression)) { |
| 376 Assign assign = stmt.expression; | 398 Assign assign = stmt.expression; |
| 377 // Handle constant assignments specially. | 399 // Handle constant assignments specially. |
| 378 // They are always safe to propagate (though we should avoid duplication). | 400 // They are always safe to propagate (though we should avoid duplication). |
| 379 // Moreover, they should not prevent other expressions from propagating. | 401 // Moreover, they should not prevent other expressions from propagating. |
| 380 if (assign.variable.readCount == 1) { | 402 if (assign.variable.readCount == 1) { |
| 381 // 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. |
| 382 constantEnvironment[assign.variable] = assign.value; | 404 constantEnvironment[assign.variable] = assign.value; |
| 383 Statement next = visitStatement(stmt.next); | 405 return (Statement next) { |
| 384 popDominatingAssignment(leftHand); | 406 popDominatingAssignment(leftHand); |
| 385 if (assign.variable.readCount > 0) { | 407 if (assign.variable.readCount > 0) { |
| 386 // The assignment could not be propagated into the successor, either | 408 // The assignment could not be propagated into the successor, |
| 387 // because it has an unsafe variable use (see [hasUnsafeVariableUse]) | 409 // either because it [hasUnsafeVariableUse] or because the |
| 388 // or because the use is outside the current try block, and we do | 410 // use is outside the current try block, and we do not currently |
| 389 // not currently support constant propagation out of a try block. | 411 // support constant propagation out of a try block. |
| 390 constantEnvironment.remove(assign.variable); | 412 constantEnvironment.remove(assign.variable); |
| 391 assign.value = visitExpression(assign.value); | 413 assign.value = visitExpression(assign.value); |
| 392 stmt.next = next; | 414 stmt.next = next; |
| 393 return stmt; | 415 return stmt; |
| 394 } else { | 416 } else { |
| 395 --assign.variable.writeCount; | 417 --assign.variable.writeCount; |
| 396 return next; | 418 return next; |
| 397 } | 419 } |
| 420 }; |
| 398 } else { | 421 } else { |
| 399 // With more than one use, we cannot propagate the constant. | 422 // With more than one use, we cannot propagate the constant. |
| 400 // Visit the following statement without polluting [environment] so | 423 // Visit the following statement without polluting [environment] so |
| 401 // that any preceding non-constant assignments might still propagate. | 424 // that any preceding non-constant assignments might still propagate. |
| 402 stmt.next = visitStatement(stmt.next); | 425 return (Statement next) { |
| 426 stmt.next = next; |
| 427 popDominatingAssignment(leftHand); |
| 428 assign.value = visitExpression(assign.value); |
| 429 return stmt; |
| 430 }; |
| 431 } |
| 432 } else { |
| 433 // Try to propagate the expression, and block previous impure expressions |
| 434 // until this has propagated. |
| 435 environment.add(stmt.expression); |
| 436 return (Statement next) { |
| 437 stmt.next = next; |
| 403 popDominatingAssignment(leftHand); | 438 popDominatingAssignment(leftHand); |
| 404 assign.value = visitExpression(assign.value); | 439 if (!environment.isEmpty && environment.last == stmt.expression) { |
| 405 return stmt; | 440 // Retain the expression statement. |
| 406 } | 441 environment.removeLast(); |
| 407 } | 442 stmt.expression = visitExpression(stmt.expression); |
| 408 // Try to propagate the expression, and block previous impure expressions | 443 return stmt; |
| 409 // until this has propagated. | 444 } else { |
| 410 environment.add(stmt.expression); | 445 // Expression was propagated into the successor. |
| 411 stmt.next = visitStatement(stmt.next); | 446 return stmt.next; |
| 412 popDominatingAssignment(leftHand); | 447 } |
| 413 if (!environment.isEmpty && environment.last == stmt.expression) { | 448 }; |
| 414 // Retain the expression statement. | |
| 415 environment.removeLast(); | |
| 416 stmt.expression = visitExpression(stmt.expression); | |
| 417 return stmt; | |
| 418 } else { | |
| 419 // Expression was propagated into the successor. | |
| 420 return stmt.next; | |
| 421 } | 449 } |
| 422 } | 450 } |
| 423 | 451 |
| 424 Expression visitAssign(Assign node) { | 452 Expression visitAssign(Assign node) { |
| 425 node.value = visitExpression(node.value); | 453 node.value = visitExpression(node.value); |
| 426 // Remove assignments to variables without any uses. This can happen | 454 // Remove assignments to variables without any uses. This can happen |
| 427 // because the assignment was propagated into its use, e.g: | 455 // because the assignment was propagated into its use, e.g: |
| 428 // | 456 // |
| 429 // { x = foo(); bar(x) } ==> bar(x = foo()) ==> bar(foo()) | 457 // { x = foo(); bar(x) } ==> bar(x = foo()) ==> bar(foo()) |
| 430 // | 458 // |
| (...skipping 738 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1169 VariableUseVisitor(this.callback); | 1197 VariableUseVisitor(this.callback); |
| 1170 | 1198 |
| 1171 visitVariableUse(VariableUse use) => callback(use); | 1199 visitVariableUse(VariableUse use) => callback(use); |
| 1172 | 1200 |
| 1173 visitInnerFunction(FunctionDefinition node) {} | 1201 visitInnerFunction(FunctionDefinition node) {} |
| 1174 | 1202 |
| 1175 static void visit(Expression node, VariableUseCallback callback) { | 1203 static void visit(Expression node, VariableUseCallback callback) { |
| 1176 new VariableUseVisitor(callback).visitExpression(node); | 1204 new VariableUseVisitor(callback).visitExpression(node); |
| 1177 } | 1205 } |
| 1178 } | 1206 } |
| OLD | NEW |