| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 library copy_propagator; | |
| 6 | |
| 7 import '../elements/elements.dart'; | |
| 8 import 'tree_ir_nodes.dart'; | |
| 9 | |
| 10 /// Eliminates moving assignments, such as w := v, by assigning directly to w | |
| 11 /// at the definition of v. | |
| 12 /// | |
| 13 /// This compensates for suboptimal register allocation, and merges closure | |
| 14 /// variables with local temporaries that were left behind when translating | |
| 15 /// out of CPS (where closure variables live in a separate space). | |
| 16 class CopyPropagator extends RecursiveVisitor { | |
| 17 | |
| 18 /// After visitStatement returns, [move] maps a variable v to an | |
| 19 /// assignment A of form w := v, under the following conditions: | |
| 20 /// - there are no uses of w before A | |
| 21 /// - A is the only use of v | |
| 22 Map<Variable, Assign> move = <Variable, Assign>{}; | |
| 23 | |
| 24 /// Like [move], except w is the key instead of v. | |
| 25 Map<Variable, Assign> inverseMove = <Variable, Assign>{}; | |
| 26 | |
| 27 /// The function currently being rewritten. | |
| 28 FunctionElement functionElement; | |
| 29 | |
| 30 void rewrite(FunctionDefinition function) { | |
| 31 if (function.isAbstract) return; | |
| 32 | |
| 33 functionElement = function.element; | |
| 34 visitFunctionDefinition(function); | |
| 35 } | |
| 36 | |
| 37 void visitFunctionDefinition(FunctionDefinition function) { | |
| 38 assert(functionElement == function.element); | |
| 39 function.body = visitStatement(function.body); | |
| 40 | |
| 41 // Try to propagate moving assignments into function parameters. | |
| 42 // For example: | |
| 43 // foo(x) { | |
| 44 // var v1 = x; | |
| 45 // BODY | |
| 46 // } | |
| 47 // ==> | |
| 48 // foo(v1) { | |
| 49 // BODY | |
| 50 // } | |
| 51 | |
| 52 // Variables must not occur more than once in the parameter list, so | |
| 53 // invalidate all moving assignments that would propagate a parameter | |
| 54 // into another parameter. For example: | |
| 55 // foo(x,y) { | |
| 56 // y = x; | |
| 57 // BODY | |
| 58 // } | |
| 59 // Cannot declare function as foo(x,x)! | |
| 60 function.parameters.forEach(visitVariable); | |
| 61 | |
| 62 // Now do the propagation. | |
| 63 for (int i=0; i<function.parameters.length; i++) { | |
| 64 Variable param = function.parameters[i]; | |
| 65 Variable replacement = copyPropagateVariable(param); | |
| 66 replacement.element = param.element; // Preserve parameter name. | |
| 67 function.parameters[i] = replacement; | |
| 68 } | |
| 69 } | |
| 70 | |
| 71 Statement visitBasicBlock(Statement node) { | |
| 72 node = visitStatement(node); | |
| 73 move.clear(); | |
| 74 inverseMove.clear(); | |
| 75 return node; | |
| 76 } | |
| 77 | |
| 78 void visitVariable(Variable variable) { | |
| 79 // We have found a use of w. | |
| 80 // Remove assignments of form w := v from the move maps. | |
| 81 Assign movingAssignment = inverseMove.remove(variable); | |
| 82 if (movingAssignment != null) { | |
| 83 move.remove(movingAssignment.definition); | |
| 84 } | |
| 85 } | |
| 86 | |
| 87 /** | |
| 88 * Called when a definition of [v] is encountered. | |
| 89 * Attempts to propagate the assignment through a moving assignment. | |
| 90 * Returns the variable to be assigned into, defaulting to [v] itself if | |
| 91 * no optimization could be performed. | |
| 92 */ | |
| 93 Variable copyPropagateVariable(Variable v) { | |
| 94 Assign movingAssign = move[v]; | |
| 95 if (movingAssign != null) { | |
| 96 // We found the pattern: | |
| 97 // v := EXPR | |
| 98 // BLOCK (does not use w) | |
| 99 // w := v (only use of v) | |
| 100 // | |
| 101 // Rewrite to: | |
| 102 // w := EXPR | |
| 103 // BLOCK | |
| 104 // w := w (to be removed later) | |
| 105 Variable w = movingAssign.variable; | |
| 106 | |
| 107 // Make w := w. | |
| 108 // We can't remove the statement from here because we don't have | |
| 109 // parent pointers. So just make it a no-op so it can be removed later. | |
| 110 movingAssign.definition = w; | |
| 111 | |
| 112 // The intermediate variable 'v' should now be orphaned, so don't bother | |
| 113 // updating its read/write counters. | |
| 114 // Due to the nop trick, the variable 'w' now has one additional read | |
| 115 // and write. | |
| 116 ++w.writeCount; | |
| 117 ++w.readCount; | |
| 118 | |
| 119 // Make w := EXPR | |
| 120 return w; | |
| 121 } | |
| 122 return v; | |
| 123 } | |
| 124 | |
| 125 Statement visitAssign(Assign node) { | |
| 126 node.next = visitStatement(node.next); | |
| 127 node.variable = copyPropagateVariable(node.variable); | |
| 128 visitExpression(node.definition); | |
| 129 visitVariable(node.variable); | |
| 130 | |
| 131 // If this is a moving assignment w := v, with this being the only use of v, | |
| 132 // try to propagate it backwards. Do not propagate assignments where w | |
| 133 // is from an outer function scope. | |
| 134 if (node.definition is Variable) { | |
| 135 Variable def = node.definition; | |
| 136 if (def.readCount == 1 && | |
| 137 node.variable.host.element == functionElement) { | |
| 138 move[node.definition] = node; | |
| 139 inverseMove[node.variable] = node; | |
| 140 } | |
| 141 } | |
| 142 | |
| 143 return node; | |
| 144 } | |
| 145 | |
| 146 Statement visitLabeledStatement(LabeledStatement node) { | |
| 147 node.next = visitBasicBlock(node.next); | |
| 148 node.body = visitStatement(node.body); | |
| 149 return node; | |
| 150 } | |
| 151 | |
| 152 Statement visitReturn(Return node) { | |
| 153 visitExpression(node.value); | |
| 154 return node; | |
| 155 } | |
| 156 | |
| 157 Statement visitBreak(Break node) { | |
| 158 return node; | |
| 159 } | |
| 160 | |
| 161 Statement visitContinue(Continue node) { | |
| 162 return node; | |
| 163 } | |
| 164 | |
| 165 Statement visitIf(If node) { | |
| 166 visitExpression(node.condition); | |
| 167 node.thenStatement = visitBasicBlock(node.thenStatement); | |
| 168 node.elseStatement = visitBasicBlock(node.elseStatement); | |
| 169 return node; | |
| 170 } | |
| 171 | |
| 172 Statement visitWhileTrue(WhileTrue node) { | |
| 173 node.body = visitBasicBlock(node.body); | |
| 174 return node; | |
| 175 } | |
| 176 | |
| 177 Statement visitWhileCondition(WhileCondition node) { | |
| 178 throw "WhileCondition before LoopRewriter"; | |
| 179 } | |
| 180 | |
| 181 Statement visitFunctionDeclaration(FunctionDeclaration node) { | |
| 182 // Unlike var declarations, function declarations are not hoisted, so we | |
| 183 // can't do copy propagation of the variable. | |
| 184 new CopyPropagator().rewrite(node.definition); | |
| 185 node.next = visitStatement(node.next); | |
| 186 return node; | |
| 187 } | |
| 188 | |
| 189 Statement visitExpressionStatement(ExpressionStatement node) { | |
| 190 node.next = visitStatement(node.next); | |
| 191 visitExpression(node.expression); | |
| 192 return node; | |
| 193 } | |
| 194 | |
| 195 void visitFunctionExpression(FunctionExpression node) { | |
| 196 new CopyPropagator().rewrite(node.definition); | |
| 197 } | |
| 198 | |
| 199 } | |
| OLD | NEW |