1 // Copyright (c) 2017 Google Inc. 2 // 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 #ifndef SOURCE_OPT_LOOP_DESCRIPTOR_H_ 16 #define SOURCE_OPT_LOOP_DESCRIPTOR_H_ 17 18 #include <algorithm> 19 #include <cstdint> 20 #include <map> 21 #include <memory> 22 #include <unordered_map> 23 #include <unordered_set> 24 #include <utility> 25 #include <vector> 26 27 #include "source/opt/basic_block.h" 28 #include "source/opt/dominator_analysis.h" 29 #include "source/opt/module.h" 30 #include "source/opt/tree_iterator.h" 31 32 namespace spvtools { 33 namespace opt { 34 35 class IRContext; 36 class CFG; 37 class LoopDescriptor; 38 39 // A class to represent and manipulate a loop in structured control flow. 40 class Loop { 41 // The type used to represent nested child loops. 42 using ChildrenList = std::vector<Loop*>; 43 44 public: 45 using iterator = ChildrenList::iterator; 46 using const_iterator = ChildrenList::const_iterator; 47 using BasicBlockListTy = std::unordered_set<uint32_t>; 48 Loop(IRContext * context)49 explicit Loop(IRContext* context) 50 : context_(context), 51 loop_header_(nullptr), 52 loop_continue_(nullptr), 53 loop_merge_(nullptr), 54 loop_preheader_(nullptr), 55 loop_latch_(nullptr), 56 parent_(nullptr), 57 loop_is_marked_for_removal_(false) {} 58 59 Loop(IRContext* context, DominatorAnalysis* analysis, BasicBlock* header, 60 BasicBlock* continue_target, BasicBlock* merge_target); 61 62 // Iterators over the immediate sub-loops. begin()63 inline iterator begin() { return nested_loops_.begin(); } end()64 inline iterator end() { return nested_loops_.end(); } begin()65 inline const_iterator begin() const { return cbegin(); } end()66 inline const_iterator end() const { return cend(); } cbegin()67 inline const_iterator cbegin() const { return nested_loops_.begin(); } cend()68 inline const_iterator cend() const { return nested_loops_.end(); } 69 70 // Returns the header (first basic block of the loop). This block contains the 71 // OpLoopMerge instruction. GetHeaderBlock()72 inline BasicBlock* GetHeaderBlock() { return loop_header_; } GetHeaderBlock()73 inline const BasicBlock* GetHeaderBlock() const { return loop_header_; } SetHeaderBlock(BasicBlock * header)74 inline void SetHeaderBlock(BasicBlock* header) { loop_header_ = header; } 75 76 // Updates the OpLoopMerge instruction to reflect the current state of the 77 // loop. UpdateLoopMergeInst()78 inline void UpdateLoopMergeInst() { 79 assert(GetHeaderBlock()->GetLoopMergeInst() && 80 "The loop is not structured"); 81 Instruction* merge_inst = GetHeaderBlock()->GetLoopMergeInst(); 82 merge_inst->SetInOperand(0, {GetMergeBlock()->id()}); 83 } 84 85 // Returns the continue target basic block. This is the block designated as 86 // the continue target by the OpLoopMerge instruction. GetContinueBlock()87 inline BasicBlock* GetContinueBlock() { return loop_continue_; } GetContinueBlock()88 inline const BasicBlock* GetContinueBlock() const { return loop_continue_; } 89 90 // Returns the latch basic block (basic block that holds the back-edge). 91 // These functions return nullptr if the loop is not structured (i.e. if it 92 // has more than one backedge). GetLatchBlock()93 inline BasicBlock* GetLatchBlock() { return loop_latch_; } GetLatchBlock()94 inline const BasicBlock* GetLatchBlock() const { return loop_latch_; } 95 96 // Sets |latch| as the loop unique block branching back to the header. 97 // A latch block must have the following properties: 98 // - |latch| must be in the loop; 99 // - must be the only block branching back to the header block. 100 void SetLatchBlock(BasicBlock* latch); 101 102 // Sets |continue_block| as the continue block of the loop. This should be the 103 // continue target of the OpLoopMerge and should dominate the latch block. 104 void SetContinueBlock(BasicBlock* continue_block); 105 106 // Returns the basic block which marks the end of the loop. 107 // These functions return nullptr if the loop is not structured. GetMergeBlock()108 inline BasicBlock* GetMergeBlock() { return loop_merge_; } GetMergeBlock()109 inline const BasicBlock* GetMergeBlock() const { return loop_merge_; } 110 // Sets |merge| as the loop merge block. A merge block must have the following 111 // properties: 112 // - |merge| must not be in the loop; 113 // - all its predecessors must be in the loop. 114 // - it must not be already used as merge block. 115 // If the loop has an OpLoopMerge in its header, this instruction is also 116 // updated. 117 void SetMergeBlock(BasicBlock* merge); 118 119 // Returns the loop pre-header, nullptr means that the loop predecessor does 120 // not qualify as a preheader. 121 // The preheader is the unique predecessor that: 122 // - Dominates the loop header; 123 // - Has only the loop header as successor. GetPreHeaderBlock()124 inline BasicBlock* GetPreHeaderBlock() { return loop_preheader_; } 125 126 // Returns the loop pre-header. GetPreHeaderBlock()127 inline const BasicBlock* GetPreHeaderBlock() const { return loop_preheader_; } 128 // Sets |preheader| as the loop preheader block. A preheader block must have 129 // the following properties: 130 // - |merge| must not be in the loop; 131 // - have an unconditional branch to the loop header. 132 void SetPreHeaderBlock(BasicBlock* preheader); 133 134 // Returns the loop pre-header, if there is no suitable preheader it will be 135 // created. Returns |nullptr| if it fails to create the preheader. 136 BasicBlock* GetOrCreatePreHeaderBlock(); 137 138 // Returns true if this loop contains any nested loops. HasNestedLoops()139 inline bool HasNestedLoops() const { return nested_loops_.size() != 0; } 140 141 // Clears and fills |exit_blocks| with all basic blocks that are not in the 142 // loop and has at least one predecessor in the loop. 143 void GetExitBlocks(std::unordered_set<uint32_t>* exit_blocks) const; 144 145 // Clears and fills |merging_blocks| with all basic blocks that are 146 // post-dominated by the merge block. The merge block must exist. 147 // The set |merging_blocks| will only contain the merge block if it is 148 // unreachable. 149 void GetMergingBlocks(std::unordered_set<uint32_t>* merging_blocks) const; 150 151 // Returns true if the loop is in a Loop Closed SSA form. 152 // In LCSSA form, all in-loop definitions are used in the loop or in phi 153 // instructions in the loop exit blocks. 154 bool IsLCSSA() const; 155 156 // Returns the depth of this loop in the loop nest. 157 // The outer-most loop has a depth of 1. GetDepth()158 inline size_t GetDepth() const { 159 size_t lvl = 1; 160 for (const Loop* loop = GetParent(); loop; loop = loop->GetParent()) lvl++; 161 return lvl; 162 } 163 NumImmediateChildren()164 inline size_t NumImmediateChildren() const { return nested_loops_.size(); } 165 HasChildren()166 inline bool HasChildren() const { return !nested_loops_.empty(); } 167 // Adds |nested| as a nested loop of this loop. Automatically register |this| 168 // as the parent of |nested|. AddNestedLoop(Loop * nested)169 inline void AddNestedLoop(Loop* nested) { 170 assert(!nested->GetParent() && "The loop has another parent."); 171 nested_loops_.push_back(nested); 172 nested->SetParent(this); 173 } 174 GetParent()175 inline Loop* GetParent() { return parent_; } GetParent()176 inline const Loop* GetParent() const { return parent_; } 177 HasParent()178 inline bool HasParent() const { return parent_; } 179 180 // Returns true if this loop is itself nested within another loop. IsNested()181 inline bool IsNested() const { return parent_ != nullptr; } 182 183 // Returns the set of all basic blocks contained within the loop. Will be all 184 // BasicBlocks dominated by the header which are not also dominated by the 185 // loop merge block. GetBlocks()186 inline const BasicBlockListTy& GetBlocks() const { 187 return loop_basic_blocks_; 188 } 189 190 // Returns true if the basic block |bb| is inside this loop. IsInsideLoop(const BasicBlock * bb)191 inline bool IsInsideLoop(const BasicBlock* bb) const { 192 return IsInsideLoop(bb->id()); 193 } 194 195 // Returns true if the basic block id |bb_id| is inside this loop. IsInsideLoop(uint32_t bb_id)196 inline bool IsInsideLoop(uint32_t bb_id) const { 197 return loop_basic_blocks_.count(bb_id); 198 } 199 200 // Returns true if the instruction |inst| is inside this loop. 201 bool IsInsideLoop(Instruction* inst) const; 202 203 // Adds the Basic Block |bb| to this loop and its parents. AddBasicBlock(const BasicBlock * bb)204 void AddBasicBlock(const BasicBlock* bb) { AddBasicBlock(bb->id()); } 205 206 // Adds the Basic Block with |id| to this loop and its parents. AddBasicBlock(uint32_t id)207 void AddBasicBlock(uint32_t id) { 208 for (Loop* loop = this; loop != nullptr; loop = loop->parent_) { 209 loop->loop_basic_blocks_.insert(id); 210 } 211 } 212 213 // Removes the Basic Block id |bb_id| from this loop and its parents. 214 // It the user responsibility to make sure the removed block is not a merge, 215 // header or continue block. RemoveBasicBlock(uint32_t bb_id)216 void RemoveBasicBlock(uint32_t bb_id) { 217 for (Loop* loop = this; loop != nullptr; loop = loop->parent_) { 218 loop->loop_basic_blocks_.erase(bb_id); 219 } 220 } 221 222 // Removes all the basic blocks from the set of basic blocks within the loop. 223 // This does not affect any of the stored pointers to the header, preheader, 224 // merge, or continue blocks. ClearBlocks()225 void ClearBlocks() { loop_basic_blocks_.clear(); } 226 227 // Adds the Basic Block |bb| this loop and its parents. AddBasicBlockToLoop(const BasicBlock * bb)228 void AddBasicBlockToLoop(const BasicBlock* bb) { 229 assert(IsBasicBlockInLoopSlow(bb) && 230 "Basic block does not belong to the loop"); 231 232 AddBasicBlock(bb); 233 } 234 235 // Returns the list of induction variables within the loop. 236 void GetInductionVariables(std::vector<Instruction*>& inductions) const; 237 238 // This function uses the |condition| to find the induction variable which is 239 // used by the loop condition within the loop. This only works if the loop is 240 // bound by a single condition and single induction variable. 241 Instruction* FindConditionVariable(const BasicBlock* condition) const; 242 243 // Returns the number of iterations within a loop when given the |induction| 244 // variable and the loop |condition| check. It stores the found number of 245 // iterations in the output parameter |iterations| and optionally, the step 246 // value in |step_value| and the initial value of the induction variable in 247 // |init_value|. 248 bool FindNumberOfIterations(const Instruction* induction, 249 const Instruction* condition, size_t* iterations, 250 int64_t* step_amount = nullptr, 251 int64_t* init_value = nullptr) const; 252 253 // Returns the value of the OpLoopMerge control operand as a bool. Loop 254 // control can be None(0), Unroll(1), or DontUnroll(2). This function returns 255 // true if it is set to Unroll. HasUnrollLoopControl()256 inline bool HasUnrollLoopControl() const { 257 assert(loop_header_); 258 if (!loop_header_->GetLoopMergeInst()) return false; 259 260 return loop_header_->GetLoopMergeInst()->GetSingleWordOperand(2) == 1; 261 } 262 263 // Finds the conditional block with a branch to the merge and continue blocks 264 // within the loop body. 265 BasicBlock* FindConditionBlock() const; 266 267 // Remove the child loop form this loop. RemoveChildLoop(Loop * loop)268 inline void RemoveChildLoop(Loop* loop) { 269 nested_loops_.erase( 270 std::find(nested_loops_.begin(), nested_loops_.end(), loop)); 271 loop->SetParent(nullptr); 272 } 273 274 // Mark this loop to be removed later by a call to 275 // LoopDescriptor::PostModificationCleanup. MarkLoopForRemoval()276 inline void MarkLoopForRemoval() { loop_is_marked_for_removal_ = true; } 277 278 // Returns whether or not this loop has been marked for removal. IsMarkedForRemoval()279 inline bool IsMarkedForRemoval() const { return loop_is_marked_for_removal_; } 280 281 // Returns true if all nested loops have been marked for removal. AreAllChildrenMarkedForRemoval()282 inline bool AreAllChildrenMarkedForRemoval() const { 283 for (const Loop* child : nested_loops_) { 284 if (!child->IsMarkedForRemoval()) { 285 return false; 286 } 287 } 288 return true; 289 } 290 291 // Checks if the loop contains any instruction that will prevent it from being 292 // cloned. If the loop is structured, the merge construct is also considered. 293 bool IsSafeToClone() const; 294 295 // Sets the parent loop of this loop, that is, a loop which contains this loop 296 // as a nested child loop. SetParent(Loop * parent)297 inline void SetParent(Loop* parent) { parent_ = parent; } 298 299 // Returns true is the instruction is invariant and safe to move wrt loop 300 bool ShouldHoistInstruction(IRContext* context, Instruction* inst); 301 302 // Returns true if all operands of inst are in basic blocks not contained in 303 // loop 304 bool AreAllOperandsOutsideLoop(IRContext* context, Instruction* inst); 305 306 // Extract the initial value from the |induction| variable and store it in 307 // |value|. If the function couldn't find the initial value of |induction| 308 // return false. 309 bool GetInductionInitValue(const Instruction* induction, 310 int64_t* value) const; 311 312 // Takes in a phi instruction |induction| and the loop |header| and returns 313 // the step operation of the loop. 314 Instruction* GetInductionStepOperation(const Instruction* induction) const; 315 316 // Returns true if we can deduce the number of loop iterations in the step 317 // operation |step|. IsSupportedCondition must also be true for the condition 318 // instruction. 319 bool IsSupportedStepOp(SpvOp step) const; 320 321 // Returns true if we can deduce the number of loop iterations in the 322 // condition operation |condition|. IsSupportedStepOp must also be true for 323 // the step instruction. 324 bool IsSupportedCondition(SpvOp condition) const; 325 326 // Creates the list of the loop's basic block in structured order and store 327 // the result in |ordered_loop_blocks|. If |include_pre_header| is true, the 328 // pre-header block will also be included at the beginning of the list if it 329 // exist. If |include_merge| is true, the merge block will also be included at 330 // the end of the list if it exist. 331 void ComputeLoopStructuredOrder(std::vector<BasicBlock*>* ordered_loop_blocks, 332 bool include_pre_header = false, 333 bool include_merge = false) const; 334 335 // Given the loop |condition|, |initial_value|, |step_value|, the trip count 336 // |number_of_iterations|, and the |unroll_factor| requested, get the new 337 // condition value for the residual loop. 338 static int64_t GetResidualConditionValue(SpvOp condition, 339 int64_t initial_value, 340 int64_t step_value, 341 size_t number_of_iterations, 342 size_t unroll_factor); 343 344 // Returns the condition instruction for entry into the loop 345 // Returns nullptr if it can't be found. 346 Instruction* GetConditionInst() const; 347 348 // Returns the context associated this loop. GetContext()349 IRContext* GetContext() const { return context_; } 350 351 // Looks at all the blocks with a branch to the header block to find one 352 // which is also dominated by the loop continue block. This block is the latch 353 // block. The specification mandates that this block should exist, therefore 354 // this function will assert if it is not found. 355 BasicBlock* FindLatchBlock(); 356 357 private: 358 IRContext* context_; 359 // The block which marks the start of the loop. 360 BasicBlock* loop_header_; 361 362 // The block which begins the body of the loop. 363 BasicBlock* loop_continue_; 364 365 // The block which marks the end of the loop. 366 BasicBlock* loop_merge_; 367 368 // The block immediately before the loop header. 369 BasicBlock* loop_preheader_; 370 371 // The block containing the backedge to the loop header. 372 BasicBlock* loop_latch_; 373 374 // A parent of a loop is the loop which contains it as a nested child loop. 375 Loop* parent_; 376 377 // Nested child loops of this loop. 378 ChildrenList nested_loops_; 379 380 // A set of all the basic blocks which comprise the loop structure. Will be 381 // computed only when needed on demand. 382 BasicBlockListTy loop_basic_blocks_; 383 384 // Check that |bb| is inside the loop using domination property. 385 // Note: this is for assertion purposes only, IsInsideLoop should be used 386 // instead. 387 bool IsBasicBlockInLoopSlow(const BasicBlock* bb); 388 389 // Returns the loop preheader if it exists, returns nullptr otherwise. 390 BasicBlock* FindLoopPreheader(DominatorAnalysis* dom_analysis); 391 392 // Sets |latch| as the loop unique latch block. No checks are performed 393 // here. SetLatchBlockImpl(BasicBlock * latch)394 inline void SetLatchBlockImpl(BasicBlock* latch) { loop_latch_ = latch; } 395 // Sets |merge| as the loop merge block. No checks are performed here. SetMergeBlockImpl(BasicBlock * merge)396 inline void SetMergeBlockImpl(BasicBlock* merge) { loop_merge_ = merge; } 397 398 // Each differnt loop |condition| affects how we calculate the number of 399 // iterations using the |condition_value|, |init_value|, and |step_values| of 400 // the induction variable. This method will return the number of iterations in 401 // a loop with those values for a given |condition|. 402 int64_t GetIterations(SpvOp condition, int64_t condition_value, 403 int64_t init_value, int64_t step_value) const; 404 405 // This is to allow for loops to be removed mid iteration without invalidating 406 // the iterators. 407 bool loop_is_marked_for_removal_; 408 409 // This is only to allow LoopDescriptor::placeholder_top_loop_ to add top 410 // level loops as child. 411 friend class LoopDescriptor; 412 friend class LoopUtils; 413 }; 414 415 // Loop descriptions class for a given function. 416 // For a given function, the class builds loop nests information. 417 // The analysis expects a structured control flow. 418 class LoopDescriptor { 419 public: 420 // Iterator interface (depth first postorder traversal). 421 using iterator = PostOrderTreeDFIterator<Loop>; 422 using const_iterator = PostOrderTreeDFIterator<const Loop>; 423 424 using pre_iterator = TreeDFIterator<Loop>; 425 using const_pre_iterator = TreeDFIterator<const Loop>; 426 427 // Creates a loop object for all loops found in |f|. 428 LoopDescriptor(IRContext* context, const Function* f); 429 430 // Disable copy constructor, to avoid double-free on destruction. 431 LoopDescriptor(const LoopDescriptor&) = delete; 432 // Move constructor. LoopDescriptor(LoopDescriptor && other)433 LoopDescriptor(LoopDescriptor&& other) : placeholder_top_loop_(nullptr) { 434 // We need to take ownership of the Loop objects in the other 435 // LoopDescriptor, to avoid double-free. 436 loops_ = std::move(other.loops_); 437 other.loops_.clear(); 438 basic_block_to_loop_ = std::move(other.basic_block_to_loop_); 439 other.basic_block_to_loop_.clear(); 440 placeholder_top_loop_ = std::move(other.placeholder_top_loop_); 441 } 442 443 // Destructor 444 ~LoopDescriptor(); 445 446 // Returns the number of loops found in the function. NumLoops()447 inline size_t NumLoops() const { return loops_.size(); } 448 449 // Returns the loop at a particular |index|. The |index| must be in bounds, 450 // check with NumLoops before calling. GetLoopByIndex(size_t index)451 inline Loop& GetLoopByIndex(size_t index) const { 452 assert(loops_.size() > index && 453 "Index out of range (larger than loop count)"); 454 return *loops_[index]; 455 } 456 457 // Returns the loops in |this| in the order their headers appear in the 458 // binary. 459 std::vector<Loop*> GetLoopsInBinaryLayoutOrder(); 460 461 // Returns the inner most loop that contains the basic block id |block_id|. 462 inline Loop* operator[](uint32_t block_id) const { 463 return FindLoopForBasicBlock(block_id); 464 } 465 466 // Returns the inner most loop that contains the basic block |bb|. 467 inline Loop* operator[](const BasicBlock* bb) const { 468 return (*this)[bb->id()]; 469 } 470 471 // Iterators for post order depth first traversal of the loops. 472 // Inner most loops will be visited first. begin()473 inline iterator begin() { return iterator::begin(&placeholder_top_loop_); } end()474 inline iterator end() { return iterator::end(&placeholder_top_loop_); } begin()475 inline const_iterator begin() const { return cbegin(); } end()476 inline const_iterator end() const { return cend(); } cbegin()477 inline const_iterator cbegin() const { 478 return const_iterator::begin(&placeholder_top_loop_); 479 } cend()480 inline const_iterator cend() const { 481 return const_iterator::end(&placeholder_top_loop_); 482 } 483 484 // Iterators for pre-order depth first traversal of the loops. 485 // Inner most loops will be visited first. pre_begin()486 inline pre_iterator pre_begin() { 487 return ++pre_iterator(&placeholder_top_loop_); 488 } pre_end()489 inline pre_iterator pre_end() { return pre_iterator(); } pre_begin()490 inline const_pre_iterator pre_begin() const { return pre_cbegin(); } pre_end()491 inline const_pre_iterator pre_end() const { return pre_cend(); } pre_cbegin()492 inline const_pre_iterator pre_cbegin() const { 493 return ++const_pre_iterator(&placeholder_top_loop_); 494 } pre_cend()495 inline const_pre_iterator pre_cend() const { return const_pre_iterator(); } 496 497 // Returns the inner most loop that contains the basic block |bb|. SetBasicBlockToLoop(uint32_t bb_id,Loop * loop)498 inline void SetBasicBlockToLoop(uint32_t bb_id, Loop* loop) { 499 basic_block_to_loop_[bb_id] = loop; 500 } 501 502 // Mark the loop |loop_to_add| as needing to be added when the user calls 503 // PostModificationCleanup. |parent| may be null. AddLoop(std::unique_ptr<Loop> && loop_to_add,Loop * parent)504 inline void AddLoop(std::unique_ptr<Loop>&& loop_to_add, Loop* parent) { 505 loops_to_add_.emplace_back(std::make_pair(parent, std::move(loop_to_add))); 506 } 507 508 // Checks all loops in |this| and will create pre-headers for all loops 509 // that don't have one. Returns |true| if any blocks were created. 510 bool CreatePreHeaderBlocksIfMissing(); 511 512 // Should be called to preserve the LoopAnalysis after loops have been marked 513 // for addition with AddLoop or MarkLoopForRemoval. 514 void PostModificationCleanup(); 515 516 // Removes the basic block id |bb_id| from the block to loop mapping. ForgetBasicBlock(uint32_t bb_id)517 inline void ForgetBasicBlock(uint32_t bb_id) { 518 basic_block_to_loop_.erase(bb_id); 519 } 520 521 // Adds the loop |new_loop| and all its nested loops to the descriptor set. 522 // The object takes ownership of all the loops. 523 Loop* AddLoopNest(std::unique_ptr<Loop> new_loop); 524 525 // Remove the loop |loop|. 526 void RemoveLoop(Loop* loop); 527 SetAsTopLoop(Loop * loop)528 void SetAsTopLoop(Loop* loop) { 529 assert(std::find(placeholder_top_loop_.begin(), placeholder_top_loop_.end(), 530 loop) == placeholder_top_loop_.end() && 531 "already registered"); 532 placeholder_top_loop_.nested_loops_.push_back(loop); 533 } 534 GetPlaceholderRootLoop()535 Loop* GetPlaceholderRootLoop() { return &placeholder_top_loop_; } GetPlaceholderRootLoop()536 const Loop* GetPlaceholderRootLoop() const { return &placeholder_top_loop_; } 537 538 private: 539 // TODO(dneto): This should be a vector of unique_ptr. But VisualStudio 2013 540 // is unable to compile it. 541 using LoopContainerType = std::vector<Loop*>; 542 543 using LoopsToAddContainerType = 544 std::vector<std::pair<Loop*, std::unique_ptr<Loop>>>; 545 546 // Creates loop descriptors for the function |f|. 547 void PopulateList(IRContext* context, const Function* f); 548 549 // Returns the inner most loop that contains the basic block id |block_id|. FindLoopForBasicBlock(uint32_t block_id)550 inline Loop* FindLoopForBasicBlock(uint32_t block_id) const { 551 std::unordered_map<uint32_t, Loop*>::const_iterator it = 552 basic_block_to_loop_.find(block_id); 553 return it != basic_block_to_loop_.end() ? it->second : nullptr; 554 } 555 556 // Erase all the loop information. 557 void ClearLoops(); 558 559 // A list of all the loops in the function. This variable owns the Loop 560 // objects. 561 LoopContainerType loops_; 562 563 // Placeholder root: this "loop" is only there to help iterators creation. 564 Loop placeholder_top_loop_; 565 566 std::unordered_map<uint32_t, Loop*> basic_block_to_loop_; 567 568 // List of the loops marked for addition when PostModificationCleanup is 569 // called. 570 LoopsToAddContainerType loops_to_add_; 571 }; 572 573 } // namespace opt 574 } // namespace spvtools 575 576 #endif // SOURCE_OPT_LOOP_DESCRIPTOR_H_ 577