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

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: SVN rebase 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 useCount = 0; 76 int useCount = 0;
77 77
78 /// The [LabeledStatement] or [WhileTrue] binding this label. 78 /// The [LabeledStatement] or [WhileTrue] binding this label.
79 JumpTarget binding; 79 JumpTarget 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(ExpressionVisitor visitor) => visitor.visitVariable(this); 94 accept(ExpressionVisitor 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 204 matching lines...) Expand 10 before | Expand all | Expand 10 after
312 305
313 WhileCondition(this.label, this.condition, this.body, 306 WhileCondition(this.label, this.condition, this.body,
314 this.next, this.updates) { 307 this.next, this.updates) {
315 assert(label.binding == null); 308 assert(label.binding == null);
316 label.binding = this; 309 label.binding = this;
317 } 310 }
318 311
319 accept(StatementVisitor visitor) => visitor.visitWhileCondition(this); 312 accept(StatementVisitor visitor) => visitor.visitWhileCondition(this);
320 } 313 }
321 314
322
323 /// A [Break] or [Continue] statement. 315 /// A [Break] or [Continue] statement.
324 abstract class Jump extends Statement { 316 abstract class Jump extends Statement {
325 Label get target; 317 Label get target;
326 } 318 }
327 319
328 /** 320 /**
329 * A break from an enclosing [LabeledStatement]. The break targets the 321 * A break from an enclosing [LabeledStatement]. The break targets the
330 * labeled statement's successor statement. 322 * labeled statement's successor statement.
331 */ 323 */
332 class Break extends Jump { 324 class Break extends Jump {
333 final Label target; 325 final Label target;
334 326
335 Statement get next => null; 327 Statement get next => null;
336 void set next(Statement s) => throw 'UNREACHABLE'; 328 void set next(Statement s) => throw 'UNREACHABLE';
337 329
338 Break(this.target) { 330 Break(this.target) {
339 ++target.useCount; 331 ++target.useCount;
340 } 332 }
341 333
342 accept(StatementVisitor visitor) => visitor.visitBreak(this); 334 accept(StatementVisitor visitor) => visitor.visitBreak(this);
343 } 335 }
344 336
345 /** 337 /**
346 * A continue to an enclosing [WhileTrue] loop. The continue targets the 338 * A continue to an enclosing [WhileTrue] or [WhileCondition] loop.
347 * loop's body. 339 * The continue targets the loop's body.
348 */ 340 */
349 class Continue extends Jump { 341 class Continue extends Jump {
350 final Label target; 342 final Label target;
351 343
352 Statement get next => null; 344 Statement get next => null;
353 void set next(Statement s) => throw 'UNREACHABLE'; 345 void set next(Statement s) => throw 'UNREACHABLE';
354 346
355 Continue(this.target) { 347 Continue(this.target) {
356 ++target.useCount; 348 ++target.useCount;
357 } 349 }
358 350
359 accept(StatementVisitor visitor) => visitor.visitContinue(this); 351 accept(StatementVisitor visitor) => visitor.visitContinue(this);
360 } 352 }
361 353
362 /** 354 /**
363 * An assignments of an [Expression] to a [Variable]. 355 * An assignments of an [Expression] to a [Variable].
364 * 356 *
365 * In contrast to the CPS-based IR, non-primitive expressions can be assigned 357 * In contrast to the CPS-based IR, non-primitive expressions can be assigned
366 * to variables. 358 * to variables.
367 */ 359 */
368 class Assign extends Statement { 360 class Assign extends Statement {
369 Statement next; 361 Statement next;
370 final Variable variable; 362 final Variable variable;
371 Expression definition; 363 Expression definition;
372 final bool hasExactlyOneUse;
373 364
374 Assign(this.variable, this.definition, this.next, this.hasExactlyOneUse); 365 Assign(this.variable, this.definition, this.next);
366
367 bool get hasExactlyOneUse => variable.readCount == 1;
375 368
376 accept(StatementVisitor visitor) => visitor.visitAssign(this); 369 accept(StatementVisitor visitor) => visitor.visitAssign(this);
377 } 370 }
378 371
379
380 /** 372 /**
381 * A return exit from the function. 373 * A return exit from the function.
382 * 374 *
383 * In contrast to the CPS-based IR, the return value is an arbitrary 375 * In contrast to the CPS-based IR, the return value is an arbitrary
384 * expression. 376 * expression.
385 */ 377 */
386 class Return extends Statement { 378 class Return extends Statement {
387 /// Should not be null. Use [Constant] with [NullConstant] for void returns. 379 /// Should not be null. Use [Constant] with [NullConstant] for void returns.
388 Expression value; 380 Expression value;
389 381
390 Statement get next => null; 382 Statement get next => null;
391 void set next(Statement s) => throw 'UNREACHABLE'; 383 void set next(Statement s) => throw 'UNREACHABLE';
392 384
393 Return(this.value); 385 Return(this.value);
394 386
395 accept(StatementVisitor visitor) => visitor.visitReturn(this); 387 accept(StatementVisitor visitor) => visitor.visitReturn(this);
396 } 388 }
397 389
398
399
400
401 /** 390 /**
402 * A conditional branch based on the true value of an [Expression]. 391 * A conditional branch based on the true value of an [Expression].
403 */ 392 */
404 class If extends Statement { 393 class If extends Statement {
405 Expression condition; 394 Expression condition;
406 Statement thenStatement; 395 Statement thenStatement;
407 Statement elseStatement; 396 Statement elseStatement;
408 397
409 Statement get next => null; 398 Statement get next => null;
410 void set next(Statement s) => throw 'UNREACHABLE'; 399 void set next(Statement s) => throw 'UNREACHABLE';
411 400
412 If(this.condition, this.thenStatement, this.elseStatement); 401 If(this.condition, this.thenStatement, this.elseStatement);
413 402
414 accept(StatementVisitor visitor) => visitor.visitIf(this); 403 accept(StatementVisitor visitor) => visitor.visitIf(this);
415 } 404 }
416 405
417
418 class ExpressionStatement extends Statement { 406 class ExpressionStatement extends Statement {
419 Statement next; 407 Statement next;
420 Expression expression; 408 Expression expression;
421 409
422 ExpressionStatement(this.expression, this.next); 410 ExpressionStatement(this.expression, this.next);
423 411
424 accept(StatementVisitor visitor) => visitor.visitExpressionStatement(this); 412 accept(StatementVisitor visitor) => visitor.visitExpressionStatement(this);
425 } 413 }
426 414
427 class FunctionDefinition extends Node { 415 class FunctionDefinition extends Node {
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
494 * translation out of SSA. Jumps are eliminated during the Tree-to-Tree 482 * translation out of SSA. Jumps are eliminated during the Tree-to-Tree
495 * control-flow recognition. 483 * control-flow recognition.
496 * 484 *
497 * Otherwise, the output of Builder looks very much like the input. In 485 * Otherwise, the output of Builder looks very much like the input. In
498 * particular, intermediate values and blocks used for local control flow are 486 * particular, intermediate values and blocks used for local control flow are
499 * still all named. 487 * still all named.
500 */ 488 */
501 class Builder extends ir.Visitor<Node> { 489 class Builder extends ir.Visitor<Node> {
502 final dart2js.Compiler compiler; 490 final dart2js.Compiler compiler;
503 491
504 // Uses of IR primitives are replaced with Tree variables. This is the 492 /// Maps variable/parameter elements to the Tree variables that represent it.
505 // mapping from primitives to variables. 493 final Map<Element, List<Variable>> element2variables =
506 final Map<ir.Primitive, Variable> variables = <ir.Primitive, Variable>{}; 494 <Element,List<Variable>>{};
507 495
508 // Continuations with more than one use are replaced with Tree labels. This 496 // Continuations with more than one use are replaced with Tree labels. This
509 // is the mapping from continuations to labels. 497 // is the mapping from continuations to labels.
510 final Map<ir.Continuation, Label> labels = <ir.Continuation, Label>{}; 498 final Map<ir.Continuation, Label> labels = <ir.Continuation, Label>{};
511 499
512 FunctionDefinition function; 500 FunctionDefinition function;
513 ir.Continuation returnContinuation; 501 ir.Continuation returnContinuation;
514 502
503 /// Variable used in [buildPhiAssignments] as a temporary when swapping
504 /// variables.
505 final Variable tempVar = new Variable(null);
506
515 Builder(this.compiler); 507 Builder(this.compiler);
516 508
509 /// Obtains the variable representing the given primitive. Returns null for
510 /// primitives that have no reference and do not need a variable.
511 Variable getVariable(ir.Primitive primitive) {
512 if (primitive.registerIndex == null) {
513 return null; // variable is unused
514 }
515 List<Variable> variables = element2variables[primitive.element];
516 if (variables == null) {
517 variables = <Variable>[];
518 element2variables[primitive.element] = variables;
519 }
520 while (variables.length <= primitive.registerIndex) {
521 variables.add(new Variable(primitive.element));
522 }
523 return variables[primitive.registerIndex];
524 }
525
526 /// Obtains a reference to the tree Variable corresponding to the IR primitive
527 /// referred to by [reference].
528 /// This increments the reference count for the given variable, so the
529 /// returned expression must be used in the tree.
530 Expression getVariableReference(ir.Reference reference) {
531 Variable variable = getVariable(reference.definition);
532 if (variable == null) {
533 compiler.internalError(
534 compiler.currentElement,
535 "Reference to ${reference.definition} has no register");
536 }
537 ++variable.readCount;
538 return variable;
539 }
540
517 FunctionDefinition build(ir.FunctionDefinition node) { 541 FunctionDefinition build(ir.FunctionDefinition node) {
542 new ir.RegisterAllocator().visit(node);
518 visit(node); 543 visit(node);
519 return function; 544 return function;
520 } 545 }
521 546
522 List<Expression> translateArguments(List<ir.Reference> args) { 547 List<Expression> translateArguments(List<ir.Reference> args) {
523 return new List<Expression>.generate(args.length, 548 return new List<Expression>.generate(args.length,
524 (int index) => variables[args[index].definition]); 549 (int index) => getVariableReference(args[index]));
525 } 550 }
526 551
527 Statement buildParameterAssignments( 552 List<Variable> translatePhiArguments(List<ir.Reference> args) {
553 return new List<Variable>.generate(args.length,
554 (int index) => getVariableReference(args[index]));
555 }
556
557 Statement buildContinuationAssignment(
558 ir.Parameter parameter,
559 Expression argument,
560 Statement buildRest()) {
561 Variable variable = getVariable(parameter);
562 Statement assignment;
563 if (variable == null) {
564 assignment = new ExpressionStatement(argument, null);
565 } else {
566 assignment = new Assign(variable, argument, null);
567 }
568 assignment.next = buildRest();
569 return assignment;
570 }
571
572 /// Simultaneously assigns each argument to the corresponding parameter,
573 /// then continues at the statement created by [buildRest].
574 Statement buildPhiAssignments(
528 List<ir.Parameter> parameters, 575 List<ir.Parameter> parameters,
529 List<Expression> arguments, 576 List<Variable> arguments,
530 Statement buildRest()) { 577 Statement buildRest()) {
531 assert(parameters.length == arguments.length); 578 assert(parameters.length == arguments.length);
579 // We want a parallel assignment to all parameters simultaneously.
580 // Since we do not have parallel assignments in dart_tree, we must linearize
581 // the assignments without attempting to read a previously-overwritten
582 // value. For example {x,y = y,x} cannot be linearized to {x = y; y = x},
583 // for this we must introduce a temporary variable: {t = x; x = y; y = t}.
584
585 // [rightHand] is the inverse of [arguments], that is, it maps variables
586 // to the assignments on which is occurs as the right-hand side.
587 Map<Variable, List<int>> rightHand = <Variable, List<int>>{};
588 for (int i = 0; i < parameters.length; i++) {
589 Variable param = getVariable(parameters[i]);
590 Variable arg = arguments[i];
591 if (param == null || param == arg) {
592 continue; // No assignment necessary.
593 }
594 List<int> list = rightHand[arg];
595 if (list == null) {
596 rightHand[arg] = list = <int>[];
597 }
598 list.add(i);
599 }
600
532 Statement first, current; 601 Statement first, current;
533 for (int i = 0; i < parameters.length; ++i) { 602 void addAssignment(Variable dst, Variable src) {
534 ir.Parameter parameter = parameters[i]; 603 if (first == null) {
535 Statement assignment; 604 first = current = new Assign(dst, src, null);
536 if (parameter.hasAtLeastOneUse) {
537 assignment = new Assign(variables[parameter], arguments[i], null,
538 parameter.hasExactlyOneUse);
539 } else { 605 } else {
540 assignment = new ExpressionStatement(arguments[i], null); 606 current = current.next = new Assign(dst, src, null);
541 }
542
543 if (first == null) {
544 current = first = assignment;
545 } else {
546 current = current.next = assignment;
547 } 607 }
548 } 608 }
549 609
610 List<Variable> assignmentSrc = new List<Variable>(parameters.length);
611 List<bool> done = new List<bool>(parameters.length);
612 void visitAssignment(int i) {
613 if (done[i] == true) {
614 return;
615 }
616 Variable param = getVariable(parameters[i]);
617 Variable arg = arguments[i];
618 if (param == null || param == arg) {
619 return; // No assignment necessary.
620 }
621 if (assignmentSrc[i] != null) {
622 // Cycle found; store argument in a temporary variable.
623 // The temporary will then be used as right-hand side when the
624 // assignment gets added.
625 if (assignmentSrc[i] != tempVar) { // Only move to temporary once.
626 assignmentSrc[i] = tempVar;
627 addAssignment(tempVar, arg);
628 }
629 return;
630 }
631 assignmentSrc[i] = arg;
632 List<int> paramUses = rightHand[param];
633 if (paramUses != null) {
634 for (int useIndex in paramUses) {
635 visitAssignment(useIndex);
636 }
637 }
638 addAssignment(param, assignmentSrc[i]);
639 done[i] = true;
640 }
641
642 for (int i = 0; i < parameters.length; i++) {
643 if (done[i] == null) {
644 visitAssignment(i);
645 }
646 }
647
550 if (first == null) { 648 if (first == null) {
551 first = buildRest(); 649 first = buildRest();
552 } else { 650 } else {
553 current.next = buildRest(); 651 current.next = buildRest();
554 } 652 }
555 return first; 653 return first;
556 } 654 }
557 655
558 Expression visitFunctionDefinition(ir.FunctionDefinition node) { 656 Expression visitFunctionDefinition(ir.FunctionDefinition node) {
559 returnContinuation = node.returnContinuation; 657 returnContinuation = node.returnContinuation;
560 List<Variable> parameters = <Variable>[]; 658 List<Variable> parameters = <Variable>[];
561 for (ir.Parameter p in node.parameters) { 659 for (ir.Parameter p in node.parameters) {
562 Variable parameter = new Variable(p.element); 660 Variable parameter = getVariable(p);
661 assert(parameter != null);
563 parameters.add(parameter); 662 parameters.add(parameter);
564 variables[p] = parameter;
565 } 663 }
566 function = new FunctionDefinition(parameters, visit(node.body)); 664 function = new FunctionDefinition(parameters, visit(node.body));
567 return null; 665 return null;
568 } 666 }
569 667
570 Statement visitLetPrim(ir.LetPrim node) { 668 Statement visitLetPrim(ir.LetPrim node) {
571 // LetPrim is translated to LetVal. 669 // LetPrim is translated to Assign.
572 Expression definition = visit(node.primitive); 670 Expression definition = visit(node.primitive);
573 if (node.primitive.hasAtLeastOneUse) { 671 Variable variable = getVariable(node.primitive);
574 Variable variable = new Variable(null); 672 if (variable != null) { // Variable is null if primitive is unused.
575 variables[node.primitive] = variable; 673 return new Assign(variable, definition, visit(node.body));
576 return new Assign(variable, definition, visit(node.body),
577 node.primitive.hasExactlyOneUse);
578 } else if (node.primitive is ir.Constant) { 674 } else if (node.primitive is ir.Constant) {
579 // TODO(kmillikin): Implement more systematic treatment of pure CPS 675 // TODO(kmillikin): Implement more systematic treatment of pure CPS
580 // values (e.g., as part of a shrinking reductions pass). 676 // values (e.g., as part of a shrinking reductions pass).
581 return visit(node.body); 677 return visit(node.body);
582 } else { 678 } else {
583 return new ExpressionStatement(definition, visit(node.body)); 679 return new ExpressionStatement(definition, visit(node.body));
584 } 680 }
585 } 681 }
586 682
587 Statement visitLetCont(ir.LetCont node) { 683 Statement visitLetCont(ir.LetCont node) {
588 Label label; 684 Label label;
589 if (node.continuation.hasMultipleUses) { 685 if (node.continuation.hasMultipleUses) {
590 label = new Label(); 686 label = new Label();
591 labels[node.continuation] = label; 687 labels[node.continuation] = label;
592 } 688 }
593 node.continuation.parameters.forEach((p) {
594 if (p.hasAtLeastOneUse) variables[p] = new Variable(null);
595 });
596 Statement body = visit(node.body); 689 Statement body = visit(node.body);
597 // The continuation's body is not always translated directly here because 690 // The continuation's body is not always translated directly here because
598 // it may have been already translated: 691 // it may have been already translated:
599 // * For singly-used continuations, the continuation's body is 692 // * For singly-used continuations, the continuation's body is
600 // translated at the site of the continuation invocation. 693 // translated at the site of the continuation invocation.
601 // * For recursive continuations, there is a single non-recursive 694 // * For recursive continuations, there is a single non-recursive
602 // invocation. The continuation's body is translated at the site 695 // invocation. The continuation's body is translated at the site
603 // of the non-recursive continuation invocation. 696 // of the non-recursive continuation invocation.
604 // See visitInvokeContinuation for the implementation. 697 // See visitInvokeContinuation for the implementation.
605 if (label == null || node.continuation.isRecursive) return body; 698 if (label == null || node.continuation.isRecursive) return body;
606 return new LabeledStatement(label, body, visit(node.continuation.body)); 699 return new LabeledStatement(label, body, visit(node.continuation.body));
607 } 700 }
608 701
609 Statement visitInvokeStatic(ir.InvokeStatic node) { 702 Statement visitInvokeStatic(ir.InvokeStatic node) {
610 // Calls are translated to direct style. 703 // Calls are translated to direct style.
611 List<Expression> arguments = translateArguments(node.arguments); 704 List<Expression> arguments = translateArguments(node.arguments);
612 Expression invoke = new InvokeStatic(node.target, node.selector, arguments); 705 Expression invoke = new InvokeStatic(node.target, node.selector, arguments);
613 ir.Continuation cont = node.continuation.definition; 706 ir.Continuation cont = node.continuation.definition;
614 if (cont == returnContinuation) { 707 if (cont == returnContinuation) {
615 return new Return(invoke); 708 return new Return(invoke);
616 } else { 709 } else {
617 assert(cont.hasExactlyOneUse); 710 assert(cont.hasExactlyOneUse);
618 assert(cont.parameters.length == 1); 711 assert(cont.parameters.length == 1);
619 return buildParameterAssignments(cont.parameters, [invoke], 712 return buildContinuationAssignment(cont.parameters.single, invoke,
620 () => visit(cont.body)); 713 () => visit(cont.body));
621 } 714 }
622 } 715 }
623 716
624 Statement visitInvokeMethod(ir.InvokeMethod node) { 717 Statement visitInvokeMethod(ir.InvokeMethod node) {
625 Variable receiver = variables[node.receiver.definition]; 718 Expression receiver = getVariableReference(node.receiver);
626 List<Expression> arguments = translateArguments(node.arguments); 719 List<Expression> arguments = translateArguments(node.arguments);
627 Expression invoke = new InvokeMethod(receiver, node.selector, arguments); 720 Expression invoke = new InvokeMethod(receiver, node.selector, arguments);
628 ir.Continuation cont = node.continuation.definition; 721 ir.Continuation cont = node.continuation.definition;
629 if (cont == returnContinuation) { 722 if (cont == returnContinuation) {
630 return new Return(invoke); 723 return new Return(invoke);
631 } else { 724 } else {
632 assert(cont.hasExactlyOneUse); 725 assert(cont.hasExactlyOneUse);
633 assert(cont.parameters.length == 1); 726 assert(cont.parameters.length == 1);
634 return buildParameterAssignments(cont.parameters, [invoke], 727 return buildContinuationAssignment(cont.parameters.single, invoke,
635 () => visit(cont.body)); 728 () => visit(cont.body));
636 } 729 }
637 } 730 }
638 731
639 Statement visitConcatenateStrings(ir.ConcatenateStrings node) { 732 Statement visitConcatenateStrings(ir.ConcatenateStrings node) {
640 List<Expression> arguments = translateArguments(node.arguments); 733 List<Expression> arguments = translateArguments(node.arguments);
641 Expression concat = new ConcatenateStrings(arguments); 734 Expression concat = new ConcatenateStrings(arguments);
642 ir.Continuation cont = node.continuation.definition; 735 ir.Continuation cont = node.continuation.definition;
643 if (cont == returnContinuation) { 736 if (cont == returnContinuation) {
644 return new Return(concat); 737 return new Return(concat);
645 } else { 738 } else {
646 assert(cont.hasExactlyOneUse); 739 assert(cont.hasExactlyOneUse);
647 assert(cont.parameters.length == 1); 740 assert(cont.parameters.length == 1);
648 return buildParameterAssignments(cont.parameters, [concat], 741 return buildContinuationAssignment(cont.parameters.single, concat,
649 () => visit(cont.body)); 742 () => visit(cont.body));
650 } 743 }
651 } 744 }
652 745
653 Statement visitInvokeConstructor(ir.InvokeConstructor node) { 746 Statement visitInvokeConstructor(ir.InvokeConstructor node) {
654 List<Expression> arguments = translateArguments(node.arguments); 747 List<Expression> arguments = translateArguments(node.arguments);
655 Expression invoke = 748 Expression invoke =
656 new InvokeConstructor(node.type, node.target, node.selector, arguments); 749 new InvokeConstructor(node.type, node.target, node.selector, arguments);
657 ir.Continuation cont = node.continuation.definition; 750 ir.Continuation cont = node.continuation.definition;
658 if (cont == returnContinuation) { 751 if (cont == returnContinuation) {
659 return new Return(invoke); 752 return new Return(invoke);
660 } else { 753 } else {
661 assert(cont.hasExactlyOneUse); 754 assert(cont.hasExactlyOneUse);
662 assert(cont.parameters.length == 1); 755 assert(cont.parameters.length == 1);
663 return buildParameterAssignments(cont.parameters, [invoke], 756 return buildContinuationAssignment(cont.parameters.single, invoke,
664 () => visit(cont.body)); 757 () => visit(cont.body));
665 } 758 }
666 } 759 }
667 760
668 Statement visitInvokeContinuation(ir.InvokeContinuation node) { 761 Statement visitInvokeContinuation(ir.InvokeContinuation node) {
669 // Invocations of the return continuation are translated to returns. 762 // Invocations of the return continuation are translated to returns.
670 // Other continuation invocations are replaced with assignments of the 763 // Other continuation invocations are replaced with assignments of the
671 // arguments to formal parameter variables, followed by the body if 764 // arguments to formal parameter variables, followed by the body if
672 // the continuation is singly reference or a break if it is multiply 765 // the continuation is singly reference or a break if it is multiply
673 // referenced. 766 // referenced.
674 ir.Continuation cont = node.continuation.definition; 767 ir.Continuation cont = node.continuation.definition;
675 if (cont == returnContinuation) { 768 if (cont == returnContinuation) {
676 assert(node.arguments.length == 1); 769 assert(node.arguments.length == 1);
677 return new Return(variables[node.arguments[0].definition]); 770 return new Return(getVariableReference(node.arguments.single));
678 } else { 771 } else {
679 List<Expression> arguments = translateArguments(node.arguments); 772 List<Expression> arguments = translatePhiArguments(node.arguments);
680 return buildParameterAssignments(cont.parameters, arguments, 773 return buildPhiAssignments(cont.parameters, arguments,
681 () { 774 () {
682 // Translate invocations of recursive and non-recursive 775 // Translate invocations of recursive and non-recursive
683 // continuations differently. 776 // continuations differently.
684 // * Non-recursive continuations 777 // * Non-recursive continuations
685 // - If there is one use, translate the continuation body 778 // - If there is one use, translate the continuation body
686 // inline at the invocation site. 779 // inline at the invocation site.
687 // - If there are multiple uses, translate to Break. 780 // - If there are multiple uses, translate to Break.
688 // * Recursive continuations 781 // * Recursive continuations
689 // - There is a single non-recursive invocation. Translate 782 // - There is a single non-recursive invocation. Translate
690 // the continuation body inline as a labeled loop at the 783 // the continuation body inline as a labeled loop at the
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
744 } 837 }
745 838
746 Expression visitContinuation(ir.Continuation node) { 839 Expression visitContinuation(ir.Continuation node) {
747 // Until continuations with multiple uses are supported, they are not 840 // Until continuations with multiple uses are supported, they are not
748 // visited. 841 // visited.
749 compiler.internalError(compiler.currentElement, 'Unexpected IR node.'); 842 compiler.internalError(compiler.currentElement, 'Unexpected IR node.');
750 return null; 843 return null;
751 } 844 }
752 845
753 Expression visitIsTrue(ir.IsTrue node) { 846 Expression visitIsTrue(ir.IsTrue node) {
754 return variables[node.value.definition]; 847 return getVariableReference(node.value);
755 } 848 }
756 } 849 }
757 850
758 /** 851 /**
759 * Performs the following transformations on the tree: 852 * Performs the following transformations on the tree:
760 * - Assignment propagation 853 * - Assignment propagation
761 * - If-to-conditional conversion 854 * - If-to-conditional conversion
762 * - Flatten nested ifs 855 * - Flatten nested ifs
763 * - Break inlining 856 * - Break inlining
764 * - Redirect breaks 857 * - Redirect breaks
(...skipping 240 matching lines...) Expand 10 before | Expand all | Expand 10 after
1005 return result; 1098 return result;
1006 } 1099 }
1007 1100
1008 node.body = visitStatement(node.body); 1101 node.body = visitStatement(node.body);
1009 1102
1010 if (node.label.useCount == 0) { 1103 if (node.label.useCount == 0) {
1011 // Eliminate the label if next was inlined at a break 1104 // Eliminate the label if next was inlined at a break
1012 return node.body; 1105 return node.body;
1013 } 1106 }
1014 1107
1108 // Do not propagate assignments into the successor statements, since they
1109 // may be overwritten by assignments in the body.
1110 List<Assign> savedEnvironment = environment;
1111 environment = <Assign>[];
1015 node.next = visitStatement(node.next); 1112 node.next = visitStatement(node.next);
1113 environment = savedEnvironment;
1114
1016 return node; 1115 return node;
1017 } 1116 }
1018 1117
1019 Statement visitIf(If node) { 1118 Statement visitIf(If node) {
1020 node.condition = visitExpression(node.condition); 1119 node.condition = visitExpression(node.condition);
1021 1120
1022 // Do not propagate assignments into branches. Doing so will lead to code 1121 // Do not propagate assignments into branches. Doing so will lead to code
1023 // duplication. 1122 // duplication.
1024 // TODO(kmillikin): Rethink this. Propagating some assignments (e.g., 1123 // TODO(kmillikin): Rethink this. Propagating some assignments (e.g.,
1025 // constants or variables) is benign. If they can occur here, they should 1124 // constants or variables) is benign. If they can occur here, they should
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
1123 Statement t, 1222 Statement t,
1124 Expression combine(Expression s, Expression t)) { 1223 Expression combine(Expression s, Expression t)) {
1125 if (s is Return && t is Return) { 1224 if (s is Return && t is Return) {
1126 return new Return(combine(s.value, t.value)); 1225 return new Return(combine(s.value, t.value));
1127 } 1226 }
1128 if (s is Assign && t is Assign && s.variable == t.variable) { 1227 if (s is Assign && t is Assign && s.variable == t.variable) {
1129 Statement next = combineStatements(s.next, t.next); 1228 Statement next = combineStatements(s.next, t.next);
1130 if (next != null) { 1229 if (next != null) {
1131 return new Assign(s.variable, 1230 return new Assign(s.variable,
1132 combine(s.definition, t.definition), 1231 combine(s.definition, t.definition),
1133 next, 1232 next);
1134 s.hasExactlyOneUse);
1135 } 1233 }
1136 } 1234 }
1137 if (s is ExpressionStatement && t is ExpressionStatement) { 1235 if (s is ExpressionStatement && t is ExpressionStatement) {
1138 Statement next = combineStatements(s.next, t.next); 1236 Statement next = combineStatements(s.next, t.next);
1139 if (next != null) { 1237 if (next != null) {
1140 return new ExpressionStatement(combine(s.expression, t.expression), 1238 return new ExpressionStatement(combine(s.expression, t.expression),
1141 next); 1239 next);
1142 } 1240 }
1143 } 1241 }
1144 return null; 1242 return null;
1145 } 1243 }
1146 1244
1147 /// Returns a statement equivalent to both [s] and [t], or null if [s] and 1245 /// Returns a statement equivalent to both [s] and [t], or null if [s] and
1148 /// [t] are incompatible. 1246 /// [t] are incompatible.
1149 /// If non-null is returned, the caller MUST discard [s] and [t] and use 1247 /// If non-null is returned, the caller MUST discard [s] and [t] and use
1150 /// the returned statement instead. 1248 /// the returned statement instead.
1151 /// If two breaks are combined, the label's break counter will be decremented. 1249 /// If two breaks are combined, the label's break counter will be decremented.
1152 static Statement combineStatements(Statement s, Statement t) { 1250 static Statement combineStatements(Statement s, Statement t) {
1153 if (s is Break && t is Break && s.target == t.target) { 1251 if (s is Break && t is Break && s.target == t.target) {
1154 --t.target.useCount; // Two breaks become one. 1252 --t.target.useCount; // Two breaks become one.
1155 return s; 1253 return s;
1156 } 1254 }
1157 if (s is Continue && t is Continue && s.target == t.target) { 1255 if (s is Continue && t is Continue && s.target == t.target) {
1158 --t.target.useCount; // Two continues become one. 1256 --t.target.useCount; // Two continues become one.
1159 return s; 1257 return s;
1160 } 1258 }
1161 if (s is Return && t is Return && equivalentExpressions(s.value, t.value)) { 1259 if (s is Return && t is Return) {
1162 return s; 1260 Expression e = combineExpressions(s.value, t.value);
1261 if (e != null) {
1262 return new Return(e);
1263 }
1163 } 1264 }
1164 return null; 1265 return null;
1165 } 1266 }
1166 1267
1167 /// True if the two expressions both syntactically and semantically 1268 /// Returns an expression equivalent to both [e1] and [e2].
1168 /// equivalent. 1269 /// If non-null is returned, the caller must discard [e1] and [e2] and use
1169 static bool equivalentExpressions(Expression e1, Expression e2) { 1270 /// the resulting expression in the tree.
1170 if (e1 == e2) { // Detect same variable reference 1271 static Expression combineExpressions(Expression e1, Expression e2) {
1171 // TODO(asgerf): This might turn the variable into a single-use, 1272 if (e1 is Variable && e1 == e2) {
1172 // but we currently don't discover this. 1273 --e1.readCount; // Two references become one.
1173 return true; 1274 return e1;
1174 } 1275 }
1175 if (e1 is Constant && e2 is Constant) { 1276 if (e1 is Constant && e2 is Constant && e1.value == e2.value) {
1176 return e1.value == e2.value; 1277 return e1;
1177 } 1278 }
1178 return false; 1279 return null;
1179 } 1280 }
1180 1281
1181 /// Try to collapse nested ifs using && and || expressions. 1282 /// Try to collapse nested ifs using && and || expressions.
1182 /// For example: 1283 /// For example:
1183 /// 1284 ///
1184 /// if (E1) { if (E2) S else break L } else break L 1285 /// if (E1) { if (E2) S else break L } else break L
1185 /// ==> 1286 /// ==>
1186 /// if (E1 && E2) S else break L 1287 /// if (E1 && E2) S else break L
1187 /// 1288 ///
1188 /// [branch1] and [branch2] control the position of the S statement. 1289 /// [branch1] and [branch2] control the position of the S statement.
(...skipping 605 matching lines...) Expand 10 before | Expand all | Expand 10 after
1794 } 1895 }
1795 } 1896 }
1796 1897
1797 /// Destructively updates each entry of [l] with the result of visiting it. 1898 /// Destructively updates each entry of [l] with the result of visiting it.
1798 void _rewriteList(List<Expression> l) { 1899 void _rewriteList(List<Expression> l) {
1799 for (int i = 0; i < l.length; i++) { 1900 for (int i = 0; i < l.length; i++) {
1800 l[i] = visitExpression(l[i]); 1901 l[i] = visitExpression(l[i]);
1801 } 1902 }
1802 } 1903 }
1803 } 1904 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698