127f30029SMichael Kruse //===- DirectiveEmitter.cpp - Directive Language Emitter ------------------===// 227f30029SMichael Kruse // 327f30029SMichael Kruse // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 427f30029SMichael Kruse // See https://llvm.org/LICENSE.txt for license information. 527f30029SMichael Kruse // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 627f30029SMichael Kruse // 727f30029SMichael Kruse //===----------------------------------------------------------------------===// 827f30029SMichael Kruse // 927f30029SMichael Kruse // DirectiveEmitter uses the descriptions of directives and clauses to construct 1027f30029SMichael Kruse // common code declarations to be used in Frontends. 1127f30029SMichael Kruse // 1227f30029SMichael Kruse //===----------------------------------------------------------------------===// 1327f30029SMichael Kruse 1427f30029SMichael Kruse #include "llvm/TableGen/DirectiveEmitter.h" 1527f30029SMichael Kruse #include "llvm/ADT/DenseMap.h" 1627f30029SMichael Kruse #include "llvm/ADT/DenseSet.h" 1727f30029SMichael Kruse #include "llvm/ADT/STLExtras.h" 1827f30029SMichael Kruse #include "llvm/ADT/SmallVector.h" 1927f30029SMichael Kruse #include "llvm/ADT/StringSet.h" 2027f30029SMichael Kruse #include "llvm/ADT/StringSwitch.h" 2127f30029SMichael Kruse #include "llvm/TableGen/Error.h" 2227f30029SMichael Kruse #include "llvm/TableGen/Record.h" 2327f30029SMichael Kruse #include "llvm/TableGen/TableGenBackend.h" 2427f30029SMichael Kruse 2527f30029SMichael Kruse #include <numeric> 2627f30029SMichael Kruse #include <vector> 2727f30029SMichael Kruse 2827f30029SMichael Kruse using namespace llvm; 2927f30029SMichael Kruse 3027f30029SMichael Kruse namespace { 3127f30029SMichael Kruse // Simple RAII helper for defining ifdef-undef-endif scopes. 3227f30029SMichael Kruse class IfDefScope { 3327f30029SMichael Kruse public: 3427f30029SMichael Kruse IfDefScope(StringRef Name, raw_ostream &OS) : Name(Name), OS(OS) { 3527f30029SMichael Kruse OS << "#ifdef " << Name << "\n" 3627f30029SMichael Kruse << "#undef " << Name << "\n"; 3727f30029SMichael Kruse } 3827f30029SMichael Kruse 3927f30029SMichael Kruse ~IfDefScope() { OS << "\n#endif // " << Name << "\n\n"; } 4027f30029SMichael Kruse 4127f30029SMichael Kruse private: 4227f30029SMichael Kruse StringRef Name; 4327f30029SMichael Kruse raw_ostream &OS; 4427f30029SMichael Kruse }; 4527f30029SMichael Kruse } // namespace 4627f30029SMichael Kruse 4727f30029SMichael Kruse // Generate enum class. Entries are emitted in the order in which they appear 4827f30029SMichael Kruse // in the `Records` vector. 4927f30029SMichael Kruse static void generateEnumClass(ArrayRef<const Record *> Records, raw_ostream &OS, 5027f30029SMichael Kruse StringRef Enum, StringRef Prefix, 5127f30029SMichael Kruse const DirectiveLanguage &DirLang, 5227f30029SMichael Kruse bool ExportEnums) { 5327f30029SMichael Kruse OS << "\n"; 5427f30029SMichael Kruse OS << "enum class " << Enum << " {\n"; 5527f30029SMichael Kruse for (const auto &R : Records) { 5627f30029SMichael Kruse BaseRecord Rec(R); 5727f30029SMichael Kruse OS << " " << Prefix << Rec.getFormattedName() << ",\n"; 5827f30029SMichael Kruse } 5927f30029SMichael Kruse OS << "};\n"; 6027f30029SMichael Kruse OS << "\n"; 6127f30029SMichael Kruse OS << "static constexpr std::size_t " << Enum 6227f30029SMichael Kruse << "_enumSize = " << Records.size() << ";\n"; 6327f30029SMichael Kruse 6427f30029SMichael Kruse // Make the enum values available in the defined namespace. This allows us to 6527f30029SMichael Kruse // write something like Enum_X if we have a `using namespace <CppNamespace>`. 6627f30029SMichael Kruse // At the same time we do not loose the strong type guarantees of the enum 6727f30029SMichael Kruse // class, that is we cannot pass an unsigned as Directive without an explicit 6827f30029SMichael Kruse // cast. 6927f30029SMichael Kruse if (ExportEnums) { 7027f30029SMichael Kruse OS << "\n"; 7127f30029SMichael Kruse for (const auto &R : Records) { 7227f30029SMichael Kruse BaseRecord Rec(R); 7327f30029SMichael Kruse OS << "constexpr auto " << Prefix << Rec.getFormattedName() << " = " 7427f30029SMichael Kruse << "llvm::" << DirLang.getCppNamespace() << "::" << Enum 7527f30029SMichael Kruse << "::" << Prefix << Rec.getFormattedName() << ";\n"; 7627f30029SMichael Kruse } 7727f30029SMichael Kruse } 7827f30029SMichael Kruse } 7927f30029SMichael Kruse 8027f30029SMichael Kruse // Generate enums for values that clauses can take. 8127f30029SMichael Kruse // Also generate function declarations for get<Enum>Name(StringRef Str). 8227f30029SMichael Kruse static void generateEnumClauseVal(ArrayRef<const Record *> Records, 8327f30029SMichael Kruse raw_ostream &OS, 8427f30029SMichael Kruse const DirectiveLanguage &DirLang, 8527f30029SMichael Kruse std::string &EnumHelperFuncs) { 8627f30029SMichael Kruse for (const auto &R : Records) { 8727f30029SMichael Kruse Clause C(R); 8827f30029SMichael Kruse const auto &ClauseVals = C.getClauseVals(); 8927f30029SMichael Kruse if (ClauseVals.size() <= 0) 9027f30029SMichael Kruse continue; 9127f30029SMichael Kruse 9227f30029SMichael Kruse const auto &EnumName = C.getEnumName(); 9327f30029SMichael Kruse if (EnumName.empty()) { 9427f30029SMichael Kruse PrintError("enumClauseValue field not set in Clause" + 9527f30029SMichael Kruse C.getFormattedName() + "."); 9627f30029SMichael Kruse return; 9727f30029SMichael Kruse } 9827f30029SMichael Kruse 9927f30029SMichael Kruse OS << "\n"; 10027f30029SMichael Kruse OS << "enum class " << EnumName << " {\n"; 10127f30029SMichael Kruse for (const ClauseVal CVal : ClauseVals) 10227f30029SMichael Kruse OS << " " << CVal.getRecordName() << "=" << CVal.getValue() << ",\n"; 10327f30029SMichael Kruse OS << "};\n"; 10427f30029SMichael Kruse 10527f30029SMichael Kruse if (DirLang.hasMakeEnumAvailableInNamespace()) { 10627f30029SMichael Kruse OS << "\n"; 10727f30029SMichael Kruse for (const auto &CV : ClauseVals) { 10827f30029SMichael Kruse OS << "constexpr auto " << CV->getName() << " = " 10927f30029SMichael Kruse << "llvm::" << DirLang.getCppNamespace() << "::" << EnumName 11027f30029SMichael Kruse << "::" << CV->getName() << ";\n"; 11127f30029SMichael Kruse } 11227f30029SMichael Kruse EnumHelperFuncs += (Twine("LLVM_ABI ") + Twine(EnumName) + Twine(" get") + 11327f30029SMichael Kruse Twine(EnumName) + Twine("(StringRef);\n")) 11427f30029SMichael Kruse .str(); 11527f30029SMichael Kruse 11627f30029SMichael Kruse EnumHelperFuncs += 11727f30029SMichael Kruse (Twine("LLVM_ABI llvm::StringRef get") + Twine(DirLang.getName()) + 11827f30029SMichael Kruse Twine(EnumName) + Twine("Name(") + Twine(EnumName) + Twine(");\n")) 11927f30029SMichael Kruse .str(); 12027f30029SMichael Kruse } 12127f30029SMichael Kruse } 12227f30029SMichael Kruse } 12327f30029SMichael Kruse 12427f30029SMichael Kruse static bool hasDuplicateClauses(ArrayRef<const Record *> Clauses, 12527f30029SMichael Kruse const Directive &Directive, 12627f30029SMichael Kruse StringSet<> &CrtClauses) { 12727f30029SMichael Kruse bool HasError = false; 12827f30029SMichael Kruse for (const VersionedClause VerClause : Clauses) { 12927f30029SMichael Kruse const auto InsRes = CrtClauses.insert(VerClause.getClause().getName()); 13027f30029SMichael Kruse if (!InsRes.second) { 13127f30029SMichael Kruse PrintError("Clause " + VerClause.getClause().getRecordName() + 13227f30029SMichael Kruse " already defined on directive " + Directive.getRecordName()); 13327f30029SMichael Kruse HasError = true; 13427f30029SMichael Kruse } 13527f30029SMichael Kruse } 13627f30029SMichael Kruse return HasError; 13727f30029SMichael Kruse } 13827f30029SMichael Kruse 13927f30029SMichael Kruse // Check for duplicate clauses in lists. Clauses cannot appear twice in the 14027f30029SMichael Kruse // three allowed list. Also, since required implies allowed, clauses cannot 14127f30029SMichael Kruse // appear in both the allowedClauses and requiredClauses lists. 14227f30029SMichael Kruse static bool 14327f30029SMichael Kruse hasDuplicateClausesInDirectives(ArrayRef<const Record *> Directives) { 14427f30029SMichael Kruse bool HasDuplicate = false; 14527f30029SMichael Kruse for (const Directive Dir : Directives) { 14627f30029SMichael Kruse StringSet<> Clauses; 14727f30029SMichael Kruse // Check for duplicates in the three allowed lists. 14827f30029SMichael Kruse if (hasDuplicateClauses(Dir.getAllowedClauses(), Dir, Clauses) || 14927f30029SMichael Kruse hasDuplicateClauses(Dir.getAllowedOnceClauses(), Dir, Clauses) || 15027f30029SMichael Kruse hasDuplicateClauses(Dir.getAllowedExclusiveClauses(), Dir, Clauses)) { 15127f30029SMichael Kruse HasDuplicate = true; 15227f30029SMichael Kruse } 15327f30029SMichael Kruse // Check for duplicate between allowedClauses and required 15427f30029SMichael Kruse Clauses.clear(); 15527f30029SMichael Kruse if (hasDuplicateClauses(Dir.getAllowedClauses(), Dir, Clauses) || 15627f30029SMichael Kruse hasDuplicateClauses(Dir.getRequiredClauses(), Dir, Clauses)) { 15727f30029SMichael Kruse HasDuplicate = true; 15827f30029SMichael Kruse } 15927f30029SMichael Kruse if (HasDuplicate) 16027f30029SMichael Kruse PrintFatalError("One or more clauses are defined multiple times on" 16127f30029SMichael Kruse " directive " + 16227f30029SMichael Kruse Dir.getRecordName()); 16327f30029SMichael Kruse } 16427f30029SMichael Kruse 16527f30029SMichael Kruse return HasDuplicate; 16627f30029SMichael Kruse } 16727f30029SMichael Kruse 16827f30029SMichael Kruse // Check consitency of records. Return true if an error has been detected. 16927f30029SMichael Kruse // Return false if the records are valid. 17027f30029SMichael Kruse bool DirectiveLanguage::HasValidityErrors() const { 17127f30029SMichael Kruse if (getDirectiveLanguages().size() != 1) { 17227f30029SMichael Kruse PrintFatalError("A single definition of DirectiveLanguage is needed."); 17327f30029SMichael Kruse return true; 17427f30029SMichael Kruse } 17527f30029SMichael Kruse 17627f30029SMichael Kruse return hasDuplicateClausesInDirectives(getDirectives()); 17727f30029SMichael Kruse } 17827f30029SMichael Kruse 17927f30029SMichael Kruse // Count the maximum number of leaf constituents per construct. 18027f30029SMichael Kruse static size_t getMaxLeafCount(const DirectiveLanguage &DirLang) { 18127f30029SMichael Kruse size_t MaxCount = 0; 18227f30029SMichael Kruse for (const Directive D : DirLang.getDirectives()) 18327f30029SMichael Kruse MaxCount = std::max(MaxCount, D.getLeafConstructs().size()); 18427f30029SMichael Kruse return MaxCount; 18527f30029SMichael Kruse } 18627f30029SMichael Kruse 18727f30029SMichael Kruse // Generate the declaration section for the enumeration in the directive 18827f30029SMichael Kruse // language. 18927f30029SMichael Kruse static void emitDirectivesDecl(const RecordKeeper &Records, raw_ostream &OS) { 19027f30029SMichael Kruse const auto DirLang = DirectiveLanguage(Records); 19127f30029SMichael Kruse if (DirLang.HasValidityErrors()) 19227f30029SMichael Kruse return; 19327f30029SMichael Kruse 19427f30029SMichael Kruse OS << "#ifndef LLVM_" << DirLang.getName() << "_INC\n"; 19527f30029SMichael Kruse OS << "#define LLVM_" << DirLang.getName() << "_INC\n"; 19627f30029SMichael Kruse OS << "\n#include \"llvm/ADT/ArrayRef.h\"\n"; 19727f30029SMichael Kruse 19827f30029SMichael Kruse if (DirLang.hasEnableBitmaskEnumInNamespace()) 19927f30029SMichael Kruse OS << "#include \"llvm/ADT/BitmaskEnum.h\"\n"; 20027f30029SMichael Kruse 20127f30029SMichael Kruse OS << "#include \"llvm/Support/Compiler.h\"\n"; 20227f30029SMichael Kruse OS << "#include <cstddef>\n"; // for size_t 20327f30029SMichael Kruse OS << "\n"; 20427f30029SMichael Kruse OS << "namespace llvm {\n"; 20527f30029SMichael Kruse OS << "class StringRef;\n"; 20627f30029SMichael Kruse 20727f30029SMichael Kruse // Open namespaces defined in the directive language 20827f30029SMichael Kruse SmallVector<StringRef, 2> Namespaces; 20927f30029SMichael Kruse SplitString(DirLang.getCppNamespace(), Namespaces, "::"); 21027f30029SMichael Kruse for (auto Ns : Namespaces) 21127f30029SMichael Kruse OS << "namespace " << Ns << " {\n"; 21227f30029SMichael Kruse 21327f30029SMichael Kruse if (DirLang.hasEnableBitmaskEnumInNamespace()) 21427f30029SMichael Kruse OS << "\nLLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();\n"; 21527f30029SMichael Kruse 21627f30029SMichael Kruse // Emit Directive associations 21727f30029SMichael Kruse std::vector<const Record *> Associations; 21827f30029SMichael Kruse copy_if(DirLang.getAssociations(), std::back_inserter(Associations), 21927f30029SMichael Kruse // Skip the "special" value 22027f30029SMichael Kruse [](const Record *Def) { return Def->getName() != "AS_FromLeaves"; }); 22127f30029SMichael Kruse generateEnumClass(Associations, OS, "Association", 22227f30029SMichael Kruse /*Prefix=*/"", DirLang, /*ExportEnums=*/false); 22327f30029SMichael Kruse 22427f30029SMichael Kruse generateEnumClass(DirLang.getCategories(), OS, "Category", /*Prefix=*/"", 22527f30029SMichael Kruse DirLang, /*ExportEnums=*/false); 22627f30029SMichael Kruse 22727f30029SMichael Kruse // Emit Directive enumeration 22827f30029SMichael Kruse generateEnumClass(DirLang.getDirectives(), OS, "Directive", 22927f30029SMichael Kruse DirLang.getDirectivePrefix(), DirLang, 23027f30029SMichael Kruse DirLang.hasMakeEnumAvailableInNamespace()); 23127f30029SMichael Kruse 23227f30029SMichael Kruse // Emit Clause enumeration 23327f30029SMichael Kruse generateEnumClass(DirLang.getClauses(), OS, "Clause", 23427f30029SMichael Kruse DirLang.getClausePrefix(), DirLang, 23527f30029SMichael Kruse DirLang.hasMakeEnumAvailableInNamespace()); 23627f30029SMichael Kruse 23727f30029SMichael Kruse // Emit ClauseVal enumeration 23827f30029SMichael Kruse std::string EnumHelperFuncs; 23927f30029SMichael Kruse generateEnumClauseVal(DirLang.getClauses(), OS, DirLang, EnumHelperFuncs); 24027f30029SMichael Kruse 24127f30029SMichael Kruse // Generic function signatures 24227f30029SMichael Kruse OS << "\n"; 24327f30029SMichael Kruse OS << "// Enumeration helper functions\n"; 24427f30029SMichael Kruse OS << "LLVM_ABI Directive get" << DirLang.getName() 24527f30029SMichael Kruse << "DirectiveKind(llvm::StringRef Str);\n"; 24627f30029SMichael Kruse OS << "\n"; 24727f30029SMichael Kruse OS << "LLVM_ABI llvm::StringRef get" << DirLang.getName() 24827f30029SMichael Kruse << "DirectiveName(Directive D);\n"; 24927f30029SMichael Kruse OS << "\n"; 25027f30029SMichael Kruse OS << "LLVM_ABI Clause get" << DirLang.getName() 25127f30029SMichael Kruse << "ClauseKind(llvm::StringRef Str);\n"; 25227f30029SMichael Kruse OS << "\n"; 25327f30029SMichael Kruse OS << "LLVM_ABI llvm::StringRef get" << DirLang.getName() 25427f30029SMichael Kruse << "ClauseName(Clause C);\n"; 25527f30029SMichael Kruse OS << "\n"; 25627f30029SMichael Kruse OS << "/// Return true if \\p C is a valid clause for \\p D in version \\p " 25727f30029SMichael Kruse << "Version.\n"; 25827f30029SMichael Kruse OS << "LLVM_ABI bool isAllowedClauseForDirective(Directive D, " 25927f30029SMichael Kruse << "Clause C, unsigned Version);\n"; 26027f30029SMichael Kruse OS << "\n"; 26127f30029SMichael Kruse OS << "constexpr std::size_t getMaxLeafCount() { return " 26227f30029SMichael Kruse << getMaxLeafCount(DirLang) << "; }\n"; 26327f30029SMichael Kruse OS << "LLVM_ABI Association getDirectiveAssociation(Directive D);\n"; 26427f30029SMichael Kruse OS << "LLVM_ABI Category getDirectiveCategory(Directive D);\n"; 26527f30029SMichael Kruse if (EnumHelperFuncs.length() > 0) { 26627f30029SMichael Kruse OS << EnumHelperFuncs; 26727f30029SMichael Kruse OS << "\n"; 26827f30029SMichael Kruse } 26927f30029SMichael Kruse 27027f30029SMichael Kruse // Closing namespaces 27127f30029SMichael Kruse for (auto Ns : reverse(Namespaces)) 27227f30029SMichael Kruse OS << "} // namespace " << Ns << "\n"; 27327f30029SMichael Kruse 27427f30029SMichael Kruse OS << "} // namespace llvm\n"; 27527f30029SMichael Kruse 27627f30029SMichael Kruse OS << "#endif // LLVM_" << DirLang.getName() << "_INC\n"; 27727f30029SMichael Kruse } 27827f30029SMichael Kruse 27927f30029SMichael Kruse // Generate function implementation for get<Enum>Name(StringRef Str) 28027f30029SMichael Kruse static void generateGetName(ArrayRef<const Record *> Records, raw_ostream &OS, 28127f30029SMichael Kruse StringRef Enum, const DirectiveLanguage &DirLang, 28227f30029SMichael Kruse StringRef Prefix) { 28327f30029SMichael Kruse OS << "\n"; 28427f30029SMichael Kruse OS << "llvm::StringRef llvm::" << DirLang.getCppNamespace() << "::get" 28527f30029SMichael Kruse << DirLang.getName() << Enum << "Name(" << Enum << " Kind) {\n"; 28627f30029SMichael Kruse OS << " switch (Kind) {\n"; 28727f30029SMichael Kruse for (const BaseRecord Rec : Records) { 28827f30029SMichael Kruse OS << " case " << Prefix << Rec.getFormattedName() << ":\n"; 28927f30029SMichael Kruse OS << " return \""; 29027f30029SMichael Kruse if (Rec.getAlternativeName().empty()) 29127f30029SMichael Kruse OS << Rec.getName(); 29227f30029SMichael Kruse else 29327f30029SMichael Kruse OS << Rec.getAlternativeName(); 29427f30029SMichael Kruse OS << "\";\n"; 29527f30029SMichael Kruse } 29627f30029SMichael Kruse OS << " }\n"; // switch 29727f30029SMichael Kruse OS << " llvm_unreachable(\"Invalid " << DirLang.getName() << " " << Enum 29827f30029SMichael Kruse << " kind\");\n"; 29927f30029SMichael Kruse OS << "}\n"; 30027f30029SMichael Kruse } 30127f30029SMichael Kruse 30227f30029SMichael Kruse // Generate function implementation for get<Enum>Kind(StringRef Str) 30327f30029SMichael Kruse static void generateGetKind(ArrayRef<const Record *> Records, raw_ostream &OS, 30427f30029SMichael Kruse StringRef Enum, const DirectiveLanguage &DirLang, 30527f30029SMichael Kruse StringRef Prefix, bool ImplicitAsUnknown) { 30627f30029SMichael Kruse 30727f30029SMichael Kruse const auto *DefaultIt = find_if( 30827f30029SMichael Kruse Records, [](const Record *R) { return R->getValueAsBit("isDefault"); }); 30927f30029SMichael Kruse 31027f30029SMichael Kruse if (DefaultIt == Records.end()) { 31127f30029SMichael Kruse PrintError("At least one " + Enum + " must be defined as default."); 31227f30029SMichael Kruse return; 31327f30029SMichael Kruse } 31427f30029SMichael Kruse 31527f30029SMichael Kruse BaseRecord DefaultRec(*DefaultIt); 31627f30029SMichael Kruse 31727f30029SMichael Kruse OS << "\n"; 31827f30029SMichael Kruse OS << Enum << " llvm::" << DirLang.getCppNamespace() << "::get" 31927f30029SMichael Kruse << DirLang.getName() << Enum << "Kind(llvm::StringRef Str) {\n"; 32027f30029SMichael Kruse OS << " return llvm::StringSwitch<" << Enum << ">(Str)\n"; 32127f30029SMichael Kruse 32227f30029SMichael Kruse for (const auto &R : Records) { 32327f30029SMichael Kruse BaseRecord Rec(R); 32427f30029SMichael Kruse if (ImplicitAsUnknown && R->getValueAsBit("isImplicit")) { 32527f30029SMichael Kruse OS << " .Case(\"" << Rec.getName() << "\"," << Prefix 32627f30029SMichael Kruse << DefaultRec.getFormattedName() << ")\n"; 32727f30029SMichael Kruse } else { 32827f30029SMichael Kruse OS << " .Case(\"" << Rec.getName() << "\"," << Prefix 32927f30029SMichael Kruse << Rec.getFormattedName() << ")\n"; 33027f30029SMichael Kruse } 33127f30029SMichael Kruse } 33227f30029SMichael Kruse OS << " .Default(" << Prefix << DefaultRec.getFormattedName() << ");\n"; 33327f30029SMichael Kruse OS << "}\n"; 33427f30029SMichael Kruse } 33527f30029SMichael Kruse 33627f30029SMichael Kruse // Generate function implementation for get<ClauseVal>Kind(StringRef Str) 33727f30029SMichael Kruse static void generateGetKindClauseVal(const DirectiveLanguage &DirLang, 33827f30029SMichael Kruse raw_ostream &OS) { 33927f30029SMichael Kruse for (const Clause C : DirLang.getClauses()) { 34027f30029SMichael Kruse const auto &ClauseVals = C.getClauseVals(); 34127f30029SMichael Kruse if (ClauseVals.size() <= 0) 34227f30029SMichael Kruse continue; 34327f30029SMichael Kruse 34427f30029SMichael Kruse auto DefaultIt = find_if(ClauseVals, [](const Record *CV) { 34527f30029SMichael Kruse return CV->getValueAsBit("isDefault"); 34627f30029SMichael Kruse }); 34727f30029SMichael Kruse 34827f30029SMichael Kruse if (DefaultIt == ClauseVals.end()) { 34927f30029SMichael Kruse PrintError("At least one val in Clause " + C.getFormattedName() + 35027f30029SMichael Kruse " must be defined as default."); 35127f30029SMichael Kruse return; 35227f30029SMichael Kruse } 35327f30029SMichael Kruse const auto DefaultName = (*DefaultIt)->getName(); 35427f30029SMichael Kruse 35527f30029SMichael Kruse const auto &EnumName = C.getEnumName(); 35627f30029SMichael Kruse if (EnumName.empty()) { 35727f30029SMichael Kruse PrintError("enumClauseValue field not set in Clause" + 35827f30029SMichael Kruse C.getFormattedName() + "."); 35927f30029SMichael Kruse return; 36027f30029SMichael Kruse } 36127f30029SMichael Kruse 36227f30029SMichael Kruse OS << "\n"; 36327f30029SMichael Kruse OS << EnumName << " llvm::" << DirLang.getCppNamespace() << "::get" 36427f30029SMichael Kruse << EnumName << "(llvm::StringRef Str) {\n"; 36527f30029SMichael Kruse OS << " return llvm::StringSwitch<" << EnumName << ">(Str)\n"; 36627f30029SMichael Kruse for (const auto &CV : ClauseVals) { 36727f30029SMichael Kruse ClauseVal CVal(CV); 36827f30029SMichael Kruse OS << " .Case(\"" << CVal.getFormattedName() << "\"," << CV->getName() 36927f30029SMichael Kruse << ")\n"; 37027f30029SMichael Kruse } 37127f30029SMichael Kruse OS << " .Default(" << DefaultName << ");\n"; 37227f30029SMichael Kruse OS << "}\n"; 37327f30029SMichael Kruse 37427f30029SMichael Kruse OS << "\n"; 37527f30029SMichael Kruse OS << "llvm::StringRef llvm::" << DirLang.getCppNamespace() << "::get" 37627f30029SMichael Kruse << DirLang.getName() << EnumName 37727f30029SMichael Kruse << "Name(llvm::" << DirLang.getCppNamespace() << "::" << EnumName 37827f30029SMichael Kruse << " x) {\n"; 37927f30029SMichael Kruse OS << " switch (x) {\n"; 38027f30029SMichael Kruse for (const auto &CV : ClauseVals) { 38127f30029SMichael Kruse ClauseVal CVal(CV); 38227f30029SMichael Kruse OS << " case " << CV->getName() << ":\n"; 38327f30029SMichael Kruse OS << " return \"" << CVal.getFormattedName() << "\";\n"; 38427f30029SMichael Kruse } 38527f30029SMichael Kruse OS << " }\n"; // switch 38627f30029SMichael Kruse OS << " llvm_unreachable(\"Invalid " << DirLang.getName() << " " 38727f30029SMichael Kruse << EnumName << " kind\");\n"; 38827f30029SMichael Kruse OS << "}\n"; 38927f30029SMichael Kruse } 39027f30029SMichael Kruse } 39127f30029SMichael Kruse 39227f30029SMichael Kruse static void generateCaseForVersionedClauses(ArrayRef<const Record *> Clauses, 39327f30029SMichael Kruse raw_ostream &OS, 39427f30029SMichael Kruse StringRef DirectiveName, 39527f30029SMichael Kruse const DirectiveLanguage &DirLang, 39627f30029SMichael Kruse StringSet<> &Cases) { 39727f30029SMichael Kruse for (const VersionedClause VerClause : Clauses) { 39827f30029SMichael Kruse const auto ClauseFormattedName = VerClause.getClause().getFormattedName(); 39927f30029SMichael Kruse 40027f30029SMichael Kruse if (Cases.insert(ClauseFormattedName).second) { 40127f30029SMichael Kruse OS << " case " << DirLang.getClausePrefix() << ClauseFormattedName 40227f30029SMichael Kruse << ":\n"; 40327f30029SMichael Kruse OS << " return " << VerClause.getMinVersion() 40427f30029SMichael Kruse << " <= Version && " << VerClause.getMaxVersion() << " >= Version;\n"; 40527f30029SMichael Kruse } 40627f30029SMichael Kruse } 40727f30029SMichael Kruse } 40827f30029SMichael Kruse 40927f30029SMichael Kruse static std::string getDirectiveName(const DirectiveLanguage &DirLang, 41027f30029SMichael Kruse const Record *Rec) { 41127f30029SMichael Kruse Directive Dir(Rec); 41227f30029SMichael Kruse return (Twine("llvm::") + DirLang.getCppNamespace() + 41327f30029SMichael Kruse "::" + DirLang.getDirectivePrefix() + Dir.getFormattedName()) 41427f30029SMichael Kruse .str(); 41527f30029SMichael Kruse } 41627f30029SMichael Kruse 41727f30029SMichael Kruse static std::string getDirectiveType(const DirectiveLanguage &DirLang) { 41827f30029SMichael Kruse return (Twine("llvm::") + DirLang.getCppNamespace() + "::Directive").str(); 41927f30029SMichael Kruse } 42027f30029SMichael Kruse 42127f30029SMichael Kruse // Generate the isAllowedClauseForDirective function implementation. 42227f30029SMichael Kruse static void generateIsAllowedClause(const DirectiveLanguage &DirLang, 42327f30029SMichael Kruse raw_ostream &OS) { 42427f30029SMichael Kruse OS << "\n"; 42527f30029SMichael Kruse OS << "bool llvm::" << DirLang.getCppNamespace() 42627f30029SMichael Kruse << "::isAllowedClauseForDirective(" 42727f30029SMichael Kruse << "Directive D, Clause C, unsigned Version) {\n"; 42827f30029SMichael Kruse OS << " assert(unsigned(D) <= llvm::" << DirLang.getCppNamespace() 42927f30029SMichael Kruse << "::Directive_enumSize);\n"; 43027f30029SMichael Kruse OS << " assert(unsigned(C) <= llvm::" << DirLang.getCppNamespace() 43127f30029SMichael Kruse << "::Clause_enumSize);\n"; 43227f30029SMichael Kruse 43327f30029SMichael Kruse OS << " switch (D) {\n"; 43427f30029SMichael Kruse 43527f30029SMichael Kruse for (const Directive Dir : DirLang.getDirectives()) { 43627f30029SMichael Kruse OS << " case " << DirLang.getDirectivePrefix() << Dir.getFormattedName() 43727f30029SMichael Kruse << ":\n"; 43827f30029SMichael Kruse if (Dir.getAllowedClauses().empty() && 43927f30029SMichael Kruse Dir.getAllowedOnceClauses().empty() && 44027f30029SMichael Kruse Dir.getAllowedExclusiveClauses().empty() && 44127f30029SMichael Kruse Dir.getRequiredClauses().empty()) { 44227f30029SMichael Kruse OS << " return false;\n"; 44327f30029SMichael Kruse } else { 44427f30029SMichael Kruse OS << " switch (C) {\n"; 44527f30029SMichael Kruse 44627f30029SMichael Kruse StringSet<> Cases; 44727f30029SMichael Kruse 44827f30029SMichael Kruse generateCaseForVersionedClauses(Dir.getAllowedClauses(), OS, 44927f30029SMichael Kruse Dir.getName(), DirLang, Cases); 45027f30029SMichael Kruse 45127f30029SMichael Kruse generateCaseForVersionedClauses(Dir.getAllowedOnceClauses(), OS, 45227f30029SMichael Kruse Dir.getName(), DirLang, Cases); 45327f30029SMichael Kruse 45427f30029SMichael Kruse generateCaseForVersionedClauses(Dir.getAllowedExclusiveClauses(), OS, 45527f30029SMichael Kruse Dir.getName(), DirLang, Cases); 45627f30029SMichael Kruse 45727f30029SMichael Kruse generateCaseForVersionedClauses(Dir.getRequiredClauses(), OS, 45827f30029SMichael Kruse Dir.getName(), DirLang, Cases); 45927f30029SMichael Kruse 46027f30029SMichael Kruse OS << " default:\n"; 46127f30029SMichael Kruse OS << " return false;\n"; 46227f30029SMichael Kruse OS << " }\n"; // End of clauses switch 46327f30029SMichael Kruse } 46427f30029SMichael Kruse OS << " break;\n"; 46527f30029SMichael Kruse } 46627f30029SMichael Kruse 46727f30029SMichael Kruse OS << " }\n"; // End of directives switch 46827f30029SMichael Kruse OS << " llvm_unreachable(\"Invalid " << DirLang.getName() 46927f30029SMichael Kruse << " Directive kind\");\n"; 47027f30029SMichael Kruse OS << "}\n"; // End of function isAllowedClauseForDirective 47127f30029SMichael Kruse } 47227f30029SMichael Kruse 47327f30029SMichael Kruse static void emitLeafTable(const DirectiveLanguage &DirLang, raw_ostream &OS, 47427f30029SMichael Kruse StringRef TableName) { 47527f30029SMichael Kruse // The leaf constructs are emitted in a form of a 2D table, where each 47627f30029SMichael Kruse // row corresponds to a directive (and there is a row for each directive). 47727f30029SMichael Kruse // 47827f30029SMichael Kruse // Each row consists of 47927f30029SMichael Kruse // - the id of the directive itself, 48027f30029SMichael Kruse // - number of leaf constructs that will follow (0 for leafs), 48127f30029SMichael Kruse // - ids of the leaf constructs (none if the directive is itself a leaf). 48227f30029SMichael Kruse // The total number of these entries is at most MaxLeafCount+2. If this 48327f30029SMichael Kruse // number is less than that, it is padded to occupy exactly MaxLeafCount+2 48427f30029SMichael Kruse // entries in memory. 48527f30029SMichael Kruse // 48627f30029SMichael Kruse // The rows are stored in the table in the lexicographical order. This 48727f30029SMichael Kruse // is intended to enable binary search when mapping a sequence of leafs 48827f30029SMichael Kruse // back to the compound directive. 48927f30029SMichael Kruse // The consequence of that is that in order to find a row corresponding 49027f30029SMichael Kruse // to the given directive, we'd need to scan the first element of each 49127f30029SMichael Kruse // row. To avoid this, an auxiliary ordering table is created, such that 49227f30029SMichael Kruse // row for Dir_A = table[auxiliary[Dir_A]]. 49327f30029SMichael Kruse 49427f30029SMichael Kruse ArrayRef<const Record *> Directives = DirLang.getDirectives(); 49527f30029SMichael Kruse DenseMap<const Record *, int> DirId; // Record * -> llvm::omp::Directive 49627f30029SMichael Kruse 49727f30029SMichael Kruse for (auto [Idx, Rec] : enumerate(Directives)) 498*4e8c9d28SJay Foad DirId.try_emplace(Rec, Idx); 49927f30029SMichael Kruse 50027f30029SMichael Kruse using LeafList = std::vector<int>; 50127f30029SMichael Kruse int MaxLeafCount = getMaxLeafCount(DirLang); 50227f30029SMichael Kruse 50327f30029SMichael Kruse // The initial leaf table, rows order is same as directive order. 50427f30029SMichael Kruse std::vector<LeafList> LeafTable(Directives.size()); 50527f30029SMichael Kruse for (auto [Idx, Rec] : enumerate(Directives)) { 50627f30029SMichael Kruse Directive Dir(Rec); 50727f30029SMichael Kruse std::vector<const Record *> Leaves = Dir.getLeafConstructs(); 50827f30029SMichael Kruse 50927f30029SMichael Kruse auto &List = LeafTable[Idx]; 51027f30029SMichael Kruse List.resize(MaxLeafCount + 2); 51127f30029SMichael Kruse List[0] = Idx; // The id of the directive itself. 51227f30029SMichael Kruse List[1] = Leaves.size(); // The number of leaves to follow. 51327f30029SMichael Kruse 51427f30029SMichael Kruse for (int I = 0; I != MaxLeafCount; ++I) 51527f30029SMichael Kruse List[I + 2] = 51627f30029SMichael Kruse static_cast<size_t>(I) < Leaves.size() ? DirId.at(Leaves[I]) : -1; 51727f30029SMichael Kruse } 51827f30029SMichael Kruse 51927f30029SMichael Kruse // Some Fortran directives are delimited, i.e. they have the form of 52027f30029SMichael Kruse // "directive"---"end directive". If "directive" is a compound construct, 52127f30029SMichael Kruse // then the set of leaf constituents will be nonempty and the same for 52227f30029SMichael Kruse // both directives. Given this set of leafs, looking up the corresponding 52327f30029SMichael Kruse // compound directive should return "directive", and not "end directive". 52427f30029SMichael Kruse // To avoid this problem, gather all "end directives" at the end of the 52527f30029SMichael Kruse // leaf table, and only do the search on the initial segment of the table 52627f30029SMichael Kruse // that excludes the "end directives". 52727f30029SMichael Kruse // It's safe to find all directives whose names begin with "end ". The 52827f30029SMichael Kruse // problem only exists for compound directives, like "end do simd". 52927f30029SMichael Kruse // All existing directives with names starting with "end " are either 53027f30029SMichael Kruse // "end directives" for an existing "directive", or leaf directives 53127f30029SMichael Kruse // (such as "end declare target"). 53227f30029SMichael Kruse DenseSet<int> EndDirectives; 53327f30029SMichael Kruse for (auto [Rec, Id] : DirId) { 53427f30029SMichael Kruse if (Directive(Rec).getName().starts_with_insensitive("end ")) 53527f30029SMichael Kruse EndDirectives.insert(Id); 53627f30029SMichael Kruse } 53727f30029SMichael Kruse 53827f30029SMichael Kruse // Avoid sorting the vector<vector> array, instead sort an index array. 53927f30029SMichael Kruse // It will also be useful later to create the auxiliary indexing array. 54027f30029SMichael Kruse std::vector<int> Ordering(Directives.size()); 54127f30029SMichael Kruse std::iota(Ordering.begin(), Ordering.end(), 0); 54227f30029SMichael Kruse 54327f30029SMichael Kruse sort(Ordering, [&](int A, int B) { 54427f30029SMichael Kruse auto &LeavesA = LeafTable[A]; 54527f30029SMichael Kruse auto &LeavesB = LeafTable[B]; 54627f30029SMichael Kruse int DirA = LeavesA[0], DirB = LeavesB[0]; 54727f30029SMichael Kruse // First of all, end directives compare greater than non-end directives. 54827f30029SMichael Kruse int IsEndA = EndDirectives.count(DirA), IsEndB = EndDirectives.count(DirB); 54927f30029SMichael Kruse if (IsEndA != IsEndB) 55027f30029SMichael Kruse return IsEndA < IsEndB; 55127f30029SMichael Kruse if (LeavesA[1] == 0 && LeavesB[1] == 0) 55227f30029SMichael Kruse return DirA < DirB; 55327f30029SMichael Kruse return std::lexicographical_compare(&LeavesA[2], &LeavesA[2] + LeavesA[1], 55427f30029SMichael Kruse &LeavesB[2], &LeavesB[2] + LeavesB[1]); 55527f30029SMichael Kruse }); 55627f30029SMichael Kruse 55727f30029SMichael Kruse // Emit the table 55827f30029SMichael Kruse 55927f30029SMichael Kruse // The directives are emitted into a scoped enum, for which the underlying 56027f30029SMichael Kruse // type is `int` (by default). The code above uses `int` to store directive 56127f30029SMichael Kruse // ids, so make sure that we catch it when something changes in the 56227f30029SMichael Kruse // underlying type. 56327f30029SMichael Kruse std::string DirectiveType = getDirectiveType(DirLang); 56427f30029SMichael Kruse OS << "\nstatic_assert(sizeof(" << DirectiveType << ") == sizeof(int));\n"; 56527f30029SMichael Kruse 56627f30029SMichael Kruse OS << "[[maybe_unused]] static const " << DirectiveType << ' ' << TableName 56727f30029SMichael Kruse << "[][" << MaxLeafCount + 2 << "] = {\n"; 56827f30029SMichael Kruse for (size_t I = 0, E = Directives.size(); I != E; ++I) { 56927f30029SMichael Kruse auto &Leaves = LeafTable[Ordering[I]]; 57027f30029SMichael Kruse OS << " {" << getDirectiveName(DirLang, Directives[Leaves[0]]); 57127f30029SMichael Kruse OS << ", static_cast<" << DirectiveType << ">(" << Leaves[1] << "),"; 57227f30029SMichael Kruse for (size_t I = 2, E = Leaves.size(); I != E; ++I) { 57327f30029SMichael Kruse int Idx = Leaves[I]; 57427f30029SMichael Kruse if (Idx >= 0) 57527f30029SMichael Kruse OS << ' ' << getDirectiveName(DirLang, Directives[Leaves[I]]) << ','; 57627f30029SMichael Kruse else 57727f30029SMichael Kruse OS << " static_cast<" << DirectiveType << ">(-1),"; 57827f30029SMichael Kruse } 57927f30029SMichael Kruse OS << "},\n"; 58027f30029SMichael Kruse } 58127f30029SMichael Kruse OS << "};\n\n"; 58227f30029SMichael Kruse 58327f30029SMichael Kruse // Emit a marker where the first "end directive" is. 58427f30029SMichael Kruse auto FirstE = find_if(Ordering, [&](int RowIdx) { 58527f30029SMichael Kruse return EndDirectives.count(LeafTable[RowIdx][0]); 58627f30029SMichael Kruse }); 58727f30029SMichael Kruse OS << "[[maybe_unused]] static auto " << TableName 58827f30029SMichael Kruse << "EndDirective = " << TableName << " + " 58927f30029SMichael Kruse << std::distance(Ordering.begin(), FirstE) << ";\n\n"; 59027f30029SMichael Kruse 59127f30029SMichael Kruse // Emit the auxiliary index table: it's the inverse of the `Ordering` 59227f30029SMichael Kruse // table above. 59327f30029SMichael Kruse OS << "[[maybe_unused]] static const int " << TableName << "Ordering[] = {\n"; 59427f30029SMichael Kruse OS << " "; 59527f30029SMichael Kruse std::vector<int> Reverse(Ordering.size()); 59627f30029SMichael Kruse for (int I = 0, E = Ordering.size(); I != E; ++I) 59727f30029SMichael Kruse Reverse[Ordering[I]] = I; 59827f30029SMichael Kruse for (int Idx : Reverse) 59927f30029SMichael Kruse OS << ' ' << Idx << ','; 60027f30029SMichael Kruse OS << "\n};\n"; 60127f30029SMichael Kruse } 60227f30029SMichael Kruse 60327f30029SMichael Kruse static void generateGetDirectiveAssociation(const DirectiveLanguage &DirLang, 60427f30029SMichael Kruse raw_ostream &OS) { 60527f30029SMichael Kruse enum struct Association { 60627f30029SMichael Kruse None = 0, // None should be the smallest value. 60727f30029SMichael Kruse Block, // The values of the rest don't matter. 60827f30029SMichael Kruse Declaration, 60927f30029SMichael Kruse Delimited, 61027f30029SMichael Kruse Loop, 61127f30029SMichael Kruse Separating, 61227f30029SMichael Kruse FromLeaves, 61327f30029SMichael Kruse Invalid, 61427f30029SMichael Kruse }; 61527f30029SMichael Kruse 61627f30029SMichael Kruse ArrayRef<const Record *> Associations = DirLang.getAssociations(); 61727f30029SMichael Kruse 61827f30029SMichael Kruse auto GetAssocValue = [](StringRef Name) -> Association { 61927f30029SMichael Kruse return StringSwitch<Association>(Name) 62027f30029SMichael Kruse .Case("AS_Block", Association::Block) 62127f30029SMichael Kruse .Case("AS_Declaration", Association::Declaration) 62227f30029SMichael Kruse .Case("AS_Delimited", Association::Delimited) 62327f30029SMichael Kruse .Case("AS_Loop", Association::Loop) 62427f30029SMichael Kruse .Case("AS_None", Association::None) 62527f30029SMichael Kruse .Case("AS_Separating", Association::Separating) 62627f30029SMichael Kruse .Case("AS_FromLeaves", Association::FromLeaves) 62727f30029SMichael Kruse .Default(Association::Invalid); 62827f30029SMichael Kruse }; 62927f30029SMichael Kruse 63027f30029SMichael Kruse auto GetAssocName = [&](Association A) -> StringRef { 63127f30029SMichael Kruse if (A != Association::Invalid && A != Association::FromLeaves) { 63227f30029SMichael Kruse const auto *F = find_if(Associations, [&](const Record *R) { 63327f30029SMichael Kruse return GetAssocValue(R->getName()) == A; 63427f30029SMichael Kruse }); 63527f30029SMichael Kruse if (F != Associations.end()) 63627f30029SMichael Kruse return (*F)->getValueAsString("name"); // enum name 63727f30029SMichael Kruse } 63827f30029SMichael Kruse llvm_unreachable("Unexpected association value"); 63927f30029SMichael Kruse }; 64027f30029SMichael Kruse 64127f30029SMichael Kruse auto ErrorPrefixFor = [&](Directive D) -> std::string { 64227f30029SMichael Kruse return (Twine("Directive '") + D.getName() + "' in namespace '" + 64327f30029SMichael Kruse DirLang.getCppNamespace() + "' ") 64427f30029SMichael Kruse .str(); 64527f30029SMichael Kruse }; 64627f30029SMichael Kruse 64727f30029SMichael Kruse auto Reduce = [&](Association A, Association B) -> Association { 64827f30029SMichael Kruse if (A > B) 64927f30029SMichael Kruse std::swap(A, B); 65027f30029SMichael Kruse 65127f30029SMichael Kruse // Calculate the result using the following rules: 65227f30029SMichael Kruse // x + x = x 65327f30029SMichael Kruse // AS_None + x = x 65427f30029SMichael Kruse // AS_Block + AS_Loop = AS_Loop 65527f30029SMichael Kruse if (A == Association::None || A == B) 65627f30029SMichael Kruse return B; 65727f30029SMichael Kruse if (A == Association::Block && B == Association::Loop) 65827f30029SMichael Kruse return B; 65927f30029SMichael Kruse if (A == Association::Loop && B == Association::Block) 66027f30029SMichael Kruse return A; 66127f30029SMichael Kruse return Association::Invalid; 66227f30029SMichael Kruse }; 66327f30029SMichael Kruse 66427f30029SMichael Kruse DenseMap<const Record *, Association> AsMap; 66527f30029SMichael Kruse 66627f30029SMichael Kruse auto CompAssocImpl = [&](const Record *R, auto &&Self) -> Association { 66727f30029SMichael Kruse if (auto F = AsMap.find(R); F != AsMap.end()) 66827f30029SMichael Kruse return F->second; 66927f30029SMichael Kruse 67027f30029SMichael Kruse Directive D(R); 67127f30029SMichael Kruse Association AS = GetAssocValue(D.getAssociation()->getName()); 67227f30029SMichael Kruse if (AS == Association::Invalid) { 67327f30029SMichael Kruse PrintFatalError(ErrorPrefixFor(D) + 67427f30029SMichael Kruse "has an unrecognized value for association: '" + 67527f30029SMichael Kruse D.getAssociation()->getName() + "'"); 67627f30029SMichael Kruse } 67727f30029SMichael Kruse if (AS != Association::FromLeaves) { 678*4e8c9d28SJay Foad AsMap.try_emplace(R, AS); 67927f30029SMichael Kruse return AS; 68027f30029SMichael Kruse } 68127f30029SMichael Kruse // Compute the association from leaf constructs. 68227f30029SMichael Kruse std::vector<const Record *> Leaves = D.getLeafConstructs(); 68327f30029SMichael Kruse if (Leaves.empty()) { 68427f30029SMichael Kruse errs() << D.getName() << '\n'; 68527f30029SMichael Kruse PrintFatalError(ErrorPrefixFor(D) + 68627f30029SMichael Kruse "requests association to be computed from leaves, " 68727f30029SMichael Kruse "but it has no leaves"); 68827f30029SMichael Kruse } 68927f30029SMichael Kruse 69027f30029SMichael Kruse Association Result = Self(Leaves[0], Self); 69127f30029SMichael Kruse for (int I = 1, E = Leaves.size(); I < E; ++I) { 69227f30029SMichael Kruse Association A = Self(Leaves[I], Self); 69327f30029SMichael Kruse Association R = Reduce(Result, A); 69427f30029SMichael Kruse if (R == Association::Invalid) { 69527f30029SMichael Kruse PrintFatalError(ErrorPrefixFor(D) + 69627f30029SMichael Kruse "has leaves with incompatible association values: " + 69727f30029SMichael Kruse GetAssocName(A) + " and " + GetAssocName(R)); 69827f30029SMichael Kruse } 69927f30029SMichael Kruse Result = R; 70027f30029SMichael Kruse } 70127f30029SMichael Kruse 70227f30029SMichael Kruse assert(Result != Association::Invalid); 70327f30029SMichael Kruse assert(Result != Association::FromLeaves); 704*4e8c9d28SJay Foad AsMap.try_emplace(R, Result); 70527f30029SMichael Kruse return Result; 70627f30029SMichael Kruse }; 70727f30029SMichael Kruse 70827f30029SMichael Kruse for (const Record *R : DirLang.getDirectives()) 70927f30029SMichael Kruse CompAssocImpl(R, CompAssocImpl); // Updates AsMap. 71027f30029SMichael Kruse 71127f30029SMichael Kruse OS << '\n'; 71227f30029SMichael Kruse 71327f30029SMichael Kruse auto GetQualifiedName = [&](StringRef Formatted) -> std::string { 71427f30029SMichael Kruse return (Twine("llvm::") + DirLang.getCppNamespace() + 71527f30029SMichael Kruse "::Directive::" + DirLang.getDirectivePrefix() + Formatted) 71627f30029SMichael Kruse .str(); 71727f30029SMichael Kruse }; 71827f30029SMichael Kruse 71927f30029SMichael Kruse std::string DirectiveTypeName = 72027f30029SMichael Kruse "llvm::" + DirLang.getCppNamespace().str() + "::Directive"; 72127f30029SMichael Kruse std::string AssociationTypeName = 72227f30029SMichael Kruse "llvm::" + DirLang.getCppNamespace().str() + "::Association"; 72327f30029SMichael Kruse 72427f30029SMichael Kruse OS << AssociationTypeName << " llvm::" << DirLang.getCppNamespace() 72527f30029SMichael Kruse << "::getDirectiveAssociation(" << DirectiveTypeName << " Dir) {\n"; 72627f30029SMichael Kruse OS << " switch (Dir) {\n"; 72727f30029SMichael Kruse for (const Record *R : DirLang.getDirectives()) { 72827f30029SMichael Kruse if (auto F = AsMap.find(R); F != AsMap.end()) { 72927f30029SMichael Kruse Directive Dir(R); 73027f30029SMichael Kruse OS << " case " << GetQualifiedName(Dir.getFormattedName()) << ":\n"; 73127f30029SMichael Kruse OS << " return " << AssociationTypeName 73227f30029SMichael Kruse << "::" << GetAssocName(F->second) << ";\n"; 73327f30029SMichael Kruse } 73427f30029SMichael Kruse } 73527f30029SMichael Kruse OS << " } // switch (Dir)\n"; 73627f30029SMichael Kruse OS << " llvm_unreachable(\"Unexpected directive\");\n"; 73727f30029SMichael Kruse OS << "}\n"; 73827f30029SMichael Kruse } 73927f30029SMichael Kruse 74027f30029SMichael Kruse static void generateGetDirectiveCategory(const DirectiveLanguage &DirLang, 74127f30029SMichael Kruse raw_ostream &OS) { 74227f30029SMichael Kruse std::string LangNamespace = "llvm::" + DirLang.getCppNamespace().str(); 74327f30029SMichael Kruse std::string CategoryTypeName = LangNamespace + "::Category"; 74427f30029SMichael Kruse std::string CategoryNamespace = CategoryTypeName + "::"; 74527f30029SMichael Kruse 74627f30029SMichael Kruse OS << '\n'; 74727f30029SMichael Kruse OS << CategoryTypeName << ' ' << LangNamespace << "::getDirectiveCategory(" 74827f30029SMichael Kruse << getDirectiveType(DirLang) << " Dir) {\n"; 74927f30029SMichael Kruse OS << " switch (Dir) {\n"; 75027f30029SMichael Kruse 75127f30029SMichael Kruse for (const Record *R : DirLang.getDirectives()) { 75227f30029SMichael Kruse Directive D(R); 75327f30029SMichael Kruse OS << " case " << getDirectiveName(DirLang, R) << ":\n"; 75427f30029SMichael Kruse OS << " return " << CategoryNamespace 75527f30029SMichael Kruse << D.getCategory()->getValueAsString("name") << ";\n"; 75627f30029SMichael Kruse } 75727f30029SMichael Kruse OS << " } // switch (Dir)\n"; 75827f30029SMichael Kruse OS << " llvm_unreachable(\"Unexpected directive\");\n"; 75927f30029SMichael Kruse OS << "}\n"; 76027f30029SMichael Kruse } 76127f30029SMichael Kruse 76227f30029SMichael Kruse // Generate a simple enum set with the give clauses. 76327f30029SMichael Kruse static void generateClauseSet(ArrayRef<const Record *> Clauses, raw_ostream &OS, 76427f30029SMichael Kruse StringRef ClauseSetPrefix, const Directive &Dir, 76527f30029SMichael Kruse const DirectiveLanguage &DirLang) { 76627f30029SMichael Kruse 76727f30029SMichael Kruse OS << "\n"; 76827f30029SMichael Kruse OS << " static " << DirLang.getClauseEnumSetClass() << " " << ClauseSetPrefix 76927f30029SMichael Kruse << DirLang.getDirectivePrefix() << Dir.getFormattedName() << " {\n"; 77027f30029SMichael Kruse 77127f30029SMichael Kruse for (const auto &C : Clauses) { 77227f30029SMichael Kruse VersionedClause VerClause(C); 77327f30029SMichael Kruse OS << " llvm::" << DirLang.getCppNamespace() 77427f30029SMichael Kruse << "::Clause::" << DirLang.getClausePrefix() 77527f30029SMichael Kruse << VerClause.getClause().getFormattedName() << ",\n"; 77627f30029SMichael Kruse } 77727f30029SMichael Kruse OS << " };\n"; 77827f30029SMichael Kruse } 77927f30029SMichael Kruse 78027f30029SMichael Kruse // Generate an enum set for the 4 kinds of clauses linked to a directive. 78127f30029SMichael Kruse static void generateDirectiveClauseSets(const DirectiveLanguage &DirLang, 78227f30029SMichael Kruse raw_ostream &OS) { 78327f30029SMichael Kruse 78427f30029SMichael Kruse IfDefScope Scope("GEN_FLANG_DIRECTIVE_CLAUSE_SETS", OS); 78527f30029SMichael Kruse 78627f30029SMichael Kruse OS << "\n"; 78727f30029SMichael Kruse OS << "namespace llvm {\n"; 78827f30029SMichael Kruse 78927f30029SMichael Kruse // Open namespaces defined in the directive language. 79027f30029SMichael Kruse SmallVector<StringRef, 2> Namespaces; 79127f30029SMichael Kruse SplitString(DirLang.getCppNamespace(), Namespaces, "::"); 79227f30029SMichael Kruse for (auto Ns : Namespaces) 79327f30029SMichael Kruse OS << "namespace " << Ns << " {\n"; 79427f30029SMichael Kruse 79527f30029SMichael Kruse for (const Directive Dir : DirLang.getDirectives()) { 79627f30029SMichael Kruse OS << "\n"; 79727f30029SMichael Kruse OS << " // Sets for " << Dir.getName() << "\n"; 79827f30029SMichael Kruse 79927f30029SMichael Kruse generateClauseSet(Dir.getAllowedClauses(), OS, "allowedClauses_", Dir, 80027f30029SMichael Kruse DirLang); 80127f30029SMichael Kruse generateClauseSet(Dir.getAllowedOnceClauses(), OS, "allowedOnceClauses_", 80227f30029SMichael Kruse Dir, DirLang); 80327f30029SMichael Kruse generateClauseSet(Dir.getAllowedExclusiveClauses(), OS, 80427f30029SMichael Kruse "allowedExclusiveClauses_", Dir, DirLang); 80527f30029SMichael Kruse generateClauseSet(Dir.getRequiredClauses(), OS, "requiredClauses_", Dir, 80627f30029SMichael Kruse DirLang); 80727f30029SMichael Kruse } 80827f30029SMichael Kruse 80927f30029SMichael Kruse // Closing namespaces 81027f30029SMichael Kruse for (auto Ns : reverse(Namespaces)) 81127f30029SMichael Kruse OS << "} // namespace " << Ns << "\n"; 81227f30029SMichael Kruse 81327f30029SMichael Kruse OS << "} // namespace llvm\n"; 81427f30029SMichael Kruse } 81527f30029SMichael Kruse 81627f30029SMichael Kruse // Generate a map of directive (key) with DirectiveClauses struct as values. 81727f30029SMichael Kruse // The struct holds the 4 sets of enumeration for the 4 kinds of clauses 81827f30029SMichael Kruse // allowances (allowed, allowed once, allowed exclusive and required). 81927f30029SMichael Kruse static void generateDirectiveClauseMap(const DirectiveLanguage &DirLang, 82027f30029SMichael Kruse raw_ostream &OS) { 82127f30029SMichael Kruse 82227f30029SMichael Kruse IfDefScope Scope("GEN_FLANG_DIRECTIVE_CLAUSE_MAP", OS); 82327f30029SMichael Kruse 82427f30029SMichael Kruse OS << "\n"; 82527f30029SMichael Kruse OS << "{\n"; 82627f30029SMichael Kruse 82727f30029SMichael Kruse for (const Directive Dir : DirLang.getDirectives()) { 82827f30029SMichael Kruse OS << " {llvm::" << DirLang.getCppNamespace() 82927f30029SMichael Kruse << "::Directive::" << DirLang.getDirectivePrefix() 83027f30029SMichael Kruse << Dir.getFormattedName() << ",\n"; 83127f30029SMichael Kruse OS << " {\n"; 83227f30029SMichael Kruse OS << " llvm::" << DirLang.getCppNamespace() << "::allowedClauses_" 83327f30029SMichael Kruse << DirLang.getDirectivePrefix() << Dir.getFormattedName() << ",\n"; 83427f30029SMichael Kruse OS << " llvm::" << DirLang.getCppNamespace() << "::allowedOnceClauses_" 83527f30029SMichael Kruse << DirLang.getDirectivePrefix() << Dir.getFormattedName() << ",\n"; 83627f30029SMichael Kruse OS << " llvm::" << DirLang.getCppNamespace() 83727f30029SMichael Kruse << "::allowedExclusiveClauses_" << DirLang.getDirectivePrefix() 83827f30029SMichael Kruse << Dir.getFormattedName() << ",\n"; 83927f30029SMichael Kruse OS << " llvm::" << DirLang.getCppNamespace() << "::requiredClauses_" 84027f30029SMichael Kruse << DirLang.getDirectivePrefix() << Dir.getFormattedName() << ",\n"; 84127f30029SMichael Kruse OS << " }\n"; 84227f30029SMichael Kruse OS << " },\n"; 84327f30029SMichael Kruse } 84427f30029SMichael Kruse 84527f30029SMichael Kruse OS << "}\n"; 84627f30029SMichael Kruse } 84727f30029SMichael Kruse 84827f30029SMichael Kruse // Generate classes entry for Flang clauses in the Flang parse-tree 84927f30029SMichael Kruse // If the clause as a non-generic class, no entry is generated. 85027f30029SMichael Kruse // If the clause does not hold a value, an EMPTY_CLASS is used. 85127f30029SMichael Kruse // If the clause class is generic then a WRAPPER_CLASS is used. When the value 85227f30029SMichael Kruse // is optional, the value class is wrapped into a std::optional. 85327f30029SMichael Kruse static void generateFlangClauseParserClass(const DirectiveLanguage &DirLang, 85427f30029SMichael Kruse raw_ostream &OS) { 85527f30029SMichael Kruse 85627f30029SMichael Kruse IfDefScope Scope("GEN_FLANG_CLAUSE_PARSER_CLASSES", OS); 85727f30029SMichael Kruse 85827f30029SMichael Kruse OS << "\n"; 85927f30029SMichael Kruse 86027f30029SMichael Kruse for (const Clause Clause : DirLang.getClauses()) { 86127f30029SMichael Kruse if (!Clause.getFlangClass().empty()) { 86227f30029SMichael Kruse OS << "WRAPPER_CLASS(" << Clause.getFormattedParserClassName() << ", "; 86327f30029SMichael Kruse if (Clause.isValueOptional() && Clause.isValueList()) { 86427f30029SMichael Kruse OS << "std::optional<std::list<" << Clause.getFlangClass() << ">>"; 86527f30029SMichael Kruse } else if (Clause.isValueOptional()) { 86627f30029SMichael Kruse OS << "std::optional<" << Clause.getFlangClass() << ">"; 86727f30029SMichael Kruse } else if (Clause.isValueList()) { 86827f30029SMichael Kruse OS << "std::list<" << Clause.getFlangClass() << ">"; 86927f30029SMichael Kruse } else { 87027f30029SMichael Kruse OS << Clause.getFlangClass(); 87127f30029SMichael Kruse } 87227f30029SMichael Kruse } else { 87327f30029SMichael Kruse OS << "EMPTY_CLASS(" << Clause.getFormattedParserClassName(); 87427f30029SMichael Kruse } 87527f30029SMichael Kruse OS << ");\n"; 87627f30029SMichael Kruse } 87727f30029SMichael Kruse } 87827f30029SMichael Kruse 87927f30029SMichael Kruse // Generate a list of the different clause classes for Flang. 88027f30029SMichael Kruse static void generateFlangClauseParserClassList(const DirectiveLanguage &DirLang, 88127f30029SMichael Kruse raw_ostream &OS) { 88227f30029SMichael Kruse 88327f30029SMichael Kruse IfDefScope Scope("GEN_FLANG_CLAUSE_PARSER_CLASSES_LIST", OS); 88427f30029SMichael Kruse 88527f30029SMichael Kruse OS << "\n"; 88627f30029SMichael Kruse interleaveComma(DirLang.getClauses(), OS, [&](const Record *C) { 88727f30029SMichael Kruse Clause Clause(C); 88827f30029SMichael Kruse OS << Clause.getFormattedParserClassName() << "\n"; 88927f30029SMichael Kruse }); 89027f30029SMichael Kruse } 89127f30029SMichael Kruse 89227f30029SMichael Kruse // Generate dump node list for the clauses holding a generic class name. 89327f30029SMichael Kruse static void generateFlangClauseDump(const DirectiveLanguage &DirLang, 89427f30029SMichael Kruse raw_ostream &OS) { 89527f30029SMichael Kruse 89627f30029SMichael Kruse IfDefScope Scope("GEN_FLANG_DUMP_PARSE_TREE_CLAUSES", OS); 89727f30029SMichael Kruse 89827f30029SMichael Kruse OS << "\n"; 89927f30029SMichael Kruse for (const Clause Clause : DirLang.getClauses()) { 90027f30029SMichael Kruse OS << "NODE(" << DirLang.getFlangClauseBaseClass() << ", " 90127f30029SMichael Kruse << Clause.getFormattedParserClassName() << ")\n"; 90227f30029SMichael Kruse } 90327f30029SMichael Kruse } 90427f30029SMichael Kruse 90527f30029SMichael Kruse // Generate Unparse functions for clauses classes in the Flang parse-tree 90627f30029SMichael Kruse // If the clause is a non-generic class, no entry is generated. 90727f30029SMichael Kruse static void generateFlangClauseUnparse(const DirectiveLanguage &DirLang, 90827f30029SMichael Kruse raw_ostream &OS) { 90927f30029SMichael Kruse 91027f30029SMichael Kruse IfDefScope Scope("GEN_FLANG_CLAUSE_UNPARSE", OS); 91127f30029SMichael Kruse 91227f30029SMichael Kruse OS << "\n"; 91327f30029SMichael Kruse 91427f30029SMichael Kruse for (const Clause Clause : DirLang.getClauses()) { 91527f30029SMichael Kruse if (!Clause.getFlangClass().empty()) { 91627f30029SMichael Kruse if (Clause.isValueOptional() && Clause.getDefaultValue().empty()) { 91727f30029SMichael Kruse OS << "void Unparse(const " << DirLang.getFlangClauseBaseClass() 91827f30029SMichael Kruse << "::" << Clause.getFormattedParserClassName() << " &x) {\n"; 91927f30029SMichael Kruse OS << " Word(\"" << Clause.getName().upper() << "\");\n"; 92027f30029SMichael Kruse 92127f30029SMichael Kruse OS << " Walk(\"(\", x.v, \")\");\n"; 92227f30029SMichael Kruse OS << "}\n"; 92327f30029SMichael Kruse } else if (Clause.isValueOptional()) { 92427f30029SMichael Kruse OS << "void Unparse(const " << DirLang.getFlangClauseBaseClass() 92527f30029SMichael Kruse << "::" << Clause.getFormattedParserClassName() << " &x) {\n"; 92627f30029SMichael Kruse OS << " Word(\"" << Clause.getName().upper() << "\");\n"; 92727f30029SMichael Kruse OS << " Put(\"(\");\n"; 92827f30029SMichael Kruse OS << " if (x.v.has_value())\n"; 92927f30029SMichael Kruse if (Clause.isValueList()) 93027f30029SMichael Kruse OS << " Walk(x.v, \",\");\n"; 93127f30029SMichael Kruse else 93227f30029SMichael Kruse OS << " Walk(x.v);\n"; 93327f30029SMichael Kruse OS << " else\n"; 93427f30029SMichael Kruse OS << " Put(\"" << Clause.getDefaultValue() << "\");\n"; 93527f30029SMichael Kruse OS << " Put(\")\");\n"; 93627f30029SMichael Kruse OS << "}\n"; 93727f30029SMichael Kruse } else { 93827f30029SMichael Kruse OS << "void Unparse(const " << DirLang.getFlangClauseBaseClass() 93927f30029SMichael Kruse << "::" << Clause.getFormattedParserClassName() << " &x) {\n"; 94027f30029SMichael Kruse OS << " Word(\"" << Clause.getName().upper() << "\");\n"; 94127f30029SMichael Kruse OS << " Put(\"(\");\n"; 94227f30029SMichael Kruse if (Clause.isValueList()) 94327f30029SMichael Kruse OS << " Walk(x.v, \",\");\n"; 94427f30029SMichael Kruse else 94527f30029SMichael Kruse OS << " Walk(x.v);\n"; 94627f30029SMichael Kruse OS << " Put(\")\");\n"; 94727f30029SMichael Kruse OS << "}\n"; 94827f30029SMichael Kruse } 94927f30029SMichael Kruse } else { 95027f30029SMichael Kruse OS << "void Before(const " << DirLang.getFlangClauseBaseClass() 95127f30029SMichael Kruse << "::" << Clause.getFormattedParserClassName() << " &) { Word(\"" 95227f30029SMichael Kruse << Clause.getName().upper() << "\"); }\n"; 95327f30029SMichael Kruse } 95427f30029SMichael Kruse } 95527f30029SMichael Kruse } 95627f30029SMichael Kruse 95727f30029SMichael Kruse // Generate check in the Enter functions for clauses classes. 95827f30029SMichael Kruse static void generateFlangClauseCheckPrototypes(const DirectiveLanguage &DirLang, 95927f30029SMichael Kruse raw_ostream &OS) { 96027f30029SMichael Kruse 96127f30029SMichael Kruse IfDefScope Scope("GEN_FLANG_CLAUSE_CHECK_ENTER", OS); 96227f30029SMichael Kruse 96327f30029SMichael Kruse OS << "\n"; 96427f30029SMichael Kruse for (const Clause Clause : DirLang.getClauses()) { 96527f30029SMichael Kruse OS << "void Enter(const parser::" << DirLang.getFlangClauseBaseClass() 96627f30029SMichael Kruse << "::" << Clause.getFormattedParserClassName() << " &);\n"; 96727f30029SMichael Kruse } 96827f30029SMichael Kruse } 96927f30029SMichael Kruse 97027f30029SMichael Kruse // Generate the mapping for clauses between the parser class and the 97127f30029SMichael Kruse // corresponding clause Kind 97227f30029SMichael Kruse static void generateFlangClauseParserKindMap(const DirectiveLanguage &DirLang, 97327f30029SMichael Kruse raw_ostream &OS) { 97427f30029SMichael Kruse 97527f30029SMichael Kruse IfDefScope Scope("GEN_FLANG_CLAUSE_PARSER_KIND_MAP", OS); 97627f30029SMichael Kruse 97727f30029SMichael Kruse OS << "\n"; 97827f30029SMichael Kruse for (const Clause Clause : DirLang.getClauses()) { 97927f30029SMichael Kruse OS << "if constexpr (std::is_same_v<A, parser::" 98027f30029SMichael Kruse << DirLang.getFlangClauseBaseClass() 98127f30029SMichael Kruse << "::" << Clause.getFormattedParserClassName(); 98227f30029SMichael Kruse OS << ">)\n"; 98327f30029SMichael Kruse OS << " return llvm::" << DirLang.getCppNamespace() 98427f30029SMichael Kruse << "::Clause::" << DirLang.getClausePrefix() << Clause.getFormattedName() 98527f30029SMichael Kruse << ";\n"; 98627f30029SMichael Kruse } 98727f30029SMichael Kruse 98827f30029SMichael Kruse OS << "llvm_unreachable(\"Invalid " << DirLang.getName() 98927f30029SMichael Kruse << " Parser clause\");\n"; 99027f30029SMichael Kruse } 99127f30029SMichael Kruse 99227f30029SMichael Kruse static bool compareClauseName(const Record *R1, const Record *R2) { 99327f30029SMichael Kruse Clause C1(R1); 99427f30029SMichael Kruse Clause C2(R2); 99527f30029SMichael Kruse return (C1.getName() > C2.getName()); 99627f30029SMichael Kruse } 99727f30029SMichael Kruse 99827f30029SMichael Kruse // Generate the parser for the clauses. 99927f30029SMichael Kruse static void generateFlangClausesParser(const DirectiveLanguage &DirLang, 100027f30029SMichael Kruse raw_ostream &OS) { 100127f30029SMichael Kruse std::vector<const Record *> Clauses = DirLang.getClauses(); 100227f30029SMichael Kruse // Sort clauses in reverse alphabetical order so with clauses with same 100327f30029SMichael Kruse // beginning, the longer option is tried before. 100427f30029SMichael Kruse sort(Clauses, compareClauseName); 100527f30029SMichael Kruse IfDefScope Scope("GEN_FLANG_CLAUSES_PARSER", OS); 100627f30029SMichael Kruse OS << "\n"; 100727f30029SMichael Kruse unsigned Index = 0; 100827f30029SMichael Kruse unsigned LastClauseIndex = Clauses.size() - 1; 100927f30029SMichael Kruse OS << "TYPE_PARSER(\n"; 101027f30029SMichael Kruse for (const Clause Clause : Clauses) { 101127f30029SMichael Kruse if (Clause.getAliases().empty()) { 101227f30029SMichael Kruse OS << " \"" << Clause.getName() << "\""; 101327f30029SMichael Kruse } else { 101427f30029SMichael Kruse OS << " (" 101527f30029SMichael Kruse << "\"" << Clause.getName() << "\"_tok"; 101627f30029SMichael Kruse for (StringRef Alias : Clause.getAliases()) { 101727f30029SMichael Kruse OS << " || \"" << Alias << "\"_tok"; 101827f30029SMichael Kruse } 101927f30029SMichael Kruse OS << ")"; 102027f30029SMichael Kruse } 102127f30029SMichael Kruse 102227f30029SMichael Kruse OS << " >> construct<" << DirLang.getFlangClauseBaseClass() 102327f30029SMichael Kruse << ">(construct<" << DirLang.getFlangClauseBaseClass() 102427f30029SMichael Kruse << "::" << Clause.getFormattedParserClassName() << ">("; 102527f30029SMichael Kruse if (Clause.getFlangClass().empty()) { 102627f30029SMichael Kruse OS << "))"; 102727f30029SMichael Kruse if (Index != LastClauseIndex) 102827f30029SMichael Kruse OS << " ||"; 102927f30029SMichael Kruse OS << "\n"; 103027f30029SMichael Kruse ++Index; 103127f30029SMichael Kruse continue; 103227f30029SMichael Kruse } 103327f30029SMichael Kruse 103427f30029SMichael Kruse if (Clause.isValueOptional()) 103527f30029SMichael Kruse OS << "maybe("; 103627f30029SMichael Kruse OS << "parenthesized("; 103727f30029SMichael Kruse if (Clause.isValueList()) 103827f30029SMichael Kruse OS << "nonemptyList("; 103927f30029SMichael Kruse 104027f30029SMichael Kruse if (!Clause.getPrefix().empty()) 104127f30029SMichael Kruse OS << "\"" << Clause.getPrefix() << ":\" >> "; 104227f30029SMichael Kruse 104327f30029SMichael Kruse // The common Flang parser are used directly. Their name is identical to 104427f30029SMichael Kruse // the Flang class with first letter as lowercase. If the Flang class is 104527f30029SMichael Kruse // not a common class, we assume there is a specific Parser<>{} with the 104627f30029SMichael Kruse // Flang class name provided. 104727f30029SMichael Kruse SmallString<128> Scratch; 104827f30029SMichael Kruse StringRef Parser = 104927f30029SMichael Kruse StringSwitch<StringRef>(Clause.getFlangClass()) 105027f30029SMichael Kruse .Case("Name", "name") 105127f30029SMichael Kruse .Case("ScalarIntConstantExpr", "scalarIntConstantExpr") 105227f30029SMichael Kruse .Case("ScalarIntExpr", "scalarIntExpr") 105327f30029SMichael Kruse .Case("ScalarExpr", "scalarExpr") 105427f30029SMichael Kruse .Case("ScalarLogicalExpr", "scalarLogicalExpr") 105527f30029SMichael Kruse .Default(("Parser<" + Clause.getFlangClass() + ">{}") 105627f30029SMichael Kruse .toStringRef(Scratch)); 105727f30029SMichael Kruse OS << Parser; 105827f30029SMichael Kruse if (!Clause.getPrefix().empty() && Clause.isPrefixOptional()) 105927f30029SMichael Kruse OS << " || " << Parser; 106027f30029SMichael Kruse if (Clause.isValueList()) // close nonemptyList(. 106127f30029SMichael Kruse OS << ")"; 106227f30029SMichael Kruse OS << ")"; // close parenthesized(. 106327f30029SMichael Kruse 106427f30029SMichael Kruse if (Clause.isValueOptional()) // close maybe(. 106527f30029SMichael Kruse OS << ")"; 106627f30029SMichael Kruse OS << "))"; 106727f30029SMichael Kruse if (Index != LastClauseIndex) 106827f30029SMichael Kruse OS << " ||"; 106927f30029SMichael Kruse OS << "\n"; 107027f30029SMichael Kruse ++Index; 107127f30029SMichael Kruse } 107227f30029SMichael Kruse OS << ")\n"; 107327f30029SMichael Kruse } 107427f30029SMichael Kruse 107527f30029SMichael Kruse // Generate the implementation section for the enumeration in the directive 107627f30029SMichael Kruse // language 107727f30029SMichael Kruse static void emitDirectivesFlangImpl(const DirectiveLanguage &DirLang, 107827f30029SMichael Kruse raw_ostream &OS) { 107927f30029SMichael Kruse generateDirectiveClauseSets(DirLang, OS); 108027f30029SMichael Kruse 108127f30029SMichael Kruse generateDirectiveClauseMap(DirLang, OS); 108227f30029SMichael Kruse 108327f30029SMichael Kruse generateFlangClauseParserClass(DirLang, OS); 108427f30029SMichael Kruse 108527f30029SMichael Kruse generateFlangClauseParserClassList(DirLang, OS); 108627f30029SMichael Kruse 108727f30029SMichael Kruse generateFlangClauseDump(DirLang, OS); 108827f30029SMichael Kruse 108927f30029SMichael Kruse generateFlangClauseUnparse(DirLang, OS); 109027f30029SMichael Kruse 109127f30029SMichael Kruse generateFlangClauseCheckPrototypes(DirLang, OS); 109227f30029SMichael Kruse 109327f30029SMichael Kruse generateFlangClauseParserKindMap(DirLang, OS); 109427f30029SMichael Kruse 109527f30029SMichael Kruse generateFlangClausesParser(DirLang, OS); 109627f30029SMichael Kruse } 109727f30029SMichael Kruse 109827f30029SMichael Kruse static void generateClauseClassMacro(const DirectiveLanguage &DirLang, 109927f30029SMichael Kruse raw_ostream &OS) { 110027f30029SMichael Kruse // Generate macros style information for legacy code in clang 110127f30029SMichael Kruse IfDefScope Scope("GEN_CLANG_CLAUSE_CLASS", OS); 110227f30029SMichael Kruse 110327f30029SMichael Kruse OS << "\n"; 110427f30029SMichael Kruse 110527f30029SMichael Kruse OS << "#ifndef CLAUSE\n"; 110627f30029SMichael Kruse OS << "#define CLAUSE(Enum, Str, Implicit)\n"; 110727f30029SMichael Kruse OS << "#endif\n"; 110827f30029SMichael Kruse OS << "#ifndef CLAUSE_CLASS\n"; 110927f30029SMichael Kruse OS << "#define CLAUSE_CLASS(Enum, Str, Class)\n"; 111027f30029SMichael Kruse OS << "#endif\n"; 111127f30029SMichael Kruse OS << "#ifndef CLAUSE_NO_CLASS\n"; 111227f30029SMichael Kruse OS << "#define CLAUSE_NO_CLASS(Enum, Str)\n"; 111327f30029SMichael Kruse OS << "#endif\n"; 111427f30029SMichael Kruse OS << "\n"; 111527f30029SMichael Kruse OS << "#define __CLAUSE(Name, Class) \\\n"; 111627f30029SMichael Kruse OS << " CLAUSE(" << DirLang.getClausePrefix() 111727f30029SMichael Kruse << "##Name, #Name, /* Implicit */ false) \\\n"; 111827f30029SMichael Kruse OS << " CLAUSE_CLASS(" << DirLang.getClausePrefix() 111927f30029SMichael Kruse << "##Name, #Name, Class)\n"; 112027f30029SMichael Kruse OS << "#define __CLAUSE_NO_CLASS(Name) \\\n"; 112127f30029SMichael Kruse OS << " CLAUSE(" << DirLang.getClausePrefix() 112227f30029SMichael Kruse << "##Name, #Name, /* Implicit */ false) \\\n"; 112327f30029SMichael Kruse OS << " CLAUSE_NO_CLASS(" << DirLang.getClausePrefix() << "##Name, #Name)\n"; 112427f30029SMichael Kruse OS << "#define __IMPLICIT_CLAUSE_CLASS(Name, Str, Class) \\\n"; 112527f30029SMichael Kruse OS << " CLAUSE(" << DirLang.getClausePrefix() 112627f30029SMichael Kruse << "##Name, Str, /* Implicit */ true) \\\n"; 112727f30029SMichael Kruse OS << " CLAUSE_CLASS(" << DirLang.getClausePrefix() 112827f30029SMichael Kruse << "##Name, Str, Class)\n"; 112927f30029SMichael Kruse OS << "#define __IMPLICIT_CLAUSE_NO_CLASS(Name, Str) \\\n"; 113027f30029SMichael Kruse OS << " CLAUSE(" << DirLang.getClausePrefix() 113127f30029SMichael Kruse << "##Name, Str, /* Implicit */ true) \\\n"; 113227f30029SMichael Kruse OS << " CLAUSE_NO_CLASS(" << DirLang.getClausePrefix() << "##Name, Str)\n"; 113327f30029SMichael Kruse OS << "\n"; 113427f30029SMichael Kruse 113527f30029SMichael Kruse for (const Clause C : DirLang.getClauses()) { 113627f30029SMichael Kruse if (C.getClangClass().empty()) { // NO_CLASS 113727f30029SMichael Kruse if (C.isImplicit()) { 113827f30029SMichael Kruse OS << "__IMPLICIT_CLAUSE_NO_CLASS(" << C.getFormattedName() << ", \"" 113927f30029SMichael Kruse << C.getFormattedName() << "\")\n"; 114027f30029SMichael Kruse } else { 114127f30029SMichael Kruse OS << "__CLAUSE_NO_CLASS(" << C.getFormattedName() << ")\n"; 114227f30029SMichael Kruse } 114327f30029SMichael Kruse } else { // CLASS 114427f30029SMichael Kruse if (C.isImplicit()) { 114527f30029SMichael Kruse OS << "__IMPLICIT_CLAUSE_CLASS(" << C.getFormattedName() << ", \"" 114627f30029SMichael Kruse << C.getFormattedName() << "\", " << C.getClangClass() << ")\n"; 114727f30029SMichael Kruse } else { 114827f30029SMichael Kruse OS << "__CLAUSE(" << C.getFormattedName() << ", " << C.getClangClass() 114927f30029SMichael Kruse << ")\n"; 115027f30029SMichael Kruse } 115127f30029SMichael Kruse } 115227f30029SMichael Kruse } 115327f30029SMichael Kruse 115427f30029SMichael Kruse OS << "\n"; 115527f30029SMichael Kruse OS << "#undef __IMPLICIT_CLAUSE_NO_CLASS\n"; 115627f30029SMichael Kruse OS << "#undef __IMPLICIT_CLAUSE_CLASS\n"; 115727f30029SMichael Kruse OS << "#undef __CLAUSE_NO_CLASS\n"; 115827f30029SMichael Kruse OS << "#undef __CLAUSE\n"; 115927f30029SMichael Kruse OS << "#undef CLAUSE_NO_CLASS\n"; 116027f30029SMichael Kruse OS << "#undef CLAUSE_CLASS\n"; 116127f30029SMichael Kruse OS << "#undef CLAUSE\n"; 116227f30029SMichael Kruse } 116327f30029SMichael Kruse 116427f30029SMichael Kruse // Generate the implemenation for the enumeration in the directive 116527f30029SMichael Kruse // language. This code can be included in library. 116627f30029SMichael Kruse void emitDirectivesBasicImpl(const DirectiveLanguage &DirLang, 116727f30029SMichael Kruse raw_ostream &OS) { 116827f30029SMichael Kruse IfDefScope Scope("GEN_DIRECTIVES_IMPL", OS); 116927f30029SMichael Kruse 117027f30029SMichael Kruse OS << "\n#include \"llvm/Support/ErrorHandling.h\"\n"; 117127f30029SMichael Kruse 117227f30029SMichael Kruse // getDirectiveKind(StringRef Str) 117327f30029SMichael Kruse generateGetKind(DirLang.getDirectives(), OS, "Directive", DirLang, 117427f30029SMichael Kruse DirLang.getDirectivePrefix(), /*ImplicitAsUnknown=*/false); 117527f30029SMichael Kruse 117627f30029SMichael Kruse // getDirectiveName(Directive Kind) 117727f30029SMichael Kruse generateGetName(DirLang.getDirectives(), OS, "Directive", DirLang, 117827f30029SMichael Kruse DirLang.getDirectivePrefix()); 117927f30029SMichael Kruse 118027f30029SMichael Kruse // getClauseKind(StringRef Str) 118127f30029SMichael Kruse generateGetKind(DirLang.getClauses(), OS, "Clause", DirLang, 118227f30029SMichael Kruse DirLang.getClausePrefix(), 118327f30029SMichael Kruse /*ImplicitAsUnknown=*/true); 118427f30029SMichael Kruse 118527f30029SMichael Kruse // getClauseName(Clause Kind) 118627f30029SMichael Kruse generateGetName(DirLang.getClauses(), OS, "Clause", DirLang, 118727f30029SMichael Kruse DirLang.getClausePrefix()); 118827f30029SMichael Kruse 118927f30029SMichael Kruse // get<ClauseVal>Kind(StringRef Str) 119027f30029SMichael Kruse generateGetKindClauseVal(DirLang, OS); 119127f30029SMichael Kruse 119227f30029SMichael Kruse // isAllowedClauseForDirective(Directive D, Clause C, unsigned Version) 119327f30029SMichael Kruse generateIsAllowedClause(DirLang, OS); 119427f30029SMichael Kruse 119527f30029SMichael Kruse // getDirectiveAssociation(Directive D) 119627f30029SMichael Kruse generateGetDirectiveAssociation(DirLang, OS); 119727f30029SMichael Kruse 119827f30029SMichael Kruse // getDirectiveCategory(Directive D) 119927f30029SMichael Kruse generateGetDirectiveCategory(DirLang, OS); 120027f30029SMichael Kruse 120127f30029SMichael Kruse // Leaf table for getLeafConstructs, etc. 120227f30029SMichael Kruse emitLeafTable(DirLang, OS, "LeafConstructTable"); 120327f30029SMichael Kruse } 120427f30029SMichael Kruse 120527f30029SMichael Kruse // Generate the implemenation section for the enumeration in the directive 120627f30029SMichael Kruse // language. 120727f30029SMichael Kruse static void emitDirectivesImpl(const RecordKeeper &Records, raw_ostream &OS) { 120827f30029SMichael Kruse const auto DirLang = DirectiveLanguage(Records); 120927f30029SMichael Kruse if (DirLang.HasValidityErrors()) 121027f30029SMichael Kruse return; 121127f30029SMichael Kruse 121227f30029SMichael Kruse emitDirectivesFlangImpl(DirLang, OS); 121327f30029SMichael Kruse 121427f30029SMichael Kruse generateClauseClassMacro(DirLang, OS); 121527f30029SMichael Kruse 121627f30029SMichael Kruse emitDirectivesBasicImpl(DirLang, OS); 121727f30029SMichael Kruse } 121827f30029SMichael Kruse 121927f30029SMichael Kruse static TableGen::Emitter::Opt 122027f30029SMichael Kruse X("gen-directive-decl", emitDirectivesDecl, 122127f30029SMichael Kruse "Generate directive related declaration code (header file)"); 122227f30029SMichael Kruse 122327f30029SMichael Kruse static TableGen::Emitter::Opt 122427f30029SMichael Kruse Y("gen-directive-impl", emitDirectivesImpl, 122527f30029SMichael Kruse "Generate directive related implementation code"); 1226