xref: /llvm-project/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp (revision 4e8c9d28132039a98feb97cec2759cddeb37d934)
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