1 //===- Region.cpp - MLIR Region Class -------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "mlir/IR/Region.h"
10 #include "mlir/IR/IRMapping.h"
11 #include "mlir/IR/Operation.h"
14 Region::Region(Operation
*container
) : container(container
) {}
17 // Operations may have cyclic references, which need to be dropped before we
18 // can start deleting them.
22 /// Return the context this region is inserted in. The region must have a valid
24 MLIRContext
*Region::getContext() {
25 assert(container
&& "region is not attached to a container");
26 return container
->getContext();
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();
36 auto Region::getArgumentTypes() -> ValueTypeRange
<BlockArgListType
> {
37 return ValueTypeRange
<BlockArgListType
>(getArguments());
40 iterator_range
<Region::args_iterator
>
41 Region::addArguments(TypeRange types
, ArrayRef
<Location
> locs
) {
42 return front().addArguments(types
, locs
);
45 Region
*Region::getParentRegion() {
46 assert(container
&& "region is not attached to a container");
47 return container
->getParentRegion();
50 bool Region::isProperAncestor(Region
*other
) {
54 while ((other
= other
->getParentRegion())) {
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];
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
, IRMapping
&mapper
) {
71 assert(dest
&& "expected valid region to clone into");
72 cloneInto(dest
, dest
->end(), mapper
);
75 /// Clone this region into 'dest' before the given position in 'dest'.
76 void Region::cloneInto(Region
*dest
, Region::iterator destPos
,
78 assert(dest
&& "expected valid region to clone into");
79 assert(this != dest
&& "cannot clone region into itself");
81 // If the list is empty there is nothing to clone.
85 // The below clone implementation takes special care to be read only for the
86 // sake of multi threading. That essentially means not adding any uses to any
87 // of the blocks or operation results contained within this region as that
88 // would lead to a write in their use-def list. This is unavoidable for
89 // 'Value's from outside the region however, in which case it is not read
90 // only. Using the BlockAndValueMapper it is possible to remap such 'Value's
91 // to ones owned by the calling thread however, making it read only once
94 // First clone all the blocks and block arguments and map them, but don't yet
95 // clone the operations, as they may otherwise add a use to a block that has
96 // not yet been mapped
97 for (Block
&block
: *this) {
98 Block
*newBlock
= new Block();
99 mapper
.map(&block
, newBlock
);
101 // Clone the block arguments. The user might be deleting arguments to the
102 // block by specifying them in the mapper. If so, we don't add the
103 // argument to the cloned block.
104 for (auto arg
: block
.getArguments())
105 if (!mapper
.contains(arg
))
106 mapper
.map(arg
, newBlock
->addArgument(arg
.getType(), arg
.getLoc()));
108 dest
->getBlocks().insert(destPos
, newBlock
);
111 auto newBlocksRange
=
112 llvm::make_range(Region::iterator(mapper
.lookup(&front())), destPos
);
114 // Now follow up with creating the operations, but don't yet clone their
115 // regions, nor set their operands. Setting the successors is safe as all have
116 // already been mapped. We are essentially just creating the operation results
117 // to be able to map them.
118 // Cloning the operands and region as well would lead to uses of operations
121 Operation::CloneOptions::all().cloneRegions(false).cloneOperands(false);
122 for (auto zippedBlocks
: llvm::zip(*this, newBlocksRange
)) {
123 Block
&sourceBlock
= std::get
<0>(zippedBlocks
);
124 Block
&clonedBlock
= std::get
<1>(zippedBlocks
);
125 // Clone and remap the operations within this block.
126 for (Operation
&op
: sourceBlock
)
127 clonedBlock
.push_back(op
.clone(mapper
, cloneOptions
));
130 // Finally now that all operation results have been mapped, set the operands
131 // and clone the regions.
132 SmallVector
<Value
> operands
;
133 for (auto zippedBlocks
: llvm::zip(*this, newBlocksRange
)) {
135 llvm::zip(std::get
<0>(zippedBlocks
), std::get
<1>(zippedBlocks
))) {
136 Operation
&source
= std::get
<0>(ops
);
137 Operation
&clone
= std::get
<1>(ops
);
139 operands
.resize(source
.getNumOperands());
141 source
.getOperands(), operands
.begin(),
142 [&](Value operand
) { return mapper
.lookupOrDefault(operand
); });
143 clone
.setOperands(operands
);
145 for (auto regions
: llvm::zip(source
.getRegions(), clone
.getRegions()))
146 std::get
<0>(regions
).cloneInto(&std::get
<1>(regions
), mapper
);
151 /// Returns 'block' if 'block' lies in this region, or otherwise finds the
152 /// ancestor of 'block' that lies in this region. Returns nullptr if the latter
154 Block
*Region::findAncestorBlockInRegion(Block
&block
) {
155 Block
*currBlock
= &block
;
156 while (currBlock
->getParent() != this) {
157 Operation
*parentOp
= currBlock
->getParentOp();
158 if (!parentOp
|| !parentOp
->getBlock())
160 currBlock
= parentOp
->getBlock();
165 /// Returns 'op' if 'op' lies in this region, or otherwise finds the
166 /// ancestor of 'op' that lies in this region. Returns nullptr if the
168 Operation
*Region::findAncestorOpInRegion(Operation
&op
) {
169 Operation
*curOp
= &op
;
170 while (Region
*opRegion
= curOp
->getParentRegion()) {
171 if (opRegion
== this)
174 curOp
= opRegion
->getParentOp();
181 void Region::dropAllReferences() {
182 for (Block
&b
: *this)
183 b
.dropAllReferences();
186 Region
*llvm::ilist_traits
<::mlir::Block
>::getParentRegion() {
188 size_t(&((Region
*)nullptr->*Region::getSublistAccess(nullptr))));
189 iplist
<Block
> *anchor(static_cast<iplist
<Block
> *>(this));
190 return reinterpret_cast<Region
*>(reinterpret_cast<char *>(anchor
) - offset
);
193 /// This is a trait method invoked when a basic block is added to a region.
194 /// We keep the region pointer up to date.
195 void llvm::ilist_traits
<::mlir::Block
>::addNodeToList(Block
*block
) {
196 assert(!block
->getParent() && "already in a region!");
197 block
->parentValidOpOrderPair
.setPointer(getParentRegion());
200 /// This is a trait method invoked when an operation is removed from a
201 /// region. We keep the region pointer up to date.
202 void llvm::ilist_traits
<::mlir::Block
>::removeNodeFromList(Block
*block
) {
203 assert(block
->getParent() && "not already in a region!");
204 block
->parentValidOpOrderPair
.setPointer(nullptr);
207 /// This is a trait method invoked when an operation is moved from one block
208 /// to another. We keep the block pointer up to date.
209 void llvm::ilist_traits
<::mlir::Block
>::transferNodesFromList(
210 ilist_traits
<Block
> &otherList
, block_iterator first
, block_iterator last
) {
211 // If we are transferring operations within the same function, the parent
212 // pointer doesn't need to be updated.
213 auto *curParent
= getParentRegion();
214 if (curParent
== otherList
.getParentRegion())
217 // Update the 'parent' member of each Block.
218 for (; first
!= last
; ++first
)
219 first
->parentValidOpOrderPair
.setPointer(curParent
);
222 //===----------------------------------------------------------------------===//
223 // Region::OpIterator
224 //===----------------------------------------------------------------------===//
226 Region::OpIterator::OpIterator(Region
*region
, bool end
)
227 : region(region
), block(end
? region
->end() : region
->begin()) {
228 if (!region
->empty())
229 skipOverBlocksWithNoOps();
232 Region::OpIterator
&Region::OpIterator::operator++() {
233 // We increment over operations, if we reach the last use then move to next
235 if (operation
!= block
->end())
237 if (operation
== block
->end()) {
239 skipOverBlocksWithNoOps();
244 void Region::OpIterator::skipOverBlocksWithNoOps() {
245 while (block
!= region
->end() && block
->empty())
248 // If we are at the last block, then set the operation to first operation of
249 // next block (sentinel value used for end).
250 if (block
== region
->end())
253 operation
= block
->begin();
256 //===----------------------------------------------------------------------===//
258 //===----------------------------------------------------------------------===//
260 RegionRange::RegionRange(MutableArrayRef
<Region
> regions
)
261 : RegionRange(regions
.data(), regions
.size()) {}
262 RegionRange::RegionRange(ArrayRef
<std::unique_ptr
<Region
>> regions
)
263 : RegionRange(regions
.data(), regions
.size()) {}
264 RegionRange::RegionRange(ArrayRef
<Region
*> regions
)
265 : RegionRange(const_cast<Region
**>(regions
.data()), regions
.size()) {}
267 /// See `llvm::detail::indexed_accessor_range_base` for details.
268 RegionRange::OwnerT
RegionRange::offset_base(const OwnerT
&owner
,
270 if (auto *region
= llvm::dyn_cast_if_present
<const std::unique_ptr
<Region
> *>(owner
))
271 return region
+ index
;
272 if (auto **region
= llvm::dyn_cast_if_present
<Region
**>(owner
))
273 return region
+ index
;
274 return &owner
.get
<Region
*>()[index
];
276 /// See `llvm::detail::indexed_accessor_range_base` for details.
277 Region
*RegionRange::dereference_iterator(const OwnerT
&owner
,
279 if (auto *region
= llvm::dyn_cast_if_present
<const std::unique_ptr
<Region
> *>(owner
))
280 return region
[index
].get();
281 if (auto **region
= llvm::dyn_cast_if_present
<Region
**>(owner
))
282 return region
[index
];
283 return &owner
.get
<Region
*>()[index
];