MLIR 22.0.0git
Region.cpp
Go to the documentation of this file.
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/IRMapping.h"
11#include "mlir/IR/Operation.h"
12using namespace mlir;
13
14Region::Region(Operation *container) : container(container) {}
15
17 // Operations may have cyclic references, which need to be dropped before we
18 // can start deleting them.
20}
21
22/// Return the context this region is inserted in. The region must have a valid
23/// parent container.
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.
32 assert(container && "region is not attached to a container");
33 return container->getLoc();
34}
35
39
42 return front().addArguments(types, locs);
43}
44
46 assert(container && "region is not attached to a container");
47 return container->getParentRegion();
48}
49
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.
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.
70void Region::cloneInto(Region *dest, IRMapping &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'.
77 IRMapping &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 // 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 IRMapper it is possible to remap such 'Value's
91 // to ones owned by the calling thread however, making it read only once
92 // again.
93
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);
100
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()));
107
108 dest->getBlocks().insert(destPos, newBlock);
109 }
110
111 auto newBlocksRange =
112 llvm::make_range(Region::iterator(mapper.lookup(&front())), destPos);
113
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
119 // not yet mapped.
120 auto cloneOptions =
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));
128 }
129
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)) {
134 for (auto ops :
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);
138
139 operands.resize(source.getNumOperands());
140 llvm::transform(
141 source.getOperands(), operands.begin(),
142 [&](Value operand) { return mapper.lookupOrDefault(operand); });
143 clone.setOperands(operands);
144
145 for (auto regions : llvm::zip(source.getRegions(), clone.getRegions()))
146 std::get<0>(regions).cloneInto(&std::get<1>(regions), mapper);
147 }
148 }
149}
150
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
153/// fails.
155 Block *currBlock = &block;
156 while (currBlock->getParent() != this) {
157 Operation *parentOp = currBlock->getParentOp();
158 if (!parentOp || !parentOp->getBlock())
159 return nullptr;
160 currBlock = parentOp->getBlock();
161 }
162 return currBlock;
163}
164
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
167/// latter fails.
169 Operation *curOp = &op;
170 while (Region *opRegion = curOp->getParentRegion()) {
171 if (opRegion == this)
172 return curOp;
173
174 curOp = opRegion->getParentOp();
175 if (!curOp)
176 return nullptr;
177 }
178 return nullptr;
179}
180
182 for (Block &b : *this)
183 b.dropAllReferences();
184}
185
186Region *llvm::ilist_traits<::mlir::Block>::getParentRegion() {
187 size_t offset(
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);
191}
192
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.
196 assert(!block->getParent() && "already in a region!");
197 block->parentValidOpOrderPair.setPointer(getParentRegion());
198}
199
200/// This is a trait method invoked when an operation is removed from a
201/// region. We keep the region pointer up to date.
203 assert(block->getParent() && "not already in a region!");
204 block->parentValidOpOrderPair.setPointer(nullptr);
205}
206
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.
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())
215 return;
216
217 // Update the 'parent' member of each Block.
218 for (; first != last; ++first)
219 first->parentValidOpOrderPair.setPointer(curParent);
220}
221
222//===----------------------------------------------------------------------===//
223// Region::OpIterator
224//===----------------------------------------------------------------------===//
225
227 : region(region), block(end ? region->end() : region->begin()) {
228 if (!region->empty())
229 skipOverBlocksWithNoOps();
230}
231
233 // We increment over operations, if we reach the last use then move to next
234 // block.
235 if (operation != block->end())
236 ++operation;
237 if (operation == block->end()) {
238 ++block;
239 skipOverBlocksWithNoOps();
240 }
241 return *this;
242}
243
244void Region::OpIterator::skipOverBlocksWithNoOps() {
245 while (block != region->end() && block->empty())
246 ++block;
247
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())
251 operation = {};
252 else
253 operation = block->begin();
254}
255
256llvm::raw_ostream &mlir::operator<<(llvm::raw_ostream &os, Region &region) {
257 if (!region.getParentOp()) {
258 os << "Region has no parent op";
259 } else {
260 os << "Region #" << region.getRegionNumber() << " in operation "
261 << region.getParentOp()->getName();
262 }
263 for (auto it : llvm::enumerate(region.getBlocks())) {
264 os << "\n Block #" << it.index() << ":";
265 for (Operation &op : it.value().getOperations())
266 os << "\n " << OpWithFlags(&op, OpPrintingFlags().skipRegions());
267 }
268 return os;
269}
270
271//===----------------------------------------------------------------------===//
272// RegionRange
273//===----------------------------------------------------------------------===//
274
276 : RegionRange(regions.data(), regions.size()) {}
277RegionRange::RegionRange(ArrayRef<std::unique_ptr<Region>> regions)
278 : RegionRange(regions.data(), regions.size()) {}
280 : RegionRange(const_cast<Region **>(regions.data()), regions.size()) {}
281
282/// See `llvm::detail::indexed_accessor_range_base` for details.
283RegionRange::OwnerT RegionRange::offset_base(const OwnerT &owner,
284 ptrdiff_t index) {
285 if (auto *region = llvm::dyn_cast_if_present<const std::unique_ptr<Region> *>(owner))
286 return region + index;
287 if (auto **region = llvm::dyn_cast_if_present<Region **>(owner))
288 return region + index;
289 return &cast<Region *>(owner)[index];
290}
291/// See `llvm::detail::indexed_accessor_range_base` for details.
292Region *RegionRange::dereference_iterator(const OwnerT &owner,
293 ptrdiff_t index) {
294 if (auto *region = llvm::dyn_cast_if_present<const std::unique_ptr<Region> *>(owner))
295 return region[index].get();
296 if (auto **region = llvm::dyn_cast_if_present<Region **>(owner))
297 return region[index];
298 return &cast<Region *>(owner)[index];
299}
b
Return true if permutation is a valid permutation of the outer_dims_perm (case OuterOrInnerPerm::Oute...
Block represents an ordered list of Operations.
Definition Block.h:33
iterator_range< args_iterator > addArguments(TypeRange types, ArrayRef< Location > locs)
Add one argument to the argument list for each type specified in the list.
Definition Block.cpp:160
Region * getParent() const
Provide a 'getParent' method for ilist_node_with_parent methods.
Definition Block.cpp:27
BlockArgument addArgument(Type type, Location loc)
Add one value to the argument list.
Definition Block.cpp:153
BlockArgListType getArguments()
Definition Block.h:87
void push_back(Operation *op)
Definition Block.h:149
Operation * getParentOp()
Returns the closest surrounding operation that contains this block.
Definition Block.cpp:31
This is a utility class for mapping one set of IR entities to another.
Definition IRMapping.h:26
auto lookup(T from) const
Lookup a mapped value within the map.
Definition IRMapping.h:72
void map(Value from, Value to)
Inserts a new mapping for 'from' to 'to'.
Definition IRMapping.h:30
bool contains(T from) const
Checks to see if a mapping for 'from' exists.
Definition IRMapping.h:51
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition Location.h:76
MLIRContext is the top-level object for a collection of MLIR operations.
Definition MLIRContext.h:63
Set of flags used to control the behavior of the various IR print methods (e.g.
A wrapper class that allows for printing an operation with a set of flags, useful to act as a "stream...
Definition Operation.h:1111
static CloneOptions all()
Returns an instance with all flags set to true.
CloneOptions & cloneRegions(bool enable=true)
Configures whether cloning should traverse into any of the regions of the operation.
CloneOptions & cloneOperands(bool enable=true)
Configures whether operation' operands should be cloned.
Operation is the basic unit of execution within MLIR.
Definition Operation.h:88
Block * getBlock()
Returns the operation block that contains this operation.
Definition Operation.h:213
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
Definition Operation.h:234
unsigned getNumOperands()
Definition Operation.h:346
OperationName getName()
The name of an operation is the key identifier for it.
Definition Operation.h:119
MutableArrayRef< Region > getRegions()
Returns the regions held by this operation.
Definition Operation.h:677
operand_range getOperands()
Returns an iterator on the underlying Value's.
Definition Operation.h:378
Region * getParentRegion()
Returns the region to which the instruction belongs.
Definition Operation.h:230
RegionRange(MutableArrayRef< Region > regions={})
Definition Region.cpp:275
This class provides iteration over the held operations of blocks directly within a region.
Definition Region.h:134
OpIterator(Region *region, bool end=false)
Initialize OpIterator for a region, specify end to return the iterator to last operation.
Definition Region.cpp:226
OpIterator & operator++()
Definition Region.cpp:232
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Definition Region.h:26
Block & front()
Definition Region.h:65
Region * getParentRegion()
Return the region containing this region or nullptr if the region is attached to a top-level operatio...
Definition Region.cpp:45
BlockArgListType getArguments()
Definition Region.h:81
iterator_range< args_iterator > addArguments(TypeRange types, ArrayRef< Location > locs)
Add one argument to the argument list for each type specified in the list.
Definition Region.cpp:41
Operation * findAncestorOpInRegion(Operation &op)
Returns 'op' if 'op' lies in this region, or otherwise finds the ancestor of 'op' that lies in this r...
Definition Region.cpp:168
unsigned getRegionNumber()
Return the number of this region in the parent operation.
Definition Region.cpp:62
void dropAllReferences()
Drop all operand uses from operations within this region, which is an essential step in breaking cycl...
Definition Region.cpp:181
static BlockListType Region::* getSublistAccess(Block *)
getSublistAccess() - Returns pointer to member of region.
Definition Region.h:71
bool empty()
Definition Region.h:60
void cloneInto(Region *dest, IRMapping &mapper)
Clone the internal blocks from this region into dest.
Definition Region.cpp:70
iterator end()
Definition Region.h:56
bool isProperAncestor(Region *other)
Return true if this region is a proper ancestor of the other region.
Definition Region.cpp:50
iterator begin()
Definition Region.h:55
Region()=default
Location getLoc()
Return a location for this region.
Definition Region.cpp:31
ValueTypeRange< BlockArgListType > getArgumentTypes()
Returns the argument types of the first block within the region.
Definition Region.cpp:36
Operation * getParentOp()
Return the parent operation this region is attached to.
Definition Region.h:200
MLIRContext * getContext()
Return the context this region is inserted in.
Definition Region.cpp:24
BlockListType & getBlocks()
Definition Region.h:45
BlockListType::iterator iterator
Definition Region.h:52
Block * findAncestorBlockInRegion(Block &block)
Returns 'block' if 'block' lies in this region, or otherwise finds the ancestor of 'block' that lies ...
Definition Region.cpp:154
This class provides an abstraction over the various different ranges of value types.
Definition TypeRange.h:37
This class implements iteration on the types of a given range of values.
Definition TypeRange.h:135
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition Value.h:96
Include the generated interface declarations.
raw_ostream & operator<<(raw_ostream &os, const AliasResult &result)
Operation * clone(OpBuilder &b, Operation *op, TypeRange newResultTypes, ValueRange newOperands)
void transferNodesFromList(ilist_traits< Block > &otherList, block_iterator first, block_iterator last)
This is a trait method invoked when an operation is moved from one block to another.
Definition Region.cpp:209
simple_ilist<::mlir::Block >::iterator block_iterator
void removeNodeFromList(Block *block)
This is a trait method invoked when an operation is removed from a region.
Definition Region.cpp:202
void addNodeToList(Block *block)
This is a trait method invoked when a basic block is added to a region.
Definition Region.cpp:195