1 //===- Value.cpp - MLIR Value Classes -------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
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"
16 using namespace mlir::detail
;
18 /// If this value is the result of an Operation, return the operation that
20 Operation
*Value::getDefiningOp() const {
21 if (auto result
= llvm::dyn_cast
<OpResult
>(*this))
22 return result
.getOwner();
26 Location
Value::getLoc() const {
27 if (auto *op
= getDefiningOp())
30 return llvm::cast
<BlockArgument
>(*this).getLoc();
33 void Value::setLoc(Location loc
) {
34 if (auto *op
= getDefiningOp())
35 return op
->setLoc(loc
);
37 return llvm::cast
<BlockArgument
>(*this).setLoc(loc
);
40 /// Return the Region in which this Value is defined.
41 Region
*Value::getParentRegion() {
42 if (auto *op
= getDefiningOp())
43 return op
->getParentRegion();
44 return llvm::cast
<BlockArgument
>(*this).getOwner()->getParent();
47 /// Return the Block in which this Value is defined.
48 Block
*Value::getParentBlock() {
49 if (Operation
*op
= getDefiningOp())
50 return op
->getBlock();
51 return llvm::cast
<BlockArgument
>(*this).getOwner();
54 //===----------------------------------------------------------------------===//
56 //===----------------------------------------------------------------------===//
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' .
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)
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
72 void Value::replaceAllUsesExcept(Value newValue
, Operation
*exceptedUser
) {
73 for (OpOperand
&use
: llvm::make_early_inc_range(getUses())) {
74 if (use
.getOwner() != exceptedUser
)
79 /// Replace all uses of 'this' value with 'newValue' if the given callback
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
))
88 /// Returns true if the value is used outside of the given block.
89 bool Value::isUsedOutsideOfBlock(Block
*block
) const {
90 return llvm::any_of(getUsers(), [block
](Operation
*user
) {
91 return user
->getBlock() != block
;
95 /// Shuffles the use-list order according to the provided indices.
96 void Value::shuffleUseList(ArrayRef
<unsigned> indices
) {
97 getImpl()->shuffleUseList(indices
);
100 //===----------------------------------------------------------------------===//
102 //===----------------------------------------------------------------------===//
104 /// Returns the parent operation of this trailing result.
105 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:
110 // | Out-of-Line results | Inline results | Operation |
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:
116 // | Inline result 0 | Operation
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
));
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);
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
));
134 OpResultImpl
*OpResultImpl::getNextResultAtOffset(intptr_t offset
) {
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:
141 // | Out-of-Line results | Inline results | Operation |
143 // So an example operation with two results would look something like:
145 // | Inline result 1 | Inline result 0 | Operation |
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.
156 // | Out-of-Line results | Inline results | Operation |
157 // ^- Say we are here.
158 // ^- If our destination is here, we can use the
161 intptr_t leftBeforeTrailing
=
162 getMaxInlineResults() - inlineResult
->getResultNumber() - 1;
163 if (leftBeforeTrailing
>= offset
)
164 return inlineResult
- offset
;
166 // Otherwise, adjust the current result pointer to the end (start in memory)
167 // of the inline result array.
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.
174 result
= inlineResult
- leftBeforeTrailing
;
175 offset
-= leftBeforeTrailing
;
178 // If we land here, the current result is an out-of-line result and we can
180 return reinterpret_cast<OutOfLineOpResult
*>(result
) - offset
;
183 /// Given a number of operation results, returns the number that need to be
185 unsigned OpResult::getNumInline(unsigned numResults
) {
186 return std::min(numResults
, OpResultImpl::getMaxInlineResults());
189 /// Given a number of operation results, returns the number that need to be
190 /// stored as trailing.
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
;
197 //===----------------------------------------------------------------------===//
199 //===----------------------------------------------------------------------===//
201 /// Provide the use list that is attached to the given block.
202 IRObjectWithUseList
<BlockOperand
> *BlockOperand::getUseList(Block
*value
) {
206 /// Return which operand this is in the operand list.
207 unsigned BlockOperand::getOperandNumber() {
208 return this - &getOwner()->getBlockOperands()[0];
211 //===----------------------------------------------------------------------===//
213 //===----------------------------------------------------------------------===//
215 /// Return which operand this is in the operand list.
216 unsigned OpOperand::getOperandNumber() {
217 return this - &getOwner()->getOpOperands()[0];