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

Side by Side Diff: pkg/compiler/lib/src/tree_ir/optimization/loop_rewriter.dart

Issue 1287253002: dart2js cps: Compile some loops as 'for' loops. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years, 4 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.loop_rewriter; 5 library tree_ir.optimization.loop_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 /// Rewrites [WhileTrue] statements. 10 /// Rewrites [WhileTrue] statements into [WhileCondition] statements.
11 /// 11 ///
12 /// Before this phase, loops usually contain a lot of "exit code", that is, 12 /// Before this phase, loops usually contain a lot of "exit code", that is,
13 /// code that happens at a point where a [Continue] can no longer be reached, 13 /// code that happens at a point where a [Continue] can no longer be reached,
14 /// and is therefore not really part of the loop. 14 /// and is therefore not really part of the loop.
15 /// Exit code is moved down after the loop using the following rewrites rules: 15 /// Exit code is moved down after the loop using the following rewrites rules:
16 /// 16 ///
17 /// EXTRACT LABELED STATEMENT: 17 /// EXTRACT LABELED STATEMENT:
18 /// 18 ///
19 /// L: 19 /// L:
20 /// while (true) { 20 /// while (true) {
(...skipping 22 matching lines...) Expand all
43 /// } 43 /// }
44 /// ==> 44 /// ==>
45 /// L: 45 /// L:
46 /// while (E) { 46 /// while (E) {
47 /// S1 47 /// S1
48 /// }; 48 /// };
49 /// S2 49 /// S2
50 /// 50 ///
51 /// A similar transformation is used when S2 occurs in the 'then' position. 51 /// A similar transformation is used when S2 occurs in the 'then' position.
52 /// 52 ///
53 /// Note that the last pattern above needs no iteration since nested ifs 53 /// Note that the pattern above needs no iteration since nested ifs have been
54 /// have been collapsed previously in the [StatementRewriter] phase. 54 /// collapsed previously in the [StatementRewriter] phase.
55 ///
55 /// 56 ///
56 /// [WhileCondition] statements exist only after this phase. 57 /// PULL INTO UPDATE EXPRESSION:
58 ///
59 /// Assignment expressions before the unique continue to a [whileCondition] are
60 /// pulled into the updates for the loop.
61 ///
62 /// L:
63 /// for (; condition; updates) {
64 /// S [ x = E; continue L ]
65 /// }
66 /// ==>
67 /// L:
68 /// for (; condition; updates, x = E) {
69 /// S [ continue L ]
70 /// }
71 ///
72 /// The decision to only pull in assignments is a heuristic to balance
73 /// readability and stack trace usability versus the modest code size
74 /// reduction one might get by aggressively moving expressions into the
75 /// updates.
57 class LoopRewriter extends RecursiveTransformer 76 class LoopRewriter extends RecursiveTransformer
58 implements Pass { 77 implements Pass {
59 String get passName => 'Loop rewriter'; 78 String get passName => 'Loop rewriter';
60 79
61 Set<Label> usedContinueLabels = new Set<Label>(); 80 Set<Label> usedContinueLabels = new Set<Label>();
62 81
82 /// Maps loop labels to a list, if that loop can accept update expressions.
83 /// The list will then be populated while traversing the body of that loop.
84 /// If a loop is not in the map, update expressions cannot be hoisted there.
85 Map<Label, List<Expression>> updateExpressions = <Label, List<Expression>>{};
86
63 void rewrite(FunctionDefinition root) { 87 void rewrite(FunctionDefinition root) {
64 root.body = visitStatement(root.body); 88 root.body = visitStatement(root.body);
65 } 89 }
66 90
67 @override 91 @override
68 void visitInnerFunction(FunctionDefinition node) { 92 void visitInnerFunction(FunctionDefinition node) {
69 node.body = new LoopRewriter().visitStatement(node.body); 93 node.body = new LoopRewriter().visitStatement(node.body);
70 } 94 }
71 95
72 Statement visitContinue(Continue node) { 96 Statement visitContinue(Continue node) {
(...skipping 20 matching lines...) Expand all
93 } else { 117 } else {
94 tail.body = inner; 118 tail.body = inner;
95 tail = inner; 119 tail = inner;
96 } 120 }
97 } 121 }
98 122
99 // Rewrite while(true) to while(condition). 123 // Rewrite while(true) to while(condition).
100 Statement loop = node; 124 Statement loop = node;
101 if (node.body is If) { 125 if (node.body is If) {
102 If body = node.body; 126 If body = node.body;
127 updateExpressions[node.label] = <Expression>[];
103 body.thenStatement = visitStatement(body.thenStatement); 128 body.thenStatement = visitStatement(body.thenStatement);
104 bool thenHasContinue = usedContinueLabels.remove(node.label); 129 bool thenHasContinue = usedContinueLabels.remove(node.label);
105 body.elseStatement = visitStatement(body.elseStatement); 130 body.elseStatement = visitStatement(body.elseStatement);
106 bool elseHasContinue = usedContinueLabels.remove(node.label); 131 bool elseHasContinue = usedContinueLabels.remove(node.label);
107 if (thenHasContinue && !elseHasContinue) { 132 if (thenHasContinue && !elseHasContinue) {
108 node.label.binding = null; // Prepare to rebind the label. 133 node.label.binding = null; // Prepare to rebind the label.
109 loop = new WhileCondition( 134 loop = new WhileCondition(
110 node.label, 135 node.label,
111 body.condition, 136 body.condition,
137 updateExpressions[node.label],
112 body.thenStatement, 138 body.thenStatement,
113 body.elseStatement); 139 body.elseStatement);
114 } else if (!thenHasContinue && elseHasContinue) { 140 } else if (!thenHasContinue && elseHasContinue) {
115 node.label.binding = null; 141 node.label.binding = null;
116 loop = new WhileCondition( 142 loop = new WhileCondition(
117 node.label, 143 node.label,
118 new Not(body.condition), 144 new Not(body.condition),
145 updateExpressions[node.label],
119 body.elseStatement, 146 body.elseStatement,
120 body.thenStatement); 147 body.thenStatement);
121 } 148 }
122 } else if (node.body is LabeledStatement) { 149 } else if (node.body is LabeledStatement) {
123 // If the body is a labeled statement, its .next has already been visited. 150 // If the body is a labeled statement, its .next has already been visited.
124 LabeledStatement body = node.body; 151 LabeledStatement body = node.body;
125 body.body = visitStatement(body.body); 152 body.body = visitStatement(body.body);
126 usedContinueLabels.remove(node.label); 153 usedContinueLabels.remove(node.label);
127 } else { 154 } else {
128 node.body = visitStatement(node.body); 155 node.body = visitStatement(node.body);
129 usedContinueLabels.remove(node.label); 156 usedContinueLabels.remove(node.label);
130 } 157 }
131 158
132 if (head == null) return loop; 159 if (head == null) return loop;
133 tail.body = loop; 160 tail.body = loop;
134 return head; 161 return head;
135 } 162 }
163
164 Statement visitExpressionStatement(ExpressionStatement node) {
165 if (updateExpressions.isEmpty) {
166 // Avoid allocating a list if there is no loop.
167 return super.visitExpressionStatement(node);
168 }
169 List<ExpressionStatement> statements = <ExpressionStatement>[];
170 while (node.next is ExpressionStatement) {
171 statements.add(node);
172 node = node.next;
173 }
174 statements.add(node);
175 Statement next = visitStatement(node.next);
176 if (next is Continue && next.target.useCount == 1) {
177 List<Expression> updates = updateExpressions[next.target];
178 if (updates != null) {
179 // Pull expressions before the continue into the for loop update.
180 // As a heuristic, we only pull in assignment expressions.
181 // Determine the index of the first assignment to pull in.
182 int assignIndex = 0;
Kevin Millikin (Google) 2015/08/13 11:32:47 Seems kind of tricky that this might be one past t
asgerf 2015/08/13 12:06:42 Yeah that looks better. Done.
183 for (int i = 0; i < statements.length; i++) {
184 if (statements[i].expression is! Assign) {
185 assignIndex = i + 1;
186 }
187 }
188 for (ExpressionStatement stmt in statements.skip(assignIndex)) {
189 updates.add(stmt.expression);
190 }
191 if (assignIndex > 0) {
192 statements[assignIndex - 1].next = next;
193 return statements.first;
194 } else {
195 return next;
196 }
197 }
198 }
199 // The expression statements could not be pulled into a loop update.
200 node.next = next;
201 return statements.first;
202 }
136 } 203 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698