LLVM 24.0.0git
FoldingSet.cpp
Go to the documentation of this file.
1//===-- Support/FoldingSet.cpp - Uniquing Hash Set --------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements a hash set that can be used to remove duplication of
10// nodes in a graph.
11//
12//===----------------------------------------------------------------------===//
13
14#include "llvm/ADT/FoldingSet.h"
15#include "llvm/ADT/STLExtras.h"
16#include "llvm/ADT/StringRef.h"
20#include <cassert>
21#include <cstring>
22using namespace llvm;
23
24//===----------------------------------------------------------------------===//
25// FoldingSetNodeIDRef Implementation
26
28 if (LHS.size() != RHS.size())
29 return LHS.size() < RHS.size();
30 return memcmp(LHS.data(), RHS.data(), LHS.size() * sizeof(unsigned)) < 0;
31}
32
33//===----------------------------------------------------------------------===//
34// FoldingSetNodeID Implementation
35
37 unsigned Size = String.size();
38
39 unsigned NumInserts = 1 + divideCeil(Size, 4);
40 Bits.reserve(Bits.size() + NumInserts);
41
42 Bits.push_back(Size);
43 if (!Size)
44 return;
45
46 unsigned Units = Size / 4;
47 unsigned Pos = 0;
48 const unsigned *Base = (const unsigned *)String.data();
49
50 // If the string is aligned do a bulk transfer.
51 if (!((intptr_t)Base & 3)) {
52 Bits.append(Base, Base + Units);
53 Pos = (Units + 1) * 4;
54 } else {
55 // Otherwise do it the hard way.
56 // To be compatible with above bulk transfer, we need to take endianness
57 // into account.
59 "Unexpected host endianness");
61 for (Pos += 4; Pos <= Size; Pos += 4) {
62 unsigned V = ((unsigned char)String[Pos - 4] << 24) |
63 ((unsigned char)String[Pos - 3] << 16) |
64 ((unsigned char)String[Pos - 2] << 8) |
65 (unsigned char)String[Pos - 1];
66 Bits.push_back(V);
67 }
68 } else { // Little-endian host
69 for (Pos += 4; Pos <= Size; Pos += 4) {
70 unsigned V = ((unsigned char)String[Pos - 1] << 24) |
71 ((unsigned char)String[Pos - 2] << 16) |
72 ((unsigned char)String[Pos - 3] << 8) |
73 (unsigned char)String[Pos - 4];
74 Bits.push_back(V);
75 }
76 }
77 }
78
79 // With the leftover bits.
80 unsigned V = 0;
81 // Pos will have overshot size by 4 - #bytes left over.
82 // No need to take endianness into account here - this is always executed.
83 switch (Pos - Size) {
84 case 1:
85 V = (V << 8) | (unsigned char)String[Size - 3];
86 [[fallthrough]];
87 case 2:
88 V = (V << 8) | (unsigned char)String[Size - 2];
89 [[fallthrough]];
90 case 3:
91 V = (V << 8) | (unsigned char)String[Size - 1];
92 break;
93 default:
94 return; // Nothing left.
95 }
96
97 Bits.push_back(V);
98}
99
101 Bits.append(ID.Bits.begin(), ID.Bits.end());
102}
103
106 unsigned *New = Allocator.Allocate<unsigned>(Bits.size());
107 llvm::uninitialized_copy(Bits, New);
108 return FoldingSetNodeIDRef(New, Bits.size());
109}
110
111//===----------------------------------------------------------------------===//
112// FoldingSetBase Implementation
113
114FoldingSetBase::FoldingSetBase(unsigned Log2InitSize) {
115 assert(5 < Log2InitSize && Log2InitSize < 32 &&
116 "Initial hash table size out of range");
117 NumBuckets = 1 << Log2InitSize;
118 Buckets = static_cast<FoldingSetNode **>(
120}
121
123 : Buckets(std::exchange(Arg.Buckets, nullptr)),
124 NumBuckets(std::exchange(Arg.NumBuckets, 0)),
125 NumNodes(std::exchange(Arg.NumNodes, 0)) {
126 Arg.incrementEpoch();
127}
128
130 if (this == &RHS)
131 return *this;
132
134 RHS.incrementEpoch();
135 free(Buckets); // This may be null if the set is in a moved-from state.
136 Buckets = std::exchange(RHS.Buckets, nullptr);
137 NumBuckets = std::exchange(RHS.NumBuckets, 0);
138 NumNodes = std::exchange(RHS.NumNodes, 0);
139 return *this;
140}
141
143
146 // Stale hashes are unreachable, so only the occupancy needs resetting.
147 if (NumBuckets)
148 memset(Buckets, 0, NumBuckets * sizeof(FoldingSetNode *));
149 NumNodes = 0;
150}
151
152void FoldingSetBase::placeNode(FoldingSetNode *N, uint32_t Hash) {
153 unsigned Mask = NumBuckets - 1;
154 unsigned I = Hash & Mask;
155 while (Buckets[I]) {
156 assert(Buckets[I] != N && "Node already in the folding set");
157 I = (I + 1) & Mask;
158 }
159 Buckets[I] = N;
160 ++NumNodes;
161}
162
163void FoldingSetBase::grow(unsigned MinNumBuckets) {
164 // The floor is the smallest size the constructor accepts.
165 unsigned NewBucketCount = std::max(64u, llvm::bit_ceil(MinNumBuckets));
166 assert(NewBucketCount > NumBuckets && "Can't shrink a folding set");
167
168 FoldingSetBase Tmp(llvm::Log2_32(NewBucketCount));
169 for (unsigned I = 0; I != NumBuckets; ++I)
170 if (FoldingSetNode *N = Buckets[I])
171 Tmp.placeNode(N, N->getFoldingSetHash());
172
173 *this = std::move(Tmp);
174}
175
177 if (N * 4 <= NumBuckets * 3)
178 return;
179 // N + (N + 2) / 3 is ceil(4N/3).
180 grow(N + (N + 2) / 3);
181}
182
184 assert(N && "Cannot insert a null node");
185 assert(Token && "Invalid token!");
187 if (LLVM_UNLIKELY((NumNodes + 1) * 4 > NumBuckets * 3))
188 grow(NumBuckets * 2);
189 uint32_t Hash = Token.Hash;
190 placeNode(N, Hash);
191 N->setFoldingSetHash(Hash);
192}
193
195 uint32_t Hash = N->getFoldingSetHash();
197 return false; // Never inserted.
198
199 unsigned Mask = NumBuckets - 1;
200 unsigned I = Hash & Mask;
201 while (Buckets[I] != N) {
202 if (LLVM_UNLIKELY(!Buckets[I]))
203 return false; // Not in folding set.
204 I = (I + 1) & Mask;
205 }
206
208
209 // Knuth TAOCP 6.4 Algorithm R: walk forward sliding each following entry
210 // whose probe path crosses the hole.
211 for (unsigned J = (I + 1) & Mask; Buckets[J]; J = (J + 1) & Mask) {
212 unsigned Ideal = Buckets[J]->getFoldingSetHash();
213 if (((I - Ideal) & Mask) < ((J - Ideal) & Mask)) {
214 Buckets[I] = Buckets[J];
215 I = J;
216 }
217 }
218 Buckets[I] = nullptr;
219 N->setFoldingSetHash(FoldingSetNodeIDRef::NotAHash);
220 --NumNodes;
221 return true;
222}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file defines the BumpPtrAllocator interface.
#define LLVM_UNLIKELY(EXPR)
Definition Compiler.h:344
This file defines a hash set that can be used to remove duplication of nodes in a graph.
#define I(x, y, z)
Definition MD5.cpp:57
This file contains some templates that are useful if you are working with the STL at all.
LLVM_ABI bool erase(FoldingSetNode *N)
Remove a node from the folding set, returning true if one was removed or false if the node was not in...
FoldingSetNode ** Buckets
Array of node pointers; a null entry marks an empty slot.
Definition FoldingSet.h:374
LLVM_ABI FoldingSetBase & operator=(FoldingSetBase &&RHS)
LLVM_ABI ~FoldingSetBase()
unsigned NumBuckets
Length of the Buckets array. Always a power of 2.
Definition FoldingSet.h:377
unsigned NumNodes
Number of nodes in the folding set.
Definition FoldingSet.h:380
LLVM_ABI void insert(FoldingSetNode *N, FoldingSetInsertToken Token)
Insert the specified node into the folding set, knowing that it is not already in the folding set.
LLVM_ABI void reserve(unsigned N)
Grow the number of buckets so that we can hold at least N nodes before rebucketing.
LLVM_ABI void clear()
Remove all nodes from the folding set.
LLVM_ABI FoldingSetBase(unsigned Log2InitSize)
Insertion token: a failed lookup fills it in, the matching insert consumes it.
Definition FoldingSet.h:284
This class describes a reference to an interned FoldingSetNodeID, which can be a useful to store node...
Definition FoldingSet.h:123
static constexpr unsigned NotAHash
Definition FoldingSet.h:127
LLVM_ABI FoldingSetNodeIDRef Intern(BumpPtrAllocator &Allocator) const
Copy this node's data to a memory region allocated from the given allocator and return a FoldingSetNo...
LLVM_ABI void AddNodeID(const FoldingSetNodeID &ID)
LLVM_ABI void AddString(StringRef String)
This class is used to maintain node state in a folding set.
Definition FoldingSet.h:309
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
constexpr bool IsLittleEndianHost
constexpr bool IsBigEndianHost
This is an optimization pass for GlobalISel generic memory operations.
bool operator<(int64_t V1, const APSInt &V2)
Definition APSInt.h:360
auto uninitialized_copy(R &&Src, IterTy Dst)
Definition STLExtras.h:2111
T bit_ceil(T Value)
Returns the smallest integral power of two no smaller than Value if Value is nonzero.
Definition bit.h:362
LLVM_ATTRIBUTE_RETURNS_NONNULL void * safe_calloc(size_t Count, size_t Sz)
Definition MemAlloc.h:38
unsigned Log2_32(uint32_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
Definition MathExtras.h:326
constexpr T divideCeil(U Numerator, V Denominator)
Returns the integer ceil(Numerator / Denominator).
Definition MathExtras.h:389
BumpPtrAllocatorImpl<> BumpPtrAllocator
The standard BumpPtrAllocator which just uses the default template parameters.
Definition Allocator.h:390
Implement std::hash so that hash_code can be used in STL containers.
Definition BitVector.h:878
#define N