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