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