RegionIterator.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  1. #pragma once
  2. #ifdef __GNUC__
  3. #pragma GCC diagnostic push
  4. #pragma GCC diagnostic ignored "-Wunused-parameter"
  5. #endif
  6. //===- RegionIterator.h - Iterators to iteratate over Regions ---*- C++ -*-===//
  7. //
  8. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  9. // See https://llvm.org/LICENSE.txt for license information.
  10. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  11. //
  12. //===----------------------------------------------------------------------===//
  13. // This file defines the iterators to iterate over the elements of a Region.
  14. //===----------------------------------------------------------------------===//
  15. #ifndef LLVM_ANALYSIS_REGIONITERATOR_H
  16. #define LLVM_ANALYSIS_REGIONITERATOR_H
  17. #include "llvm/ADT/DepthFirstIterator.h"
  18. #include "llvm/ADT/GraphTraits.h"
  19. #include "llvm/ADT/PointerIntPair.h"
  20. #include "llvm/Analysis/RegionInfo.h"
  21. #include "llvm/IR/CFG.h"
  22. #include <cassert>
  23. #include <iterator>
  24. #include <type_traits>
  25. namespace llvm {
  26. class BasicBlock;
  27. //===----------------------------------------------------------------------===//
  28. /// Hierarchical RegionNode successor iterator.
  29. ///
  30. /// This iterator iterates over all successors of a RegionNode.
  31. ///
  32. /// For a BasicBlock RegionNode it skips all BasicBlocks that are not part of
  33. /// the parent Region. Furthermore for BasicBlocks that start a subregion, a
  34. /// RegionNode representing the subregion is returned.
  35. ///
  36. /// For a subregion RegionNode there is just one successor. The RegionNode
  37. /// representing the exit of the subregion.
  38. template <class NodeRef, class BlockT, class RegionT> class RNSuccIterator {
  39. public:
  40. using iterator_category = std::forward_iterator_tag;
  41. using value_type = NodeRef;
  42. using difference_type = std::ptrdiff_t;
  43. using pointer = value_type *;
  44. using reference = value_type &;
  45. private:
  46. using BlockTraits = GraphTraits<BlockT *>;
  47. using SuccIterTy = typename BlockTraits::ChildIteratorType;
  48. // The iterator works in two modes, bb mode or region mode.
  49. enum ItMode {
  50. // In BB mode it returns all successors of this BasicBlock as its
  51. // successors.
  52. ItBB,
  53. // In region mode there is only one successor, thats the regionnode mapping
  54. // to the exit block of the regionnode
  55. ItRgBegin, // At the beginning of the regionnode successor.
  56. ItRgEnd // At the end of the regionnode successor.
  57. };
  58. static_assert(std::is_pointer<NodeRef>::value,
  59. "FIXME: Currently RNSuccIterator only supports NodeRef as "
  60. "pointers due to the use of pointer-specific data structures "
  61. "(e.g. PointerIntPair and SmallPtrSet) internally. Generalize "
  62. "it to support non-pointer types");
  63. // Use two bit to represent the mode iterator.
  64. PointerIntPair<NodeRef, 2, ItMode> Node;
  65. // The block successor iterator.
  66. SuccIterTy BItor;
  67. // advanceRegionSucc - A region node has only one successor. It reaches end
  68. // once we advance it.
  69. void advanceRegionSucc() {
  70. assert(Node.getInt() == ItRgBegin && "Cannot advance region successor!");
  71. Node.setInt(ItRgEnd);
  72. }
  73. NodeRef getNode() const { return Node.getPointer(); }
  74. // isRegionMode - Is the current iterator in region mode?
  75. bool isRegionMode() const { return Node.getInt() != ItBB; }
  76. // Get the immediate successor. This function may return a Basic Block
  77. // RegionNode or a subregion RegionNode.
  78. NodeRef getISucc(BlockT *BB) const {
  79. NodeRef succ;
  80. succ = getNode()->getParent()->getNode(BB);
  81. assert(succ && "BB not in Region or entered subregion!");
  82. return succ;
  83. }
  84. // getRegionSucc - Return the successor basic block of a SubRegion RegionNode.
  85. inline BlockT* getRegionSucc() const {
  86. assert(Node.getInt() == ItRgBegin && "Cannot get the region successor!");
  87. return getNode()->template getNodeAs<RegionT>()->getExit();
  88. }
  89. // isExit - Is this the exit BB of the Region?
  90. inline bool isExit(BlockT* BB) const {
  91. return getNode()->getParent()->getExit() == BB;
  92. }
  93. public:
  94. using Self = RNSuccIterator<NodeRef, BlockT, RegionT>;
  95. /// Create begin iterator of a RegionNode.
  96. inline RNSuccIterator(NodeRef node)
  97. : Node(node, node->isSubRegion() ? ItRgBegin : ItBB),
  98. BItor(BlockTraits::child_begin(node->getEntry())) {
  99. // Skip the exit block
  100. if (!isRegionMode())
  101. while (BlockTraits::child_end(node->getEntry()) != BItor && isExit(*BItor))
  102. ++BItor;
  103. if (isRegionMode() && isExit(getRegionSucc()))
  104. advanceRegionSucc();
  105. }
  106. /// Create an end iterator.
  107. inline RNSuccIterator(NodeRef node, bool)
  108. : Node(node, node->isSubRegion() ? ItRgEnd : ItBB),
  109. BItor(BlockTraits::child_end(node->getEntry())) {}
  110. inline bool operator==(const Self& x) const {
  111. assert(isRegionMode() == x.isRegionMode() && "Broken iterator!");
  112. if (isRegionMode())
  113. return Node.getInt() == x.Node.getInt();
  114. else
  115. return BItor == x.BItor;
  116. }
  117. inline bool operator!=(const Self& x) const { return !operator==(x); }
  118. inline value_type operator*() const {
  119. BlockT *BB = isRegionMode() ? getRegionSucc() : *BItor;
  120. assert(!isExit(BB) && "Iterator out of range!");
  121. return getISucc(BB);
  122. }
  123. inline Self& operator++() {
  124. if(isRegionMode()) {
  125. // The Region only has 1 successor.
  126. advanceRegionSucc();
  127. } else {
  128. // Skip the exit.
  129. do
  130. ++BItor;
  131. while (BItor != BlockTraits::child_end(getNode()->getEntry())
  132. && isExit(*BItor));
  133. }
  134. return *this;
  135. }
  136. inline Self operator++(int) {
  137. Self tmp = *this;
  138. ++*this;
  139. return tmp;
  140. }
  141. };
  142. //===----------------------------------------------------------------------===//
  143. /// Flat RegionNode iterator.
  144. ///
  145. /// The Flat Region iterator will iterate over all BasicBlock RegionNodes that
  146. /// are contained in the Region and its subregions. This is close to a virtual
  147. /// control flow graph of the Region.
  148. template <class NodeRef, class BlockT, class RegionT>
  149. class RNSuccIterator<FlatIt<NodeRef>, BlockT, RegionT> {
  150. using BlockTraits = GraphTraits<BlockT *>;
  151. using SuccIterTy = typename BlockTraits::ChildIteratorType;
  152. NodeRef Node;
  153. SuccIterTy Itor;
  154. public:
  155. using iterator_category = std::forward_iterator_tag;
  156. using value_type = NodeRef;
  157. using difference_type = std::ptrdiff_t;
  158. using pointer = value_type *;
  159. using reference = value_type &;
  160. using Self = RNSuccIterator<FlatIt<NodeRef>, BlockT, RegionT>;
  161. /// Create the iterator from a RegionNode.
  162. ///
  163. /// Note that the incoming node must be a bb node, otherwise it will trigger
  164. /// an assertion when we try to get a BasicBlock.
  165. inline RNSuccIterator(NodeRef node)
  166. : Node(node), Itor(BlockTraits::child_begin(node->getEntry())) {
  167. assert(!Node->isSubRegion() &&
  168. "Subregion node not allowed in flat iterating mode!");
  169. assert(Node->getParent() && "A BB node must have a parent!");
  170. // Skip the exit block of the iterating region.
  171. while (BlockTraits::child_end(Node->getEntry()) != Itor &&
  172. Node->getParent()->getExit() == *Itor)
  173. ++Itor;
  174. }
  175. /// Create an end iterator
  176. inline RNSuccIterator(NodeRef node, bool)
  177. : Node(node), Itor(BlockTraits::child_end(node->getEntry())) {
  178. assert(!Node->isSubRegion() &&
  179. "Subregion node not allowed in flat iterating mode!");
  180. }
  181. inline bool operator==(const Self& x) const {
  182. assert(Node->getParent() == x.Node->getParent()
  183. && "Cannot compare iterators of different regions!");
  184. return Itor == x.Itor && Node == x.Node;
  185. }
  186. inline bool operator!=(const Self& x) const { return !operator==(x); }
  187. inline value_type operator*() const {
  188. BlockT *BB = *Itor;
  189. // Get the iterating region.
  190. RegionT *Parent = Node->getParent();
  191. // The only case that the successor reaches out of the region is it reaches
  192. // the exit of the region.
  193. assert(Parent->getExit() != BB && "iterator out of range!");
  194. return Parent->getBBNode(BB);
  195. }
  196. inline Self& operator++() {
  197. // Skip the exit block of the iterating region.
  198. do
  199. ++Itor;
  200. while (Itor != succ_end(Node->getEntry())
  201. && Node->getParent()->getExit() == *Itor);
  202. return *this;
  203. }
  204. inline Self operator++(int) {
  205. Self tmp = *this;
  206. ++*this;
  207. return tmp;
  208. }
  209. };
  210. template <class NodeRef, class BlockT, class RegionT>
  211. inline RNSuccIterator<NodeRef, BlockT, RegionT> succ_begin(NodeRef Node) {
  212. return RNSuccIterator<NodeRef, BlockT, RegionT>(Node);
  213. }
  214. template <class NodeRef, class BlockT, class RegionT>
  215. inline RNSuccIterator<NodeRef, BlockT, RegionT> succ_end(NodeRef Node) {
  216. return RNSuccIterator<NodeRef, BlockT, RegionT>(Node, true);
  217. }
  218. //===--------------------------------------------------------------------===//
  219. // RegionNode GraphTraits specialization so the bbs in the region can be
  220. // iterate by generic graph iterators.
  221. //
  222. // NodeT can either be region node or const region node, otherwise child_begin
  223. // and child_end fail.
  224. #define RegionNodeGraphTraits(NodeT, BlockT, RegionT) \
  225. template <> struct GraphTraits<NodeT *> { \
  226. using NodeRef = NodeT *; \
  227. using ChildIteratorType = RNSuccIterator<NodeRef, BlockT, RegionT>; \
  228. static NodeRef getEntryNode(NodeRef N) { return N; } \
  229. static inline ChildIteratorType child_begin(NodeRef N) { \
  230. return RNSuccIterator<NodeRef, BlockT, RegionT>(N); \
  231. } \
  232. static inline ChildIteratorType child_end(NodeRef N) { \
  233. return RNSuccIterator<NodeRef, BlockT, RegionT>(N, true); \
  234. } \
  235. }; \
  236. template <> struct GraphTraits<FlatIt<NodeT *>> { \
  237. using NodeRef = NodeT *; \
  238. using ChildIteratorType = \
  239. RNSuccIterator<FlatIt<NodeRef>, BlockT, RegionT>; \
  240. static NodeRef getEntryNode(NodeRef N) { return N; } \
  241. static inline ChildIteratorType child_begin(NodeRef N) { \
  242. return RNSuccIterator<FlatIt<NodeRef>, BlockT, RegionT>(N); \
  243. } \
  244. static inline ChildIteratorType child_end(NodeRef N) { \
  245. return RNSuccIterator<FlatIt<NodeRef>, BlockT, RegionT>(N, true); \
  246. } \
  247. }
  248. #define RegionGraphTraits(RegionT, NodeT) \
  249. template <> struct GraphTraits<RegionT *> : public GraphTraits<NodeT *> { \
  250. using nodes_iterator = df_iterator<NodeRef>; \
  251. static NodeRef getEntryNode(RegionT *R) { \
  252. return R->getNode(R->getEntry()); \
  253. } \
  254. static nodes_iterator nodes_begin(RegionT *R) { \
  255. return nodes_iterator::begin(getEntryNode(R)); \
  256. } \
  257. static nodes_iterator nodes_end(RegionT *R) { \
  258. return nodes_iterator::end(getEntryNode(R)); \
  259. } \
  260. }; \
  261. template <> \
  262. struct GraphTraits<FlatIt<RegionT *>> \
  263. : public GraphTraits<FlatIt<NodeT *>> { \
  264. using nodes_iterator = \
  265. df_iterator<NodeRef, df_iterator_default_set<NodeRef>, false, \
  266. GraphTraits<FlatIt<NodeRef>>>; \
  267. static NodeRef getEntryNode(RegionT *R) { \
  268. return R->getBBNode(R->getEntry()); \
  269. } \
  270. static nodes_iterator nodes_begin(RegionT *R) { \
  271. return nodes_iterator::begin(getEntryNode(R)); \
  272. } \
  273. static nodes_iterator nodes_end(RegionT *R) { \
  274. return nodes_iterator::end(getEntryNode(R)); \
  275. } \
  276. }
  277. RegionNodeGraphTraits(RegionNode, BasicBlock, Region);
  278. RegionNodeGraphTraits(const RegionNode, BasicBlock, Region);
  279. RegionGraphTraits(Region, RegionNode);
  280. RegionGraphTraits(const Region, const RegionNode);
  281. template <> struct GraphTraits<RegionInfo*>
  282. : public GraphTraits<FlatIt<RegionNode*>> {
  283. using nodes_iterator =
  284. df_iterator<NodeRef, df_iterator_default_set<NodeRef>, false,
  285. GraphTraits<FlatIt<NodeRef>>>;
  286. static NodeRef getEntryNode(RegionInfo *RI) {
  287. return GraphTraits<FlatIt<Region*>>::getEntryNode(RI->getTopLevelRegion());
  288. }
  289. static nodes_iterator nodes_begin(RegionInfo* RI) {
  290. return nodes_iterator::begin(getEntryNode(RI));
  291. }
  292. static nodes_iterator nodes_end(RegionInfo *RI) {
  293. return nodes_iterator::end(getEntryNode(RI));
  294. }
  295. };
  296. template <> struct GraphTraits<RegionInfoPass*>
  297. : public GraphTraits<RegionInfo *> {
  298. using nodes_iterator =
  299. df_iterator<NodeRef, df_iterator_default_set<NodeRef>, false,
  300. GraphTraits<FlatIt<NodeRef>>>;
  301. static NodeRef getEntryNode(RegionInfoPass *RI) {
  302. return GraphTraits<RegionInfo*>::getEntryNode(&RI->getRegionInfo());
  303. }
  304. static nodes_iterator nodes_begin(RegionInfoPass* RI) {
  305. return GraphTraits<RegionInfo*>::nodes_begin(&RI->getRegionInfo());
  306. }
  307. static nodes_iterator nodes_end(RegionInfoPass *RI) {
  308. return GraphTraits<RegionInfo*>::nodes_end(&RI->getRegionInfo());
  309. }
  310. };
  311. } // end namespace llvm
  312. #endif // LLVM_ANALYSIS_REGIONITERATOR_H
  313. #ifdef __GNUC__
  314. #pragma GCC diagnostic pop
  315. #endif