github.com/johnnyeven/libtools@v0.0.0-20191126065708-61829c1adf46/third_party/mlir/lib/IR/Region.cpp (about) 1 //===- Region.cpp - MLIR Region Class -------------------------------------===// 2 // 3 // Copyright 2019 The MLIR Authors. 4 // 5 // Licensed under the Apache License, Version 2.0 (the "License"); 6 // you may not use this file except in compliance with the License. 7 // You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, software 12 // distributed under the License is distributed on an "AS IS" BASIS, 13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 // See the License for the specific language governing permissions and 15 // limitations under the License. 16 // ============================================================================= 17 18 #include "mlir/IR/Region.h" 19 #include "mlir/IR/BlockAndValueMapping.h" 20 #include "mlir/IR/Operation.h" 21 using namespace mlir; 22 23 Region::Region(Operation *container) : container(container) {} 24 25 Region::~Region() { 26 // Operations may have cyclic references, which need to be dropped before we 27 // can start deleting them. 28 dropAllReferences(); 29 } 30 31 /// Return the context this region is inserted in. The region must have a valid 32 /// parent container. 33 MLIRContext *Region::getContext() { 34 assert(container && "region is not attached to a container"); 35 return container->getContext(); 36 } 37 38 /// Return a location for this region. This is the location attached to the 39 /// parent container. The region must have a valid parent container. 40 Location Region::getLoc() { 41 assert(container && "region is not attached to a container"); 42 return container->getLoc(); 43 } 44 45 Region *Region::getParentRegion() { 46 assert(container && "region is not attached to a container"); 47 return container->getParentRegion(); 48 } 49 50 Operation *Region::getParentOp() { return container; } 51 52 bool Region::isProperAncestor(Region *other) { 53 if (this == other) 54 return false; 55 56 while ((other = other->getParentRegion())) { 57 if (this == other) 58 return true; 59 } 60 return false; 61 } 62 63 /// Return the number of this region in the parent operation. 64 unsigned Region::getRegionNumber() { 65 // Regions are always stored consecutively, so use pointer subtraction to 66 // figure out what number this is. 67 return this - &getParentOp()->getRegions()[0]; 68 } 69 70 /// Clone the internal blocks from this region into `dest`. Any 71 /// cloned blocks are appended to the back of dest. 72 void Region::cloneInto(Region *dest, BlockAndValueMapping &mapper) { 73 assert(dest && "expected valid region to clone into"); 74 cloneInto(dest, dest->end(), mapper); 75 } 76 77 /// Clone this region into 'dest' before the given position in 'dest'. 78 void Region::cloneInto(Region *dest, Region::iterator destPos, 79 BlockAndValueMapping &mapper) { 80 assert(dest && "expected valid region to clone into"); 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 void Region::dropAllReferences() { 120 for (Block &b : *this) 121 b.dropAllReferences(); 122 } 123 124 /// Check if there are any values used by operations in `region` defined 125 /// outside its ancestor region `limit`. That is, given `A{B{C{}}}` with region 126 /// `C` and limit `B`, the values defined in `B` can be used but the values 127 /// defined in `A` cannot. Emit errors if `noteLoc` is provided; this location 128 /// is used to point to the operation containing the region, the actual error is 129 /// reported at the operation with an offending use. 130 static bool isIsolatedAbove(Region ®ion, Region &limit, 131 llvm::Optional<Location> noteLoc) { 132 assert(limit.isAncestor(®ion) && 133 "expected isolation limit to be an ancestor of the given region"); 134 135 // List of regions to analyze. Each region is processed independently, with 136 // respect to the common `limit` region, so we can look at them in any order. 137 // Therefore, use a simple vector and push/pop back the current region. 138 SmallVector<Region *, 8> pendingRegions; 139 pendingRegions.push_back(®ion); 140 141 // Traverse all operations in the region. 142 while (!pendingRegions.empty()) { 143 for (Block &block : *pendingRegions.pop_back_val()) { 144 for (Operation &op : block) { 145 for (Value *operand : op.getOperands()) { 146 // Check that any value that is used by an operation is defined in the 147 // same region as either an operation result or a block argument. 148 if (operand->getParentRegion()->isProperAncestor(&limit)) { 149 if (noteLoc) { 150 op.emitOpError("using value defined outside the region") 151 .attachNote(noteLoc) 152 << "required by region isolation constraints"; 153 } 154 return false; 155 } 156 } 157 // Schedule any regions the operations contain for further checking. 158 pendingRegions.reserve(pendingRegions.size() + op.getNumRegions()); 159 for (Region &subRegion : op.getRegions()) 160 pendingRegions.push_back(&subRegion); 161 } 162 } 163 } 164 return true; 165 } 166 167 bool Region::isIsolatedFromAbove(llvm::Optional<Location> noteLoc) { 168 return isIsolatedAbove(*this, *this, noteLoc); 169 } 170 171 Region *llvm::ilist_traits<::mlir::Block>::getParentRegion() { 172 size_t Offset( 173 size_t(&((Region *)nullptr->*Region::getSublistAccess(nullptr)))); 174 iplist<Block> *Anchor(static_cast<iplist<Block> *>(this)); 175 return reinterpret_cast<Region *>(reinterpret_cast<char *>(Anchor) - Offset); 176 } 177 178 /// This is a trait method invoked when a basic block is added to a region. 179 /// We keep the region pointer up to date. 180 void llvm::ilist_traits<::mlir::Block>::addNodeToList(Block *block) { 181 assert(!block->getParent() && "already in a region!"); 182 block->parentValidInstOrderPair.setPointer(getParentRegion()); 183 } 184 185 /// This is a trait method invoked when an operation is removed from a 186 /// region. We keep the region pointer up to date. 187 void llvm::ilist_traits<::mlir::Block>::removeNodeFromList(Block *block) { 188 assert(block->getParent() && "not already in a region!"); 189 block->parentValidInstOrderPair.setPointer(nullptr); 190 } 191 192 /// This is a trait method invoked when an operation is moved from one block 193 /// to another. We keep the block pointer up to date. 194 void llvm::ilist_traits<::mlir::Block>::transferNodesFromList( 195 ilist_traits<Block> &otherList, block_iterator first, block_iterator last) { 196 // If we are transferring operations within the same function, the parent 197 // pointer doesn't need to be updated. 198 auto *curParent = getParentRegion(); 199 if (curParent == otherList.getParentRegion()) 200 return; 201 202 // Update the 'parent' member of each Block. 203 for (; first != last; ++first) 204 first->parentValidInstOrderPair.setPointer(curParent); 205 }