/home/arjun/llvm-project/mlir/lib/IR/Value.cpp
Line | Count | Source (jump to first uncovered line) |
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/Operation.h" |
12 | | #include "mlir/IR/StandardTypes.h" |
13 | | #include "llvm/ADT/SmallPtrSet.h" |
14 | | |
15 | | using namespace mlir; |
16 | | using namespace mlir::detail; |
17 | | |
18 | | /// Construct a value. |
19 | | Value::Value(BlockArgumentImpl *impl) |
20 | 0 | : ownerAndKind(impl, Kind::BlockArgument) {} |
21 | 0 | Value::Value(Operation *op, unsigned resultNo) { |
22 | 0 | assert(op->getNumResults() > resultNo && "invalid result number"); |
23 | 0 | if (LLVM_LIKELY(canPackResultInline(resultNo))) { |
24 | 0 | ownerAndKind = {op, static_cast<Kind>(resultNo)}; |
25 | 0 | return; |
26 | 0 | } |
27 | 0 | |
28 | 0 | // If we can't pack the result directly, grab the use list from the parent op. |
29 | 0 | unsigned trailingNo = resultNo - OpResult::getMaxInlineResults(); |
30 | 0 | ownerAndKind = {op->getTrailingResult(trailingNo), Kind::TrailingOpResult}; |
31 | 0 | } |
32 | | |
33 | | /// Return the type of this value. |
34 | 0 | Type Value::getType() const { |
35 | 0 | if (BlockArgument arg = dyn_cast<BlockArgument>()) |
36 | 0 | return arg.getType(); |
37 | 0 | |
38 | 0 | // If this is an operation result, query the parent operation. |
39 | 0 | OpResult result = cast<OpResult>(); |
40 | 0 | Operation *owner = result.getOwner(); |
41 | 0 | if (owner->hasSingleResult) |
42 | 0 | return owner->resultType; |
43 | 0 | return owner->resultType.cast<TupleType>().getType(result.getResultNumber()); |
44 | 0 | } |
45 | | |
46 | | /// Mutate the type of this Value to be of the specified type. |
47 | 0 | void Value::setType(Type newType) { |
48 | 0 | if (BlockArgument arg = dyn_cast<BlockArgument>()) |
49 | 0 | return arg.setType(newType); |
50 | 0 | OpResult result = cast<OpResult>(); |
51 | 0 |
|
52 | 0 | // If the owner has a single result, simply update it directly. |
53 | 0 | Operation *owner = result.getOwner(); |
54 | 0 | if (owner->hasSingleResult) { |
55 | 0 | owner->resultType = newType; |
56 | 0 | return; |
57 | 0 | } |
58 | 0 | unsigned resultNo = result.getResultNumber(); |
59 | 0 |
|
60 | 0 | // Otherwise, rebuild the tuple if the new type is different from the current. |
61 | 0 | auto curTypes = owner->resultType.cast<TupleType>().getTypes(); |
62 | 0 | if (curTypes[resultNo] == newType) |
63 | 0 | return; |
64 | 0 | auto newTypes = llvm::to_vector<4>(curTypes); |
65 | 0 | newTypes[resultNo] = newType; |
66 | 0 | owner->resultType = TupleType::get(newTypes, newType.getContext()); |
67 | 0 | } |
68 | | |
69 | | /// If this value is the result of an Operation, return the operation that |
70 | | /// defines it. |
71 | 0 | Operation *Value::getDefiningOp() const { |
72 | 0 | if (auto result = dyn_cast<OpResult>()) |
73 | 0 | return result.getOwner(); |
74 | 0 | return nullptr; |
75 | 0 | } |
76 | | |
77 | 0 | Location Value::getLoc() const { |
78 | 0 | if (auto *op = getDefiningOp()) |
79 | 0 | return op->getLoc(); |
80 | 0 | return UnknownLoc::get(getContext()); |
81 | 0 | } |
82 | | |
83 | | /// Return the Region in which this Value is defined. |
84 | 0 | Region *Value::getParentRegion() { |
85 | 0 | if (auto *op = getDefiningOp()) |
86 | 0 | return op->getParentRegion(); |
87 | 0 | return cast<BlockArgument>().getOwner()->getParent(); |
88 | 0 | } |
89 | | |
90 | | /// Return the Block in which this Value is defined. |
91 | 0 | Block *Value::getParentBlock() { |
92 | 0 | if (Operation *op = getDefiningOp()) |
93 | 0 | return op->getBlock(); |
94 | 0 | return cast<BlockArgument>().getOwner(); |
95 | 0 | } |
96 | | |
97 | | //===----------------------------------------------------------------------===// |
98 | | // Value::UseLists |
99 | | //===----------------------------------------------------------------------===// |
100 | | |
101 | | /// Provide the use list that is attached to this value. |
102 | 0 | IRObjectWithUseList<OpOperand> *Value::getUseList() const { |
103 | 0 | if (BlockArgument arg = dyn_cast<BlockArgument>()) |
104 | 0 | return arg.getImpl(); |
105 | 0 | if (getKind() != Kind::TrailingOpResult) { |
106 | 0 | OpResult result = cast<OpResult>(); |
107 | 0 | return result.getOwner()->getInlineResult(result.getResultNumber()); |
108 | 0 | } |
109 | 0 | |
110 | 0 | // Otherwise this is a trailing operation result, which contains a use list. |
111 | 0 | return reinterpret_cast<TrailingOpResult *>(ownerAndKind.getPointer()); |
112 | 0 | } |
113 | | |
114 | | /// Drop all uses of this object from their respective owners. |
115 | 0 | void Value::dropAllUses() const { return getUseList()->dropAllUses(); } |
116 | | |
117 | | /// Replace all uses of 'this' value with the new value, updating anything in |
118 | | /// the IR that uses 'this' to use the other value instead. When this returns |
119 | | /// there are zero uses of 'this'. |
120 | 0 | void Value::replaceAllUsesWith(Value newValue) const { |
121 | 0 | return getUseList()->replaceAllUsesWith(newValue); |
122 | 0 | } |
123 | | |
124 | | /// Replace all uses of 'this' value with the new value, updating anything in |
125 | | /// the IR that uses 'this' to use the other value instead except if the user is |
126 | | /// listed in 'exceptions' . |
127 | | void Value::replaceAllUsesExcept( |
128 | 0 | Value newValue, const SmallPtrSetImpl<Operation *> &exceptions) const { |
129 | 0 | for (auto &use : llvm::make_early_inc_range(getUses())) { |
130 | 0 | if (exceptions.count(use.getOwner()) == 0) |
131 | 0 | use.set(newValue); |
132 | 0 | } |
133 | 0 | } |
134 | | |
135 | | /// Replace all uses of 'this' value with 'newValue' if the given callback |
136 | | /// returns true. |
137 | | void Value::replaceUsesWithIf(Value newValue, |
138 | 0 | function_ref<bool(OpOperand &)> shouldReplace) { |
139 | 0 | for (OpOperand &use : llvm::make_early_inc_range(getUses())) |
140 | 0 | if (shouldReplace(use)) |
141 | 0 | use.set(newValue); |
142 | 0 | } |
143 | | |
144 | | /// Returns true if the value is used outside of the given block. |
145 | 0 | bool Value::isUsedOutsideOfBlock(Block *block) { |
146 | 0 | return llvm::any_of(getUsers(), [block](Operation *user) { |
147 | 0 | return user->getBlock() != block; |
148 | 0 | }); |
149 | 0 | } |
150 | | |
151 | | //===--------------------------------------------------------------------===// |
152 | | // Uses |
153 | | |
154 | 0 | auto Value::use_begin() const -> use_iterator { |
155 | 0 | return getUseList()->use_begin(); |
156 | 0 | } |
157 | | |
158 | | /// Returns true if this value has exactly one use. |
159 | 0 | bool Value::hasOneUse() const { return getUseList()->hasOneUse(); } |
160 | | |
161 | | /// Returns true if this value has no uses. |
162 | 0 | bool Value::use_empty() const { return getUseList()->use_empty(); } |
163 | | |
164 | | //===----------------------------------------------------------------------===// |
165 | | // OpResult |
166 | | //===----------------------------------------------------------------------===// |
167 | | |
168 | | /// Returns the operation that owns this result. |
169 | 0 | Operation *OpResult::getOwner() const { |
170 | 0 | // If the result is in-place, the `owner` is the operation. |
171 | 0 | void *owner = ownerAndKind.getPointer(); |
172 | 0 | if (LLVM_LIKELY(getKind() != Kind::TrailingOpResult)) |
173 | 0 | return static_cast<Operation *>(owner); |
174 | 0 | |
175 | 0 | // Otherwise, query the trailing result for the owner. |
176 | 0 | return static_cast<TrailingOpResult *>(owner)->getOwner(); |
177 | 0 | } |
178 | | |
179 | | /// Return the result number of this result. |
180 | 0 | unsigned OpResult::getResultNumber() const { |
181 | 0 | // If the result is in-place, we can use the kind directly. |
182 | 0 | if (LLVM_LIKELY(getKind() != Kind::TrailingOpResult)) |
183 | 0 | return static_cast<unsigned>(ownerAndKind.getInt()); |
184 | 0 | // Otherwise, query the trailing result. |
185 | 0 | auto *result = static_cast<TrailingOpResult *>(ownerAndKind.getPointer()); |
186 | 0 | return result->getResultNumber(); |
187 | 0 | } |
188 | | |
189 | | /// Given a number of operation results, returns the number that need to be |
190 | | /// stored inline. |
191 | 0 | unsigned OpResult::getNumInline(unsigned numResults) { |
192 | 0 | return std::min(numResults, getMaxInlineResults()); |
193 | 0 | } |
194 | | |
195 | | /// Given a number of operation results, returns the number that need to be |
196 | | /// stored as trailing. |
197 | 0 | unsigned OpResult::getNumTrailing(unsigned numResults) { |
198 | 0 | // If we can pack all of the results, there is no need for additional storage. |
199 | 0 | unsigned maxInline = getMaxInlineResults(); |
200 | 0 | return numResults <= maxInline ? 0 : numResults - maxInline; |
201 | 0 | } |
202 | | |
203 | | //===----------------------------------------------------------------------===// |
204 | | // BlockOperand |
205 | | //===----------------------------------------------------------------------===// |
206 | | |
207 | | /// Provide the use list that is attached to the given block. |
208 | 0 | IRObjectWithUseList<BlockOperand> *BlockOperand::getUseList(Block *value) { |
209 | 0 | return value; |
210 | 0 | } |
211 | | |
212 | | /// Return which operand this is in the operand list. |
213 | 0 | unsigned BlockOperand::getOperandNumber() { |
214 | 0 | return this - &getOwner()->getBlockOperands()[0]; |
215 | 0 | } |
216 | | |
217 | | //===----------------------------------------------------------------------===// |
218 | | // OpOperand |
219 | | //===----------------------------------------------------------------------===// |
220 | | |
221 | | /// Provide the use list that is attached to the given value. |
222 | 0 | IRObjectWithUseList<OpOperand> *OpOperand::getUseList(Value value) { |
223 | 0 | return value.getUseList(); |
224 | 0 | } |
225 | | |
226 | | /// Return the current value being used by this operand. |
227 | 0 | Value OpOperand::get() const { |
228 | 0 | return IROperand<OpOperand, OpaqueValue>::get(); |
229 | 0 | } |
230 | | |
231 | | /// Set the operand to the given value. |
232 | 0 | void OpOperand::set(Value value) { |
233 | 0 | IROperand<OpOperand, OpaqueValue>::set(value); |
234 | 0 | } |
235 | | |
236 | | /// Return which operand this is in the operand list. |
237 | 0 | unsigned OpOperand::getOperandNumber() { |
238 | 0 | return this - &getOwner()->getOpOperands()[0]; |
239 | 0 | } |
240 | | |
241 | | //===----------------------------------------------------------------------===// |
242 | | // OpaqueValue |
243 | | //===----------------------------------------------------------------------===// |
244 | | |
245 | | /// Implicit conversion from 'Value'. |
246 | 0 | OpaqueValue::OpaqueValue(Value value) : impl(value.getAsOpaquePointer()) {} |
247 | | |
248 | | /// Implicit conversion back to 'Value'. |
249 | 0 | OpaqueValue::operator Value() const { |
250 | 0 | return Value::getFromOpaquePointer(impl); |
251 | 0 | } |