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 #include "vm/flow_graph_optimizer.h" | 5 #include "vm/flow_graph_optimizer.h" |
6 | 6 |
7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
8 #include "vm/cha.h" | 8 #include "vm/cha.h" |
9 #include "vm/flow_graph_builder.h" | 9 #include "vm/flow_graph_builder.h" |
10 #include "vm/flow_graph_compiler.h" | 10 #include "vm/flow_graph_compiler.h" |
(...skipping 1599 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1610 // and false successor and rename all dominated uses to refer to a | 1610 // and false successor and rename all dominated uses to refer to a |
1611 // Constraint instead of this definition. | 1611 // Constraint instead of this definition. |
1612 void InsertConstraintsFor(Definition* defn); | 1612 void InsertConstraintsFor(Definition* defn); |
1613 | 1613 |
1614 // Create a constraint for defn, insert it after given instruction and | 1614 // Create a constraint for defn, insert it after given instruction and |
1615 // rename all uses that are dominated by it. | 1615 // rename all uses that are dominated by it. |
1616 ConstraintInstr* InsertConstraintFor(Definition* defn, | 1616 ConstraintInstr* InsertConstraintFor(Definition* defn, |
1617 Range* constraint, | 1617 Range* constraint, |
1618 Instruction* after); | 1618 Instruction* after); |
1619 | 1619 |
| 1620 void ConstrainValueAfterBranch(Definition* defn, Value* use); |
| 1621 void ConstrainValueAfterCheckArrayBound(Definition* defn, |
| 1622 CheckArrayBoundInstr* check); |
| 1623 Definition* LoadArrayLength(CheckArrayBoundInstr* check); |
| 1624 |
| 1625 |
| 1626 |
1620 // Replace uses of the definition def that are dominated by instruction dom | 1627 // Replace uses of the definition def that are dominated by instruction dom |
1621 // with uses of other definition. | 1628 // with uses of other definition. |
1622 void RenameDominatedUses(Definition* def, | 1629 void RenameDominatedUses(Definition* def, |
1623 Instruction* dom, | 1630 Instruction* dom, |
1624 Definition* other); | 1631 Definition* other); |
1625 | 1632 |
1626 | 1633 |
1627 // Walk the dominator tree and infer ranges for smi values. | 1634 // Walk the dominator tree and infer ranges for smi values. |
1628 void InferRanges(); | 1635 void InferRanges(); |
1629 void InferRangesRecursive(BlockEntryInstr* block); | 1636 void InferRangesRecursive(BlockEntryInstr* block); |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1668 // as smi values. | 1675 // as smi values. |
1669 GrowableArray<ConstraintInstr*> constraints_; | 1676 GrowableArray<ConstraintInstr*> constraints_; |
1670 | 1677 |
1671 // Bitvector for a quick filtering of known smi values. | 1678 // Bitvector for a quick filtering of known smi values. |
1672 BitVector* smi_definitions_; | 1679 BitVector* smi_definitions_; |
1673 | 1680 |
1674 // Worklist for induction variables analysis. | 1681 // Worklist for induction variables analysis. |
1675 GrowableArray<Definition*> worklist_; | 1682 GrowableArray<Definition*> worklist_; |
1676 BitVector* marked_defns_; | 1683 BitVector* marked_defns_; |
1677 | 1684 |
| 1685 class ArrayLengthData : public ValueObject { |
| 1686 public: |
| 1687 ArrayLengthData(Definition* array, Definition* array_length) |
| 1688 : array_(array), array_length_(array_length) { } |
| 1689 |
| 1690 Definition* array() const { return array_; } |
| 1691 Definition* array_length() const { return array_length_; } |
| 1692 |
| 1693 typedef Definition* Value; |
| 1694 typedef Definition* Key; |
| 1695 typedef class ArrayLengthData Pair; |
| 1696 |
| 1697 // KeyValueTrait members. |
| 1698 static Key KeyOf(const ArrayLengthData& data) { |
| 1699 return data.array(); |
| 1700 } |
| 1701 |
| 1702 static Value ValueOf(const ArrayLengthData& data) { |
| 1703 return data.array_length(); |
| 1704 } |
| 1705 |
| 1706 static inline intptr_t Hashcode(Key key) { |
| 1707 return reinterpret_cast<intptr_t>(key); |
| 1708 } |
| 1709 |
| 1710 static inline bool IsKeyEqual(const ArrayLengthData& kv, Key key) { |
| 1711 return kv.array() == key; |
| 1712 } |
| 1713 |
| 1714 private: |
| 1715 Definition* array_; |
| 1716 Definition* array_length_; |
| 1717 }; |
| 1718 |
| 1719 DirectChainedHashMap<ArrayLengthData> array_lengths_; |
| 1720 |
1678 DISALLOW_COPY_AND_ASSIGN(RangeAnalysis); | 1721 DISALLOW_COPY_AND_ASSIGN(RangeAnalysis); |
1679 }; | 1722 }; |
1680 | 1723 |
1681 | 1724 |
1682 void RangeAnalysis::Analyze() { | 1725 void RangeAnalysis::Analyze() { |
1683 CollectSmiValues(); | 1726 CollectSmiValues(); |
1684 InsertConstraints(); | 1727 InsertConstraints(); |
1685 InferRanges(); | 1728 InferRanges(); |
1686 RemoveConstraints(); | 1729 RemoveConstraints(); |
1687 } | 1730 } |
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1856 constraint->set_ssa_temp_index(flow_graph_->alloc_ssa_temp_index()); | 1899 constraint->set_ssa_temp_index(flow_graph_->alloc_ssa_temp_index()); |
1857 RenameDominatedUses(defn, after, constraint); | 1900 RenameDominatedUses(defn, after, constraint); |
1858 constraints_.Add(constraint); | 1901 constraints_.Add(constraint); |
1859 constraint->value()->set_instruction(constraint); | 1902 constraint->value()->set_instruction(constraint); |
1860 constraint->value()->set_use_index(0); | 1903 constraint->value()->set_use_index(0); |
1861 constraint->value()->AddToInputUseList(); | 1904 constraint->value()->AddToInputUseList(); |
1862 return constraint; | 1905 return constraint; |
1863 } | 1906 } |
1864 | 1907 |
1865 | 1908 |
| 1909 void RangeAnalysis::ConstrainValueAfterBranch(Definition* defn, Value* use) { |
| 1910 BranchInstr* branch = use->instruction()->AsBranch(); |
| 1911 RelationalOpInstr* rel_op = branch->comparison()->AsRelationalOp(); |
| 1912 if ((rel_op != NULL) && (rel_op->operands_class_id() == kSmiCid)) { |
| 1913 // Found comparison of two smis. Constrain defn at true and false |
| 1914 // successors using the other operand as a boundary. |
| 1915 Definition* boundary; |
| 1916 Token::Kind op_kind; |
| 1917 if (use->use_index() == 0) { // Left operand. |
| 1918 boundary = rel_op->InputAt(1)->definition(); |
| 1919 op_kind = rel_op->kind(); |
| 1920 } else { |
| 1921 ASSERT(use->use_index() == 1); // Right operand. |
| 1922 boundary = rel_op->InputAt(0)->definition(); |
| 1923 // InsertConstraintFor assumes that defn is left operand of a |
| 1924 // comparison if it is right operand flip the comparison. |
| 1925 op_kind = FlipComparison(rel_op->kind()); |
| 1926 } |
| 1927 |
| 1928 // Constrain definition at the true successor. |
| 1929 ConstraintInstr* true_constraint = |
| 1930 InsertConstraintFor(defn, |
| 1931 ConstraintRange(op_kind, boundary), |
| 1932 branch->true_successor()); |
| 1933 // Mark true_constraint an artificial use of boundary. This ensures |
| 1934 // that constraint's range is recalculated if boundary's range changes. |
| 1935 if (true_constraint != NULL) true_constraint->AddDependency(boundary); |
| 1936 |
| 1937 // Constrain definition with a negated condition at the false successor. |
| 1938 ConstraintInstr* false_constraint = |
| 1939 InsertConstraintFor( |
| 1940 defn, |
| 1941 ConstraintRange(NegateComparison(op_kind), boundary), |
| 1942 branch->false_successor()); |
| 1943 // Mark false_constraint an artificial use of boundary. This ensures |
| 1944 // that constraint's range is recalculated if boundary's range changes. |
| 1945 if (false_constraint != NULL) false_constraint->AddDependency(boundary); |
| 1946 } |
| 1947 } |
| 1948 |
1866 void RangeAnalysis::InsertConstraintsFor(Definition* defn) { | 1949 void RangeAnalysis::InsertConstraintsFor(Definition* defn) { |
1867 for (Value* use = defn->input_use_list(); | 1950 for (Value* use = defn->input_use_list(); |
1868 use != NULL; | 1951 use != NULL; |
1869 use = use->next_use()) { | 1952 use = use->next_use()) { |
1870 if (use->instruction()->IsBranch()) { | 1953 if (use->instruction()->IsBranch()) { |
1871 BranchInstr* branch = use->instruction()->AsBranch(); | 1954 ConstrainValueAfterBranch(defn, use); |
1872 RelationalOpInstr* rel_op = branch->comparison()->AsRelationalOp(); | 1955 } else if (use->instruction()->IsCheckArrayBound()) { |
1873 if ((rel_op != NULL) && (rel_op->operands_class_id() == kSmiCid)) { | 1956 ConstrainValueAfterCheckArrayBound( |
1874 // Found comparison of two smis. Constrain defn at true and false | 1957 defn, |
1875 // successors using the other operand as a boundary. | 1958 use->instruction()->AsCheckArrayBound()); |
1876 Definition* boundary; | |
1877 Token::Kind op_kind; | |
1878 if (use->use_index() == 0) { // Left operand. | |
1879 boundary = rel_op->InputAt(1)->definition(); | |
1880 op_kind = rel_op->kind(); | |
1881 } else { | |
1882 ASSERT(use->use_index() == 1); // Right operand. | |
1883 boundary = rel_op->InputAt(0)->definition(); | |
1884 // InsertConstraintFor assumes that defn is left operand of a | |
1885 // comparison if it is right operand flip the comparison. | |
1886 op_kind = FlipComparison(rel_op->kind()); | |
1887 } | |
1888 | |
1889 // Constrain definition at the true successor. | |
1890 ConstraintInstr* true_constraint = | |
1891 InsertConstraintFor(defn, | |
1892 ConstraintRange(op_kind, boundary), | |
1893 branch->true_successor()); | |
1894 // Mark true_constraint an artificial use of boundary. This ensures | |
1895 // that constraint's range is recalculated if boundary's range changes. | |
1896 if (true_constraint != NULL) true_constraint->AddDependency(boundary); | |
1897 | |
1898 // Constrain definition with a negated condition at the false successor. | |
1899 ConstraintInstr* false_constraint = | |
1900 InsertConstraintFor( | |
1901 defn, | |
1902 ConstraintRange(NegateComparison(op_kind), boundary), | |
1903 branch->false_successor()); | |
1904 // Mark false_constraint an artificial use of boundary. This ensures | |
1905 // that constraint's range is recalculated if boundary's range changes. | |
1906 if (false_constraint != NULL) false_constraint->AddDependency(boundary); | |
1907 } | |
1908 } | 1959 } |
1909 } | 1960 } |
1910 } | 1961 } |
1911 | 1962 |
1912 | 1963 |
| 1964 Definition* RangeAnalysis::LoadArrayLength(CheckArrayBoundInstr* check) { |
| 1965 Definition* array = check->array()->definition(); |
| 1966 |
| 1967 Definition* length = array_lengths_.Lookup(array); |
| 1968 if (length != NULL) return length; |
| 1969 |
| 1970 StaticCallInstr* allocation = array->AsStaticCall(); |
| 1971 if ((allocation != NULL) && |
| 1972 allocation->is_known_constructor() && |
| 1973 (allocation->ResultCid() == kArrayCid)) { |
| 1974 // For fixed length arrays check if array is the result of a constructor |
| 1975 // call. In this case we can use the length passed to the constructor |
| 1976 // instead of loading it from array itself. |
| 1977 length = allocation->ArgumentAt(1)->value()->definition(); |
| 1978 } else { |
| 1979 // Load length from the array. Do not insert instruction into the graph. |
| 1980 // It will only be used in range boundaries. |
| 1981 LoadFieldInstr* length_load = new LoadFieldInstr( |
| 1982 check->array()->Copy(), |
| 1983 Array::length_offset(), |
| 1984 Type::ZoneHandle(Type::SmiType()), |
| 1985 true); // Immutable. |
| 1986 length_load->set_recognized_kind(MethodRecognizer::kObjectArrayLength); |
| 1987 length_load->set_result_cid(kSmiCid); |
| 1988 length_load->set_ssa_temp_index(flow_graph_->alloc_ssa_temp_index()); |
| 1989 length = length_load; |
| 1990 } |
| 1991 |
| 1992 ASSERT(length != NULL); |
| 1993 array_lengths_.Insert(ArrayLengthData(array, length)); |
| 1994 return length; |
| 1995 } |
| 1996 |
| 1997 |
| 1998 void RangeAnalysis::ConstrainValueAfterCheckArrayBound( |
| 1999 Definition* defn, CheckArrayBoundInstr* check) { |
| 2000 if ((check->array_type() != kArrayCid) && |
| 2001 (check->array_type() != kImmutableArrayCid)) { |
| 2002 return; |
| 2003 } |
| 2004 |
| 2005 Definition* length = LoadArrayLength(check); |
| 2006 |
| 2007 Range* constraint_range = new Range( |
| 2008 RangeBoundary::FromConstant(0), |
| 2009 RangeBoundary::FromDefinition(length, -1)); |
| 2010 InsertConstraintFor(defn, constraint_range, check); |
| 2011 } |
| 2012 |
| 2013 |
1913 void RangeAnalysis::InsertConstraints() { | 2014 void RangeAnalysis::InsertConstraints() { |
1914 for (intptr_t i = 0; i < smi_checks_.length(); i++) { | 2015 for (intptr_t i = 0; i < smi_checks_.length(); i++) { |
1915 CheckSmiInstr* check = smi_checks_[i]; | 2016 CheckSmiInstr* check = smi_checks_[i]; |
1916 ConstraintInstr* constraint = | 2017 ConstraintInstr* constraint = |
1917 InsertConstraintFor(check->value()->definition(), | 2018 InsertConstraintFor(check->value()->definition(), |
1918 Range::Unknown(), | 2019 Range::Unknown(), |
1919 check); | 2020 check); |
1920 if (constraint != NULL) { | 2021 if (constraint != NULL) { |
1921 InsertConstraintsFor(constraint); // Constrain uses further. | 2022 InsertConstraintsFor(constraint); // Constrain uses further. |
1922 } | 2023 } |
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2088 | 2189 |
2089 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { | 2190 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { |
2090 Instruction* current = it.Current(); | 2191 Instruction* current = it.Current(); |
2091 | 2192 |
2092 Definition* defn = current->AsDefinition(); | 2193 Definition* defn = current->AsDefinition(); |
2093 if ((defn != NULL) && | 2194 if ((defn != NULL) && |
2094 (defn->ssa_temp_index() != -1) && | 2195 (defn->ssa_temp_index() != -1) && |
2095 smi_definitions_->Contains(defn->ssa_temp_index())) { | 2196 smi_definitions_->Contains(defn->ssa_temp_index())) { |
2096 defn->InferRange(); | 2197 defn->InferRange(); |
2097 } else if (FLAG_array_bounds_check_elimination && | 2198 } else if (FLAG_array_bounds_check_elimination && |
2098 current->IsCheckArrayBound() && | 2199 current->IsCheckArrayBound()) { |
2099 current->AsCheckArrayBound()->IsRedundant()) { | 2200 CheckArrayBoundInstr* check = current->AsCheckArrayBound(); |
2100 it.RemoveCurrentFromGraph(); | 2201 RangeBoundary array_length = |
| 2202 RangeBoundary::FromDefinition(LoadArrayLength(check)); |
| 2203 if (check->IsRedundant(array_length)) it.RemoveCurrentFromGraph(); |
2101 } | 2204 } |
2102 } | 2205 } |
2103 | 2206 |
2104 for (intptr_t i = 0; i < block->dominated_blocks().length(); ++i) { | 2207 for (intptr_t i = 0; i < block->dominated_blocks().length(); ++i) { |
2105 InferRangesRecursive(block->dominated_blocks()[i]); | 2208 InferRangesRecursive(block->dominated_blocks()[i]); |
2106 } | 2209 } |
2107 } | 2210 } |
2108 | 2211 |
2109 | 2212 |
2110 void RangeAnalysis::InferRanges() { | 2213 void RangeAnalysis::InferRanges() { |
(...skipping 427 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2538 static bool IsLoadEliminationCandidate(Definition* def) { | 2641 static bool IsLoadEliminationCandidate(Definition* def) { |
2539 // Immutable loads (not affected by side effects) are handled | 2642 // Immutable loads (not affected by side effects) are handled |
2540 // in the DominatorBasedCSE pass. | 2643 // in the DominatorBasedCSE pass. |
2541 // TODO(fschneider): Extend to other load instructions. | 2644 // TODO(fschneider): Extend to other load instructions. |
2542 return (def->IsLoadField() && def->AffectedBySideEffect()) | 2645 return (def->IsLoadField() && def->AffectedBySideEffect()) |
2543 || def->IsLoadIndexed(); | 2646 || def->IsLoadIndexed(); |
2544 } | 2647 } |
2545 | 2648 |
2546 | 2649 |
2547 static intptr_t NumberLoadExpressions(FlowGraph* graph) { | 2650 static intptr_t NumberLoadExpressions(FlowGraph* graph) { |
2548 DirectChainedHashMap<Definition*> map; | 2651 DirectChainedHashMap<PointerKeyValueTrait<Definition> > map; |
2549 intptr_t expr_id = 0; | 2652 intptr_t expr_id = 0; |
2550 for (BlockIterator it = graph->reverse_postorder_iterator(); | 2653 for (BlockIterator it = graph->reverse_postorder_iterator(); |
2551 !it.Done(); | 2654 !it.Done(); |
2552 it.Advance()) { | 2655 it.Advance()) { |
2553 BlockEntryInstr* block = it.Current(); | 2656 BlockEntryInstr* block = it.Current(); |
2554 for (ForwardInstructionIterator instr_it(block); | 2657 for (ForwardInstructionIterator instr_it(block); |
2555 !instr_it.Done(); | 2658 !instr_it.Done(); |
2556 instr_it.Advance()) { | 2659 instr_it.Advance()) { |
2557 Definition* defn = instr_it.Current()->AsDefinition(); | 2660 Definition* defn = instr_it.Current()->AsDefinition(); |
2558 if ((defn == NULL) || !IsLoadEliminationCandidate(defn)) { | 2661 if ((defn == NULL) || !IsLoadEliminationCandidate(defn)) { |
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2728 ComputeAvailableLoads(graph, max_expr_id, avail_in); | 2831 ComputeAvailableLoads(graph, max_expr_id, avail_in); |
2729 | 2832 |
2730 GrowableArray<Definition*> definitions(max_expr_id); | 2833 GrowableArray<Definition*> definitions(max_expr_id); |
2731 for (intptr_t j = 0; j < max_expr_id ; j++) { | 2834 for (intptr_t j = 0; j < max_expr_id ; j++) { |
2732 definitions.Add(NULL); | 2835 definitions.Add(NULL); |
2733 } | 2836 } |
2734 changed = OptimizeLoads(graph->graph_entry(), &definitions, avail_in); | 2837 changed = OptimizeLoads(graph->graph_entry(), &definitions, avail_in); |
2735 } | 2838 } |
2736 } | 2839 } |
2737 | 2840 |
2738 DirectChainedHashMap<Instruction*> map; | 2841 DirectChainedHashMap<PointerKeyValueTrait<Instruction> > map; |
2739 changed = OptimizeRecursive(graph->graph_entry(), &map) || changed; | 2842 changed = OptimizeRecursive(graph->graph_entry(), &map) || changed; |
2740 | 2843 |
2741 return changed; | 2844 return changed; |
2742 } | 2845 } |
2743 | 2846 |
2744 | 2847 |
2745 bool DominatorBasedCSE::OptimizeRecursive( | 2848 bool DominatorBasedCSE::OptimizeRecursive( |
2746 BlockEntryInstr* block, | 2849 BlockEntryInstr* block, |
2747 DirectChainedHashMap<Instruction*>* map) { | 2850 DirectChainedHashMap<PointerKeyValueTrait<Instruction> >* map) { |
2748 bool changed = false; | 2851 bool changed = false; |
2749 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { | 2852 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { |
2750 Instruction* current = it.Current(); | 2853 Instruction* current = it.Current(); |
2751 if (current->AffectedBySideEffect()) continue; | 2854 if (current->AffectedBySideEffect()) continue; |
2752 Instruction* replacement = map->Lookup(current); | 2855 Instruction* replacement = map->Lookup(current); |
2753 if (replacement == NULL) { | 2856 if (replacement == NULL) { |
2754 map->Insert(current); | 2857 map->Insert(current); |
2755 continue; | 2858 continue; |
2756 } | 2859 } |
2757 // Replace current with lookup result. | 2860 // Replace current with lookup result. |
2758 ReplaceCurrentInstruction(&it, current, replacement); | 2861 ReplaceCurrentInstruction(&it, current, replacement); |
2759 changed = true; | 2862 changed = true; |
2760 } | 2863 } |
2761 | 2864 |
2762 // Process children in the dominator tree recursively. | 2865 // Process children in the dominator tree recursively. |
2763 intptr_t num_children = block->dominated_blocks().length(); | 2866 intptr_t num_children = block->dominated_blocks().length(); |
2764 for (intptr_t i = 0; i < num_children; ++i) { | 2867 for (intptr_t i = 0; i < num_children; ++i) { |
2765 BlockEntryInstr* child = block->dominated_blocks()[i]; | 2868 BlockEntryInstr* child = block->dominated_blocks()[i]; |
2766 if (i < num_children - 1) { | 2869 if (i < num_children - 1) { |
2767 DirectChainedHashMap<Instruction*> child_map(*map); // Copy map. | 2870 // Copy map. |
| 2871 DirectChainedHashMap<PointerKeyValueTrait<Instruction> > child_map(*map); |
2768 changed = OptimizeRecursive(child, &child_map) || changed; | 2872 changed = OptimizeRecursive(child, &child_map) || changed; |
2769 } else { | 2873 } else { |
2770 // Reuse map for the last child. | 2874 // Reuse map for the last child. |
2771 changed = OptimizeRecursive(child, map) || changed; | 2875 changed = OptimizeRecursive(child, map) || changed; |
2772 } | 2876 } |
2773 } | 2877 } |
2774 return changed; | 2878 return changed; |
2775 } | 2879 } |
2776 | 2880 |
2777 | 2881 |
(...skipping 760 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3538 | 3642 |
3539 if (FLAG_trace_constant_propagation) { | 3643 if (FLAG_trace_constant_propagation) { |
3540 OS::Print("\n==== After constant propagation ====\n"); | 3644 OS::Print("\n==== After constant propagation ====\n"); |
3541 FlowGraphPrinter printer(*graph_); | 3645 FlowGraphPrinter printer(*graph_); |
3542 printer.PrintBlocks(); | 3646 printer.PrintBlocks(); |
3543 } | 3647 } |
3544 } | 3648 } |
3545 | 3649 |
3546 | 3650 |
3547 } // namespace dart | 3651 } // namespace dart |
OLD | NEW |