diff options
Diffstat (limited to 'utils')
-rw-r--r-- | utils/TableGen/ClangASTNodesEmitter.cpp | 10 | ||||
-rw-r--r-- | utils/TableGen/ClangAttrEmitter.cpp | 264 | ||||
-rw-r--r-- | utils/TableGen/ClangCommentCommandInfoEmitter.cpp | 8 | ||||
-rw-r--r-- | utils/TableGen/ClangCommentHTMLNamedCharacterReferenceEmitter.cpp | 9 | ||||
-rw-r--r-- | utils/TableGen/ClangDataCollectorsEmitter.cpp | 5 | ||||
-rw-r--r-- | utils/TableGen/ClangDiagnosticsEmitter.cpp | 18 | ||||
-rw-r--r-- | utils/TableGen/ClangOpcodesEmitter.cpp | 357 | ||||
-rw-r--r-- | utils/TableGen/ClangOpenCLBuiltinEmitter.cpp | 540 | ||||
-rw-r--r-- | utils/TableGen/ClangOptionDocEmitter.cpp | 9 | ||||
-rw-r--r-- | utils/TableGen/ClangSACheckersEmitter.cpp | 5 | ||||
-rw-r--r-- | utils/TableGen/ClangTypeNodesEmitter.cpp | 220 | ||||
-rw-r--r-- | utils/TableGen/NeonEmitter.cpp | 60 | ||||
-rw-r--r-- | utils/TableGen/TableGen.cpp | 12 | ||||
-rw-r--r-- | utils/TableGen/TableGenBackends.h | 2 |
14 files changed, 1251 insertions, 268 deletions
diff --git a/utils/TableGen/ClangASTNodesEmitter.cpp b/utils/TableGen/ClangASTNodesEmitter.cpp index a0bbdbab33542..3ece9be6a5c77 100644 --- a/utils/TableGen/ClangASTNodesEmitter.cpp +++ b/utils/TableGen/ClangASTNodesEmitter.cpp @@ -10,6 +10,8 @@ // //===----------------------------------------------------------------------===// +#include "TableGenBackends.h" + #include "llvm/TableGen/Record.h" #include "llvm/TableGen/TableGenBackend.h" #include <cctype> @@ -173,15 +175,14 @@ void ClangASTNodesEmitter::run(raw_ostream &OS) { OS << "#undef ABSTRACT_" << macroName(Root.getName()) << "\n"; } -namespace clang { -void EmitClangASTNodes(RecordKeeper &RK, raw_ostream &OS, - const std::string &N, const std::string &S) { +void clang::EmitClangASTNodes(RecordKeeper &RK, raw_ostream &OS, + const std::string &N, const std::string &S) { ClangASTNodesEmitter(RK, N, S).run(OS); } // Emits and addendum to a .inc file to enumerate the clang declaration // contexts. -void EmitClangDeclContext(RecordKeeper &Records, raw_ostream &OS) { +void clang::EmitClangDeclContext(RecordKeeper &Records, raw_ostream &OS) { // FIXME: Find a .td file format to allow for this to be represented better. emitSourceFileHeader("List of AST Decl nodes", OS); @@ -225,4 +226,3 @@ void EmitClangDeclContext(RecordKeeper &Records, raw_ostream &OS) { OS << "#undef DECL_CONTEXT\n"; OS << "#undef DECL_CONTEXT_BASE\n"; } -} // end namespace clang diff --git a/utils/TableGen/ClangAttrEmitter.cpp b/utils/TableGen/ClangAttrEmitter.cpp index f315262ad0f40..0d92a321c7475 100644 --- a/utils/TableGen/ClangAttrEmitter.cpp +++ b/utils/TableGen/ClangAttrEmitter.cpp @@ -10,6 +10,8 @@ // //===----------------------------------------------------------------------===// +#include "TableGenBackends.h" + #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" @@ -303,6 +305,8 @@ namespace { std::string getIsOmitted() const override { if (type == "IdentifierInfo *") return "!get" + getUpperName().str() + "()"; + if (type == "TypeSourceInfo *") + return "!get" + getUpperName().str() + "Loc()"; if (type == "ParamIdx") return "!get" + getUpperName().str() + "().isValid()"; return "false"; @@ -336,6 +340,8 @@ namespace { << " OS << \" \" << SA->get" << getUpperName() << "()->getName();\n"; } else if (type == "TypeSourceInfo *") { + if (isOptional()) + OS << " if (SA->get" << getUpperName() << "Loc())"; OS << " OS << \" \" << SA->get" << getUpperName() << "().getAsString();\n"; } else if (type == "bool") { @@ -1251,51 +1257,51 @@ createArgument(const Record &Arg, StringRef Attr, llvm::StringRef ArgName = Search->getName(); if (ArgName == "AlignedArgument") - Ptr = llvm::make_unique<AlignedArgument>(Arg, Attr); + Ptr = std::make_unique<AlignedArgument>(Arg, Attr); else if (ArgName == "EnumArgument") - Ptr = llvm::make_unique<EnumArgument>(Arg, Attr); + Ptr = std::make_unique<EnumArgument>(Arg, Attr); else if (ArgName == "ExprArgument") - Ptr = llvm::make_unique<ExprArgument>(Arg, Attr); + Ptr = std::make_unique<ExprArgument>(Arg, Attr); else if (ArgName == "FunctionArgument") - Ptr = llvm::make_unique<SimpleArgument>(Arg, Attr, "FunctionDecl *"); + Ptr = std::make_unique<SimpleArgument>(Arg, Attr, "FunctionDecl *"); else if (ArgName == "NamedArgument") - Ptr = llvm::make_unique<SimpleArgument>(Arg, Attr, "NamedDecl *"); + Ptr = std::make_unique<SimpleArgument>(Arg, Attr, "NamedDecl *"); else if (ArgName == "IdentifierArgument") - Ptr = llvm::make_unique<SimpleArgument>(Arg, Attr, "IdentifierInfo *"); + Ptr = std::make_unique<SimpleArgument>(Arg, Attr, "IdentifierInfo *"); else if (ArgName == "DefaultBoolArgument") - Ptr = llvm::make_unique<DefaultSimpleArgument>( + Ptr = std::make_unique<DefaultSimpleArgument>( Arg, Attr, "bool", Arg.getValueAsBit("Default")); else if (ArgName == "BoolArgument") - Ptr = llvm::make_unique<SimpleArgument>(Arg, Attr, "bool"); + Ptr = std::make_unique<SimpleArgument>(Arg, Attr, "bool"); else if (ArgName == "DefaultIntArgument") - Ptr = llvm::make_unique<DefaultSimpleArgument>( + Ptr = std::make_unique<DefaultSimpleArgument>( Arg, Attr, "int", Arg.getValueAsInt("Default")); else if (ArgName == "IntArgument") - Ptr = llvm::make_unique<SimpleArgument>(Arg, Attr, "int"); + Ptr = std::make_unique<SimpleArgument>(Arg, Attr, "int"); else if (ArgName == "StringArgument") - Ptr = llvm::make_unique<StringArgument>(Arg, Attr); + Ptr = std::make_unique<StringArgument>(Arg, Attr); else if (ArgName == "TypeArgument") - Ptr = llvm::make_unique<TypeArgument>(Arg, Attr); + Ptr = std::make_unique<TypeArgument>(Arg, Attr); else if (ArgName == "UnsignedArgument") - Ptr = llvm::make_unique<SimpleArgument>(Arg, Attr, "unsigned"); + Ptr = std::make_unique<SimpleArgument>(Arg, Attr, "unsigned"); else if (ArgName == "VariadicUnsignedArgument") - Ptr = llvm::make_unique<VariadicArgument>(Arg, Attr, "unsigned"); + Ptr = std::make_unique<VariadicArgument>(Arg, Attr, "unsigned"); else if (ArgName == "VariadicStringArgument") - Ptr = llvm::make_unique<VariadicStringArgument>(Arg, Attr); + Ptr = std::make_unique<VariadicStringArgument>(Arg, Attr); else if (ArgName == "VariadicEnumArgument") - Ptr = llvm::make_unique<VariadicEnumArgument>(Arg, Attr); + Ptr = std::make_unique<VariadicEnumArgument>(Arg, Attr); else if (ArgName == "VariadicExprArgument") - Ptr = llvm::make_unique<VariadicExprArgument>(Arg, Attr); + Ptr = std::make_unique<VariadicExprArgument>(Arg, Attr); else if (ArgName == "VariadicParamIdxArgument") - Ptr = llvm::make_unique<VariadicParamIdxArgument>(Arg, Attr); + Ptr = std::make_unique<VariadicParamIdxArgument>(Arg, Attr); else if (ArgName == "VariadicParamOrParamIdxArgument") - Ptr = llvm::make_unique<VariadicParamOrParamIdxArgument>(Arg, Attr); + Ptr = std::make_unique<VariadicParamOrParamIdxArgument>(Arg, Attr); else if (ArgName == "ParamIdxArgument") - Ptr = llvm::make_unique<SimpleArgument>(Arg, Attr, "ParamIdx"); + Ptr = std::make_unique<SimpleArgument>(Arg, Attr, "ParamIdx"); else if (ArgName == "VariadicIdentifierArgument") - Ptr = llvm::make_unique<VariadicIdentifierArgument>(Arg, Attr); + Ptr = std::make_unique<VariadicIdentifierArgument>(Arg, Attr); else if (ArgName == "VersionArgument") - Ptr = llvm::make_unique<VersionArgument>(Arg, Attr); + Ptr = std::make_unique<VersionArgument>(Arg, Attr); if (!Ptr) { // Search in reverse order so that the most-derived type is handled first. @@ -1343,7 +1349,7 @@ static void writeGetSpellingFunction(Record &R, raw_ostream &OS) { return; } - OS << " switch (SpellingListIndex) {\n" + OS << " switch (getAttributeSpellingListIndex()) {\n" " default:\n" " llvm_unreachable(\"Unknown attribute spelling!\");\n" " return \"(No spelling)\";\n"; @@ -1371,11 +1377,10 @@ writePrettyPrintFunction(Record &R, return; } - OS << - " switch (SpellingListIndex) {\n" - " default:\n" - " llvm_unreachable(\"Unknown attribute spelling!\");\n" - " break;\n"; + OS << " switch (getAttributeSpellingListIndex()) {\n" + " default:\n" + " llvm_unreachable(\"Unknown attribute spelling!\");\n" + " break;\n"; for (unsigned I = 0; I < Spellings.size(); ++ I) { llvm::SmallString<16> Prefix; @@ -1556,11 +1561,12 @@ static void writeAttrAccessorDefinition(const Record &R, raw_ostream &OS) { const StringRef Name = Accessor->getValueAsString("Name"); std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(*Accessor); - OS << " bool " << Name << "() const { return SpellingListIndex == "; + OS << " bool " << Name + << "() const { return getAttributeSpellingListIndex() == "; for (unsigned Index = 0; Index < Spellings.size(); ++Index) { OS << getSpellingListIndex(SpellingList, Spellings[Index]); if (Index != Spellings.size() - 1) - OS << " ||\n SpellingListIndex == "; + OS << " ||\n getAttributeSpellingListIndex() == "; else OS << "; }\n"; } @@ -1592,6 +1598,13 @@ CreateSemanticSpellings(const std::vector<FlattenedSpelling> &Spellings, std::string Ret(" enum Spelling {\n"); std::set<std::string> Uniques; unsigned Idx = 0; + + // If we have a need to have this many spellings we likely need to add an + // extra bit to the SpellingIndex in AttributeCommonInfo, then increase the + // value of SpellingNotCalculated there and here. + assert(Spellings.size() < 15 && + "Too many spellings, would step on SpellingNotCalculated in " + "AttributeCommonInfo"); for (auto I = Spellings.begin(), E = Spellings.end(); I != E; ++I, ++Idx) { const FlattenedSpelling &S = *I; const std::string &Variety = S.variety(); @@ -1625,6 +1638,7 @@ CreateSemanticSpellings(const std::vector<FlattenedSpelling> &Spellings, // enumerator. Ret += " " + EnumName + " = " + llvm::utostr(Idx); } + Ret += ",\n SpellingNotCalculated = 15\n"; Ret += "\n };\n\n"; return Ret; } @@ -2207,16 +2221,15 @@ static void emitClangAttrThisIsaIdentifierArgList(RecordKeeper &Records, OS << "#endif // CLANG_ATTR_THIS_ISA_IDENTIFIER_ARG_LIST\n\n"; } -namespace clang { - // Emits the class definitions for attributes. -void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) { +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"; std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"); + ParsedAttrMap AttrMap = getParsedAttrList(Records); for (const auto *Attr : Attrs) { const Record &R = *Attr; @@ -2285,38 +2298,97 @@ void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) { if (!ElideSpelling) OS << CreateSemanticSpellings(Spellings, SemanticToSyntacticMap); + const auto &ParsedAttrSpellingItr = llvm::find_if( + AttrMap, [R](const std::pair<std::string, const Record *> &P) { + return &R == P.second; + }); + // Emit CreateImplicit factory methods. - auto emitCreateImplicit = [&](bool emitFake) { - OS << " static " << R.getName() << "Attr *CreateImplicit("; + auto emitCreate = [&](bool Implicit, bool emitFake) { + OS << " static " << R.getName() << "Attr *Create"; + if (Implicit) + OS << "Implicit"; + OS << "("; OS << "ASTContext &Ctx"; - if (!ElideSpelling) - OS << ", Spelling S"; for (auto const &ai : Args) { if (ai->isFake() && !emitFake) continue; OS << ", "; ai->writeCtorParameters(OS); } - OS << ", SourceRange Loc = SourceRange()"; - OS << ") {\n"; + OS << ", const AttributeCommonInfo &CommonInfo = {SourceRange{}}) {\n"; OS << " auto *A = new (Ctx) " << R.getName(); - OS << "Attr(Loc, Ctx, "; + OS << "Attr(Ctx, CommonInfo"; for (auto const &ai : Args) { if (ai->isFake() && !emitFake) continue; - ai->writeImplicitCtorArgs(OS); OS << ", "; + ai->writeImplicitCtorArgs(OS); + } + OS << ");\n"; + if (Implicit) { + OS << " A->setImplicit(true);\n"; + } + if (Implicit || ElideSpelling) { + OS << " if (!A->isAttributeSpellingListCalculated() && " + "!A->getAttrName())\n"; + OS << " A->setAttributeSpellingListIndex(0);\n"; } - OS << (ElideSpelling ? "0" : "S") << ");\n"; - OS << " A->setImplicit(true);\n"; OS << " return A;\n }\n\n"; }; + auto emitCreateNoCI = [&](bool Implicit, bool emitFake) { + OS <<" static " << R.getName() << "Attr *Create"; + if (Implicit) + OS << "Implicit"; + OS << "("; + OS << "ASTContext &Ctx"; + for (auto const &ai : Args) { + if (ai->isFake() && !emitFake) continue; + 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 (ParsedAttrSpellingItr != std::end(AttrMap)) + OS << "AT_" << ParsedAttrSpellingItr->first; + else + OS << "NoSemaHandlerAttribute"; + + OS << ", Syntax"; + if (!ElideSpelling) + OS << ", S"; + OS << ");\n"; + OS << " return Create"; + if (Implicit) + OS << "Implicit"; + OS << "(Ctx"; + for (auto const &ai : Args) { + if (ai->isFake() && !emitFake) continue; + OS << ", "; + ai->writeImplicitCtorArgs(OS); + } + OS << ", I);\n"; + OS << " }\n"; + }; + + auto emitCreates = [&](bool emitFake) { + emitCreate(true, emitFake); + emitCreate(false, emitFake); + emitCreateNoCI(true, emitFake); + emitCreateNoCI(false, emitFake); + }; + // Emit a CreateImplicit that takes all the arguments. - emitCreateImplicit(true); + emitCreates(true); // Emit a CreateImplicit that takes all the non-fake arguments. - if (HasFakeArg) { - emitCreateImplicit(false); - } + if (HasFakeArg) + emitCreates(false); // Emit constructors. auto emitCtor = [&](bool emitOpt, bool emitFake) { @@ -2325,8 +2397,9 @@ void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) { if (arg->isOptional()) return emitOpt; return true; }; - - OS << " " << R.getName() << "Attr(SourceRange R, ASTContext &Ctx\n"; + OS << " " << R.getName() + << "Attr(ASTContext &Ctx, const AttributeCommonInfo &CommonInfo"; + OS << '\n'; for (auto const &ai : Args) { if (!shouldEmitArg(ai)) continue; OS << " , "; @@ -2334,12 +2407,10 @@ void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) { OS << "\n"; } - OS << " , "; - OS << "unsigned SI\n"; - OS << " )\n"; - OS << " : " << SuperName << "(attr::" << R.getName() << ", R, SI, " - << ( R.getValueAsBit("LateParsed") ? "true" : "false" ); + OS << " : " << SuperName << "(Ctx, CommonInfo, "; + OS << "attr::" << R.getName() << ", " + << (R.getValueAsBit("LateParsed") ? "true" : "false"); if (Inheritable) { OS << ", " << (R.getValueAsBit("InheritEvenIfAlreadyPresent") ? "true" @@ -2371,14 +2442,12 @@ void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) { emitCtor(true, true); // Emit a constructor that takes all the non-fake arguments. - if (HasFakeArg) { + if (HasFakeArg) emitCtor(true, false); - } // Emit a constructor that takes all the non-fake, non-optional arguments. - if (HasOptArg) { + if (HasOptArg) emitCtor(false, false); - } OS << " " << R.getName() << "Attr *clone(ASTContext &C) const;\n"; OS << " void printPretty(raw_ostream &OS,\n" @@ -2388,8 +2457,8 @@ void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) { if (!ElideSpelling) { assert(!SemanticToSyntacticMap.empty() && "Empty semantic mapping list"); OS << " Spelling getSemanticSpelling() const {\n"; - WriteSemanticSpellingSwitch("SpellingListIndex", SemanticToSyntacticMap, - OS); + WriteSemanticSpellingSwitch("getAttributeSpellingListIndex()", + SemanticToSyntacticMap, OS); OS << " }\n"; } @@ -2422,7 +2491,7 @@ void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) { } // Emits the class method definitions for attributes. -void EmitClangAttrImpl(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"); @@ -2443,15 +2512,15 @@ void EmitClangAttrImpl(RecordKeeper &Records, raw_ostream &OS) { OS << R.getName() << "Attr *" << R.getName() << "Attr::clone(ASTContext &C) const {\n"; - OS << " auto *A = new (C) " << R.getName() << "Attr(getLocation(), C"; + OS << " auto *A = new (C) " << R.getName() << "Attr(C, *this"; for (auto const &ai : Args) { OS << ", "; ai->writeCloneArgs(OS); } - OS << ", getSpellingListIndex());\n"; + OS << ");\n"; OS << " A->Inherited = Inherited;\n"; OS << " A->IsPackExpansion = IsPackExpansion;\n"; - OS << " A->Implicit = Implicit;\n"; + OS << " A->setImplicit(Implicit);\n"; OS << " return A;\n}\n\n"; writePrettyPrintFunction(R, Args, OS); @@ -2487,8 +2556,6 @@ void EmitClangAttrImpl(RecordKeeper &Records, raw_ostream &OS) { EmitFunc("printPretty(OS, Policy)"); } -} // end namespace clang - static void emitAttrList(raw_ostream &OS, StringRef Class, const std::vector<Record*> &AttrList) { for (auto Cur : AttrList) { @@ -2751,24 +2818,23 @@ void EmitClangAttrPCHRead(RecordKeeper &Records, raw_ostream &OS) { const Record &R = *Attr; if (!R.getValueAsBit("ASTNode")) continue; - + OS << " case attr::" << R.getName() << ": {\n"; if (R.isSubClassOf(InhClass)) OS << " bool isInherited = Record.readInt();\n"; OS << " bool isImplicit = Record.readInt();\n"; - OS << " unsigned Spelling = Record.readInt();\n"; ArgRecords = R.getValueAsListOfDefs("Args"); Args.clear(); for (const auto *Arg : ArgRecords) { Args.emplace_back(createArgument(*Arg, R.getName())); Args.back()->writePCHReadDecls(OS); } - OS << " New = new (Context) " << R.getName() << "Attr(Range, Context"; + OS << " New = new (Context) " << R.getName() << "Attr(Context, Info"; for (auto const &ri : Args) { OS << ", "; ri->writePCHReadArgs(OS); } - OS << ", Spelling);\n"; + OS << ");\n"; if (R.isSubClassOf(InhClass)) OS << " cast<InheritableAttr>(New)->setInherited(isInherited);\n"; OS << " New->setImplicit(isImplicit);\n"; @@ -2798,7 +2864,6 @@ void EmitClangAttrPCHWrite(RecordKeeper &Records, raw_ostream &OS) { if (R.isSubClassOf(InhClass)) OS << " Record.push_back(SA->isInherited());\n"; OS << " Record.push_back(A->isImplicit());\n"; - OS << " Record.push_back(A->getSpellingListIndex());\n"; for (const auto *Arg : Args) createArgument(*Arg, R.getName())->writePCHWrite(OS); @@ -3015,7 +3080,11 @@ void EmitClangAttrSpellingListIndex(RecordKeeper &Records, raw_ostream &OS) { emitSourceFileHeader("Code to translate different attribute spellings " "into internal identifiers", OS); - OS << " switch (AttrKind) {\n"; + OS << " switch (getParsedKind()) {\n"; + OS << " case IgnoredAttribute:\n"; + OS << " case UnknownAttribute:\n"; + OS << " case NoSemaHandlerAttribute:\n"; + OS << " llvm_unreachable(\"Ignored/unknown shouldn't get here\");\n"; ParsedAttrMap Attrs = getParsedAttrList(Records); for (const auto &I : Attrs) { @@ -3024,16 +3093,7 @@ void EmitClangAttrSpellingListIndex(RecordKeeper &Records, raw_ostream &OS) { OS << " case AT_" << I.first << ": {\n"; for (unsigned I = 0; I < Spellings.size(); ++ I) { OS << " if (Name == \"" << Spellings[I].name() << "\" && " - << "SyntaxUsed == " - << StringSwitch<unsigned>(Spellings[I].variety()) - .Case("GNU", 0) - .Case("CXX11", 1) - .Case("C2x", 2) - .Case("Declspec", 3) - .Case("Microsoft", 4) - .Case("Keyword", 5) - .Case("Pragma", 6) - .Default(0) + << "getSyntax() == AttributeCommonInfo::AS_" << Spellings[I].variety() << " && Scope == \"" << Spellings[I].nameSpace() << "\")\n" << " return " << I << ";\n"; } @@ -3154,12 +3214,12 @@ void EmitClangAttrTemplateInstantiateHelper(const std::vector<Record *> &Attrs, for (auto const &ai : Args) ai->writeTemplateInstantiation(OS); - OS << " return new (C) " << R.getName() << "Attr(A->getLocation(), C"; + OS << " return new (C) " << R.getName() << "Attr(C, *A"; for (auto const &ai : Args) { OS << ", "; ai->writeTemplateInstantiationArgs(OS); } - OS << ", A->getSpellingListIndex());\n }\n"; + OS << ");\n }\n"; } OS << " } // end switch\n" << " llvm_unreachable(\"Unknown attribute!\");\n" @@ -3477,7 +3537,7 @@ static std::string GenerateLangOptRequirements(const Record &R, OS << " if (" << GenerateTestExpression(LangOpts) << ")\n"; OS << " return true;\n\n"; OS << " S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) "; - OS << "<< Attr.getName();\n"; + OS << "<< Attr;\n"; OS << " return false;\n"; OS << "}\n\n"; @@ -3671,10 +3731,10 @@ void EmitClangAttrParsedAttrKinds(RecordKeeper &Records, raw_ostream &OS) { // specific attribute, or MSP430-specific attribute. Additionally, an // attribute can be spelled GNU<"dllexport"> and Declspec<"dllexport"> // for the same semantic attribute. Ultimately, we need to map each of - // these to a single ParsedAttr::Kind value, but the StringMatcher - // class cannot handle duplicate match strings. So we generate a list of - // string to match based on the syntax, and emit multiple string matchers - // depending on the syntax used. + // these to a single AttributeCommonInfo::Kind value, but the + // StringMatcher class cannot handle duplicate match strings. So we + // generate a list of string to match based on the syntax, and emit + // multiple string matchers depending on the syntax used. std::string AttrName; if (Attr.isSubClassOf("TargetSpecificAttr") && !Attr.isValueUnset("ParseKind")) { @@ -3719,33 +3779,33 @@ void EmitClangAttrParsedAttrKinds(RecordKeeper &Records, raw_ostream &OS) { if (SemaHandler) Matches->push_back(StringMatcher::StringPair( - Spelling, "return ParsedAttr::AT_" + AttrName + ";")); + Spelling, "return AttributeCommonInfo::AT_" + AttrName + ";")); else Matches->push_back(StringMatcher::StringPair( - Spelling, "return ParsedAttr::IgnoredAttribute;")); + Spelling, "return AttributeCommonInfo::IgnoredAttribute;")); } } } - OS << "static ParsedAttr::Kind getAttrKind(StringRef Name, "; - OS << "ParsedAttr::Syntax Syntax) {\n"; - OS << " if (ParsedAttr::AS_GNU == Syntax) {\n"; + OS << "static AttributeCommonInfo::Kind getAttrKind(StringRef Name, "; + OS << "AttributeCommonInfo::Syntax Syntax) {\n"; + OS << " if (AttributeCommonInfo::AS_GNU == Syntax) {\n"; StringMatcher("Name", GNU, OS).Emit(); - OS << " } else if (ParsedAttr::AS_Declspec == Syntax) {\n"; + OS << " } else if (AttributeCommonInfo::AS_Declspec == Syntax) {\n"; StringMatcher("Name", Declspec, OS).Emit(); - OS << " } else if (ParsedAttr::AS_Microsoft == Syntax) {\n"; + OS << " } else if (AttributeCommonInfo::AS_Microsoft == Syntax) {\n"; StringMatcher("Name", Microsoft, OS).Emit(); - OS << " } else if (ParsedAttr::AS_CXX11 == Syntax) {\n"; + OS << " } else if (AttributeCommonInfo::AS_CXX11 == Syntax) {\n"; StringMatcher("Name", CXX11, OS).Emit(); - OS << " } else if (ParsedAttr::AS_C2x == Syntax) {\n"; + OS << " } else if (AttributeCommonInfo::AS_C2x == Syntax) {\n"; StringMatcher("Name", C2x, OS).Emit(); - OS << " } else if (ParsedAttr::AS_Keyword == Syntax || "; - OS << "ParsedAttr::AS_ContextSensitiveKeyword == Syntax) {\n"; + OS << " } else if (AttributeCommonInfo::AS_Keyword == Syntax || "; + OS << "AttributeCommonInfo::AS_ContextSensitiveKeyword == Syntax) {\n"; StringMatcher("Name", Keywords, OS).Emit(); - OS << " } else if (ParsedAttr::AS_Pragma == Syntax) {\n"; + OS << " } else if (AttributeCommonInfo::AS_Pragma == Syntax) {\n"; StringMatcher("Name", Pragma, OS).Emit(); OS << " }\n"; - OS << " return ParsedAttr::UnknownAttribute;\n" + OS << " return AttributeCommonInfo::UnknownAttribute;\n" << "}\n"; } diff --git a/utils/TableGen/ClangCommentCommandInfoEmitter.cpp b/utils/TableGen/ClangCommentCommandInfoEmitter.cpp index c0dd70281a4d9..fc79d59713d69 100644 --- a/utils/TableGen/ClangCommentCommandInfoEmitter.cpp +++ b/utils/TableGen/ClangCommentCommandInfoEmitter.cpp @@ -11,6 +11,8 @@ // //===----------------------------------------------------------------------===// +#include "TableGenBackends.h" + #include "llvm/TableGen/Record.h" #include "llvm/TableGen/StringMatcher.h" #include "llvm/TableGen/TableGenBackend.h" @@ -18,8 +20,7 @@ using namespace llvm; -namespace clang { -void EmitClangCommentCommandInfo(RecordKeeper &Records, raw_ostream &OS) { +void clang::EmitClangCommentCommandInfo(RecordKeeper &Records, raw_ostream &OS) { emitSourceFileHeader("A list of commands useable in documentation " "comments", OS); @@ -105,7 +106,7 @@ static std::string MangleName(StringRef Str) { return Mangled; } -void EmitClangCommentCommandList(RecordKeeper &Records, raw_ostream &OS) { +void clang::EmitClangCommentCommandList(RecordKeeper &Records, raw_ostream &OS) { emitSourceFileHeader("A list of commands useable in documentation " "comments", OS); @@ -121,4 +122,3 @@ void EmitClangCommentCommandList(RecordKeeper &Records, raw_ostream &OS) { OS << "COMMENT_COMMAND(" << MangledName << ")\n"; } } -} // end namespace clang diff --git a/utils/TableGen/ClangCommentHTMLNamedCharacterReferenceEmitter.cpp b/utils/TableGen/ClangCommentHTMLNamedCharacterReferenceEmitter.cpp index 81af5b4b95f19..ed3f4bd6ef6c1 100644 --- a/utils/TableGen/ClangCommentHTMLNamedCharacterReferenceEmitter.cpp +++ b/utils/TableGen/ClangCommentHTMLNamedCharacterReferenceEmitter.cpp @@ -11,6 +11,7 @@ // //===----------------------------------------------------------------------===// +#include "TableGenBackends.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/ConvertUTF.h" #include "llvm/TableGen/Error.h" @@ -45,9 +46,8 @@ static bool translateCodePointToUTF8(unsigned CodePoint, return true; } -namespace clang { -void EmitClangCommentHTMLNamedCharacterReferences(RecordKeeper &Records, - raw_ostream &OS) { +void clang::EmitClangCommentHTMLNamedCharacterReferences(RecordKeeper &Records, + raw_ostream &OS) { std::vector<Record *> Tags = Records.getAllDerivedDefinitions("NCR"); std::vector<StringMatcher::StringPair> NameToUTF8; SmallString<32> CLiteral; @@ -79,6 +79,3 @@ void EmitClangCommentHTMLNamedCharacterReferences(RecordKeeper &Records, OS << " return StringRef();\n" << "}\n\n"; } - -} // end namespace clang - diff --git a/utils/TableGen/ClangDataCollectorsEmitter.cpp b/utils/TableGen/ClangDataCollectorsEmitter.cpp index 4079efc808231..45082935c1f79 100644 --- a/utils/TableGen/ClangDataCollectorsEmitter.cpp +++ b/utils/TableGen/ClangDataCollectorsEmitter.cpp @@ -1,10 +1,10 @@ +#include "TableGenBackends.h" #include "llvm/TableGen/Record.h" #include "llvm/TableGen/TableGenBackend.h" using namespace llvm; -namespace clang { -void EmitClangDataCollectors(RecordKeeper &RK, raw_ostream &OS) { +void clang::EmitClangDataCollectors(RecordKeeper &RK, raw_ostream &OS) { const auto &Defs = RK.getClasses(); for (const auto &Entry : Defs) { Record &R = *Entry.second; @@ -15,4 +15,3 @@ void EmitClangDataCollectors(RecordKeeper &RK, raw_ostream &OS) { } OS << "#undef DEF_ADD_DATA\n"; } -} // end namespace clang diff --git a/utils/TableGen/ClangDiagnosticsEmitter.cpp b/utils/TableGen/ClangDiagnosticsEmitter.cpp index 13e564e130ce4..778375010041d 100644 --- a/utils/TableGen/ClangDiagnosticsEmitter.cpp +++ b/utils/TableGen/ClangDiagnosticsEmitter.cpp @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// +#include "TableGenBackends.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/PointerUnion.h" @@ -1187,9 +1188,8 @@ static bool isRemark(const Record &Diag) { /// ClangDiagsDefsEmitter - The top-level class emits .def files containing /// declarations of Clang diagnostics. -namespace clang { -void EmitClangDiagsDefs(RecordKeeper &Records, raw_ostream &OS, - const std::string &Component) { +void clang::EmitClangDiagsDefs(RecordKeeper &Records, raw_ostream &OS, + const std::string &Component) { // Write the #if guard if (!Component.empty()) { std::string ComponentName = StringRef(Component).upper(); @@ -1288,7 +1288,6 @@ void EmitClangDiagsDefs(RecordKeeper &Records, raw_ostream &OS, OS << ")\n"; } } -} // end namespace clang //===----------------------------------------------------------------------===// // Warning Group Tables generation @@ -1528,8 +1527,7 @@ static void emitCategoryTable(RecordKeeper &Records, raw_ostream &OS) { OS << "#endif // GET_CATEGORY_TABLE\n\n"; } -namespace clang { -void EmitClangDiagGroups(RecordKeeper &Records, raw_ostream &OS) { +void clang::EmitClangDiagGroups(RecordKeeper &Records, raw_ostream &OS) { // Compute a mapping from a DiagGroup to all of its parents. DiagGroupParentMap DGParentMap(Records); @@ -1565,7 +1563,6 @@ void EmitClangDiagGroups(RecordKeeper &Records, raw_ostream &OS) { OS); emitCategoryTable(Records, OS); } -} // end namespace clang //===----------------------------------------------------------------------===// // Diagnostic name index generation @@ -1582,8 +1579,7 @@ struct RecordIndexElement }; } // end anonymous namespace. -namespace clang { -void EmitClangDiagsIndexName(RecordKeeper &Records, raw_ostream &OS) { +void clang::EmitClangDiagsIndexName(RecordKeeper &Records, raw_ostream &OS) { const std::vector<Record*> &Diags = Records.getAllDerivedDefinitions("Diagnostic"); @@ -1673,7 +1669,7 @@ void writeDiagnosticText(DiagnosticTextBuilder &Builder, const Record *R, } // namespace } // namespace docs -void EmitClangDiagDocs(RecordKeeper &Records, raw_ostream &OS) { +void clang::EmitClangDiagDocs(RecordKeeper &Records, raw_ostream &OS) { using namespace docs; // Get the documentation introduction paragraph. @@ -1792,5 +1788,3 @@ void EmitClangDiagDocs(RecordKeeper &Records, raw_ostream &OS) { OS << "\n"; } } - -} // end namespace clang diff --git a/utils/TableGen/ClangOpcodesEmitter.cpp b/utils/TableGen/ClangOpcodesEmitter.cpp new file mode 100644 index 0000000000000..e5bfac5ba1b6f --- /dev/null +++ b/utils/TableGen/ClangOpcodesEmitter.cpp @@ -0,0 +1,357 @@ +//=== ClangOpcodesEmitter.cpp - constexpr interpreter opcodes ---*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// These tablegen backends emit Clang AST node tables +// +//===----------------------------------------------------------------------===// + +#include "TableGenBackends.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Record.h" +#include "llvm/TableGen/StringMatcher.h" +#include "llvm/TableGen/TableGenBackend.h" + +using namespace llvm; + +namespace { +class ClangOpcodesEmitter { + RecordKeeper &Records; + Record Root; + unsigned NumTypes; + +public: + ClangOpcodesEmitter(RecordKeeper &R) + : Records(R), Root("Opcode", SMLoc(), R), + NumTypes(Records.getAllDerivedDefinitions("Type").size()) {} + + void run(raw_ostream &OS); + +private: + /// Emits the opcode name for the opcode enum. + /// The name is obtained by concatenating the name with the list of types. + void EmitEnum(raw_ostream &OS, StringRef N, Record *R); + + /// Emits the switch case and the invocation in the interpreter. + void EmitInterp(raw_ostream &OS, StringRef N, Record *R); + + /// Emits the disassembler. + void EmitDisasm(raw_ostream &OS, StringRef N, Record *R); + + /// Emits the byte code emitter method. + void EmitEmitter(raw_ostream &OS, StringRef N, Record *R); + + /// Emits the prototype. + void EmitProto(raw_ostream &OS, StringRef N, Record *R); + + /// Emits the prototype to dispatch from a type. + void EmitGroup(raw_ostream &OS, StringRef N, Record *R); + + /// Emits the evaluator method. + void EmitEval(raw_ostream &OS, StringRef N, Record *R); + + void PrintTypes(raw_ostream &OS, ArrayRef<Record *> Types); +}; + +void Enumerate(const Record *R, + StringRef N, + std::function<void(ArrayRef<Record *>, Twine)> &&F) { + llvm::SmallVector<Record *, 2> TypePath; + auto *Types = R->getValueAsListInit("Types"); + + std::function<void(size_t, const Twine &)> Rec; + Rec = [&TypePath, Types, &Rec, &F](size_t I, const Twine &ID) { + if (I >= Types->size()) { + F(TypePath, ID); + return; + } + + if (auto *TypeClass = dyn_cast<DefInit>(Types->getElement(I))) { + for (auto *Type : TypeClass->getDef()->getValueAsListOfDefs("Types")) { + TypePath.push_back(Type); + Rec(I + 1, ID + Type->getName()); + TypePath.pop_back(); + } + } else { + PrintFatalError("Expected a type class"); + } + }; + Rec(0, N); +} + +} // namespace + +void ClangOpcodesEmitter::run(raw_ostream &OS) { + for (auto *Opcode : Records.getAllDerivedDefinitions(Root.getName())) { + // The name is the record name, unless overriden. + StringRef N = Opcode->getValueAsString("Name"); + if (N.empty()) + N = Opcode->getName(); + + EmitEnum(OS, N, Opcode); + EmitInterp(OS, N, Opcode); + EmitDisasm(OS, N, Opcode); + EmitProto(OS, N, Opcode); + EmitGroup(OS, N, Opcode); + EmitEmitter(OS, N, Opcode); + EmitEval(OS, N, Opcode); + } +} + +void ClangOpcodesEmitter::EmitEnum(raw_ostream &OS, StringRef N, Record *R) { + OS << "#ifdef GET_OPCODE_NAMES\n"; + Enumerate(R, N, [&OS](ArrayRef<Record *>, const Twine &ID) { + OS << "OP_" << ID << ",\n"; + }); + OS << "#endif\n"; +} + +void ClangOpcodesEmitter::EmitInterp(raw_ostream &OS, StringRef N, Record *R) { + OS << "#ifdef GET_INTERP\n"; + + Enumerate(R, N, [this, R, &OS, &N](ArrayRef<Record *> TS, const Twine &ID) { + bool CanReturn = R->getValueAsBit("CanReturn"); + bool ChangesPC = R->getValueAsBit("ChangesPC"); + auto Args = R->getValueAsListOfDefs("Args"); + + OS << "case OP_" << ID << ": {\n"; + + // Emit calls to read arguments. + for (size_t I = 0, N = Args.size(); I < N; ++I) { + OS << "\tauto V" << I; + OS << " = "; + OS << "PC.read<" << Args[I]->getValueAsString("Name") << ">();\n"; + } + + // Emit a call to the template method and pass arguments. + OS << "\tif (!" << N; + PrintTypes(OS, TS); + OS << "(S"; + if (ChangesPC) + OS << ", PC"; + else + OS << ", OpPC"; + if (CanReturn) + OS << ", Result"; + for (size_t I = 0, N = Args.size(); I < N; ++I) + OS << ", V" << I; + OS << "))\n"; + OS << "\t\treturn false;\n"; + + // Bail out if interpreter returned. + if (CanReturn) { + OS << "\tif (!S.Current || S.Current->isRoot())\n"; + OS << "\t\treturn true;\n"; + } + + OS << "\tcontinue;\n"; + OS << "}\n"; + }); + OS << "#endif\n"; +} + +void ClangOpcodesEmitter::EmitDisasm(raw_ostream &OS, StringRef N, Record *R) { + OS << "#ifdef GET_DISASM\n"; + Enumerate(R, N, [R, &OS](ArrayRef<Record *>, const Twine &ID) { + OS << "case OP_" << ID << ":\n"; + OS << "\tPrintName(\"" << ID << "\");\n"; + OS << "\tOS << \"\\t\""; + + for (auto *Arg : R->getValueAsListOfDefs("Args")) + OS << " << PC.read<" << Arg->getValueAsString("Name") << ">() << \" \""; + + OS << "<< \"\\n\";\n"; + OS << "\tcontinue;\n"; + }); + OS << "#endif\n"; +} + +void ClangOpcodesEmitter::EmitEmitter(raw_ostream &OS, StringRef N, Record *R) { + if (R->getValueAsBit("HasCustomLink")) + return; + + OS << "#ifdef GET_LINK_IMPL\n"; + Enumerate(R, N, [R, &OS](ArrayRef<Record *>, const Twine &ID) { + auto Args = R->getValueAsListOfDefs("Args"); + + // Emit the list of arguments. + OS << "bool ByteCodeEmitter::emit" << ID << "("; + for (size_t I = 0, N = Args.size(); I < N; ++I) + OS << Args[I]->getValueAsString("Name") << " A" << I << ","; + OS << "const SourceInfo &L) {\n"; + + // Emit a call to write the opcodes. + OS << "\treturn emitOp<"; + for (size_t I = 0, N = Args.size(); I < N; ++I) { + if (I != 0) + OS << ", "; + OS << Args[I]->getValueAsString("Name"); + } + OS << ">(OP_" << ID; + for (size_t I = 0, N = Args.size(); I < N; ++I) + OS << ", A" << I; + OS << ", L);\n"; + OS << "}\n"; + }); + OS << "#endif\n"; +} + +void ClangOpcodesEmitter::EmitProto(raw_ostream &OS, StringRef N, Record *R) { + OS << "#if defined(GET_EVAL_PROTO) || defined(GET_LINK_PROTO)\n"; + auto Args = R->getValueAsListOfDefs("Args"); + Enumerate(R, N, [&OS, &Args](ArrayRef<Record *> TS, const Twine &ID) { + OS << "bool emit" << ID << "("; + for (auto *Arg : Args) + OS << Arg->getValueAsString("Name") << ", "; + OS << "const SourceInfo &);\n"; + }); + + // Emit a template method for custom emitters to have less to implement. + auto TypeCount = R->getValueAsListInit("Types")->size(); + if (R->getValueAsBit("HasCustomEval") && TypeCount) { + OS << "#if defined(GET_EVAL_PROTO)\n"; + OS << "template<"; + for (size_t I = 0; I < TypeCount; ++I) { + if (I != 0) + OS << ", "; + OS << "PrimType"; + } + OS << ">\n"; + OS << "bool emit" << N << "("; + for (auto *Arg : Args) + OS << Arg->getValueAsString("Name") << ", "; + OS << "const SourceInfo &);\n"; + OS << "#endif\n"; + } + + OS << "#endif\n"; +} + +void ClangOpcodesEmitter::EmitGroup(raw_ostream &OS, StringRef N, Record *R) { + if (!R->getValueAsBit("HasGroup")) + return; + + auto *Types = R->getValueAsListInit("Types"); + auto Args = R->getValueAsListOfDefs("Args"); + + // Emit the prototype of the group emitter in the header. + OS << "#if defined(GET_EVAL_PROTO) || defined(GET_LINK_PROTO)\n"; + OS << "bool emit" << N << "("; + for (size_t I = 0, N = Types->size(); I < N; ++I) + OS << "PrimType, "; + for (auto *Arg : Args) + OS << Arg->getValueAsString("Name") << ", "; + OS << "const SourceInfo &I);\n"; + OS << "#endif\n"; + + // Emit the dispatch implementation in the source. + OS << "#if defined(GET_EVAL_IMPL) || defined(GET_LINK_IMPL)\n"; + OS << "bool \n"; + OS << "#if defined(GET_EVAL_IMPL)\n"; + OS << "EvalEmitter\n"; + OS << "#else\n"; + OS << "ByteCodeEmitter\n"; + OS << "#endif\n"; + OS << "::emit" << N << "("; + for (size_t I = 0, N = Types->size(); I < N; ++I) + OS << "PrimType T" << I << ", "; + for (size_t I = 0, N = Args.size(); I < N; ++I) + OS << Args[I]->getValueAsString("Name") << " A" << I << ", "; + OS << "const SourceInfo &I) {\n"; + + std::function<void(size_t, const Twine &)> Rec; + llvm::SmallVector<Record *, 2> TS; + Rec = [this, &Rec, &OS, Types, &Args, R, &TS, N](size_t I, const Twine &ID) { + if (I >= Types->size()) { + // Print a call to the emitter method. + // Custom evaluator methods dispatch to template methods. + if (R->getValueAsBit("HasCustomEval")) { + OS << "#ifdef GET_LINK_IMPL\n"; + OS << "return emit" << ID << "\n"; + OS << "#else\n"; + OS << "return emit" << N; + PrintTypes(OS, TS); + OS << "\n#endif\n"; + } else { + OS << "return emit" << ID; + } + + OS << "("; + for (size_t I = 0; I < Args.size(); ++I) { + OS << "A" << I << ", "; + } + OS << "I);\n"; + return; + } + + // Print a switch statement selecting T. + if (auto *TypeClass = dyn_cast<DefInit>(Types->getElement(I))) { + OS << "switch (T" << I << "){\n"; + auto Cases = TypeClass->getDef()->getValueAsListOfDefs("Types"); + for (auto *Case : Cases) { + OS << "case PT_" << Case->getName() << ":\n"; + TS.push_back(Case); + Rec(I + 1, ID + Case->getName()); + TS.pop_back(); + } + // Emit a default case if not all types are present. + if (Cases.size() < NumTypes) + OS << "default: llvm_unreachable(\"invalid type\");\n"; + OS << "}\n"; + OS << "llvm_unreachable(\"invalid enum value\");\n"; + } else { + PrintFatalError("Expected a type class"); + } + }; + Rec(0, N); + + OS << "}\n"; + OS << "#endif\n"; +} + +void ClangOpcodesEmitter::EmitEval(raw_ostream &OS, StringRef N, Record *R) { + if (R->getValueAsBit("HasCustomEval")) + return; + + OS << "#ifdef GET_EVAL_IMPL\n"; + Enumerate(R, N, [this, R, &N, &OS](ArrayRef<Record *> TS, const Twine &ID) { + auto Args = R->getValueAsListOfDefs("Args"); + + OS << "bool EvalEmitter::emit" << ID << "("; + for (size_t I = 0, N = Args.size(); I < N; ++I) + OS << Args[I]->getValueAsString("Name") << " A" << I << ","; + OS << "const SourceInfo &L) {\n"; + OS << "if (!isActive()) return true;\n"; + OS << "CurrentSource = L;\n"; + + OS << "return " << N; + PrintTypes(OS, TS); + OS << "(S, OpPC"; + for (size_t I = 0, N = Args.size(); I < N; ++I) + OS << ", A" << I; + OS << ");\n"; + OS << "}\n"; + }); + + OS << "#endif\n"; +} + +void ClangOpcodesEmitter::PrintTypes(raw_ostream &OS, ArrayRef<Record *> Types) { + if (Types.empty()) + return; + OS << "<"; + for (size_t I = 0, N = Types.size(); I < N; ++I) { + if (I != 0) + OS << ", "; + OS << "PT_" << Types[I]->getName(); + } + OS << ">"; +} + +void clang::EmitClangOpcodes(RecordKeeper &Records, raw_ostream &OS) { + ClangOpcodesEmitter(Records).run(OS); +} diff --git a/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp b/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp index 8d83b1c7fa6b9..c8975d7bf615d 100644 --- a/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp +++ b/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp @@ -15,20 +15,49 @@ // // For a successful lookup of e.g. the "cos" builtin, isOpenCLBuiltin("cos") // returns a pair <Index, Len>. -// OpenCLBuiltins[Index] to OpenCLBuiltins[Index + Len] contains the pairs +// BuiltinTable[Index] to BuiltinTable[Index + Len] contains the pairs // <SigIndex, SigLen> of the overloads of "cos". -// OpenCLSignature[SigIndex] to OpenCLSignature[SigIndex + SigLen] contains -// one of the signatures of "cos". The OpenCLSignature entry can be -// referenced by other functions, i.e. "sin", since multiple OpenCL builtins -// share the same signature. +// SignatureTable[SigIndex] to SignatureTable[SigIndex + SigLen] contains +// one of the signatures of "cos". The SignatureTable entry can be +// referenced by other functions, e.g. "sin", to exploit the fact that +// many OpenCL builtins share the same signature. +// +// The file generated by this TableGen emitter contains the following: +// +// * Structs and enums to represent types and function signatures. +// +// * OpenCLTypeStruct TypeTable[] +// Type information for return types and arguments. +// +// * unsigned SignatureTable[] +// A list of types representing function signatures. Each entry is an index +// into the above TypeTable. Multiple entries following each other form a +// signature, where the first entry is the return type and subsequent +// entries are the argument types. +// +// * OpenCLBuiltinStruct BuiltinTable[] +// Each entry represents one overload of an OpenCL builtin function and +// consists of an index into the SignatureTable and the number of arguments. +// +// * std::pair<unsigned, unsigned> isOpenCLBuiltin(llvm::StringRef Name) +// Find out whether a string matches an existing OpenCL builtin function +// name and return an index into BuiltinTable and the number of overloads. +// +// * void OCL2Qual(ASTContext&, OpenCLTypeStruct, std::vector<QualType>&) +// Convert an OpenCLTypeStruct type to a list of QualType instances. +// One OpenCLTypeStruct can represent multiple types, primarily when using +// GenTypes. +// //===----------------------------------------------------------------------===// +#include "TableGenBackends.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include "llvm/TableGen/Error.h" @@ -57,34 +86,49 @@ private: // The output file. raw_ostream &OS; - // Emit the enums and structs. + // Helper function for BuiltinNameEmitter::EmitDeclarations. Generate enum + // definitions in the Output string parameter, and save their Record instances + // in the List parameter. + // \param Types (in) List containing the Types to extract. + // \param TypesSeen (inout) List containing the Types already extracted. + // \param Output (out) String containing the enums to emit in the output file. + // \param List (out) List containing the extracted Types, except the Types in + // TypesSeen. + void ExtractEnumTypes(std::vector<Record *> &Types, + StringMap<bool> &TypesSeen, std::string &Output, + std::vector<const Record *> &List); + + // Emit the enum or struct used in the generated file. + // Populate the TypeList at the same time. void EmitDeclarations(); - // Parse the Records generated by TableGen and populate OverloadInfo and - // SignatureSet. + // Parse the Records generated by TableGen to populate the SignaturesList, + // FctOverloadMap and TypeMap. void GetOverloads(); - // Emit the OpenCLSignature table. This table contains all possible - // signatures, and is a struct OpenCLType. A signature is composed of a - // return type (mandatory), followed by zero or more argument types. + // Emit the TypeTable containing all types used by OpenCL builtins. + void EmitTypeTable(); + + // Emit the SignatureTable. This table contains all the possible signatures. + // A signature is stored as a list of indexes of the TypeTable. + // The first index references the return type (mandatory), and the followings + // reference its arguments. // E.g.: - // // 12 - // { OCLT_uchar, 4, clang::LangAS::Default, false }, - // { OCLT_float, 4, clang::LangAS::Default, false }, - // This means that index 12 represents a signature - // - returning a uchar vector of 4 elements, and - // - taking as first argument a float vector of 4 elements. + // 15, 2, 15 can represent a function with the signature: + // int func(float, int) + // The "int" type being at the index 15 in the TypeTable. void EmitSignatureTable(); - // Emit the OpenCLBuiltins table. This table contains all overloads of + // Emit the BuiltinTable table. This table contains all the overloads of // each function, and is a struct OpenCLBuiltinDecl. // E.g.: - // // acos - // { 2, 0, "", 100 }, - // This means that the signature of this acos overload is defined in OpenCL - // version 1.0 (100) and does not belong to any extension (""). It has a - // 1 argument (+1 for the return type), stored at index 0 in the - // OpenCLSignature table. + // // 891 convert_float2_rtn + // { 58, 2, 100, 0 }, + // This means that the signature of this convert_float2_rtn overload has + // 1 argument (+1 for the return type), stored at index 58 in + // the SignatureTable. The last two values represent the minimum (1.0) and + // maximum (0, meaning no max version) OpenCL version in which this overload + // is supported. void EmitBuiltinTable(); // Emit a StringMatcher function to check whether a function name is an @@ -102,20 +146,30 @@ private: // <<float>, 5>, // ... // <<double, double>, 35>. - std::vector<std::pair<std::vector<Record *>, unsigned>> SignatureSet; + std::vector<std::pair<std::vector<Record *>, unsigned>> SignaturesList; // Map the name of a builtin function to its prototypes (instances of the // TableGen "Builtin" class). // Each prototype is registered as a pair of: // <pointer to the "Builtin" instance, - // cumulative index of the associated signature in the SignatureSet> + // cumulative index of the associated signature in the SignaturesList> // E.g.: The function cos: (float cos(float), double cos(double), ...) // <"cos", <<ptrToPrototype0, 5>, - // <ptrToPrototype1, 35>> - // <ptrToPrototype2, 79>> + // <ptrToPrototype1, 35>, + // <ptrToPrototype2, 79>> // ptrToPrototype1 has the following signature: <double, double> MapVector<StringRef, std::vector<std::pair<const Record *, unsigned>>> - OverloadInfo; + FctOverloadMap; + + // Contains the map of OpenCL types to their index in the TypeTable. + MapVector<const Record *, unsigned> TypeMap; + + // List of OpenCL type names in the same order as in enum OpenCLTypeID. + // This list does not contain generic types. + std::vector<const Record *> TypeList; + + // Same as TypeList, but for generic types only. + std::vector<const Record *> GenTypeList; }; } // namespace @@ -125,12 +179,14 @@ void BuiltinNameEmitter::Emit() { OS << "#include \"llvm/ADT/StringRef.h\"\n"; OS << "using namespace clang;\n\n"; + // Emit enums and structs. EmitDeclarations(); GetOverloads(); + // Emit tables. + EmitTypeTable(); EmitSignatureTable(); - EmitBuiltinTable(); EmitStringMatcher(); @@ -138,100 +194,226 @@ void BuiltinNameEmitter::Emit() { EmitQualTypeFinder(); } +void BuiltinNameEmitter::ExtractEnumTypes(std::vector<Record *> &Types, + StringMap<bool> &TypesSeen, + std::string &Output, + std::vector<const Record *> &List) { + raw_string_ostream SS(Output); + + for (const auto *T : Types) { + if (TypesSeen.find(T->getValueAsString("Name")) == TypesSeen.end()) { + SS << " OCLT_" + T->getValueAsString("Name") << ",\n"; + // Save the type names in the same order as their enum value. Note that + // the Record can be a VectorType or something else, only the name is + // important. + List.push_back(T); + TypesSeen.insert(std::make_pair(T->getValueAsString("Name"), true)); + } + } + SS.flush(); +} + void BuiltinNameEmitter::EmitDeclarations() { + // Enum of scalar type names (float, int, ...) and generic type sets. OS << "enum OpenCLTypeID {\n"; - std::vector<Record *> Types = Records.getAllDerivedDefinitions("Type"); + StringMap<bool> TypesSeen; - for (const auto *T : Types) { - if (TypesSeen.find(T->getValueAsString("Name")) == TypesSeen.end()) - OS << " OCLT_" + T->getValueAsString("Name") << ",\n"; - TypesSeen.insert(std::make_pair(T->getValueAsString("Name"), true)); - } + std::string GenTypeEnums; + std::string TypeEnums; + + // Extract generic types and non-generic types separately, to keep + // gentypes at the end of the enum which simplifies the special handling + // for gentypes in SemaLookup. + std::vector<Record *> GenTypes = + Records.getAllDerivedDefinitions("GenericType"); + ExtractEnumTypes(GenTypes, TypesSeen, GenTypeEnums, GenTypeList); + + std::vector<Record *> Types = Records.getAllDerivedDefinitions("Type"); + ExtractEnumTypes(Types, TypesSeen, TypeEnums, TypeList); + + OS << TypeEnums; + OS << GenTypeEnums; OS << "};\n"; + // Structure definitions. OS << R"( +// Image access qualifier. +enum OpenCLAccessQual : unsigned char { + OCLAQ_None, + OCLAQ_ReadOnly, + OCLAQ_WriteOnly, + OCLAQ_ReadWrite +}; -// Type used in a prototype of an OpenCL builtin function. -struct OpenCLType { - // A type (e.g.: float, int, ...) - OpenCLTypeID ID; - // Size of vector (if applicable) - unsigned VectorWidth; - // Address space of the pointer (if applicable) - LangAS AS; - // Whether the type is a pointer - bool isPointer; +// Represents a return type or argument type. +struct OpenCLTypeStruct { + // A type (e.g. float, int, ...). + const OpenCLTypeID ID; + // Vector size (if applicable; 0 for scalars and generic types). + const unsigned VectorWidth; + // 0 if the type is not a pointer. + const bool IsPointer; + // 0 if the type is not const. + const bool IsConst; + // 0 if the type is not volatile. + const bool IsVolatile; + // Access qualifier. + const OpenCLAccessQual AccessQualifier; + // Address space of the pointer (if applicable). + const LangAS AS; }; // One overload of an OpenCL builtin function. -struct OpenCLBuiltinDecl { - // Number of arguments for the signature - unsigned NumArgs; - // Index in the OpenCLSignature table to get the required types - unsigned ArgTableIndex; - // Extension to which it belongs (e.g. cl_khr_subgroups) - const char *Extension; - // Version in which it was introduced (e.g. CL20) - unsigned Version; +struct OpenCLBuiltinStruct { + // Index of the signature in the OpenCLTypeStruct table. + const unsigned SigTableIndex; + // Entries between index SigTableIndex and (SigTableIndex + NumTypes - 1) in + // the SignatureTable represent the complete signature. The first type at + // index SigTableIndex is the return type. + const unsigned NumTypes; + // First OpenCL version in which this overload was introduced (e.g. CL20). + const unsigned short MinVersion; + // First OpenCL version in which this overload was removed (e.g. CL20). + const unsigned short MaxVersion; }; )"; } +// Verify that the combination of GenTypes in a signature is supported. +// To simplify the logic for creating overloads in SemaLookup, only allow +// a signature to contain different GenTypes if these GenTypes represent +// the same number of actual scalar or vector types. +// +// Exit with a fatal error if an unsupported construct is encountered. +static void VerifySignature(const std::vector<Record *> &Signature, + const Record *BuiltinRec) { + unsigned GenTypeVecSizes = 1; + unsigned GenTypeTypes = 1; + + for (const auto *T : Signature) { + // Check all GenericType arguments in this signature. + if (T->isSubClassOf("GenericType")) { + // Check number of vector sizes. + unsigned NVecSizes = + T->getValueAsDef("VectorList")->getValueAsListOfInts("List").size(); + if (NVecSizes != GenTypeVecSizes && NVecSizes != 1) { + if (GenTypeVecSizes > 1) { + // We already saw a gentype with a different number of vector sizes. + PrintFatalError(BuiltinRec->getLoc(), + "number of vector sizes should be equal or 1 for all gentypes " + "in a declaration"); + } + GenTypeVecSizes = NVecSizes; + } + + // Check number of data types. + unsigned NTypes = + T->getValueAsDef("TypeList")->getValueAsListOfDefs("List").size(); + if (NTypes != GenTypeTypes && NTypes != 1) { + if (GenTypeTypes > 1) { + // We already saw a gentype with a different number of types. + PrintFatalError(BuiltinRec->getLoc(), + "number of types should be equal or 1 for all gentypes " + "in a declaration"); + } + GenTypeTypes = NTypes; + } + } + } +} + void BuiltinNameEmitter::GetOverloads() { + // Populate the TypeMap. + std::vector<Record *> Types = Records.getAllDerivedDefinitions("Type"); + unsigned I = 0; + for (const auto &T : Types) { + TypeMap.insert(std::make_pair(T, I++)); + } + + // Populate the SignaturesList and the FctOverloadMap. unsigned CumulativeSignIndex = 0; std::vector<Record *> Builtins = Records.getAllDerivedDefinitions("Builtin"); for (const auto *B : Builtins) { StringRef BName = B->getValueAsString("Name"); - if (OverloadInfo.find(BName) == OverloadInfo.end()) { - OverloadInfo.insert(std::make_pair( + if (FctOverloadMap.find(BName) == FctOverloadMap.end()) { + FctOverloadMap.insert(std::make_pair( BName, std::vector<std::pair<const Record *, unsigned>>{})); } auto Signature = B->getValueAsListOfDefs("Signature"); + // Reuse signatures to avoid unnecessary duplicates. auto it = - std::find_if(SignatureSet.begin(), SignatureSet.end(), + std::find_if(SignaturesList.begin(), SignaturesList.end(), [&](const std::pair<std::vector<Record *>, unsigned> &a) { return a.first == Signature; }); unsigned SignIndex; - if (it == SignatureSet.end()) { - SignatureSet.push_back(std::make_pair(Signature, CumulativeSignIndex)); + if (it == SignaturesList.end()) { + VerifySignature(Signature, B); + SignaturesList.push_back(std::make_pair(Signature, CumulativeSignIndex)); SignIndex = CumulativeSignIndex; CumulativeSignIndex += Signature.size(); } else { SignIndex = it->second; } - OverloadInfo[BName].push_back(std::make_pair(B, SignIndex)); + FctOverloadMap[BName].push_back(std::make_pair(B, SignIndex)); } } +void BuiltinNameEmitter::EmitTypeTable() { + OS << "static const OpenCLTypeStruct TypeTable[] = {\n"; + for (const auto &T : TypeMap) { + const char *AccessQual = + StringSwitch<const char *>(T.first->getValueAsString("AccessQualifier")) + .Case("RO", "OCLAQ_ReadOnly") + .Case("WO", "OCLAQ_WriteOnly") + .Case("RW", "OCLAQ_ReadWrite") + .Default("OCLAQ_None"); + + OS << " // " << T.second << "\n" + << " {OCLT_" << T.first->getValueAsString("Name") << ", " + << T.first->getValueAsInt("VecWidth") << ", " + << T.first->getValueAsBit("IsPointer") << ", " + << T.first->getValueAsBit("IsConst") << ", " + << T.first->getValueAsBit("IsVolatile") << ", " + << AccessQual << ", " + << T.first->getValueAsString("AddrSpace") << "},\n"; + } + OS << "};\n\n"; +} + void BuiltinNameEmitter::EmitSignatureTable() { - OS << "static const OpenCLType OpenCLSignature[] = {\n"; - for (auto &P : SignatureSet) { - OS << "// " << P.second << "\n"; - for (Record *R : P.first) { - OS << "{ OCLT_" << R->getValueAsString("Name") << ", " - << R->getValueAsInt("VecWidth") << ", " - << R->getValueAsString("AddrSpace") << ", " - << R->getValueAsBit("IsPointer") << "},"; - OS << "\n"; + // Store a type (e.g. int, float, int2, ...). The type is stored as an index + // of a struct OpenCLType table. Multiple entries following each other form a + // signature. + OS << "static const unsigned SignatureTable[] = {\n"; + for (const auto &P : SignaturesList) { + OS << " // " << P.second << "\n "; + for (const Record *R : P.first) { + OS << TypeMap.find(R)->second << ", "; } + OS << "\n"; } OS << "};\n\n"; } void BuiltinNameEmitter::EmitBuiltinTable() { - OS << "static const OpenCLBuiltinDecl OpenCLBuiltins[] = {\n"; - for (auto &i : OverloadInfo) { - StringRef Name = i.first; - OS << "// " << Name << "\n"; - for (auto &Overload : i.second) { - OS << " { " << Overload.first->getValueAsListOfDefs("Signature").size() - << ", " << Overload.second << ", " << '"' - << Overload.first->getValueAsString("Extension") << "\", " - << Overload.first->getValueAsDef("Version")->getValueAsInt("Version") + unsigned Index = 0; + + OS << "static const OpenCLBuiltinStruct BuiltinTable[] = {\n"; + for (const auto &FOM : FctOverloadMap) { + + OS << " // " << (Index + 1) << ": " << FOM.first << "\n"; + + for (const auto &Overload : FOM.second) { + OS << " { " << Overload.second << ", " + << Overload.first->getValueAsListOfDefs("Signature").size() << ", " + << Overload.first->getValueAsDef("MinVersion")->getValueAsInt("ID") + << ", " + << Overload.first->getValueAsDef("MaxVersion")->getValueAsInt("ID") << " },\n"; + Index++; } } OS << "};\n\n"; @@ -240,7 +422,7 @@ void BuiltinNameEmitter::EmitBuiltinTable() { void BuiltinNameEmitter::EmitStringMatcher() { std::vector<StringMatcher::StringPair> ValidBuiltins; unsigned CumulativeIndex = 1; - for (auto &i : OverloadInfo) { + for (auto &i : FctOverloadMap) { auto &Ov = i.second; std::string RetStmt; raw_string_ostream SS(RetStmt); @@ -253,30 +435,137 @@ void BuiltinNameEmitter::EmitStringMatcher() { } OS << R"( -// Return 0 if name is not a recognized OpenCL builtin, or an index -// into a table of declarations if it is an OpenCL builtin. -static std::pair<unsigned, unsigned> isOpenCLBuiltin(llvm::StringRef name) { +// Find out whether a string matches an existing OpenCL builtin function name. +// Returns: A pair <0, 0> if no name matches. +// A pair <Index, Len> indexing the BuiltinTable if the name is +// matching an OpenCL builtin function. +static std::pair<unsigned, unsigned> isOpenCLBuiltin(llvm::StringRef Name) { )"; - StringMatcher("name", ValidBuiltins, OS).Emit(0, true); + StringMatcher("Name", ValidBuiltins, OS).Emit(0, true); OS << " return std::make_pair(0, 0);\n"; - OS << "}\n"; + OS << "} // isOpenCLBuiltin\n"; } void BuiltinNameEmitter::EmitQualTypeFinder() { OS << R"( -static QualType OCL2Qual(ASTContext &Context, OpenCLType Ty) { - QualType RT = Context.VoidTy; - switch (Ty.ID) { +// Convert an OpenCLTypeStruct type to a list of QualTypes. +// Generic types represent multiple types and vector sizes, thus a vector +// is returned. The conversion is done in two steps: +// Step 1: A switch statement fills a vector with scalar base types for the +// Cartesian product of (vector sizes) x (types) for generic types, +// or a single scalar type for non generic types. +// Step 2: Qualifiers and other type properties such as vector size are +// applied. +static void OCL2Qual(ASTContext &Context, const OpenCLTypeStruct &Ty, + llvm::SmallVectorImpl<QualType> &QT) { + // Number of scalar types in the GenType. + unsigned GenTypeNumTypes; + // Pointer to the list of vector sizes for the GenType. + llvm::ArrayRef<unsigned> GenVectorSizes; )"; + // Generate list of vector sizes for each generic type. + for (const auto *VectList : Records.getAllDerivedDefinitions("IntList")) { + OS << " constexpr unsigned List" + << VectList->getValueAsString("Name") << "[] = {"; + for (const auto V : VectList->getValueAsListOfInts("List")) { + OS << V << ", "; + } + OS << "};\n"; + } + + // Step 1. + // Start of switch statement over all types. + OS << "\n switch (Ty.ID) {\n"; + + // Switch cases for image types (Image2d, Image3d, ...) + std::vector<Record *> ImageTypes = + Records.getAllDerivedDefinitions("ImageType"); + + // Map an image type name to its 3 access-qualified types (RO, WO, RW). + std::map<StringRef, SmallVector<Record *, 3>> ImageTypesMap; + for (auto *IT : ImageTypes) { + auto Entry = ImageTypesMap.find(IT->getValueAsString("Name")); + if (Entry == ImageTypesMap.end()) { + SmallVector<Record *, 3> ImageList; + ImageList.push_back(IT); + ImageTypesMap.insert( + std::make_pair(IT->getValueAsString("Name"), ImageList)); + } else { + Entry->second.push_back(IT); + } + } + + // Emit the cases for the image types. For an image type name, there are 3 + // corresponding QualTypes ("RO", "WO", "RW"). The "AccessQualifier" field + // tells which one is needed. Emit a switch statement that puts the + // corresponding QualType into "QT". + for (const auto &ITE : ImageTypesMap) { + OS << " case OCLT_" << ITE.first.str() << ":\n" + << " switch (Ty.AccessQualifier) {\n" + << " case OCLAQ_None:\n" + << " llvm_unreachable(\"Image without access qualifier\");\n"; + for (const auto &Image : ITE.second) { + OS << StringSwitch<const char *>( + Image->getValueAsString("AccessQualifier")) + .Case("RO", " case OCLAQ_ReadOnly:\n") + .Case("WO", " case OCLAQ_WriteOnly:\n") + .Case("RW", " case OCLAQ_ReadWrite:\n") + << " QT.push_back(Context." + << Image->getValueAsDef("QTName")->getValueAsString("Name") << ");\n" + << " break;\n"; + } + OS << " }\n" + << " break;\n"; + } + + // Switch cases for generic types. + for (const auto *GenType : Records.getAllDerivedDefinitions("GenericType")) { + OS << " case OCLT_" << GenType->getValueAsString("Name") << ":\n"; + OS << " QT.append({"; + + // Build the Cartesian product of (vector sizes) x (types). Only insert + // the plain scalar types for now; other type information such as vector + // size and type qualifiers will be added after the switch statement. + for (unsigned I = 0; I < GenType->getValueAsDef("VectorList") + ->getValueAsListOfInts("List") + .size(); + I++) { + for (const auto *T : + GenType->getValueAsDef("TypeList")->getValueAsListOfDefs("List")) { + OS << "Context." + << T->getValueAsDef("QTName")->getValueAsString("Name") << ", "; + } + } + OS << "});\n"; + // GenTypeNumTypes is the number of types in the GenType + // (e.g. float/double/half). + OS << " GenTypeNumTypes = " + << GenType->getValueAsDef("TypeList")->getValueAsListOfDefs("List") + .size() + << ";\n"; + // GenVectorSizes is the list of vector sizes for this GenType. + // QT contains GenTypeNumTypes * #GenVectorSizes elements. + OS << " GenVectorSizes = List" + << GenType->getValueAsDef("VectorList")->getValueAsString("Name") + << ";\n"; + OS << " break;\n"; + } + + // Switch cases for non generic, non image types (int, int4, float, ...). + // Only insert the plain scalar type; vector information and type qualifiers + // are added in step 2. std::vector<Record *> Types = Records.getAllDerivedDefinitions("Type"); StringMap<bool> TypesSeen; for (const auto *T : Types) { + // Check this is not an image type + if (ImageTypesMap.find(T->getValueAsString("Name")) != ImageTypesMap.end()) + continue; // Check we have not seen this Type if (TypesSeen.find(T->getValueAsString("Name")) != TypesSeen.end()) continue; @@ -284,35 +573,74 @@ static QualType OCL2Qual(ASTContext &Context, OpenCLType Ty) { // Check the Type does not have an "abstract" QualType auto QT = T->getValueAsDef("QTName"); - if (QT->getValueAsString("Name") == "null") + if (QT->getValueAsBit("IsAbstract") == 1) continue; + // Emit the cases for non generic, non image types. + OS << " case OCLT_" << T->getValueAsString("Name") << ":\n"; + OS << " QT.push_back(Context." << QT->getValueAsString("Name") + << ");\n"; + OS << " break;\n"; + } - OS << " case OCLT_" << T->getValueAsString("Name") << ":\n"; - OS << " RT = Context." << QT->getValueAsString("Name") << ";\n"; - OS << " break;\n"; + // End of switch statement. + OS << " default:\n" + << " llvm_unreachable(\"OpenCL builtin type not handled yet\");\n" + << " } // end of switch (Ty.ID)\n\n"; + + // Step 2. + // Add ExtVector types if this was a generic type, as the switch statement + // above only populated the list with scalar types. This completes the + // construction of the Cartesian product of (vector sizes) x (types). + OS << " // Construct the different vector types for each generic type.\n"; + OS << " if (Ty.ID >= " << TypeList.size() << ") {"; + OS << R"( + for (unsigned I = 0; I < QT.size(); I++) { + // For scalars, size is 1. + if (GenVectorSizes[I / GenTypeNumTypes] != 1) { + QT[I] = Context.getExtVectorType(QT[I], + GenVectorSizes[I / GenTypeNumTypes]); + } + } } - OS << " }\n"; +)"; - // Special cases + // Assign the right attributes to the types (e.g. vector size). OS << R"( - if (Ty.VectorWidth > 0) - RT = Context.getExtVectorType(RT, Ty.VectorWidth); + // Set vector size for non-generic vector types. + if (Ty.VectorWidth > 1) { + for (unsigned Index = 0; Index < QT.size(); Index++) { + QT[Index] = Context.getExtVectorType(QT[Index], Ty.VectorWidth); + } + } + + if (Ty.IsVolatile != 0) { + for (unsigned Index = 0; Index < QT.size(); Index++) { + QT[Index] = Context.getVolatileType(QT[Index]); + } + } - if (Ty.isPointer) { - RT = Context.getAddrSpaceQualType(RT, Ty.AS); - RT = Context.getPointerType(RT); + if (Ty.IsConst != 0) { + for (unsigned Index = 0; Index < QT.size(); Index++) { + QT[Index] = Context.getConstType(QT[Index]); + } } - return RT; -} + // Transform the type to a pointer as the last step, if necessary. + // Builtin functions only have pointers on [const|volatile], no + // [const|volatile] pointers, so this is ok to do it as a last step. + if (Ty.IsPointer != 0) { + for (unsigned Index = 0; Index < QT.size(); Index++) { + QT[Index] = Context.getAddrSpaceQualType(QT[Index], Ty.AS); + QT[Index] = Context.getPointerType(QT[Index]); + } + } )"; -} -namespace clang { + // End of the "OCL2Qual" function. + OS << "\n} // OCL2Qual\n"; +} -void EmitClangOpenCLBuiltins(RecordKeeper &Records, raw_ostream &OS) { +void clang::EmitClangOpenCLBuiltins(RecordKeeper &Records, raw_ostream &OS) { BuiltinNameEmitter NameChecker(Records, OS); NameChecker.Emit(); } - -} // end namespace clang diff --git a/utils/TableGen/ClangOptionDocEmitter.cpp b/utils/TableGen/ClangOptionDocEmitter.cpp index 7027113c4fa81..b944ad9608f5e 100644 --- a/utils/TableGen/ClangOptionDocEmitter.cpp +++ b/utils/TableGen/ClangOptionDocEmitter.cpp @@ -8,6 +8,7 @@ // //===----------------------------------------------------------------------===// +#include "TableGenBackends.h" #include "llvm/TableGen/Error.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" @@ -21,8 +22,6 @@ using namespace llvm; -namespace clang { -namespace docs { namespace { struct DocumentedOption { Record *Option; @@ -380,11 +379,8 @@ void emitDocumentation(int Depth, const Documentation &Doc, } } // namespace -} // namespace docs - -void EmitClangOptDocs(RecordKeeper &Records, raw_ostream &OS) { - using namespace docs; +void clang::EmitClangOptDocs(RecordKeeper &Records, raw_ostream &OS) { const Record *DocInfo = Records.getDef("GlobalDocumentation"); if (!DocInfo) { PrintFatalError("The GlobalDocumentation top-level definition is missing, " @@ -396,4 +392,3 @@ void EmitClangOptDocs(RecordKeeper &Records, raw_ostream &OS) { emitDocumentation(0, extractDocumentation(Records), DocInfo, OS); } -} // end namespace clang diff --git a/utils/TableGen/ClangSACheckersEmitter.cpp b/utils/TableGen/ClangSACheckersEmitter.cpp index 7dd0895b76d45..feefbeb411387 100644 --- a/utils/TableGen/ClangSACheckersEmitter.cpp +++ b/utils/TableGen/ClangSACheckersEmitter.cpp @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// +#include "TableGenBackends.h" #include "llvm/ADT/StringMap.h" #include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" @@ -174,8 +175,7 @@ static void printOption(llvm::raw_ostream &OS, StringRef FullName, OS << "true"; } -namespace clang { -void EmitClangSACheckers(RecordKeeper &Records, raw_ostream &OS) { +void clang::EmitClangSACheckers(RecordKeeper &Records, raw_ostream &OS) { std::vector<Record*> checkers = Records.getAllDerivedDefinitions("Checker"); std::vector<Record*> packages = Records.getAllDerivedDefinitions("Package"); @@ -315,4 +315,3 @@ void EmitClangSACheckers(RecordKeeper &Records, raw_ostream &OS) { OS << "#endif // GET_CHECKER_OPTIONS\n" "\n"; } -} // end namespace clang diff --git a/utils/TableGen/ClangTypeNodesEmitter.cpp b/utils/TableGen/ClangTypeNodesEmitter.cpp new file mode 100644 index 0000000000000..c9986c8fa496b --- /dev/null +++ b/utils/TableGen/ClangTypeNodesEmitter.cpp @@ -0,0 +1,220 @@ +//=== ClangTypeNodesEmitter.cpp - Generate type node tables -----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This tblgen backend emits the node table (the .def file) for Clang +// type nodes. +// +// This file defines the AST type info database. Each type node is +// enumerated by providing its name (e.g., "Builtin" or "Enum") and +// base class (e.g., "Type" or "TagType"). Depending on where in the +// abstract syntax tree the type will show up, the enumeration uses +// one of five different macros: +// +// TYPE(Class, Base) - A type that can show up anywhere in the AST, +// and might be dependent, canonical, or non-canonical. All clients +// will need to understand these types. +// +// ABSTRACT_TYPE(Class, Base) - An abstract class that shows up in +// the type hierarchy but has no concrete instances. +// +// NON_CANONICAL_TYPE(Class, Base) - A type that can show up +// anywhere in the AST but will never be a part of a canonical +// type. Clients that only need to deal with canonical types +// (ignoring, e.g., typedefs and other type aliases used for +// pretty-printing) can ignore these types. +// +// DEPENDENT_TYPE(Class, Base) - A type that will only show up +// within a C++ template that has not been instantiated, e.g., a +// type that is always dependent. Clients that do not need to deal +// with uninstantiated C++ templates can ignore these types. +// +// NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) - A type that +// is non-canonical unless it is dependent. Defaults to TYPE because +// it is neither reliably dependent nor reliably non-canonical. +// +// There is a sixth macro, independent of the others. Most clients +// will not need to use it. +// +// LEAF_TYPE(Class) - A type that never has inner types. Clients +// which can operate on such types more efficiently may wish to do so. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/StringRef.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Record.h" +#include "llvm/TableGen/TableGenBackend.h" +#include <set> +#include <string> +#include <vector> +#include "TableGenBackends.h" + +using namespace llvm; + +// These are spellings in the generated output. +#define TypeMacroName "TYPE" +#define AbstractTypeMacroName "ABSTRACT_TYPE" +#define DependentTypeMacroName "DEPENDENT_TYPE" +#define NonCanonicalTypeMacroName "NON_CANONICAL_TYPE" +#define NonCanonicalUnlessDependentTypeMacroName "NON_CANONICAL_UNLESS_DEPENDENT_TYPE" +#define TypeMacroArgs "(Class, Base)" +#define LastTypeMacroName "LAST_TYPE" +#define LeafTypeMacroName "LEAF_TYPE" + +// These are spellings in the tblgen file. +// (Type is also used for the spelling of the AST class.) +#define TypeClassName "Type" +#define DerivedTypeClassName "DerivedType" +#define AlwaysDependentClassName "AlwaysDependent" +#define NeverCanonicalClassName "NeverCanonical" +#define NeverCanonicalUnlessDependentClassName "NeverCanonicalUnlessDependent" +#define LeafTypeClassName "LeafType" +#define AbstractFieldName "Abstract" +#define BaseFieldName "Base" + +static StringRef getIdForType(Record *type) { + // The record name is expected to be the full C++ class name, + // including "Type". Check for that and strip it off. + auto fullName = type->getName(); + if (!fullName.endswith("Type")) + PrintFatalError(type->getLoc(), "name of Type node doesn't end in Type"); + return fullName.drop_back(4); +} + +namespace { +class TypeNodeEmitter { + RecordKeeper &Records; + raw_ostream &Out; + const std::vector<Record*> Types; + std::vector<StringRef> MacrosToUndef; + +public: + TypeNodeEmitter(RecordKeeper &records, raw_ostream &out) + : Records(records), Out(out), + Types(Records.getAllDerivedDefinitions("Type")) { + } + + void emit(); + +private: + void emitFallbackDefine(StringRef macroName, StringRef fallbackMacroName, + StringRef args); + + void emitNodeInvocations(); + void emitLastNodeInvocation(); + void emitLeafNodeInvocations(); + + void addMacroToUndef(StringRef macroName); + void emitUndefs(); +}; +} + +void TypeNodeEmitter::emit() { + if (Types.empty()) + PrintFatalError("no Type records in input!"); + + emitSourceFileHeader("An x-macro database of Clang type nodes", Out); + + // Preamble + addMacroToUndef(TypeMacroName); + addMacroToUndef(AbstractTypeMacroName); + emitFallbackDefine(AbstractTypeMacroName, TypeMacroName, TypeMacroArgs); + emitFallbackDefine(NonCanonicalTypeMacroName, TypeMacroName, TypeMacroArgs); + emitFallbackDefine(DependentTypeMacroName, TypeMacroName, TypeMacroArgs); + emitFallbackDefine(NonCanonicalUnlessDependentTypeMacroName, TypeMacroName, + TypeMacroArgs); + + // Invocations. + emitNodeInvocations(); + emitLastNodeInvocation(); + emitLeafNodeInvocations(); + + // Postmatter + emitUndefs(); +} + +void TypeNodeEmitter::emitFallbackDefine(StringRef macroName, + StringRef fallbackMacroName, + StringRef args) { + Out << "#ifndef " << macroName << "\n"; + Out << "# define " << macroName << args + << " " << fallbackMacroName << args << "\n"; + Out << "#endif\n"; + + addMacroToUndef(macroName); +} + +void TypeNodeEmitter::emitNodeInvocations() { + for (auto type : Types) { + // The name with the Type suffix. + StringRef id = getIdForType(type); + + // Figure out which macro to use. + StringRef macroName; + auto setMacroName = [&](StringRef newName) { + if (!macroName.empty()) + PrintFatalError(type->getLoc(), + Twine("conflict when computing macro name for " + "Type node: trying to use both \"") + + macroName + "\" and \"" + newName + "\""); + macroName = newName; + }; + if (type->isSubClassOf(AlwaysDependentClassName)) + setMacroName(DependentTypeMacroName); + if (type->isSubClassOf(NeverCanonicalClassName)) + setMacroName(NonCanonicalTypeMacroName); + if (type->isSubClassOf(NeverCanonicalUnlessDependentClassName)) + setMacroName(NonCanonicalUnlessDependentTypeMacroName); + if (type->getValueAsBit(AbstractFieldName)) + setMacroName(AbstractTypeMacroName); + if (macroName.empty()) + macroName = TypeMacroName; + + // Compute the base class. + StringRef baseName = TypeClassName; + if (type->isSubClassOf(DerivedTypeClassName)) + baseName = type->getValueAsDef(BaseFieldName)->getName(); + + // Generate the invocation line. + Out << macroName << "(" << id << ", " << baseName << ")\n"; + } +} + +void TypeNodeEmitter::emitLastNodeInvocation() { + // We check that this is non-empty earlier. + Out << "#ifdef " LastTypeMacroName "\n" + LastTypeMacroName "(" << getIdForType(Types.back()) << ")\n" + "#undef " LastTypeMacroName "\n" + "#endif\n"; +} + +void TypeNodeEmitter::emitLeafNodeInvocations() { + Out << "#ifdef " LeafTypeMacroName "\n"; + + for (auto type : Types) { + if (!type->isSubClassOf(LeafTypeClassName)) continue; + Out << LeafTypeMacroName "(" << getIdForType(type) << ")\n"; + } + + Out << "#undef " LeafTypeMacroName "\n" + "#endif\n"; +} + +void TypeNodeEmitter::addMacroToUndef(StringRef macroName) { + MacrosToUndef.push_back(macroName); +} + +void TypeNodeEmitter::emitUndefs() { + for (auto ¯oName : MacrosToUndef) { + Out << "#undef " << macroName << "\n"; + } +} + +void clang::EmitClangTypeNodes(RecordKeeper &records, raw_ostream &out) { + TypeNodeEmitter(records, out).emit(); +} diff --git a/utils/TableGen/NeonEmitter.cpp b/utils/TableGen/NeonEmitter.cpp index 5cb688061dcb8..9d668a2815341 100644 --- a/utils/TableGen/NeonEmitter.cpp +++ b/utils/TableGen/NeonEmitter.cpp @@ -23,6 +23,7 @@ // //===----------------------------------------------------------------------===// +#include "TableGenBackends.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/None.h" @@ -332,6 +333,17 @@ class Intrinsic { NeonEmitter &Emitter; std::stringstream OS; + bool isBigEndianSafe() const { + if (BigEndianSafe) + return true; + + for (const auto &T : Types){ + if (T.isVector() && T.getNumElements() > 1) + return false; + } + return true; + } + public: Intrinsic(Record *R, StringRef Name, StringRef Proto, TypeSpec OutTS, TypeSpec InTS, ClassKind CK, ListInit *Body, NeonEmitter &Emitter, @@ -624,7 +636,7 @@ std::string Type::builtin_str() const { default: llvm_unreachable("Unhandled case!"); } - if (isChar() && !Pointer) + if (isChar() && !Pointer && Signed) // Make chars explicitly signed. S = "S" + S; else if (isInteger() && !Pointer && !Signed) @@ -1293,7 +1305,7 @@ void Intrinsic::emitReverseVariable(Variable &Dest, Variable &Src) { } void Intrinsic::emitArgumentReversal() { - if (BigEndianSafe) + if (isBigEndianSafe()) return; // Reverse all vector arguments. @@ -1314,7 +1326,7 @@ void Intrinsic::emitArgumentReversal() { } void Intrinsic::emitReturnReversal() { - if (BigEndianSafe) + if (isBigEndianSafe()) return; if (!getReturnType().isVector() || getReturnType().isVoid() || getReturnType().getNumElements() == 1) @@ -1401,7 +1413,7 @@ void Intrinsic::emitBodyAsBuiltinCall() { if (T.getNumVectors() > 1) { // Check if an explicit cast is needed. std::string Cast; - if (T.isChar() || T.isPoly() || !T.isSigned()) { + if (LocalCK == ClassB) { Type T2 = T; T2.makeOneVector(); T2.makeInteger(8, /*Signed=*/true); @@ -1430,9 +1442,13 @@ void Intrinsic::emitBodyAsBuiltinCall() { } // Check if an explicit cast is needed. - if (CastToType.isVector()) { + if (CastToType.isVector() && + (LocalCK == ClassB || (T.isHalf() && !T.isScalarForMangling()))) { CastToType.makeInteger(8, true); Arg = "(" + CastToType.str() + ")" + Arg; + } else if (CastToType.isVector() && LocalCK == ClassI) { + CastToType.makeSigned(); + Arg = "(" + CastToType.str() + ")" + Arg; } S += Arg + ", "; @@ -1578,7 +1594,10 @@ std::pair<Type, std::string> Intrinsic::DagEmitter::emitDagCall(DagInit *DI) { Intr.Dependencies.insert(&Callee); // Now create the call itself. - std::string S = CallPrefix.str() + Callee.getMangledName(true) + "("; + std::string S = ""; + if (!Callee.isBigEndianSafe()) + S += CallPrefix.str(); + S += Callee.getMangledName(true) + "("; for (unsigned I = 0; I < DI->getNumArgs() - 1; ++I) { if (I != 0) S += ", "; @@ -1732,12 +1751,12 @@ std::pair<Type, std::string> Intrinsic::DagEmitter::emitDagShuffle(DagInit *DI){ SetTheory ST; SetTheory::RecSet Elts; - ST.addOperator("lowhalf", llvm::make_unique<LowHalf>()); - ST.addOperator("highhalf", llvm::make_unique<HighHalf>()); + ST.addOperator("lowhalf", std::make_unique<LowHalf>()); + ST.addOperator("highhalf", std::make_unique<HighHalf>()); ST.addOperator("rev", - llvm::make_unique<Rev>(Arg1.first.getElementSizeInBits())); + std::make_unique<Rev>(Arg1.first.getElementSizeInBits())); ST.addExpander("MaskExpand", - llvm::make_unique<MaskExpander>(Arg1.first.getNumElements())); + std::make_unique<MaskExpander>(Arg1.first.getNumElements())); ST.evaluate(DI->getArg(2), Elts, None); std::string S = "__builtin_shufflevector(" + Arg1.second + ", " + Arg2.second; @@ -1889,6 +1908,11 @@ Intrinsic::DagEmitter::emitDagArg(Init *Arg, std::string ArgName) { } std::string Intrinsic::generate() { + // Avoid duplicated code for big and little endian + if (isBigEndianSafe()) { + generateImpl(false, "", ""); + return OS.str(); + } // Little endian intrinsics are simple and don't require any argument // swapping. OS << "#ifdef __LITTLE_ENDIAN__\n"; @@ -2456,7 +2480,7 @@ void NeonEmitter::run(raw_ostream &OS) { for (auto *I : Defs) I->indexBody(); - llvm::stable_sort(Defs, llvm::less_ptr<Intrinsic>()); + llvm::stable_sort(Defs, llvm::deref<std::less<>>()); // Only emit a def when its requirements have been met. // FIXME: This loop could be made faster, but it's fast enough for now. @@ -2563,7 +2587,7 @@ void NeonEmitter::runFP16(raw_ostream &OS) { for (auto *I : Defs) I->indexBody(); - llvm::stable_sort(Defs, llvm::less_ptr<Intrinsic>()); + llvm::stable_sort(Defs, llvm::deref<std::less<>>()); // Only emit a def when its requirements have been met. // FIXME: This loop could be made faster, but it's fast enough for now. @@ -2610,22 +2634,18 @@ void NeonEmitter::runFP16(raw_ostream &OS) { OS << "#endif /* __ARM_FP16_H */\n"; } -namespace clang { - -void EmitNeon(RecordKeeper &Records, raw_ostream &OS) { +void clang::EmitNeon(RecordKeeper &Records, raw_ostream &OS) { NeonEmitter(Records).run(OS); } -void EmitFP16(RecordKeeper &Records, raw_ostream &OS) { +void clang::EmitFP16(RecordKeeper &Records, raw_ostream &OS) { NeonEmitter(Records).runFP16(OS); } -void EmitNeonSema(RecordKeeper &Records, raw_ostream &OS) { +void clang::EmitNeonSema(RecordKeeper &Records, raw_ostream &OS) { NeonEmitter(Records).runHeader(OS); } -void EmitNeonTest(RecordKeeper &Records, raw_ostream &OS) { +void clang::EmitNeonTest(RecordKeeper &Records, raw_ostream &OS) { llvm_unreachable("Neon test generation no longer implemented!"); } - -} // end namespace clang diff --git a/utils/TableGen/TableGen.cpp b/utils/TableGen/TableGen.cpp index b9ec90fd5bccc..d0f8a7564496b 100644 --- a/utils/TableGen/TableGen.cpp +++ b/utils/TableGen/TableGen.cpp @@ -47,6 +47,8 @@ enum ActionType { GenClangCommentNodes, GenClangDeclNodes, GenClangStmtNodes, + GenClangTypeNodes, + GenClangOpcodes, GenClangSACheckers, GenClangCommentHTMLTags, GenClangCommentHTMLTagsProperties, @@ -129,6 +131,10 @@ cl::opt<ActionType> Action( "Generate Clang AST declaration nodes"), clEnumValN(GenClangStmtNodes, "gen-clang-stmt-nodes", "Generate Clang AST statement nodes"), + clEnumValN(GenClangTypeNodes, "gen-clang-type-nodes", + "Generate Clang AST type nodes"), + clEnumValN(GenClangOpcodes, "gen-clang-opcodes", + "Generate Clang constexpr interpreter opcodes"), clEnumValN(GenClangSACheckers, "gen-clang-sa-checkers", "Generate Clang Static Analyzer checkers"), clEnumValN(GenClangCommentHTMLTags, "gen-clang-comment-html-tags", @@ -251,6 +257,12 @@ bool ClangTableGenMain(raw_ostream &OS, RecordKeeper &Records) { case GenClangStmtNodes: EmitClangASTNodes(Records, OS, "Stmt", ""); break; + case GenClangTypeNodes: + EmitClangTypeNodes(Records, OS); + break; + case GenClangOpcodes: + EmitClangOpcodes(Records, OS); + break; case GenClangSACheckers: EmitClangSACheckers(Records, OS); break; diff --git a/utils/TableGen/TableGenBackends.h b/utils/TableGen/TableGenBackends.h index 02af66c5bf814..cdd492b4e558d 100644 --- a/utils/TableGen/TableGenBackends.h +++ b/utils/TableGen/TableGenBackends.h @@ -27,6 +27,7 @@ namespace clang { void EmitClangDeclContext(llvm::RecordKeeper &RK, llvm::raw_ostream &OS); void EmitClangASTNodes(llvm::RecordKeeper &RK, llvm::raw_ostream &OS, const std::string &N, const std::string &S); +void EmitClangTypeNodes(llvm::RecordKeeper &Records, llvm::raw_ostream &OS); void EmitClangAttrParserStringSwitches(llvm::RecordKeeper &Records, llvm::raw_ostream &OS); @@ -77,6 +78,7 @@ void EmitClangCommentCommandInfo(llvm::RecordKeeper &Records, llvm::raw_ostream &OS); void EmitClangCommentCommandList(llvm::RecordKeeper &Records, llvm::raw_ostream &OS); +void EmitClangOpcodes(llvm::RecordKeeper &Records, llvm::raw_ostream &OS); void EmitNeon(llvm::RecordKeeper &Records, llvm::raw_ostream &OS); void EmitFP16(llvm::RecordKeeper &Records, llvm::raw_ostream &OS); |