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

Side by Side Diff: pkg/compiler/lib/src/cps_ir/shrinking_reductions.dart

Issue 1601863005: Remove useless branches in shrinking_reductions. (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Created 4 years, 11 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 | no next file » | 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 dart2js.cps_ir.shrinking_reductions; 5 library dart2js.cps_ir.shrinking_reductions;
6 6
7 import 'cps_ir_nodes.dart'; 7 import 'cps_ir_nodes.dart';
8 import 'optimizers.dart'; 8 import 'optimizers.dart';
9 import 'cps_fragment.dart'; 9 import 'cps_fragment.dart';
10 import '../constants/values.dart' as values;
10 11
11 /** 12 /**
12 * [ShrinkingReducer] applies shrinking reductions to CPS terms as described 13 * [ShrinkingReducer] applies shrinking reductions to CPS terms as described
13 * in 'Compiling with Continuations, Continued' by Andrew Kennedy. 14 * in 'Compiling with Continuations, Continued' by Andrew Kennedy.
14 */ 15 */
15 class ShrinkingReducer extends Pass { 16 class ShrinkingReducer extends Pass {
16 String get passName => 'Shrinking reductions'; 17 String get passName => 'Shrinking reductions';
17 18
18 List<_ReductionTask> _worklist; 19 List<_ReductionTask> _worklist;
19 20
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
74 break; 75 break;
75 case _ReductionKind.BETA_CONT_LIN: 76 case _ReductionKind.BETA_CONT_LIN:
76 _reduceBetaContLin(task); 77 _reduceBetaContLin(task);
77 break; 78 break;
78 case _ReductionKind.ETA_CONT: 79 case _ReductionKind.ETA_CONT:
79 _reduceEtaCont(task); 80 _reduceEtaCont(task);
80 break; 81 break;
81 case _ReductionKind.DEAD_PARAMETER: 82 case _ReductionKind.DEAD_PARAMETER:
82 _reduceDeadParameter(task); 83 _reduceDeadParameter(task);
83 break; 84 break;
85 case _ReductionKind.BRANCH:
86 _reduceBranch(task);
87 break;
84 default: 88 default:
85 assert(false); 89 assert(false);
86 } 90 }
87 } 91 }
88 92
89 /// Applies the dead-val reduction: 93 /// Applies the dead-val reduction:
90 /// letprim x = V in E -> E (x not free in E). 94 /// letprim x = V in E -> E (x not free in E).
91 void _reduceDeadVal(_ReductionTask task) { 95 void _reduceDeadVal(_ReductionTask task) {
92 assert(_isDeadVal(task.node)); 96 assert(_isDeadVal(task.node));
93 97
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
184 } 188 }
185 } 189 }
186 190
187 // Replace all occurrences with the wrapped continuation. 191 // Replace all occurrences with the wrapped continuation.
188 cont.replaceUsesWith(wrappedCont); 192 cont.replaceUsesWith(wrappedCont);
189 193
190 // Perform bookkeeping on removed body and scan for new redexes. 194 // Perform bookkeeping on removed body and scan for new redexes.
191 new _RemovalVisitor(_worklist).visit(cont); 195 new _RemovalVisitor(_worklist).visit(cont);
192 } 196 }
193 197
198 void _reduceBranch(_ReductionTask task) {
199 Branch branch = task.node;
200 // Task can be added as both a useless if and a constant folding.
201 if (branch.parent == _DELETED) return;
202
203 // Replace Branch with InvokeContinuation of one of the targets. When the
204 // branch is deleted the other target becomes unreferenced and the chosen
205 // target becomes available for eta-cont and further reductions.
206 Continuation target;
207
208 Primitive condition = branch.condition.definition;
209 if (condition is Constant) {
210 target = isTruthyConstant(condition.value, strict: branch.isStrictCheck)
211 ? branch.trueContinuation.definition
212 : branch.falseContinuation.definition;
213 } else if (_isBranchTargetOfUselessIf(branch.trueContinuation.definition)) {
214 target = branch.trueContinuation.definition;
215 } else {
216 return;
217 }
218
219 InvokeContinuation invoke = new InvokeContinuation(
220 target, <Primitive>[]
221 // TODO(sra): Add sourceInformation.
222 /*, sourceInformation: branch.sourceInformation*/);
223 branch.parent.body = invoke;
224 invoke.parent = branch.parent;
225 branch.parent = _DELETED;
226
227 new _RemovalVisitor(_worklist).visit(branch);
228 }
229
194 void _reduceDeadParameter(_ReductionTask task) { 230 void _reduceDeadParameter(_ReductionTask task) {
195 // Continuation eta-reduction can destroy a dead parameter redex. For 231 // Continuation eta-reduction can destroy a dead parameter redex. For
196 // example, in the term: 232 // example, in the term:
197 // 233 //
198 // let cont k0(v0) = /* v0 is not used */ in 234 // let cont k0(v0) = /* v0 is not used */ in
199 // let cont k1(v1) = k0(v1) in 235 // let cont k1(v1) = k0(v1) in
200 // call foo () k1 236 // call foo () k1
201 // 237 //
202 // Continuation eta-reduction of k1 gives: 238 // Continuation eta-reduction of k1 gives:
203 // 239 //
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after
364 // constant time by using union-find data structure. 400 // constant time by using union-find data structure.
365 for (int i = 0; i < cont.parameters.length; i++) { 401 for (int i = 0; i < cont.parameters.length; i++) {
366 if (invoke.arguments[i].definition != cont.parameters[i]) { 402 if (invoke.arguments[i].definition != cont.parameters[i]) {
367 return false; 403 return false;
368 } 404 }
369 } 405 }
370 406
371 return true; 407 return true;
372 } 408 }
373 409
410 bool _isBranchTargetOfUselessIf(Continuation cont) {
411 // A useless-if has an empty then and else branch, e.g. `if (cond);`.
412 //
413 // Detect T or F in
414 //
415 // let cont Join() = ...
416 // in let cont T() = Join()
417 // F() = Join()
418 // in branch condition T F
419 //
420 if (!cont.hasExactlyOneUse) return false;
421 if (cont.firstRef.parent is! Branch) return false;
422 Branch branch = cont.firstRef.parent;
423 Continuation trueCont = branch.trueContinuation.definition;
424 Continuation falseCont = branch.falseContinuation.definition;
425 // Are both continuations the same InvokeContinuation on a join?
426 if (trueCont.body is! InvokeContinuation) return false;
427 if (falseCont.body is! InvokeContinuation) return false;
428 InvokeContinuation trueInvoke = trueCont.body;
429 InvokeContinuation falseInvoke = falseCont.body;
430 if (trueInvoke.continuation.definition !=
431 falseInvoke.continuation.definition) {
432 return false;
433 }
434 assert(trueInvoke.arguments.length == falseInvoke.arguments.length);
435 // Matching zero arguments should be adequate, since isomorphic true and false
436 // invocations should result in redundant phis which are removed elsewhere.
437 if (trueInvoke.arguments.isNotEmpty) return false;
438 return true;
439 }
440
374 bool _isDeadParameter(Parameter parameter) { 441 bool _isDeadParameter(Parameter parameter) {
375 // We cannot remove function parameters as an intraprocedural optimization. 442 // We cannot remove function parameters as an intraprocedural optimization.
376 if (parameter.parent is! Continuation || parameter.hasAtLeastOneUse) { 443 if (parameter.parent is! Continuation || parameter.hasAtLeastOneUse) {
377 return false; 444 return false;
378 } 445 }
379 446
380 // We cannot remove exception handler parameters, they have a fixed arity 447 // We cannot remove exception handler parameters, they have a fixed arity
381 // of two. 448 // of two.
382 if (parameter.parent.parent is LetHandler) { 449 if (parameter.parent.parent is LetHandler) {
383 return false; 450 return false;
(...skipping 20 matching lines...) Expand all
404 final List<_ReductionTask> worklist; 471 final List<_ReductionTask> worklist;
405 472
406 _RedexVisitor(this.worklist); 473 _RedexVisitor(this.worklist);
407 474
408 void processLetPrim(LetPrim node) { 475 void processLetPrim(LetPrim node) {
409 if (_isDeadVal(node)) { 476 if (_isDeadVal(node)) {
410 worklist.add(new _ReductionTask(_ReductionKind.DEAD_VAL, node)); 477 worklist.add(new _ReductionTask(_ReductionKind.DEAD_VAL, node));
411 } 478 }
412 } 479 }
413 480
481 void processBranch(Branch node) {
482 if (node.condition.definition is Constant) {
483 worklist.add(new _ReductionTask(_ReductionKind.BRANCH, node));
484 }
485 }
486
414 void processContinuation(Continuation node) { 487 void processContinuation(Continuation node) {
415 // While it would be nice to remove exception handlers that are provably 488 // While it would be nice to remove exception handlers that are provably
416 // unnecessary (e.g., the body cannot throw), that takes more sophisticated 489 // unnecessary (e.g., the body cannot throw), that takes more sophisticated
417 // analysis than we do in this pass. 490 // analysis than we do in this pass.
418 if (node.parent is LetHandler) return; 491 if (node.parent is LetHandler) return;
419 492
420 // Continuation beta- and eta-redexes can overlap, namely when an eta-redex 493 // Continuation beta- and eta-redexes can overlap, namely when an eta-redex
421 // is invoked exactly once. We prioritize continuation beta-redexes over 494 // is invoked exactly once. We prioritize continuation beta-redexes over
422 // eta-redexes because some reductions (e.g., dead parameter elimination) 495 // eta-redexes because some reductions (e.g., dead parameter elimination)
423 // can destroy a continuation eta-redex. If we prioritized eta- over 496 // can destroy a continuation eta-redex. If we prioritized eta- over
424 // beta-redexes, this would implicitly "create" the corresponding beta-redex 497 // beta-redexes, this would implicitly "create" the corresponding beta-redex
425 // (in the sense that it would still apply) and the algorithm would not 498 // (in the sense that it would still apply) and the algorithm would not
426 // detect it. 499 // detect it.
427 if (_isDeadCont(node)) { 500 if (_isDeadCont(node)) {
428 worklist.add(new _ReductionTask(_ReductionKind.DEAD_CONT, node)); 501 worklist.add(new _ReductionTask(_ReductionKind.DEAD_CONT, node));
429 } else if (_isBetaContLin(node)){ 502 } else if (_isBetaContLin(node)){
430 worklist.add(new _ReductionTask(_ReductionKind.BETA_CONT_LIN, node)); 503 worklist.add(new _ReductionTask(_ReductionKind.BETA_CONT_LIN, node));
431 } else if (_isEtaCont(node)) { 504 } else if (_isEtaCont(node)) {
432 worklist.add(new _ReductionTask(_ReductionKind.ETA_CONT, node)); 505 worklist.add(new _ReductionTask(_ReductionKind.ETA_CONT, node));
506 } else if (_isBranchTargetOfUselessIf(node)) {
507 worklist.add(new _ReductionTask(_ReductionKind.BRANCH,
508 node.firstRef.parent));
433 } 509 }
434 } 510 }
435 511
436 void processParameter(Parameter node) { 512 void processParameter(Parameter node) {
437 if (_isDeadParameter(node)) { 513 if (_isDeadParameter(node)) {
438 worklist.add(new _ReductionTask(_ReductionKind.DEAD_PARAMETER, node)); 514 worklist.add(new _ReductionTask(_ReductionKind.DEAD_PARAMETER, node));
439 } 515 }
440 } 516 }
441 } 517 }
442 518
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
479 if (cont.isRecursive && cont.hasAtMostOneUse) { 555 if (cont.isRecursive && cont.hasAtMostOneUse) {
480 // Convert recursive to nonrecursive continuations. If the 556 // Convert recursive to nonrecursive continuations. If the
481 // continuation is still in use, it is either dead and will be 557 // continuation is still in use, it is either dead and will be
482 // removed, or it is called nonrecursively outside its body. 558 // removed, or it is called nonrecursively outside its body.
483 cont.isRecursive = false; 559 cont.isRecursive = false;
484 } 560 }
485 if (_isDeadCont(cont)) { 561 if (_isDeadCont(cont)) {
486 worklist.add(new _ReductionTask(_ReductionKind.DEAD_CONT, cont)); 562 worklist.add(new _ReductionTask(_ReductionKind.DEAD_CONT, cont));
487 } else if (_isBetaContLin(cont)) { 563 } else if (_isBetaContLin(cont)) {
488 worklist.add(new _ReductionTask(_ReductionKind.BETA_CONT_LIN, cont)); 564 worklist.add(new _ReductionTask(_ReductionKind.BETA_CONT_LIN, cont));
565 } else if (_isBranchTargetOfUselessIf(cont)) {
566 worklist.add(
567 new _ReductionTask(_ReductionKind.BRANCH, cont.firstRef.parent));
489 } 568 }
490 } 569 }
491 } 570 }
492 } 571 }
493 } 572 }
494 573
495 574
496 575
497 class _ReductionKind { 576 class _ReductionKind {
498 final String name; 577 final String name;
499 final int hashCode; 578 final int hashCode;
500 579
501 const _ReductionKind(this.name, this.hashCode); 580 const _ReductionKind(this.name, this.hashCode);
502 581
503 static const _ReductionKind DEAD_VAL = const _ReductionKind('dead-val', 0); 582 static const _ReductionKind DEAD_VAL = const _ReductionKind('dead-val', 0);
504 static const _ReductionKind DEAD_CONT = const _ReductionKind('dead-cont', 1); 583 static const _ReductionKind DEAD_CONT = const _ReductionKind('dead-cont', 1);
505 static const _ReductionKind BETA_CONT_LIN = 584 static const _ReductionKind BETA_CONT_LIN =
506 const _ReductionKind('beta-cont-lin', 2); 585 const _ReductionKind('beta-cont-lin', 2);
507 static const _ReductionKind ETA_CONT = const _ReductionKind('eta-cont', 3); 586 static const _ReductionKind ETA_CONT = const _ReductionKind('eta-cont', 3);
508 static const _ReductionKind DEAD_PARAMETER = 587 static const _ReductionKind DEAD_PARAMETER =
509 const _ReductionKind('dead-parameter', 4); 588 const _ReductionKind('dead-parameter', 4);
589 static const _ReductionKind BRANCH = const _ReductionKind('branch', 5);
510 590
511 String toString() => name; 591 String toString() => name;
512 } 592 }
513 593
514 /// Represents a reduction task on the worklist. Implements both hashCode and 594 /// Represents a reduction task on the worklist. Implements both hashCode and
515 /// operator== since instantiations are used as Set elements. 595 /// operator== since instantiations are used as Set elements.
516 class _ReductionTask { 596 class _ReductionTask {
517 final _ReductionKind kind; 597 final _ReductionKind kind;
518 final Node node; 598 final Node node;
519 599
(...skipping 12 matching lines...) Expand all
532 612
533 String toString() => "$kind: $node"; 613 String toString() => "$kind: $node";
534 } 614 }
535 615
536 /// A dummy class used solely to mark nodes as deleted once they are removed 616 /// A dummy class used solely to mark nodes as deleted once they are removed
537 /// from a term. 617 /// from a term.
538 class _DeletedNode extends Node { 618 class _DeletedNode extends Node {
539 accept(_) {} 619 accept(_) {}
540 setParentPointers() {} 620 setParentPointers() {}
541 } 621 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698