Bug Summary

File:build/source/mlir/include/mlir/IR/Value.h
Warning:line 122, 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/source/build-llvm/tools/clang/stage2-bins -resource-dir /usr/lib/llvm-17/lib/clang/17 -D MLIR_CUDA_CONVERSIONS_ENABLED=1 -D MLIR_ROCM_CONVERSIONS_ENABLED=1 -D _DEBUG -D _GLIBCXX_ASSERTIONS -D _GNU_SOURCE -D _LIBCPP_ENABLE_ASSERTIONS -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I tools/mlir/lib/Interfaces -I /build/source/mlir/lib/Interfaces -I include -I /build/source/llvm/include -I /build/source/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-17/lib/clang/17/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/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fmacro-prefix-map=/build/source/= -fcoverage-prefix-map=/build/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fcoverage-prefix-map=/build/source/= -source-date-epoch 1683717183 -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/source/build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/source/= -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-2023-05-10-133810-16478-1 -x c++ /build/source/mlir/lib/Interfaces/ControlFlowInterfaces.cpp

/build/source/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
38/// std::nullopt if `operandIndex` isn't a successor operand index.
39std::optional<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 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.
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, 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).
93static 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.
152LogicalResult 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 &region = 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).
226static 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.
267bool 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
306bool RegionBranchOpInterface::isRepetitiveRegion(unsigned index) {
307 Region *region = &getOperation()->getRegion(index);
308 return isRegionReachable(region, region);
309}
310
311void RegionBranchOpInterface::getSuccessorRegions(
312 std::optional<unsigned> index, SmallVectorImpl<RegionSuccessor> &regions) {
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
332Region *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
342Region *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`.
360bool 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.
372std::optional<MutableOperandRange>
373mlir::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.
393std::optional<OperandRange>
394mlir::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}

/build/source/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
130/// std::nullopt if `operandIndex` isn't a successor operand index.
131std::optional<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(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
183private:
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.
191class InvocationBounds {
192public:
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
210private:
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.
220bool 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.
225Region *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.
230Region *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`.
238bool 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.
247std::optional<MutableOperandRange>
248getMutableRegionBranchSuccessorOperands(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.
254std::optional<OperandRange>
255getRegionBranchSuccessorOperands(Operation *operation,
256 std::optional<unsigned> regionIndex);
257
258//===----------------------------------------------------------------------===//
259// ControlFlow Traits
260//===----------------------------------------------------------------------===//
261
262namespace 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.
267template <typename ConcreteType>
268struct 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

/build/source/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 /// 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).
93class Value {
94public:
95 constexpr Value(detail::ValueImpl *impl = nullptr) : impl(impl) {}
13
Null pointer value stored to field '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(); }
17
Called C++ object pointer is null
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 void printAsOperand(raw_ostream &os, const OpPrintingFlags &flags);
230
231 /// Methods for supporting PointerLikeTypeTraits.
232 void *getAsOpaquePointer() const { return impl; }
233 static Value getFromOpaquePointer(const void *pointer) {
234 return reinterpret_cast<detail::ValueImpl *>(const_cast<void *>(pointer));
235 }
236 detail::ValueImpl *getImpl() const { return impl; }
237
238 friend ::llvm::hash_code hash_value(Value arg);
239
240protected:
241 /// A pointer to the internal implementation of the value.
242 detail::ValueImpl *impl;
243};
244
245inline raw_ostream &operator<<(raw_ostream &os, Value value) {
246 value.print(os);
247 return os;
248}
249
250//===----------------------------------------------------------------------===//
251// OpOperand
252//===----------------------------------------------------------------------===//
253
254/// This class represents an operand of an operation. Instances of this class
255/// contain a reference to a specific `Value`.
256class OpOperand : public IROperand<OpOperand, Value> {
257public:
258 /// Provide the use list that is attached to the given value.
259 static IRObjectWithUseList<OpOperand> *getUseList(Value value) {
260 return value.getImpl();
261 }
262
263 /// Return which operand this is in the OpOperand list of the Operation.
264 unsigned getOperandNumber();
265
266private:
267 /// Keep the constructor private and accessible to the OperandStorage class
268 /// only to avoid hard-to-debug typo/programming mistakes.
269 friend class OperandStorage;
270 using IROperand<OpOperand, Value>::IROperand;
271};
272
273//===----------------------------------------------------------------------===//
274// BlockArgument
275//===----------------------------------------------------------------------===//
276
277namespace detail {
278/// The internal implementation of a BlockArgument.
279class BlockArgumentImpl : public ValueImpl {
280public:
281 static bool classof(const ValueImpl *value) {
282 return value->getKind() == ValueImpl::Kind::BlockArgument;
283 }
284
285private:
286 BlockArgumentImpl(Type type, Block *owner, int64_t index, Location loc)
287 : ValueImpl(type, Kind::BlockArgument), owner(owner), index(index),
288 loc(loc) {}
289
290 /// The owner of this argument.
291 Block *owner;
292
293 /// The position in the argument list.
294 int64_t index;
295
296 /// The source location of this argument.
297 Location loc;
298
299 /// Allow access to owner and constructor.
300 friend BlockArgument;
301};
302} // namespace detail
303
304/// This class represents an argument of a Block.
305class BlockArgument : public Value {
306public:
307 using Value::Value;
308
309 static bool classof(Value value) {
310 return llvm::isa<detail::BlockArgumentImpl>(value.getImpl());
311 }
312
313 /// Returns the block that owns this argument.
314 Block *getOwner() const { return getImpl()->owner; }
315
316 /// Returns the number of this argument.
317 unsigned getArgNumber() const { return getImpl()->index; }
318
319 /// Return the location for this argument.
320 Location getLoc() const { return getImpl()->loc; }
321 void setLoc(Location loc) { getImpl()->loc = loc; }
322
323private:
324 /// Allocate a new argument with the given type and owner.
325 static BlockArgument create(Type type, Block *owner, int64_t index,
326 Location loc) {
327 return new detail::BlockArgumentImpl(type, owner, index, loc);
328 }
329
330 /// Destroy and deallocate this argument.
331 void destroy() { delete getImpl(); }
332
333 /// Get a raw pointer to the internal implementation.
334 detail::BlockArgumentImpl *getImpl() const {
335 return reinterpret_cast<detail::BlockArgumentImpl *>(impl);
336 }
337
338 /// Cache the position in the block argument list.
339 void setArgNumber(int64_t index) { getImpl()->index = index; }
340
341 /// Allow access to `create`, `destroy` and `setArgNumber`.
342 friend Block;
343
344 /// Allow access to 'getImpl'.
345 friend Value;
346};
347
348//===----------------------------------------------------------------------===//
349// OpResult
350//===----------------------------------------------------------------------===//
351
352namespace detail {
353/// This class provides the implementation for an operation result.
354class alignas(8) OpResultImpl : public ValueImpl {
355public:
356 using ValueImpl::ValueImpl;
357
358 static bool classof(const ValueImpl *value) {
359 return value->getKind() != ValueImpl::Kind::BlockArgument;
360 }
361
362 /// Returns the parent operation of this result.
363 Operation *getOwner() const;
364
365 /// Returns the result number of this op result.
366 unsigned getResultNumber() const;
367
368 /// Returns the next operation result at `offset` after this result. This
369 /// method is useful when indexing the result storage of an operation, given
370 /// that there is more than one kind of operation result (with the different
371 /// kinds having different sizes) and that operations are stored in reverse
372 /// order.
373 OpResultImpl *getNextResultAtOffset(intptr_t offset);
374
375 /// Returns the maximum number of results that can be stored inline.
376 static unsigned getMaxInlineResults() {
377 return static_cast<unsigned>(Kind::OutOfLineOpResult);
378 }
379};
380
381/// This class provides the implementation for an operation result whose index
382/// can be represented "inline" in the underlying ValueImpl.
383struct InlineOpResult : public OpResultImpl {
384public:
385 InlineOpResult(Type type, unsigned resultNo)
386 : OpResultImpl(type, static_cast<ValueImpl::Kind>(resultNo)) {
387 assert(resultNo < getMaxInlineResults())(static_cast <bool> (resultNo < getMaxInlineResults(
)) ? void (0) : __assert_fail ("resultNo < getMaxInlineResults()"
, "mlir/include/mlir/IR/Value.h", 387, __extension__ __PRETTY_FUNCTION__
))
;
388 }
389
390 /// Return the result number of this op result.
391 unsigned getResultNumber() const { return static_cast<unsigned>(getKind()); }
392
393 static bool classof(const OpResultImpl *value) {
394 return value->getKind() != ValueImpl::Kind::OutOfLineOpResult;
395 }
396};
397
398/// This class provides the implementation for an operation result whose index
399/// cannot be represented "inline", and thus requires an additional index field.
400class OutOfLineOpResult : public OpResultImpl {
401public:
402 OutOfLineOpResult(Type type, uint64_t outOfLineIndex)
403 : OpResultImpl(type, Kind::OutOfLineOpResult),
404 outOfLineIndex(outOfLineIndex) {}
405
406 static bool classof(const OpResultImpl *value) {
407 return value->getKind() == ValueImpl::Kind::OutOfLineOpResult;
408 }
409
410 /// Return the result number of this op result.
411 unsigned getResultNumber() const {
412 return outOfLineIndex + getMaxInlineResults();
413 }
414
415 /// The trailing result number, or the offset from the beginning of the
416 /// `OutOfLineOpResult` array.
417 uint64_t outOfLineIndex;
418};
419
420/// Return the result number of this op result.
421inline unsigned OpResultImpl::getResultNumber() const {
422 if (const auto *outOfLineResult = dyn_cast<OutOfLineOpResult>(this))
423 return outOfLineResult->getResultNumber();
424 return cast<InlineOpResult>(this)->getResultNumber();
425}
426
427/// TypedValue is a Value with a statically know type.
428/// TypedValue can be null/empty
429template <typename Ty>
430struct TypedValue : Value {
431 using Value::Value;
432
433 static bool classof(Value value) { return llvm::isa<Ty>(value.getType()); }
434
435 /// Return the known Type
436 Ty getType() { return Value::getType().template cast<Ty>(); }
437 void setType(Ty ty) { Value::setType(ty); }
438};
439
440} // namespace detail
441
442/// This is a value defined by a result of an operation.
443class OpResult : public Value {
444public:
445 using Value::Value;
446
447 static bool classof(Value value) {
448 return llvm::isa<detail::OpResultImpl>(value.getImpl());
449 }
450
451 /// Returns the operation that owns this result.
452 Operation *getOwner() const { return getImpl()->getOwner(); }
453
454 /// Returns the number of this result.
455 unsigned getResultNumber() const { return getImpl()->getResultNumber(); }
456
457private:
458 /// Get a raw pointer to the internal implementation.
459 detail::OpResultImpl *getImpl() const {
460 return reinterpret_cast<detail::OpResultImpl *>(impl);
461 }
462
463 /// Given a number of operation results, returns the number that need to be
464 /// stored inline.
465 static unsigned getNumInline(unsigned numResults);
466
467 /// Given a number of operation results, returns the number that need to be
468 /// stored as trailing.
469 static unsigned getNumTrailing(unsigned numResults);
470
471 /// Allow access to constructor.
472 friend Operation;
473};
474
475/// Make Value hashable.
476inline ::llvm::hash_code hash_value(Value arg) {
477 return ::llvm::hash_value(arg.getImpl());
478}
479
480template <typename Ty, typename Value = mlir::Value>
481/// If Ty is mlir::Type this will select `Value` instead of having a wrapper
482/// around it. This helps resolve ambiguous conversion issues.
483using TypedValue = std::conditional_t<std::is_same_v<Ty, mlir::Type>,
484 mlir::Value, detail::TypedValue<Ty>>;
485
486} // namespace mlir
487
488namespace llvm {
489
490template <>
491struct DenseMapInfo<mlir::Value> {
492 static mlir::Value getEmptyKey() {
493 void *pointer = llvm::DenseMapInfo<void *>::getEmptyKey();
494 return mlir::Value::getFromOpaquePointer(pointer);
495 }
496 static mlir::Value getTombstoneKey() {
497 void *pointer = llvm::DenseMapInfo<void *>::getTombstoneKey();
498 return mlir::Value::getFromOpaquePointer(pointer);
499 }
500 static unsigned getHashValue(mlir::Value val) {
501 return mlir::hash_value(val);
502 }
503 static bool isEqual(mlir::Value lhs, mlir::Value rhs) { return lhs == rhs; }
504};
505template <>
506struct DenseMapInfo<mlir::BlockArgument> : public DenseMapInfo<mlir::Value> {
507 static mlir::BlockArgument getEmptyKey() {
508 void *pointer = llvm::DenseMapInfo<void *>::getEmptyKey();
509 return reinterpret_cast<mlir::detail::BlockArgumentImpl *>(pointer);
510 }
511 static mlir::BlockArgument getTombstoneKey() {
512 void *pointer = llvm::DenseMapInfo<void *>::getTombstoneKey();
513 return reinterpret_cast<mlir::detail::BlockArgumentImpl *>(pointer);
514 }
515};
516template <>
517struct DenseMapInfo<mlir::OpResult> : public DenseMapInfo<mlir::Value> {
518 static mlir::OpResult getEmptyKey() {
519 void *pointer = llvm::DenseMapInfo<void *>::getEmptyKey();
520 return reinterpret_cast<mlir::detail::OpResultImpl *>(pointer);
521 }
522 static mlir::OpResult getTombstoneKey() {
523 void *pointer = llvm::DenseMapInfo<void *>::getTombstoneKey();
524 return reinterpret_cast<mlir::detail::OpResultImpl *>(pointer);
525 }
526};
527
528/// Allow stealing the low bits of a value.
529template <>
530struct PointerLikeTypeTraits<mlir::Value> {
531public:
532 static inline void *getAsVoidPointer(mlir::Value value) {
533 return const_cast<void *>(value.getAsOpaquePointer());
534 }
535 static inline mlir::Value getFromVoidPointer(void *pointer) {
536 return mlir::Value::getFromOpaquePointer(pointer);
537 }
538 enum {
539 NumLowBitsAvailable =
540 PointerLikeTypeTraits<mlir::detail::ValueImpl *>::NumLowBitsAvailable
541 };
542};
543template <>
544struct PointerLikeTypeTraits<mlir::BlockArgument>
545 : public PointerLikeTypeTraits<mlir::Value> {
546public:
547 static inline mlir::BlockArgument getFromVoidPointer(void *pointer) {
548 return reinterpret_cast<mlir::detail::BlockArgumentImpl *>(pointer);
549 }
550};
551template <>
552struct PointerLikeTypeTraits<mlir::OpResult>
553 : public PointerLikeTypeTraits<mlir::Value> {
554public:
555 static inline mlir::OpResult getFromVoidPointer(void *pointer) {
556 return reinterpret_cast<mlir::detail::OpResultImpl *>(pointer);
557 }
558};
559
560/// Add support for llvm style casts. We provide a cast between To and From if
561/// From is mlir::Value or derives from it.
562template <typename To, typename From>
563struct CastInfo<
564 To, From,
565 std::enable_if_t<std::is_same_v<mlir::Value, std::remove_const_t<From>> ||
566 std::is_base_of_v<mlir::Value, From>>>
567 : NullableValueCastFailed<To>,
568 DefaultDoCastIfPossible<To, From, CastInfo<To, From>> {
569 /// Arguments are taken as mlir::Value here and not as `From`, because
570 /// when casting from an intermediate type of the hierarchy to one of its
571 /// children, the val.getKind() inside T::classof will use the static
572 /// getKind() of the parent instead of the non-static ValueImpl::getKind()
573 /// that returns the dynamic type. This means that T::classof would end up
574 /// comparing the static Kind of the children to the static Kind of its
575 /// parent, making it impossible to downcast from the parent to the child.
576 static inline bool isPossible(mlir::Value ty) {
577 /// Return a constant true instead of a dynamic true when casting to self or
578 /// up the hierarchy.
579 if constexpr (std::is_base_of_v<To, From>) {
580 (void)ty;
581 return true;
582 } else {
583 return To::classof(ty);
584 }
585 }
586 static inline To doCast(mlir::Value value) { return To(value.getImpl()); }
587};
588
589} // namespace llvm
590
591#endif