diff --git a/clang/include/clang/AST/TypeOrdering.h b/clang/include/clang/AST/TypeOrdering.h --- a/clang/include/clang/AST/TypeOrdering.h +++ b/clang/include/clang/AST/TypeOrdering.h @@ -34,7 +34,6 @@ } namespace llvm { - template struct DenseMapInfo; template<> struct DenseMapInfo { static inline clang::QualType getEmptyKey() { return clang::QualType(); } diff --git a/clang/include/clang/Basic/SourceLocation.h b/clang/include/clang/Basic/SourceLocation.h --- a/clang/include/clang/Basic/SourceLocation.h +++ b/clang/include/clang/Basic/SourceLocation.h @@ -23,8 +23,6 @@ namespace llvm { -template struct DenseMapInfo; - class FoldingSetNodeID; template struct FoldingSetTrait; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -74,7 +74,6 @@ namespace llvm { class APSInt; - template struct DenseMapInfo; template class DenseSet; class SmallBitVector; struct InlineAsmIdentifierInfo; diff --git a/llvm/include/llvm/ADT/APInt.h b/llvm/include/llvm/ADT/APInt.h --- a/llvm/include/llvm/ADT/APInt.h +++ b/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 @@ -31,7 +32,6 @@ template class SmallVectorImpl; template class ArrayRef; template class Optional; -template struct DenseMapInfo; class APInt; diff --git a/llvm/include/llvm/ADT/ArrayRef.h b/llvm/include/llvm/ADT/ArrayRef.h --- a/llvm/include/llvm/ADT/ArrayRef.h +++ b/llvm/include/llvm/ADT/ArrayRef.h @@ -26,8 +26,6 @@ namespace llvm { - template 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. diff --git a/llvm/include/llvm/ADT/DenseMapInfo.h b/llvm/include/llvm/ADT/DenseMapInfo.h --- a/llvm/include/llvm/ADT/DenseMapInfo.h +++ b/llvm/include/llvm/ADT/DenseMapInfo.h @@ -39,8 +39,7 @@ } // end namespace detail -template -struct DenseMapInfo { +template struct DenseMapInfo { //static inline T getEmptyKey(); //static inline T getTombstoneKey(); //static unsigned getHashValue(const T &Val); diff --git a/llvm/include/llvm/ADT/Hashing.h b/llvm/include/llvm/ADT/Hashing.h --- a/llvm/include/llvm/ADT/Hashing.h +++ b/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 namespace llvm { -template struct DenseMapInfo; /// An opaque object representing a hash code. /// diff --git a/llvm/include/llvm/ADT/ImmutableList.h b/llvm/include/llvm/ADT/ImmutableList.h --- a/llvm/include/llvm/ADT/ImmutableList.h +++ b/llvm/include/llvm/ADT/ImmutableList.h @@ -220,7 +220,6 @@ // Partially-specialized Traits. //===----------------------------------------------------------------------===// -template struct DenseMapInfo; template struct DenseMapInfo> { static inline ImmutableList getEmptyKey() { return reinterpret_cast*>(-1); diff --git a/llvm/include/llvm/ADT/PointerIntPair.h b/llvm/include/llvm/ADT/PointerIntPair.h --- a/llvm/include/llvm/ADT/PointerIntPair.h +++ b/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 struct DenseMapInfo; template struct PointerIntPairInfo; diff --git a/llvm/include/llvm/ADT/StringRef.h b/llvm/include/llvm/ADT/StringRef.h --- a/llvm/include/llvm/ADT/StringRef.h +++ b/llvm/include/llvm/ADT/StringRef.h @@ -35,7 +35,6 @@ class APInt; class hash_code; template class SmallVectorImpl; - template struct DenseMapInfo; class StringRef; /// Helper functions for StringRef::getAsInteger. diff --git a/llvm/include/llvm/BinaryFormat/WasmTraits.h b/llvm/include/llvm/BinaryFormat/WasmTraits.h --- a/llvm/include/llvm/BinaryFormat/WasmTraits.h +++ b/llvm/include/llvm/BinaryFormat/WasmTraits.h @@ -18,8 +18,6 @@ namespace llvm { -template struct DenseMapInfo; - // Traits for using WasmSignature in a DenseMap. template <> struct DenseMapInfo { static wasm::WasmSignature getEmptyKey() { diff --git a/llvm/include/llvm/CodeGen/SelectionDAGNodes.h b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h --- a/llvm/include/llvm/CodeGen/SelectionDAGNodes.h +++ b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h @@ -58,7 +58,6 @@ class APInt; class Constant; -template struct DenseMapInfo; class GlobalValue; class MachineBasicBlock; class MachineConstantPoolValue; diff --git a/llvm/include/llvm/IR/Attributes.h b/llvm/include/llvm/IR/Attributes.h --- a/llvm/include/llvm/IR/Attributes.h +++ b/llvm/include/llvm/IR/Attributes.h @@ -37,7 +37,6 @@ class AttributeImpl; class AttributeListImpl; class AttributeSetNode; -template 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 friend struct DenseMapInfo; + template 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 friend struct DenseMapInfo; + template friend struct DenseMapInfo; /// The attributes that we are managing. This can be null to represent /// the empty attributes list. diff --git a/llvm/include/llvm/Support/TypeSize.h b/llvm/include/llvm/Support/TypeSize.h --- a/llvm/include/llvm/Support/TypeSize.h +++ b/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 struct DenseMapInfo; template <> struct DenseMapInfo { static inline ElementCount getEmptyKey() { return ElementCount::getScalable(~0U); diff --git a/llvm/unittests/ADT/DenseMapTest.cpp b/llvm/unittests/ADT/DenseMapTest.cpp --- a/llvm/unittests/ADT/DenseMapTest.cpp +++ b/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 +struct DenseMapInfo::value>> { + static inline T getEmptyKey() { return {static_cast(~0)}; } + static inline T getTombstoneKey() { return {static_cast(~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 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 diff --git a/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVOps.h b/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVOps.h --- a/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVOps.h +++ b/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVOps.h @@ -40,25 +40,6 @@ namespace llvm { -/// spirv::Function ops hash just like pointers. -template <> -struct DenseMapInfo { - static mlir::spirv::FuncOp getEmptyKey() { - auto pointer = llvm::DenseMapInfo::getEmptyKey(); - return mlir::spirv::FuncOp::getFromOpaquePointer(pointer); - } - static mlir::spirv::FuncOp getTombstoneKey() { - auto pointer = llvm::DenseMapInfo::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 { diff --git a/mlir/include/mlir/IR/Attributes.h b/mlir/include/mlir/IR/Attributes.h --- a/mlir/include/mlir/IR/Attributes.h +++ b/mlir/include/mlir/IR/Attributes.h @@ -198,6 +198,19 @@ return LHS == RHS; } }; +template +struct DenseMapInfo< + T, std::enable_if_t::value>> + : public DenseMapInfo { + static T getEmptyKey() { + const void *pointer = llvm::DenseMapInfo::getEmptyKey(); + return T::getFromOpaquePointer(pointer); + } + static T getTombstoneKey() { + const void *pointer = llvm::DenseMapInfo::getTombstoneKey(); + return T::getFromOpaquePointer(pointer); + } +}; /// Allow LLVM to steal the low bits of Attributes. template <> struct PointerLikeTypeTraits { diff --git a/mlir/include/mlir/IR/BuiltinOps.h b/mlir/include/mlir/IR/BuiltinOps.h --- a/mlir/include/mlir/IR/BuiltinOps.h +++ b/mlir/include/mlir/IR/BuiltinOps.h @@ -49,23 +49,6 @@ } // end namespace mlir namespace llvm { -// Functions hash just like pointers. -template <> -struct DenseMapInfo { - static mlir::FuncOp getEmptyKey() { - auto *pointer = llvm::DenseMapInfo::getEmptyKey(); - return mlir::FuncOp::getFromOpaquePointer(pointer); - } - static mlir::FuncOp getTombstoneKey() { - auto *pointer = llvm::DenseMapInfo::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 { diff --git a/mlir/include/mlir/IR/OpDefinition.h b/mlir/include/mlir/IR/OpDefinition.h --- a/mlir/include/mlir/IR/OpDefinition.h +++ b/mlir/include/mlir/IR/OpDefinition.h @@ -1906,4 +1906,25 @@ } // namespace impl } // end namespace mlir +namespace llvm { + +template +struct DenseMapInfo< + T, std::enable_if_t::value>> { + static inline T getEmptyKey() { + auto *pointer = llvm::DenseMapInfo::getEmptyKey(); + return T::getFromOpaquePointer(pointer); + } + static inline T getTombstoneKey() { + auto *pointer = llvm::DenseMapInfo::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 diff --git a/mlir/include/mlir/IR/Types.h b/mlir/include/mlir/IR/Types.h --- a/mlir/include/mlir/IR/Types.h +++ b/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 +struct DenseMapInfo::value>> + : public DenseMapInfo { + static T getEmptyKey() { + const void *pointer = llvm::DenseMapInfo::getEmptyKey(); + return T::getFromOpaquePointer(pointer); + } + static T getTombstoneKey() { + const void *pointer = llvm::DenseMapInfo::getTombstoneKey(); + return T::getFromOpaquePointer(pointer); + } +}; /// We align TypeStorage by 8, so allow LLVM to steal the low bits. template <> struct PointerLikeTypeTraits { diff --git a/mlir/include/mlir/Support/LLVM.h b/mlir/include/mlir/Support/LLVM.h --- a/mlir/include/mlir/Support/LLVM.h +++ b/mlir/include/mlir/Support/LLVM.h @@ -46,7 +46,8 @@ } // namespace detail template class DenseMap; -template struct DenseMapInfo; +template +struct DenseMapInfo; template class DenseSet; class MallocAllocator; template class MutableArrayRef; @@ -90,7 +91,8 @@ // // Containers. using llvm::ArrayRef; -using llvm::DenseMapInfo; +template +using DenseMapInfo = llvm::DenseMapInfo; template , typename BucketT = llvm::detail::DenseMapPair>