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