diff options
30 files changed, 370 insertions, 160 deletions
diff --git a/mlir/bindings/python/pybind.cpp b/mlir/bindings/python/pybind.cpp index 10445edaf12..caff9af59ac 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<intptr_t>(value.getValue())); + return std::to_string( + reinterpret_cast<intptr_t>(value.getValue().getAsOpaquePointer())); } PythonValueHandle call(const std::vector<PythonValueHandle> &args) { diff --git a/mlir/include/mlir/Analysis/AffineAnalysis.h b/mlir/include/mlir/Analysis/AffineAnalysis.h index 5d9422883c1..6029a9ccdaa 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 791c164c7d2..cbd2e63fd3e 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 66f0033bf2f..75d7b98e20f 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 8e873bfb1c3..c8298760bad 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 5f3ea87f3cc..b7423a58f2a 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 b4d8ad65e60..04bd8b50fb6 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 6607f267057..f9629a8d99e 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<Value>. 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 b5189b48a85..33feea7bcbb 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<BlockArgumentPtr>; + using BlockArgListType = MutableArrayRef<BlockArgumentPtr>; BlockArgListType getArguments() { return arguments; } diff --git a/mlir/include/mlir/IR/BlockAndValueMapping.h b/mlir/include/mlir/IR/BlockAndValueMapping.h index 82173c34368..b7ad36072bd 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 <typename T> T *lookup(T *from) const { - auto *result = lookupOrNull(from); + template <typename T> 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 <typename T> 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<T *>(it->second) : value; + return it != valueMap.end() ? reinterpret_cast<Block *>(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<IRObjectWithUseList *, IRObjectWithUseList *> valueMap; + DenseMap<void *, void *> valueMap; }; } // end namespace mlir diff --git a/mlir/include/mlir/IR/OpImplementation.h b/mlir/include/mlir/IR/OpImplementation.h index e58a5b07038..8e2aed29500 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 <typename T, typename std::enable_if< - std::is_convertible<T &, ValueRange>::value && - !std::is_convertible<T &, ValuePtr>::value, - T>::type * = nullptr> +template <typename T, + typename std::enable_if<std::is_convertible<T &, ValueRange>::value && + !std::is_convertible<T &, Value &>::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 <typename T, typename std::enable_if< - !std::is_convertible<T &, ValueRef>::value && - !std::is_convertible<T &, ValuePtr>::value && + !std::is_convertible<T &, Value &>::value && !std::is_convertible<T &, Type &>::value && !std::is_convertible<T &, Attribute &>::value && !std::is_convertible<T &, ValueRange>::value && diff --git a/mlir/include/mlir/IR/Operation.h b/mlir/include/mlir/IR/Operation.h index 9ab900c8761..29227613468 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 14681663372..ef2ff44ef6e 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 <typename ValueIteratorT> class ValueTypeIterator final - : public llvm::mapped_iterator<ValueIteratorT, Type (*)(ValuePtr)> { - static Type unwrap(ValuePtr value) { return value->getType(); } + : public llvm::mapped_iterator<ValueIteratorT, Type (*)(Value)> { + 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<ValueIteratorT, Type (*)(ValuePtr)>(it, &unwrap) { - } + : llvm::mapped_iterator<ValueIteratorT, Type (*)(Value)>(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<OperandRange, OpOperand *, - ValuePtr, ValuePtr, ValuePtr> { + 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<ResultRange, OpResultPtr, - ValuePtr, ValuePtr, ValuePtr> { + : public detail::indexed_accessor_range_base<ResultRange, OpResult *, Value, + Value, Value> { 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 const *, OpOperand *, OpResultPtr>, - ValuePtr, ValuePtr, ValuePtr> { + ValueRange, PointerUnion<const Value *, OpOperand *, OpResult *>, + Value, Value, Value> { public: using RangeBaseT::RangeBaseT; template <typename Arg, typename = typename std::enable_if_t< - std::is_constructible<ArrayRef<ValuePtr>, Arg>::value && - !std::is_convertible<Arg, ValuePtr>::value>> - ValueRange(Arg &&arg) - : ValueRange(ArrayRef<ValuePtr>(std::forward<Arg>(arg))) {} - ValueRange(ValuePtr const &value) : ValueRange(&value, /*count=*/1) {} - ValueRange(const std::initializer_list<ValuePtr> &values) - : ValueRange(ArrayRef<ValuePtr>(values)) {} + std::is_constructible<ArrayRef<Value>, Arg>::value && + !std::is_convertible<Arg, Value>::value>> + ValueRange(Arg &&arg) : ValueRange(ArrayRef<Value>(std::forward<Arg>(arg))) {} + ValueRange(const Value &value) : ValueRange(&value, /*count=*/1) {} + ValueRange(const std::initializer_list<Value> &values) + : ValueRange(ArrayRef<Value>(values)) {} ValueRange(iterator_range<OperandRange::iterator> values) : ValueRange(OperandRange(values)) {} ValueRange(iterator_range<ResultRange::iterator> values) : ValueRange(ResultRange(values)) {} - ValueRange(ArrayRef<ValuePtr> values = llvm::None); + ValueRange(ArrayRef<Value> 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<ValuePtr const *, OpOperand *, OpResultPtr>; + using OwnerT = PointerUnion<const Value *, OpOperand *, OpResult *>; /// 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 b4713226559..fd9d317ed35 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 898d0da2b28..05720ed39af 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 <typename OperandType> class ValueUseIterator; template <typename OperandType> 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 030e6fa58b1..26703a25306 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, + }; + + ValueImpl(Kind kind, Type type) : typeAndKind(type, kind) {} + +private: + /// The type of the value and its kind. + llvm::PointerIntPair<Type, 1, Kind> typeAndKind; + + /// Allow access to 'typeAndKind'. + friend Value; +}; -/// Operands contain a Value. -using OpOperand = IROperandImpl<Value>; +/// The internal implementation of a BlockArgument. +class BlockArgumentImpl : public ValueImpl { + BlockArgumentImpl(Type type, Block *owner) + : ValueImpl(Kind::BlockArgument, type), owner(owner) {} -/// 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. + /// 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 <typename U> bool isa() const { return U::classof(this); } - template <typename U> U *dyn_cast() const { - return isa<U>() ? (U *)this : nullptr; + template <typename U> bool isa() const { + assert(impl && "isa<> used on a null type."); + return U::classof(*this); + } + template <typename U> U dyn_cast() const { + return isa<U>() ? U(impl) : U(nullptr); } - template <typename U> U *cast() const { + template <typename U> U dyn_cast_or_null() const { + return (impl && isa<U>()) ? U(impl) : U(nullptr); + } + template <typename U> U cast() const { assert(isa<U>()); - 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; } + + operator bool() const { return impl; } + bool operator==(const Value &other) const { return impl == other.impl; } + bool operator!=(const Value &other) const { return !(*this == other); } - Type getType() const { return typeAndKind.getPointer(); } + /// 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<IROperand>; + using user_range = iterator_range<user_iterator>; + + 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(); + /// Methods for supporting PointerLikeTypeTraits. + void *getAsOpaquePointer() const { return static_cast<void *>(impl); } + static Value getFromOpaquePointer(const void *pointer) { + return reinterpret_cast<detail::ValueImpl *>(const_cast<void *>(pointer)); + } + + friend ::llvm::hash_code hash_value(Value arg); + protected: - Value(Kind kind, Type type) : typeAndKind(type, kind) {} + /// The internal implementation of this value. + mutable detail::ValueImpl *impl; -private: - llvm::PointerIntPair<Type, 1, Kind> typeAndKind; + /// 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<use_iterator> { /// Block arguments are values. class BlockArgument : public Value { public: - static bool classof(const Value *value) { - return const_cast<Value *>(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) {} - - /// The owner of this operand. - /// TODO: can encode this more efficiently to avoid the space hit of this - /// through bitpacking shenanigans. - Block *const owner; + /// 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 *>(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 *>(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; } + + static bool classof(Value value) { return value.getKind() == Kind::OpResult; } - Operation *getOwner() { return owner; } + /// 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<detail::OpResultImpl *>(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<mlir::Value> { + static mlir::Value getEmptyKey() { + auto pointer = llvm::DenseMapInfo<void *>::getEmptyKey(); + return mlir::Value(static_cast<mlir::detail::ValueImpl *>(pointer)); + } + static mlir::Value getTombstoneKey() { + auto pointer = llvm::DenseMapInfo<void *>::getTombstoneKey(); + return mlir::Value(static_cast<mlir::detail::ValueImpl *>(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::detail::ValueImpl *>::NumLowBitsAvailable + }; +}; + +template <> struct DenseMapInfo<mlir::BlockArgument> { + static mlir::BlockArgument getEmptyKey() { + auto pointer = llvm::DenseMapInfo<void *>::getEmptyKey(); + return mlir::BlockArgument(static_cast<mlir::detail::ValueImpl *>(pointer)); + } + static mlir::BlockArgument getTombstoneKey() { + auto pointer = llvm::DenseMapInfo<void *>::getTombstoneKey(); + return mlir::BlockArgument(static_cast<mlir::detail::ValueImpl *>(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::detail::ValueImpl *>::NumLowBitsAvailable + }; +}; +} // end namespace llvm + #endif diff --git a/mlir/lib/Analysis/AffineStructures.cpp b/mlir/lib/Analysis/AffineStructures.cpp index 7ab547483cd..ce96a19751f 100644 --- a/mlir/lib/Analysis/AffineStructures.cpp +++ b/mlir/lib/Analysis/AffineStructures.cpp @@ -1965,7 +1965,7 @@ void FlatAffineConstraints::addLocalFloorDiv(ArrayRef<int64_t> 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<ValuePtr> &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 060a505593a..ea1501e8998 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<BlockArgument>(a)->getOwner(), b->getBlock()); + return dominates(a.cast<BlockArgument>()->getOwner(), b->getBlock()); } DominanceInfoNode *DominanceInfo::getNode(Block *a) { diff --git a/mlir/lib/Analysis/Liveness.cpp b/mlir/lib/Analysis/Liveness.cpp index bef0b9fa385..9b7b806c558 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<BlockArgument>(value)->getOwner(); + currentBlock = value.cast<BlockArgument>()->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<BlockArgument>(value); + auto blockArg = value.cast<BlockArgument>(); os << "arg" << blockArg->getArgNumber() << "@" << blockIds[blockArg->getOwner()]; } diff --git a/mlir/lib/Analysis/SliceAnalysis.cpp b/mlir/lib/Analysis/SliceAnalysis.cpp index befe3d39759..89ee613b370 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<BlockArgument>(operand)) { + if (auto blockArg = operand.dyn_cast<BlockArgument>()) { 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 bfe72101e85..d80f9865ccb 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<BlockArgument>(value)) + if (auto arg = value.dyn_cast<BlockArgument>()) 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<BlockArgument>(value)->getOwner()->getParentOp(); + auto *parentOp = value.cast<BlockArgument>()->getOwner()->getParentOp(); return isa<FuncOp>(parentOp) || isa<AffineForOp>(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<BlockArgument>(val); + auto ivArg = val.dyn_cast<BlockArgument>(); 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 5fbbdea60c2..be90b1ce5a6 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<BlockArgument>(v)) + if (v.isa<BlockArgument>()) return v; auto it = aliases.find(v); @@ -51,7 +51,7 @@ ValuePtr Aliases::find(ValuePtr v) { } while (true) { - if (isa<BlockArgument>(v)) + if (v.isa<BlockArgument>()) return v; if (auto alloc = dyn_cast_or_null<AllocOp>(v->getDefiningOp())) { if (isStrided(alloc.getType())) diff --git a/mlir/lib/Dialect/LoopOps/LoopOps.cpp b/mlir/lib/Dialect/LoopOps/LoopOps.cpp index d3040c1bbb2..8e19eba911a 100644 --- a/mlir/lib/Dialect/LoopOps/LoopOps.cpp +++ b/mlir/lib/Dialect/LoopOps/LoopOps.cpp @@ -136,7 +136,7 @@ LogicalResult ForOp::moveOutOfLoop(ArrayRef<Operation *> ops) { } ForOp mlir::loop::getForInductionVarOwner(ValuePtr val) { - auto ivArg = dyn_cast<BlockArgument>(val); + auto ivArg = val.dyn_cast<BlockArgument>(); 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 7ff471dfda5..424c2e0427e 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<BlockArgument>(val)) { + } else if (auto arg = val.dyn_cast<BlockArgument>()) { 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 a574f87c530..4eeb5e4e95c 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<BlockArgument>(arg)->getOwner() == &block && + assert(arg.cast<BlockArgument>()->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<OpResult>(result)->getResultNumber()) + if (int resultNo = result.cast<OpResult>()->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<OpResult>(value)) + if (OpResultPtr result = value.dyn_cast<OpResult>()) getResultIDAndNumber(result, lookupValue, resultNo); auto it = valueIDs.find(lookupValue); diff --git a/mlir/lib/IR/Block.cpp b/mlir/lib/IR/Block.cpp index b168a8facd2..3abbe1027ce 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 1dc7cb4bafd..77288b228aa 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 1c68686a0cb..5dfd3b02cc6 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<ValuePtr> values) +ValueRange::ValueRange(ArrayRef<Value> 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<OpOperand *>()) return operand + index; - if (OpResultPtr result = owner.dyn_cast<OpResultPtr>()) + if (OpResult *result = owner.dyn_cast<OpResult *>()) return result + index; - return owner.get<ValuePtr const *>() + index; + return owner.get<const Value *>() + 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<OpOperand *>()) return operand[index].get(); // An OpResult is a value, so we can return it directly. - if (OpResultPtr result = owner.dyn_cast<OpResultPtr>()) - return &result[index]; + if (OpResult *result = owner.dyn_cast<OpResult *>()) + return result[index]; // Otherwise, this is a raw value array so just index directly. - return owner.get<ValuePtr const *>()[index]; + return owner.get<const Value *>()[index]; } diff --git a/mlir/lib/IR/TypeUtilities.cpp b/mlir/lib/IR/TypeUtilities.cpp index 8bc67e46fdc..1fa13a85c51 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 d723eec8b29..ffb9601f1c9 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<OpResult>()) +Operation *Value::getDefiningOp() const { + if (auto result = dyn_cast<OpResult>()) return result->getOwner(); return nullptr; } |