1//===- Value.cpp - MLIR Value Classes -------------------------------------===//
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 "mlir/IR/Value.h"
10#include "mlir/IR/Block.h"
11#include "mlir/IR/BuiltinTypes.h"
12#include "mlir/IR/Operation.h"
13#include "llvm/ADT/SmallPtrSet.h"
14
15using namespace mlir;
16using namespace mlir::detail;
17
18/// If this value is the result of an Operation, return the operation that
19/// defines it.
20Operation *Value::getDefiningOp() const {
21 if (auto result = llvm::dyn_cast<OpResult>(Val: *this))
22 return result.getOwner();
23 return nullptr;
24}
25
26Location Value::getLoc() const {
27 if (auto *op = getDefiningOp())
28 return op->getLoc();
29
30 return llvm::cast<BlockArgument>(Val: *this).getLoc();
31}
32
33void Value::setLoc(Location loc) {
34 if (auto *op = getDefiningOp())
35 return op->setLoc(loc);
36
37 return llvm::cast<BlockArgument>(Val&: *this).setLoc(loc);
38}
39
40/// Return the Region in which this Value is defined.
41Region *Value::getParentRegion() {
42 if (auto *op = getDefiningOp())
43 return op->getParentRegion();
44 return llvm::cast<BlockArgument>(Val&: *this).getOwner()->getParent();
45}
46
47/// Return the Block in which this Value is defined.
48Block *Value::getParentBlock() {
49 if (Operation *op = getDefiningOp())
50 return op->getBlock();
51 return llvm::cast<BlockArgument>(Val&: *this).getOwner();
52}
53
54unsigned Value::getNumUses() const {
55 return (unsigned)std::distance(first: use_begin(), last: use_end());
56}
57
58bool Value::hasNUses(unsigned n) const {
59 return hasNItems(Begin: use_begin(), End: use_end(), N: n);
60}
61
62bool Value::hasNUsesOrMore(unsigned n) const {
63 return hasNItemsOrMore(Begin: use_begin(), End: use_end(), N: n);
64}
65
66//===----------------------------------------------------------------------===//
67// Value::UseLists
68//===----------------------------------------------------------------------===//
69
70/// Replace all uses of 'this' value with the new value, updating anything in
71/// the IR that uses 'this' to use the other value instead except if the user is
72/// listed in 'exceptions' .
73void Value::replaceAllUsesExcept(
74 Value newValue, const SmallPtrSetImpl<Operation *> &exceptions) {
75 for (OpOperand &use : llvm::make_early_inc_range(Range: getUses())) {
76 if (exceptions.count(Ptr: use.getOwner()) == 0)
77 use.set(newValue);
78 }
79}
80
81/// Replace all uses of 'this' value with 'newValue', updating anything in the
82/// IR that uses 'this' to use the other value instead except if the user is
83/// 'exceptedUser'.
84void Value::replaceAllUsesExcept(Value newValue, Operation *exceptedUser) {
85 for (OpOperand &use : llvm::make_early_inc_range(Range: getUses())) {
86 if (use.getOwner() != exceptedUser)
87 use.set(newValue);
88 }
89}
90
91/// Replace all uses of 'this' value with 'newValue' if the given callback
92/// returns true.
93void Value::replaceUsesWithIf(Value newValue,
94 function_ref<bool(OpOperand &)> shouldReplace) {
95 for (OpOperand &use : llvm::make_early_inc_range(Range: getUses()))
96 if (shouldReplace(use))
97 use.set(newValue);
98}
99
100/// Returns true if the value is used outside of the given block.
101bool Value::isUsedOutsideOfBlock(Block *block) const {
102 return llvm::any_of(Range: getUsers(), P: [block](Operation *user) {
103 return user->getBlock() != block;
104 });
105}
106
107/// Shuffles the use-list order according to the provided indices.
108void Value::shuffleUseList(ArrayRef<unsigned> indices) {
109 getImpl()->shuffleUseList(indices);
110}
111
112//===----------------------------------------------------------------------===//
113// OpResult
114//===----------------------------------------------------------------------===//
115
116/// Returns the parent operation of this trailing result.
117Operation *OpResultImpl::getOwner() const {
118 // We need to do some arithmetic to get the operation pointer. Results are
119 // stored in reverse order before the operation, so move the trailing owner up
120 // to the start of the array. A rough diagram of the memory layout is:
121 //
122 // | Out-of-Line results | Inline results | Operation |
123 //
124 // Given that the results are reverse order we use the result number to know
125 // how far to jump to get to the operation. So if we are currently the 0th
126 // result, the layout would be:
127 //
128 // | Inline result 0 | Operation
129 //
130 // ^-- To get the base address of the operation, we add the result count + 1.
131 if (const auto *result = dyn_cast<InlineOpResult>(Val: this)) {
132 result += result->getResultNumber() + 1;
133 return reinterpret_cast<Operation *>(const_cast<InlineOpResult *>(result));
134 }
135
136 // Out-of-line results are stored in an array just before the inline results.
137 const OutOfLineOpResult *outOfLineIt = (const OutOfLineOpResult *)(this);
138 outOfLineIt += (outOfLineIt->outOfLineIndex + 1);
139
140 // Move the owner past the inline results to get to the operation.
141 const auto *inlineIt = reinterpret_cast<const InlineOpResult *>(outOfLineIt);
142 inlineIt += getMaxInlineResults();
143 return reinterpret_cast<Operation *>(const_cast<InlineOpResult *>(inlineIt));
144}
145
146OpResultImpl *OpResultImpl::getNextResultAtOffset(intptr_t offset) {
147 if (offset == 0)
148 return this;
149 // We need to do some arithmetic to get the next result given that results are
150 // in reverse order, and that we need to account for the different types of
151 // results. As a reminder, the rough diagram of the memory layout is:
152 //
153 // | Out-of-Line results | Inline results | Operation |
154 //
155 // So an example operation with two results would look something like:
156 //
157 // | Inline result 1 | Inline result 0 | Operation |
158 //
159
160 // Handle the case where this result is an inline result.
161 OpResultImpl *result = this;
162 if (auto *inlineResult = dyn_cast<InlineOpResult>(Val: this)) {
163 // Check to see how many results there are after this one before the start
164 // of the out-of-line results. If the desired offset is less than the number
165 // remaining, we can directly use the offset from the current result
166 // pointer. The following diagrams highlight the two situations.
167 //
168 // | Out-of-Line results | Inline results | Operation |
169 // ^- Say we are here.
170 // ^- If our destination is here, we can use the
171 // offset directly.
172 //
173 intptr_t leftBeforeTrailing =
174 getMaxInlineResults() - inlineResult->getResultNumber() - 1;
175 if (leftBeforeTrailing >= offset)
176 return inlineResult - offset;
177
178 // Otherwise, adjust the current result pointer to the end (start in memory)
179 // of the inline result array.
180 //
181 // | Out-of-Line results | Inline results | Operation |
182 // ^- Say we are here.
183 // ^- If our destination is here, we need to first jump to
184 // the end (start in memory) of the inline result array.
185 //
186 result = inlineResult - leftBeforeTrailing;
187 offset -= leftBeforeTrailing;
188 }
189
190 // If we land here, the current result is an out-of-line result and we can
191 // offset directly.
192 return reinterpret_cast<OutOfLineOpResult *>(result) - offset;
193}
194
195/// Given a number of operation results, returns the number that need to be
196/// stored inline.
197unsigned OpResult::getNumInline(unsigned numResults) {
198 return std::min(a: numResults, b: OpResultImpl::getMaxInlineResults());
199}
200
201/// Given a number of operation results, returns the number that need to be
202/// stored as trailing.
203unsigned OpResult::getNumTrailing(unsigned numResults) {
204 // If we can pack all of the results, there is no need for additional storage.
205 unsigned maxInline = OpResultImpl::getMaxInlineResults();
206 return numResults <= maxInline ? 0 : numResults - maxInline;
207}
208
209//===----------------------------------------------------------------------===//
210// BlockOperand
211//===----------------------------------------------------------------------===//
212
213/// Provide the use list that is attached to the given block.
214IRObjectWithUseList<BlockOperand> *BlockOperand::getUseList(Block *value) {
215 return value;
216}
217
218/// Return which operand this is in the operand list.
219unsigned BlockOperand::getOperandNumber() {
220 return this - &getOwner()->getBlockOperands()[0];
221}
222
223//===----------------------------------------------------------------------===//
224// OpOperand
225//===----------------------------------------------------------------------===//
226
227/// Return which operand this is in the operand list.
228unsigned OpOperand::getOperandNumber() {
229 return this - &getOwner()->getOpOperands()[0];
230}
231

source code of mlir/lib/IR/Value.cpp