xref: /freebsd-src/contrib/llvm-project/llvm/utils/TableGen/DirectiveEmitter.cpp (revision e8d8bef961a50d4dc22501cde4fb9fb0be1b2532)
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 
14*e8d8bef9SDimitry Andric #include "llvm/TableGen/DirectiveEmitter.h"
155ffd83dbSDimitry Andric #include "llvm/ADT/STLExtras.h"
165ffd83dbSDimitry Andric #include "llvm/ADT/SmallVector.h"
175ffd83dbSDimitry Andric #include "llvm/ADT/StringSet.h"
185ffd83dbSDimitry Andric #include "llvm/TableGen/Error.h"
195ffd83dbSDimitry Andric #include "llvm/TableGen/Record.h"
205ffd83dbSDimitry Andric #include "llvm/TableGen/TableGenBackend.h"
215ffd83dbSDimitry Andric 
225ffd83dbSDimitry Andric using namespace llvm;
235ffd83dbSDimitry Andric 
245ffd83dbSDimitry Andric namespace {
255ffd83dbSDimitry Andric // Simple RAII helper for defining ifdef-undef-endif scopes.
265ffd83dbSDimitry Andric class IfDefScope {
275ffd83dbSDimitry Andric public:
285ffd83dbSDimitry Andric   IfDefScope(StringRef Name, raw_ostream &OS) : Name(Name), OS(OS) {
295ffd83dbSDimitry Andric     OS << "#ifdef " << Name << "\n"
305ffd83dbSDimitry Andric        << "#undef " << Name << "\n";
315ffd83dbSDimitry Andric   }
325ffd83dbSDimitry Andric 
335ffd83dbSDimitry Andric   ~IfDefScope() { OS << "\n#endif // " << Name << "\n\n"; }
345ffd83dbSDimitry Andric 
355ffd83dbSDimitry Andric private:
365ffd83dbSDimitry Andric   StringRef Name;
375ffd83dbSDimitry Andric   raw_ostream &OS;
385ffd83dbSDimitry Andric };
395ffd83dbSDimitry Andric } // end anonymous namespace
405ffd83dbSDimitry Andric 
415ffd83dbSDimitry Andric namespace llvm {
425ffd83dbSDimitry Andric 
435ffd83dbSDimitry Andric // Generate enum class
445ffd83dbSDimitry Andric void GenerateEnumClass(const std::vector<Record *> &Records, raw_ostream &OS,
45*e8d8bef9SDimitry Andric                        StringRef Enum, StringRef Prefix,
46*e8d8bef9SDimitry Andric                        const DirectiveLanguage &DirLang) {
475ffd83dbSDimitry Andric   OS << "\n";
485ffd83dbSDimitry Andric   OS << "enum class " << Enum << " {\n";
495ffd83dbSDimitry Andric   for (const auto &R : Records) {
50*e8d8bef9SDimitry Andric     BaseRecord Rec{R};
51*e8d8bef9SDimitry Andric     OS << "  " << Prefix << Rec.getFormattedName() << ",\n";
525ffd83dbSDimitry Andric   }
535ffd83dbSDimitry Andric   OS << "};\n";
545ffd83dbSDimitry Andric   OS << "\n";
555ffd83dbSDimitry Andric   OS << "static constexpr std::size_t " << Enum
565ffd83dbSDimitry Andric      << "_enumSize = " << Records.size() << ";\n";
575ffd83dbSDimitry Andric 
585ffd83dbSDimitry Andric   // Make the enum values available in the defined namespace. This allows us to
595ffd83dbSDimitry Andric   // write something like Enum_X if we have a `using namespace <CppNamespace>`.
605ffd83dbSDimitry Andric   // At the same time we do not loose the strong type guarantees of the enum
615ffd83dbSDimitry Andric   // class, that is we cannot pass an unsigned as Directive without an explicit
625ffd83dbSDimitry Andric   // cast.
63*e8d8bef9SDimitry Andric   if (DirLang.hasMakeEnumAvailableInNamespace()) {
645ffd83dbSDimitry Andric     OS << "\n";
655ffd83dbSDimitry Andric     for (const auto &R : Records) {
66*e8d8bef9SDimitry Andric       BaseRecord Rec{R};
67*e8d8bef9SDimitry Andric       OS << "constexpr auto " << Prefix << Rec.getFormattedName() << " = "
68*e8d8bef9SDimitry Andric          << "llvm::" << DirLang.getCppNamespace() << "::" << Enum
69*e8d8bef9SDimitry Andric          << "::" << Prefix << Rec.getFormattedName() << ";\n";
705ffd83dbSDimitry Andric     }
715ffd83dbSDimitry Andric   }
725ffd83dbSDimitry Andric }
735ffd83dbSDimitry Andric 
74*e8d8bef9SDimitry Andric // Generate enums for values that clauses can take.
75*e8d8bef9SDimitry Andric // Also generate function declarations for get<Enum>Name(StringRef Str).
76*e8d8bef9SDimitry Andric void GenerateEnumClauseVal(const std::vector<Record *> &Records,
77*e8d8bef9SDimitry Andric                            raw_ostream &OS, const DirectiveLanguage &DirLang,
78*e8d8bef9SDimitry Andric                            std::string &EnumHelperFuncs) {
79*e8d8bef9SDimitry Andric   for (const auto &R : Records) {
80*e8d8bef9SDimitry Andric     Clause C{R};
81*e8d8bef9SDimitry Andric     const auto &ClauseVals = C.getClauseVals();
82*e8d8bef9SDimitry Andric     if (ClauseVals.size() <= 0)
83*e8d8bef9SDimitry Andric       continue;
84*e8d8bef9SDimitry Andric 
85*e8d8bef9SDimitry Andric     const auto &EnumName = C.getEnumName();
86*e8d8bef9SDimitry Andric     if (EnumName.size() == 0) {
87*e8d8bef9SDimitry Andric       PrintError("enumClauseValue field not set in Clause" +
88*e8d8bef9SDimitry Andric                  C.getFormattedName() + ".");
89*e8d8bef9SDimitry Andric       return;
90*e8d8bef9SDimitry Andric     }
91*e8d8bef9SDimitry Andric 
92*e8d8bef9SDimitry Andric     OS << "\n";
93*e8d8bef9SDimitry Andric     OS << "enum class " << EnumName << " {\n";
94*e8d8bef9SDimitry Andric     for (const auto &CV : ClauseVals) {
95*e8d8bef9SDimitry Andric       ClauseVal CVal{CV};
96*e8d8bef9SDimitry Andric       OS << "  " << CV->getName() << "=" << CVal.getValue() << ",\n";
97*e8d8bef9SDimitry Andric     }
98*e8d8bef9SDimitry Andric     OS << "};\n";
99*e8d8bef9SDimitry Andric 
100*e8d8bef9SDimitry Andric     if (DirLang.hasMakeEnumAvailableInNamespace()) {
101*e8d8bef9SDimitry Andric       OS << "\n";
102*e8d8bef9SDimitry Andric       for (const auto &CV : ClauseVals) {
103*e8d8bef9SDimitry Andric         OS << "constexpr auto " << CV->getName() << " = "
104*e8d8bef9SDimitry Andric            << "llvm::" << DirLang.getCppNamespace() << "::" << EnumName
105*e8d8bef9SDimitry Andric            << "::" << CV->getName() << ";\n";
106*e8d8bef9SDimitry Andric       }
107*e8d8bef9SDimitry Andric       EnumHelperFuncs += (llvm::Twine(EnumName) + llvm::Twine(" get") +
108*e8d8bef9SDimitry Andric                           llvm::Twine(EnumName) + llvm::Twine("(StringRef);\n"))
109*e8d8bef9SDimitry Andric                              .str();
110*e8d8bef9SDimitry Andric 
111*e8d8bef9SDimitry Andric       EnumHelperFuncs +=
112*e8d8bef9SDimitry Andric           (llvm::Twine("llvm::StringRef get") + llvm::Twine(DirLang.getName()) +
113*e8d8bef9SDimitry Andric            llvm::Twine(EnumName) + llvm::Twine("Name(") +
114*e8d8bef9SDimitry Andric            llvm::Twine(EnumName) + llvm::Twine(");\n"))
115*e8d8bef9SDimitry Andric               .str();
116*e8d8bef9SDimitry Andric     }
117*e8d8bef9SDimitry Andric   }
118*e8d8bef9SDimitry Andric }
119*e8d8bef9SDimitry Andric 
120*e8d8bef9SDimitry Andric bool HasDuplicateClauses(const std::vector<Record *> &Clauses,
121*e8d8bef9SDimitry Andric                          const Directive &Directive,
122*e8d8bef9SDimitry Andric                          llvm::StringSet<> &CrtClauses) {
123*e8d8bef9SDimitry Andric   bool HasError = false;
124*e8d8bef9SDimitry Andric   for (const auto &C : Clauses) {
125*e8d8bef9SDimitry Andric     VersionedClause VerClause{C};
126*e8d8bef9SDimitry Andric     const auto insRes = CrtClauses.insert(VerClause.getClause().getName());
127*e8d8bef9SDimitry Andric     if (!insRes.second) {
128*e8d8bef9SDimitry Andric       PrintError("Clause " + VerClause.getClause().getRecordName() +
129*e8d8bef9SDimitry Andric                  " already defined on directive " + Directive.getRecordName());
130*e8d8bef9SDimitry Andric       HasError = true;
131*e8d8bef9SDimitry Andric     }
132*e8d8bef9SDimitry Andric   }
133*e8d8bef9SDimitry Andric   return HasError;
134*e8d8bef9SDimitry Andric }
135*e8d8bef9SDimitry Andric 
136*e8d8bef9SDimitry Andric // Check for duplicate clauses in lists. Clauses cannot appear twice in the
137*e8d8bef9SDimitry Andric // three allowed list. Also, since required implies allowed, clauses cannot
138*e8d8bef9SDimitry Andric // appear in both the allowedClauses and requiredClauses lists.
139*e8d8bef9SDimitry Andric bool HasDuplicateClausesInDirectives(const std::vector<Record *> &Directives) {
140*e8d8bef9SDimitry Andric   bool HasDuplicate = false;
141*e8d8bef9SDimitry Andric   for (const auto &D : Directives) {
142*e8d8bef9SDimitry Andric     Directive Dir{D};
143*e8d8bef9SDimitry Andric     llvm::StringSet<> Clauses;
144*e8d8bef9SDimitry Andric     // Check for duplicates in the three allowed lists.
145*e8d8bef9SDimitry Andric     if (HasDuplicateClauses(Dir.getAllowedClauses(), Dir, Clauses) ||
146*e8d8bef9SDimitry Andric         HasDuplicateClauses(Dir.getAllowedOnceClauses(), Dir, Clauses) ||
147*e8d8bef9SDimitry Andric         HasDuplicateClauses(Dir.getAllowedExclusiveClauses(), Dir, Clauses)) {
148*e8d8bef9SDimitry Andric       HasDuplicate = true;
149*e8d8bef9SDimitry Andric     }
150*e8d8bef9SDimitry Andric     // Check for duplicate between allowedClauses and required
151*e8d8bef9SDimitry Andric     Clauses.clear();
152*e8d8bef9SDimitry Andric     if (HasDuplicateClauses(Dir.getAllowedClauses(), Dir, Clauses) ||
153*e8d8bef9SDimitry Andric         HasDuplicateClauses(Dir.getRequiredClauses(), Dir, Clauses)) {
154*e8d8bef9SDimitry Andric       HasDuplicate = true;
155*e8d8bef9SDimitry Andric     }
156*e8d8bef9SDimitry Andric     if (HasDuplicate)
157*e8d8bef9SDimitry Andric       PrintFatalError("One or more clauses are defined multiple times on"
158*e8d8bef9SDimitry Andric                       " directive " +
159*e8d8bef9SDimitry Andric                       Dir.getRecordName());
160*e8d8bef9SDimitry Andric   }
161*e8d8bef9SDimitry Andric 
162*e8d8bef9SDimitry Andric   return HasDuplicate;
163*e8d8bef9SDimitry Andric }
164*e8d8bef9SDimitry Andric 
165*e8d8bef9SDimitry Andric // Check consitency of records. Return true if an error has been detected.
166*e8d8bef9SDimitry Andric // Return false if the records are valid.
167*e8d8bef9SDimitry Andric bool DirectiveLanguage::HasValidityErrors() const {
168*e8d8bef9SDimitry Andric   if (getDirectiveLanguages().size() != 1) {
169*e8d8bef9SDimitry Andric     PrintFatalError("A single definition of DirectiveLanguage is needed.");
170*e8d8bef9SDimitry Andric     return true;
171*e8d8bef9SDimitry Andric   }
172*e8d8bef9SDimitry Andric 
173*e8d8bef9SDimitry Andric   return HasDuplicateClausesInDirectives(getDirectives());
174*e8d8bef9SDimitry Andric }
175*e8d8bef9SDimitry Andric 
1765ffd83dbSDimitry Andric // Generate the declaration section for the enumeration in the directive
1775ffd83dbSDimitry Andric // language
1785ffd83dbSDimitry Andric void EmitDirectivesDecl(RecordKeeper &Records, raw_ostream &OS) {
179*e8d8bef9SDimitry Andric   const auto DirLang = DirectiveLanguage{Records};
180*e8d8bef9SDimitry Andric   if (DirLang.HasValidityErrors())
1815ffd83dbSDimitry Andric     return;
1825ffd83dbSDimitry Andric 
183*e8d8bef9SDimitry Andric   OS << "#ifndef LLVM_" << DirLang.getName() << "_INC\n";
184*e8d8bef9SDimitry Andric   OS << "#define LLVM_" << DirLang.getName() << "_INC\n";
1855ffd83dbSDimitry Andric 
186*e8d8bef9SDimitry Andric   if (DirLang.hasEnableBitmaskEnumInNamespace())
1875ffd83dbSDimitry Andric     OS << "\n#include \"llvm/ADT/BitmaskEnum.h\"\n";
1885ffd83dbSDimitry Andric 
1895ffd83dbSDimitry Andric   OS << "\n";
1905ffd83dbSDimitry Andric   OS << "namespace llvm {\n";
1915ffd83dbSDimitry Andric   OS << "class StringRef;\n";
1925ffd83dbSDimitry Andric 
1935ffd83dbSDimitry Andric   // Open namespaces defined in the directive language
1945ffd83dbSDimitry Andric   llvm::SmallVector<StringRef, 2> Namespaces;
195*e8d8bef9SDimitry Andric   llvm::SplitString(DirLang.getCppNamespace(), Namespaces, "::");
1965ffd83dbSDimitry Andric   for (auto Ns : Namespaces)
1975ffd83dbSDimitry Andric     OS << "namespace " << Ns << " {\n";
1985ffd83dbSDimitry Andric 
199*e8d8bef9SDimitry Andric   if (DirLang.hasEnableBitmaskEnumInNamespace())
2005ffd83dbSDimitry Andric     OS << "\nLLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();\n";
2015ffd83dbSDimitry Andric 
2025ffd83dbSDimitry Andric   // Emit Directive enumeration
203*e8d8bef9SDimitry Andric   GenerateEnumClass(DirLang.getDirectives(), OS, "Directive",
204*e8d8bef9SDimitry Andric                     DirLang.getDirectivePrefix(), DirLang);
2055ffd83dbSDimitry Andric 
2065ffd83dbSDimitry Andric   // Emit Clause enumeration
207*e8d8bef9SDimitry Andric   GenerateEnumClass(DirLang.getClauses(), OS, "Clause",
208*e8d8bef9SDimitry Andric                     DirLang.getClausePrefix(), DirLang);
209*e8d8bef9SDimitry Andric 
210*e8d8bef9SDimitry Andric   // Emit ClauseVal enumeration
211*e8d8bef9SDimitry Andric   std::string EnumHelperFuncs;
212*e8d8bef9SDimitry Andric   GenerateEnumClauseVal(DirLang.getClauses(), OS, DirLang, EnumHelperFuncs);
2135ffd83dbSDimitry Andric 
2145ffd83dbSDimitry Andric   // Generic function signatures
2155ffd83dbSDimitry Andric   OS << "\n";
2165ffd83dbSDimitry Andric   OS << "// Enumeration helper functions\n";
217*e8d8bef9SDimitry Andric   OS << "Directive get" << DirLang.getName()
2185ffd83dbSDimitry Andric      << "DirectiveKind(llvm::StringRef Str);\n";
2195ffd83dbSDimitry Andric   OS << "\n";
220*e8d8bef9SDimitry Andric   OS << "llvm::StringRef get" << DirLang.getName()
2215ffd83dbSDimitry Andric      << "DirectiveName(Directive D);\n";
2225ffd83dbSDimitry Andric   OS << "\n";
223*e8d8bef9SDimitry Andric   OS << "Clause get" << DirLang.getName()
224*e8d8bef9SDimitry Andric      << "ClauseKind(llvm::StringRef Str);\n";
2255ffd83dbSDimitry Andric   OS << "\n";
226*e8d8bef9SDimitry Andric   OS << "llvm::StringRef get" << DirLang.getName() << "ClauseName(Clause C);\n";
2275ffd83dbSDimitry Andric   OS << "\n";
2285ffd83dbSDimitry Andric   OS << "/// Return true if \\p C is a valid clause for \\p D in version \\p "
2295ffd83dbSDimitry Andric      << "Version.\n";
2305ffd83dbSDimitry Andric   OS << "bool isAllowedClauseForDirective(Directive D, "
2315ffd83dbSDimitry Andric      << "Clause C, unsigned Version);\n";
2325ffd83dbSDimitry Andric   OS << "\n";
233*e8d8bef9SDimitry Andric   if (EnumHelperFuncs.length() > 0) {
234*e8d8bef9SDimitry Andric     OS << EnumHelperFuncs;
235*e8d8bef9SDimitry Andric     OS << "\n";
236*e8d8bef9SDimitry Andric   }
2375ffd83dbSDimitry Andric 
2385ffd83dbSDimitry Andric   // Closing namespaces
2395ffd83dbSDimitry Andric   for (auto Ns : llvm::reverse(Namespaces))
2405ffd83dbSDimitry Andric     OS << "} // namespace " << Ns << "\n";
2415ffd83dbSDimitry Andric 
2425ffd83dbSDimitry Andric   OS << "} // namespace llvm\n";
2435ffd83dbSDimitry Andric 
244*e8d8bef9SDimitry Andric   OS << "#endif // LLVM_" << DirLang.getName() << "_INC\n";
2455ffd83dbSDimitry Andric }
2465ffd83dbSDimitry Andric 
2475ffd83dbSDimitry Andric // Generate function implementation for get<Enum>Name(StringRef Str)
2485ffd83dbSDimitry Andric void GenerateGetName(const std::vector<Record *> &Records, raw_ostream &OS,
249*e8d8bef9SDimitry Andric                      StringRef Enum, const DirectiveLanguage &DirLang,
250*e8d8bef9SDimitry Andric                      StringRef Prefix) {
2515ffd83dbSDimitry Andric   OS << "\n";
252*e8d8bef9SDimitry Andric   OS << "llvm::StringRef llvm::" << DirLang.getCppNamespace() << "::get"
253*e8d8bef9SDimitry Andric      << DirLang.getName() << Enum << "Name(" << Enum << " Kind) {\n";
2545ffd83dbSDimitry Andric   OS << "  switch (Kind) {\n";
2555ffd83dbSDimitry Andric   for (const auto &R : Records) {
256*e8d8bef9SDimitry Andric     BaseRecord Rec{R};
257*e8d8bef9SDimitry Andric     OS << "    case " << Prefix << Rec.getFormattedName() << ":\n";
2585ffd83dbSDimitry Andric     OS << "      return \"";
259*e8d8bef9SDimitry Andric     if (Rec.getAlternativeName().empty())
260*e8d8bef9SDimitry Andric       OS << Rec.getName();
2615ffd83dbSDimitry Andric     else
262*e8d8bef9SDimitry Andric       OS << Rec.getAlternativeName();
2635ffd83dbSDimitry Andric     OS << "\";\n";
2645ffd83dbSDimitry Andric   }
2655ffd83dbSDimitry Andric   OS << "  }\n"; // switch
266*e8d8bef9SDimitry Andric   OS << "  llvm_unreachable(\"Invalid " << DirLang.getName() << " " << Enum
2675ffd83dbSDimitry Andric      << " kind\");\n";
2685ffd83dbSDimitry Andric   OS << "}\n";
2695ffd83dbSDimitry Andric }
2705ffd83dbSDimitry Andric 
2715ffd83dbSDimitry Andric // Generate function implementation for get<Enum>Kind(StringRef Str)
2725ffd83dbSDimitry Andric void GenerateGetKind(const std::vector<Record *> &Records, raw_ostream &OS,
273*e8d8bef9SDimitry Andric                      StringRef Enum, const DirectiveLanguage &DirLang,
274*e8d8bef9SDimitry Andric                      StringRef Prefix, bool ImplicitAsUnknown) {
2755ffd83dbSDimitry Andric 
276*e8d8bef9SDimitry Andric   auto DefaultIt = llvm::find_if(
277*e8d8bef9SDimitry Andric       Records, [](Record *R) { return R->getValueAsBit("isDefault") == true; });
2785ffd83dbSDimitry Andric 
2795ffd83dbSDimitry Andric   if (DefaultIt == Records.end()) {
280*e8d8bef9SDimitry Andric     PrintError("At least one " + Enum + " must be defined as default.");
2815ffd83dbSDimitry Andric     return;
2825ffd83dbSDimitry Andric   }
2835ffd83dbSDimitry Andric 
284*e8d8bef9SDimitry Andric   BaseRecord DefaultRec{(*DefaultIt)};
2855ffd83dbSDimitry Andric 
2865ffd83dbSDimitry Andric   OS << "\n";
287*e8d8bef9SDimitry Andric   OS << Enum << " llvm::" << DirLang.getCppNamespace() << "::get"
288*e8d8bef9SDimitry Andric      << DirLang.getName() << Enum << "Kind(llvm::StringRef Str) {\n";
2895ffd83dbSDimitry Andric   OS << "  return llvm::StringSwitch<" << Enum << ">(Str)\n";
2905ffd83dbSDimitry Andric 
2915ffd83dbSDimitry Andric   for (const auto &R : Records) {
292*e8d8bef9SDimitry Andric     BaseRecord Rec{R};
2935ffd83dbSDimitry Andric     if (ImplicitAsUnknown && R->getValueAsBit("isImplicit")) {
294*e8d8bef9SDimitry Andric       OS << "    .Case(\"" << Rec.getName() << "\"," << Prefix
295*e8d8bef9SDimitry Andric          << DefaultRec.getFormattedName() << ")\n";
2965ffd83dbSDimitry Andric     } else {
297*e8d8bef9SDimitry Andric       OS << "    .Case(\"" << Rec.getName() << "\"," << Prefix
298*e8d8bef9SDimitry Andric          << Rec.getFormattedName() << ")\n";
299*e8d8bef9SDimitry Andric     }
300*e8d8bef9SDimitry Andric   }
301*e8d8bef9SDimitry Andric   OS << "    .Default(" << Prefix << DefaultRec.getFormattedName() << ");\n";
302*e8d8bef9SDimitry Andric   OS << "}\n";
303*e8d8bef9SDimitry Andric }
304*e8d8bef9SDimitry Andric 
305*e8d8bef9SDimitry Andric // Generate function implementation for get<ClauseVal>Kind(StringRef Str)
306*e8d8bef9SDimitry Andric void GenerateGetKindClauseVal(const DirectiveLanguage &DirLang,
307*e8d8bef9SDimitry Andric                               raw_ostream &OS) {
308*e8d8bef9SDimitry Andric   for (const auto &R : DirLang.getClauses()) {
309*e8d8bef9SDimitry Andric     Clause C{R};
310*e8d8bef9SDimitry Andric     const auto &ClauseVals = C.getClauseVals();
311*e8d8bef9SDimitry Andric     if (ClauseVals.size() <= 0)
312*e8d8bef9SDimitry Andric       continue;
313*e8d8bef9SDimitry Andric 
314*e8d8bef9SDimitry Andric     auto DefaultIt = llvm::find_if(ClauseVals, [](Record *CV) {
315*e8d8bef9SDimitry Andric       return CV->getValueAsBit("isDefault") == true;
316*e8d8bef9SDimitry Andric     });
317*e8d8bef9SDimitry Andric 
318*e8d8bef9SDimitry Andric     if (DefaultIt == ClauseVals.end()) {
319*e8d8bef9SDimitry Andric       PrintError("At least one val in Clause " + C.getFormattedName() +
320*e8d8bef9SDimitry Andric                  " must be defined as default.");
321*e8d8bef9SDimitry Andric       return;
322*e8d8bef9SDimitry Andric     }
323*e8d8bef9SDimitry Andric     const auto DefaultName = (*DefaultIt)->getName();
324*e8d8bef9SDimitry Andric 
325*e8d8bef9SDimitry Andric     const auto &EnumName = C.getEnumName();
326*e8d8bef9SDimitry Andric     if (EnumName.size() == 0) {
327*e8d8bef9SDimitry Andric       PrintError("enumClauseValue field not set in Clause" +
328*e8d8bef9SDimitry Andric                  C.getFormattedName() + ".");
329*e8d8bef9SDimitry Andric       return;
330*e8d8bef9SDimitry Andric     }
331*e8d8bef9SDimitry Andric 
332*e8d8bef9SDimitry Andric     OS << "\n";
333*e8d8bef9SDimitry Andric     OS << EnumName << " llvm::" << DirLang.getCppNamespace() << "::get"
334*e8d8bef9SDimitry Andric        << EnumName << "(llvm::StringRef Str) {\n";
335*e8d8bef9SDimitry Andric     OS << "  return llvm::StringSwitch<" << EnumName << ">(Str)\n";
336*e8d8bef9SDimitry Andric     for (const auto &CV : ClauseVals) {
337*e8d8bef9SDimitry Andric       ClauseVal CVal{CV};
338*e8d8bef9SDimitry Andric       OS << "    .Case(\"" << CVal.getFormattedName() << "\"," << CV->getName()
3395ffd83dbSDimitry Andric          << ")\n";
3405ffd83dbSDimitry Andric     }
341*e8d8bef9SDimitry Andric     OS << "    .Default(" << DefaultName << ");\n";
3425ffd83dbSDimitry Andric     OS << "}\n";
343*e8d8bef9SDimitry Andric 
344*e8d8bef9SDimitry Andric     OS << "\n";
345*e8d8bef9SDimitry Andric     OS << "llvm::StringRef llvm::" << DirLang.getCppNamespace() << "::get"
346*e8d8bef9SDimitry Andric        << DirLang.getName() << EnumName
347*e8d8bef9SDimitry Andric        << "Name(llvm::" << DirLang.getCppNamespace() << "::" << EnumName
348*e8d8bef9SDimitry Andric        << " x) {\n";
349*e8d8bef9SDimitry Andric     OS << "  switch (x) {\n";
350*e8d8bef9SDimitry Andric     for (const auto &CV : ClauseVals) {
351*e8d8bef9SDimitry Andric       ClauseVal CVal{CV};
352*e8d8bef9SDimitry Andric       OS << "    case " << CV->getName() << ":\n";
353*e8d8bef9SDimitry Andric       OS << "      return \"" << CVal.getFormattedName() << "\";\n";
354*e8d8bef9SDimitry Andric     }
355*e8d8bef9SDimitry Andric     OS << "  }\n"; // switch
356*e8d8bef9SDimitry Andric     OS << "  llvm_unreachable(\"Invalid " << DirLang.getName() << " "
357*e8d8bef9SDimitry Andric        << EnumName << " kind\");\n";
358*e8d8bef9SDimitry Andric     OS << "}\n";
359*e8d8bef9SDimitry Andric   }
3605ffd83dbSDimitry Andric }
3615ffd83dbSDimitry Andric 
3625ffd83dbSDimitry Andric void GenerateCaseForVersionedClauses(const std::vector<Record *> &Clauses,
3635ffd83dbSDimitry Andric                                      raw_ostream &OS, StringRef DirectiveName,
364*e8d8bef9SDimitry Andric                                      const DirectiveLanguage &DirLang,
3655ffd83dbSDimitry Andric                                      llvm::StringSet<> &Cases) {
3665ffd83dbSDimitry Andric   for (const auto &C : Clauses) {
367*e8d8bef9SDimitry Andric     VersionedClause VerClause{C};
3685ffd83dbSDimitry Andric 
369*e8d8bef9SDimitry Andric     const auto ClauseFormattedName = VerClause.getClause().getFormattedName();
370*e8d8bef9SDimitry Andric 
371*e8d8bef9SDimitry Andric     if (Cases.find(ClauseFormattedName) == Cases.end()) {
372*e8d8bef9SDimitry Andric       Cases.insert(ClauseFormattedName);
373*e8d8bef9SDimitry Andric       OS << "        case " << DirLang.getClausePrefix() << ClauseFormattedName
374*e8d8bef9SDimitry Andric          << ":\n";
375*e8d8bef9SDimitry Andric       OS << "          return " << VerClause.getMinVersion()
376*e8d8bef9SDimitry Andric          << " <= Version && " << VerClause.getMaxVersion() << " >= Version;\n";
3775ffd83dbSDimitry Andric     }
3785ffd83dbSDimitry Andric   }
3795ffd83dbSDimitry Andric }
3805ffd83dbSDimitry Andric 
3815ffd83dbSDimitry Andric // Generate the isAllowedClauseForDirective function implementation.
382*e8d8bef9SDimitry Andric void GenerateIsAllowedClause(const DirectiveLanguage &DirLang,
383*e8d8bef9SDimitry Andric                              raw_ostream &OS) {
3845ffd83dbSDimitry Andric   OS << "\n";
385*e8d8bef9SDimitry Andric   OS << "bool llvm::" << DirLang.getCppNamespace()
386*e8d8bef9SDimitry Andric      << "::isAllowedClauseForDirective("
3875ffd83dbSDimitry Andric      << "Directive D, Clause C, unsigned Version) {\n";
388*e8d8bef9SDimitry Andric   OS << "  assert(unsigned(D) <= llvm::" << DirLang.getCppNamespace()
3895ffd83dbSDimitry Andric      << "::Directive_enumSize);\n";
390*e8d8bef9SDimitry Andric   OS << "  assert(unsigned(C) <= llvm::" << DirLang.getCppNamespace()
3915ffd83dbSDimitry Andric      << "::Clause_enumSize);\n";
3925ffd83dbSDimitry Andric 
3935ffd83dbSDimitry Andric   OS << "  switch (D) {\n";
3945ffd83dbSDimitry Andric 
395*e8d8bef9SDimitry Andric   for (const auto &D : DirLang.getDirectives()) {
396*e8d8bef9SDimitry Andric     Directive Dir{D};
3975ffd83dbSDimitry Andric 
398*e8d8bef9SDimitry Andric     OS << "    case " << DirLang.getDirectivePrefix() << Dir.getFormattedName()
3995ffd83dbSDimitry Andric        << ":\n";
400*e8d8bef9SDimitry Andric     if (Dir.getAllowedClauses().size() == 0 &&
401*e8d8bef9SDimitry Andric         Dir.getAllowedOnceClauses().size() == 0 &&
402*e8d8bef9SDimitry Andric         Dir.getAllowedExclusiveClauses().size() == 0 &&
403*e8d8bef9SDimitry Andric         Dir.getRequiredClauses().size() == 0) {
4045ffd83dbSDimitry Andric       OS << "      return false;\n";
4055ffd83dbSDimitry Andric     } else {
4065ffd83dbSDimitry Andric       OS << "      switch (C) {\n";
4075ffd83dbSDimitry Andric 
4085ffd83dbSDimitry Andric       llvm::StringSet<> Cases;
4095ffd83dbSDimitry Andric 
410*e8d8bef9SDimitry Andric       GenerateCaseForVersionedClauses(Dir.getAllowedClauses(), OS,
411*e8d8bef9SDimitry Andric                                       Dir.getName(), DirLang, Cases);
4125ffd83dbSDimitry Andric 
413*e8d8bef9SDimitry Andric       GenerateCaseForVersionedClauses(Dir.getAllowedOnceClauses(), OS,
414*e8d8bef9SDimitry Andric                                       Dir.getName(), DirLang, Cases);
4155ffd83dbSDimitry Andric 
416*e8d8bef9SDimitry Andric       GenerateCaseForVersionedClauses(Dir.getAllowedExclusiveClauses(), OS,
417*e8d8bef9SDimitry Andric                                       Dir.getName(), DirLang, Cases);
4185ffd83dbSDimitry Andric 
419*e8d8bef9SDimitry Andric       GenerateCaseForVersionedClauses(Dir.getRequiredClauses(), OS,
420*e8d8bef9SDimitry Andric                                       Dir.getName(), DirLang, Cases);
4215ffd83dbSDimitry Andric 
4225ffd83dbSDimitry Andric       OS << "        default:\n";
4235ffd83dbSDimitry Andric       OS << "          return false;\n";
4245ffd83dbSDimitry Andric       OS << "      }\n"; // End of clauses switch
4255ffd83dbSDimitry Andric     }
4265ffd83dbSDimitry Andric     OS << "      break;\n";
4275ffd83dbSDimitry Andric   }
4285ffd83dbSDimitry Andric 
4295ffd83dbSDimitry Andric   OS << "  }\n"; // End of directives switch
430*e8d8bef9SDimitry Andric   OS << "  llvm_unreachable(\"Invalid " << DirLang.getName()
4315ffd83dbSDimitry Andric      << " Directive kind\");\n";
4325ffd83dbSDimitry Andric   OS << "}\n"; // End of function isAllowedClauseForDirective
4335ffd83dbSDimitry Andric }
4345ffd83dbSDimitry Andric 
4355ffd83dbSDimitry Andric // Generate a simple enum set with the give clauses.
4365ffd83dbSDimitry Andric void GenerateClauseSet(const std::vector<Record *> &Clauses, raw_ostream &OS,
437*e8d8bef9SDimitry Andric                        StringRef ClauseSetPrefix, Directive &Dir,
438*e8d8bef9SDimitry Andric                        const DirectiveLanguage &DirLang) {
4395ffd83dbSDimitry Andric 
4405ffd83dbSDimitry Andric   OS << "\n";
441*e8d8bef9SDimitry Andric   OS << "  static " << DirLang.getClauseEnumSetClass() << " " << ClauseSetPrefix
442*e8d8bef9SDimitry Andric      << DirLang.getDirectivePrefix() << Dir.getFormattedName() << " {\n";
4435ffd83dbSDimitry Andric 
4445ffd83dbSDimitry Andric   for (const auto &C : Clauses) {
445*e8d8bef9SDimitry Andric     VersionedClause VerClause{C};
446*e8d8bef9SDimitry Andric     OS << "    llvm::" << DirLang.getCppNamespace()
447*e8d8bef9SDimitry Andric        << "::Clause::" << DirLang.getClausePrefix()
448*e8d8bef9SDimitry Andric        << VerClause.getClause().getFormattedName() << ",\n";
4495ffd83dbSDimitry Andric   }
4505ffd83dbSDimitry Andric   OS << "  };\n";
4515ffd83dbSDimitry Andric }
4525ffd83dbSDimitry Andric 
4535ffd83dbSDimitry Andric // Generate an enum set for the 4 kinds of clauses linked to a directive.
454*e8d8bef9SDimitry Andric void GenerateDirectiveClauseSets(const DirectiveLanguage &DirLang,
455*e8d8bef9SDimitry Andric                                  raw_ostream &OS) {
4565ffd83dbSDimitry Andric 
4575ffd83dbSDimitry Andric   IfDefScope Scope("GEN_FLANG_DIRECTIVE_CLAUSE_SETS", OS);
4585ffd83dbSDimitry Andric 
4595ffd83dbSDimitry Andric   OS << "\n";
4605ffd83dbSDimitry Andric   OS << "namespace llvm {\n";
4615ffd83dbSDimitry Andric 
4625ffd83dbSDimitry Andric   // Open namespaces defined in the directive language.
4635ffd83dbSDimitry Andric   llvm::SmallVector<StringRef, 2> Namespaces;
464*e8d8bef9SDimitry Andric   llvm::SplitString(DirLang.getCppNamespace(), Namespaces, "::");
4655ffd83dbSDimitry Andric   for (auto Ns : Namespaces)
4665ffd83dbSDimitry Andric     OS << "namespace " << Ns << " {\n";
4675ffd83dbSDimitry Andric 
468*e8d8bef9SDimitry Andric   for (const auto &D : DirLang.getDirectives()) {
469*e8d8bef9SDimitry Andric     Directive Dir{D};
4705ffd83dbSDimitry Andric 
4715ffd83dbSDimitry Andric     OS << "\n";
472*e8d8bef9SDimitry Andric     OS << "  // Sets for " << Dir.getName() << "\n";
4735ffd83dbSDimitry Andric 
474*e8d8bef9SDimitry Andric     GenerateClauseSet(Dir.getAllowedClauses(), OS, "allowedClauses_", Dir,
475*e8d8bef9SDimitry Andric                       DirLang);
476*e8d8bef9SDimitry Andric     GenerateClauseSet(Dir.getAllowedOnceClauses(), OS, "allowedOnceClauses_",
477*e8d8bef9SDimitry Andric                       Dir, DirLang);
478*e8d8bef9SDimitry Andric     GenerateClauseSet(Dir.getAllowedExclusiveClauses(), OS,
479*e8d8bef9SDimitry Andric                       "allowedExclusiveClauses_", Dir, DirLang);
480*e8d8bef9SDimitry Andric     GenerateClauseSet(Dir.getRequiredClauses(), OS, "requiredClauses_", Dir,
481*e8d8bef9SDimitry Andric                       DirLang);
4825ffd83dbSDimitry Andric   }
4835ffd83dbSDimitry Andric 
4845ffd83dbSDimitry Andric   // Closing namespaces
4855ffd83dbSDimitry Andric   for (auto Ns : llvm::reverse(Namespaces))
4865ffd83dbSDimitry Andric     OS << "} // namespace " << Ns << "\n";
4875ffd83dbSDimitry Andric 
4885ffd83dbSDimitry Andric   OS << "} // namespace llvm\n";
4895ffd83dbSDimitry Andric }
4905ffd83dbSDimitry Andric 
4915ffd83dbSDimitry Andric // Generate a map of directive (key) with DirectiveClauses struct as values.
4925ffd83dbSDimitry Andric // The struct holds the 4 sets of enumeration for the 4 kinds of clauses
4935ffd83dbSDimitry Andric // allowances (allowed, allowed once, allowed exclusive and required).
494*e8d8bef9SDimitry Andric void GenerateDirectiveClauseMap(const DirectiveLanguage &DirLang,
495*e8d8bef9SDimitry Andric                                 raw_ostream &OS) {
4965ffd83dbSDimitry Andric 
4975ffd83dbSDimitry Andric   IfDefScope Scope("GEN_FLANG_DIRECTIVE_CLAUSE_MAP", OS);
4985ffd83dbSDimitry Andric 
4995ffd83dbSDimitry Andric   OS << "\n";
5005ffd83dbSDimitry Andric   OS << "{\n";
501*e8d8bef9SDimitry Andric 
502*e8d8bef9SDimitry Andric   for (const auto &D : DirLang.getDirectives()) {
503*e8d8bef9SDimitry Andric     Directive Dir{D};
504*e8d8bef9SDimitry Andric     OS << "  {llvm::" << DirLang.getCppNamespace()
505*e8d8bef9SDimitry Andric        << "::Directive::" << DirLang.getDirectivePrefix()
506*e8d8bef9SDimitry Andric        << Dir.getFormattedName() << ",\n";
507*e8d8bef9SDimitry Andric     OS << "    {\n";
508*e8d8bef9SDimitry Andric     OS << "      llvm::" << DirLang.getCppNamespace() << "::allowedClauses_"
509*e8d8bef9SDimitry Andric        << DirLang.getDirectivePrefix() << Dir.getFormattedName() << ",\n";
510*e8d8bef9SDimitry Andric     OS << "      llvm::" << DirLang.getCppNamespace() << "::allowedOnceClauses_"
511*e8d8bef9SDimitry Andric        << DirLang.getDirectivePrefix() << Dir.getFormattedName() << ",\n";
512*e8d8bef9SDimitry Andric     OS << "      llvm::" << DirLang.getCppNamespace()
513*e8d8bef9SDimitry Andric        << "::allowedExclusiveClauses_" << DirLang.getDirectivePrefix()
514*e8d8bef9SDimitry Andric        << Dir.getFormattedName() << ",\n";
515*e8d8bef9SDimitry Andric     OS << "      llvm::" << DirLang.getCppNamespace() << "::requiredClauses_"
516*e8d8bef9SDimitry Andric        << DirLang.getDirectivePrefix() << Dir.getFormattedName() << ",\n";
5175ffd83dbSDimitry Andric     OS << "    }\n";
5185ffd83dbSDimitry Andric     OS << "  },\n";
5195ffd83dbSDimitry Andric   }
5205ffd83dbSDimitry Andric 
521*e8d8bef9SDimitry Andric   OS << "}\n";
5225ffd83dbSDimitry Andric }
5235ffd83dbSDimitry Andric 
524*e8d8bef9SDimitry Andric // Generate classes entry for Flang clauses in the Flang parse-tree
525*e8d8bef9SDimitry Andric // If the clause as a non-generic class, no entry is generated.
526*e8d8bef9SDimitry Andric // If the clause does not hold a value, an EMPTY_CLASS is used.
527*e8d8bef9SDimitry Andric // If the clause class is generic then a WRAPPER_CLASS is used. When the value
528*e8d8bef9SDimitry Andric // is optional, the value class is wrapped into a std::optional.
529*e8d8bef9SDimitry Andric void GenerateFlangClauseParserClass(const DirectiveLanguage &DirLang,
530*e8d8bef9SDimitry Andric                                     raw_ostream &OS) {
531*e8d8bef9SDimitry Andric 
532*e8d8bef9SDimitry Andric   IfDefScope Scope("GEN_FLANG_CLAUSE_PARSER_CLASSES", OS);
533*e8d8bef9SDimitry Andric 
534*e8d8bef9SDimitry Andric   OS << "\n";
535*e8d8bef9SDimitry Andric 
536*e8d8bef9SDimitry Andric   for (const auto &C : DirLang.getClauses()) {
537*e8d8bef9SDimitry Andric     Clause Clause{C};
538*e8d8bef9SDimitry Andric     if (!Clause.getFlangClass().empty()) {
539*e8d8bef9SDimitry Andric       OS << "WRAPPER_CLASS(" << Clause.getFormattedParserClassName() << ", ";
540*e8d8bef9SDimitry Andric       if (Clause.isValueOptional() && Clause.isValueList()) {
541*e8d8bef9SDimitry Andric         OS << "std::optional<std::list<" << Clause.getFlangClass() << ">>";
542*e8d8bef9SDimitry Andric       } else if (Clause.isValueOptional()) {
543*e8d8bef9SDimitry Andric         OS << "std::optional<" << Clause.getFlangClass() << ">";
544*e8d8bef9SDimitry Andric       } else if (Clause.isValueList()) {
545*e8d8bef9SDimitry Andric         OS << "std::list<" << Clause.getFlangClass() << ">";
546*e8d8bef9SDimitry Andric       } else {
547*e8d8bef9SDimitry Andric         OS << Clause.getFlangClass();
548*e8d8bef9SDimitry Andric       }
549*e8d8bef9SDimitry Andric     } else {
550*e8d8bef9SDimitry Andric       OS << "EMPTY_CLASS(" << Clause.getFormattedParserClassName();
551*e8d8bef9SDimitry Andric     }
552*e8d8bef9SDimitry Andric     OS << ");\n";
553*e8d8bef9SDimitry Andric   }
554*e8d8bef9SDimitry Andric }
555*e8d8bef9SDimitry Andric 
556*e8d8bef9SDimitry Andric // Generate a list of the different clause classes for Flang.
557*e8d8bef9SDimitry Andric void GenerateFlangClauseParserClassList(const DirectiveLanguage &DirLang,
558*e8d8bef9SDimitry Andric                                         raw_ostream &OS) {
559*e8d8bef9SDimitry Andric 
560*e8d8bef9SDimitry Andric   IfDefScope Scope("GEN_FLANG_CLAUSE_PARSER_CLASSES_LIST", OS);
561*e8d8bef9SDimitry Andric 
562*e8d8bef9SDimitry Andric   OS << "\n";
563*e8d8bef9SDimitry Andric   llvm::interleaveComma(DirLang.getClauses(), OS, [&](Record *C) {
564*e8d8bef9SDimitry Andric     Clause Clause{C};
565*e8d8bef9SDimitry Andric     OS << Clause.getFormattedParserClassName() << "\n";
566*e8d8bef9SDimitry Andric   });
567*e8d8bef9SDimitry Andric }
568*e8d8bef9SDimitry Andric 
569*e8d8bef9SDimitry Andric // Generate dump node list for the clauses holding a generic class name.
570*e8d8bef9SDimitry Andric void GenerateFlangClauseDump(const DirectiveLanguage &DirLang,
571*e8d8bef9SDimitry Andric                              raw_ostream &OS) {
572*e8d8bef9SDimitry Andric 
573*e8d8bef9SDimitry Andric   IfDefScope Scope("GEN_FLANG_DUMP_PARSE_TREE_CLAUSES", OS);
574*e8d8bef9SDimitry Andric 
575*e8d8bef9SDimitry Andric   OS << "\n";
576*e8d8bef9SDimitry Andric   for (const auto &C : DirLang.getClauses()) {
577*e8d8bef9SDimitry Andric     Clause Clause{C};
578*e8d8bef9SDimitry Andric     OS << "NODE(" << DirLang.getFlangClauseBaseClass() << ", "
579*e8d8bef9SDimitry Andric        << Clause.getFormattedParserClassName() << ")\n";
580*e8d8bef9SDimitry Andric   }
581*e8d8bef9SDimitry Andric }
582*e8d8bef9SDimitry Andric 
583*e8d8bef9SDimitry Andric // Generate Unparse functions for clauses classes in the Flang parse-tree
584*e8d8bef9SDimitry Andric // If the clause is a non-generic class, no entry is generated.
585*e8d8bef9SDimitry Andric void GenerateFlangClauseUnparse(const DirectiveLanguage &DirLang,
586*e8d8bef9SDimitry Andric                                 raw_ostream &OS) {
587*e8d8bef9SDimitry Andric 
588*e8d8bef9SDimitry Andric   IfDefScope Scope("GEN_FLANG_CLAUSE_UNPARSE", OS);
589*e8d8bef9SDimitry Andric 
590*e8d8bef9SDimitry Andric   OS << "\n";
591*e8d8bef9SDimitry Andric 
592*e8d8bef9SDimitry Andric   for (const auto &C : DirLang.getClauses()) {
593*e8d8bef9SDimitry Andric     Clause Clause{C};
594*e8d8bef9SDimitry Andric     if (!Clause.getFlangClass().empty()) {
595*e8d8bef9SDimitry Andric       if (Clause.isValueOptional() && Clause.getDefaultValue().empty()) {
596*e8d8bef9SDimitry Andric         OS << "void Unparse(const " << DirLang.getFlangClauseBaseClass()
597*e8d8bef9SDimitry Andric            << "::" << Clause.getFormattedParserClassName() << " &x) {\n";
598*e8d8bef9SDimitry Andric         OS << "  Word(\"" << Clause.getName().upper() << "\");\n";
599*e8d8bef9SDimitry Andric 
600*e8d8bef9SDimitry Andric         OS << "  Walk(\"(\", x.v, \")\");\n";
601*e8d8bef9SDimitry Andric         OS << "}\n";
602*e8d8bef9SDimitry Andric       } else if (Clause.isValueOptional()) {
603*e8d8bef9SDimitry Andric         OS << "void Unparse(const " << DirLang.getFlangClauseBaseClass()
604*e8d8bef9SDimitry Andric            << "::" << Clause.getFormattedParserClassName() << " &x) {\n";
605*e8d8bef9SDimitry Andric         OS << "  Word(\"" << Clause.getName().upper() << "\");\n";
606*e8d8bef9SDimitry Andric         OS << "  Put(\"(\");\n";
607*e8d8bef9SDimitry Andric         OS << "  if (x.v.has_value())\n";
608*e8d8bef9SDimitry Andric         if (Clause.isValueList())
609*e8d8bef9SDimitry Andric           OS << "    Walk(x.v, \",\");\n";
610*e8d8bef9SDimitry Andric         else
611*e8d8bef9SDimitry Andric           OS << "    Walk(x.v);\n";
612*e8d8bef9SDimitry Andric         OS << "  else\n";
613*e8d8bef9SDimitry Andric         OS << "    Put(\"" << Clause.getDefaultValue() << "\");\n";
614*e8d8bef9SDimitry Andric         OS << "  Put(\")\");\n";
615*e8d8bef9SDimitry Andric         OS << "}\n";
616*e8d8bef9SDimitry Andric       } else {
617*e8d8bef9SDimitry Andric         OS << "void Unparse(const " << DirLang.getFlangClauseBaseClass()
618*e8d8bef9SDimitry Andric            << "::" << Clause.getFormattedParserClassName() << " &x) {\n";
619*e8d8bef9SDimitry Andric         OS << "  Word(\"" << Clause.getName().upper() << "\");\n";
620*e8d8bef9SDimitry Andric         OS << "  Put(\"(\");\n";
621*e8d8bef9SDimitry Andric         if (Clause.isValueList())
622*e8d8bef9SDimitry Andric           OS << "  Walk(x.v, \",\");\n";
623*e8d8bef9SDimitry Andric         else
624*e8d8bef9SDimitry Andric           OS << "  Walk(x.v);\n";
625*e8d8bef9SDimitry Andric         OS << "  Put(\")\");\n";
626*e8d8bef9SDimitry Andric         OS << "}\n";
627*e8d8bef9SDimitry Andric       }
628*e8d8bef9SDimitry Andric     } else {
629*e8d8bef9SDimitry Andric       OS << "void Before(const " << DirLang.getFlangClauseBaseClass()
630*e8d8bef9SDimitry Andric          << "::" << Clause.getFormattedParserClassName() << " &) { Word(\""
631*e8d8bef9SDimitry Andric          << Clause.getName().upper() << "\"); }\n";
632*e8d8bef9SDimitry Andric     }
633*e8d8bef9SDimitry Andric   }
634*e8d8bef9SDimitry Andric }
635*e8d8bef9SDimitry Andric 
636*e8d8bef9SDimitry Andric // Generate the implementation section for the enumeration in the directive
6375ffd83dbSDimitry Andric // language
638*e8d8bef9SDimitry Andric void EmitDirectivesFlangImpl(const DirectiveLanguage &DirLang,
639*e8d8bef9SDimitry Andric                              raw_ostream &OS) {
6405ffd83dbSDimitry Andric 
641*e8d8bef9SDimitry Andric   GenerateDirectiveClauseSets(DirLang, OS);
6425ffd83dbSDimitry Andric 
643*e8d8bef9SDimitry Andric   GenerateDirectiveClauseMap(DirLang, OS);
644*e8d8bef9SDimitry Andric 
645*e8d8bef9SDimitry Andric   GenerateFlangClauseParserClass(DirLang, OS);
646*e8d8bef9SDimitry Andric 
647*e8d8bef9SDimitry Andric   GenerateFlangClauseParserClassList(DirLang, OS);
648*e8d8bef9SDimitry Andric 
649*e8d8bef9SDimitry Andric   GenerateFlangClauseDump(DirLang, OS);
650*e8d8bef9SDimitry Andric 
651*e8d8bef9SDimitry Andric   GenerateFlangClauseUnparse(DirLang, OS);
6525ffd83dbSDimitry Andric }
6535ffd83dbSDimitry Andric 
654*e8d8bef9SDimitry Andric void GenerateClauseClassMacro(const DirectiveLanguage &DirLang,
655*e8d8bef9SDimitry Andric                               raw_ostream &OS) {
656*e8d8bef9SDimitry Andric   // Generate macros style information for legacy code in clang
657*e8d8bef9SDimitry Andric   IfDefScope Scope("GEN_CLANG_CLAUSE_CLASS", OS);
658*e8d8bef9SDimitry Andric 
659*e8d8bef9SDimitry Andric   OS << "\n";
660*e8d8bef9SDimitry Andric 
661*e8d8bef9SDimitry Andric   OS << "#ifndef CLAUSE\n";
662*e8d8bef9SDimitry Andric   OS << "#define CLAUSE(Enum, Str, Implicit)\n";
663*e8d8bef9SDimitry Andric   OS << "#endif\n";
664*e8d8bef9SDimitry Andric   OS << "#ifndef CLAUSE_CLASS\n";
665*e8d8bef9SDimitry Andric   OS << "#define CLAUSE_CLASS(Enum, Str, Class)\n";
666*e8d8bef9SDimitry Andric   OS << "#endif\n";
667*e8d8bef9SDimitry Andric   OS << "#ifndef CLAUSE_NO_CLASS\n";
668*e8d8bef9SDimitry Andric   OS << "#define CLAUSE_NO_CLASS(Enum, Str)\n";
669*e8d8bef9SDimitry Andric   OS << "#endif\n";
670*e8d8bef9SDimitry Andric   OS << "\n";
671*e8d8bef9SDimitry Andric   OS << "#define __CLAUSE(Name, Class)                      \\\n";
672*e8d8bef9SDimitry Andric   OS << "  CLAUSE(" << DirLang.getClausePrefix()
673*e8d8bef9SDimitry Andric      << "##Name, #Name, /* Implicit */ false) \\\n";
674*e8d8bef9SDimitry Andric   OS << "  CLAUSE_CLASS(" << DirLang.getClausePrefix()
675*e8d8bef9SDimitry Andric      << "##Name, #Name, Class)\n";
676*e8d8bef9SDimitry Andric   OS << "#define __CLAUSE_NO_CLASS(Name)                    \\\n";
677*e8d8bef9SDimitry Andric   OS << "  CLAUSE(" << DirLang.getClausePrefix()
678*e8d8bef9SDimitry Andric      << "##Name, #Name, /* Implicit */ false) \\\n";
679*e8d8bef9SDimitry Andric   OS << "  CLAUSE_NO_CLASS(" << DirLang.getClausePrefix() << "##Name, #Name)\n";
680*e8d8bef9SDimitry Andric   OS << "#define __IMPLICIT_CLAUSE_CLASS(Name, Str, Class)  \\\n";
681*e8d8bef9SDimitry Andric   OS << "  CLAUSE(" << DirLang.getClausePrefix()
682*e8d8bef9SDimitry Andric      << "##Name, Str, /* Implicit */ true)    \\\n";
683*e8d8bef9SDimitry Andric   OS << "  CLAUSE_CLASS(" << DirLang.getClausePrefix()
684*e8d8bef9SDimitry Andric      << "##Name, Str, Class)\n";
685*e8d8bef9SDimitry Andric   OS << "#define __IMPLICIT_CLAUSE_NO_CLASS(Name, Str)      \\\n";
686*e8d8bef9SDimitry Andric   OS << "  CLAUSE(" << DirLang.getClausePrefix()
687*e8d8bef9SDimitry Andric      << "##Name, Str, /* Implicit */ true)    \\\n";
688*e8d8bef9SDimitry Andric   OS << "  CLAUSE_NO_CLASS(" << DirLang.getClausePrefix() << "##Name, Str)\n";
689*e8d8bef9SDimitry Andric   OS << "\n";
690*e8d8bef9SDimitry Andric 
691*e8d8bef9SDimitry Andric   for (const auto &R : DirLang.getClauses()) {
692*e8d8bef9SDimitry Andric     Clause C{R};
693*e8d8bef9SDimitry Andric     if (C.getClangClass().empty()) { // NO_CLASS
694*e8d8bef9SDimitry Andric       if (C.isImplicit()) {
695*e8d8bef9SDimitry Andric         OS << "__IMPLICIT_CLAUSE_NO_CLASS(" << C.getFormattedName() << ", \""
696*e8d8bef9SDimitry Andric            << C.getFormattedName() << "\")\n";
697*e8d8bef9SDimitry Andric       } else {
698*e8d8bef9SDimitry Andric         OS << "__CLAUSE_NO_CLASS(" << C.getFormattedName() << ")\n";
699*e8d8bef9SDimitry Andric       }
700*e8d8bef9SDimitry Andric     } else { // CLASS
701*e8d8bef9SDimitry Andric       if (C.isImplicit()) {
702*e8d8bef9SDimitry Andric         OS << "__IMPLICIT_CLAUSE_CLASS(" << C.getFormattedName() << ", \""
703*e8d8bef9SDimitry Andric            << C.getFormattedName() << "\", " << C.getClangClass() << ")\n";
704*e8d8bef9SDimitry Andric       } else {
705*e8d8bef9SDimitry Andric         OS << "__CLAUSE(" << C.getFormattedName() << ", " << C.getClangClass()
706*e8d8bef9SDimitry Andric            << ")\n";
707*e8d8bef9SDimitry Andric       }
708*e8d8bef9SDimitry Andric     }
709*e8d8bef9SDimitry Andric   }
710*e8d8bef9SDimitry Andric 
711*e8d8bef9SDimitry Andric   OS << "\n";
712*e8d8bef9SDimitry Andric   OS << "#undef __IMPLICIT_CLAUSE_NO_CLASS\n";
713*e8d8bef9SDimitry Andric   OS << "#undef __IMPLICIT_CLAUSE_CLASS\n";
714*e8d8bef9SDimitry Andric   OS << "#undef __CLAUSE\n";
715*e8d8bef9SDimitry Andric   OS << "#undef CLAUSE_NO_CLASS\n";
716*e8d8bef9SDimitry Andric   OS << "#undef CLAUSE_CLASS\n";
717*e8d8bef9SDimitry Andric   OS << "#undef CLAUSE\n";
718*e8d8bef9SDimitry Andric }
719*e8d8bef9SDimitry Andric 
720*e8d8bef9SDimitry Andric // Generate the implementation section for the enumeration in the directive
7215ffd83dbSDimitry Andric // language.
7225ffd83dbSDimitry Andric void EmitDirectivesGen(RecordKeeper &Records, raw_ostream &OS) {
723*e8d8bef9SDimitry Andric   const auto DirLang = DirectiveLanguage{Records};
724*e8d8bef9SDimitry Andric   if (DirLang.HasValidityErrors())
7255ffd83dbSDimitry Andric     return;
726*e8d8bef9SDimitry Andric 
727*e8d8bef9SDimitry Andric   EmitDirectivesFlangImpl(DirLang, OS);
728*e8d8bef9SDimitry Andric 
729*e8d8bef9SDimitry Andric   GenerateClauseClassMacro(DirLang, OS);
7305ffd83dbSDimitry Andric }
7315ffd83dbSDimitry Andric 
732*e8d8bef9SDimitry Andric // Generate the implementation for the enumeration in the directive
7335ffd83dbSDimitry Andric // language. This code can be included in library.
7345ffd83dbSDimitry Andric void EmitDirectivesImpl(RecordKeeper &Records, raw_ostream &OS) {
735*e8d8bef9SDimitry Andric   const auto DirLang = DirectiveLanguage{Records};
736*e8d8bef9SDimitry Andric   if (DirLang.HasValidityErrors())
7375ffd83dbSDimitry Andric     return;
7385ffd83dbSDimitry Andric 
739*e8d8bef9SDimitry Andric   if (!DirLang.getIncludeHeader().empty())
740*e8d8bef9SDimitry Andric     OS << "#include \"" << DirLang.getIncludeHeader() << "\"\n\n";
7415ffd83dbSDimitry Andric 
7425ffd83dbSDimitry Andric   OS << "#include \"llvm/ADT/StringRef.h\"\n";
7435ffd83dbSDimitry Andric   OS << "#include \"llvm/ADT/StringSwitch.h\"\n";
7445ffd83dbSDimitry Andric   OS << "#include \"llvm/Support/ErrorHandling.h\"\n";
7455ffd83dbSDimitry Andric   OS << "\n";
7465ffd83dbSDimitry Andric   OS << "using namespace llvm;\n";
7475ffd83dbSDimitry Andric   llvm::SmallVector<StringRef, 2> Namespaces;
748*e8d8bef9SDimitry Andric   llvm::SplitString(DirLang.getCppNamespace(), Namespaces, "::");
7495ffd83dbSDimitry Andric   for (auto Ns : Namespaces)
7505ffd83dbSDimitry Andric     OS << "using namespace " << Ns << ";\n";
7515ffd83dbSDimitry Andric 
7525ffd83dbSDimitry Andric   // getDirectiveKind(StringRef Str)
753*e8d8bef9SDimitry Andric   GenerateGetKind(DirLang.getDirectives(), OS, "Directive", DirLang,
754*e8d8bef9SDimitry Andric                   DirLang.getDirectivePrefix(), /*ImplicitAsUnknown=*/false);
7555ffd83dbSDimitry Andric 
7565ffd83dbSDimitry Andric   // getDirectiveName(Directive Kind)
757*e8d8bef9SDimitry Andric   GenerateGetName(DirLang.getDirectives(), OS, "Directive", DirLang,
758*e8d8bef9SDimitry Andric                   DirLang.getDirectivePrefix());
7595ffd83dbSDimitry Andric 
7605ffd83dbSDimitry Andric   // getClauseKind(StringRef Str)
761*e8d8bef9SDimitry Andric   GenerateGetKind(DirLang.getClauses(), OS, "Clause", DirLang,
762*e8d8bef9SDimitry Andric                   DirLang.getClausePrefix(),
763*e8d8bef9SDimitry Andric                   /*ImplicitAsUnknown=*/true);
7645ffd83dbSDimitry Andric 
7655ffd83dbSDimitry Andric   // getClauseName(Clause Kind)
766*e8d8bef9SDimitry Andric   GenerateGetName(DirLang.getClauses(), OS, "Clause", DirLang,
767*e8d8bef9SDimitry Andric                   DirLang.getClausePrefix());
768*e8d8bef9SDimitry Andric 
769*e8d8bef9SDimitry Andric   // get<ClauseVal>Kind(StringRef Str)
770*e8d8bef9SDimitry Andric   GenerateGetKindClauseVal(DirLang, OS);
7715ffd83dbSDimitry Andric 
7725ffd83dbSDimitry Andric   // isAllowedClauseForDirective(Directive D, Clause C, unsigned Version)
773*e8d8bef9SDimitry Andric   GenerateIsAllowedClause(DirLang, OS);
7745ffd83dbSDimitry Andric }
7755ffd83dbSDimitry Andric 
7765ffd83dbSDimitry Andric } // namespace llvm
777