blob: 8b839054755138a88687724374b65e971a8eaf5c [file] [log] [blame]
//===- Value.h - Base of the SSA Value hierarchy ----------------*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// This file defines generic Value type and manipulation utilities.
//
//===----------------------------------------------------------------------===//
#ifndef MLIR_IR_VALUE_H
#define MLIR_IR_VALUE_H
#include "mlir/IR/Types.h"
#include "mlir/IR/UseDefLists.h"
#include "mlir/Support/LLVM.h"
#include "llvm/Support/PointerLikeTypeTraits.h"
namespace mlir {
class AsmState;
class Block;
class BlockArgument;
class Operation;
class OpOperand;
class OpResult;
class Region;
class Value;
//===----------------------------------------------------------------------===//
// Value
//===----------------------------------------------------------------------===//
namespace detail {
/// The base class for all derived Value classes. It contains all of the
/// components that are shared across Value classes.
class alignas(8) ValueImpl : public IRObjectWithUseList<OpOperand> {
public:
/// The enumeration represents the various different kinds of values the
/// internal representation may take. We use all of the bits from Type that we
/// can to store indices inline.
enum class Kind {
/// The first N kinds are all inline operation results. An inline operation
/// result means that the kind represents the result number. This removes
/// the need to store an additional index value. The derived class here is
/// an `OpResultImpl`.
InlineOpResult = 0,
/// The next kind represents a 'out-of-line' operation result. This is for
/// results with numbers larger than we can represent inline. The derived
/// class here is an `OpResultImpl`.
OutOfLineOpResult = 6,
/// The last kind represents a block argument. The derived class here is an
/// `BlockArgumentImpl`.
BlockArgument = 7
};
/// Return the type of this value.
Type getType() const { return typeAndKind.getPointer(); }
/// Set the type of this value.
void setType(Type type) { return typeAndKind.setPointer(type); }
/// Return the kind of this value.
Kind getKind() const { return typeAndKind.getInt(); }
protected:
ValueImpl(Type type, Kind kind) : typeAndKind(type, kind) {}
/// The type of this result and the kind.
llvm::PointerIntPair<Type, 3, Kind> typeAndKind;
};
} // namespace detail
/// This class represents an instance of an SSA value in the MLIR system,
/// representing a computable value that has a type and a set of users. An SSA
/// value is either a BlockArgument or the result of an operation. Note: This
/// class has value-type semantics and is just a simple wrapper around a
/// ValueImpl that is either owner by a block(in the case of a BlockArgument) or
/// an Operation(in the case of an OpResult).
class Value {
public:
Value(detail::ValueImpl *impl = nullptr) : impl(impl) {}
Value(const Value &) = default;
Value &operator=(const Value &) = default;
template <typename U>
bool isa() const {
assert(*this && "isa<> used on a null type.");
return U::classof(*this);
}
template <typename First, typename Second, typename... Rest>
bool isa() const {
return isa<First>() || isa<Second, Rest...>();
}
template <typename U>
U dyn_cast() const {
return isa<U>() ? U(impl) : U(nullptr);
}
template <typename U>
U dyn_cast_or_null() const {
return (*this && isa<U>()) ? U(impl) : U(nullptr);
}
template <typename U>
U cast() const {
assert(isa<U>());
return U(impl);
}
explicit operator bool() const { return impl; }
bool operator==(const Value &other) const { return impl == other.impl; }
bool operator!=(const Value &other) const { return !(*this == other); }
/// Return the type of this value.
Type getType() const { return impl->getType(); }
/// Utility to get the associated MLIRContext that this value is defined in.
MLIRContext *getContext() const { return getType().getContext(); }
/// Mutate the type of this Value to be of the specified type.
///
/// Note that this is an extremely dangerous operation which can create
/// completely invalid IR very easily. It is strongly recommended that you
/// recreate IR objects with the right types instead of mutating them in
/// place.
void setType(Type newType) { impl->setType(newType); }
/// If this value is the result of an operation, return the operation that
/// defines it.
Operation *getDefiningOp() const;
/// If this value is the result of an operation of type OpTy, return the
/// operation that defines it.
template <typename OpTy>
OpTy getDefiningOp() const {
return llvm::dyn_cast_or_null<OpTy>(getDefiningOp());
}
/// Return the location of this value.
Location getLoc() const;
void setLoc(Location loc);
/// Return the Region in which this Value is defined.
Region *getParentRegion();
/// Return the Block in which this Value is defined.
Block *getParentBlock();
//===--------------------------------------------------------------------===//
// UseLists
//===--------------------------------------------------------------------===//
/// Drop all uses of this object from their respective owners.
void dropAllUses() const { return impl->dropAllUses(); }
/// Replace all uses of 'this' value with the new value, updating anything in
/// the IR that uses 'this' to use the other value instead. When this returns
/// there are zero uses of 'this'.
void replaceAllUsesWith(Value newValue) const {
impl->replaceAllUsesWith(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
/// listed in 'exceptions' .
void
replaceAllUsesExcept(Value newValue,
const SmallPtrSetImpl<Operation *> &exceptions) const;
/// 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 replaceAllUsesExcept(Value newValue, Operation *exceptedUser) const;
/// Replace all uses of 'this' value with 'newValue' if the given callback
/// returns true.
void replaceUsesWithIf(Value newValue,
function_ref<bool(OpOperand &)> shouldReplace);
/// Returns true if the value is used outside of the given block.
bool isUsedOutsideOfBlock(Block *block);
//===--------------------------------------------------------------------===//
// Uses
/// This class implements an iterator over the uses of a value.
using use_iterator = ValueUseIterator<OpOperand>;
using use_range = iterator_range<use_iterator>;
use_iterator use_begin() const { return impl->use_begin(); }
use_iterator use_end() const { return use_iterator(); }
/// Returns a range of all uses, which is useful for iterating over all uses.
use_range getUses() const { return {use_begin(), use_end()}; }
/// Returns true if this value has exactly one use.
bool hasOneUse() const { return impl->hasOneUse(); }
/// Returns true if this value has no uses.
bool use_empty() const { return impl->use_empty(); }
//===--------------------------------------------------------------------===//
// Users
using user_iterator = ValueUserIterator<use_iterator, OpOperand>;
using user_range = iterator_range<user_iterator>;
user_iterator user_begin() const { return use_begin(); }
user_iterator user_end() const { return use_end(); }
user_range getUsers() const { return {user_begin(), user_end()}; }
//===--------------------------------------------------------------------===//
// Utilities
void print(raw_ostream &os);
void print(raw_ostream &os, AsmState &state);
void dump();
/// Print this value as if it were an operand.
void printAsOperand(raw_ostream &os, AsmState &state);
/// Methods for supporting PointerLikeTypeTraits.
void *getAsOpaquePointer() const { return impl; }
static Value getFromOpaquePointer(const void *pointer) {
return reinterpret_cast<detail::ValueImpl *>(const_cast<void *>(pointer));
}
detail::ValueImpl *getImpl() const { return impl; }
friend ::llvm::hash_code hash_value(Value arg);
protected:
/// A pointer to the internal implementation of the value.
detail::ValueImpl *impl;
};
inline raw_ostream &operator<<(raw_ostream &os, Value value) {
value.print(os);
return os;
}
//===----------------------------------------------------------------------===//
// OpOperand
//===----------------------------------------------------------------------===//
/// This class represents an operand of an operation. Instances of this class
/// contain a reference to a specific `Value`.
class OpOperand : public IROperand<OpOperand, Value> {
public:
/// Provide the use list that is attached to the given value.
static IRObjectWithUseList<OpOperand> *getUseList(Value value) {
return value.getImpl();
}
/// Return which operand this is in the OpOperand list of the Operation.
unsigned getOperandNumber();
private:
/// Keep the constructor private and accessible to the OperandStorage class
/// only to avoid hard-to-debug typo/programming mistakes.
friend class OperandStorage;
using IROperand<OpOperand, Value>::IROperand;
};
//===----------------------------------------------------------------------===//
// BlockArgument
//===----------------------------------------------------------------------===//
namespace detail {
/// The internal implementation of a BlockArgument.
class BlockArgumentImpl : public ValueImpl {
public:
static bool classof(const ValueImpl *value) {
return value->getKind() == ValueImpl::Kind::BlockArgument;
}
private:
BlockArgumentImpl(Type type, Block *owner, int64_t index, Location loc)
: ValueImpl(type, Kind::BlockArgument), owner(owner), index(index),
loc(loc) {}
/// The owner of this argument.
Block *owner;
/// The position in the argument list.
int64_t index;
/// The source location of this argument.
Location loc;
/// Allow access to owner and constructor.
friend BlockArgument;
};
} // end namespace detail
/// This class represents an argument of a Block.
class BlockArgument : public Value {
public:
using Value::Value;
static bool classof(Value value) {
return llvm::isa<detail::BlockArgumentImpl>(value.getImpl());
}
/// Returns the block that owns this argument.
Block *getOwner() const { return getImpl()->owner; }
/// Returns the number of this argument.
unsigned getArgNumber() const { return getImpl()->index; }
/// Return the location for this argument.
Location getLoc() const { return getImpl()->loc; }
void setLoc(Location loc) { getImpl()->loc = loc; }
private:
/// Allocate a new argument with the given type and owner.
static BlockArgument create(Type type, Block *owner, int64_t index,
Location loc) {
return new detail::BlockArgumentImpl(type, owner, index, loc);
}
/// Destroy and deallocate this argument.
void destroy() { delete getImpl(); }
/// Get a raw pointer to the internal implementation.
detail::BlockArgumentImpl *getImpl() const {
return reinterpret_cast<detail::BlockArgumentImpl *>(impl);
}
/// Cache the position in the block argument list.
void setArgNumber(int64_t index) { getImpl()->index = index; }
/// Allow access to `create`, `destroy` and `setArgNumber`.
friend Block;
/// Allow access to 'getImpl'.
friend Value;
};
//===----------------------------------------------------------------------===//
// OpResult
//===----------------------------------------------------------------------===//
namespace detail {
/// This class provides the implementation for an operation result.
class alignas(8) OpResultImpl : public ValueImpl {
public:
using ValueImpl::ValueImpl;
static bool classof(const ValueImpl *value) {
return value->getKind() != ValueImpl::Kind::BlockArgument;
}
/// Returns the parent operation of this result.
Operation *getOwner() const;
/// Returns the result number of this op result.
unsigned getResultNumber() const;
/// Returns the next operation result at `offset` after this result. This
/// method is useful when indexing the result storage of an operation, given
/// that there is more than one kind of operation result (with the different
/// kinds having different sizes) and that operations are stored in reverse
/// order.
OpResultImpl *getNextResultAtOffset(intptr_t offset);
/// Returns the maximum number of results that can be stored inline.
static unsigned getMaxInlineResults() {
return static_cast<unsigned>(Kind::OutOfLineOpResult);
}
};
/// This class provides the implementation for an operation result whose index
/// can be represented "inline" in the underlying ValueImpl.
struct InlineOpResult : public OpResultImpl {
public:
InlineOpResult(Type type, unsigned resultNo)
: OpResultImpl(type, static_cast<ValueImpl::Kind>(resultNo)) {
assert(resultNo < getMaxInlineResults());
}
/// Return the result number of this op result.
unsigned getResultNumber() const { return static_cast<unsigned>(getKind()); }
static bool classof(const OpResultImpl *value) {
return value->getKind() != ValueImpl::Kind::OutOfLineOpResult;
}
};
/// This class provides the implementation for an operation result whose index
/// cannot be represented "inline", and thus requires an additional index field.
class OutOfLineOpResult : public OpResultImpl {
public:
OutOfLineOpResult(Type type, uint64_t outOfLineIndex)
: OpResultImpl(type, Kind::OutOfLineOpResult),
outOfLineIndex(outOfLineIndex) {}
static bool classof(const OpResultImpl *value) {
return value->getKind() == ValueImpl::Kind::OutOfLineOpResult;
}
/// Return the result number of this op result.
unsigned getResultNumber() const {
return outOfLineIndex + getMaxInlineResults();
}
/// The trailing result number, or the offset from the beginning of the
/// `OutOfLineOpResult` array.
uint64_t outOfLineIndex;
};
/// Return the result number of this op result.
inline unsigned OpResultImpl::getResultNumber() const {
if (const auto *outOfLineResult = dyn_cast<OutOfLineOpResult>(this))
return outOfLineResult->getResultNumber();
return cast<InlineOpResult>(this)->getResultNumber();
}
} // end namespace detail
/// This is a value defined by a result of an operation.
class OpResult : public Value {
public:
using Value::Value;
static bool classof(Value value) {
return llvm::isa<detail::OpResultImpl>(value.getImpl());
}
/// Returns the operation that owns this result.
Operation *getOwner() const { return getImpl()->getOwner(); }
/// Returns the number of this result.
unsigned getResultNumber() const { return getImpl()->getResultNumber(); }
private:
/// Get a raw pointer to the internal implementation.
detail::OpResultImpl *getImpl() const {
return reinterpret_cast<detail::OpResultImpl *>(impl);
}
/// Given a number of operation results, returns the number that need to be
/// stored inline.
static unsigned getNumInline(unsigned numResults);
/// Given a number of operation results, returns the number that need to be
/// stored as trailing.
static unsigned getNumTrailing(unsigned numResults);
/// Allow access to constructor.
friend Operation;
};
/// Make Value hashable.
inline ::llvm::hash_code hash_value(Value arg) {
return ::llvm::hash_value(arg.getImpl());
}
} // namespace mlir
namespace llvm {
template <>
struct DenseMapInfo<mlir::Value> {
static mlir::Value getEmptyKey() {
void *pointer = llvm::DenseMapInfo<void *>::getEmptyKey();
return mlir::Value::getFromOpaquePointer(pointer);
}
static mlir::Value getTombstoneKey() {
void *pointer = llvm::DenseMapInfo<void *>::getTombstoneKey();
return mlir::Value::getFromOpaquePointer(pointer);
}
static unsigned getHashValue(mlir::Value val) {
return mlir::hash_value(val);
}
static bool isEqual(mlir::Value lhs, mlir::Value rhs) { return lhs == rhs; }
};
template <>
struct DenseMapInfo<mlir::BlockArgument> : public DenseMapInfo<mlir::Value> {
static mlir::BlockArgument getEmptyKey() {
void *pointer = llvm::DenseMapInfo<void *>::getEmptyKey();
return reinterpret_cast<mlir::detail::BlockArgumentImpl *>(pointer);
}
static mlir::BlockArgument getTombstoneKey() {
void *pointer = llvm::DenseMapInfo<void *>::getTombstoneKey();
return reinterpret_cast<mlir::detail::BlockArgumentImpl *>(pointer);
}
};
template <>
struct DenseMapInfo<mlir::OpResult> : public DenseMapInfo<mlir::Value> {
static mlir::OpResult getEmptyKey() {
void *pointer = llvm::DenseMapInfo<void *>::getEmptyKey();
return reinterpret_cast<mlir::detail::OpResultImpl *>(pointer);
}
static mlir::OpResult getTombstoneKey() {
void *pointer = llvm::DenseMapInfo<void *>::getTombstoneKey();
return reinterpret_cast<mlir::detail::OpResultImpl *>(pointer);
}
};
/// Allow stealing the low bits of a value.
template <>
struct PointerLikeTypeTraits<mlir::Value> {
public:
static inline void *getAsVoidPointer(mlir::Value value) {
return const_cast<void *>(value.getAsOpaquePointer());
}
static inline mlir::Value getFromVoidPointer(void *pointer) {
return mlir::Value::getFromOpaquePointer(pointer);
}
enum {
NumLowBitsAvailable =
PointerLikeTypeTraits<mlir::detail::ValueImpl *>::NumLowBitsAvailable
};
};
template <>
struct PointerLikeTypeTraits<mlir::BlockArgument>
: public PointerLikeTypeTraits<mlir::Value> {
public:
static inline mlir::BlockArgument getFromVoidPointer(void *pointer) {
return reinterpret_cast<mlir::detail::BlockArgumentImpl *>(pointer);
}
};
template <>
struct PointerLikeTypeTraits<mlir::OpResult>
: public PointerLikeTypeTraits<mlir::Value> {
public:
static inline mlir::OpResult getFromVoidPointer(void *pointer) {
return reinterpret_cast<mlir::detail::OpResultImpl *>(pointer);
}
};
} // end namespace llvm
#endif