/home/arjun/llvm-project/mlir/lib/IR/Block.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===- Block.cpp - MLIR Block 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/Block.h" |
10 | | #include "mlir/IR/Builders.h" |
11 | | #include "mlir/IR/Operation.h" |
12 | | using namespace mlir; |
13 | | |
14 | | //===----------------------------------------------------------------------===// |
15 | | // BlockArgument |
16 | | //===----------------------------------------------------------------------===// |
17 | | |
18 | | /// Returns the number of this argument. |
19 | 0 | unsigned BlockArgument::getArgNumber() const { |
20 | 0 | // Arguments are not stored in place, so we have to find it within the list. |
21 | 0 | auto argList = getOwner()->getArguments(); |
22 | 0 | return std::distance(argList.begin(), llvm::find(argList, *this)); |
23 | 0 | } |
24 | | |
25 | | //===----------------------------------------------------------------------===// |
26 | | // Block |
27 | | //===----------------------------------------------------------------------===// |
28 | | |
29 | | Block::~Block() { |
30 | | assert(!verifyOpOrder() && "Expected valid operation ordering."); |
31 | | clear(); |
32 | | for (BlockArgument arg : arguments) |
33 | | arg.destroy(); |
34 | | } |
35 | | |
36 | 0 | Region *Block::getParent() const { return parentValidOpOrderPair.getPointer(); } |
37 | | |
38 | | /// Returns the closest surrounding operation that contains this block or |
39 | | /// nullptr if this block is unlinked. |
40 | 0 | Operation *Block::getParentOp() { |
41 | 0 | return getParent() ? getParent()->getParentOp() : nullptr; |
42 | 0 | } |
43 | | |
44 | | /// Return if this block is the entry block in the parent region. |
45 | 0 | bool Block::isEntryBlock() { return this == &getParent()->front(); } |
46 | | |
47 | | /// Insert this block (which must not already be in a region) right before the |
48 | | /// specified block. |
49 | 0 | void Block::insertBefore(Block *block) { |
50 | 0 | assert(!getParent() && "already inserted into a block!"); |
51 | 0 | assert(block->getParent() && "cannot insert before a block without a parent"); |
52 | 0 | block->getParent()->getBlocks().insert(block->getIterator(), this); |
53 | 0 | } |
54 | | |
55 | | /// Unlink this block from its current region and insert it right before the |
56 | | /// specific block. |
57 | 0 | void Block::moveBefore(Block *block) { |
58 | 0 | assert(block->getParent() && "cannot insert before a block without a parent"); |
59 | 0 | block->getParent()->getBlocks().splice( |
60 | 0 | block->getIterator(), getParent()->getBlocks(), getIterator()); |
61 | 0 | } |
62 | | |
63 | | /// Unlink this Block from its parent Region and delete it. |
64 | 0 | void Block::erase() { |
65 | 0 | assert(getParent() && "Block has no parent"); |
66 | 0 | getParent()->getBlocks().erase(this); |
67 | 0 | } |
68 | | |
69 | | /// Returns 'op' if 'op' lies in this block, or otherwise finds the |
70 | | /// ancestor operation of 'op' that lies in this block. Returns nullptr if |
71 | | /// the latter fails. |
72 | 0 | Operation *Block::findAncestorOpInBlock(Operation &op) { |
73 | 0 | // Traverse up the operation hierarchy starting from the owner of operand to |
74 | 0 | // find the ancestor operation that resides in the block of 'forOp'. |
75 | 0 | auto *currOp = &op; |
76 | 0 | while (currOp->getBlock() != this) { |
77 | 0 | currOp = currOp->getParentOp(); |
78 | 0 | if (!currOp) |
79 | 0 | return nullptr; |
80 | 0 | } |
81 | 0 | return currOp; |
82 | 0 | } |
83 | | |
84 | | /// This drops all operand uses from operations within this block, which is |
85 | | /// an essential step in breaking cyclic dependences between references when |
86 | | /// they are to be deleted. |
87 | 0 | void Block::dropAllReferences() { |
88 | 0 | for (Operation &i : *this) |
89 | 0 | i.dropAllReferences(); |
90 | 0 | } |
91 | | |
92 | 0 | void Block::dropAllDefinedValueUses() { |
93 | 0 | for (auto arg : getArguments()) |
94 | 0 | arg.dropAllUses(); |
95 | 0 | for (auto &op : *this) |
96 | 0 | op.dropAllDefinedValueUses(); |
97 | 0 | dropAllUses(); |
98 | 0 | } |
99 | | |
100 | | /// Returns true if the ordering of the child operations is valid, false |
101 | | /// otherwise. |
102 | 0 | bool Block::isOpOrderValid() { return parentValidOpOrderPair.getInt(); } |
103 | | |
104 | | /// Invalidates the current ordering of operations. |
105 | 0 | void Block::invalidateOpOrder() { |
106 | 0 | // Validate the current ordering. |
107 | 0 | assert(!verifyOpOrder()); |
108 | 0 | parentValidOpOrderPair.setInt(false); |
109 | 0 | } |
110 | | |
111 | | /// Verifies the current ordering of child operations. Returns false if the |
112 | | /// order is valid, true otherwise. |
113 | 0 | bool Block::verifyOpOrder() { |
114 | 0 | // The order is already known to be invalid. |
115 | 0 | if (!isOpOrderValid()) |
116 | 0 | return false; |
117 | 0 | // The order is valid if there are less than 2 operations. |
118 | 0 | if (operations.empty() || std::next(operations.begin()) == operations.end()) |
119 | 0 | return false; |
120 | 0 | |
121 | 0 | Operation *prev = nullptr; |
122 | 0 | for (auto &i : *this) { |
123 | 0 | // The previous operation must have a smaller order index than the next as |
124 | 0 | // it appears earlier in the list. |
125 | 0 | if (prev && prev->orderIndex != Operation::kInvalidOrderIdx && |
126 | 0 | prev->orderIndex >= i.orderIndex) |
127 | 0 | return true; |
128 | 0 | prev = &i; |
129 | 0 | } |
130 | 0 | return false; |
131 | 0 | } |
132 | | |
133 | | /// Recomputes the ordering of child operations within the block. |
134 | 0 | void Block::recomputeOpOrder() { |
135 | 0 | parentValidOpOrderPair.setInt(true); |
136 | 0 |
|
137 | 0 | unsigned orderIndex = 0; |
138 | 0 | for (auto &op : *this) |
139 | 0 | op.orderIndex = (orderIndex += Operation::kOrderStride); |
140 | 0 | } |
141 | | |
142 | | //===----------------------------------------------------------------------===// |
143 | | // Argument list management. |
144 | | //===----------------------------------------------------------------------===// |
145 | | |
146 | | /// Return a range containing the types of the arguments for this block. |
147 | 0 | auto Block::getArgumentTypes() -> ValueTypeRange<BlockArgListType> { |
148 | 0 | return ValueTypeRange<BlockArgListType>(getArguments()); |
149 | 0 | } |
150 | | |
151 | 0 | BlockArgument Block::addArgument(Type type) { |
152 | 0 | BlockArgument arg = BlockArgument::create(type, this); |
153 | 0 | arguments.push_back(arg); |
154 | 0 | return arg; |
155 | 0 | } |
156 | | |
157 | | /// Add one argument to the argument list for each type specified in the list. |
158 | 0 | auto Block::addArguments(TypeRange types) -> iterator_range<args_iterator> { |
159 | 0 | size_t initialSize = arguments.size(); |
160 | 0 | arguments.reserve(initialSize + types.size()); |
161 | 0 | for (auto type : types) |
162 | 0 | addArgument(type); |
163 | 0 | return {arguments.data() + initialSize, arguments.data() + arguments.size()}; |
164 | 0 | } |
165 | | |
166 | 0 | BlockArgument Block::insertArgument(unsigned index, Type type) { |
167 | 0 | auto arg = BlockArgument::create(type, this); |
168 | 0 | assert(index <= arguments.size()); |
169 | 0 | arguments.insert(arguments.begin() + index, arg); |
170 | 0 | return arg; |
171 | 0 | } |
172 | | |
173 | 0 | void Block::eraseArgument(unsigned index) { |
174 | 0 | assert(index < arguments.size()); |
175 | 0 | arguments[index].destroy(); |
176 | 0 | arguments.erase(arguments.begin() + index); |
177 | 0 | } |
178 | | |
179 | | /// Insert one value to the given position of the argument list. The existing |
180 | | /// arguments are shifted. The block is expected not to have predecessors. |
181 | 0 | BlockArgument Block::insertArgument(args_iterator it, Type type) { |
182 | 0 | assert(llvm::empty(getPredecessors()) && |
183 | 0 | "cannot insert arguments to blocks with predecessors"); |
184 | 0 |
|
185 | 0 | // Use the args_iterator (on the BlockArgListType) to compute the insertion |
186 | 0 | // iterator in the underlying argument storage. |
187 | 0 | size_t distance = std::distance(args_begin(), it); |
188 | 0 | auto arg = BlockArgument::create(type, this); |
189 | 0 | arguments.insert(std::next(arguments.begin(), distance), arg); |
190 | 0 | return arg; |
191 | 0 | } |
192 | | |
193 | | //===----------------------------------------------------------------------===// |
194 | | // Terminator management |
195 | | //===----------------------------------------------------------------------===// |
196 | | |
197 | | /// Get the terminator operation of this block. This function asserts that |
198 | | /// the block has a valid terminator operation. |
199 | 0 | Operation *Block::getTerminator() { |
200 | 0 | assert(!empty() && !back().isKnownNonTerminator()); |
201 | 0 | return &back(); |
202 | 0 | } |
203 | | |
204 | | /// Return true if this block has no predecessors. |
205 | 0 | bool Block::hasNoPredecessors() { return pred_begin() == pred_end(); } |
206 | | |
207 | | // Indexed successor access. |
208 | 0 | unsigned Block::getNumSuccessors() { |
209 | 0 | return empty() ? 0 : back().getNumSuccessors(); |
210 | 0 | } |
211 | | |
212 | 0 | Block *Block::getSuccessor(unsigned i) { |
213 | 0 | assert(i < getNumSuccessors()); |
214 | 0 | return getTerminator()->getSuccessor(i); |
215 | 0 | } |
216 | | |
217 | | /// If this block has exactly one predecessor, return it. Otherwise, return |
218 | | /// null. |
219 | | /// |
220 | | /// Note that multiple edges from a single block (e.g. if you have a cond |
221 | | /// branch with the same block as the true/false destinations) is not |
222 | | /// considered to be a single predecessor. |
223 | 0 | Block *Block::getSinglePredecessor() { |
224 | 0 | auto it = pred_begin(); |
225 | 0 | if (it == pred_end()) |
226 | 0 | return nullptr; |
227 | 0 | auto *firstPred = *it; |
228 | 0 | ++it; |
229 | 0 | return it == pred_end() ? firstPred : nullptr; |
230 | 0 | } |
231 | | |
232 | | /// If this block has a unique predecessor, i.e., all incoming edges originate |
233 | | /// from one block, return it. Otherwise, return null. |
234 | 0 | Block *Block::getUniquePredecessor() { |
235 | 0 | auto it = pred_begin(), e = pred_end(); |
236 | 0 | if (it == e) |
237 | 0 | return nullptr; |
238 | 0 | |
239 | 0 | // Check for any conflicting predecessors. |
240 | 0 | auto *firstPred = *it; |
241 | 0 | for (++it; it != e; ++it) |
242 | 0 | if (*it != firstPred) |
243 | 0 | return nullptr; |
244 | 0 | return firstPred; |
245 | 0 | } |
246 | | |
247 | | //===----------------------------------------------------------------------===// |
248 | | // Other |
249 | | //===----------------------------------------------------------------------===// |
250 | | |
251 | | /// Split the block into two blocks before the specified operation or |
252 | | /// iterator. |
253 | | /// |
254 | | /// Note that all operations BEFORE the specified iterator stay as part of |
255 | | /// the original basic block, and the rest of the operations in the original |
256 | | /// block are moved to the new block, including the old terminator. The |
257 | | /// original block is left without a terminator. |
258 | | /// |
259 | | /// The newly formed Block is returned, and the specified iterator is |
260 | | /// invalidated. |
261 | 0 | Block *Block::splitBlock(iterator splitBefore) { |
262 | 0 | // Start by creating a new basic block, and insert it immediate after this |
263 | 0 | // one in the containing region. |
264 | 0 | auto newBB = new Block(); |
265 | 0 | getParent()->getBlocks().insert(std::next(Region::iterator(this)), newBB); |
266 | 0 |
|
267 | 0 | // Move all of the operations from the split point to the end of the region |
268 | 0 | // into the new block. |
269 | 0 | newBB->getOperations().splice(newBB->end(), getOperations(), splitBefore, |
270 | 0 | end()); |
271 | 0 | return newBB; |
272 | 0 | } |
273 | | |
274 | | //===----------------------------------------------------------------------===// |
275 | | // Predecessors |
276 | | //===----------------------------------------------------------------------===// |
277 | | |
278 | 0 | Block *PredecessorIterator::unwrap(BlockOperand &value) { |
279 | 0 | return value.getOwner()->getBlock(); |
280 | 0 | } |
281 | | |
282 | | /// Get the successor number in the predecessor terminator. |
283 | 0 | unsigned PredecessorIterator::getSuccessorIndex() const { |
284 | 0 | return I->getOperandNumber(); |
285 | 0 | } |
286 | | |
287 | | //===----------------------------------------------------------------------===// |
288 | | // Successors |
289 | | //===----------------------------------------------------------------------===// |
290 | | |
291 | 0 | SuccessorRange::SuccessorRange(Block *block) : SuccessorRange(nullptr, 0) { |
292 | 0 | if (Operation *term = block->getTerminator()) |
293 | 0 | if ((count = term->getNumSuccessors())) |
294 | 0 | base = term->getBlockOperands().data(); |
295 | 0 | } |
296 | | |
297 | 0 | SuccessorRange::SuccessorRange(Operation *term) : SuccessorRange(nullptr, 0) { |
298 | 0 | if ((count = term->getNumSuccessors())) |
299 | 0 | base = term->getBlockOperands().data(); |
300 | 0 | } |