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; }
emplaceBlock()46   Block &emplaceBlock() {
47     push_back(new Block);
48     return back();
49   }
50 
51   // Iteration over the blocks in the region.
52   using iterator = BlockListType::iterator;
53   using reverse_iterator = BlockListType::reverse_iterator;
54 
begin()55   iterator begin() { return blocks.begin(); }
end()56   iterator end() { return blocks.end(); }
rbegin()57   reverse_iterator rbegin() { return blocks.rbegin(); }
rend()58   reverse_iterator rend() { return blocks.rend(); }
59 
empty()60   bool empty() { return blocks.empty(); }
push_back(Block * block)61   void push_back(Block *block) { blocks.push_back(block); }
push_front(Block * block)62   void push_front(Block *block) { blocks.push_front(block); }
63 
back()64   Block &back() { return blocks.back(); }
front()65   Block &front() { return blocks.front(); }
66 
67   /// Return true if this region has exactly one block.
hasOneBlock()68   bool hasOneBlock() { return !empty() && std::next(begin()) == end(); }
69 
70   /// getSublistAccess() - Returns pointer to member of region.
getSublistAccess(Block *)71   static BlockListType Region::*getSublistAccess(Block *) {
72     return &Region::blocks;
73   }
74 
75   //===--------------------------------------------------------------------===//
76   // Argument Handling
77   //===--------------------------------------------------------------------===//
78 
79   // This is the list of arguments to the block.
80   using BlockArgListType = MutableArrayRef<BlockArgument>;
getArguments()81   BlockArgListType getArguments() {
82     return empty() ? BlockArgListType() : front().getArguments();
83   }
84 
85   /// Returns the argument types of the first block within the region.
86   ValueTypeRange<BlockArgListType> getArgumentTypes();
87 
88   using args_iterator = BlockArgListType::iterator;
89   using reverse_args_iterator = BlockArgListType::reverse_iterator;
args_begin()90   args_iterator args_begin() { return getArguments().begin(); }
args_end()91   args_iterator args_end() { return getArguments().end(); }
args_rbegin()92   reverse_args_iterator args_rbegin() { return getArguments().rbegin(); }
args_rend()93   reverse_args_iterator args_rend() { return getArguments().rend(); }
94 
args_empty()95   bool args_empty() { return getArguments().empty(); }
96 
97   /// Add one value to the argument list.
addArgument(Type type,Location loc)98   BlockArgument addArgument(Type type, Location loc) {
99     return front().addArgument(type, loc);
100   }
101 
102   /// Insert one value to the position in the argument list indicated by the
103   /// given iterator. The existing arguments are shifted. The block is expected
104   /// not to have predecessors.
insertArgument(args_iterator it,Type type,Location loc)105   BlockArgument insertArgument(args_iterator it, Type type, Location loc) {
106     return front().insertArgument(it, type, loc);
107   }
108 
109   /// Add one argument to the argument list for each type specified in the list.
110   /// `locs` contains the locations for each of the new arguments, and must be
111   /// of equal size to `types`.
112   iterator_range<args_iterator> addArguments(TypeRange types,
113                                              ArrayRef<Location> locs);
114 
115   /// Add one value to the argument list at the specified position.
insertArgument(unsigned index,Type type,Location loc)116   BlockArgument insertArgument(unsigned index, Type type, Location loc) {
117     return front().insertArgument(index, type, loc);
118   }
119 
120   /// Erase the argument at 'index' and remove it from the argument list.
eraseArgument(unsigned index)121   void eraseArgument(unsigned index) { front().eraseArgument(index); }
122 
getNumArguments()123   unsigned getNumArguments() { return getArguments().size(); }
getArgument(unsigned i)124   BlockArgument getArgument(unsigned i) { return getArguments()[i]; }
125 
126   //===--------------------------------------------------------------------===//
127   // Operation list utilities
128   //===--------------------------------------------------------------------===//
129 
130   /// This class provides iteration over the held operations of blocks directly
131   /// within a region.
132   class OpIterator final
133       : public llvm::iterator_facade_base<OpIterator, std::forward_iterator_tag,
134                                           Operation> {
135   public:
136     /// Initialize OpIterator for a region, specify `end` to return the iterator
137     /// to last operation.
138     explicit OpIterator(Region *region, bool end = false);
139 
140     using llvm::iterator_facade_base<OpIterator, std::forward_iterator_tag,
141                                      Operation>::operator++;
142     OpIterator &operator++();
143     Operation *operator->() const { return &*operation; }
144     Operation &operator*() const { return *operation; }
145 
146     /// Compare this iterator with another.
147     bool operator==(const OpIterator &rhs) const {
148       return operation == rhs.operation;
149     }
150     bool operator!=(const OpIterator &rhs) const { return !(*this == rhs); }
151 
152   private:
153     void skipOverBlocksWithNoOps();
154 
155     /// The region whose operations are being iterated over.
156     Region *region;
157     /// The block of 'region' whose operations are being iterated over.
158     Region::iterator block;
159     /// The current operation within 'block'.
160     Block::iterator operation;
161   };
162 
163   /// This class provides iteration over the held operations of a region for a
164   /// specific operation type.
165   template <typename OpT>
166   using op_iterator = detail::op_iterator<OpT, OpIterator>;
167 
168   /// Return iterators that walk the operations nested directly within this
169   /// region.
op_begin()170   OpIterator op_begin() { return OpIterator(this); }
op_end()171   OpIterator op_end() { return OpIterator(this, /*end=*/true); }
getOps()172   iterator_range<OpIterator> getOps() { return {op_begin(), op_end()}; }
173 
174   /// Return iterators that walk operations of type 'T' nested directly within
175   /// this region.
176   template <typename OpT>
op_begin()177   op_iterator<OpT> op_begin() {
178     return detail::op_filter_iterator<OpT, OpIterator>(op_begin(), op_end());
179   }
180   template <typename OpT>
op_end()181   op_iterator<OpT> op_end() {
182     return detail::op_filter_iterator<OpT, OpIterator>(op_end(), op_end());
183   }
184   template <typename OpT>
getOps()185   iterator_range<op_iterator<OpT>> getOps() {
186     auto endIt = op_end();
187     return {detail::op_filter_iterator<OpT, OpIterator>(op_begin(), endIt),
188             detail::op_filter_iterator<OpT, OpIterator>(endIt, endIt)};
189   }
190 
191   //===--------------------------------------------------------------------===//
192   // Misc. utilities
193   //===--------------------------------------------------------------------===//
194 
195   /// Return the region containing this region or nullptr if the region is
196   /// attached to a top-level operation.
197   Region *getParentRegion();
198 
199   /// Return the parent operation this region is attached to.
getParentOp()200   Operation *getParentOp() { return container; }
201 
202   /// Find the first parent operation of the given type, or nullptr if there is
203   /// no ancestor operation.
204   template <typename ParentT>
getParentOfType()205   ParentT getParentOfType() {
206     auto *region = this;
207     do {
208       if (auto parent = dyn_cast_or_null<ParentT>(region->container))
209         return parent;
210     } while ((region = region->getParentRegion()));
211     return ParentT();
212   }
213 
214   /// Return the number of this region in the parent operation.
215   unsigned getRegionNumber();
216 
217   /// Return true if this region is a proper ancestor of the `other` region.
218   bool isProperAncestor(Region *other);
219 
220   /// Return true if this region is ancestor of the `other` region.  A region
221   /// is considered as its own ancestor, use `isProperAncestor` to avoid this.
isAncestor(Region * other)222   bool isAncestor(Region *other) {
223     return this == other || isProperAncestor(other);
224   }
225 
226   /// Clone the internal blocks from this region into dest. Any
227   /// cloned blocks are appended to the back of dest. If the mapper
228   /// contains entries for block arguments, these arguments are not included
229   /// in the respective cloned block.
230   ///
231   /// Calling this method from multiple threads is generally safe if through the
232   /// process of cloning, no new uses of 'Value's from outside the region are
233   /// created. Using the mapper, it is possible to avoid adding uses to outside
234   /// operands by remapping them to 'Value's owned by the caller thread.
235   void cloneInto(Region *dest, BlockAndValueMapping &mapper);
236   /// Clone this region into 'dest' before the given position in 'dest'.
237   void cloneInto(Region *dest, Region::iterator destPos,
238                  BlockAndValueMapping &mapper);
239 
240   /// Takes body of another region (that region will have no body after this
241   /// operation completes).  The current body of this region is cleared.
takeBody(Region & other)242   void takeBody(Region &other) {
243     dropAllReferences();
244     blocks.clear();
245     blocks.splice(blocks.end(), other.getBlocks());
246   }
247 
248   /// Returns 'block' if 'block' lies in this region, or otherwise finds the
249   /// ancestor of 'block' that lies in this region. Returns nullptr if the
250   /// latter fails.
251   Block *findAncestorBlockInRegion(Block &block);
252 
253   /// Returns 'op' if 'op' lies in this region, or otherwise finds the
254   /// ancestor of 'op' that lies in this region. Returns nullptr if the
255   /// latter fails.
256   Operation *findAncestorOpInRegion(Operation &op);
257 
258   /// Drop all operand uses from operations within this region, which is
259   /// an essential step in breaking cyclic dependences between references when
260   /// they are to be deleted.
261   void dropAllReferences();
262 
263   //===--------------------------------------------------------------------===//
264   // Operation Walkers
265   //===--------------------------------------------------------------------===//
266 
267   /// Walk the operations in this region. The callback method is called for each
268   /// nested region, block or operation, depending on the callback provided.
269   /// Regions, blocks and operations at the same nesting level are visited in
270   /// lexicographical order. The walk order for enclosing regions, blocks and
271   /// operations with respect to their nested ones is specified by 'Order'
272   /// (post-order by default). This method is invoked for void-returning
273   /// callbacks. A callback on a block or operation is allowed to erase that
274   /// block or operation only if the walk is in post-order. See non-void method
275   /// for pre-order erasure. See Operation::walk for more details.
276   template <WalkOrder Order = WalkOrder::PostOrder, typename FnT,
277             typename RetT = detail::walkResultType<FnT>>
278   typename std::enable_if<std::is_same<RetT, void>::value, RetT>::type
walk(FnT && callback)279   walk(FnT &&callback) {
280     for (auto &block : *this)
281       block.walk<Order>(callback);
282   }
283 
284   /// Walk the operations in this region. The callback method is called for each
285   /// nested region, block or operation, depending on the callback provided.
286   /// Regions, blocks and operations at the same nesting level are visited in
287   /// lexicographical order. The walk order for enclosing regions, blocks and
288   /// operations with respect to their nested ones is specified by 'Order'
289   /// (post-order by default). This method is invoked for skippable or
290   /// interruptible callbacks. A callback on a block or operation is allowed to
291   /// erase that block or operation if either:
292   ///   * the walk is in post-order,
293   ///   * or the walk is in pre-order and the walk is skipped after the erasure.
294   /// See Operation::walk for more details.
295   template <WalkOrder Order = WalkOrder::PostOrder, typename FnT,
296             typename RetT = detail::walkResultType<FnT>>
297   typename std::enable_if<std::is_same<RetT, WalkResult>::value, RetT>::type
walk(FnT && callback)298   walk(FnT &&callback) {
299     for (auto &block : *this)
300       if (block.walk<Order>(callback).wasInterrupted())
301         return WalkResult::interrupt();
302     return WalkResult::advance();
303   }
304 
305   //===--------------------------------------------------------------------===//
306   // CFG view utilities
307   //===--------------------------------------------------------------------===//
308 
309   /// Displays the CFG in a window. This is for use from the debugger and
310   /// depends on Graphviz to generate the graph.
311   /// This function is defined in ViewOpGraph.cpp and only works with that
312   /// target linked.
313   void viewGraph(const Twine &regionName);
314   void viewGraph();
315 
316 private:
317   BlockListType blocks;
318 
319   /// This is the object we are part of.
320   Operation *container = nullptr;
321 };
322 
323 /// This class provides an abstraction over the different types of ranges over
324 /// Regions. In many cases, this prevents the need to explicitly materialize a
325 /// SmallVector/std::vector. This class should be used in places that are not
326 /// suitable for a more derived type (e.g. ArrayRef) or a template range
327 /// parameter.
328 class RegionRange
329     : public llvm::detail::indexed_accessor_range_base<
330           RegionRange,
331           PointerUnion<Region *, const std::unique_ptr<Region> *, Region **>,
332           Region *, Region *, Region *> {
333   /// The type representing the owner of this range. This is either an owning
334   /// list of regions, a list of region unique pointers, or a list of region
335   /// pointers.
336   using OwnerT =
337       PointerUnion<Region *, const std::unique_ptr<Region> *, Region **>;
338 
339 public:
340   using RangeBaseT::RangeBaseT;
341 
342   RegionRange(MutableArrayRef<Region> regions = llvm::None);
343 
344   template <typename Arg,
345             typename = typename std::enable_if_t<std::is_constructible<
346                 ArrayRef<std::unique_ptr<Region>>, Arg>::value>>
RegionRange(Arg && arg)347   RegionRange(Arg &&arg)
348       : RegionRange(ArrayRef<std::unique_ptr<Region>>(std::forward<Arg>(arg))) {
349   }
350   template <typename Arg>
351   RegionRange(
352       Arg &&arg,
353       typename std::enable_if_t<
354           std::is_constructible<ArrayRef<Region *>, Arg>::value> * = nullptr)
RegionRange(ArrayRef<Region * > (std::forward<Arg> (arg)))355       : RegionRange(ArrayRef<Region *>(std::forward<Arg>(arg))) {}
356   RegionRange(ArrayRef<std::unique_ptr<Region>> regions);
357   RegionRange(ArrayRef<Region *> regions);
358 
359 private:
360   /// See `llvm::detail::indexed_accessor_range_base` for details.
361   static OwnerT offset_base(const OwnerT &owner, ptrdiff_t index);
362   /// See `llvm::detail::indexed_accessor_range_base` for details.
363   static Region *dereference_iterator(const OwnerT &owner, ptrdiff_t index);
364 
365   /// Allow access to `offset_base` and `dereference_iterator`.
366   friend RangeBaseT;
367 };
368 
369 } // namespace mlir
370 
371 #endif // MLIR_IR_REGION_H
372