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

Side by Side Diff: sdk/lib/_internal/compiler/implementation/dart_backend/dart_tree.dart

Issue 312793002: dart2dart: Preserve variable names throughout the IR. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Properly linearize phi assignments, remove unused write count Created 6 years, 6 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 library dart_tree; 5 library dart_tree;
6 6
7 import '../dart2jslib.dart' as dart2js; 7 import '../dart2jslib.dart' as dart2js;
8 import '../elements/elements.dart' 8 import '../elements/elements.dart'
9 show Element, FunctionElement, FunctionSignature, ParameterElement, 9 show Element, FunctionElement, FunctionSignature, ParameterElement,
10 ClassElement; 10 ClassElement;
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
76 int breakCount = 0; 76 int breakCount = 0;
77 77
78 /// The [LabeledStatement] binding this label. 78 /// The [LabeledStatement] binding this label.
79 LabeledStatement binding; 79 LabeledStatement binding;
80 } 80 }
81 81
82 /** 82 /**
83 * Variables are [Expression]s. 83 * Variables are [Expression]s.
84 */ 84 */
85 class Variable extends Expression { 85 class Variable extends Expression {
86 // A counter used to generate names. The counter is reset to 0 for each 86 /// Element used for synthesizing a name for the variable.
87 // function emitted. 87 /// Different variables may have the same element. May be null.
88 static int counter = 0; 88 Element element;
89 static String _newName() => 'v${counter++}';
90 89
91 Element element; 90 int readCount = 0;
92 String cachedName;
93
94 String get name {
95 if (cachedName != null) return cachedName;
96 return cachedName = ((element == null) ? _newName() : element.name);
97 }
98 91
99 Variable(this.element); 92 Variable(this.element);
100 93
101 accept(Visitor visitor) => visitor.visitVariable(this); 94 accept(Visitor visitor) => visitor.visitVariable(this);
102 } 95 }
103 96
104 /** 97 /**
105 * Common interface for invocations with arguments. 98 * Common interface for invocations with arguments.
106 */ 99 */
107 abstract class Invoke { 100 abstract class Invoke {
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after
264 /** 257 /**
265 * An assignments of an [Expression] to a [Variable]. 258 * An assignments of an [Expression] to a [Variable].
266 * 259 *
267 * In contrast to the CPS-based IR, non-primitive expressions can be assigned 260 * In contrast to the CPS-based IR, non-primitive expressions can be assigned
268 * to variables. 261 * to variables.
269 */ 262 */
270 class Assign extends Statement { 263 class Assign extends Statement {
271 Statement next; 264 Statement next;
272 final Variable variable; 265 final Variable variable;
273 Expression definition; 266 Expression definition;
274 final bool hasExactlyOneUse;
275 267
276 Assign(this.variable, this.definition, this.next, this.hasExactlyOneUse); 268 Assign(this.variable, this.definition, this.next);
269
270 bool get hasExactlyOneUse => variable.readCount == 1;
277 271
278 accept(Visitor visitor) => visitor.visitAssign(this); 272 accept(Visitor visitor) => visitor.visitAssign(this);
279 } 273 }
280 274
281 /** 275 /**
282 * A return exit from the function. 276 * A return exit from the function.
283 * 277 *
284 * In contrast to the CPS-based IR, the return value is an arbitrary 278 * In contrast to the CPS-based IR, the return value is an arbitrary
285 * expression. 279 * expression.
286 */ 280 */
287 class Return extends Statement { 281 class Return extends Statement {
288 /// Should not be null. Use [Constant] with [NullConstant] for void returns. 282 /// Should not be null. Use [Constant] with [NullConstant] for void returns.
289 Expression value; 283 Expression value;
290 284
291 Statement get next => null; 285 Statement get next => null;
292 void set next(Statement s) => throw 'UNREACHABLE'; 286 void set next(Statement s) => throw 'UNREACHABLE';
293 287
294 Return(this.value); 288 Return(this.value);
295 289
296 accept(Visitor visitor) => visitor.visitReturn(this); 290 accept(Visitor visitor) => visitor.visitReturn(this);
297 } 291 }
298 292
299 /** 293 /**
300 * A break from an enclosing [LabeledStatement]. The break targets the 294 * A break from an enclosing [LabeledStatement]. The break targets the
301 * labeled statement's successor statement. 295 * labeled statement's successor statement.
302 */ 296 */
303 class Break extends Statement { 297 class Break extends Statement {
304 Label _target; 298 Label target;
305
306 Label get target => _target;
307 void set target(Label newTarget) {
308 ++newTarget.breakCount;
309 --_target.breakCount;
310 _target = newTarget;
311 }
312 299
313 Statement get next => null; 300 Statement get next => null;
314 void set next(Statement s) => throw 'UNREACHABLE'; 301 void set next(Statement s) => throw 'UNREACHABLE';
315 302
316 Break(this._target) { 303 Break(this.target) {
317 ++target.breakCount; 304 ++target.breakCount;
318 } 305 }
319 306
320 accept(Visitor visitor) => visitor.visitBreak(this); 307 accept(Visitor visitor) => visitor.visitBreak(this);
321 } 308 }
322 309
323 /** 310 /**
324 * A continue to an enclosing [While] loop. The continue targets the 311 * A continue to an enclosing [While] loop. The continue targets the
325 * loop's body. 312 * loop's body.
326 */ 313 */
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
437 * translation out of SSA. Jumps are eliminated during the Tree-to-Tree 424 * translation out of SSA. Jumps are eliminated during the Tree-to-Tree
438 * control-flow recognition. 425 * control-flow recognition.
439 * 426 *
440 * Otherwise, the output of Builder looks very much like the input. In 427 * Otherwise, the output of Builder looks very much like the input. In
441 * particular, intermediate values and blocks used for local control flow are 428 * particular, intermediate values and blocks used for local control flow are
442 * still all named. 429 * still all named.
443 */ 430 */
444 class Builder extends ir.Visitor<Node> { 431 class Builder extends ir.Visitor<Node> {
445 final dart2js.Compiler compiler; 432 final dart2js.Compiler compiler;
446 433
447 // Uses of IR primitives are replaced with Tree variables. This is the 434 /// Maps variable/parameter elements to the Tree variables that represent it.
448 // mapping from primitives to variables. 435 final Map<Element, List<Variable>> element2variables =
449 final Map<ir.Primitive, Variable> variables = <ir.Primitive, Variable>{}; 436 <Element,List<Variable>>{};
450 437
451 // Continuations with more than one use are replaced with Tree labels. This 438 // Continuations with more than one use are replaced with Tree labels. This
452 // is the mapping from continuations to labels. 439 // is the mapping from continuations to labels.
453 final Map<ir.Continuation, Label> labels = <ir.Continuation, Label>{}; 440 final Map<ir.Continuation, Label> labels = <ir.Continuation, Label>{};
454 441
455 FunctionDefinition function; 442 FunctionDefinition function;
456 ir.Continuation returnContinuation; 443 ir.Continuation returnContinuation;
457 444
458 Builder(this.compiler); 445 Builder(this.compiler);
459 446
447 /// Obtains the variable representing the given primitive. Returns null for
448 /// primitives that have no reference and do not need a variable.
449 Variable getVariable(ir.Primitive primitive) {
450 if (primitive.registerIndex == null) {
451 return null; // variable is unused
452 }
453 List<Variable> variables = element2variables[primitive.element];
454 if (variables == null) {
455 variables = <Variable>[];
456 element2variables[primitive.element] = variables;
457 }
458 while (variables.length <= primitive.registerIndex) {
459 variables.add(new Variable(primitive.element));
460 }
461 return variables[primitive.registerIndex];
462 }
463
464 /// Obtains a reference to the tree Variable corresponding to the IR primitive
465 /// referred to by [reference].
466 /// This increments the reference count for the given variable, so the
467 /// returned expression must be used in the tree.
468 Expression getVariableReference(ir.Reference reference) {
469 Variable variable = getVariable(reference.definition);
470 if (variable == null) {
471 compiler.internalError(
472 compiler.currentElement,
473 "Reference to ${reference.definition} has no register");
474 }
475 ++variable.readCount;
476 return variable;
477 }
478
460 FunctionDefinition build(ir.FunctionDefinition node) { 479 FunctionDefinition build(ir.FunctionDefinition node) {
480 new ir.RegisterAllocator().visit(node);
461 visit(node); 481 visit(node);
462 return function; 482 return function;
463 } 483 }
464 484
465 List<Expression> translateArguments(List<ir.Reference> args) { 485 List<Expression> translateArguments(List<ir.Reference> args) {
466 return new List<Expression>.generate(args.length, 486 return new List<Expression>.generate(args.length,
467 (int index) => variables[args[index].definition]); 487 (int index) => getVariableReference(args[index]));
468 } 488 }
469 489
470 Statement buildParameterAssignments( 490 List<Variable> translatePhiArguments(List<ir.Reference> args) {
491 return new List<Variable>.generate(args.length,
492 (int index) => getVariableReference(args[index]));
493 }
494
495 Statement buildContinuationAssignment(
496 ir.Parameter parameter,
497 Expression argument,
498 Statement buildRest()) {
499 Variable variable = getVariable(parameter);
500 Statement assignment;
501 if (variable == null) {
502 assignment = new ExpressionStatement(argument, null);
503 } else {
504 assignment = new Assign(variable, argument, null);
505 }
506 assignment.next = buildRest();
507 return assignment;
508 }
509
510 /// Simultaneously assigns each argument to the corresponding parameter,
511 /// then continues at the statement created by [buildRest].
512 Statement buildPhiAssignments(
471 List<ir.Parameter> parameters, 513 List<ir.Parameter> parameters,
472 List<Expression> arguments, 514 List<Variable> arguments,
473 Statement buildRest()) { 515 Statement buildRest()) {
474 assert(parameters.length == arguments.length); 516 assert(parameters.length == arguments.length);
517 // We want a parallel assignment to all parameters simultaneously.
518 // Since we do not have parallel assignments in dart_tree, we must linearize
519 // the assignments without attempting to read a previously-overwritten
520 // value. For example {x,y = y,x} cannot be linearized to {x = y; y = x},
521 // for this we must introduce a temporary variable: {t = x; x = y; y = t}.
522
523 // [rightHand] is the inverse of [arguments], that is, it maps variables
524 // to the assignments on which is occurs as the right-hand side.
525 Map<Variable, List<int>> rightHand = <Variable, List<int>>{};
526 for (int i = 0; i < parameters.length; i++) {
527 Variable param = getVariable(parameters[i]);
528 Variable arg = arguments[i];
529 if (param == null || param == arg)
530 continue; // No assignment necessary.
531 List<int> list = rightHand[arg];
532 if (list == null) {
533 rightHand[arg] = list = <int>[];
534 }
535 list.add(i);
536 }
537
475 Statement first, current; 538 Statement first, current;
476 for (int i = 0; i < parameters.length; ++i) { 539 void addAssignment(Variable dst, Variable src) {
477 ir.Parameter parameter = parameters[i]; 540 if (first == null) {
478 Statement assignment; 541 first = current = new Assign(dst, src, null);
479 if (parameter.hasAtLeastOneUse) {
480 assignment = new Assign(variables[parameter], arguments[i], null,
481 parameter.hasExactlyOneUse);
482 } else { 542 } else {
483 assignment = new ExpressionStatement(arguments[i], null); 543 current = current.next = new Assign(dst, src, null);
484 }
485
486 if (first == null) {
487 current = first = assignment;
488 } else {
489 current = current.next = assignment;
490 } 544 }
491 } 545 }
492 546
547 Variable temp = new Variable(null);
548 List<Variable> assignmentSrc = new List<Variable>(parameters.length);
549 List<bool> done = new List<bool>(parameters.length);
550 void visitAssignment(int i) {
551 if (done[i] == true)
552 return;
sigurdm 2014/06/12 14:12:19 Can be on one line
asgerf 2014/06/12 15:24:11 Thanks.
553 Variable param = getVariable(parameters[i]);
554 Variable arg = arguments[i];
555 if (param == null || param == arg)
556 return; // No assignment necessary.
557 if (assignmentSrc[i] != null) {
558 // Cycle found; store argument in a temporary variable.
559 // The temporary will then be used as right-hand side when the
560 // assignment gets added.
561 if (assignmentSrc[i] != temp) { // Only move to temporary once.
562 assignmentSrc[i] = temp;
563 addAssignment(temp, arg);
564 }
565 return;
566 }
567 assignmentSrc[i] = arg;
568 List<int> paramUses = rightHand[param];
569 if (paramUses != null) {
570 for (int useIndex in paramUses) {
571 visitAssignment(useIndex);
572 }
573 }
574 addAssignment(param, assignmentSrc[i]);
575 done[i] = true;
576 }
577
578 for (int i = 0; i < parameters.length; i++) {
579 if (done[i] == null) {
580 visitAssignment(i);
581 }
582 }
583
493 if (first == null) { 584 if (first == null) {
494 first = buildRest(); 585 first = buildRest();
495 } else { 586 } else {
496 current.next = buildRest(); 587 current.next = buildRest();
497 } 588 }
498 return first; 589 return first;
499 } 590 }
500 591
501 Expression visitFunctionDefinition(ir.FunctionDefinition node) { 592 Expression visitFunctionDefinition(ir.FunctionDefinition node) {
502 returnContinuation = node.returnContinuation; 593 returnContinuation = node.returnContinuation;
503 List<Variable> parameters = <Variable>[]; 594 List<Variable> parameters = <Variable>[];
504 for (ir.Parameter p in node.parameters) { 595 for (ir.Parameter p in node.parameters) {
505 Variable parameter = new Variable(p.element); 596 Variable parameter = getVariable(p);
597 assert(parameter != null);
506 parameters.add(parameter); 598 parameters.add(parameter);
507 variables[p] = parameter;
508 } 599 }
509 function = new FunctionDefinition(parameters, visit(node.body)); 600 function = new FunctionDefinition(parameters, visit(node.body));
510 return null; 601 return null;
511 } 602 }
512 603
513 Statement visitLetPrim(ir.LetPrim node) { 604 Statement visitLetPrim(ir.LetPrim node) {
514 // LetPrim is translated to LetVal. 605 // LetPrim is translated to Assign.
515 Expression definition = visit(node.primitive); 606 Expression definition = visit(node.primitive);
516 if (node.primitive.hasAtLeastOneUse) { 607 Variable variable = getVariable(node.primitive);
517 Variable variable = new Variable(null); 608 if (variable != null) { // Variable is null if primitive is unused.
518 variables[node.primitive] = variable; 609 return new Assign(variable, definition, visit(node.body));
519 return new Assign(variable, definition, visit(node.body),
520 node.primitive.hasExactlyOneUse);
521 } else if (node.primitive is ir.Constant) { 610 } else if (node.primitive is ir.Constant) {
522 // TODO(kmillikin): Implement more systematic treatment of pure CPS 611 // TODO(kmillikin): Implement more systematic treatment of pure CPS
523 // values (e.g., as part of a shrinking reductions pass). 612 // values (e.g., as part of a shrinking reductions pass).
524 return visit(node.body); 613 return visit(node.body);
525 } else { 614 } else {
526 return new ExpressionStatement(definition, visit(node.body)); 615 return new ExpressionStatement(definition, visit(node.body));
527 } 616 }
528 } 617 }
529 618
530 Statement visitLetCont(ir.LetCont node) { 619 Statement visitLetCont(ir.LetCont node) {
531 Label label; 620 Label label;
532 if (node.continuation.hasMultipleUses) { 621 if (node.continuation.hasMultipleUses) {
533 label = new Label(); 622 label = new Label();
534 labels[node.continuation] = label; 623 labels[node.continuation] = label;
535 } 624 }
536 node.continuation.parameters.forEach((p) {
537 if (p.hasAtLeastOneUse) variables[p] = new Variable(null);
538 });
539 Statement body = visit(node.body); 625 Statement body = visit(node.body);
540 // The continuation's body is not always translated directly here because 626 // The continuation's body is not always translated directly here because
541 // it may have been already translated: 627 // it may have been already translated:
542 // * For singly-used continuations, the continuation's body is 628 // * For singly-used continuations, the continuation's body is
543 // translated at the site of the continuation invocation. 629 // translated at the site of the continuation invocation.
544 // * For recursive continuations, there is a single non-recursive 630 // * For recursive continuations, there is a single non-recursive
545 // invocation. The continuation's body is translated at the site 631 // invocation. The continuation's body is translated at the site
546 // of the non-recursive continuation invocation. 632 // of the non-recursive continuation invocation.
547 // See visitInvokeContinuation for the implementation. 633 // See visitInvokeContinuation for the implementation.
548 if (label == null || node.continuation.isRecursive) return body; 634 if (label == null || node.continuation.isRecursive) return body;
549 return new LabeledStatement(label, body, visit(node.continuation.body)); 635 return new LabeledStatement(label, body, visit(node.continuation.body));
550 } 636 }
551 637
552 Statement visitInvokeStatic(ir.InvokeStatic node) { 638 Statement visitInvokeStatic(ir.InvokeStatic node) {
553 // Calls are translated to direct style. 639 // Calls are translated to direct style.
554 List<Expression> arguments = translateArguments(node.arguments); 640 List<Expression> arguments = translateArguments(node.arguments);
555 Expression invoke = new InvokeStatic(node.target, node.selector, arguments); 641 Expression invoke = new InvokeStatic(node.target, node.selector, arguments);
556 ir.Continuation cont = node.continuation.definition; 642 ir.Continuation cont = node.continuation.definition;
557 if (cont == returnContinuation) { 643 if (cont == returnContinuation) {
558 return new Return(invoke); 644 return new Return(invoke);
559 } else { 645 } else {
560 assert(cont.hasExactlyOneUse); 646 assert(cont.hasExactlyOneUse);
561 assert(cont.parameters.length == 1); 647 assert(cont.parameters.length == 1);
562 return buildParameterAssignments(cont.parameters, [invoke], 648 return buildContinuationAssignment(cont.parameters[0], invoke,
sigurdm 2014/06/12 14:12:19 You can use cont.parameters.single, it also assert
asgerf 2014/06/12 15:24:15 single is only defined for Link. cont.parameters i
sigurdm 2014/06/13 07:40:07 No - single is defined on Iterable which List impl
563 () => visit(cont.body)); 649 () => visit(cont.body));
564 } 650 }
565 } 651 }
566 652
567 Statement visitInvokeMethod(ir.InvokeMethod node) { 653 Statement visitInvokeMethod(ir.InvokeMethod node) {
568 Variable receiver = variables[node.receiver.definition]; 654 Expression receiver = getVariableReference(node.receiver);
569 List<Expression> arguments = translateArguments(node.arguments); 655 List<Expression> arguments = translateArguments(node.arguments);
570 Expression invoke = new InvokeMethod(receiver, node.selector, arguments); 656 Expression invoke = new InvokeMethod(receiver, node.selector, arguments);
571 ir.Continuation cont = node.continuation.definition; 657 ir.Continuation cont = node.continuation.definition;
572 if (cont == returnContinuation) { 658 if (cont == returnContinuation) {
573 return new Return(invoke); 659 return new Return(invoke);
574 } else { 660 } else {
575 assert(cont.hasExactlyOneUse); 661 assert(cont.hasExactlyOneUse);
576 assert(cont.parameters.length == 1); 662 assert(cont.parameters.length == 1);
577 return buildParameterAssignments(cont.parameters, [invoke], 663 return buildContinuationAssignment(cont.parameters[0], invoke,
578 () => visit(cont.body)); 664 () => visit(cont.body));
579 } 665 }
580 } 666 }
581 667
582 Statement visitConcatenateStrings(ir.ConcatenateStrings node) { 668 Statement visitConcatenateStrings(ir.ConcatenateStrings node) {
583 List<Expression> arguments = translateArguments(node.arguments); 669 List<Expression> arguments = translateArguments(node.arguments);
584 Expression concat = new ConcatenateStrings(arguments); 670 Expression concat = new ConcatenateStrings(arguments);
585 ir.Continuation cont = node.continuation.definition; 671 ir.Continuation cont = node.continuation.definition;
586 if (cont == returnContinuation) { 672 if (cont == returnContinuation) {
587 return new Return(concat); 673 return new Return(concat);
588 } else { 674 } else {
589 assert(cont.hasExactlyOneUse); 675 assert(cont.hasExactlyOneUse);
590 assert(cont.parameters.length == 1); 676 assert(cont.parameters.length == 1);
591 return buildParameterAssignments(cont.parameters, [concat], 677 return buildContinuationAssignment(cont.parameters[0], concat,
592 () => visit(cont.body)); 678 () => visit(cont.body));
593 } 679 }
594 } 680 }
595 681
596 Statement visitInvokeConstructor(ir.InvokeConstructor node) { 682 Statement visitInvokeConstructor(ir.InvokeConstructor node) {
597 List<Expression> arguments = translateArguments(node.arguments); 683 List<Expression> arguments = translateArguments(node.arguments);
598 Expression invoke = 684 Expression invoke =
599 new InvokeConstructor(node.type, node.target, node.selector, arguments); 685 new InvokeConstructor(node.type, node.target, node.selector, arguments);
600 ir.Continuation cont = node.continuation.definition; 686 ir.Continuation cont = node.continuation.definition;
601 if (cont == returnContinuation) { 687 if (cont == returnContinuation) {
602 return new Return(invoke); 688 return new Return(invoke);
603 } else { 689 } else {
604 assert(cont.hasExactlyOneUse); 690 assert(cont.hasExactlyOneUse);
605 assert(cont.parameters.length == 1); 691 assert(cont.parameters.length == 1);
606 return buildParameterAssignments(cont.parameters, [invoke], 692 return buildContinuationAssignment(cont.parameters[0], invoke,
607 () => visit(cont.body)); 693 () => visit(cont.body));
608 } 694 }
609 } 695 }
610 696
611 Statement visitInvokeContinuation(ir.InvokeContinuation node) { 697 Statement visitInvokeContinuation(ir.InvokeContinuation node) {
612 // Invocations of the return continuation are translated to returns. 698 // Invocations of the return continuation are translated to returns.
613 // Other continuation invocations are replaced with assignments of the 699 // Other continuation invocations are replaced with assignments of the
614 // arguments to formal parameter variables, followed by the body if 700 // arguments to formal parameter variables, followed by the body if
615 // the continuation is singly reference or a break if it is multiply 701 // the continuation is singly reference or a break if it is multiply
616 // referenced. 702 // referenced.
617 ir.Continuation cont = node.continuation.definition; 703 ir.Continuation cont = node.continuation.definition;
618 if (cont == returnContinuation) { 704 if (cont == returnContinuation) {
619 assert(node.arguments.length == 1); 705 assert(node.arguments.length == 1);
620 return new Return(variables[node.arguments[0].definition]); 706 return new Return(getVariableReference(node.arguments[0]));
621 } else { 707 } else {
622 List<Expression> arguments = translateArguments(node.arguments); 708 List<Expression> arguments = translatePhiArguments(node.arguments);
623 return buildParameterAssignments(cont.parameters, arguments, 709 return buildPhiAssignments(cont.parameters, arguments,
624 () { 710 () {
625 // Translate invocations of recursive and non-recursive 711 // Translate invocations of recursive and non-recursive
626 // continuations differently. 712 // continuations differently.
627 // * Non-recursive continuations 713 // * Non-recursive continuations
628 // - If there is one use, translate the continuation body 714 // - If there is one use, translate the continuation body
629 // inline at the invocation site. 715 // inline at the invocation site.
630 // - If there are multiple uses, translate to Break. 716 // - If there are multiple uses, translate to Break.
631 // * Recursive continuations 717 // * Recursive continuations
632 // - There is a single non-recursive invocation. Translate 718 // - There is a single non-recursive invocation. Translate
633 // the continuation body inline as a labeled loop at the 719 // the continuation body inline as a labeled loop at the
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
687 } 773 }
688 774
689 Expression visitContinuation(ir.Continuation node) { 775 Expression visitContinuation(ir.Continuation node) {
690 // Until continuations with multiple uses are supported, they are not 776 // Until continuations with multiple uses are supported, they are not
691 // visited. 777 // visited.
692 compiler.internalError(compiler.currentElement, 'Unexpected IR node.'); 778 compiler.internalError(compiler.currentElement, 'Unexpected IR node.');
693 return null; 779 return null;
694 } 780 }
695 781
696 Expression visitIsTrue(ir.IsTrue node) { 782 Expression visitIsTrue(ir.IsTrue node) {
697 return variables[node.value.definition]; 783 return getVariableReference(node.value);
698 } 784 }
699 } 785 }
700 786
701 /** 787 /**
702 * Performs the following transformations on the tree: 788 * Performs the following transformations on the tree:
703 * - Assignment propagation 789 * - Assignment propagation
704 * - If-to-conditional conversion 790 * - If-to-conditional conversion
705 * - Flatten nested ifs 791 * - Flatten nested ifs
706 * - Break inlining 792 * - Break inlining
707 * - Redirect breaks 793 * - Redirect breaks
(...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after
933 1019
934 Statement visitLabeledStatement(LabeledStatement node) { 1020 Statement visitLabeledStatement(LabeledStatement node) {
935 if (node.next is Break) { 1021 if (node.next is Break) {
936 // Eliminate label if next is just a break statement 1022 // Eliminate label if next is just a break statement
937 // Breaks to this label are redirected to the outer label. 1023 // Breaks to this label are redirected to the outer label.
938 // Note that breakCount for the two labels is updated proactively here 1024 // Note that breakCount for the two labels is updated proactively here
939 // so breaks can reliably tell if they should inline their target. 1025 // so breaks can reliably tell if they should inline their target.
940 Break next = node.next; 1026 Break next = node.next;
941 Label newTarget = redirect(next.target); 1027 Label newTarget = redirect(next.target);
942 labelRedirects[node.label] = newTarget; 1028 labelRedirects[node.label] = newTarget;
943 newTarget.breakCount += node.label.breakCount; 1029 newTarget.breakCount += node.label.breakCount - 1;
944 node.label.breakCount = 0; 1030 node.label.breakCount = 0;
945 Statement result = visitStatement(node.body); 1031 Statement result = visitStatement(node.body);
946 labelRedirects.remove(node.label); // Save some space. 1032 labelRedirects.remove(node.label); // Save some space.
947 return result; 1033 return result;
948 } 1034 }
949 1035
950 node.body = visitStatement(node.body); 1036 node.body = visitStatement(node.body);
951 1037
952 if (node.label.breakCount == 0) { 1038 if (node.label.breakCount == 0) {
953 // Eliminate the label if next was inlined at a break 1039 // Eliminate the label if next was inlined at a break
954 return node.body; 1040 return node.body;
955 } 1041 }
956 1042
1043 // Do not propagate assignments into the successor statements, since they
1044 // may be overwritten by assignments in the body.
1045 List<Assign> savedEnvironment = environment;
1046 environment = <Assign>[];
957 node.next = visitStatement(node.next); 1047 node.next = visitStatement(node.next);
1048 environment = savedEnvironment;
1049
958 return node; 1050 return node;
959 } 1051 }
960 1052
961 Statement visitIf(If node) { 1053 Statement visitIf(If node) {
962 node.condition = visitExpression(node.condition); 1054 node.condition = visitExpression(node.condition);
963 1055
964 // Do not propagate assignments into branches. Doing so will lead to code 1056 // Do not propagate assignments into branches. Doing so will lead to code
965 // duplication. 1057 // duplication.
966 // TODO(kmillikin): Rethink this. Propagating some assignments (e.g., 1058 // TODO(kmillikin): Rethink this. Propagating some assignments (e.g.,
967 // constants or variables) is benign. If they can occur here, they should 1059 // constants or variables) is benign. If they can occur here, they should
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
1060 Statement t, 1152 Statement t,
1061 Expression combine(Expression s, Expression t)) { 1153 Expression combine(Expression s, Expression t)) {
1062 if (s is Return && t is Return) { 1154 if (s is Return && t is Return) {
1063 return new Return(combine(s.value, t.value)); 1155 return new Return(combine(s.value, t.value));
1064 } 1156 }
1065 if (s is Assign && t is Assign && s.variable == t.variable) { 1157 if (s is Assign && t is Assign && s.variable == t.variable) {
1066 Statement next = combineStatements(s.next, t.next); 1158 Statement next = combineStatements(s.next, t.next);
1067 if (next != null) { 1159 if (next != null) {
1068 return new Assign(s.variable, 1160 return new Assign(s.variable,
1069 combine(s.definition, t.definition), 1161 combine(s.definition, t.definition),
1070 next, 1162 next);
1071 s.hasExactlyOneUse);
1072 } 1163 }
1073 } 1164 }
1074 if (s is ExpressionStatement && t is ExpressionStatement) { 1165 if (s is ExpressionStatement && t is ExpressionStatement) {
1075 Statement next = combineStatements(s.next, t.next); 1166 Statement next = combineStatements(s.next, t.next);
1076 if (next != null) { 1167 if (next != null) {
1077 return new ExpressionStatement(combine(s.expression, t.expression), 1168 return new ExpressionStatement(combine(s.expression, t.expression),
1078 next); 1169 next);
1079 } 1170 }
1080 } 1171 }
1081 return null; 1172 return null;
1082 } 1173 }
1083 1174
1084 /// Returns a statement equivalent to both [s] and [t], or null if [s] and 1175 /// Returns a statement equivalent to both [s] and [t], or null if [s] and
1085 /// [t] are incompatible. 1176 /// [t] are incompatible.
1086 /// If non-null is returned, the caller MUST discard [s] and [t] and use 1177 /// If non-null is returned, the caller MUST discard [s] and [t] and use
1087 /// the returned statement instead. 1178 /// the returned statement instead.
1088 /// If two breaks are combined, the label's break counter will be decremented. 1179 /// If two breaks are combined, the label's break counter will be decremented.
1089 static Statement combineStatements(Statement s, Statement t) { 1180 static Statement combineStatements(Statement s, Statement t) {
1090 if (s is Break && t is Break && s.target == t.target) { 1181 if (s is Break && t is Break && s.target == t.target) {
1091 --t.target.breakCount; // Two breaks become one. 1182 --t.target.breakCount; // Two breaks become one.
1092 return s; 1183 return s;
1093 } 1184 }
1094 if (s is Return && t is Return && equivalentExpressions(s.value, t.value)) { 1185 if (s is Return && t is Return) {
1095 return s; 1186 Expression e = combineExpressions(s.value, t.value);
1187 if (e != null) {
1188 return new Return(e);
1189 }
1096 } 1190 }
1097 return null; 1191 return null;
1098 } 1192 }
1099 1193
1100 /// True if the two expressions both syntactically and semantically 1194 /// Returns an expression equivalent to both [e1] and [e2].
1101 /// equivalent. 1195 /// If non-null is returned, the caller must discard [e1] and [e2] and use
1102 static bool equivalentExpressions(Expression e1, Expression e2) { 1196 /// the resulting expression in the tree.
1103 if (e1 == e2) { // Detect same variable reference 1197 static Expression combineExpressions(Expression e1, Expression e2) {
1104 // TODO(asgerf): This might turn the variable into a single-use, 1198 if (e1 is Variable && e1 == e2) {
1105 // but we currently don't discover this. 1199 --e1.readCount; // Two references become one.
1106 return true; 1200 return e1;
1107 } 1201 }
1108 if (e1 is Constant && e2 is Constant) { 1202 if (e1 is Constant && e2 is Constant && e1.value == e2.value) {
1109 return e1.value == e2.value; 1203 return e1;
1110 } 1204 }
1111 return false; 1205 return null;
1112 } 1206 }
1113 1207
1114 /// Try to collapse nested ifs using && and || expressions. 1208 /// Try to collapse nested ifs using && and || expressions.
1115 /// For example: 1209 /// For example:
1116 /// 1210 ///
1117 /// if (E1) { if (E2) S else break L } else break L 1211 /// if (E1) { if (E2) S else break L } else break L
1118 /// ==> 1212 /// ==>
1119 /// if (E1 && E2) S else break L 1213 /// if (E1 && E2) S else break L
1120 /// 1214 ///
1121 /// [branch1] and [branch2] control the position of the S statement. 1215 /// [branch1] and [branch2] control the position of the S statement.
(...skipping 480 matching lines...) Expand 10 before | Expand all | Expand 10 after
1602 } 1696 }
1603 } 1697 }
1604 1698
1605 /// Destructively updates each entry of [l] with the result of visiting it. 1699 /// Destructively updates each entry of [l] with the result of visiting it.
1606 void _rewriteList(List<Expression> l) { 1700 void _rewriteList(List<Expression> l) {
1607 for (int i = 0; i < l.length; i++) { 1701 for (int i = 0; i < l.length; i++) {
1608 l[i] = visitExpression(l[i]); 1702 l[i] = visitExpression(l[i]);
1609 } 1703 }
1610 } 1704 }
1611 } 1705 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698