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