Bug Summary

File:build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/mlir/include/mlir/IR/Value.h
Warning:line 118, column 33
Called C++ object pointer is null

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name ControlFlowInterfaces.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/build-llvm/tools/clang/stage2-bins -resource-dir /usr/lib/llvm-16/lib/clang/16.0.0 -D MLIR_CUDA_CONVERSIONS_ENABLED=1 -D MLIR_ROCM_CONVERSIONS_ENABLED=1 -D _DEBUG -D _GNU_SOURCE -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I tools/mlir/lib/Interfaces -I /build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/mlir/lib/Interfaces -I include -I /build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/llvm/include -I /build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/mlir/include -I tools/mlir/include -D _FORTIFY_SOURCE=2 -D NDEBUG -U NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/x86_64-linux-gnu/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/backward -internal-isystem /usr/lib/llvm-16/lib/clang/16.0.0/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fmacro-prefix-map=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/= -fcoverage-prefix-map=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fcoverage-prefix-map=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/= -O2 -Wno-unused-command-line-argument -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-class-memaccess -Wno-redundant-move -Wno-pessimizing-move -Wno-noexcept-type -Wno-comment -Wno-misleading-indentation -std=c++17 -fdeprecated-macro -fdebug-compilation-dir=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/= -ferror-limit 19 -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -vectorize-loops -vectorize-slp -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2022-10-03-140002-15933-1 -x c++ /build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/mlir/lib/Interfaces/ControlFlowInterfaces.cpp

