diff options
author | Douglas Gregor <dgregor@apple.com> | 2010-12-06 18:36:25 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2010-12-06 18:36:25 +0000 |
commit | 381d34e0b205ca27bcc7e7c1652561941c437965 (patch) | |
tree | bcc773b9b2992ca9f0cc00534faf29b0e9464a8a | |
parent | 40c2913cef2c211f1fe720ffef83fdb3e4d0fabf (diff) |
Re-implement caching for the linkage calculation of declarations.
My previous attempt at solving the compile-time problem with many
redeclarations of the same entity cached both linkage and visibility,
while this patch only tackles linkage. There are several reasons for
this difference:
- Linkage is a language concept, and is evaluated many times during
semantic analysis and codegen, while visibility is only a
code-generation concept that is evaluated only once per (unique)
declaration. Hence, we *must* optimize linkage calculations but
don't need to optimize visibility computation.
- Once we know the linkage of a declaration, subsequent
redeclarations can't change that linkage. Hence, cache
invalidation is far simpler than for visibility, where a later
redeclaration can completely change the visibility.
- We have 3 spare bits in Decl to store the linkage cache, so the
cache doesn't increase the size of declarations. With the
visibility+linkage cache, NamedDecl got larger.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@121023 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/AST/Decl.h | 44 | ||||
-rw-r--r-- | include/clang/AST/DeclBase.h | 23 | ||||
-rw-r--r-- | include/clang/AST/Redeclarable.h | 20 | ||||
-rw-r--r-- | lib/AST/Decl.cpp | 114 | ||||
-rw-r--r-- | lib/Serialization/ASTReaderDecl.cpp | 4 |
5 files changed, 140 insertions, 65 deletions
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index bdc91a168e..299d5f6f4e 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -264,7 +264,7 @@ public: }; /// \brief Determine what kind of linkage this entity has. - Linkage getLinkage() const { return getLinkageAndVisibility().linkage(); } + Linkage getLinkage() const; /// \brief Determines the visibility of this entity. Visibility getVisibility() const { return getLinkageAndVisibility().visibility(); } @@ -272,6 +272,10 @@ public: /// \brief Determines the linkage and visibility of this entity. LinkageInfo getLinkageAndVisibility() const; + /// \brief Clear the linkage cache in response to a change + /// to the declaration. + void ClearLinkageCache() { HasCachedLinkage = 0; } + /// \brief Looks through UsingDecls and ObjCCompatibleAliasDecls for /// the underlying named decl. NamedDecl *getUnderlyingDecl(); @@ -625,6 +629,8 @@ private: bool NRVOVariable : 1; friend class StmtIteratorBase; + friend class ASTDeclReader; + protected: VarDecl(Kind DK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, StorageClass SC, @@ -660,10 +666,7 @@ public: StorageClass getStorageClassAsWritten() const { return (StorageClass) SClassAsWritten; } - void setStorageClass(StorageClass SC) { - assert(isLegalForVariable(SC)); - SClass = SC; - } + void setStorageClass(StorageClass SC); void setStorageClassAsWritten(StorageClass SC) { assert(isLegalForVariable(SC)); SClassAsWritten = SC; @@ -1478,10 +1481,7 @@ public: } StorageClass getStorageClass() const { return StorageClass(SClass); } - void setStorageClass(StorageClass SC) { - assert(isLegalForFunction(SC)); - SClass = SC; - } + void setStorageClass(StorageClass SC); StorageClass getStorageClassAsWritten() const { return StorageClass(SClassAsWritten); @@ -2558,6 +2558,32 @@ inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, return DB; } +template<typename decl_type> +void Redeclarable<decl_type>::setPreviousDeclaration(decl_type *PrevDecl) { + // Note: This routine is implemented here because we need both NamedDecl + // and Redeclarable to be defined. + + 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 + // redeclaration is invalid, it won't be PrevDecl, but we want it anyway. + RedeclLink = PreviousDeclLink(llvm::cast<decl_type>( + PrevDecl->getMostRecentDeclaration())); + First = PrevDecl->getFirstDeclaration(); + assert(First->RedeclLink.NextIsLatest() && "Expected first"); + } else { + // Make this first. + First = static_cast<decl_type*>(this); + } + + // First one will point to this one as latest. + First->RedeclLink = LatestDeclLink(static_cast<decl_type*>(this)); + if (NamedDecl *ND = dyn_cast<NamedDecl>(static_cast<decl_type*>(this))) + ND->ClearLinkageCache(); +} + } // end namespace clang #endif diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index 0aa60ce978..f091ce043a 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -198,7 +198,7 @@ private: return DeclCtx.get<DeclContext*>(); } - /// Loc - The location that this decl. + /// Loc - The location of this decl. SourceLocation Loc; /// DeclKind - This indicates which class this is. @@ -231,8 +231,19 @@ protected: unsigned ChangedAfterLoad : 1; /// IdentifierNamespace - This specifies what IDNS_* namespace this lives in. - unsigned IdentifierNamespace : 15; + unsigned IdentifierNamespace : 12; + /// \brief Whether the \c CachedLinkage field is active. + /// + /// This field is only valid for NamedDecls subclasses. + mutable unsigned HasCachedLinkage : 1; + + /// \brief If \c HasCachedLinkage, the linkage of this declaration. + /// + /// This field is only valid for NamedDecls subclasses. + mutable unsigned CachedLinkage : 2; + + private: void CheckAccessDeclContext() const; @@ -243,7 +254,9 @@ protected: Loc(L), DeclKind(DK), InvalidDecl(0), HasAttrs(false), Implicit(false), Used(false), Access(AS_none), PCHLevel(0), ChangedAfterLoad(false), - IdentifierNamespace(getIdentifierNamespaceForKind(DK)) { + IdentifierNamespace(getIdentifierNamespaceForKind(DK)), + HasCachedLinkage(0) + { if (Decl::CollectingStats()) add(DK); } @@ -251,7 +264,9 @@ protected: : NextDeclInContext(0), DeclKind(DK), InvalidDecl(0), HasAttrs(false), Implicit(false), Used(false), Access(AS_none), PCHLevel(0), ChangedAfterLoad(false), - IdentifierNamespace(getIdentifierNamespaceForKind(DK)) { + IdentifierNamespace(getIdentifierNamespaceForKind(DK)), + HasCachedLinkage(0) + { if (Decl::CollectingStats()) add(DK); } diff --git a/include/clang/AST/Redeclarable.h b/include/clang/AST/Redeclarable.h index ba778293ba..e87ca78d63 100644 --- a/include/clang/AST/Redeclarable.h +++ b/include/clang/AST/Redeclarable.h @@ -109,25 +109,7 @@ public: /// \brief Set the previous declaration. If PrevDecl is NULL, set this as the /// first and only declaration. - void setPreviousDeclaration(decl_type *PrevDecl) { - 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 - // redeclaration is invalid, it won't be PrevDecl, but we want it anyway. - RedeclLink = PreviousDeclLink(llvm::cast<decl_type>( - PrevDecl->getMostRecentDeclaration())); - First = PrevDecl->getFirstDeclaration(); - assert(First->RedeclLink.NextIsLatest() && "Expected first"); - } else { - // Make this first. - First = static_cast<decl_type*>(this); - } - - // First one will point to this one as latest. - First->RedeclLink = LatestDeclLink(static_cast<decl_type*>(this)); - } + void setPreviousDeclaration(decl_type *PrevDecl); /// \brief Iterates through all the redeclarations of the same decl. class redecl_iterator { diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 71bda4156f..90a561e5c6 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -85,6 +85,15 @@ struct LVFlags { ConsiderVisibilityAttributes(true) { } + /// \brief Returns a set of flags that is only useful for computing the + /// linkage, not the visibility, of a declaration. + static LVFlags CreateOnlyDeclLinkage() { + LVFlags F; + F.ConsiderGlobalVisibility = false; + F.ConsiderVisibilityAttributes = false; + return F; + } + /// Returns a set of flags, otherwise based on these, which ignores /// off all sources of visibility except template arguments. LVFlags onlyTemplateVisibility() const { @@ -119,10 +128,14 @@ getLVForTemplateParameterList(const TemplateParameterList *Params) { return LV; } +/// getLVForDecl - Get the linkage and visibility for the given declaration. +static LinkageInfo getLVForDecl(const NamedDecl *D, LVFlags F); + /// \brief Get the most restrictive linkage for the types and /// declarations in the given template argument list. static LVPair getLVForTemplateArgumentList(const TemplateArgument *Args, - unsigned NumArgs) { + unsigned NumArgs, + LVFlags &F) { LVPair LV(ExternalLinkage, DefaultVisibility); for (unsigned I = 0; I != NumArgs; ++I) { @@ -140,21 +153,24 @@ static LVPair getLVForTemplateArgumentList(const TemplateArgument *Args, // The decl can validly be null as the representation of nullptr // arguments, valid only in C++0x. if (Decl *D = Args[I].getAsDecl()) { - if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) - LV = merge(LV, ND->getLinkageAndVisibility()); - if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) - LV = merge(LV, VD->getLinkageAndVisibility()); + if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) { + LinkageInfo LI = getLVForDecl(ND, F); + LV = merge(LV, LVPair(LI.linkage(), LI.visibility())); + } } break; case TemplateArgument::Template: - if (TemplateDecl *Template = Args[I].getAsTemplate().getAsTemplateDecl()) - LV = merge(LV, Template->getLinkageAndVisibility()); + if (TemplateDecl *Template = Args[I].getAsTemplate().getAsTemplateDecl()){ + LinkageInfo LI = getLVForDecl(Template, F); + LV = merge(LV, LVPair(LI.linkage(), LI.visibility())); + } break; case TemplateArgument::Pack: LV = merge(LV, getLVForTemplateArgumentList(Args[I].pack_begin(), - Args[I].pack_size())); + Args[I].pack_size(), + F)); break; } } @@ -163,14 +179,11 @@ static LVPair getLVForTemplateArgumentList(const TemplateArgument *Args, } static LVPair -getLVForTemplateArgumentList(const TemplateArgumentList &TArgs) { - return getLVForTemplateArgumentList(TArgs.data(), TArgs.size()); +getLVForTemplateArgumentList(const TemplateArgumentList &TArgs, + LVFlags &F) { + return getLVForTemplateArgumentList(TArgs.data(), TArgs.size(), F); } -/// getLVForDecl - Get the cached linkage and visibility for the given -/// declaration. -static LinkageInfo getLVForDecl(const NamedDecl *D, LVFlags F); - static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) { assert(D->getDeclContext()->getRedeclContext()->isFileContext() && "Not a name having namespace scope"); @@ -296,7 +309,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) { // is visible, or if the prior declaration specifies no // linkage, then the identifier has external linkage. if (const VarDecl *PrevVar = Var->getPreviousDeclaration()) { - LinkageInfo PrevLV = PrevVar->getLinkageAndVisibility(); + LinkageInfo PrevLV = getLVForDecl(PrevVar, F); if (PrevLV.linkage()) LV.setLinkage(PrevLV.linkage()); LV.mergeVisibility(PrevLV); } @@ -331,7 +344,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) { // is visible, or if the prior declaration specifies no // linkage, then the identifier has external linkage. if (const FunctionDecl *PrevFunc = Function->getPreviousDeclaration()) { - LinkageInfo PrevLV = PrevFunc->getLinkageAndVisibility(); + LinkageInfo PrevLV = getLVForDecl(PrevFunc, F); if (PrevLV.linkage()) LV.setLinkage(PrevLV.linkage()); LV.mergeVisibility(PrevLV); } @@ -342,7 +355,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) { LV.merge(getLVForDecl(SpecInfo->getTemplate(), F.onlyTemplateVisibility())); const TemplateArgumentList &TemplateArgs = *SpecInfo->TemplateArguments; - LV.merge(getLVForTemplateArgumentList(TemplateArgs)); + LV.merge(getLVForTemplateArgumentList(TemplateArgs, F)); } // - a named class (Clause 9), or an unnamed class defined in a @@ -366,7 +379,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) { // The arguments at which the template was instantiated. const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); - LV.merge(getLVForTemplateArgumentList(TemplateArgs)); + LV.merge(getLVForTemplateArgumentList(TemplateArgs, F)); } // Consider -fvisibility unless the type has C linkage. @@ -377,8 +390,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) { // - an enumerator belonging to an enumeration with external linkage; } else if (isa<EnumConstantDecl>(D)) { - LinkageInfo EnumLV = - cast<NamedDecl>(D->getDeclContext())->getLinkageAndVisibility(); + LinkageInfo EnumLV = getLVForDecl(cast<NamedDecl>(D->getDeclContext()), F); if (!isExternalLinkage(EnumLV.linkage())) return LinkageInfo::none(); LV.merge(EnumLV); @@ -464,7 +476,7 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, LVFlags F) { // the template parameters and arguments. if (FunctionTemplateSpecializationInfo *Spec = MD->getTemplateSpecializationInfo()) { - LV.merge(getLVForTemplateArgumentList(*Spec->TemplateArguments)); + LV.merge(getLVForTemplateArgumentList(*Spec->TemplateArguments, F)); LV.merge(getLVForTemplateParameterList( Spec->getTemplate()->getTemplateParameters())); @@ -499,7 +511,7 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, LVFlags F) { = dyn_cast<ClassTemplateSpecializationDecl>(RD)) { // Merge template argument/parameter information for member // class template specializations. - LV.merge(getLVForTemplateArgumentList(Spec->getTemplateArgs())); + LV.merge(getLVForTemplateArgumentList(Spec->getTemplateArgs(), F)); LV.merge(getLVForTemplateParameterList( Spec->getSpecializedTemplate()->getTemplateParameters())); } @@ -525,8 +537,27 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, LVFlags F) { return LV; } +Linkage NamedDecl::getLinkage() const { + if (HasCachedLinkage) { +#ifndef NDEBUG + assert(CachedLinkage == getLVForDecl(this, + LVFlags::CreateOnlyDeclLinkage()).linkage()); +#endif + return Linkage(CachedLinkage); + } + + CachedLinkage = getLVForDecl(this, + LVFlags::CreateOnlyDeclLinkage()).linkage(); + HasCachedLinkage = 1; + return Linkage(CachedLinkage); +} + LinkageInfo NamedDecl::getLinkageAndVisibility() const { - return getLVForDecl(this, LVFlags()); + LinkageInfo LI = getLVForDecl(this, LVFlags()); + assert(!HasCachedLinkage || (CachedLinkage == LI.linkage())); + HasCachedLinkage = 1; + CachedLinkage = LI.linkage(); + return LI; } static LinkageInfo getLVForDecl(const NamedDecl *D, LVFlags Flags) { @@ -581,11 +612,13 @@ static LinkageInfo getLVForDecl(const NamedDecl *D, LVFlags Flags) { return LinkageInfo::uniqueExternal(); LinkageInfo LV; - if (const VisibilityAttr *VA = GetExplicitVisibility(Function)) - LV.setVisibility(GetVisibilityFromAttr(VA)); - + if (Flags.ConsiderVisibilityAttributes) { + if (const VisibilityAttr *VA = GetExplicitVisibility(Function)) + LV.setVisibility(GetVisibilityFromAttr(VA)); + } + if (const FunctionDecl *Prev = Function->getPreviousDeclaration()) { - LinkageInfo PrevLV = Prev->getLinkageAndVisibility(); + LinkageInfo PrevLV = getLVForDecl(Prev, Flags); if (PrevLV.linkage()) LV.setLinkage(PrevLV.linkage()); LV.mergeVisibility(PrevLV); } @@ -602,11 +635,13 @@ static LinkageInfo getLVForDecl(const NamedDecl *D, LVFlags Flags) { LinkageInfo LV; if (Var->getStorageClass() == SC_PrivateExtern) LV.setVisibility(HiddenVisibility); - else if (const VisibilityAttr *VA = GetExplicitVisibility(Var)) - LV.setVisibility(GetVisibilityFromAttr(VA)); - + else if (Flags.ConsiderVisibilityAttributes) { + if (const VisibilityAttr *VA = GetExplicitVisibility(Var)) + LV.setVisibility(GetVisibilityFromAttr(VA)); + } + if (const VarDecl *Prev = Var->getPreviousDeclaration()) { - LinkageInfo PrevLV = Prev->getLinkageAndVisibility(); + LinkageInfo PrevLV = getLVForDecl(Prev, Flags); if (PrevLV.linkage()) LV.setLinkage(PrevLV.linkage()); LV.mergeVisibility(PrevLV); } @@ -878,6 +913,14 @@ VarDecl *VarDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, return new (C) VarDecl(Var, DC, L, Id, T, TInfo, S, SCAsWritten); } +void VarDecl::setStorageClass(StorageClass SC) { + assert(isLegalForVariable(SC)); + if (getStorageClass() != SC) + ClearLinkageCache(); + + SClass = SC; +} + SourceLocation VarDecl::getInnerLocStart() const { SourceLocation Start = getTypeSpecStartLoc(); if (Start.isInvalid()) @@ -1277,6 +1320,14 @@ FunctionDecl *FunctionDecl::getCanonicalDecl() { return getFirstDeclaration(); } +void FunctionDecl::setStorageClass(StorageClass SC) { + assert(isLegalForFunction(SC)); + if (getStorageClass() != SC) + ClearLinkageCache(); + + SClass = SC; +} + /// \brief Returns a value indicating whether this function /// corresponds to a builtin function. /// @@ -1787,6 +1838,7 @@ void TagDecl::setTypedefForAnonDecl(TypedefDecl *TDD) { TypedefDeclOrQualifier = TDD; if (TypeForDecl) TypeForDecl->ClearLinkageCache(); + ClearLinkageCache(); } void TagDecl::startDefinition() { diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index adbf3bff3c..7053f404e4 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -384,7 +384,7 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) { // FunctionDecl's body is handled last at ASTDeclReader::Visit, // after everything else is read. - FD->setStorageClass((StorageClass)Record[Idx++]); + FD->SClass = (StorageClass)Record[Idx++]; FD->setStorageClassAsWritten((StorageClass)Record[Idx++]); FD->setInlineSpecified(Record[Idx++]); FD->setVirtualAsWritten(Record[Idx++]); @@ -651,7 +651,7 @@ void ASTDeclReader::VisitIndirectFieldDecl(IndirectFieldDecl *FD) { void ASTDeclReader::VisitVarDecl(VarDecl *VD) { VisitDeclaratorDecl(VD); VisitRedeclarable(VD); - VD->setStorageClass((StorageClass)Record[Idx++]); + VD->SClass = (StorageClass)Record[Idx++]; VD->setStorageClassAsWritten((StorageClass)Record[Idx++]); VD->setThreadSpecified(Record[Idx++]); VD->setCXXDirectInitializer(Record[Idx++]); |