dataflow_iterator.h revision 7940e44f4517de5e2634a7e07d58d0fb26160513
1/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef ART_SRC_COMPILER_DEX_DATAFLOW_ITERATOR_H_
18#define ART_SRC_COMPILER_DEX_DATAFLOW_ITERATOR_H_
19
20#include "compiler_ir.h"
21#include "mir_graph.h"
22
23namespace art {
24
25  /*
26   * This class supports iterating over lists of basic blocks in various
27   * interesting orders.  Note that for efficiency, the visit orders have been pre-computed.
28   * The order itself will not change during the iteration.  However, for some uses,
29   * auxiliary data associated with the basic blocks may be changed during the iteration,
30   * necessitating another pass over the list.
31   *
32   * To support this usage, we have is_iterative_.  If false, the iteration is a one-shot
33   * pass through the pre-computed list using Next().  If true, the caller must tell the
34   * iterator whether a change has been made that necessitates another pass.  Use
35   * Next(had_change) for this.  The general idea is that the iterative_ use case means
36   * that the iterator will keep repeating the full basic block list until a complete pass
37   * is made through it with no changes.  Note that calling Next(true) does not affect
38   * the iteration order or short-curcuit the current pass - it simply tells the iterator
39   * that once it has finished walking through the block list it should reset and do another
40   * full pass through the list.
41   */
42  class DataflowIterator {
43    public:
44
45      virtual ~DataflowIterator(){}
46
47      // Return the next BasicBlock* to visit.
48      BasicBlock* Next() {
49        DCHECK(!is_iterative_);
50        return NextBody(false);
51      }
52
53      /*
54       * Return the next BasicBlock* to visit, and tell the iterator whether any change
55       * has occurred that requires another full pass over the block list.
56       */
57      BasicBlock* Next(bool had_change) {
58        DCHECK(is_iterative_);
59        return NextBody(had_change);
60      }
61
62    protected:
63      DataflowIterator(MIRGraph* mir_graph, bool is_iterative, int start_idx, int end_idx,
64                       bool reverse)
65          : mir_graph_(mir_graph),
66            is_iterative_(is_iterative),
67            start_idx_(start_idx),
68            end_idx_(end_idx),
69            reverse_(reverse),
70            block_id_list_(NULL),
71            idx_(0),
72            changed_(false) {}
73
74      virtual BasicBlock* NextBody(bool had_change) ALWAYS_INLINE;
75
76      MIRGraph* const mir_graph_;
77      const bool is_iterative_;
78      const int start_idx_;
79      const int end_idx_;
80      const bool reverse_;
81      GrowableArray<int>* block_id_list_;
82      int idx_;
83      bool changed_;
84
85  }; // DataflowIterator
86
87  class ReachableNodesIterator : public DataflowIterator {
88    public:
89      ReachableNodesIterator(MIRGraph* mir_graph, bool is_iterative)
90          : DataflowIterator(mir_graph, is_iterative, 0,
91                             mir_graph->GetNumReachableBlocks(), false) {
92        idx_ = start_idx_;
93        block_id_list_ = mir_graph->GetDfsOrder();
94      }
95  };
96
97  class PreOrderDfsIterator : public DataflowIterator {
98    public:
99      PreOrderDfsIterator(MIRGraph* mir_graph, bool is_iterative)
100          : DataflowIterator(mir_graph, is_iterative, 0,
101                             mir_graph->GetNumReachableBlocks(), false) {
102        idx_ = start_idx_;
103        block_id_list_ = mir_graph->GetDfsOrder();
104      }
105  };
106
107  class PostOrderDfsIterator : public DataflowIterator {
108    public:
109
110      PostOrderDfsIterator(MIRGraph* mir_graph, bool is_iterative)
111          : DataflowIterator(mir_graph, is_iterative, 0,
112                             mir_graph->GetNumReachableBlocks(), false) {
113        idx_ = start_idx_;
114        block_id_list_ = mir_graph->GetDfsPostOrder();
115      }
116  };
117
118  class ReversePostOrderDfsIterator : public DataflowIterator {
119    public:
120      ReversePostOrderDfsIterator(MIRGraph* mir_graph, bool is_iterative)
121          : DataflowIterator(mir_graph, is_iterative,
122                             mir_graph->GetNumReachableBlocks() -1, 0, true) {
123        idx_ = start_idx_;
124        block_id_list_ = mir_graph->GetDfsPostOrder();
125      }
126  };
127
128  class PostOrderDOMIterator : public DataflowIterator {
129    public:
130      PostOrderDOMIterator(MIRGraph* mir_graph, bool is_iterative)
131          : DataflowIterator(mir_graph, is_iterative, 0,
132                             mir_graph->GetNumReachableBlocks(), false) {
133        idx_ = start_idx_;
134        block_id_list_ = mir_graph->GetDomPostOrder();
135      }
136  };
137
138  class AllNodesIterator : public DataflowIterator {
139    public:
140      AllNodesIterator(MIRGraph* mir_graph, bool is_iterative)
141          : DataflowIterator(mir_graph, is_iterative, 0, 0, false) {
142        all_nodes_iterator_ =
143            new (mir_graph->GetArena()) GrowableArray<BasicBlock*>::Iterator (mir_graph->GetBlockList());
144      }
145
146      void Reset() {
147        all_nodes_iterator_->Reset();
148      }
149
150      BasicBlock* NextBody(bool had_change) ALWAYS_INLINE;
151
152    private:
153      GrowableArray<BasicBlock*>::Iterator* all_nodes_iterator_;
154  };
155
156}  // namespace art
157
158#endif // ART_SRC_COMPILER_DEX_DATAFLOW_ITERATOR_H_
159