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