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