File: | build/source/mlir/include/mlir/IR/Value.h |
Warning: | line 122, column 33 Called C++ object pointer is null |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===- ControlFlowInterfaces.cpp - ControlFlow Interfaces -----------------===// | |||
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 <utility> | |||
10 | ||||
11 | #include "mlir/IR/BuiltinTypes.h" | |||
12 | #include "mlir/Interfaces/ControlFlowInterfaces.h" | |||
13 | #include "llvm/ADT/SmallPtrSet.h" | |||
14 | ||||
15 | using namespace mlir; | |||
16 | ||||
17 | //===----------------------------------------------------------------------===// | |||
18 | // ControlFlowInterfaces | |||
19 | //===----------------------------------------------------------------------===// | |||
20 | ||||
21 | #include "mlir/Interfaces/ControlFlowInterfaces.cpp.inc" | |||
22 | ||||
23 | SuccessorOperands::SuccessorOperands(MutableOperandRange forwardedOperands) | |||
24 | : producedOperandCount(0), forwardedOperands(std::move(forwardedOperands)) { | |||
25 | } | |||
26 | ||||
27 | SuccessorOperands::SuccessorOperands(unsigned int producedOperandCount, | |||
28 | MutableOperandRange forwardedOperands) | |||
29 | : producedOperandCount(producedOperandCount), | |||
30 | forwardedOperands(std::move(forwardedOperands)) {} | |||
31 | ||||
32 | //===----------------------------------------------------------------------===// | |||
33 | // BranchOpInterface | |||
34 | //===----------------------------------------------------------------------===// | |||
35 | ||||
36 | /// Returns the `BlockArgument` corresponding to operand `operandIndex` in some | |||
37 | /// successor if 'operandIndex' is within the range of 'operands', or | |||
38 | /// std::nullopt if `operandIndex` isn't a successor operand index. | |||
39 | std::optional<BlockArgument> | |||
40 | detail::getBranchSuccessorArgument(const SuccessorOperands &operands, | |||
41 | unsigned operandIndex, Block *successor) { | |||
42 | OperandRange forwardedOperands = operands.getForwardedOperands(); | |||
43 | // Check that the operands are valid. | |||
44 | if (forwardedOperands.empty()) | |||
45 | return std::nullopt; | |||
46 | ||||
47 | // Check to ensure that this operand is within the range. | |||
48 | unsigned operandsStart = forwardedOperands.getBeginOperandIndex(); | |||
49 | if (operandIndex < operandsStart || | |||
50 | operandIndex >= (operandsStart + forwardedOperands.size())) | |||
51 | return std::nullopt; | |||
52 | ||||
53 | // Index the successor. | |||
54 | unsigned argIndex = | |||
55 | operands.getProducedOperandCount() + operandIndex - operandsStart; | |||
56 | return successor->getArgument(argIndex); | |||
57 | } | |||
58 | ||||
59 | /// Verify that the given operands match those of the given successor block. | |||
60 | LogicalResult | |||
61 | detail::verifyBranchSuccessorOperands(Operation *op, unsigned succNo, | |||
62 | const SuccessorOperands &operands) { | |||
63 | // Check the count. | |||
64 | unsigned operandCount = operands.size(); | |||
65 | Block *destBB = op->getSuccessor(succNo); | |||
66 | if (operandCount != destBB->getNumArguments()) | |||
| ||||
67 | return op->emitError() << "branch has " << operandCount | |||
68 | << " operands for successor #" << succNo | |||
69 | << ", but target block has " | |||
70 | << destBB->getNumArguments(); | |||
71 | ||||
72 | // Check the types. | |||
73 | for (unsigned i = operands.getProducedOperandCount(); i != operandCount; | |||
74 | ++i) { | |||
75 | if (!cast<BranchOpInterface>(op).areTypesCompatible( | |||
76 | operands[i].getType(), destBB->getArgument(i).getType())) | |||
77 | return op->emitError() << "type mismatch for bb argument #" << i | |||
78 | << " of successor #" << succNo; | |||
79 | } | |||
80 | return success(); | |||
81 | } | |||
82 | ||||
83 | //===----------------------------------------------------------------------===// | |||
84 | // RegionBranchOpInterface | |||
85 | //===----------------------------------------------------------------------===// | |||
86 | ||||
87 | /// Verify that types match along all region control flow edges originating from | |||
88 | /// `sourceNo` (region # if source is a region, std::nullopt if source is parent | |||
89 | /// op). `getInputsTypesForRegion` is a function that returns the types of the | |||
90 | /// inputs that flow from `sourceIndex' to the given region, or std::nullopt if | |||
91 | /// the exact type match verification is not necessary (e.g., if the Op verifies | |||
92 | /// the match itself). | |||
93 | static LogicalResult verifyTypesAlongAllEdges( | |||
94 | Operation *op, std::optional<unsigned> sourceNo, | |||
95 | function_ref<std::optional<TypeRange>(std::optional<unsigned>)> | |||
96 | getInputsTypesForRegion) { | |||
97 | auto regionInterface = cast<RegionBranchOpInterface>(op); | |||
98 | ||||
99 | SmallVector<RegionSuccessor, 2> successors; | |||
100 | regionInterface.getSuccessorRegions(sourceNo, successors); | |||
101 | ||||
102 | for (RegionSuccessor &succ : successors) { | |||
103 | std::optional<unsigned> succRegionNo; | |||
104 | if (!succ.isParent()) | |||
105 | succRegionNo = succ.getSuccessor()->getRegionNumber(); | |||
106 | ||||
107 | auto printEdgeName = [&](InFlightDiagnostic &diag) -> InFlightDiagnostic & { | |||
108 | diag << "from "; | |||
109 | if (sourceNo) | |||
110 | diag << "Region #" << sourceNo.value(); | |||
111 | else | |||
112 | diag << "parent operands"; | |||
113 | ||||
114 | diag << " to "; | |||
115 | if (succRegionNo) | |||
116 | diag << "Region #" << succRegionNo.value(); | |||
117 | else | |||
118 | diag << "parent results"; | |||
119 | return diag; | |||
120 | }; | |||
121 | ||||
122 | std::optional<TypeRange> sourceTypes = | |||
123 | getInputsTypesForRegion(succRegionNo); | |||
124 | if (!sourceTypes.has_value()) | |||
125 | continue; | |||
126 | ||||
127 | TypeRange succInputsTypes = succ.getSuccessorInputs().getTypes(); | |||
128 | if (sourceTypes->size() != succInputsTypes.size()) { | |||
129 | InFlightDiagnostic diag = op->emitOpError(" region control flow edge "); | |||
130 | return printEdgeName(diag) << ": source has " << sourceTypes->size() | |||
131 | << " operands, but target successor needs " | |||
132 | << succInputsTypes.size(); | |||
133 | } | |||
134 | ||||
135 | for (const auto &typesIdx : | |||
136 | llvm::enumerate(llvm::zip(*sourceTypes, succInputsTypes))) { | |||
137 | Type sourceType = std::get<0>(typesIdx.value()); | |||
138 | Type inputType = std::get<1>(typesIdx.value()); | |||
139 | if (!regionInterface.areTypesCompatible(sourceType, inputType)) { | |||
140 | InFlightDiagnostic diag = op->emitOpError(" along control flow edge "); | |||
141 | return printEdgeName(diag) | |||
142 | << ": source type #" << typesIdx.index() << " " << sourceType | |||
143 | << " should match input type #" << typesIdx.index() << " " | |||
144 | << inputType; | |||
145 | } | |||
146 | } | |||
147 | } | |||
148 | return success(); | |||
149 | } | |||
150 | ||||
151 | /// Verify that types match along control flow edges described the given op. | |||
152 | LogicalResult detail::verifyTypesAlongControlFlowEdges(Operation *op) { | |||
153 | auto regionInterface = cast<RegionBranchOpInterface>(op); | |||
154 | ||||
155 | auto inputTypesFromParent = | |||
156 | [&](std::optional<unsigned> regionNo) -> TypeRange { | |||
157 | return regionInterface.getSuccessorEntryOperands(regionNo).getTypes(); | |||
158 | }; | |||
159 | ||||
160 | // Verify types along control flow edges originating from the parent. | |||
161 | if (failed(verifyTypesAlongAllEdges(op, std::nullopt, inputTypesFromParent))) | |||
162 | return failure(); | |||
163 | ||||
164 | auto areTypesCompatible = [&](TypeRange lhs, TypeRange rhs) { | |||
165 | if (lhs.size() != rhs.size()) | |||
166 | return false; | |||
167 | for (auto types : llvm::zip(lhs, rhs)) { | |||
168 | if (!regionInterface.areTypesCompatible(std::get<0>(types), | |||
169 | std::get<1>(types))) { | |||
170 | return false; | |||
171 | } | |||
172 | } | |||
173 | return true; | |||
174 | }; | |||
175 | ||||
176 | // Verify types along control flow edges originating from each region. | |||
177 | for (unsigned regionNo : llvm::seq(0U, op->getNumRegions())) { | |||
178 | Region ®ion = op->getRegion(regionNo); | |||
179 | ||||
180 | // Since there can be multiple `ReturnLike` terminators or others | |||
181 | // implementing the `RegionBranchTerminatorOpInterface`, all should have the | |||
182 | // same operand types when passing them to the same region. | |||
183 | ||||
184 | std::optional<OperandRange> regionReturnOperands; | |||
185 | for (Block &block : region) { | |||
186 | Operation *terminator = block.getTerminator(); | |||
187 | auto terminatorOperands = | |||
188 | getRegionBranchSuccessorOperands(terminator, regionNo); | |||
189 | if (!terminatorOperands) | |||
190 | continue; | |||
191 | ||||
192 | if (!regionReturnOperands) { | |||
193 | regionReturnOperands = terminatorOperands; | |||
194 | continue; | |||
195 | } | |||
196 | ||||
197 | // Found more than one ReturnLike terminator. Make sure the operand types | |||
198 | // match with the first one. | |||
199 | if (!areTypesCompatible(regionReturnOperands->getTypes(), | |||
200 | terminatorOperands->getTypes())) | |||
201 | return op->emitOpError("Region #") | |||
202 | << regionNo | |||
203 | << " operands mismatch between return-like terminators"; | |||
204 | } | |||
205 | ||||
206 | auto inputTypesFromRegion = | |||
207 | [&](std::optional<unsigned> regionNo) -> std::optional<TypeRange> { | |||
208 | // If there is no return-like terminator, the op itself should verify | |||
209 | // type consistency. | |||
210 | if (!regionReturnOperands) | |||
211 | return std::nullopt; | |||
212 | ||||
213 | // All successors get the same set of operand types. | |||
214 | return TypeRange(regionReturnOperands->getTypes()); | |||
215 | }; | |||
216 | ||||
217 | if (failed(verifyTypesAlongAllEdges(op, regionNo, inputTypesFromRegion))) | |||
218 | return failure(); | |||
219 | } | |||
220 | ||||
221 | return success(); | |||
222 | } | |||
223 | ||||
224 | /// Return `true` if region `r` is reachable from region `begin` according to | |||
225 | /// the RegionBranchOpInterface (by taking a branch). | |||
226 | static bool isRegionReachable(Region *begin, Region *r) { | |||
227 | assert(begin->getParentOp() == r->getParentOp() &&(static_cast <bool> (begin->getParentOp() == r->getParentOp () && "expected that both regions belong to the same op" ) ? void (0) : __assert_fail ("begin->getParentOp() == r->getParentOp() && \"expected that both regions belong to the same op\"" , "mlir/lib/Interfaces/ControlFlowInterfaces.cpp", 228, __extension__ __PRETTY_FUNCTION__)) | |||
228 | "expected that both regions belong to the same op")(static_cast <bool> (begin->getParentOp() == r->getParentOp () && "expected that both regions belong to the same op" ) ? void (0) : __assert_fail ("begin->getParentOp() == r->getParentOp() && \"expected that both regions belong to the same op\"" , "mlir/lib/Interfaces/ControlFlowInterfaces.cpp", 228, __extension__ __PRETTY_FUNCTION__)); | |||
229 | auto op = cast<RegionBranchOpInterface>(begin->getParentOp()); | |||
230 | SmallVector<bool> visited(op->getNumRegions(), false); | |||
231 | visited[begin->getRegionNumber()] = true; | |||
232 | ||||
233 | // Retrieve all successors of the region and enqueue them in the worklist. | |||
234 | SmallVector<unsigned> worklist; | |||
235 | auto enqueueAllSuccessors = [&](unsigned index) { | |||
236 | SmallVector<RegionSuccessor> successors; | |||
237 | op.getSuccessorRegions(index, successors); | |||
238 | for (RegionSuccessor successor : successors) | |||
239 | if (!successor.isParent()) | |||
240 | worklist.push_back(successor.getSuccessor()->getRegionNumber()); | |||
241 | }; | |||
242 | enqueueAllSuccessors(begin->getRegionNumber()); | |||
243 | ||||
244 | // Process all regions in the worklist via DFS. | |||
245 | while (!worklist.empty()) { | |||
246 | unsigned nextRegion = worklist.pop_back_val(); | |||
247 | if (nextRegion == r->getRegionNumber()) | |||
248 | return true; | |||
249 | if (visited[nextRegion]) | |||
250 | continue; | |||
251 | visited[nextRegion] = true; | |||
252 | enqueueAllSuccessors(nextRegion); | |||
253 | } | |||
254 | ||||
255 | return false; | |||
256 | } | |||
257 | ||||
258 | /// Return `true` if `a` and `b` are in mutually exclusive regions. | |||
259 | /// | |||
260 | /// 1. Find the first common of `a` and `b` (ancestor) that implements | |||
261 | /// RegionBranchOpInterface. | |||
262 | /// 2. Determine the regions `regionA` and `regionB` in which `a` and `b` are | |||
263 | /// contained. | |||
264 | /// 3. Check if `regionA` and `regionB` are mutually exclusive. They are | |||
265 | /// mutually exclusive if they are not reachable from each other as per | |||
266 | /// RegionBranchOpInterface::getSuccessorRegions. | |||
267 | bool mlir::insideMutuallyExclusiveRegions(Operation *a, Operation *b) { | |||
268 | assert(a && "expected non-empty operation")(static_cast <bool> (a && "expected non-empty operation" ) ? void (0) : __assert_fail ("a && \"expected non-empty operation\"" , "mlir/lib/Interfaces/ControlFlowInterfaces.cpp", 268, __extension__ __PRETTY_FUNCTION__)); | |||
269 | assert(b && "expected non-empty operation")(static_cast <bool> (b && "expected non-empty operation" ) ? void (0) : __assert_fail ("b && \"expected non-empty operation\"" , "mlir/lib/Interfaces/ControlFlowInterfaces.cpp", 269, __extension__ __PRETTY_FUNCTION__)); | |||
270 | ||||
271 | auto branchOp = a->getParentOfType<RegionBranchOpInterface>(); | |||
272 | while (branchOp) { | |||
273 | // Check if b is inside branchOp. (We already know that a is.) | |||
274 | if (!branchOp->isProperAncestor(b)) { | |||
275 | // Check next enclosing RegionBranchOpInterface. | |||
276 | branchOp = branchOp->getParentOfType<RegionBranchOpInterface>(); | |||
277 | continue; | |||
278 | } | |||
279 | ||||
280 | // b is contained in branchOp. Retrieve the regions in which `a` and `b` | |||
281 | // are contained. | |||
282 | Region *regionA = nullptr, *regionB = nullptr; | |||
283 | for (Region &r : branchOp->getRegions()) { | |||
284 | if (r.findAncestorOpInRegion(*a)) { | |||
285 | assert(!regionA && "already found a region for a")(static_cast <bool> (!regionA && "already found a region for a" ) ? void (0) : __assert_fail ("!regionA && \"already found a region for a\"" , "mlir/lib/Interfaces/ControlFlowInterfaces.cpp", 285, __extension__ __PRETTY_FUNCTION__)); | |||
286 | regionA = &r; | |||
287 | } | |||
288 | if (r.findAncestorOpInRegion(*b)) { | |||
289 | assert(!regionB && "already found a region for b")(static_cast <bool> (!regionB && "already found a region for b" ) ? void (0) : __assert_fail ("!regionB && \"already found a region for b\"" , "mlir/lib/Interfaces/ControlFlowInterfaces.cpp", 289, __extension__ __PRETTY_FUNCTION__)); | |||
290 | regionB = &r; | |||
291 | } | |||
292 | } | |||
293 | assert(regionA && regionB && "could not find region of op")(static_cast <bool> (regionA && regionB && "could not find region of op") ? void (0) : __assert_fail ("regionA && regionB && \"could not find region of op\"" , "mlir/lib/Interfaces/ControlFlowInterfaces.cpp", 293, __extension__ __PRETTY_FUNCTION__)); | |||
294 | ||||
295 | // `a` and `b` are in mutually exclusive regions if both regions are | |||
296 | // distinct and neither region is reachable from the other region. | |||
297 | return regionA != regionB && !isRegionReachable(regionA, regionB) && | |||
298 | !isRegionReachable(regionB, regionA); | |||
299 | } | |||
300 | ||||
301 | // Could not find a common RegionBranchOpInterface among a's and b's | |||
302 | // ancestors. | |||
303 | return false; | |||
304 | } | |||
305 | ||||
306 | bool RegionBranchOpInterface::isRepetitiveRegion(unsigned index) { | |||
307 | Region *region = &getOperation()->getRegion(index); | |||
308 | return isRegionReachable(region, region); | |||
309 | } | |||
310 | ||||
311 | void RegionBranchOpInterface::getSuccessorRegions( | |||
312 | std::optional<unsigned> index, SmallVectorImpl<RegionSuccessor> ®ions) { | |||
313 | unsigned numInputs = 0; | |||
314 | if (index) { | |||
315 | // If the predecessor is a region, get the number of operands from an | |||
316 | // exiting terminator in the region. | |||
317 | for (Block &block : getOperation()->getRegion(*index)) { | |||
318 | Operation *terminator = block.getTerminator(); | |||
319 | if (getRegionBranchSuccessorOperands(terminator, *index)) { | |||
320 | numInputs = terminator->getNumOperands(); | |||
321 | break; | |||
322 | } | |||
323 | } | |||
324 | } else { | |||
325 | // Otherwise, use the number of parent operation operands. | |||
326 | numInputs = getOperation()->getNumOperands(); | |||
327 | } | |||
328 | SmallVector<Attribute, 2> operands(numInputs, nullptr); | |||
329 | getSuccessorRegions(index, operands, regions); | |||
330 | } | |||
331 | ||||
332 | Region *mlir::getEnclosingRepetitiveRegion(Operation *op) { | |||
333 | while (Region *region = op->getParentRegion()) { | |||
334 | op = region->getParentOp(); | |||
335 | if (auto branchOp = dyn_cast<RegionBranchOpInterface>(op)) | |||
336 | if (branchOp.isRepetitiveRegion(region->getRegionNumber())) | |||
337 | return region; | |||
338 | } | |||
339 | return nullptr; | |||
340 | } | |||
341 | ||||
342 | Region *mlir::getEnclosingRepetitiveRegion(Value value) { | |||
343 | Region *region = value.getParentRegion(); | |||
344 | while (region) { | |||
345 | Operation *op = region->getParentOp(); | |||
346 | if (auto branchOp = dyn_cast<RegionBranchOpInterface>(op)) | |||
347 | if (branchOp.isRepetitiveRegion(region->getRegionNumber())) | |||
348 | return region; | |||
349 | region = op->getParentRegion(); | |||
350 | } | |||
351 | return nullptr; | |||
352 | } | |||
353 | ||||
354 | //===----------------------------------------------------------------------===// | |||
355 | // RegionBranchTerminatorOpInterface | |||
356 | //===----------------------------------------------------------------------===// | |||
357 | ||||
358 | /// Returns true if the given operation is either annotated with the | |||
359 | /// `ReturnLike` trait or implements the `RegionBranchTerminatorOpInterface`. | |||
360 | bool mlir::isRegionReturnLike(Operation *operation) { | |||
361 | return dyn_cast<RegionBranchTerminatorOpInterface>(operation) || | |||
362 | operation->hasTrait<OpTrait::ReturnLike>(); | |||
363 | } | |||
364 | ||||
365 | /// Returns the mutable operands that are passed to the region with the given | |||
366 | /// `regionIndex`. If the operation does not implement the | |||
367 | /// `RegionBranchTerminatorOpInterface` and is not marked as `ReturnLike`, the | |||
368 | /// result will be `std::nullopt`. In all other cases, the resulting | |||
369 | /// `OperandRange` represents all operands that are passed to the specified | |||
370 | /// successor region. If `regionIndex` is `std::nullopt`, all operands that are | |||
371 | /// passed to the parent operation will be returned. | |||
372 | std::optional<MutableOperandRange> | |||
373 | mlir::getMutableRegionBranchSuccessorOperands( | |||
374 | Operation *operation, std::optional<unsigned> regionIndex) { | |||
375 | // Try to query a RegionBranchTerminatorOpInterface to determine | |||
376 | // all successor operands that will be passed to the successor | |||
377 | // input arguments. | |||
378 | if (auto regionTerminatorInterface = | |||
379 | dyn_cast<RegionBranchTerminatorOpInterface>(operation)) | |||
380 | return regionTerminatorInterface.getMutableSuccessorOperands(regionIndex); | |||
381 | ||||
382 | // TODO: The ReturnLike trait should imply a default implementation of the | |||
383 | // RegionBranchTerminatorOpInterface. This would make this code significantly | |||
384 | // easier. Furthermore, this may even make this function obsolete. | |||
385 | if (operation->hasTrait<OpTrait::ReturnLike>()) | |||
386 | return MutableOperandRange(operation); | |||
387 | return std::nullopt; | |||
388 | } | |||
389 | ||||
390 | /// Returns the read only operands that are passed to the region with the given | |||
391 | /// `regionIndex`. See `getMutableRegionBranchSuccessorOperands` for more | |||
392 | /// information. | |||
393 | std::optional<OperandRange> | |||
394 | mlir::getRegionBranchSuccessorOperands(Operation *operation, | |||
395 | std::optional<unsigned> regionIndex) { | |||
396 | auto range = getMutableRegionBranchSuccessorOperands(operation, regionIndex); | |||
397 | if (range) | |||
398 | return range->operator OperandRange(); | |||
399 | return std::nullopt; | |||
400 | } |
1 | //===- ControlFlowInterfaces.h - ControlFlow Interfaces ---------*- 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 contains the definitions of the branch interfaces defined in |
10 | // `ControlFlowInterfaces.td`. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #ifndef MLIR_INTERFACES_CONTROLFLOWINTERFACES_H |
15 | #define MLIR_INTERFACES_CONTROLFLOWINTERFACES_H |
16 | |
17 | #include "mlir/IR/OpDefinition.h" |
18 | |
19 | namespace mlir { |
20 | class BranchOpInterface; |
21 | class RegionBranchOpInterface; |
22 | |
23 | /// This class models how operands are forwarded to block arguments in control |
24 | /// flow. It consists of a number, denoting how many of the successors block |
25 | /// arguments are produced by the operation, followed by a range of operands |
26 | /// that are forwarded. The produced operands are passed to the first few |
27 | /// block arguments of the successor, followed by the forwarded operands. |
28 | /// It is unsupported to pass them in a different order. |
29 | /// |
30 | /// An example operation with both of these concepts would be a branch-on-error |
31 | /// operation, that internally produces an error object on the error path: |
32 | /// |
33 | /// invoke %function(%0) |
34 | /// label ^success ^error(%1 : i32) |
35 | /// |
36 | /// ^error(%e: !error, %arg0 : i32): |
37 | /// ... |
38 | /// |
39 | /// This operation would return an instance of SuccessorOperands with a produced |
40 | /// operand count of 1 (mapped to %e in the successor) and a forwarded |
41 | /// operands range consisting of %1 in the example above (mapped to %arg0 in the |
42 | /// successor). |
43 | class SuccessorOperands { |
44 | public: |
45 | /// Constructs a SuccessorOperands with no produced operands that simply |
46 | /// forwards operands to the successor. |
47 | explicit SuccessorOperands(MutableOperandRange forwardedOperands); |
48 | |
49 | /// Constructs a SuccessorOperands with the given amount of produced operands |
50 | /// and forwarded operands. |
51 | SuccessorOperands(unsigned producedOperandCount, |
52 | MutableOperandRange forwardedOperands); |
53 | |
54 | /// Returns the amount of operands passed to the successor. This consists both |
55 | /// of produced operands by the operation as well as forwarded ones. |
56 | unsigned size() const { |
57 | return producedOperandCount + forwardedOperands.size(); |
58 | } |
59 | |
60 | /// Returns true if there are no successor operands. |
61 | bool empty() const { return size() == 0; } |
62 | |
63 | /// Returns the amount of operands that are produced internally by the |
64 | /// operation. These are passed to the first few block arguments. |
65 | unsigned getProducedOperandCount() const { return producedOperandCount; } |
66 | |
67 | /// Returns true if the successor operand denoted by `index` is produced by |
68 | /// the operation. |
69 | bool isOperandProduced(unsigned index) const { |
70 | return index < producedOperandCount; |
71 | } |
72 | |
73 | /// Returns the Value that is passed to the successors block argument denoted |
74 | /// by `index`. If it is produced by the operation, no such value exists and |
75 | /// a null Value is returned. |
76 | Value operator[](unsigned index) const { |
77 | if (isOperandProduced(index)) |
78 | return Value(); |
79 | return forwardedOperands[index - producedOperandCount]; |
80 | } |
81 | |
82 | /// Get the range of operands that are simply forwarded to the successor. |
83 | OperandRange getForwardedOperands() const { return forwardedOperands; } |
84 | |
85 | /// Get a slice of the operands forwarded to the successor. The given range |
86 | /// must not contain any operands produced by the operation. |
87 | MutableOperandRange slice(unsigned subStart, unsigned subLen) const { |
88 | assert(!isOperandProduced(subStart) &&(static_cast <bool> (!isOperandProduced(subStart) && "can't slice operands produced by the operation") ? void (0) : __assert_fail ("!isOperandProduced(subStart) && \"can't slice operands produced by the operation\"" , "mlir/include/mlir/Interfaces/ControlFlowInterfaces.h", 89, __extension__ __PRETTY_FUNCTION__)) |
89 | "can't slice operands produced by the operation")(static_cast <bool> (!isOperandProduced(subStart) && "can't slice operands produced by the operation") ? void (0) : __assert_fail ("!isOperandProduced(subStart) && \"can't slice operands produced by the operation\"" , "mlir/include/mlir/Interfaces/ControlFlowInterfaces.h", 89, __extension__ __PRETTY_FUNCTION__)); |
90 | return forwardedOperands.slice(subStart - producedOperandCount, subLen); |
91 | } |
92 | |
93 | /// Erase operands forwarded to the successor. The given range must |
94 | /// not contain any operands produced by the operation. |
95 | void erase(unsigned subStart, unsigned subLen = 1) { |
96 | assert(!isOperandProduced(subStart) &&(static_cast <bool> (!isOperandProduced(subStart) && "can't erase operands produced by the operation") ? void (0) : __assert_fail ("!isOperandProduced(subStart) && \"can't erase operands produced by the operation\"" , "mlir/include/mlir/Interfaces/ControlFlowInterfaces.h", 97, __extension__ __PRETTY_FUNCTION__)) |
97 | "can't erase operands produced by the operation")(static_cast <bool> (!isOperandProduced(subStart) && "can't erase operands produced by the operation") ? void (0) : __assert_fail ("!isOperandProduced(subStart) && \"can't erase operands produced by the operation\"" , "mlir/include/mlir/Interfaces/ControlFlowInterfaces.h", 97, __extension__ __PRETTY_FUNCTION__)); |
98 | forwardedOperands.erase(subStart - producedOperandCount, subLen); |
99 | } |
100 | |
101 | /// Add new operands that are forwarded to the successor. |
102 | void append(ValueRange valueRange) { forwardedOperands.append(valueRange); } |
103 | |
104 | /// Gets the index of the forwarded operand within the operation which maps |
105 | /// to the block argument denoted by `blockArgumentIndex`. The block argument |
106 | /// must be mapped to a forwarded operand. |
107 | unsigned getOperandIndex(unsigned blockArgumentIndex) const { |
108 | assert(!isOperandProduced(blockArgumentIndex) &&(static_cast <bool> (!isOperandProduced(blockArgumentIndex ) && "can't map operand produced by the operation") ? void (0) : __assert_fail ("!isOperandProduced(blockArgumentIndex) && \"can't map operand produced by the operation\"" , "mlir/include/mlir/Interfaces/ControlFlowInterfaces.h", 109 , __extension__ __PRETTY_FUNCTION__)) |
109 | "can't map operand produced by the operation")(static_cast <bool> (!isOperandProduced(blockArgumentIndex ) && "can't map operand produced by the operation") ? void (0) : __assert_fail ("!isOperandProduced(blockArgumentIndex) && \"can't map operand produced by the operation\"" , "mlir/include/mlir/Interfaces/ControlFlowInterfaces.h", 109 , __extension__ __PRETTY_FUNCTION__)); |
110 | OperandRange operands = forwardedOperands; |
111 | return operands.getBeginOperandIndex() + |
112 | (blockArgumentIndex - producedOperandCount); |
113 | } |
114 | |
115 | private: |
116 | /// Amount of operands that are produced internally within the operation and |
117 | /// passed to the first few block arguments. |
118 | unsigned producedOperandCount; |
119 | /// Range of operands that are forwarded to the remaining block arguments. |
120 | MutableOperandRange forwardedOperands; |
121 | }; |
122 | |
123 | //===----------------------------------------------------------------------===// |
124 | // BranchOpInterface |
125 | //===----------------------------------------------------------------------===// |
126 | |
127 | namespace detail { |
128 | /// Return the `BlockArgument` corresponding to operand `operandIndex` in some |
129 | /// successor if `operandIndex` is within the range of `operands`, or |
130 | /// std::nullopt if `operandIndex` isn't a successor operand index. |
131 | std::optional<BlockArgument> |
132 | getBranchSuccessorArgument(const SuccessorOperands &operands, |
133 | unsigned operandIndex, Block *successor); |
134 | |
135 | /// Verify that the given operands match those of the given successor block. |
136 | LogicalResult verifyBranchSuccessorOperands(Operation *op, unsigned succNo, |
137 | const SuccessorOperands &operands); |
138 | } // namespace detail |
139 | |
140 | //===----------------------------------------------------------------------===// |
141 | // RegionBranchOpInterface |
142 | //===----------------------------------------------------------------------===// |
143 | |
144 | namespace detail { |
145 | /// Verify that types match along control flow edges described the given op. |
146 | LogicalResult verifyTypesAlongControlFlowEdges(Operation *op); |
147 | } // namespace detail |
148 | |
149 | /// This class represents a successor of a region. A region successor can either |
150 | /// be another region, or the parent operation. If the successor is a region, |
151 | /// this class represents the destination region, as well as a set of arguments |
152 | /// from that region that will be populated when control flows into the region. |
153 | /// If the successor is the parent operation, this class represents an optional |
154 | /// set of results that will be populated when control returns to the parent |
155 | /// operation. |
156 | /// |
157 | /// This interface assumes that the values from the current region that are used |
158 | /// to populate the successor inputs are the operands of the return-like |
159 | /// terminator operations in the blocks within this region. |
160 | class RegionSuccessor { |
161 | public: |
162 | /// Initialize a successor that branches to another region of the parent |
163 | /// operation. |
164 | RegionSuccessor(Region *region, Block::BlockArgListType regionInputs = {}) |
165 | : region(region), inputs(regionInputs) {} |
166 | /// Initialize a successor that branches back to/out of the parent operation. |
167 | RegionSuccessor(Operation::result_range results) |
168 | : inputs(ValueRange(results)) {} |
169 | /// Constructor with no arguments. |
170 | RegionSuccessor() : inputs(ValueRange()) {} |
171 | |
172 | /// Return the given region successor. Returns nullptr if the successor is the |
173 | /// parent operation. |
174 | Region *getSuccessor() const { return region; } |
175 | |
176 | /// Return true if the successor is the parent operation. |
177 | bool isParent() const { return region == nullptr; } |
178 | |
179 | /// Return the inputs to the successor that are remapped by the exit values of |
180 | /// the current region. |
181 | ValueRange getSuccessorInputs() const { return inputs; } |
182 | |
183 | private: |
184 | Region *region{nullptr}; |
185 | ValueRange inputs; |
186 | }; |
187 | |
188 | /// This class represents upper and lower bounds on the number of times a region |
189 | /// of a `RegionBranchOpInterface` can be invoked. The lower bound is at least |
190 | /// zero, but the upper bound may not be known. |
191 | class InvocationBounds { |
192 | public: |
193 | /// Create invocation bounds. The lower bound must be at least 0 and only the |
194 | /// upper bound can be unknown. |
195 | InvocationBounds(unsigned lb, std::optional<unsigned> ub) |
196 | : lower(lb), upper(ub) { |
197 | assert((!ub || ub >= lb) && "upper bound cannot be less than lower bound")(static_cast <bool> ((!ub || ub >= lb) && "upper bound cannot be less than lower bound" ) ? void (0) : __assert_fail ("(!ub || ub >= lb) && \"upper bound cannot be less than lower bound\"" , "mlir/include/mlir/Interfaces/ControlFlowInterfaces.h", 197 , __extension__ __PRETTY_FUNCTION__)); |
198 | } |
199 | |
200 | /// Return the lower bound. |
201 | unsigned getLowerBound() const { return lower; } |
202 | |
203 | /// Return the upper bound. |
204 | std::optional<unsigned> getUpperBound() const { return upper; } |
205 | |
206 | /// Returns the unknown invocation bounds, i.e., there is no information on |
207 | /// how many times a region may be invoked. |
208 | static InvocationBounds getUnknown() { return {0, std::nullopt}; } |
209 | |
210 | private: |
211 | /// The minimum number of times the successor region will be invoked. |
212 | unsigned lower; |
213 | /// The maximum number of times the successor region will be invoked or |
214 | /// `std::nullopt` if an upper bound is not known. |
215 | std::optional<unsigned> upper; |
216 | }; |
217 | |
218 | /// Return `true` if `a` and `b` are in mutually exclusive regions as per |
219 | /// RegionBranchOpInterface. |
220 | bool insideMutuallyExclusiveRegions(Operation *a, Operation *b); |
221 | |
222 | /// Return the first enclosing region of the given op that may be executed |
223 | /// repetitively as per RegionBranchOpInterface or `nullptr` if no such region |
224 | /// exists. |
225 | Region *getEnclosingRepetitiveRegion(Operation *op); |
226 | |
227 | /// Return the first enclosing region of the given Value that may be executed |
228 | /// repetitively as per RegionBranchOpInterface or `nullptr` if no such region |
229 | /// exists. |
230 | Region *getEnclosingRepetitiveRegion(Value value); |
231 | |
232 | //===----------------------------------------------------------------------===// |
233 | // RegionBranchTerminatorOpInterface |
234 | //===----------------------------------------------------------------------===// |
235 | |
236 | /// Returns true if the given operation is either annotated with the |
237 | /// `ReturnLike` trait or implements the `RegionBranchTerminatorOpInterface`. |
238 | bool isRegionReturnLike(Operation *operation); |
239 | |
240 | /// Returns the mutable operands that are passed to the region with the given |
241 | /// `regionIndex`. If the operation does not implement the |
242 | /// `RegionBranchTerminatorOpInterface` and is not marked as `ReturnLike`, the |
243 | /// result will be `std::nullopt`. In all other cases, the resulting |
244 | /// `OperandRange` represents all operands that are passed to the specified |
245 | /// successor region. If `regionIndex` is `std::nullopt`, all operands that are |
246 | /// passed to the parent operation will be returned. |
247 | std::optional<MutableOperandRange> |
248 | getMutableRegionBranchSuccessorOperands(Operation *operation, |
249 | std::optional<unsigned> regionIndex); |
250 | |
251 | /// Returns the read only operands that are passed to the region with the given |
252 | /// `regionIndex`. See `getMutableRegionBranchSuccessorOperands` for more |
253 | /// information. |
254 | std::optional<OperandRange> |
255 | getRegionBranchSuccessorOperands(Operation *operation, |
256 | std::optional<unsigned> regionIndex); |
257 | |
258 | //===----------------------------------------------------------------------===// |
259 | // ControlFlow Traits |
260 | //===----------------------------------------------------------------------===// |
261 | |
262 | namespace OpTrait { |
263 | /// This trait indicates that a terminator operation is "return-like". This |
264 | /// means that it exits its current region and forwards its operands as "exit" |
265 | /// values to the parent region. Operations with this trait are not permitted to |
266 | /// contain successors or produce results. |
267 | template <typename ConcreteType> |
268 | struct ReturnLike : public TraitBase<ConcreteType, ReturnLike> { |
269 | static LogicalResult verifyTrait(Operation *op) { |
270 | static_assert(ConcreteType::template hasTrait<IsTerminator>(), |
271 | "expected operation to be a terminator"); |
272 | static_assert(ConcreteType::template hasTrait<ZeroResults>(), |
273 | "expected operation to have zero results"); |
274 | static_assert(ConcreteType::template hasTrait<ZeroSuccessors>(), |
275 | "expected operation to have zero successors"); |
276 | return success(); |
277 | } |
278 | }; |
279 | } // namespace OpTrait |
280 | |
281 | } // namespace mlir |
282 | |
283 | //===----------------------------------------------------------------------===// |
284 | // ControlFlow Interfaces |
285 | //===----------------------------------------------------------------------===// |
286 | |
287 | /// Include the generated interface declarations. |
288 | #include "mlir/Interfaces/ControlFlowInterfaces.h.inc" |
289 | |
290 | #endif // MLIR_INTERFACES_CONTROLFLOWINTERFACES_H |
1 | //===- Value.h - Base of the SSA Value hierarchy ----------------*- 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 generic Value type and manipulation utilities. | |||
10 | // | |||
11 | //===----------------------------------------------------------------------===// | |||
12 | ||||
13 | #ifndef MLIR_IR_VALUE_H | |||
14 | #define MLIR_IR_VALUE_H | |||
15 | ||||
16 | #include "mlir/IR/Types.h" | |||
17 | #include "mlir/IR/UseDefLists.h" | |||
18 | #include "mlir/Support/LLVM.h" | |||
19 | #include "llvm/Support/PointerLikeTypeTraits.h" | |||
20 | ||||
21 | namespace mlir { | |||
22 | class AsmState; | |||
23 | class Block; | |||
24 | class BlockArgument; | |||
25 | class Operation; | |||
26 | class OpOperand; | |||
27 | class OpPrintingFlags; | |||
28 | class OpResult; | |||
29 | class Region; | |||
30 | class Value; | |||
31 | ||||
32 | //===----------------------------------------------------------------------===// | |||
33 | // Value | |||
34 | //===----------------------------------------------------------------------===// | |||
35 | ||||
36 | namespace detail { | |||
37 | ||||
38 | /// The base class for all derived Value classes. It contains all of the | |||
39 | /// components that are shared across Value classes. | |||
40 | class alignas(8) ValueImpl : public IRObjectWithUseList<OpOperand> { | |||
41 | public: | |||
42 | /// The enumeration represents the various different kinds of values the | |||
43 | /// internal representation may take. We use all of the bits from Type that we | |||
44 | /// can to store indices inline. | |||
45 | enum class Kind { | |||
46 | /// The first N kinds are all inline operation results. An inline operation | |||
47 | /// result means that the kind represents the result number. This removes | |||
48 | /// the need to store an additional index value. The derived class here is | |||
49 | /// an `OpResultImpl`. | |||
50 | InlineOpResult = 0, | |||
51 | ||||
52 | /// The next kind represents a 'out-of-line' operation result. This is for | |||
53 | /// results with numbers larger than we can represent inline. The derived | |||
54 | /// class here is an `OpResultImpl`. | |||
55 | OutOfLineOpResult = 6, | |||
56 | ||||
57 | /// The last kind represents a block argument. The derived class here is an | |||
58 | /// `BlockArgumentImpl`. | |||
59 | BlockArgument = 7 | |||
60 | }; | |||
61 | ||||
62 | /// Return the type of this value. | |||
63 | Type getType() const { return typeAndKind.getPointer(); } | |||
64 | ||||
65 | /// Set the type of this value. | |||
66 | void setType(Type type) { return typeAndKind.setPointer(type); } | |||
67 | ||||
68 | /// Return the kind of this value. | |||
69 | Kind getKind() const { return typeAndKind.getInt(); } | |||
70 | ||||
71 | protected: | |||
72 | ValueImpl(Type type, Kind kind) : typeAndKind(type, kind) {} | |||
73 | ||||
74 | /// Expose a few methods explicitly for the debugger to call for | |||
75 | /// visualization. | |||
76 | #ifndef NDEBUG | |||
77 | LLVM_DUMP_METHOD__attribute__((noinline)) __attribute__((__used__)) Type debug_getType() const { return getType(); } | |||
78 | LLVM_DUMP_METHOD__attribute__((noinline)) __attribute__((__used__)) Kind debug_getKind() const { return getKind(); } | |||
79 | ||||
80 | #endif | |||
81 | ||||
82 | /// The type of this result and the kind. | |||
83 | llvm::PointerIntPair<Type, 3, Kind> typeAndKind; | |||
84 | }; | |||
85 | } // namespace detail | |||
86 | ||||
87 | /// This class represents an instance of an SSA value in the MLIR system, | |||
88 | /// representing a computable value that has a type and a set of users. An SSA | |||
89 | /// value is either a BlockArgument or the result of an operation. Note: This | |||
90 | /// class has value-type semantics and is just a simple wrapper around a | |||
91 | /// ValueImpl that is either owner by a block(in the case of a BlockArgument) or | |||
92 | /// an Operation(in the case of an OpResult). | |||
93 | class Value { | |||
94 | public: | |||
95 | constexpr Value(detail::ValueImpl *impl = nullptr) : impl(impl) {} | |||
96 | ||||
97 | template <typename U> | |||
98 | bool isa() const { | |||
99 | return llvm::isa<U>(*this); | |||
100 | } | |||
101 | ||||
102 | template <typename U> | |||
103 | U dyn_cast() const { | |||
104 | return llvm::dyn_cast<U>(*this); | |||
105 | } | |||
106 | ||||
107 | template <typename U> | |||
108 | U dyn_cast_or_null() const { | |||
109 | return llvm::dyn_cast_if_present<U>(*this); | |||
110 | } | |||
111 | ||||
112 | template <typename U> | |||
113 | U cast() const { | |||
114 | return llvm::cast<U>(*this); | |||
115 | } | |||
116 | ||||
117 | explicit operator bool() const { return impl; } | |||
118 | bool operator==(const Value &other) const { return impl == other.impl; } | |||
119 | bool operator!=(const Value &other) const { return !(*this == other); } | |||
120 | ||||
121 | /// Return the type of this value. | |||
122 | Type getType() const { return impl->getType(); } | |||
| ||||
123 | ||||
124 | /// Utility to get the associated MLIRContext that this value is defined in. | |||
125 | MLIRContext *getContext() const { return getType().getContext(); } | |||
126 | ||||
127 | /// Mutate the type of this Value to be of the specified type. | |||
128 | /// | |||
129 | /// Note that this is an extremely dangerous operation which can create | |||
130 | /// completely invalid IR very easily. It is strongly recommended that you | |||
131 | /// recreate IR objects with the right types instead of mutating them in | |||
132 | /// place. | |||
133 | void setType(Type newType) { impl->setType(newType); } | |||
134 | ||||
135 | /// If this value is the result of an operation, return the operation that | |||
136 | /// defines it. | |||
137 | Operation *getDefiningOp() const; | |||
138 | ||||
139 | /// If this value is the result of an operation of type OpTy, return the | |||
140 | /// operation that defines it. | |||
141 | template <typename OpTy> | |||
142 | OpTy getDefiningOp() const { | |||
143 | return llvm::dyn_cast_or_null<OpTy>(getDefiningOp()); | |||
144 | } | |||
145 | ||||
146 | /// Return the location of this value. | |||
147 | Location getLoc() const; | |||
148 | void setLoc(Location loc); | |||
149 | ||||
150 | /// Return the Region in which this Value is defined. | |||
151 | Region *getParentRegion(); | |||
152 | ||||
153 | /// Return the Block in which this Value is defined. | |||
154 | Block *getParentBlock(); | |||
155 | ||||
156 | //===--------------------------------------------------------------------===// | |||
157 | // UseLists | |||
158 | //===--------------------------------------------------------------------===// | |||
159 | ||||
160 | /// Drop all uses of this object from their respective owners. | |||
161 | void dropAllUses() const { return impl->dropAllUses(); } | |||
162 | ||||
163 | /// Replace all uses of 'this' value with the new value, updating anything in | |||
164 | /// the IR that uses 'this' to use the other value instead. When this returns | |||
165 | /// there are zero uses of 'this'. | |||
166 | void replaceAllUsesWith(Value newValue) const { | |||
167 | impl->replaceAllUsesWith(newValue); | |||
168 | } | |||
169 | ||||
170 | /// Replace all uses of 'this' value with 'newValue', updating anything in the | |||
171 | /// IR that uses 'this' to use the other value instead except if the user is | |||
172 | /// listed in 'exceptions' . | |||
173 | void | |||
174 | replaceAllUsesExcept(Value newValue, | |||
175 | const SmallPtrSetImpl<Operation *> &exceptions) const; | |||
176 | ||||
177 | /// Replace all uses of 'this' value with 'newValue', updating anything in the | |||
178 | /// IR that uses 'this' to use the other value instead except if the user is | |||
179 | /// 'exceptedUser'. | |||
180 | void replaceAllUsesExcept(Value newValue, Operation *exceptedUser) const; | |||
181 | ||||
182 | /// Replace all uses of 'this' value with 'newValue' if the given callback | |||
183 | /// returns true. | |||
184 | void replaceUsesWithIf(Value newValue, | |||
185 | function_ref<bool(OpOperand &)> shouldReplace); | |||
186 | ||||
187 | /// Returns true if the value is used outside of the given block. | |||
188 | bool isUsedOutsideOfBlock(Block *block); | |||
189 | ||||
190 | //===--------------------------------------------------------------------===// | |||
191 | // Uses | |||
192 | ||||
193 | /// This class implements an iterator over the uses of a value. | |||
194 | using use_iterator = ValueUseIterator<OpOperand>; | |||
195 | using use_range = iterator_range<use_iterator>; | |||
196 | ||||
197 | use_iterator use_begin() const { return impl->use_begin(); } | |||
198 | use_iterator use_end() const { return use_iterator(); } | |||
199 | ||||
200 | /// Returns a range of all uses, which is useful for iterating over all uses. | |||
201 | use_range getUses() const { return {use_begin(), use_end()}; } | |||
202 | ||||
203 | /// Returns true if this value has exactly one use. | |||
204 | bool hasOneUse() const { return impl->hasOneUse(); } | |||
205 | ||||
206 | /// Returns true if this value has no uses. | |||
207 | bool use_empty() const { return impl->use_empty(); } | |||
208 | ||||
209 | //===--------------------------------------------------------------------===// | |||
210 | // Users | |||
211 | ||||
212 | using user_iterator = ValueUserIterator<use_iterator, OpOperand>; | |||
213 | using user_range = iterator_range<user_iterator>; | |||
214 | ||||
215 | user_iterator user_begin() const { return use_begin(); } | |||
216 | user_iterator user_end() const { return use_end(); } | |||
217 | user_range getUsers() const { return {user_begin(), user_end()}; } | |||
218 | ||||
219 | //===--------------------------------------------------------------------===// | |||
220 | // Utilities | |||
221 | ||||
222 | void print(raw_ostream &os); | |||
223 | void print(raw_ostream &os, const OpPrintingFlags &flags); | |||
224 | void print(raw_ostream &os, AsmState &state); | |||
225 | void dump(); | |||
226 | ||||
227 | /// Print this value as if it were an operand. | |||
228 | void printAsOperand(raw_ostream &os, AsmState &state); | |||
229 | ||||
230 | /// Methods for supporting PointerLikeTypeTraits. | |||
231 | void *getAsOpaquePointer() const { return impl; } | |||
232 | static Value getFromOpaquePointer(const void *pointer) { | |||
233 | return reinterpret_cast<detail::ValueImpl *>(const_cast<void *>(pointer)); | |||
234 | } | |||
235 | detail::ValueImpl *getImpl() const { return impl; } | |||
236 | ||||
237 | friend ::llvm::hash_code hash_value(Value arg); | |||
238 | ||||
239 | protected: | |||
240 | /// A pointer to the internal implementation of the value. | |||
241 | detail::ValueImpl *impl; | |||
242 | }; | |||
243 | ||||
244 | inline raw_ostream &operator<<(raw_ostream &os, Value value) { | |||
245 | value.print(os); | |||
246 | return os; | |||
247 | } | |||
248 | ||||
249 | //===----------------------------------------------------------------------===// | |||
250 | // OpOperand | |||
251 | //===----------------------------------------------------------------------===// | |||
252 | ||||
253 | /// This class represents an operand of an operation. Instances of this class | |||
254 | /// contain a reference to a specific `Value`. | |||
255 | class OpOperand : public IROperand<OpOperand, Value> { | |||
256 | public: | |||
257 | /// Provide the use list that is attached to the given value. | |||
258 | static IRObjectWithUseList<OpOperand> *getUseList(Value value) { | |||
259 | return value.getImpl(); | |||
260 | } | |||
261 | ||||
262 | /// Return which operand this is in the OpOperand list of the Operation. | |||
263 | unsigned getOperandNumber(); | |||
264 | ||||
265 | private: | |||
266 | /// Keep the constructor private and accessible to the OperandStorage class | |||
267 | /// only to avoid hard-to-debug typo/programming mistakes. | |||
268 | friend class OperandStorage; | |||
269 | using IROperand<OpOperand, Value>::IROperand; | |||
270 | }; | |||
271 | ||||
272 | //===----------------------------------------------------------------------===// | |||
273 | // BlockArgument | |||
274 | //===----------------------------------------------------------------------===// | |||
275 | ||||
276 | namespace detail { | |||
277 | /// The internal implementation of a BlockArgument. | |||
278 | class BlockArgumentImpl : public ValueImpl { | |||
279 | public: | |||
280 | static bool classof(const ValueImpl *value) { | |||
281 | return value->getKind() == ValueImpl::Kind::BlockArgument; | |||
282 | } | |||
283 | ||||
284 | private: | |||
285 | BlockArgumentImpl(Type type, Block *owner, int64_t index, Location loc) | |||
286 | : ValueImpl(type, Kind::BlockArgument), owner(owner), index(index), | |||
287 | loc(loc) {} | |||
288 | ||||
289 | /// The owner of this argument. | |||
290 | Block *owner; | |||
291 | ||||
292 | /// The position in the argument list. | |||
293 | int64_t index; | |||
294 | ||||
295 | /// The source location of this argument. | |||
296 | Location loc; | |||
297 | ||||
298 | /// Allow access to owner and constructor. | |||
299 | friend BlockArgument; | |||
300 | }; | |||
301 | } // namespace detail | |||
302 | ||||
303 | /// This class represents an argument of a Block. | |||
304 | class BlockArgument : public Value { | |||
305 | public: | |||
306 | using Value::Value; | |||
307 | ||||
308 | static bool classof(Value value) { | |||
309 | return llvm::isa<detail::BlockArgumentImpl>(value.getImpl()); | |||
310 | } | |||
311 | ||||
312 | /// Returns the block that owns this argument. | |||
313 | Block *getOwner() const { return getImpl()->owner; } | |||
314 | ||||
315 | /// Returns the number of this argument. | |||
316 | unsigned getArgNumber() const { return getImpl()->index; } | |||
317 | ||||
318 | /// Return the location for this argument. | |||
319 | Location getLoc() const { return getImpl()->loc; } | |||
320 | void setLoc(Location loc) { getImpl()->loc = loc; } | |||
321 | ||||
322 | private: | |||
323 | /// Allocate a new argument with the given type and owner. | |||
324 | static BlockArgument create(Type type, Block *owner, int64_t index, | |||
325 | Location loc) { | |||
326 | return new detail::BlockArgumentImpl(type, owner, index, loc); | |||
327 | } | |||
328 | ||||
329 | /// Destroy and deallocate this argument. | |||
330 | void destroy() { delete getImpl(); } | |||
331 | ||||
332 | /// Get a raw pointer to the internal implementation. | |||
333 | detail::BlockArgumentImpl *getImpl() const { | |||
334 | return reinterpret_cast<detail::BlockArgumentImpl *>(impl); | |||
335 | } | |||
336 | ||||
337 | /// Cache the position in the block argument list. | |||
338 | void setArgNumber(int64_t index) { getImpl()->index = index; } | |||
339 | ||||
340 | /// Allow access to `create`, `destroy` and `setArgNumber`. | |||
341 | friend Block; | |||
342 | ||||
343 | /// Allow access to 'getImpl'. | |||
344 | friend Value; | |||
345 | }; | |||
346 | ||||
347 | //===----------------------------------------------------------------------===// | |||
348 | // OpResult | |||
349 | //===----------------------------------------------------------------------===// | |||
350 | ||||
351 | namespace detail { | |||
352 | /// This class provides the implementation for an operation result. | |||
353 | class alignas(8) OpResultImpl : public ValueImpl { | |||
354 | public: | |||
355 | using ValueImpl::ValueImpl; | |||
356 | ||||
357 | static bool classof(const ValueImpl *value) { | |||
358 | return value->getKind() != ValueImpl::Kind::BlockArgument; | |||
359 | } | |||
360 | ||||
361 | /// Returns the parent operation of this result. | |||
362 | Operation *getOwner() const; | |||
363 | ||||
364 | /// Returns the result number of this op result. | |||
365 | unsigned getResultNumber() const; | |||
366 | ||||
367 | /// Returns the next operation result at `offset` after this result. This | |||
368 | /// method is useful when indexing the result storage of an operation, given | |||
369 | /// that there is more than one kind of operation result (with the different | |||
370 | /// kinds having different sizes) and that operations are stored in reverse | |||
371 | /// order. | |||
372 | OpResultImpl *getNextResultAtOffset(intptr_t offset); | |||
373 | ||||
374 | /// Returns the maximum number of results that can be stored inline. | |||
375 | static unsigned getMaxInlineResults() { | |||
376 | return static_cast<unsigned>(Kind::OutOfLineOpResult); | |||
377 | } | |||
378 | }; | |||
379 | ||||
380 | /// This class provides the implementation for an operation result whose index | |||
381 | /// can be represented "inline" in the underlying ValueImpl. | |||
382 | struct InlineOpResult : public OpResultImpl { | |||
383 | public: | |||
384 | InlineOpResult(Type type, unsigned resultNo) | |||
385 | : OpResultImpl(type, static_cast<ValueImpl::Kind>(resultNo)) { | |||
386 | assert(resultNo < getMaxInlineResults())(static_cast <bool> (resultNo < getMaxInlineResults( )) ? void (0) : __assert_fail ("resultNo < getMaxInlineResults()" , "mlir/include/mlir/IR/Value.h", 386, __extension__ __PRETTY_FUNCTION__ )); | |||
387 | } | |||
388 | ||||
389 | /// Return the result number of this op result. | |||
390 | unsigned getResultNumber() const { return static_cast<unsigned>(getKind()); } | |||
391 | ||||
392 | static bool classof(const OpResultImpl *value) { | |||
393 | return value->getKind() != ValueImpl::Kind::OutOfLineOpResult; | |||
394 | } | |||
395 | }; | |||
396 | ||||
397 | /// This class provides the implementation for an operation result whose index | |||
398 | /// cannot be represented "inline", and thus requires an additional index field. | |||
399 | class OutOfLineOpResult : public OpResultImpl { | |||
400 | public: | |||
401 | OutOfLineOpResult(Type type, uint64_t outOfLineIndex) | |||
402 | : OpResultImpl(type, Kind::OutOfLineOpResult), | |||
403 | outOfLineIndex(outOfLineIndex) {} | |||
404 | ||||
405 | static bool classof(const OpResultImpl *value) { | |||
406 | return value->getKind() == ValueImpl::Kind::OutOfLineOpResult; | |||
407 | } | |||
408 | ||||
409 | /// Return the result number of this op result. | |||
410 | unsigned getResultNumber() const { | |||
411 | return outOfLineIndex + getMaxInlineResults(); | |||
412 | } | |||
413 | ||||
414 | /// The trailing result number, or the offset from the beginning of the | |||
415 | /// `OutOfLineOpResult` array. | |||
416 | uint64_t outOfLineIndex; | |||
417 | }; | |||
418 | ||||
419 | /// Return the result number of this op result. | |||
420 | inline unsigned OpResultImpl::getResultNumber() const { | |||
421 | if (const auto *outOfLineResult = dyn_cast<OutOfLineOpResult>(this)) | |||
422 | return outOfLineResult->getResultNumber(); | |||
423 | return cast<InlineOpResult>(this)->getResultNumber(); | |||
424 | } | |||
425 | ||||
426 | /// TypedValue is a Value with a statically know type. | |||
427 | /// TypedValue can be null/empty | |||
428 | template <typename Ty> | |||
429 | struct TypedValue : Value { | |||
430 | using Value::Value; | |||
431 | ||||
432 | static bool classof(Value value) { return llvm::isa<Ty>(value.getType()); } | |||
433 | ||||
434 | /// Return the known Type | |||
435 | Ty getType() { return Value::getType().template cast<Ty>(); } | |||
436 | void setType(Ty ty) { Value::setType(ty); } | |||
437 | }; | |||
438 | ||||
439 | } // namespace detail | |||
440 | ||||
441 | /// This is a value defined by a result of an operation. | |||
442 | class OpResult : public Value { | |||
443 | public: | |||
444 | using Value::Value; | |||
445 | ||||
446 | static bool classof(Value value) { | |||
447 | return llvm::isa<detail::OpResultImpl>(value.getImpl()); | |||
448 | } | |||
449 | ||||
450 | /// Returns the operation that owns this result. | |||
451 | Operation *getOwner() const { return getImpl()->getOwner(); } | |||
452 | ||||
453 | /// Returns the number of this result. | |||
454 | unsigned getResultNumber() const { return getImpl()->getResultNumber(); } | |||
455 | ||||
456 | private: | |||
457 | /// Get a raw pointer to the internal implementation. | |||
458 | detail::OpResultImpl *getImpl() const { | |||
459 | return reinterpret_cast<detail::OpResultImpl *>(impl); | |||
460 | } | |||
461 | ||||
462 | /// Given a number of operation results, returns the number that need to be | |||
463 | /// stored inline. | |||
464 | static unsigned getNumInline(unsigned numResults); | |||
465 | ||||
466 | /// Given a number of operation results, returns the number that need to be | |||
467 | /// stored as trailing. | |||
468 | static unsigned getNumTrailing(unsigned numResults); | |||
469 | ||||
470 | /// Allow access to constructor. | |||
471 | friend Operation; | |||
472 | }; | |||
473 | ||||
474 | /// Make Value hashable. | |||
475 | inline ::llvm::hash_code hash_value(Value arg) { | |||
476 | return ::llvm::hash_value(arg.getImpl()); | |||
477 | } | |||
478 | ||||
479 | template <typename Ty, typename Value = mlir::Value> | |||
480 | /// If Ty is mlir::Type this will select `Value` instead of having a wrapper | |||
481 | /// around it. This helps resolve ambiguous conversion issues. | |||
482 | using TypedValue = std::conditional_t<std::is_same_v<Ty, mlir::Type>, | |||
483 | mlir::Value, detail::TypedValue<Ty>>; | |||
484 | ||||
485 | } // namespace mlir | |||
486 | ||||
487 | namespace llvm { | |||
488 | ||||
489 | template <> | |||
490 | struct DenseMapInfo<mlir::Value> { | |||
491 | static mlir::Value getEmptyKey() { | |||
492 | void *pointer = llvm::DenseMapInfo<void *>::getEmptyKey(); | |||
493 | return mlir::Value::getFromOpaquePointer(pointer); | |||
494 | } | |||
495 | static mlir::Value getTombstoneKey() { | |||
496 | void *pointer = llvm::DenseMapInfo<void *>::getTombstoneKey(); | |||
497 | return mlir::Value::getFromOpaquePointer(pointer); | |||
498 | } | |||
499 | static unsigned getHashValue(mlir::Value val) { | |||
500 | return mlir::hash_value(val); | |||
501 | } | |||
502 | static bool isEqual(mlir::Value lhs, mlir::Value rhs) { return lhs == rhs; } | |||
503 | }; | |||
504 | template <> | |||
505 | struct DenseMapInfo<mlir::BlockArgument> : public DenseMapInfo<mlir::Value> { | |||
506 | static mlir::BlockArgument getEmptyKey() { | |||
507 | void *pointer = llvm::DenseMapInfo<void *>::getEmptyKey(); | |||
508 | return reinterpret_cast<mlir::detail::BlockArgumentImpl *>(pointer); | |||
509 | } | |||
510 | static mlir::BlockArgument getTombstoneKey() { | |||
511 | void *pointer = llvm::DenseMapInfo<void *>::getTombstoneKey(); | |||
512 | return reinterpret_cast<mlir::detail::BlockArgumentImpl *>(pointer); | |||
513 | } | |||
514 | }; | |||
515 | template <> | |||
516 | struct DenseMapInfo<mlir::OpResult> : public DenseMapInfo<mlir::Value> { | |||
517 | static mlir::OpResult getEmptyKey() { | |||
518 | void *pointer = llvm::DenseMapInfo<void *>::getEmptyKey(); | |||
519 | return reinterpret_cast<mlir::detail::OpResultImpl *>(pointer); | |||
520 | } | |||
521 | static mlir::OpResult getTombstoneKey() { | |||
522 | void *pointer = llvm::DenseMapInfo<void *>::getTombstoneKey(); | |||
523 | return reinterpret_cast<mlir::detail::OpResultImpl *>(pointer); | |||
524 | } | |||
525 | }; | |||
526 | ||||
527 | /// Allow stealing the low bits of a value. | |||
528 | template <> | |||
529 | struct PointerLikeTypeTraits<mlir::Value> { | |||
530 | public: | |||
531 | static inline void *getAsVoidPointer(mlir::Value value) { | |||
532 | return const_cast<void *>(value.getAsOpaquePointer()); | |||
533 | } | |||
534 | static inline mlir::Value getFromVoidPointer(void *pointer) { | |||
535 | return mlir::Value::getFromOpaquePointer(pointer); | |||
536 | } | |||
537 | enum { | |||
538 | NumLowBitsAvailable = | |||
539 | PointerLikeTypeTraits<mlir::detail::ValueImpl *>::NumLowBitsAvailable | |||
540 | }; | |||
541 | }; | |||
542 | template <> | |||
543 | struct PointerLikeTypeTraits<mlir::BlockArgument> | |||
544 | : public PointerLikeTypeTraits<mlir::Value> { | |||
545 | public: | |||
546 | static inline mlir::BlockArgument getFromVoidPointer(void *pointer) { | |||
547 | return reinterpret_cast<mlir::detail::BlockArgumentImpl *>(pointer); | |||
548 | } | |||
549 | }; | |||
550 | template <> | |||
551 | struct PointerLikeTypeTraits<mlir::OpResult> | |||
552 | : public PointerLikeTypeTraits<mlir::Value> { | |||
553 | public: | |||
554 | static inline mlir::OpResult getFromVoidPointer(void *pointer) { | |||
555 | return reinterpret_cast<mlir::detail::OpResultImpl *>(pointer); | |||
556 | } | |||
557 | }; | |||
558 | ||||
559 | /// Add support for llvm style casts. We provide a cast between To and From if | |||
560 | /// From is mlir::Value or derives from it. | |||
561 | template <typename To, typename From> | |||
562 | struct CastInfo< | |||
563 | To, From, | |||
564 | std::enable_if_t<std::is_same_v<mlir::Value, std::remove_const_t<From>> || | |||
565 | std::is_base_of_v<mlir::Value, From>>> | |||
566 | : NullableValueCastFailed<To>, | |||
567 | DefaultDoCastIfPossible<To, From, CastInfo<To, From>> { | |||
568 | /// Arguments are taken as mlir::Value here and not as `From`, because | |||
569 | /// when casting from an intermediate type of the hierarchy to one of its | |||
570 | /// children, the val.getKind() inside T::classof will use the static | |||
571 | /// getKind() of the parent instead of the non-static ValueImpl::getKind() | |||
572 | /// that returns the dynamic type. This means that T::classof would end up | |||
573 | /// comparing the static Kind of the children to the static Kind of its | |||
574 | /// parent, making it impossible to downcast from the parent to the child. | |||
575 | static inline bool isPossible(mlir::Value ty) { | |||
576 | /// Return a constant true instead of a dynamic true when casting to self or | |||
577 | /// up the hierarchy. | |||
578 | if constexpr (std::is_base_of_v<To, From>) { | |||
579 | (void)ty; | |||
580 | return true; | |||
581 | } else { | |||
582 | return To::classof(ty); | |||
583 | } | |||
584 | } | |||
585 | static inline To doCast(mlir::Value value) { return To(value.getImpl()); } | |||
586 | }; | |||
587 | ||||
588 | } // namespace llvm | |||
589 | ||||
590 | #endif |