Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / llvm / utils / TableGen / DirectiveEmitter.cpp
blobb6aee665f8ee0bb8920c0f40fc879f98027ef0ac
1 //===- DirectiveEmitter.cpp - Directive Language Emitter ------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // DirectiveEmitter uses the descriptions of directives and clauses to construct
10 // common code declarations to be used in Frontends.
12 //===----------------------------------------------------------------------===//
14 #include "llvm/TableGen/DirectiveEmitter.h"
15 #include "llvm/ADT/STLExtras.h"
16 #include "llvm/ADT/SmallVector.h"
17 #include "llvm/ADT/StringSet.h"
18 #include "llvm/ADT/StringSwitch.h"
19 #include "llvm/TableGen/Error.h"
20 #include "llvm/TableGen/Record.h"
21 #include "llvm/TableGen/TableGenBackend.h"
23 using namespace llvm;
25 namespace {
26 // Simple RAII helper for defining ifdef-undef-endif scopes.
27 class IfDefScope {
28 public:
29 IfDefScope(StringRef Name, raw_ostream &OS) : Name(Name), OS(OS) {
30 OS << "#ifdef " << Name << "\n"
31 << "#undef " << Name << "\n";
34 ~IfDefScope() { OS << "\n#endif // " << Name << "\n\n"; }
36 private:
37 StringRef Name;
38 raw_ostream &OS;
40 } // namespace
42 // Generate enum class
43 static void GenerateEnumClass(const std::vector<Record *> &Records,
44 raw_ostream &OS, StringRef Enum, StringRef Prefix,
45 const DirectiveLanguage &DirLang) {
46 OS << "\n";
47 OS << "enum class " << Enum << " {\n";
48 for (const auto &R : Records) {
49 BaseRecord Rec{R};
50 OS << " " << Prefix << Rec.getFormattedName() << ",\n";
52 OS << "};\n";
53 OS << "\n";
54 OS << "static constexpr std::size_t " << Enum
55 << "_enumSize = " << Records.size() << ";\n";
57 // Make the enum values available in the defined namespace. This allows us to
58 // write something like Enum_X if we have a `using namespace <CppNamespace>`.
59 // At the same time we do not loose the strong type guarantees of the enum
60 // class, that is we cannot pass an unsigned as Directive without an explicit
61 // cast.
62 if (DirLang.hasMakeEnumAvailableInNamespace()) {
63 OS << "\n";
64 for (const auto &R : Records) {
65 BaseRecord Rec{R};
66 OS << "constexpr auto " << Prefix << Rec.getFormattedName() << " = "
67 << "llvm::" << DirLang.getCppNamespace() << "::" << Enum
68 << "::" << Prefix << Rec.getFormattedName() << ";\n";
73 // Generate enums for values that clauses can take.
74 // Also generate function declarations for get<Enum>Name(StringRef Str).
75 static void GenerateEnumClauseVal(const std::vector<Record *> &Records,
76 raw_ostream &OS,
77 const DirectiveLanguage &DirLang,
78 std::string &EnumHelperFuncs) {
79 for (const auto &R : Records) {
80 Clause C{R};
81 const auto &ClauseVals = C.getClauseVals();
82 if (ClauseVals.size() <= 0)
83 continue;
85 const auto &EnumName = C.getEnumName();
86 if (EnumName.size() == 0) {
87 PrintError("enumClauseValue field not set in Clause" +
88 C.getFormattedName() + ".");
89 return;
92 OS << "\n";
93 OS << "enum class " << EnumName << " {\n";
94 for (const auto &CV : ClauseVals) {
95 ClauseVal CVal{CV};
96 OS << " " << CV->getName() << "=" << CVal.getValue() << ",\n";
98 OS << "};\n";
100 if (DirLang.hasMakeEnumAvailableInNamespace()) {
101 OS << "\n";
102 for (const auto &CV : ClauseVals) {
103 OS << "constexpr auto " << CV->getName() << " = "
104 << "llvm::" << DirLang.getCppNamespace() << "::" << EnumName
105 << "::" << CV->getName() << ";\n";
107 EnumHelperFuncs += (llvm::Twine(EnumName) + llvm::Twine(" get") +
108 llvm::Twine(EnumName) + llvm::Twine("(StringRef);\n"))
109 .str();
111 EnumHelperFuncs +=
112 (llvm::Twine("llvm::StringRef get") + llvm::Twine(DirLang.getName()) +
113 llvm::Twine(EnumName) + llvm::Twine("Name(") +
114 llvm::Twine(EnumName) + llvm::Twine(");\n"))
115 .str();
120 static bool HasDuplicateClauses(const std::vector<Record *> &Clauses,
121 const Directive &Directive,
122 llvm::StringSet<> &CrtClauses) {
123 bool HasError = false;
124 for (const auto &C : Clauses) {
125 VersionedClause VerClause{C};
126 const auto insRes = CrtClauses.insert(VerClause.getClause().getName());
127 if (!insRes.second) {
128 PrintError("Clause " + VerClause.getClause().getRecordName() +
129 " already defined on directive " + Directive.getRecordName());
130 HasError = true;
133 return HasError;
136 // Check for duplicate clauses in lists. Clauses cannot appear twice in the
137 // three allowed list. Also, since required implies allowed, clauses cannot
138 // appear in both the allowedClauses and requiredClauses lists.
139 static bool
140 HasDuplicateClausesInDirectives(const std::vector<Record *> &Directives) {
141 bool HasDuplicate = false;
142 for (const auto &D : Directives) {
143 Directive Dir{D};
144 llvm::StringSet<> Clauses;
145 // Check for duplicates in the three allowed lists.
146 if (HasDuplicateClauses(Dir.getAllowedClauses(), Dir, Clauses) ||
147 HasDuplicateClauses(Dir.getAllowedOnceClauses(), Dir, Clauses) ||
148 HasDuplicateClauses(Dir.getAllowedExclusiveClauses(), Dir, Clauses)) {
149 HasDuplicate = true;
151 // Check for duplicate between allowedClauses and required
152 Clauses.clear();
153 if (HasDuplicateClauses(Dir.getAllowedClauses(), Dir, Clauses) ||
154 HasDuplicateClauses(Dir.getRequiredClauses(), Dir, Clauses)) {
155 HasDuplicate = true;
157 if (HasDuplicate)
158 PrintFatalError("One or more clauses are defined multiple times on"
159 " directive " +
160 Dir.getRecordName());
163 return HasDuplicate;
166 // Check consitency of records. Return true if an error has been detected.
167 // Return false if the records are valid.
168 bool DirectiveLanguage::HasValidityErrors() const {
169 if (getDirectiveLanguages().size() != 1) {
170 PrintFatalError("A single definition of DirectiveLanguage is needed.");
171 return true;
174 return HasDuplicateClausesInDirectives(getDirectives());
177 // Generate the declaration section for the enumeration in the directive
178 // language
179 static void EmitDirectivesDecl(RecordKeeper &Records, raw_ostream &OS) {
180 const auto DirLang = DirectiveLanguage{Records};
181 if (DirLang.HasValidityErrors())
182 return;
184 OS << "#ifndef LLVM_" << DirLang.getName() << "_INC\n";
185 OS << "#define LLVM_" << DirLang.getName() << "_INC\n";
187 if (DirLang.hasEnableBitmaskEnumInNamespace())
188 OS << "\n#include \"llvm/ADT/BitmaskEnum.h\"\n";
190 OS << "\n";
191 OS << "namespace llvm {\n";
192 OS << "class StringRef;\n";
194 // Open namespaces defined in the directive language
195 llvm::SmallVector<StringRef, 2> Namespaces;
196 llvm::SplitString(DirLang.getCppNamespace(), Namespaces, "::");
197 for (auto Ns : Namespaces)
198 OS << "namespace " << Ns << " {\n";
200 if (DirLang.hasEnableBitmaskEnumInNamespace())
201 OS << "\nLLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();\n";
203 // Emit Directive enumeration
204 GenerateEnumClass(DirLang.getDirectives(), OS, "Directive",
205 DirLang.getDirectivePrefix(), DirLang);
207 // Emit Clause enumeration
208 GenerateEnumClass(DirLang.getClauses(), OS, "Clause",
209 DirLang.getClausePrefix(), DirLang);
211 // Emit ClauseVal enumeration
212 std::string EnumHelperFuncs;
213 GenerateEnumClauseVal(DirLang.getClauses(), OS, DirLang, EnumHelperFuncs);
215 // Generic function signatures
216 OS << "\n";
217 OS << "// Enumeration helper functions\n";
218 OS << "Directive get" << DirLang.getName()
219 << "DirectiveKind(llvm::StringRef Str);\n";
220 OS << "\n";
221 OS << "llvm::StringRef get" << DirLang.getName()
222 << "DirectiveName(Directive D);\n";
223 OS << "\n";
224 OS << "Clause get" << DirLang.getName()
225 << "ClauseKind(llvm::StringRef Str);\n";
226 OS << "\n";
227 OS << "llvm::StringRef get" << DirLang.getName() << "ClauseName(Clause C);\n";
228 OS << "\n";
229 OS << "/// Return true if \\p C is a valid clause for \\p D in version \\p "
230 << "Version.\n";
231 OS << "bool isAllowedClauseForDirective(Directive D, "
232 << "Clause C, unsigned Version);\n";
233 OS << "\n";
234 if (EnumHelperFuncs.length() > 0) {
235 OS << EnumHelperFuncs;
236 OS << "\n";
239 // Closing namespaces
240 for (auto Ns : llvm::reverse(Namespaces))
241 OS << "} // namespace " << Ns << "\n";
243 OS << "} // namespace llvm\n";
245 OS << "#endif // LLVM_" << DirLang.getName() << "_INC\n";
248 // Generate function implementation for get<Enum>Name(StringRef Str)
249 static void GenerateGetName(const std::vector<Record *> &Records,
250 raw_ostream &OS, StringRef Enum,
251 const DirectiveLanguage &DirLang,
252 StringRef Prefix) {
253 OS << "\n";
254 OS << "llvm::StringRef llvm::" << DirLang.getCppNamespace() << "::get"
255 << DirLang.getName() << Enum << "Name(" << Enum << " Kind) {\n";
256 OS << " switch (Kind) {\n";
257 for (const auto &R : Records) {
258 BaseRecord Rec{R};
259 OS << " case " << Prefix << Rec.getFormattedName() << ":\n";
260 OS << " return \"";
261 if (Rec.getAlternativeName().empty())
262 OS << Rec.getName();
263 else
264 OS << Rec.getAlternativeName();
265 OS << "\";\n";
267 OS << " }\n"; // switch
268 OS << " llvm_unreachable(\"Invalid " << DirLang.getName() << " " << Enum
269 << " kind\");\n";
270 OS << "}\n";
273 // Generate function implementation for get<Enum>Kind(StringRef Str)
274 static void GenerateGetKind(const std::vector<Record *> &Records,
275 raw_ostream &OS, StringRef Enum,
276 const DirectiveLanguage &DirLang, StringRef Prefix,
277 bool ImplicitAsUnknown) {
279 auto DefaultIt = llvm::find_if(
280 Records, [](Record *R) { return R->getValueAsBit("isDefault") == true; });
282 if (DefaultIt == Records.end()) {
283 PrintError("At least one " + Enum + " must be defined as default.");
284 return;
287 BaseRecord DefaultRec{(*DefaultIt)};
289 OS << "\n";
290 OS << Enum << " llvm::" << DirLang.getCppNamespace() << "::get"
291 << DirLang.getName() << Enum << "Kind(llvm::StringRef Str) {\n";
292 OS << " return llvm::StringSwitch<" << Enum << ">(Str)\n";
294 for (const auto &R : Records) {
295 BaseRecord Rec{R};
296 if (ImplicitAsUnknown && R->getValueAsBit("isImplicit")) {
297 OS << " .Case(\"" << Rec.getName() << "\"," << Prefix
298 << DefaultRec.getFormattedName() << ")\n";
299 } else {
300 OS << " .Case(\"" << Rec.getName() << "\"," << Prefix
301 << Rec.getFormattedName() << ")\n";
304 OS << " .Default(" << Prefix << DefaultRec.getFormattedName() << ");\n";
305 OS << "}\n";
308 // Generate function implementation for get<ClauseVal>Kind(StringRef Str)
309 static void GenerateGetKindClauseVal(const DirectiveLanguage &DirLang,
310 raw_ostream &OS) {
311 for (const auto &R : DirLang.getClauses()) {
312 Clause C{R};
313 const auto &ClauseVals = C.getClauseVals();
314 if (ClauseVals.size() <= 0)
315 continue;
317 auto DefaultIt = llvm::find_if(ClauseVals, [](Record *CV) {
318 return CV->getValueAsBit("isDefault") == true;
321 if (DefaultIt == ClauseVals.end()) {
322 PrintError("At least one val in Clause " + C.getFormattedName() +
323 " must be defined as default.");
324 return;
326 const auto DefaultName = (*DefaultIt)->getName();
328 const auto &EnumName = C.getEnumName();
329 if (EnumName.size() == 0) {
330 PrintError("enumClauseValue field not set in Clause" +
331 C.getFormattedName() + ".");
332 return;
335 OS << "\n";
336 OS << EnumName << " llvm::" << DirLang.getCppNamespace() << "::get"
337 << EnumName << "(llvm::StringRef Str) {\n";
338 OS << " return llvm::StringSwitch<" << EnumName << ">(Str)\n";
339 for (const auto &CV : ClauseVals) {
340 ClauseVal CVal{CV};
341 OS << " .Case(\"" << CVal.getFormattedName() << "\"," << CV->getName()
342 << ")\n";
344 OS << " .Default(" << DefaultName << ");\n";
345 OS << "}\n";
347 OS << "\n";
348 OS << "llvm::StringRef llvm::" << DirLang.getCppNamespace() << "::get"
349 << DirLang.getName() << EnumName
350 << "Name(llvm::" << DirLang.getCppNamespace() << "::" << EnumName
351 << " x) {\n";
352 OS << " switch (x) {\n";
353 for (const auto &CV : ClauseVals) {
354 ClauseVal CVal{CV};
355 OS << " case " << CV->getName() << ":\n";
356 OS << " return \"" << CVal.getFormattedName() << "\";\n";
358 OS << " }\n"; // switch
359 OS << " llvm_unreachable(\"Invalid " << DirLang.getName() << " "
360 << EnumName << " kind\");\n";
361 OS << "}\n";
365 static void
366 GenerateCaseForVersionedClauses(const std::vector<Record *> &Clauses,
367 raw_ostream &OS, StringRef DirectiveName,
368 const DirectiveLanguage &DirLang,
369 llvm::StringSet<> &Cases) {
370 for (const auto &C : Clauses) {
371 VersionedClause VerClause{C};
373 const auto ClauseFormattedName = VerClause.getClause().getFormattedName();
375 if (Cases.insert(ClauseFormattedName).second) {
376 OS << " case " << DirLang.getClausePrefix() << ClauseFormattedName
377 << ":\n";
378 OS << " return " << VerClause.getMinVersion()
379 << " <= Version && " << VerClause.getMaxVersion() << " >= Version;\n";
384 // Generate the isAllowedClauseForDirective function implementation.
385 static void GenerateIsAllowedClause(const DirectiveLanguage &DirLang,
386 raw_ostream &OS) {
387 OS << "\n";
388 OS << "bool llvm::" << DirLang.getCppNamespace()
389 << "::isAllowedClauseForDirective("
390 << "Directive D, Clause C, unsigned Version) {\n";
391 OS << " assert(unsigned(D) <= llvm::" << DirLang.getCppNamespace()
392 << "::Directive_enumSize);\n";
393 OS << " assert(unsigned(C) <= llvm::" << DirLang.getCppNamespace()
394 << "::Clause_enumSize);\n";
396 OS << " switch (D) {\n";
398 for (const auto &D : DirLang.getDirectives()) {
399 Directive Dir{D};
401 OS << " case " << DirLang.getDirectivePrefix() << Dir.getFormattedName()
402 << ":\n";
403 if (Dir.getAllowedClauses().size() == 0 &&
404 Dir.getAllowedOnceClauses().size() == 0 &&
405 Dir.getAllowedExclusiveClauses().size() == 0 &&
406 Dir.getRequiredClauses().size() == 0) {
407 OS << " return false;\n";
408 } else {
409 OS << " switch (C) {\n";
411 llvm::StringSet<> Cases;
413 GenerateCaseForVersionedClauses(Dir.getAllowedClauses(), OS,
414 Dir.getName(), DirLang, Cases);
416 GenerateCaseForVersionedClauses(Dir.getAllowedOnceClauses(), OS,
417 Dir.getName(), DirLang, Cases);
419 GenerateCaseForVersionedClauses(Dir.getAllowedExclusiveClauses(), OS,
420 Dir.getName(), DirLang, Cases);
422 GenerateCaseForVersionedClauses(Dir.getRequiredClauses(), OS,
423 Dir.getName(), DirLang, Cases);
425 OS << " default:\n";
426 OS << " return false;\n";
427 OS << " }\n"; // End of clauses switch
429 OS << " break;\n";
432 OS << " }\n"; // End of directives switch
433 OS << " llvm_unreachable(\"Invalid " << DirLang.getName()
434 << " Directive kind\");\n";
435 OS << "}\n"; // End of function isAllowedClauseForDirective
438 // Generate a simple enum set with the give clauses.
439 static void GenerateClauseSet(const std::vector<Record *> &Clauses,
440 raw_ostream &OS, StringRef ClauseSetPrefix,
441 Directive &Dir,
442 const DirectiveLanguage &DirLang) {
444 OS << "\n";
445 OS << " static " << DirLang.getClauseEnumSetClass() << " " << ClauseSetPrefix
446 << DirLang.getDirectivePrefix() << Dir.getFormattedName() << " {\n";
448 for (const auto &C : Clauses) {
449 VersionedClause VerClause{C};
450 OS << " llvm::" << DirLang.getCppNamespace()
451 << "::Clause::" << DirLang.getClausePrefix()
452 << VerClause.getClause().getFormattedName() << ",\n";
454 OS << " };\n";
457 // Generate an enum set for the 4 kinds of clauses linked to a directive.
458 static void GenerateDirectiveClauseSets(const DirectiveLanguage &DirLang,
459 raw_ostream &OS) {
461 IfDefScope Scope("GEN_FLANG_DIRECTIVE_CLAUSE_SETS", OS);
463 OS << "\n";
464 OS << "namespace llvm {\n";
466 // Open namespaces defined in the directive language.
467 llvm::SmallVector<StringRef, 2> Namespaces;
468 llvm::SplitString(DirLang.getCppNamespace(), Namespaces, "::");
469 for (auto Ns : Namespaces)
470 OS << "namespace " << Ns << " {\n";
472 for (const auto &D : DirLang.getDirectives()) {
473 Directive Dir{D};
475 OS << "\n";
476 OS << " // Sets for " << Dir.getName() << "\n";
478 GenerateClauseSet(Dir.getAllowedClauses(), OS, "allowedClauses_", Dir,
479 DirLang);
480 GenerateClauseSet(Dir.getAllowedOnceClauses(), OS, "allowedOnceClauses_",
481 Dir, DirLang);
482 GenerateClauseSet(Dir.getAllowedExclusiveClauses(), OS,
483 "allowedExclusiveClauses_", Dir, DirLang);
484 GenerateClauseSet(Dir.getRequiredClauses(), OS, "requiredClauses_", Dir,
485 DirLang);
488 // Closing namespaces
489 for (auto Ns : llvm::reverse(Namespaces))
490 OS << "} // namespace " << Ns << "\n";
492 OS << "} // namespace llvm\n";
495 // Generate a map of directive (key) with DirectiveClauses struct as values.
496 // The struct holds the 4 sets of enumeration for the 4 kinds of clauses
497 // allowances (allowed, allowed once, allowed exclusive and required).
498 static void GenerateDirectiveClauseMap(const DirectiveLanguage &DirLang,
499 raw_ostream &OS) {
501 IfDefScope Scope("GEN_FLANG_DIRECTIVE_CLAUSE_MAP", OS);
503 OS << "\n";
504 OS << "{\n";
506 for (const auto &D : DirLang.getDirectives()) {
507 Directive Dir{D};
508 OS << " {llvm::" << DirLang.getCppNamespace()
509 << "::Directive::" << DirLang.getDirectivePrefix()
510 << Dir.getFormattedName() << ",\n";
511 OS << " {\n";
512 OS << " llvm::" << DirLang.getCppNamespace() << "::allowedClauses_"
513 << DirLang.getDirectivePrefix() << Dir.getFormattedName() << ",\n";
514 OS << " llvm::" << DirLang.getCppNamespace() << "::allowedOnceClauses_"
515 << DirLang.getDirectivePrefix() << Dir.getFormattedName() << ",\n";
516 OS << " llvm::" << DirLang.getCppNamespace()
517 << "::allowedExclusiveClauses_" << DirLang.getDirectivePrefix()
518 << Dir.getFormattedName() << ",\n";
519 OS << " llvm::" << DirLang.getCppNamespace() << "::requiredClauses_"
520 << DirLang.getDirectivePrefix() << Dir.getFormattedName() << ",\n";
521 OS << " }\n";
522 OS << " },\n";
525 OS << "}\n";
528 // Generate classes entry for Flang clauses in the Flang parse-tree
529 // If the clause as a non-generic class, no entry is generated.
530 // If the clause does not hold a value, an EMPTY_CLASS is used.
531 // If the clause class is generic then a WRAPPER_CLASS is used. When the value
532 // is optional, the value class is wrapped into a std::optional.
533 static void GenerateFlangClauseParserClass(const DirectiveLanguage &DirLang,
534 raw_ostream &OS) {
536 IfDefScope Scope("GEN_FLANG_CLAUSE_PARSER_CLASSES", OS);
538 OS << "\n";
540 for (const auto &C : DirLang.getClauses()) {
541 Clause Clause{C};
542 if (!Clause.getFlangClass().empty()) {
543 OS << "WRAPPER_CLASS(" << Clause.getFormattedParserClassName() << ", ";
544 if (Clause.isValueOptional() && Clause.isValueList()) {
545 OS << "std::optional<std::list<" << Clause.getFlangClass() << ">>";
546 } else if (Clause.isValueOptional()) {
547 OS << "std::optional<" << Clause.getFlangClass() << ">";
548 } else if (Clause.isValueList()) {
549 OS << "std::list<" << Clause.getFlangClass() << ">";
550 } else {
551 OS << Clause.getFlangClass();
553 } else {
554 OS << "EMPTY_CLASS(" << Clause.getFormattedParserClassName();
556 OS << ");\n";
560 // Generate a list of the different clause classes for Flang.
561 static void GenerateFlangClauseParserClassList(const DirectiveLanguage &DirLang,
562 raw_ostream &OS) {
564 IfDefScope Scope("GEN_FLANG_CLAUSE_PARSER_CLASSES_LIST", OS);
566 OS << "\n";
567 llvm::interleaveComma(DirLang.getClauses(), OS, [&](Record *C) {
568 Clause Clause{C};
569 OS << Clause.getFormattedParserClassName() << "\n";
573 // Generate dump node list for the clauses holding a generic class name.
574 static void GenerateFlangClauseDump(const DirectiveLanguage &DirLang,
575 raw_ostream &OS) {
577 IfDefScope Scope("GEN_FLANG_DUMP_PARSE_TREE_CLAUSES", OS);
579 OS << "\n";
580 for (const auto &C : DirLang.getClauses()) {
581 Clause Clause{C};
582 OS << "NODE(" << DirLang.getFlangClauseBaseClass() << ", "
583 << Clause.getFormattedParserClassName() << ")\n";
587 // Generate Unparse functions for clauses classes in the Flang parse-tree
588 // If the clause is a non-generic class, no entry is generated.
589 static void GenerateFlangClauseUnparse(const DirectiveLanguage &DirLang,
590 raw_ostream &OS) {
592 IfDefScope Scope("GEN_FLANG_CLAUSE_UNPARSE", OS);
594 OS << "\n";
596 for (const auto &C : DirLang.getClauses()) {
597 Clause Clause{C};
598 if (!Clause.getFlangClass().empty()) {
599 if (Clause.isValueOptional() && Clause.getDefaultValue().empty()) {
600 OS << "void Unparse(const " << DirLang.getFlangClauseBaseClass()
601 << "::" << Clause.getFormattedParserClassName() << " &x) {\n";
602 OS << " Word(\"" << Clause.getName().upper() << "\");\n";
604 OS << " Walk(\"(\", x.v, \")\");\n";
605 OS << "}\n";
606 } else if (Clause.isValueOptional()) {
607 OS << "void Unparse(const " << DirLang.getFlangClauseBaseClass()
608 << "::" << Clause.getFormattedParserClassName() << " &x) {\n";
609 OS << " Word(\"" << Clause.getName().upper() << "\");\n";
610 OS << " Put(\"(\");\n";
611 OS << " if (x.v.has_value())\n";
612 if (Clause.isValueList())
613 OS << " Walk(x.v, \",\");\n";
614 else
615 OS << " Walk(x.v);\n";
616 OS << " else\n";
617 OS << " Put(\"" << Clause.getDefaultValue() << "\");\n";
618 OS << " Put(\")\");\n";
619 OS << "}\n";
620 } else {
621 OS << "void Unparse(const " << DirLang.getFlangClauseBaseClass()
622 << "::" << Clause.getFormattedParserClassName() << " &x) {\n";
623 OS << " Word(\"" << Clause.getName().upper() << "\");\n";
624 OS << " Put(\"(\");\n";
625 if (Clause.isValueList())
626 OS << " Walk(x.v, \",\");\n";
627 else
628 OS << " Walk(x.v);\n";
629 OS << " Put(\")\");\n";
630 OS << "}\n";
632 } else {
633 OS << "void Before(const " << DirLang.getFlangClauseBaseClass()
634 << "::" << Clause.getFormattedParserClassName() << " &) { Word(\""
635 << Clause.getName().upper() << "\"); }\n";
640 // Generate check in the Enter functions for clauses classes.
641 static void GenerateFlangClauseCheckPrototypes(const DirectiveLanguage &DirLang,
642 raw_ostream &OS) {
644 IfDefScope Scope("GEN_FLANG_CLAUSE_CHECK_ENTER", OS);
646 OS << "\n";
647 for (const auto &C : DirLang.getClauses()) {
648 Clause Clause{C};
649 OS << "void Enter(const parser::" << DirLang.getFlangClauseBaseClass()
650 << "::" << Clause.getFormattedParserClassName() << " &);\n";
654 // Generate the mapping for clauses between the parser class and the
655 // corresponding clause Kind
656 static void GenerateFlangClauseParserKindMap(const DirectiveLanguage &DirLang,
657 raw_ostream &OS) {
659 IfDefScope Scope("GEN_FLANG_CLAUSE_PARSER_KIND_MAP", OS);
661 OS << "\n";
662 for (const auto &C : DirLang.getClauses()) {
663 Clause Clause{C};
664 OS << "if constexpr (std::is_same_v<A, parser::"
665 << DirLang.getFlangClauseBaseClass()
666 << "::" << Clause.getFormattedParserClassName();
667 OS << ">)\n";
668 OS << " return llvm::" << DirLang.getCppNamespace()
669 << "::Clause::" << DirLang.getClausePrefix() << Clause.getFormattedName()
670 << ";\n";
673 OS << "llvm_unreachable(\"Invalid " << DirLang.getName()
674 << " Parser clause\");\n";
677 static bool compareClauseName(Record *R1, Record *R2) {
678 Clause C1{R1};
679 Clause C2{R2};
680 return (C1.getName() > C2.getName());
683 // Generate the parser for the clauses.
684 static void GenerateFlangClausesParser(const DirectiveLanguage &DirLang,
685 raw_ostream &OS) {
686 std::vector<Record *> Clauses = DirLang.getClauses();
687 // Sort clauses in reverse alphabetical order so with clauses with same
688 // beginning, the longer option is tried before.
689 llvm::sort(Clauses, compareClauseName);
690 IfDefScope Scope("GEN_FLANG_CLAUSES_PARSER", OS);
691 OS << "\n";
692 unsigned index = 0;
693 unsigned lastClauseIndex = DirLang.getClauses().size() - 1;
694 OS << "TYPE_PARSER(\n";
695 for (const auto &C : Clauses) {
696 Clause Clause{C};
697 if (Clause.getAliases().empty()) {
698 OS << " \"" << Clause.getName() << "\"";
699 } else {
700 OS << " ("
701 << "\"" << Clause.getName() << "\"_tok";
702 for (StringRef alias : Clause.getAliases()) {
703 OS << " || \"" << alias << "\"_tok";
705 OS << ")";
708 OS << " >> construct<" << DirLang.getFlangClauseBaseClass()
709 << ">(construct<" << DirLang.getFlangClauseBaseClass()
710 << "::" << Clause.getFormattedParserClassName() << ">(";
711 if (Clause.getFlangClass().empty()) {
712 OS << "))";
713 if (index != lastClauseIndex)
714 OS << " ||";
715 OS << "\n";
716 ++index;
717 continue;
720 if (Clause.isValueOptional())
721 OS << "maybe(";
722 OS << "parenthesized(";
723 if (Clause.isValueList())
724 OS << "nonemptyList(";
726 if (!Clause.getPrefix().empty())
727 OS << "\"" << Clause.getPrefix() << ":\" >> ";
729 // The common Flang parser are used directly. Their name is identical to
730 // the Flang class with first letter as lowercase. If the Flang class is
731 // not a common class, we assume there is a specific Parser<>{} with the
732 // Flang class name provided.
733 llvm::SmallString<128> Scratch;
734 StringRef Parser =
735 llvm::StringSwitch<StringRef>(Clause.getFlangClass())
736 .Case("Name", "name")
737 .Case("ScalarIntConstantExpr", "scalarIntConstantExpr")
738 .Case("ScalarIntExpr", "scalarIntExpr")
739 .Case("ScalarExpr", "scalarExpr")
740 .Case("ScalarLogicalExpr", "scalarLogicalExpr")
741 .Default(("Parser<" + Clause.getFlangClass() + ">{}")
742 .toStringRef(Scratch));
743 OS << Parser;
744 if (!Clause.getPrefix().empty() && Clause.isPrefixOptional())
745 OS << " || " << Parser;
746 if (Clause.isValueList()) // close nonemptyList(.
747 OS << ")";
748 OS << ")"; // close parenthesized(.
750 if (Clause.isValueOptional()) // close maybe(.
751 OS << ")";
752 OS << "))";
753 if (index != lastClauseIndex)
754 OS << " ||";
755 OS << "\n";
756 ++index;
758 OS << ")\n";
761 // Generate the implementation section for the enumeration in the directive
762 // language
763 static void EmitDirectivesFlangImpl(const DirectiveLanguage &DirLang,
764 raw_ostream &OS) {
766 GenerateDirectiveClauseSets(DirLang, OS);
768 GenerateDirectiveClauseMap(DirLang, OS);
770 GenerateFlangClauseParserClass(DirLang, OS);
772 GenerateFlangClauseParserClassList(DirLang, OS);
774 GenerateFlangClauseDump(DirLang, OS);
776 GenerateFlangClauseUnparse(DirLang, OS);
778 GenerateFlangClauseCheckPrototypes(DirLang, OS);
780 GenerateFlangClauseParserKindMap(DirLang, OS);
782 GenerateFlangClausesParser(DirLang, OS);
785 static void GenerateClauseClassMacro(const DirectiveLanguage &DirLang,
786 raw_ostream &OS) {
787 // Generate macros style information for legacy code in clang
788 IfDefScope Scope("GEN_CLANG_CLAUSE_CLASS", OS);
790 OS << "\n";
792 OS << "#ifndef CLAUSE\n";
793 OS << "#define CLAUSE(Enum, Str, Implicit)\n";
794 OS << "#endif\n";
795 OS << "#ifndef CLAUSE_CLASS\n";
796 OS << "#define CLAUSE_CLASS(Enum, Str, Class)\n";
797 OS << "#endif\n";
798 OS << "#ifndef CLAUSE_NO_CLASS\n";
799 OS << "#define CLAUSE_NO_CLASS(Enum, Str)\n";
800 OS << "#endif\n";
801 OS << "\n";
802 OS << "#define __CLAUSE(Name, Class) \\\n";
803 OS << " CLAUSE(" << DirLang.getClausePrefix()
804 << "##Name, #Name, /* Implicit */ false) \\\n";
805 OS << " CLAUSE_CLASS(" << DirLang.getClausePrefix()
806 << "##Name, #Name, Class)\n";
807 OS << "#define __CLAUSE_NO_CLASS(Name) \\\n";
808 OS << " CLAUSE(" << DirLang.getClausePrefix()
809 << "##Name, #Name, /* Implicit */ false) \\\n";
810 OS << " CLAUSE_NO_CLASS(" << DirLang.getClausePrefix() << "##Name, #Name)\n";
811 OS << "#define __IMPLICIT_CLAUSE_CLASS(Name, Str, Class) \\\n";
812 OS << " CLAUSE(" << DirLang.getClausePrefix()
813 << "##Name, Str, /* Implicit */ true) \\\n";
814 OS << " CLAUSE_CLASS(" << DirLang.getClausePrefix()
815 << "##Name, Str, Class)\n";
816 OS << "#define __IMPLICIT_CLAUSE_NO_CLASS(Name, Str) \\\n";
817 OS << " CLAUSE(" << DirLang.getClausePrefix()
818 << "##Name, Str, /* Implicit */ true) \\\n";
819 OS << " CLAUSE_NO_CLASS(" << DirLang.getClausePrefix() << "##Name, Str)\n";
820 OS << "\n";
822 for (const auto &R : DirLang.getClauses()) {
823 Clause C{R};
824 if (C.getClangClass().empty()) { // NO_CLASS
825 if (C.isImplicit()) {
826 OS << "__IMPLICIT_CLAUSE_NO_CLASS(" << C.getFormattedName() << ", \""
827 << C.getFormattedName() << "\")\n";
828 } else {
829 OS << "__CLAUSE_NO_CLASS(" << C.getFormattedName() << ")\n";
831 } else { // CLASS
832 if (C.isImplicit()) {
833 OS << "__IMPLICIT_CLAUSE_CLASS(" << C.getFormattedName() << ", \""
834 << C.getFormattedName() << "\", " << C.getClangClass() << ")\n";
835 } else {
836 OS << "__CLAUSE(" << C.getFormattedName() << ", " << C.getClangClass()
837 << ")\n";
842 OS << "\n";
843 OS << "#undef __IMPLICIT_CLAUSE_NO_CLASS\n";
844 OS << "#undef __IMPLICIT_CLAUSE_CLASS\n";
845 OS << "#undef __CLAUSE\n";
846 OS << "#undef CLAUSE_NO_CLASS\n";
847 OS << "#undef CLAUSE_CLASS\n";
848 OS << "#undef CLAUSE\n";
851 // Generate the implemenation for the enumeration in the directive
852 // language. This code can be included in library.
853 void EmitDirectivesBasicImpl(const DirectiveLanguage &DirLang,
854 raw_ostream &OS) {
855 IfDefScope Scope("GEN_DIRECTIVES_IMPL", OS);
857 // getDirectiveKind(StringRef Str)
858 GenerateGetKind(DirLang.getDirectives(), OS, "Directive", DirLang,
859 DirLang.getDirectivePrefix(), /*ImplicitAsUnknown=*/false);
861 // getDirectiveName(Directive Kind)
862 GenerateGetName(DirLang.getDirectives(), OS, "Directive", DirLang,
863 DirLang.getDirectivePrefix());
865 // getClauseKind(StringRef Str)
866 GenerateGetKind(DirLang.getClauses(), OS, "Clause", DirLang,
867 DirLang.getClausePrefix(),
868 /*ImplicitAsUnknown=*/true);
870 // getClauseName(Clause Kind)
871 GenerateGetName(DirLang.getClauses(), OS, "Clause", DirLang,
872 DirLang.getClausePrefix());
874 // get<ClauseVal>Kind(StringRef Str)
875 GenerateGetKindClauseVal(DirLang, OS);
877 // isAllowedClauseForDirective(Directive D, Clause C, unsigned Version)
878 GenerateIsAllowedClause(DirLang, OS);
881 // Generate the implemenation section for the enumeration in the directive
882 // language.
883 static void EmitDirectivesImpl(RecordKeeper &Records, raw_ostream &OS) {
884 const auto DirLang = DirectiveLanguage{Records};
885 if (DirLang.HasValidityErrors())
886 return;
888 EmitDirectivesFlangImpl(DirLang, OS);
890 GenerateClauseClassMacro(DirLang, OS);
892 EmitDirectivesBasicImpl(DirLang, OS);
895 static TableGen::Emitter::Opt
896 X("gen-directive-decl", EmitDirectivesDecl,
897 "Generate directive related declaration code (header file)");
899 static TableGen::Emitter::Opt
900 Y("gen-directive-impl", EmitDirectivesImpl,
901 "Generate directive related implementation code");