[clang] 7420f96 - [TableGen] Move generated *Attr class methods out of line
Reid Kleckner via cfe-commits
cfe-commits at lists.llvm.org
Thu Mar 12 09:08:03 PDT 2020
Author: Reid Kleckner
Date: 2020-03-12T09:07:57-07:00
New Revision: 7420f96924a3889af628c851ff1940aae614f3f3
URL: https://github.com/llvm/llvm-project/commit/7420f96924a3889af628c851ff1940aae614f3f3
DIFF: https://github.com/llvm/llvm-project/commit/7420f96924a3889af628c851ff1940aae614f3f3.diff
LOG: [TableGen] Move generated *Attr class methods out of line
After this change, clang spends ~200ms parsing Attrs.inc instead of
~560ms. A large part of the cost was from the StringSwitch
instantiations, but this is a good way to avoid similar problems in the
future.
Reviewed By: aaron.ballman, rjmccall
Differential Revision: https://reviews.llvm.org/D76040
Added:
Modified:
clang/utils/TableGen/ClangAttrEmitter.cpp
Removed:
################################################################################
diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp
index d8b5480c2b26..20fb9bc14439 100644
--- a/clang/utils/TableGen/ClangAttrEmitter.cpp
+++ b/clang/utils/TableGen/ClangAttrEmitter.cpp
@@ -426,8 +426,8 @@ namespace {
}
void writeCtorBody(raw_ostream &OS) const override {
- OS << " if (!" << getUpperName() << ".empty())\n";
- OS << " std::memcpy(" << getLowerName() << ", " << getUpperName()
+ OS << " if (!" << getUpperName() << ".empty())\n";
+ OS << " std::memcpy(" << getLowerName() << ", " << getUpperName()
<< ".data(), " << getLowerName() << "Length);\n";
}
@@ -691,8 +691,8 @@ namespace {
}
void writeCtorBody(raw_ostream &OS) const override {
- OS << " std::copy(" << getUpperName() << ", " << getUpperName()
- << " + " << ArgSizeName << ", " << ArgName << ");\n";
+ OS << " std::copy(" << getUpperName() << ", " << getUpperName() << " + "
+ << ArgSizeName << ", " << ArgName << ");\n";
}
void writeCtorInitializers(raw_ostream &OS) const override {
@@ -894,37 +894,45 @@ namespace {
OS << " }\n";
}
- void writeConversion(raw_ostream &OS) const {
- OS << " static bool ConvertStrTo" << type << "(StringRef Val, ";
- OS << type << " &Out) {\n";
- OS << " Optional<" << type << "> R = llvm::StringSwitch<Optional<";
+ void writeConversion(raw_ostream &OS, bool Header) const {
+ if (Header) {
+ OS << " static bool ConvertStrTo" << type << "(StringRef Val, " << type
+ << " &Out);\n";
+ OS << " static const char *Convert" << type << "ToStr(" << type
+ << " Val);\n";
+ return;
+ }
+
+ OS << "bool " << getAttrName() << "Attr::ConvertStrTo" << type
+ << "(StringRef Val, " << type << " &Out) {\n";
+ OS << " Optional<" << type << "> R = llvm::StringSwitch<Optional<";
OS << type << ">>(Val)\n";
for (size_t I = 0; I < enums.size(); ++I) {
- OS << " .Case(\"" << values[I] << "\", ";
+ OS << " .Case(\"" << values[I] << "\", ";
OS << getAttrName() << "Attr::" << enums[I] << ")\n";
}
- OS << " .Default(Optional<" << type << ">());\n";
- OS << " if (R) {\n";
- OS << " Out = *R;\n return true;\n }\n";
- OS << " return false;\n";
- OS << " }\n\n";
+ OS << " .Default(Optional<" << type << ">());\n";
+ OS << " if (R) {\n";
+ OS << " Out = *R;\n return true;\n }\n";
+ OS << " return false;\n";
+ OS << "}\n\n";
// Mapping from enumeration values back to enumeration strings isn't
// trivial because some enumeration values have multiple named
// enumerators, such as type_visibility(internal) and
// type_visibility(hidden) both mapping to TypeVisibilityAttr::Hidden.
- OS << " static const char *Convert" << type << "ToStr("
- << type << " Val) {\n"
- << " switch(Val) {\n";
+ OS << "const char *" << getAttrName() << "Attr::Convert" << type
+ << "ToStr(" << type << " Val) {\n"
+ << " switch(Val) {\n";
SmallDenseSet<StringRef, 8> Uniques;
for (size_t I = 0; I < enums.size(); ++I) {
if (Uniques.insert(enums[I]).second)
- OS << " case " << getAttrName() << "Attr::" << enums[I]
+ OS << " case " << getAttrName() << "Attr::" << enums[I]
<< ": return \"" << values[I] << "\";\n";
}
- OS << " }\n"
- << " llvm_unreachable(\"No enumerator with that value\");\n"
- << " }\n";
+ OS << " }\n"
+ << " llvm_unreachable(\"No enumerator with that value\");\n"
+ << "}\n";
}
};
@@ -1006,33 +1014,42 @@ namespace {
OS << " " << WritePCHRecord(QualifiedTypeName, "(*i)");
}
- void writeConversion(raw_ostream &OS) const {
- OS << " static bool ConvertStrTo" << type << "(StringRef Val, ";
+ void writeConversion(raw_ostream &OS, bool Header) const {
+ if (Header) {
+ OS << " static bool ConvertStrTo" << type << "(StringRef Val, " << type
+ << " &Out);\n";
+ OS << " static const char *Convert" << type << "ToStr(" << type
+ << " Val);\n";
+ return;
+ }
+
+ OS << "bool " << getAttrName() << "Attr::ConvertStrTo" << type
+ << "(StringRef Val, ";
OS << type << " &Out) {\n";
- OS << " Optional<" << type << "> R = llvm::StringSwitch<Optional<";
+ OS << " Optional<" << type << "> R = llvm::StringSwitch<Optional<";
OS << type << ">>(Val)\n";
for (size_t I = 0; I < enums.size(); ++I) {
- OS << " .Case(\"" << values[I] << "\", ";
+ OS << " .Case(\"" << values[I] << "\", ";
OS << getAttrName() << "Attr::" << enums[I] << ")\n";
}
- OS << " .Default(Optional<" << type << ">());\n";
- OS << " if (R) {\n";
- OS << " Out = *R;\n return true;\n }\n";
- OS << " return false;\n";
- OS << " }\n\n";
-
- OS << " static const char *Convert" << type << "ToStr("
- << type << " Val) {\n"
- << " switch(Val) {\n";
+ OS << " .Default(Optional<" << type << ">());\n";
+ OS << " if (R) {\n";
+ OS << " Out = *R;\n return true;\n }\n";
+ OS << " return false;\n";
+ OS << "}\n\n";
+
+ OS << "const char *" << getAttrName() << "Attr::Convert" << type
+ << "ToStr(" << type << " Val) {\n"
+ << " switch(Val) {\n";
SmallDenseSet<StringRef, 8> Uniques;
for (size_t I = 0; I < enums.size(); ++I) {
if (Uniques.insert(enums[I]).second)
- OS << " case " << getAttrName() << "Attr::" << enums[I]
- << ": return \"" << values[I] << "\";\n";
+ OS << " case " << getAttrName() << "Attr::" << enums[I]
+ << ": return \"" << values[I] << "\";\n";
}
- OS << " }\n"
- << " llvm_unreachable(\"No enumerator with that value\");\n"
- << " }\n";
+ OS << " }\n"
+ << " llvm_unreachable(\"No enumerator with that value\");\n"
+ << "}\n";
}
};
@@ -1208,15 +1225,15 @@ namespace {
{}
void writeCtorBody(raw_ostream &OS) const override {
- OS << " for (size_t I = 0, E = " << getArgSizeName() << "; I != E;\n"
- " ++I) {\n"
- " StringRef Ref = " << getUpperName() << "[I];\n"
- " if (!Ref.empty()) {\n"
- " char *Mem = new (Ctx, 1) char[Ref.size()];\n"
- " std::memcpy(Mem, Ref.data(), Ref.size());\n"
- " " << getArgName() << "[I] = StringRef(Mem, Ref.size());\n"
- " }\n"
- " }\n";
+ OS << " for (size_t I = 0, E = " << getArgSizeName() << "; I != E;\n"
+ " ++I) {\n"
+ " StringRef Ref = " << getUpperName() << "[I];\n"
+ " if (!Ref.empty()) {\n"
+ " char *Mem = new (Ctx, 1) char[Ref.size()];\n"
+ " std::memcpy(Mem, Ref.data(), Ref.size());\n"
+ " " << getArgName() << "[I] = StringRef(Mem, Ref.size());\n"
+ " }\n"
+ " }\n";
}
void writeValueImpl(raw_ostream &OS) const override {
@@ -1353,7 +1370,7 @@ static void writeDeprecatedAttrValue(raw_ostream &OS, std::string &Variety) {
OS << " OS << \"";
}
-static void writeGetSpellingFunction(Record &R, raw_ostream &OS) {
+static void writeGetSpellingFunction(const Record &R, raw_ostream &OS) {
std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(R);
OS << "const char *" << R.getName() << "Attr::getSpelling() const {\n";
@@ -1377,7 +1394,7 @@ static void writeGetSpellingFunction(Record &R, raw_ostream &OS) {
}
static void
-writePrettyPrintFunction(Record &R,
+writePrettyPrintFunction(const Record &R,
const std::vector<std::unique_ptr<Argument>> &Args,
raw_ostream &OS) {
std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(R);
@@ -2231,13 +2248,8 @@ static void emitClangAttrThisIsaIdentifierArgList(RecordKeeper &Records,
OS << "#endif // CLANG_ATTR_THIS_ISA_IDENTIFIER_ARG_LIST\n\n";
}
-// Emits the class definitions for attributes.
-void clang::EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
- emitSourceFileHeader("Attribute classes' definitions", OS);
-
- OS << "#ifndef LLVM_CLANG_ATTR_CLASSES_INC\n";
- OS << "#define LLVM_CLANG_ATTR_CLASSES_INC\n\n";
-
+static void emitAttributes(RecordKeeper &Records, raw_ostream &OS,
+ bool Header) {
std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
ParsedAttrMap AttrMap = getParsedAttrList(Records);
@@ -2271,7 +2283,10 @@ void clang::EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
Inheritable = true;
}
- OS << "class " << R.getName() << "Attr : public " << SuperName << " {\n";
+ if (Header)
+ OS << "class " << R.getName() << "Attr : public " << SuperName << " {\n";
+ else
+ OS << "\n// " << R.getName() << "Attr implementation\n\n";
std::vector<Record*> ArgRecords = R.getValueAsListOfDefs("Args");
std::vector<std::unique_ptr<Argument>> Args;
@@ -2281,8 +2296,10 @@ void clang::EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
bool HasFakeArg = false;
for (const auto *ArgRecord : ArgRecords) {
Args.emplace_back(createArgument(*ArgRecord, R.getName()));
- Args.back()->writeDeclarations(OS);
- OS << "\n\n";
+ if (Header) {
+ Args.back()->writeDeclarations(OS);
+ OS << "\n\n";
+ }
// For these purposes, fake takes priority over optional.
if (Args.back()->isFake()) {
@@ -2292,7 +2309,8 @@ void clang::EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
}
}
- OS << "public:\n";
+ if (Header)
+ OS << "public:\n";
std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(R);
@@ -2305,8 +2323,11 @@ void clang::EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
// This maps spelling index values to semantic Spelling enumerants.
SemanticSpellingMap SemanticToSyntacticMap;
+ std::string SpellingEnum;
if (!ElideSpelling)
- OS << CreateSemanticSpellings(Spellings, SemanticToSyntacticMap);
+ SpellingEnum = CreateSemanticSpellings(Spellings, SemanticToSyntacticMap);
+ if (Header)
+ OS << SpellingEnum;
const auto &ParsedAttrSpellingItr = llvm::find_if(
AttrMap, [R](const std::pair<std::string, const Record *> &P) {
@@ -2315,9 +2336,14 @@ void clang::EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
// Emit CreateImplicit factory methods.
auto emitCreate = [&](bool Implicit, bool emitFake) {
- OS << " static " << R.getName() << "Attr *Create";
- if (Implicit)
- OS << "Implicit";
+ if (Header)
+ OS << " static ";
+ OS << R.getName() << "Attr *";
+ if (!Header)
+ OS << R.getName() << "Attr::";
+ OS << "Create";
+ if (Implicit)
+ OS << "Implicit";
OS << "(";
OS << "ASTContext &Ctx";
for (auto const &ai : Args) {
@@ -2325,8 +2351,17 @@ void clang::EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
OS << ", ";
ai->writeCtorParameters(OS);
}
- OS << ", const AttributeCommonInfo &CommonInfo = {SourceRange{}}) {\n";
- OS << " auto *A = new (Ctx) " << R.getName();
+ OS << ", const AttributeCommonInfo &CommonInfo";
+ if (Header)
+ OS << " = {SourceRange{}}";
+ OS << ")";
+ if (Header) {
+ OS << ";\n";
+ return;
+ }
+
+ OS << " {\n";
+ OS << " auto *A = new (Ctx) " << R.getName();
OS << "Attr(Ctx, CommonInfo";
for (auto const &ai : Args) {
if (ai->isFake() && !emitFake) continue;
@@ -2335,18 +2370,23 @@ void clang::EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
}
OS << ");\n";
if (Implicit) {
- OS << " A->setImplicit(true);\n";
+ OS << " A->setImplicit(true);\n";
}
if (Implicit || ElideSpelling) {
- OS << " if (!A->isAttributeSpellingListCalculated() && "
+ OS << " if (!A->isAttributeSpellingListCalculated() && "
"!A->getAttrName())\n";
- OS << " A->setAttributeSpellingListIndex(0);\n";
+ OS << " A->setAttributeSpellingListIndex(0);\n";
}
- OS << " return A;\n }\n\n";
+ OS << " return A;\n}\n\n";
};
auto emitCreateNoCI = [&](bool Implicit, bool emitFake) {
- OS <<" static " << R.getName() << "Attr *Create";
+ if (Header)
+ OS << " static ";
+ OS << R.getName() << "Attr *";
+ if (!Header)
+ OS << R.getName() << "Attr::";
+ OS << "Create";
if (Implicit)
OS << "Implicit";
OS << "(";
@@ -2357,12 +2397,19 @@ void clang::EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
ai->writeCtorParameters(OS);
}
OS << ", SourceRange Range, AttributeCommonInfo::Syntax Syntax";
- if (!ElideSpelling)
- OS << ", " << R.getName()
- << "Attr::Spelling S = "
- "static_cast<Spelling>(SpellingNotCalculated)";
- OS << ") {\n";
- OS << " AttributeCommonInfo I(Range, ";
+ if (!ElideSpelling) {
+ OS << ", " << R.getName() << "Attr::Spelling S";
+ if (Header)
+ OS << " = static_cast<Spelling>(SpellingNotCalculated)";
+ }
+ OS << ")";
+ if (Header) {
+ OS << ";\n";
+ return;
+ }
+
+ OS << " {\n";
+ OS << " AttributeCommonInfo I(Range, ";
if (ParsedAttrSpellingItr != std::end(AttrMap))
OS << "AT_" << ParsedAttrSpellingItr->first;
@@ -2373,7 +2420,7 @@ void clang::EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
if (!ElideSpelling)
OS << ", S";
OS << ");\n";
- OS << " return Create";
+ OS << " return Create";
if (Implicit)
OS << "Implicit";
OS << "(Ctx";
@@ -2383,7 +2430,7 @@ void clang::EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
ai->writeImplicitCtorArgs(OS);
}
OS << ", I);\n";
- OS << " }\n";
+ OS << "}\n\n";
};
auto emitCreates = [&](bool emitFake) {
@@ -2393,6 +2440,9 @@ void clang::EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
emitCreateNoCI(false, emitFake);
};
+ if (Header)
+ OS << " // Factory methods\n";
+
// Emit a CreateImplicit that takes all the arguments.
emitCreates(true);
@@ -2407,7 +2457,11 @@ void clang::EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
if (arg->isOptional()) return emitOpt;
return true;
};
- OS << " " << R.getName()
+ if (Header)
+ OS << " ";
+ else
+ OS << R.getName() << "Attr::";
+ OS << R.getName()
<< "Attr(ASTContext &Ctx, const AttributeCommonInfo &CommonInfo";
OS << '\n';
for (auto const &ai : Args) {
@@ -2417,8 +2471,12 @@ void clang::EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
OS << "\n";
}
- OS << " )\n";
- OS << " : " << SuperName << "(Ctx, CommonInfo, ";
+ OS << " )";
+ if (Header) {
+ OS << ";\n";
+ return;
+ }
+ OS << "\n : " << SuperName << "(Ctx, CommonInfo, ";
OS << "attr::" << R.getName() << ", "
<< (R.getValueAsBit("LateParsed") ? "true" : "false");
if (Inheritable) {
@@ -2444,9 +2502,12 @@ void clang::EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
if (!shouldEmitArg(ai)) continue;
ai->writeCtorBody(OS);
}
- OS << " }\n\n";
+ OS << "}\n\n";
};
+ if (Header)
+ OS << "\n // Constructors\n";
+
// Emit a constructor that includes all the arguments.
// This is necessary for cloning.
emitCtor(true, true);
@@ -2459,43 +2520,84 @@ void clang::EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
if (HasOptArg)
emitCtor(false, false);
- OS << " " << R.getName() << "Attr *clone(ASTContext &C) const;\n";
- OS << " void printPretty(raw_ostream &OS,\n"
- << " const PrintingPolicy &Policy) const;\n";
- OS << " const char *getSpelling() const;\n";
+ if (Header) {
+ OS << '\n';
+ OS << " " << R.getName() << "Attr *clone(ASTContext &C) const;\n";
+ OS << " void printPretty(raw_ostream &OS,\n"
+ << " const PrintingPolicy &Policy) const;\n";
+ OS << " const char *getSpelling() const;\n";
+ }
if (!ElideSpelling) {
assert(!SemanticToSyntacticMap.empty() && "Empty semantic mapping list");
- OS << " Spelling getSemanticSpelling() const {\n";
- WriteSemanticSpellingSwitch("getAttributeSpellingListIndex()",
- SemanticToSyntacticMap, OS);
- OS << " }\n";
+ if (Header)
+ OS << " Spelling getSemanticSpelling() const;\n";
+ else {
+ OS << R.getName() << "Attr::Spelling " << R.getName()
+ << "Attr::getSemanticSpelling() const {\n";
+ WriteSemanticSpellingSwitch("getAttributeSpellingListIndex()",
+ SemanticToSyntacticMap, OS);
+ OS << "}\n";
+ }
}
- writeAttrAccessorDefinition(R, OS);
+ if (Header)
+ writeAttrAccessorDefinition(R, OS);
for (auto const &ai : Args) {
- ai->writeAccessors(OS);
+ if (Header) {
+ ai->writeAccessors(OS);
+ } else {
+ ai->writeAccessorDefinitions(OS);
+ }
OS << "\n\n";
// Don't write conversion routines for fake arguments.
if (ai->isFake()) continue;
if (ai->isEnumArg())
- static_cast<const EnumArgument *>(ai.get())->writeConversion(OS);
+ static_cast<const EnumArgument *>(ai.get())->writeConversion(OS,
+ Header);
else if (ai->isVariadicEnumArg())
- static_cast<const VariadicEnumArgument *>(ai.get())
- ->writeConversion(OS);
+ static_cast<const VariadicEnumArgument *>(ai.get())->writeConversion(
+ OS, Header);
}
- OS << R.getValueAsString("AdditionalMembers");
- OS << "\n\n";
+ if (Header) {
+ OS << R.getValueAsString("AdditionalMembers");
+ OS << "\n\n";
+
+ OS << " static bool classof(const Attr *A) { return A->getKind() == "
+ << "attr::" << R.getName() << "; }\n";
- OS << " static bool classof(const Attr *A) { return A->getKind() == "
- << "attr::" << R.getName() << "; }\n";
+ OS << "};\n\n";
+ } else {
+ OS << R.getName() << "Attr *" << R.getName()
+ << "Attr::clone(ASTContext &C) const {\n";
+ OS << " auto *A = new (C) " << R.getName() << "Attr(C, *this";
+ for (auto const &ai : Args) {
+ OS << ", ";
+ ai->writeCloneArgs(OS);
+ }
+ OS << ");\n";
+ OS << " A->Inherited = Inherited;\n";
+ OS << " A->IsPackExpansion = IsPackExpansion;\n";
+ OS << " A->setImplicit(Implicit);\n";
+ OS << " return A;\n}\n\n";
- OS << "};\n\n";
+ writePrettyPrintFunction(R, Args, OS);
+ writeGetSpellingFunction(R, OS);
+ }
}
+}
+// Emits the class definitions for attributes.
+void clang::EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
+ emitSourceFileHeader("Attribute classes' definitions", OS);
+
+ OS << "#ifndef LLVM_CLANG_ATTR_CLASSES_INC\n";
+ OS << "#define LLVM_CLANG_ATTR_CLASSES_INC\n\n";
+
+ emitAttributes(Records, OS, true);
OS << "#endif // LLVM_CLANG_ATTR_CLASSES_INC\n";
}
@@ -2504,38 +2606,9 @@ void clang::EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
void clang::EmitClangAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
emitSourceFileHeader("Attribute classes' member function definitions", OS);
- std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
+ emitAttributes(Records, OS, false);
- for (auto *Attr : Attrs) {
- Record &R = *Attr;
-
- if (!R.getValueAsBit("ASTNode"))
- continue;
-
- std::vector<Record*> ArgRecords = R.getValueAsListOfDefs("Args");
- std::vector<std::unique_ptr<Argument>> Args;
- for (const auto *Arg : ArgRecords)
- Args.emplace_back(createArgument(*Arg, R.getName()));
-
- for (auto const &ai : Args)
- ai->writeAccessorDefinitions(OS);
-
- OS << R.getName() << "Attr *" << R.getName()
- << "Attr::clone(ASTContext &C) const {\n";
- OS << " auto *A = new (C) " << R.getName() << "Attr(C, *this";
- for (auto const &ai : Args) {
- OS << ", ";
- ai->writeCloneArgs(OS);
- }
- OS << ");\n";
- OS << " A->Inherited = Inherited;\n";
- OS << " A->IsPackExpansion = IsPackExpansion;\n";
- OS << " A->setImplicit(Implicit);\n";
- OS << " return A;\n}\n\n";
-
- writePrettyPrintFunction(R, Args, OS);
- writeGetSpellingFunction(R, OS);
- }
+ std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr");
// Instead of relying on virtual dispatch we just create a huge dispatch
// switch. This is both smaller and faster than virtual functions.
More information about the cfe-commits
mailing list