[llvm] [SmallPtrSet] Optimize Grow and inline FindBucketFor. NFC (PR #206304)
via llvm-commits
llvm-commits at lists.llvm.org
Sat Jun 27 22:04:30 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-support
Author: Fangrui Song (MaskRay)
<details>
<summary>Changes</summary>
During rehashing every key is known absent, so skip the equal-key comparison.
DenseMap got a similar optimization in #<!-- -->200595
FindBucketFor is then only used by insert_imp_big; inline its probe loop
there. The loop takes 7 inst instead of 9 in the clang-generated
assembly after removing the two `LLVM_LIKELY`.
---
Full diff: https://github.com/llvm/llvm-project/pull/206304.diff
2 Files Affected:
- (modified) llvm/include/llvm/ADT/SmallPtrSet.h (-1)
- (modified) llvm/lib/Support/SmallPtrSet.cpp (+22-24)
``````````diff
diff --git a/llvm/include/llvm/ADT/SmallPtrSet.h b/llvm/include/llvm/ADT/SmallPtrSet.h
index d7b4bbf6bd64f..d685279d3c31b 100644
--- a/llvm/include/llvm/ADT/SmallPtrSet.h
+++ b/llvm/include/llvm/ADT/SmallPtrSet.h
@@ -245,7 +245,6 @@ class SmallPtrSetImplBase : public DebugEpochBase {
LLVM_ABI std::pair<const void *const *, bool> insert_imp_big(const void *Ptr);
LLVM_ABI const void *const *doFind(const void *Ptr) const;
- const void *const *FindBucketFor(const void *Ptr) const;
LLVM_ABI void shrink_and_clear();
protected:
diff --git a/llvm/lib/Support/SmallPtrSet.cpp b/llvm/lib/Support/SmallPtrSet.cpp
index d8e66b9c89c74..265b8eba4076d 100644
--- a/llvm/lib/Support/SmallPtrSet.cpp
+++ b/llvm/lib/Support/SmallPtrSet.cpp
@@ -44,16 +44,21 @@ SmallPtrSetImplBase::insert_imp_big(const void *Ptr) {
Grow(CurArraySize < 64 ? 128 : CurArraySize * 2);
}
- // Okay, we know we have space. Find a hash bucket.
- const void **Bucket = const_cast<const void**>(FindBucketFor(Ptr));
- if (*Bucket == Ptr)
- return {Bucket, false}; // Already inserted, good.
+ // Find the first empty bucket or Ptr itself on the probe chain.
+ unsigned Mask = CurArraySize - 1;
+ unsigned I = DenseMapInfo<void *>::getHashValue(Ptr) & Mask;
+ const void **Array = CurArray;
+ while (Array[I] != getEmptyMarker()) {
+ if (Array[I] == Ptr)
+ return {Array + I, false};
+ I = (I + 1) & Mask;
+ }
- // Otherwise, insert it.
+ // Insert into the empty bucket.
++NumEntries;
- *Bucket = Ptr;
+ Array[I] = Ptr;
incrementEpoch();
- return {Bucket, true};
+ return {Array + I, true};
}
const void *const *SmallPtrSetImplBase::doFind(const void *Ptr) const {
@@ -69,19 +74,6 @@ const void *const *SmallPtrSetImplBase::doFind(const void *Ptr) const {
}
}
-const void *const *SmallPtrSetImplBase::FindBucketFor(const void *Ptr) const {
- unsigned Mask = CurArraySize - 1;
- unsigned Bucket = DenseMapInfo<void *>::getHashValue(Ptr) & Mask;
- const void *const *Array = CurArray;
- while (true) {
- if (LLVM_LIKELY(Array[Bucket] == getEmptyMarker()))
- return Array + Bucket;
- if (LLVM_LIKELY(Array[Bucket] == Ptr))
- return Array + Bucket;
- Bucket = (Bucket + 1) & Mask;
- }
-}
-
void SmallPtrSetImplBase::eraseFromBucket(const void **Bucket) {
// Knuth TAOCP 6.4 Algorithm R: walk forward sliding each following entry
// whose probe path crosses the hole.
@@ -114,10 +106,16 @@ void SmallPtrSetImplBase::Grow(unsigned NewSize) {
memset(CurArray, -1, NewSize*sizeof(void*));
// Copy over all valid entries.
- for (const void *&Bucket : OldBuckets) {
- // Copy over the element if it is valid.
- if (Bucket != getEmptyMarker())
- *const_cast<void **>(FindBucketFor(Bucket)) = const_cast<void *>(Bucket);
+ unsigned Mask = CurArraySize - 1;
+ for (const void *Ptr : OldBuckets) {
+ if (Ptr == getEmptyMarker())
+ continue;
+ // Find the first empty bucket on this key's probe chain; there is no equal
+ // key, so nothing to compare against.
+ unsigned I = DenseMapInfo<void *>::getHashValue(Ptr) & Mask;
+ while (NewBuckets[I] != getEmptyMarker())
+ I = (I + 1) & Mask;
+ NewBuckets[I] = Ptr;
}
if (!WasSmall)
``````````
</details>
https://github.com/llvm/llvm-project/pull/206304
More information about the llvm-commits
mailing list