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 "compiler_ir.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_(NULL), 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 GrowableArray<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, 0), 308 all_nodes_iterator_(mir_graph->GetBlockList()) { 309 } 310 311 /** 312 * @brief Resetting the iterator. 313 */ Reset()314 void Reset() { 315 all_nodes_iterator_.Reset(); 316 } 317 318 /** 319 * @brief Get the next BasicBlock depending on iteration order. 320 * @param had_change did the user of the iteration change the previous BasicBlock. 321 * @return the next BasicBlock following the iteration order, 0 if finished. 322 */ 323 virtual BasicBlock* Next(bool had_change = false) ALWAYS_INLINE; 324 325 private: 326 GrowableArray<BasicBlock*>::Iterator all_nodes_iterator_; /**< @brief The list of all the nodes */ 327 }; 328 329 /** 330 * @class TopologicalSortIterator 331 * @brief Used to perform a Topological Sort Iteration of a MIRGraph. 332 */ 333 class TopologicalSortIterator : public DataflowIterator { 334 public: 335 /** 336 * @brief The constructor, using all of the reachable blocks of the MIRGraph. 337 * @param mir_graph The MIRGraph considered. 338 */ TopologicalSortIterator(MIRGraph * mir_graph)339 explicit TopologicalSortIterator(MIRGraph* mir_graph) 340 : DataflowIterator(mir_graph, 0, mir_graph->GetTopologicalSortOrder()->Size()) { 341 // Extra setup for TopologicalSortIterator. 342 idx_ = start_idx_; 343 block_id_list_ = mir_graph->GetTopologicalSortOrder(); 344 } 345 346 /** 347 * @brief Get the next BasicBlock depending on iteration order. 348 * @param had_change did the user of the iteration change the previous BasicBlock. 349 * @return the next BasicBlock following the iteration order, 0 if finished. 350 */ 351 virtual BasicBlock* Next(bool had_change = false) { 352 // Update changed: if had_changed is true, we remember it for the whole iteration. 353 changed_ |= had_change; 354 355 return ForwardSingleNext(); 356 } 357 }; 358 359 /** 360 * @class RepeatingTopologicalSortIterator 361 * @brief Used to perform a Topological Sort Iteration of a MIRGraph. 362 * @details If there is a change during an iteration, the iteration starts over at the end of the 363 * iteration. 364 */ 365 class RepeatingTopologicalSortIterator : public DataflowIterator { 366 public: 367 /** 368 * @brief The constructor, using all of the reachable blocks of the MIRGraph. 369 * @param mir_graph The MIRGraph considered. 370 */ RepeatingTopologicalSortIterator(MIRGraph * mir_graph)371 explicit RepeatingTopologicalSortIterator(MIRGraph* mir_graph) 372 : DataflowIterator(mir_graph, 0, mir_graph->GetTopologicalSortOrder()->Size()) { 373 // Extra setup for RepeatingTopologicalSortIterator. 374 idx_ = start_idx_; 375 block_id_list_ = mir_graph->GetTopologicalSortOrder(); 376 } 377 378 /** 379 * @brief Get the next BasicBlock depending on iteration order. 380 * @param had_change did the user of the iteration change the previous BasicBlock. 381 * @return the next BasicBlock following the iteration order, 0 if finished. 382 */ 383 virtual BasicBlock* Next(bool had_change = false) { 384 // Update changed: if had_changed is true, we remember it for the whole iteration. 385 changed_ |= had_change; 386 387 return ForwardRepeatNext(); 388 } 389 }; 390 391 /** 392 * @class LoopRepeatingTopologicalSortIterator 393 * @brief Used to perform a Topological Sort Iteration of a MIRGraph, repeating loops as needed. 394 * @details The iterator uses the visited flags to keep track of the blocks that need 395 * recalculation and keeps a stack of loop heads in the MIRGraph. At the end of the loop 396 * it returns back to the loop head if it needs to be recalculated. Due to the use of 397 * the visited flags and the loop head stack in the MIRGraph, it's not possible to use 398 * two iterators at the same time or modify this data during iteration (though inspection 399 * of this data is allowed and sometimes even expected). 400 * 401 * NOTE: This iterator is not suitable for passes that need to propagate changes to 402 * predecessors, such as type inferrence. 403 */ 404 class LoopRepeatingTopologicalSortIterator : public DataflowIterator { 405 public: 406 /** 407 * @brief The constructor, using all of the reachable blocks of the MIRGraph. 408 * @param mir_graph The MIRGraph considered. 409 */ LoopRepeatingTopologicalSortIterator(MIRGraph * mir_graph)410 explicit LoopRepeatingTopologicalSortIterator(MIRGraph* mir_graph) 411 : DataflowIterator(mir_graph, 0, mir_graph->GetTopologicalSortOrder()->Size()), 412 loop_ends_(mir_graph->GetTopologicalSortOrderLoopEnds()), 413 loop_head_stack_(mir_graph_->GetTopologicalSortOrderLoopHeadStack()) { 414 // Extra setup for RepeatingTopologicalSortIterator. 415 idx_ = start_idx_; 416 block_id_list_ = mir_graph->GetTopologicalSortOrder(); 417 // Clear visited flags and check that the loop head stack is empty. 418 mir_graph->ClearAllVisitedFlags(); 419 DCHECK_EQ(loop_head_stack_->Size(), 0u); 420 } 421 ~LoopRepeatingTopologicalSortIterator()422 ~LoopRepeatingTopologicalSortIterator() { 423 DCHECK_EQ(loop_head_stack_->Size(), 0u); 424 } 425 426 /** 427 * @brief Get the next BasicBlock depending on iteration order. 428 * @param had_change did the user of the iteration change the previous BasicBlock. 429 * @return the next BasicBlock following the iteration order, 0 if finished. 430 */ 431 virtual BasicBlock* Next(bool had_change = false) OVERRIDE; 432 433 private: 434 const GrowableArray<BasicBlockId>* const loop_ends_; 435 GrowableArray<std::pair<uint16_t, bool>>* const loop_head_stack_; 436 }; 437 438 } // namespace art 439 440 #endif // ART_COMPILER_DEX_DATAFLOW_ITERATOR_H_ 441