xref: /freebsd/contrib/llvm-project/llvm/utils/TableGen/DirectiveEmitter.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
15ffd83dbSDimitry Andric //===- DirectiveEmitter.cpp - Directive Language Emitter ------------------===//
25ffd83dbSDimitry Andric //
35ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65ffd83dbSDimitry Andric //
75ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
85ffd83dbSDimitry Andric //
95ffd83dbSDimitry Andric // DirectiveEmitter uses the descriptions of directives and clauses to construct
105ffd83dbSDimitry Andric // common code declarations to be used in Frontends.
115ffd83dbSDimitry Andric //
125ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
135ffd83dbSDimitry Andric 
14e8d8bef9SDimitry Andric #include "llvm/TableGen/DirectiveEmitter.h"
15*0fca6ea1SDimitry Andric #include "llvm/ADT/DenseMap.h"
16*0fca6ea1SDimitry Andric #include "llvm/ADT/DenseSet.h"
175ffd83dbSDimitry Andric #include "llvm/ADT/STLExtras.h"
185ffd83dbSDimitry Andric #include "llvm/ADT/SmallVector.h"
195ffd83dbSDimitry Andric #include "llvm/ADT/StringSet.h"
20fcaf7f86SDimitry Andric #include "llvm/ADT/StringSwitch.h"
215ffd83dbSDimitry Andric #include "llvm/TableGen/Error.h"
225ffd83dbSDimitry Andric #include "llvm/TableGen/Record.h"
2306c3fb27SDimitry Andric #include "llvm/TableGen/TableGenBackend.h"
245ffd83dbSDimitry Andric 
25*0fca6ea1SDimitry Andric #include <numeric>
26*0fca6ea1SDimitry Andric #include <vector>
27*0fca6ea1SDimitry Andric 
285ffd83dbSDimitry Andric using namespace llvm;
295ffd83dbSDimitry Andric 
305ffd83dbSDimitry Andric namespace {
315ffd83dbSDimitry Andric // Simple RAII helper for defining ifdef-undef-endif scopes.
325ffd83dbSDimitry Andric class IfDefScope {
335ffd83dbSDimitry Andric public:
IfDefScope(StringRef Name,raw_ostream & OS)345ffd83dbSDimitry Andric   IfDefScope(StringRef Name, raw_ostream &OS) : Name(Name), OS(OS) {
355ffd83dbSDimitry Andric     OS << "#ifdef " << Name << "\n"
365ffd83dbSDimitry Andric        << "#undef " << Name << "\n";
375ffd83dbSDimitry Andric   }
385ffd83dbSDimitry Andric 
~IfDefScope()395ffd83dbSDimitry Andric   ~IfDefScope() { OS << "\n#endif // " << Name << "\n\n"; }
405ffd83dbSDimitry Andric 
415ffd83dbSDimitry Andric private:
425ffd83dbSDimitry Andric   StringRef Name;
435ffd83dbSDimitry Andric   raw_ostream &OS;
445ffd83dbSDimitry Andric };
4506c3fb27SDimitry Andric } // namespace
465ffd83dbSDimitry Andric 
47*0fca6ea1SDimitry Andric // Generate enum class. Entries are emitted in the order in which they appear
48*0fca6ea1SDimitry Andric // in the `Records` vector.
GenerateEnumClass(const std::vector<Record * > & Records,raw_ostream & OS,StringRef Enum,StringRef Prefix,const DirectiveLanguage & DirLang,bool ExportEnums)4906c3fb27SDimitry Andric static void GenerateEnumClass(const std::vector<Record *> &Records,
5006c3fb27SDimitry Andric                               raw_ostream &OS, StringRef Enum, StringRef Prefix,
51*0fca6ea1SDimitry Andric                               const DirectiveLanguage &DirLang,
52*0fca6ea1SDimitry Andric                               bool ExportEnums) {
535ffd83dbSDimitry Andric   OS << "\n";
545ffd83dbSDimitry Andric   OS << "enum class " << Enum << " {\n";
555ffd83dbSDimitry Andric   for (const auto &R : Records) {
56e8d8bef9SDimitry Andric     BaseRecord Rec{R};
57e8d8bef9SDimitry Andric     OS << "  " << Prefix << Rec.getFormattedName() << ",\n";
585ffd83dbSDimitry Andric   }
595ffd83dbSDimitry Andric   OS << "};\n";
605ffd83dbSDimitry Andric   OS << "\n";
615ffd83dbSDimitry Andric   OS << "static constexpr std::size_t " << Enum
625ffd83dbSDimitry Andric      << "_enumSize = " << Records.size() << ";\n";
635ffd83dbSDimitry Andric 
645ffd83dbSDimitry Andric   // Make the enum values available in the defined namespace. This allows us to
655ffd83dbSDimitry Andric   // write something like Enum_X if we have a `using namespace <CppNamespace>`.
665ffd83dbSDimitry Andric   // At the same time we do not loose the strong type guarantees of the enum
675ffd83dbSDimitry Andric   // class, that is we cannot pass an unsigned as Directive without an explicit
685ffd83dbSDimitry Andric   // cast.
69*0fca6ea1SDimitry Andric   if (ExportEnums) {
705ffd83dbSDimitry Andric     OS << "\n";
715ffd83dbSDimitry Andric     for (const auto &R : Records) {
72e8d8bef9SDimitry Andric       BaseRecord Rec{R};
73e8d8bef9SDimitry Andric       OS << "constexpr auto " << Prefix << Rec.getFormattedName() << " = "
74e8d8bef9SDimitry Andric          << "llvm::" << DirLang.getCppNamespace() << "::" << Enum
75e8d8bef9SDimitry Andric          << "::" << Prefix << Rec.getFormattedName() << ";\n";
765ffd83dbSDimitry Andric     }
775ffd83dbSDimitry Andric   }
785ffd83dbSDimitry Andric }
795ffd83dbSDimitry Andric 
80e8d8bef9SDimitry Andric // Generate enums for values that clauses can take.
81e8d8bef9SDimitry Andric // Also generate function declarations for get<Enum>Name(StringRef Str).
GenerateEnumClauseVal(const std::vector<Record * > & Records,raw_ostream & OS,const DirectiveLanguage & DirLang,std::string & EnumHelperFuncs)8206c3fb27SDimitry Andric static void GenerateEnumClauseVal(const std::vector<Record *> &Records,
8306c3fb27SDimitry Andric                                   raw_ostream &OS,
8406c3fb27SDimitry Andric                                   const DirectiveLanguage &DirLang,
85e8d8bef9SDimitry Andric                                   std::string &EnumHelperFuncs) {
86e8d8bef9SDimitry Andric   for (const auto &R : Records) {
87e8d8bef9SDimitry Andric     Clause C{R};
88e8d8bef9SDimitry Andric     const auto &ClauseVals = C.getClauseVals();
89e8d8bef9SDimitry Andric     if (ClauseVals.size() <= 0)
90e8d8bef9SDimitry Andric       continue;
91e8d8bef9SDimitry Andric 
92e8d8bef9SDimitry Andric     const auto &EnumName = C.getEnumName();
93e8d8bef9SDimitry Andric     if (EnumName.size() == 0) {
94e8d8bef9SDimitry Andric       PrintError("enumClauseValue field not set in Clause" +
95e8d8bef9SDimitry Andric                  C.getFormattedName() + ".");
96e8d8bef9SDimitry Andric       return;
97e8d8bef9SDimitry Andric     }
98e8d8bef9SDimitry Andric 
99e8d8bef9SDimitry Andric     OS << "\n";
100e8d8bef9SDimitry Andric     OS << "enum class " << EnumName << " {\n";
101e8d8bef9SDimitry Andric     for (const auto &CV : ClauseVals) {
102e8d8bef9SDimitry Andric       ClauseVal CVal{CV};
103e8d8bef9SDimitry Andric       OS << "  " << CV->getName() << "=" << CVal.getValue() << ",\n";
104e8d8bef9SDimitry Andric     }
105e8d8bef9SDimitry Andric     OS << "};\n";
106e8d8bef9SDimitry Andric 
107e8d8bef9SDimitry Andric     if (DirLang.hasMakeEnumAvailableInNamespace()) {
108e8d8bef9SDimitry Andric       OS << "\n";
109e8d8bef9SDimitry Andric       for (const auto &CV : ClauseVals) {
110e8d8bef9SDimitry Andric         OS << "constexpr auto " << CV->getName() << " = "
111e8d8bef9SDimitry Andric            << "llvm::" << DirLang.getCppNamespace() << "::" << EnumName
112e8d8bef9SDimitry Andric            << "::" << CV->getName() << ";\n";
113e8d8bef9SDimitry Andric       }
114e8d8bef9SDimitry Andric       EnumHelperFuncs += (llvm::Twine(EnumName) + llvm::Twine(" get") +
115e8d8bef9SDimitry Andric                           llvm::Twine(EnumName) + llvm::Twine("(StringRef);\n"))
116e8d8bef9SDimitry Andric                              .str();
117e8d8bef9SDimitry Andric 
118e8d8bef9SDimitry Andric       EnumHelperFuncs +=
119e8d8bef9SDimitry Andric           (llvm::Twine("llvm::StringRef get") + llvm::Twine(DirLang.getName()) +
120e8d8bef9SDimitry Andric            llvm::Twine(EnumName) + llvm::Twine("Name(") +
121e8d8bef9SDimitry Andric            llvm::Twine(EnumName) + llvm::Twine(");\n"))
122e8d8bef9SDimitry Andric               .str();
123e8d8bef9SDimitry Andric     }
124e8d8bef9SDimitry Andric   }
125e8d8bef9SDimitry Andric }
126e8d8bef9SDimitry Andric 
HasDuplicateClauses(const std::vector<Record * > & Clauses,const Directive & Directive,llvm::StringSet<> & CrtClauses)12706c3fb27SDimitry Andric static bool HasDuplicateClauses(const std::vector<Record *> &Clauses,
128e8d8bef9SDimitry Andric                                 const Directive &Directive,
129e8d8bef9SDimitry Andric                                 llvm::StringSet<> &CrtClauses) {
130e8d8bef9SDimitry Andric   bool HasError = false;
131e8d8bef9SDimitry Andric   for (const auto &C : Clauses) {
132e8d8bef9SDimitry Andric     VersionedClause VerClause{C};
133e8d8bef9SDimitry Andric     const auto insRes = CrtClauses.insert(VerClause.getClause().getName());
134e8d8bef9SDimitry Andric     if (!insRes.second) {
135e8d8bef9SDimitry Andric       PrintError("Clause " + VerClause.getClause().getRecordName() +
136e8d8bef9SDimitry Andric                  " already defined on directive " + Directive.getRecordName());
137e8d8bef9SDimitry Andric       HasError = true;
138e8d8bef9SDimitry Andric     }
139e8d8bef9SDimitry Andric   }
140e8d8bef9SDimitry Andric   return HasError;
141e8d8bef9SDimitry Andric }
142e8d8bef9SDimitry Andric 
143e8d8bef9SDimitry Andric // Check for duplicate clauses in lists. Clauses cannot appear twice in the
144e8d8bef9SDimitry Andric // three allowed list. Also, since required implies allowed, clauses cannot
145e8d8bef9SDimitry Andric // appear in both the allowedClauses and requiredClauses lists.
14606c3fb27SDimitry Andric static bool
HasDuplicateClausesInDirectives(const std::vector<Record * > & Directives)14706c3fb27SDimitry Andric HasDuplicateClausesInDirectives(const std::vector<Record *> &Directives) {
148e8d8bef9SDimitry Andric   bool HasDuplicate = false;
149e8d8bef9SDimitry Andric   for (const auto &D : Directives) {
150e8d8bef9SDimitry Andric     Directive Dir{D};
151e8d8bef9SDimitry Andric     llvm::StringSet<> Clauses;
152e8d8bef9SDimitry Andric     // Check for duplicates in the three allowed lists.
153e8d8bef9SDimitry Andric     if (HasDuplicateClauses(Dir.getAllowedClauses(), Dir, Clauses) ||
154e8d8bef9SDimitry Andric         HasDuplicateClauses(Dir.getAllowedOnceClauses(), Dir, Clauses) ||
155e8d8bef9SDimitry Andric         HasDuplicateClauses(Dir.getAllowedExclusiveClauses(), Dir, Clauses)) {
156e8d8bef9SDimitry Andric       HasDuplicate = true;
157e8d8bef9SDimitry Andric     }
158e8d8bef9SDimitry Andric     // Check for duplicate between allowedClauses and required
159e8d8bef9SDimitry Andric     Clauses.clear();
160e8d8bef9SDimitry Andric     if (HasDuplicateClauses(Dir.getAllowedClauses(), Dir, Clauses) ||
161e8d8bef9SDimitry Andric         HasDuplicateClauses(Dir.getRequiredClauses(), Dir, Clauses)) {
162e8d8bef9SDimitry Andric       HasDuplicate = true;
163e8d8bef9SDimitry Andric     }
164e8d8bef9SDimitry Andric     if (HasDuplicate)
165e8d8bef9SDimitry Andric       PrintFatalError("One or more clauses are defined multiple times on"
166e8d8bef9SDimitry Andric                       " directive " +
167e8d8bef9SDimitry Andric                       Dir.getRecordName());
168e8d8bef9SDimitry Andric   }
169e8d8bef9SDimitry Andric 
170e8d8bef9SDimitry Andric   return HasDuplicate;
171e8d8bef9SDimitry Andric }
172e8d8bef9SDimitry Andric 
173e8d8bef9SDimitry Andric // Check consitency of records. Return true if an error has been detected.
174e8d8bef9SDimitry Andric // Return false if the records are valid.
HasValidityErrors() const175e8d8bef9SDimitry Andric bool DirectiveLanguage::HasValidityErrors() const {
176e8d8bef9SDimitry Andric   if (getDirectiveLanguages().size() != 1) {
177e8d8bef9SDimitry Andric     PrintFatalError("A single definition of DirectiveLanguage is needed.");
178e8d8bef9SDimitry Andric     return true;
179e8d8bef9SDimitry Andric   }
180e8d8bef9SDimitry Andric 
181e8d8bef9SDimitry Andric   return HasDuplicateClausesInDirectives(getDirectives());
182e8d8bef9SDimitry Andric }
183e8d8bef9SDimitry Andric 
184*0fca6ea1SDimitry Andric // Count the maximum number of leaf constituents per construct.
GetMaxLeafCount(const DirectiveLanguage & DirLang)185*0fca6ea1SDimitry Andric static size_t GetMaxLeafCount(const DirectiveLanguage &DirLang) {
186*0fca6ea1SDimitry Andric   size_t MaxCount = 0;
187*0fca6ea1SDimitry Andric   for (Record *R : DirLang.getDirectives()) {
188*0fca6ea1SDimitry Andric     size_t Count = Directive{R}.getLeafConstructs().size();
189*0fca6ea1SDimitry Andric     MaxCount = std::max(MaxCount, Count);
190*0fca6ea1SDimitry Andric   }
191*0fca6ea1SDimitry Andric   return MaxCount;
192*0fca6ea1SDimitry Andric }
193*0fca6ea1SDimitry Andric 
1945ffd83dbSDimitry Andric // Generate the declaration section for the enumeration in the directive
1955ffd83dbSDimitry Andric // language
EmitDirectivesDecl(RecordKeeper & Records,raw_ostream & OS)19606c3fb27SDimitry Andric static void EmitDirectivesDecl(RecordKeeper &Records, raw_ostream &OS) {
197e8d8bef9SDimitry Andric   const auto DirLang = DirectiveLanguage{Records};
198e8d8bef9SDimitry Andric   if (DirLang.HasValidityErrors())
1995ffd83dbSDimitry Andric     return;
2005ffd83dbSDimitry Andric 
201e8d8bef9SDimitry Andric   OS << "#ifndef LLVM_" << DirLang.getName() << "_INC\n";
202e8d8bef9SDimitry Andric   OS << "#define LLVM_" << DirLang.getName() << "_INC\n";
203*0fca6ea1SDimitry Andric   OS << "\n#include \"llvm/ADT/ArrayRef.h\"\n";
2045ffd83dbSDimitry Andric 
205e8d8bef9SDimitry Andric   if (DirLang.hasEnableBitmaskEnumInNamespace())
206*0fca6ea1SDimitry Andric     OS << "#include \"llvm/ADT/BitmaskEnum.h\"\n";
2075ffd83dbSDimitry Andric 
208*0fca6ea1SDimitry Andric   OS << "#include <cstddef>\n"; // for size_t
2095ffd83dbSDimitry Andric   OS << "\n";
2105ffd83dbSDimitry Andric   OS << "namespace llvm {\n";
2115ffd83dbSDimitry Andric   OS << "class StringRef;\n";
2125ffd83dbSDimitry Andric 
2135ffd83dbSDimitry Andric   // Open namespaces defined in the directive language
2145ffd83dbSDimitry Andric   llvm::SmallVector<StringRef, 2> Namespaces;
215e8d8bef9SDimitry Andric   llvm::SplitString(DirLang.getCppNamespace(), Namespaces, "::");
2165ffd83dbSDimitry Andric   for (auto Ns : Namespaces)
2175ffd83dbSDimitry Andric     OS << "namespace " << Ns << " {\n";
2185ffd83dbSDimitry Andric 
219e8d8bef9SDimitry Andric   if (DirLang.hasEnableBitmaskEnumInNamespace())
2205ffd83dbSDimitry Andric     OS << "\nLLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();\n";
2215ffd83dbSDimitry Andric 
222*0fca6ea1SDimitry Andric   // Emit Directive associations
223*0fca6ea1SDimitry Andric   std::vector<Record *> associations;
224*0fca6ea1SDimitry Andric   llvm::copy_if(
225*0fca6ea1SDimitry Andric       DirLang.getAssociations(), std::back_inserter(associations),
226*0fca6ea1SDimitry Andric       // Skip the "special" value
227*0fca6ea1SDimitry Andric       [](const Record *Def) { return Def->getName() != "AS_FromLeaves"; });
228*0fca6ea1SDimitry Andric   GenerateEnumClass(associations, OS, "Association",
229*0fca6ea1SDimitry Andric                     /*Prefix=*/"", DirLang, /*ExportEnums=*/false);
230*0fca6ea1SDimitry Andric 
231*0fca6ea1SDimitry Andric   GenerateEnumClass(DirLang.getCategories(), OS, "Category", /*Prefix=*/"",
232*0fca6ea1SDimitry Andric                     DirLang, /*ExportEnums=*/false);
233*0fca6ea1SDimitry Andric 
2345ffd83dbSDimitry Andric   // Emit Directive enumeration
235e8d8bef9SDimitry Andric   GenerateEnumClass(DirLang.getDirectives(), OS, "Directive",
236*0fca6ea1SDimitry Andric                     DirLang.getDirectivePrefix(), DirLang,
237*0fca6ea1SDimitry Andric                     DirLang.hasMakeEnumAvailableInNamespace());
2385ffd83dbSDimitry Andric 
2395ffd83dbSDimitry Andric   // Emit Clause enumeration
240e8d8bef9SDimitry Andric   GenerateEnumClass(DirLang.getClauses(), OS, "Clause",
241*0fca6ea1SDimitry Andric                     DirLang.getClausePrefix(), DirLang,
242*0fca6ea1SDimitry Andric                     DirLang.hasMakeEnumAvailableInNamespace());
243e8d8bef9SDimitry Andric 
244e8d8bef9SDimitry Andric   // Emit ClauseVal enumeration
245e8d8bef9SDimitry Andric   std::string EnumHelperFuncs;
246e8d8bef9SDimitry Andric   GenerateEnumClauseVal(DirLang.getClauses(), OS, DirLang, EnumHelperFuncs);
2475ffd83dbSDimitry Andric 
2485ffd83dbSDimitry Andric   // Generic function signatures
2495ffd83dbSDimitry Andric   OS << "\n";
2505ffd83dbSDimitry Andric   OS << "// Enumeration helper functions\n";
251e8d8bef9SDimitry Andric   OS << "Directive get" << DirLang.getName()
2525ffd83dbSDimitry Andric      << "DirectiveKind(llvm::StringRef Str);\n";
2535ffd83dbSDimitry Andric   OS << "\n";
254e8d8bef9SDimitry Andric   OS << "llvm::StringRef get" << DirLang.getName()
2555ffd83dbSDimitry Andric      << "DirectiveName(Directive D);\n";
2565ffd83dbSDimitry Andric   OS << "\n";
257e8d8bef9SDimitry Andric   OS << "Clause get" << DirLang.getName()
258e8d8bef9SDimitry Andric      << "ClauseKind(llvm::StringRef Str);\n";
2595ffd83dbSDimitry Andric   OS << "\n";
260e8d8bef9SDimitry Andric   OS << "llvm::StringRef get" << DirLang.getName() << "ClauseName(Clause C);\n";
2615ffd83dbSDimitry Andric   OS << "\n";
2625ffd83dbSDimitry Andric   OS << "/// Return true if \\p C is a valid clause for \\p D in version \\p "
2635ffd83dbSDimitry Andric      << "Version.\n";
2645ffd83dbSDimitry Andric   OS << "bool isAllowedClauseForDirective(Directive D, "
2655ffd83dbSDimitry Andric      << "Clause C, unsigned Version);\n";
2665ffd83dbSDimitry Andric   OS << "\n";
267*0fca6ea1SDimitry Andric   OS << "constexpr std::size_t getMaxLeafCount() { return "
268*0fca6ea1SDimitry Andric      << GetMaxLeafCount(DirLang) << "; }\n";
269*0fca6ea1SDimitry Andric   OS << "Association getDirectiveAssociation(Directive D);\n";
270*0fca6ea1SDimitry Andric   OS << "Category getDirectiveCategory(Directive D);\n";
271e8d8bef9SDimitry Andric   if (EnumHelperFuncs.length() > 0) {
272e8d8bef9SDimitry Andric     OS << EnumHelperFuncs;
273e8d8bef9SDimitry Andric     OS << "\n";
274e8d8bef9SDimitry Andric   }
2755ffd83dbSDimitry Andric 
2765ffd83dbSDimitry Andric   // Closing namespaces
2775ffd83dbSDimitry Andric   for (auto Ns : llvm::reverse(Namespaces))
2785ffd83dbSDimitry Andric     OS << "} // namespace " << Ns << "\n";
2795ffd83dbSDimitry Andric 
2805ffd83dbSDimitry Andric   OS << "} // namespace llvm\n";
2815ffd83dbSDimitry Andric 
282e8d8bef9SDimitry Andric   OS << "#endif // LLVM_" << DirLang.getName() << "_INC\n";
2835ffd83dbSDimitry Andric }
2845ffd83dbSDimitry Andric 
2855ffd83dbSDimitry Andric // Generate function implementation for get<Enum>Name(StringRef Str)
GenerateGetName(const std::vector<Record * > & Records,raw_ostream & OS,StringRef Enum,const DirectiveLanguage & DirLang,StringRef Prefix)28606c3fb27SDimitry Andric static void GenerateGetName(const std::vector<Record *> &Records,
28706c3fb27SDimitry Andric                             raw_ostream &OS, StringRef Enum,
28806c3fb27SDimitry Andric                             const DirectiveLanguage &DirLang,
289e8d8bef9SDimitry Andric                             StringRef Prefix) {
2905ffd83dbSDimitry Andric   OS << "\n";
291e8d8bef9SDimitry Andric   OS << "llvm::StringRef llvm::" << DirLang.getCppNamespace() << "::get"
292e8d8bef9SDimitry Andric      << DirLang.getName() << Enum << "Name(" << Enum << " Kind) {\n";
2935ffd83dbSDimitry Andric   OS << "  switch (Kind) {\n";
2945ffd83dbSDimitry Andric   for (const auto &R : Records) {
295e8d8bef9SDimitry Andric     BaseRecord Rec{R};
296e8d8bef9SDimitry Andric     OS << "    case " << Prefix << Rec.getFormattedName() << ":\n";
2975ffd83dbSDimitry Andric     OS << "      return \"";
298e8d8bef9SDimitry Andric     if (Rec.getAlternativeName().empty())
299e8d8bef9SDimitry Andric       OS << Rec.getName();
3005ffd83dbSDimitry Andric     else
301e8d8bef9SDimitry Andric       OS << Rec.getAlternativeName();
3025ffd83dbSDimitry Andric     OS << "\";\n";
3035ffd83dbSDimitry Andric   }
3045ffd83dbSDimitry Andric   OS << "  }\n"; // switch
305e8d8bef9SDimitry Andric   OS << "  llvm_unreachable(\"Invalid " << DirLang.getName() << " " << Enum
3065ffd83dbSDimitry Andric      << " kind\");\n";
3075ffd83dbSDimitry Andric   OS << "}\n";
3085ffd83dbSDimitry Andric }
3095ffd83dbSDimitry Andric 
3105ffd83dbSDimitry Andric // Generate function implementation for get<Enum>Kind(StringRef Str)
GenerateGetKind(const std::vector<Record * > & Records,raw_ostream & OS,StringRef Enum,const DirectiveLanguage & DirLang,StringRef Prefix,bool ImplicitAsUnknown)31106c3fb27SDimitry Andric static void GenerateGetKind(const std::vector<Record *> &Records,
31206c3fb27SDimitry Andric                             raw_ostream &OS, StringRef Enum,
31306c3fb27SDimitry Andric                             const DirectiveLanguage &DirLang, StringRef Prefix,
31406c3fb27SDimitry Andric                             bool ImplicitAsUnknown) {
3155ffd83dbSDimitry Andric 
316e8d8bef9SDimitry Andric   auto DefaultIt = llvm::find_if(
317e8d8bef9SDimitry Andric       Records, [](Record *R) { return R->getValueAsBit("isDefault") == true; });
3185ffd83dbSDimitry Andric 
3195ffd83dbSDimitry Andric   if (DefaultIt == Records.end()) {
320e8d8bef9SDimitry Andric     PrintError("At least one " + Enum + " must be defined as default.");
3215ffd83dbSDimitry Andric     return;
3225ffd83dbSDimitry Andric   }
3235ffd83dbSDimitry Andric 
324e8d8bef9SDimitry Andric   BaseRecord DefaultRec{(*DefaultIt)};
3255ffd83dbSDimitry Andric 
3265ffd83dbSDimitry Andric   OS << "\n";
327e8d8bef9SDimitry Andric   OS << Enum << " llvm::" << DirLang.getCppNamespace() << "::get"
328e8d8bef9SDimitry Andric      << DirLang.getName() << Enum << "Kind(llvm::StringRef Str) {\n";
3295ffd83dbSDimitry Andric   OS << "  return llvm::StringSwitch<" << Enum << ">(Str)\n";
3305ffd83dbSDimitry Andric 
3315ffd83dbSDimitry Andric   for (const auto &R : Records) {
332e8d8bef9SDimitry Andric     BaseRecord Rec{R};
3335ffd83dbSDimitry Andric     if (ImplicitAsUnknown && R->getValueAsBit("isImplicit")) {
334e8d8bef9SDimitry Andric       OS << "    .Case(\"" << Rec.getName() << "\"," << Prefix
335e8d8bef9SDimitry Andric          << DefaultRec.getFormattedName() << ")\n";
3365ffd83dbSDimitry Andric     } else {
337e8d8bef9SDimitry Andric       OS << "    .Case(\"" << Rec.getName() << "\"," << Prefix
338e8d8bef9SDimitry Andric          << Rec.getFormattedName() << ")\n";
339e8d8bef9SDimitry Andric     }
340e8d8bef9SDimitry Andric   }
341e8d8bef9SDimitry Andric   OS << "    .Default(" << Prefix << DefaultRec.getFormattedName() << ");\n";
342e8d8bef9SDimitry Andric   OS << "}\n";
343e8d8bef9SDimitry Andric }
344e8d8bef9SDimitry Andric 
345e8d8bef9SDimitry Andric // Generate function implementation for get<ClauseVal>Kind(StringRef Str)
GenerateGetKindClauseVal(const DirectiveLanguage & DirLang,raw_ostream & OS)34606c3fb27SDimitry Andric static void GenerateGetKindClauseVal(const DirectiveLanguage &DirLang,
347e8d8bef9SDimitry Andric                                      raw_ostream &OS) {
348e8d8bef9SDimitry Andric   for (const auto &R : DirLang.getClauses()) {
349e8d8bef9SDimitry Andric     Clause C{R};
350e8d8bef9SDimitry Andric     const auto &ClauseVals = C.getClauseVals();
351e8d8bef9SDimitry Andric     if (ClauseVals.size() <= 0)
352e8d8bef9SDimitry Andric       continue;
353e8d8bef9SDimitry Andric 
354e8d8bef9SDimitry Andric     auto DefaultIt = llvm::find_if(ClauseVals, [](Record *CV) {
355e8d8bef9SDimitry Andric       return CV->getValueAsBit("isDefault") == true;
356e8d8bef9SDimitry Andric     });
357e8d8bef9SDimitry Andric 
358e8d8bef9SDimitry Andric     if (DefaultIt == ClauseVals.end()) {
359e8d8bef9SDimitry Andric       PrintError("At least one val in Clause " + C.getFormattedName() +
360e8d8bef9SDimitry Andric                  " must be defined as default.");
361e8d8bef9SDimitry Andric       return;
362e8d8bef9SDimitry Andric     }
363e8d8bef9SDimitry Andric     const auto DefaultName = (*DefaultIt)->getName();
364e8d8bef9SDimitry Andric 
365e8d8bef9SDimitry Andric     const auto &EnumName = C.getEnumName();
366e8d8bef9SDimitry Andric     if (EnumName.size() == 0) {
367e8d8bef9SDimitry Andric       PrintError("enumClauseValue field not set in Clause" +
368e8d8bef9SDimitry Andric                  C.getFormattedName() + ".");
369e8d8bef9SDimitry Andric       return;
370e8d8bef9SDimitry Andric     }
371e8d8bef9SDimitry Andric 
372e8d8bef9SDimitry Andric     OS << "\n";
373e8d8bef9SDimitry Andric     OS << EnumName << " llvm::" << DirLang.getCppNamespace() << "::get"
374e8d8bef9SDimitry Andric        << EnumName << "(llvm::StringRef Str) {\n";
375e8d8bef9SDimitry Andric     OS << "  return llvm::StringSwitch<" << EnumName << ">(Str)\n";
376e8d8bef9SDimitry Andric     for (const auto &CV : ClauseVals) {
377e8d8bef9SDimitry Andric       ClauseVal CVal{CV};
378e8d8bef9SDimitry Andric       OS << "    .Case(\"" << CVal.getFormattedName() << "\"," << CV->getName()
3795ffd83dbSDimitry Andric          << ")\n";
3805ffd83dbSDimitry Andric     }
381e8d8bef9SDimitry Andric     OS << "    .Default(" << DefaultName << ");\n";
3825ffd83dbSDimitry Andric     OS << "}\n";
383e8d8bef9SDimitry Andric 
384e8d8bef9SDimitry Andric     OS << "\n";
385e8d8bef9SDimitry Andric     OS << "llvm::StringRef llvm::" << DirLang.getCppNamespace() << "::get"
386e8d8bef9SDimitry Andric        << DirLang.getName() << EnumName
387e8d8bef9SDimitry Andric        << "Name(llvm::" << DirLang.getCppNamespace() << "::" << EnumName
388e8d8bef9SDimitry Andric        << " x) {\n";
389e8d8bef9SDimitry Andric     OS << "  switch (x) {\n";
390e8d8bef9SDimitry Andric     for (const auto &CV : ClauseVals) {
391e8d8bef9SDimitry Andric       ClauseVal CVal{CV};
392e8d8bef9SDimitry Andric       OS << "    case " << CV->getName() << ":\n";
393e8d8bef9SDimitry Andric       OS << "      return \"" << CVal.getFormattedName() << "\";\n";
394e8d8bef9SDimitry Andric     }
395e8d8bef9SDimitry Andric     OS << "  }\n"; // switch
396e8d8bef9SDimitry Andric     OS << "  llvm_unreachable(\"Invalid " << DirLang.getName() << " "
397e8d8bef9SDimitry Andric        << EnumName << " kind\");\n";
398e8d8bef9SDimitry Andric     OS << "}\n";
399e8d8bef9SDimitry Andric   }
4005ffd83dbSDimitry Andric }
4015ffd83dbSDimitry Andric 
40206c3fb27SDimitry Andric static void
GenerateCaseForVersionedClauses(const std::vector<Record * > & Clauses,raw_ostream & OS,StringRef DirectiveName,const DirectiveLanguage & DirLang,llvm::StringSet<> & Cases)40306c3fb27SDimitry Andric GenerateCaseForVersionedClauses(const std::vector<Record *> &Clauses,
4045ffd83dbSDimitry Andric                                 raw_ostream &OS, StringRef DirectiveName,
405e8d8bef9SDimitry Andric                                 const DirectiveLanguage &DirLang,
4065ffd83dbSDimitry Andric                                 llvm::StringSet<> &Cases) {
4075ffd83dbSDimitry Andric   for (const auto &C : Clauses) {
408e8d8bef9SDimitry Andric     VersionedClause VerClause{C};
4095ffd83dbSDimitry Andric 
410e8d8bef9SDimitry Andric     const auto ClauseFormattedName = VerClause.getClause().getFormattedName();
411e8d8bef9SDimitry Andric 
41281ad6265SDimitry Andric     if (Cases.insert(ClauseFormattedName).second) {
413e8d8bef9SDimitry Andric       OS << "        case " << DirLang.getClausePrefix() << ClauseFormattedName
414e8d8bef9SDimitry Andric          << ":\n";
415e8d8bef9SDimitry Andric       OS << "          return " << VerClause.getMinVersion()
416e8d8bef9SDimitry Andric          << " <= Version && " << VerClause.getMaxVersion() << " >= Version;\n";
4175ffd83dbSDimitry Andric     }
4185ffd83dbSDimitry Andric   }
4195ffd83dbSDimitry Andric }
4205ffd83dbSDimitry Andric 
GetDirectiveName(const DirectiveLanguage & DirLang,const Record * Rec)421*0fca6ea1SDimitry Andric static std::string GetDirectiveName(const DirectiveLanguage &DirLang,
422*0fca6ea1SDimitry Andric                                     const Record *Rec) {
423*0fca6ea1SDimitry Andric   Directive Dir{Rec};
424*0fca6ea1SDimitry Andric   return (llvm::Twine("llvm::") + DirLang.getCppNamespace() +
425*0fca6ea1SDimitry Andric           "::" + DirLang.getDirectivePrefix() + Dir.getFormattedName())
426*0fca6ea1SDimitry Andric       .str();
427*0fca6ea1SDimitry Andric }
428*0fca6ea1SDimitry Andric 
GetDirectiveType(const DirectiveLanguage & DirLang)429*0fca6ea1SDimitry Andric static std::string GetDirectiveType(const DirectiveLanguage &DirLang) {
430*0fca6ea1SDimitry Andric   return (llvm::Twine("llvm::") + DirLang.getCppNamespace() + "::Directive")
431*0fca6ea1SDimitry Andric       .str();
432*0fca6ea1SDimitry Andric }
433*0fca6ea1SDimitry Andric 
4345ffd83dbSDimitry Andric // Generate the isAllowedClauseForDirective function implementation.
GenerateIsAllowedClause(const DirectiveLanguage & DirLang,raw_ostream & OS)43506c3fb27SDimitry Andric static void GenerateIsAllowedClause(const DirectiveLanguage &DirLang,
436e8d8bef9SDimitry Andric                                     raw_ostream &OS) {
4375ffd83dbSDimitry Andric   OS << "\n";
438e8d8bef9SDimitry Andric   OS << "bool llvm::" << DirLang.getCppNamespace()
439e8d8bef9SDimitry Andric      << "::isAllowedClauseForDirective("
4405ffd83dbSDimitry Andric      << "Directive D, Clause C, unsigned Version) {\n";
441e8d8bef9SDimitry Andric   OS << "  assert(unsigned(D) <= llvm::" << DirLang.getCppNamespace()
4425ffd83dbSDimitry Andric      << "::Directive_enumSize);\n";
443e8d8bef9SDimitry Andric   OS << "  assert(unsigned(C) <= llvm::" << DirLang.getCppNamespace()
4445ffd83dbSDimitry Andric      << "::Clause_enumSize);\n";
4455ffd83dbSDimitry Andric 
4465ffd83dbSDimitry Andric   OS << "  switch (D) {\n";
4475ffd83dbSDimitry Andric 
448e8d8bef9SDimitry Andric   for (const auto &D : DirLang.getDirectives()) {
449e8d8bef9SDimitry Andric     Directive Dir{D};
4505ffd83dbSDimitry Andric 
451e8d8bef9SDimitry Andric     OS << "    case " << DirLang.getDirectivePrefix() << Dir.getFormattedName()
4525ffd83dbSDimitry Andric        << ":\n";
453e8d8bef9SDimitry Andric     if (Dir.getAllowedClauses().size() == 0 &&
454e8d8bef9SDimitry Andric         Dir.getAllowedOnceClauses().size() == 0 &&
455e8d8bef9SDimitry Andric         Dir.getAllowedExclusiveClauses().size() == 0 &&
456e8d8bef9SDimitry Andric         Dir.getRequiredClauses().size() == 0) {
4575ffd83dbSDimitry Andric       OS << "      return false;\n";
4585ffd83dbSDimitry Andric     } else {
4595ffd83dbSDimitry Andric       OS << "      switch (C) {\n";
4605ffd83dbSDimitry Andric 
4615ffd83dbSDimitry Andric       llvm::StringSet<> Cases;
4625ffd83dbSDimitry Andric 
463e8d8bef9SDimitry Andric       GenerateCaseForVersionedClauses(Dir.getAllowedClauses(), OS,
464e8d8bef9SDimitry Andric                                       Dir.getName(), DirLang, Cases);
4655ffd83dbSDimitry Andric 
466e8d8bef9SDimitry Andric       GenerateCaseForVersionedClauses(Dir.getAllowedOnceClauses(), OS,
467e8d8bef9SDimitry Andric                                       Dir.getName(), DirLang, Cases);
4685ffd83dbSDimitry Andric 
469e8d8bef9SDimitry Andric       GenerateCaseForVersionedClauses(Dir.getAllowedExclusiveClauses(), OS,
470e8d8bef9SDimitry Andric                                       Dir.getName(), DirLang, Cases);
4715ffd83dbSDimitry Andric 
472e8d8bef9SDimitry Andric       GenerateCaseForVersionedClauses(Dir.getRequiredClauses(), OS,
473e8d8bef9SDimitry Andric                                       Dir.getName(), DirLang, Cases);
4745ffd83dbSDimitry Andric 
4755ffd83dbSDimitry Andric       OS << "        default:\n";
4765ffd83dbSDimitry Andric       OS << "          return false;\n";
4775ffd83dbSDimitry Andric       OS << "      }\n"; // End of clauses switch
4785ffd83dbSDimitry Andric     }
4795ffd83dbSDimitry Andric     OS << "      break;\n";
4805ffd83dbSDimitry Andric   }
4815ffd83dbSDimitry Andric 
4825ffd83dbSDimitry Andric   OS << "  }\n"; // End of directives switch
483e8d8bef9SDimitry Andric   OS << "  llvm_unreachable(\"Invalid " << DirLang.getName()
4845ffd83dbSDimitry Andric      << " Directive kind\");\n";
4855ffd83dbSDimitry Andric   OS << "}\n"; // End of function isAllowedClauseForDirective
4865ffd83dbSDimitry Andric }
4875ffd83dbSDimitry Andric 
EmitLeafTable(const DirectiveLanguage & DirLang,raw_ostream & OS,StringRef TableName)488*0fca6ea1SDimitry Andric static void EmitLeafTable(const DirectiveLanguage &DirLang, raw_ostream &OS,
489*0fca6ea1SDimitry Andric                           StringRef TableName) {
490*0fca6ea1SDimitry Andric   // The leaf constructs are emitted in a form of a 2D table, where each
491*0fca6ea1SDimitry Andric   // row corresponds to a directive (and there is a row for each directive).
492*0fca6ea1SDimitry Andric   //
493*0fca6ea1SDimitry Andric   // Each row consists of
494*0fca6ea1SDimitry Andric   // - the id of the directive itself,
495*0fca6ea1SDimitry Andric   // - number of leaf constructs that will follow (0 for leafs),
496*0fca6ea1SDimitry Andric   // - ids of the leaf constructs (none if the directive is itself a leaf).
497*0fca6ea1SDimitry Andric   // The total number of these entries is at most MaxLeafCount+2. If this
498*0fca6ea1SDimitry Andric   // number is less than that, it is padded to occupy exactly MaxLeafCount+2
499*0fca6ea1SDimitry Andric   // entries in memory.
500*0fca6ea1SDimitry Andric   //
501*0fca6ea1SDimitry Andric   // The rows are stored in the table in the lexicographical order. This
502*0fca6ea1SDimitry Andric   // is intended to enable binary search when mapping a sequence of leafs
503*0fca6ea1SDimitry Andric   // back to the compound directive.
504*0fca6ea1SDimitry Andric   // The consequence of that is that in order to find a row corresponding
505*0fca6ea1SDimitry Andric   // to the given directive, we'd need to scan the first element of each
506*0fca6ea1SDimitry Andric   // row. To avoid this, an auxiliary ordering table is created, such that
507*0fca6ea1SDimitry Andric   //   row for Dir_A = table[auxiliary[Dir_A]].
508*0fca6ea1SDimitry Andric 
509*0fca6ea1SDimitry Andric   std::vector<Record *> Directives = DirLang.getDirectives();
510*0fca6ea1SDimitry Andric   DenseMap<Record *, int> DirId; // Record * -> llvm::omp::Directive
511*0fca6ea1SDimitry Andric 
512*0fca6ea1SDimitry Andric   for (auto [Idx, Rec] : llvm::enumerate(Directives))
513*0fca6ea1SDimitry Andric     DirId.insert(std::make_pair(Rec, Idx));
514*0fca6ea1SDimitry Andric 
515*0fca6ea1SDimitry Andric   using LeafList = std::vector<int>;
516*0fca6ea1SDimitry Andric   int MaxLeafCount = GetMaxLeafCount(DirLang);
517*0fca6ea1SDimitry Andric 
518*0fca6ea1SDimitry Andric   // The initial leaf table, rows order is same as directive order.
519*0fca6ea1SDimitry Andric   std::vector<LeafList> LeafTable(Directives.size());
520*0fca6ea1SDimitry Andric   for (auto [Idx, Rec] : llvm::enumerate(Directives)) {
521*0fca6ea1SDimitry Andric     Directive Dir{Rec};
522*0fca6ea1SDimitry Andric     std::vector<Record *> Leaves = Dir.getLeafConstructs();
523*0fca6ea1SDimitry Andric 
524*0fca6ea1SDimitry Andric     auto &List = LeafTable[Idx];
525*0fca6ea1SDimitry Andric     List.resize(MaxLeafCount + 2);
526*0fca6ea1SDimitry Andric     List[0] = Idx;           // The id of the directive itself.
527*0fca6ea1SDimitry Andric     List[1] = Leaves.size(); // The number of leaves to follow.
528*0fca6ea1SDimitry Andric 
529*0fca6ea1SDimitry Andric     for (int I = 0; I != MaxLeafCount; ++I)
530*0fca6ea1SDimitry Andric       List[I + 2] =
531*0fca6ea1SDimitry Andric           static_cast<size_t>(I) < Leaves.size() ? DirId.at(Leaves[I]) : -1;
532*0fca6ea1SDimitry Andric   }
533*0fca6ea1SDimitry Andric 
534*0fca6ea1SDimitry Andric   // Some Fortran directives are delimited, i.e. they have the form of
535*0fca6ea1SDimitry Andric   // "directive"---"end directive". If "directive" is a compound construct,
536*0fca6ea1SDimitry Andric   // then the set of leaf constituents will be nonempty and the same for
537*0fca6ea1SDimitry Andric   // both directives. Given this set of leafs, looking up the corresponding
538*0fca6ea1SDimitry Andric   // compound directive should return "directive", and not "end directive".
539*0fca6ea1SDimitry Andric   // To avoid this problem, gather all "end directives" at the end of the
540*0fca6ea1SDimitry Andric   // leaf table, and only do the search on the initial segment of the table
541*0fca6ea1SDimitry Andric   // that excludes the "end directives".
542*0fca6ea1SDimitry Andric   // It's safe to find all directives whose names begin with "end ". The
543*0fca6ea1SDimitry Andric   // problem only exists for compound directives, like "end do simd".
544*0fca6ea1SDimitry Andric   // All existing directives with names starting with "end " are either
545*0fca6ea1SDimitry Andric   // "end directives" for an existing "directive", or leaf directives
546*0fca6ea1SDimitry Andric   // (such as "end declare target").
547*0fca6ea1SDimitry Andric   DenseSet<int> EndDirectives;
548*0fca6ea1SDimitry Andric   for (auto [Rec, Id] : DirId) {
549*0fca6ea1SDimitry Andric     if (Directive{Rec}.getName().starts_with_insensitive("end "))
550*0fca6ea1SDimitry Andric       EndDirectives.insert(Id);
551*0fca6ea1SDimitry Andric   }
552*0fca6ea1SDimitry Andric 
553*0fca6ea1SDimitry Andric   // Avoid sorting the vector<vector> array, instead sort an index array.
554*0fca6ea1SDimitry Andric   // It will also be useful later to create the auxiliary indexing array.
555*0fca6ea1SDimitry Andric   std::vector<int> Ordering(Directives.size());
556*0fca6ea1SDimitry Andric   std::iota(Ordering.begin(), Ordering.end(), 0);
557*0fca6ea1SDimitry Andric 
558*0fca6ea1SDimitry Andric   llvm::sort(Ordering, [&](int A, int B) {
559*0fca6ea1SDimitry Andric     auto &LeavesA = LeafTable[A];
560*0fca6ea1SDimitry Andric     auto &LeavesB = LeafTable[B];
561*0fca6ea1SDimitry Andric     int DirA = LeavesA[0], DirB = LeavesB[0];
562*0fca6ea1SDimitry Andric     // First of all, end directives compare greater than non-end directives.
563*0fca6ea1SDimitry Andric     int IsEndA = EndDirectives.count(DirA), IsEndB = EndDirectives.count(DirB);
564*0fca6ea1SDimitry Andric     if (IsEndA != IsEndB)
565*0fca6ea1SDimitry Andric       return IsEndA < IsEndB;
566*0fca6ea1SDimitry Andric     if (LeavesA[1] == 0 && LeavesB[1] == 0)
567*0fca6ea1SDimitry Andric       return DirA < DirB;
568*0fca6ea1SDimitry Andric     return std::lexicographical_compare(&LeavesA[2], &LeavesA[2] + LeavesA[1],
569*0fca6ea1SDimitry Andric                                         &LeavesB[2], &LeavesB[2] + LeavesB[1]);
570*0fca6ea1SDimitry Andric   });
571*0fca6ea1SDimitry Andric 
572*0fca6ea1SDimitry Andric   // Emit the table
573*0fca6ea1SDimitry Andric 
574*0fca6ea1SDimitry Andric   // The directives are emitted into a scoped enum, for which the underlying
575*0fca6ea1SDimitry Andric   // type is `int` (by default). The code above uses `int` to store directive
576*0fca6ea1SDimitry Andric   // ids, so make sure that we catch it when something changes in the
577*0fca6ea1SDimitry Andric   // underlying type.
578*0fca6ea1SDimitry Andric   std::string DirectiveType = GetDirectiveType(DirLang);
579*0fca6ea1SDimitry Andric   OS << "\nstatic_assert(sizeof(" << DirectiveType << ") == sizeof(int));\n";
580*0fca6ea1SDimitry Andric 
581*0fca6ea1SDimitry Andric   OS << "[[maybe_unused]] static const " << DirectiveType << ' ' << TableName
582*0fca6ea1SDimitry Andric      << "[][" << MaxLeafCount + 2 << "] = {\n";
583*0fca6ea1SDimitry Andric   for (size_t I = 0, E = Directives.size(); I != E; ++I) {
584*0fca6ea1SDimitry Andric     auto &Leaves = LeafTable[Ordering[I]];
585*0fca6ea1SDimitry Andric     OS << "    {" << GetDirectiveName(DirLang, Directives[Leaves[0]]);
586*0fca6ea1SDimitry Andric     OS << ", static_cast<" << DirectiveType << ">(" << Leaves[1] << "),";
587*0fca6ea1SDimitry Andric     for (size_t I = 2, E = Leaves.size(); I != E; ++I) {
588*0fca6ea1SDimitry Andric       int Idx = Leaves[I];
589*0fca6ea1SDimitry Andric       if (Idx >= 0)
590*0fca6ea1SDimitry Andric         OS << ' ' << GetDirectiveName(DirLang, Directives[Leaves[I]]) << ',';
591*0fca6ea1SDimitry Andric       else
592*0fca6ea1SDimitry Andric         OS << " static_cast<" << DirectiveType << ">(-1),";
593*0fca6ea1SDimitry Andric     }
594*0fca6ea1SDimitry Andric     OS << "},\n";
595*0fca6ea1SDimitry Andric   }
596*0fca6ea1SDimitry Andric   OS << "};\n\n";
597*0fca6ea1SDimitry Andric 
598*0fca6ea1SDimitry Andric   // Emit a marker where the first "end directive" is.
599*0fca6ea1SDimitry Andric   auto FirstE = llvm::find_if(Ordering, [&](int RowIdx) {
600*0fca6ea1SDimitry Andric     return EndDirectives.count(LeafTable[RowIdx][0]);
601*0fca6ea1SDimitry Andric   });
602*0fca6ea1SDimitry Andric   OS << "[[maybe_unused]] static auto " << TableName
603*0fca6ea1SDimitry Andric      << "EndDirective = " << TableName << " + "
604*0fca6ea1SDimitry Andric      << std::distance(Ordering.begin(), FirstE) << ";\n\n";
605*0fca6ea1SDimitry Andric 
606*0fca6ea1SDimitry Andric   // Emit the auxiliary index table: it's the inverse of the `Ordering`
607*0fca6ea1SDimitry Andric   // table above.
608*0fca6ea1SDimitry Andric   OS << "[[maybe_unused]] static const int " << TableName << "Ordering[] = {\n";
609*0fca6ea1SDimitry Andric   OS << "   ";
610*0fca6ea1SDimitry Andric   std::vector<int> Reverse(Ordering.size());
611*0fca6ea1SDimitry Andric   for (int I = 0, E = Ordering.size(); I != E; ++I)
612*0fca6ea1SDimitry Andric     Reverse[Ordering[I]] = I;
613*0fca6ea1SDimitry Andric   for (int Idx : Reverse)
614*0fca6ea1SDimitry Andric     OS << ' ' << Idx << ',';
615*0fca6ea1SDimitry Andric   OS << "\n};\n";
616*0fca6ea1SDimitry Andric }
617*0fca6ea1SDimitry Andric 
GenerateGetDirectiveAssociation(const DirectiveLanguage & DirLang,raw_ostream & OS)618*0fca6ea1SDimitry Andric static void GenerateGetDirectiveAssociation(const DirectiveLanguage &DirLang,
619*0fca6ea1SDimitry Andric                                             raw_ostream &OS) {
620*0fca6ea1SDimitry Andric   enum struct Association {
621*0fca6ea1SDimitry Andric     None = 0, // None should be the smallest value.
622*0fca6ea1SDimitry Andric     Block,    // The values of the rest don't matter.
623*0fca6ea1SDimitry Andric     Declaration,
624*0fca6ea1SDimitry Andric     Delimited,
625*0fca6ea1SDimitry Andric     Loop,
626*0fca6ea1SDimitry Andric     Separating,
627*0fca6ea1SDimitry Andric     FromLeaves,
628*0fca6ea1SDimitry Andric     Invalid,
629*0fca6ea1SDimitry Andric   };
630*0fca6ea1SDimitry Andric 
631*0fca6ea1SDimitry Andric   std::vector<Record *> associations = DirLang.getAssociations();
632*0fca6ea1SDimitry Andric 
633*0fca6ea1SDimitry Andric   auto getAssocValue = [](StringRef name) -> Association {
634*0fca6ea1SDimitry Andric     return StringSwitch<Association>(name)
635*0fca6ea1SDimitry Andric         .Case("AS_Block", Association::Block)
636*0fca6ea1SDimitry Andric         .Case("AS_Declaration", Association::Declaration)
637*0fca6ea1SDimitry Andric         .Case("AS_Delimited", Association::Delimited)
638*0fca6ea1SDimitry Andric         .Case("AS_Loop", Association::Loop)
639*0fca6ea1SDimitry Andric         .Case("AS_None", Association::None)
640*0fca6ea1SDimitry Andric         .Case("AS_Separating", Association::Separating)
641*0fca6ea1SDimitry Andric         .Case("AS_FromLeaves", Association::FromLeaves)
642*0fca6ea1SDimitry Andric         .Default(Association::Invalid);
643*0fca6ea1SDimitry Andric   };
644*0fca6ea1SDimitry Andric 
645*0fca6ea1SDimitry Andric   auto getAssocName = [&](Association A) -> StringRef {
646*0fca6ea1SDimitry Andric     if (A != Association::Invalid && A != Association::FromLeaves) {
647*0fca6ea1SDimitry Andric       auto F = llvm::find_if(associations, [&](const Record *R) {
648*0fca6ea1SDimitry Andric         return getAssocValue(R->getName()) == A;
649*0fca6ea1SDimitry Andric       });
650*0fca6ea1SDimitry Andric       if (F != associations.end())
651*0fca6ea1SDimitry Andric         return (*F)->getValueAsString("name"); // enum name
652*0fca6ea1SDimitry Andric     }
653*0fca6ea1SDimitry Andric     llvm_unreachable("Unexpected association value");
654*0fca6ea1SDimitry Andric   };
655*0fca6ea1SDimitry Andric 
656*0fca6ea1SDimitry Andric   auto errorPrefixFor = [&](Directive D) -> std::string {
657*0fca6ea1SDimitry Andric     return (Twine("Directive '") + D.getName() + "' in namespace '" +
658*0fca6ea1SDimitry Andric             DirLang.getCppNamespace() + "' ")
659*0fca6ea1SDimitry Andric         .str();
660*0fca6ea1SDimitry Andric   };
661*0fca6ea1SDimitry Andric 
662*0fca6ea1SDimitry Andric   auto reduce = [&](Association A, Association B) -> Association {
663*0fca6ea1SDimitry Andric     if (A > B)
664*0fca6ea1SDimitry Andric       std::swap(A, B);
665*0fca6ea1SDimitry Andric 
666*0fca6ea1SDimitry Andric     // Calculate the result using the following rules:
667*0fca6ea1SDimitry Andric     //   x + x = x
668*0fca6ea1SDimitry Andric     //   AS_None + x = x
669*0fca6ea1SDimitry Andric     //   AS_Block + AS_Loop = AS_Loop
670*0fca6ea1SDimitry Andric     if (A == Association::None || A == B)
671*0fca6ea1SDimitry Andric       return B;
672*0fca6ea1SDimitry Andric     if (A == Association::Block && B == Association::Loop)
673*0fca6ea1SDimitry Andric       return B;
674*0fca6ea1SDimitry Andric     if (A == Association::Loop && B == Association::Block)
675*0fca6ea1SDimitry Andric       return A;
676*0fca6ea1SDimitry Andric     return Association::Invalid;
677*0fca6ea1SDimitry Andric   };
678*0fca6ea1SDimitry Andric 
679*0fca6ea1SDimitry Andric   llvm::DenseMap<const Record *, Association> AsMap;
680*0fca6ea1SDimitry Andric 
681*0fca6ea1SDimitry Andric   auto compAssocImpl = [&](const Record *R, auto &&Self) -> Association {
682*0fca6ea1SDimitry Andric     if (auto F = AsMap.find(R); F != AsMap.end())
683*0fca6ea1SDimitry Andric       return F->second;
684*0fca6ea1SDimitry Andric 
685*0fca6ea1SDimitry Andric     Directive D{R};
686*0fca6ea1SDimitry Andric     Association AS = getAssocValue(D.getAssociation()->getName());
687*0fca6ea1SDimitry Andric     if (AS == Association::Invalid) {
688*0fca6ea1SDimitry Andric       PrintFatalError(errorPrefixFor(D) +
689*0fca6ea1SDimitry Andric                       "has an unrecognized value for association: '" +
690*0fca6ea1SDimitry Andric                       D.getAssociation()->getName() + "'");
691*0fca6ea1SDimitry Andric     }
692*0fca6ea1SDimitry Andric     if (AS != Association::FromLeaves) {
693*0fca6ea1SDimitry Andric       AsMap.insert(std::make_pair(R, AS));
694*0fca6ea1SDimitry Andric       return AS;
695*0fca6ea1SDimitry Andric     }
696*0fca6ea1SDimitry Andric     // Compute the association from leaf constructs.
697*0fca6ea1SDimitry Andric     std::vector<Record *> leaves = D.getLeafConstructs();
698*0fca6ea1SDimitry Andric     if (leaves.empty()) {
699*0fca6ea1SDimitry Andric       llvm::errs() << D.getName() << '\n';
700*0fca6ea1SDimitry Andric       PrintFatalError(errorPrefixFor(D) +
701*0fca6ea1SDimitry Andric                       "requests association to be computed from leaves, "
702*0fca6ea1SDimitry Andric                       "but it has no leaves");
703*0fca6ea1SDimitry Andric     }
704*0fca6ea1SDimitry Andric 
705*0fca6ea1SDimitry Andric     Association Result = Self(leaves[0], Self);
706*0fca6ea1SDimitry Andric     for (int I = 1, E = leaves.size(); I < E; ++I) {
707*0fca6ea1SDimitry Andric       Association A = Self(leaves[I], Self);
708*0fca6ea1SDimitry Andric       Association R = reduce(Result, A);
709*0fca6ea1SDimitry Andric       if (R == Association::Invalid) {
710*0fca6ea1SDimitry Andric         PrintFatalError(errorPrefixFor(D) +
711*0fca6ea1SDimitry Andric                         "has leaves with incompatible association values: " +
712*0fca6ea1SDimitry Andric                         getAssocName(A) + " and " + getAssocName(R));
713*0fca6ea1SDimitry Andric       }
714*0fca6ea1SDimitry Andric       Result = R;
715*0fca6ea1SDimitry Andric     }
716*0fca6ea1SDimitry Andric 
717*0fca6ea1SDimitry Andric     assert(Result != Association::Invalid);
718*0fca6ea1SDimitry Andric     assert(Result != Association::FromLeaves);
719*0fca6ea1SDimitry Andric     AsMap.insert(std::make_pair(R, Result));
720*0fca6ea1SDimitry Andric     return Result;
721*0fca6ea1SDimitry Andric   };
722*0fca6ea1SDimitry Andric 
723*0fca6ea1SDimitry Andric   for (Record *R : DirLang.getDirectives())
724*0fca6ea1SDimitry Andric     compAssocImpl(R, compAssocImpl); // Updates AsMap.
725*0fca6ea1SDimitry Andric 
726*0fca6ea1SDimitry Andric   OS << '\n';
727*0fca6ea1SDimitry Andric 
728*0fca6ea1SDimitry Andric   auto getQualifiedName = [&](StringRef Formatted) -> std::string {
729*0fca6ea1SDimitry Andric     return (llvm::Twine("llvm::") + DirLang.getCppNamespace() +
730*0fca6ea1SDimitry Andric             "::Directive::" + DirLang.getDirectivePrefix() + Formatted)
731*0fca6ea1SDimitry Andric         .str();
732*0fca6ea1SDimitry Andric   };
733*0fca6ea1SDimitry Andric 
734*0fca6ea1SDimitry Andric   std::string DirectiveTypeName =
735*0fca6ea1SDimitry Andric       std::string("llvm::") + DirLang.getCppNamespace().str() + "::Directive";
736*0fca6ea1SDimitry Andric   std::string AssociationTypeName =
737*0fca6ea1SDimitry Andric       std::string("llvm::") + DirLang.getCppNamespace().str() + "::Association";
738*0fca6ea1SDimitry Andric 
739*0fca6ea1SDimitry Andric   OS << AssociationTypeName << " llvm::" << DirLang.getCppNamespace()
740*0fca6ea1SDimitry Andric      << "::getDirectiveAssociation(" << DirectiveTypeName << " Dir) {\n";
741*0fca6ea1SDimitry Andric   OS << "  switch (Dir) {\n";
742*0fca6ea1SDimitry Andric   for (Record *R : DirLang.getDirectives()) {
743*0fca6ea1SDimitry Andric     if (auto F = AsMap.find(R); F != AsMap.end()) {
744*0fca6ea1SDimitry Andric       Directive Dir{R};
745*0fca6ea1SDimitry Andric       OS << "  case " << getQualifiedName(Dir.getFormattedName()) << ":\n";
746*0fca6ea1SDimitry Andric       OS << "    return " << AssociationTypeName
747*0fca6ea1SDimitry Andric          << "::" << getAssocName(F->second) << ";\n";
748*0fca6ea1SDimitry Andric     }
749*0fca6ea1SDimitry Andric   }
750*0fca6ea1SDimitry Andric   OS << "  } // switch (Dir)\n";
751*0fca6ea1SDimitry Andric   OS << "  llvm_unreachable(\"Unexpected directive\");\n";
752*0fca6ea1SDimitry Andric   OS << "}\n";
753*0fca6ea1SDimitry Andric }
754*0fca6ea1SDimitry Andric 
GenerateGetDirectiveCategory(const DirectiveLanguage & DirLang,raw_ostream & OS)755*0fca6ea1SDimitry Andric static void GenerateGetDirectiveCategory(const DirectiveLanguage &DirLang,
756*0fca6ea1SDimitry Andric                                          raw_ostream &OS) {
757*0fca6ea1SDimitry Andric   std::string LangNamespace = "llvm::" + DirLang.getCppNamespace().str();
758*0fca6ea1SDimitry Andric   std::string CategoryTypeName = LangNamespace + "::Category";
759*0fca6ea1SDimitry Andric   std::string CategoryNamespace = CategoryTypeName + "::";
760*0fca6ea1SDimitry Andric 
761*0fca6ea1SDimitry Andric   OS << '\n';
762*0fca6ea1SDimitry Andric   OS << CategoryTypeName << ' ' << LangNamespace << "::getDirectiveCategory("
763*0fca6ea1SDimitry Andric      << GetDirectiveType(DirLang) << " Dir) {\n";
764*0fca6ea1SDimitry Andric   OS << "  switch (Dir) {\n";
765*0fca6ea1SDimitry Andric 
766*0fca6ea1SDimitry Andric   for (Record *R : DirLang.getDirectives()) {
767*0fca6ea1SDimitry Andric     Directive D{R};
768*0fca6ea1SDimitry Andric     OS << "  case " << GetDirectiveName(DirLang, R) << ":\n";
769*0fca6ea1SDimitry Andric     OS << "    return " << CategoryNamespace
770*0fca6ea1SDimitry Andric        << D.getCategory()->getValueAsString("name") << ";\n";
771*0fca6ea1SDimitry Andric   }
772*0fca6ea1SDimitry Andric   OS << "  } // switch (Dir)\n";
773*0fca6ea1SDimitry Andric   OS << "  llvm_unreachable(\"Unexpected directive\");\n";
774*0fca6ea1SDimitry Andric   OS << "}\n";
775*0fca6ea1SDimitry Andric }
776*0fca6ea1SDimitry Andric 
7775ffd83dbSDimitry Andric // Generate a simple enum set with the give clauses.
GenerateClauseSet(const std::vector<Record * > & Clauses,raw_ostream & OS,StringRef ClauseSetPrefix,Directive & Dir,const DirectiveLanguage & DirLang)77806c3fb27SDimitry Andric static void GenerateClauseSet(const std::vector<Record *> &Clauses,
77906c3fb27SDimitry Andric                               raw_ostream &OS, StringRef ClauseSetPrefix,
78006c3fb27SDimitry Andric                               Directive &Dir,
781e8d8bef9SDimitry Andric                               const DirectiveLanguage &DirLang) {
7825ffd83dbSDimitry Andric 
7835ffd83dbSDimitry Andric   OS << "\n";
784e8d8bef9SDimitry Andric   OS << "  static " << DirLang.getClauseEnumSetClass() << " " << ClauseSetPrefix
785e8d8bef9SDimitry Andric      << DirLang.getDirectivePrefix() << Dir.getFormattedName() << " {\n";
7865ffd83dbSDimitry Andric 
7875ffd83dbSDimitry Andric   for (const auto &C : Clauses) {
788e8d8bef9SDimitry Andric     VersionedClause VerClause{C};
789e8d8bef9SDimitry Andric     OS << "    llvm::" << DirLang.getCppNamespace()
790e8d8bef9SDimitry Andric        << "::Clause::" << DirLang.getClausePrefix()
791e8d8bef9SDimitry Andric        << VerClause.getClause().getFormattedName() << ",\n";
7925ffd83dbSDimitry Andric   }
7935ffd83dbSDimitry Andric   OS << "  };\n";
7945ffd83dbSDimitry Andric }
7955ffd83dbSDimitry Andric 
7965ffd83dbSDimitry Andric // Generate an enum set for the 4 kinds of clauses linked to a directive.
GenerateDirectiveClauseSets(const DirectiveLanguage & DirLang,raw_ostream & OS)79706c3fb27SDimitry Andric static void GenerateDirectiveClauseSets(const DirectiveLanguage &DirLang,
798e8d8bef9SDimitry Andric                                         raw_ostream &OS) {
7995ffd83dbSDimitry Andric 
8005ffd83dbSDimitry Andric   IfDefScope Scope("GEN_FLANG_DIRECTIVE_CLAUSE_SETS", OS);
8015ffd83dbSDimitry Andric 
8025ffd83dbSDimitry Andric   OS << "\n";
8035ffd83dbSDimitry Andric   OS << "namespace llvm {\n";
8045ffd83dbSDimitry Andric 
8055ffd83dbSDimitry Andric   // Open namespaces defined in the directive language.
8065ffd83dbSDimitry Andric   llvm::SmallVector<StringRef, 2> Namespaces;
807e8d8bef9SDimitry Andric   llvm::SplitString(DirLang.getCppNamespace(), Namespaces, "::");
8085ffd83dbSDimitry Andric   for (auto Ns : Namespaces)
8095ffd83dbSDimitry Andric     OS << "namespace " << Ns << " {\n";
8105ffd83dbSDimitry Andric 
811e8d8bef9SDimitry Andric   for (const auto &D : DirLang.getDirectives()) {
812e8d8bef9SDimitry Andric     Directive Dir{D};
8135ffd83dbSDimitry Andric 
8145ffd83dbSDimitry Andric     OS << "\n";
815e8d8bef9SDimitry Andric     OS << "  // Sets for " << Dir.getName() << "\n";
8165ffd83dbSDimitry Andric 
817e8d8bef9SDimitry Andric     GenerateClauseSet(Dir.getAllowedClauses(), OS, "allowedClauses_", Dir,
818e8d8bef9SDimitry Andric                       DirLang);
819e8d8bef9SDimitry Andric     GenerateClauseSet(Dir.getAllowedOnceClauses(), OS, "allowedOnceClauses_",
820e8d8bef9SDimitry Andric                       Dir, DirLang);
821e8d8bef9SDimitry Andric     GenerateClauseSet(Dir.getAllowedExclusiveClauses(), OS,
822e8d8bef9SDimitry Andric                       "allowedExclusiveClauses_", Dir, DirLang);
823e8d8bef9SDimitry Andric     GenerateClauseSet(Dir.getRequiredClauses(), OS, "requiredClauses_", Dir,
824e8d8bef9SDimitry Andric                       DirLang);
8255ffd83dbSDimitry Andric   }
8265ffd83dbSDimitry Andric 
8275ffd83dbSDimitry Andric   // Closing namespaces
8285ffd83dbSDimitry Andric   for (auto Ns : llvm::reverse(Namespaces))
8295ffd83dbSDimitry Andric     OS << "} // namespace " << Ns << "\n";
8305ffd83dbSDimitry Andric 
8315ffd83dbSDimitry Andric   OS << "} // namespace llvm\n";
8325ffd83dbSDimitry Andric }
8335ffd83dbSDimitry Andric 
8345ffd83dbSDimitry Andric // Generate a map of directive (key) with DirectiveClauses struct as values.
8355ffd83dbSDimitry Andric // The struct holds the 4 sets of enumeration for the 4 kinds of clauses
8365ffd83dbSDimitry Andric // allowances (allowed, allowed once, allowed exclusive and required).
GenerateDirectiveClauseMap(const DirectiveLanguage & DirLang,raw_ostream & OS)83706c3fb27SDimitry Andric static void GenerateDirectiveClauseMap(const DirectiveLanguage &DirLang,
838e8d8bef9SDimitry Andric                                        raw_ostream &OS) {
8395ffd83dbSDimitry Andric 
8405ffd83dbSDimitry Andric   IfDefScope Scope("GEN_FLANG_DIRECTIVE_CLAUSE_MAP", OS);
8415ffd83dbSDimitry Andric 
8425ffd83dbSDimitry Andric   OS << "\n";
8435ffd83dbSDimitry Andric   OS << "{\n";
844e8d8bef9SDimitry Andric 
845e8d8bef9SDimitry Andric   for (const auto &D : DirLang.getDirectives()) {
846e8d8bef9SDimitry Andric     Directive Dir{D};
847e8d8bef9SDimitry Andric     OS << "  {llvm::" << DirLang.getCppNamespace()
848e8d8bef9SDimitry Andric        << "::Directive::" << DirLang.getDirectivePrefix()
849e8d8bef9SDimitry Andric        << Dir.getFormattedName() << ",\n";
850e8d8bef9SDimitry Andric     OS << "    {\n";
851e8d8bef9SDimitry Andric     OS << "      llvm::" << DirLang.getCppNamespace() << "::allowedClauses_"
852e8d8bef9SDimitry Andric        << DirLang.getDirectivePrefix() << Dir.getFormattedName() << ",\n";
853e8d8bef9SDimitry Andric     OS << "      llvm::" << DirLang.getCppNamespace() << "::allowedOnceClauses_"
854e8d8bef9SDimitry Andric        << DirLang.getDirectivePrefix() << Dir.getFormattedName() << ",\n";
855e8d8bef9SDimitry Andric     OS << "      llvm::" << DirLang.getCppNamespace()
856e8d8bef9SDimitry Andric        << "::allowedExclusiveClauses_" << DirLang.getDirectivePrefix()
857e8d8bef9SDimitry Andric        << Dir.getFormattedName() << ",\n";
858e8d8bef9SDimitry Andric     OS << "      llvm::" << DirLang.getCppNamespace() << "::requiredClauses_"
859e8d8bef9SDimitry Andric        << DirLang.getDirectivePrefix() << Dir.getFormattedName() << ",\n";
8605ffd83dbSDimitry Andric     OS << "    }\n";
8615ffd83dbSDimitry Andric     OS << "  },\n";
8625ffd83dbSDimitry Andric   }
8635ffd83dbSDimitry Andric 
864e8d8bef9SDimitry Andric   OS << "}\n";
8655ffd83dbSDimitry Andric }
8665ffd83dbSDimitry Andric 
867e8d8bef9SDimitry Andric // Generate classes entry for Flang clauses in the Flang parse-tree
868e8d8bef9SDimitry Andric // If the clause as a non-generic class, no entry is generated.
869e8d8bef9SDimitry Andric // If the clause does not hold a value, an EMPTY_CLASS is used.
870e8d8bef9SDimitry Andric // If the clause class is generic then a WRAPPER_CLASS is used. When the value
871e8d8bef9SDimitry Andric // is optional, the value class is wrapped into a std::optional.
GenerateFlangClauseParserClass(const DirectiveLanguage & DirLang,raw_ostream & OS)87206c3fb27SDimitry Andric static void GenerateFlangClauseParserClass(const DirectiveLanguage &DirLang,
873e8d8bef9SDimitry Andric                                            raw_ostream &OS) {
874e8d8bef9SDimitry Andric 
875e8d8bef9SDimitry Andric   IfDefScope Scope("GEN_FLANG_CLAUSE_PARSER_CLASSES", OS);
876e8d8bef9SDimitry Andric 
877e8d8bef9SDimitry Andric   OS << "\n";
878e8d8bef9SDimitry Andric 
879e8d8bef9SDimitry Andric   for (const auto &C : DirLang.getClauses()) {
880e8d8bef9SDimitry Andric     Clause Clause{C};
881e8d8bef9SDimitry Andric     if (!Clause.getFlangClass().empty()) {
882e8d8bef9SDimitry Andric       OS << "WRAPPER_CLASS(" << Clause.getFormattedParserClassName() << ", ";
883e8d8bef9SDimitry Andric       if (Clause.isValueOptional() && Clause.isValueList()) {
884e8d8bef9SDimitry Andric         OS << "std::optional<std::list<" << Clause.getFlangClass() << ">>";
885e8d8bef9SDimitry Andric       } else if (Clause.isValueOptional()) {
886e8d8bef9SDimitry Andric         OS << "std::optional<" << Clause.getFlangClass() << ">";
887e8d8bef9SDimitry Andric       } else if (Clause.isValueList()) {
888e8d8bef9SDimitry Andric         OS << "std::list<" << Clause.getFlangClass() << ">";
889e8d8bef9SDimitry Andric       } else {
890e8d8bef9SDimitry Andric         OS << Clause.getFlangClass();
891e8d8bef9SDimitry Andric       }
892e8d8bef9SDimitry Andric     } else {
893e8d8bef9SDimitry Andric       OS << "EMPTY_CLASS(" << Clause.getFormattedParserClassName();
894e8d8bef9SDimitry Andric     }
895e8d8bef9SDimitry Andric     OS << ");\n";
896e8d8bef9SDimitry Andric   }
897e8d8bef9SDimitry Andric }
898e8d8bef9SDimitry Andric 
899e8d8bef9SDimitry Andric // Generate a list of the different clause classes for Flang.
GenerateFlangClauseParserClassList(const DirectiveLanguage & DirLang,raw_ostream & OS)90006c3fb27SDimitry Andric static void GenerateFlangClauseParserClassList(const DirectiveLanguage &DirLang,
901e8d8bef9SDimitry Andric                                                raw_ostream &OS) {
902e8d8bef9SDimitry Andric 
903e8d8bef9SDimitry Andric   IfDefScope Scope("GEN_FLANG_CLAUSE_PARSER_CLASSES_LIST", OS);
904e8d8bef9SDimitry Andric 
905e8d8bef9SDimitry Andric   OS << "\n";
906e8d8bef9SDimitry Andric   llvm::interleaveComma(DirLang.getClauses(), OS, [&](Record *C) {
907e8d8bef9SDimitry Andric     Clause Clause{C};
908e8d8bef9SDimitry Andric     OS << Clause.getFormattedParserClassName() << "\n";
909e8d8bef9SDimitry Andric   });
910e8d8bef9SDimitry Andric }
911e8d8bef9SDimitry Andric 
912e8d8bef9SDimitry Andric // Generate dump node list for the clauses holding a generic class name.
GenerateFlangClauseDump(const DirectiveLanguage & DirLang,raw_ostream & OS)91306c3fb27SDimitry Andric static void GenerateFlangClauseDump(const DirectiveLanguage &DirLang,
914e8d8bef9SDimitry Andric                                     raw_ostream &OS) {
915e8d8bef9SDimitry Andric 
916e8d8bef9SDimitry Andric   IfDefScope Scope("GEN_FLANG_DUMP_PARSE_TREE_CLAUSES", OS);
917e8d8bef9SDimitry Andric 
918e8d8bef9SDimitry Andric   OS << "\n";
919e8d8bef9SDimitry Andric   for (const auto &C : DirLang.getClauses()) {
920e8d8bef9SDimitry Andric     Clause Clause{C};
921e8d8bef9SDimitry Andric     OS << "NODE(" << DirLang.getFlangClauseBaseClass() << ", "
922e8d8bef9SDimitry Andric        << Clause.getFormattedParserClassName() << ")\n";
923e8d8bef9SDimitry Andric   }
924e8d8bef9SDimitry Andric }
925e8d8bef9SDimitry Andric 
926e8d8bef9SDimitry Andric // Generate Unparse functions for clauses classes in the Flang parse-tree
927e8d8bef9SDimitry Andric // If the clause is a non-generic class, no entry is generated.
GenerateFlangClauseUnparse(const DirectiveLanguage & DirLang,raw_ostream & OS)92806c3fb27SDimitry Andric static void GenerateFlangClauseUnparse(const DirectiveLanguage &DirLang,
929e8d8bef9SDimitry Andric                                        raw_ostream &OS) {
930e8d8bef9SDimitry Andric 
931e8d8bef9SDimitry Andric   IfDefScope Scope("GEN_FLANG_CLAUSE_UNPARSE", OS);
932e8d8bef9SDimitry Andric 
933e8d8bef9SDimitry Andric   OS << "\n";
934e8d8bef9SDimitry Andric 
935e8d8bef9SDimitry Andric   for (const auto &C : DirLang.getClauses()) {
936e8d8bef9SDimitry Andric     Clause Clause{C};
937e8d8bef9SDimitry Andric     if (!Clause.getFlangClass().empty()) {
938e8d8bef9SDimitry Andric       if (Clause.isValueOptional() && Clause.getDefaultValue().empty()) {
939e8d8bef9SDimitry Andric         OS << "void Unparse(const " << DirLang.getFlangClauseBaseClass()
940e8d8bef9SDimitry Andric            << "::" << Clause.getFormattedParserClassName() << " &x) {\n";
941e8d8bef9SDimitry Andric         OS << "  Word(\"" << Clause.getName().upper() << "\");\n";
942e8d8bef9SDimitry Andric 
943e8d8bef9SDimitry Andric         OS << "  Walk(\"(\", x.v, \")\");\n";
944e8d8bef9SDimitry Andric         OS << "}\n";
945e8d8bef9SDimitry Andric       } else if (Clause.isValueOptional()) {
946e8d8bef9SDimitry Andric         OS << "void Unparse(const " << DirLang.getFlangClauseBaseClass()
947e8d8bef9SDimitry Andric            << "::" << Clause.getFormattedParserClassName() << " &x) {\n";
948e8d8bef9SDimitry Andric         OS << "  Word(\"" << Clause.getName().upper() << "\");\n";
949e8d8bef9SDimitry Andric         OS << "  Put(\"(\");\n";
950e8d8bef9SDimitry Andric         OS << "  if (x.v.has_value())\n";
951e8d8bef9SDimitry Andric         if (Clause.isValueList())
952e8d8bef9SDimitry Andric           OS << "    Walk(x.v, \",\");\n";
953e8d8bef9SDimitry Andric         else
954e8d8bef9SDimitry Andric           OS << "    Walk(x.v);\n";
955e8d8bef9SDimitry Andric         OS << "  else\n";
956e8d8bef9SDimitry Andric         OS << "    Put(\"" << Clause.getDefaultValue() << "\");\n";
957e8d8bef9SDimitry Andric         OS << "  Put(\")\");\n";
958e8d8bef9SDimitry Andric         OS << "}\n";
959e8d8bef9SDimitry Andric       } else {
960e8d8bef9SDimitry Andric         OS << "void Unparse(const " << DirLang.getFlangClauseBaseClass()
961e8d8bef9SDimitry Andric            << "::" << Clause.getFormattedParserClassName() << " &x) {\n";
962e8d8bef9SDimitry Andric         OS << "  Word(\"" << Clause.getName().upper() << "\");\n";
963e8d8bef9SDimitry Andric         OS << "  Put(\"(\");\n";
964e8d8bef9SDimitry Andric         if (Clause.isValueList())
965e8d8bef9SDimitry Andric           OS << "  Walk(x.v, \",\");\n";
966e8d8bef9SDimitry Andric         else
967e8d8bef9SDimitry Andric           OS << "  Walk(x.v);\n";
968e8d8bef9SDimitry Andric         OS << "  Put(\")\");\n";
969e8d8bef9SDimitry Andric         OS << "}\n";
970e8d8bef9SDimitry Andric       }
971e8d8bef9SDimitry Andric     } else {
972e8d8bef9SDimitry Andric       OS << "void Before(const " << DirLang.getFlangClauseBaseClass()
973e8d8bef9SDimitry Andric          << "::" << Clause.getFormattedParserClassName() << " &) { Word(\""
974e8d8bef9SDimitry Andric          << Clause.getName().upper() << "\"); }\n";
975e8d8bef9SDimitry Andric     }
976e8d8bef9SDimitry Andric   }
977e8d8bef9SDimitry Andric }
978e8d8bef9SDimitry Andric 
979fe6060f1SDimitry Andric // Generate check in the Enter functions for clauses classes.
GenerateFlangClauseCheckPrototypes(const DirectiveLanguage & DirLang,raw_ostream & OS)98006c3fb27SDimitry Andric static void GenerateFlangClauseCheckPrototypes(const DirectiveLanguage &DirLang,
981fe6060f1SDimitry Andric                                                raw_ostream &OS) {
982fe6060f1SDimitry Andric 
983fe6060f1SDimitry Andric   IfDefScope Scope("GEN_FLANG_CLAUSE_CHECK_ENTER", OS);
984fe6060f1SDimitry Andric 
985fe6060f1SDimitry Andric   OS << "\n";
986fe6060f1SDimitry Andric   for (const auto &C : DirLang.getClauses()) {
987fe6060f1SDimitry Andric     Clause Clause{C};
988fe6060f1SDimitry Andric     OS << "void Enter(const parser::" << DirLang.getFlangClauseBaseClass()
989fe6060f1SDimitry Andric        << "::" << Clause.getFormattedParserClassName() << " &);\n";
990fe6060f1SDimitry Andric   }
991fe6060f1SDimitry Andric }
992fe6060f1SDimitry Andric 
993fe6060f1SDimitry Andric // Generate the mapping for clauses between the parser class and the
994fe6060f1SDimitry Andric // corresponding clause Kind
GenerateFlangClauseParserKindMap(const DirectiveLanguage & DirLang,raw_ostream & OS)99506c3fb27SDimitry Andric static void GenerateFlangClauseParserKindMap(const DirectiveLanguage &DirLang,
996fe6060f1SDimitry Andric                                              raw_ostream &OS) {
997fe6060f1SDimitry Andric 
998fe6060f1SDimitry Andric   IfDefScope Scope("GEN_FLANG_CLAUSE_PARSER_KIND_MAP", OS);
999fe6060f1SDimitry Andric 
1000fe6060f1SDimitry Andric   OS << "\n";
1001fe6060f1SDimitry Andric   for (const auto &C : DirLang.getClauses()) {
1002fe6060f1SDimitry Andric     Clause Clause{C};
1003fe6060f1SDimitry Andric     OS << "if constexpr (std::is_same_v<A, parser::"
1004fe6060f1SDimitry Andric        << DirLang.getFlangClauseBaseClass()
1005fe6060f1SDimitry Andric        << "::" << Clause.getFormattedParserClassName();
1006fe6060f1SDimitry Andric     OS << ">)\n";
1007fe6060f1SDimitry Andric     OS << "  return llvm::" << DirLang.getCppNamespace()
1008fe6060f1SDimitry Andric        << "::Clause::" << DirLang.getClausePrefix() << Clause.getFormattedName()
1009fe6060f1SDimitry Andric        << ";\n";
1010fe6060f1SDimitry Andric   }
1011fe6060f1SDimitry Andric 
1012fe6060f1SDimitry Andric   OS << "llvm_unreachable(\"Invalid " << DirLang.getName()
1013fe6060f1SDimitry Andric      << " Parser clause\");\n";
1014fe6060f1SDimitry Andric }
1015fe6060f1SDimitry Andric 
compareClauseName(Record * R1,Record * R2)101606c3fb27SDimitry Andric static bool compareClauseName(Record *R1, Record *R2) {
1017fcaf7f86SDimitry Andric   Clause C1{R1};
1018fcaf7f86SDimitry Andric   Clause C2{R2};
1019fcaf7f86SDimitry Andric   return (C1.getName() > C2.getName());
1020fcaf7f86SDimitry Andric }
1021fcaf7f86SDimitry Andric 
1022fcaf7f86SDimitry Andric // Generate the parser for the clauses.
GenerateFlangClausesParser(const DirectiveLanguage & DirLang,raw_ostream & OS)102306c3fb27SDimitry Andric static void GenerateFlangClausesParser(const DirectiveLanguage &DirLang,
1024fcaf7f86SDimitry Andric                                        raw_ostream &OS) {
1025fcaf7f86SDimitry Andric   std::vector<Record *> Clauses = DirLang.getClauses();
1026fcaf7f86SDimitry Andric   // Sort clauses in reverse alphabetical order so with clauses with same
1027fcaf7f86SDimitry Andric   // beginning, the longer option is tried before.
1028fcaf7f86SDimitry Andric   llvm::sort(Clauses, compareClauseName);
1029fcaf7f86SDimitry Andric   IfDefScope Scope("GEN_FLANG_CLAUSES_PARSER", OS);
1030fcaf7f86SDimitry Andric   OS << "\n";
1031fcaf7f86SDimitry Andric   unsigned index = 0;
1032fcaf7f86SDimitry Andric   unsigned lastClauseIndex = DirLang.getClauses().size() - 1;
1033fcaf7f86SDimitry Andric   OS << "TYPE_PARSER(\n";
1034fcaf7f86SDimitry Andric   for (const auto &C : Clauses) {
1035fcaf7f86SDimitry Andric     Clause Clause{C};
1036fcaf7f86SDimitry Andric     if (Clause.getAliases().empty()) {
1037fcaf7f86SDimitry Andric       OS << "  \"" << Clause.getName() << "\"";
1038fcaf7f86SDimitry Andric     } else {
1039fcaf7f86SDimitry Andric       OS << "  ("
1040fcaf7f86SDimitry Andric          << "\"" << Clause.getName() << "\"_tok";
1041fcaf7f86SDimitry Andric       for (StringRef alias : Clause.getAliases()) {
1042fcaf7f86SDimitry Andric         OS << " || \"" << alias << "\"_tok";
1043fcaf7f86SDimitry Andric       }
1044fcaf7f86SDimitry Andric       OS << ")";
1045fcaf7f86SDimitry Andric     }
1046fcaf7f86SDimitry Andric 
1047fcaf7f86SDimitry Andric     OS << " >> construct<" << DirLang.getFlangClauseBaseClass()
1048fcaf7f86SDimitry Andric        << ">(construct<" << DirLang.getFlangClauseBaseClass()
1049fcaf7f86SDimitry Andric        << "::" << Clause.getFormattedParserClassName() << ">(";
1050fcaf7f86SDimitry Andric     if (Clause.getFlangClass().empty()) {
1051fcaf7f86SDimitry Andric       OS << "))";
1052fcaf7f86SDimitry Andric       if (index != lastClauseIndex)
1053fcaf7f86SDimitry Andric         OS << " ||";
1054fcaf7f86SDimitry Andric       OS << "\n";
1055fcaf7f86SDimitry Andric       ++index;
1056fcaf7f86SDimitry Andric       continue;
1057fcaf7f86SDimitry Andric     }
1058fcaf7f86SDimitry Andric 
1059fcaf7f86SDimitry Andric     if (Clause.isValueOptional())
1060fcaf7f86SDimitry Andric       OS << "maybe(";
1061fcaf7f86SDimitry Andric     OS << "parenthesized(";
106206c3fb27SDimitry Andric     if (Clause.isValueList())
106306c3fb27SDimitry Andric       OS << "nonemptyList(";
1064fcaf7f86SDimitry Andric 
1065fcaf7f86SDimitry Andric     if (!Clause.getPrefix().empty())
1066fcaf7f86SDimitry Andric       OS << "\"" << Clause.getPrefix() << ":\" >> ";
1067fcaf7f86SDimitry Andric 
1068fcaf7f86SDimitry Andric     // The common Flang parser are used directly. Their name is identical to
1069fcaf7f86SDimitry Andric     // the Flang class with first letter as lowercase. If the Flang class is
1070fcaf7f86SDimitry Andric     // not a common class, we assume there is a specific Parser<>{} with the
1071fcaf7f86SDimitry Andric     // Flang class name provided.
1072fcaf7f86SDimitry Andric     llvm::SmallString<128> Scratch;
1073fcaf7f86SDimitry Andric     StringRef Parser =
1074fcaf7f86SDimitry Andric         llvm::StringSwitch<StringRef>(Clause.getFlangClass())
1075fcaf7f86SDimitry Andric             .Case("Name", "name")
1076fcaf7f86SDimitry Andric             .Case("ScalarIntConstantExpr", "scalarIntConstantExpr")
1077fcaf7f86SDimitry Andric             .Case("ScalarIntExpr", "scalarIntExpr")
10785f757f3fSDimitry Andric             .Case("ScalarExpr", "scalarExpr")
1079fcaf7f86SDimitry Andric             .Case("ScalarLogicalExpr", "scalarLogicalExpr")
1080fcaf7f86SDimitry Andric             .Default(("Parser<" + Clause.getFlangClass() + ">{}")
1081fcaf7f86SDimitry Andric                          .toStringRef(Scratch));
1082fcaf7f86SDimitry Andric     OS << Parser;
1083fcaf7f86SDimitry Andric     if (!Clause.getPrefix().empty() && Clause.isPrefixOptional())
1084fcaf7f86SDimitry Andric       OS << " || " << Parser;
108506c3fb27SDimitry Andric     if (Clause.isValueList()) // close nonemptyList(.
108606c3fb27SDimitry Andric       OS << ")";
1087fcaf7f86SDimitry Andric     OS << ")"; // close parenthesized(.
1088fcaf7f86SDimitry Andric 
1089fcaf7f86SDimitry Andric     if (Clause.isValueOptional()) // close maybe(.
1090fcaf7f86SDimitry Andric       OS << ")";
1091fcaf7f86SDimitry Andric     OS << "))";
1092fcaf7f86SDimitry Andric     if (index != lastClauseIndex)
1093fcaf7f86SDimitry Andric       OS << " ||";
1094fcaf7f86SDimitry Andric     OS << "\n";
1095fcaf7f86SDimitry Andric     ++index;
1096fcaf7f86SDimitry Andric   }
1097fcaf7f86SDimitry Andric   OS << ")\n";
1098fcaf7f86SDimitry Andric }
1099fcaf7f86SDimitry Andric 
1100e8d8bef9SDimitry Andric // Generate the implementation section for the enumeration in the directive
11015ffd83dbSDimitry Andric // language
EmitDirectivesFlangImpl(const DirectiveLanguage & DirLang,raw_ostream & OS)110206c3fb27SDimitry Andric static void EmitDirectivesFlangImpl(const DirectiveLanguage &DirLang,
1103e8d8bef9SDimitry Andric                                     raw_ostream &OS) {
11045ffd83dbSDimitry Andric 
1105e8d8bef9SDimitry Andric   GenerateDirectiveClauseSets(DirLang, OS);
11065ffd83dbSDimitry Andric 
1107e8d8bef9SDimitry Andric   GenerateDirectiveClauseMap(DirLang, OS);
1108e8d8bef9SDimitry Andric 
1109e8d8bef9SDimitry Andric   GenerateFlangClauseParserClass(DirLang, OS);
1110e8d8bef9SDimitry Andric 
1111e8d8bef9SDimitry Andric   GenerateFlangClauseParserClassList(DirLang, OS);
1112e8d8bef9SDimitry Andric 
1113e8d8bef9SDimitry Andric   GenerateFlangClauseDump(DirLang, OS);
1114e8d8bef9SDimitry Andric 
1115e8d8bef9SDimitry Andric   GenerateFlangClauseUnparse(DirLang, OS);
1116fe6060f1SDimitry Andric 
1117fe6060f1SDimitry Andric   GenerateFlangClauseCheckPrototypes(DirLang, OS);
1118fe6060f1SDimitry Andric 
1119fe6060f1SDimitry Andric   GenerateFlangClauseParserKindMap(DirLang, OS);
1120fcaf7f86SDimitry Andric 
1121fcaf7f86SDimitry Andric   GenerateFlangClausesParser(DirLang, OS);
11225ffd83dbSDimitry Andric }
11235ffd83dbSDimitry Andric 
GenerateClauseClassMacro(const DirectiveLanguage & DirLang,raw_ostream & OS)112406c3fb27SDimitry Andric static void GenerateClauseClassMacro(const DirectiveLanguage &DirLang,
1125e8d8bef9SDimitry Andric                                      raw_ostream &OS) {
1126e8d8bef9SDimitry Andric   // Generate macros style information for legacy code in clang
1127e8d8bef9SDimitry Andric   IfDefScope Scope("GEN_CLANG_CLAUSE_CLASS", OS);
1128e8d8bef9SDimitry Andric 
1129e8d8bef9SDimitry Andric   OS << "\n";
1130e8d8bef9SDimitry Andric 
1131e8d8bef9SDimitry Andric   OS << "#ifndef CLAUSE\n";
1132e8d8bef9SDimitry Andric   OS << "#define CLAUSE(Enum, Str, Implicit)\n";
1133e8d8bef9SDimitry Andric   OS << "#endif\n";
1134e8d8bef9SDimitry Andric   OS << "#ifndef CLAUSE_CLASS\n";
1135e8d8bef9SDimitry Andric   OS << "#define CLAUSE_CLASS(Enum, Str, Class)\n";
1136e8d8bef9SDimitry Andric   OS << "#endif\n";
1137e8d8bef9SDimitry Andric   OS << "#ifndef CLAUSE_NO_CLASS\n";
1138e8d8bef9SDimitry Andric   OS << "#define CLAUSE_NO_CLASS(Enum, Str)\n";
1139e8d8bef9SDimitry Andric   OS << "#endif\n";
1140e8d8bef9SDimitry Andric   OS << "\n";
1141e8d8bef9SDimitry Andric   OS << "#define __CLAUSE(Name, Class)                      \\\n";
1142e8d8bef9SDimitry Andric   OS << "  CLAUSE(" << DirLang.getClausePrefix()
1143e8d8bef9SDimitry Andric      << "##Name, #Name, /* Implicit */ false) \\\n";
1144e8d8bef9SDimitry Andric   OS << "  CLAUSE_CLASS(" << DirLang.getClausePrefix()
1145e8d8bef9SDimitry Andric      << "##Name, #Name, Class)\n";
1146e8d8bef9SDimitry Andric   OS << "#define __CLAUSE_NO_CLASS(Name)                    \\\n";
1147e8d8bef9SDimitry Andric   OS << "  CLAUSE(" << DirLang.getClausePrefix()
1148e8d8bef9SDimitry Andric      << "##Name, #Name, /* Implicit */ false) \\\n";
1149e8d8bef9SDimitry Andric   OS << "  CLAUSE_NO_CLASS(" << DirLang.getClausePrefix() << "##Name, #Name)\n";
1150e8d8bef9SDimitry Andric   OS << "#define __IMPLICIT_CLAUSE_CLASS(Name, Str, Class)  \\\n";
1151e8d8bef9SDimitry Andric   OS << "  CLAUSE(" << DirLang.getClausePrefix()
1152e8d8bef9SDimitry Andric      << "##Name, Str, /* Implicit */ true)    \\\n";
1153e8d8bef9SDimitry Andric   OS << "  CLAUSE_CLASS(" << DirLang.getClausePrefix()
1154e8d8bef9SDimitry Andric      << "##Name, Str, Class)\n";
1155e8d8bef9SDimitry Andric   OS << "#define __IMPLICIT_CLAUSE_NO_CLASS(Name, Str)      \\\n";
1156e8d8bef9SDimitry Andric   OS << "  CLAUSE(" << DirLang.getClausePrefix()
1157e8d8bef9SDimitry Andric      << "##Name, Str, /* Implicit */ true)    \\\n";
1158e8d8bef9SDimitry Andric   OS << "  CLAUSE_NO_CLASS(" << DirLang.getClausePrefix() << "##Name, Str)\n";
1159e8d8bef9SDimitry Andric   OS << "\n";
1160e8d8bef9SDimitry Andric 
1161e8d8bef9SDimitry Andric   for (const auto &R : DirLang.getClauses()) {
1162e8d8bef9SDimitry Andric     Clause C{R};
1163e8d8bef9SDimitry Andric     if (C.getClangClass().empty()) { // NO_CLASS
1164e8d8bef9SDimitry Andric       if (C.isImplicit()) {
1165e8d8bef9SDimitry Andric         OS << "__IMPLICIT_CLAUSE_NO_CLASS(" << C.getFormattedName() << ", \""
1166e8d8bef9SDimitry Andric            << C.getFormattedName() << "\")\n";
1167e8d8bef9SDimitry Andric       } else {
1168e8d8bef9SDimitry Andric         OS << "__CLAUSE_NO_CLASS(" << C.getFormattedName() << ")\n";
1169e8d8bef9SDimitry Andric       }
1170e8d8bef9SDimitry Andric     } else { // CLASS
1171e8d8bef9SDimitry Andric       if (C.isImplicit()) {
1172e8d8bef9SDimitry Andric         OS << "__IMPLICIT_CLAUSE_CLASS(" << C.getFormattedName() << ", \""
1173e8d8bef9SDimitry Andric            << C.getFormattedName() << "\", " << C.getClangClass() << ")\n";
1174e8d8bef9SDimitry Andric       } else {
1175e8d8bef9SDimitry Andric         OS << "__CLAUSE(" << C.getFormattedName() << ", " << C.getClangClass()
1176e8d8bef9SDimitry Andric            << ")\n";
1177e8d8bef9SDimitry Andric       }
1178e8d8bef9SDimitry Andric     }
1179e8d8bef9SDimitry Andric   }
1180e8d8bef9SDimitry Andric 
1181e8d8bef9SDimitry Andric   OS << "\n";
1182e8d8bef9SDimitry Andric   OS << "#undef __IMPLICIT_CLAUSE_NO_CLASS\n";
1183e8d8bef9SDimitry Andric   OS << "#undef __IMPLICIT_CLAUSE_CLASS\n";
1184*0fca6ea1SDimitry Andric   OS << "#undef __CLAUSE_NO_CLASS\n";
1185e8d8bef9SDimitry Andric   OS << "#undef __CLAUSE\n";
1186e8d8bef9SDimitry Andric   OS << "#undef CLAUSE_NO_CLASS\n";
1187e8d8bef9SDimitry Andric   OS << "#undef CLAUSE_CLASS\n";
1188e8d8bef9SDimitry Andric   OS << "#undef CLAUSE\n";
1189e8d8bef9SDimitry Andric }
1190e8d8bef9SDimitry Andric 
1191fe6060f1SDimitry Andric // Generate the implemenation for the enumeration in the directive
11925ffd83dbSDimitry Andric // language. This code can be included in library.
EmitDirectivesBasicImpl(const DirectiveLanguage & DirLang,raw_ostream & OS)1193fe6060f1SDimitry Andric void EmitDirectivesBasicImpl(const DirectiveLanguage &DirLang,
1194fe6060f1SDimitry Andric                              raw_ostream &OS) {
1195fe6060f1SDimitry Andric   IfDefScope Scope("GEN_DIRECTIVES_IMPL", OS);
11965ffd83dbSDimitry Andric 
1197*0fca6ea1SDimitry Andric   OS << "\n#include \"llvm/Support/ErrorHandling.h\"\n";
1198*0fca6ea1SDimitry Andric 
11995ffd83dbSDimitry Andric   // getDirectiveKind(StringRef Str)
1200e8d8bef9SDimitry Andric   GenerateGetKind(DirLang.getDirectives(), OS, "Directive", DirLang,
1201e8d8bef9SDimitry Andric                   DirLang.getDirectivePrefix(), /*ImplicitAsUnknown=*/false);
12025ffd83dbSDimitry Andric 
12035ffd83dbSDimitry Andric   // getDirectiveName(Directive Kind)
1204e8d8bef9SDimitry Andric   GenerateGetName(DirLang.getDirectives(), OS, "Directive", DirLang,
1205e8d8bef9SDimitry Andric                   DirLang.getDirectivePrefix());
12065ffd83dbSDimitry Andric 
12075ffd83dbSDimitry Andric   // getClauseKind(StringRef Str)
1208e8d8bef9SDimitry Andric   GenerateGetKind(DirLang.getClauses(), OS, "Clause", DirLang,
1209e8d8bef9SDimitry Andric                   DirLang.getClausePrefix(),
1210e8d8bef9SDimitry Andric                   /*ImplicitAsUnknown=*/true);
12115ffd83dbSDimitry Andric 
12125ffd83dbSDimitry Andric   // getClauseName(Clause Kind)
1213e8d8bef9SDimitry Andric   GenerateGetName(DirLang.getClauses(), OS, "Clause", DirLang,
1214e8d8bef9SDimitry Andric                   DirLang.getClausePrefix());
1215e8d8bef9SDimitry Andric 
1216e8d8bef9SDimitry Andric   // get<ClauseVal>Kind(StringRef Str)
1217e8d8bef9SDimitry Andric   GenerateGetKindClauseVal(DirLang, OS);
12185ffd83dbSDimitry Andric 
12195ffd83dbSDimitry Andric   // isAllowedClauseForDirective(Directive D, Clause C, unsigned Version)
1220e8d8bef9SDimitry Andric   GenerateIsAllowedClause(DirLang, OS);
1221*0fca6ea1SDimitry Andric 
1222*0fca6ea1SDimitry Andric   // getDirectiveAssociation(Directive D)
1223*0fca6ea1SDimitry Andric   GenerateGetDirectiveAssociation(DirLang, OS);
1224*0fca6ea1SDimitry Andric 
1225*0fca6ea1SDimitry Andric   // getDirectiveCategory(Directive D)
1226*0fca6ea1SDimitry Andric   GenerateGetDirectiveCategory(DirLang, OS);
1227*0fca6ea1SDimitry Andric 
1228*0fca6ea1SDimitry Andric   // Leaf table for getLeafConstructs, etc.
1229*0fca6ea1SDimitry Andric   EmitLeafTable(DirLang, OS, "LeafConstructTable");
12305ffd83dbSDimitry Andric }
12315ffd83dbSDimitry Andric 
1232fe6060f1SDimitry Andric // Generate the implemenation section for the enumeration in the directive
1233fe6060f1SDimitry Andric // language.
EmitDirectivesImpl(RecordKeeper & Records,raw_ostream & OS)123406c3fb27SDimitry Andric static void EmitDirectivesImpl(RecordKeeper &Records, raw_ostream &OS) {
1235fe6060f1SDimitry Andric   const auto DirLang = DirectiveLanguage{Records};
1236fe6060f1SDimitry Andric   if (DirLang.HasValidityErrors())
1237fe6060f1SDimitry Andric     return;
1238fe6060f1SDimitry Andric 
1239fe6060f1SDimitry Andric   EmitDirectivesFlangImpl(DirLang, OS);
1240fe6060f1SDimitry Andric 
1241fe6060f1SDimitry Andric   GenerateClauseClassMacro(DirLang, OS);
1242fe6060f1SDimitry Andric 
1243fe6060f1SDimitry Andric   EmitDirectivesBasicImpl(DirLang, OS);
1244fe6060f1SDimitry Andric }
1245fe6060f1SDimitry Andric 
124606c3fb27SDimitry Andric static TableGen::Emitter::Opt
124706c3fb27SDimitry Andric     X("gen-directive-decl", EmitDirectivesDecl,
124806c3fb27SDimitry Andric       "Generate directive related declaration code (header file)");
124906c3fb27SDimitry Andric 
125006c3fb27SDimitry Andric static TableGen::Emitter::Opt
125106c3fb27SDimitry Andric     Y("gen-directive-impl", EmitDirectivesImpl,
125206c3fb27SDimitry Andric       "Generate directive related implementation code");
1253