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