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