/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/mlir/lib/Interfaces/ControlFlowInterfaces.cpp

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
15using namespace mlir;
16
17//===----------------------------------------------------------------------===//
18// ControlFlowInterfaces
19//===----------------------------------------------------------------------===//
20
21#include "mlir/Interfaces/ControlFlowInterfaces.cpp.inc"
22
23SuccessorOperands::SuccessorOperands(MutableOperandRange forwardedOperands)
24 : producedOperandCount(0), forwardedOperands(std::move(forwardedOperands)) {
25}
26
27SuccessorOperands::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 None if
38/// `operandIndex` isn't a successor operand index.
39Optional<BlockArgument>
40detail::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 llvm::None;
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 llvm::None;
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.
60LogicalResult
61detail::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())
1
Assuming the condition is false
2
Taking false branch
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;
3
Assuming 'i' is not equal to 'operandCount'
4
Loop condition is true. Entering loop body
7
Assuming 'i' is not equal to 'operandCount'
8
Loop condition is true. Entering loop body
74 ++i) {
75 if (!cast<BranchOpInterface>(op).areTypesCompatible(
5
Assuming the condition is false
6
Taking false branch
76 operands[i].getType(), destBB->getArgument(i).getType()))
9
Calling 'SuccessorOperands::operator[]'
15
Returning from 'SuccessorOperands::operator[]'
16
Calling 'Value::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, llvm::None 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 llvm::None if
91/// the exact type match verification is not necessary (e.g., if the Op verifies
92/// the match itself).
93static LogicalResult
94verifyTypesAlongAllEdges(Operation *op, Optional<unsigned> sourceNo,
95 function_ref<Optional<TypeRange>(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 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 Optional<TypeRange> sourceTypes = getInputsTypesForRegion(succRegionNo);
123 if (!sourceTypes.has_value())
124 continue;
125
126 TypeRange succInputsTypes = succ.getSuccessorInputs().getTypes();
127 if (sourceTypes->size() != succInputsTypes.size()) {
128 InFlightDiagnostic diag = op->emitOpError(" region control flow edge ");
129 return printEdgeName(diag) << ": source has " << sourceTypes->size()
130 << " operands, but target successor needs "
131 << succInputsTypes.size();
132 }
133
134 for (const auto &typesIdx :
135 llvm::enumerate(llvm::zip(*sourceTypes, succInputsTypes))) {
136 Type sourceType = std::get<0>(typesIdx.value());
137 Type inputType = std::get<1>(typesIdx.value());
138 if (!regionInterface.areTypesCompatible(sourceType, inputType)) {
139 InFlightDiagnostic diag = op->emitOpError(" along control flow edge ");
140 return printEdgeName(diag)
141 << ": source type #" << typesIdx.index() << " " << sourceType
142 << " should match input type #" << typesIdx.index() << " "
143 << inputType;
144 }
145 }
146 }
147 return success();
148}
149
150/// Verify that types match along control flow edges described the given op.
151LogicalResult detail::verifyTypesAlongControlFlowEdges(Operation *op) {
152 auto regionInterface = cast<RegionBranchOpInterface>(op);
153
154 auto inputTypesFromParent = [&](Optional<unsigned> regionNo) -> TypeRange {
155 return regionInterface.getSuccessorEntryOperands(regionNo).getTypes();
156 };
157
158 // Verify types along control flow edges originating from the parent.
159 if (failed(verifyTypesAlongAllEdges(op, llvm::None, inputTypesFromParent)))
160 return failure();
161
162 // RegionBranchOpInterface should not be implemented by Ops that do not have
163 // attached regions.
164 assert(op->getNumRegions() != 0)(static_cast <bool> (op->getNumRegions() != 0) ? void
(0) : __assert_fail ("op->getNumRegions() != 0", "mlir/lib/Interfaces/ControlFlowInterfaces.cpp"
, 164, __extension__ __PRETTY_FUNCTION__))
;
165
166 auto areTypesCompatible = [&](TypeRange lhs, TypeRange rhs) {
167 if (lhs.size() != rhs.size())
168 return false;
169 for (auto types : llvm::zip(lhs, rhs)) {
170 if (!regionInterface.areTypesCompatible(std::get<0>(types),
171 std::get<1>(types))) {
172 return false;
173 }
174 }
175 return true;
176 };
177
178 // Verify types along control flow edges originating from each region.
179 for (unsigned regionNo : llvm::seq(0U, op->getNumRegions())) {
180 Region &region = op->getRegion(regionNo);
181
182 // Since there can be multiple `ReturnLike` terminators or others
183 // implementing the `RegionBranchTerminatorOpInterface`, all should have the
184 // same operand types when passing them to the same region.
185
186 Optional<OperandRange> regionReturnOperands;
187 for (Block &block : region) {
188 Operation *terminator = block.getTerminator();
189 auto terminatorOperands =
190 getRegionBranchSuccessorOperands(terminator, regionNo);
191 if (!terminatorOperands)
192 continue;
193
194 if (!regionReturnOperands) {
195 regionReturnOperands = terminatorOperands;
196 continue;
197 }
198
199 // Found more than one ReturnLike terminator. Make sure the operand types
200 // match with the first one.
201 if (!areTypesCompatible(regionReturnOperands->getTypes(),
202 terminatorOperands->getTypes()))
203 return op->emitOpError("Region #")
204 << regionNo
205 << " operands mismatch between return-like terminators";
206 }
207
208 auto inputTypesFromRegion =
209 [&](Optional<unsigned> regionNo) -> Optional<TypeRange> {
210 // If there is no return-like terminator, the op itself should verify
211 // type consistency.
212 if (!regionReturnOperands)
213 return llvm::None;
214
215 // All successors get the same set of operand types.
216 return TypeRange(regionReturnOperands->getTypes());
217 };
218
219 if (failed(verifyTypesAlongAllEdges(op, regionNo, inputTypesFromRegion)))
220 return failure();
221 }
222
223 return success();
224}
225
226/// Return `true` if region `r` is reachable from region `begin` according to
227/// the RegionBranchOpInterface (by taking a branch).
228static bool isRegionReachable(Region *begin, Region *r) {
229 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", 230, __extension__
__PRETTY_FUNCTION__))
230 "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", 230, __extension__
__PRETTY_FUNCTION__))
;
231 auto op = cast<RegionBranchOpInterface>(begin->getParentOp());
232 SmallVector<bool> visited(op->getNumRegions(), false);
233 visited[begin->getRegionNumber()] = true;
234
235 // Retrieve all successors of the region and enqueue them in the worklist.
236 SmallVector<unsigned> worklist;
237 auto enqueueAllSuccessors = [&](unsigned index) {
238 SmallVector<RegionSuccessor> successors;
239 op.getSuccessorRegions(index, successors);
240 for (RegionSuccessor successor : successors)
241 if (!successor.isParent())
242 worklist.push_back(successor.getSuccessor()->getRegionNumber());
243 };
244 enqueueAllSuccessors(begin->getRegionNumber());
245
246 // Process all regions in the worklist via DFS.
247 while (!worklist.empty()) {
248 unsigned nextRegion = worklist.pop_back_val();
249 if (nextRegion == r->getRegionNumber())
250 return true;
251 if (visited[nextRegion])
252 continue;
253 visited[nextRegion] = true;
254 enqueueAllSuccessors(nextRegion);
255 }
256
257 return false;
258}
259
260/// Return `true` if `a` and `b` are in mutually exclusive regions.
261///
262/// 1. Find the first common of `a` and `b` (ancestor) that implements
263/// RegionBranchOpInterface.
264/// 2. Determine the regions `regionA` and `regionB` in which `a` and `b` are
265/// contained.
266/// 3. Check if `regionA` and `regionB` are mutually exclusive. They are
267/// mutually exclusive if they are not reachable from each other as per
268/// RegionBranchOpInterface::getSuccessorRegions.
269bool mlir::insideMutuallyExclusiveRegions(Operation *a, Operation *b) {
270 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", 270, __extension__
__PRETTY_FUNCTION__))
;
271 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", 271, __extension__
__PRETTY_FUNCTION__))
;
272
273 auto branchOp = a->getParentOfType<RegionBranchOpInterface>();
274 while (branchOp) {
275 // Check if b is inside branchOp. (We already know that a is.)
276 if (!branchOp->isProperAncestor(b)) {
277 // Check next enclosing RegionBranchOpInterface.
278 branchOp = branchOp->getParentOfType<RegionBranchOpInterface>();
279 continue;
280 }
281
282 // b is contained in branchOp. Retrieve the regions in which `a` and `b`
283 // are contained.
284 Region *regionA = nullptr, *regionB = nullptr;
285 for (Region &r : branchOp->getRegions()) {
286 if (r.findAncestorOpInRegion(*a)) {
287 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", 287, __extension__
__PRETTY_FUNCTION__))
;
288 regionA = &r;
289 }
290 if (r.findAncestorOpInRegion(*b)) {
291 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", 291, __extension__
__PRETTY_FUNCTION__))
;
292 regionB = &r;
293 }
294 }
295 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", 295, __extension__
__PRETTY_FUNCTION__))
;
296
297 // `a` and `b` are in mutually exclusive regions if both regions are
298 // distinct and neither region is reachable from the other region.
299 return regionA != regionB && !isRegionReachable(regionA, regionB) &&
300 !isRegionReachable(regionB, regionA);
301 }
302
303 // Could not find a common RegionBranchOpInterface among a's and b's
304 // ancestors.
305 return false;
306}
307
308bool RegionBranchOpInterface::isRepetitiveRegion(unsigned index) {
309 Region *region = &getOperation()->getRegion(index);
310 return isRegionReachable(region, region);
311}
312
313void RegionBranchOpInterface::getSuccessorRegions(
314 Optional<unsigned> index, SmallVectorImpl<RegionSuccessor> &regions) {
315 unsigned numInputs = 0;
316 if (index) {
317 // If the predecessor is a region, get the number of operands from an
318 // exiting terminator in the region.
319 for (Block &block : getOperation()->getRegion(*index)) {
320 Operation *terminator = block.getTerminator();
321 if (getRegionBranchSuccessorOperands(terminator, *index)) {
322 numInputs = terminator->getNumOperands();
323 break;
324 }
325 }
326 } else {
327 // Otherwise, use the number of parent operation operands.
328 numInputs = getOperation()->getNumOperands();
329 }
330 SmallVector<Attribute, 2> operands(numInputs, nullptr);
331 getSuccessorRegions(index, operands, regions);
332}
333
334Region *mlir::getEnclosingRepetitiveRegion(Operation *op) {
335 while (Region *region = op->getParentRegion()) {
336 op = region->getParentOp();
337 if (auto branchOp = dyn_cast<RegionBranchOpInterface>(op))
338 if (branchOp.isRepetitiveRegion(region->getRegionNumber()))
339 return region;
340 }
341 return nullptr;
342}
343
344Region *mlir::getEnclosingRepetitiveRegion(Value value) {
345 Region *region = value.getParentRegion();
346 while (region) {
347 Operation *op = region->getParentOp();
348 if (auto branchOp = dyn_cast<RegionBranchOpInterface>(op))
349 if (branchOp.isRepetitiveRegion(region->getRegionNumber()))
350 return region;
351 region = op->getParentRegion();
352 }
353 return nullptr;
354}
355
356//===----------------------------------------------------------------------===//
357// RegionBranchTerminatorOpInterface
358//===----------------------------------------------------------------------===//
359
360/// Returns true if the given operation is either annotated with the
361/// `ReturnLike` trait or implements the `RegionBranchTerminatorOpInterface`.
362bool mlir::isRegionReturnLike(Operation *operation) {
363 return dyn_cast<RegionBranchTerminatorOpInterface>(operation) ||
364 operation->hasTrait<OpTrait::ReturnLike>();
365}
366
367/// Returns the mutable operands that are passed to the region with the given
368/// `regionIndex`. If the operation does not implement the
369/// `RegionBranchTerminatorOpInterface` and is not marked as `ReturnLike`, the
370/// result will be `llvm::None`. In all other cases, the resulting
371/// `OperandRange` represents all operands that are passed to the specified
372/// successor region. If `regionIndex` is `llvm::None`, all operands that are
373/// passed to the parent operation will be returned.
374Optional<MutableOperandRange>
375mlir::getMutableRegionBranchSuccessorOperands(Operation *operation,
376 Optional<unsigned> regionIndex) {
377 // Try to query a RegionBranchTerminatorOpInterface to determine
378 // all successor operands that will be passed to the successor
379 // input arguments.
380 if (auto regionTerminatorInterface =
381 dyn_cast<RegionBranchTerminatorOpInterface>(operation))
382 return regionTerminatorInterface.getMutableSuccessorOperands(regionIndex);
383
384 // TODO: The ReturnLike trait should imply a default implementation of the
385 // RegionBranchTerminatorOpInterface. This would make this code significantly
386 // easier. Furthermore, this may even make this function obsolete.
387 if (operation->hasTrait<OpTrait::ReturnLike>())
388 return MutableOperandRange(operation);
389 return llvm::None;
390}
391
392/// Returns the read only operands that are passed to the region with the given
393/// `regionIndex`. See `getMutableRegionBranchSuccessorOperands` for more
394/// information.
395Optional<OperandRange>
396mlir::getRegionBranchSuccessorOperands(Operation *operation,
397 Optional<unsigned> regionIndex) {
398 auto range = getMutableRegionBranchSuccessorOperands(operation, regionIndex);
399 return range ? Optional<OperandRange>(*range) : llvm::None;
400}

