Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(370)

Side by Side Diff: runtime/vm/flow_graph_optimizer.cc

Issue 11273111: Allow bound check elimination to eliminate checks when both array length and index boundaries are e… (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: address Florian's comments Created 8 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/flow_graph_optimizer.h ('k') | runtime/vm/hash_map.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph_optimizer.h ('k') | runtime/vm/hash_map.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698