r232726 - Devirtualize Attr and all subclasses.

Rafael EspĂ­ndola rafael.espindola at gmail.com
Thu Mar 19 09:21:25 PDT 2015


Nice!

On 19 March 2015 at 12:06, Benjamin Kramer <benny.kra at googlemail.com> wrote:
> 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
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits



More information about the cfe-commits mailing list