[llvm] [DenseMap] memcpy buckets with trivial copy constructor and destructor. NFC (PR #224193)
Fangrui Song via llvm-commits
llvm-commits at lists.llvm.org
Wed Sep 16 22:55:59 PDT 2026
https://github.com/MaskRay updated https://github.com/llvm/llvm-project/pull/224193
>From 16a2e516d39b9bbba40fb32703642c4c5303bdab Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Wed, 16 Sep 2026 21:37:34 -0700
Subject: [PATCH 1/2] [DenseMap] memcpy buckets with trivial copy constructor
and destructor. NFC
std::pair has a user-provided copy assignment operator, so
std::is_trivially_copyable is false. Define is weaker
isRelocatableBucket instead.
This optimizes some DenseMap instantiations within lld (e.g.
lld/ELF/SyntheticSections.cpp)
---
llvm/include/llvm/ADT/DenseMap.h | 9 ++++++++-
llvm/unittests/ADT/DenseMapTest.cpp | 4 ++++
2 files changed, 12 insertions(+), 1 deletion(-)
diff --git a/llvm/include/llvm/ADT/DenseMap.h b/llvm/include/llvm/ADT/DenseMap.h
index 0126935ca3598..56c56c489915e 100644
--- a/llvm/include/llvm/ADT/DenseMap.h
+++ b/llvm/include/llvm/ADT/DenseMap.h
@@ -88,6 +88,13 @@ template <typename KeyT, typename ValueT> struct DenseMapPair {
} // end namespace detail
namespace densemap::detail {
+// Relocating copy-constructs and runs no destructor, so it does not need
+// trivial assignment, which a std::pair value type lacks.
+template <typename BucketT>
+inline constexpr bool isRelocatableBucket =
+ std::is_trivially_copy_constructible_v<BucketT> &&
+ std::is_trivially_destructible_v<BucketT>;
+
using UsedT = uint32_t;
// Number of used words backing N buckets where N is zero or a power of two.
@@ -596,7 +603,7 @@ class DenseMapBase : public DebugEpochBase {
const UsedT *OtherU = other.getUsed();
std::memcpy(U, OtherU,
llvm::densemap::detail::usedWords(NumBuckets) * sizeof(UsedT));
- if constexpr (std::is_trivially_copyable_v<BucketT>) {
+ if constexpr (densemap::detail::isRelocatableBucket<BucketT>) {
memcpy(reinterpret_cast<void *>(Buckets), OtherBuckets,
NumBuckets * sizeof(BucketT));
} else {
diff --git a/llvm/unittests/ADT/DenseMapTest.cpp b/llvm/unittests/ADT/DenseMapTest.cpp
index 9ff486cbc2cff..abdd9657fecd9 100644
--- a/llvm/unittests/ADT/DenseMapTest.cpp
+++ b/llvm/unittests/ADT/DenseMapTest.cpp
@@ -475,10 +475,14 @@ TEST(DenseMapCustomTest, EqualityComparison) {
}
using IntBucket = detail::DenseMapPair<int, int>;
+using PairKeyBucket = detail::DenseMapPair<std::pair<int, int>, int>;
static_assert(std::is_trivially_copyable_v<IntBucket>);
static_assert(!std::is_trivially_default_constructible_v<IntBucket>);
+static_assert(!std::is_trivially_copyable_v<PairKeyBucket>);
+static_assert(densemap::detail::isRelocatableBucket<PairKeyBucket>);
+
// A bucket converts to a std::pair, so code naming the pair type keeps working.
static_assert(std::is_convertible_v<IntBucket, std::pair<int, int>>);
static_assert(std::is_convertible_v<IntBucket, std::pair<const int, int>>);
>From 5d26ef34030d631f9c436a1294cf6a41a8a98434 Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Wed, 16 Sep 2026 22:55:47 -0700
Subject: [PATCH 2/2] Update llvm/unittests/ADT/DenseMapTest.cpp
Co-authored-by: Kazu Hirata <kazu at google.com>
---
llvm/unittests/ADT/DenseMapTest.cpp | 3 +++
1 file changed, 3 insertions(+)
diff --git a/llvm/unittests/ADT/DenseMapTest.cpp b/llvm/unittests/ADT/DenseMapTest.cpp
index abdd9657fecd9..f593db284963e 100644
--- a/llvm/unittests/ADT/DenseMapTest.cpp
+++ b/llvm/unittests/ADT/DenseMapTest.cpp
@@ -476,6 +476,9 @@ TEST(DenseMapCustomTest, EqualityComparison) {
using IntBucket = detail::DenseMapPair<int, int>;
using PairKeyBucket = detail::DenseMapPair<std::pair<int, int>, int>;
+using PairValueBucket = detail::DenseMapPair<int, std::pair<int, int>>;
+using PairPairBucket =
+ detail::DenseMapPair<std::pair<int, int>, std::pair<int, int>>;
static_assert(std::is_trivially_copyable_v<IntBucket>);
static_assert(!std::is_trivially_default_constructible_v<IntBucket>);
More information about the llvm-commits
mailing list