From: Benjamin Kramer Date: Thu, 19 Mar 2015 16:06:49 +0000 (+0000) Subject: Devirtualize Attr and all subclasses. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5d00c12060d126231439ea6e8806967abdb952bf;p=clang Devirtualize Attr and all subclasses. We know all subclasses in tblgen so just generate a giant switch for the few virtual methods or turn them into a member variable using spare bits. The giant jump tables aren't pretty but still much smaller than a vtable for every attribute, shrinking Release+Asserts clang by ~400k. Also halves the size of the Attr base class. No functional change intended. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@232726 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h index 787843e64f..c3e7f2a99f 100644 --- a/include/clang/AST/Attr.h +++ b/include/clang/AST/Attr.h @@ -52,8 +52,8 @@ protected: bool Inherited : 1; bool IsPackExpansion : 1; bool Implicit : 1; - - virtual ~Attr(); + bool IsLateParsed : 1; + bool DuplicatesAllowed : 1; void* operator new(size_t bytes) throw() { llvm_unreachable("Attrs cannot be allocated with regular 'new'."); @@ -74,9 +74,11 @@ public: } protected: - Attr(attr::Kind AK, SourceRange R, unsigned SpellingListIndex = 0) + Attr(attr::Kind AK, SourceRange R, unsigned SpellingListIndex, + bool IsLateParsed, bool DuplicatesAllowed) : Range(R), AttrKind(AK), SpellingListIndex(SpellingListIndex), - Inherited(false), IsPackExpansion(false), Implicit(false) {} + Inherited(false), IsPackExpansion(false), Implicit(false), + IsLateParsed(IsLateParsed), DuplicatesAllowed(DuplicatesAllowed) {} public: @@ -85,7 +87,7 @@ public: } unsigned getSpellingListIndex() const { return SpellingListIndex; } - virtual const char *getSpelling() const = 0; + const char *getSpelling() const; SourceLocation getLocation() const { return Range.getBegin(); } SourceRange getRange() const { return Range; } @@ -102,25 +104,24 @@ public: bool isPackExpansion() const { return IsPackExpansion; } // Clone this attribute. - virtual Attr *clone(ASTContext &C) const = 0; + Attr *clone(ASTContext &C) const; - virtual bool isLateParsed() const { return false; } + bool isLateParsed() const { return IsLateParsed; } // Pretty print this attribute. - virtual void printPretty(raw_ostream &OS, - const PrintingPolicy &Policy) const = 0; + void printPretty(raw_ostream &OS, const PrintingPolicy &Policy) const; /// \brief By default, attributes cannot be duplicated when being merged; /// however, an attribute can override this. Returns true if the attribute /// can be duplicated when merging. - virtual bool duplicatesAllowed() const { return false; } + bool duplicatesAllowed() const { return DuplicatesAllowed; } }; class InheritableAttr : public Attr { - virtual void anchor(); protected: - InheritableAttr(attr::Kind AK, SourceRange R, unsigned SpellingListIndex = 0) - : Attr(AK, R, SpellingListIndex) {} + InheritableAttr(attr::Kind AK, SourceRange R, unsigned SpellingListIndex, + bool IsLateParsed, bool DuplicatesAllowed) + : Attr(AK, R, SpellingListIndex, IsLateParsed, DuplicatesAllowed) {} public: void setInherited(bool I) { Inherited = I; } @@ -132,11 +133,11 @@ public: }; class InheritableParamAttr : public InheritableAttr { - void anchor() override; protected: - InheritableParamAttr(attr::Kind AK, SourceRange R, - unsigned SpellingListIndex = 0) - : InheritableAttr(AK, R, SpellingListIndex) {} + InheritableParamAttr(attr::Kind AK, SourceRange R, unsigned SpellingListIndex, + bool IsLateParsed, bool DuplicatesAllowed) + : InheritableAttr(AK, R, SpellingListIndex, IsLateParsed, + DuplicatesAllowed) {} public: // Implement isa/cast/dyncast/etc. diff --git a/lib/AST/AttrImpl.cpp b/lib/AST/AttrImpl.cpp index 0bf6bcd909..cb60870013 100644 --- a/lib/AST/AttrImpl.cpp +++ b/lib/AST/AttrImpl.cpp @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// // -// This file contains out-of-line virtual methods for Attr classes. +// This file contains out-of-line methods for Attr classes. // //===----------------------------------------------------------------------===// @@ -18,10 +18,4 @@ #include "llvm/ADT/StringSwitch.h" using namespace clang; -Attr::~Attr() { } - -void InheritableAttr::anchor() { } - -void InheritableParamAttr::anchor() { } - #include "clang/AST/AttrImpl.inc" diff --git a/utils/TableGen/ClangAttrEmitter.cpp b/utils/TableGen/ClangAttrEmitter.cpp index 4bf18089b5..c2f9dec0c0 100644 --- a/utils/TableGen/ClangAttrEmitter.cpp +++ b/utils/TableGen/ClangAttrEmitter.cpp @@ -1520,7 +1520,9 @@ void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) { OS << "unsigned SI\n"; OS << " )\n"; - OS << " : " << SuperName << "(attr::" << R.getName() << ", R, SI)\n"; + OS << " : " << SuperName << "(attr::" << R.getName() << ", R, SI, " + << R.getValueAsBit("LateParsed") << ", " + << R.getValueAsBit("DuplicatesAllowedWhileMerging") << ")\n"; for (auto const &ai : Args) { OS << " , "; @@ -1552,7 +1554,9 @@ void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) { OS << "unsigned SI\n"; OS << " )\n"; - OS << " : " << SuperName << "(attr::" << R.getName() << ", R, SI)\n"; + OS << " : " << SuperName << "(attr::" << R.getName() << ", R, SI, " + << R.getValueAsBit("LateParsed") << ", " + << R.getValueAsBit("DuplicatesAllowedWhileMerging") << ")\n"; for (auto const &ai : Args) { OS << " , "; @@ -1571,10 +1575,10 @@ void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) { OS << " }\n\n"; } - OS << " " << R.getName() << "Attr *clone(ASTContext &C) const override;\n"; + OS << " " << R.getName() << "Attr *clone(ASTContext &C) const;\n"; OS << " void printPretty(raw_ostream &OS,\n" - << " const PrintingPolicy &Policy) const override;\n"; - OS << " const char *getSpelling() const override;\n"; + << " const PrintingPolicy &Policy) const;\n"; + OS << " const char *getSpelling() const;\n"; if (!ElideSpelling) { assert(!SemanticToSyntacticMap.empty() && "Empty semantic mapping list"); @@ -1603,13 +1607,6 @@ void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) { OS << " static bool classof(const Attr *A) { return A->getKind() == " << "attr::" << R.getName() << "; }\n"; - bool LateParsed = R.getValueAsBit("LateParsed"); - OS << " bool isLateParsed() const override { return " - << LateParsed << "; }\n"; - - if (R.getValueAsBit("DuplicatesAllowedWhileMerging")) - OS << " bool duplicatesAllowed() const override { return true; }\n\n"; - OS << "};\n\n"; } @@ -1652,6 +1649,36 @@ void EmitClangAttrImpl(RecordKeeper &Records, raw_ostream &OS) { writePrettyPrintFunction(R, Args, OS); writeGetSpellingFunction(R, OS); } + + // Instead of relying on virtual dispatch we just create a huge dispatch + // switch. This is both smaller and faster than virtual functions. + auto EmitFunc = [&](const char *Method) { + OS << " switch (getKind()) {\n"; + for (const auto *Attr : Attrs) { + const Record &R = *Attr; + if (!R.getValueAsBit("ASTNode")) + continue; + + OS << " case attr::" << R.getName() << ":\n"; + OS << " return cast<" << R.getName() << "Attr>(this)->" << Method + << ";\n"; + } + OS << " case attr::NUM_ATTRS:\n"; + OS << " break;\n"; + OS << " }\n"; + OS << " llvm_unreachable(\"Unexpected attribute kind!\");\n"; + OS << "}\n\n"; + }; + + OS << "const char *Attr::getSpelling() const {\n"; + EmitFunc("getSpelling()"); + + OS << "Attr *Attr::clone(ASTContext &C) const {\n"; + EmitFunc("clone(C)"); + + OS << "void Attr::printPretty(raw_ostream &OS, " + "const PrintingPolicy &Policy) const {\n"; + EmitFunc("printPretty(OS, Policy)"); } } // end namespace clang