Bug Summary

File:build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/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-store=region -analyzer-opt-analyze-nested-blocks -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-15~++20220420111733+e13d2efed663/build-llvm/tools/clang/stage2-bins -resource-dir /usr/lib/llvm-15/lib/clang/15.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-15~++20220420111733+e13d2efed663/mlir/lib/Interfaces -I include -I /build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/llvm/include -I /build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/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-15/lib/clang/15.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-15~++20220420111733+e13d2efed663/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fmacro-prefix-map=/build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/= -fcoverage-prefix-map=/build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fcoverage-prefix-map=/build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/= -O3 -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 -std=c++14 -fdeprecated-macro -fdebug-compilation-dir=/build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/= -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-04-20-140412-16051-1 -x c++ /build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/mlir/lib/Interfaces/ControlFlowInterfaces.cpp

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

/build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/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<ZeroResult>(),
270 "expected operation to have zero results");
271 static_assert(ConcreteType::template hasTrait<ZeroSuccessor>(),
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-15~++20220420111733+e13d2efed663/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} // namespace detail
423
424/// This is a value defined by a result of an operation.
425class OpResult : public Value {
426public:
427 using Value::Value;
428
429 static bool classof(Value value) {
430 return llvm::isa<detail::OpResultImpl>(value.getImpl());
431 }
432
433 /// Returns the operation that owns this result.
434 Operation *getOwner() const { return getImpl()->getOwner(); }
435
436 /// Returns the number of this result.
437 unsigned getResultNumber() const { return getImpl()->getResultNumber(); }
438
439private:
440 /// Get a raw pointer to the internal implementation.
441 detail::OpResultImpl *getImpl() const {
442 return reinterpret_cast<detail::OpResultImpl *>(impl);
443 }
444
445 /// Given a number of operation results, returns the number that need to be
446 /// stored inline.
447 static unsigned getNumInline(unsigned numResults);
448
449 /// Given a number of operation results, returns the number that need to be
450 /// stored as trailing.
451 static unsigned getNumTrailing(unsigned numResults);
452
453 /// Allow access to constructor.
454 friend Operation;
455};
456
457/// Make Value hashable.
458inline ::llvm::hash_code hash_value(Value arg) {
459 return ::llvm::hash_value(arg.getImpl());
460}
461
462} // namespace mlir
463
464namespace llvm {
465
466template <>
467struct DenseMapInfo<mlir::Value> {
468 static mlir::Value getEmptyKey() {
469 void *pointer = llvm::DenseMapInfo<void *>::getEmptyKey();
470 return mlir::Value::getFromOpaquePointer(pointer);
471 }
472 static mlir::Value getTombstoneKey() {
473 void *pointer = llvm::DenseMapInfo<void *>::getTombstoneKey();
474 return mlir::Value::getFromOpaquePointer(pointer);
475 }
476 static unsigned getHashValue(mlir::Value val) {
477 return mlir::hash_value(val);
478 }
479 static bool isEqual(mlir::Value lhs, mlir::Value rhs) { return lhs == rhs; }
480};
481template <>
482struct DenseMapInfo<mlir::BlockArgument> : public DenseMapInfo<mlir::Value> {
483 static mlir::BlockArgument getEmptyKey() {
484 void *pointer = llvm::DenseMapInfo<void *>::getEmptyKey();
485 return reinterpret_cast<mlir::detail::BlockArgumentImpl *>(pointer);
486 }
487 static mlir::BlockArgument getTombstoneKey() {
488 void *pointer = llvm::DenseMapInfo<void *>::getTombstoneKey();
489 return reinterpret_cast<mlir::detail::BlockArgumentImpl *>(pointer);
490 }
491};
492template <>
493struct DenseMapInfo<mlir::OpResult> : public DenseMapInfo<mlir::Value> {
494 static mlir::OpResult getEmptyKey() {
495 void *pointer = llvm::DenseMapInfo<void *>::getEmptyKey();
496 return reinterpret_cast<mlir::detail::OpResultImpl *>(pointer);
497 }
498 static mlir::OpResult getTombstoneKey() {
499 void *pointer = llvm::DenseMapInfo<void *>::getTombstoneKey();
500 return reinterpret_cast<mlir::detail::OpResultImpl *>(pointer);
501 }
502};
503
504/// Allow stealing the low bits of a value.
505template <>
506struct PointerLikeTypeTraits<mlir::Value> {
507public:
508 static inline void *getAsVoidPointer(mlir::Value value) {
509 return const_cast<void *>(value.getAsOpaquePointer());
510 }
511 static inline mlir::Value getFromVoidPointer(void *pointer) {
512 return mlir::Value::getFromOpaquePointer(pointer);
513 }
514 enum {
515 NumLowBitsAvailable =
516 PointerLikeTypeTraits<mlir::detail::ValueImpl *>::NumLowBitsAvailable
517 };
518};
519template <>
520struct PointerLikeTypeTraits<mlir::BlockArgument>
521 : public PointerLikeTypeTraits<mlir::Value> {
522public:
523 static inline mlir::BlockArgument getFromVoidPointer(void *pointer) {
524 return reinterpret_cast<mlir::detail::BlockArgumentImpl *>(pointer);
525 }
526};
527template <>
528struct PointerLikeTypeTraits<mlir::OpResult>
529 : public PointerLikeTypeTraits<mlir::Value> {
530public:
531 static inline mlir::OpResult getFromVoidPointer(void *pointer) {
532 return reinterpret_cast<mlir::detail::OpResultImpl *>(pointer);
533 }
534};
535
536} // namespace llvm
537
538#endif