MLIR  19.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"
12 using namespace mlir;
13 
14 Region::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 
37  return ValueTypeRange<BlockArgListType>(getArguments());
38 }
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.
70 void 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 BlockAndValueMapper 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 
186 Region *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 
244 void 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 
256 //===----------------------------------------------------------------------===//
257 // RegionRange
258 //===----------------------------------------------------------------------===//
259 
261  : RegionRange(regions.data(), regions.size()) {}
262 RegionRange::RegionRange(ArrayRef<std::unique_ptr<Region>> regions)
263  : RegionRange(regions.data(), regions.size()) {}
265  : RegionRange(const_cast<Region **>(regions.data()), regions.size()) {}
266 
267 /// See `llvm::detail::indexed_accessor_range_base` for details.
268 RegionRange::OwnerT RegionRange::offset_base(const OwnerT &owner,
269  ptrdiff_t index) {
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];
275 }
276 /// See `llvm::detail::indexed_accessor_range_base` for details.
277 Region *RegionRange::dereference_iterator(const OwnerT &owner,
278  ptrdiff_t index) {
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];
284 }
Block represents an ordered list of Operations.
Definition: Block.h:30
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:159
Region * getParent() const
Provide a 'getParent' method for ilist_node_with_parent methods.
Definition: Block.cpp:26
BlockArgument addArgument(Type type, Location loc)
Add one value to the argument list.
Definition: Block.cpp:152
BlockArgListType getArguments()
Definition: Block.h:84
void dropAllReferences()
This drops all operand uses from operations within this block, which is an essential step in breaking...
Definition: Block.cpp:88
void push_back(Operation *op)
Definition: Block.h:146
Operation * getParentOp()
Returns the closest surrounding operation that contains this block.
Definition: Block.cpp:30
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:63
MLIRContext is the top-level object for a collection of MLIR operations.
Definition: MLIRContext.h:60
static CloneOptions all()
Returns an instance with all flags set to true.
Definition: Operation.cpp:685
CloneOptions & cloneRegions(bool enable=true)
Configures whether cloning should traverse into any of the regions of the operation.
Definition: Operation.cpp:689
CloneOptions & cloneOperands(bool enable=true)
Configures whether operation' operands should be cloned.
Definition: Operation.cpp:694
Operation is the basic unit of execution within MLIR.
Definition: Operation.h:88
Operation * clone(IRMapping &mapper, CloneOptions options=CloneOptions::all())
Create a deep copy of this operation, remapping any operands that use values outside of the operation...
Definition: Operation.cpp:717
MLIRContext * getContext()
Return the context this operation is associated with.
Definition: Operation.h:216
Location getLoc()
The source location the operation was defined or derived from.
Definition: Operation.h:223
unsigned getNumOperands()
Definition: Operation.h:341
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
Definition: Operation.h:234
Block * getBlock()
Returns the operation block that contains this operation.
Definition: Operation.h:213
MutableArrayRef< Region > getRegions()
Returns the regions held by this operation.
Definition: Operation.h:672
operand_range getOperands()
Returns an iterator on the underlying Value's.
Definition: Operation.h:373
void setOperands(ValueRange operands)
Replace the current operands of this operation with the ones provided in 'operands'.
Definition: Operation.cpp:237
Region * getParentRegion()
Returns the region to which the instruction belongs.
Definition: Operation.h:230
This class provides an abstraction over the different types of ranges over Regions.
Definition: Region.h:346
RegionRange(MutableArrayRef< Region > regions=std::nullopt)
Definition: Region.cpp:260
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
Region * getParentRegion()
Return the region containing this region or nullptr if the region is attached to a top-level operatio...
Definition: Region.cpp:45
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
Operation * getParentOp()
Return the parent operation this region is attached to.
Definition: Region.h:200
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
Region()=default
BlockListType & getBlocks()
Definition: Region.h:45
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
MLIRContext * getContext()
Return the context this region is inserted in.
Definition: Region.cpp:24
Block & front()
Definition: Region.h:65
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:36
This class implements iteration on the types of a given range of values.
Definition: TypeRange.h:131
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.
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
Definition: BlockSupport.h:247
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