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

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

Issue 368363002: dart2dart: Copy propagation in dart_tree. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Typo fix Created 6 years, 5 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « sdk/lib/_internal/compiler/implementation/dart_backend/backend.dart ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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;
« no previous file with comments | « sdk/lib/_internal/compiler/implementation/dart_backend/backend.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698