| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 ssa; | 5 part of ssa; |
| 6 | 6 |
| 7 abstract class OptimizationPhase { | 7 abstract class OptimizationPhase { |
| 8 String get name; | 8 String get name; |
| 9 void visitGraph(HGraph graph); | 9 void visitGraph(HGraph graph); |
| 10 } | 10 } |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 48 new SsaTypePropagator(compiler), | 48 new SsaTypePropagator(compiler), |
| 49 // Run a dead code eliminator before LICM because dead | 49 // Run a dead code eliminator before LICM because dead |
| 50 // interceptors are often in the way of LICM'able instructions. | 50 // interceptors are often in the way of LICM'able instructions. |
| 51 new SsaDeadCodeEliminator(compiler, this), | 51 new SsaDeadCodeEliminator(compiler, this), |
| 52 new SsaGlobalValueNumberer(compiler), | 52 new SsaGlobalValueNumberer(compiler), |
| 53 // After GVN, some instructions might need their type to be | 53 // After GVN, some instructions might need their type to be |
| 54 // updated because they now have different inputs. | 54 // updated because they now have different inputs. |
| 55 new SsaTypePropagator(compiler), | 55 new SsaTypePropagator(compiler), |
| 56 new SsaCodeMotion(), | 56 new SsaCodeMotion(), |
| 57 new SsaLoadElimination(compiler), | 57 new SsaLoadElimination(compiler), |
| 58 new SsaRedundantPhiEliminator(), |
| 58 new SsaDeadPhiEliminator(), | 59 new SsaDeadPhiEliminator(), |
| 59 new SsaTypePropagator(compiler), | 60 new SsaTypePropagator(compiler), |
| 60 new SsaValueRangeAnalyzer(compiler, constantSystem, this, work), | 61 new SsaValueRangeAnalyzer(compiler, constantSystem, this, work), |
| 61 // Previous optimizations may have generated new | 62 // Previous optimizations may have generated new |
| 62 // opportunities for instruction simplification. | 63 // opportunities for instruction simplification. |
| 63 new SsaInstructionSimplifier(constantSystem, backend, this, work), | 64 new SsaInstructionSimplifier(constantSystem, backend, this, work), |
| 64 new SsaCheckInserter( | 65 new SsaCheckInserter( |
| 65 trustPrimitives, backend, work, context.boundsChecked), | 66 trustPrimitives, backend, work, context.boundsChecked), |
| 66 ]; | 67 ]; |
| 67 phases.forEach(runPhase); | 68 phases.forEach(runPhase); |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 190 | 191 |
| 191 HInstruction visitInstruction(HInstruction node) { | 192 HInstruction visitInstruction(HInstruction node) { |
| 192 return node; | 193 return node; |
| 193 } | 194 } |
| 194 | 195 |
| 195 HInstruction visitBoolify(HBoolify node) { | 196 HInstruction visitBoolify(HBoolify node) { |
| 196 List<HInstruction> inputs = node.inputs; | 197 List<HInstruction> inputs = node.inputs; |
| 197 assert(inputs.length == 1); | 198 assert(inputs.length == 1); |
| 198 HInstruction input = inputs[0]; | 199 HInstruction input = inputs[0]; |
| 199 if (input.isBoolean(compiler)) return input; | 200 if (input.isBoolean(compiler)) return input; |
| 201 |
| 202 // If the code is unreachable, remove the HBoolify. This can happen when |
| 203 // there is a throw expression in a short-circuit conditional. Removing the |
| 204 // unreachable HBoolify makes it easier to reconstruct the short-circuit |
| 205 // operation. |
| 206 if (input.instructionType.isEmpty && !input.instructionType.isNullable) |
| 207 return input; |
| 208 |
| 200 // All values that cannot be 'true' are boolified to false. | 209 // All values that cannot be 'true' are boolified to false. |
| 201 TypeMask mask = input.instructionType; | 210 TypeMask mask = input.instructionType; |
| 202 if (!mask.contains(backend.jsBoolClass, compiler.world)) { | 211 if (!mask.contains(backend.jsBoolClass, compiler.world)) { |
| 203 return graph.addConstantBool(false, compiler); | 212 return graph.addConstantBool(false, compiler); |
| 204 } | 213 } |
| 205 return node; | 214 return node; |
| 206 } | 215 } |
| 207 | 216 |
| 208 HInstruction visitNot(HNot node) { | 217 HInstruction visitNot(HNot node) { |
| 209 List<HInstruction> inputs = node.inputs; | 218 List<HInstruction> inputs = node.inputs; |
| (...skipping 296 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 506 // in the remaining optimizations. | 515 // in the remaining optimizations. |
| 507 return super.visitRelational(node); | 516 return super.visitRelational(node); |
| 508 } | 517 } |
| 509 | 518 |
| 510 HInstruction handleIdentityCheck(HRelational node) { | 519 HInstruction handleIdentityCheck(HRelational node) { |
| 511 HInstruction left = node.left; | 520 HInstruction left = node.left; |
| 512 HInstruction right = node.right; | 521 HInstruction right = node.right; |
| 513 TypeMask leftType = left.instructionType; | 522 TypeMask leftType = left.instructionType; |
| 514 TypeMask rightType = right.instructionType; | 523 TypeMask rightType = right.instructionType; |
| 515 | 524 |
| 525 HInstruction makeTrue() => graph.addConstantBool(true, compiler); |
| 526 HInstruction makeFalse() => graph.addConstantBool(false, compiler); |
| 527 |
| 516 // Intersection of int and double return conflicting, so | 528 // Intersection of int and double return conflicting, so |
| 517 // we don't optimize on numbers to preserve the runtime semantics. | 529 // we don't optimize on numbers to preserve the runtime semantics. |
| 518 if (!(left.isNumberOrNull(compiler) && right.isNumberOrNull(compiler))) { | 530 if (!(left.isNumberOrNull(compiler) && right.isNumberOrNull(compiler))) { |
| 519 TypeMask intersection = leftType.intersection(rightType, compiler.world); | 531 TypeMask intersection = leftType.intersection(rightType, compiler.world); |
| 520 if (intersection.isEmpty && !intersection.isNullable) { | 532 if (intersection.isEmpty && !intersection.isNullable) { |
| 521 return graph.addConstantBool(false, compiler); | 533 return makeFalse(); |
| 522 } | 534 } |
| 523 } | 535 } |
| 524 | 536 |
| 525 if (left.isNull() && right.isNull()) { | 537 if (left.isNull() && right.isNull()) { |
| 526 return graph.addConstantBool(true, compiler); | 538 return makeTrue(); |
| 539 } |
| 540 |
| 541 HInstruction compareConstant(HConstant constant, HInstruction input) { |
| 542 if (constant.constant.isTrue) { |
| 543 return input; |
| 544 } else { |
| 545 return new HNot(input, backend.boolType); |
| 546 } |
| 527 } | 547 } |
| 528 | 548 |
| 529 if (left.isConstantBoolean() && right.isBoolean(compiler)) { | 549 if (left.isConstantBoolean() && right.isBoolean(compiler)) { |
| 530 HConstant constant = left; | 550 return compareConstant(left, right); |
| 531 if (constant.constant.isTrue) { | |
| 532 return right; | |
| 533 } else { | |
| 534 return new HNot(right, backend.boolType); | |
| 535 } | |
| 536 } | 551 } |
| 537 | 552 |
| 538 if (right.isConstantBoolean() && left.isBoolean(compiler)) { | 553 if (right.isConstantBoolean() && left.isBoolean(compiler)) { |
| 539 HConstant constant = right; | 554 return compareConstant(right, left); |
| 540 if (constant.constant.isTrue) { | 555 } |
| 541 return left; | 556 |
| 542 } else { | 557 |
| 543 return new HNot(left, backend.boolType); | 558 if (identical(left.nonCheck(), right.nonCheck())) { |
| 544 } | 559 // Avoid constant-folding `identical(x, x)` when `x` might be double. The |
| 560 // dart2js runtime has not always been consistent with the Dart |
| 561 // specification (section 16.0.1), which makes distinctions on NaNs and |
| 562 // -0.0 that are hard to implement efficiently. |
| 563 if (left.isIntegerOrNull(compiler)) return makeTrue(); |
| 564 if (!left.canBePrimitiveNumber(compiler)) return makeTrue(); |
| 545 } | 565 } |
| 546 | 566 |
| 547 return null; | 567 return null; |
| 548 } | 568 } |
| 549 | 569 |
| 550 HInstruction visitIdentity(HIdentity node) { | 570 HInstruction visitIdentity(HIdentity node) { |
| 551 HInstruction newInstruction = handleIdentityCheck(node); | 571 HInstruction newInstruction = handleIdentityCheck(node); |
| 552 return newInstruction == null ? super.visitIdentity(node) : newInstruction; | 572 return newInstruction == null ? super.visitIdentity(node) : newInstruction; |
| 553 } | 573 } |
| 554 | 574 |
| (...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 815 type, | 835 type, |
| 816 HTypeConversion.CHECKED_MODE_CHECK); | 836 HTypeConversion.CHECKED_MODE_CHECK); |
| 817 if (other != value) { | 837 if (other != value) { |
| 818 node.block.addBefore(node, other); | 838 node.block.addBefore(node, other); |
| 819 value = other; | 839 value = other; |
| 820 } | 840 } |
| 821 } | 841 } |
| 822 return new HFieldSet(field, receiver, value); | 842 return new HFieldSet(field, receiver, value); |
| 823 } | 843 } |
| 824 | 844 |
| 845 HInstruction visitInvokeStatic(HInvokeStatic node) { |
| 846 if (node.element == backend.getCheckConcurrentModificationError()) { |
| 847 if (node.inputs.length == 2) { |
| 848 HInstruction firstArgument = node.inputs[0]; |
| 849 if (firstArgument is HConstant) { |
| 850 HConstant constant = firstArgument; |
| 851 if (constant.constant.isTrue) return constant; |
| 852 } |
| 853 } |
| 854 } |
| 855 return node; |
| 856 } |
| 857 |
| 825 HInstruction visitStringConcat(HStringConcat node) { | 858 HInstruction visitStringConcat(HStringConcat node) { |
| 826 // Simplify string concat: | 859 // Simplify string concat: |
| 827 // | 860 // |
| 828 // "" + R -> R | 861 // "" + R -> R |
| 829 // L + "" -> L | 862 // L + "" -> L |
| 830 // "L" + "R" -> "LR" | 863 // "L" + "R" -> "LR" |
| 831 // (prefix + "L") + "R" -> prefix + "LR" | 864 // (prefix + "L") + "R" -> prefix + "LR" |
| 832 // | 865 // |
| 833 StringConstantValue getString(HInstruction instruction) { | 866 StringConstantValue getString(HInstruction instruction) { |
| 834 if (!instruction.isConstantString()) return null; | 867 if (!instruction.isConstantString()) return null; |
| (...skipping 1411 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2246 | 2279 |
| 2247 keyedValues.forEach((receiver, values) { | 2280 keyedValues.forEach((receiver, values) { |
| 2248 result.keyedValues[receiver] = | 2281 result.keyedValues[receiver] = |
| 2249 new Map<HInstruction, HInstruction>.from(values); | 2282 new Map<HInstruction, HInstruction>.from(values); |
| 2250 }); | 2283 }); |
| 2251 | 2284 |
| 2252 result.nonEscapingReceivers.addAll(nonEscapingReceivers); | 2285 result.nonEscapingReceivers.addAll(nonEscapingReceivers); |
| 2253 return result; | 2286 return result; |
| 2254 } | 2287 } |
| 2255 } | 2288 } |
| OLD | NEW |