aboutsummaryrefslogtreecommitdiff
path: root/llvm
diff options
context:
space:
mode:
authorFangrui Song <i@maskray.me>2024-07-25 14:07:31 -0700
committerGitHub <noreply@github.com>2024-07-25 14:07:31 -0700
commitc9e5af3944e85c5f1272c48522b4e9eda398b462 (patch)
treeaaaf5cfee15044ca2a7cdde1447130951ab0084b /llvm
parent4aa4ee909029cd7cd85d67b41d488a6edb802dce (diff)
downloadllvm-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.h80
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