10b57cec5SDimitry Andric //===- llvm/ADT/FoldingSet.h - 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 //===----------------------------------------------------------------------===// 81fd87a68SDimitry Andric /// 91fd87a68SDimitry Andric /// \file 101fd87a68SDimitry Andric /// This file defines a hash set that can be used to remove duplication of nodes 111fd87a68SDimitry Andric /// in a graph. This code was originally created by Chris Lattner for use with 121fd87a68SDimitry Andric /// SelectionDAGCSEMap, but was isolated to provide use across the llvm code 131fd87a68SDimitry Andric /// set. 140b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 150b57cec5SDimitry Andric 160b57cec5SDimitry Andric #ifndef LLVM_ADT_FOLDINGSET_H 170b57cec5SDimitry Andric #define LLVM_ADT_FOLDINGSET_H 180b57cec5SDimitry Andric 1981ad6265SDimitry Andric #include "llvm/ADT/Hashing.h" 205f757f3fSDimitry Andric #include "llvm/ADT/STLForwardCompat.h" 210b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h" 220b57cec5SDimitry Andric #include "llvm/ADT/iterator.h" 230b57cec5SDimitry Andric #include "llvm/Support/Allocator.h" 24*0fca6ea1SDimitry Andric #include "llvm/Support/xxhash.h" 250b57cec5SDimitry Andric #include <cassert> 260b57cec5SDimitry Andric #include <cstddef> 270b57cec5SDimitry Andric #include <cstdint> 2881ad6265SDimitry Andric #include <type_traits> 290b57cec5SDimitry Andric #include <utility> 300b57cec5SDimitry Andric 310b57cec5SDimitry Andric namespace llvm { 320b57cec5SDimitry Andric 330b57cec5SDimitry Andric /// This folding set used for two purposes: 340b57cec5SDimitry Andric /// 1. Given information about a node we want to create, look up the unique 350b57cec5SDimitry Andric /// instance of the node in the set. If the node already exists, return 360b57cec5SDimitry Andric /// it, otherwise return the bucket it should be inserted into. 370b57cec5SDimitry Andric /// 2. Given a node that has already been created, remove it from the set. 380b57cec5SDimitry Andric /// 390b57cec5SDimitry Andric /// This class is implemented as a single-link chained hash table, where the 400b57cec5SDimitry Andric /// "buckets" are actually the nodes themselves (the next pointer is in the 410b57cec5SDimitry Andric /// node). The last node points back to the bucket to simplify node removal. 420b57cec5SDimitry Andric /// 430b57cec5SDimitry Andric /// Any node that is to be included in the folding set must be a subclass of 440b57cec5SDimitry Andric /// FoldingSetNode. The node class must also define a Profile method used to 450b57cec5SDimitry Andric /// establish the unique bits of data for the node. The Profile method is 460b57cec5SDimitry Andric /// passed a FoldingSetNodeID object which is used to gather the bits. Just 470b57cec5SDimitry Andric /// call one of the Add* functions defined in the FoldingSetBase::NodeID class. 480b57cec5SDimitry Andric /// NOTE: That the folding set does not own the nodes and it is the 490b57cec5SDimitry Andric /// responsibility of the user to dispose of the nodes. 500b57cec5SDimitry Andric /// 510b57cec5SDimitry Andric /// Eg. 520b57cec5SDimitry Andric /// class MyNode : public FoldingSetNode { 530b57cec5SDimitry Andric /// private: 540b57cec5SDimitry Andric /// std::string Name; 550b57cec5SDimitry Andric /// unsigned Value; 560b57cec5SDimitry Andric /// public: 570b57cec5SDimitry Andric /// MyNode(const char *N, unsigned V) : Name(N), Value(V) {} 580b57cec5SDimitry Andric /// ... 590b57cec5SDimitry Andric /// void Profile(FoldingSetNodeID &ID) const { 600b57cec5SDimitry Andric /// ID.AddString(Name); 610b57cec5SDimitry Andric /// ID.AddInteger(Value); 620b57cec5SDimitry Andric /// } 630b57cec5SDimitry Andric /// ... 640b57cec5SDimitry Andric /// }; 650b57cec5SDimitry Andric /// 660b57cec5SDimitry Andric /// To define the folding set itself use the FoldingSet template; 670b57cec5SDimitry Andric /// 680b57cec5SDimitry Andric /// Eg. 690b57cec5SDimitry Andric /// FoldingSet<MyNode> MyFoldingSet; 700b57cec5SDimitry Andric /// 710b57cec5SDimitry Andric /// Four public methods are available to manipulate the folding set; 720b57cec5SDimitry Andric /// 730b57cec5SDimitry Andric /// 1) If you have an existing node that you want add to the set but unsure 740b57cec5SDimitry Andric /// that the node might already exist then call; 750b57cec5SDimitry Andric /// 760b57cec5SDimitry Andric /// MyNode *M = MyFoldingSet.GetOrInsertNode(N); 770b57cec5SDimitry Andric /// 780b57cec5SDimitry Andric /// If The result is equal to the input then the node has been inserted. 790b57cec5SDimitry Andric /// Otherwise, the result is the node existing in the folding set, and the 800b57cec5SDimitry Andric /// input can be discarded (use the result instead.) 810b57cec5SDimitry Andric /// 820b57cec5SDimitry Andric /// 2) If you are ready to construct a node but want to check if it already 830b57cec5SDimitry Andric /// exists, then call FindNodeOrInsertPos with a FoldingSetNodeID of the bits to 840b57cec5SDimitry Andric /// check; 850b57cec5SDimitry Andric /// 860b57cec5SDimitry Andric /// FoldingSetNodeID ID; 870b57cec5SDimitry Andric /// ID.AddString(Name); 880b57cec5SDimitry Andric /// ID.AddInteger(Value); 890b57cec5SDimitry Andric /// void *InsertPoint; 900b57cec5SDimitry Andric /// 910b57cec5SDimitry Andric /// MyNode *M = MyFoldingSet.FindNodeOrInsertPos(ID, InsertPoint); 920b57cec5SDimitry Andric /// 93480093f4SDimitry Andric /// If found then M will be non-NULL, else InsertPoint will point to where it 940b57cec5SDimitry Andric /// should be inserted using InsertNode. 950b57cec5SDimitry Andric /// 96480093f4SDimitry Andric /// 3) If you get a NULL result from FindNodeOrInsertPos then you can insert a 97480093f4SDimitry Andric /// new node with InsertNode; 980b57cec5SDimitry Andric /// 99480093f4SDimitry Andric /// MyFoldingSet.InsertNode(M, InsertPoint); 1000b57cec5SDimitry Andric /// 1010b57cec5SDimitry Andric /// 4) Finally, if you want to remove a node from the folding set call; 1020b57cec5SDimitry Andric /// 103480093f4SDimitry Andric /// bool WasRemoved = MyFoldingSet.RemoveNode(M); 1040b57cec5SDimitry Andric /// 1050b57cec5SDimitry Andric /// The result indicates whether the node existed in the folding set. 1060b57cec5SDimitry Andric 1070b57cec5SDimitry Andric class FoldingSetNodeID; 1080b57cec5SDimitry Andric class StringRef; 1090b57cec5SDimitry Andric 1100b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 1110b57cec5SDimitry Andric /// FoldingSetBase - Implements the folding set functionality. The main 1120b57cec5SDimitry Andric /// structure is an array of buckets. Each bucket is indexed by the hash of 1130b57cec5SDimitry Andric /// the nodes it contains. The bucket itself points to the nodes contained 1140b57cec5SDimitry Andric /// in the bucket via a singly linked list. The last node in the list points 1150b57cec5SDimitry Andric /// back to the bucket to facilitate node removal. 1160b57cec5SDimitry Andric /// 1170b57cec5SDimitry Andric class FoldingSetBase { 1180b57cec5SDimitry Andric protected: 1190b57cec5SDimitry Andric /// Buckets - Array of bucket chains. 1200b57cec5SDimitry Andric void **Buckets; 1210b57cec5SDimitry Andric 1220b57cec5SDimitry Andric /// NumBuckets - Length of the Buckets array. Always a power of 2. 1230b57cec5SDimitry Andric unsigned NumBuckets; 1240b57cec5SDimitry Andric 1250b57cec5SDimitry Andric /// NumNodes - Number of nodes in the folding set. Growth occurs when NumNodes 1260b57cec5SDimitry Andric /// is greater than twice the number of buckets. 1270b57cec5SDimitry Andric unsigned NumNodes; 1280b57cec5SDimitry Andric 1290b57cec5SDimitry Andric explicit FoldingSetBase(unsigned Log2InitSize = 6); 1300b57cec5SDimitry Andric FoldingSetBase(FoldingSetBase &&Arg); 1310b57cec5SDimitry Andric FoldingSetBase &operator=(FoldingSetBase &&RHS); 1320b57cec5SDimitry Andric ~FoldingSetBase(); 1330b57cec5SDimitry Andric 1340b57cec5SDimitry Andric public: 1350b57cec5SDimitry Andric //===--------------------------------------------------------------------===// 1360b57cec5SDimitry Andric /// Node - This class is used to maintain the singly linked bucket list in 1370b57cec5SDimitry Andric /// a folding set. 1380b57cec5SDimitry Andric class Node { 1390b57cec5SDimitry Andric private: 1400b57cec5SDimitry Andric // NextInFoldingSetBucket - next link in the bucket list. 1410b57cec5SDimitry Andric void *NextInFoldingSetBucket = nullptr; 1420b57cec5SDimitry Andric 1430b57cec5SDimitry Andric public: 1440b57cec5SDimitry Andric Node() = default; 1450b57cec5SDimitry Andric 1460b57cec5SDimitry Andric // Accessors 1470b57cec5SDimitry Andric void *getNextInBucket() const { return NextInFoldingSetBucket; } 1480b57cec5SDimitry Andric void SetNextInBucket(void *N) { NextInFoldingSetBucket = N; } 1490b57cec5SDimitry Andric }; 1500b57cec5SDimitry Andric 1510b57cec5SDimitry Andric /// clear - Remove all nodes from the folding set. 1520b57cec5SDimitry Andric void clear(); 1530b57cec5SDimitry Andric 1540b57cec5SDimitry Andric /// size - Returns the number of nodes in the folding set. 1550b57cec5SDimitry Andric unsigned size() const { return NumNodes; } 1560b57cec5SDimitry Andric 1570b57cec5SDimitry Andric /// empty - Returns true if there are no nodes in the folding set. 1580b57cec5SDimitry Andric bool empty() const { return NumNodes == 0; } 1590b57cec5SDimitry Andric 1600b57cec5SDimitry Andric /// capacity - Returns the number of nodes permitted in the folding set 1610b57cec5SDimitry Andric /// before a rebucket operation is performed. 1620b57cec5SDimitry Andric unsigned capacity() { 1630b57cec5SDimitry Andric // We allow a load factor of up to 2.0, 1640b57cec5SDimitry Andric // so that means our capacity is NumBuckets * 2 1650b57cec5SDimitry Andric return NumBuckets * 2; 1660b57cec5SDimitry Andric } 1670b57cec5SDimitry Andric 1685ffd83dbSDimitry Andric protected: 1695ffd83dbSDimitry Andric /// Functions provided by the derived class to compute folding properties. 1705ffd83dbSDimitry Andric /// This is effectively a vtable for FoldingSetBase, except that we don't 1715ffd83dbSDimitry Andric /// actually store a pointer to it in the object. 1725ffd83dbSDimitry Andric struct FoldingSetInfo { 1735ffd83dbSDimitry Andric /// GetNodeProfile - Instantiations of the FoldingSet template implement 1745ffd83dbSDimitry Andric /// this function to gather data bits for the given node. 1755ffd83dbSDimitry Andric void (*GetNodeProfile)(const FoldingSetBase *Self, Node *N, 1765ffd83dbSDimitry Andric FoldingSetNodeID &ID); 1775ffd83dbSDimitry Andric 1785ffd83dbSDimitry Andric /// NodeEquals - Instantiations of the FoldingSet template implement 1795ffd83dbSDimitry Andric /// this function to compare the given node with the given ID. 1805ffd83dbSDimitry Andric bool (*NodeEquals)(const FoldingSetBase *Self, Node *N, 1815ffd83dbSDimitry Andric const FoldingSetNodeID &ID, unsigned IDHash, 1825ffd83dbSDimitry Andric FoldingSetNodeID &TempID); 1835ffd83dbSDimitry Andric 1845ffd83dbSDimitry Andric /// ComputeNodeHash - Instantiations of the FoldingSet template implement 1855ffd83dbSDimitry Andric /// this function to compute a hash value for the given node. 1865ffd83dbSDimitry Andric unsigned (*ComputeNodeHash)(const FoldingSetBase *Self, Node *N, 1875ffd83dbSDimitry Andric FoldingSetNodeID &TempID); 1885ffd83dbSDimitry Andric }; 1895ffd83dbSDimitry Andric 1900b57cec5SDimitry Andric private: 1910b57cec5SDimitry Andric /// GrowHashTable - Double the size of the hash table and rehash everything. 1925ffd83dbSDimitry Andric void GrowHashTable(const FoldingSetInfo &Info); 1930b57cec5SDimitry Andric 1940b57cec5SDimitry Andric /// GrowBucketCount - resize the hash table and rehash everything. 1950b57cec5SDimitry Andric /// NewBucketCount must be a power of two, and must be greater than the old 1960b57cec5SDimitry Andric /// bucket count. 1975ffd83dbSDimitry Andric void GrowBucketCount(unsigned NewBucketCount, const FoldingSetInfo &Info); 1980b57cec5SDimitry Andric 1990b57cec5SDimitry Andric protected: 2000b57cec5SDimitry Andric // The below methods are protected to encourage subclasses to provide a more 2010b57cec5SDimitry Andric // type-safe API. 2020b57cec5SDimitry Andric 2035ffd83dbSDimitry Andric /// reserve - Increase the number of buckets such that adding the 2045ffd83dbSDimitry Andric /// EltCount-th node won't cause a rebucket operation. reserve is permitted 2055ffd83dbSDimitry Andric /// to allocate more space than requested by EltCount. 2065ffd83dbSDimitry Andric void reserve(unsigned EltCount, const FoldingSetInfo &Info); 2075ffd83dbSDimitry Andric 2080b57cec5SDimitry Andric /// RemoveNode - Remove a node from the folding set, returning true if one 2090b57cec5SDimitry Andric /// was removed or false if the node was not in the folding set. 2100b57cec5SDimitry Andric bool RemoveNode(Node *N); 2110b57cec5SDimitry Andric 2120b57cec5SDimitry Andric /// GetOrInsertNode - If there is an existing simple Node exactly 2130b57cec5SDimitry Andric /// equal to the specified node, return it. Otherwise, insert 'N' and return 2140b57cec5SDimitry Andric /// it instead. 2155ffd83dbSDimitry Andric Node *GetOrInsertNode(Node *N, const FoldingSetInfo &Info); 2160b57cec5SDimitry Andric 2170b57cec5SDimitry Andric /// FindNodeOrInsertPos - Look up the node specified by ID. If it exists, 2180b57cec5SDimitry Andric /// return it. If not, return the insertion token that will make insertion 2190b57cec5SDimitry Andric /// faster. 2205ffd83dbSDimitry Andric Node *FindNodeOrInsertPos(const FoldingSetNodeID &ID, void *&InsertPos, 2215ffd83dbSDimitry Andric const FoldingSetInfo &Info); 2220b57cec5SDimitry Andric 2230b57cec5SDimitry Andric /// InsertNode - Insert the specified node into the folding set, knowing that 2240b57cec5SDimitry Andric /// it is not already in the folding set. InsertPos must be obtained from 2250b57cec5SDimitry Andric /// FindNodeOrInsertPos. 2265ffd83dbSDimitry Andric void InsertNode(Node *N, void *InsertPos, const FoldingSetInfo &Info); 2270b57cec5SDimitry Andric }; 2280b57cec5SDimitry Andric 2290b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 2300b57cec5SDimitry Andric 2310b57cec5SDimitry Andric /// DefaultFoldingSetTrait - This class provides default implementations 2320b57cec5SDimitry Andric /// for FoldingSetTrait implementations. 2330b57cec5SDimitry Andric template<typename T> struct DefaultFoldingSetTrait { 2340b57cec5SDimitry Andric static void Profile(const T &X, FoldingSetNodeID &ID) { 2350b57cec5SDimitry Andric X.Profile(ID); 2360b57cec5SDimitry Andric } 2370b57cec5SDimitry Andric static void Profile(T &X, FoldingSetNodeID &ID) { 2380b57cec5SDimitry Andric X.Profile(ID); 2390b57cec5SDimitry Andric } 2400b57cec5SDimitry Andric 2410b57cec5SDimitry Andric // Equals - Test if the profile for X would match ID, using TempID 2420b57cec5SDimitry Andric // to compute a temporary ID if necessary. The default implementation 2430b57cec5SDimitry Andric // just calls Profile and does a regular comparison. Implementations 2440b57cec5SDimitry Andric // can override this to provide more efficient implementations. 2450b57cec5SDimitry Andric static inline bool Equals(T &X, const FoldingSetNodeID &ID, unsigned IDHash, 2460b57cec5SDimitry Andric FoldingSetNodeID &TempID); 2470b57cec5SDimitry Andric 2480b57cec5SDimitry Andric // ComputeHash - Compute a hash value for X, using TempID to 2490b57cec5SDimitry Andric // compute a temporary ID if necessary. The default implementation 2500b57cec5SDimitry Andric // just calls Profile and does a regular hash computation. 2510b57cec5SDimitry Andric // Implementations can override this to provide more efficient 2520b57cec5SDimitry Andric // implementations. 2530b57cec5SDimitry Andric static inline unsigned ComputeHash(T &X, FoldingSetNodeID &TempID); 2540b57cec5SDimitry Andric }; 2550b57cec5SDimitry Andric 2560b57cec5SDimitry Andric /// FoldingSetTrait - This trait class is used to define behavior of how 2570b57cec5SDimitry Andric /// to "profile" (in the FoldingSet parlance) an object of a given type. 2580b57cec5SDimitry Andric /// The default behavior is to invoke a 'Profile' method on an object, but 2590b57cec5SDimitry Andric /// through template specialization the behavior can be tailored for specific 2600b57cec5SDimitry Andric /// types. Combined with the FoldingSetNodeWrapper class, one can add objects 2610b57cec5SDimitry Andric /// to FoldingSets that were not originally designed to have that behavior. 26281ad6265SDimitry Andric template <typename T, typename Enable = void> 26381ad6265SDimitry Andric struct FoldingSetTrait : public DefaultFoldingSetTrait<T> {}; 2640b57cec5SDimitry Andric 2650b57cec5SDimitry Andric /// DefaultContextualFoldingSetTrait - Like DefaultFoldingSetTrait, but 2660b57cec5SDimitry Andric /// for ContextualFoldingSets. 2670b57cec5SDimitry Andric template<typename T, typename Ctx> 2680b57cec5SDimitry Andric struct DefaultContextualFoldingSetTrait { 2690b57cec5SDimitry Andric static void Profile(T &X, FoldingSetNodeID &ID, Ctx Context) { 2700b57cec5SDimitry Andric X.Profile(ID, Context); 2710b57cec5SDimitry Andric } 2720b57cec5SDimitry Andric 2730b57cec5SDimitry Andric static inline bool Equals(T &X, const FoldingSetNodeID &ID, unsigned IDHash, 2740b57cec5SDimitry Andric FoldingSetNodeID &TempID, Ctx Context); 2750b57cec5SDimitry Andric static inline unsigned ComputeHash(T &X, FoldingSetNodeID &TempID, 2760b57cec5SDimitry Andric Ctx Context); 2770b57cec5SDimitry Andric }; 2780b57cec5SDimitry Andric 2790b57cec5SDimitry Andric /// ContextualFoldingSetTrait - Like FoldingSetTrait, but for 2800b57cec5SDimitry Andric /// ContextualFoldingSets. 2810b57cec5SDimitry Andric template<typename T, typename Ctx> struct ContextualFoldingSetTrait 2820b57cec5SDimitry Andric : public DefaultContextualFoldingSetTrait<T, Ctx> {}; 2830b57cec5SDimitry Andric 2840b57cec5SDimitry Andric //===--------------------------------------------------------------------===// 2850b57cec5SDimitry Andric /// FoldingSetNodeIDRef - This class describes a reference to an interned 2860b57cec5SDimitry Andric /// FoldingSetNodeID, which can be a useful to store node id data rather 2870b57cec5SDimitry Andric /// than using plain FoldingSetNodeIDs, since the 32-element SmallVector 2880b57cec5SDimitry Andric /// is often much larger than necessary, and the possibility of heap 2890b57cec5SDimitry Andric /// allocation means it requires a non-trivial destructor call. 2900b57cec5SDimitry Andric class FoldingSetNodeIDRef { 2910b57cec5SDimitry Andric const unsigned *Data = nullptr; 2920b57cec5SDimitry Andric size_t Size = 0; 2930b57cec5SDimitry Andric 2940b57cec5SDimitry Andric public: 2950b57cec5SDimitry Andric FoldingSetNodeIDRef() = default; 2960b57cec5SDimitry Andric FoldingSetNodeIDRef(const unsigned *D, size_t S) : Data(D), Size(S) {} 2970b57cec5SDimitry Andric 298*0fca6ea1SDimitry Andric // Compute a strong hash value used to lookup the node in the FoldingSetBase. 299*0fca6ea1SDimitry Andric // The hash value is not guaranteed to be deterministic across processes. 30081ad6265SDimitry Andric unsigned ComputeHash() const { 30181ad6265SDimitry Andric return static_cast<unsigned>(hash_combine_range(Data, Data + Size)); 30281ad6265SDimitry Andric } 3030b57cec5SDimitry Andric 304*0fca6ea1SDimitry Andric // Compute a deterministic hash value across processes that is suitable for 305*0fca6ea1SDimitry Andric // on-disk serialization. 306*0fca6ea1SDimitry Andric unsigned computeStableHash() const { 307*0fca6ea1SDimitry Andric return static_cast<unsigned>(xxh3_64bits(ArrayRef( 308*0fca6ea1SDimitry Andric reinterpret_cast<const uint8_t *>(Data), sizeof(unsigned) * Size))); 309*0fca6ea1SDimitry Andric } 310*0fca6ea1SDimitry Andric 3110b57cec5SDimitry Andric bool operator==(FoldingSetNodeIDRef) const; 3120b57cec5SDimitry Andric 3130b57cec5SDimitry Andric bool operator!=(FoldingSetNodeIDRef RHS) const { return !(*this == RHS); } 3140b57cec5SDimitry Andric 3150b57cec5SDimitry Andric /// Used to compare the "ordering" of two nodes as defined by the 3160b57cec5SDimitry Andric /// profiled bits and their ordering defined by memcmp(). 3170b57cec5SDimitry Andric bool operator<(FoldingSetNodeIDRef) const; 3180b57cec5SDimitry Andric 3190b57cec5SDimitry Andric const unsigned *getData() const { return Data; } 3200b57cec5SDimitry Andric size_t getSize() const { return Size; } 3210b57cec5SDimitry Andric }; 3220b57cec5SDimitry Andric 3230b57cec5SDimitry Andric //===--------------------------------------------------------------------===// 3240b57cec5SDimitry Andric /// FoldingSetNodeID - This class is used to gather all the unique data bits of 3250b57cec5SDimitry Andric /// a node. When all the bits are gathered this class is used to produce a 3260b57cec5SDimitry Andric /// hash value for the node. 3270b57cec5SDimitry Andric class FoldingSetNodeID { 3280b57cec5SDimitry Andric /// Bits - Vector of all the data bits that make the node unique. 3290b57cec5SDimitry Andric /// Use a SmallVector to avoid a heap allocation in the common case. 3300b57cec5SDimitry Andric SmallVector<unsigned, 32> Bits; 3310b57cec5SDimitry Andric 3320b57cec5SDimitry Andric public: 3330b57cec5SDimitry Andric FoldingSetNodeID() = default; 3340b57cec5SDimitry Andric 3350b57cec5SDimitry Andric FoldingSetNodeID(FoldingSetNodeIDRef Ref) 3360b57cec5SDimitry Andric : Bits(Ref.getData(), Ref.getData() + Ref.getSize()) {} 3370b57cec5SDimitry Andric 3380b57cec5SDimitry Andric /// Add* - Add various data types to Bit data. 33981ad6265SDimitry Andric void AddPointer(const void *Ptr) { 34081ad6265SDimitry Andric // Note: this adds pointers to the hash using sizes and endianness that 34181ad6265SDimitry Andric // depend on the host. It doesn't matter, however, because hashing on 34281ad6265SDimitry Andric // pointer values is inherently unstable. Nothing should depend on the 34381ad6265SDimitry Andric // ordering of nodes in the folding set. 34481ad6265SDimitry Andric static_assert(sizeof(uintptr_t) <= sizeof(unsigned long long), 34581ad6265SDimitry Andric "unexpected pointer size"); 34681ad6265SDimitry Andric AddInteger(reinterpret_cast<uintptr_t>(Ptr)); 34781ad6265SDimitry Andric } 34881ad6265SDimitry Andric void AddInteger(signed I) { Bits.push_back(I); } 34981ad6265SDimitry Andric void AddInteger(unsigned I) { Bits.push_back(I); } 35081ad6265SDimitry Andric void AddInteger(long I) { AddInteger((unsigned long)I); } 35181ad6265SDimitry Andric void AddInteger(unsigned long I) { 35281ad6265SDimitry Andric if (sizeof(long) == sizeof(int)) 35381ad6265SDimitry Andric AddInteger(unsigned(I)); 35481ad6265SDimitry Andric else if (sizeof(long) == sizeof(long long)) { 35581ad6265SDimitry Andric AddInteger((unsigned long long)I); 35681ad6265SDimitry Andric } else { 35781ad6265SDimitry Andric llvm_unreachable("unexpected sizeof(long)"); 35881ad6265SDimitry Andric } 35981ad6265SDimitry Andric } 36081ad6265SDimitry Andric void AddInteger(long long I) { AddInteger((unsigned long long)I); } 36181ad6265SDimitry Andric void AddInteger(unsigned long long I) { 36281ad6265SDimitry Andric AddInteger(unsigned(I)); 36381ad6265SDimitry Andric AddInteger(unsigned(I >> 32)); 36481ad6265SDimitry Andric } 36581ad6265SDimitry Andric 3660b57cec5SDimitry Andric void AddBoolean(bool B) { AddInteger(B ? 1U : 0U); } 3670b57cec5SDimitry Andric void AddString(StringRef String); 3680b57cec5SDimitry Andric void AddNodeID(const FoldingSetNodeID &ID); 3690b57cec5SDimitry Andric 3700b57cec5SDimitry Andric template <typename T> 3710b57cec5SDimitry Andric inline void Add(const T &x) { FoldingSetTrait<T>::Profile(x, *this); } 3720b57cec5SDimitry Andric 3730b57cec5SDimitry Andric /// clear - Clear the accumulated profile, allowing this FoldingSetNodeID 3740b57cec5SDimitry Andric /// object to be used to compute a new profile. 3750b57cec5SDimitry Andric inline void clear() { Bits.clear(); } 3760b57cec5SDimitry Andric 377*0fca6ea1SDimitry Andric // Compute a strong hash value for this FoldingSetNodeID, used to lookup the 378*0fca6ea1SDimitry Andric // node in the FoldingSetBase. The hash value is not guaranteed to be 379*0fca6ea1SDimitry Andric // deterministic across processes. 38081ad6265SDimitry Andric unsigned ComputeHash() const { 38181ad6265SDimitry Andric return FoldingSetNodeIDRef(Bits.data(), Bits.size()).ComputeHash(); 38281ad6265SDimitry Andric } 3830b57cec5SDimitry Andric 384*0fca6ea1SDimitry Andric // Compute a deterministic hash value across processes that is suitable for 385*0fca6ea1SDimitry Andric // on-disk serialization. 386*0fca6ea1SDimitry Andric unsigned computeStableHash() const { 387*0fca6ea1SDimitry Andric return FoldingSetNodeIDRef(Bits.data(), Bits.size()).computeStableHash(); 388*0fca6ea1SDimitry Andric } 389*0fca6ea1SDimitry Andric 3900b57cec5SDimitry Andric /// operator== - Used to compare two nodes to each other. 3910b57cec5SDimitry Andric bool operator==(const FoldingSetNodeID &RHS) const; 3920b57cec5SDimitry Andric bool operator==(const FoldingSetNodeIDRef RHS) const; 3930b57cec5SDimitry Andric 3940b57cec5SDimitry Andric bool operator!=(const FoldingSetNodeID &RHS) const { return !(*this == RHS); } 3950b57cec5SDimitry Andric bool operator!=(const FoldingSetNodeIDRef RHS) const { return !(*this ==RHS);} 3960b57cec5SDimitry Andric 3970b57cec5SDimitry Andric /// Used to compare the "ordering" of two nodes as defined by the 3980b57cec5SDimitry Andric /// profiled bits and their ordering defined by memcmp(). 3990b57cec5SDimitry Andric bool operator<(const FoldingSetNodeID &RHS) const; 4000b57cec5SDimitry Andric bool operator<(const FoldingSetNodeIDRef RHS) const; 4010b57cec5SDimitry Andric 4020b57cec5SDimitry Andric /// Intern - Copy this node's data to a memory region allocated from the 4030b57cec5SDimitry Andric /// given allocator and return a FoldingSetNodeIDRef describing the 4040b57cec5SDimitry Andric /// interned data. 4050b57cec5SDimitry Andric FoldingSetNodeIDRef Intern(BumpPtrAllocator &Allocator) const; 4060b57cec5SDimitry Andric }; 4070b57cec5SDimitry Andric 4080b57cec5SDimitry Andric // Convenience type to hide the implementation of the folding set. 4090b57cec5SDimitry Andric using FoldingSetNode = FoldingSetBase::Node; 4100b57cec5SDimitry Andric template<class T> class FoldingSetIterator; 4110b57cec5SDimitry Andric template<class T> class FoldingSetBucketIterator; 4120b57cec5SDimitry Andric 4130b57cec5SDimitry Andric // Definitions of FoldingSetTrait and ContextualFoldingSetTrait functions, which 4140b57cec5SDimitry Andric // require the definition of FoldingSetNodeID. 4150b57cec5SDimitry Andric template<typename T> 4160b57cec5SDimitry Andric inline bool 4170b57cec5SDimitry Andric DefaultFoldingSetTrait<T>::Equals(T &X, const FoldingSetNodeID &ID, 4180b57cec5SDimitry Andric unsigned /*IDHash*/, 4190b57cec5SDimitry Andric FoldingSetNodeID &TempID) { 4200b57cec5SDimitry Andric FoldingSetTrait<T>::Profile(X, TempID); 4210b57cec5SDimitry Andric return TempID == ID; 4220b57cec5SDimitry Andric } 4230b57cec5SDimitry Andric template<typename T> 4240b57cec5SDimitry Andric inline unsigned 4250b57cec5SDimitry Andric DefaultFoldingSetTrait<T>::ComputeHash(T &X, FoldingSetNodeID &TempID) { 4260b57cec5SDimitry Andric FoldingSetTrait<T>::Profile(X, TempID); 4270b57cec5SDimitry Andric return TempID.ComputeHash(); 4280b57cec5SDimitry Andric } 4290b57cec5SDimitry Andric template<typename T, typename Ctx> 4300b57cec5SDimitry Andric inline bool 4310b57cec5SDimitry Andric DefaultContextualFoldingSetTrait<T, Ctx>::Equals(T &X, 4320b57cec5SDimitry Andric const FoldingSetNodeID &ID, 4330b57cec5SDimitry Andric unsigned /*IDHash*/, 4340b57cec5SDimitry Andric FoldingSetNodeID &TempID, 4350b57cec5SDimitry Andric Ctx Context) { 4360b57cec5SDimitry Andric ContextualFoldingSetTrait<T, Ctx>::Profile(X, TempID, Context); 4370b57cec5SDimitry Andric return TempID == ID; 4380b57cec5SDimitry Andric } 4390b57cec5SDimitry Andric template<typename T, typename Ctx> 4400b57cec5SDimitry Andric inline unsigned 4410b57cec5SDimitry Andric DefaultContextualFoldingSetTrait<T, Ctx>::ComputeHash(T &X, 4420b57cec5SDimitry Andric FoldingSetNodeID &TempID, 4430b57cec5SDimitry Andric Ctx Context) { 4440b57cec5SDimitry Andric ContextualFoldingSetTrait<T, Ctx>::Profile(X, TempID, Context); 4450b57cec5SDimitry Andric return TempID.ComputeHash(); 4460b57cec5SDimitry Andric } 4470b57cec5SDimitry Andric 4480b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 4490b57cec5SDimitry Andric /// FoldingSetImpl - An implementation detail that lets us share code between 4500b57cec5SDimitry Andric /// FoldingSet and ContextualFoldingSet. 4515ffd83dbSDimitry Andric template <class Derived, class T> class FoldingSetImpl : public FoldingSetBase { 4520b57cec5SDimitry Andric protected: 4530b57cec5SDimitry Andric explicit FoldingSetImpl(unsigned Log2InitSize) 4540b57cec5SDimitry Andric : FoldingSetBase(Log2InitSize) {} 4550b57cec5SDimitry Andric 4560b57cec5SDimitry Andric FoldingSetImpl(FoldingSetImpl &&Arg) = default; 4570b57cec5SDimitry Andric FoldingSetImpl &operator=(FoldingSetImpl &&RHS) = default; 4580b57cec5SDimitry Andric ~FoldingSetImpl() = default; 4590b57cec5SDimitry Andric 4600b57cec5SDimitry Andric public: 4610b57cec5SDimitry Andric using iterator = FoldingSetIterator<T>; 4620b57cec5SDimitry Andric 4630b57cec5SDimitry Andric iterator begin() { return iterator(Buckets); } 4640b57cec5SDimitry Andric iterator end() { return iterator(Buckets+NumBuckets); } 4650b57cec5SDimitry Andric 4660b57cec5SDimitry Andric using const_iterator = FoldingSetIterator<const T>; 4670b57cec5SDimitry Andric 4680b57cec5SDimitry Andric const_iterator begin() const { return const_iterator(Buckets); } 4690b57cec5SDimitry Andric const_iterator end() const { return const_iterator(Buckets+NumBuckets); } 4700b57cec5SDimitry Andric 4710b57cec5SDimitry Andric using bucket_iterator = FoldingSetBucketIterator<T>; 4720b57cec5SDimitry Andric 4730b57cec5SDimitry Andric bucket_iterator bucket_begin(unsigned hash) { 4740b57cec5SDimitry Andric return bucket_iterator(Buckets + (hash & (NumBuckets-1))); 4750b57cec5SDimitry Andric } 4760b57cec5SDimitry Andric 4770b57cec5SDimitry Andric bucket_iterator bucket_end(unsigned hash) { 4780b57cec5SDimitry Andric return bucket_iterator(Buckets + (hash & (NumBuckets-1)), true); 4790b57cec5SDimitry Andric } 4800b57cec5SDimitry Andric 4815ffd83dbSDimitry Andric /// reserve - Increase the number of buckets such that adding the 4825ffd83dbSDimitry Andric /// EltCount-th node won't cause a rebucket operation. reserve is permitted 4835ffd83dbSDimitry Andric /// to allocate more space than requested by EltCount. 4845ffd83dbSDimitry Andric void reserve(unsigned EltCount) { 4855ffd83dbSDimitry Andric return FoldingSetBase::reserve(EltCount, Derived::getFoldingSetInfo()); 4865ffd83dbSDimitry Andric } 4875ffd83dbSDimitry Andric 4880b57cec5SDimitry Andric /// RemoveNode - Remove a node from the folding set, returning true if one 4890b57cec5SDimitry Andric /// was removed or false if the node was not in the folding set. 4905ffd83dbSDimitry Andric bool RemoveNode(T *N) { 4915ffd83dbSDimitry Andric return FoldingSetBase::RemoveNode(N); 4925ffd83dbSDimitry Andric } 4930b57cec5SDimitry Andric 4940b57cec5SDimitry Andric /// GetOrInsertNode - If there is an existing simple Node exactly 4950b57cec5SDimitry Andric /// equal to the specified node, return it. Otherwise, insert 'N' and 4960b57cec5SDimitry Andric /// return it instead. 4970b57cec5SDimitry Andric T *GetOrInsertNode(T *N) { 4985ffd83dbSDimitry Andric return static_cast<T *>( 4995ffd83dbSDimitry Andric FoldingSetBase::GetOrInsertNode(N, Derived::getFoldingSetInfo())); 5000b57cec5SDimitry Andric } 5010b57cec5SDimitry Andric 5020b57cec5SDimitry Andric /// FindNodeOrInsertPos - Look up the node specified by ID. If it exists, 5030b57cec5SDimitry Andric /// return it. If not, return the insertion token that will make insertion 5040b57cec5SDimitry Andric /// faster. 5050b57cec5SDimitry Andric T *FindNodeOrInsertPos(const FoldingSetNodeID &ID, void *&InsertPos) { 5065ffd83dbSDimitry Andric return static_cast<T *>(FoldingSetBase::FindNodeOrInsertPos( 5075ffd83dbSDimitry Andric ID, InsertPos, Derived::getFoldingSetInfo())); 5080b57cec5SDimitry Andric } 5090b57cec5SDimitry Andric 5100b57cec5SDimitry Andric /// InsertNode - Insert the specified node into the folding set, knowing that 5110b57cec5SDimitry Andric /// it is not already in the folding set. InsertPos must be obtained from 5120b57cec5SDimitry Andric /// FindNodeOrInsertPos. 5130b57cec5SDimitry Andric void InsertNode(T *N, void *InsertPos) { 5145ffd83dbSDimitry Andric FoldingSetBase::InsertNode(N, InsertPos, Derived::getFoldingSetInfo()); 5150b57cec5SDimitry Andric } 5160b57cec5SDimitry Andric 5170b57cec5SDimitry Andric /// InsertNode - Insert the specified node into the folding set, knowing that 5180b57cec5SDimitry Andric /// it is not already in the folding set. 5190b57cec5SDimitry Andric void InsertNode(T *N) { 5200b57cec5SDimitry Andric T *Inserted = GetOrInsertNode(N); 5210b57cec5SDimitry Andric (void)Inserted; 5220b57cec5SDimitry Andric assert(Inserted == N && "Node already inserted!"); 5230b57cec5SDimitry Andric } 5240b57cec5SDimitry Andric }; 5250b57cec5SDimitry Andric 5260b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 5270b57cec5SDimitry Andric /// FoldingSet - This template class is used to instantiate a specialized 5280b57cec5SDimitry Andric /// implementation of the folding set to the node class T. T must be a 5290b57cec5SDimitry Andric /// subclass of FoldingSetNode and implement a Profile function. 5300b57cec5SDimitry Andric /// 5310b57cec5SDimitry Andric /// Note that this set type is movable and move-assignable. However, its 5320b57cec5SDimitry Andric /// moved-from state is not a valid state for anything other than 5330b57cec5SDimitry Andric /// move-assigning and destroying. This is primarily to enable movable APIs 5340b57cec5SDimitry Andric /// that incorporate these objects. 5355ffd83dbSDimitry Andric template <class T> 5365ffd83dbSDimitry Andric class FoldingSet : public FoldingSetImpl<FoldingSet<T>, T> { 5375ffd83dbSDimitry Andric using Super = FoldingSetImpl<FoldingSet, T>; 5380b57cec5SDimitry Andric using Node = typename Super::Node; 5390b57cec5SDimitry Andric 5405ffd83dbSDimitry Andric /// GetNodeProfile - Each instantiation of the FoldingSet needs to provide a 5410b57cec5SDimitry Andric /// way to convert nodes into a unique specifier. 5425ffd83dbSDimitry Andric static void GetNodeProfile(const FoldingSetBase *, Node *N, 5435ffd83dbSDimitry Andric FoldingSetNodeID &ID) { 5440b57cec5SDimitry Andric T *TN = static_cast<T *>(N); 5450b57cec5SDimitry Andric FoldingSetTrait<T>::Profile(*TN, ID); 5460b57cec5SDimitry Andric } 5470b57cec5SDimitry Andric 5480b57cec5SDimitry Andric /// NodeEquals - Instantiations may optionally provide a way to compare a 5490b57cec5SDimitry Andric /// node with a specified ID. 5505ffd83dbSDimitry Andric static bool NodeEquals(const FoldingSetBase *, Node *N, 5515ffd83dbSDimitry Andric const FoldingSetNodeID &ID, unsigned IDHash, 5525ffd83dbSDimitry Andric FoldingSetNodeID &TempID) { 5530b57cec5SDimitry Andric T *TN = static_cast<T *>(N); 5540b57cec5SDimitry Andric return FoldingSetTrait<T>::Equals(*TN, ID, IDHash, TempID); 5550b57cec5SDimitry Andric } 5560b57cec5SDimitry Andric 5570b57cec5SDimitry Andric /// ComputeNodeHash - Instantiations may optionally provide a way to compute a 5580b57cec5SDimitry Andric /// hash value directly from a node. 5595ffd83dbSDimitry Andric static unsigned ComputeNodeHash(const FoldingSetBase *, Node *N, 5605ffd83dbSDimitry Andric FoldingSetNodeID &TempID) { 5610b57cec5SDimitry Andric T *TN = static_cast<T *>(N); 5620b57cec5SDimitry Andric return FoldingSetTrait<T>::ComputeHash(*TN, TempID); 5630b57cec5SDimitry Andric } 5640b57cec5SDimitry Andric 5655ffd83dbSDimitry Andric static const FoldingSetBase::FoldingSetInfo &getFoldingSetInfo() { 5665ffd83dbSDimitry Andric static constexpr FoldingSetBase::FoldingSetInfo Info = { 5675ffd83dbSDimitry Andric GetNodeProfile, NodeEquals, ComputeNodeHash}; 5685ffd83dbSDimitry Andric return Info; 5695ffd83dbSDimitry Andric } 5705ffd83dbSDimitry Andric friend Super; 5715ffd83dbSDimitry Andric 5720b57cec5SDimitry Andric public: 5730b57cec5SDimitry Andric explicit FoldingSet(unsigned Log2InitSize = 6) : Super(Log2InitSize) {} 5740b57cec5SDimitry Andric FoldingSet(FoldingSet &&Arg) = default; 5750b57cec5SDimitry Andric FoldingSet &operator=(FoldingSet &&RHS) = default; 5760b57cec5SDimitry Andric }; 5770b57cec5SDimitry Andric 5780b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 5790b57cec5SDimitry Andric /// ContextualFoldingSet - This template class is a further refinement 5800b57cec5SDimitry Andric /// of FoldingSet which provides a context argument when calling 5810b57cec5SDimitry Andric /// Profile on its nodes. Currently, that argument is fixed at 5820b57cec5SDimitry Andric /// initialization time. 5830b57cec5SDimitry Andric /// 5840b57cec5SDimitry Andric /// T must be a subclass of FoldingSetNode and implement a Profile 5850b57cec5SDimitry Andric /// function with signature 5860b57cec5SDimitry Andric /// void Profile(FoldingSetNodeID &, Ctx); 5870b57cec5SDimitry Andric template <class T, class Ctx> 5885ffd83dbSDimitry Andric class ContextualFoldingSet 5895ffd83dbSDimitry Andric : public FoldingSetImpl<ContextualFoldingSet<T, Ctx>, T> { 5900b57cec5SDimitry Andric // Unfortunately, this can't derive from FoldingSet<T> because the 5910b57cec5SDimitry Andric // construction of the vtable for FoldingSet<T> requires 5920b57cec5SDimitry Andric // FoldingSet<T>::GetNodeProfile to be instantiated, which in turn 5930b57cec5SDimitry Andric // requires a single-argument T::Profile(). 5940b57cec5SDimitry Andric 5955ffd83dbSDimitry Andric using Super = FoldingSetImpl<ContextualFoldingSet, T>; 5960b57cec5SDimitry Andric using Node = typename Super::Node; 5970b57cec5SDimitry Andric 5980b57cec5SDimitry Andric Ctx Context; 5990b57cec5SDimitry Andric 6005ffd83dbSDimitry Andric static const Ctx &getContext(const FoldingSetBase *Base) { 6015ffd83dbSDimitry Andric return static_cast<const ContextualFoldingSet*>(Base)->Context; 6025ffd83dbSDimitry Andric } 6035ffd83dbSDimitry Andric 6040b57cec5SDimitry Andric /// GetNodeProfile - Each instantiatation of the FoldingSet needs to provide a 6050b57cec5SDimitry Andric /// way to convert nodes into a unique specifier. 6065ffd83dbSDimitry Andric static void GetNodeProfile(const FoldingSetBase *Base, Node *N, 6075ffd83dbSDimitry Andric FoldingSetNodeID &ID) { 6080b57cec5SDimitry Andric T *TN = static_cast<T *>(N); 6095ffd83dbSDimitry Andric ContextualFoldingSetTrait<T, Ctx>::Profile(*TN, ID, getContext(Base)); 6100b57cec5SDimitry Andric } 6110b57cec5SDimitry Andric 6125ffd83dbSDimitry Andric static bool NodeEquals(const FoldingSetBase *Base, Node *N, 6135ffd83dbSDimitry Andric const FoldingSetNodeID &ID, unsigned IDHash, 6145ffd83dbSDimitry Andric FoldingSetNodeID &TempID) { 6150b57cec5SDimitry Andric T *TN = static_cast<T *>(N); 6160b57cec5SDimitry Andric return ContextualFoldingSetTrait<T, Ctx>::Equals(*TN, ID, IDHash, TempID, 6175ffd83dbSDimitry Andric getContext(Base)); 6180b57cec5SDimitry Andric } 6190b57cec5SDimitry Andric 6205ffd83dbSDimitry Andric static unsigned ComputeNodeHash(const FoldingSetBase *Base, Node *N, 6215ffd83dbSDimitry Andric FoldingSetNodeID &TempID) { 6220b57cec5SDimitry Andric T *TN = static_cast<T *>(N); 6235ffd83dbSDimitry Andric return ContextualFoldingSetTrait<T, Ctx>::ComputeHash(*TN, TempID, 6245ffd83dbSDimitry Andric getContext(Base)); 6250b57cec5SDimitry Andric } 6260b57cec5SDimitry Andric 6275ffd83dbSDimitry Andric static const FoldingSetBase::FoldingSetInfo &getFoldingSetInfo() { 6285ffd83dbSDimitry Andric static constexpr FoldingSetBase::FoldingSetInfo Info = { 6295ffd83dbSDimitry Andric GetNodeProfile, NodeEquals, ComputeNodeHash}; 6305ffd83dbSDimitry Andric return Info; 6315ffd83dbSDimitry Andric } 6325ffd83dbSDimitry Andric friend Super; 6335ffd83dbSDimitry Andric 6340b57cec5SDimitry Andric public: 6350b57cec5SDimitry Andric explicit ContextualFoldingSet(Ctx Context, unsigned Log2InitSize = 6) 6360b57cec5SDimitry Andric : Super(Log2InitSize), Context(Context) {} 6370b57cec5SDimitry Andric 6380b57cec5SDimitry Andric Ctx getContext() const { return Context; } 6390b57cec5SDimitry Andric }; 6400b57cec5SDimitry Andric 6410b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 6420b57cec5SDimitry Andric /// FoldingSetVector - This template class combines a FoldingSet and a vector 6430b57cec5SDimitry Andric /// to provide the interface of FoldingSet but with deterministic iteration 6440b57cec5SDimitry Andric /// order based on the insertion order. T must be a subclass of FoldingSetNode 6450b57cec5SDimitry Andric /// and implement a Profile function. 6460b57cec5SDimitry Andric template <class T, class VectorT = SmallVector<T*, 8>> 6470b57cec5SDimitry Andric class FoldingSetVector { 6480b57cec5SDimitry Andric FoldingSet<T> Set; 6490b57cec5SDimitry Andric VectorT Vector; 6500b57cec5SDimitry Andric 6510b57cec5SDimitry Andric public: 6520b57cec5SDimitry Andric explicit FoldingSetVector(unsigned Log2InitSize = 6) : Set(Log2InitSize) {} 6530b57cec5SDimitry Andric 6540b57cec5SDimitry Andric using iterator = pointee_iterator<typename VectorT::iterator>; 6550b57cec5SDimitry Andric 6560b57cec5SDimitry Andric iterator begin() { return Vector.begin(); } 6570b57cec5SDimitry Andric iterator end() { return Vector.end(); } 6580b57cec5SDimitry Andric 6590b57cec5SDimitry Andric using const_iterator = pointee_iterator<typename VectorT::const_iterator>; 6600b57cec5SDimitry Andric 6610b57cec5SDimitry Andric const_iterator begin() const { return Vector.begin(); } 6620b57cec5SDimitry Andric const_iterator end() const { return Vector.end(); } 6630b57cec5SDimitry Andric 6640b57cec5SDimitry Andric /// clear - Remove all nodes from the folding set. 6650b57cec5SDimitry Andric void clear() { Set.clear(); Vector.clear(); } 6660b57cec5SDimitry Andric 6670b57cec5SDimitry Andric /// FindNodeOrInsertPos - Look up the node specified by ID. If it exists, 6680b57cec5SDimitry Andric /// return it. If not, return the insertion token that will make insertion 6690b57cec5SDimitry Andric /// faster. 6700b57cec5SDimitry Andric T *FindNodeOrInsertPos(const FoldingSetNodeID &ID, void *&InsertPos) { 6710b57cec5SDimitry Andric return Set.FindNodeOrInsertPos(ID, InsertPos); 6720b57cec5SDimitry Andric } 6730b57cec5SDimitry Andric 6740b57cec5SDimitry Andric /// GetOrInsertNode - If there is an existing simple Node exactly 6750b57cec5SDimitry Andric /// equal to the specified node, return it. Otherwise, insert 'N' and 6760b57cec5SDimitry Andric /// return it instead. 6770b57cec5SDimitry Andric T *GetOrInsertNode(T *N) { 6780b57cec5SDimitry Andric T *Result = Set.GetOrInsertNode(N); 6790b57cec5SDimitry Andric if (Result == N) Vector.push_back(N); 6800b57cec5SDimitry Andric return Result; 6810b57cec5SDimitry Andric } 6820b57cec5SDimitry Andric 6830b57cec5SDimitry Andric /// InsertNode - Insert the specified node into the folding set, knowing that 6840b57cec5SDimitry Andric /// it is not already in the folding set. InsertPos must be obtained from 6850b57cec5SDimitry Andric /// FindNodeOrInsertPos. 6860b57cec5SDimitry Andric void InsertNode(T *N, void *InsertPos) { 6870b57cec5SDimitry Andric Set.InsertNode(N, InsertPos); 6880b57cec5SDimitry Andric Vector.push_back(N); 6890b57cec5SDimitry Andric } 6900b57cec5SDimitry Andric 6910b57cec5SDimitry Andric /// InsertNode - Insert the specified node into the folding set, knowing that 6920b57cec5SDimitry Andric /// it is not already in the folding set. 6930b57cec5SDimitry Andric void InsertNode(T *N) { 6940b57cec5SDimitry Andric Set.InsertNode(N); 6950b57cec5SDimitry Andric Vector.push_back(N); 6960b57cec5SDimitry Andric } 6970b57cec5SDimitry Andric 6980b57cec5SDimitry Andric /// size - Returns the number of nodes in the folding set. 6990b57cec5SDimitry Andric unsigned size() const { return Set.size(); } 7000b57cec5SDimitry Andric 7010b57cec5SDimitry Andric /// empty - Returns true if there are no nodes in the folding set. 7020b57cec5SDimitry Andric bool empty() const { return Set.empty(); } 7030b57cec5SDimitry Andric }; 7040b57cec5SDimitry Andric 7050b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 7060b57cec5SDimitry Andric /// FoldingSetIteratorImpl - This is the common iterator support shared by all 7070b57cec5SDimitry Andric /// folding sets, which knows how to walk the folding set hash table. 7080b57cec5SDimitry Andric class FoldingSetIteratorImpl { 7090b57cec5SDimitry Andric protected: 7100b57cec5SDimitry Andric FoldingSetNode *NodePtr; 7110b57cec5SDimitry Andric 7120b57cec5SDimitry Andric FoldingSetIteratorImpl(void **Bucket); 7130b57cec5SDimitry Andric 7140b57cec5SDimitry Andric void advance(); 7150b57cec5SDimitry Andric 7160b57cec5SDimitry Andric public: 7170b57cec5SDimitry Andric bool operator==(const FoldingSetIteratorImpl &RHS) const { 7180b57cec5SDimitry Andric return NodePtr == RHS.NodePtr; 7190b57cec5SDimitry Andric } 7200b57cec5SDimitry Andric bool operator!=(const FoldingSetIteratorImpl &RHS) const { 7210b57cec5SDimitry Andric return NodePtr != RHS.NodePtr; 7220b57cec5SDimitry Andric } 7230b57cec5SDimitry Andric }; 7240b57cec5SDimitry Andric 7250b57cec5SDimitry Andric template <class T> class FoldingSetIterator : public FoldingSetIteratorImpl { 7260b57cec5SDimitry Andric public: 7270b57cec5SDimitry Andric explicit FoldingSetIterator(void **Bucket) : FoldingSetIteratorImpl(Bucket) {} 7280b57cec5SDimitry Andric 7290b57cec5SDimitry Andric T &operator*() const { 7300b57cec5SDimitry Andric return *static_cast<T*>(NodePtr); 7310b57cec5SDimitry Andric } 7320b57cec5SDimitry Andric 7330b57cec5SDimitry Andric T *operator->() const { 7340b57cec5SDimitry Andric return static_cast<T*>(NodePtr); 7350b57cec5SDimitry Andric } 7360b57cec5SDimitry Andric 7370b57cec5SDimitry Andric inline FoldingSetIterator &operator++() { // Preincrement 7380b57cec5SDimitry Andric advance(); 7390b57cec5SDimitry Andric return *this; 7400b57cec5SDimitry Andric } 7410b57cec5SDimitry Andric FoldingSetIterator operator++(int) { // Postincrement 7420b57cec5SDimitry Andric FoldingSetIterator tmp = *this; ++*this; return tmp; 7430b57cec5SDimitry Andric } 7440b57cec5SDimitry Andric }; 7450b57cec5SDimitry Andric 7460b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 7470b57cec5SDimitry Andric /// FoldingSetBucketIteratorImpl - This is the common bucket iterator support 7480b57cec5SDimitry Andric /// shared by all folding sets, which knows how to walk a particular bucket 7490b57cec5SDimitry Andric /// of a folding set hash table. 7500b57cec5SDimitry Andric class FoldingSetBucketIteratorImpl { 7510b57cec5SDimitry Andric protected: 7520b57cec5SDimitry Andric void *Ptr; 7530b57cec5SDimitry Andric 7540b57cec5SDimitry Andric explicit FoldingSetBucketIteratorImpl(void **Bucket); 7550b57cec5SDimitry Andric 7560b57cec5SDimitry Andric FoldingSetBucketIteratorImpl(void **Bucket, bool) : Ptr(Bucket) {} 7570b57cec5SDimitry Andric 7580b57cec5SDimitry Andric void advance() { 7590b57cec5SDimitry Andric void *Probe = static_cast<FoldingSetNode*>(Ptr)->getNextInBucket(); 7600b57cec5SDimitry Andric uintptr_t x = reinterpret_cast<uintptr_t>(Probe) & ~0x1; 7610b57cec5SDimitry Andric Ptr = reinterpret_cast<void*>(x); 7620b57cec5SDimitry Andric } 7630b57cec5SDimitry Andric 7640b57cec5SDimitry Andric public: 7650b57cec5SDimitry Andric bool operator==(const FoldingSetBucketIteratorImpl &RHS) const { 7660b57cec5SDimitry Andric return Ptr == RHS.Ptr; 7670b57cec5SDimitry Andric } 7680b57cec5SDimitry Andric bool operator!=(const FoldingSetBucketIteratorImpl &RHS) const { 7690b57cec5SDimitry Andric return Ptr != RHS.Ptr; 7700b57cec5SDimitry Andric } 7710b57cec5SDimitry Andric }; 7720b57cec5SDimitry Andric 7730b57cec5SDimitry Andric template <class T> 7740b57cec5SDimitry Andric class FoldingSetBucketIterator : public FoldingSetBucketIteratorImpl { 7750b57cec5SDimitry Andric public: 7760b57cec5SDimitry Andric explicit FoldingSetBucketIterator(void **Bucket) : 7770b57cec5SDimitry Andric FoldingSetBucketIteratorImpl(Bucket) {} 7780b57cec5SDimitry Andric 7790b57cec5SDimitry Andric FoldingSetBucketIterator(void **Bucket, bool) : 7800b57cec5SDimitry Andric FoldingSetBucketIteratorImpl(Bucket, true) {} 7810b57cec5SDimitry Andric 7820b57cec5SDimitry Andric T &operator*() const { return *static_cast<T*>(Ptr); } 7830b57cec5SDimitry Andric T *operator->() const { return static_cast<T*>(Ptr); } 7840b57cec5SDimitry Andric 7850b57cec5SDimitry Andric inline FoldingSetBucketIterator &operator++() { // Preincrement 7860b57cec5SDimitry Andric advance(); 7870b57cec5SDimitry Andric return *this; 7880b57cec5SDimitry Andric } 7890b57cec5SDimitry Andric FoldingSetBucketIterator operator++(int) { // Postincrement 7900b57cec5SDimitry Andric FoldingSetBucketIterator tmp = *this; ++*this; return tmp; 7910b57cec5SDimitry Andric } 7920b57cec5SDimitry Andric }; 7930b57cec5SDimitry Andric 7940b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 7950b57cec5SDimitry Andric /// FoldingSetNodeWrapper - This template class is used to "wrap" arbitrary 7960b57cec5SDimitry Andric /// types in an enclosing object so that they can be inserted into FoldingSets. 7970b57cec5SDimitry Andric template <typename T> 7980b57cec5SDimitry Andric class FoldingSetNodeWrapper : public FoldingSetNode { 7990b57cec5SDimitry Andric T data; 8000b57cec5SDimitry Andric 8010b57cec5SDimitry Andric public: 8020b57cec5SDimitry Andric template <typename... Ts> 8030b57cec5SDimitry Andric explicit FoldingSetNodeWrapper(Ts &&... Args) 8040b57cec5SDimitry Andric : data(std::forward<Ts>(Args)...) {} 8050b57cec5SDimitry Andric 8060b57cec5SDimitry Andric void Profile(FoldingSetNodeID &ID) { FoldingSetTrait<T>::Profile(data, ID); } 8070b57cec5SDimitry Andric 8080b57cec5SDimitry Andric T &getValue() { return data; } 8090b57cec5SDimitry Andric const T &getValue() const { return data; } 8100b57cec5SDimitry Andric 8110b57cec5SDimitry Andric operator T&() { return data; } 8120b57cec5SDimitry Andric operator const T&() const { return data; } 8130b57cec5SDimitry Andric }; 8140b57cec5SDimitry Andric 8150b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8160b57cec5SDimitry Andric /// FastFoldingSetNode - This is a subclass of FoldingSetNode which stores 8170b57cec5SDimitry Andric /// a FoldingSetNodeID value rather than requiring the node to recompute it 8180b57cec5SDimitry Andric /// each time it is needed. This trades space for speed (which can be 8190b57cec5SDimitry Andric /// significant if the ID is long), and it also permits nodes to drop 8200b57cec5SDimitry Andric /// information that would otherwise only be required for recomputing an ID. 8210b57cec5SDimitry Andric class FastFoldingSetNode : public FoldingSetNode { 8220b57cec5SDimitry Andric FoldingSetNodeID FastID; 8230b57cec5SDimitry Andric 8240b57cec5SDimitry Andric protected: 8250b57cec5SDimitry Andric explicit FastFoldingSetNode(const FoldingSetNodeID &ID) : FastID(ID) {} 8260b57cec5SDimitry Andric 8270b57cec5SDimitry Andric public: 8280b57cec5SDimitry Andric void Profile(FoldingSetNodeID &ID) const { ID.AddNodeID(FastID); } 8290b57cec5SDimitry Andric }; 8300b57cec5SDimitry Andric 8310b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8320b57cec5SDimitry Andric // Partial specializations of FoldingSetTrait. 8330b57cec5SDimitry Andric 8340b57cec5SDimitry Andric template<typename T> struct FoldingSetTrait<T*> { 8350b57cec5SDimitry Andric static inline void Profile(T *X, FoldingSetNodeID &ID) { 8360b57cec5SDimitry Andric ID.AddPointer(X); 8370b57cec5SDimitry Andric } 8380b57cec5SDimitry Andric }; 8390b57cec5SDimitry Andric template <typename T1, typename T2> 8400b57cec5SDimitry Andric struct FoldingSetTrait<std::pair<T1, T2>> { 8410b57cec5SDimitry Andric static inline void Profile(const std::pair<T1, T2> &P, 8420b57cec5SDimitry Andric FoldingSetNodeID &ID) { 8430b57cec5SDimitry Andric ID.Add(P.first); 8440b57cec5SDimitry Andric ID.Add(P.second); 8450b57cec5SDimitry Andric } 8460b57cec5SDimitry Andric }; 8470b57cec5SDimitry Andric 84881ad6265SDimitry Andric template <typename T> 849bdd1243dSDimitry Andric struct FoldingSetTrait<T, std::enable_if_t<std::is_enum<T>::value>> { 85081ad6265SDimitry Andric static void Profile(const T &X, FoldingSetNodeID &ID) { 8515f757f3fSDimitry Andric ID.AddInteger(llvm::to_underlying(X)); 85281ad6265SDimitry Andric } 85381ad6265SDimitry Andric }; 85481ad6265SDimitry Andric 8550b57cec5SDimitry Andric } // end namespace llvm 8560b57cec5SDimitry Andric 8570b57cec5SDimitry Andric #endif // LLVM_ADT_FOLDINGSET_H 858