loop_utils.h 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. // Copyright (c) 2018 Google LLC.
  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. #ifndef SOURCE_OPT_LOOP_UTILS_H_
  15. #define SOURCE_OPT_LOOP_UTILS_H_
  16. #include <list>
  17. #include <memory>
  18. #include <unordered_map>
  19. #include <vector>
  20. #include "source/opt/ir_context.h"
  21. #include "source/opt/loop_descriptor.h"
  22. namespace spvtools {
  23. namespace opt {
  24. // Class to gather some metrics about a Region Of Interest (ROI).
  25. // So far it counts the number of instructions in a ROI (excluding debug
  26. // and label instructions) per basic block and in total.
  27. struct CodeMetrics {
  28. void Analyze(const Loop& loop);
  29. // The number of instructions per basic block in the ROI.
  30. std::unordered_map<uint32_t, size_t> block_sizes_;
  31. // Number of instruction in the ROI.
  32. size_t roi_size_;
  33. };
  34. // LoopUtils is used to encapsulte loop optimizations and from the passes which
  35. // use them. Any pass which needs a loop optimization should do it through this
  36. // or through a pass which is using this.
  37. class LoopUtils {
  38. public:
  39. // Holds a auxiliary results of the loop cloning procedure.
  40. struct LoopCloningResult {
  41. using ValueMapTy = std::unordered_map<uint32_t, uint32_t>;
  42. using BlockMapTy = std::unordered_map<uint32_t, BasicBlock*>;
  43. using PtrMap = std::unordered_map<Instruction*, Instruction*>;
  44. PtrMap ptr_map_;
  45. // Mapping between the original loop ids and the new one.
  46. ValueMapTy value_map_;
  47. // Mapping between original loop blocks to the cloned one.
  48. BlockMapTy old_to_new_bb_;
  49. // Mapping between the cloned loop blocks to original one.
  50. BlockMapTy new_to_old_bb_;
  51. // List of cloned basic block.
  52. std::vector<std::unique_ptr<BasicBlock>> cloned_bb_;
  53. };
  54. LoopUtils(IRContext* context, Loop* loop)
  55. : context_(context),
  56. loop_desc_(
  57. context->GetLoopDescriptor(loop->GetHeaderBlock()->GetParent())),
  58. loop_(loop),
  59. function_(*loop_->GetHeaderBlock()->GetParent()) {}
  60. // The converts the current loop to loop closed SSA form.
  61. // In the loop closed SSA, all loop exiting values go through a dedicated Phi
  62. // instruction. For instance:
  63. //
  64. // for (...) {
  65. // A1 = ...
  66. // if (...)
  67. // A2 = ...
  68. // A = phi A1, A2
  69. // }
  70. // ... = op A ...
  71. //
  72. // Becomes
  73. //
  74. // for (...) {
  75. // A1 = ...
  76. // if (...)
  77. // A2 = ...
  78. // A = phi A1, A2
  79. // }
  80. // C = phi A
  81. // ... = op C ...
  82. //
  83. // This makes some loop transformations (such as loop unswitch) simpler
  84. // (removes the needs to take care of exiting variables).
  85. void MakeLoopClosedSSA();
  86. // Create dedicate exit basic block. This ensure all exit basic blocks has the
  87. // loop as sole predecessors.
  88. // By construction, structured control flow already has a dedicated exit
  89. // block.
  90. // Preserves: CFG, def/use and instruction to block mapping.
  91. void CreateLoopDedicatedExits();
  92. // Clone |loop_| and remap its instructions. Newly created blocks
  93. // will be added to the |cloning_result.cloned_bb_| list, correctly ordered to
  94. // be inserted into a function.
  95. // It is assumed that |ordered_loop_blocks| is compatible with the result of
  96. // |Loop::ComputeLoopStructuredOrder|. If the preheader and merge block are in
  97. // the list they will also be cloned. If not, the resulting loop will share
  98. // them with the original loop.
  99. // The function preserves the def/use, cfg and instr to block analyses.
  100. // The cloned loop nest will be added to the loop descriptor and will have
  101. // ownership.
  102. Loop* CloneLoop(LoopCloningResult* cloning_result,
  103. const std::vector<BasicBlock*>& ordered_loop_blocks) const;
  104. // Clone |loop_| and remap its instructions, as above. Overload to compute
  105. // loop block ordering within method rather than taking in as parameter.
  106. Loop* CloneLoop(LoopCloningResult* cloning_result) const;
  107. // Clone the |loop_| and make the new loop branch to the second loop on exit.
  108. Loop* CloneAndAttachLoopToHeader(LoopCloningResult* cloning_result);
  109. // Perform a partial unroll of |loop| by given |factor|. This will copy the
  110. // body of the loop |factor| times. So a |factor| of one would give a new loop
  111. // with the original body plus one unrolled copy body.
  112. bool PartiallyUnroll(size_t factor);
  113. // Fully unroll |loop|.
  114. bool FullyUnroll();
  115. // This function validates that |loop| meets the assumptions made by the
  116. // implementation of the loop unroller. As the implementation accommodates
  117. // more types of loops this function can reduce its checks.
  118. //
  119. // The conditions checked to ensure the loop can be unrolled are as follows:
  120. // 1. That the loop is in structured order.
  121. // 2. That the continue block is a branch to the header.
  122. // 3. That the only phi used in the loop is the induction variable.
  123. // TODO([email protected]): This is a temporary measure, after the loop is
  124. // converted into LCSAA form and has a single entry and exit we can rewrite
  125. // the other phis.
  126. // 4. That this is an inner most loop, or that loops contained within this
  127. // loop have already been fully unrolled.
  128. // 5. That each instruction in the loop is only used within the loop.
  129. // (Related to the above phi condition).
  130. bool CanPerformUnroll();
  131. // Maintains the loop descriptor object after the unroll functions have been
  132. // called, otherwise the analysis should be invalidated.
  133. void Finalize();
  134. // Returns the context associate to |loop_|.
  135. IRContext* GetContext() { return context_; }
  136. // Returns the loop descriptor owning |loop_|.
  137. LoopDescriptor* GetLoopDescriptor() { return loop_desc_; }
  138. // Returns the loop on which the object operates on.
  139. Loop* GetLoop() const { return loop_; }
  140. // Returns the function that |loop_| belong to.
  141. Function* GetFunction() const { return &function_; }
  142. private:
  143. IRContext* context_;
  144. LoopDescriptor* loop_desc_;
  145. Loop* loop_;
  146. Function& function_;
  147. // Populates the loop nest of |new_loop| according to |loop_| nest.
  148. void PopulateLoopNest(Loop* new_loop,
  149. const LoopCloningResult& cloning_result) const;
  150. // Populates |new_loop| descriptor according to |old_loop|'s one.
  151. void PopulateLoopDesc(Loop* new_loop, Loop* old_loop,
  152. const LoopCloningResult& cloning_result) const;
  153. };
  154. } // namespace opt
  155. } // namespace spvtools
  156. #endif // SOURCE_OPT_LOOP_UTILS_H_