xref: /freebsd/contrib/llvm-project/llvm/include/llvm/ADT/FoldingSet.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
1 //===- llvm/ADT/FoldingSet.h - 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 /// \file
10 /// This file defines a hash set that can be used to remove duplication of nodes
11 /// in a graph.  This code was originally created by Chris Lattner for use with
12 /// SelectionDAGCSEMap, but was isolated to provide use across the llvm code
13 /// set.
14 //===----------------------------------------------------------------------===//
15 
16 #ifndef LLVM_ADT_FOLDINGSET_H
17 #define LLVM_ADT_FOLDINGSET_H
18 
19 #include "llvm/ADT/Hashing.h"
20 #include "llvm/ADT/STLForwardCompat.h"
21 #include "llvm/ADT/SmallVector.h"
22 #include "llvm/ADT/iterator.h"
23 #include "llvm/Support/Allocator.h"
24 #include "llvm/Support/Compiler.h"
25 #include "llvm/Support/xxhash.h"
26 #include <cassert>
27 #include <cstddef>
28 #include <cstdint>
29 #include <type_traits>
30 #include <utility>
31 
32 namespace llvm {
33 
34 /// This folding set used for two purposes:
35 ///   1. Given information about a node we want to create, look up the unique
36 ///      instance of the node in the set.  If the node already exists, return
37 ///      it, otherwise return the bucket it should be inserted into.
38 ///   2. Given a node that has already been created, remove it from the set.
39 ///
40 /// This class is implemented as a single-link chained hash table, where the
41 /// "buckets" are actually the nodes themselves (the next pointer is in the
42 /// node).  The last node points back to the bucket to simplify node removal.
43 ///
44 /// Any node that is to be included in the folding set must be a subclass of
45 /// FoldingSetNode.  The node class must also define a Profile method used to
46 /// establish the unique bits of data for the node.  The Profile method is
47 /// passed a FoldingSetNodeID object which is used to gather the bits.  Just
48 /// call one of the Add* functions defined in the FoldingSetBase::NodeID class.
49 /// NOTE: That the folding set does not own the nodes and it is the
50 /// responsibility of the user to dispose of the nodes.
51 ///
52 /// Eg.
53 ///    class MyNode : public FoldingSetNode {
54 ///    private:
55 ///      std::string Name;
56 ///      unsigned Value;
57 ///    public:
58 ///      MyNode(const char *N, unsigned V) : Name(N), Value(V) {}
59 ///       ...
60 ///      void Profile(FoldingSetNodeID &ID) const {
61 ///        ID.AddString(Name);
62 ///        ID.AddInteger(Value);
63 ///      }
64 ///      ...
65 ///    };
66 ///
67 /// To define the folding set itself use the FoldingSet template;
68 ///
69 /// Eg.
70 ///    FoldingSet<MyNode> MyFoldingSet;
71 ///
72 /// Four public methods are available to manipulate the folding set;
73 ///
74 /// 1) If you have an existing node that you want add to the set but unsure
75 /// that the node might already exist then call;
76 ///
77 ///    MyNode *M = MyFoldingSet.GetOrInsertNode(N);
78 ///
79 /// If The result is equal to the input then the node has been inserted.
80 /// Otherwise, the result is the node existing in the folding set, and the
81 /// input can be discarded (use the result instead.)
82 ///
83 /// 2) If you are ready to construct a node but want to check if it already
84 /// exists, then call FindNodeOrInsertPos with a FoldingSetNodeID of the bits to
85 /// check;
86 ///
87 ///   FoldingSetNodeID ID;
88 ///   ID.AddString(Name);
89 ///   ID.AddInteger(Value);
90 ///   void *InsertPoint;
91 ///
92 ///    MyNode *M = MyFoldingSet.FindNodeOrInsertPos(ID, InsertPoint);
93 ///
94 /// If found then M will be non-NULL, else InsertPoint will point to where it
95 /// should be inserted using InsertNode.
96 ///
97 /// 3) If you get a NULL result from FindNodeOrInsertPos then you can insert a
98 /// new node with InsertNode;
99 ///
100 ///    MyFoldingSet.InsertNode(M, InsertPoint);
101 ///
102 /// 4) Finally, if you want to remove a node from the folding set call;
103 ///
104 ///    bool WasRemoved = MyFoldingSet.RemoveNode(M);
105 ///
106 /// The result indicates whether the node existed in the folding set.
107 
108 class FoldingSetNodeID;
109 class StringRef;
110 
111 //===----------------------------------------------------------------------===//
112 /// FoldingSetBase - Implements the folding set functionality.  The main
113 /// structure is an array of buckets.  Each bucket is indexed by the hash of
114 /// the nodes it contains.  The bucket itself points to the nodes contained
115 /// in the bucket via a singly linked list.  The last node in the list points
116 /// back to the bucket to facilitate node removal.
117 ///
118 class FoldingSetBase {
119 protected:
120   /// Buckets - Array of bucket chains.
121   void **Buckets;
122 
123   /// NumBuckets - Length of the Buckets array.  Always a power of 2.
124   unsigned NumBuckets;
125 
126   /// NumNodes - Number of nodes in the folding set. Growth occurs when NumNodes
127   /// is greater than twice the number of buckets.
128   unsigned NumNodes;
129 
130   LLVM_ABI explicit FoldingSetBase(unsigned Log2InitSize = 6);
131   LLVM_ABI FoldingSetBase(FoldingSetBase &&Arg);
132   LLVM_ABI FoldingSetBase &operator=(FoldingSetBase &&RHS);
133   LLVM_ABI ~FoldingSetBase();
134 
135 public:
136   //===--------------------------------------------------------------------===//
137   /// Node - This class is used to maintain the singly linked bucket list in
138   /// a folding set.
139   class Node {
140   private:
141     // NextInFoldingSetBucket - next link in the bucket list.
142     void *NextInFoldingSetBucket = nullptr;
143 
144   public:
145     Node() = default;
146 
147     // Accessors
getNextInBucket()148     void *getNextInBucket() const { return NextInFoldingSetBucket; }
SetNextInBucket(void * N)149     void SetNextInBucket(void *N) { NextInFoldingSetBucket = N; }
150   };
151 
152   /// clear - Remove all nodes from the folding set.
153   LLVM_ABI void clear();
154 
155   /// size - Returns the number of nodes in the folding set.
size()156   unsigned size() const { return NumNodes; }
157 
158   /// empty - Returns true if there are no nodes in the folding set.
empty()159   bool empty() const { return NumNodes == 0; }
160 
161   /// capacity - Returns the number of nodes permitted in the folding set
162   /// before a rebucket operation is performed.
capacity()163   unsigned capacity() {
164     // We allow a load factor of up to 2.0,
165     // so that means our capacity is NumBuckets * 2
166     return NumBuckets * 2;
167   }
168 
169 protected:
170   /// Functions provided by the derived class to compute folding properties.
171   /// This is effectively a vtable for FoldingSetBase, except that we don't
172   /// actually store a pointer to it in the object.
173   struct FoldingSetInfo {
174     /// GetNodeProfile - Instantiations of the FoldingSet template implement
175     /// this function to gather data bits for the given node.
176     void (*GetNodeProfile)(const FoldingSetBase *Self, Node *N,
177                            FoldingSetNodeID &ID);
178 
179     /// NodeEquals - Instantiations of the FoldingSet template implement
180     /// this function to compare the given node with the given ID.
181     bool (*NodeEquals)(const FoldingSetBase *Self, Node *N,
182                        const FoldingSetNodeID &ID, unsigned IDHash,
183                        FoldingSetNodeID &TempID);
184 
185     /// ComputeNodeHash - Instantiations of the FoldingSet template implement
186     /// this function to compute a hash value for the given node.
187     unsigned (*ComputeNodeHash)(const FoldingSetBase *Self, Node *N,
188                                 FoldingSetNodeID &TempID);
189   };
190 
191 private:
192   /// GrowHashTable - Double the size of the hash table and rehash everything.
193   void GrowHashTable(const FoldingSetInfo &Info);
194 
195   /// GrowBucketCount - resize the hash table and rehash everything.
196   /// NewBucketCount must be a power of two, and must be greater than the old
197   /// bucket count.
198   void GrowBucketCount(unsigned NewBucketCount, const FoldingSetInfo &Info);
199 
200 protected:
201   // The below methods are protected to encourage subclasses to provide a more
202   // type-safe API.
203 
204   /// reserve - Increase the number of buckets such that adding the
205   /// EltCount-th node won't cause a rebucket operation. reserve is permitted
206   /// to allocate more space than requested by EltCount.
207   LLVM_ABI void reserve(unsigned EltCount, const FoldingSetInfo &Info);
208 
209   /// RemoveNode - Remove a node from the folding set, returning true if one
210   /// was removed or false if the node was not in the folding set.
211   LLVM_ABI bool RemoveNode(Node *N);
212 
213   /// GetOrInsertNode - If there is an existing simple Node exactly
214   /// equal to the specified node, return it.  Otherwise, insert 'N' and return
215   /// it instead.
216   LLVM_ABI Node *GetOrInsertNode(Node *N, const FoldingSetInfo &Info);
217 
218   /// FindNodeOrInsertPos - Look up the node specified by ID.  If it exists,
219   /// return it.  If not, return the insertion token that will make insertion
220   /// faster.
221   LLVM_ABI Node *FindNodeOrInsertPos(const FoldingSetNodeID &ID,
222                                      void *&InsertPos,
223                                      const FoldingSetInfo &Info);
224 
225   /// InsertNode - Insert the specified node into the folding set, knowing that
226   /// it is not already in the folding set.  InsertPos must be obtained from
227   /// FindNodeOrInsertPos.
228   LLVM_ABI void InsertNode(Node *N, void *InsertPos,
229                            const FoldingSetInfo &Info);
230 };
231 
232 //===----------------------------------------------------------------------===//
233 
234 /// DefaultFoldingSetTrait - This class provides default implementations
235 /// for FoldingSetTrait implementations.
236 template<typename T> struct DefaultFoldingSetTrait {
ProfileDefaultFoldingSetTrait237   static void Profile(const T &X, FoldingSetNodeID &ID) {
238     X.Profile(ID);
239   }
ProfileDefaultFoldingSetTrait240   static void Profile(T &X, FoldingSetNodeID &ID) {
241     X.Profile(ID);
242   }
243 
244   // Equals - Test if the profile for X would match ID, using TempID
245   // to compute a temporary ID if necessary. The default implementation
246   // just calls Profile and does a regular comparison. Implementations
247   // can override this to provide more efficient implementations.
248   static inline bool Equals(T &X, const FoldingSetNodeID &ID, unsigned IDHash,
249                             FoldingSetNodeID &TempID);
250 
251   // ComputeHash - Compute a hash value for X, using TempID to
252   // compute a temporary ID if necessary. The default implementation
253   // just calls Profile and does a regular hash computation.
254   // Implementations can override this to provide more efficient
255   // implementations.
256   static inline unsigned ComputeHash(T &X, FoldingSetNodeID &TempID);
257 };
258 
259 /// FoldingSetTrait - This trait class is used to define behavior of how
260 /// to "profile" (in the FoldingSet parlance) an object of a given type.
261 /// The default behavior is to invoke a 'Profile' method on an object, but
262 /// through template specialization the behavior can be tailored for specific
263 /// types.  Combined with the FoldingSetNodeWrapper class, one can add objects
264 /// to FoldingSets that were not originally designed to have that behavior.
265 template <typename T, typename Enable = void>
266 struct FoldingSetTrait : public DefaultFoldingSetTrait<T> {};
267 
268 /// DefaultContextualFoldingSetTrait - Like DefaultFoldingSetTrait, but
269 /// for ContextualFoldingSets.
270 template<typename T, typename Ctx>
271 struct DefaultContextualFoldingSetTrait {
ProfileDefaultContextualFoldingSetTrait272   static void Profile(T &X, FoldingSetNodeID &ID, Ctx Context) {
273     X.Profile(ID, Context);
274   }
275 
276   static inline bool Equals(T &X, const FoldingSetNodeID &ID, unsigned IDHash,
277                             FoldingSetNodeID &TempID, Ctx Context);
278   static inline unsigned ComputeHash(T &X, FoldingSetNodeID &TempID,
279                                      Ctx Context);
280 };
281 
282 /// ContextualFoldingSetTrait - Like FoldingSetTrait, but for
283 /// ContextualFoldingSets.
284 template<typename T, typename Ctx> struct ContextualFoldingSetTrait
285   : public DefaultContextualFoldingSetTrait<T, Ctx> {};
286 
287 //===--------------------------------------------------------------------===//
288 /// FoldingSetNodeIDRef - This class describes a reference to an interned
289 /// FoldingSetNodeID, which can be a useful to store node id data rather
290 /// than using plain FoldingSetNodeIDs, since the 32-element SmallVector
291 /// is often much larger than necessary, and the possibility of heap
292 /// allocation means it requires a non-trivial destructor call.
293 class FoldingSetNodeIDRef {
294   const unsigned *Data = nullptr;
295   size_t Size = 0;
296 
297 public:
298   FoldingSetNodeIDRef() = default;
FoldingSetNodeIDRef(const unsigned * D,size_t S)299   FoldingSetNodeIDRef(const unsigned *D, size_t S) : Data(D), Size(S) {}
300 
301   // Compute a strong hash value used to lookup the node in the FoldingSetBase.
302   // The hash value is not guaranteed to be deterministic across processes.
ComputeHash()303   unsigned ComputeHash() const {
304     return static_cast<unsigned>(hash_combine_range(Data, Data + Size));
305   }
306 
307   // Compute a deterministic hash value across processes that is suitable for
308   // on-disk serialization.
computeStableHash()309   unsigned computeStableHash() const {
310     return static_cast<unsigned>(xxh3_64bits(ArrayRef(
311         reinterpret_cast<const uint8_t *>(Data), sizeof(unsigned) * Size)));
312   }
313 
314   LLVM_ABI bool operator==(FoldingSetNodeIDRef) const;
315 
316   bool operator!=(FoldingSetNodeIDRef RHS) const { return !(*this == RHS); }
317 
318   /// Used to compare the "ordering" of two nodes as defined by the
319   /// profiled bits and their ordering defined by memcmp().
320   LLVM_ABI bool operator<(FoldingSetNodeIDRef) const;
321 
getData()322   const unsigned *getData() const { return Data; }
getSize()323   size_t getSize() const { return Size; }
324 };
325 
326 //===--------------------------------------------------------------------===//
327 /// FoldingSetNodeID - This class is used to gather all the unique data bits of
328 /// a node.  When all the bits are gathered this class is used to produce a
329 /// hash value for the node.
330 class FoldingSetNodeID {
331   /// Bits - Vector of all the data bits that make the node unique.
332   /// Use a SmallVector to avoid a heap allocation in the common case.
333   SmallVector<unsigned, 32> Bits;
334 
335 public:
336   FoldingSetNodeID() = default;
337 
FoldingSetNodeID(FoldingSetNodeIDRef Ref)338   FoldingSetNodeID(FoldingSetNodeIDRef Ref)
339     : Bits(Ref.getData(), Ref.getData() + Ref.getSize()) {}
340 
341   /// Add* - Add various data types to Bit data.
AddPointer(const void * Ptr)342   void AddPointer(const void *Ptr) {
343     // Note: this adds pointers to the hash using sizes and endianness that
344     // depend on the host. It doesn't matter, however, because hashing on
345     // pointer values is inherently unstable. Nothing should depend on the
346     // ordering of nodes in the folding set.
347     static_assert(sizeof(uintptr_t) <= sizeof(unsigned long long),
348                   "unexpected pointer size");
349     AddInteger(reinterpret_cast<uintptr_t>(Ptr));
350   }
AddInteger(signed I)351   void AddInteger(signed I) { Bits.push_back(I); }
AddInteger(unsigned I)352   void AddInteger(unsigned I) { Bits.push_back(I); }
AddInteger(long I)353   void AddInteger(long I) { AddInteger((unsigned long)I); }
AddInteger(unsigned long I)354   void AddInteger(unsigned long I) {
355     if (sizeof(long) == sizeof(int))
356       AddInteger(unsigned(I));
357     else if (sizeof(long) == sizeof(long long)) {
358       AddInteger((unsigned long long)I);
359     } else {
360       llvm_unreachable("unexpected sizeof(long)");
361     }
362   }
AddInteger(long long I)363   void AddInteger(long long I) { AddInteger((unsigned long long)I); }
AddInteger(unsigned long long I)364   void AddInteger(unsigned long long I) {
365     AddInteger(unsigned(I));
366     AddInteger(unsigned(I >> 32));
367   }
368 
AddBoolean(bool B)369   void AddBoolean(bool B) { AddInteger(B ? 1U : 0U); }
370   LLVM_ABI void AddString(StringRef String);
371   LLVM_ABI void AddNodeID(const FoldingSetNodeID &ID);
372 
373   template <typename T>
Add(const T & x)374   inline void Add(const T &x) { FoldingSetTrait<T>::Profile(x, *this); }
375 
376   /// clear - Clear the accumulated profile, allowing this FoldingSetNodeID
377   /// object to be used to compute a new profile.
clear()378   inline void clear() { Bits.clear(); }
379 
380   // Compute a strong hash value for this FoldingSetNodeID, used to lookup the
381   // node in the FoldingSetBase. The hash value is not guaranteed to be
382   // deterministic across processes.
ComputeHash()383   unsigned ComputeHash() const {
384     return FoldingSetNodeIDRef(Bits.data(), Bits.size()).ComputeHash();
385   }
386 
387   // Compute a deterministic hash value across processes that is suitable for
388   // on-disk serialization.
computeStableHash()389   unsigned computeStableHash() const {
390     return FoldingSetNodeIDRef(Bits.data(), Bits.size()).computeStableHash();
391   }
392 
393   /// operator== - Used to compare two nodes to each other.
394   LLVM_ABI bool operator==(const FoldingSetNodeID &RHS) const;
395   LLVM_ABI bool operator==(const FoldingSetNodeIDRef RHS) const;
396 
397   bool operator!=(const FoldingSetNodeID &RHS) const { return !(*this == RHS); }
398   bool operator!=(const FoldingSetNodeIDRef RHS) const { return !(*this ==RHS);}
399 
400   /// Used to compare the "ordering" of two nodes as defined by the
401   /// profiled bits and their ordering defined by memcmp().
402   LLVM_ABI bool operator<(const FoldingSetNodeID &RHS) const;
403   LLVM_ABI bool operator<(const FoldingSetNodeIDRef RHS) const;
404 
405   /// Intern - Copy this node's data to a memory region allocated from the
406   /// given allocator and return a FoldingSetNodeIDRef describing the
407   /// interned data.
408   LLVM_ABI FoldingSetNodeIDRef Intern(BumpPtrAllocator &Allocator) const;
409 };
410 
411 // Convenience type to hide the implementation of the folding set.
412 using FoldingSetNode = FoldingSetBase::Node;
413 template<class T> class FoldingSetIterator;
414 template<class T> class FoldingSetBucketIterator;
415 
416 // Definitions of FoldingSetTrait and ContextualFoldingSetTrait functions, which
417 // require the definition of FoldingSetNodeID.
418 template<typename T>
419 inline bool
Equals(T & X,const FoldingSetNodeID & ID,unsigned,FoldingSetNodeID & TempID)420 DefaultFoldingSetTrait<T>::Equals(T &X, const FoldingSetNodeID &ID,
421                                   unsigned /*IDHash*/,
422                                   FoldingSetNodeID &TempID) {
423   FoldingSetTrait<T>::Profile(X, TempID);
424   return TempID == ID;
425 }
426 template<typename T>
427 inline unsigned
ComputeHash(T & X,FoldingSetNodeID & TempID)428 DefaultFoldingSetTrait<T>::ComputeHash(T &X, FoldingSetNodeID &TempID) {
429   FoldingSetTrait<T>::Profile(X, TempID);
430   return TempID.ComputeHash();
431 }
432 template<typename T, typename Ctx>
433 inline bool
Equals(T & X,const FoldingSetNodeID & ID,unsigned,FoldingSetNodeID & TempID,Ctx Context)434 DefaultContextualFoldingSetTrait<T, Ctx>::Equals(T &X,
435                                                  const FoldingSetNodeID &ID,
436                                                  unsigned /*IDHash*/,
437                                                  FoldingSetNodeID &TempID,
438                                                  Ctx Context) {
439   ContextualFoldingSetTrait<T, Ctx>::Profile(X, TempID, Context);
440   return TempID == ID;
441 }
442 template<typename T, typename Ctx>
443 inline unsigned
ComputeHash(T & X,FoldingSetNodeID & TempID,Ctx Context)444 DefaultContextualFoldingSetTrait<T, Ctx>::ComputeHash(T &X,
445                                                       FoldingSetNodeID &TempID,
446                                                       Ctx Context) {
447   ContextualFoldingSetTrait<T, Ctx>::Profile(X, TempID, Context);
448   return TempID.ComputeHash();
449 }
450 
451 //===----------------------------------------------------------------------===//
452 /// FoldingSetImpl - An implementation detail that lets us share code between
453 /// FoldingSet and ContextualFoldingSet.
454 template <class Derived, class T> class FoldingSetImpl : public FoldingSetBase {
455 protected:
FoldingSetImpl(unsigned Log2InitSize)456   explicit FoldingSetImpl(unsigned Log2InitSize)
457       : FoldingSetBase(Log2InitSize) {}
458 
459   FoldingSetImpl(FoldingSetImpl &&Arg) = default;
460   FoldingSetImpl &operator=(FoldingSetImpl &&RHS) = default;
461   ~FoldingSetImpl() = default;
462 
463 public:
464   using iterator = FoldingSetIterator<T>;
465 
begin()466   iterator begin() { return iterator(Buckets); }
end()467   iterator end() { return iterator(Buckets+NumBuckets); }
468 
469   using const_iterator = FoldingSetIterator<const T>;
470 
begin()471   const_iterator begin() const { return const_iterator(Buckets); }
end()472   const_iterator end() const { return const_iterator(Buckets+NumBuckets); }
473 
474   using bucket_iterator = FoldingSetBucketIterator<T>;
475 
bucket_begin(unsigned hash)476   bucket_iterator bucket_begin(unsigned hash) {
477     return bucket_iterator(Buckets + (hash & (NumBuckets-1)));
478   }
479 
bucket_end(unsigned hash)480   bucket_iterator bucket_end(unsigned hash) {
481     return bucket_iterator(Buckets + (hash & (NumBuckets-1)), true);
482   }
483 
484   /// reserve - Increase the number of buckets such that adding the
485   /// EltCount-th node won't cause a rebucket operation. reserve is permitted
486   /// to allocate more space than requested by EltCount.
reserve(unsigned EltCount)487   void reserve(unsigned EltCount) {
488     return FoldingSetBase::reserve(EltCount, Derived::getFoldingSetInfo());
489   }
490 
491   /// RemoveNode - Remove a node from the folding set, returning true if one
492   /// was removed or false if the node was not in the folding set.
RemoveNode(T * N)493   bool RemoveNode(T *N) {
494     return FoldingSetBase::RemoveNode(N);
495   }
496 
497   /// GetOrInsertNode - If there is an existing simple Node exactly
498   /// equal to the specified node, return it.  Otherwise, insert 'N' and
499   /// return it instead.
GetOrInsertNode(T * N)500   T *GetOrInsertNode(T *N) {
501     return static_cast<T *>(
502         FoldingSetBase::GetOrInsertNode(N, Derived::getFoldingSetInfo()));
503   }
504 
505   /// FindNodeOrInsertPos - Look up the node specified by ID.  If it exists,
506   /// return it.  If not, return the insertion token that will make insertion
507   /// faster.
FindNodeOrInsertPos(const FoldingSetNodeID & ID,void * & InsertPos)508   T *FindNodeOrInsertPos(const FoldingSetNodeID &ID, void *&InsertPos) {
509     return static_cast<T *>(FoldingSetBase::FindNodeOrInsertPos(
510         ID, InsertPos, Derived::getFoldingSetInfo()));
511   }
512 
513   /// InsertNode - Insert the specified node into the folding set, knowing that
514   /// it is not already in the folding set.  InsertPos must be obtained from
515   /// FindNodeOrInsertPos.
InsertNode(T * N,void * InsertPos)516   void InsertNode(T *N, void *InsertPos) {
517     FoldingSetBase::InsertNode(N, InsertPos, Derived::getFoldingSetInfo());
518   }
519 
520   /// InsertNode - Insert the specified node into the folding set, knowing that
521   /// it is not already in the folding set.
InsertNode(T * N)522   void InsertNode(T *N) {
523     T *Inserted = GetOrInsertNode(N);
524     (void)Inserted;
525     assert(Inserted == N && "Node already inserted!");
526   }
527 };
528 
529 //===----------------------------------------------------------------------===//
530 /// FoldingSet - This template class is used to instantiate a specialized
531 /// implementation of the folding set to the node class T.  T must be a
532 /// subclass of FoldingSetNode and implement a Profile function.
533 ///
534 /// Note that this set type is movable and move-assignable. However, its
535 /// moved-from state is not a valid state for anything other than
536 /// move-assigning and destroying. This is primarily to enable movable APIs
537 /// that incorporate these objects.
538 template <class T>
539 class FoldingSet : public FoldingSetImpl<FoldingSet<T>, T> {
540   using Super = FoldingSetImpl<FoldingSet, T>;
541   using Node = typename Super::Node;
542 
543   /// GetNodeProfile - Each instantiation of the FoldingSet needs to provide a
544   /// way to convert nodes into a unique specifier.
GetNodeProfile(const FoldingSetBase *,Node * N,FoldingSetNodeID & ID)545   static void GetNodeProfile(const FoldingSetBase *, Node *N,
546                              FoldingSetNodeID &ID) {
547     T *TN = static_cast<T *>(N);
548     FoldingSetTrait<T>::Profile(*TN, ID);
549   }
550 
551   /// NodeEquals - Instantiations may optionally provide a way to compare a
552   /// node with a specified ID.
NodeEquals(const FoldingSetBase *,Node * N,const FoldingSetNodeID & ID,unsigned IDHash,FoldingSetNodeID & TempID)553   static bool NodeEquals(const FoldingSetBase *, Node *N,
554                          const FoldingSetNodeID &ID, unsigned IDHash,
555                          FoldingSetNodeID &TempID) {
556     T *TN = static_cast<T *>(N);
557     return FoldingSetTrait<T>::Equals(*TN, ID, IDHash, TempID);
558   }
559 
560   /// ComputeNodeHash - Instantiations may optionally provide a way to compute a
561   /// hash value directly from a node.
ComputeNodeHash(const FoldingSetBase *,Node * N,FoldingSetNodeID & TempID)562   static unsigned ComputeNodeHash(const FoldingSetBase *, Node *N,
563                                   FoldingSetNodeID &TempID) {
564     T *TN = static_cast<T *>(N);
565     return FoldingSetTrait<T>::ComputeHash(*TN, TempID);
566   }
567 
getFoldingSetInfo()568   static const FoldingSetBase::FoldingSetInfo &getFoldingSetInfo() {
569     static constexpr FoldingSetBase::FoldingSetInfo Info = {
570         GetNodeProfile, NodeEquals, ComputeNodeHash};
571     return Info;
572   }
573   friend Super;
574 
575 public:
Super(Log2InitSize)576   explicit FoldingSet(unsigned Log2InitSize = 6) : Super(Log2InitSize) {}
577   FoldingSet(FoldingSet &&Arg) = default;
578   FoldingSet &operator=(FoldingSet &&RHS) = default;
579 };
580 
581 //===----------------------------------------------------------------------===//
582 /// ContextualFoldingSet - This template class is a further refinement
583 /// of FoldingSet which provides a context argument when calling
584 /// Profile on its nodes.  Currently, that argument is fixed at
585 /// initialization time.
586 ///
587 /// T must be a subclass of FoldingSetNode and implement a Profile
588 /// function with signature
589 ///   void Profile(FoldingSetNodeID &, Ctx);
590 template <class T, class Ctx>
591 class ContextualFoldingSet
592     : public FoldingSetImpl<ContextualFoldingSet<T, Ctx>, T> {
593   // Unfortunately, this can't derive from FoldingSet<T> because the
594   // construction of the vtable for FoldingSet<T> requires
595   // FoldingSet<T>::GetNodeProfile to be instantiated, which in turn
596   // requires a single-argument T::Profile().
597 
598   using Super = FoldingSetImpl<ContextualFoldingSet, T>;
599   using Node = typename Super::Node;
600 
601   Ctx Context;
602 
getContext(const FoldingSetBase * Base)603   static const Ctx &getContext(const FoldingSetBase *Base) {
604     return static_cast<const ContextualFoldingSet*>(Base)->Context;
605   }
606 
607   /// GetNodeProfile - Each instantiatation of the FoldingSet needs to provide a
608   /// way to convert nodes into a unique specifier.
GetNodeProfile(const FoldingSetBase * Base,Node * N,FoldingSetNodeID & ID)609   static void GetNodeProfile(const FoldingSetBase *Base, Node *N,
610                              FoldingSetNodeID &ID) {
611     T *TN = static_cast<T *>(N);
612     ContextualFoldingSetTrait<T, Ctx>::Profile(*TN, ID, getContext(Base));
613   }
614 
NodeEquals(const FoldingSetBase * Base,Node * N,const FoldingSetNodeID & ID,unsigned IDHash,FoldingSetNodeID & TempID)615   static bool NodeEquals(const FoldingSetBase *Base, Node *N,
616                          const FoldingSetNodeID &ID, unsigned IDHash,
617                          FoldingSetNodeID &TempID) {
618     T *TN = static_cast<T *>(N);
619     return ContextualFoldingSetTrait<T, Ctx>::Equals(*TN, ID, IDHash, TempID,
620                                                      getContext(Base));
621   }
622 
ComputeNodeHash(const FoldingSetBase * Base,Node * N,FoldingSetNodeID & TempID)623   static unsigned ComputeNodeHash(const FoldingSetBase *Base, Node *N,
624                                   FoldingSetNodeID &TempID) {
625     T *TN = static_cast<T *>(N);
626     return ContextualFoldingSetTrait<T, Ctx>::ComputeHash(*TN, TempID,
627                                                           getContext(Base));
628   }
629 
getFoldingSetInfo()630   static const FoldingSetBase::FoldingSetInfo &getFoldingSetInfo() {
631     static constexpr FoldingSetBase::FoldingSetInfo Info = {
632         GetNodeProfile, NodeEquals, ComputeNodeHash};
633     return Info;
634   }
635   friend Super;
636 
637 public:
638   explicit ContextualFoldingSet(Ctx Context, unsigned Log2InitSize = 6)
Super(Log2InitSize)639       : Super(Log2InitSize), Context(Context) {}
640 
getContext()641   Ctx getContext() const { return Context; }
642 };
643 
644 //===----------------------------------------------------------------------===//
645 /// FoldingSetVector - This template class combines a FoldingSet and a vector
646 /// to provide the interface of FoldingSet but with deterministic iteration
647 /// order based on the insertion order. T must be a subclass of FoldingSetNode
648 /// and implement a Profile function.
649 template <class T, class VectorT = SmallVector<T*, 8>>
650 class FoldingSetVector {
651   FoldingSet<T> Set;
652   VectorT Vector;
653 
654 public:
Set(Log2InitSize)655   explicit FoldingSetVector(unsigned Log2InitSize = 6) : Set(Log2InitSize) {}
656 
657   using iterator = pointee_iterator<typename VectorT::iterator>;
658 
begin()659   iterator begin() { return Vector.begin(); }
end()660   iterator end()   { return Vector.end(); }
661 
662   using const_iterator = pointee_iterator<typename VectorT::const_iterator>;
663 
begin()664   const_iterator begin() const { return Vector.begin(); }
end()665   const_iterator end()   const { return Vector.end(); }
666 
667   /// clear - Remove all nodes from the folding set.
clear()668   void clear() { Set.clear(); Vector.clear(); }
669 
670   /// FindNodeOrInsertPos - Look up the node specified by ID.  If it exists,
671   /// return it.  If not, return the insertion token that will make insertion
672   /// faster.
FindNodeOrInsertPos(const FoldingSetNodeID & ID,void * & InsertPos)673   T *FindNodeOrInsertPos(const FoldingSetNodeID &ID, void *&InsertPos) {
674     return Set.FindNodeOrInsertPos(ID, InsertPos);
675   }
676 
677   /// GetOrInsertNode - If there is an existing simple Node exactly
678   /// equal to the specified node, return it.  Otherwise, insert 'N' and
679   /// return it instead.
GetOrInsertNode(T * N)680   T *GetOrInsertNode(T *N) {
681     T *Result = Set.GetOrInsertNode(N);
682     if (Result == N) Vector.push_back(N);
683     return Result;
684   }
685 
686   /// InsertNode - Insert the specified node into the folding set, knowing that
687   /// it is not already in the folding set.  InsertPos must be obtained from
688   /// FindNodeOrInsertPos.
InsertNode(T * N,void * InsertPos)689   void InsertNode(T *N, void *InsertPos) {
690     Set.InsertNode(N, InsertPos);
691     Vector.push_back(N);
692   }
693 
694   /// InsertNode - Insert the specified node into the folding set, knowing that
695   /// it is not already in the folding set.
InsertNode(T * N)696   void InsertNode(T *N) {
697     Set.InsertNode(N);
698     Vector.push_back(N);
699   }
700 
701   /// size - Returns the number of nodes in the folding set.
size()702   unsigned size() const { return Set.size(); }
703 
704   /// empty - Returns true if there are no nodes in the folding set.
empty()705   bool empty() const { return Set.empty(); }
706 };
707 
708 //===----------------------------------------------------------------------===//
709 /// FoldingSetIteratorImpl - This is the common iterator support shared by all
710 /// folding sets, which knows how to walk the folding set hash table.
711 class FoldingSetIteratorImpl {
712 protected:
713   FoldingSetNode *NodePtr;
714 
715   LLVM_ABI FoldingSetIteratorImpl(void **Bucket);
716 
717   LLVM_ABI void advance();
718 
719 public:
720   bool operator==(const FoldingSetIteratorImpl &RHS) const {
721     return NodePtr == RHS.NodePtr;
722   }
723   bool operator!=(const FoldingSetIteratorImpl &RHS) const {
724     return NodePtr != RHS.NodePtr;
725   }
726 };
727 
728 template <class T> class FoldingSetIterator : public FoldingSetIteratorImpl {
729 public:
FoldingSetIterator(void ** Bucket)730   explicit FoldingSetIterator(void **Bucket) : FoldingSetIteratorImpl(Bucket) {}
731 
732   T &operator*() const {
733     return *static_cast<T*>(NodePtr);
734   }
735 
736   T *operator->() const {
737     return static_cast<T*>(NodePtr);
738   }
739 
740   inline FoldingSetIterator &operator++() {          // Preincrement
741     advance();
742     return *this;
743   }
744   FoldingSetIterator operator++(int) {        // Postincrement
745     FoldingSetIterator tmp = *this; ++*this; return tmp;
746   }
747 };
748 
749 //===----------------------------------------------------------------------===//
750 /// FoldingSetBucketIteratorImpl - This is the common bucket iterator support
751 /// shared by all folding sets, which knows how to walk a particular bucket
752 /// of a folding set hash table.
753 class FoldingSetBucketIteratorImpl {
754 protected:
755   void *Ptr;
756 
757   LLVM_ABI explicit FoldingSetBucketIteratorImpl(void **Bucket);
758 
FoldingSetBucketIteratorImpl(void ** Bucket,bool)759   FoldingSetBucketIteratorImpl(void **Bucket, bool) : Ptr(Bucket) {}
760 
advance()761   void advance() {
762     void *Probe = static_cast<FoldingSetNode*>(Ptr)->getNextInBucket();
763     uintptr_t x = reinterpret_cast<uintptr_t>(Probe) & ~0x1;
764     Ptr = reinterpret_cast<void*>(x);
765   }
766 
767 public:
768   bool operator==(const FoldingSetBucketIteratorImpl &RHS) const {
769     return Ptr == RHS.Ptr;
770   }
771   bool operator!=(const FoldingSetBucketIteratorImpl &RHS) const {
772     return Ptr != RHS.Ptr;
773   }
774 };
775 
776 template <class T>
777 class FoldingSetBucketIterator : public FoldingSetBucketIteratorImpl {
778 public:
FoldingSetBucketIterator(void ** Bucket)779   explicit FoldingSetBucketIterator(void **Bucket) :
780     FoldingSetBucketIteratorImpl(Bucket) {}
781 
FoldingSetBucketIterator(void ** Bucket,bool)782   FoldingSetBucketIterator(void **Bucket, bool) :
783     FoldingSetBucketIteratorImpl(Bucket, true) {}
784 
785   T &operator*() const { return *static_cast<T*>(Ptr); }
786   T *operator->() const { return static_cast<T*>(Ptr); }
787 
788   inline FoldingSetBucketIterator &operator++() { // Preincrement
789     advance();
790     return *this;
791   }
792   FoldingSetBucketIterator operator++(int) {      // Postincrement
793     FoldingSetBucketIterator tmp = *this; ++*this; return tmp;
794   }
795 };
796 
797 //===----------------------------------------------------------------------===//
798 /// FoldingSetNodeWrapper - This template class is used to "wrap" arbitrary
799 /// types in an enclosing object so that they can be inserted into FoldingSets.
800 template <typename T>
801 class FoldingSetNodeWrapper : public FoldingSetNode {
802   T data;
803 
804 public:
805   template <typename... Ts>
FoldingSetNodeWrapper(Ts &&...Args)806   explicit FoldingSetNodeWrapper(Ts &&... Args)
807       : data(std::forward<Ts>(Args)...) {}
808 
Profile(FoldingSetNodeID & ID)809   void Profile(FoldingSetNodeID &ID) { FoldingSetTrait<T>::Profile(data, ID); }
810 
getValue()811   T &getValue() { return data; }
getValue()812   const T &getValue() const { return data; }
813 
814   operator T&() { return data; }
815   operator const T&() const { return data; }
816 };
817 
818 //===----------------------------------------------------------------------===//
819 /// FastFoldingSetNode - This is a subclass of FoldingSetNode which stores
820 /// a FoldingSetNodeID value rather than requiring the node to recompute it
821 /// each time it is needed. This trades space for speed (which can be
822 /// significant if the ID is long), and it also permits nodes to drop
823 /// information that would otherwise only be required for recomputing an ID.
824 class FastFoldingSetNode : public FoldingSetNode {
825   FoldingSetNodeID FastID;
826 
827 protected:
FastFoldingSetNode(const FoldingSetNodeID & ID)828   explicit FastFoldingSetNode(const FoldingSetNodeID &ID) : FastID(ID) {}
829 
830 public:
Profile(FoldingSetNodeID & ID)831   void Profile(FoldingSetNodeID &ID) const { ID.AddNodeID(FastID); }
832 };
833 
834 //===----------------------------------------------------------------------===//
835 // Partial specializations of FoldingSetTrait.
836 
837 template<typename T> struct FoldingSetTrait<T*> {
838   static inline void Profile(T *X, FoldingSetNodeID &ID) {
839     ID.AddPointer(X);
840   }
841 };
842 template <typename T1, typename T2>
843 struct FoldingSetTrait<std::pair<T1, T2>> {
844   static inline void Profile(const std::pair<T1, T2> &P,
845                              FoldingSetNodeID &ID) {
846     ID.Add(P.first);
847     ID.Add(P.second);
848   }
849 };
850 
851 template <typename T>
852 struct FoldingSetTrait<T, std::enable_if_t<std::is_enum<T>::value>> {
853   static void Profile(const T &X, FoldingSetNodeID &ID) {
854     ID.AddInteger(llvm::to_underlying(X));
855   }
856 };
857 
858 } // end namespace llvm
859 
860 #endif // LLVM_ADT_FOLDINGSET_H
861