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 import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem; | 5 import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem; |
6 import '../common/names.dart' show Selectors; | 6 import '../common/names.dart' show Selectors; |
7 import '../common/tasks.dart' show CompilerTask; | 7 import '../common/tasks.dart' show CompilerTask; |
8 import '../compiler.dart' show Compiler; | 8 import '../compiler.dart' show Compiler; |
9 import '../constants/constant_system.dart'; | 9 import '../constants/constant_system.dart'; |
10 import '../constants/values.dart'; | 10 import '../constants/values.dart'; |
(...skipping 1441 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1452 check.inputs.add(minusOne); | 1452 check.inputs.add(minusOne); |
1453 minusOne.usedBy.add(check); | 1453 minusOne.usedBy.add(check); |
1454 } | 1454 } |
1455 } | 1455 } |
1456 | 1456 |
1457 class SsaDeadCodeEliminator extends HGraphVisitor implements OptimizationPhase { | 1457 class SsaDeadCodeEliminator extends HGraphVisitor implements OptimizationPhase { |
1458 final String name = "SsaDeadCodeEliminator"; | 1458 final String name = "SsaDeadCodeEliminator"; |
1459 | 1459 |
1460 final ClosedWorld closedWorld; | 1460 final ClosedWorld closedWorld; |
1461 final SsaOptimizerTask optimizer; | 1461 final SsaOptimizerTask optimizer; |
| 1462 HGraph _graph; |
1462 SsaLiveBlockAnalyzer analyzer; | 1463 SsaLiveBlockAnalyzer analyzer; |
1463 Map<HInstruction, bool> trivialDeadStoreReceivers = | 1464 Map<HInstruction, bool> trivialDeadStoreReceivers = |
1464 new Maplet<HInstruction, bool>(); | 1465 new Maplet<HInstruction, bool>(); |
1465 bool eliminatedSideEffects = false; | 1466 bool eliminatedSideEffects = false; |
1466 | 1467 |
1467 SsaDeadCodeEliminator(this.closedWorld, this.optimizer); | 1468 SsaDeadCodeEliminator(this.closedWorld, this.optimizer); |
1468 | 1469 |
1469 HInstruction zapInstructionCache; | 1470 HInstruction zapInstructionCache; |
1470 HInstruction get zapInstruction { | 1471 HInstruction get zapInstruction { |
1471 if (zapInstructionCache == null) { | 1472 if (zapInstructionCache == null) { |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1589 instruction.onlyThrowsNSM() && | 1590 instruction.onlyThrowsNSM() && |
1590 hasFollowingThrowingNSM(instruction)) { | 1591 hasFollowingThrowingNSM(instruction)) { |
1591 return true; | 1592 return true; |
1592 } | 1593 } |
1593 return !instruction.canThrow() && | 1594 return !instruction.canThrow() && |
1594 instruction is! HParameterValue && | 1595 instruction is! HParameterValue && |
1595 instruction is! HLocalSet; | 1596 instruction is! HLocalSet; |
1596 } | 1597 } |
1597 | 1598 |
1598 void visitGraph(HGraph graph) { | 1599 void visitGraph(HGraph graph) { |
| 1600 _graph = graph; |
1599 analyzer = new SsaLiveBlockAnalyzer(graph, closedWorld, optimizer); | 1601 analyzer = new SsaLiveBlockAnalyzer(graph, closedWorld, optimizer); |
1600 analyzer.analyze(); | 1602 analyzer.analyze(); |
1601 visitPostDominatorTree(graph); | 1603 visitPostDominatorTree(graph); |
1602 cleanPhis(graph); | 1604 cleanPhis(); |
1603 } | 1605 } |
1604 | 1606 |
1605 void visitBasicBlock(HBasicBlock block) { | 1607 void visitBasicBlock(HBasicBlock block) { |
1606 bool isDeadBlock = analyzer.isDeadBlock(block); | 1608 bool isDeadBlock = analyzer.isDeadBlock(block); |
1607 block.isLive = !isDeadBlock; | 1609 block.isLive = !isDeadBlock; |
| 1610 simplifyControlFlow(block); |
1608 // Start from the last non-control flow instruction in the block. | 1611 // Start from the last non-control flow instruction in the block. |
1609 HInstruction instruction = block.last.previous; | 1612 HInstruction instruction = block.last.previous; |
1610 while (instruction != null) { | 1613 while (instruction != null) { |
1611 var previous = instruction.previous; | 1614 var previous = instruction.previous; |
1612 if (isDeadBlock) { | 1615 if (isDeadBlock) { |
1613 eliminatedSideEffects = | 1616 eliminatedSideEffects = |
1614 eliminatedSideEffects || instruction.sideEffects.hasSideEffects(); | 1617 eliminatedSideEffects || instruction.sideEffects.hasSideEffects(); |
1615 removeUsers(instruction); | 1618 removeUsers(instruction); |
1616 block.remove(instruction); | 1619 block.remove(instruction); |
1617 } else if (isDeadCode(instruction)) { | 1620 } else if (isDeadCode(instruction)) { |
1618 block.remove(instruction); | 1621 block.remove(instruction); |
1619 } | 1622 } |
1620 instruction = previous; | 1623 instruction = previous; |
1621 } | 1624 } |
| 1625 block.forEachPhi(simplifyPhi); |
1622 } | 1626 } |
1623 | 1627 |
1624 void cleanPhis(HGraph graph) { | 1628 void simplifyPhi(HPhi phi) { |
| 1629 // If the phi is of the form `phi(x, HTypeKnown(x))`, it does not strengthen |
| 1630 // `x`. We can replace the phi with `x` to potentially make the HTypeKnown |
| 1631 // refinement node dead and potentially make a HIf control no HPhis. |
| 1632 |
| 1633 // TODO(sra): Implement version of this test that works for a subgraph of |
| 1634 // HPhi nodes. |
| 1635 HInstruction base = null; |
| 1636 bool seenUnrefinedBase = false; |
| 1637 for (HInstruction input in phi.inputs) { |
| 1638 HInstruction value = input; |
| 1639 while (value is HTypeKnown) { |
| 1640 HTypeKnown refinement = value; |
| 1641 value = refinement.checkedInput; |
| 1642 } |
| 1643 if (value == input) seenUnrefinedBase = true; |
| 1644 base ??= value; |
| 1645 if (base != value) return; |
| 1646 } |
| 1647 |
| 1648 if (seenUnrefinedBase) { |
| 1649 HBasicBlock block = phi.block; |
| 1650 block.rewrite(phi, base); |
| 1651 block.removePhi(phi); |
| 1652 } |
| 1653 } |
| 1654 |
| 1655 void simplifyControlFlow(HBasicBlock block) { |
| 1656 HControlFlow instruction = block.last; |
| 1657 if (instruction is HIf) { |
| 1658 HInstruction condition = instruction.condition; |
| 1659 if (condition.isConstant()) return; |
| 1660 |
| 1661 // We want to remove an if-then-else diamond when the then- and else- |
| 1662 // branches are empty and the condition does not control a HPhi. We cannot |
| 1663 // change the CFG structure so we replace the HIf condition with a |
| 1664 // constant. This may leave the original condition unused. i.e. a |
| 1665 // candidate for being dead code. |
| 1666 |
| 1667 List<HBasicBlock> dominated = block.dominatedBlocks; |
| 1668 // Diamond-like control flow dominates the then-, else- and join- blocks. |
| 1669 if (dominated.length != 3) return; |
| 1670 HBasicBlock join = dominated.last; |
| 1671 if (!join.phis.isEmpty) return; // condition controls a phi. |
| 1672 // Ignore exit block - usually the join in `if (...) return ...` |
| 1673 if (join.isExitBlock()) return; |
| 1674 |
| 1675 int thenSize = measureEmptyInterval(instruction.thenBlock, join); |
| 1676 if (thenSize == null) return; |
| 1677 int elseSize = measureEmptyInterval(instruction.elseBlock, join); |
| 1678 if (elseSize == null) return; |
| 1679 |
| 1680 // Pick the 'live' branch to be the smallest subgraph. |
| 1681 bool value = thenSize <= elseSize; |
| 1682 HInstruction newCondition = _graph.addConstantBool(value, closedWorld); |
| 1683 instruction.inputs[0] = newCondition; |
| 1684 condition.usedBy.remove(instruction); |
| 1685 newCondition.usedBy.add(instruction); |
| 1686 } |
| 1687 } |
| 1688 |
| 1689 /// Returns the number of blocks from [start] up to but not including [end]. |
| 1690 /// Returns `null` if any of the blocks is non-empty (other than control |
| 1691 /// flow). Returns `null` if there is an exit from the region other than |
| 1692 /// [end] or via control flow other than HGoto and HIf. |
| 1693 int measureEmptyInterval(HBasicBlock start, HBasicBlock end) { |
| 1694 if (start.first != start.last) return null; // start is not empty. |
| 1695 // Do a simple single-block region test first. |
| 1696 if (start.last is HGoto && |
| 1697 start.successors.length == 1 && |
| 1698 start.successors.single == end) { |
| 1699 return 1; |
| 1700 } |
| 1701 // TODO(sra): Implement fuller test. |
| 1702 return null; |
| 1703 } |
| 1704 |
| 1705 void cleanPhis() { |
1625 L: | 1706 L: |
1626 for (HBasicBlock block in graph.blocks) { | 1707 for (HBasicBlock block in _graph.blocks) { |
1627 List<HBasicBlock> predecessors = block.predecessors; | 1708 List<HBasicBlock> predecessors = block.predecessors; |
1628 // Zap all inputs to phis that correspond to dead blocks. | 1709 // Zap all inputs to phis that correspond to dead blocks. |
1629 block.forEachPhi((HPhi phi) { | 1710 block.forEachPhi((HPhi phi) { |
1630 for (int i = 0; i < phi.inputs.length; ++i) { | 1711 for (int i = 0; i < phi.inputs.length; ++i) { |
1631 if (!predecessors[i].isLive && phi.inputs[i] != zapInstruction) { | 1712 if (!predecessors[i].isLive && phi.inputs[i] != zapInstruction) { |
1632 replaceInput(i, phi, zapInstruction); | 1713 replaceInput(i, phi, zapInstruction); |
1633 } | 1714 } |
1634 } | 1715 } |
1635 }); | 1716 }); |
1636 if (predecessors.length < 2) continue L; | 1717 if (predecessors.length < 2) continue L; |
(...skipping 1233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2870 | 2951 |
2871 keyedValues.forEach((receiver, values) { | 2952 keyedValues.forEach((receiver, values) { |
2872 result.keyedValues[receiver] = | 2953 result.keyedValues[receiver] = |
2873 new Map<HInstruction, HInstruction>.from(values); | 2954 new Map<HInstruction, HInstruction>.from(values); |
2874 }); | 2955 }); |
2875 | 2956 |
2876 result.nonEscapingReceivers.addAll(nonEscapingReceivers); | 2957 result.nonEscapingReceivers.addAll(nonEscapingReceivers); |
2877 return result; | 2958 return result; |
2878 } | 2959 } |
2879 } | 2960 } |
OLD | NEW |