/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/mlir/include/mlir/Interfaces/ControlFlowInterfaces.h

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
19namespace mlir {
20class BranchOpInterface;
21class 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).
43class SuccessorOperands {
44public:
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))
10
Taking true branch
78 return Value();
11
Passing null pointer value via 1st parameter 'impl'
12
Calling default constructor for 'Value'
14
Returning from default constructor for '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
115private:
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
127namespace detail {
128/// Return the `BlockArgument` corresponding to operand `operandIndex` in some
129/// successor if `operandIndex` is within the range of `operands`, or None if
130/// `operandIndex` isn't a successor operand index.
131Optional<BlockArgument>
132getBranchSuccessorArgument(const SuccessorOperands &operands,
133 unsigned operandIndex, Block *successor);
134
135/// Verify that the given operands match those of the given successor block.
136LogicalResult verifyBranchSuccessorOperands(Operation *op, unsigned succNo,
137 const SuccessorOperands &operands);
138} // namespace detail
139
140//===----------------------------------------------------------------------===//
141// RegionBranchOpInterface
142//===----------------------------------------------------------------------===//
143
144namespace detail {
145/// Verify that types match along control flow edges described the given op.
146LogicalResult 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.
160class RegionSuccessor {
161public:
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(Optional<Operation::result_range> results = {})
168 : inputs(results ? ValueRange(*results) : ValueRange()) {}
169
170 /// Return the given region successor. Returns nullptr if the successor is the
171 /// parent operation.
172 Region *getSuccessor() const { return region; }
173
174 /// Return true if the successor is the parent operation.
175 bool isParent() const { return region == nullptr; }
176
177 /// Return the inputs to the successor that are remapped by the exit values of
178 /// the current region.
179 ValueRange getSuccessorInputs() const { return inputs; }
180
181private:
182 Region *region{nullptr};
183 ValueRange inputs;
184};
185
186/// This class represents upper and lower bounds on the number of times a region
187/// of a `RegionBranchOpInterface` can be invoked. The lower bound is at least
188/// zero, but the upper bound may not be known.
189class InvocationBounds {
190public:
191 /// Create invocation bounds. The lower bound must be at least 0 and only the
192 /// upper bound can be unknown.
193 InvocationBounds(unsigned lb, Optional<unsigned> ub) : lower(lb), upper(ub) {
194 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", 194
, __extension__ __PRETTY_FUNCTION__))
;
195 }
196
197 /// Return the lower bound.
198 unsigned getLowerBound() const { return lower; }
199
200 /// Return the upper bound.
201 Optional<unsigned> getUpperBound() const { return upper; }
202
203 /// Returns the unknown invocation bounds, i.e., there is no information on
204 /// how many times a region may be invoked.
205 static InvocationBounds getUnknown() { return {0, llvm::None}; }
206
207private:
208 /// The minimum number of times the successor region will be invoked.
209 unsigned lower;
210 /// The maximum number of times the successor region will be invoked or `None`
211 /// if an upper bound is not known.
212 Optional<unsigned> upper;
213};
214
215/// Return `true` if `a` and `b` are in mutually exclusive regions as per
216/// RegionBranchOpInterface.
217bool insideMutuallyExclusiveRegions(Operation *a, Operation *b);
218
219/// Return the first enclosing region of the given op that may be executed
220/// repetitively as per RegionBranchOpInterface or `nullptr` if no such region
221/// exists.
222Region *getEnclosingRepetitiveRegion(Operation *op);
223
224/// Return the first enclosing region of the given Value that may be executed
225/// repetitively as per RegionBranchOpInterface or `nullptr` if no such region
226/// exists.
227Region *getEnclosingRepetitiveRegion(Value value);
228
229//===----------------------------------------------------------------------===//
230// RegionBranchTerminatorOpInterface
231//===----------------------------------------------------------------------===//
232
233/// Returns true if the given operation is either annotated with the
234/// `ReturnLike` trait or implements the `RegionBranchTerminatorOpInterface`.
235bool isRegionReturnLike(Operation *operation);
236
237/// Returns the mutable operands that are passed to the region with the given
238/// `regionIndex`. If the operation does not implement the
239/// `RegionBranchTerminatorOpInterface` and is not marked as `ReturnLike`, the
240/// result will be `llvm::None`. In all other cases, the resulting
241/// `OperandRange` represents all operands that are passed to the specified
242/// successor region. If `regionIndex` is `llvm::None`, all operands that are
243/// passed to the parent operation will be returned.
244Optional<MutableOperandRange>
245getMutableRegionBranchSuccessorOperands(Operation *operation,
246 Optional<unsigned> regionIndex);
247
248/// Returns the read only operands that are passed to the region with the given
249/// `regionIndex`. See `getMutableRegionBranchSuccessorOperands` for more
250/// information.
251Optional<OperandRange>
252getRegionBranchSuccessorOperands(Operation *operation,
253 Optional<unsigned> regionIndex);
254
255//===----------------------------------------------------------------------===//
256// ControlFlow Traits
257//===----------------------------------------------------------------------===//
258
259namespace OpTrait {
260/// This trait indicates that a terminator operation is "return-like". This
261/// means that it exits its current region and forwards its operands as "exit"
262/// values to the parent region. Operations with this trait are not permitted to
263/// contain successors or produce results.
264template <typename ConcreteType>
265struct ReturnLike : public TraitBase<ConcreteType, ReturnLike> {
266 static LogicalResult verifyTrait(Operation *op) {
267 static_assert(ConcreteType::template hasTrait<IsTerminator>(),
268 "expected operation to be a terminator");
269 static_assert(ConcreteType::template hasTrait<ZeroResults>(),
270 "expected operation to have zero results");
271 static_assert(ConcreteType::template hasTrait<ZeroSuccessors>(),
272 "expected operation to have zero successors");
273 return success();
274 }
275};
276} // namespace OpTrait
277
278} // namespace mlir
279
280//===----------------------------------------------------------------------===//
281// ControlFlow Interfaces
282//===----------------------------------------------------------------------===//
283
284/// Include the generated interface declarations.
285#include "mlir/Interfaces/ControlFlowInterfaces.h.inc"
286
287#endif // MLIR_INTERFACES_CONTROLFLOWINTERFACES_H

