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