From: Richard Smith Date: Wed, 15 Apr 2020 22:00:08 +0000 (-0700) Subject: Remove vptr dispatch from FoldingSet. X-Git-Tag: llvmorg-12-init~8878 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=1132c75bd77a4ae5e4634e22ac693128e3f39e5c;p=platform%2Fupstream%2Fllvm.git Remove vptr dispatch from FoldingSet. Summary: Instead of storing a vptr in each FoldingSet instance, form an equivalent struct and pass it implicitly from FoldingSet into the various FoldingSetBase methods. This has three benefits: * FoldingSet becomes one pointer smaller. * Under LTO, the "virtual" functions are much easier to inline. * The element type no longer needs to be complete when instantiating FoldingSet, only when instantiating an insert / lookup member. Reviewers: rnk Subscribers: hiraditya, dexonsmith, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D78247 --- diff --git a/llvm/include/llvm/ADT/FoldingSet.h b/llvm/include/llvm/ADT/FoldingSet.h index 4968b1e..97dacc8 100644 --- a/llvm/include/llvm/ADT/FoldingSet.h +++ b/llvm/include/llvm/ADT/FoldingSet.h @@ -110,8 +110,6 @@ class StringRef; /// back to the bucket to facilitate node removal. /// class FoldingSetBase { - virtual void anchor(); // Out of line virtual method. - protected: /// Buckets - Array of bucket chains. void **Buckets; @@ -154,11 +152,6 @@ public: /// empty - Returns true if there are no nodes in the folding set. bool empty() const { return NumNodes == 0; } - /// reserve - Increase the number of buckets such that adding the - /// EltCount-th node won't cause a rebucket operation. reserve is permitted - /// to allocate more space than requested by EltCount. - void reserve(unsigned EltCount); - /// capacity - Returns the number of nodes permitted in the folding set /// before a rebucket operation is performed. unsigned capacity() { @@ -167,32 +160,46 @@ public: return NumBuckets * 2; } +protected: + /// Functions provided by the derived class to compute folding properties. + /// This is effectively a vtable for FoldingSetBase, except that we don't + /// actually store a pointer to it in the object. + struct FoldingSetInfo { + /// GetNodeProfile - Instantiations of the FoldingSet template implement + /// this function to gather data bits for the given node. + void (*GetNodeProfile)(const FoldingSetBase *Self, Node *N, + FoldingSetNodeID &ID); + + /// NodeEquals - Instantiations of the FoldingSet template implement + /// this function to compare the given node with the given ID. + bool (*NodeEquals)(const FoldingSetBase *Self, Node *N, + const FoldingSetNodeID &ID, unsigned IDHash, + FoldingSetNodeID &TempID); + + /// ComputeNodeHash - Instantiations of the FoldingSet template implement + /// this function to compute a hash value for the given node. + unsigned (*ComputeNodeHash)(const FoldingSetBase *Self, Node *N, + FoldingSetNodeID &TempID); + }; + private: /// GrowHashTable - Double the size of the hash table and rehash everything. - void GrowHashTable(); + void GrowHashTable(const FoldingSetInfo &Info); /// GrowBucketCount - resize the hash table and rehash everything. /// NewBucketCount must be a power of two, and must be greater than the old /// bucket count. - void GrowBucketCount(unsigned NewBucketCount); + void GrowBucketCount(unsigned NewBucketCount, const FoldingSetInfo &Info); protected: - /// GetNodeProfile - Instantiations of the FoldingSet template implement - /// this function to gather data bits for the given node. - virtual void GetNodeProfile(Node *N, FoldingSetNodeID &ID) const = 0; - - /// NodeEquals - Instantiations of the FoldingSet template implement - /// this function to compare the given node with the given ID. - virtual bool NodeEquals(Node *N, const FoldingSetNodeID &ID, unsigned IDHash, - FoldingSetNodeID &TempID) const=0; - - /// ComputeNodeHash - Instantiations of the FoldingSet template implement - /// this function to compute a hash value for the given node. - virtual unsigned ComputeNodeHash(Node *N, FoldingSetNodeID &TempID) const = 0; - // The below methods are protected to encourage subclasses to provide a more // type-safe API. + /// reserve - Increase the number of buckets such that adding the + /// EltCount-th node won't cause a rebucket operation. reserve is permitted + /// to allocate more space than requested by EltCount. + void reserve(unsigned EltCount, const FoldingSetInfo &Info); + /// RemoveNode - Remove a node from the folding set, returning true if one /// was removed or false if the node was not in the folding set. bool RemoveNode(Node *N); @@ -200,17 +207,18 @@ protected: /// GetOrInsertNode - If there is an existing simple Node exactly /// equal to the specified node, return it. Otherwise, insert 'N' and return /// it instead. - Node *GetOrInsertNode(Node *N); + Node *GetOrInsertNode(Node *N, const FoldingSetInfo &Info); /// FindNodeOrInsertPos - Look up the node specified by ID. If it exists, /// return it. If not, return the insertion token that will make insertion /// faster. - Node *FindNodeOrInsertPos(const FoldingSetNodeID &ID, void *&InsertPos); + Node *FindNodeOrInsertPos(const FoldingSetNodeID &ID, void *&InsertPos, + const FoldingSetInfo &Info); /// InsertNode - Insert the specified node into the folding set, knowing that /// it is not already in the folding set. InsertPos must be obtained from /// FindNodeOrInsertPos. - void InsertNode(Node *N, void *InsertPos); + void InsertNode(Node *N, void *InsertPos, const FoldingSetInfo &Info); }; //===----------------------------------------------------------------------===// @@ -397,7 +405,7 @@ DefaultContextualFoldingSetTrait::ComputeHash(T &X, //===----------------------------------------------------------------------===// /// FoldingSetImpl - An implementation detail that lets us share code between /// FoldingSet and ContextualFoldingSet. -template class FoldingSetImpl : public FoldingSetBase { +template class FoldingSetImpl : public FoldingSetBase { protected: explicit FoldingSetImpl(unsigned Log2InitSize) : FoldingSetBase(Log2InitSize) {} @@ -427,29 +435,40 @@ public: return bucket_iterator(Buckets + (hash & (NumBuckets-1)), true); } + /// reserve - Increase the number of buckets such that adding the + /// EltCount-th node won't cause a rebucket operation. reserve is permitted + /// to allocate more space than requested by EltCount. + void reserve(unsigned EltCount) { + return FoldingSetBase::reserve(EltCount, Derived::getFoldingSetInfo()); + } + /// RemoveNode - Remove a node from the folding set, returning true if one /// was removed or false if the node was not in the folding set. - bool RemoveNode(T *N) { return FoldingSetBase::RemoveNode(N); } + bool RemoveNode(T *N) { + return FoldingSetBase::RemoveNode(N); + } /// GetOrInsertNode - If there is an existing simple Node exactly /// equal to the specified node, return it. Otherwise, insert 'N' and /// return it instead. T *GetOrInsertNode(T *N) { - return static_cast(FoldingSetBase::GetOrInsertNode(N)); + return static_cast( + FoldingSetBase::GetOrInsertNode(N, Derived::getFoldingSetInfo())); } /// FindNodeOrInsertPos - Look up the node specified by ID. If it exists, /// return it. If not, return the insertion token that will make insertion /// faster. T *FindNodeOrInsertPos(const FoldingSetNodeID &ID, void *&InsertPos) { - return static_cast(FoldingSetBase::FindNodeOrInsertPos(ID, InsertPos)); + return static_cast(FoldingSetBase::FindNodeOrInsertPos( + ID, InsertPos, Derived::getFoldingSetInfo())); } /// InsertNode - Insert the specified node into the folding set, knowing that /// it is not already in the folding set. InsertPos must be obtained from /// FindNodeOrInsertPos. void InsertNode(T *N, void *InsertPos) { - FoldingSetBase::InsertNode(N, InsertPos); + FoldingSetBase::InsertNode(N, InsertPos, Derived::getFoldingSetInfo()); } /// InsertNode - Insert the specified node into the folding set, knowing that @@ -470,32 +489,43 @@ public: /// moved-from state is not a valid state for anything other than /// move-assigning and destroying. This is primarily to enable movable APIs /// that incorporate these objects. -template class FoldingSet final : public FoldingSetImpl { - using Super = FoldingSetImpl; +template +class FoldingSet : public FoldingSetImpl, T> { + using Super = FoldingSetImpl; using Node = typename Super::Node; /// GetNodeProfile - Each instantiatation of the FoldingSet needs to provide a /// way to convert nodes into a unique specifier. - void GetNodeProfile(Node *N, FoldingSetNodeID &ID) const override { + static void GetNodeProfile(const FoldingSetBase *, Node *N, + FoldingSetNodeID &ID) { T *TN = static_cast(N); FoldingSetTrait::Profile(*TN, ID); } /// NodeEquals - Instantiations may optionally provide a way to compare a /// node with a specified ID. - bool NodeEquals(Node *N, const FoldingSetNodeID &ID, unsigned IDHash, - FoldingSetNodeID &TempID) const override { + static bool NodeEquals(const FoldingSetBase *, Node *N, + const FoldingSetNodeID &ID, unsigned IDHash, + FoldingSetNodeID &TempID) { T *TN = static_cast(N); return FoldingSetTrait::Equals(*TN, ID, IDHash, TempID); } /// ComputeNodeHash - Instantiations may optionally provide a way to compute a /// hash value directly from a node. - unsigned ComputeNodeHash(Node *N, FoldingSetNodeID &TempID) const override { + static unsigned ComputeNodeHash(const FoldingSetBase *, Node *N, + FoldingSetNodeID &TempID) { T *TN = static_cast(N); return FoldingSetTrait::ComputeHash(*TN, TempID); } + static const FoldingSetBase::FoldingSetInfo &getFoldingSetInfo() { + static constexpr FoldingSetBase::FoldingSetInfo Info = { + GetNodeProfile, NodeEquals, ComputeNodeHash}; + return Info; + } + friend Super; + public: explicit FoldingSet(unsigned Log2InitSize = 6) : Super(Log2InitSize) {} FoldingSet(FoldingSet &&Arg) = default; @@ -512,35 +542,51 @@ public: /// function with signature /// void Profile(FoldingSetNodeID &, Ctx); template -class ContextualFoldingSet final : public FoldingSetImpl { +class ContextualFoldingSet + : public FoldingSetImpl, T> { // Unfortunately, this can't derive from FoldingSet because the // construction of the vtable for FoldingSet requires // FoldingSet::GetNodeProfile to be instantiated, which in turn // requires a single-argument T::Profile(). - using Super = FoldingSetImpl; + using Super = FoldingSetImpl; using Node = typename Super::Node; Ctx Context; + static const Ctx &getContext(const FoldingSetBase *Base) { + return static_cast(Base)->Context; + } + /// GetNodeProfile - Each instantiatation of the FoldingSet needs to provide a /// way to convert nodes into a unique specifier. - void GetNodeProfile(Node *N, FoldingSetNodeID &ID) const override { + static void GetNodeProfile(const FoldingSetBase *Base, Node *N, + FoldingSetNodeID &ID) { T *TN = static_cast(N); - ContextualFoldingSetTrait::Profile(*TN, ID, Context); + ContextualFoldingSetTrait::Profile(*TN, ID, getContext(Base)); } - bool NodeEquals(Node *N, const FoldingSetNodeID &ID, unsigned IDHash, - FoldingSetNodeID &TempID) const override { + static bool NodeEquals(const FoldingSetBase *Base, Node *N, + const FoldingSetNodeID &ID, unsigned IDHash, + FoldingSetNodeID &TempID) { T *TN = static_cast(N); return ContextualFoldingSetTrait::Equals(*TN, ID, IDHash, TempID, - Context); + getContext(Base)); } - unsigned ComputeNodeHash(Node *N, FoldingSetNodeID &TempID) const override { + static unsigned ComputeNodeHash(const FoldingSetBase *Base, Node *N, + FoldingSetNodeID &TempID) { T *TN = static_cast(N); - return ContextualFoldingSetTrait::ComputeHash(*TN, TempID, Context); + return ContextualFoldingSetTrait::ComputeHash(*TN, TempID, + getContext(Base)); + } + + static const FoldingSetBase::FoldingSetInfo &getFoldingSetInfo() { + static constexpr FoldingSetBase::FoldingSetInfo Info = { + GetNodeProfile, NodeEquals, ComputeNodeHash}; + return Info; } + friend Super; public: explicit ContextualFoldingSet(Ctx Context, unsigned Log2InitSize = 6) diff --git a/llvm/lib/Support/FoldingSet.cpp b/llvm/lib/Support/FoldingSet.cpp index 6f67bb3..e195089 100644 --- a/llvm/lib/Support/FoldingSet.cpp +++ b/llvm/lib/Support/FoldingSet.cpp @@ -224,8 +224,6 @@ static void **AllocateBuckets(unsigned NumBuckets) { //===----------------------------------------------------------------------===// // FoldingSetBase Implementation -void FoldingSetBase::anchor() {} - FoldingSetBase::FoldingSetBase(unsigned Log2InitSize) { assert(5 < Log2InitSize && Log2InitSize < 32 && "Initial hash table size out of range"); @@ -267,8 +265,10 @@ void FoldingSetBase::clear() { NumNodes = 0; } -void FoldingSetBase::GrowBucketCount(unsigned NewBucketCount) { - assert((NewBucketCount > NumBuckets) && "Can't shrink a folding set with GrowBucketCount"); +void FoldingSetBase::GrowBucketCount(unsigned NewBucketCount, + const FoldingSetInfo &Info) { + assert((NewBucketCount > NumBuckets) && + "Can't shrink a folding set with GrowBucketCount"); assert(isPowerOf2_32(NewBucketCount) && "Bad bucket count!"); void **OldBuckets = Buckets; unsigned OldNumBuckets = NumBuckets; @@ -291,8 +291,9 @@ void FoldingSetBase::GrowBucketCount(unsigned NewBucketCount) { // Insert the node into the new bucket, after recomputing the hash. InsertNode(NodeInBucket, - GetBucketFor(ComputeNodeHash(NodeInBucket, TempID), - Buckets, NumBuckets)); + GetBucketFor(Info.ComputeNodeHash(this, NodeInBucket, TempID), + Buckets, NumBuckets), + Info); TempID.clear(); } } @@ -302,25 +303,24 @@ void FoldingSetBase::GrowBucketCount(unsigned NewBucketCount) { /// GrowHashTable - Double the size of the hash table and rehash everything. /// -void FoldingSetBase::GrowHashTable() { - GrowBucketCount(NumBuckets * 2); +void FoldingSetBase::GrowHashTable(const FoldingSetInfo &Info) { + GrowBucketCount(NumBuckets * 2, Info); } -void FoldingSetBase::reserve(unsigned EltCount) { +void FoldingSetBase::reserve(unsigned EltCount, const FoldingSetInfo &Info) { // This will give us somewhere between EltCount / 2 and // EltCount buckets. This puts us in the load factor // range of 1.0 - 2.0. if(EltCount < capacity()) return; - GrowBucketCount(PowerOf2Floor(EltCount)); + GrowBucketCount(PowerOf2Floor(EltCount), Info); } /// FindNodeOrInsertPos - Look up the node specified by ID. If it exists, /// return it. If not, return the insertion token that will make insertion /// faster. -FoldingSetBase::Node * -FoldingSetBase::FindNodeOrInsertPos(const FoldingSetNodeID &ID, - void *&InsertPos) { +FoldingSetBase::Node *FoldingSetBase::FindNodeOrInsertPos( + const FoldingSetNodeID &ID, void *&InsertPos, const FoldingSetInfo &Info) { unsigned IDHash = ID.ComputeHash(); void **Bucket = GetBucketFor(IDHash, Buckets, NumBuckets); void *Probe = *Bucket; @@ -329,7 +329,7 @@ FoldingSetBase::FindNodeOrInsertPos(const FoldingSetNodeID &ID, FoldingSetNodeID TempID; while (Node *NodeInBucket = GetNextPtr(Probe)) { - if (NodeEquals(NodeInBucket, ID, IDHash, TempID)) + if (Info.NodeEquals(this, NodeInBucket, ID, IDHash, TempID)) return NodeInBucket; TempID.clear(); @@ -344,13 +344,15 @@ FoldingSetBase::FindNodeOrInsertPos(const FoldingSetNodeID &ID, /// InsertNode - Insert the specified node into the folding set, knowing that it /// is not already in the map. InsertPos must be obtained from /// FindNodeOrInsertPos. -void FoldingSetBase::InsertNode(Node *N, void *InsertPos) { +void FoldingSetBase::InsertNode(Node *N, void *InsertPos, + const FoldingSetInfo &Info) { assert(!N->getNextInBucket()); // Do we need to grow the hashtable? if (NumNodes+1 > capacity()) { - GrowHashTable(); + GrowHashTable(Info); FoldingSetNodeID TempID; - InsertPos = GetBucketFor(ComputeNodeHash(N, TempID), Buckets, NumBuckets); + InsertPos = GetBucketFor(Info.ComputeNodeHash(this, N, TempID), Buckets, + NumBuckets); } ++NumNodes; @@ -414,13 +416,15 @@ bool FoldingSetBase::RemoveNode(Node *N) { /// GetOrInsertNode - If there is an existing simple Node exactly /// equal to the specified node, return it. Otherwise, insert 'N' and it /// instead. -FoldingSetBase::Node *FoldingSetBase::GetOrInsertNode(FoldingSetBase::Node *N) { +FoldingSetBase::Node * +FoldingSetBase::GetOrInsertNode(FoldingSetBase::Node *N, + const FoldingSetInfo &Info) { FoldingSetNodeID ID; - GetNodeProfile(N, ID); + Info.GetNodeProfile(this, N, ID); void *IP; - if (Node *E = FindNodeOrInsertPos(ID, IP)) + if (Node *E = FindNodeOrInsertPos(ID, IP, Info)) return E; - InsertNode(N, IP); + InsertNode(N, IP, Info); return N; }