| OLD | NEW |
| 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 part of tree_ir.optimization; | 5 part of tree_ir.optimization; |
| 6 | 6 |
| 7 /// Eliminates moving assignments, such as w := v, by assigning directly to w | 7 /// Eliminates moving assignments, such as w := v, by assigning directly to w |
| 8 /// at the definition of v. | 8 /// at the definition of v. |
| 9 /// | 9 /// |
| 10 /// This compensates for suboptimal register allocation, and merges closure | 10 /// This compensates for suboptimal register allocation, and merges closure |
| 11 /// variables with local temporaries that were left behind when translating | 11 /// variables with local temporaries that were left behind when translating |
| 12 /// out of CPS (where closure variables live in a separate space). | 12 /// out of CPS (where closure variables live in a separate space). |
| 13 class CopyPropagator extends RecursiveVisitor with PassMixin { | 13 class CopyPropagator extends RecursiveVisitor with PassMixin { |
| 14 | 14 |
| 15 /// After visitStatement returns, [move] maps a variable v to an | 15 /// After visitStatement returns, [move] maps a variable v to an |
| 16 /// assignment A of form w := v, under the following conditions: | 16 /// assignment A of form w := v, under the following conditions: |
| 17 /// - there are no uses of w before A | 17 /// - there are no reads or writes of w before A |
| 18 /// - A is the only use of v | 18 /// - A is the only use of v |
| 19 Map<Variable, Assign> move = <Variable, Assign>{}; | 19 Map<Variable, Assign> move = <Variable, Assign>{}; |
| 20 | 20 |
| 21 /// Like [move], except w is the key instead of v. | 21 /// Like [move], except w is the key instead of v. |
| 22 Map<Variable, Assign> inverseMove = <Variable, Assign>{}; | 22 Map<Variable, Assign> inverseMove = <Variable, Assign>{}; |
| 23 | 23 |
| 24 ExecutableElement currentElement; | 24 ExecutableElement currentElement; |
| 25 | 25 |
| 26 void rewriteExecutableDefinition(ExecutableDefinition root) { | 26 void rewriteExecutableDefinition(ExecutableDefinition root) { |
| 27 currentElement = root.element; | 27 currentElement = root.element; |
| (...skipping 16 matching lines...) Expand all Loading... |
| 44 // } | 44 // } |
| 45 | 45 |
| 46 // Variables must not occur more than once in the parameter list, so | 46 // Variables must not occur more than once in the parameter list, so |
| 47 // invalidate all moving assignments that would propagate a parameter | 47 // invalidate all moving assignments that would propagate a parameter |
| 48 // into another parameter. For example: | 48 // into another parameter. For example: |
| 49 // foo(x,y) { | 49 // foo(x,y) { |
| 50 // y = x; | 50 // y = x; |
| 51 // BODY | 51 // BODY |
| 52 // } | 52 // } |
| 53 // Cannot declare function as foo(x,x)! | 53 // Cannot declare function as foo(x,x)! |
| 54 node.parameters.forEach(visitVariable); | 54 node.parameters.forEach(invalidateMovingAssignment); |
| 55 | 55 |
| 56 // Now do the propagation. | 56 // Now do the propagation. |
| 57 for (int i = 0; i < node.parameters.length; i++) { | 57 for (int i = 0; i < node.parameters.length; i++) { |
| 58 Variable param = node.parameters[i]; | 58 Variable param = node.parameters[i]; |
| 59 Variable replacement = copyPropagateVariable(param); | 59 Variable replacement = copyPropagateVariable(param); |
| 60 replacement.element = param.element; // Preserve parameter name. | 60 replacement.element = param.element; // Preserve parameter name. |
| 61 node.parameters[i] = replacement; | 61 node.parameters[i] = replacement; |
| 62 } | 62 } |
| 63 } | 63 } |
| 64 | 64 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 80 // } | 80 // } |
| 81 | 81 |
| 82 // Variables must not occur more than once in the parameter list, so | 82 // Variables must not occur more than once in the parameter list, so |
| 83 // invalidate all moving assignments that would propagate a parameter | 83 // invalidate all moving assignments that would propagate a parameter |
| 84 // into another parameter. For example: | 84 // into another parameter. For example: |
| 85 // foo(x,y) { | 85 // foo(x,y) { |
| 86 // y = x; | 86 // y = x; |
| 87 // BODY | 87 // BODY |
| 88 // } | 88 // } |
| 89 // Cannot declare function as foo(x,x)! | 89 // Cannot declare function as foo(x,x)! |
| 90 node.parameters.forEach(visitVariable); | 90 node.parameters.forEach(invalidateMovingAssignment); |
| 91 | 91 |
| 92 // Now do the propagation. | 92 // Now do the propagation. |
| 93 for (int i = 0; i < node.parameters.length; i++) { | 93 for (int i = 0; i < node.parameters.length; i++) { |
| 94 Variable param = node.parameters[i]; | 94 Variable param = node.parameters[i]; |
| 95 Variable replacement = copyPropagateVariable(param); | 95 Variable replacement = copyPropagateVariable(param); |
| 96 replacement.element = param.element; // Preserve parameter name. | 96 replacement.element = param.element; // Preserve parameter name. |
| 97 node.parameters[i] = replacement; | 97 node.parameters[i] = replacement; |
| 98 } | 98 } |
| 99 | 99 |
| 100 } | 100 } |
| 101 | 101 |
| 102 | 102 |
| 103 Statement visitBasicBlock(Statement node) { | 103 Statement visitBasicBlock(Statement node) { |
| 104 node = visitStatement(node); | 104 node = visitStatement(node); |
| 105 move.clear(); | 105 move.clear(); |
| 106 inverseMove.clear(); | 106 inverseMove.clear(); |
| 107 return node; | 107 return node; |
| 108 } | 108 } |
| 109 | 109 |
| 110 void visitVariable(Variable variable) { | 110 /// Remove an assignment of form [w] := v from the move maps. |
| 111 // We have found a use of w. | 111 void invalidateMovingAssignment(Variable w) { |
| 112 // Remove assignments of form w := v from the move maps. | 112 Assign movingAssignment = inverseMove.remove(w); |
| 113 Assign movingAssignment = inverseMove.remove(variable); | |
| 114 if (movingAssignment != null) { | 113 if (movingAssignment != null) { |
| 115 move.remove(movingAssignment.definition); | 114 VariableUse def = movingAssignment.definition; |
| 115 move.remove(def.variable); |
| 116 } | 116 } |
| 117 } | 117 } |
| 118 | 118 |
| 119 visitVariableUse(VariableUse node) { |
| 120 // We found a use of w; we can't propagate assignments across this use. |
| 121 invalidateMovingAssignment(node.variable); |
| 122 } |
| 123 |
| 119 /** | 124 /** |
| 120 * Called when a definition of [v] is encountered. | 125 * Called when a definition of [v] is encountered. |
| 121 * Attempts to propagate the assignment through a moving assignment. | 126 * Attempts to propagate the assignment through a moving assignment. |
| 122 * Returns the variable to be assigned into, defaulting to [v] itself if | 127 * Returns the variable to be assigned into, defaulting to [v] itself if |
| 123 * no optimization could be performed. | 128 * no optimization could be performed. |
| 124 */ | 129 */ |
| 125 Variable copyPropagateVariable(Variable v) { | 130 Variable copyPropagateVariable(Variable v) { |
| 126 Assign movingAssign = move[v]; | 131 Assign movingAssign = move[v]; |
| 127 if (movingAssign != null) { | 132 if (movingAssign != null) { |
| 128 // We found the pattern: | 133 // We found the pattern: |
| 129 // v := EXPR | 134 // v := EXPR |
| 130 // BLOCK (does not use w) | 135 // BLOCK (does not use w) |
| 131 // w := v (only use of v) | 136 // w := v (only use of v) |
| 132 // | 137 // |
| 133 // Rewrite to: | 138 // Rewrite to: |
| 134 // w := EXPR | 139 // w := EXPR |
| 135 // BLOCK | 140 // BLOCK |
| 136 // w := w (to be removed later) | 141 // w := w (to be removed later) |
| 137 Variable w = movingAssign.variable; | 142 Variable w = movingAssign.variable; |
| 138 | 143 |
| 139 // Make w := w. | 144 // Make w := w. |
| 140 // We can't remove the statement from here because we don't have | 145 // We can't remove the statement from here because we don't have |
| 141 // parent pointers. So just make it a no-op so it can be removed later. | 146 // parent pointers. So just make it a no-op so it can be removed later. |
| 142 movingAssign.definition = w; | 147 movingAssign.definition = new VariableUse(w); |
| 143 | 148 |
| 144 // The intermediate variable 'v' should now be orphaned, so don't bother | 149 // The intermediate variable 'v' should now be orphaned, so don't bother |
| 145 // updating its read/write counters. | 150 // updating its read/write counters. |
| 146 // Due to the nop trick, the variable 'w' now has one additional read | |
| 147 // and write. | |
| 148 ++w.writeCount; | |
| 149 ++w.readCount; | |
| 150 | 151 |
| 151 // Make w := EXPR | 152 // Make w := EXPR |
| 153 ++w.writeCount; |
| 152 return w; | 154 return w; |
| 153 } | 155 } |
| 154 return v; | 156 return v; |
| 155 } | 157 } |
| 156 | 158 |
| 157 Statement visitAssign(Assign node) { | 159 Statement visitAssign(Assign node) { |
| 158 node.next = visitStatement(node.next); | 160 node.next = visitStatement(node.next); |
| 159 node.variable = copyPropagateVariable(node.variable); | 161 node.variable = copyPropagateVariable(node.variable); |
| 162 |
| 163 // If a moving assignment w := v exists later, and we assign to w here, |
| 164 // the moving assignment is no longer a candidate for copy propagation. |
| 165 invalidateMovingAssignment(node.variable); |
| 166 |
| 160 visitExpression(node.definition); | 167 visitExpression(node.definition); |
| 161 visitVariable(node.variable); | |
| 162 | 168 |
| 163 // If this is a moving assignment w := v, with this being the only use of v, | 169 // If this is a moving assignment w := v, with this being the only use of v, |
| 164 // try to propagate it backwards. Do not propagate assignments where w | 170 // try to propagate it backwards. Do not propagate assignments where w |
| 165 // is from an outer function scope. | 171 // is from an outer function scope. |
| 166 if (node.definition is Variable) { | 172 if (node.definition is VariableUse) { |
| 167 Variable def = node.definition; | 173 VariableUse definition = node.definition; |
| 168 if (def.readCount == 1 && | 174 if (definition.variable.readCount == 1 && |
| 169 node.variable.host == currentElement) { | 175 node.variable.host == currentElement) { |
| 170 move[node.definition] = node; | 176 move[definition.variable] = node; |
| 171 inverseMove[node.variable] = node; | 177 inverseMove[node.variable] = node; |
| 172 } | 178 } |
| 173 } | 179 } |
| 174 | 180 |
| 175 return node; | 181 return node; |
| 176 } | 182 } |
| 177 | 183 |
| 178 Statement visitLabeledStatement(LabeledStatement node) { | 184 Statement visitLabeledStatement(LabeledStatement node) { |
| 179 node.next = visitBasicBlock(node.next); | 185 node.next = visitBasicBlock(node.next); |
| 180 node.body = visitStatement(node.body); | 186 node.body = visitStatement(node.body); |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 239 | 245 |
| 240 void visitFunctionExpression(FunctionExpression node) { | 246 void visitFunctionExpression(FunctionExpression node) { |
| 241 new CopyPropagator().rewrite(node.definition); | 247 new CopyPropagator().rewrite(node.definition); |
| 242 } | 248 } |
| 243 | 249 |
| 244 void visitFieldInitializer(FieldInitializer node) { | 250 void visitFieldInitializer(FieldInitializer node) { |
| 245 visitStatement(node.body); | 251 visitStatement(node.body); |
| 246 } | 252 } |
| 247 | 253 |
| 248 } | 254 } |
| OLD | NEW |