| //===----------------------------------------------------------------------===// | |
| // | |
| // 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); | |
| } | |
| } | |
| void densemap::detail::rehashRelocatable(void *Dst, UsedT *DstUsed, | |
| unsigned DstNumBuckets, | |
| const void *Src, const UsedT *SrcUsed, | |
| unsigned SrcNumBuckets, | |
| size_t BucketSize, | |
| BucketHasher Hasher) { | |
| const unsigned Mask = DstNumBuckets - 1; | |
| if (!Hasher) | |
| return rehashBySize<true>(Dst, DstUsed, Mask, Src, SrcUsed, SrcNumBuckets, | |
| BucketSize, Hasher); | |
| return rehashBySize<false>(Dst, DstUsed, Mask, Src, SrcUsed, SrcNumBuckets, | |
| BucketSize, Hasher); | |
| } | |
| void *densemap::detail::growRelocatable(void *OldBuckets, const UsedT *OldUsed, | |
| unsigned OldNumBuckets, | |
| unsigned NewNumBuckets, | |
| size_t BucketSize, size_t Align, | |
| BucketHasher Hasher, bool FreeOld) { | |
| void *Storage = allocate_buffer(allocBytes(BucketSize, NewNumBuckets), Align); | |
| UsedT *NewUsed = usedFor(Storage, BucketSize, NewNumBuckets); | |
| clearUsed(NewUsed, NewNumBuckets); | |
| if (OldNumBuckets) { | |
| rehashRelocatable(Storage, NewUsed, NewNumBuckets, OldBuckets, OldUsed, | |
| OldNumBuckets, BucketSize, Hasher); | |
| if (FreeOld) | |
| deallocate_buffer(OldBuckets, allocBytes(BucketSize, OldNumBuckets), | |
| Align); | |
| } | |
| return Storage; | |
| } |