| 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 /** | 7 /** |
| 8 * Performs the following transformations on the tree: | 8 * Performs the following transformations on the tree: |
| 9 * - Assignment propagation | 9 * - Assignment propagation |
| 10 * - If-to-conditional conversion | 10 * - If-to-conditional conversion |
| (...skipping 19 matching lines...) Expand all Loading... |
| 30 * seen, but are only processed once to keep this transformation linear in | 30 * seen, but are only processed once to keep this transformation linear in |
| 31 * the size of the tree. | 31 * the size of the tree. |
| 32 * | 32 * |
| 33 * The transformation builds an environment containing [Assign] bindings that | 33 * The transformation builds an environment containing [Assign] bindings that |
| 34 * are in scope. These bindings have yet-untranslated definitions. When a use | 34 * are in scope. These bindings have yet-untranslated definitions. When a use |
| 35 * is encountered the transformation determines if it is safe and profitable | 35 * is encountered the transformation determines if it is safe and profitable |
| 36 * to propagate the definition to its use. If so, it is removed from the | 36 * to propagate the definition to its use. If so, it is removed from the |
| 37 * environment and the definition is recursively processed (in the | 37 * environment and the definition is recursively processed (in the |
| 38 * new environment at the use site) before being propagated. | 38 * new environment at the use site) before being propagated. |
| 39 * | 39 * |
| 40 * See [visitVariable] for the implementation of the heuristic for propagating | 40 * See [visitVariableUse] for the implementation of the heuristic for |
| 41 * a definition. | 41 * propagating a definition. |
| 42 * | 42 * |
| 43 * | 43 * |
| 44 * IF-TO-CONDITIONAL CONVERSION: | 44 * IF-TO-CONDITIONAL CONVERSION: |
| 45 * If-statement are converted to conditional expressions when possible. | 45 * If-statement are converted to conditional expressions when possible. |
| 46 * For example: | 46 * For example: |
| 47 * | 47 * |
| 48 * if (v0) { v1 = foo(); break L } else { v1 = bar(); break L } | 48 * if (v0) { v1 = foo(); break L } else { v1 = bar(); break L } |
| 49 * ==> | 49 * ==> |
| 50 * { v1 = v0 ? foo() : bar(); break L } | 50 * { v1 = v0 ? foo() : bar(); break L } |
| 51 * | 51 * |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 150 for (int i = node.arguments.length - 1; i >= 0; --i) { | 150 for (int i = node.arguments.length - 1; i >= 0; --i) { |
| 151 node.arguments[i] = visitStatement(node.arguments[i]); | 151 node.arguments[i] = visitStatement(node.arguments[i]); |
| 152 assert(environment.isEmpty); | 152 assert(environment.isEmpty); |
| 153 } | 153 } |
| 154 }); | 154 }); |
| 155 return node; | 155 return node; |
| 156 } | 156 } |
| 157 | 157 |
| 158 Expression visitExpression(Expression e) => e.processed ? e : e.accept(this); | 158 Expression visitExpression(Expression e) => e.processed ? e : e.accept(this); |
| 159 | 159 |
| 160 Expression visitVariable(Variable node) { | 160 @override |
| 161 Expression visitVariableUse(VariableUse node) { |
| 161 // Propagate constant to use site. | 162 // Propagate constant to use site. |
| 162 Expression constant = constantEnvironment[node]; | 163 Expression constant = constantEnvironment[node.variable]; |
| 163 if (constant != null) return constant; | 164 if (constant != null) return constant; |
| 164 | 165 |
| 165 // Propagate a variable's definition to its use site if: | 166 // Propagate a variable's definition to its use site if: |
| 166 // 1. It has a single use, to avoid code growth and potential duplication | 167 // 1. It has a single use, to avoid code growth and potential duplication |
| 167 // of side effects, AND | 168 // of side effects, AND |
| 168 // 2. It was the most recent expression evaluated so that we do not | 169 // 2. It was the most recent expression evaluated so that we do not |
| 169 // reorder expressions with side effects. | 170 // reorder expressions with side effects. |
| 170 if (!environment.isEmpty && | 171 if (!environment.isEmpty && |
| 171 environment.last.variable == node && | 172 environment.last.variable == node.variable && |
| 172 environment.last.hasExactlyOneUse) { | 173 environment.last.hasExactlyOneUse) { |
| 173 return visitExpression(environment.removeLast().definition); | 174 return visitExpression(environment.removeLast().definition); |
| 174 } | 175 } |
| 176 |
| 175 // If the definition could not be propagated, leave the variable use. | 177 // If the definition could not be propagated, leave the variable use. |
| 176 return node; | 178 return node; |
| 177 } | 179 } |
| 178 | 180 |
| 179 /// Returns true if [exp] has no side effects and has a constant value within | 181 /// Returns true if [exp] has no side effects and has a constant value within |
| 180 /// any given activation of the enclosing method. | 182 /// any given activation of the enclosing method. |
| 181 bool isEffectivelyConstant(Expression exp) { | 183 bool isEffectivelyConstant(Expression exp) { |
| 182 // TODO(asgerf): Can be made more aggressive e.g. by checking conditional | 184 // TODO(asgerf): Can be made more aggressive e.g. by checking conditional |
| 183 // expressions recursively. Determine if that is a valuable optimization | 185 // expressions recursively. Determine if that is a valuable optimization |
| 184 // and/or if it is better handled at the CPS level. | 186 // and/or if it is better handled at the CPS level. |
| 185 return exp is Constant || | 187 return exp is Constant || |
| 186 exp is This || | 188 exp is This || |
| 187 exp is ReifyTypeVar || | 189 exp is ReifyTypeVar || |
| 188 exp is Variable && constantEnvironment.containsKey(exp); | 190 exp is VariableUse && constantEnvironment.containsKey(exp.variable); |
| 189 } | 191 } |
| 190 | 192 |
| 191 Statement visitAssign(Assign node) { | 193 Statement visitAssign(Assign node) { |
| 192 if (isEffectivelyConstant(node.definition) && | 194 if (isEffectivelyConstant(node.definition) && |
| 193 node.variable.writeCount == 1) { | 195 node.variable.writeCount == 1) { |
| 194 // Handle constant assignments specially. | 196 // Handle constant assignments specially. |
| 195 // They are always safe to propagate (though we should avoid duplication). | 197 // They are always safe to propagate (though we should avoid duplication). |
| 196 // Moreover, they should not prevent other expressions from propagating. | 198 // Moreover, they should not prevent other expressions from propagating. |
| 197 if (node.variable.readCount <= 1) { | 199 if (node.variable.readCount <= 1) { |
| 198 // A single-use constant should always be propagted to its use site. | 200 // A single-use constant should always be propagted to its use site. |
| (...skipping 331 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 530 return new Return(e); | 532 return new Return(e); |
| 531 } | 533 } |
| 532 } | 534 } |
| 533 return null; | 535 return null; |
| 534 } | 536 } |
| 535 | 537 |
| 536 /// Returns an expression equivalent to both [e1] and [e2]. | 538 /// Returns an expression equivalent to both [e1] and [e2]. |
| 537 /// If non-null is returned, the caller must discard [e1] and [e2] and use | 539 /// If non-null is returned, the caller must discard [e1] and [e2] and use |
| 538 /// the resulting expression in the tree. | 540 /// the resulting expression in the tree. |
| 539 static Expression combineExpressions(Expression e1, Expression e2) { | 541 static Expression combineExpressions(Expression e1, Expression e2) { |
| 540 if (e1 is Variable && e1 == e2) { | 542 if (e1 is VariableUse && e2 is VariableUse && e1.variable == e2.variable) { |
| 541 --e1.readCount; // Two references become one. | 543 --e1.variable.readCount; // Two references become one. |
| 542 return e1; | 544 return e1; |
| 543 } | 545 } |
| 544 if (e1 is Constant && e2 is Constant && e1.value == e2.value) { | 546 if (e1 is Constant && e2 is Constant && e1.value == e2.value) { |
| 545 return e1; | 547 return e1; |
| 546 } | 548 } |
| 547 return null; | 549 return null; |
| 548 } | 550 } |
| 549 | 551 |
| 550 /// Try to collapse nested ifs using && and || expressions. | 552 /// Try to collapse nested ifs using && and || expressions. |
| 551 /// For example: | 553 /// For example: |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 625 } | 627 } |
| 626 | 628 |
| 627 Expression makeCondition(Expression e, bool polarity) { | 629 Expression makeCondition(Expression e, bool polarity) { |
| 628 return polarity ? e : new Not(e); | 630 return polarity ? e : new Not(e); |
| 629 } | 631 } |
| 630 | 632 |
| 631 Statement getBranch(If node, bool polarity) { | 633 Statement getBranch(If node, bool polarity) { |
| 632 return polarity ? node.thenStatement : node.elseStatement; | 634 return polarity ? node.thenStatement : node.elseStatement; |
| 633 } | 635 } |
| 634 } | 636 } |
| OLD | NEW |