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