1 //===- Region.cpp - MLIR Region Class -------------------------------------===// 2 // 3 // Part of the MLIR 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 Region *Region::getParentRegion() { 37 assert(container && "region is not attached to a container"); 38 return container->getParentRegion(); 39 } 40 41 Operation *Region::getParentOp() { return container; } 42 43 bool Region::isProperAncestor(Region *other) { 44 if (this == other) 45 return false; 46 47 while ((other = other->getParentRegion())) { 48 if (this == other) 49 return true; 50 } 51 return false; 52 } 53 54 /// Return the number of this region in the parent operation. 55 unsigned Region::getRegionNumber() { 56 // Regions are always stored consecutively, so use pointer subtraction to 57 // figure out what number this is. 58 return this - &getParentOp()->getRegions()[0]; 59 } 60 61 /// Clone the internal blocks from this region into `dest`. Any 62 /// cloned blocks are appended to the back of dest. 63 void Region::cloneInto(Region *dest, BlockAndValueMapping &mapper) { 64 assert(dest && "expected valid region to clone into"); 65 cloneInto(dest, dest->end(), mapper); 66 } 67 68 /// Clone this region into 'dest' before the given position in 'dest'. 69 void Region::cloneInto(Region *dest, Region::iterator destPos, 70 BlockAndValueMapping &mapper) { 71 assert(dest && "expected valid region to clone into"); 72 assert(this != dest && "cannot clone region into itself"); 73 74 // If the list is empty there is nothing to clone. 75 if (empty()) 76 return; 77 78 for (Block &block : *this) { 79 Block *newBlock = new Block(); 80 mapper.map(&block, newBlock); 81 82 // Clone the block arguments. The user might be deleting arguments to the 83 // block by specifying them in the mapper. If so, we don't add the 84 // argument to the cloned block. 85 for (auto arg : block.getArguments()) 86 if (!mapper.contains(arg)) 87 mapper.map(arg, newBlock->addArgument(arg.getType())); 88 89 // Clone and remap the operations within this block. 90 for (auto &op : block) 91 newBlock->push_back(op.clone(mapper)); 92 93 dest->getBlocks().insert(destPos, newBlock); 94 } 95 96 // Now that each of the blocks have been cloned, go through and remap the 97 // operands of each of the operations. 98 auto remapOperands = [&](Operation *op) { 99 for (auto &operand : op->getOpOperands()) 100 if (auto mappedOp = mapper.lookupOrNull(operand.get())) 101 operand.set(mappedOp); 102 for (auto &succOp : op->getBlockOperands()) 103 if (auto *mappedOp = mapper.lookupOrNull(succOp.get())) 104 succOp.set(mappedOp); 105 }; 106 107 for (iterator it(mapper.lookup(&front())); it != destPos; ++it) 108 it->walk(remapOperands); 109 } 110 111 void Region::dropAllReferences() { 112 for (Block &b : *this) 113 b.dropAllReferences(); 114 } 115 116 /// Check if there are any values used by operations in `region` defined 117 /// outside its ancestor region `limit`. That is, given `A{B{C{}}}` with region 118 /// `C` and limit `B`, the values defined in `B` can be used but the values 119 /// defined in `A` cannot. Emit errors if `noteLoc` is provided; this location 120 /// is used to point to the operation containing the region, the actual error is 121 /// reported at the operation with an offending use. 122 static bool isIsolatedAbove(Region ®ion, Region &limit, 123 Optional<Location> noteLoc) { 124 assert(limit.isAncestor(®ion) && 125 "expected isolation limit to be an ancestor of the given region"); 126 127 // List of regions to analyze. Each region is processed independently, with 128 // respect to the common `limit` region, so we can look at them in any order. 129 // Therefore, use a simple vector and push/pop back the current region. 130 SmallVector<Region *, 8> pendingRegions; 131 pendingRegions.push_back(®ion); 132 133 // Traverse all operations in the region. 134 while (!pendingRegions.empty()) { 135 for (Block &block : *pendingRegions.pop_back_val()) { 136 for (Operation &op : block) { 137 for (Value operand : op.getOperands()) { 138 // operand should be non-null here if the IR is well-formed. But 139 // we don't assert here as this function is called from the verifier 140 // and so could be called on invalid IR. 141 if (!operand) { 142 if (noteLoc) 143 op.emitOpError("block's operand not defined").attachNote(noteLoc); 144 return false; 145 } 146 147 // Check that any value that is used by an operation is defined in the 148 // same region as either an operation result or a block argument. 149 if (operand.getParentRegion()->isProperAncestor(&limit)) { 150 if (noteLoc) { 151 op.emitOpError("using value defined outside the region") 152 .attachNote(noteLoc) 153 << "required by region isolation constraints"; 154 } 155 return false; 156 } 157 } 158 // Schedule any regions the operations contain for further checking. 159 pendingRegions.reserve(pendingRegions.size() + op.getNumRegions()); 160 for (Region &subRegion : op.getRegions()) 161 pendingRegions.push_back(&subRegion); 162 } 163 } 164 } 165 return true; 166 } 167 168 bool Region::isIsolatedFromAbove(Optional<Location> noteLoc) { 169 return isIsolatedAbove(*this, *this, noteLoc); 170 } 171 172 Region *llvm::ilist_traits<::mlir::Block>::getParentRegion() { 173 size_t Offset( 174 size_t(&((Region *)nullptr->*Region::getSublistAccess(nullptr)))); 175 iplist<Block> *Anchor(static_cast<iplist<Block> *>(this)); 176 return reinterpret_cast<Region *>(reinterpret_cast<char *>(Anchor) - Offset); 177 } 178 179 /// This is a trait method invoked when a basic block is added to a region. 180 /// We keep the region pointer up to date. 181 void llvm::ilist_traits<::mlir::Block>::addNodeToList(Block *block) { 182 assert(!block->getParent() && "already in a region!"); 183 block->parentValidOpOrderPair.setPointer(getParentRegion()); 184 } 185 186 /// This is a trait method invoked when an operation is removed from a 187 /// region. We keep the region pointer up to date. 188 void llvm::ilist_traits<::mlir::Block>::removeNodeFromList(Block *block) { 189 assert(block->getParent() && "not already in a region!"); 190 block->parentValidOpOrderPair.setPointer(nullptr); 191 } 192 193 /// This is a trait method invoked when an operation is moved from one block 194 /// to another. We keep the block pointer up to date. 195 void llvm::ilist_traits<::mlir::Block>::transferNodesFromList( 196 ilist_traits<Block> &otherList, block_iterator first, block_iterator last) { 197 // If we are transferring operations within the same function, the parent 198 // pointer doesn't need to be updated. 199 auto *curParent = getParentRegion(); 200 if (curParent == otherList.getParentRegion()) 201 return; 202 203 // Update the 'parent' member of each Block. 204 for (; first != last; ++first) 205 first->parentValidOpOrderPair.setPointer(curParent); 206 } 207 208 //===----------------------------------------------------------------------===// 209 // RegionRange 210 //===----------------------------------------------------------------------===// 211 212 RegionRange::RegionRange(MutableArrayRef<Region> regions) 213 : RegionRange(regions.data(), regions.size()) {} 214 RegionRange::RegionRange(ArrayRef<std::unique_ptr<Region>> regions) 215 : RegionRange(regions.data(), regions.size()) {} 216 217 /// See `detail::indexed_accessor_range_base` for details. 218 RegionRange::OwnerT RegionRange::offset_base(const OwnerT &owner, 219 ptrdiff_t index) { 220 if (auto *operand = owner.dyn_cast<const std::unique_ptr<Region> *>()) 221 return operand + index; 222 return &owner.get<Region *>()[index]; 223 } 224 /// See `detail::indexed_accessor_range_base` for details. 225 Region *RegionRange::dereference_iterator(const OwnerT &owner, 226 ptrdiff_t index) { 227 if (auto *operand = owner.dyn_cast<const std::unique_ptr<Region> *>()) 228 return operand[index].get(); 229 return &owner.get<Region *>()[index]; 230 } 231