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 auto Region::getArgumentTypes() -> ValueTypeRange<BlockArgListType> { 37 return ValueTypeRange<BlockArgListType>(getArguments()); 38 } 39 40 iterator_range<Region::args_iterator> 41 Region::addArguments(TypeRange types, ArrayRef<Location> locs) { 42 return front().addArguments(types, locs); 43 } 44 45 Region *Region::getParentRegion() { 46 assert(container && "region is not attached to a container"); 47 return container->getParentRegion(); 48 } 49 50 bool Region::isProperAncestor(Region *other) { 51 if (this == other) 52 return false; 53 54 while ((other = other->getParentRegion())) { 55 if (this == other) 56 return true; 57 } 58 return false; 59 } 60 61 /// Return the number of this region in the parent operation. 62 unsigned Region::getRegionNumber() { 63 // Regions are always stored consecutively, so use pointer subtraction to 64 // figure out what number this is. 65 return this - &getParentOp()->getRegions()[0]; 66 } 67 68 /// Clone the internal blocks from this region into `dest`. Any 69 /// cloned blocks are appended to the back of dest. 70 void Region::cloneInto(Region *dest, BlockAndValueMapping &mapper) { 71 assert(dest && "expected valid region to clone into"); 72 cloneInto(dest, dest->end(), mapper); 73 } 74 75 /// Clone this region into 'dest' before the given position in 'dest'. 76 void Region::cloneInto(Region *dest, Region::iterator destPos, 77 BlockAndValueMapping &mapper) { 78 assert(dest && "expected valid region to clone into"); 79 assert(this != dest && "cannot clone region into itself"); 80 81 // If the list is empty there is nothing to clone. 82 if (empty()) 83 return; 84 85 for (Block &block : *this) { 86 Block *newBlock = new Block(); 87 mapper.map(&block, newBlock); 88 89 // Clone the block arguments. The user might be deleting arguments to the 90 // block by specifying them in the mapper. If so, we don't add the 91 // argument to the cloned block. 92 for (auto arg : block.getArguments()) 93 if (!mapper.contains(arg)) 94 mapper.map(arg, newBlock->addArgument(arg.getType(), arg.getLoc())); 95 96 // Clone and remap the operations within this block. 97 for (auto &op : block) 98 newBlock->push_back(op.clone(mapper)); 99 100 dest->getBlocks().insert(destPos, newBlock); 101 } 102 103 // Now that each of the blocks have been cloned, go through and remap the 104 // operands of each of the operations. 105 auto remapOperands = [&](Operation *op) { 106 for (auto &operand : op->getOpOperands()) 107 if (auto mappedOp = mapper.lookupOrNull(operand.get())) 108 operand.set(mappedOp); 109 for (auto &succOp : op->getBlockOperands()) 110 if (auto *mappedOp = mapper.lookupOrNull(succOp.get())) 111 succOp.set(mappedOp); 112 }; 113 114 for (iterator it(mapper.lookup(&front())); it != destPos; ++it) 115 it->walk(remapOperands); 116 } 117 118 /// Returns 'block' if 'block' lies in this region, or otherwise finds the 119 /// ancestor of 'block' that lies in this region. Returns nullptr if the latter 120 /// fails. 121 Block *Region::findAncestorBlockInRegion(Block &block) { 122 Block *currBlock = █ 123 while (currBlock->getParent() != this) { 124 Operation *parentOp = currBlock->getParentOp(); 125 if (!parentOp || !parentOp->getBlock()) 126 return nullptr; 127 currBlock = parentOp->getBlock(); 128 } 129 return currBlock; 130 } 131 132 /// Returns 'op' if 'op' lies in this region, or otherwise finds the 133 /// ancestor of 'op' that lies in this region. Returns nullptr if the 134 /// latter fails. 135 Operation *Region::findAncestorOpInRegion(Operation &op) { 136 Operation *curOp = &op; 137 while (Region *opRegion = curOp->getParentRegion()) { 138 if (opRegion == this) 139 return curOp; 140 141 curOp = opRegion->getParentOp(); 142 if (!curOp) 143 return nullptr; 144 } 145 return nullptr; 146 } 147 148 void Region::dropAllReferences() { 149 for (Block &b : *this) 150 b.dropAllReferences(); 151 } 152 153 Region *llvm::ilist_traits<::mlir::Block>::getParentRegion() { 154 size_t offset( 155 size_t(&((Region *)nullptr->*Region::getSublistAccess(nullptr)))); 156 iplist<Block> *anchor(static_cast<iplist<Block> *>(this)); 157 return reinterpret_cast<Region *>(reinterpret_cast<char *>(anchor) - offset); 158 } 159 160 /// This is a trait method invoked when a basic block is added to a region. 161 /// We keep the region pointer up to date. 162 void llvm::ilist_traits<::mlir::Block>::addNodeToList(Block *block) { 163 assert(!block->getParent() && "already in a region!"); 164 block->parentValidOpOrderPair.setPointer(getParentRegion()); 165 } 166 167 /// This is a trait method invoked when an operation is removed from a 168 /// region. We keep the region pointer up to date. 169 void llvm::ilist_traits<::mlir::Block>::removeNodeFromList(Block *block) { 170 assert(block->getParent() && "not already in a region!"); 171 block->parentValidOpOrderPair.setPointer(nullptr); 172 } 173 174 /// This is a trait method invoked when an operation is moved from one block 175 /// to another. We keep the block pointer up to date. 176 void llvm::ilist_traits<::mlir::Block>::transferNodesFromList( 177 ilist_traits<Block> &otherList, block_iterator first, block_iterator last) { 178 // If we are transferring operations within the same function, the parent 179 // pointer doesn't need to be updated. 180 auto *curParent = getParentRegion(); 181 if (curParent == otherList.getParentRegion()) 182 return; 183 184 // Update the 'parent' member of each Block. 185 for (; first != last; ++first) 186 first->parentValidOpOrderPair.setPointer(curParent); 187 } 188 189 //===----------------------------------------------------------------------===// 190 // Region::OpIterator 191 //===----------------------------------------------------------------------===// 192 193 Region::OpIterator::OpIterator(Region *region, bool end) 194 : region(region), block(end ? region->end() : region->begin()) { 195 if (!region->empty()) 196 skipOverBlocksWithNoOps(); 197 } 198 199 Region::OpIterator &Region::OpIterator::operator++() { 200 // We increment over operations, if we reach the last use then move to next 201 // block. 202 if (operation != block->end()) 203 ++operation; 204 if (operation == block->end()) { 205 ++block; 206 skipOverBlocksWithNoOps(); 207 } 208 return *this; 209 } 210 211 void Region::OpIterator::skipOverBlocksWithNoOps() { 212 while (block != region->end() && block->empty()) 213 ++block; 214 215 // If we are at the last block, then set the operation to first operation of 216 // next block (sentinel value used for end). 217 if (block == region->end()) 218 operation = {}; 219 else 220 operation = block->begin(); 221 } 222 223 //===----------------------------------------------------------------------===// 224 // RegionRange 225 //===----------------------------------------------------------------------===// 226 227 RegionRange::RegionRange(MutableArrayRef<Region> regions) 228 : RegionRange(regions.data(), regions.size()) {} 229 RegionRange::RegionRange(ArrayRef<std::unique_ptr<Region>> regions) 230 : RegionRange(regions.data(), regions.size()) {} 231 232 /// See `llvm::detail::indexed_accessor_range_base` for details. 233 RegionRange::OwnerT RegionRange::offset_base(const OwnerT &owner, 234 ptrdiff_t index) { 235 if (auto *operand = owner.dyn_cast<const std::unique_ptr<Region> *>()) 236 return operand + index; 237 return &owner.get<Region *>()[index]; 238 } 239 /// See `llvm::detail::indexed_accessor_range_base` for details. 240 Region *RegionRange::dereference_iterator(const OwnerT &owner, 241 ptrdiff_t index) { 242 if (auto *operand = owner.dyn_cast<const std::unique_ptr<Region> *>()) 243 return operand[index].get(); 244 return &owner.get<Region *>()[index]; 245 } 246