forked from OSchip/llvm-project
216 lines
8.0 KiB
C++
216 lines
8.0 KiB
C++
//===- Value.cpp - MLIR Value Classes -------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "mlir/IR/Value.h"
|
|
#include "mlir/IR/Block.h"
|
|
#include "mlir/IR/BuiltinTypes.h"
|
|
#include "mlir/IR/Operation.h"
|
|
#include "llvm/ADT/SmallPtrSet.h"
|
|
|
|
using namespace mlir;
|
|
using namespace mlir::detail;
|
|
|
|
/// If this value is the result of an Operation, return the operation that
|
|
/// defines it.
|
|
Operation *Value::getDefiningOp() const {
|
|
if (auto result = dyn_cast<OpResult>())
|
|
return result.getOwner();
|
|
return nullptr;
|
|
}
|
|
|
|
Location Value::getLoc() const {
|
|
if (auto *op = getDefiningOp())
|
|
return op->getLoc();
|
|
|
|
return cast<BlockArgument>().getLoc();
|
|
}
|
|
|
|
void Value::setLoc(Location loc) {
|
|
if (auto *op = getDefiningOp())
|
|
return op->setLoc(loc);
|
|
|
|
return cast<BlockArgument>().setLoc(loc);
|
|
}
|
|
|
|
/// Return the Region in which this Value is defined.
|
|
Region *Value::getParentRegion() {
|
|
if (auto *op = getDefiningOp())
|
|
return op->getParentRegion();
|
|
return cast<BlockArgument>().getOwner()->getParent();
|
|
}
|
|
|
|
/// Return the Block in which this Value is defined.
|
|
Block *Value::getParentBlock() {
|
|
if (Operation *op = getDefiningOp())
|
|
return op->getBlock();
|
|
return cast<BlockArgument>().getOwner();
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Value::UseLists
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// Replace all uses of 'this' value with the new value, updating anything in
|
|
/// the IR that uses 'this' to use the other value instead except if the user is
|
|
/// listed in 'exceptions' .
|
|
void Value::replaceAllUsesExcept(
|
|
Value newValue, const SmallPtrSetImpl<Operation *> &exceptions) const {
|
|
for (OpOperand &use : llvm::make_early_inc_range(getUses())) {
|
|
if (exceptions.count(use.getOwner()) == 0)
|
|
use.set(newValue);
|
|
}
|
|
}
|
|
|
|
/// Replace all uses of 'this' value with 'newValue', updating anything in the
|
|
/// IR that uses 'this' to use the other value instead except if the user is
|
|
/// 'exceptedUser'.
|
|
void Value::replaceAllUsesExcept(Value newValue,
|
|
Operation *exceptedUser) const {
|
|
for (OpOperand &use : llvm::make_early_inc_range(getUses())) {
|
|
if (use.getOwner() != exceptedUser)
|
|
use.set(newValue);
|
|
}
|
|
}
|
|
|
|
/// Replace all uses of 'this' value with 'newValue' if the given callback
|
|
/// returns true.
|
|
void Value::replaceUsesWithIf(Value newValue,
|
|
function_ref<bool(OpOperand &)> shouldReplace) {
|
|
for (OpOperand &use : llvm::make_early_inc_range(getUses()))
|
|
if (shouldReplace(use))
|
|
use.set(newValue);
|
|
}
|
|
|
|
/// Returns true if the value is used outside of the given block.
|
|
bool Value::isUsedOutsideOfBlock(Block *block) {
|
|
return llvm::any_of(getUsers(), [block](Operation *user) {
|
|
return user->getBlock() != block;
|
|
});
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// OpResult
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// Returns the parent operation of this trailing result.
|
|
Operation *OpResultImpl::getOwner() const {
|
|
// We need to do some arithmetic to get the operation pointer. Results are
|
|
// stored in reverse order before the operation, so move the trailing owner up
|
|
// to the start of the array. A rough diagram of the memory layout is:
|
|
//
|
|
// | Out-of-Line results | Inline results | Operation |
|
|
//
|
|
// Given that the results are reverse order we use the result number to know
|
|
// how far to jump to get to the operation. So if we are currently the 0th
|
|
// result, the layout would be:
|
|
//
|
|
// | Inline result 0 | Operation
|
|
//
|
|
// ^-- To get the base address of the operation, we add the result count + 1.
|
|
if (const auto *result = dyn_cast<InlineOpResult>(this)) {
|
|
result += result->getResultNumber() + 1;
|
|
return reinterpret_cast<Operation *>(const_cast<InlineOpResult *>(result));
|
|
}
|
|
|
|
// Out-of-line results are stored in an array just before the inline results.
|
|
const OutOfLineOpResult *outOfLineIt = (const OutOfLineOpResult *)(this);
|
|
outOfLineIt += (outOfLineIt->outOfLineIndex + 1);
|
|
|
|
// Move the owner past the inline results to get to the operation.
|
|
const auto *inlineIt = reinterpret_cast<const InlineOpResult *>(outOfLineIt);
|
|
inlineIt += getMaxInlineResults();
|
|
return reinterpret_cast<Operation *>(const_cast<InlineOpResult *>(inlineIt));
|
|
}
|
|
|
|
OpResultImpl *OpResultImpl::getNextResultAtOffset(intptr_t offset) {
|
|
if (offset == 0)
|
|
return this;
|
|
// We need to do some arithmetic to get the next result given that results are
|
|
// in reverse order, and that we need to account for the different types of
|
|
// results. As a reminder, the rough diagram of the memory layout is:
|
|
//
|
|
// | Out-of-Line results | Inline results | Operation |
|
|
//
|
|
// So an example operation with two results would look something like:
|
|
//
|
|
// | Inline result 1 | Inline result 0 | Operation |
|
|
//
|
|
|
|
// Handle the case where this result is an inline result.
|
|
OpResultImpl *result = this;
|
|
if (auto *inlineResult = dyn_cast<InlineOpResult>(this)) {
|
|
// Check to see how many results there are after this one before the start
|
|
// of the out-of-line results. If the desired offset is less than the number
|
|
// remaining, we can directly use the offset from the current result
|
|
// pointer. The following diagrams highlight the two situations.
|
|
//
|
|
// | Out-of-Line results | Inline results | Operation |
|
|
// ^- Say we are here.
|
|
// ^- If our destination is here, we can use the
|
|
// offset directly.
|
|
//
|
|
intptr_t leftBeforeTrailing =
|
|
getMaxInlineResults() - inlineResult->getResultNumber() - 1;
|
|
if (leftBeforeTrailing >= offset)
|
|
return inlineResult - offset;
|
|
|
|
// Otherwise, adjust the current result pointer to the end (start in memory)
|
|
// of the inline result array.
|
|
//
|
|
// | Out-of-Line results | Inline results | Operation |
|
|
// ^- Say we are here.
|
|
// ^- If our destination is here, we need to first jump to
|
|
// the end (start in memory) of the inline result array.
|
|
//
|
|
result = inlineResult - leftBeforeTrailing;
|
|
offset -= leftBeforeTrailing;
|
|
}
|
|
|
|
// If we land here, the current result is an out-of-line result and we can
|
|
// offset directly.
|
|
return reinterpret_cast<OutOfLineOpResult *>(result) - offset;
|
|
}
|
|
|
|
/// Given a number of operation results, returns the number that need to be
|
|
/// stored inline.
|
|
unsigned OpResult::getNumInline(unsigned numResults) {
|
|
return std::min(numResults, OpResultImpl::getMaxInlineResults());
|
|
}
|
|
|
|
/// Given a number of operation results, returns the number that need to be
|
|
/// stored as trailing.
|
|
unsigned OpResult::getNumTrailing(unsigned numResults) {
|
|
// If we can pack all of the results, there is no need for additional storage.
|
|
unsigned maxInline = OpResultImpl::getMaxInlineResults();
|
|
return numResults <= maxInline ? 0 : numResults - maxInline;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// BlockOperand
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// Provide the use list that is attached to the given block.
|
|
IRObjectWithUseList<BlockOperand> *BlockOperand::getUseList(Block *value) {
|
|
return value;
|
|
}
|
|
|
|
/// Return which operand this is in the operand list.
|
|
unsigned BlockOperand::getOperandNumber() {
|
|
return this - &getOwner()->getBlockOperands()[0];
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// OpOperand
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// Return which operand this is in the operand list.
|
|
unsigned OpOperand::getOperandNumber() {
|
|
return this - &getOwner()->getOpOperands()[0];
|
|
}
|
|
|