14c05f8caSChris Lattner //===- Value.cpp - MLIR Value Classes -------------------------------------===//
24c05f8caSChris Lattner //
330857107SMehdi Amini // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
456222a06SMehdi Amini // See https://llvm.org/LICENSE.txt for license information.
556222a06SMehdi Amini // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
64c05f8caSChris Lattner //
756222a06SMehdi Amini //===----------------------------------------------------------------------===//
84c05f8caSChris Lattner
94c05f8caSChris Lattner #include "mlir/IR/Value.h"
104beef47bSAlex Zinenko #include "mlir/IR/Block.h"
1109f7a55fSRiver Riddle #include "mlir/IR/BuiltinTypes.h"
129ffdc930SRiver Riddle #include "mlir/IR/Operation.h"
13ad9988f4SAlexander Belyaev #include "llvm/ADT/SmallPtrSet.h"
1448e9ef43SRiver Riddle
154c05f8caSChris Lattner using namespace mlir;
1648e9ef43SRiver Riddle using namespace mlir::detail;
174c05f8caSChris Lattner
18f9d91531SRiver Riddle /// If this value is the result of an Operation, return the operation that
19f9d91531SRiver Riddle /// defines it.
getDefiningOp() const20ab46543cSRiver Riddle Operation *Value::getDefiningOp() const {
2168f58812STres Popp if (auto result = llvm::dyn_cast<OpResult>(*this))
222bdf33ccSRiver Riddle return result.getOwner();
234c05f8caSChris Lattner return nullptr;
244c05f8caSChris Lattner }
254c05f8caSChris Lattner
getLoc() const262bdf33ccSRiver Riddle Location Value::getLoc() const {
27ce502af9SRiver Riddle if (auto *op = getDefiningOp())
2851f6c0eaSMehdi Amini return op->getLoc();
294589dd92SRiver Riddle
3068f58812STres Popp return llvm::cast<BlockArgument>(*this).getLoc();
3181467f50SChris Lattner }
3281467f50SChris Lattner
setLoc(Location loc)3381467f50SChris Lattner void Value::setLoc(Location loc) {
3481467f50SChris Lattner if (auto *op = getDefiningOp())
3581467f50SChris Lattner return op->setLoc(loc);
3681467f50SChris Lattner
3768f58812STres Popp return llvm::cast<BlockArgument>(*this).setLoc(loc);
3851f6c0eaSMehdi Amini }
3951f6c0eaSMehdi Amini
404beef47bSAlex Zinenko /// Return the Region in which this Value is defined.
getParentRegion()411e429540SRiver Riddle Region *Value::getParentRegion() {
42f29731d1SRiver Riddle if (auto *op = getDefiningOp())
43f29731d1SRiver Riddle return op->getParentRegion();
4468f58812STres Popp return llvm::cast<BlockArgument>(*this).getOwner()->getParent();
454beef47bSAlex Zinenko }
464beef47bSAlex Zinenko
47469c02d0SRiver Riddle /// Return the Block in which this Value is defined.
getParentBlock()48469c02d0SRiver Riddle Block *Value::getParentBlock() {
49469c02d0SRiver Riddle if (Operation *op = getDefiningOp())
50469c02d0SRiver Riddle return op->getBlock();
5168f58812STres Popp return llvm::cast<BlockArgument>(*this).getOwner();
52469c02d0SRiver Riddle }
53469c02d0SRiver Riddle
544c05f8caSChris Lattner //===----------------------------------------------------------------------===//
550d6ebb4fSRiver Riddle // Value::UseLists
560d6ebb4fSRiver Riddle //===----------------------------------------------------------------------===//
570d6ebb4fSRiver Riddle
580d6ebb4fSRiver Riddle /// Replace all uses of 'this' value with the new value, updating anything in
59ad9988f4SAlexander Belyaev /// the IR that uses 'this' to use the other value instead except if the user is
60ad9988f4SAlexander Belyaev /// listed in 'exceptions' .
replaceAllUsesExcept(Value newValue,const SmallPtrSetImpl<Operation * > & exceptions)61ad9988f4SAlexander Belyaev void Value::replaceAllUsesExcept(
62*26a0b277SMehdi Amini Value newValue, const SmallPtrSetImpl<Operation *> &exceptions) {
6312874e93SSean Silva for (OpOperand &use : llvm::make_early_inc_range(getUses())) {
64ad9988f4SAlexander Belyaev if (exceptions.count(use.getOwner()) == 0)
65ad9988f4SAlexander Belyaev use.set(newValue);
66ad9988f4SAlexander Belyaev }
67ad9988f4SAlexander Belyaev }
68ad9988f4SAlexander Belyaev
6912874e93SSean Silva /// Replace all uses of 'this' value with 'newValue', updating anything in the
7012874e93SSean Silva /// IR that uses 'this' to use the other value instead except if the user is
7112874e93SSean Silva /// 'exceptedUser'.
replaceAllUsesExcept(Value newValue,Operation * exceptedUser)72*26a0b277SMehdi Amini void Value::replaceAllUsesExcept(Value newValue, Operation *exceptedUser) {
7312874e93SSean Silva for (OpOperand &use : llvm::make_early_inc_range(getUses())) {
7412874e93SSean Silva if (use.getOwner() != exceptedUser)
7512874e93SSean Silva use.set(newValue);
7612874e93SSean Silva }
7712874e93SSean Silva }
7812874e93SSean Silva
790816de16SRiver Riddle /// Replace all uses of 'this' value with 'newValue' if the given callback
800816de16SRiver Riddle /// returns true.
replaceUsesWithIf(Value newValue,function_ref<bool (OpOperand &)> shouldReplace)810816de16SRiver Riddle void Value::replaceUsesWithIf(Value newValue,
820816de16SRiver Riddle function_ref<bool(OpOperand &)> shouldReplace) {
830816de16SRiver Riddle for (OpOperand &use : llvm::make_early_inc_range(getUses()))
840816de16SRiver Riddle if (shouldReplace(use))
850816de16SRiver Riddle use.set(newValue);
860816de16SRiver Riddle }
870816de16SRiver Riddle
88469c02d0SRiver Riddle /// Returns true if the value is used outside of the given block.
isUsedOutsideOfBlock(Block * block) const89*26a0b277SMehdi Amini bool Value::isUsedOutsideOfBlock(Block *block) const {
90469c02d0SRiver Riddle return llvm::any_of(getUsers(), [block](Operation *user) {
91469c02d0SRiver Riddle return user->getBlock() != block;
92469c02d0SRiver Riddle });
93469c02d0SRiver Riddle }
94469c02d0SRiver Riddle
9561278191SMatteo Franciolini /// Shuffles the use-list order according to the provided indices.
shuffleUseList(ArrayRef<unsigned> indices)9661278191SMatteo Franciolini void Value::shuffleUseList(ArrayRef<unsigned> indices) {
9761278191SMatteo Franciolini getImpl()->shuffleUseList(indices);
9861278191SMatteo Franciolini }
9961278191SMatteo Franciolini
1000d6ebb4fSRiver Riddle //===----------------------------------------------------------------------===//
101fd01d862SRiver Riddle // OpResult
102fd01d862SRiver Riddle //===----------------------------------------------------------------------===//
103fd01d862SRiver Riddle
1043dfa8614SRiver Riddle /// Returns the parent operation of this trailing result.
getOwner() const1053dfa8614SRiver Riddle Operation *OpResultImpl::getOwner() const {
1063dfa8614SRiver Riddle // We need to do some arithmetic to get the operation pointer. Results are
1073dfa8614SRiver Riddle // stored in reverse order before the operation, so move the trailing owner up
1083dfa8614SRiver Riddle // to the start of the array. A rough diagram of the memory layout is:
1093dfa8614SRiver Riddle //
1103dfa8614SRiver Riddle // | Out-of-Line results | Inline results | Operation |
1113dfa8614SRiver Riddle //
1123dfa8614SRiver Riddle // Given that the results are reverse order we use the result number to know
1133dfa8614SRiver Riddle // how far to jump to get to the operation. So if we are currently the 0th
1143dfa8614SRiver Riddle // result, the layout would be:
1153dfa8614SRiver Riddle //
1163dfa8614SRiver Riddle // | Inline result 0 | Operation
1173dfa8614SRiver Riddle //
1183dfa8614SRiver Riddle // ^-- To get the base address of the operation, we add the result count + 1.
1193dfa8614SRiver Riddle if (const auto *result = dyn_cast<InlineOpResult>(this)) {
1203dfa8614SRiver Riddle result += result->getResultNumber() + 1;
1213dfa8614SRiver Riddle return reinterpret_cast<Operation *>(const_cast<InlineOpResult *>(result));
122fd01d862SRiver Riddle }
123fd01d862SRiver Riddle
1243dfa8614SRiver Riddle // Out-of-line results are stored in an array just before the inline results.
1253dfa8614SRiver Riddle const OutOfLineOpResult *outOfLineIt = (const OutOfLineOpResult *)(this);
1263dfa8614SRiver Riddle outOfLineIt += (outOfLineIt->outOfLineIndex + 1);
1273dfa8614SRiver Riddle
1283dfa8614SRiver Riddle // Move the owner past the inline results to get to the operation.
1293dfa8614SRiver Riddle const auto *inlineIt = reinterpret_cast<const InlineOpResult *>(outOfLineIt);
1303dfa8614SRiver Riddle inlineIt += getMaxInlineResults();
1313dfa8614SRiver Riddle return reinterpret_cast<Operation *>(const_cast<InlineOpResult *>(inlineIt));
1323dfa8614SRiver Riddle }
1333dfa8614SRiver Riddle
getNextResultAtOffset(intptr_t offset)1343dfa8614SRiver Riddle OpResultImpl *OpResultImpl::getNextResultAtOffset(intptr_t offset) {
1353dfa8614SRiver Riddle if (offset == 0)
1363dfa8614SRiver Riddle return this;
1373dfa8614SRiver Riddle // We need to do some arithmetic to get the next result given that results are
1383dfa8614SRiver Riddle // in reverse order, and that we need to account for the different types of
1393dfa8614SRiver Riddle // results. As a reminder, the rough diagram of the memory layout is:
1403dfa8614SRiver Riddle //
1413dfa8614SRiver Riddle // | Out-of-Line results | Inline results | Operation |
1423dfa8614SRiver Riddle //
1433dfa8614SRiver Riddle // So an example operation with two results would look something like:
1443dfa8614SRiver Riddle //
1453dfa8614SRiver Riddle // | Inline result 1 | Inline result 0 | Operation |
1463dfa8614SRiver Riddle //
1473dfa8614SRiver Riddle
1483dfa8614SRiver Riddle // Handle the case where this result is an inline result.
1493dfa8614SRiver Riddle OpResultImpl *result = this;
1503dfa8614SRiver Riddle if (auto *inlineResult = dyn_cast<InlineOpResult>(this)) {
1513dfa8614SRiver Riddle // Check to see how many results there are after this one before the start
1523dfa8614SRiver Riddle // of the out-of-line results. If the desired offset is less than the number
1533dfa8614SRiver Riddle // remaining, we can directly use the offset from the current result
1543dfa8614SRiver Riddle // pointer. The following diagrams highlight the two situations.
1553dfa8614SRiver Riddle //
1563dfa8614SRiver Riddle // | Out-of-Line results | Inline results | Operation |
1573dfa8614SRiver Riddle // ^- Say we are here.
1583dfa8614SRiver Riddle // ^- If our destination is here, we can use the
1593dfa8614SRiver Riddle // offset directly.
1603dfa8614SRiver Riddle //
1613dfa8614SRiver Riddle intptr_t leftBeforeTrailing =
1623dfa8614SRiver Riddle getMaxInlineResults() - inlineResult->getResultNumber() - 1;
1633dfa8614SRiver Riddle if (leftBeforeTrailing >= offset)
1643dfa8614SRiver Riddle return inlineResult - offset;
1653dfa8614SRiver Riddle
1663dfa8614SRiver Riddle // Otherwise, adjust the current result pointer to the end (start in memory)
1673dfa8614SRiver Riddle // of the inline result array.
1683dfa8614SRiver Riddle //
1693dfa8614SRiver Riddle // | Out-of-Line results | Inline results | Operation |
1703dfa8614SRiver Riddle // ^- Say we are here.
1713dfa8614SRiver Riddle // ^- If our destination is here, we need to first jump to
1723dfa8614SRiver Riddle // the end (start in memory) of the inline result array.
1733dfa8614SRiver Riddle //
1743dfa8614SRiver Riddle result = inlineResult - leftBeforeTrailing;
1753dfa8614SRiver Riddle offset -= leftBeforeTrailing;
1763dfa8614SRiver Riddle }
1773dfa8614SRiver Riddle
1783dfa8614SRiver Riddle // If we land here, the current result is an out-of-line result and we can
1793dfa8614SRiver Riddle // offset directly.
1803dfa8614SRiver Riddle return reinterpret_cast<OutOfLineOpResult *>(result) - offset;
18148e9ef43SRiver Riddle }
18248e9ef43SRiver Riddle
18348e9ef43SRiver Riddle /// Given a number of operation results, returns the number that need to be
18448e9ef43SRiver Riddle /// stored inline.
getNumInline(unsigned numResults)18548e9ef43SRiver Riddle unsigned OpResult::getNumInline(unsigned numResults) {
1863dfa8614SRiver Riddle return std::min(numResults, OpResultImpl::getMaxInlineResults());
187fd01d862SRiver Riddle }
188fd01d862SRiver Riddle
189fd01d862SRiver Riddle /// Given a number of operation results, returns the number that need to be
190fd01d862SRiver Riddle /// stored as trailing.
getNumTrailing(unsigned numResults)191fd01d862SRiver Riddle unsigned OpResult::getNumTrailing(unsigned numResults) {
192fd01d862SRiver Riddle // If we can pack all of the results, there is no need for additional storage.
1933dfa8614SRiver Riddle unsigned maxInline = OpResultImpl::getMaxInlineResults();
19448e9ef43SRiver Riddle return numResults <= maxInline ? 0 : numResults - maxInline;
195fd01d862SRiver Riddle }
196fd01d862SRiver Riddle
197fd01d862SRiver Riddle //===----------------------------------------------------------------------===//
198f83a8efeSRiver Riddle // BlockOperand
199f83a8efeSRiver Riddle //===----------------------------------------------------------------------===//
200f83a8efeSRiver Riddle
2010d6ebb4fSRiver Riddle /// Provide the use list that is attached to the given block.
getUseList(Block * value)2020d6ebb4fSRiver Riddle IRObjectWithUseList<BlockOperand> *BlockOperand::getUseList(Block *value) {
2030d6ebb4fSRiver Riddle return value;
2040d6ebb4fSRiver Riddle }
205f83a8efeSRiver Riddle
206f83a8efeSRiver Riddle /// Return which operand this is in the operand list.
getOperandNumber()207f83a8efeSRiver Riddle unsigned BlockOperand::getOperandNumber() {
208f83a8efeSRiver Riddle return this - &getOwner()->getBlockOperands()[0];
209f83a8efeSRiver Riddle }
210f83a8efeSRiver Riddle
211f83a8efeSRiver Riddle //===----------------------------------------------------------------------===//
212f83a8efeSRiver Riddle // OpOperand
213f83a8efeSRiver Riddle //===----------------------------------------------------------------------===//
214f83a8efeSRiver Riddle
215f83a8efeSRiver Riddle /// Return which operand this is in the operand list.
getOperandNumber()216f83a8efeSRiver Riddle unsigned OpOperand::getOperandNumber() {
217f83a8efeSRiver Riddle return this - &getOwner()->getOpOperands()[0];
218f83a8efeSRiver Riddle }
219