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

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

Issue 1215503012: dart2js cps: Do not propagate uses of loop variables past their update. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Another non-complex -> simple Created 5 years, 5 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
« no previous file with comments | « no previous file | tests/compiler/dart2js_extra/dart2js_extra.status » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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.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 9
10 /** 10 /**
11 * Performs the following transformations on the tree: 11 * Translates to direct-style.
12 *
13 * In addition to the general IR constraints (see [CheckTreeIntegrity]),
14 * the input is assumed to satisfy the following criteria:
15 *
16 * All expressions other than those nested in [Assign] or [ExpressionStatement]
17 * must be simple. A [VariableUse] and [This] is a simple expression.
18 * The right-hand of an [Assign] may not be an [Assign].
19 *
20 * Moreover, every variable must either be an SSA variable or a mutable
21 * variable, and must satisfy the corresponding criteria:
22 *
23 * SSA VARIABLE:
24 * An SSA variable must have a unique definition site, which is either an
25 * assignment or label. In case of a label, its target must act as the unique
26 * reaching definition of that variable at all uses of the variable and at
27 * all other label targets where the variable is in scope.
28 *
29 * (The second criterion is to ensure that we can move a use of an SSA variable
30 * across a label without changing its reaching definition).
31 *
32 * MUTABLE VARIABLE:
33 * Uses of mutable variables are considered complex expressions, and hence must
34 * not be nested in other expressions. Assignments to mutable variables must
35 * have simple right-hand sides.
36 *
37 * ----
38 *
39 * This pass performs the following transformations on the tree:
12 * - Assignment inlining 40 * - Assignment inlining
13 * - Assignment expression propagation 41 * - Assignment expression propagation
14 * - If-to-conditional conversion 42 * - If-to-conditional conversion
15 * - Flatten nested ifs 43 * - Flatten nested ifs
16 * - Break inlining 44 * - Break inlining
17 * - Redirect breaks 45 * - Redirect breaks
18 * 46 *
19 * The above transformations all eliminate statements from the tree, and may 47 * The above transformations all eliminate statements from the tree, and may
20 * introduce redexes of each other. 48 * introduce redexes of each other.
21 * 49 *
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
106 * {... jump L1 ...} 134 * {... jump L1 ...}
107 * 135 *
108 * This may trigger a flattening of nested ifs in case the eliminated label 136 * This may trigger a flattening of nested ifs in case the eliminated label
109 * separated two ifs. 137 * separated two ifs.
110 */ 138 */
111 class StatementRewriter extends Transformer implements Pass { 139 class StatementRewriter extends Transformer implements Pass {
112 String get passName => 'Statement rewriter'; 140 String get passName => 'Statement rewriter';
113 141
114 @override 142 @override
115 void rewrite(FunctionDefinition node) { 143 void rewrite(FunctionDefinition node) {
144 node.parameters.forEach(pushDominatingAssignment);
116 node.body = visitStatement(node.body); 145 node.body = visitStatement(node.body);
146 node.parameters.forEach(popDominatingAssignment);
117 } 147 }
118 148
119 /// The most recently evaluated impure expressions, with the most recent 149 /// The most recently evaluated impure expressions, with the most recent
120 /// expression being last. 150 /// expression being last.
121 /// 151 ///
122 /// Most importantly, this contains [Assign] expressions that we attempt to 152 /// Most importantly, this contains [Assign] expressions that we attempt to
123 /// inline at their use site. It also contains other impure expressions that 153 /// inline at their use site. It also contains other impure expressions that
124 /// we can propagate to a variable use if they are known to return the value 154 /// we can propagate to a variable use if they are known to return the value
125 /// of that variable. 155 /// of that variable.
126 /// 156 ///
(...skipping 11 matching lines...) Expand all
138 168
139 /// Substitution map for labels. Any break to a label L should be substituted 169 /// Substitution map for labels. Any break to a label L should be substituted
140 /// for a break to L' if L maps to L'. 170 /// for a break to L' if L maps to L'.
141 Map<Label, Jump> labelRedirects = <Label, Jump>{}; 171 Map<Label, Jump> labelRedirects = <Label, Jump>{};
142 172
143 /// Number of uses of the given variable that are still unseen. 173 /// Number of uses of the given variable that are still unseen.
144 /// Used to detect the first use of a variable (since we do backwards 174 /// Used to detect the first use of a variable (since we do backwards
145 /// traversal, the first use is the last one seen). 175 /// traversal, the first use is the last one seen).
146 Map<Variable, int> unseenUses = <Variable, int>{}; 176 Map<Variable, int> unseenUses = <Variable, int>{};
147 177
178 /// Number of assignments to a given variable that dominate the current
179 /// position.
180 ///
181 /// Pure expressions will not be inlined if it uses a variable with more than
182 /// one dominating assignment, because the reaching definition of the used
183 /// variable might have changed since it was put in the environment.
184 final Map<Variable, int> dominatingAssignments = <Variable, int>{};
185
148 /// Rewriter for methods. 186 /// Rewriter for methods.
149 StatementRewriter() : constantEnvironment = <Variable, Expression>{}; 187 StatementRewriter() : constantEnvironment = <Variable, Expression>{};
150 188
151 /// Rewriter for nested functions. 189 /// Rewriter for nested functions.
152 StatementRewriter.nested(StatementRewriter parent) 190 StatementRewriter.nested(StatementRewriter parent)
153 : constantEnvironment = parent.constantEnvironment, 191 : constantEnvironment = parent.constantEnvironment,
154 unseenUses = parent.unseenUses; 192 unseenUses = parent.unseenUses;
155 193
156 /// A set of labels that can be safely inlined at their use. 194 /// A set of labels that can be safely inlined at their use.
157 /// 195 ///
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
189 } 227 }
190 228
191 /// If the given expression always returns the value of one of its 229 /// If the given expression always returns the value of one of its
192 /// subexpressions, and that subexpression is a variable use, returns that 230 /// subexpressions, and that subexpression is a variable use, returns that
193 /// variable. Otherwise `null`. 231 /// variable. Otherwise `null`.
194 Variable getRightHand(Expression e) { 232 Variable getRightHand(Expression e) {
195 Expression value = getValueSubexpression(e); 233 Expression value = getValueSubexpression(e);
196 return value is VariableUse ? value.variable : null; 234 return value is VariableUse ? value.variable : null;
197 } 235 }
198 236
237 /// True if the given expression (taken from [constantEnvironment]) uses a
238 /// variable that might have been reassigned since [node] was evaluated.
239 bool hasUnsafeVariableUse(Expression node) {
240 bool wasFound = false;
241 VariableUseVisitor.visit(node, (VariableUse use) {
242 if (dominatingAssignments[use.variable] > 1) {
243 wasFound = true;
244 }
245 });
246 return wasFound;
247 }
248
249 void pushDominatingAssignment(Variable variable) {
250 if (variable != null) {
251 dominatingAssignments.putIfAbsent(variable, () => 0);
252 ++dominatingAssignments[variable];
253 }
254 }
255
256 void popDominatingAssignment(Variable variable) {
257 if (variable != null) {
258 --dominatingAssignments[variable];
259 }
260 }
261
199 @override 262 @override
200 Expression visitVariableUse(VariableUse node) { 263 Expression visitVariableUse(VariableUse node) {
201 // Count of number of unseen uses remaining. 264 // Count of number of unseen uses remaining.
202 unseenUses.putIfAbsent(node.variable, () => node.variable.readCount); 265 unseenUses.putIfAbsent(node.variable, () => node.variable.readCount);
203 --unseenUses[node.variable]; 266 --unseenUses[node.variable];
204 267
205 // We traverse the tree right-to-left, so when we have seen all uses, 268 // We traverse the tree right-to-left, so when we have seen all uses,
206 // it means we are looking at the first use. 269 // it means we are looking at the first use.
207 assert(unseenUses[node.variable] < node.variable.readCount); 270 assert(unseenUses[node.variable] < node.variable.readCount);
208 assert(unseenUses[node.variable] >= 0); 271 assert(unseenUses[node.variable] >= 0);
209 bool isFirstUse = unseenUses[node.variable] == 0; 272 bool isFirstUse = unseenUses[node.variable] == 0;
210 273
211 // Propagate constant to use site. 274 // Propagate constant to use site.
212 Expression constant = constantEnvironment[node.variable]; 275 Expression constant = constantEnvironment[node.variable];
213 if (constant != null) { 276 if (constant != null && !hasUnsafeVariableUse(constant)) {
214 --node.variable.readCount; 277 --node.variable.readCount;
215 return visitExpression(constant); 278 return visitExpression(constant);
216 } 279 }
217 280
218 // Try to propagate another expression into this variable use. 281 // Try to propagate another expression into this variable use.
219 if (!environment.isEmpty) { 282 if (!environment.isEmpty) {
220 Expression binding = environment.last; 283 Expression binding = environment.last;
221 284
222 // Is this variable assigned by the most recently evaluated impure 285 // Is this variable assigned by the most recently evaluated impure
223 // expression? 286 // expression?
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
294 } 357 }
295 358
296 /// True if [node] is an assignment that can be propagated as a constant. 359 /// True if [node] is an assignment that can be propagated as a constant.
297 bool isEffectivelyConstantAssignment(Expression node) { 360 bool isEffectivelyConstantAssignment(Expression node) {
298 return node is Assign && 361 return node is Assign &&
299 node.variable.writeCount == 1 && 362 node.variable.writeCount == 1 &&
300 isEffectivelyConstant(node.value); 363 isEffectivelyConstant(node.value);
301 } 364 }
302 365
303 Statement visitExpressionStatement(ExpressionStatement stmt) { 366 Statement visitExpressionStatement(ExpressionStatement stmt) {
367 Variable leftHand = getLeftHand(stmt.expression);
368 pushDominatingAssignment(leftHand);
304 if (isEffectivelyConstantAssignment(stmt.expression) && 369 if (isEffectivelyConstantAssignment(stmt.expression) &&
305 !usesRecentlyAssignedVariable(stmt.expression)) { 370 !usesRecentlyAssignedVariable(stmt.expression)) {
306 Assign assign = stmt.expression; 371 Assign assign = stmt.expression;
307 // Handle constant assignments specially. 372 // Handle constant assignments specially.
308 // They are always safe to propagate (though we should avoid duplication). 373 // They are always safe to propagate (though we should avoid duplication).
309 // Moreover, they should not prevent other expressions from propagating. 374 // Moreover, they should not prevent other expressions from propagating.
310 if (assign.variable.readCount == 1) { 375 if (assign.variable.readCount == 1) {
311 // A single-use constant should always be propagted to its use site. 376 // A single-use constant should always be propagated to its use site.
312 constantEnvironment[assign.variable] = assign.value; 377 constantEnvironment[assign.variable] = assign.value;
313 --assign.variable.writeCount; 378 Statement next = visitStatement(stmt.next);
314 return visitStatement(stmt.next); 379 popDominatingAssignment(leftHand);
380 if (assign.variable.readCount > 0) {
381 // The assignment could not be propagated.
382 assign.value = visitExpression(assign.value);
383 stmt.next = next;
384 return stmt;
385 } else {
386 --assign.variable.writeCount;
387 return next;
388 }
315 } else { 389 } else {
316 // With more than one use, we cannot propagate the constant. 390 // With more than one use, we cannot propagate the constant.
317 // Visit the following statement without polluting [environment] so 391 // Visit the following statement without polluting [environment] so
318 // that any preceding non-constant assignments might still propagate. 392 // that any preceding non-constant assignments might still propagate.
319 stmt.next = visitStatement(stmt.next); 393 stmt.next = visitStatement(stmt.next);
394 popDominatingAssignment(leftHand);
320 assign.value = visitExpression(assign.value); 395 assign.value = visitExpression(assign.value);
321 return stmt; 396 return stmt;
322 } 397 }
323 } 398 }
324 // Try to propagate the expression, and block previous impure expressions 399 // Try to propagate the expression, and block previous impure expressions
325 // until this has propagated. 400 // until this has propagated.
326 environment.add(stmt.expression); 401 environment.add(stmt.expression);
327 stmt.next = visitStatement(stmt.next); 402 stmt.next = visitStatement(stmt.next);
403 popDominatingAssignment(leftHand);
328 if (!environment.isEmpty && environment.last == stmt.expression) { 404 if (!environment.isEmpty && environment.last == stmt.expression) {
329 // Retain the expression statement. 405 // Retain the expression statement.
330 environment.removeLast(); 406 environment.removeLast();
331 stmt.expression = visitExpression(stmt.expression); 407 stmt.expression = visitExpression(stmt.expression);
332 return stmt; 408 return stmt;
333 } else { 409 } else {
334 // Expression was propagated into the successor. 410 // Expression was propagated into the successor.
335 return stmt.next; 411 return stmt.next;
336 } 412 }
337 } 413 }
(...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after
542 // Not introduced yet 618 // Not introduced yet
543 throw "Unexpected WhileCondition in StatementRewriter"; 619 throw "Unexpected WhileCondition in StatementRewriter";
544 } 620 }
545 621
546 Statement visitTry(Try node) { 622 Statement visitTry(Try node) {
547 inEmptyEnvironment(() { 623 inEmptyEnvironment(() {
548 Set<Label> saved = safeForInlining; 624 Set<Label> saved = safeForInlining;
549 safeForInlining = new Set<Label>(); 625 safeForInlining = new Set<Label>();
550 node.tryBody = visitStatement(node.tryBody); 626 node.tryBody = visitStatement(node.tryBody);
551 safeForInlining = saved; 627 safeForInlining = saved;
628 node.catchParameters.forEach(pushDominatingAssignment);
552 node.catchBody = visitStatement(node.catchBody); 629 node.catchBody = visitStatement(node.catchBody);
630 node.catchParameters.forEach(popDominatingAssignment);
553 }); 631 });
554 return node; 632 return node;
555 } 633 }
556 634
557 Expression visitConstant(Constant node) { 635 Expression visitConstant(Constant node) {
558 return node; 636 return node;
559 } 637 }
560 638
561 Expression visitThis(This node) { 639 Expression visitThis(This node) {
562 return node; 640 return node;
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after
748 // expressions if the statements could not be combined. 826 // expressions if the statements could not be combined.
749 827
750 // Combine the expressions. 828 // Combine the expressions.
751 CombinedExpressions values = 829 CombinedExpressions values =
752 combineAsConditional(s.expression, t.expression, condition); 830 combineAsConditional(s.expression, t.expression, condition);
753 831
754 // Put this into the environment and try to combine the statements. 832 // Put this into the environment and try to combine the statements.
755 // We are not in risk of reprocessing the original subexpressions because 833 // We are not in risk of reprocessing the original subexpressions because
756 // the combined expression will always hide them inside a Conditional. 834 // the combined expression will always hide them inside a Conditional.
757 environment.add(values.combined); 835 environment.add(values.combined);
836
837 Variable leftHand = getLeftHand(values.combined);
838 pushDominatingAssignment(leftHand);
758 Statement next = combineStatements(s.next, t.next); 839 Statement next = combineStatements(s.next, t.next);
840 popDominatingAssignment(leftHand);
759 841
760 if (next == null) { 842 if (next == null) {
761 // Statements could not be combined. 843 // Statements could not be combined.
762 // Restore the environment and uncombine expressions again. 844 // Restore the environment and uncombine expressions again.
763 environment.removeLast(); 845 environment.removeLast();
764 values.uncombine(); 846 values.uncombine();
765 return null; 847 return null;
766 } else if (!environment.isEmpty && environment.last == values.combined) { 848 } else if (!environment.isEmpty && environment.last == values.combined) {
767 // Statements were combined but the combined expression could not be 849 // Statements were combined but the combined expression could not be
768 // propagated. Leave it as an expression statement here. 850 // propagated. Leave it as an expression statement here.
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
823 CombinedExpressions values = combineExpressions(s.value, t.value); 905 CombinedExpressions values = combineExpressions(s.value, t.value);
824 if (values != null) { 906 if (values != null) {
825 return new Return(values.combined); 907 return new Return(values.combined);
826 } 908 }
827 } 909 }
828 if (s is ExpressionStatement && t is ExpressionStatement) { 910 if (s is ExpressionStatement && t is ExpressionStatement) {
829 CombinedExpressions values = 911 CombinedExpressions values =
830 combineExpressions(s.expression, t.expression); 912 combineExpressions(s.expression, t.expression);
831 if (values == null) return null; 913 if (values == null) return null;
832 environment.add(values.combined); 914 environment.add(values.combined);
915 Variable leftHand = getLeftHand(values.combined);
916 pushDominatingAssignment(leftHand);
833 Statement next = combineStatements(s.next, t.next); 917 Statement next = combineStatements(s.next, t.next);
918 popDominatingAssignment(leftHand);
834 if (next == null) { 919 if (next == null) {
835 // The successors could not be combined. 920 // The successors could not be combined.
836 // Restore the environment and uncombine the values again. 921 // Restore the environment and uncombine the values again.
837 assert(environment.last == values.combined); 922 assert(environment.last == values.combined);
838 environment.removeLast(); 923 environment.removeLast();
839 values.uncombine(); 924 values.uncombine();
840 return null; 925 return null;
841 } else if (!environment.isEmpty && environment.last == values.combined) { 926 } else if (!environment.isEmpty && environment.last == values.combined) {
842 // The successors were combined but the combined expressions were not 927 // The successors were combined but the combined expressions were not
843 // propagated. Leave the combined expression as a statement. 928 // propagated. Leave the combined expression as a statement.
(...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after
1039 IsVariableUsedVisitor(this.variable); 1124 IsVariableUsedVisitor(this.variable);
1040 1125
1041 visitVariableUse(VariableUse node) { 1126 visitVariableUse(VariableUse node) {
1042 if (node.variable == variable) { 1127 if (node.variable == variable) {
1043 wasFound = true; 1128 wasFound = true;
1044 } 1129 }
1045 } 1130 }
1046 1131
1047 visitInnerFunction(FunctionDefinition node) {} 1132 visitInnerFunction(FunctionDefinition node) {}
1048 } 1133 }
1134
1135 typedef VariableUseCallback(VariableUse use);
1136
1137 class VariableUseVisitor extends RecursiveVisitor {
1138 VariableUseCallback callback;
1139
1140 VariableUseVisitor(this.callback);
1141
1142 visitVariableUse(VariableUse use) => callback(use);
1143
1144 visitInnerFunction(FunctionDefinition node) {}
1145
1146 static void visit(Expression node, VariableUseCallback callback) {
1147 new VariableUseVisitor(callback).visitExpression(node);
1148 }
1149 }
OLDNEW
« no previous file with comments | « no previous file | tests/compiler/dart2js_extra/dart2js_extra.status » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698