From 04d9e746f1792ecf610d823eb486332e1ab8030b Mon Sep 17 00:00:00 2001 From: Daniel Berlin Date: Fri, 10 Mar 2017 00:25:26 +0000 Subject: [PATCH] Add support for DenseMap/DenseSet count and find using const pointers Summary: Similar to SmallPtrSet, this makes find and count work with both const referneces and const pointers. Reviewers: dblaikie Subscribers: llvm-commits, mzolotukhin Differential Revision: https://reviews.llvm.org/D30713 llvm-svn: 297424 --- llvm/include/llvm/ADT/DenseMap.h | 11 +++++++---- llvm/include/llvm/ADT/DenseSet.h | 8 +++++--- llvm/include/llvm/Support/type_traits.h | 9 +++++++++ llvm/lib/Transforms/Vectorize/LoopVectorize.cpp | 6 +++--- llvm/unittests/ADT/DenseMapTest.cpp | 14 ++++++++++++++ llvm/unittests/ADT/DenseSetTest.cpp | 13 +++++++++++++ 6 files changed, 51 insertions(+), 10 deletions(-) diff --git a/llvm/include/llvm/ADT/DenseMap.h b/llvm/include/llvm/ADT/DenseMap.h index a689bcbf1515..fd8d3bf368a8 100644 --- a/llvm/include/llvm/ADT/DenseMap.h +++ b/llvm/include/llvm/ADT/DenseMap.h @@ -53,6 +53,9 @@ class DenseMapIterator; template class DenseMapBase : public DebugEpochBase { + template + using const_arg_type_t = typename const_pointer_or_const_ref::type; + public: typedef unsigned size_type; typedef KeyT key_type; @@ -119,18 +122,18 @@ public: } /// Return 1 if the specified key is in the map, 0 otherwise. - size_type count(const KeyT &Val) const { + size_type count(const_arg_type_t Val) const { const BucketT *TheBucket; return LookupBucketFor(Val, TheBucket) ? 1 : 0; } - iterator find(const KeyT &Val) { + iterator find(const_arg_type_t Val) { BucketT *TheBucket; if (LookupBucketFor(Val, TheBucket)) return iterator(TheBucket, getBucketsEnd(), *this, true); return end(); } - const_iterator find(const KeyT &Val) const { + const_iterator find(const_arg_type_t Val) const { const BucketT *TheBucket; if (LookupBucketFor(Val, TheBucket)) return const_iterator(TheBucket, getBucketsEnd(), *this, true); @@ -159,7 +162,7 @@ public: /// lookup - Return the entry for the specified key, or a default /// constructed value if no such entry exists. - ValueT lookup(const KeyT &Val) const { + ValueT lookup(const_arg_type_t Val) const { const BucketT *TheBucket; if (LookupBucketFor(Val, TheBucket)) return TheBucket->getSecond(); diff --git a/llvm/include/llvm/ADT/DenseSet.h b/llvm/include/llvm/ADT/DenseSet.h index b1345f7da738..fcf304c3ecc4 100644 --- a/llvm/include/llvm/ADT/DenseSet.h +++ b/llvm/include/llvm/ADT/DenseSet.h @@ -48,6 +48,8 @@ class DenseSetImpl { static_assert(sizeof(typename MapTy::value_type) == sizeof(ValueT), "DenseMap buckets unexpectedly large!"); MapTy TheMap; + template + using const_arg_type_t = typename const_pointer_or_const_ref::type; public: typedef ValueT key_type; @@ -78,7 +80,7 @@ public: } /// Return 1 if the specified key is in the set, 0 otherwise. - size_type count(const ValueT &V) const { + size_type count(const_arg_type_t V) const { return TheMap.count(V); } @@ -154,8 +156,8 @@ public: const_iterator begin() const { return ConstIterator(TheMap.begin()); } const_iterator end() const { return ConstIterator(TheMap.end()); } - iterator find(const ValueT &V) { return Iterator(TheMap.find(V)); } - const_iterator find(const ValueT &V) const { + iterator find(const_arg_type_t V) { return Iterator(TheMap.find(V)); } + const_iterator find(const_arg_type_t V) const { return ConstIterator(TheMap.find(V)); } diff --git a/llvm/include/llvm/Support/type_traits.h b/llvm/include/llvm/Support/type_traits.h index 7706ff527197..ce4bbf8cb2cc 100644 --- a/llvm/include/llvm/Support/type_traits.h +++ b/llvm/include/llvm/Support/type_traits.h @@ -95,6 +95,15 @@ struct add_const_past_pointer< typedef const typename std::remove_pointer::type *type; }; +template +struct const_pointer_or_const_ref { + using type = const T &; +}; +template +struct const_pointer_or_const_ref< + T, typename std::enable_if::value>::type> { + using type = typename add_const_past_pointer::type; +}; } // If the compiler supports detecting whether a class is final, define diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp index 080f265b258f..223986cde64c 100644 --- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp +++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp @@ -3657,7 +3657,7 @@ void InnerLoopVectorizer::fixupIVUsers(PHINode *OrigPhi, namespace { struct CSEDenseMapInfo { - static bool canHandle(Instruction *I) { + static bool canHandle(const Instruction *I) { return isa(I) || isa(I) || isa(I) || isa(I); } @@ -3667,12 +3667,12 @@ struct CSEDenseMapInfo { static inline Instruction *getTombstoneKey() { return DenseMapInfo::getTombstoneKey(); } - static unsigned getHashValue(Instruction *I) { + static unsigned getHashValue(const Instruction *I) { assert(canHandle(I) && "Unknown instruction!"); return hash_combine(I->getOpcode(), hash_combine_range(I->value_op_begin(), I->value_op_end())); } - static bool isEqual(Instruction *LHS, Instruction *RHS) { + static bool isEqual(const Instruction *LHS, const Instruction *RHS) { if (LHS == getEmptyKey() || RHS == getEmptyKey() || LHS == getTombstoneKey() || RHS == getTombstoneKey()) return LHS == RHS; diff --git a/llvm/unittests/ADT/DenseMapTest.cpp b/llvm/unittests/ADT/DenseMapTest.cpp index 80f0462bc8fb..273f4da021c4 100644 --- a/llvm/unittests/ADT/DenseMapTest.cpp +++ b/llvm/unittests/ADT/DenseMapTest.cpp @@ -580,4 +580,18 @@ TEST(DenseMapCustomTest, TryEmplaceTest) { EXPECT_EQ(Try1.first, Try2.first); EXPECT_NE(nullptr, P); } + +TEST(DenseMapCustomTest, ConstTest) { + // Test that const pointers work okay for count and find, even when the + // underlying map is a non-const pointer. + DenseMap Map; + int A; + int *B = &A; + const int *C = &A; + Map.insert({B, 0}); + EXPECT_EQ(Map.count(B), 1u); + EXPECT_EQ(Map.count(C), 1u); + EXPECT_NE(Map.find(B), Map.end()); + EXPECT_NE(Map.find(C), Map.end()); +} } diff --git a/llvm/unittests/ADT/DenseSetTest.cpp b/llvm/unittests/ADT/DenseSetTest.cpp index 19feb415a9dd..a09537a3e990 100644 --- a/llvm/unittests/ADT/DenseSetTest.cpp +++ b/llvm/unittests/ADT/DenseSetTest.cpp @@ -185,4 +185,17 @@ TEST(DenseSetCustomTest, ReserveTest) { EXPECT_EQ(0, CountCopyAndMove::Copy); } } +TEST(DenseSetCustomTest, ConstTest) { + // Test that const pointers work okay for count and find, even when the + // underlying map is a non-const pointer. + DenseSet Map; + int A; + int *B = &A; + const int *C = &A; + Map.insert(B); + EXPECT_EQ(Map.count(B), 1u); + EXPECT_EQ(Map.count(C), 1u); + EXPECT_NE(Map.find(B), Map.end()); + EXPECT_NE(Map.find(C), Map.end()); +} } -- GitLab