control_dependence.h 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. // Copyright (c) 2021 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_CONTROL_DEPENDENCE_H_
  15. #define SOURCE_OPT_CONTROL_DEPENDENCE_H_
  16. #include <algorithm>
  17. #include <cstdint>
  18. #include <functional>
  19. #include <ostream>
  20. #include <unordered_map>
  21. #include <vector>
  22. #include "source/opt/cfg.h"
  23. #include "source/opt/dominator_analysis.h"
  24. namespace spvtools {
  25. namespace opt {
  26. class ControlDependence {
  27. public:
  28. // The label of the source of this dependence, i.e. the block on which the
  29. // target is dependent on.
  30. // A |source_bb_id| of 0 represents an "entry" dependence, meaning that the
  31. // execution of |target_bb_id| is only dependent on entry to the function.
  32. uint32_t source_bb_id() const { return source_bb_id_; }
  33. // The label of the target of this dependence, i.e. the block which is
  34. // dependent on the source.
  35. uint32_t target_bb_id() const { return target_bb_id_; }
  36. // The label of the target of the *branch* for this dependence.
  37. // Equal to the ID of the entry block for entry dependences.
  38. //
  39. // For example, for the partial CFG pictured below:
  40. // 1 ---> 2 ---> 4 ---> 6
  41. // \ \ ^
  42. // \-> 3 \-> 5 -----/
  43. // Block 6 is control dependent on block 1, but this dependence comes from the
  44. // branch 1 -> 2, so in this case the branch target ID would be 2.
  45. uint32_t branch_target_bb_id() const { return branch_target_bb_id_; }
  46. // Create a direct control dependence from BB ID |source| to |target|.
  47. ControlDependence(uint32_t source, uint32_t target)
  48. : source_bb_id_(source),
  49. target_bb_id_(target),
  50. branch_target_bb_id_(target) {}
  51. // Create a control dependence from BB ID |source| to |target| through the
  52. // branch from |source| to |branch_target|.
  53. ControlDependence(uint32_t source, uint32_t target, uint32_t branch_target)
  54. : source_bb_id_(source),
  55. target_bb_id_(target),
  56. branch_target_bb_id_(branch_target) {}
  57. // Gets the ID of the conditional value for the branch corresponding to this
  58. // control dependence. This is the first input operand for both
  59. // OpConditionalBranch and OpSwitch.
  60. // Returns 0 for entry dependences.
  61. uint32_t GetConditionID(const CFG& cfg) const;
  62. bool operator==(const ControlDependence& other) const;
  63. bool operator!=(const ControlDependence& other) const {
  64. return !(*this == other);
  65. }
  66. // Comparison operators, ordered lexicographically. Total ordering.
  67. bool operator<(const ControlDependence& other) const;
  68. bool operator>(const ControlDependence& other) const { return other < *this; }
  69. bool operator<=(const ControlDependence& other) const {
  70. return !(*this > other);
  71. }
  72. bool operator>=(const ControlDependence& other) const {
  73. return !(*this < other);
  74. }
  75. private:
  76. uint32_t source_bb_id_;
  77. uint32_t target_bb_id_;
  78. uint32_t branch_target_bb_id_;
  79. };
  80. // Prints |dep| to |os| in a human-readable way. For example,
  81. // 1->2 (target_bb_id = branch_target_bb_id = 2)
  82. // 3->4 through 5 (target_bb_id = 4, branch_target_bb_id = 5)
  83. std::ostream& operator<<(std::ostream& os, const ControlDependence& dep);
  84. // Represents the control dependence graph. A basic block is control dependent
  85. // on another if the result of that block (e.g. the condition of a conditional
  86. // branch) influences whether it is executed or not. More formally, a block A is
  87. // control dependent on B iff:
  88. // 1. there exists a path from A to the exit node that does *not* go through B
  89. // (i.e., A does not postdominate B), and
  90. // 2. there exists a path B -> b_1 -> ... -> b_n -> A such that A post-dominates
  91. // all nodes b_i.
  92. class ControlDependenceAnalysis {
  93. public:
  94. // Map basic block labels to control dependencies/dependents.
  95. // Not guaranteed to be in any particular order.
  96. using ControlDependenceList = std::vector<ControlDependence>;
  97. using ControlDependenceListMap =
  98. std::unordered_map<uint32_t, ControlDependenceList>;
  99. // 0, the label number for the pseudo entry block.
  100. // All control dependences on the pseudo entry block are of type kEntry, and
  101. // vice versa.
  102. static constexpr uint32_t kPseudoEntryBlock = 0;
  103. // Build the control dependence graph for the given control flow graph |cfg|
  104. // and corresponding post-dominator analysis |pdom|.
  105. void ComputeControlDependenceGraph(const CFG& cfg,
  106. const PostDominatorAnalysis& pdom);
  107. // Get the list of the nodes that depend on a block.
  108. // Return value is not guaranteed to be in any particular order.
  109. const ControlDependenceList& GetDependenceTargets(uint32_t block) const {
  110. return forward_nodes_.at(block);
  111. }
  112. // Get the list of the nodes on which a block depends on.
  113. // Return value is not guaranteed to be in any particular order.
  114. const ControlDependenceList& GetDependenceSources(uint32_t block) const {
  115. return reverse_nodes_.at(block);
  116. }
  117. // Runs the function |f| on each block label in the CDG. If any iteration
  118. // returns false, immediately stops iteration and returns false. Otherwise
  119. // returns true. Nodes are iterated in some undefined order, including the
  120. // pseudo-entry block.
  121. bool WhileEachBlockLabel(std::function<bool(uint32_t)> f) const {
  122. for (const auto& entry : forward_nodes_) {
  123. if (!f(entry.first)) {
  124. return false;
  125. }
  126. }
  127. return true;
  128. }
  129. // Runs the function |f| on each block label in the CDG. Nodes are iterated in
  130. // some undefined order, including the pseudo-entry block.
  131. void ForEachBlockLabel(std::function<void(uint32_t)> f) const {
  132. WhileEachBlockLabel([&f](uint32_t label) {
  133. f(label);
  134. return true;
  135. });
  136. }
  137. // Returns true if the block |id| exists in the control dependence graph.
  138. // This can be false even if the block exists in the function when it is part
  139. // of an infinite loop, since it is not part of the post-dominator tree.
  140. bool HasBlock(uint32_t id) const { return forward_nodes_.count(id) > 0; }
  141. // Returns true if block |a| is dependent on block |b|.
  142. bool IsDependent(uint32_t a, uint32_t b) const {
  143. if (!HasBlock(a)) return false;
  144. // BBs tend to have more dependents (targets) than they are dependent on
  145. // (sources), so search sources.
  146. const ControlDependenceList& a_sources = GetDependenceSources(a);
  147. return std::find_if(a_sources.begin(), a_sources.end(),
  148. [b](const ControlDependence& dep) {
  149. return dep.source_bb_id() == b;
  150. }) != a_sources.end();
  151. }
  152. private:
  153. // Computes the post-dominance frontiers (i.e. the reverse CDG) for each node
  154. // in the post-dominator tree. Only modifies reverse_nodes_; forward_nodes_ is
  155. // not modified.
  156. void ComputePostDominanceFrontiers(const CFG& cfg,
  157. const PostDominatorAnalysis& pdom);
  158. // Computes the post-dominance frontier for a specific node |pdom_node| in the
  159. // post-dominator tree. Result is placed in reverse_nodes_[pdom_node.id()].
  160. void ComputePostDominanceFrontierForNode(const CFG& cfg,
  161. const PostDominatorAnalysis& pdom,
  162. uint32_t function_entry,
  163. const DominatorTreeNode& pdom_node);
  164. // Computes the forward graph (forward_nodes_) from the reverse graph
  165. // (reverse_nodes_).
  166. void ComputeForwardGraphFromReverse();
  167. ControlDependenceListMap forward_nodes_;
  168. ControlDependenceListMap reverse_nodes_;
  169. };
  170. } // namespace opt
  171. } // namespace spvtools
  172. #endif // SOURCE_OPT_CONTROL_DEPENDENCE_H_