diff --git a/mlir/bindings/python/pybind.cpp b/mlir/bindings/python/pybind.cpp index 10445edaf125..caff9af59acc 100644 --- a/mlir/bindings/python/pybind.cpp +++ b/mlir/bindings/python/pybind.cpp @@ -87,7 +87,8 @@ struct PythonValueHandle { operator ValueHandle &() { return value; } std::string str() const { - return std::to_string(reinterpret_cast(value.getValue())); + return std::to_string( + reinterpret_cast(value.getValue().getAsOpaquePointer())); } PythonValueHandle call(const std::vector &args) { diff --git a/mlir/include/mlir/Analysis/AffineAnalysis.h b/mlir/include/mlir/Analysis/AffineAnalysis.h index 5d9422883c11..6029a9ccdaa4 100644 --- a/mlir/include/mlir/Analysis/AffineAnalysis.h +++ b/mlir/include/mlir/Analysis/AffineAnalysis.h @@ -15,9 +15,7 @@ #ifndef MLIR_ANALYSIS_AFFINE_ANALYSIS_H #define MLIR_ANALYSIS_AFFINE_ANALYSIS_H -#include "mlir/Support/LLVM.h" -#include "mlir/Support/LogicalResult.h" -#include "llvm/ADT/ArrayRef.h" +#include "mlir/IR/Value.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallVector.h" @@ -28,10 +26,9 @@ class AffineForOp; class AffineValueMap; class FlatAffineConstraints; class Operation; -class Value; // TODO(riverriddle) Remove this after Value is value-typed. -using ValuePtr = Value *; +using ValuePtr = Value; /// Returns in `affineApplyOps`, the sequence of those AffineApplyOp /// Operations that are reachable via a search starting from `operands` and diff --git a/mlir/include/mlir/Analysis/Liveness.h b/mlir/include/mlir/Analysis/Liveness.h index 791c164c7d29..cbd2e63fd3ef 100644 --- a/mlir/include/mlir/Analysis/Liveness.h +++ b/mlir/include/mlir/Analysis/Liveness.h @@ -33,7 +33,7 @@ class Region; class Value; // TODO(riverriddle) Remove this after Value is value-typed. -using ValuePtr = Value *; +using ValuePtr = Value; /// Represents an analysis for computing liveness information from a /// given top-level operation. The analysis iterates over all associated diff --git a/mlir/include/mlir/Analysis/LoopAnalysis.h b/mlir/include/mlir/Analysis/LoopAnalysis.h index 66f0033bf2fc..75d7b98e20f7 100644 --- a/mlir/include/mlir/Analysis/LoopAnalysis.h +++ b/mlir/include/mlir/Analysis/LoopAnalysis.h @@ -28,7 +28,7 @@ class Operation; class Value; // TODO(riverriddle) Remove this after Value is value-typed. -using ValuePtr = Value *; +using ValuePtr = Value; /// Returns the trip count of the loop as an affine map with its corresponding /// operands if the latter is expressible as an affine expression, and nullptr diff --git a/mlir/include/mlir/Conversion/AffineToStandard/AffineToStandard.h b/mlir/include/mlir/Conversion/AffineToStandard/AffineToStandard.h index 8e873bfb1c3b..c8298760bad0 100644 --- a/mlir/include/mlir/Conversion/AffineToStandard/AffineToStandard.h +++ b/mlir/include/mlir/Conversion/AffineToStandard/AffineToStandard.h @@ -22,7 +22,7 @@ class RewritePattern; class Value; // TODO(riverriddle) Remove this after Value is value-typed. -using ValuePtr = Value *; +using ValuePtr = Value; // Owning list of rewriting patterns. class OwningRewritePatternList; diff --git a/mlir/include/mlir/Conversion/LoopsToGPU/LoopsToGPU.h b/mlir/include/mlir/Conversion/LoopsToGPU/LoopsToGPU.h index 5f3ea87f3cc8..b7423a58f2a4 100644 --- a/mlir/include/mlir/Conversion/LoopsToGPU/LoopsToGPU.h +++ b/mlir/include/mlir/Conversion/LoopsToGPU/LoopsToGPU.h @@ -16,7 +16,7 @@ struct LogicalResult; class Value; // TODO(riverriddle) Remove this after Value is value-typed. -using ValuePtr = Value *; +using ValuePtr = Value; namespace loop { class ForOp; diff --git a/mlir/include/mlir/Dialect/VectorOps/Utils.h b/mlir/include/mlir/Dialect/VectorOps/Utils.h index b4d8ad65e60f..04bd8b50fb66 100644 --- a/mlir/include/mlir/Dialect/VectorOps/Utils.h +++ b/mlir/include/mlir/Dialect/VectorOps/Utils.h @@ -26,7 +26,7 @@ class Value; class VectorType; // TODO(riverriddle) Remove this after Value is value-typed. -using ValuePtr = Value *; +using ValuePtr = Value; /// Computes and returns the multi-dimensional ratio of `superShape` to /// `subShape`. This is calculated by performing a traversal from minor to major diff --git a/mlir/include/mlir/EDSC/Builders.h b/mlir/include/mlir/EDSC/Builders.h index 6607f267057b..f9629a8d99e9 100644 --- a/mlir/include/mlir/EDSC/Builders.h +++ b/mlir/include/mlir/EDSC/Builders.h @@ -329,6 +329,7 @@ public: /// Implicit conversion useful for automatic conversion to Container. operator ValuePtr() const { return getValue(); } + operator bool() const { return hasValue(); } /// Generic mlir::Op create. This is the key to being extensible to the whole /// of MLIR without duplicating the type system or the op definitions. diff --git a/mlir/include/mlir/IR/Block.h b/mlir/include/mlir/IR/Block.h index b5189b48a85f..33feea7bcbb4 100644 --- a/mlir/include/mlir/IR/Block.h +++ b/mlir/include/mlir/IR/Block.h @@ -63,7 +63,7 @@ public: //===--------------------------------------------------------------------===// // This is the list of arguments to the block. - using BlockArgListType = ArrayRef; + using BlockArgListType = MutableArrayRef; BlockArgListType getArguments() { return arguments; } diff --git a/mlir/include/mlir/IR/BlockAndValueMapping.h b/mlir/include/mlir/IR/BlockAndValueMapping.h index 82173c34368b..b7ad36072bd1 100644 --- a/mlir/include/mlir/IR/BlockAndValueMapping.h +++ b/mlir/include/mlir/IR/BlockAndValueMapping.h @@ -28,14 +28,18 @@ public: /// Inserts a new mapping for 'from' to 'to'. If there is an existing mapping, /// it is overwritten. void map(Block *from, Block *to) { valueMap[from] = to; } - void map(ValuePtr from, ValuePtr to) { valueMap[from] = to; } + void map(Value from, Value to) { + valueMap[from.getAsOpaquePointer()] = to.getAsOpaquePointer(); + } /// Erases a mapping for 'from'. - void erase(IRObjectWithUseList *from) { valueMap.erase(from); } + void erase(Block *from) { valueMap.erase(from); } + void erase(Value from) { valueMap.erase(from.getAsOpaquePointer()); } /// Checks to see if a mapping for 'from' exists. - bool contains(IRObjectWithUseList *from) const { - return valueMap.count(from); + bool contains(Block *from) const { return valueMap.count(from); } + bool contains(Value from) const { + return valueMap.count(from.getAsOpaquePointer()); } /// Lookup a mapped value within the map. If a mapping for the provided value @@ -43,23 +47,19 @@ public: Block *lookupOrNull(Block *from) const { return lookupOrValue(from, (Block *)nullptr); } - ValuePtr lookupOrNull(ValuePtr from) const { - return lookupOrValue(from, (ValuePtr) nullptr); - } + Value lookupOrNull(Value from) const { return lookupOrValue(from, Value()); } /// Lookup a mapped value within the map. If a mapping for the provided value /// does not exist then return the provided value. Block *lookupOrDefault(Block *from) const { return lookupOrValue(from, from); } - ValuePtr lookupOrDefault(ValuePtr from) const { - return lookupOrValue(from, from); - } + Value lookupOrDefault(Value from) const { return lookupOrValue(from, from); } /// Lookup a mapped value within the map. This asserts the provided value /// exists within the map. - template T *lookup(T *from) const { - auto *result = lookupOrNull(from); + template T lookup(T from) const { + auto result = lookupOrNull(from); assert(result && "expected 'from' to be contained within the map"); return result; } @@ -69,14 +69,18 @@ public: private: /// Utility lookupOrValue that looks up an existing key or returns the - /// provided value. This function assumes that if a mapping does exist, then - /// it is of 'T' type. - template T *lookupOrValue(T *from, T *value) const { + /// provided value. + Block *lookupOrValue(Block *from, Block *value) const { auto it = valueMap.find(from); - return it != valueMap.end() ? static_cast(it->second) : value; + return it != valueMap.end() ? reinterpret_cast(it->second) : value; + } + Value lookupOrValue(Value from, Value value) const { + auto it = valueMap.find(from.getAsOpaquePointer()); + return it != valueMap.end() ? Value::getFromOpaquePointer(it->second) + : value; } - DenseMap valueMap; + DenseMap valueMap; }; } // end namespace mlir diff --git a/mlir/include/mlir/IR/OpImplementation.h b/mlir/include/mlir/IR/OpImplementation.h index e58a5b070383..8e2aed29500b 100644 --- a/mlir/include/mlir/IR/OpImplementation.h +++ b/mlir/include/mlir/IR/OpImplementation.h @@ -142,17 +142,14 @@ private: // Make the implementations convenient to use. inline OpAsmPrinter &operator<<(OpAsmPrinter &p, ValueRef value) { - p.printOperand(&value); + p.printOperand(value); return p; } -inline OpAsmPrinter &operator<<(OpAsmPrinter &p, ValuePtr value) { - return p << *value; -} -template ::value && - !std::is_convertible::value, - T>::type * = nullptr> +template ::value && + !std::is_convertible::value, + T>::type * = nullptr> inline OpAsmPrinter &operator<<(OpAsmPrinter &p, const T &values) { p.printOperands(values); return p; @@ -172,8 +169,7 @@ inline OpAsmPrinter &operator<<(OpAsmPrinter &p, Attribute attr) { // even if it isn't exactly one of them. For example, we want to print // FunctionType with the Type version above, not have it match this. template ::value && - !std::is_convertible::value && + !std::is_convertible::value && !std::is_convertible::value && !std::is_convertible::value && !std::is_convertible::value && diff --git a/mlir/include/mlir/IR/Operation.h b/mlir/include/mlir/IR/Operation.h index 9ab900c87616..29227613468a 100644 --- a/mlir/include/mlir/IR/Operation.h +++ b/mlir/include/mlir/IR/Operation.h @@ -246,7 +246,7 @@ public: unsigned getNumResults() { return numResults; } - ValuePtr getResult(unsigned idx) { return &getOpResult(idx); } + ValuePtr getResult(unsigned idx) { return getOpResult(idx); } /// Support result iteration. using result_range = ResultRange; diff --git a/mlir/include/mlir/IR/OperationSupport.h b/mlir/include/mlir/IR/OperationSupport.h index 146816633725..ef2ff44ef6e0 100644 --- a/mlir/include/mlir/IR/OperationSupport.h +++ b/mlir/include/mlir/IR/OperationSupport.h @@ -525,8 +525,8 @@ private: /// This class implements iteration on the types of a given range of values. template class ValueTypeIterator final - : public llvm::mapped_iterator { - static Type unwrap(ValuePtr value) { return value->getType(); } + : public llvm::mapped_iterator { + static Type unwrap(Value value) { return value.getType(); } public: using reference = Type; @@ -536,8 +536,7 @@ public: /// Initializes the type iterator to the specified value iterator. ValueTypeIterator(ValueIteratorT it) - : llvm::mapped_iterator(it, &unwrap) { - } + : llvm::mapped_iterator(it, &unwrap) {} }; //===----------------------------------------------------------------------===// @@ -546,7 +545,7 @@ public: /// This class implements the operand iterators for the Operation class. class OperandRange final : public detail::indexed_accessor_range_base { + Value, Value, Value> { public: using RangeBaseT::RangeBaseT; OperandRange(Operation *op); @@ -561,7 +560,7 @@ private: return object + index; } /// See `detail::indexed_accessor_range_base` for details. - static ValuePtr dereference_iterator(OpOperand *object, ptrdiff_t index) { + static Value dereference_iterator(OpOperand *object, ptrdiff_t index) { return object[index].get(); } @@ -574,8 +573,8 @@ private: /// This class implements the result iterators for the Operation class. class ResultRange final - : public detail::indexed_accessor_range_base { + : public detail::indexed_accessor_range_base { public: using RangeBaseT::RangeBaseT; ResultRange(Operation *op); @@ -586,12 +585,12 @@ public: private: /// See `detail::indexed_accessor_range_base` for details. - static OpResultPtr offset_base(OpResultPtr object, ptrdiff_t index) { + static OpResult *offset_base(OpResult *object, ptrdiff_t index) { return object + index; } /// See `detail::indexed_accessor_range_base` for details. - static ValuePtr dereference_iterator(OpResultPtr object, ptrdiff_t index) { - return &object[index]; + static Value dereference_iterator(OpResult *object, ptrdiff_t index) { + return object[index]; } /// Allow access to `offset_base` and `dereference_iterator`. @@ -608,25 +607,24 @@ private: /// parameter. class ValueRange final : public detail::indexed_accessor_range_base< - ValueRange, PointerUnion, - ValuePtr, ValuePtr, ValuePtr> { + ValueRange, PointerUnion, + Value, Value, Value> { public: using RangeBaseT::RangeBaseT; template , Arg>::value && - !std::is_convertible::value>> - ValueRange(Arg &&arg) - : ValueRange(ArrayRef(std::forward(arg))) {} - ValueRange(ValuePtr const &value) : ValueRange(&value, /*count=*/1) {} - ValueRange(const std::initializer_list &values) - : ValueRange(ArrayRef(values)) {} + std::is_constructible, Arg>::value && + !std::is_convertible::value>> + ValueRange(Arg &&arg) : ValueRange(ArrayRef(std::forward(arg))) {} + ValueRange(const Value &value) : ValueRange(&value, /*count=*/1) {} + ValueRange(const std::initializer_list &values) + : ValueRange(ArrayRef(values)) {} ValueRange(iterator_range values) : ValueRange(OperandRange(values)) {} ValueRange(iterator_range values) : ValueRange(ResultRange(values)) {} - ValueRange(ArrayRef values = llvm::None); + ValueRange(ArrayRef values = llvm::None); ValueRange(OperandRange values); ValueRange(ResultRange values); @@ -637,12 +635,12 @@ public: private: /// The type representing the owner of this range. This is either a list of /// values, operands, or results. - using OwnerT = PointerUnion; + using OwnerT = PointerUnion; /// See `detail::indexed_accessor_range_base` for details. static OwnerT offset_base(const OwnerT &owner, ptrdiff_t index); /// See `detail::indexed_accessor_range_base` for details. - static ValuePtr dereference_iterator(const OwnerT &owner, ptrdiff_t index); + static Value dereference_iterator(const OwnerT &owner, ptrdiff_t index); /// Allow access to `offset_base` and `dereference_iterator`. friend RangeBaseT; diff --git a/mlir/include/mlir/IR/TypeUtilities.h b/mlir/include/mlir/IR/TypeUtilities.h index b4713226559d..fd9d317ed359 100644 --- a/mlir/include/mlir/IR/TypeUtilities.h +++ b/mlir/include/mlir/IR/TypeUtilities.h @@ -33,7 +33,6 @@ Type getElementTypeOrSelf(Type type); /// Return the element type or return the type itself. Type getElementTypeOrSelf(Attribute attr); Type getElementTypeOrSelf(ValuePtr val); -Type getElementTypeOrSelf(ValueRef val); /// Get the types within a nested Tuple. A helper for the class method that /// handles storage concerns, which is tricky to do in tablegen. diff --git a/mlir/include/mlir/IR/UseDefLists.h b/mlir/include/mlir/IR/UseDefLists.h index 898d0da2b28a..05720ed39af8 100644 --- a/mlir/include/mlir/IR/UseDefLists.h +++ b/mlir/include/mlir/IR/UseDefLists.h @@ -21,6 +21,7 @@ namespace mlir { class IROperand; class Operation; +class Value; template class ValueUseIterator; template class ValueUserIterator; @@ -167,6 +168,22 @@ private: } }; +/// A reference to a value, suitable for use as an operand of an operation. +class OpOperand : public IROperand { +public: + OpOperand(Operation *owner) : IROperand(owner) {} + OpOperand(Operation *owner, Value value); + + /// Return the current value being used by this operand. + Value get(); + + /// Set the current value being used by this operand. + void set(Value newValue); + + /// Return which operand this is in the operand list of the User. + unsigned getOperandNumber(); +}; + /// A reference to a value, suitable for use as an operand of an operation, /// operation, etc. IRValueTy is the root type to use for values this tracks, /// and SSAUserTy is the type that will contain operands. diff --git a/mlir/include/mlir/IR/Value.h b/mlir/include/mlir/IR/Value.h index 030e6fa58b12..26703a253063 100644 --- a/mlir/include/mlir/IR/Value.h +++ b/mlir/include/mlir/IR/Value.h @@ -25,40 +25,101 @@ class OpResult; class Region; class Value; -/// Using directives that simplify the transition of Value to being value typed. -using BlockArgumentPtr = BlockArgument *; -using OpResultPtr = OpResult *; -using ValueRef = Value &; -using ValuePtr = Value *; +namespace detail { +/// The internal implementation of a Value. +class ValueImpl : public IRObjectWithUseList { +protected: + /// This enumerates all of the SSA value kinds. + enum class Kind { + BlockArgument, + OpResult, + }; -/// Operands contain a Value. -using OpOperand = IROperandImpl; + ValueImpl(Kind kind, Type type) : typeAndKind(type, kind) {} -/// This is the common base class for all SSA values in the MLIR system, -/// representing a computable value that has a type and a set of users. +private: + /// The type of the value and its kind. + llvm::PointerIntPair typeAndKind; + + /// Allow access to 'typeAndKind'. + friend Value; +}; + +/// The internal implementation of a BlockArgument. +class BlockArgumentImpl : public ValueImpl { + BlockArgumentImpl(Type type, Block *owner) + : ValueImpl(Kind::BlockArgument, type), owner(owner) {} + + /// The owner of this argument. + Block *owner; + + /// Allow access to owner and constructor. + friend BlockArgument; +}; + +class OpResultImpl : public ValueImpl { + OpResultImpl(Type type, Operation *owner) + : ValueImpl(Kind::OpResult, type), owner(owner) {} + + /// The owner of this result. + Operation *owner; + + /// Allow access to owner and the constructor. + friend OpResult; +}; +} // 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 IRObjectWithUseList { +class Value { public: /// This enumerates all of the SSA value kinds in the MLIR system. enum class Kind { - BlockArgument, // block argument - OpResult, // operation result + BlockArgument, + OpResult, }; + Value(std::nullptr_t) : impl(nullptr) {} + Value(detail::ValueImpl *impl = nullptr) : impl(impl) {} + Value(const Value &) = default; + Value &operator=(const Value &) = default; ~Value() {} - template bool isa() const { return U::classof(this); } - template U *dyn_cast() const { - return isa() ? (U *)this : nullptr; + template bool isa() const { + assert(impl && "isa<> used on a null type."); + return U::classof(*this); } - template U *cast() const { + template U dyn_cast() const { + return isa() ? U(impl) : U(nullptr); + } + template U dyn_cast_or_null() const { + return (impl && isa()) ? U(impl) : U(nullptr); + } + template U cast() const { assert(isa()); - return (U *)this; + return U(impl); } - Kind getKind() const { return typeAndKind.getInt(); } + /// Temporary methods to enable transition of Value to being used as a + /// value-type. + /// TODO(riverriddle) Remove these when all usages have been removed. + Value operator*() const { return *this; } + Value *operator->() const { return (Value *)this; } - Type getType() const { return typeAndKind.getPointer(); } + 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 kind of this value. + Kind getKind() const { return (Kind)impl->typeAndKind.getInt(); } + + /// Return the type of this value. + Type getType() const { return impl->typeAndKind.getPointer(); } /// Utility to get the associated MLIRContext that this value is defined in. MLIRContext *getContext() const { return getType().getContext(); } @@ -69,18 +130,18 @@ public: /// 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) { typeAndKind.setPointer(newType); } + void setType(Type newType) { impl->typeAndKind.setPointer(newType); } /// 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(ValuePtr newValue) { - IRObjectWithUseList::replaceAllUsesWith(newValue); + void replaceAllUsesWith(Value newValue) const { + impl->replaceAllUsesWith(newValue.impl); } /// If this value is the result of an operation, return the operation that /// defines it. - Operation *getDefiningOp(); + Operation *getDefiningOp() const; /// If this value is the result of an operation, use it as a location, /// otherwise return an unknown location. @@ -98,24 +159,51 @@ public: /// Returns a range of all uses, which is useful for iterating over all uses. inline use_range getUses(); + using user_iterator = ValueUserIterator; + using user_range = iterator_range; + + user_iterator user_begin() const { return impl->user_begin(); } + user_iterator user_end() const { return impl->user_end(); } + + /// Returns a range of all users. + user_range getUsers() const { return impl->getUsers(); } + + /// Returns true if this value has no uses. + bool use_empty() const { return impl->use_empty(); } + + /// Returns true if this value has exactly one use. + bool hasOneUse() const { return impl->hasOneUse(); } + + /// Drop all uses of this object from their respective owners. + void dropAllUses() const { impl->dropAllUses(); } + void print(raw_ostream &os); void dump(); -protected: - Value(Kind kind, Type type) : typeAndKind(type, kind) {} + /// Methods for supporting PointerLikeTypeTraits. + void *getAsOpaquePointer() const { return static_cast(impl); } + static Value getFromOpaquePointer(const void *pointer) { + return reinterpret_cast(const_cast(pointer)); + } -private: - llvm::PointerIntPair typeAndKind; + friend ::llvm::hash_code hash_value(Value arg); + +protected: + /// The internal implementation of this value. + mutable detail::ValueImpl *impl; + + /// Allow access to 'impl'. + friend OpOperand; }; -inline raw_ostream &operator<<(raw_ostream &os, ValueRef value) { +inline raw_ostream &operator<<(raw_ostream &os, Value value) { value.print(os); return os; } // Utility functions for iterating through Value uses. inline auto Value::use_begin() -> use_iterator { - return use_iterator((OpOperand *)getFirstUse()); + return use_iterator((OpOperand *)impl->getFirstUse()); } inline auto Value::use_end() -> use_iterator { return use_iterator(nullptr); } @@ -127,47 +215,154 @@ inline auto Value::getUses() -> iterator_range { /// Block arguments are values. class BlockArgument : public Value { public: - static bool classof(const Value *value) { - return const_cast(value)->getKind() == Kind::BlockArgument; + using Value::Value; + + /// Temporary methods to enable transition of Value to being used as a + /// value-type. + /// TODO(riverriddle) Remove this when all usages have been removed. + BlockArgument *operator->() { return this; } + + static bool classof(Value value) { + return value.getKind() == Kind::BlockArgument; } - Block *getOwner() { return owner; } + /// Returns the block that owns this argument. + Block *getOwner() const { return getImpl()->owner; } /// Returns the number of this argument. - unsigned getArgNumber(); + unsigned getArgNumber() const; private: - friend class Block; // For access to private constructor. - BlockArgument(Type type, Block *owner) - : Value(Value::Kind::BlockArgument, type), owner(owner) {} + /// Allocate a new argument with the given type and owner. + static BlockArgument create(Type type, Block *owner) { + return new detail::BlockArgumentImpl(type, owner); + } - /// The owner of this operand. - /// TODO: can encode this more efficiently to avoid the space hit of this - /// through bitpacking shenanigans. - Block *const 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(impl); + } + + /// Allow access to `create` and `destroy`. + friend Block; }; /// This is a value defined by a result of an operation. class OpResult : public Value { public: - OpResult(Type type, Operation *owner) - : Value(Value::Kind::OpResult, type), owner(owner) {} + using Value::Value; - static bool classof(const Value *value) { - return const_cast(value)->getKind() == Kind::OpResult; - } + /// Temporary methods to enable transition of Value to being used as a + /// value-type. + /// TODO(riverriddle) Remove these when all usages have been removed. + OpResult *operator*() { return this; } + OpResult *operator->() { return this; } - Operation *getOwner() { return owner; } + static bool classof(Value value) { return value.getKind() == Kind::OpResult; } + + /// Returns the operation that owns this result. + Operation *getOwner() const { return getImpl()->owner; } /// Returns the number of this result. - unsigned getResultNumber(); + unsigned getResultNumber() const; private: - /// The owner of this operand. - /// TODO: can encode this more efficiently to avoid the space hit of this - /// through bitpacking shenanigans. - Operation *const owner; + /// Allocate a new result with the given type and owner. + static OpResult create(Type type, Operation *owner) { + return new detail::OpResultImpl(type, owner); + } + + /// Destroy and deallocate this result. + void destroy() { delete getImpl(); } + + /// Get a raw pointer to the internal implementation. + detail::OpResultImpl *getImpl() const { + return reinterpret_cast(impl); + } + + /// Allow access to `create` and `destroy`. + friend Operation; }; + +/// Make Value hashable. +inline ::llvm::hash_code hash_value(Value arg) { + return ::llvm::hash_value(arg.impl); +} + +/// Using directives that simplify the transition of Value to being value typed. +using BlockArgumentPtr = BlockArgument; +using OpResultPtr = OpResult; +using ValueRef = Value; +using ValuePtr = Value; + } // namespace mlir +namespace llvm { + +template <> struct DenseMapInfo { + static mlir::Value getEmptyKey() { + auto pointer = llvm::DenseMapInfo::getEmptyKey(); + return mlir::Value(static_cast(pointer)); + } + static mlir::Value getTombstoneKey() { + auto pointer = llvm::DenseMapInfo::getTombstoneKey(); + return mlir::Value(static_cast(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 { +public: + static inline void *getAsVoidPointer(mlir::Value I) { + return const_cast(I.getAsOpaquePointer()); + } + static inline mlir::Value getFromVoidPointer(void *P) { + return mlir::Value::getFromOpaquePointer(P); + } + enum { + NumLowBitsAvailable = + PointerLikeTypeTraits::NumLowBitsAvailable + }; +}; + +template <> struct DenseMapInfo { + static mlir::BlockArgument getEmptyKey() { + auto pointer = llvm::DenseMapInfo::getEmptyKey(); + return mlir::BlockArgument(static_cast(pointer)); + } + static mlir::BlockArgument getTombstoneKey() { + auto pointer = llvm::DenseMapInfo::getTombstoneKey(); + return mlir::BlockArgument(static_cast(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 { +public: + static inline void *getAsVoidPointer(mlir::Value I) { + return const_cast(I.getAsOpaquePointer()); + } + static inline mlir::BlockArgument getFromVoidPointer(void *P) { + return mlir::Value::getFromOpaquePointer(P).cast(); + } + enum { + NumLowBitsAvailable = + PointerLikeTypeTraits::NumLowBitsAvailable + }; +}; +} // end namespace llvm + #endif diff --git a/mlir/lib/Analysis/AffineStructures.cpp b/mlir/lib/Analysis/AffineStructures.cpp index 7ab547483cdb..ce96a19751fc 100644 --- a/mlir/lib/Analysis/AffineStructures.cpp +++ b/mlir/lib/Analysis/AffineStructures.cpp @@ -1965,7 +1965,7 @@ void FlatAffineConstraints::addLocalFloorDiv(ArrayRef dividend, bool FlatAffineConstraints::findId(ValueRef id, unsigned *pos) const { unsigned i = 0; for (const auto &mayBeId : ids) { - if (mayBeId.hasValue() && mayBeId.getValue() == &id) { + if (mayBeId.hasValue() && mayBeId.getValue() == id) { *pos = i; return true; } @@ -1976,7 +1976,7 @@ bool FlatAffineConstraints::findId(ValueRef id, unsigned *pos) const { bool FlatAffineConstraints::containsId(ValueRef id) const { return llvm::any_of(ids, [&](const Optional &mayBeId) { - return mayBeId.hasValue() && mayBeId.getValue() == &id; + return mayBeId.hasValue() && mayBeId.getValue() == id; }); } diff --git a/mlir/lib/Analysis/Dominance.cpp b/mlir/lib/Analysis/Dominance.cpp index 060a505593a6..ea1501e8998e 100644 --- a/mlir/lib/Analysis/Dominance.cpp +++ b/mlir/lib/Analysis/Dominance.cpp @@ -129,7 +129,7 @@ bool DominanceInfo::properlyDominates(ValuePtr a, Operation *b) { // block arguments properly dominate all operations in their own block, so // we use a dominates check here, not a properlyDominates check. - return dominates(cast(a)->getOwner(), b->getBlock()); + return dominates(a.cast()->getOwner(), b->getBlock()); } DominanceInfoNode *DominanceInfo::getNode(Block *a) { diff --git a/mlir/lib/Analysis/Liveness.cpp b/mlir/lib/Analysis/Liveness.cpp index bef0b9fa3856..9b7b806c558f 100644 --- a/mlir/lib/Analysis/Liveness.cpp +++ b/mlir/lib/Analysis/Liveness.cpp @@ -174,7 +174,7 @@ Liveness::OperationListT Liveness::resolveLiveness(ValuePtr value) const { if (Operation *defOp = value->getDefiningOp()) currentBlock = defOp->getBlock(); else - currentBlock = cast(value)->getOwner(); + currentBlock = value.cast()->getOwner(); toProcess.push_back(currentBlock); visited.insert(currentBlock); @@ -272,7 +272,7 @@ void Liveness::print(raw_ostream &os) const { if (Operation *defOp = value->getDefiningOp()) os << "val_" << defOp->getName(); else { - auto blockArg = cast(value); + auto blockArg = value.cast(); os << "arg" << blockArg->getArgNumber() << "@" << blockIds[blockArg->getOwner()]; } diff --git a/mlir/lib/Analysis/SliceAnalysis.cpp b/mlir/lib/Analysis/SliceAnalysis.cpp index befe3d397598..89ee613b370c 100644 --- a/mlir/lib/Analysis/SliceAnalysis.cpp +++ b/mlir/lib/Analysis/SliceAnalysis.cpp @@ -96,7 +96,7 @@ static void getBackwardSliceImpl(Operation *op, for (auto en : llvm::enumerate(op->getOperands())) { auto operand = en.value(); - if (auto blockArg = dyn_cast(operand)) { + if (auto blockArg = operand.dyn_cast()) { if (auto affIv = getForInductionVarOwner(operand)) { auto *affOp = affIv.getOperation(); if (backwardSlice->count(affOp) == 0) diff --git a/mlir/lib/Dialect/AffineOps/AffineOps.cpp b/mlir/lib/Dialect/AffineOps/AffineOps.cpp index bfe72101e852..d80f9865ccbe 100644 --- a/mlir/lib/Dialect/AffineOps/AffineOps.cpp +++ b/mlir/lib/Dialect/AffineOps/AffineOps.cpp @@ -107,7 +107,7 @@ static bool isFunctionRegion(Region *region) { /// function. A value of index type defined at the top level is always a valid /// symbol. bool mlir::isTopLevelValue(ValuePtr value) { - if (auto arg = dyn_cast(value)) + if (auto arg = value.dyn_cast()) return isFunctionRegion(arg->getOwner()->getParent()); return isFunctionRegion(value->getDefiningOp()->getParentRegion()); } @@ -134,7 +134,7 @@ bool mlir::isValidDim(ValuePtr value) { return false; } // This value has to be a block argument for a FuncOp or an affine.for. - auto *parentOp = cast(value)->getOwner()->getParentOp(); + auto *parentOp = value.cast()->getOwner()->getParentOp(); return isa(parentOp) || isa(parentOp); } @@ -1571,7 +1571,7 @@ bool mlir::isForInductionVar(ValuePtr val) { /// Returns the loop parent of an induction variable. If the provided value is /// not an induction variable, then return nullptr. AffineForOp mlir::getForInductionVarOwner(ValuePtr val) { - auto ivArg = dyn_cast(val); + auto ivArg = val.dyn_cast(); if (!ivArg || !ivArg->getOwner()) return AffineForOp(); auto *containingInst = ivArg->getOwner()->getParent()->getParentOp(); diff --git a/mlir/lib/Dialect/Linalg/Analysis/DependenceAnalysis.cpp b/mlir/lib/Dialect/Linalg/Analysis/DependenceAnalysis.cpp index 5fbbdea60c21..be90b1ce5a69 100644 --- a/mlir/lib/Dialect/Linalg/Analysis/DependenceAnalysis.cpp +++ b/mlir/lib/Dialect/Linalg/Analysis/DependenceAnalysis.cpp @@ -41,7 +41,7 @@ static StringRef toStringRef(LinalgDependenceGraph::DependenceType dt) { } ValuePtr Aliases::find(ValuePtr v) { - if (isa(v)) + if (v.isa()) return v; auto it = aliases.find(v); @@ -51,7 +51,7 @@ ValuePtr Aliases::find(ValuePtr v) { } while (true) { - if (isa(v)) + if (v.isa()) return v; if (auto alloc = dyn_cast_or_null(v->getDefiningOp())) { if (isStrided(alloc.getType())) diff --git a/mlir/lib/Dialect/LoopOps/LoopOps.cpp b/mlir/lib/Dialect/LoopOps/LoopOps.cpp index d3040c1bbb23..8e19eba911a9 100644 --- a/mlir/lib/Dialect/LoopOps/LoopOps.cpp +++ b/mlir/lib/Dialect/LoopOps/LoopOps.cpp @@ -136,7 +136,7 @@ LogicalResult ForOp::moveOutOfLoop(ArrayRef ops) { } ForOp mlir::loop::getForInductionVarOwner(ValuePtr val) { - auto ivArg = dyn_cast(val); + auto ivArg = val.dyn_cast(); if (!ivArg) return ForOp(); assert(ivArg->getOwner() && "unlinked block argument"); diff --git a/mlir/lib/Dialect/SPIRV/Serialization/Serializer.cpp b/mlir/lib/Dialect/SPIRV/Serialization/Serializer.cpp index 7ff471dfda5d..424c2e0427e2 100644 --- a/mlir/lib/Dialect/SPIRV/Serialization/Serializer.cpp +++ b/mlir/lib/Dialect/SPIRV/Serialization/Serializer.cpp @@ -509,7 +509,7 @@ void Serializer::printValueIDMap(raw_ostream &os) { << "id = " << valueIDPair.second << ' '; if (auto *op = val->getDefiningOp()) { os << "from op '" << op->getName() << "'"; - } else if (auto arg = dyn_cast(val)) { + } else if (auto arg = val.dyn_cast()) { Block *block = arg->getOwner(); os << "from argument of block " << block << ' '; os << " in op '" << block->getParentOp()->getName() << "'"; diff --git a/mlir/lib/IR/AsmPrinter.cpp b/mlir/lib/IR/AsmPrinter.cpp index a574f87c530d..4eeb5e4e95c9 100644 --- a/mlir/lib/IR/AsmPrinter.cpp +++ b/mlir/lib/IR/AsmPrinter.cpp @@ -1612,7 +1612,7 @@ void OperationPrinter::numberValuesInRegion(Region ®ion) { void OperationPrinter::numberValuesInBlock(Block &block) { auto setArgNameFn = [&](ValuePtr arg, StringRef name) { assert(!valueIDs.count(arg) && "arg numbered multiple times"); - assert(cast(arg)->getOwner() == &block && + assert(arg.cast()->getOwner() == &block && "arg not defined in 'block'"); setValueName(arg, name); }; @@ -1658,7 +1658,7 @@ void OperationPrinter::numberValuesInOp(Operation &op) { setValueName(result, name); // Record the result number for groups not anchored at 0. - if (int resultNo = cast(result)->getResultNumber()) + if (int resultNo = result.cast()->getResultNumber()) resultGroups.push_back(resultNo); }; @@ -1831,7 +1831,7 @@ void OperationPrinter::printValueIDImpl(ValuePtr value, bool printResultNo, // If this is a reference to the result of a multi-result operation or // operation, print out the # identifier and make sure to map our lookup // to the first result of the operation. - if (OpResultPtr result = dyn_cast(value)) + if (OpResultPtr result = value.dyn_cast()) getResultIDAndNumber(result, lookupValue, resultNo); auto it = valueIDs.find(lookupValue); diff --git a/mlir/lib/IR/Block.cpp b/mlir/lib/IR/Block.cpp index b168a8facd21..3abbe1027cee 100644 --- a/mlir/lib/IR/Block.cpp +++ b/mlir/lib/IR/Block.cpp @@ -16,10 +16,10 @@ using namespace mlir; //===----------------------------------------------------------------------===// /// Returns the number of this argument. -unsigned BlockArgument::getArgNumber() { +unsigned BlockArgument::getArgNumber() const { // Arguments are not stored in place, so we have to find it within the list. auto argList = getOwner()->getArguments(); - return std::distance(argList.begin(), llvm::find(argList, this)); + return std::distance(argList.begin(), llvm::find(argList, *this)); } //===----------------------------------------------------------------------===// @@ -29,7 +29,8 @@ unsigned BlockArgument::getArgNumber() { Block::~Block() { assert(!verifyOpOrder() && "Expected valid operation ordering."); clear(); - llvm::DeleteContainerPointers(arguments); + for (BlockArgument arg : arguments) + arg.destroy(); } Region *Block::getParent() const { return parentValidOpOrderPair.getPointer(); } @@ -143,7 +144,7 @@ void Block::recomputeOpOrder() { //===----------------------------------------------------------------------===// BlockArgumentPtr Block::addArgument(Type type) { - auto *arg = new BlockArgument(type, this); + BlockArgument arg = BlockArgument::create(type, this); arguments.push_back(arg); return arg; } @@ -163,7 +164,7 @@ void Block::eraseArgument(unsigned index, bool updatePredTerms) { assert(index < arguments.size()); // Delete the argument. - delete arguments[index]; + arguments[index].destroy(); arguments.erase(arguments.begin() + index); // If we aren't updating predecessors, there is nothing left to do. diff --git a/mlir/lib/IR/Operation.cpp b/mlir/lib/IR/Operation.cpp index 1dc7cb4bafd3..77288b228aa3 100644 --- a/mlir/lib/IR/Operation.cpp +++ b/mlir/lib/IR/Operation.cpp @@ -68,23 +68,29 @@ OperationName OperationName::getFromOpaquePointer(void *pointer) { //===----------------------------------------------------------------------===// /// Return the result number of this result. -unsigned OpResult::getResultNumber() { - // Results are always stored consecutively, so use pointer subtraction to - // figure out what number this is. - return this - &getOwner()->getOpResults()[0]; +unsigned OpResult::getResultNumber() const { + // Results are not stored in place, so we have to find it within the list. + auto resList = getOwner()->getOpResults(); + return std::distance(resList.begin(), llvm::find(resList, *this)); } //===----------------------------------------------------------------------===// // OpOperand //===----------------------------------------------------------------------===// -// TODO: This namespace is only required because of a bug in GCC<7.0. -namespace mlir { +OpOperand::OpOperand(Operation *owner, Value value) + : IROperand(owner, value.impl) {} + +/// Return the current value being used by this operand. +Value OpOperand::get() { return (detail::ValueImpl *)IROperand::get(); } + +/// Set the current value being used by this operand. +void OpOperand::set(Value newValue) { IROperand::set(newValue.impl); } + /// Return which operand this is in the operand list. -template <> unsigned OpOperand::getOperandNumber() { +unsigned OpOperand::getOperandNumber() { return this - &getOwner()->getOpOperands()[0]; } -} // end namespace mlir //===----------------------------------------------------------------------===// // BlockOperand @@ -179,7 +185,7 @@ Operation *Operation::create(Location location, OperationName name, auto instResults = op->getOpResults(); for (unsigned i = 0, e = resultTypes.size(); i != e; ++i) - new (&instResults[i]) OpResult(resultTypes[i], op); + new (&instResults[i]) OpResult(OpResult::create(resultTypes[i], op)); auto opOperands = op->getOpOperands(); @@ -256,7 +262,7 @@ Operation::~Operation() { getOperandStorage().~OperandStorage(); for (auto &result : getOpResults()) - result.~OpResult(); + result.destroy(); // Explicitly run the destructors for the successors. for (auto &successor : getBlockOperands()) diff --git a/mlir/lib/IR/OperationSupport.cpp b/mlir/lib/IR/OperationSupport.cpp index 1c68686a0cbc..5dfd3b02cc64 100644 --- a/mlir/lib/IR/OperationSupport.cpp +++ b/mlir/lib/IR/OperationSupport.cpp @@ -155,7 +155,7 @@ ResultRange::ResultRange(Operation *op) //===----------------------------------------------------------------------===// // ValueRange -ValueRange::ValueRange(ArrayRef values) +ValueRange::ValueRange(ArrayRef values) : ValueRange(values.data(), values.size()) {} ValueRange::ValueRange(OperandRange values) : ValueRange(values.begin().getBase(), values.size()) {} @@ -167,19 +167,18 @@ ValueRange::OwnerT ValueRange::offset_base(const OwnerT &owner, ptrdiff_t index) { if (OpOperand *operand = owner.dyn_cast()) return operand + index; - if (OpResultPtr result = owner.dyn_cast()) + if (OpResult *result = owner.dyn_cast()) return result + index; - return owner.get() + index; + return owner.get() + index; } /// See `detail::indexed_accessor_range_base` for details. -ValuePtr ValueRange::dereference_iterator(const OwnerT &owner, - ptrdiff_t index) { +Value ValueRange::dereference_iterator(const OwnerT &owner, ptrdiff_t index) { // Operands access the held value via 'get'. if (OpOperand *operand = owner.dyn_cast()) return operand[index].get(); // An OpResult is a value, so we can return it directly. - if (OpResultPtr result = owner.dyn_cast()) - return &result[index]; + if (OpResult *result = owner.dyn_cast()) + return result[index]; // Otherwise, this is a raw value array so just index directly. - return owner.get()[index]; + return owner.get()[index]; } diff --git a/mlir/lib/IR/TypeUtilities.cpp b/mlir/lib/IR/TypeUtilities.cpp index 8bc67e46fdcf..1fa13a85c514 100644 --- a/mlir/lib/IR/TypeUtilities.cpp +++ b/mlir/lib/IR/TypeUtilities.cpp @@ -28,10 +28,6 @@ Type mlir::getElementTypeOrSelf(ValuePtr val) { return getElementTypeOrSelf(val->getType()); } -Type mlir::getElementTypeOrSelf(ValueRef val) { - return getElementTypeOrSelf(val.getType()); -} - Type mlir::getElementTypeOrSelf(Attribute attr) { return getElementTypeOrSelf(attr.getType()); } diff --git a/mlir/lib/IR/Value.cpp b/mlir/lib/IR/Value.cpp index d723eec8b29c..ffb9601f1c93 100644 --- a/mlir/lib/IR/Value.cpp +++ b/mlir/lib/IR/Value.cpp @@ -13,8 +13,8 @@ using namespace mlir; /// If this value is the result of an Operation, return the operation that /// defines it. -Operation *Value::getDefiningOp() { - if (auto *result = dyn_cast()) +Operation *Value::getDefiningOp() const { + if (auto result = dyn_cast()) return result->getOwner(); return nullptr; }