/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/mlir/include/mlir/IR/Value.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
21namespace mlir {
22class AsmState;
23class Block;
24class BlockArgument;
25class Operation;
26class OpOperand;
27class OpPrintingFlags;
28class OpResult;
29class Region;
30class Value;
31
32//===----------------------------------------------------------------------===//
33// Value
34//===----------------------------------------------------------------------===//
35
36namespace detail {
37
38/// The base class for all derived Value classes. It contains all of the
39/// components that are shared across Value classes.
40class alignas(8) ValueImpl : public IRObjectWithUseList<OpOperand> {
41public:
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
71protected:
72 ValueImpl(Type type, Kind kind) : typeAndKind(type, kind) {}
73
74 /// The type of this result and the kind.
75 llvm::PointerIntPair<Type, 3, Kind> typeAndKind;
76};
77} // namespace detail
78
79/// This class represents an instance of an SSA value in the MLIR system,
80/// representing a computable value that has a type and a set of users. An SSA
81/// value is either a BlockArgument or the result of an operation. Note: This
82/// class has value-type semantics and is just a simple wrapper around a
83/// ValueImpl that is either owner by a block(in the case of a BlockArgument) or
84/// an Operation(in the case of an OpResult).
85class Value {
86public:
87 constexpr Value(detail::ValueImpl *impl = nullptr) : impl(impl) {}
13
Null pointer value stored to field 'impl'
88
89 template <typename U>
90 bool isa() const {
91 assert(*this && "isa<> used on a null type.")(static_cast <bool> (*this && "isa<> used on a null type."
) ? void (0) : __assert_fail ("*this && \"isa<> used on a null type.\""
, "mlir/include/mlir/IR/Value.h", 91, __extension__ __PRETTY_FUNCTION__
))
;
92 return U::classof(*this);
93 }
94
95 template <typename First, typename Second, typename... Rest>
96 bool isa() const {
97 return isa<First>() || isa<Second, Rest...>();
98 }
99 template <typename U>
100 U dyn_cast() const {
101 return isa<U>() ? U(impl) : U(nullptr);
102 }
103 template <typename U>
104 U dyn_cast_or_null() const {
105 return (*this && isa<U>()) ? U(impl) : U(nullptr);
106 }
107 template <typename U>
108 U cast() const {
109 assert(isa<U>())(static_cast <bool> (isa<U>()) ? void (0) : __assert_fail
("isa<U>()", "mlir/include/mlir/IR/Value.h", 109, __extension__
__PRETTY_FUNCTION__))
;
110 return U(impl);
111 }
112
113 explicit operator bool() const { return impl; }
114 bool operator==(const Value &other) const { return impl == other.impl; }
115 bool operator!=(const Value &other) const { return !(*this == other); }
116
117 /// Return the type of this value.
118 Type getType() const { return impl->getType(); }
17
Called C++ object pointer is null
119
120 /// Utility to get the associated MLIRContext that this value is defined in.
121 MLIRContext *getContext() const { return getType().getContext(); }
122
123 /// Mutate the type of this Value to be of the specified type.
124 ///
125 /// Note that this is an extremely dangerous operation which can create
126 /// completely invalid IR very easily. It is strongly recommended that you
127 /// recreate IR objects with the right types instead of mutating them in
128 /// place.
129 void setType(Type newType) { impl->setType(newType); }
130
131 /// If this value is the result of an operation, return the operation that
132 /// defines it.
133 Operation *getDefiningOp() const;
134
135 /// If this value is the result of an operation of type OpTy, return the
136 /// operation that defines it.
137 template <typename OpTy>
138 OpTy getDefiningOp() const {
139 return llvm::dyn_cast_or_null<OpTy>(getDefiningOp());
140 }
141
142 /// Return the location of this value.
143 Location getLoc() const;
144 void setLoc(Location loc);
145
146 /// Return the Region in which this Value is defined.
147 Region *getParentRegion();
148
149 /// Return the Block in which this Value is defined.
150 Block *getParentBlock();
151
152 //===--------------------------------------------------------------------===//
153 // UseLists
154 //===--------------------------------------------------------------------===//
155
156 /// Drop all uses of this object from their respective owners.
157 void dropAllUses() const { return impl->dropAllUses(); }
158
159 /// Replace all uses of 'this' value with the new value, updating anything in
160 /// the IR that uses 'this' to use the other value instead. When this returns
161 /// there are zero uses of 'this'.
162 void replaceAllUsesWith(Value newValue) const {
163 impl->replaceAllUsesWith(newValue);
164 }
165
166 /// Replace all uses of 'this' value with 'newValue', updating anything in the
167 /// IR that uses 'this' to use the other value instead except if the user is
168 /// listed in 'exceptions' .
169 void
170 replaceAllUsesExcept(Value newValue,
171 const SmallPtrSetImpl<Operation *> &exceptions) const;
172
173 /// Replace all uses of 'this' value with 'newValue', updating anything in the
174 /// IR that uses 'this' to use the other value instead except if the user is
175 /// 'exceptedUser'.
176 void replaceAllUsesExcept(Value newValue, Operation *exceptedUser) const;
177
178 /// Replace all uses of 'this' value with 'newValue' if the given callback
179 /// returns true.
180 void replaceUsesWithIf(Value newValue,
181 function_ref<bool(OpOperand &)> shouldReplace);
182
183 /// Returns true if the value is used outside of the given block.
184 bool isUsedOutsideOfBlock(Block *block);
185
186 //===--------------------------------------------------------------------===//
187 // Uses
188
189 /// This class implements an iterator over the uses of a value.
190 using use_iterator = ValueUseIterator<OpOperand>;
191 using use_range = iterator_range<use_iterator>;
192
193 use_iterator use_begin() const { return impl->use_begin(); }
194 use_iterator use_end() const { return use_iterator(); }
195
196 /// Returns a range of all uses, which is useful for iterating over all uses.
197 use_range getUses() const { return {use_begin(), use_end()}; }
198
199 /// Returns true if this value has exactly one use.
200 bool hasOneUse() const { return impl->hasOneUse(); }
201
202 /// Returns true if this value has no uses.
203 bool use_empty() const { return impl->use_empty(); }
204
205 //===--------------------------------------------------------------------===//
206 // Users
207
208 using user_iterator = ValueUserIterator<use_iterator, OpOperand>;
209 using user_range = iterator_range<user_iterator>;
210
211 user_iterator user_begin() const { return use_begin(); }
212 user_iterator user_end() const { return use_end(); }
213 user_range getUsers() const { return {user_begin(), user_end()}; }
214
215 //===--------------------------------------------------------------------===//
216 // Utilities
217
218 void print(raw_ostream &os);
219 void print(raw_ostream &os, const OpPrintingFlags &flags);
220 void print(raw_ostream &os, AsmState &state);
221 void dump();
222
223 /// Print this value as if it were an operand.
224 void printAsOperand(raw_ostream &os, AsmState &state);
225
226 /// Methods for supporting PointerLikeTypeTraits.
227 void *getAsOpaquePointer() const { return impl; }
228 static Value getFromOpaquePointer(const void *pointer) {
229 return reinterpret_cast<detail::ValueImpl *>(const_cast<void *>(pointer));
230 }
231 detail::ValueImpl *getImpl() const { return impl; }
232
233 friend ::llvm::hash_code hash_value(Value arg);
234
235protected:
236 /// A pointer to the internal implementation of the value.
237 detail::ValueImpl *impl;
238};
239
240inline raw_ostream &operator<<(raw_ostream &os, Value value) {
241 value.print(os);
242 return os;
243}
244
245//===----------------------------------------------------------------------===//
246// OpOperand
247//===----------------------------------------------------------------------===//
248
249/// This class represents an operand of an operation. Instances of this class
250/// contain a reference to a specific `Value`.
251class OpOperand : public IROperand<OpOperand, Value> {
252public:
253 /// Provide the use list that is attached to the given value.
254 static IRObjectWithUseList<OpOperand> *getUseList(Value value) {
255 return value.getImpl();
256 }
257
258 /// Return which operand this is in the OpOperand list of the Operation.
259 unsigned getOperandNumber();
260
261private:
262 /// Keep the constructor private and accessible to the OperandStorage class
263 /// only to avoid hard-to-debug typo/programming mistakes.
264 friend class OperandStorage;
265 using IROperand<OpOperand, Value>::IROperand;
266};
267
268//===----------------------------------------------------------------------===//
269// BlockArgument
270//===----------------------------------------------------------------------===//
271
272namespace detail {
273/// The internal implementation of a BlockArgument.
274class BlockArgumentImpl : public ValueImpl {
275public:
276 static bool classof(const ValueImpl *value) {
277 return value->getKind() == ValueImpl::Kind::BlockArgument;
278 }
279
280private:
281 BlockArgumentImpl(Type type, Block *owner, int64_t index, Location loc)
282 : ValueImpl(type, Kind::BlockArgument), owner(owner), index(index),
283 loc(loc) {}
284
285 /// The owner of this argument.
286 Block *owner;
287
288 /// The position in the argument list.
289 int64_t index;
290
291 /// The source location of this argument.
292 Location loc;
293
294 /// Allow access to owner and constructor.
295 friend BlockArgument;
296};
297} // namespace detail
298
299/// This class represents an argument of a Block.
300class BlockArgument : public Value {
301public:
302 using Value::Value;
303
304 static bool classof(Value value) {
305 return llvm::isa<detail::BlockArgumentImpl>(value.getImpl());
306 }
307
308 /// Returns the block that owns this argument.
309 Block *getOwner() const { return getImpl()->owner; }
310
311 /// Returns the number of this argument.
312 unsigned getArgNumber() const { return getImpl()->index; }
313
314 /// Return the location for this argument.
315 Location getLoc() const { return getImpl()->loc; }
316 void setLoc(Location loc) { getImpl()->loc = loc; }
317
318private:
319 /// Allocate a new argument with the given type and owner.
320 static BlockArgument create(Type type, Block *owner, int64_t index,
321 Location loc) {
322 return new detail::BlockArgumentImpl(type, owner, index, loc);
323 }
324
325 /// Destroy and deallocate this argument.
326 void destroy() { delete getImpl(); }
327
328 /// Get a raw pointer to the internal implementation.
329 detail::BlockArgumentImpl *getImpl() const {
330 return reinterpret_cast<detail::BlockArgumentImpl *>(impl);
331 }
332
333 /// Cache the position in the block argument list.
334 void setArgNumber(int64_t index) { getImpl()->index = index; }
335
336 /// Allow access to `create`, `destroy` and `setArgNumber`.
337 friend Block;
338
339 /// Allow access to 'getImpl'.
340 friend Value;
341};
342
343//===----------------------------------------------------------------------===//
344// OpResult
345//===----------------------------------------------------------------------===//
346
347namespace detail {
348/// This class provides the implementation for an operation result.
349class alignas(8) OpResultImpl : public ValueImpl {
350public:
351 using ValueImpl::ValueImpl;
352
353 static bool classof(const ValueImpl *value) {
354 return value->getKind() != ValueImpl::Kind::BlockArgument;
355 }
356
357 /// Returns the parent operation of this result.
358 Operation *getOwner() const;
359
360 /// Returns the result number of this op result.
361 unsigned getResultNumber() const;
362
363 /// Returns the next operation result at `offset` after this result. This
364 /// method is useful when indexing the result storage of an operation, given
365 /// that there is more than one kind of operation result (with the different
366 /// kinds having different sizes) and that operations are stored in reverse
367 /// order.
368 OpResultImpl *getNextResultAtOffset(intptr_t offset);
369
370 /// Returns the maximum number of results that can be stored inline.
371 static unsigned getMaxInlineResults() {
372 return static_cast<unsigned>(Kind::OutOfLineOpResult);
373 }
374};
375
376/// This class provides the implementation for an operation result whose index
377/// can be represented "inline" in the underlying ValueImpl.
378struct InlineOpResult : public OpResultImpl {
379public:
380 InlineOpResult(Type type, unsigned resultNo)
381 : OpResultImpl(type, static_cast<ValueImpl::Kind>(resultNo)) {
382 assert(resultNo < getMaxInlineResults())(static_cast <bool> (resultNo < getMaxInlineResults(
)) ? void (0) : __assert_fail ("resultNo < getMaxInlineResults()"
, "mlir/include/mlir/IR/Value.h", 382, __extension__ __PRETTY_FUNCTION__
))
;
383 }
384
385 /// Return the result number of this op result.
386 unsigned getResultNumber() const { return static_cast<unsigned>(getKind()); }
387
388 static bool classof(const OpResultImpl *value) {
389 return value->getKind() != ValueImpl::Kind::OutOfLineOpResult;
390 }
391};
392
393/// This class provides the implementation for an operation result whose index
394/// cannot be represented "inline", and thus requires an additional index field.
395class OutOfLineOpResult : public OpResultImpl {
396public:
397 OutOfLineOpResult(Type type, uint64_t outOfLineIndex)
398 : OpResultImpl(type, Kind::OutOfLineOpResult),
399 outOfLineIndex(outOfLineIndex) {}
400
401 static bool classof(const OpResultImpl *value) {
402 return value->getKind() == ValueImpl::Kind::OutOfLineOpResult;
403 }
404
405 /// Return the result number of this op result.
406 unsigned getResultNumber() const {
407 return outOfLineIndex + getMaxInlineResults();
408 }
409
410 /// The trailing result number, or the offset from the beginning of the
411 /// `OutOfLineOpResult` array.
412 uint64_t outOfLineIndex;
413};
414
415/// Return the result number of this op result.
416inline unsigned OpResultImpl::getResultNumber() const {
417 if (const auto *outOfLineResult = dyn_cast<OutOfLineOpResult>(this))
418 return outOfLineResult->getResultNumber();
419 return cast<InlineOpResult>(this)->getResultNumber();
420}
421
422/// TypedValue is a Value with a statically know type.
423/// TypedValue can be null/empty
424template <typename Ty>
425struct TypedValue : Value {
426 /// Return the known Type
427 Ty getType() { return Value::getType().template cast<Ty>(); }
428 void setType(mlir::Type ty) {
429 assert(ty.template isa<Ty>())(static_cast <bool> (ty.template isa<Ty>()) ? void
(0) : __assert_fail ("ty.template isa<Ty>()", "mlir/include/mlir/IR/Value.h"
, 429, __extension__ __PRETTY_FUNCTION__))
;
430 Value::setType(ty);
431 }
432
433 TypedValue(Value val) : Value(val) {
434 assert(!val || val.getType().template isa<Ty>())(static_cast <bool> (!val || val.getType().template isa
<Ty>()) ? void (0) : __assert_fail ("!val || val.getType().template isa<Ty>()"
, "mlir/include/mlir/IR/Value.h", 434, __extension__ __PRETTY_FUNCTION__
))
;
435 }
436 TypedValue &operator=(const Value &other) {
437 assert(!other || other.getType().template isa<Ty>())(static_cast <bool> (!other || other.getType().template
isa<Ty>()) ? void (0) : __assert_fail ("!other || other.getType().template isa<Ty>()"
, "mlir/include/mlir/IR/Value.h", 437, __extension__ __PRETTY_FUNCTION__
))
;
438 Value::operator=(other);
439 return *this;
440 }
441};
442
443} // namespace detail
444
445/// This is a value defined by a result of an operation.
446class OpResult : public Value {
447public:
448 using Value::Value;
449
450 static bool classof(Value value) {
451 return llvm::isa<detail::OpResultImpl>(value.getImpl());
452 }
453
454 /// Returns the operation that owns this result.
455 Operation *getOwner() const { return getImpl()->getOwner(); }
456
457 /// Returns the number of this result.
458 unsigned getResultNumber() const { return getImpl()->getResultNumber(); }
459
460private:
461 /// Get a raw pointer to the internal implementation.
462 detail::OpResultImpl *getImpl() const {
463 return reinterpret_cast<detail::OpResultImpl *>(impl);
464 }
465
466 /// Given a number of operation results, returns the number that need to be
467 /// stored inline.
468 static unsigned getNumInline(unsigned numResults);
469
470 /// Given a number of operation results, returns the number that need to be
471 /// stored as trailing.
472 static unsigned getNumTrailing(unsigned numResults);
473
474 /// Allow access to constructor.
475 friend Operation;
476};
477
478/// Make Value hashable.
479inline ::llvm::hash_code hash_value(Value arg) {
480 return ::llvm::hash_value(arg.getImpl());
481}
482
483template <typename Ty, typename Value = mlir::Value>
484/// If Ty is mlir::Type this will select `Value` instead of having a wrapper
485/// around it. This helps resolve ambiguous conversion issues.
486using TypedValue = std::conditional_t<std::is_same_v<Ty, mlir::Type>,
487 mlir::Value, detail::TypedValue<Ty>>;
488
489} // namespace mlir
490
491namespace llvm {
492
493template <>
494struct DenseMapInfo<mlir::Value> {
495 static mlir::Value getEmptyKey() {
496 void *pointer = llvm::DenseMapInfo<void *>::getEmptyKey();
497 return mlir::Value::getFromOpaquePointer(pointer);
498 }
499 static mlir::Value getTombstoneKey() {
500 void *pointer = llvm::DenseMapInfo<void *>::getTombstoneKey();
501 return mlir::Value::getFromOpaquePointer(pointer);
502 }
503 static unsigned getHashValue(mlir::Value val) {
504 return mlir::hash_value(val);
505 }
506 static bool isEqual(mlir::Value lhs, mlir::Value rhs) { return lhs == rhs; }
507};
508template <>
509struct DenseMapInfo<mlir::BlockArgument> : public DenseMapInfo<mlir::Value> {
510 static mlir::BlockArgument getEmptyKey() {
511 void *pointer = llvm::DenseMapInfo<void *>::getEmptyKey();
512 return reinterpret_cast<mlir::detail::BlockArgumentImpl *>(pointer);
513 }
514 static mlir::BlockArgument getTombstoneKey() {
515 void *pointer = llvm::DenseMapInfo<void *>::getTombstoneKey();
516 return reinterpret_cast<mlir::detail::BlockArgumentImpl *>(pointer);
517 }
518};
519template <>
520struct DenseMapInfo<mlir::OpResult> : public DenseMapInfo<mlir::Value> {
521 static mlir::OpResult getEmptyKey() {
522 void *pointer = llvm::DenseMapInfo<void *>::getEmptyKey();
523 return reinterpret_cast<mlir::detail::OpResultImpl *>(pointer);
524 }
525 static mlir::OpResult getTombstoneKey() {
526 void *pointer = llvm::DenseMapInfo<void *>::getTombstoneKey();
527 return reinterpret_cast<mlir::detail::OpResultImpl *>(pointer);
528 }
529};
530
531/// Allow stealing the low bits of a value.
532template <>
533struct PointerLikeTypeTraits<mlir::Value> {
534public:
535 static inline void *getAsVoidPointer(mlir::Value value) {
536 return const_cast<void *>(value.getAsOpaquePointer());
537 }
538 static inline mlir::Value getFromVoidPointer(void *pointer) {
539 return mlir::Value::getFromOpaquePointer(pointer);
540 }
541 enum {
542 NumLowBitsAvailable =
543 PointerLikeTypeTraits<mlir::detail::ValueImpl *>::NumLowBitsAvailable
544 };
545};
546template <>
547struct PointerLikeTypeTraits<mlir::BlockArgument>
548 : public PointerLikeTypeTraits<mlir::Value> {
549public:
550 static inline mlir::BlockArgument getFromVoidPointer(void *pointer) {
551 return reinterpret_cast<mlir::detail::BlockArgumentImpl *>(pointer);
552 }
553};
554template <>
555struct PointerLikeTypeTraits<mlir::OpResult>
556 : public PointerLikeTypeTraits<mlir::Value> {
557public:
558 static inline mlir::OpResult getFromVoidPointer(void *pointer) {
559 return reinterpret_cast<mlir::detail::OpResultImpl *>(pointer);
560 }
561};
562
563} // namespace llvm
564
565#endif