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_COMPILER_DEX_DATAFLOW_ITERATOR_H_ 18 #define ART_COMPILER_DEX_DATAFLOW_ITERATOR_H_ 19 20 #include "base/logging.h" 21 #include "mir_graph.h" 22 23 namespace 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. If this behavior is required, use the 31 * "Repeating" variant. For the repeating variant, the caller must tell the iterator 32 * whether a change has been made that necessitates another pass. Note that calling Next(true) 33 * does not affect the iteration order or short-circuit the current pass - it simply tells 34 * the iterator that once it has finished walking through the block list it should reset and 35 * do another full pass through the list. 36 */ 37 /** 38 * @class DataflowIterator 39 * @brief The main iterator class, all other iterators derive of this one to define an iteration order. 40 */ 41 class DataflowIterator { 42 public: ~DataflowIterator()43 virtual ~DataflowIterator() {} 44 45 /** 46 * @brief How many times have we repeated the iterator across the BasicBlocks? 47 * @return the number of iteration repetitions. 48 */ GetRepeatCount()49 int32_t GetRepeatCount() { return repeats_; } 50 51 /** 52 * @brief Has the user of the iterator reported a change yet? 53 * @details Does not mean there was or not a change, it is only whether the user passed a true to the Next function call. 54 * @return whether the user of the iterator reported a change yet. 55 */ GetChanged()56 int32_t GetChanged() { return changed_; } 57 58 /** 59 * @brief Get the next BasicBlock depending on iteration order. 60 * @param had_change did the user of the iteration change the previous BasicBlock. 61 * @return the next BasicBlock following the iteration order, 0 if finished. 62 */ 63 virtual BasicBlock* Next(bool had_change = false) = 0; 64 65 protected: 66 /** 67 * @param mir_graph the MIRGraph we are interested in. 68 * @param start_idx the first index we want to iterate across. 69 * @param end_idx the last index we want to iterate (not included). 70 */ DataflowIterator(MIRGraph * mir_graph,int32_t start_idx,int32_t end_idx)71 DataflowIterator(MIRGraph* mir_graph, int32_t start_idx, int32_t end_idx) 72 : mir_graph_(mir_graph), 73 start_idx_(start_idx), 74 end_idx_(end_idx), 75 block_id_list_(nullptr), 76 idx_(0), 77 repeats_(0), 78 changed_(false) {} 79 80 /** 81 * @brief Get the next BasicBlock iterating forward. 82 * @return the next BasicBlock iterating forward. 83 */ 84 virtual BasicBlock* ForwardSingleNext() ALWAYS_INLINE; 85 86 /** 87 * @brief Get the next BasicBlock iterating backward. 88 * @return the next BasicBlock iterating backward. 89 */ 90 virtual BasicBlock* ReverseSingleNext() ALWAYS_INLINE; 91 92 /** 93 * @brief Get the next BasicBlock iterating forward, restart if a BasicBlock was reported changed during the last iteration. 94 * @return the next BasicBlock iterating forward, with chance of repeating the iteration. 95 */ 96 virtual BasicBlock* ForwardRepeatNext() ALWAYS_INLINE; 97 98 /** 99 * @brief Get the next BasicBlock iterating backward, restart if a BasicBlock was reported changed during the last iteration. 100 * @return the next BasicBlock iterating backward, with chance of repeating the iteration. 101 */ 102 virtual BasicBlock* ReverseRepeatNext() ALWAYS_INLINE; 103 104 MIRGraph* const mir_graph_; /**< @brief the MIRGraph */ 105 const int32_t start_idx_; /**< @brief the start index for the iteration */ 106 const int32_t end_idx_; /**< @brief the last index for the iteration */ 107 const ArenaVector<BasicBlockId>* block_id_list_; /**< @brief the list of BasicBlocks we want to iterate on */ 108 int32_t idx_; /**< @brief Current index for the iterator */ 109 int32_t repeats_; /**< @brief Number of repeats over the iteration */ 110 bool changed_; /**< @brief Has something changed during the current iteration? */ 111 }; // DataflowIterator 112 113 /** 114 * @class PreOrderDfsIterator 115 * @brief Used to perform a Pre-order Depth-First-Search Iteration of a MIRGraph. 116 */ 117 class PreOrderDfsIterator : public DataflowIterator { 118 public: 119 /** 120 * @brief The constructor, using all of the reachable blocks of the MIRGraph. 121 * @param mir_graph The MIRGraph considered. 122 */ PreOrderDfsIterator(MIRGraph * mir_graph)123 explicit PreOrderDfsIterator(MIRGraph* mir_graph) 124 : DataflowIterator(mir_graph, 0, mir_graph->GetNumReachableBlocks()) { 125 // Extra setup for the PreOrderDfsIterator. 126 idx_ = start_idx_; 127 block_id_list_ = &mir_graph->GetDfsOrder(); 128 } 129 130 /** 131 * @brief Get the next BasicBlock depending on iteration order. 132 * @param had_change did the user of the iteration change the previous BasicBlock. 133 * @return the next BasicBlock following the iteration order, 0 if finished. 134 */ 135 virtual BasicBlock* Next(bool had_change = false) { 136 // Update changed: if had_changed is true, we remember it for the whole iteration. 137 changed_ |= had_change; 138 139 return ForwardSingleNext(); 140 } 141 }; 142 143 /** 144 * @class RepeatingPreOrderDfsIterator 145 * @brief Used to perform a Repeating Pre-order Depth-First-Search Iteration of a MIRGraph. 146 * @details If there is a change during an iteration, the iteration starts over at the end of the iteration. 147 */ 148 class RepeatingPreOrderDfsIterator : public DataflowIterator { 149 public: 150 /** 151 * @brief The constructor, using all of the reachable blocks of the MIRGraph. 152 * @param mir_graph The MIRGraph considered. 153 */ RepeatingPreOrderDfsIterator(MIRGraph * mir_graph)154 explicit RepeatingPreOrderDfsIterator(MIRGraph* mir_graph) 155 : DataflowIterator(mir_graph, 0, mir_graph->GetNumReachableBlocks()) { 156 // Extra setup for the RepeatingPreOrderDfsIterator. 157 idx_ = start_idx_; 158 block_id_list_ = &mir_graph->GetDfsOrder(); 159 } 160 161 /** 162 * @brief Get the next BasicBlock depending on iteration order. 163 * @param had_change did the user of the iteration change the previous BasicBlock. 164 * @return the next BasicBlock following the iteration order, 0 if finished. 165 */ 166 virtual BasicBlock* Next(bool had_change = false) { 167 // Update changed: if had_changed is true, we remember it for the whole iteration. 168 changed_ |= had_change; 169 170 return ForwardRepeatNext(); 171 } 172 }; 173 174 /** 175 * @class RepeatingPostOrderDfsIterator 176 * @brief Used to perform a Repeating Post-order Depth-First-Search Iteration of a MIRGraph. 177 * @details If there is a change during an iteration, the iteration starts over at the end of the iteration. 178 */ 179 class RepeatingPostOrderDfsIterator : public DataflowIterator { 180 public: 181 /** 182 * @brief The constructor, using all of the reachable blocks of the MIRGraph. 183 * @param mir_graph The MIRGraph considered. 184 */ RepeatingPostOrderDfsIterator(MIRGraph * mir_graph)185 explicit RepeatingPostOrderDfsIterator(MIRGraph* mir_graph) 186 : DataflowIterator(mir_graph, 0, mir_graph->GetNumReachableBlocks()) { 187 // Extra setup for the RepeatingPostOrderDfsIterator. 188 idx_ = start_idx_; 189 block_id_list_ = &mir_graph->GetDfsPostOrder(); 190 } 191 192 /** 193 * @brief Get the next BasicBlock depending on iteration order. 194 * @param had_change did the user of the iteration change the previous BasicBlock. 195 * @return the next BasicBlock following the iteration order, 0 if finished. 196 */ 197 virtual BasicBlock* Next(bool had_change = false) { 198 // Update changed: if had_changed is true, we remember it for the whole iteration. 199 changed_ |= had_change; 200 201 return ForwardRepeatNext(); 202 } 203 }; 204 205 /** 206 * @class ReversePostOrderDfsIterator 207 * @brief Used to perform a Reverse Post-order Depth-First-Search Iteration of a MIRGraph. 208 */ 209 class ReversePostOrderDfsIterator : public DataflowIterator { 210 public: 211 /** 212 * @brief The constructor, using all of the reachable blocks of the MIRGraph. 213 * @param mir_graph The MIRGraph considered. 214 */ ReversePostOrderDfsIterator(MIRGraph * mir_graph)215 explicit ReversePostOrderDfsIterator(MIRGraph* mir_graph) 216 : DataflowIterator(mir_graph, mir_graph->GetNumReachableBlocks() -1, 0) { 217 // Extra setup for the ReversePostOrderDfsIterator. 218 idx_ = start_idx_; 219 block_id_list_ = &mir_graph->GetDfsPostOrder(); 220 } 221 222 /** 223 * @brief Get the next BasicBlock depending on iteration order. 224 * @param had_change did the user of the iteration change the previous BasicBlock. 225 * @return the next BasicBlock following the iteration order, 0 if finished. 226 */ 227 virtual BasicBlock* Next(bool had_change = false) { 228 // Update changed: if had_changed is true, we remember it for the whole iteration. 229 changed_ |= had_change; 230 231 return ReverseSingleNext(); 232 } 233 }; 234 235 /** 236 * @class ReversePostOrderDfsIterator 237 * @brief Used to perform a Repeating Reverse Post-order Depth-First-Search Iteration of a MIRGraph. 238 * @details If there is a change during an iteration, the iteration starts over at the end of the iteration. 239 */ 240 class RepeatingReversePostOrderDfsIterator : public DataflowIterator { 241 public: 242 /** 243 * @brief The constructor, using all of the reachable blocks of the MIRGraph. 244 * @param mir_graph The MIRGraph considered. 245 */ RepeatingReversePostOrderDfsIterator(MIRGraph * mir_graph)246 explicit RepeatingReversePostOrderDfsIterator(MIRGraph* mir_graph) 247 : DataflowIterator(mir_graph, mir_graph->GetNumReachableBlocks() -1, 0) { 248 // Extra setup for the RepeatingReversePostOrderDfsIterator 249 idx_ = start_idx_; 250 block_id_list_ = &mir_graph->GetDfsPostOrder(); 251 } 252 253 /** 254 * @brief Get the next BasicBlock depending on iteration order. 255 * @param had_change did the user of the iteration change the previous BasicBlock. 256 * @return the next BasicBlock following the iteration order, 0 if finished. 257 */ 258 virtual BasicBlock* Next(bool had_change = false) { 259 // Update changed: if had_changed is true, we remember it for the whole iteration. 260 changed_ |= had_change; 261 262 return ReverseRepeatNext(); 263 } 264 }; 265 266 /** 267 * @class PostOrderDOMIterator 268 * @brief Used to perform a Post-order Domination Iteration of a MIRGraph. 269 */ 270 class PostOrderDOMIterator : public DataflowIterator { 271 public: 272 /** 273 * @brief The constructor, using all of the reachable blocks of the MIRGraph. 274 * @param mir_graph The MIRGraph considered. 275 */ PostOrderDOMIterator(MIRGraph * mir_graph)276 explicit PostOrderDOMIterator(MIRGraph* mir_graph) 277 : DataflowIterator(mir_graph, 0, mir_graph->GetNumReachableBlocks()) { 278 // Extra setup for thePostOrderDOMIterator. 279 idx_ = start_idx_; 280 block_id_list_ = &mir_graph->GetDomPostOrder(); 281 } 282 283 /** 284 * @brief Get the next BasicBlock depending on iteration order. 285 * @param had_change did the user of the iteration change the previous BasicBlock. 286 * @return the next BasicBlock following the iteration order, 0 if finished. 287 */ 288 virtual BasicBlock* Next(bool had_change = false) { 289 // Update changed: if had_changed is true, we remember it for the whole iteration. 290 changed_ |= had_change; 291 292 return ForwardSingleNext(); 293 } 294 }; 295 296 /** 297 * @class AllNodesIterator 298 * @brief Used to perform an iteration on all the BasicBlocks a MIRGraph. 299 */ 300 class AllNodesIterator : public DataflowIterator { 301 public: 302 /** 303 * @brief The constructor, using all of the reachable blocks of the MIRGraph. 304 * @param mir_graph The MIRGraph considered. 305 */ AllNodesIterator(MIRGraph * mir_graph)306 explicit AllNodesIterator(MIRGraph* mir_graph) 307 : DataflowIterator(mir_graph, 0, mir_graph->GetBlockList().size()) { 308 } 309 310 /** 311 * @brief Resetting the iterator. 312 */ Reset()313 void Reset() { 314 idx_ = 0; 315 } 316 317 /** 318 * @brief Get the next BasicBlock depending on iteration order. 319 * @param had_change did the user of the iteration change the previous BasicBlock. 320 * @return the next BasicBlock following the iteration order, 0 if finished. 321 */ 322 virtual BasicBlock* Next(bool had_change = false) ALWAYS_INLINE; 323 }; 324 325 /** 326 * @class TopologicalSortIterator 327 * @brief Used to perform a Topological Sort Iteration of a MIRGraph. 328 */ 329 class TopologicalSortIterator : public DataflowIterator { 330 public: 331 /** 332 * @brief The constructor, using all of the reachable blocks of the MIRGraph. 333 * @param mir_graph The MIRGraph considered. 334 */ TopologicalSortIterator(MIRGraph * mir_graph)335 explicit TopologicalSortIterator(MIRGraph* mir_graph) 336 : DataflowIterator(mir_graph, 0, mir_graph->GetTopologicalSortOrder().size()), 337 loop_ends_(&mir_graph->GetTopologicalSortOrderLoopEnds()), 338 loop_head_stack_(mir_graph_->GetTopologicalSortOrderLoopHeadStack()) { 339 // Extra setup for TopologicalSortIterator. 340 idx_ = start_idx_; 341 block_id_list_ = &mir_graph->GetTopologicalSortOrder(); 342 } 343 344 /** 345 * @brief Get the next BasicBlock depending on iteration order. 346 * @param had_change did the user of the iteration change the previous BasicBlock. 347 * @return the next BasicBlock following the iteration order, 0 if finished. 348 */ 349 virtual BasicBlock* Next(bool had_change = false) OVERRIDE; 350 351 private: 352 const ArenaVector<BasicBlockId>* const loop_ends_; 353 ArenaVector<std::pair<uint16_t, bool>>* const loop_head_stack_; 354 }; 355 356 /** 357 * @class LoopRepeatingTopologicalSortIterator 358 * @brief Used to perform a Topological Sort Iteration of a MIRGraph, repeating loops as needed. 359 * @details The iterator uses the visited flags to keep track of the blocks that need 360 * recalculation and keeps a stack of loop heads in the MIRGraph. At the end of the loop 361 * it returns back to the loop head if it needs to be recalculated. Due to the use of 362 * the visited flags and the loop head stack in the MIRGraph, it's not possible to use 363 * two iterators at the same time or modify this data during iteration (though inspection 364 * of this data is allowed and sometimes even expected). 365 * 366 * NOTE: This iterator is not suitable for passes that need to propagate changes to 367 * predecessors, such as type inferrence. 368 */ 369 class LoopRepeatingTopologicalSortIterator : public DataflowIterator { 370 public: 371 /** 372 * @brief The constructor, using all of the reachable blocks of the MIRGraph. 373 * @param mir_graph The MIRGraph considered. 374 */ LoopRepeatingTopologicalSortIterator(MIRGraph * mir_graph)375 explicit LoopRepeatingTopologicalSortIterator(MIRGraph* mir_graph) 376 : DataflowIterator(mir_graph, 0, mir_graph->GetTopologicalSortOrder().size()), 377 loop_ends_(&mir_graph->GetTopologicalSortOrderLoopEnds()), 378 loop_head_stack_(mir_graph_->GetTopologicalSortOrderLoopHeadStack()) { 379 // Extra setup for RepeatingTopologicalSortIterator. 380 idx_ = start_idx_; 381 block_id_list_ = &mir_graph->GetTopologicalSortOrder(); 382 // Clear visited flags and check that the loop head stack is empty. 383 mir_graph->ClearAllVisitedFlags(); 384 DCHECK_EQ(loop_head_stack_->size(), 0u); 385 } 386 ~LoopRepeatingTopologicalSortIterator()387 ~LoopRepeatingTopologicalSortIterator() { 388 DCHECK_EQ(loop_head_stack_->size(), 0u); 389 } 390 391 /** 392 * @brief Get the next BasicBlock depending on iteration order. 393 * @param had_change did the user of the iteration change the previous BasicBlock. 394 * @return the next BasicBlock following the iteration order, 0 if finished. 395 */ 396 virtual BasicBlock* Next(bool had_change = false) OVERRIDE; 397 398 private: 399 const ArenaVector<BasicBlockId>* const loop_ends_; 400 ArenaVector<std::pair<uint16_t, bool>>* const loop_head_stack_; 401 }; 402 403 } // namespace art 404 405 #endif // ART_COMPILER_DEX_DATAFLOW_ITERATOR_H_ 406