/home/arjun/llvm-project/mlir/include/mlir/IR/Block.h
Line | Count | Source (jump to first uncovered line) |
1 | | //===- Block.h - MLIR Block Class -------------------------------*- C++ -*-===// |
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 | | // This file defines the Block class. |
10 | | // |
11 | | //===----------------------------------------------------------------------===// |
12 | | |
13 | | #ifndef MLIR_IR_BLOCK_H |
14 | | #define MLIR_IR_BLOCK_H |
15 | | |
16 | | #include "mlir/IR/BlockSupport.h" |
17 | | #include "mlir/IR/Visitors.h" |
18 | | |
19 | | namespace mlir { |
20 | | class TypeRange; |
21 | | template <typename ValueRangeT> class ValueTypeRange; |
22 | | |
23 | | /// `Block` represents an ordered list of `Operation`s. |
24 | | class Block : public IRObjectWithUseList<BlockOperand>, |
25 | | public llvm::ilist_node_with_parent<Block, Region> { |
26 | | public: |
27 | 0 | explicit Block() {} |
28 | | ~Block(); |
29 | | |
30 | 0 | void clear() { |
31 | 0 | // Drop all references from within this block. |
32 | 0 | dropAllReferences(); |
33 | 0 |
|
34 | 0 | // Clear operations in the reverse order so that uses are destroyed |
35 | 0 | // before their defs. |
36 | 0 | while (!empty()) |
37 | 0 | operations.pop_back(); |
38 | 0 | } |
39 | | |
40 | | /// Provide a 'getParent' method for ilist_node_with_parent methods. |
41 | | /// We mark it as a const function because ilist_node_with_parent specifically |
42 | | /// requires a 'getParent() const' method. Once ilist_node removes this |
43 | | /// constraint, we should drop the const to fit the rest of the MLIR const |
44 | | /// model. |
45 | | Region *getParent() const; |
46 | | |
47 | | /// Returns the closest surrounding operation that contains this block. |
48 | | Operation *getParentOp(); |
49 | | |
50 | | /// Return if this block is the entry block in the parent region. |
51 | | bool isEntryBlock(); |
52 | | |
53 | | /// Insert this block (which must not already be in a region) right before |
54 | | /// the specified block. |
55 | | void insertBefore(Block *block); |
56 | | |
57 | | /// Unlink this block from its current region and insert it right before the |
58 | | /// specific block. |
59 | | void moveBefore(Block *block); |
60 | | |
61 | | /// Unlink this Block from its parent region and delete it. |
62 | | void erase(); |
63 | | |
64 | | //===--------------------------------------------------------------------===// |
65 | | // Block argument management |
66 | | //===--------------------------------------------------------------------===// |
67 | | |
68 | | // This is the list of arguments to the block. |
69 | | using BlockArgListType = MutableArrayRef<BlockArgument>; |
70 | | |
71 | 0 | BlockArgListType getArguments() { return arguments; } |
72 | | |
73 | | /// Return a range containing the types of the arguments for this block. |
74 | | ValueTypeRange<BlockArgListType> getArgumentTypes(); |
75 | | |
76 | | using args_iterator = BlockArgListType::iterator; |
77 | | using reverse_args_iterator = BlockArgListType::reverse_iterator; |
78 | 0 | args_iterator args_begin() { return getArguments().begin(); } |
79 | 0 | args_iterator args_end() { return getArguments().end(); } |
80 | 0 | reverse_args_iterator args_rbegin() { return getArguments().rbegin(); } |
81 | 0 | reverse_args_iterator args_rend() { return getArguments().rend(); } |
82 | | |
83 | 0 | bool args_empty() { return arguments.empty(); } |
84 | | |
85 | | /// Add one value to the argument list. |
86 | | BlockArgument addArgument(Type type); |
87 | | |
88 | | /// Insert one value to the position in the argument list indicated by the |
89 | | /// given iterator. The existing arguments are shifted. The block is expected |
90 | | /// not to have predecessors. |
91 | | BlockArgument insertArgument(args_iterator it, Type type); |
92 | | |
93 | | /// Add one argument to the argument list for each type specified in the list. |
94 | | iterator_range<args_iterator> addArguments(TypeRange types); |
95 | | |
96 | | /// Add one value to the argument list at the specified position. |
97 | | BlockArgument insertArgument(unsigned index, Type type); |
98 | | |
99 | | /// Erase the argument at 'index' and remove it from the argument list. |
100 | | void eraseArgument(unsigned index); |
101 | | |
102 | 0 | unsigned getNumArguments() { return arguments.size(); } |
103 | 0 | BlockArgument getArgument(unsigned i) { return arguments[i]; } |
104 | | |
105 | | //===--------------------------------------------------------------------===// |
106 | | // Operation list management |
107 | | //===--------------------------------------------------------------------===// |
108 | | |
109 | | /// This is the list of operations in the block. |
110 | | using OpListType = llvm::iplist<Operation>; |
111 | 0 | OpListType &getOperations() { return operations; } |
112 | | |
113 | | // Iteration over the operations in the block. |
114 | | using iterator = OpListType::iterator; |
115 | | using reverse_iterator = OpListType::reverse_iterator; |
116 | | |
117 | 0 | iterator begin() { return operations.begin(); } |
118 | 0 | iterator end() { return operations.end(); } |
119 | 0 | reverse_iterator rbegin() { return operations.rbegin(); } |
120 | 0 | reverse_iterator rend() { return operations.rend(); } |
121 | | |
122 | 0 | bool empty() { return operations.empty(); } |
123 | 0 | void push_back(Operation *op) { operations.push_back(op); } |
124 | 0 | void push_front(Operation *op) { operations.push_front(op); } |
125 | | |
126 | 0 | Operation &back() { return operations.back(); } |
127 | 0 | Operation &front() { return operations.front(); } |
128 | | |
129 | | /// Returns 'op' if 'op' lies in this block, or otherwise finds the |
130 | | /// ancestor operation of 'op' that lies in this block. Returns nullptr if |
131 | | /// the latter fails. |
132 | | /// TODO: This is very specific functionality that should live somewhere else, |
133 | | /// probably in Dominance.cpp. |
134 | | Operation *findAncestorOpInBlock(Operation &op); |
135 | | |
136 | | /// This drops all operand uses from operations within this block, which is |
137 | | /// an essential step in breaking cyclic dependences between references when |
138 | | /// they are to be deleted. |
139 | | void dropAllReferences(); |
140 | | |
141 | | /// This drops all uses of values defined in this block or in the blocks of |
142 | | /// nested regions wherever the uses are located. |
143 | | void dropAllDefinedValueUses(); |
144 | | |
145 | | /// Returns true if the ordering of the child operations is valid, false |
146 | | /// otherwise. |
147 | | bool isOpOrderValid(); |
148 | | |
149 | | /// Invalidates the current ordering of operations. |
150 | | void invalidateOpOrder(); |
151 | | |
152 | | /// Verifies the current ordering of child operations matches the |
153 | | /// validOpOrder flag. Returns false if the order is valid, true otherwise. |
154 | | bool verifyOpOrder(); |
155 | | |
156 | | /// Recomputes the ordering of child operations within the block. |
157 | | void recomputeOpOrder(); |
158 | | |
159 | | /// This class provides iteration over the held operations of a block for a |
160 | | /// specific operation type. |
161 | | template <typename OpT> |
162 | | using op_iterator = detail::op_iterator<OpT, iterator>; |
163 | | |
164 | | /// Return an iterator range over the operations within this block that are of |
165 | | /// 'OpT'. |
166 | | template <typename OpT> iterator_range<op_iterator<OpT>> getOps() { |
167 | | auto endIt = end(); |
168 | | return {detail::op_filter_iterator<OpT, iterator>(begin(), endIt), |
169 | | detail::op_filter_iterator<OpT, iterator>(endIt, endIt)}; |
170 | | } |
171 | | template <typename OpT> op_iterator<OpT> op_begin() { |
172 | | return detail::op_filter_iterator<OpT, iterator>(begin(), end()); |
173 | | } |
174 | | template <typename OpT> op_iterator<OpT> op_end() { |
175 | | return detail::op_filter_iterator<OpT, iterator>(end(), end()); |
176 | | } |
177 | | |
178 | | /// Return an iterator range over the operation within this block excluding |
179 | | /// the terminator operation at the end. |
180 | 0 | iterator_range<iterator> without_terminator() { |
181 | 0 | if (begin() == end()) |
182 | 0 | return {begin(), end()}; |
183 | 0 | auto endIt = --end(); |
184 | 0 | return {begin(), endIt}; |
185 | 0 | } |
186 | | |
187 | | //===--------------------------------------------------------------------===// |
188 | | // Terminator management |
189 | | //===--------------------------------------------------------------------===// |
190 | | |
191 | | /// Get the terminator operation of this block. This function asserts that |
192 | | /// the block has a valid terminator operation. |
193 | | Operation *getTerminator(); |
194 | | |
195 | | //===--------------------------------------------------------------------===// |
196 | | // Predecessors and successors. |
197 | | //===--------------------------------------------------------------------===// |
198 | | |
199 | | // Predecessor iteration. |
200 | | using pred_iterator = PredecessorIterator; |
201 | 0 | pred_iterator pred_begin() { |
202 | 0 | return pred_iterator((BlockOperand *)getFirstUse()); |
203 | 0 | } |
204 | 0 | pred_iterator pred_end() { return pred_iterator(nullptr); } |
205 | 0 | iterator_range<pred_iterator> getPredecessors() { |
206 | 0 | return {pred_begin(), pred_end()}; |
207 | 0 | } |
208 | | |
209 | | /// Return true if this block has no predecessors. |
210 | | bool hasNoPredecessors(); |
211 | | |
212 | | /// If this block has exactly one predecessor, return it. Otherwise, return |
213 | | /// null. |
214 | | /// |
215 | | /// Note that if a block has duplicate predecessors from a single block (e.g. |
216 | | /// if you have a conditional branch with the same block as the true/false |
217 | | /// destinations) is not considered to be a single predecessor. |
218 | | Block *getSinglePredecessor(); |
219 | | |
220 | | /// If this block has a unique predecessor, i.e., all incoming edges originate |
221 | | /// from one block, return it. Otherwise, return null. |
222 | | Block *getUniquePredecessor(); |
223 | | |
224 | | // Indexed successor access. |
225 | | unsigned getNumSuccessors(); |
226 | | Block *getSuccessor(unsigned i); |
227 | | |
228 | | // Successor iteration. |
229 | | using succ_iterator = SuccessorRange::iterator; |
230 | 0 | succ_iterator succ_begin() { return getSuccessors().begin(); } |
231 | 0 | succ_iterator succ_end() { return getSuccessors().end(); } |
232 | 0 | SuccessorRange getSuccessors() { return SuccessorRange(this); } |
233 | | |
234 | | //===--------------------------------------------------------------------===// |
235 | | // Operation Walkers |
236 | | //===--------------------------------------------------------------------===// |
237 | | |
238 | | /// Walk the operations in this block in postorder, calling the callback for |
239 | | /// each operation. |
240 | | /// See Operation::walk for more details. |
241 | | template <typename FnT, typename RetT = detail::walkResultType<FnT>> |
242 | 0 | RetT walk(FnT &&callback) { |
243 | 0 | return walk(begin(), end(), std::forward<FnT>(callback)); |
244 | 0 | } Unexecuted instantiation: Ops.cpp:_ZN4mlir5Block4walkIRZL6verifyNS_18GenericAtomicRMWOpEE4$_24NS_10WalkResultEEET0_OT_ Unexecuted instantiation: Region.cpp:_ZN4mlir5Block4walkIRZNS_6Region9cloneIntoEPS2_N4llvm14ilist_iteratorINS4_12ilist_detail12node_optionsIS0_Lb1ELb0EvEELb0ELb0EEERNS_20BlockAndValueMappingEE3$_0vEET0_OT_ |
245 | | |
246 | | /// Walk the operations in the specified [begin, end) range of this block in |
247 | | /// postorder, calling the callback for each operation. This method is invoked |
248 | | /// for void return callbacks. |
249 | | /// See Operation::walk for more details. |
250 | | template <typename FnT, typename RetT = detail::walkResultType<FnT>> |
251 | | typename std::enable_if<std::is_same<RetT, void>::value, RetT>::type |
252 | 0 | walk(Block::iterator begin, Block::iterator end, FnT &&callback) { |
253 | 0 | for (auto &op : llvm::make_early_inc_range(llvm::make_range(begin, end))) |
254 | 0 | detail::walkOperations(&op, callback); |
255 | 0 | } |
256 | | |
257 | | /// Walk the operations in the specified [begin, end) range of this block in |
258 | | /// postorder, calling the callback for each operation. This method is invoked |
259 | | /// for interruptible callbacks. |
260 | | /// See Operation::walk for more details. |
261 | | template <typename FnT, typename RetT = detail::walkResultType<FnT>> |
262 | | typename std::enable_if<std::is_same<RetT, WalkResult>::value, RetT>::type |
263 | 0 | walk(Block::iterator begin, Block::iterator end, FnT &&callback) { |
264 | 0 | for (auto &op : llvm::make_early_inc_range(llvm::make_range(begin, end))) |
265 | 0 | if (detail::walkOperations(&op, callback).wasInterrupted()) |
266 | 0 | return WalkResult::interrupt(); |
267 | 0 | return WalkResult::advance(); |
268 | 0 | } |
269 | | |
270 | | //===--------------------------------------------------------------------===// |
271 | | // Other |
272 | | //===--------------------------------------------------------------------===// |
273 | | |
274 | | /// Split the block into two blocks before the specified operation or |
275 | | /// iterator. |
276 | | /// |
277 | | /// Note that all operations BEFORE the specified iterator stay as part of |
278 | | /// the original basic block, and the rest of the operations in the original |
279 | | /// block are moved to the new block, including the old terminator. The |
280 | | /// original block is left without a terminator. |
281 | | /// |
282 | | /// The newly formed Block is returned, and the specified iterator is |
283 | | /// invalidated. |
284 | | Block *splitBlock(iterator splitBefore); |
285 | 0 | Block *splitBlock(Operation *splitBeforeOp) { |
286 | 0 | return splitBlock(iterator(splitBeforeOp)); |
287 | 0 | } |
288 | | |
289 | | /// Returns pointer to member of operation list. |
290 | 0 | static OpListType Block::*getSublistAccess(Operation *) { |
291 | 0 | return &Block::operations; |
292 | 0 | } |
293 | | |
294 | | void print(raw_ostream &os); |
295 | | void print(raw_ostream &os, AsmState &state); |
296 | | void dump(); |
297 | | |
298 | | /// Print out the name of the block without printing its body. |
299 | | /// NOTE: The printType argument is ignored. We keep it for compatibility |
300 | | /// with LLVM dominator machinery that expects it to exist. |
301 | | void printAsOperand(raw_ostream &os, bool printType = true); |
302 | | void printAsOperand(raw_ostream &os, AsmState &state); |
303 | | |
304 | | private: |
305 | | /// Pair of the parent object that owns this block and a bit that signifies if |
306 | | /// the operations within this block have a valid ordering. |
307 | | llvm::PointerIntPair<Region *, /*IntBits=*/1, bool> parentValidOpOrderPair; |
308 | | |
309 | | /// This is the list of operations in the block. |
310 | | OpListType operations; |
311 | | |
312 | | /// This is the list of arguments to the block. |
313 | | std::vector<BlockArgument> arguments; |
314 | | |
315 | | Block(Block &) = delete; |
316 | | void operator=(Block &) = delete; |
317 | | |
318 | | friend struct llvm::ilist_traits<Block>; |
319 | | }; |
320 | | } // end namespace mlir |
321 | | |
322 | | #endif // MLIR_IR_BLOCK_H |