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 Size < RHS.Size;
30 return memcmp(Data, RHS.Data, Size * sizeof(*Data)) < 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
105 return *this < FoldingSetNodeIDRef(RHS.Bits.data(), RHS.Bits.size());
106}
107
109 return FoldingSetNodeIDRef(Bits.data(), Bits.size()) < RHS;
110}
111
114 unsigned *New = Allocator.Allocate<unsigned>(Bits.size());
115 llvm::uninitialized_copy(Bits, New);
116 return FoldingSetNodeIDRef(New, Bits.size());
117}
118
119//===----------------------------------------------------------------------===//
120// FoldingSetBase Implementation
121
122FoldingSetBase::FoldingSetBase(unsigned Log2InitSize) {
123 assert(5 < Log2InitSize && Log2InitSize < 32 &&
124 "Initial hash table size out of range");
125 NumBuckets = 1 << Log2InitSize;
126 Buckets = static_cast<void **>(safe_calloc(NumBuckets, sizeof(void *)));
127}
128
130 : Buckets(std::exchange(Arg.Buckets, nullptr)),
131 NumBuckets(std::exchange(Arg.NumBuckets, 0)),
132 NumNodes(std::exchange(Arg.NumNodes, 0)) {
133 Arg.incrementEpoch();
134}
135
137 if (this == &RHS)
138 return *this;
139
141 RHS.incrementEpoch();
142 free(Buckets); // This may be null if the set is in a moved-from state.
143 Buckets = std::exchange(RHS.Buckets, nullptr);
144 NumBuckets = std::exchange(RHS.NumBuckets, 0);
145 NumNodes = std::exchange(RHS.NumNodes, 0);
146 return *this;
147}
148
150
153 // Stale hashes are unreachable, so only the occupancy needs resetting.
154 if (NumBuckets)
155 memset(Buckets, 0, NumBuckets * sizeof(void *));
156 NumNodes = 0;
157}
158
159void FoldingSetBase::placeNode(Node *N, uint32_t Hash) {
160 unsigned Mask = NumBuckets - 1;
161 unsigned I = Hash & Mask;
162 while (Buckets[I]) {
163 assert(Buckets[I] != N && "Node already in the folding set");
164 I = (I + 1) & Mask;
165 }
166 Buckets[I] = N;
167 ++NumNodes;
168}
169
170void FoldingSetBase::grow(unsigned MinNumBuckets) {
171 // The floor is the smallest size the constructor accepts.
172 unsigned NewBucketCount = std::max(64u, llvm::bit_ceil(MinNumBuckets));
173 assert(NewBucketCount > NumBuckets && "Can't shrink a folding set");
174
175 FoldingSetBase Tmp(llvm::Log2_32(NewBucketCount));
176 for (unsigned I = 0; I != NumBuckets; ++I)
177 if (void *N = Buckets[I])
178 Tmp.placeNode(static_cast<Node *>(N),
179 static_cast<Node *>(N)->getFoldingSetHash());
180
181 *this = std::move(Tmp);
182}
183
185 if (N * 4 <= NumBuckets * 3)
186 return;
187 // N + (N + 2) / 3 is ceil(4N/3).
188 grow(N + (N + 2) / 3);
189}
190
192 assert(N && "Cannot insert a null node");
193 assert(Token && "Invalid token!");
195 if (LLVM_UNLIKELY((NumNodes + 1) * 4 > NumBuckets * 3))
196 grow(NumBuckets * 2);
197 uint32_t Hash = Token.Hash;
198 placeNode(N, Hash);
199 N->setFoldingSetHash(Hash);
200}
201
203 uint32_t Hash = N->getFoldingSetHash();
205 return false; // Never inserted.
206
207 unsigned Mask = NumBuckets - 1;
208 unsigned I = Hash & Mask;
209 while (Buckets[I] != N) {
210 if (LLVM_UNLIKELY(!Buckets[I]))
211 return false; // Not in folding set.
212 I = (I + 1) & Mask;
213 }
214
216
217 // Knuth TAOCP 6.4 Algorithm R: walk forward sliding each following entry
218 // whose probe path crosses the hole.
219 for (unsigned J = (I + 1) & Mask; Buckets[J]; J = (J + 1) & Mask) {
220 unsigned Ideal = static_cast<Node *>(Buckets[J])->getFoldingSetHash();
221 if (((I - Ideal) & Mask) < ((J - Ideal) & Mask)) {
222 Buckets[I] = Buckets[J];
223 I = J;
224 }
225 }
226 Buckets[I] = nullptr;
227 N->setFoldingSetHash(FoldingSetNodeIDRef::NotAHash);
228 --NumNodes;
229 return true;
230}
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.
This class is used to maintain node state in a folding set.
Definition FoldingSet.h:345
void ** Buckets
Array of node pointers; a null entry marks an empty slot.
Definition FoldingSet.h:329
LLVM_ABI FoldingSetBase & operator=(FoldingSetBase &&RHS)
LLVM_ABI ~FoldingSetBase()
LLVM_ABI bool erase(Node *N)
Remove a node from the folding set, returning true if one was removed or false if the node was not in...
unsigned NumBuckets
Length of the Buckets array. Always a power of 2.
Definition FoldingSet.h:332
unsigned NumNodes
Number of nodes in the folding set.
Definition FoldingSet.h:335
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 insert(Node *N, FoldingSetInsertToken Token)
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 FoldingSetBase(unsigned Log2InitSize)
Insertion token: a failed lookup fills it in, the matching insert consumes it.
Definition FoldingSet.h:300
This class describes a reference to an interned FoldingSetNodeID, which can be a useful to store node...
Definition FoldingSet.h:168
LLVM_ABI bool operator<(FoldingSetNodeIDRef) const
Used to compare the "ordering" of two nodes as defined by the profiled bits and their ordering define...
static constexpr unsigned NotAHash
Definition FoldingSet.h:176
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 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.
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