105cf3216SChris Lattner //===- Region.cpp - MLIR Region Class -------------------------------------===// 205cf3216SChris Lattner // 330857107SMehdi Amini // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 456222a06SMehdi Amini // See https://llvm.org/LICENSE.txt for license information. 556222a06SMehdi Amini // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 605cf3216SChris Lattner // 756222a06SMehdi Amini //===----------------------------------------------------------------------===// 805cf3216SChris Lattner 905cf3216SChris Lattner #include "mlir/IR/Region.h" 104d67b278SJeff Niu #include "mlir/IR/IRMapping.h" 1105cf3216SChris Lattner #include "mlir/IR/Operation.h" 1205cf3216SChris Lattner using namespace mlir; 1305cf3216SChris Lattner 1405cf3216SChris Lattner Region::Region(Operation *container) : container(container) {} 1505cf3216SChris Lattner 1605cf3216SChris Lattner Region::~Region() { 1705cf3216SChris Lattner // Operations may have cyclic references, which need to be dropped before we 1805cf3216SChris Lattner // can start deleting them. 194dfe6d45SAlex Zinenko dropAllReferences(); 2005cf3216SChris Lattner } 2105cf3216SChris Lattner 2205cf3216SChris Lattner /// Return the context this region is inserted in. The region must have a valid 2305cf3216SChris Lattner /// parent container. 2405cf3216SChris Lattner MLIRContext *Region::getContext() { 25e7d594bbSRiver Riddle assert(container && "region is not attached to a container"); 26e7d594bbSRiver Riddle return container->getContext(); 2705cf3216SChris Lattner } 2805cf3216SChris Lattner 2905cf3216SChris Lattner /// Return a location for this region. This is the location attached to the 3005cf3216SChris Lattner /// parent container. The region must have a valid parent container. 3105cf3216SChris Lattner Location Region::getLoc() { 32e7d594bbSRiver Riddle assert(container && "region is not attached to a container"); 33e7d594bbSRiver Riddle return container->getLoc(); 3405cf3216SChris Lattner } 3505cf3216SChris Lattner 36706d992cSRahul Joshi auto Region::getArgumentTypes() -> ValueTypeRange<BlockArgListType> { 37706d992cSRahul Joshi return ValueTypeRange<BlockArgListType>(getArguments()); 38706d992cSRahul Joshi } 39706d992cSRahul Joshi 40e084679fSRiver Riddle iterator_range<Region::args_iterator> 41e084679fSRiver Riddle Region::addArguments(TypeRange types, ArrayRef<Location> locs) { 42e084679fSRiver Riddle return front().addArguments(types, locs); 43e2b71610SRahul Joshi } 44e2b71610SRahul Joshi 451e429540SRiver Riddle Region *Region::getParentRegion() { 46e7d594bbSRiver Riddle assert(container && "region is not attached to a container"); 471e429540SRiver Riddle return container->getParentRegion(); 4805cf3216SChris Lattner } 4905cf3216SChris Lattner 5005cf3216SChris Lattner bool Region::isProperAncestor(Region *other) { 5105cf3216SChris Lattner if (this == other) 5205cf3216SChris Lattner return false; 5305cf3216SChris Lattner 541e429540SRiver Riddle while ((other = other->getParentRegion())) { 5505cf3216SChris Lattner if (this == other) 5605cf3216SChris Lattner return true; 5705cf3216SChris Lattner } 5805cf3216SChris Lattner return false; 5905cf3216SChris Lattner } 6005cf3216SChris Lattner 619e3c2650SRiver Riddle /// Return the number of this region in the parent operation. 629e3c2650SRiver Riddle unsigned Region::getRegionNumber() { 639e3c2650SRiver Riddle // Regions are always stored consecutively, so use pointer subtraction to 649e3c2650SRiver Riddle // figure out what number this is. 651e429540SRiver Riddle return this - &getParentOp()->getRegions()[0]; 669e3c2650SRiver Riddle } 679e3c2650SRiver Riddle 6805cf3216SChris Lattner /// Clone the internal blocks from this region into `dest`. Any 6905cf3216SChris Lattner /// cloned blocks are appended to the back of dest. 704d67b278SJeff Niu void Region::cloneInto(Region *dest, IRMapping &mapper) { 71929466b5SRiver Riddle assert(dest && "expected valid region to clone into"); 72929466b5SRiver Riddle cloneInto(dest, dest->end(), mapper); 73929466b5SRiver Riddle } 74929466b5SRiver Riddle 75929466b5SRiver Riddle /// Clone this region into 'dest' before the given position in 'dest'. 76929466b5SRiver Riddle void Region::cloneInto(Region *dest, Region::iterator destPos, 774d67b278SJeff Niu IRMapping &mapper) { 7805cf3216SChris Lattner assert(dest && "expected valid region to clone into"); 797c67ec0fSChristian Sigg assert(this != dest && "cannot clone region into itself"); 8005cf3216SChris Lattner 8105cf3216SChris Lattner // If the list is empty there is nothing to clone. 8205cf3216SChris Lattner if (empty()) 8305cf3216SChris Lattner return; 8405cf3216SChris Lattner 85a41aaf16SMarkus Böck // The below clone implementation takes special care to be read only for the 86a41aaf16SMarkus Böck // sake of multi threading. That essentially means not adding any uses to any 87a41aaf16SMarkus Böck // of the blocks or operation results contained within this region as that 88a41aaf16SMarkus Böck // would lead to a write in their use-def list. This is unavoidable for 89a41aaf16SMarkus Böck // 'Value's from outside the region however, in which case it is not read 90a41aaf16SMarkus Böck // only. Using the BlockAndValueMapper it is possible to remap such 'Value's 91a41aaf16SMarkus Böck // to ones owned by the calling thread however, making it read only once 92a41aaf16SMarkus Böck // again. 93a41aaf16SMarkus Böck 94a41aaf16SMarkus Böck // First clone all the blocks and block arguments and map them, but don't yet 95a41aaf16SMarkus Böck // clone the operations, as they may otherwise add a use to a block that has 96a41aaf16SMarkus Böck // not yet been mapped 9705cf3216SChris Lattner for (Block &block : *this) { 9805cf3216SChris Lattner Block *newBlock = new Block(); 9905cf3216SChris Lattner mapper.map(&block, newBlock); 10005cf3216SChris Lattner 10105cf3216SChris Lattner // Clone the block arguments. The user might be deleting arguments to the 10205cf3216SChris Lattner // block by specifying them in the mapper. If so, we don't add the 10305cf3216SChris Lattner // argument to the cloned block. 10435807bc4SRiver Riddle for (auto arg : block.getArguments()) 10505cf3216SChris Lattner if (!mapper.contains(arg)) 1065f782d25SDominik Grewe mapper.map(arg, newBlock->addArgument(arg.getType(), arg.getLoc())); 10705cf3216SChris Lattner 108929466b5SRiver Riddle dest->getBlocks().insert(destPos, newBlock); 10905cf3216SChris Lattner } 11005cf3216SChris Lattner 111a41aaf16SMarkus Böck auto newBlocksRange = 112a41aaf16SMarkus Böck llvm::make_range(Region::iterator(mapper.lookup(&front())), destPos); 11305cf3216SChris Lattner 114a41aaf16SMarkus Böck // Now follow up with creating the operations, but don't yet clone their 115a41aaf16SMarkus Böck // regions, nor set their operands. Setting the successors is safe as all have 116a41aaf16SMarkus Böck // already been mapped. We are essentially just creating the operation results 117a41aaf16SMarkus Böck // to be able to map them. 118a41aaf16SMarkus Böck // Cloning the operands and region as well would lead to uses of operations 119a41aaf16SMarkus Böck // not yet mapped. 120a41aaf16SMarkus Böck auto cloneOptions = 121a41aaf16SMarkus Böck Operation::CloneOptions::all().cloneRegions(false).cloneOperands(false); 122a41aaf16SMarkus Böck for (auto zippedBlocks : llvm::zip(*this, newBlocksRange)) { 123a41aaf16SMarkus Böck Block &sourceBlock = std::get<0>(zippedBlocks); 124a41aaf16SMarkus Böck Block &clonedBlock = std::get<1>(zippedBlocks); 125a41aaf16SMarkus Böck // Clone and remap the operations within this block. 126a41aaf16SMarkus Böck for (Operation &op : sourceBlock) 127a41aaf16SMarkus Böck clonedBlock.push_back(op.clone(mapper, cloneOptions)); 128a41aaf16SMarkus Böck } 129a41aaf16SMarkus Böck 130a41aaf16SMarkus Böck // Finally now that all operation results have been mapped, set the operands 131a41aaf16SMarkus Böck // and clone the regions. 132a41aaf16SMarkus Böck SmallVector<Value> operands; 133a41aaf16SMarkus Böck for (auto zippedBlocks : llvm::zip(*this, newBlocksRange)) { 134a41aaf16SMarkus Böck for (auto ops : 135a41aaf16SMarkus Böck llvm::zip(std::get<0>(zippedBlocks), std::get<1>(zippedBlocks))) { 136a41aaf16SMarkus Böck Operation &source = std::get<0>(ops); 137a41aaf16SMarkus Böck Operation &clone = std::get<1>(ops); 138a41aaf16SMarkus Böck 139a41aaf16SMarkus Böck operands.resize(source.getNumOperands()); 140a41aaf16SMarkus Böck llvm::transform( 141a41aaf16SMarkus Böck source.getOperands(), operands.begin(), 142a41aaf16SMarkus Böck [&](Value operand) { return mapper.lookupOrDefault(operand); }); 143a41aaf16SMarkus Böck clone.setOperands(operands); 144a41aaf16SMarkus Böck 145a41aaf16SMarkus Böck for (auto regions : llvm::zip(source.getRegions(), clone.getRegions())) 146a41aaf16SMarkus Böck std::get<0>(regions).cloneInto(&std::get<1>(regions), mapper); 147a41aaf16SMarkus Böck } 148a41aaf16SMarkus Böck } 14905cf3216SChris Lattner } 15005cf3216SChris Lattner 151c79227caSMarcel Koester /// Returns 'block' if 'block' lies in this region, or otherwise finds the 152c79227caSMarcel Koester /// ancestor of 'block' that lies in this region. Returns nullptr if the latter 153c79227caSMarcel Koester /// fails. 154c79227caSMarcel Koester Block *Region::findAncestorBlockInRegion(Block &block) { 155412ae15dSChris Lattner Block *currBlock = █ 156c79227caSMarcel Koester while (currBlock->getParent() != this) { 157c79227caSMarcel Koester Operation *parentOp = currBlock->getParentOp(); 158c79227caSMarcel Koester if (!parentOp || !parentOp->getBlock()) 159c79227caSMarcel Koester return nullptr; 160c79227caSMarcel Koester currBlock = parentOp->getBlock(); 161c79227caSMarcel Koester } 162c79227caSMarcel Koester return currBlock; 163c79227caSMarcel Koester } 164c79227caSMarcel Koester 165412ae15dSChris Lattner /// Returns 'op' if 'op' lies in this region, or otherwise finds the 166412ae15dSChris Lattner /// ancestor of 'op' that lies in this region. Returns nullptr if the 167412ae15dSChris Lattner /// latter fails. 168412ae15dSChris Lattner Operation *Region::findAncestorOpInRegion(Operation &op) { 169412ae15dSChris Lattner Operation *curOp = &op; 170412ae15dSChris Lattner while (Region *opRegion = curOp->getParentRegion()) { 171412ae15dSChris Lattner if (opRegion == this) 172412ae15dSChris Lattner return curOp; 173412ae15dSChris Lattner 174412ae15dSChris Lattner curOp = opRegion->getParentOp(); 175412ae15dSChris Lattner if (!curOp) 176412ae15dSChris Lattner return nullptr; 177412ae15dSChris Lattner } 178412ae15dSChris Lattner return nullptr; 179412ae15dSChris Lattner } 180412ae15dSChris Lattner 1814dfe6d45SAlex Zinenko void Region::dropAllReferences() { 1824dfe6d45SAlex Zinenko for (Block &b : *this) 1834dfe6d45SAlex Zinenko b.dropAllReferences(); 1844dfe6d45SAlex Zinenko } 1854dfe6d45SAlex Zinenko 1861e429540SRiver Riddle Region *llvm::ilist_traits<::mlir::Block>::getParentRegion() { 18702b6fb21SMehdi Amini size_t offset( 18805cf3216SChris Lattner size_t(&((Region *)nullptr->*Region::getSublistAccess(nullptr)))); 18902b6fb21SMehdi Amini iplist<Block> *anchor(static_cast<iplist<Block> *>(this)); 19002b6fb21SMehdi Amini return reinterpret_cast<Region *>(reinterpret_cast<char *>(anchor) - offset); 19105cf3216SChris Lattner } 19205cf3216SChris Lattner 19305cf3216SChris Lattner /// This is a trait method invoked when a basic block is added to a region. 19405cf3216SChris Lattner /// We keep the region pointer up to date. 19505cf3216SChris Lattner void llvm::ilist_traits<::mlir::Block>::addNodeToList(Block *block) { 19605cf3216SChris Lattner assert(!block->getParent() && "already in a region!"); 197f6188b5bSSean Silva block->parentValidOpOrderPair.setPointer(getParentRegion()); 19805cf3216SChris Lattner } 19905cf3216SChris Lattner 20005cf3216SChris Lattner /// This is a trait method invoked when an operation is removed from a 20105cf3216SChris Lattner /// region. We keep the region pointer up to date. 20205cf3216SChris Lattner void llvm::ilist_traits<::mlir::Block>::removeNodeFromList(Block *block) { 20305cf3216SChris Lattner assert(block->getParent() && "not already in a region!"); 204f6188b5bSSean Silva block->parentValidOpOrderPair.setPointer(nullptr); 20505cf3216SChris Lattner } 20605cf3216SChris Lattner 20705cf3216SChris Lattner /// This is a trait method invoked when an operation is moved from one block 20805cf3216SChris Lattner /// to another. We keep the block pointer up to date. 20905cf3216SChris Lattner void llvm::ilist_traits<::mlir::Block>::transferNodesFromList( 21005cf3216SChris Lattner ilist_traits<Block> &otherList, block_iterator first, block_iterator last) { 21105cf3216SChris Lattner // If we are transferring operations within the same function, the parent 21205cf3216SChris Lattner // pointer doesn't need to be updated. 2131e429540SRiver Riddle auto *curParent = getParentRegion(); 2141e429540SRiver Riddle if (curParent == otherList.getParentRegion()) 21505cf3216SChris Lattner return; 21605cf3216SChris Lattner 21705cf3216SChris Lattner // Update the 'parent' member of each Block. 21805cf3216SChris Lattner for (; first != last; ++first) 219f6188b5bSSean Silva first->parentValidOpOrderPair.setPointer(curParent); 22005cf3216SChris Lattner } 22170aeb456SJacques Pienaar 22270aeb456SJacques Pienaar //===----------------------------------------------------------------------===// 2231e4faf23SRiver Riddle // Region::OpIterator 2241e4faf23SRiver Riddle //===----------------------------------------------------------------------===// 2251e4faf23SRiver Riddle 2261e4faf23SRiver Riddle Region::OpIterator::OpIterator(Region *region, bool end) 2271e4faf23SRiver Riddle : region(region), block(end ? region->end() : region->begin()) { 2281e4faf23SRiver Riddle if (!region->empty()) 2291e4faf23SRiver Riddle skipOverBlocksWithNoOps(); 2301e4faf23SRiver Riddle } 2311e4faf23SRiver Riddle 2321e4faf23SRiver Riddle Region::OpIterator &Region::OpIterator::operator++() { 2331e4faf23SRiver Riddle // We increment over operations, if we reach the last use then move to next 2341e4faf23SRiver Riddle // block. 2351e4faf23SRiver Riddle if (operation != block->end()) 2361e4faf23SRiver Riddle ++operation; 2371e4faf23SRiver Riddle if (operation == block->end()) { 2381e4faf23SRiver Riddle ++block; 2391e4faf23SRiver Riddle skipOverBlocksWithNoOps(); 2401e4faf23SRiver Riddle } 2411e4faf23SRiver Riddle return *this; 2421e4faf23SRiver Riddle } 2431e4faf23SRiver Riddle 2441e4faf23SRiver Riddle void Region::OpIterator::skipOverBlocksWithNoOps() { 2451e4faf23SRiver Riddle while (block != region->end() && block->empty()) 2461e4faf23SRiver Riddle ++block; 2471e4faf23SRiver Riddle 2481e4faf23SRiver Riddle // If we are at the last block, then set the operation to first operation of 2491e4faf23SRiver Riddle // next block (sentinel value used for end). 2501e4faf23SRiver Riddle if (block == region->end()) 2511e4faf23SRiver Riddle operation = {}; 2521e4faf23SRiver Riddle else 2531e4faf23SRiver Riddle operation = block->begin(); 2541e4faf23SRiver Riddle } 2551e4faf23SRiver Riddle 2561e4faf23SRiver Riddle //===----------------------------------------------------------------------===// 25770aeb456SJacques Pienaar // RegionRange 25870aeb456SJacques Pienaar //===----------------------------------------------------------------------===// 25970aeb456SJacques Pienaar 2607be6a40aSRiver Riddle RegionRange::RegionRange(MutableArrayRef<Region> regions) 2617be6a40aSRiver Riddle : RegionRange(regions.data(), regions.size()) {} 2627be6a40aSRiver Riddle RegionRange::RegionRange(ArrayRef<std::unique_ptr<Region>> regions) 2637be6a40aSRiver Riddle : RegionRange(regions.data(), regions.size()) {} 264979ffe97SMogball RegionRange::RegionRange(ArrayRef<Region *> regions) 265979ffe97SMogball : RegionRange(const_cast<Region **>(regions.data()), regions.size()) {} 2667be6a40aSRiver Riddle 267204c3b55SRiver Riddle /// See `llvm::detail::indexed_accessor_range_base` for details. 2687be6a40aSRiver Riddle RegionRange::OwnerT RegionRange::offset_base(const OwnerT &owner, 2697be6a40aSRiver Riddle ptrdiff_t index) { 27068f58812STres Popp if (auto *region = llvm::dyn_cast_if_present<const std::unique_ptr<Region> *>(owner)) 271979ffe97SMogball return region + index; 27268f58812STres Popp if (auto **region = llvm::dyn_cast_if_present<Region **>(owner)) 273979ffe97SMogball return region + index; 274*fcb1591bSKazu Hirata return &cast<Region *>(owner)[index]; 2757be6a40aSRiver Riddle } 276204c3b55SRiver Riddle /// See `llvm::detail::indexed_accessor_range_base` for details. 2777be6a40aSRiver Riddle Region *RegionRange::dereference_iterator(const OwnerT &owner, 2787be6a40aSRiver Riddle ptrdiff_t index) { 27968f58812STres Popp if (auto *region = llvm::dyn_cast_if_present<const std::unique_ptr<Region> *>(owner)) 280979ffe97SMogball return region[index].get(); 28168f58812STres Popp if (auto **region = llvm::dyn_cast_if_present<Region **>(owner)) 282979ffe97SMogball return region[index]; 283*fcb1591bSKazu Hirata return &cast<Region *>(owner)[index]; 28470aeb456SJacques Pienaar } 285