| 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 part of tree_ir.optimization; | 5 part of tree_ir.optimization; |
| 6 | 6 |
| 7 /// Rewrites [WhileTrue] statements with an [If] body into a [WhileCondition], | 7 /// Rewrites [WhileTrue] statements. |
| 8 /// in situations where only one of the branches contains a [Continue] to the | 8 /// |
| 9 /// loop. Schematically: | 9 /// Before this phase, loops usually contain a lot of "exit code", that is, |
| 10 /// code that happens at a point where a [Continue] can no longer be reached, |
| 11 /// and is therefore not really part of the loop. |
| 12 /// Exit code is moved down after the loop using the following rewrites rules: |
| 13 /// |
| 14 /// EXTRACT LABELED STATEMENT: |
| 10 /// | 15 /// |
| 11 /// L: | 16 /// L: |
| 12 /// while (true) { | 17 /// while (true) { |
| 18 /// L2: { |
| 19 /// S1 (has references to L) |
| 20 /// } |
| 21 /// S2 (has no references to L) |
| 22 /// } |
| 23 /// |
| 24 /// ==> |
| 25 /// |
| 26 /// L2: { |
| 27 /// L: while (true) S1 |
| 28 /// } |
| 29 /// S2 |
| 30 /// |
| 31 /// INTRODUCE CONDITIONAL LOOP: |
| 32 /// |
| 33 /// L: |
| 34 /// while (true) { |
| 13 /// if (E) { | 35 /// if (E) { |
| 14 /// S1 (has references to L) | 36 /// S1 (has references to L) |
| 15 /// } else { | 37 /// } else { |
| 16 /// S2 (has no references to L) | 38 /// S2 (has no references to L) |
| 17 /// } | 39 /// } |
| 18 /// } | 40 /// } |
| 19 /// ==> | 41 /// ==> |
| 20 /// L: | 42 /// L: |
| 21 /// while (E) { | 43 /// while (E) { |
| 22 /// S1 | 44 /// S1 |
| 23 /// }; | 45 /// }; |
| 24 /// S2 | 46 /// S2 |
| 25 /// | 47 /// |
| 26 /// A similar transformation is used when S2 occurs in the 'then' position. | 48 /// A similar transformation is used when S2 occurs in the 'then' position. |
| 27 /// | 49 /// |
| 28 /// Note that the above pattern needs no iteration since nested ifs | 50 /// Note that the last pattern above needs no iteration since nested ifs |
| 29 /// have been collapsed previously in the [StatementRewriter] phase. | 51 /// have been collapsed previously in the [StatementRewriter] phase. |
| 52 /// |
| 53 /// [WhileCondition] statements exist only after this phase. |
| 30 class LoopRewriter extends RecursiveTransformer | 54 class LoopRewriter extends RecursiveTransformer |
| 31 implements Pass { | 55 implements Pass { |
| 32 String get passName => 'Loop rewriter'; | 56 String get passName => 'Loop rewriter'; |
| 33 | 57 |
| 34 Set<Label> usedContinueLabels = new Set<Label>(); | 58 Set<Label> usedContinueLabels = new Set<Label>(); |
| 35 | 59 |
| 36 void rewrite(RootNode root) { | 60 void rewrite(RootNode root) { |
| 37 root.replaceEachBody(visitStatement); | 61 root.replaceEachBody(visitStatement); |
| 38 } | 62 } |
| 39 | 63 |
| 40 @override | 64 @override |
| 41 void visitInnerFunction(FunctionDefinition node) { | 65 void visitInnerFunction(FunctionDefinition node) { |
| 42 node.body = new LoopRewriter().visitStatement(node.body); | 66 node.body = new LoopRewriter().visitStatement(node.body); |
| 43 } | 67 } |
| 44 | 68 |
| 45 Statement visitContinue(Continue node) { | 69 Statement visitContinue(Continue node) { |
| 46 usedContinueLabels.add(node.target); | 70 usedContinueLabels.add(node.target); |
| 47 return node; | 71 return node; |
| 48 } | 72 } |
| 49 | 73 |
| 50 Statement visitWhileTrue(WhileTrue node) { | 74 Statement visitWhileTrue(WhileTrue node) { |
| 51 assert(!usedContinueLabels.contains(node.label)); | 75 assert(!usedContinueLabels.contains(node.label)); |
| 76 |
| 77 // Pull labeled statements outside the loop when possible. |
| 78 // [head] and [tail] are the first and last labeled statements that were |
| 79 // pulled out, and null when none have been pulled out. |
| 80 LabeledStatement head, tail; |
| 81 while (node.body is LabeledStatement) { |
| 82 LabeledStatement inner = node.body; |
| 83 inner.next = visitStatement(inner.next); |
| 84 bool nextHasContinue = usedContinueLabels.remove(node.label); |
| 85 if (nextHasContinue) break; |
| 86 node.body = inner.body; |
| 87 inner.body = node; |
| 88 if (head == null) { |
| 89 head = tail = inner; |
| 90 } else { |
| 91 tail.body = inner; |
| 92 tail = inner; |
| 93 } |
| 94 } |
| 95 |
| 96 // Rewrite while(true) to while(condition). |
| 97 Statement loop = node; |
| 52 if (node.body is If) { | 98 if (node.body is If) { |
| 53 If body = node.body; | 99 If body = node.body; |
| 54 body.thenStatement = visitStatement(body.thenStatement); | 100 body.thenStatement = visitStatement(body.thenStatement); |
| 55 bool thenHasContinue = usedContinueLabels.remove(node.label); | 101 bool thenHasContinue = usedContinueLabels.remove(node.label); |
| 56 body.elseStatement = visitStatement(body.elseStatement); | 102 body.elseStatement = visitStatement(body.elseStatement); |
| 57 bool elseHasContinue = usedContinueLabels.remove(node.label); | 103 bool elseHasContinue = usedContinueLabels.remove(node.label); |
| 58 if (thenHasContinue && !elseHasContinue) { | 104 if (thenHasContinue && !elseHasContinue) { |
| 59 node.label.binding = null; // Prepare to rebind the label. | 105 node.label.binding = null; // Prepare to rebind the label. |
| 60 return new WhileCondition( | 106 loop = new WhileCondition( |
| 61 node.label, | 107 node.label, |
| 62 body.condition, | 108 body.condition, |
| 63 body.thenStatement, | 109 body.thenStatement, |
| 64 body.elseStatement); | 110 body.elseStatement); |
| 65 } else if (!thenHasContinue && elseHasContinue) { | 111 } else if (!thenHasContinue && elseHasContinue) { |
| 66 node.label.binding = null; | 112 node.label.binding = null; |
| 67 return new WhileCondition( | 113 loop = new WhileCondition( |
| 68 node.label, | 114 node.label, |
| 69 new Not(body.condition), | 115 new Not(body.condition), |
| 70 body.elseStatement, | 116 body.elseStatement, |
| 71 body.thenStatement); | 117 body.thenStatement); |
| 72 } | 118 } |
| 119 } else if (node.body is LabeledStatement) { |
| 120 // If the body is a labeled statement, its .next has already been visited. |
| 121 LabeledStatement body = node.body; |
| 122 body.body = visitStatement(body.body); |
| 123 usedContinueLabels.remove(node.label); |
| 73 } else { | 124 } else { |
| 74 node.body = visitStatement(node.body); | 125 node.body = visitStatement(node.body); |
| 75 usedContinueLabels.remove(node.label); | 126 usedContinueLabels.remove(node.label); |
| 76 } | 127 } |
| 77 return node; | 128 |
| 129 if (head == null) return loop; |
| 130 tail.body = loop; |
| 131 return head; |
| 78 } | 132 } |
| 79 } | 133 } |
| OLD | NEW |