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 |