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

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

Issue 918653002: Propagate pseudo-constants expressions separately in tree rewriter. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Rebase Created 5 years, 10 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 | Annotate | Revision Log
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 part of tree_ir.optimization; 5 part of tree_ir.optimization;
6 6
7 /** 7 /**
8 * Performs the following transformations on the tree: 8 * Performs the following transformations on the tree:
9 * - Assignment propagation 9 * - Assignment propagation
10 * - If-to-conditional conversion 10 * - If-to-conditional conversion
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
89 * {... jump L1 ...} 89 * {... jump L1 ...}
90 * 90 *
91 * This may trigger a flattening of nested ifs in case the eliminated label 91 * This may trigger a flattening of nested ifs in case the eliminated label
92 * separated two ifs. 92 * separated two ifs.
93 */ 93 */
94 class StatementRewriter extends Visitor<Statement, Expression> with PassMixin { 94 class StatementRewriter extends Visitor<Statement, Expression> with PassMixin {
95 // The binding environment. The rightmost element of the list is the nearest 95 // The binding environment. The rightmost element of the list is the nearest
96 // available enclosing binding. 96 // available enclosing binding.
97 List<Assign> environment; 97 List<Assign> environment;
98 98
99 /// Binding environment for variables that are assigned to effectively
100 /// constant expressions (see [isEffectivelyConstant]).
101 final Map<Variable, Expression> constantEnvironment;
102
99 /// Substitution map for labels. Any break to a label L should be substituted 103 /// Substitution map for labels. Any break to a label L should be substituted
100 /// for a break to L' if L maps to L'. 104 /// for a break to L' if L maps to L'.
101 Map<Label, Jump> labelRedirects = <Label, Jump>{}; 105 Map<Label, Jump> labelRedirects = <Label, Jump>{};
102 106
107 /// Rewriter for methods.
108 StatementRewriter() : constantEnvironment = <Variable, Expression>{};
109
110 /// Rewriter for nested functions.
111 StatementRewriter.nested(StatementRewriter parent)
112 : constantEnvironment = parent.constantEnvironment;
113
103 /// Returns the redirect target of [label] or [label] itself if it should not 114 /// Returns the redirect target of [label] or [label] itself if it should not
104 /// be redirected. 115 /// be redirected.
105 Jump redirect(Jump jump) { 116 Jump redirect(Jump jump) {
106 Jump newJump = labelRedirects[jump.target]; 117 Jump newJump = labelRedirects[jump.target];
107 return newJump != null ? newJump : jump; 118 return newJump != null ? newJump : jump;
108 } 119 }
109 120
110
111 rewriteExecutableDefinition(ExecutableDefinition definition) { 121 rewriteExecutableDefinition(ExecutableDefinition definition) {
112 definition.body = rewriteInEmptyEnvironment(definition.body); 122 inEmptyEnvironment(() {
123 definition.body = visitStatement(definition.body);
124 });
113 } 125 }
114 126
115 void rewriteConstructorDefinition(ConstructorDefinition definition) { 127 void rewriteConstructorDefinition(ConstructorDefinition definition) {
116 if (definition.isAbstract) return; 128 if (definition.isAbstract) return;
117 definition.initializers.forEach(visitExpression); 129 definition.initializers.forEach(visitExpression);
118 rewriteExecutableDefinition(definition); 130 rewriteExecutableDefinition(definition);
119 } 131 }
120 132
121 Statement rewriteInEmptyEnvironment(Statement body) { 133 void inEmptyEnvironment(void action()) {
122 List<Assign> oldEnvironment = environment; 134 List<Assign> oldEnvironment = environment;
123 environment = <Assign>[]; 135 environment = <Assign>[];
124 136 action();
125 Statement result = visitStatement(body);
126 // TODO(kmillikin): Allow definitions that are not propagated. Here,
127 // this means rebuilding the binding with a recursively unnamed definition,
128 // or else introducing a variable definition and an assignment.
129 assert(environment.isEmpty); 137 assert(environment.isEmpty);
130 environment = oldEnvironment; 138 environment = oldEnvironment;
131 return result;
132 } 139 }
133 140
134 Expression visitFieldInitializer(FieldInitializer node) { 141 Expression visitFieldInitializer(FieldInitializer node) {
135 node.body = rewriteInEmptyEnvironment(node.body); 142 inEmptyEnvironment(() {
143 node.body = visitStatement(node.body);
144 });
136 return node; 145 return node;
137 } 146 }
138 147
139 Expression visitSuperInitializer(SuperInitializer node) { 148 Expression visitSuperInitializer(SuperInitializer node) {
140 for (int i = node.arguments.length - 1; i >= 0; --i) { 149 inEmptyEnvironment(() {
141 node.arguments[i] = rewriteInEmptyEnvironment(node.arguments[i]); 150 for (int i = node.arguments.length - 1; i >= 0; --i) {
142 } 151 node.arguments[i] = visitStatement(node.arguments[i]);
152 assert(environment.isEmpty);
153 }
154 });
143 return node; 155 return node;
144 } 156 }
145 157
146 Expression visitExpression(Expression e) => e.processed ? e : e.accept(this); 158 Expression visitExpression(Expression e) => e.processed ? e : e.accept(this);
147 159
148 Expression visitVariable(Variable node) { 160 Expression visitVariable(Variable node) {
161 // Propagate constant to use site.
162 Expression constant = constantEnvironment[node];
163 if (constant != null) return constant;
164
149 // Propagate a variable's definition to its use site if: 165 // Propagate a variable's definition to its use site if:
150 // 1. It has a single use, to avoid code growth and potential duplication 166 // 1. It has a single use, to avoid code growth and potential duplication
151 // of side effects, AND 167 // of side effects, AND
152 // 2. It was the most recent expression evaluated so that we do not 168 // 2. It was the most recent expression evaluated so that we do not
153 // reorder expressions with side effects. 169 // reorder expressions with side effects.
154 if (!environment.isEmpty && 170 if (!environment.isEmpty &&
155 environment.last.variable == node && 171 environment.last.variable == node &&
156 environment.last.hasExactlyOneUse) { 172 environment.last.hasExactlyOneUse) {
157 return visitExpression(environment.removeLast().definition); 173 return visitExpression(environment.removeLast().definition);
158 } 174 }
159 // If the definition could not be propagated, leave the variable use. 175 // If the definition could not be propagated, leave the variable use.
160 return node; 176 return node;
161 } 177 }
162 178
179 /// Returns true if [exp] has no side effects and has a constant value within
180 /// any given activation of the enclosing method.
181 bool isEffectivelyConstant(Expression exp) {
182 // TODO(asgerf): Can be made more aggressive e.g. by checking conditional
183 // expressions recursively. Determine if that is a valuable optimization
184 // and/or if it is better handled at the CPS level.
185 return exp is Constant ||
186 exp is This ||
187 exp is ReifyTypeVar ||
188 exp is Variable && constantEnvironment.containsKey(exp);
189 }
163 190
164 Statement visitAssign(Assign node) { 191 Statement visitAssign(Assign node) {
165 environment.add(node); 192 if (isEffectivelyConstant(node.definition) &&
166 Statement next = visitStatement(node.next); 193 node.variable.writeCount == 1) {
167 194 // Handle constant assignments specially.
168 if (!environment.isEmpty && environment.last == node) { 195 // They are always safe to propagate (though we should avoid duplication).
169 // The definition could not be propagated. Residualize the let binding. 196 // Moreover, they should not prevent other expressions from propagating.
170 node.next = next; 197 if (node.variable.readCount <= 1) {
171 environment.removeLast(); 198 // A single-use constant should always be propagted to its use site.
172 node.definition = visitExpression(node.definition); 199 constantEnvironment[node.variable] = visitExpression(node.definition);
173 return node; 200 return visitStatement(node.next);
201 } else {
202 // With more than one use, we cannot propagate the constant.
203 // Visit the following statement without polluting [environment] so
204 // that any preceding non-constant assignments might still propagate.
205 node.next = visitStatement(node.next);
206 node.definition = visitExpression(node.definition);
207 return node;
208 }
209 } else {
210 // Try to propagate assignment, and block previous assignment until this
211 // has propagated.
212 environment.add(node);
213 Statement next = visitStatement(node.next);
214 if (!environment.isEmpty && environment.last == node) {
215 // The definition could not be propagated. Residualize the let binding.
216 node.next = next;
217 environment.removeLast();
218 node.definition = visitExpression(node.definition);
219 return node;
220 }
221 assert(!environment.contains(node));
222 return next;
174 } 223 }
175 assert(!environment.contains(node));
176 return next;
177 } 224 }
178 225
179 Expression visitInvokeStatic(InvokeStatic node) { 226 Expression visitInvokeStatic(InvokeStatic node) {
180 // Process arguments right-to-left, the opposite of evaluation order. 227 // Process arguments right-to-left, the opposite of evaluation order.
181 for (int i = node.arguments.length - 1; i >= 0; --i) { 228 for (int i = node.arguments.length - 1; i >= 0; --i) {
182 node.arguments[i] = visitExpression(node.arguments[i]); 229 node.arguments[i] = visitExpression(node.arguments[i]);
183 } 230 }
184 return node; 231 return node;
185 } 232 }
186 233
(...skipping 23 matching lines...) Expand all
210 Expression visitConcatenateStrings(ConcatenateStrings node) { 257 Expression visitConcatenateStrings(ConcatenateStrings node) {
211 for (int i = node.arguments.length - 1; i >= 0; --i) { 258 for (int i = node.arguments.length - 1; i >= 0; --i) {
212 node.arguments[i] = visitExpression(node.arguments[i]); 259 node.arguments[i] = visitExpression(node.arguments[i]);
213 } 260 }
214 return node; 261 return node;
215 } 262 }
216 263
217 Expression visitConditional(Conditional node) { 264 Expression visitConditional(Conditional node) {
218 node.condition = visitExpression(node.condition); 265 node.condition = visitExpression(node.condition);
219 266
220 List<Assign> savedEnvironment = environment; 267 inEmptyEnvironment(() {
221 environment = <Assign>[]; 268 node.thenExpression = visitExpression(node.thenExpression);
222 node.thenExpression = visitExpression(node.thenExpression); 269 node.elseExpression = visitExpression(node.elseExpression);
223 assert(environment.isEmpty); 270 });
224 node.elseExpression = visitExpression(node.elseExpression);
225 assert(environment.isEmpty);
226 environment = savedEnvironment;
227 271
228 return node; 272 return node;
229 } 273 }
230 274
231 Expression visitLogicalOperator(LogicalOperator node) { 275 Expression visitLogicalOperator(LogicalOperator node) {
232 node.left = visitExpression(node.left); 276 node.left = visitExpression(node.left);
233 277
234 environment.add(null); // impure expressions may not propagate across branch 278 // Impure expressions may not propagate across the branch.
235 node.right = visitExpression(node.right); 279 inEmptyEnvironment(() {
236 environment.removeLast(); 280 node.right = visitExpression(node.right);
281 });
237 282
238 return node; 283 return node;
239 } 284 }
240 285
241 Expression visitNot(Not node) { 286 Expression visitNot(Not node) {
242 node.operand = visitExpression(node.operand); 287 node.operand = visitExpression(node.operand);
243 return node; 288 return node;
244 } 289 }
245 290
246 Expression visitFunctionExpression(FunctionExpression node) { 291 Expression visitFunctionExpression(FunctionExpression node) {
247 new StatementRewriter().rewrite(node.definition); 292 new StatementRewriter.nested(this).rewrite(node.definition);
248 return node; 293 return node;
249 } 294 }
250 295
251 Statement visitFunctionDeclaration(FunctionDeclaration node) { 296 Statement visitFunctionDeclaration(FunctionDeclaration node) {
252 new StatementRewriter().rewrite(node.definition); 297 new StatementRewriter.nested(this).rewrite(node.definition);
253 node.next = visitStatement(node.next); 298 node.next = visitStatement(node.next);
254 return node; 299 return node;
255 } 300 }
256 301
257 Statement visitReturn(Return node) { 302 Statement visitReturn(Return node) {
258 node.value = visitExpression(node.value); 303 node.value = visitExpression(node.value);
259 return node; 304 return node;
260 } 305 }
261 306
262 307
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
294 339
295 node.body = visitStatement(node.body); 340 node.body = visitStatement(node.body);
296 341
297 if (node.label.useCount == 0) { 342 if (node.label.useCount == 0) {
298 // Eliminate the label if next was inlined at a break 343 // Eliminate the label if next was inlined at a break
299 return node.body; 344 return node.body;
300 } 345 }
301 346
302 // Do not propagate assignments into the successor statements, since they 347 // Do not propagate assignments into the successor statements, since they
303 // may be overwritten by assignments in the body. 348 // may be overwritten by assignments in the body.
304 List<Assign> savedEnvironment = environment; 349 inEmptyEnvironment(() {
305 environment = <Assign>[]; 350 node.next = visitStatement(node.next);
306 node.next = visitStatement(node.next); 351 });
307 environment = savedEnvironment;
308 352
309 return node; 353 return node;
310 } 354 }
311 355
312 Statement visitIf(If node) { 356 Statement visitIf(If node) {
313 node.condition = visitExpression(node.condition); 357 node.condition = visitExpression(node.condition);
314 358
315 // Do not propagate assignments into branches. Doing so will lead to code 359 // Do not propagate assignments into branches. Doing so will lead to code
316 // duplication. 360 // duplication.
317 // TODO(kmillikin): Rethink this. Propagating some assignments (e.g., 361 // TODO(kmillikin): Rethink this. Propagating some assignments
318 // constants or variables) is benign. If they can occur here, they should 362 // (e.g. variables) is benign. If they can occur here, they should
319 // be handled well. 363 // be handled well.
320 List<Assign> savedEnvironment = environment; 364 inEmptyEnvironment(() {
321 environment = <Assign>[]; 365 node.thenStatement = visitStatement(node.thenStatement);
322 node.thenStatement = visitStatement(node.thenStatement); 366 node.elseStatement = visitStatement(node.elseStatement);
323 assert(environment.isEmpty); 367 });
324 node.elseStatement = visitStatement(node.elseStatement);
325 assert(environment.isEmpty);
326 environment = savedEnvironment;
327 368
328 tryCollapseIf(node); 369 tryCollapseIf(node);
329 370
330 Statement reduced = combineStatementsWithSubexpressions( 371 Statement reduced = combineStatementsWithSubexpressions(
331 node.thenStatement, 372 node.thenStatement,
332 node.elseStatement, 373 node.elseStatement,
333 (t,f) => new Conditional(node.condition, t, f)..processed = true); 374 (t,f) => new Conditional(node.condition, t, f)..processed = true);
334 if (reduced != null) { 375 if (reduced != null) {
335 if (reduced.next is Break) { 376 if (reduced.next is Break) {
336 // In case the break can now be inlined. 377 // In case the break can now be inlined.
337 reduced = visitStatement(reduced); 378 reduced = visitStatement(reduced);
338 } 379 }
339 return reduced; 380 return reduced;
340 } 381 }
341 382
342 return node; 383 return node;
343 } 384 }
344 385
345 Statement visitWhileTrue(WhileTrue node) { 386 Statement visitWhileTrue(WhileTrue node) {
346 // Do not propagate assignments into loops. Doing so is not safe for 387 // Do not propagate assignments into loops. Doing so is not safe for
347 // variables modified in the loop (the initial value will be propagated). 388 // variables modified in the loop (the initial value will be propagated).
348 List<Assign> savedEnvironment = environment; 389 inEmptyEnvironment(() {
349 environment = <Assign>[]; 390 node.body = visitStatement(node.body);
350 node.body = visitStatement(node.body); 391 });
351 assert(environment.isEmpty);
352 environment = savedEnvironment;
353 return node; 392 return node;
354 } 393 }
355 394
356 Statement visitWhileCondition(WhileCondition node) { 395 Statement visitWhileCondition(WhileCondition node) {
357 // Not introduced yet 396 // Not introduced yet
358 throw "Unexpected WhileCondition in StatementRewriter"; 397 throw "Unexpected WhileCondition in StatementRewriter";
359 } 398 }
360 399
361 Expression visitConstant(Constant node) { 400 Expression visitConstant(Constant node) {
362 return node; 401 return node;
(...skipping 26 matching lines...) Expand all
389 428
390 Expression visitTypeOperator(TypeOperator node) { 429 Expression visitTypeOperator(TypeOperator node) {
391 node.receiver = visitExpression(node.receiver); 430 node.receiver = visitExpression(node.receiver);
392 return node; 431 return node;
393 } 432 }
394 433
395 Statement visitExpressionStatement(ExpressionStatement node) { 434 Statement visitExpressionStatement(ExpressionStatement node) {
396 node.expression = visitExpression(node.expression); 435 node.expression = visitExpression(node.expression);
397 // Do not allow propagation of assignments past an expression evaluated 436 // Do not allow propagation of assignments past an expression evaluated
398 // for its side effects because it risks reordering side effects. 437 // for its side effects because it risks reordering side effects.
399 // TODO(kmillikin): Rethink this. Some propagation is benign, e.g., 438 // TODO(kmillikin): Rethink this. Some propagation is benign,
400 // constants, variables, or other pure values that are not destroyed by 439 // e.g. variables, or other pure values that are not destroyed by
401 // the expression statement. If they can occur here they should be 440 // the expression statement. If they can occur here they should be
402 // handled well. 441 // handled well.
403 List<Assign> savedEnvironment = environment; 442 inEmptyEnvironment(() {
404 environment = <Assign>[]; 443 node.next = visitStatement(node.next);
405 node.next = visitStatement(node.next); 444 });
406 assert(environment.isEmpty);
407 environment = savedEnvironment;
408 return node; 445 return node;
409 } 446 }
410 447
411 Statement visitSetField(SetField node) { 448 Statement visitSetField(SetField node) {
412 node.next = visitStatement(node.next); 449 node.next = visitStatement(node.next);
413 node.value = visitExpression(node.value); 450 node.value = visitExpression(node.value);
414 node.object = visitExpression(node.object); 451 node.object = visitExpression(node.object);
415 return node; 452 return node;
416 } 453 }
417 454
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after
570 if (innerElse is Break && innerElse.target == outerElse.target) { 607 if (innerElse is Break && innerElse.target == outerElse.target) {
571 // We always put S in the then branch of the result, and adjust the 608 // We always put S in the then branch of the result, and adjust the
572 // condition expression if S was actually found in the else branch(es). 609 // condition expression if S was actually found in the else branch(es).
573 outerIf.condition = new LogicalOperator.and( 610 outerIf.condition = new LogicalOperator.and(
574 makeCondition(outerIf.condition, branch1), 611 makeCondition(outerIf.condition, branch1),
575 makeCondition(innerIf.condition, branch2)); 612 makeCondition(innerIf.condition, branch2));
576 outerIf.thenStatement = innerThen; 613 outerIf.thenStatement = innerThen;
577 --innerElse.target.useCount; 614 --innerElse.target.useCount;
578 615
579 // Try to inline the remaining break. Do not propagate assignments. 616 // Try to inline the remaining break. Do not propagate assignments.
580 List<Assign> savedEnvironment = environment; 617 inEmptyEnvironment(() {
581 environment = <Assign>[]; 618 outerIf.elseStatement = visitStatement(outerElse);
582 outerIf.elseStatement = visitStatement(outerElse); 619 });
583 assert(environment.isEmpty);
584 environment = savedEnvironment;
585 620
586 return outerIf.elseStatement is If && innerThen is Break; 621 return outerIf.elseStatement is If && innerThen is Break;
587 } 622 }
588 } 623 }
589 return false; 624 return false;
590 } 625 }
591 626
592 Expression makeCondition(Expression e, bool polarity) { 627 Expression makeCondition(Expression e, bool polarity) {
593 return polarity ? e : new Not(e); 628 return polarity ? e : new Not(e);
594 } 629 }
595 630
596 Statement getBranch(If node, bool polarity) { 631 Statement getBranch(If node, bool polarity) {
597 return polarity ? node.thenStatement : node.elseStatement; 632 return polarity ? node.thenStatement : node.elseStatement;
598 } 633 }
599 } 634 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/cps_ir/cps_ir_tracer.dart ('k') | pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698