[llvm] [DenseMap] Share rehash and grow for relocatable bucket types. NFC (PR #225018)
Alexis Engelke via llvm-commits
llvm-commits at lists.llvm.org
Mon Sep 21 00:17:52 PDT 2026
================
@@ -0,0 +1,101 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/Support/MemAlloc.h"
+#include <cstring>
+
+using namespace llvm;
+using namespace llvm::densemap;
+using namespace llvm::densemap::detail;
+
+// A nonzero FixedSize turns the bucket copy into a couple of stores.
+template <size_t FixedSize, bool InlinePtrHash>
+static void rehashLoop(void *DstBuckets, UsedT *DstUsed, unsigned Mask,
+ const void *SrcBuckets, const UsedT *SrcUsed,
+ unsigned SrcNumBuckets, size_t RuntimeSize,
+ BucketHasher Hasher) {
+ const size_t BucketSize = FixedSize ? FixedSize : RuntimeSize;
+ char *Dst = static_cast<char *>(DstBuckets);
+ const char *Src = static_cast<const char *>(SrcBuckets);
+ forEachUsed(SrcUsed, SrcNumBuckets, [&](unsigned I) {
+ const char *SrcBucket = Src + static_cast<size_t>(I) * BucketSize;
+ unsigned Hash;
+ if constexpr (InlinePtrHash) {
+ void *Key;
+ std::memcpy(&Key, SrcBucket, sizeof(Key));
+ Hash = DenseMapInfo<void *>::getHashValue(Key);
+ } else {
+ Hash = Hasher(SrcBucket);
+ }
+ unsigned BucketNo = Hash & Mask;
+ while (used(DstUsed, BucketNo))
+ BucketNo = (BucketNo + 1) & Mask;
+ std::memcpy(Dst + static_cast<size_t>(BucketNo) * BucketSize, SrcBucket,
+ BucketSize);
+ setUsed(DstUsed, BucketNo);
+ });
+}
+
+template <bool InlinePtrHash>
+static void rehashBySize(void *Dst, UsedT *DstUsed, unsigned Mask,
+ const void *Src, const UsedT *SrcUsed,
+ unsigned SrcNumBuckets, size_t BucketSize,
+ BucketHasher Hasher) {
+ // The bucket sizes of 95% of the grow instantiations in an LLVM build.
+ switch (BucketSize) {
+#define REHASH_CASE(N) \
+ case N: \
+ return rehashLoop<N, InlinePtrHash>(Dst, DstUsed, Mask, Src, SrcUsed, \
+ SrcNumBuckets, BucketSize, Hasher);
+ REHASH_CASE(4)
+ REHASH_CASE(8)
+ REHASH_CASE(12)
+ REHASH_CASE(16)
+ REHASH_CASE(24)
+ REHASH_CASE(32)
+ REHASH_CASE(40)
+ REHASH_CASE(48)
+#undef REHASH_CASE
+ default:
+ return rehashLoop<0, InlinePtrHash>(Dst, DstUsed, Mask, Src, SrcUsed,
+ SrcNumBuckets, BucketSize, Hasher);
+ }
----------------
aengelke wrote:
In my experience (haven't checked this instance), LLVM is bad at lowering switches of calls (it generates a jump table to jumps). I had better experience with function pointer tables. Unless of course all these function calls get inlined? (What does the generated code look like here?)
https://github.com/llvm/llvm-project/pull/225018
More information about the llvm-commits
mailing list