1 /** 2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef COMPILER_OPTIMIZER_ANALYSIS_LOOP_ANALYZER_H 17 #define COMPILER_OPTIMIZER_ANALYSIS_LOOP_ANALYZER_H 18 19 #include "optimizer/ir/inst.h" 20 #include "optimizer/pass.h" 21 22 namespace panda::compiler { 23 class BasicBlock; 24 class Graph; 25 26 class Loop final { 27 public: Loop(ArenaAllocator * allocator,BasicBlock * header,uint32_t id)28 Loop(ArenaAllocator *allocator, BasicBlock *header, uint32_t id) 29 : header_(header), 30 back_edges_(allocator->Adapter()), 31 blocks_(allocator->Adapter()), 32 inner_loops_(allocator->Adapter()), 33 id_(id) 34 { 35 } 36 37 DEFAULT_MOVE_SEMANTIC(Loop); 38 DEFAULT_COPY_SEMANTIC(Loop); 39 ~Loop() = default; 40 41 bool operator==(const Loop &other) const 42 { 43 return std::tie(header_, pre_header_, is_irreducible_, is_root_, is_infinite_) == 44 std::tie(other.header_, other.pre_header_, other.is_irreducible_, other.is_root_, 45 other.is_infinite_) && 46 IsEqualBlocks(blocks_, other.blocks_) && IsEqualBlocks(back_edges_, other.back_edges_); 47 } 48 GetHeader()49 BasicBlock *GetHeader() const 50 { 51 return header_; 52 } SetPreHeader(BasicBlock * pre_header)53 void SetPreHeader(BasicBlock *pre_header) 54 { 55 pre_header_ = pre_header; 56 } 57 GetPreHeader()58 BasicBlock *GetPreHeader() const 59 { 60 return pre_header_; 61 } AppendBackEdge(BasicBlock * block)62 void AppendBackEdge(BasicBlock *block) 63 { 64 ASSERT(std::find(back_edges_.begin(), back_edges_.end(), block) == back_edges_.end()); 65 back_edges_.push_back(block); 66 } 67 ReplaceBackEdge(BasicBlock * block,BasicBlock * new_block)68 void ReplaceBackEdge(BasicBlock *block, BasicBlock *new_block) 69 { 70 ASSERT(block != new_block); 71 ASSERT(std::find(back_edges_.begin(), back_edges_.end(), new_block) == back_edges_.end()); 72 auto it = std::find(back_edges_.begin(), back_edges_.end(), block); 73 ASSERT(it != back_edges_.end()); 74 ASSERT(std::find(it + 1, back_edges_.end(), block) == back_edges_.end()); 75 back_edges_[std::distance(back_edges_.begin(), it)] = new_block; 76 } 77 HasBackEdge(BasicBlock * block)78 bool HasBackEdge(BasicBlock *block) const 79 { 80 auto it = std::find(back_edges_.begin(), back_edges_.end(), block); 81 return it != back_edges_.end(); 82 } 83 RemoveBackEdge(BasicBlock * block)84 void RemoveBackEdge(BasicBlock *block) 85 { 86 auto it = std::find(back_edges_.begin(), back_edges_.end(), block); 87 ASSERT(it != back_edges_.end()); 88 ASSERT(std::find(it + 1, back_edges_.end(), block) == back_edges_.end()); 89 back_edges_[std::distance(back_edges_.begin(), it)] = back_edges_.back(); 90 back_edges_.pop_back(); 91 } 92 93 void MoveHeaderToSucc(); 94 GetBackEdges()95 const ArenaVector<BasicBlock *> &GetBackEdges() const 96 { 97 return back_edges_; 98 } 99 100 void AppendBlock(BasicBlock *block); 101 102 // NB! please use carefully, ensure that the block 103 // 1. is not a header of the loop 104 // 2. is not a back-edge of the loop 105 // 3. is not a pre-header of any inner loop 106 void RemoveBlock(BasicBlock *block); 107 GetBlocks()108 ArenaVector<BasicBlock *> &GetBlocks() 109 { 110 return blocks_; 111 } GetBlocks()112 const ArenaVector<BasicBlock *> &GetBlocks() const 113 { 114 return blocks_; 115 } AppendInnerLoop(Loop * inner_loop)116 void AppendInnerLoop(Loop *inner_loop) 117 { 118 inner_loops_.push_back(inner_loop); 119 } GetInnerLoops()120 ArenaVector<Loop *> &GetInnerLoops() 121 { 122 return inner_loops_; 123 } GetInnerLoops()124 const ArenaVector<Loop *> &GetInnerLoops() const 125 { 126 return inner_loops_; 127 } SetOuterLoop(Loop * outer_loop)128 void SetOuterLoop(Loop *outer_loop) 129 { 130 outer_loop_ = outer_loop; 131 } GetOuterLoop()132 Loop *GetOuterLoop() const 133 { 134 return outer_loop_; 135 } SetIsIrreducible(bool is_irreducible)136 void SetIsIrreducible(bool is_irreducible) 137 { 138 is_irreducible_ = is_irreducible; 139 } IsIrreducible()140 bool IsIrreducible() const 141 { 142 return is_irreducible_; 143 } IsInfinite()144 bool IsInfinite() const 145 { 146 return is_infinite_; 147 } SetIsInfinite(bool is_infinite)148 void SetIsInfinite(bool is_infinite) 149 { 150 is_infinite_ = is_infinite; 151 } SetAsRoot()152 void SetAsRoot() 153 { 154 is_root_ = true; 155 } IsRoot()156 bool IsRoot() const 157 { 158 return is_root_; 159 } GetId()160 uint32_t GetId() const 161 { 162 return id_; 163 } 164 165 bool IsOsrLoop() const; 166 167 bool IsTryCatchLoop() const; 168 169 bool IsInside(Loop *other); 170 171 private: 172 void CheckInfinity(); 173 174 template <typename T> IsEqualBlocks(const ArenaVector<T> & blocks,const ArenaVector<T> & others)175 static inline bool IsEqualBlocks(const ArenaVector<T> &blocks, const ArenaVector<T> &others) 176 { 177 return blocks.size() == others.size() && std::is_permutation(blocks.begin(), blocks.end(), others.begin()); 178 } 179 180 private: 181 BasicBlock *header_ {nullptr}; 182 BasicBlock *pre_header_ {nullptr}; 183 ArenaVector<BasicBlock *> back_edges_; 184 ArenaVector<BasicBlock *> blocks_; 185 ArenaVector<Loop *> inner_loops_; 186 Loop *outer_loop_ {nullptr}; 187 bool is_irreducible_ {false}; 188 bool is_infinite_ {false}; 189 bool is_root_ {false}; 190 uint32_t id_ {INVALID_ID}; 191 192 friend class LoopAnalyzer; 193 }; 194 195 class LoopAnalyzer final : public Analysis { 196 public: 197 using Analysis::Analysis; 198 199 bool RunImpl() override; 200 GetPassName()201 const char *GetPassName() const override 202 { 203 return "LoopAnalysis"; 204 } 205 206 void CreateRootLoop(); 207 Loop *CreateNewLoop(BasicBlock *loop_header); 208 209 private: 210 void ResetLoopInfo(); 211 void CollectBackEdges(); 212 void BackEdgeSearch(BasicBlock *block); 213 void ProcessNewBackEdge(BasicBlock *header, BasicBlock *back_edge); 214 void FindAndInsertPreHeaders(Loop *loop); 215 void MovePhiInputsToPreHeader(BasicBlock *header, BasicBlock *pre_header, const ArenaVector<int> &fw_edges_indexes); 216 void UpdateControlFlowWithPreHeader(BasicBlock *header, BasicBlock *pre_header, 217 const ArenaVector<int> &fw_edges_indexes); 218 ArenaVector<int> GetForwardEdgesIndexes(BasicBlock *header); 219 bool PreHeaderExists(Loop *loop); 220 BasicBlock *CreatePreHeader(BasicBlock *header); 221 void PopulateLoops(); 222 void NaturalLoopSearch(Loop *loop, BasicBlock *block); 223 void SearchInfiniteLoops(Loop *loop); 224 225 private: 226 Marker black_marker_ {}; 227 Marker gray_marker_ {}; 228 uint32_t loop_counter_ {0}; 229 }; 230 231 BasicBlock *GetLoopOutsideSuccessor(Loop *loop); 232 // NOLINTNEXTLINE(readability-redundant-declaration) 233 bool IsLoopSingleBackEdgeExitPoint(Loop *loop); 234 235 } // namespace panda::compiler 236 237 #endif // COMPILER_OPTIMIZER_ANALYSIS_LOOP_ANALYZER_H 238