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