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 (Size != RHS.Size)
29 return false;
30 return memcmp(Data, RHS.Data, Size * sizeof(*Data)) == 0;
31}
32
34 if (Size != RHS.Size)
35 return Size < RHS.Size;
36 return memcmp(Data, RHS.Data, Size * sizeof(*Data)) < 0;
37}
38
39//===----------------------------------------------------------------------===//
40// FoldingSetNodeID Implementation
41
43 unsigned Size = String.size();
44
45 unsigned NumInserts = 1 + divideCeil(Size, 4);
46 Bits.reserve(Bits.size() + NumInserts);
47
48 Bits.push_back(Size);
49 if (!Size)
50 return;
51
52 unsigned Units = Size / 4;
53 unsigned Pos = 0;
54 const unsigned *Base = (const unsigned *)String.data();
55
56 // If the string is aligned do a bulk transfer.
57 if (!((intptr_t)Base & 3)) {
58 Bits.append(Base, Base + Units);
59 Pos = (Units + 1) * 4;
60 } else {
61 // Otherwise do it the hard way.
62 // To be compatible with above bulk transfer, we need to take endianness
63 // into account.
65 "Unexpected host endianness");
67 for (Pos += 4; Pos <= Size; Pos += 4) {
68 unsigned V = ((unsigned char)String[Pos - 4] << 24) |
69 ((unsigned char)String[Pos - 3] << 16) |
70 ((unsigned char)String[Pos - 2] << 8) |
71 (unsigned char)String[Pos - 1];
72 Bits.push_back(V);
73 }
74 } else { // Little-endian host
75 for (Pos += 4; Pos <= Size; Pos += 4) {
76 unsigned V = ((unsigned char)String[Pos - 1] << 24) |
77 ((unsigned char)String[Pos - 2] << 16) |
78 ((unsigned char)String[Pos - 3] << 8) |
79 (unsigned char)String[Pos - 4];
80 Bits.push_back(V);
81 }
82 }
83 }
84
85 // With the leftover bits.
86 unsigned V = 0;
87 // Pos will have overshot size by 4 - #bytes left over.
88 // No need to take endianness into account here - this is always executed.
89 switch (Pos - Size) {
90 case 1:
91 V = (V << 8) | (unsigned char)String[Size - 3];
92 [[fallthrough]];
93 case 2:
94 V = (V << 8) | (unsigned char)String[Size - 2];
95 [[fallthrough]];
96 case 3:
97 V = (V << 8) | (unsigned char)String[Size - 1];
98 break;
99 default:
100 return; // Nothing left.
101 }
102
103 Bits.push_back(V);
104}
105
107 Bits.append(ID.Bits.begin(), ID.Bits.end());
108}
109
111 return *this == FoldingSetNodeIDRef(RHS.Bits.data(), RHS.Bits.size());
112}
113
115 return FoldingSetNodeIDRef(Bits.data(), Bits.size()) == RHS;
116}
117
119 return *this < FoldingSetNodeIDRef(RHS.Bits.data(), RHS.Bits.size());
120}
121
123 return FoldingSetNodeIDRef(Bits.data(), Bits.size()) < RHS;
124}
125
128 unsigned *New = Allocator.Allocate<unsigned>(Bits.size());
129 llvm::uninitialized_copy(Bits, New);
130 return FoldingSetNodeIDRef(New, Bits.size());
131}
132
133//===----------------------------------------------------------------------===//
134/// Helper functions for FoldingSetBase.
135
136/// GetNextPtr - In order to save space, each bucket is a
137/// singly-linked-list. In order to make deletion more efficient, we make
138/// the list circular, so we can delete a node without computing its hash.
139/// The problem with this is that the start of the hash buckets are not
140/// Nodes. If NextInBucketPtr is a bucket pointer, this method returns null:
141/// use GetBucketPtr when this happens.
142static FoldingSetBase::Node *GetNextPtr(void *NextInBucketPtr) {
143 // The low bit is set if this is the pointer back to the bucket.
144 if (reinterpret_cast<intptr_t>(NextInBucketPtr) & 1)
145 return nullptr;
146
147 return static_cast<FoldingSetBase::Node *>(NextInBucketPtr);
148}
149
150/// GetBucketPtr - Provides a casting of a bucket pointer for isNode
151/// testing.
152static void **GetBucketPtr(void *NextInBucketPtr) {
153 intptr_t Ptr = reinterpret_cast<intptr_t>(NextInBucketPtr);
154 assert((Ptr & 1) && "Not a bucket pointer");
155 return reinterpret_cast<void **>(Ptr & ~intptr_t(1));
156}
157
158/// GetBucketFor - Hash the specified node ID and return the hash bucket for
159/// the specified ID.
160static void **GetBucketFor(unsigned Hash, void **Buckets, unsigned NumBuckets) {
161 // NumBuckets is always a power of 2.
162 unsigned BucketNum = Hash & (NumBuckets - 1);
163 return Buckets + BucketNum;
164}
165
166/// AllocateBuckets - Allocate initialized bucket memory.
167static void **AllocateBuckets(unsigned NumBuckets) {
168 void **Buckets =
169 static_cast<void **>(safe_calloc(NumBuckets + 1, sizeof(void *)));
170 // Set the very last bucket to be a non-null "pointer".
171 Buckets[NumBuckets] = reinterpret_cast<void *>(-1);
172 return Buckets;
173}
174
175//===----------------------------------------------------------------------===//
176// FoldingSetBase Implementation
177
178FoldingSetBase::FoldingSetBase(unsigned Log2InitSize) {
179 assert(5 < Log2InitSize && Log2InitSize < 32 &&
180 "Initial hash table size out of range");
181 NumBuckets = 1 << Log2InitSize;
183 NumNodes = 0;
184}
185
188 Arg.incrementEpoch();
189 Arg.Buckets = nullptr;
190 Arg.NumBuckets = 0;
191 Arg.NumNodes = 0;
192}
193
196 RHS.incrementEpoch();
197 free(Buckets); // This may be null if the set is in a moved-from state.
198 Buckets = RHS.Buckets;
199 NumBuckets = RHS.NumBuckets;
200 NumNodes = RHS.NumNodes;
201 RHS.Buckets = nullptr;
202 RHS.NumBuckets = 0;
203 RHS.NumNodes = 0;
204 return *this;
205}
206
208
211 // Set all but the last bucket to null pointers.
212 memset(Buckets, 0, NumBuckets * sizeof(void *));
213
214 // Set the very last bucket to be a non-null "pointer".
215 Buckets[NumBuckets] = reinterpret_cast<void *>(-1);
216
217 // Reset the node count to zero.
218 NumNodes = 0;
219}
220
221void FoldingSetBase::GrowBucketCount(unsigned NewBucketCount,
222 const FoldingSetInfo &Info) {
223 assert((NewBucketCount > NumBuckets) &&
224 "Can't shrink a folding set with GrowBucketCount");
225 assert(isPowerOf2_32(NewBucketCount) && "Bad bucket count!");
226
227 FoldingSetBase Tmp(llvm::Log2_32(NewBucketCount));
228 FoldingSetNodeID TempID;
229 for (unsigned i = 0; i != NumBuckets; ++i) {
230 void *Probe = Buckets[i];
231 if (!Probe)
232 continue;
233 while (Node *NodeInBucket = GetNextPtr(Probe)) {
234 // Figure out the next link, remove NodeInBucket from the old link.
235 Probe = NodeInBucket->getNextInBucket();
236 NodeInBucket->SetNextInBucket(nullptr);
237
238 // Insert the node into the new bucket, after recomputing the hash.
239 Tmp.InsertNode(
240 NodeInBucket,
241 GetBucketFor(Info.ComputeNodeHash(this, NodeInBucket, TempID),
242 Tmp.Buckets, Tmp.NumBuckets),
243 Info);
244 TempID.clear();
245 }
246 }
247
248 *this = std::move(Tmp);
249}
250
251void FoldingSetBase::reserve(unsigned EltCount, const FoldingSetInfo &Info) {
252 // This will give us somewhere between EltCount / 2 and
253 // EltCount buckets. This puts us in the load factor
254 // range of 1.0 - 2.0.
255 if (EltCount <= capacity())
256 return;
257 GrowBucketCount(llvm::bit_floor(EltCount), Info);
258}
259
261 const FoldingSetNodeID &ID, void *&InsertPos, const FoldingSetInfo &Info) {
262 unsigned IDHash = ID.ComputeHash();
263 void **Bucket = GetBucketFor(IDHash, Buckets, NumBuckets);
264 void *Probe = *Bucket;
265
266 InsertPos = nullptr;
267
268 FoldingSetNodeID TempID;
269 while (Node *NodeInBucket = GetNextPtr(Probe)) {
270 if (Info.NodeEquals(this, NodeInBucket, ID, IDHash, TempID))
271 return NodeInBucket;
272 TempID.clear();
273
274 Probe = NodeInBucket->getNextInBucket();
275 }
276
277 // Didn't find the node, return null with the bucket as the InsertPos.
278 InsertPos = Bucket;
279 return nullptr;
280}
281
282void FoldingSetBase::InsertNode(Node *N, void *InsertPos,
283 const FoldingSetInfo &Info) {
284 assert(!N->getNextInBucket());
286 // Do we need to grow the hashtable?
287 if (NumNodes + 1 > capacity()) {
288 GrowBucketCount(NumBuckets * 2, Info);
289 FoldingSetNodeID TempID;
290 InsertPos = GetBucketFor(Info.ComputeNodeHash(this, N, TempID), Buckets,
291 NumBuckets);
292 }
293
294 ++NumNodes;
295
296 /// The insert position is actually a bucket pointer.
297 void **Bucket = static_cast<void **>(InsertPos);
298
299 void *Next = *Bucket;
300
301 // If this is the first insertion into this bucket, its next pointer will be
302 // null. Pretend as if it pointed to itself, setting the low bit to indicate
303 // that it is a pointer to the bucket.
304 if (!Next)
305 Next = reinterpret_cast<void *>(reinterpret_cast<intptr_t>(Bucket) | 1);
306
307 // Set the node's next pointer, and make the bucket point to the node.
308 N->SetNextInBucket(Next);
309 *Bucket = N;
310}
311
313 // Because each bucket is a circular list, we don't need to compute N's hash
314 // to remove it.
315 void *Ptr = N->getNextInBucket();
316 if (!Ptr)
317 return false; // Not in folding set.
318
320 --NumNodes;
321 N->SetNextInBucket(nullptr);
322
323 // Remember what N originally pointed to, either a bucket or another node.
324 void *NodeNextPtr = Ptr;
325
326 // Chase around the list until we find the node (or bucket) which points to N.
327 while (true) {
328 if (Node *NodeInBucket = GetNextPtr(Ptr)) {
329 // Advance pointer.
330 Ptr = NodeInBucket->getNextInBucket();
331
332 // We found a node that points to N, change it to point to N's next node,
333 // removing N from the list.
334 if (Ptr == N) {
335 NodeInBucket->SetNextInBucket(NodeNextPtr);
336 return true;
337 }
338 } else {
339 void **Bucket = GetBucketPtr(Ptr);
340 Ptr = *Bucket;
341
342 // If we found that the bucket points to N, update the bucket to point to
343 // whatever is next.
344 if (Ptr == N) {
345 *Bucket = NodeNextPtr;
346 return true;
347 }
348 }
349 }
350}
351
355 Info.GetNodeProfile(this, N, ID);
356 void *IP;
357 if (Node *E = FindNodeOrInsertPos(ID, IP, Info))
358 return E;
359 InsertNode(N, IP, Info);
360 return N;
361}
362
363//===----------------------------------------------------------------------===//
364// FoldingSetIteratorImpl Implementation
365
367 void **Bucket)
368 : DebugEpochBase::HandleBase(Epoch) {
369 // Skip to the first non-null non-self-cycle bucket.
370 while (*Bucket != reinterpret_cast<void *>(-1) &&
371 (!*Bucket || !GetNextPtr(*Bucket)))
372 ++Bucket;
373
374 NodePtr = static_cast<FoldingSetNode *>(*Bucket);
375}
376
378 assert(isHandleInSync() && "invalid iterator access!");
379 // If there is another link within this bucket, go to it.
380 void *Probe = NodePtr->getNextInBucket();
381
382 if (FoldingSetNode *NextNodeInBucket = GetNextPtr(Probe))
383 NodePtr = NextNodeInBucket;
384 else {
385 // Otherwise, this is the last link in this bucket.
386 void **Bucket = GetBucketPtr(Probe);
387
388 // Skip to the next non-null non-self-cycle bucket.
389 do {
390 ++Bucket;
391 } while (*Bucket != reinterpret_cast<void *>(-1) &&
392 (!*Bucket || !GetNextPtr(*Bucket)));
393
394 NodePtr = static_cast<FoldingSetNode *>(*Bucket);
395 }
396}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file defines the BumpPtrAllocator interface.
static void ** GetBucketPtr(void *NextInBucketPtr)
GetBucketPtr - Provides a casting of a bucket pointer for isNode testing.
static void ** GetBucketFor(unsigned Hash, void **Buckets, unsigned NumBuckets)
GetBucketFor - Hash the specified node ID and return the hash bucket for the specified ID.
static void ** AllocateBuckets(unsigned NumBuckets)
AllocateBuckets - Allocate initialized bucket memory.
static FoldingSetBase::Node * GetNextPtr(void *NextInBucketPtr)
Helper functions for FoldingSetBase.
This file defines a hash set that can be used to remove duplication of nodes in a graph.
This file contains some templates that are useful if you are working with the STL at all.
This class is used to maintain the singly linked bucket list in a folding set.
Definition FoldingSet.h:320
Implements the folding set functionality.
Definition FoldingSet.h:299
void ** Buckets
Array of bucket chains.
Definition FoldingSet.h:302
LLVM_ABI void reserve(unsigned EltCount, const FoldingSetInfo &Info)
Grow the number of buckets so that we can hold at least EltCount nodes before rebucketing.
unsigned capacity() const
Returns the number of nodes permitted in the folding set before a rebucket operation is performed.
Definition FoldingSet.h:344
LLVM_ABI bool RemoveNode(Node *N)
Remove a node from the folding set, returning true if one was removed or false if the node was not in...
LLVM_ABI FoldingSetBase & operator=(FoldingSetBase &&RHS)
LLVM_ABI ~FoldingSetBase()
unsigned NumBuckets
Length of the Buckets array. Always a power of 2.
Definition FoldingSet.h:305
unsigned NumNodes
Number of nodes in the folding set.
Definition FoldingSet.h:309
LLVM_ABI Node * GetOrInsertNode(Node *N, const FoldingSetInfo &Info)
If there is an existing node exactly equal to the node N, return it.
LLVM_ABI void InsertNode(Node *N, void *InsertPos, const FoldingSetInfo &Info)
Insert the specified node into the folding set, knowing that it is not already in the folding set.
LLVM_ABI void clear()
Remove all nodes from the folding set.
LLVM_ABI Node * FindNodeOrInsertPos(const FoldingSetNodeID &ID, void *&InsertPos, const FoldingSetInfo &Info)
Look up the node specified by ID.
LLVM_ABI FoldingSetBase(unsigned Log2InitSize)
LLVM_ABI FoldingSetIteratorImpl(const DebugEpochBase *Epoch, void **Bucket)
This class describes a reference to an interned FoldingSetNodeID, which can be a useful to store node...
Definition FoldingSet.h:175
LLVM_ABI bool operator==(FoldingSetNodeIDRef) const
LLVM_ABI bool operator<(FoldingSetNodeIDRef) const
Used to compare the "ordering" of two nodes as defined by the profiled bits and their ordering define...
This class is used to gather all the unique data bits of a node.
Definition FoldingSet.h:212
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...
void clear()
Clear the accumulated profile, allowing this FoldingSetNodeID object to be used to compute a new prof...
Definition FoldingSet.h:257
LLVM_ABI bool operator==(const FoldingSetNodeID &RHS) const
operator== - Used to compare two nodes to each other.
LLVM_ABI bool operator<(const FoldingSetNodeID &RHS) const
Used to compare the "ordering" of two nodes as defined by the profiled bits and their ordering define...
LLVM_ABI void AddNodeID(const FoldingSetNodeID &ID)
LLVM_ABI void AddString(StringRef String)
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.
FoldingSetBase::Node FoldingSetNode
Definition FoldingSet.h:407
auto uninitialized_copy(R &&Src, IterTy Dst)
Definition STLExtras.h:2111
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 bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
Definition MathExtras.h:280
constexpr T divideCeil(U Numerator, V Denominator)
Returns the integer ceil(Numerator / Denominator).
Definition MathExtras.h:389
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Next
Definition InstrProf.h:147
BumpPtrAllocatorImpl<> BumpPtrAllocator
The standard BumpPtrAllocator which just uses the default template parameters.
Definition Allocator.h:390
T bit_floor(T Value)
Returns the largest integral power of two no greater than Value if Value is nonzero.
Definition bit.h:347
#define N
Functions provided by the derived class to compute folding properties.
Definition FoldingSet.h:354