r232726 - Devirtualize Attr and all subclasses.

Benjamin Kramer benny.kra at googlemail.com
Thu Mar 19 09:06:49 PDT 2015


Author: d0k
Date: Thu Mar 19 11:06:49 2015
New Revision: 232726

URL: http://llvm.org/viewvc/llvm-project?rev=232726&view=rev
Log:
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.

Modified:
    cfe/trunk/include/clang/AST/Attr.h
    cfe/trunk/lib/AST/AttrImpl.cpp
    cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp

Modified: cfe/trunk/include/clang/AST/Attr.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Attr.h?rev=232726&r1=232725&r2=232726&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Attr.h (original)
+++ cfe/trunk/include/clang/AST/Attr.h Thu Mar 19 11:06:49 2015
@@ -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.

Modified: cfe/trunk/lib/AST/AttrImpl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/AttrImpl.cpp?rev=232726&r1=232725&r2=232726&view=diff
==============================================================================
--- cfe/trunk/lib/AST/AttrImpl.cpp (original)
+++ cfe/trunk/lib/AST/AttrImpl.cpp Thu Mar 19 11:06:49 2015
@@ -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"

Modified: cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp?rev=232726&r1=232725&r2=232726&view=diff
==============================================================================
--- cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp (original)
+++ cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp Thu Mar 19 11:06:49 2015
@@ -1520,7 +1520,9 @@ void EmitClangAttrClass(RecordKeeper &Re
     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 &Re
       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 &Re
       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 &Re
     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 &Rec
     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





More information about the cfe-commits mailing list