1 //===- Region.cpp - MLIR Region Class -------------------------------------===// 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 #include "mlir/IR/Region.h" 10 #include "mlir/IR/BlockAndValueMapping.h" 11 #include "mlir/IR/Operation.h" 12 using namespace mlir; 13 14 Region::Region(Operation *container) : container(container) {} 15 16 Region::~Region() { 17 // Operations may have cyclic references, which need to be dropped before we 18 // can start deleting them. 19 dropAllReferences(); 20 } 21 22 /// Return the context this region is inserted in. The region must have a valid 23 /// parent container. 24 MLIRContext *Region::getContext() { 25 assert(container && "region is not attached to a container"); 26 return container->getContext(); 27 } 28 29 /// Return a location for this region. This is the location attached to the 30 /// parent container. The region must have a valid parent container. 31 Location Region::getLoc() { 32 assert(container && "region is not attached to a container"); 33 return container->getLoc(); 34 } 35 36 /// Add one argument to the argument list for each type specified in the list. 37 iterator_range<Region::args_iterator> Region::addArguments(TypeRange types) { 38 return front().addArguments(types); 39 } 40 41 Region *Region::getParentRegion() { 42 assert(container && "region is not attached to a container"); 43 return container->getParentRegion(); 44 } 45 46 Operation *Region::getParentOp() { return container; } 47 48 bool Region::isProperAncestor(Region *other) { 49 if (this == other) 50 return false; 51 52 while ((other = other->getParentRegion())) { 53 if (this == other) 54 return true; 55 } 56 return false; 57 } 58 59 /// Return the number of this region in the parent operation. 60 unsigned Region::getRegionNumber() { 61 // Regions are always stored consecutively, so use pointer subtraction to 62 // figure out what number this is. 63 return this - &getParentOp()->getRegions()[0]; 64 } 65 66 /// Clone the internal blocks from this region into `dest`. Any 67 /// cloned blocks are appended to the back of dest. 68 void Region::cloneInto(Region *dest, BlockAndValueMapping &mapper) { 69 assert(dest && "expected valid region to clone into"); 70 cloneInto(dest, dest->end(), mapper); 71 } 72 73 /// Clone this region into 'dest' before the given position in 'dest'. 74 void Region::cloneInto(Region *dest, Region::iterator destPos, 75 BlockAndValueMapping &mapper) { 76 assert(dest && "expected valid region to clone into"); 77 assert(this != dest && "cannot clone region into itself"); 78 79 // If the list is empty there is nothing to clone. 80 if (empty()) 81 return; 82 83 for (Block &block : *this) { 84 Block *newBlock = new Block(); 85 mapper.map(&block, newBlock); 86 87 // Clone the block arguments. The user might be deleting arguments to the 88 // block by specifying them in the mapper. If so, we don't add the 89 // argument to the cloned block. 90 for (auto arg : block.getArguments()) 91 if (!mapper.contains(arg)) 92 mapper.map(arg, newBlock->addArgument(arg.getType())); 93 94 // Clone and remap the operations within this block. 95 for (auto &op : block) 96 newBlock->push_back(op.clone(mapper)); 97 98 dest->getBlocks().insert(destPos, newBlock); 99 } 100 101 // Now that each of the blocks have been cloned, go through and remap the 102 // operands of each of the operations. 103 auto remapOperands = [&](Operation *op) { 104 for (auto &operand : op->getOpOperands()) 105 if (auto mappedOp = mapper.lookupOrNull(operand.get())) 106 operand.set(mappedOp); 107 for (auto &succOp : op->getBlockOperands()) 108 if (auto *mappedOp = mapper.lookupOrNull(succOp.get())) 109 succOp.set(mappedOp); 110 }; 111 112 for (iterator it(mapper.lookup(&front())); it != destPos; ++it) 113 it->walk(remapOperands); 114 } 115 116 /// Returns 'block' if 'block' lies in this region, or otherwise finds the 117 /// ancestor of 'block' that lies in this region. Returns nullptr if the latter 118 /// fails. 119 Block *Region::findAncestorBlockInRegion(Block &block) { 120 auto currBlock = █ 121 while (currBlock->getParent() != this) { 122 Operation *parentOp = currBlock->getParentOp(); 123 if (!parentOp || !parentOp->getBlock()) 124 return nullptr; 125 currBlock = parentOp->getBlock(); 126 } 127 return currBlock; 128 } 129 130 void Region::dropAllReferences() { 131 for (Block &b : *this) 132 b.dropAllReferences(); 133 } 134 135 /// Check if there are any values used by operations in `region` defined 136 /// outside its ancestor region `limit`. That is, given `A{B{C{}}}` with region 137 /// `C` and limit `B`, the values defined in `B` can be used but the values 138 /// defined in `A` cannot. Emit errors if `noteLoc` is provided; this location 139 /// is used to point to the operation containing the region, the actual error is 140 /// reported at the operation with an offending use. 141 static bool isIsolatedAbove(Region ®ion, Region &limit, 142 Optional<Location> noteLoc) { 143 assert(limit.isAncestor(®ion) && 144 "expected isolation limit to be an ancestor of the given region"); 145 146 // List of regions to analyze. Each region is processed independently, with 147 // respect to the common `limit` region, so we can look at them in any order. 148 // Therefore, use a simple vector and push/pop back the current region. 149 SmallVector<Region *, 8> pendingRegions; 150 pendingRegions.push_back(®ion); 151 152 // Traverse all operations in the region. 153 while (!pendingRegions.empty()) { 154 for (Operation &op : pendingRegions.pop_back_val()->getOps()) { 155 for (Value operand : op.getOperands()) { 156 // operand should be non-null here if the IR is well-formed. But 157 // we don't assert here as this function is called from the verifier 158 // and so could be called on invalid IR. 159 if (!operand) { 160 if (noteLoc) 161 op.emitOpError("block's operand not defined").attachNote(noteLoc); 162 return false; 163 } 164 165 // Check that any value that is used by an operation is defined in the 166 // same region as either an operation result or a block argument. 167 if (operand.getParentRegion()->isProperAncestor(&limit)) { 168 if (noteLoc) { 169 op.emitOpError("using value defined outside the region") 170 .attachNote(noteLoc) 171 << "required by region isolation constraints"; 172 } 173 return false; 174 } 175 } 176 // Schedule any regions the operations contain for further checking. 177 pendingRegions.reserve(pendingRegions.size() + op.getNumRegions()); 178 for (Region &subRegion : op.getRegions()) 179 pendingRegions.push_back(&subRegion); 180 } 181 } 182 return true; 183 } 184 185 bool Region::isIsolatedFromAbove(Optional<Location> noteLoc) { 186 return isIsolatedAbove(*this, *this, noteLoc); 187 } 188 189 Region *llvm::ilist_traits<::mlir::Block>::getParentRegion() { 190 size_t Offset( 191 size_t(&((Region *)nullptr->*Region::getSublistAccess(nullptr)))); 192 iplist<Block> *Anchor(static_cast<iplist<Block> *>(this)); 193 return reinterpret_cast<Region *>(reinterpret_cast<char *>(Anchor) - Offset); 194 } 195 196 /// This is a trait method invoked when a basic block is added to a region. 197 /// We keep the region pointer up to date. 198 void llvm::ilist_traits<::mlir::Block>::addNodeToList(Block *block) { 199 assert(!block->getParent() && "already in a region!"); 200 block->parentValidOpOrderPair.setPointer(getParentRegion()); 201 } 202 203 /// This is a trait method invoked when an operation is removed from a 204 /// region. We keep the region pointer up to date. 205 void llvm::ilist_traits<::mlir::Block>::removeNodeFromList(Block *block) { 206 assert(block->getParent() && "not already in a region!"); 207 block->parentValidOpOrderPair.setPointer(nullptr); 208 } 209 210 /// This is a trait method invoked when an operation is moved from one block 211 /// to another. We keep the block pointer up to date. 212 void llvm::ilist_traits<::mlir::Block>::transferNodesFromList( 213 ilist_traits<Block> &otherList, block_iterator first, block_iterator last) { 214 // If we are transferring operations within the same function, the parent 215 // pointer doesn't need to be updated. 216 auto *curParent = getParentRegion(); 217 if (curParent == otherList.getParentRegion()) 218 return; 219 220 // Update the 'parent' member of each Block. 221 for (; first != last; ++first) 222 first->parentValidOpOrderPair.setPointer(curParent); 223 } 224 225 //===----------------------------------------------------------------------===// 226 // Region::OpIterator 227 //===----------------------------------------------------------------------===// 228 229 Region::OpIterator::OpIterator(Region *region, bool end) 230 : region(region), block(end ? region->end() : region->begin()) { 231 if (!region->empty()) 232 skipOverBlocksWithNoOps(); 233 } 234 235 Region::OpIterator &Region::OpIterator::operator++() { 236 // We increment over operations, if we reach the last use then move to next 237 // block. 238 if (operation != block->end()) 239 ++operation; 240 if (operation == block->end()) { 241 ++block; 242 skipOverBlocksWithNoOps(); 243 } 244 return *this; 245 } 246 247 void Region::OpIterator::skipOverBlocksWithNoOps() { 248 while (block != region->end() && block->empty()) 249 ++block; 250 251 // If we are at the last block, then set the operation to first operation of 252 // next block (sentinel value used for end). 253 if (block == region->end()) 254 operation = {}; 255 else 256 operation = block->begin(); 257 } 258 259 //===----------------------------------------------------------------------===// 260 // RegionRange 261 //===----------------------------------------------------------------------===// 262 263 RegionRange::RegionRange(MutableArrayRef<Region> regions) 264 : RegionRange(regions.data(), regions.size()) {} 265 RegionRange::RegionRange(ArrayRef<std::unique_ptr<Region>> regions) 266 : RegionRange(regions.data(), regions.size()) {} 267 268 /// See `llvm::detail::indexed_accessor_range_base` for details. 269 RegionRange::OwnerT RegionRange::offset_base(const OwnerT &owner, 270 ptrdiff_t index) { 271 if (auto *operand = owner.dyn_cast<const std::unique_ptr<Region> *>()) 272 return operand + index; 273 return &owner.get<Region *>()[index]; 274 } 275 /// See `llvm::detail::indexed_accessor_range_base` for details. 276 Region *RegionRange::dereference_iterator(const OwnerT &owner, 277 ptrdiff_t index) { 278 if (auto *operand = owner.dyn_cast<const std::unique_ptr<Region> *>()) 279 return operand[index].get(); 280 return &owner.get<Region *>()[index]; 281 } 282