Home | History | Annotate | Download | only in dex
      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:
     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        */
     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        */
     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        */
     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        */
    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        */
    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        */
    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        */
    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        */
    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        */
    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        */
    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        */
    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        */
    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       */
    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       */
    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 
    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