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