diff options
author | Fangrui Song <i@maskray.me> | 2024-07-25 14:07:31 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-07-25 14:07:31 -0700 |
commit | c9e5af3944e85c5f1272c48522b4e9eda398b462 (patch) | |
tree | aaaf5cfee15044ca2a7cdde1447130951ab0084b /llvm | |
parent | 4aa4ee909029cd7cd85d67b41d488a6edb802dce (diff) | |
download | llvm-c9e5af3944e85c5f1272c48522b4e9eda398b462.zip llvm-c9e5af3944e85c5f1272c48522b4e9eda398b462.tar.gz llvm-c9e5af3944e85c5f1272c48522b4e9eda398b462.tar.bz2 |
[DenseMap] Optimize find/erase
`LookupBucketFor` is used for `find`, `insert`, `erase`, and their
variants. While tombstone comparison isn't needed by `find`/`erase`,
`LookupBucketFor` calls `getTombstoneKey` regardless, which might have
an opaque implementation or just not optimized out, leading to
unnecessary overhead for `find` and `erase`.
Pull Request: https://github.com/llvm/llvm-project/pull/100517
Diffstat (limited to 'llvm')
-rw-r--r-- | llvm/include/llvm/ADT/DenseMap.h | 80 |
1 files changed, 49 insertions, 31 deletions
diff --git a/llvm/include/llvm/ADT/DenseMap.h b/llvm/include/llvm/ADT/DenseMap.h index 7ccc944..67d474d 100644 --- a/llvm/include/llvm/ADT/DenseMap.h +++ b/llvm/include/llvm/ADT/DenseMap.h @@ -143,8 +143,7 @@ public: /// Return true if the specified key is in the map, false otherwise. bool contains(const_arg_type_t<KeyT> Val) const { - const BucketT *TheBucket; - return LookupBucketFor(Val, TheBucket); + return doFind(Val) != nullptr; } /// Return 1 if the specified key is in the map, 0 otherwise. @@ -153,21 +152,17 @@ public: } iterator find(const_arg_type_t<KeyT> Val) { - BucketT *TheBucket; - if (LookupBucketFor(Val, TheBucket)) - return makeIterator(TheBucket, - shouldReverseIterate<KeyT>() ? getBuckets() - : getBucketsEnd(), - *this, true); + if (BucketT *Bucket = doFind(Val)) + return makeIterator( + Bucket, shouldReverseIterate<KeyT>() ? getBuckets() : getBucketsEnd(), + *this, true); return end(); } const_iterator find(const_arg_type_t<KeyT> Val) const { - const BucketT *TheBucket; - if (LookupBucketFor(Val, TheBucket)) - return makeConstIterator(TheBucket, - shouldReverseIterate<KeyT>() ? getBuckets() - : getBucketsEnd(), - *this, true); + if (const BucketT *Bucket = doFind(Val)) + return makeConstIterator( + Bucket, shouldReverseIterate<KeyT>() ? getBuckets() : getBucketsEnd(), + *this, true); return end(); } @@ -178,31 +173,26 @@ public: /// type used. template<class LookupKeyT> iterator find_as(const LookupKeyT &Val) { - BucketT *TheBucket; - if (LookupBucketFor(Val, TheBucket)) - return makeIterator(TheBucket, - shouldReverseIterate<KeyT>() ? getBuckets() - : getBucketsEnd(), - *this, true); + if (BucketT *Bucket = doFind(Val)) + return makeIterator( + Bucket, shouldReverseIterate<KeyT>() ? getBuckets() : getBucketsEnd(), + *this, true); return end(); } template<class LookupKeyT> const_iterator find_as(const LookupKeyT &Val) const { - const BucketT *TheBucket; - if (LookupBucketFor(Val, TheBucket)) - return makeConstIterator(TheBucket, - shouldReverseIterate<KeyT>() ? getBuckets() - : getBucketsEnd(), - *this, true); + if (const BucketT *Bucket = doFind(Val)) + return makeConstIterator( + Bucket, shouldReverseIterate<KeyT>() ? getBuckets() : getBucketsEnd(), + *this, true); return end(); } /// lookup - Return the entry for the specified key, or a default /// constructed value if no such entry exists. ValueT lookup(const_arg_type_t<KeyT> Val) const { - const BucketT *TheBucket; - if (LookupBucketFor(Val, TheBucket)) - return TheBucket->getSecond(); + if (const BucketT *Bucket = doFind(Val)) + return Bucket->getSecond(); return ValueT(); } @@ -343,8 +333,8 @@ public: } bool erase(const KeyT &Val) { - BucketT *TheBucket; - if (!LookupBucketFor(Val, TheBucket)) + BucketT *TheBucket = doFind(Val); + if (!TheBucket) return false; // not in map. TheBucket->getSecond().~ValueT(); @@ -643,6 +633,34 @@ private: return TheBucket; } + template <typename LookupKeyT> BucketT *doFind(const LookupKeyT &Val) { + BucketT *BucketsPtr = getBuckets(); + const unsigned NumBuckets = getNumBuckets(); + if (NumBuckets == 0) + return nullptr; + + const KeyT EmptyKey = getEmptyKey(); + unsigned BucketNo = getHashValue(Val) & (NumBuckets - 1); + unsigned ProbeAmt = 1; + while (true) { + BucketT *Bucket = BucketsPtr + BucketNo; + if (LLVM_LIKELY(KeyInfoT::isEqual(Val, Bucket->getFirst()))) + return Bucket; + if (LLVM_LIKELY(KeyInfoT::isEqual(Bucket->getFirst(), EmptyKey))) + return nullptr; + + // Otherwise, it's a hash collision or a tombstone, continue quadratic + // probing. + BucketNo += ProbeAmt++; + BucketNo &= NumBuckets - 1; + } + } + + template <typename LookupKeyT> + const BucketT *doFind(const LookupKeyT &Val) const { + return const_cast<DenseMapBase *>(this)->doFind(Val); // NOLINT + } + /// LookupBucketFor - Lookup the appropriate bucket for Val, returning it in /// FoundBucket. If the bucket contains the key and a value, this returns /// true, otherwise it returns a bucket with an empty marker or tombstone and |