| //===- Value.h - Base of the SSA Value hierarchy ----------------*- C++ -*-===// |
| // |
| // Part of the MLIR 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" |
| |
| namespace mlir { |
| class AsmState; |
| class BlockArgument; |
| class Operation; |
| class OpResult; |
| class Region; |
| class Value; |
| |
| namespace detail { |
| /// The internal implementation of a BlockArgument. |
| class BlockArgumentImpl; |
| } // end 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: |
| /// The enumeration represents the various different kinds of values the |
| /// internal representation may take. We steal 2 bits to support a total of 4 |
| /// possible values. |
| enum class Kind { |
| /// The first N kinds are all inline operation results. An inline operation |
| /// result means that the kind represents the result number, and the owner |
| /// pointer is the owning `Operation*`. Note: These are packed first to make |
| /// result number lookups more efficient. |
| OpResult0 = 0, |
| OpResult1 = 1, |
| |
| /// The next kind represents a 'trailing' operation result. This is for |
| /// results with numbers larger than we can represent inline. The owner here |
| /// is an `TrailingOpResult*` that points to a trailing storage on the |
| /// parent operation. |
| TrailingOpResult = 2, |
| |
| /// The last kind represents a block argument. The owner here is a |
| /// `BlockArgumentImpl*`. |
| BlockArgument = 3 |
| }; |
| |
| /// This value represents the 'owner' of the value and its kind. See the |
| /// 'Kind' enumeration above for a more detailed description of each kind of |
| /// owner. |
| struct ImplTypeTraits : public llvm::PointerLikeTypeTraits<void *> { |
| // We know that all pointers within the ImplType are aligned by 8-bytes, |
| // meaning that we can steal up to 3 bits for the different values. |
| enum { NumLowBitsAvailable = 3 }; |
| }; |
| using ImplType = llvm::PointerIntPair<void *, 2, Kind, ImplTypeTraits>; |
| |
| public: |
| constexpr Value(std::nullptr_t) : ownerAndKind() {} |
| Value(ImplType ownerAndKind = {}) : ownerAndKind(ownerAndKind) {} |
| 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 U> U dyn_cast() const { |
| return isa<U>() ? U(ownerAndKind) : U(nullptr); |
| } |
| template <typename U> U dyn_cast_or_null() const { |
| return (*this && isa<U>()) ? U(ownerAndKind) : U(nullptr); |
| } |
| template <typename U> U cast() const { |
| assert(isa<U>()); |
| return U(ownerAndKind); |
| } |
| |
| operator bool() const { return ownerAndKind.getPointer(); } |
| bool operator==(const Value &other) const { |
| return ownerAndKind == other.ownerAndKind; |
| } |
| bool operator!=(const Value &other) const { return !(*this == other); } |
| |
| /// Return the type of this value. |
| Type getType() const; |
| |
| /// 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); |
| |
| /// 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, use it as a location, |
| /// otherwise return an unknown location. |
| Location getLoc() const; |
| |
| /// Return the Region in which this Value is defined. |
| Region *getParentRegion(); |
| |
| //===--------------------------------------------------------------------===// |
| // UseLists |
| //===--------------------------------------------------------------------===// |
| |
| /// Provide the use list that is attached to this value. |
| IRObjectWithUseList<OpOperand> *getUseList() const; |
| |
| /// Drop all uses of this object from their respective owners. |
| void dropAllUses() const; |
| |
| /// 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; |
| |
| //===--------------------------------------------------------------------===// |
| // Uses |
| |
| /// This class implements an iterator over the uses of a value. |
| using use_iterator = FilteredValueUseIterator<OpOperand>; |
| using use_range = iterator_range<use_iterator>; |
| |
| use_iterator use_begin() const; |
| 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; |
| |
| /// Returns true if this value has no uses. |
| bool use_empty() const; |
| |
| //===--------------------------------------------------------------------===// |
| // 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 |
| |
| /// Returns the kind of this value. |
| Kind getKind() const { return ownerAndKind.getInt(); } |
| |
| 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 ownerAndKind.getOpaqueValue(); } |
| static Value getFromOpaquePointer(const void *pointer) { |
| Value value; |
| value.ownerAndKind.setFromOpaqueValue(const_cast<void *>(pointer)); |
| return value; |
| } |
| |
| friend ::llvm::hash_code hash_value(Value arg); |
| |
| protected: |
| /// Returns true if the given operation result can be packed inline. |
| static bool canPackResultInline(unsigned resultNo) { |
| return resultNo < static_cast<unsigned>(Kind::TrailingOpResult); |
| } |
| |
| /// Construct a value. |
| Value(detail::BlockArgumentImpl *impl); |
| Value(Operation *op, unsigned resultNo); |
| |
| /// This value represents the 'owner' of the value and its kind. See the |
| /// 'Kind' enumeration above for a more detailed description of each kind of |
| /// owner. |
| ImplType ownerAndKind; |
| }; |
| |
| inline raw_ostream &operator<<(raw_ostream &os, Value value) { |
| value.print(os); |
| return os; |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // BlockArgument |
| //===----------------------------------------------------------------------===// |
| |
| namespace detail { |
| /// The internal implementation of a BlockArgument. |
| class BlockArgumentImpl : public IRObjectWithUseList<OpOperand> { |
| BlockArgumentImpl(Type type, Block *owner) : type(type), owner(owner) {} |
| |
| /// The type of this argument. |
| Type type; |
| |
| /// The owner of this argument. |
| Block *owner; |
| |
| /// Allow access to owner and constructor. |
| friend BlockArgument; |
| }; |
| } // end namespace detail |
| |
| /// Block arguments are values. |
| class BlockArgument : public Value { |
| public: |
| using Value::Value; |
| |
| static bool classof(Value value) { |
| return value.getKind() == Kind::BlockArgument; |
| } |
| |
| /// Returns the block that owns this argument. |
| Block *getOwner() const { return getImpl()->owner; } |
| |
| /// Return the type of this value. |
| Type getType() const { return getImpl()->type; } |
| |
| /// Set the type of this value. |
| void setType(Type newType) { getImpl()->type = newType; } |
| |
| /// Returns the number of this argument. |
| unsigned getArgNumber() const; |
| |
| private: |
| /// Allocate a new argument with the given type and owner. |
| static BlockArgument create(Type type, Block *owner) { |
| return new detail::BlockArgumentImpl(type, owner); |
| } |
| |
| /// 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 *>( |
| ownerAndKind.getPointer()); |
| } |
| |
| /// Allow access to `create` and `destroy`. |
| friend Block; |
| |
| /// Allow access to 'getImpl'. |
| friend Value; |
| }; |
| |
| //===----------------------------------------------------------------------===// |
| // OpResult |
| //===----------------------------------------------------------------------===// |
| |
| /// 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 value.getKind() != Kind::BlockArgument; |
| } |
| |
| /// Returns the operation that owns this result. |
| Operation *getOwner() const; |
| |
| /// Returns the number of this result. |
| unsigned getResultNumber() const; |
| |
| private: |
| /// Given a number of operation results, returns the number that need to be |
| /// stored as trailing. |
| static unsigned getNumTrailing(unsigned numResults); |
| |
| /// Allow access to `create` and `destroy`. |
| friend Operation; |
| }; |
| |
| /// Make Value hashable. |
| inline ::llvm::hash_code hash_value(Value arg) { |
| return ::llvm::hash_value(arg.ownerAndKind.getOpaqueValue()); |
| } |
| |
| } // namespace mlir |
| |
| namespace llvm { |
| |
| template <> struct DenseMapInfo<mlir::Value> { |
| static mlir::Value getEmptyKey() { |
| auto pointer = llvm::DenseMapInfo<void *>::getEmptyKey(); |
| return mlir::Value::getFromOpaquePointer(pointer); |
| } |
| static mlir::Value getTombstoneKey() { |
| auto 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; } |
| }; |
| |
| /// Allow stealing the low bits of a value. |
| template <> struct PointerLikeTypeTraits<mlir::Value> { |
| public: |
| static inline void *getAsVoidPointer(mlir::Value I) { |
| return const_cast<void *>(I.getAsOpaquePointer()); |
| } |
| static inline mlir::Value getFromVoidPointer(void *P) { |
| return mlir::Value::getFromOpaquePointer(P); |
| } |
| enum { |
| NumLowBitsAvailable = |
| PointerLikeTypeTraits<mlir::Value::ImplType>::NumLowBitsAvailable |
| }; |
| }; |
| |
| template <> struct DenseMapInfo<mlir::BlockArgument> { |
| static mlir::BlockArgument getEmptyKey() { |
| auto pointer = llvm::DenseMapInfo<void *>::getEmptyKey(); |
| return mlir::BlockArgument( |
| mlir::Value::ImplType::getFromOpaqueValue(pointer)); |
| } |
| static mlir::BlockArgument getTombstoneKey() { |
| auto pointer = llvm::DenseMapInfo<void *>::getTombstoneKey(); |
| return mlir::BlockArgument( |
| mlir::Value::ImplType::getFromOpaqueValue(pointer)); |
| } |
| static unsigned getHashValue(mlir::BlockArgument val) { |
| return mlir::hash_value(val); |
| } |
| static bool isEqual(mlir::BlockArgument LHS, mlir::BlockArgument RHS) { |
| return LHS == RHS; |
| } |
| }; |
| |
| /// Allow stealing the low bits of a value. |
| template <> struct PointerLikeTypeTraits<mlir::BlockArgument> { |
| public: |
| static inline void *getAsVoidPointer(mlir::Value I) { |
| return const_cast<void *>(I.getAsOpaquePointer()); |
| } |
| static inline mlir::BlockArgument getFromVoidPointer(void *P) { |
| return mlir::Value::getFromOpaquePointer(P).cast<mlir::BlockArgument>(); |
| } |
| enum { |
| NumLowBitsAvailable = |
| PointerLikeTypeTraits<mlir::Value>::NumLowBitsAvailable |
| }; |
| }; |
| } // end namespace llvm |
| |
| #endif |