From 093b2d48b46919e4323f4217ab13a4ec46c8ac0a Mon Sep 17 00:00:00 2001 From: Manuel Klimek Date: Wed, 25 Mar 2015 23:18:30 +0000 Subject: [PATCH] Keep track of canonical decls in Redeclarable. More than 2x speedup on modules builds with large redecl chains. Roughly 15-20% speedup on non-modules builds for very large TUs. Between 2-3% cost in memory on large TUs. llvm-svn: 233228 --- clang/include/clang/AST/Decl.h | 2 -- clang/include/clang/AST/Redeclarable.h | 19 +++++-------------- clang/lib/Serialization/ASTReaderDecl.cpp | 4 ++++ 3 files changed, 9 insertions(+), 16 deletions(-) diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 009335dc58ea..7f7e437b736f 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -3738,8 +3738,6 @@ void Redeclarable::setPreviousDecl(decl_type *PrevDecl) { assert(RedeclLink.NextIsLatest() && "setPreviousDecl on a decl already in a redeclaration chain"); - decl_type *First; - if (PrevDecl) { // Point to previous. Make sure that this is actually the most recent // redeclaration, or we can build invalid chains. If the most recent diff --git a/clang/include/clang/AST/Redeclarable.h b/clang/include/clang/AST/Redeclarable.h index c798d708326a..92046d582bf3 100644 --- a/clang/include/clang/AST/Redeclarable.h +++ b/clang/include/clang/AST/Redeclarable.h @@ -121,14 +121,15 @@ protected: /// /// If there is only one declaration, it is DeclLink RedeclLink; + decl_type *First; decl_type *getNextRedeclaration() const { return RedeclLink.getNext(static_cast(this)); } public: - Redeclarable(const ASTContext &Ctx) - : RedeclLink(LatestDeclLink(Ctx)) {} + Redeclarable(const ASTContext &Ctx) + : RedeclLink(LatestDeclLink(Ctx)), First(static_cast(this)) {} /// \brief Return the previous declaration of this declaration or NULL if this /// is the first declaration. @@ -144,21 +145,11 @@ public: /// \brief Return the first declaration of this declaration or itself if this /// is the only declaration. - decl_type *getFirstDecl() { - decl_type *D = static_cast(this); - while (D->getPreviousDecl()) - D = D->getPreviousDecl(); - return D; - } + decl_type *getFirstDecl() { return First; } /// \brief Return the first declaration of this declaration or itself if this /// is the only declaration. - const decl_type *getFirstDecl() const { - const decl_type *D = static_cast(this); - while (D->getPreviousDecl()) - D = D->getPreviousDecl(); - return D; - } + const decl_type *getFirstDecl() const { return First; } /// \brief True if this is the first declaration in its redeclaration chain. bool isFirstDecl() const { return RedeclLink.NextIsLatest(); } diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index d384f3d46e86..10de9f754de6 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -2106,6 +2106,7 @@ ASTDeclReader::VisitRedeclarable(Redeclarable *D) { // which is the one that matters and mark the real previous DeclID to be // loaded & attached later on. D->RedeclLink = Redeclarable::PreviousDeclLink(FirstDecl); + D->First = FirstDecl->getCanonicalDecl(); } // Note that this declaration has been deserialized. @@ -2209,6 +2210,7 @@ void ASTDeclReader::mergeRedeclarable(Redeclarable *DBase, T *Existing, // of the existing declaration, so that this declaration has the // appropriate canonical declaration. D->RedeclLink = Redeclarable::PreviousDeclLink(ExistingCanon); + D->First = ExistingCanon; // When we merge a namespace, update its pointer to the first namespace. // We cannot have loaded any redeclarations of this declaration yet, so @@ -2828,6 +2830,7 @@ void ASTDeclReader::attachPreviousDeclImpl(ASTReader &Reader, Redeclarable *D, Decl *Previous, Decl *Canon) { D->RedeclLink.setPrevious(cast(Previous)); + D->First = cast(Previous)->First; } namespace clang { template<> @@ -2838,6 +2841,7 @@ void ASTDeclReader::attachPreviousDeclImpl(ASTReader &Reader, FunctionDecl *PrevFD = cast(Previous); FD->RedeclLink.setPrevious(PrevFD); + FD->First = PrevFD->First; // If the previous declaration is an inline function declaration, then this // declaration is too.