xref: /llvm-project/mlir/lib/IR/Region.cpp (revision fcb1591b46f12b8908a8cdb252611708820102f8)
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 = &block;
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