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 |