| 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 /** | 119 /** |
| 120 * Called when a definition of [v] is encountered. | 120 * Called when a definition of [v] is encountered. |
| 121 * Attempts to propagate the assignment through a moving assignment. | 121 * Attempts to propagate the assignment through a moving assignment. |
| 122 * Returns the variable to be assigned into, defaulting to [v] itself if | 122 * Returns the variable to be assigned into, defaulting to [v] itself if |
| 123 * no optimization could be performed. | 123 * no optimization could be performed. |
| 124 */ | 124 */ |
| 125 Variable copyPropagateVariable(Variable v) { | 125 Variable copyPropagateVariable(Variable v) { |
| 126 Assign movingAssign = move[v]; | 126 Assign movingAssign = move[v]; |
| 127 if (movingAssign != null) { | 127 if (movingAssign != null) { |
| 128 // We found the pattern: | 128 // We found the pattern: |
| 129 // v := EXPR | 129 // v := EXPR |
| 130 // BLOCK (does not use w) | 130 // BLOCK (does not use w) |
| 131 // w := v (only use of v) | 131 // w := v (only use of v) |
| 132 // | 132 // |
| 133 // Rewrite to: | 133 // Rewrite to: |
| 134 // w := EXPR | 134 // w := EXPR |
| 135 // BLOCK | 135 // BLOCK |
| 136 // w := w (to be removed later) | 136 // w := w (to be removed later) |
| 137 Variable w = movingAssign.variable; | 137 Variable w = movingAssign.variable; |
| 138 | 138 |
| 139 // Make w := w. | 139 // Make w := w. |
| 140 // We can't remove the statement from here because we don't have | 140 // 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. | 141 // parent pointers. So just make it a no-op so it can be removed later. |
| 142 movingAssign.definition = w; | 142 movingAssign.definition = new VariableUse(w); |
| 143 | 143 |
| 144 // The intermediate variable 'v' should now be orphaned, so don't bother | 144 // The intermediate variable 'v' should now be orphaned, so don't bother |
| 145 // updating its read/write counters. | 145 // 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 | 146 |
| 151 // Make w := EXPR | 147 // Make w := EXPR |
| 148 ++w.writeCount; |
| 152 return w; | 149 return w; |
| 153 } | 150 } |
| 154 return v; | 151 return v; |
| 155 } | 152 } |
| 156 | 153 |
| 157 Statement visitAssign(Assign node) { | 154 Statement visitAssign(Assign node) { |
| 158 node.next = visitStatement(node.next); | 155 node.next = visitStatement(node.next); |
| 159 node.variable = copyPropagateVariable(node.variable); | 156 node.variable = copyPropagateVariable(node.variable); |
| 157 |
| 158 // If a moving assignment w := v exists later, and we assign to w here, |
| 159 // the moving assignment is no longer a candidate for copy propagation. |
| 160 invalidateMovingAssignment(node.variable); |
| 161 |
| 160 visitExpression(node.definition); | 162 visitExpression(node.definition); |
| 161 visitVariable(node.variable); | |
| 162 | 163 |
| 163 // If this is a moving assignment w := v, with this being the only use of v, | 164 // 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 | 165 // try to propagate it backwards. Do not propagate assignments where w |
| 165 // is from an outer function scope. | 166 // is from an outer function scope. |
| 166 if (node.definition is Variable) { | 167 if (node.definition is VariableUse) { |
| 167 Variable def = node.definition; | 168 VariableUse definition = node.definition; |
| 168 if (def.readCount == 1 && | 169 if (definition.variable.readCount == 1 && |
| 169 node.variable.host == currentElement) { | 170 node.variable.host == currentElement) { |
| 170 move[node.definition] = node; | 171 move[definition.variable] = node; |
| 171 inverseMove[node.variable] = node; | 172 inverseMove[node.variable] = node; |
| 172 } | 173 } |
| 173 } | 174 } |
| 174 | 175 |
| 175 return node; | 176 return node; |
| 176 } | 177 } |
| 177 | 178 |
| 178 Statement visitLabeledStatement(LabeledStatement node) { | 179 Statement visitLabeledStatement(LabeledStatement node) { |
| 179 node.next = visitBasicBlock(node.next); | 180 node.next = visitBasicBlock(node.next); |
| 180 node.body = visitStatement(node.body); | 181 node.body = visitStatement(node.body); |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 233 | 234 |
| 234 void visitFunctionExpression(FunctionExpression node) { | 235 void visitFunctionExpression(FunctionExpression node) { |
| 235 new CopyPropagator().rewrite(node.definition); | 236 new CopyPropagator().rewrite(node.definition); |
| 236 } | 237 } |
| 237 | 238 |
| 238 void visitFieldInitializer(FieldInitializer node) { | 239 void visitFieldInitializer(FieldInitializer node) { |
| 239 visitStatement(node.body); | 240 visitStatement(node.body); |
| 240 } | 241 } |
| 241 | 242 |
| 242 } | 243 } |
| OLD | NEW |