• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===- Region.h - MLIR Region Class -----------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file defines the Region class.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef MLIR_IR_REGION_H
14 #define MLIR_IR_REGION_H
15 
16 #include "mlir/IR/Block.h"
17 
18 namespace mlir {
19 class TypeRange;
20 template <typename ValueRangeT>
21 class ValueTypeRange;
22 class BlockAndValueMapping;
23 
24 /// This class contains a list of basic blocks and a link to the parent
25 /// operation it is attached to.
26 class Region {
27 public:
28   Region() = default;
29   explicit Region(Operation *container);
30   ~Region();
31 
32   /// Return the context this region is inserted in.  The region must have a
33   /// valid parent container.
34   MLIRContext *getContext();
35 
36   /// Return a location for this region. This is the location attached to the
37   /// parent container. The region must have a valid parent container.
38   Location getLoc();
39 
40   //===--------------------------------------------------------------------===//
41   // Block list management
42   //===--------------------------------------------------------------------===//
43 
44   using BlockListType = llvm::iplist<Block>;
getBlocks()45   BlockListType &getBlocks() { return blocks; }
46 
47   // Iteration over the blocks in the region.
48   using iterator = BlockListType::iterator;
49   using reverse_iterator = BlockListType::reverse_iterator;
50 
begin()51   iterator begin() { return blocks.begin(); }
end()52   iterator end() { return blocks.end(); }
rbegin()53   reverse_iterator rbegin() { return blocks.rbegin(); }
rend()54   reverse_iterator rend() { return blocks.rend(); }
55 
empty()56   bool empty() { return blocks.empty(); }
push_back(Block * block)57   void push_back(Block *block) { blocks.push_back(block); }
push_front(Block * block)58   void push_front(Block *block) { blocks.push_front(block); }
59 
back()60   Block &back() { return blocks.back(); }
front()61   Block &front() { return blocks.front(); }
62 
63   /// getSublistAccess() - Returns pointer to member of region.
getSublistAccess(Block *)64   static BlockListType Region::*getSublistAccess(Block *) {
65     return &Region::blocks;
66   }
67 
68   //===--------------------------------------------------------------------===//
69   // Argument Handling
70   //===--------------------------------------------------------------------===//
71 
72   // This is the list of arguments to the block.
73   using BlockArgListType = MutableArrayRef<BlockArgument>;
getArguments()74   BlockArgListType getArguments() {
75     return empty() ? BlockArgListType() : front().getArguments();
76   }
77 
78   ValueTypeRange<BlockArgListType> getArgumentTypes();
79 
80   using args_iterator = BlockArgListType::iterator;
81   using reverse_args_iterator = BlockArgListType::reverse_iterator;
args_begin()82   args_iterator args_begin() { return getArguments().begin(); }
args_end()83   args_iterator args_end() { return getArguments().end(); }
args_rbegin()84   reverse_args_iterator args_rbegin() { return getArguments().rbegin(); }
args_rend()85   reverse_args_iterator args_rend() { return getArguments().rend(); }
86 
args_empty()87   bool args_empty() { return getArguments().empty(); }
88 
89   /// Add one value to the argument list.
addArgument(Type type)90   BlockArgument addArgument(Type type) { return front().addArgument(type); }
91 
92   /// Insert one value to the position in the argument list indicated by the
93   /// given iterator. The existing arguments are shifted. The block is expected
94   /// not to have predecessors.
insertArgument(args_iterator it,Type type)95   BlockArgument insertArgument(args_iterator it, Type type) {
96     return front().insertArgument(it, type);
97   }
98 
99   /// Add one argument to the argument list for each type specified in the list.
100   iterator_range<args_iterator> addArguments(TypeRange types);
101 
102   /// Add one value to the argument list at the specified position.
insertArgument(unsigned index,Type type)103   BlockArgument insertArgument(unsigned index, Type type) {
104     return front().insertArgument(index, type);
105   }
106 
107   /// Erase the argument at 'index' and remove it from the argument list.
eraseArgument(unsigned index)108   void eraseArgument(unsigned index) { front().eraseArgument(index); }
109 
getNumArguments()110   unsigned getNumArguments() { return getArguments().size(); }
getArgument(unsigned i)111   BlockArgument getArgument(unsigned i) { return getArguments()[i]; }
112 
113   //===--------------------------------------------------------------------===//
114   // Operation list utilities
115   //===--------------------------------------------------------------------===//
116 
117   /// This class provides iteration over the held operations of blocks directly
118   /// within a region.
119   class OpIterator final
120       : public llvm::iterator_facade_base<OpIterator, std::forward_iterator_tag,
121                                           Operation> {
122   public:
123     /// Initialize OpIterator for a region, specify `end` to return the iterator
124     /// to last operation.
125     explicit OpIterator(Region *region, bool end = false);
126 
127     using llvm::iterator_facade_base<OpIterator, std::forward_iterator_tag,
128                                      Operation>::operator++;
129     OpIterator &operator++();
130     Operation *operator->() const { return &*operation; }
131     Operation &operator*() const { return *operation; }
132 
133     /// Compare this iterator with another.
134     bool operator==(const OpIterator &rhs) const {
135       return operation == rhs.operation;
136     }
137     bool operator!=(const OpIterator &rhs) const { return !(*this == rhs); }
138 
139   private:
140     void skipOverBlocksWithNoOps();
141 
142     /// The region whose operations are being iterated over.
143     Region *region;
144     /// The block of 'region' whose operations are being iterated over.
145     Region::iterator block;
146     /// The current operation within 'block'.
147     Block::iterator operation;
148   };
149 
150   /// This class provides iteration over the held operations of a region for a
151   /// specific operation type.
152   template <typename OpT>
153   using op_iterator = detail::op_iterator<OpT, OpIterator>;
154 
155   /// Return iterators that walk the operations nested directly within this
156   /// region.
op_begin()157   OpIterator op_begin() { return OpIterator(this); }
op_end()158   OpIterator op_end() { return OpIterator(this, /*end=*/true); }
getOps()159   iterator_range<OpIterator> getOps() { return {op_begin(), op_end()}; }
160 
161   /// Return iterators that walk operations of type 'T' nested directly within
162   /// this region.
op_begin()163   template <typename OpT> op_iterator<OpT> op_begin() {
164     return detail::op_filter_iterator<OpT, OpIterator>(op_begin(), op_end());
165   }
op_end()166   template <typename OpT> op_iterator<OpT> op_end() {
167     return detail::op_filter_iterator<OpT, OpIterator>(op_end(), op_end());
168   }
getOps()169   template <typename OpT> iterator_range<op_iterator<OpT>> getOps() {
170     auto endIt = op_end();
171     return {detail::op_filter_iterator<OpT, OpIterator>(op_begin(), endIt),
172             detail::op_filter_iterator<OpT, OpIterator>(endIt, endIt)};
173   }
174 
175   //===--------------------------------------------------------------------===//
176   // Misc. utilities
177   //===--------------------------------------------------------------------===//
178 
179   /// Return the region containing this region or nullptr if the region is
180   /// attached to a top-level operation.
181   Region *getParentRegion();
182 
183   /// Return the parent operation this region is attached to.
184   Operation *getParentOp();
185 
186   /// Find the first parent operation of the given type, or nullptr if there is
187   /// no ancestor operation.
getParentOfType()188   template <typename ParentT> ParentT getParentOfType() {
189     auto *region = this;
190     do {
191       if (auto parent = dyn_cast_or_null<ParentT>(region->container))
192         return parent;
193     } while ((region = region->getParentRegion()));
194     return ParentT();
195   }
196 
197   /// Return the number of this region in the parent operation.
198   unsigned getRegionNumber();
199 
200   /// Return true if this region is a proper ancestor of the `other` region.
201   bool isProperAncestor(Region *other);
202 
203   /// Return true if this region is ancestor of the `other` region.  A region
204   /// is considered as its own ancestor, use `isProperAncestor` to avoid this.
isAncestor(Region * other)205   bool isAncestor(Region *other) {
206     return this == other || isProperAncestor(other);
207   }
208 
209   /// Clone the internal blocks from this region into dest. Any
210   /// cloned blocks are appended to the back of dest. If the mapper
211   /// contains entries for block arguments, these arguments are not included
212   /// in the respective cloned block.
213   void cloneInto(Region *dest, BlockAndValueMapping &mapper);
214   /// Clone this region into 'dest' before the given position in 'dest'.
215   void cloneInto(Region *dest, Region::iterator destPos,
216                  BlockAndValueMapping &mapper);
217 
218   /// Takes body of another region (that region will have no body after this
219   /// operation completes).  The current body of this region is cleared.
takeBody(Region & other)220   void takeBody(Region &other) {
221     blocks.clear();
222     blocks.splice(blocks.end(), other.getBlocks());
223   }
224 
225   /// Check that this does not use any value defined outside it.
226   /// Emit errors if `noteLoc` is provided; this location is used to point
227   /// to the operation containing the region, the actual error is reported at
228   /// the operation with an offending use.
229   bool isIsolatedFromAbove(Optional<Location> noteLoc = llvm::None);
230 
231   /// Returns 'block' if 'block' lies in this region, or otherwise finds the
232   /// ancestor of 'block' that lies in this region. Returns nullptr if the
233   /// latter fails.
234   Block *findAncestorBlockInRegion(Block &block);
235 
236   /// Drop all operand uses from operations within this region, which is
237   /// an essential step in breaking cyclic dependences between references when
238   /// they are to be deleted.
239   void dropAllReferences();
240 
241   //===--------------------------------------------------------------------===//
242   // Operation Walkers
243   //===--------------------------------------------------------------------===//
244 
245   /// Walk the operations in this region in postorder, calling the callback for
246   /// each operation. This method is invoked for void-returning callbacks.
247   /// See Operation::walk for more details.
248   template <typename FnT, typename RetT = detail::walkResultType<FnT>>
249   typename std::enable_if<std::is_same<RetT, void>::value, RetT>::type
walk(FnT && callback)250   walk(FnT &&callback) {
251     for (auto &block : *this)
252       block.walk(callback);
253   }
254 
255   /// Walk the operations in this region in postorder, calling the callback for
256   /// each operation. This method is invoked for interruptible callbacks.
257   /// See Operation::walk for more details.
258   template <typename FnT, typename RetT = detail::walkResultType<FnT>>
259   typename std::enable_if<std::is_same<RetT, WalkResult>::value, RetT>::type
walk(FnT && callback)260   walk(FnT &&callback) {
261     for (auto &block : *this)
262       if (block.walk(callback).wasInterrupted())
263         return WalkResult::interrupt();
264     return WalkResult::advance();
265   }
266 
267   //===--------------------------------------------------------------------===//
268   // CFG view utilities
269   //===--------------------------------------------------------------------===//
270 
271   /// Displays the CFG in a window. This is for use from the debugger and
272   /// depends on Graphviz to generate the graph.
273   /// This function is defined in ViewRegionGraph and only works with that
274   /// target linked.
275   void viewGraph(const Twine &regionName);
276   void viewGraph();
277 
278 private:
279   BlockListType blocks;
280 
281   /// This is the object we are part of.
282   Operation *container = nullptr;
283 };
284 
285 /// This class provides an abstraction over the different types of ranges over
286 /// Regions. In many cases, this prevents the need to explicitly materialize a
287 /// SmallVector/std::vector. This class should be used in places that are not
288 /// suitable for a more derived type (e.g. ArrayRef) or a template range
289 /// parameter.
290 class RegionRange
291     : public llvm::detail::indexed_accessor_range_base<
292           RegionRange, PointerUnion<Region *, const std::unique_ptr<Region> *>,
293           Region *, Region *, Region *> {
294   /// The type representing the owner of this range. This is either a list of
295   /// values, operands, or results.
296   using OwnerT = PointerUnion<Region *, const std::unique_ptr<Region> *>;
297 
298 public:
299   using RangeBaseT::RangeBaseT;
300 
301   RegionRange(MutableArrayRef<Region> regions = llvm::None);
302 
303   template <typename Arg,
304             typename = typename std::enable_if_t<std::is_constructible<
305                 ArrayRef<std::unique_ptr<Region>>, Arg>::value>>
RegionRange(Arg && arg)306   RegionRange(Arg &&arg)
307       : RegionRange(ArrayRef<std::unique_ptr<Region>>(std::forward<Arg>(arg))) {
308   }
309   RegionRange(ArrayRef<std::unique_ptr<Region>> regions);
310 
311 private:
312   /// See `llvm::detail::indexed_accessor_range_base` for details.
313   static OwnerT offset_base(const OwnerT &owner, ptrdiff_t index);
314   /// See `llvm::detail::indexed_accessor_range_base` for details.
315   static Region *dereference_iterator(const OwnerT &owner, ptrdiff_t index);
316 
317   /// Allow access to `offset_base` and `dereference_iterator`.
318   friend RangeBaseT;
319 };
320 
321 } // end namespace mlir
322 
323 #endif // MLIR_IR_REGION_H
324