register_pressure.h 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  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_REGISTER_PRESSURE_H_
  15. #define SOURCE_OPT_REGISTER_PRESSURE_H_
  16. #include <unordered_map>
  17. #include <unordered_set>
  18. #include <utility>
  19. #include <vector>
  20. #include "source/opt/function.h"
  21. #include "source/opt/types.h"
  22. namespace spvtools {
  23. namespace opt {
  24. class IRContext;
  25. class Loop;
  26. class LoopDescriptor;
  27. // Handles the register pressure of a function for different regions (function,
  28. // loop, basic block). It also contains some utilities to foresee the register
  29. // pressure following code transformations.
  30. class RegisterLiveness {
  31. public:
  32. // Classification of SSA registers.
  33. struct RegisterClass {
  34. analysis::Type* type_;
  35. bool is_uniform_;
  36. bool operator==(const RegisterClass& rhs) const {
  37. return std::tie(type_, is_uniform_) ==
  38. std::tie(rhs.type_, rhs.is_uniform_);
  39. }
  40. };
  41. struct RegionRegisterLiveness {
  42. using LiveSet = std::unordered_set<Instruction*>;
  43. using RegClassSetTy = std::vector<std::pair<RegisterClass, size_t>>;
  44. // SSA register live when entering the basic block.
  45. LiveSet live_in_;
  46. // SSA register live when exiting the basic block.
  47. LiveSet live_out_;
  48. // Maximum number of required registers.
  49. size_t used_registers_;
  50. // Break down of the number of required registers per class of register.
  51. RegClassSetTy registers_classes_;
  52. void Clear() {
  53. live_out_.clear();
  54. live_in_.clear();
  55. used_registers_ = 0;
  56. registers_classes_.clear();
  57. }
  58. void AddRegisterClass(const RegisterClass& reg_class) {
  59. auto it = std::find_if(
  60. registers_classes_.begin(), registers_classes_.end(),
  61. [&reg_class](const std::pair<RegisterClass, size_t>& class_count) {
  62. return class_count.first == reg_class;
  63. });
  64. if (it != registers_classes_.end()) {
  65. it->second++;
  66. } else {
  67. registers_classes_.emplace_back(std::move(reg_class),
  68. static_cast<size_t>(1));
  69. }
  70. }
  71. void AddRegisterClass(Instruction* insn);
  72. };
  73. RegisterLiveness(IRContext* context, Function* f) : context_(context) {
  74. Analyze(f);
  75. }
  76. // Returns liveness and register information for the basic block |bb|. If no
  77. // entry exist for the basic block, the function returns null.
  78. const RegionRegisterLiveness* Get(const BasicBlock* bb) const {
  79. return Get(bb->id());
  80. }
  81. // Returns liveness and register information for the basic block id |bb_id|.
  82. // If no entry exist for the basic block, the function returns null.
  83. const RegionRegisterLiveness* Get(uint32_t bb_id) const {
  84. RegionRegisterLivenessMap::const_iterator it = block_pressure_.find(bb_id);
  85. if (it != block_pressure_.end()) {
  86. return &it->second;
  87. }
  88. return nullptr;
  89. }
  90. IRContext* GetContext() const { return context_; }
  91. // Returns liveness and register information for the basic block |bb|. If no
  92. // entry exist for the basic block, the function returns null.
  93. RegionRegisterLiveness* Get(const BasicBlock* bb) { return Get(bb->id()); }
  94. // Returns liveness and register information for the basic block id |bb_id|.
  95. // If no entry exist for the basic block, the function returns null.
  96. RegionRegisterLiveness* Get(uint32_t bb_id) {
  97. RegionRegisterLivenessMap::iterator it = block_pressure_.find(bb_id);
  98. if (it != block_pressure_.end()) {
  99. return &it->second;
  100. }
  101. return nullptr;
  102. }
  103. // Returns liveness and register information for the basic block id |bb_id| or
  104. // create a new empty entry if no entry already existed.
  105. RegionRegisterLiveness* GetOrInsert(uint32_t bb_id) {
  106. return &block_pressure_[bb_id];
  107. }
  108. // Compute the register pressure for the |loop| and store the result into
  109. // |reg_pressure|. The live-in set corresponds to the live-in set of the
  110. // header block, the live-out set of the loop corresponds to the union of the
  111. // live-in sets of each exit basic block.
  112. void ComputeLoopRegisterPressure(const Loop& loop,
  113. RegionRegisterLiveness* reg_pressure) const;
  114. // Estimate the register pressure for the |l1| and |l2| as if they were making
  115. // one unique loop. The result is stored into |simulation_result|.
  116. void SimulateFusion(const Loop& l1, const Loop& l2,
  117. RegionRegisterLiveness* simulation_result) const;
  118. // Estimate the register pressure of |loop| after it has been fissioned
  119. // according to |moved_instructions| and |copied_instructions|. The function
  120. // assumes that the fission creates a new loop before |loop|, moves any
  121. // instructions present inside |moved_instructions| and copies any
  122. // instructions present inside |copied_instructions| into this new loop.
  123. // The set |loop1_sim_result| store the simulation result of the loop with the
  124. // moved instructions. The set |loop2_sim_result| store the simulation result
  125. // of the loop with the removed instructions.
  126. void SimulateFission(
  127. const Loop& loop,
  128. const std::unordered_set<Instruction*>& moved_instructions,
  129. const std::unordered_set<Instruction*>& copied_instructions,
  130. RegionRegisterLiveness* loop1_sim_result,
  131. RegionRegisterLiveness* loop2_sim_result) const;
  132. private:
  133. using RegionRegisterLivenessMap =
  134. std::unordered_map<uint32_t, RegionRegisterLiveness>;
  135. IRContext* context_;
  136. RegionRegisterLivenessMap block_pressure_;
  137. void Analyze(Function* f);
  138. };
  139. // Handles the register pressure of a function for different regions (function,
  140. // loop, basic block). It also contains some utilities to foresee the register
  141. // pressure following code transformations.
  142. class LivenessAnalysis {
  143. using LivenessAnalysisMap =
  144. std::unordered_map<const Function*, RegisterLiveness>;
  145. public:
  146. LivenessAnalysis(IRContext* context) : context_(context) {}
  147. // Computes the liveness analysis for the function |f| and cache the result.
  148. // If the analysis was performed for this function, then the cached analysis
  149. // is returned.
  150. const RegisterLiveness* Get(Function* f) {
  151. LivenessAnalysisMap::iterator it = analysis_cache_.find(f);
  152. if (it != analysis_cache_.end()) {
  153. return &it->second;
  154. }
  155. return &analysis_cache_.emplace(f, RegisterLiveness{context_, f})
  156. .first->second;
  157. }
  158. private:
  159. IRContext* context_;
  160. LivenessAnalysisMap analysis_cache_;
  161. };
  162. } // namespace opt
  163. } // namespace spvtools
  164. #endif // SOURCE_OPT_REGISTER_PRESSURE_H_