rriddle created this revision. rriddle added reviewers: dblaikie, mehdi_amini, lattner, silvas. Herald added subscribers: wenzhicui, wrengr, Chia-hungDuan, dcaballe, cota, teijeong, dexonsmith, rdzhabarov, tatianashp, ThomasRaoux, jdoerfert, AlexeySotkin, msifontes, jurahul, Kayjukh, grosul1, Joonsoo, liufengdb, aartbik, lucyrfox, mgester, arpith-jacob, antiagainst, shauheen, mravishankar, bollu, sbc100. Herald added a reviewer: antiagainst. Herald added a reviewer: ftynse. rriddle requested review of this revision. Herald added subscribers: llvm-commits, cfe-commits, stephenneuendorffer, nicolasvasilache, aheejin. Herald added projects: clang, MLIR, LLVM.
This allows for using SFINAE partial specialization for DenseMapInfo. In MLIR, this is particularly useful as it will allow for defining partial specializations that support all Attribute, Op, and Type classes without needing to specialize DenseMapInfo for each individual class. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D113641 Files: clang/include/clang/AST/TypeOrdering.h clang/include/clang/Basic/SourceLocation.h clang/include/clang/Sema/Sema.h llvm/include/llvm/ADT/APInt.h llvm/include/llvm/ADT/ArrayRef.h llvm/include/llvm/ADT/DenseMapInfo.h llvm/include/llvm/ADT/Hashing.h llvm/include/llvm/ADT/ImmutableList.h llvm/include/llvm/ADT/PointerIntPair.h llvm/include/llvm/ADT/StringRef.h llvm/include/llvm/BinaryFormat/WasmTraits.h llvm/include/llvm/CodeGen/SelectionDAGNodes.h llvm/include/llvm/IR/Attributes.h llvm/include/llvm/Support/TypeSize.h llvm/unittests/ADT/DenseMapTest.cpp mlir/include/mlir/Dialect/SPIRV/IR/SPIRVOps.h mlir/include/mlir/IR/Attributes.h mlir/include/mlir/IR/BuiltinOps.h mlir/include/mlir/IR/OpDefinition.h mlir/include/mlir/IR/Types.h mlir/include/mlir/Support/LLVM.h
Index: mlir/include/mlir/Support/LLVM.h =================================================================== --- mlir/include/mlir/Support/LLVM.h +++ mlir/include/mlir/Support/LLVM.h @@ -46,7 +46,8 @@ } // namespace detail template <typename KeyT, typename ValueT, typename KeyInfoT, typename BucketT> class DenseMap; -template <typename T> struct DenseMapInfo; +template <typename T, typename Enable> +struct DenseMapInfo; template <typename ValueT, typename ValueInfoT> class DenseSet; class MallocAllocator; template <typename T> class MutableArrayRef; @@ -90,7 +91,8 @@ // // Containers. using llvm::ArrayRef; -using llvm::DenseMapInfo; +template <typename T, typename Enable = void> +using DenseMapInfo = llvm::DenseMapInfo<T, Enable>; template <typename KeyT, typename ValueT, typename KeyInfoT = DenseMapInfo<KeyT>, typename BucketT = llvm::detail::DenseMapPair<KeyT, ValueT>> Index: mlir/include/mlir/IR/Types.h =================================================================== --- mlir/include/mlir/IR/Types.h +++ mlir/include/mlir/IR/Types.h @@ -269,6 +269,18 @@ static unsigned getHashValue(mlir::Type val) { return mlir::hash_value(val); } static bool isEqual(mlir::Type LHS, mlir::Type RHS) { return LHS == RHS; } }; +template <typename T> +struct DenseMapInfo<T, std::enable_if_t<std::is_base_of<mlir::Type, T>::value>> + : public DenseMapInfo<mlir::Type> { + static T getEmptyKey() { + const void *pointer = llvm::DenseMapInfo<const void *>::getEmptyKey(); + return T::getFromOpaquePointer(pointer); + } + static T getTombstoneKey() { + const void *pointer = llvm::DenseMapInfo<const void *>::getTombstoneKey(); + return T::getFromOpaquePointer(pointer); + } +}; /// We align TypeStorage by 8, so allow LLVM to steal the low bits. template <> struct PointerLikeTypeTraits<mlir::Type> { Index: mlir/include/mlir/IR/OpDefinition.h =================================================================== --- mlir/include/mlir/IR/OpDefinition.h +++ mlir/include/mlir/IR/OpDefinition.h @@ -1906,4 +1906,25 @@ } // namespace impl } // end namespace mlir +namespace llvm { + +template <typename T> +struct DenseMapInfo< + T, std::enable_if_t<std::is_base_of<mlir::OpState, T>::value>> { + static inline T getEmptyKey() { + auto *pointer = llvm::DenseMapInfo<void *>::getEmptyKey(); + return T::getFromOpaquePointer(pointer); + } + static inline T getTombstoneKey() { + auto *pointer = llvm::DenseMapInfo<void *>::getTombstoneKey(); + return T::getFromOpaquePointer(pointer); + } + static unsigned getHashValue(T val) { + return hash_value(val.getAsOpaquePointer()); + } + static bool isEqual(T lhs, T rhs) { return lhs == rhs; } +}; + +} // end namespace llvm + #endif Index: mlir/include/mlir/IR/BuiltinOps.h =================================================================== --- mlir/include/mlir/IR/BuiltinOps.h +++ mlir/include/mlir/IR/BuiltinOps.h @@ -49,23 +49,6 @@ } // end namespace mlir namespace llvm { -// Functions hash just like pointers. -template <> -struct DenseMapInfo<mlir::FuncOp> { - static mlir::FuncOp getEmptyKey() { - auto *pointer = llvm::DenseMapInfo<void *>::getEmptyKey(); - return mlir::FuncOp::getFromOpaquePointer(pointer); - } - static mlir::FuncOp getTombstoneKey() { - auto *pointer = llvm::DenseMapInfo<void *>::getTombstoneKey(); - return mlir::FuncOp::getFromOpaquePointer(pointer); - } - static unsigned getHashValue(mlir::FuncOp val) { - return hash_value(val.getAsOpaquePointer()); - } - static bool isEqual(mlir::FuncOp lhs, mlir::FuncOp rhs) { return lhs == rhs; } -}; - /// Allow stealing the low bits of FuncOp. template <> struct PointerLikeTypeTraits<mlir::FuncOp> { Index: mlir/include/mlir/IR/Attributes.h =================================================================== --- mlir/include/mlir/IR/Attributes.h +++ mlir/include/mlir/IR/Attributes.h @@ -198,6 +198,19 @@ return LHS == RHS; } }; +template <typename T> +struct DenseMapInfo< + T, std::enable_if_t<std::is_base_of<mlir::Attribute, T>::value>> + : public DenseMapInfo<mlir::Attribute> { + static T getEmptyKey() { + const void *pointer = llvm::DenseMapInfo<const void *>::getEmptyKey(); + return T::getFromOpaquePointer(pointer); + } + static T getTombstoneKey() { + const void *pointer = llvm::DenseMapInfo<const void *>::getTombstoneKey(); + return T::getFromOpaquePointer(pointer); + } +}; /// Allow LLVM to steal the low bits of Attributes. template <> struct PointerLikeTypeTraits<mlir::Attribute> { Index: mlir/include/mlir/Dialect/SPIRV/IR/SPIRVOps.h =================================================================== --- mlir/include/mlir/Dialect/SPIRV/IR/SPIRVOps.h +++ mlir/include/mlir/Dialect/SPIRV/IR/SPIRVOps.h @@ -40,25 +40,6 @@ namespace llvm { -/// spirv::Function ops hash just like pointers. -template <> -struct DenseMapInfo<mlir::spirv::FuncOp> { - static mlir::spirv::FuncOp getEmptyKey() { - auto pointer = llvm::DenseMapInfo<void *>::getEmptyKey(); - return mlir::spirv::FuncOp::getFromOpaquePointer(pointer); - } - static mlir::spirv::FuncOp getTombstoneKey() { - auto pointer = llvm::DenseMapInfo<void *>::getTombstoneKey(); - return mlir::spirv::FuncOp::getFromOpaquePointer(pointer); - } - static unsigned getHashValue(mlir::spirv::FuncOp val) { - return hash_value(val.getAsOpaquePointer()); - } - static bool isEqual(mlir::spirv::FuncOp LHS, mlir::spirv::FuncOp RHS) { - return LHS == RHS; - } -}; - /// Allow stealing the low bits of spirv::Function ops. template <> struct PointerLikeTypeTraits<mlir::spirv::FuncOp> { Index: llvm/unittests/ADT/DenseMapTest.cpp =================================================================== --- llvm/unittests/ADT/DenseMapTest.cpp +++ llvm/unittests/ADT/DenseMapTest.cpp @@ -655,4 +655,44 @@ EXPECT_EQ(Map.find(K2), Map.end()); EXPECT_EQ(Map.find(K3), Map.end()); } +} // namespace + +namespace { +struct A { + int value; +}; +struct B : public A {}; +} // namespace + +namespace llvm { +template <typename T> +struct DenseMapInfo<T, std::enable_if_t<std::is_base_of<A, T>::value>> { + static inline T getEmptyKey() { return {static_cast<int>(~0)}; } + static inline T getTombstoneKey() { return {static_cast<int>(~0U - 1)}; } + static unsigned getHashValue(const T &Val) { return Val.value; } + static bool isEqual(const T &LHS, const T &RHS) { + return LHS.value == RHS.value; + } +}; +} // namespace llvm + +namespace { +TEST(DenseMapCustomTest, SFINAEMapInfo) { + // Test that we can use a pointer to an incomplete type as a DenseMap key. + // This is an important build time optimization, since many classes have + // DenseMap members. + DenseMap<B, int> Map; + B Keys[3] = {{0}, {1}, {2}}; + Map.insert({Keys[0], 1}); + Map.insert({Keys[1], 2}); + Map.insert({Keys[2], 3}); + EXPECT_EQ(Map.count(Keys[0]), 1u); + EXPECT_EQ(Map[Keys[0]], 1); + EXPECT_EQ(Map[Keys[1]], 2); + EXPECT_EQ(Map[Keys[2]], 3); + Map.clear(); + EXPECT_EQ(Map.find(Keys[0]), Map.end()); + EXPECT_EQ(Map.find(Keys[1]), Map.end()); + EXPECT_EQ(Map.find(Keys[2]), Map.end()); } +} // namespace Index: llvm/include/llvm/Support/TypeSize.h =================================================================== --- llvm/include/llvm/Support/TypeSize.h +++ llvm/include/llvm/Support/TypeSize.h @@ -246,10 +246,9 @@ } }; - //===----------------------------------------------------------------------===// // LinearPolySize - base class for fixed- or scalable sizes. -// ^ ^ +// ^ ^ // | | // | +----- ElementCount - Leaf class to represent an element count // | (vscale x unsigned) @@ -499,7 +498,6 @@ return OS; } -template <typename T> struct DenseMapInfo; template <> struct DenseMapInfo<ElementCount> { static inline ElementCount getEmptyKey() { return ElementCount::getScalable(~0U); Index: llvm/include/llvm/IR/Attributes.h =================================================================== --- llvm/include/llvm/IR/Attributes.h +++ llvm/include/llvm/IR/Attributes.h @@ -37,7 +37,6 @@ class AttributeImpl; class AttributeListImpl; class AttributeSetNode; -template<typename T> struct DenseMapInfo; class FoldingSetNodeID; class Function; class LLVMContext; @@ -266,7 +265,7 @@ /// and removing string or integer attributes involves a FoldingSet lookup. class AttributeSet { friend AttributeListImpl; - template <typename Ty> friend struct DenseMapInfo; + template <typename Ty, typename Enable> friend struct DenseMapInfo; // TODO: Extract AvailableAttrs from AttributeSetNode and store them here. // This will allow an efficient implementation of addAttribute and @@ -409,7 +408,7 @@ friend class AttributeListImpl; friend class AttributeSet; friend class AttributeSetNode; - template <typename Ty> friend struct DenseMapInfo; + template <typename Ty, typename Enable> friend struct DenseMapInfo; /// The attributes that we are managing. This can be null to represent /// the empty attributes list. Index: llvm/include/llvm/CodeGen/SelectionDAGNodes.h =================================================================== --- llvm/include/llvm/CodeGen/SelectionDAGNodes.h +++ llvm/include/llvm/CodeGen/SelectionDAGNodes.h @@ -58,7 +58,6 @@ class APInt; class Constant; -template <typename T> struct DenseMapInfo; class GlobalValue; class MachineBasicBlock; class MachineConstantPoolValue; Index: llvm/include/llvm/BinaryFormat/WasmTraits.h =================================================================== --- llvm/include/llvm/BinaryFormat/WasmTraits.h +++ llvm/include/llvm/BinaryFormat/WasmTraits.h @@ -18,8 +18,6 @@ namespace llvm { -template <typename T> struct DenseMapInfo; - // Traits for using WasmSignature in a DenseMap. template <> struct DenseMapInfo<wasm::WasmSignature> { static wasm::WasmSignature getEmptyKey() { Index: llvm/include/llvm/ADT/StringRef.h =================================================================== --- llvm/include/llvm/ADT/StringRef.h +++ llvm/include/llvm/ADT/StringRef.h @@ -35,7 +35,6 @@ class APInt; class hash_code; template <typename T> class SmallVectorImpl; - template <typename T> struct DenseMapInfo; class StringRef; /// Helper functions for StringRef::getAsInteger. Index: llvm/include/llvm/ADT/PointerIntPair.h =================================================================== --- llvm/include/llvm/ADT/PointerIntPair.h +++ llvm/include/llvm/ADT/PointerIntPair.h @@ -13,6 +13,7 @@ #ifndef LLVM_ADT_POINTERINTPAIR_H #define LLVM_ADT_POINTERINTPAIR_H +#include "llvm/ADT/DenseMapInfo.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/PointerLikeTypeTraits.h" #include "llvm/Support/type_traits.h" @@ -22,7 +23,6 @@ namespace llvm { -template <typename T> struct DenseMapInfo; template <typename PointerT, unsigned IntBits, typename PtrTraits> struct PointerIntPairInfo; Index: llvm/include/llvm/ADT/ImmutableList.h =================================================================== --- llvm/include/llvm/ADT/ImmutableList.h +++ llvm/include/llvm/ADT/ImmutableList.h @@ -220,7 +220,6 @@ // Partially-specialized Traits. //===----------------------------------------------------------------------===// -template<typename T> struct DenseMapInfo; template<typename T> struct DenseMapInfo<ImmutableList<T>> { static inline ImmutableList<T> getEmptyKey() { return reinterpret_cast<ImmutableListImpl<T>*>(-1); Index: llvm/include/llvm/ADT/Hashing.h =================================================================== --- llvm/include/llvm/ADT/Hashing.h +++ llvm/include/llvm/ADT/Hashing.h @@ -44,6 +44,7 @@ #ifndef LLVM_ADT_HASHING_H #define LLVM_ADT_HASHING_H +#include "llvm/ADT/DenseMapInfo.h" #include "llvm/Support/DataTypes.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/SwapByteOrder.h" @@ -56,7 +57,6 @@ #include <utility> namespace llvm { -template <typename T> struct DenseMapInfo; /// An opaque object representing a hash code. /// Index: llvm/include/llvm/ADT/DenseMapInfo.h =================================================================== --- llvm/include/llvm/ADT/DenseMapInfo.h +++ llvm/include/llvm/ADT/DenseMapInfo.h @@ -39,8 +39,7 @@ } // end namespace detail -template<typename T> -struct DenseMapInfo { +template <typename T, typename Enable = void> struct DenseMapInfo { //static inline T getEmptyKey(); //static inline T getTombstoneKey(); //static unsigned getHashValue(const T &Val); Index: llvm/include/llvm/ADT/ArrayRef.h =================================================================== --- llvm/include/llvm/ADT/ArrayRef.h +++ llvm/include/llvm/ADT/ArrayRef.h @@ -26,8 +26,6 @@ namespace llvm { - template<typename T> struct DenseMapInfo; - /// ArrayRef - Represent a constant reference to an array (0 or more elements /// consecutively in memory), i.e. a start pointer and a length. It allows /// various APIs to take consecutive elements easily and conveniently. Index: llvm/include/llvm/ADT/APInt.h =================================================================== --- llvm/include/llvm/ADT/APInt.h +++ llvm/include/llvm/ADT/APInt.h @@ -15,6 +15,7 @@ #ifndef LLVM_ADT_APINT_H #define LLVM_ADT_APINT_H +#include "llvm/ADT/DenseMapInfo.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/MathExtras.h" #include <cassert> @@ -31,7 +32,6 @@ template <typename T> class SmallVectorImpl; template <typename T> class ArrayRef; template <typename T> class Optional; -template <typename T> struct DenseMapInfo; class APInt; Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -74,7 +74,6 @@ namespace llvm { class APSInt; - template <typename ValueT> struct DenseMapInfo; template <typename ValueT, typename ValueInfoT> class DenseSet; class SmallBitVector; struct InlineAsmIdentifierInfo; Index: clang/include/clang/Basic/SourceLocation.h =================================================================== --- clang/include/clang/Basic/SourceLocation.h +++ clang/include/clang/Basic/SourceLocation.h @@ -23,8 +23,6 @@ namespace llvm { -template <typename T> struct DenseMapInfo; - class FoldingSetNodeID; template <typename T> struct FoldingSetTrait; Index: clang/include/clang/AST/TypeOrdering.h =================================================================== --- clang/include/clang/AST/TypeOrdering.h +++ clang/include/clang/AST/TypeOrdering.h @@ -34,7 +34,6 @@ } namespace llvm { - template<class> struct DenseMapInfo; template<> struct DenseMapInfo<clang::QualType> { static inline clang::QualType getEmptyKey() { return clang::QualType(); }
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits