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 ®ionName); 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