229 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "mlir/IR/Value.h"10#include "mlir/IR/Block.h"11#include "mlir/IR/Operation.h"12 13using namespace mlir;14using namespace mlir::detail;15 16/// If this value is the result of an Operation, return the operation that17/// defines it.18Operation *Value::getDefiningOp() const {19 if (auto result = llvm::dyn_cast<OpResult>(*this))20 return result.getOwner();21 return nullptr;22}23 24Location Value::getLoc() const {25 if (auto *op = getDefiningOp())26 return op->getLoc();27 28 return llvm::cast<BlockArgument>(*this).getLoc();29}30 31void Value::setLoc(Location loc) {32 if (auto *op = getDefiningOp())33 return op->setLoc(loc);34 35 return llvm::cast<BlockArgument>(*this).setLoc(loc);36}37 38/// Return the Region in which this Value is defined.39Region *Value::getParentRegion() {40 if (auto *op = getDefiningOp())41 return op->getParentRegion();42 return llvm::cast<BlockArgument>(*this).getOwner()->getParent();43}44 45/// Return the Block in which this Value is defined.46Block *Value::getParentBlock() {47 if (Operation *op = getDefiningOp())48 return op->getBlock();49 return llvm::cast<BlockArgument>(*this).getOwner();50}51 52unsigned Value::getNumUses() const {53 return (unsigned)std::distance(use_begin(), use_end());54}55 56bool Value::hasNUses(unsigned n) const {57 return hasNItems(use_begin(), use_end(), n);58}59 60bool Value::hasNUsesOrMore(unsigned n) const {61 return hasNItemsOrMore(use_begin(), use_end(), n);62}63 64//===----------------------------------------------------------------------===//65// Value::UseLists66//===----------------------------------------------------------------------===//67 68/// Replace all uses of 'this' value with the new value, updating anything in69/// the IR that uses 'this' to use the other value instead except if the user is70/// listed in 'exceptions' .71void Value::replaceAllUsesExcept(72 Value newValue, const SmallPtrSetImpl<Operation *> &exceptions) {73 for (OpOperand &use : llvm::make_early_inc_range(getUses())) {74 if (exceptions.count(use.getOwner()) == 0)75 use.set(newValue);76 }77}78 79/// Replace all uses of 'this' value with 'newValue', updating anything in the80/// IR that uses 'this' to use the other value instead except if the user is81/// 'exceptedUser'.82void Value::replaceAllUsesExcept(Value newValue, Operation *exceptedUser) {83 for (OpOperand &use : llvm::make_early_inc_range(getUses())) {84 if (use.getOwner() != exceptedUser)85 use.set(newValue);86 }87}88 89/// Replace all uses of 'this' value with 'newValue' if the given callback90/// returns true.91void Value::replaceUsesWithIf(Value newValue,92 function_ref<bool(OpOperand &)> shouldReplace) {93 for (OpOperand &use : llvm::make_early_inc_range(getUses()))94 if (shouldReplace(use))95 use.set(newValue);96}97 98/// Returns true if the value is used outside of the given block.99bool Value::isUsedOutsideOfBlock(Block *block) const {100 return llvm::any_of(getUsers(), [block](Operation *user) {101 return user->getBlock() != block;102 });103}104 105/// Shuffles the use-list order according to the provided indices.106void Value::shuffleUseList(ArrayRef<unsigned> indices) {107 getImpl()->shuffleUseList(indices);108}109 110//===----------------------------------------------------------------------===//111// OpResult112//===----------------------------------------------------------------------===//113 114/// Returns the parent operation of this trailing result.115Operation *OpResultImpl::getOwner() const {116 // We need to do some arithmetic to get the operation pointer. Results are117 // stored in reverse order before the operation, so move the trailing owner up118 // to the start of the array. A rough diagram of the memory layout is:119 //120 // | Out-of-Line results | Inline results | Operation |121 //122 // Given that the results are reverse order we use the result number to know123 // how far to jump to get to the operation. So if we are currently the 0th124 // result, the layout would be:125 //126 // | Inline result 0 | Operation127 //128 // ^-- To get the base address of the operation, we add the result count + 1.129 if (const auto *result = dyn_cast<InlineOpResult>(this)) {130 result += result->getResultNumber() + 1;131 return reinterpret_cast<Operation *>(const_cast<InlineOpResult *>(result));132 }133 134 // Out-of-line results are stored in an array just before the inline results.135 const OutOfLineOpResult *outOfLineIt = (const OutOfLineOpResult *)(this);136 outOfLineIt += (outOfLineIt->outOfLineIndex + 1);137 138 // Move the owner past the inline results to get to the operation.139 const auto *inlineIt = reinterpret_cast<const InlineOpResult *>(outOfLineIt);140 inlineIt += getMaxInlineResults();141 return reinterpret_cast<Operation *>(const_cast<InlineOpResult *>(inlineIt));142}143 144OpResultImpl *OpResultImpl::getNextResultAtOffset(intptr_t offset) {145 if (offset == 0)146 return this;147 // We need to do some arithmetic to get the next result given that results are148 // in reverse order, and that we need to account for the different types of149 // results. As a reminder, the rough diagram of the memory layout is:150 //151 // | Out-of-Line results | Inline results | Operation |152 //153 // So an example operation with two results would look something like:154 //155 // | Inline result 1 | Inline result 0 | Operation |156 //157 158 // Handle the case where this result is an inline result.159 OpResultImpl *result = this;160 if (auto *inlineResult = dyn_cast<InlineOpResult>(this)) {161 // Check to see how many results there are after this one before the start162 // of the out-of-line results. If the desired offset is less than the number163 // remaining, we can directly use the offset from the current result164 // pointer. The following diagrams highlight the two situations.165 //166 // | Out-of-Line results | Inline results | Operation |167 // ^- Say we are here.168 // ^- If our destination is here, we can use the169 // offset directly.170 //171 intptr_t leftBeforeTrailing =172 getMaxInlineResults() - inlineResult->getResultNumber() - 1;173 if (leftBeforeTrailing >= offset)174 return inlineResult - offset;175 176 // Otherwise, adjust the current result pointer to the end (start in memory)177 // of the inline result array.178 //179 // | Out-of-Line results | Inline results | Operation |180 // ^- Say we are here.181 // ^- If our destination is here, we need to first jump to182 // the end (start in memory) of the inline result array.183 //184 result = inlineResult - leftBeforeTrailing;185 offset -= leftBeforeTrailing;186 }187 188 // If we land here, the current result is an out-of-line result and we can189 // offset directly.190 return reinterpret_cast<OutOfLineOpResult *>(result) - offset;191}192 193/// Given a number of operation results, returns the number that need to be194/// stored inline.195unsigned OpResult::getNumInline(unsigned numResults) {196 return std::min(numResults, OpResultImpl::getMaxInlineResults());197}198 199/// Given a number of operation results, returns the number that need to be200/// stored as trailing.201unsigned OpResult::getNumTrailing(unsigned numResults) {202 // If we can pack all of the results, there is no need for additional storage.203 unsigned maxInline = OpResultImpl::getMaxInlineResults();204 return numResults <= maxInline ? 0 : numResults - maxInline;205}206 207//===----------------------------------------------------------------------===//208// BlockOperand209//===----------------------------------------------------------------------===//210 211/// Provide the use list that is attached to the given block.212IRObjectWithUseList<BlockOperand> *BlockOperand::getUseList(Block *value) {213 return value;214}215 216/// Return which operand this is in the operand list.217unsigned BlockOperand::getOperandNumber() {218 return this - &getOwner()->getBlockOperands()[0];219}220 221//===----------------------------------------------------------------------===//222// OpOperand223//===----------------------------------------------------------------------===//224 225/// Return which operand this is in the operand list.226unsigned OpOperand::getOperandNumber() {227 return this - &getOwner()->getOpOperands()[0];228}229