| Index: sdk/lib/_internal/compiler/implementation/dart_backend/dart_tree.dart
|
| diff --git a/sdk/lib/_internal/compiler/implementation/dart_backend/dart_tree.dart b/sdk/lib/_internal/compiler/implementation/dart_backend/dart_tree.dart
|
| index 936224770e4a3c0b057e38f24f6a9ae5ad1249b4..620de03e62ac137575ccf651fde50460505034f4 100644
|
| --- a/sdk/lib/_internal/compiler/implementation/dart_backend/dart_tree.dart
|
| +++ b/sdk/lib/_internal/compiler/implementation/dart_backend/dart_tree.dart
|
| @@ -422,7 +422,7 @@ class Continue extends Jump {
|
| */
|
| class Assign extends Statement {
|
| Statement next;
|
| - final Variable variable;
|
| + Variable variable;
|
| Expression definition;
|
|
|
| /// If true, this declares a new copy of the closure variable.
|
| @@ -1110,84 +1110,6 @@ class Builder extends ir.Visitor<Node> {
|
| }
|
| }
|
|
|
| -/// Eliminates redundant variables and assignments that occur immediately after
|
| -/// parameters are declared or after a function declaration.
|
| -///
|
| -/// These patterns arise when translating out of CPS where closure variables
|
| -/// live in a separate space. Since function parameters are IR primitives they
|
| -/// must be moved into a separate closure variable for inner functions to access
|
| -/// them. For example:
|
| -///
|
| -/// foo(x) {
|
| -/// let v1 = ref x in BODY
|
| -/// }
|
| -/// ==> (dart_tree Builder)
|
| -/// foo(x) {
|
| -/// var v1 = x;
|
| -/// BODY..
|
| -/// }
|
| -///
|
| -/// This phase attempts to merge v1 and x in the example above.
|
| -/// A similar pattern can occur for local function declarations that are used
|
| -/// from closures.
|
| -class CopyPropagateClosureVariables extends RecursiveVisitor {
|
| -
|
| - void rewrite(FunctionDefinition definition) {
|
| - visitFunctionDefinition(definition);
|
| - }
|
| -
|
| - /// Performs the rewrite:
|
| - ///
|
| - /// foo(x) { var v0 = x; S }
|
| - /// ==> (move v0 into parameter)
|
| - /// foo(v0) { S }
|
| - /// ==> (change the name of v0 to be x, so we preserve the parameter name)
|
| - /// foo(x) { S[v0\x] }
|
| - ///
|
| - /// Condition: x cannot be used anywhere else.
|
| - visitFunctionDefinition(FunctionDefinition definition) {
|
| - while (definition.body is Assign) {
|
| - Assign assign = definition.body;
|
| - if (assign.definition is! Variable) break;
|
| -
|
| - Variable rightHand = assign.definition;
|
| - if (rightHand.readCount != 1) break;
|
| -
|
| - int paramIndex = definition.parameters.indexOf(rightHand);
|
| - if (paramIndex == -1) break;
|
| -
|
| - // A variable may not occur as a parameter more than once.
|
| - if (definition.parameters.contains(assign.variable)) break;
|
| -
|
| - definition.parameters[paramIndex] = assign.variable;
|
| - assign.variable.element = rightHand.element;
|
| - definition.body = assign.next;
|
| - }
|
| -
|
| - visitStatement(definition.body); // Visit nested function definitions.
|
| - }
|
| -
|
| - /// Performs the rewrite:
|
| - ///
|
| - /// int v0() { S }
|
| - /// foo = v0;
|
| - /// ==>
|
| - /// int foo() { S }
|
| - ///
|
| - /// Condition: v0 cannot be used anywhere else.
|
| - visitFunctionDeclaration(FunctionDeclaration node) {
|
| - Statement next = node.next;
|
| - if (next is Assign &&
|
| - next.definition == node.variable &&
|
| - node.variable.readCount == 1 &&
|
| - next.variable.writeCount == 1) {
|
| - node.variable = next.variable;
|
| - node.next = next.next;
|
| - }
|
| - super.visitFunctionDeclaration(node);
|
| - }
|
| -
|
| -}
|
|
|
| /**
|
| * Performs the following transformations on the tree:
|
| @@ -1733,6 +1655,187 @@ class StatementRewriter extends Visitor<Statement, Expression> {
|
| }
|
| }
|
|
|
| +/// Eliminates moving assignments, such as w := v, by assigning directly to w
|
| +/// at the definition of v.
|
| +///
|
| +/// This compensates for suboptimal register allocation, and merges closure
|
| +/// variables with local temporaries that were left behind when translating
|
| +/// out of CPS (where closure variables live in a separate space).
|
| +class CopyPropagator extends RecursiveVisitor {
|
| +
|
| + /// After visitStatement returns, [move] maps a variable v to an
|
| + /// assignment A of form w := v, under the following conditions:
|
| + /// - there are no uses of w before A
|
| + /// - A is the only use of v
|
| + Map<Variable, Assign> move = <Variable, Assign>{};
|
| +
|
| + /// Like [move], except w is the key instead of v.
|
| + Map<Variable, Assign> inverseMove = <Variable, Assign>{};
|
| +
|
| + void rewrite(FunctionDefinition function) {
|
| + visitFunctionDefinition(function);
|
| + }
|
| +
|
| + void visitFunctionDefinition(FunctionDefinition function) {
|
| + function.body = visitStatement(function.body);
|
| +
|
| + // Try to propagate moving assignments into function parameters.
|
| + // For example:
|
| + // foo(x) {
|
| + // var v1 = x;
|
| + // BODY
|
| + // }
|
| + // ==>
|
| + // foo(v1) {
|
| + // BODY
|
| + // }
|
| +
|
| + // Variables must not occur more than once in the parameter list, so
|
| + // invalidate all moving assignments that would propagate a parameter
|
| + // into another parameter. For example:
|
| + // foo(x,y) {
|
| + // y = x;
|
| + // BODY
|
| + // }
|
| + // Cannot declare function as foo(x,x)!
|
| + function.parameters.forEach(visitVariable);
|
| +
|
| + // Now do the propagation.
|
| + for (int i=0; i<function.parameters.length; i++) {
|
| + Variable param = function.parameters[i];
|
| + Variable replacement = copyPropagateVariable(param);
|
| + replacement.element = param.element; // Preserve parameter name.
|
| + function.parameters[i] = replacement;
|
| + }
|
| + }
|
| +
|
| + Statement visitBasicBlock(Statement node) {
|
| + node = visitStatement(node);
|
| + move.clear();
|
| + inverseMove.clear();
|
| + return node;
|
| + }
|
| +
|
| + void visitVariable(Variable variable) {
|
| + // We have found a use of w.
|
| + // Remove assignments of form w := v from the move maps.
|
| + Assign movingAssignment = inverseMove.remove(variable);
|
| + if (movingAssignment != null) {
|
| + move.remove(movingAssignment.definition);
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Called when a definition of [v] is encountered.
|
| + * Attempts to propagate the assignment through a moving assignment.
|
| + * Returns the variable to be assigned into, defaulting to [v] itself if
|
| + * no optimization could be performed.
|
| + */
|
| + Variable copyPropagateVariable(Variable v) {
|
| + Assign movingAssign = move[v];
|
| + if (movingAssign != null) {
|
| + // We found the pattern:
|
| + // v := EXPR
|
| + // BLOCK (does not use w)
|
| + // w := v (only use of v)
|
| + //
|
| + // Rewrite to:
|
| + // w := EXPR
|
| + // BLOCK
|
| + // w := w (to be removed later)
|
| + Variable w = movingAssign.variable;
|
| +
|
| + // Make w := w.
|
| + // We can't remove the statement from here because we don't have
|
| + // parent pointers. So just make it a no-op so it can be removed later.
|
| + movingAssign.definition = w;
|
| +
|
| + // The intermediate variable 'v' should now be orphaned, so don't bother
|
| + // updating its read/write counters.
|
| + // Due to the nop trick, the variable 'w' now has one additional read
|
| + // and write.
|
| + ++w.writeCount;
|
| + ++w.readCount;
|
| +
|
| + // Make w := EXPR
|
| + return w;
|
| + }
|
| + return v;
|
| + }
|
| +
|
| + Statement visitAssign(Assign node) {
|
| + node.next = visitStatement(node.next);
|
| + node.variable = copyPropagateVariable(node.variable);
|
| + visitExpression(node.definition);
|
| + visitVariable(node.variable);
|
| +
|
| + // If this is a moving assignment w := v, with this being the only use of v,
|
| + // try to propagate it backwards.
|
| + if (node.definition is Variable) {
|
| + Variable def = node.definition;
|
| + if (def.readCount == 1) {
|
| + move[node.definition] = node;
|
| + inverseMove[node.variable] = node;
|
| + }
|
| + }
|
| +
|
| + return node;
|
| + }
|
| +
|
| + Statement visitLabeledStatement(LabeledStatement node) {
|
| + node.next = visitBasicBlock(node.next);
|
| + node.body = visitStatement(node.body);
|
| + return node;
|
| + }
|
| +
|
| + Statement visitReturn(Return node) {
|
| + visitExpression(node.value);
|
| + return node;
|
| + }
|
| +
|
| + Statement visitBreak(Break node) {
|
| + return node;
|
| + }
|
| +
|
| + Statement visitContinue(Continue node) {
|
| + return node;
|
| + }
|
| +
|
| + Statement visitIf(If node) {
|
| + visitExpression(node.condition);
|
| + node.thenStatement = visitBasicBlock(node.thenStatement);
|
| + node.elseStatement = visitBasicBlock(node.elseStatement);
|
| + return node;
|
| + }
|
| +
|
| + Statement visitWhileTrue(WhileTrue node) {
|
| + node.body = visitBasicBlock(node.body);
|
| + return node;
|
| + }
|
| +
|
| + Statement visitWhileCondition(WhileCondition node) {
|
| + throw "WhileCondition before LoopRewriter";
|
| + }
|
| +
|
| + Statement visitFunctionDeclaration(FunctionDeclaration node) {
|
| + new CopyPropagator().visitFunctionDefinition(node.definition);
|
| + node.next = visitStatement(node.next);
|
| + node.variable = copyPropagateVariable(node.variable);
|
| + return node;
|
| + }
|
| +
|
| + Statement visitExpressionStatement(ExpressionStatement node) {
|
| + visitExpression(node.expression);
|
| + node.next = visitStatement(node.next);
|
| + return node;
|
| + }
|
| +
|
| + void visitFunctionExpression(FunctionExpression node) {
|
| + new CopyPropagator().visitFunctionDefinition(node.definition);
|
| + }
|
| +
|
| +}
|
| +
|
| /// Rewrites [WhileTrue] statements with an [If] body into a [WhileCondition],
|
| /// in situations where only one of the branches contains a [Continue] to the
|
| /// loop. Schematically:
|
| @@ -1771,6 +1874,12 @@ class LoopRewriter extends RecursiveVisitor {
|
| }
|
|
|
| Statement visitAssign(Assign node) {
|
| + // Clean up redundant assignments left behind in the previous phase.
|
| + if (node.variable == node.definition) {
|
| + --node.variable.readCount;
|
| + --node.variable.writeCount;
|
| + return visitStatement(node.next);
|
| + }
|
| visitExpression(node.definition);
|
| node.next = visitStatement(node.next);
|
| return node;
|
|
|