xref: /freebsd-src/contrib/llvm-project/llvm/lib/Support/FoldingSet.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
10b57cec5SDimitry Andric //===-- Support/FoldingSet.cpp - Uniquing Hash Set --------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file implements a hash set that can be used to remove duplication of
100b57cec5SDimitry Andric // nodes in a graph.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "llvm/ADT/FoldingSet.h"
155ffd83dbSDimitry Andric #include "llvm/ADT/StringRef.h"
160b57cec5SDimitry Andric #include "llvm/Support/Allocator.h"
170b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
180b57cec5SDimitry Andric #include "llvm/Support/MathExtras.h"
19bdd1243dSDimitry Andric #include "llvm/Support/SwapByteOrder.h"
200b57cec5SDimitry Andric #include <cassert>
210b57cec5SDimitry Andric #include <cstring>
220b57cec5SDimitry Andric using namespace llvm;
230b57cec5SDimitry Andric 
240b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
250b57cec5SDimitry Andric // FoldingSetNodeIDRef Implementation
260b57cec5SDimitry Andric 
operator ==(FoldingSetNodeIDRef RHS) const270b57cec5SDimitry Andric bool FoldingSetNodeIDRef::operator==(FoldingSetNodeIDRef RHS) const {
280b57cec5SDimitry Andric   if (Size != RHS.Size) return false;
290b57cec5SDimitry Andric   return memcmp(Data, RHS.Data, Size*sizeof(*Data)) == 0;
300b57cec5SDimitry Andric }
310b57cec5SDimitry Andric 
320b57cec5SDimitry Andric /// Used to compare the "ordering" of two nodes as defined by the
330b57cec5SDimitry Andric /// profiled bits and their ordering defined by memcmp().
operator <(FoldingSetNodeIDRef RHS) const340b57cec5SDimitry Andric bool FoldingSetNodeIDRef::operator<(FoldingSetNodeIDRef RHS) const {
350b57cec5SDimitry Andric   if (Size != RHS.Size)
360b57cec5SDimitry Andric     return Size < RHS.Size;
370b57cec5SDimitry Andric   return memcmp(Data, RHS.Data, Size*sizeof(*Data)) < 0;
380b57cec5SDimitry Andric }
390b57cec5SDimitry Andric 
400b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
410b57cec5SDimitry Andric // FoldingSetNodeID Implementation
420b57cec5SDimitry Andric 
430b57cec5SDimitry Andric /// Add* - Add various data types to Bit data.
440b57cec5SDimitry Andric ///
AddString(StringRef String)450b57cec5SDimitry Andric void FoldingSetNodeID::AddString(StringRef String) {
460b57cec5SDimitry Andric   unsigned Size =  String.size();
475ffd83dbSDimitry Andric 
485ffd83dbSDimitry Andric   unsigned NumInserts = 1 + divideCeil(Size, 4);
495ffd83dbSDimitry Andric   Bits.reserve(Bits.size() + NumInserts);
505ffd83dbSDimitry Andric 
510b57cec5SDimitry Andric   Bits.push_back(Size);
520b57cec5SDimitry Andric   if (!Size) return;
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric   unsigned Units = Size / 4;
550b57cec5SDimitry Andric   unsigned Pos = 0;
560b57cec5SDimitry Andric   const unsigned *Base = (const unsigned*) String.data();
570b57cec5SDimitry Andric 
580b57cec5SDimitry Andric   // If the string is aligned do a bulk transfer.
590b57cec5SDimitry Andric   if (!((intptr_t)Base & 3)) {
600b57cec5SDimitry Andric     Bits.append(Base, Base + Units);
610b57cec5SDimitry Andric     Pos = (Units + 1) * 4;
620b57cec5SDimitry Andric   } else {
630b57cec5SDimitry Andric     // Otherwise do it the hard way.
640b57cec5SDimitry Andric     // To be compatible with above bulk transfer, we need to take endianness
650b57cec5SDimitry Andric     // into account.
660b57cec5SDimitry Andric     static_assert(sys::IsBigEndianHost || sys::IsLittleEndianHost,
670b57cec5SDimitry Andric                   "Unexpected host endianness");
680b57cec5SDimitry Andric     if (sys::IsBigEndianHost) {
690b57cec5SDimitry Andric       for (Pos += 4; Pos <= Size; Pos += 4) {
700b57cec5SDimitry Andric         unsigned V = ((unsigned char)String[Pos - 4] << 24) |
710b57cec5SDimitry Andric                      ((unsigned char)String[Pos - 3] << 16) |
720b57cec5SDimitry Andric                      ((unsigned char)String[Pos - 2] << 8) |
730b57cec5SDimitry Andric                       (unsigned char)String[Pos - 1];
740b57cec5SDimitry Andric         Bits.push_back(V);
750b57cec5SDimitry Andric       }
760b57cec5SDimitry Andric     } else {  // Little-endian host
770b57cec5SDimitry Andric       for (Pos += 4; Pos <= Size; Pos += 4) {
780b57cec5SDimitry Andric         unsigned V = ((unsigned char)String[Pos - 1] << 24) |
790b57cec5SDimitry Andric                      ((unsigned char)String[Pos - 2] << 16) |
800b57cec5SDimitry Andric                      ((unsigned char)String[Pos - 3] << 8) |
810b57cec5SDimitry Andric                       (unsigned char)String[Pos - 4];
820b57cec5SDimitry Andric         Bits.push_back(V);
830b57cec5SDimitry Andric       }
840b57cec5SDimitry Andric     }
850b57cec5SDimitry Andric   }
860b57cec5SDimitry Andric 
870b57cec5SDimitry Andric   // With the leftover bits.
880b57cec5SDimitry Andric   unsigned V = 0;
890b57cec5SDimitry Andric   // Pos will have overshot size by 4 - #bytes left over.
900b57cec5SDimitry Andric   // No need to take endianness into account here - this is always executed.
910b57cec5SDimitry Andric   switch (Pos - Size) {
92bdd1243dSDimitry Andric   case 1: V = (V << 8) | (unsigned char)String[Size - 3]; [[fallthrough]];
93bdd1243dSDimitry Andric   case 2: V = (V << 8) | (unsigned char)String[Size - 2]; [[fallthrough]];
940b57cec5SDimitry Andric   case 3: V = (V << 8) | (unsigned char)String[Size - 1]; break;
950b57cec5SDimitry Andric   default: return; // Nothing left.
960b57cec5SDimitry Andric   }
970b57cec5SDimitry Andric 
980b57cec5SDimitry Andric   Bits.push_back(V);
990b57cec5SDimitry Andric }
1000b57cec5SDimitry Andric 
1010b57cec5SDimitry Andric // AddNodeID - Adds the Bit data of another ID to *this.
AddNodeID(const FoldingSetNodeID & ID)1020b57cec5SDimitry Andric void FoldingSetNodeID::AddNodeID(const FoldingSetNodeID &ID) {
1030b57cec5SDimitry Andric   Bits.append(ID.Bits.begin(), ID.Bits.end());
1040b57cec5SDimitry Andric }
1050b57cec5SDimitry Andric 
1060b57cec5SDimitry Andric /// operator== - Used to compare two nodes to each other.
1070b57cec5SDimitry Andric ///
operator ==(const FoldingSetNodeID & RHS) const1080b57cec5SDimitry Andric bool FoldingSetNodeID::operator==(const FoldingSetNodeID &RHS) const {
1090b57cec5SDimitry Andric   return *this == FoldingSetNodeIDRef(RHS.Bits.data(), RHS.Bits.size());
1100b57cec5SDimitry Andric }
1110b57cec5SDimitry Andric 
1120b57cec5SDimitry Andric /// operator== - Used to compare two nodes to each other.
1130b57cec5SDimitry Andric ///
operator ==(FoldingSetNodeIDRef RHS) const1140b57cec5SDimitry Andric bool FoldingSetNodeID::operator==(FoldingSetNodeIDRef RHS) const {
1150b57cec5SDimitry Andric   return FoldingSetNodeIDRef(Bits.data(), Bits.size()) == RHS;
1160b57cec5SDimitry Andric }
1170b57cec5SDimitry Andric 
1180b57cec5SDimitry Andric /// Used to compare the "ordering" of two nodes as defined by the
1190b57cec5SDimitry Andric /// profiled bits and their ordering defined by memcmp().
operator <(const FoldingSetNodeID & RHS) const1200b57cec5SDimitry Andric bool FoldingSetNodeID::operator<(const FoldingSetNodeID &RHS) const {
1210b57cec5SDimitry Andric   return *this < FoldingSetNodeIDRef(RHS.Bits.data(), RHS.Bits.size());
1220b57cec5SDimitry Andric }
1230b57cec5SDimitry Andric 
operator <(FoldingSetNodeIDRef RHS) const1240b57cec5SDimitry Andric bool FoldingSetNodeID::operator<(FoldingSetNodeIDRef RHS) const {
1250b57cec5SDimitry Andric   return FoldingSetNodeIDRef(Bits.data(), Bits.size()) < RHS;
1260b57cec5SDimitry Andric }
1270b57cec5SDimitry Andric 
1280b57cec5SDimitry Andric /// Intern - Copy this node's data to a memory region allocated from the
1290b57cec5SDimitry Andric /// given allocator and return a FoldingSetNodeIDRef describing the
1300b57cec5SDimitry Andric /// interned data.
1310b57cec5SDimitry Andric FoldingSetNodeIDRef
Intern(BumpPtrAllocator & Allocator) const1320b57cec5SDimitry Andric FoldingSetNodeID::Intern(BumpPtrAllocator &Allocator) const {
1330b57cec5SDimitry Andric   unsigned *New = Allocator.Allocate<unsigned>(Bits.size());
1340b57cec5SDimitry Andric   std::uninitialized_copy(Bits.begin(), Bits.end(), New);
1350b57cec5SDimitry Andric   return FoldingSetNodeIDRef(New, Bits.size());
1360b57cec5SDimitry Andric }
1370b57cec5SDimitry Andric 
1380b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
1390b57cec5SDimitry Andric /// Helper functions for FoldingSetBase.
1400b57cec5SDimitry Andric 
1410b57cec5SDimitry Andric /// GetNextPtr - In order to save space, each bucket is a
1420b57cec5SDimitry Andric /// singly-linked-list. In order to make deletion more efficient, we make
1430b57cec5SDimitry Andric /// the list circular, so we can delete a node without computing its hash.
1440b57cec5SDimitry Andric /// The problem with this is that the start of the hash buckets are not
1450b57cec5SDimitry Andric /// Nodes.  If NextInBucketPtr is a bucket pointer, this method returns null:
1460b57cec5SDimitry Andric /// use GetBucketPtr when this happens.
GetNextPtr(void * NextInBucketPtr)1470b57cec5SDimitry Andric static FoldingSetBase::Node *GetNextPtr(void *NextInBucketPtr) {
1480b57cec5SDimitry Andric   // The low bit is set if this is the pointer back to the bucket.
1490b57cec5SDimitry Andric   if (reinterpret_cast<intptr_t>(NextInBucketPtr) & 1)
1500b57cec5SDimitry Andric     return nullptr;
1510b57cec5SDimitry Andric 
1520b57cec5SDimitry Andric   return static_cast<FoldingSetBase::Node*>(NextInBucketPtr);
1530b57cec5SDimitry Andric }
1540b57cec5SDimitry Andric 
1550b57cec5SDimitry Andric 
1560b57cec5SDimitry Andric /// testing.
GetBucketPtr(void * NextInBucketPtr)1570b57cec5SDimitry Andric static void **GetBucketPtr(void *NextInBucketPtr) {
1580b57cec5SDimitry Andric   intptr_t Ptr = reinterpret_cast<intptr_t>(NextInBucketPtr);
1590b57cec5SDimitry Andric   assert((Ptr & 1) && "Not a bucket pointer");
1600b57cec5SDimitry Andric   return reinterpret_cast<void**>(Ptr & ~intptr_t(1));
1610b57cec5SDimitry Andric }
1620b57cec5SDimitry Andric 
1630b57cec5SDimitry Andric /// GetBucketFor - Hash the specified node ID and return the hash bucket for
1640b57cec5SDimitry Andric /// the specified ID.
GetBucketFor(unsigned Hash,void ** Buckets,unsigned NumBuckets)1650b57cec5SDimitry Andric static void **GetBucketFor(unsigned Hash, void **Buckets, unsigned NumBuckets) {
1660b57cec5SDimitry Andric   // NumBuckets is always a power of 2.
1670b57cec5SDimitry Andric   unsigned BucketNum = Hash & (NumBuckets-1);
1680b57cec5SDimitry Andric   return Buckets + BucketNum;
1690b57cec5SDimitry Andric }
1700b57cec5SDimitry Andric 
1710b57cec5SDimitry Andric /// AllocateBuckets - Allocated initialized bucket memory.
AllocateBuckets(unsigned NumBuckets)1720b57cec5SDimitry Andric static void **AllocateBuckets(unsigned NumBuckets) {
1730b57cec5SDimitry Andric   void **Buckets = static_cast<void**>(safe_calloc(NumBuckets + 1,
1740b57cec5SDimitry Andric                                                    sizeof(void*)));
1750b57cec5SDimitry Andric   // Set the very last bucket to be a non-null "pointer".
1760b57cec5SDimitry Andric   Buckets[NumBuckets] = reinterpret_cast<void*>(-1);
1770b57cec5SDimitry Andric   return Buckets;
1780b57cec5SDimitry Andric }
1790b57cec5SDimitry Andric 
1800b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
1810b57cec5SDimitry Andric // FoldingSetBase Implementation
1820b57cec5SDimitry Andric 
FoldingSetBase(unsigned Log2InitSize)1830b57cec5SDimitry Andric FoldingSetBase::FoldingSetBase(unsigned Log2InitSize) {
1840b57cec5SDimitry Andric   assert(5 < Log2InitSize && Log2InitSize < 32 &&
1850b57cec5SDimitry Andric          "Initial hash table size out of range");
1860b57cec5SDimitry Andric   NumBuckets = 1 << Log2InitSize;
1870b57cec5SDimitry Andric   Buckets = AllocateBuckets(NumBuckets);
1880b57cec5SDimitry Andric   NumNodes = 0;
1890b57cec5SDimitry Andric }
1900b57cec5SDimitry Andric 
FoldingSetBase(FoldingSetBase && Arg)1910b57cec5SDimitry Andric FoldingSetBase::FoldingSetBase(FoldingSetBase &&Arg)
1920b57cec5SDimitry Andric     : Buckets(Arg.Buckets), NumBuckets(Arg.NumBuckets), NumNodes(Arg.NumNodes) {
1930b57cec5SDimitry Andric   Arg.Buckets = nullptr;
1940b57cec5SDimitry Andric   Arg.NumBuckets = 0;
1950b57cec5SDimitry Andric   Arg.NumNodes = 0;
1960b57cec5SDimitry Andric }
1970b57cec5SDimitry Andric 
operator =(FoldingSetBase && RHS)1980b57cec5SDimitry Andric FoldingSetBase &FoldingSetBase::operator=(FoldingSetBase &&RHS) {
1990b57cec5SDimitry Andric   free(Buckets); // This may be null if the set is in a moved-from state.
2000b57cec5SDimitry Andric   Buckets = RHS.Buckets;
2010b57cec5SDimitry Andric   NumBuckets = RHS.NumBuckets;
2020b57cec5SDimitry Andric   NumNodes = RHS.NumNodes;
2030b57cec5SDimitry Andric   RHS.Buckets = nullptr;
2040b57cec5SDimitry Andric   RHS.NumBuckets = 0;
2050b57cec5SDimitry Andric   RHS.NumNodes = 0;
2060b57cec5SDimitry Andric   return *this;
2070b57cec5SDimitry Andric }
2080b57cec5SDimitry Andric 
~FoldingSetBase()2090b57cec5SDimitry Andric FoldingSetBase::~FoldingSetBase() {
2100b57cec5SDimitry Andric   free(Buckets);
2110b57cec5SDimitry Andric }
2120b57cec5SDimitry Andric 
clear()2130b57cec5SDimitry Andric void FoldingSetBase::clear() {
2140b57cec5SDimitry Andric   // Set all but the last bucket to null pointers.
2150b57cec5SDimitry Andric   memset(Buckets, 0, NumBuckets*sizeof(void*));
2160b57cec5SDimitry Andric 
2170b57cec5SDimitry Andric   // Set the very last bucket to be a non-null "pointer".
2180b57cec5SDimitry Andric   Buckets[NumBuckets] = reinterpret_cast<void*>(-1);
2190b57cec5SDimitry Andric 
2200b57cec5SDimitry Andric   // Reset the node count to zero.
2210b57cec5SDimitry Andric   NumNodes = 0;
2220b57cec5SDimitry Andric }
2230b57cec5SDimitry Andric 
GrowBucketCount(unsigned NewBucketCount,const FoldingSetInfo & Info)2245ffd83dbSDimitry Andric void FoldingSetBase::GrowBucketCount(unsigned NewBucketCount,
2255ffd83dbSDimitry Andric                                      const FoldingSetInfo &Info) {
2265ffd83dbSDimitry Andric   assert((NewBucketCount > NumBuckets) &&
2275ffd83dbSDimitry Andric          "Can't shrink a folding set with GrowBucketCount");
2280b57cec5SDimitry Andric   assert(isPowerOf2_32(NewBucketCount) && "Bad bucket count!");
2290b57cec5SDimitry Andric   void **OldBuckets = Buckets;
2300b57cec5SDimitry Andric   unsigned OldNumBuckets = NumBuckets;
2310b57cec5SDimitry Andric 
2320b57cec5SDimitry Andric   // Clear out new buckets.
2330b57cec5SDimitry Andric   Buckets = AllocateBuckets(NewBucketCount);
2340b57cec5SDimitry Andric   // Set NumBuckets only if allocation of new buckets was successful.
2350b57cec5SDimitry Andric   NumBuckets = NewBucketCount;
2360b57cec5SDimitry Andric   NumNodes = 0;
2370b57cec5SDimitry Andric 
2380b57cec5SDimitry Andric   // Walk the old buckets, rehashing nodes into their new place.
2390b57cec5SDimitry Andric   FoldingSetNodeID TempID;
2400b57cec5SDimitry Andric   for (unsigned i = 0; i != OldNumBuckets; ++i) {
2410b57cec5SDimitry Andric     void *Probe = OldBuckets[i];
2420b57cec5SDimitry Andric     if (!Probe) continue;
2430b57cec5SDimitry Andric     while (Node *NodeInBucket = GetNextPtr(Probe)) {
2440b57cec5SDimitry Andric       // Figure out the next link, remove NodeInBucket from the old link.
2450b57cec5SDimitry Andric       Probe = NodeInBucket->getNextInBucket();
2460b57cec5SDimitry Andric       NodeInBucket->SetNextInBucket(nullptr);
2470b57cec5SDimitry Andric 
2480b57cec5SDimitry Andric       // Insert the node into the new bucket, after recomputing the hash.
2490b57cec5SDimitry Andric       InsertNode(NodeInBucket,
2505ffd83dbSDimitry Andric                  GetBucketFor(Info.ComputeNodeHash(this, NodeInBucket, TempID),
2515ffd83dbSDimitry Andric                               Buckets, NumBuckets),
2525ffd83dbSDimitry Andric                  Info);
2530b57cec5SDimitry Andric       TempID.clear();
2540b57cec5SDimitry Andric     }
2550b57cec5SDimitry Andric   }
2560b57cec5SDimitry Andric 
2570b57cec5SDimitry Andric   free(OldBuckets);
2580b57cec5SDimitry Andric }
2590b57cec5SDimitry Andric 
2600b57cec5SDimitry Andric /// GrowHashTable - Double the size of the hash table and rehash everything.
2610b57cec5SDimitry Andric ///
GrowHashTable(const FoldingSetInfo & Info)2625ffd83dbSDimitry Andric void FoldingSetBase::GrowHashTable(const FoldingSetInfo &Info) {
2635ffd83dbSDimitry Andric   GrowBucketCount(NumBuckets * 2, Info);
2640b57cec5SDimitry Andric }
2650b57cec5SDimitry Andric 
reserve(unsigned EltCount,const FoldingSetInfo & Info)2665ffd83dbSDimitry Andric void FoldingSetBase::reserve(unsigned EltCount, const FoldingSetInfo &Info) {
2670b57cec5SDimitry Andric   // This will give us somewhere between EltCount / 2 and
2680b57cec5SDimitry Andric   // EltCount buckets.  This puts us in the load factor
2690b57cec5SDimitry Andric   // range of 1.0 - 2.0.
2700b57cec5SDimitry Andric   if(EltCount < capacity())
2710b57cec5SDimitry Andric     return;
272*06c3fb27SDimitry Andric   GrowBucketCount(llvm::bit_floor(EltCount), Info);
2730b57cec5SDimitry Andric }
2740b57cec5SDimitry Andric 
2750b57cec5SDimitry Andric /// FindNodeOrInsertPos - Look up the node specified by ID.  If it exists,
2760b57cec5SDimitry Andric /// return it.  If not, return the insertion token that will make insertion
2770b57cec5SDimitry Andric /// faster.
FindNodeOrInsertPos(const FoldingSetNodeID & ID,void * & InsertPos,const FoldingSetInfo & Info)2785ffd83dbSDimitry Andric FoldingSetBase::Node *FoldingSetBase::FindNodeOrInsertPos(
2795ffd83dbSDimitry Andric     const FoldingSetNodeID &ID, void *&InsertPos, const FoldingSetInfo &Info) {
2800b57cec5SDimitry Andric   unsigned IDHash = ID.ComputeHash();
2810b57cec5SDimitry Andric   void **Bucket = GetBucketFor(IDHash, Buckets, NumBuckets);
2820b57cec5SDimitry Andric   void *Probe = *Bucket;
2830b57cec5SDimitry Andric 
2840b57cec5SDimitry Andric   InsertPos = nullptr;
2850b57cec5SDimitry Andric 
2860b57cec5SDimitry Andric   FoldingSetNodeID TempID;
2870b57cec5SDimitry Andric   while (Node *NodeInBucket = GetNextPtr(Probe)) {
2885ffd83dbSDimitry Andric     if (Info.NodeEquals(this, NodeInBucket, ID, IDHash, TempID))
2890b57cec5SDimitry Andric       return NodeInBucket;
2900b57cec5SDimitry Andric     TempID.clear();
2910b57cec5SDimitry Andric 
2920b57cec5SDimitry Andric     Probe = NodeInBucket->getNextInBucket();
2930b57cec5SDimitry Andric   }
2940b57cec5SDimitry Andric 
2950b57cec5SDimitry Andric   // Didn't find the node, return null with the bucket as the InsertPos.
2960b57cec5SDimitry Andric   InsertPos = Bucket;
2970b57cec5SDimitry Andric   return nullptr;
2980b57cec5SDimitry Andric }
2990b57cec5SDimitry Andric 
3000b57cec5SDimitry Andric /// InsertNode - Insert the specified node into the folding set, knowing that it
3010b57cec5SDimitry Andric /// is not already in the map.  InsertPos must be obtained from
3020b57cec5SDimitry Andric /// FindNodeOrInsertPos.
InsertNode(Node * N,void * InsertPos,const FoldingSetInfo & Info)3035ffd83dbSDimitry Andric void FoldingSetBase::InsertNode(Node *N, void *InsertPos,
3045ffd83dbSDimitry Andric                                 const FoldingSetInfo &Info) {
3050b57cec5SDimitry Andric   assert(!N->getNextInBucket());
3060b57cec5SDimitry Andric   // Do we need to grow the hashtable?
3070b57cec5SDimitry Andric   if (NumNodes+1 > capacity()) {
3085ffd83dbSDimitry Andric     GrowHashTable(Info);
3090b57cec5SDimitry Andric     FoldingSetNodeID TempID;
3105ffd83dbSDimitry Andric     InsertPos = GetBucketFor(Info.ComputeNodeHash(this, N, TempID), Buckets,
3115ffd83dbSDimitry Andric                              NumBuckets);
3120b57cec5SDimitry Andric   }
3130b57cec5SDimitry Andric 
3140b57cec5SDimitry Andric   ++NumNodes;
3150b57cec5SDimitry Andric 
3160b57cec5SDimitry Andric   /// The insert position is actually a bucket pointer.
3170b57cec5SDimitry Andric   void **Bucket = static_cast<void**>(InsertPos);
3180b57cec5SDimitry Andric 
3190b57cec5SDimitry Andric   void *Next = *Bucket;
3200b57cec5SDimitry Andric 
3210b57cec5SDimitry Andric   // If this is the first insertion into this bucket, its next pointer will be
3220b57cec5SDimitry Andric   // null.  Pretend as if it pointed to itself, setting the low bit to indicate
3230b57cec5SDimitry Andric   // that it is a pointer to the bucket.
3240b57cec5SDimitry Andric   if (!Next)
3250b57cec5SDimitry Andric     Next = reinterpret_cast<void*>(reinterpret_cast<intptr_t>(Bucket)|1);
3260b57cec5SDimitry Andric 
3270b57cec5SDimitry Andric   // Set the node's next pointer, and make the bucket point to the node.
3280b57cec5SDimitry Andric   N->SetNextInBucket(Next);
3290b57cec5SDimitry Andric   *Bucket = N;
3300b57cec5SDimitry Andric }
3310b57cec5SDimitry Andric 
3320b57cec5SDimitry Andric /// RemoveNode - Remove a node from the folding set, returning true if one was
3330b57cec5SDimitry Andric /// removed or false if the node was not in the folding set.
RemoveNode(Node * N)3340b57cec5SDimitry Andric bool FoldingSetBase::RemoveNode(Node *N) {
3350b57cec5SDimitry Andric   // Because each bucket is a circular list, we don't need to compute N's hash
3360b57cec5SDimitry Andric   // to remove it.
3370b57cec5SDimitry Andric   void *Ptr = N->getNextInBucket();
3380b57cec5SDimitry Andric   if (!Ptr) return false;  // Not in folding set.
3390b57cec5SDimitry Andric 
3400b57cec5SDimitry Andric   --NumNodes;
3410b57cec5SDimitry Andric   N->SetNextInBucket(nullptr);
3420b57cec5SDimitry Andric 
3430b57cec5SDimitry Andric   // Remember what N originally pointed to, either a bucket or another node.
3440b57cec5SDimitry Andric   void *NodeNextPtr = Ptr;
3450b57cec5SDimitry Andric 
3460b57cec5SDimitry Andric   // Chase around the list until we find the node (or bucket) which points to N.
3470b57cec5SDimitry Andric   while (true) {
3480b57cec5SDimitry Andric     if (Node *NodeInBucket = GetNextPtr(Ptr)) {
3490b57cec5SDimitry Andric       // Advance pointer.
3500b57cec5SDimitry Andric       Ptr = NodeInBucket->getNextInBucket();
3510b57cec5SDimitry Andric 
3520b57cec5SDimitry Andric       // We found a node that points to N, change it to point to N's next node,
3530b57cec5SDimitry Andric       // removing N from the list.
3540b57cec5SDimitry Andric       if (Ptr == N) {
3550b57cec5SDimitry Andric         NodeInBucket->SetNextInBucket(NodeNextPtr);
3560b57cec5SDimitry Andric         return true;
3570b57cec5SDimitry Andric       }
3580b57cec5SDimitry Andric     } else {
3590b57cec5SDimitry Andric       void **Bucket = GetBucketPtr(Ptr);
3600b57cec5SDimitry Andric       Ptr = *Bucket;
3610b57cec5SDimitry Andric 
3620b57cec5SDimitry Andric       // If we found that the bucket points to N, update the bucket to point to
3630b57cec5SDimitry Andric       // whatever is next.
3640b57cec5SDimitry Andric       if (Ptr == N) {
3650b57cec5SDimitry Andric         *Bucket = NodeNextPtr;
3660b57cec5SDimitry Andric         return true;
3670b57cec5SDimitry Andric       }
3680b57cec5SDimitry Andric     }
3690b57cec5SDimitry Andric   }
3700b57cec5SDimitry Andric }
3710b57cec5SDimitry Andric 
3720b57cec5SDimitry Andric /// GetOrInsertNode - If there is an existing simple Node exactly
3730b57cec5SDimitry Andric /// equal to the specified node, return it.  Otherwise, insert 'N' and it
3740b57cec5SDimitry Andric /// instead.
3755ffd83dbSDimitry Andric FoldingSetBase::Node *
GetOrInsertNode(FoldingSetBase::Node * N,const FoldingSetInfo & Info)3765ffd83dbSDimitry Andric FoldingSetBase::GetOrInsertNode(FoldingSetBase::Node *N,
3775ffd83dbSDimitry Andric                                 const FoldingSetInfo &Info) {
3780b57cec5SDimitry Andric   FoldingSetNodeID ID;
3795ffd83dbSDimitry Andric   Info.GetNodeProfile(this, N, ID);
3800b57cec5SDimitry Andric   void *IP;
3815ffd83dbSDimitry Andric   if (Node *E = FindNodeOrInsertPos(ID, IP, Info))
3820b57cec5SDimitry Andric     return E;
3835ffd83dbSDimitry Andric   InsertNode(N, IP, Info);
3840b57cec5SDimitry Andric   return N;
3850b57cec5SDimitry Andric }
3860b57cec5SDimitry Andric 
3870b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
3880b57cec5SDimitry Andric // FoldingSetIteratorImpl Implementation
3890b57cec5SDimitry Andric 
FoldingSetIteratorImpl(void ** Bucket)3900b57cec5SDimitry Andric FoldingSetIteratorImpl::FoldingSetIteratorImpl(void **Bucket) {
3910b57cec5SDimitry Andric   // Skip to the first non-null non-self-cycle bucket.
3920b57cec5SDimitry Andric   while (*Bucket != reinterpret_cast<void*>(-1) &&
3930b57cec5SDimitry Andric          (!*Bucket || !GetNextPtr(*Bucket)))
3940b57cec5SDimitry Andric     ++Bucket;
3950b57cec5SDimitry Andric 
3960b57cec5SDimitry Andric   NodePtr = static_cast<FoldingSetNode*>(*Bucket);
3970b57cec5SDimitry Andric }
3980b57cec5SDimitry Andric 
advance()3990b57cec5SDimitry Andric void FoldingSetIteratorImpl::advance() {
4000b57cec5SDimitry Andric   // If there is another link within this bucket, go to it.
4010b57cec5SDimitry Andric   void *Probe = NodePtr->getNextInBucket();
4020b57cec5SDimitry Andric 
4030b57cec5SDimitry Andric   if (FoldingSetNode *NextNodeInBucket = GetNextPtr(Probe))
4040b57cec5SDimitry Andric     NodePtr = NextNodeInBucket;
4050b57cec5SDimitry Andric   else {
4060b57cec5SDimitry Andric     // Otherwise, this is the last link in this bucket.
4070b57cec5SDimitry Andric     void **Bucket = GetBucketPtr(Probe);
4080b57cec5SDimitry Andric 
4090b57cec5SDimitry Andric     // Skip to the next non-null non-self-cycle bucket.
4100b57cec5SDimitry Andric     do {
4110b57cec5SDimitry Andric       ++Bucket;
4120b57cec5SDimitry Andric     } while (*Bucket != reinterpret_cast<void*>(-1) &&
4130b57cec5SDimitry Andric              (!*Bucket || !GetNextPtr(*Bucket)));
4140b57cec5SDimitry Andric 
4150b57cec5SDimitry Andric     NodePtr = static_cast<FoldingSetNode*>(*Bucket);
4160b57cec5SDimitry Andric   }
4170b57cec5SDimitry Andric }
4180b57cec5SDimitry Andric 
4190b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
4200b57cec5SDimitry Andric // FoldingSetBucketIteratorImpl Implementation
4210b57cec5SDimitry Andric 
FoldingSetBucketIteratorImpl(void ** Bucket)4220b57cec5SDimitry Andric FoldingSetBucketIteratorImpl::FoldingSetBucketIteratorImpl(void **Bucket) {
4230b57cec5SDimitry Andric   Ptr = (!*Bucket || !GetNextPtr(*Bucket)) ? (void*) Bucket : *Bucket;
4240b57cec5SDimitry Andric }
425