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.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "llvm/ADT/STLExtras.h"
15 #include "llvm/ADT/SmallVector.h"
16 #include "llvm/ADT/StringExtras.h"
17 #include "llvm/ADT/StringSet.h"
18 #include "llvm/TableGen/Error.h"
19 #include "llvm/TableGen/Record.h"
20 #include "llvm/TableGen/TableGenBackend.h"
21 
22 
23 using namespace llvm;
24 
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";
32   }
33 
34   ~IfDefScope() { OS << "\n#endif // " << Name << "\n\n"; }
35 
36 private:
37   StringRef Name;
38   raw_ostream &OS;
39 };
40 } // end anonymous namespace
41 
42 namespace llvm {
43 
44 // Wrapper class that contains DirectiveLanguage's information defined in
45 // DirectiveBase.td and provides helper methods for accessing it.
46 class DirectiveLanguage {
47 public:
48   explicit DirectiveLanguage(const llvm::Record *Def) : Def(Def) {}
49 
50   StringRef getName() const { return Def->getValueAsString("name"); }
51 
52   StringRef getCppNamespace() const {
53     return Def->getValueAsString("cppNamespace");
54   }
55 
56   StringRef getDirectivePrefix() const {
57     return Def->getValueAsString("directivePrefix");
58   }
59 
60   StringRef getClausePrefix() const {
61     return Def->getValueAsString("clausePrefix");
62   }
63 
64   StringRef getIncludeHeader() const {
65     return Def->getValueAsString("includeHeader");
66   }
67 
68   StringRef getClauseEnumSetClass() const {
69     return Def->getValueAsString("clauseEnumSetClass");
70   }
71 
72   StringRef getFlangClauseBaseClass() const {
73     return Def->getValueAsString("flangClauseBaseClass");
74   }
75 
76   bool hasMakeEnumAvailableInNamespace() const {
77     return Def->getValueAsBit("makeEnumAvailableInNamespace");
78   }
79 
80   bool hasEnableBitmaskEnumInNamespace() const {
81     return Def->getValueAsBit("enableBitmaskEnumInNamespace");
82   }
83 
84 private:
85   const llvm::Record *Def;
86 };
87 
88 // Base record class used for Directive and Clause class defined in
89 // DirectiveBase.td.
90 class BaseRecord {
91 public:
92   explicit BaseRecord(const llvm::Record *Def) : Def(Def) {}
93 
94   StringRef getName() const { return Def->getValueAsString("name"); }
95 
96   StringRef getAlternativeName() const {
97     return Def->getValueAsString("alternativeName");
98   }
99 
100   // Returns the name of the directive formatted for output. Whitespace are
101   // replaced with underscores.
102   std::string getFormattedName() {
103     StringRef Name = Def->getValueAsString("name");
104     std::string N = Name.str();
105     std::replace(N.begin(), N.end(), ' ', '_');
106     return N;
107   }
108 
109   bool isDefault() const { return Def->getValueAsBit("isDefault"); }
110 
111 protected:
112   const llvm::Record *Def;
113 };
114 
115 // Wrapper class that contains a Directive's information defined in
116 // DirectiveBase.td and provides helper methods for accessing it.
117 class Directive : public BaseRecord {
118 public:
119   explicit Directive(const llvm::Record *Def) : BaseRecord(Def) {}
120 
121   std::vector<Record *> getAllowedClauses() const {
122     return Def->getValueAsListOfDefs("allowedClauses");
123   }
124 
125   std::vector<Record *> getAllowedOnceClauses() const {
126     return Def->getValueAsListOfDefs("allowedOnceClauses");
127   }
128 
129   std::vector<Record *> getAllowedExclusiveClauses() const {
130     return Def->getValueAsListOfDefs("allowedExclusiveClauses");
131   }
132 
133   std::vector<Record *> getRequiredClauses() const {
134     return Def->getValueAsListOfDefs("requiredClauses");
135   }
136 };
137 
138 // Wrapper class that contains Clause's information defined in DirectiveBase.td
139 // and provides helper methods for accessing it.
140 class Clause : public BaseRecord {
141 public:
142   explicit Clause(const llvm::Record *Def) : BaseRecord(Def) {}
143 
144   // Optional field.
145   StringRef getClangClass() const {
146     return Def->getValueAsString("clangClass");
147   }
148 
149   // Optional field.
150   StringRef getFlangClass() const {
151     return Def->getValueAsString("flangClass");
152   }
153 
154   // Optional field.
155   StringRef getFlangClassValue() const {
156     return Def->getValueAsString("flangClassValue");
157   }
158 
159   // Get the formatted name for Flang parser class. The generic formatted class
160   // name is constructed from the name were the first letter of each word is
161   // captitalized and the underscores are removed.
162   // ex: async -> Async
163   //     num_threads -> NumThreads
164   std::string getFormattedParserClassName() {
165     StringRef Name = Def->getValueAsString("name");
166     std::string N = Name.str();
167     bool Cap = true;
168     std::transform(N.begin(), N.end(), N.begin(), [&Cap](unsigned char C) {
169       if (Cap == true) {
170         C = llvm::toUpper(C);
171         Cap = false;
172       } else if (C == '_') {
173         Cap = true;
174       }
175       return C;
176     });
177     N.erase(std::remove(N.begin(), N.end(), '_'), N.end());
178     return N;
179   }
180 
181   bool isValueOptional() const { return Def->getValueAsBit("isValueOptional"); }
182 
183   bool isImplict() const { return Def->getValueAsBit("isImplicit"); }
184 };
185 
186 // Wrapper class that contains VersionedClause's information defined in
187 // DirectiveBase.td and provides helper methods for accessing it.
188 class VersionedClause {
189 public:
190   explicit VersionedClause(const llvm::Record *Def) : Def(Def) {}
191 
192   // Return the specific clause record wrapped in the Clause class.
193   Clause getClause() const { return Clause{Def->getValueAsDef("clause")}; }
194 
195   int64_t getMinVersion() const { return Def->getValueAsInt("minVersion"); }
196 
197   int64_t getMaxVersion() const { return Def->getValueAsInt("maxVersion"); }
198 
199 private:
200   const llvm::Record *Def;
201 };
202 
203 // Generate enum class
204 void GenerateEnumClass(const std::vector<Record *> &Records, raw_ostream &OS,
205                        StringRef Enum, StringRef Prefix,
206                        DirectiveLanguage &DirLang) {
207   OS << "\n";
208   OS << "enum class " << Enum << " {\n";
209   for (const auto &R : Records) {
210     BaseRecord Rec{R};
211     OS << "  " << Prefix << Rec.getFormattedName() << ",\n";
212   }
213   OS << "};\n";
214   OS << "\n";
215   OS << "static constexpr std::size_t " << Enum
216      << "_enumSize = " << Records.size() << ";\n";
217 
218   // Make the enum values available in the defined namespace. This allows us to
219   // write something like Enum_X if we have a `using namespace <CppNamespace>`.
220   // At the same time we do not loose the strong type guarantees of the enum
221   // class, that is we cannot pass an unsigned as Directive without an explicit
222   // cast.
223   if (DirLang.hasMakeEnumAvailableInNamespace()) {
224     OS << "\n";
225     for (const auto &R : Records) {
226       BaseRecord Rec{R};
227       OS << "constexpr auto " << Prefix << Rec.getFormattedName() << " = "
228          << "llvm::" << DirLang.getCppNamespace() << "::" << Enum
229          << "::" << Prefix << Rec.getFormattedName() << ";\n";
230     }
231   }
232 }
233 
234 // Generate the declaration section for the enumeration in the directive
235 // language
236 void EmitDirectivesDecl(RecordKeeper &Records, raw_ostream &OS) {
237 
238   const auto &DirectiveLanguages =
239       Records.getAllDerivedDefinitions("DirectiveLanguage");
240 
241   if (DirectiveLanguages.size() != 1) {
242     PrintError("A single definition of DirectiveLanguage is needed.");
243     return;
244   }
245 
246   DirectiveLanguage DirLang{DirectiveLanguages[0]};
247 
248   OS << "#ifndef LLVM_" << DirLang.getName() << "_INC\n";
249   OS << "#define LLVM_" << DirLang.getName() << "_INC\n";
250 
251   if (DirLang.hasEnableBitmaskEnumInNamespace())
252     OS << "\n#include \"llvm/ADT/BitmaskEnum.h\"\n";
253 
254   OS << "\n";
255   OS << "namespace llvm {\n";
256   OS << "class StringRef;\n";
257 
258   // Open namespaces defined in the directive language
259   llvm::SmallVector<StringRef, 2> Namespaces;
260   llvm::SplitString(DirLang.getCppNamespace(), Namespaces, "::");
261   for (auto Ns : Namespaces)
262     OS << "namespace " << Ns << " {\n";
263 
264   if (DirLang.hasEnableBitmaskEnumInNamespace())
265     OS << "\nLLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();\n";
266 
267   // Emit Directive enumeration
268   const auto &Directives = Records.getAllDerivedDefinitions("Directive");
269   GenerateEnumClass(Directives, OS, "Directive", DirLang.getDirectivePrefix(),
270                     DirLang);
271 
272   // Emit Clause enumeration
273   const auto &Clauses = Records.getAllDerivedDefinitions("Clause");
274   GenerateEnumClass(Clauses, OS, "Clause", DirLang.getClausePrefix(), DirLang);
275 
276   // Generic function signatures
277   OS << "\n";
278   OS << "// Enumeration helper functions\n";
279   OS << "Directive get" << DirLang.getName()
280      << "DirectiveKind(llvm::StringRef Str);\n";
281   OS << "\n";
282   OS << "llvm::StringRef get" << DirLang.getName()
283      << "DirectiveName(Directive D);\n";
284   OS << "\n";
285   OS << "Clause get" << DirLang.getName()
286      << "ClauseKind(llvm::StringRef Str);\n";
287   OS << "\n";
288   OS << "llvm::StringRef get" << DirLang.getName() << "ClauseName(Clause C);\n";
289   OS << "\n";
290   OS << "/// Return true if \\p C is a valid clause for \\p D in version \\p "
291      << "Version.\n";
292   OS << "bool isAllowedClauseForDirective(Directive D, "
293      << "Clause C, unsigned Version);\n";
294   OS << "\n";
295 
296   // Closing namespaces
297   for (auto Ns : llvm::reverse(Namespaces))
298     OS << "} // namespace " << Ns << "\n";
299 
300   OS << "} // namespace llvm\n";
301 
302   OS << "#endif // LLVM_" << DirLang.getName() << "_INC\n";
303 }
304 
305 // Generate function implementation for get<Enum>Name(StringRef Str)
306 void GenerateGetName(const std::vector<Record *> &Records, raw_ostream &OS,
307                      StringRef Enum, DirectiveLanguage &DirLang,
308                      StringRef Prefix) {
309   OS << "\n";
310   OS << "llvm::StringRef llvm::" << DirLang.getCppNamespace() << "::get"
311      << DirLang.getName() << Enum << "Name(" << Enum << " Kind) {\n";
312   OS << "  switch (Kind) {\n";
313   for (const auto &R : Records) {
314     BaseRecord Rec{R};
315     OS << "    case " << Prefix << Rec.getFormattedName() << ":\n";
316     OS << "      return \"";
317     if (Rec.getAlternativeName().empty())
318       OS << Rec.getName();
319     else
320       OS << Rec.getAlternativeName();
321     OS << "\";\n";
322   }
323   OS << "  }\n"; // switch
324   OS << "  llvm_unreachable(\"Invalid " << DirLang.getName() << " " << Enum
325      << " kind\");\n";
326   OS << "}\n";
327 }
328 
329 // Generate function implementation for get<Enum>Kind(StringRef Str)
330 void GenerateGetKind(const std::vector<Record *> &Records, raw_ostream &OS,
331                      StringRef Enum, DirectiveLanguage &DirLang,
332                      StringRef Prefix, bool ImplicitAsUnknown) {
333 
334   auto DefaultIt = std::find_if(Records.begin(), Records.end(), [](Record *R) {
335     return R->getValueAsBit("isDefault") == true;
336   });
337 
338   if (DefaultIt == Records.end()) {
339     PrintError("A least one " + Enum + " must be defined as default.");
340     return;
341   }
342 
343   BaseRecord DefaultRec{(*DefaultIt)};
344 
345   OS << "\n";
346   OS << Enum << " llvm::" << DirLang.getCppNamespace() << "::get"
347      << DirLang.getName() << Enum << "Kind(llvm::StringRef Str) {\n";
348   OS << "  return llvm::StringSwitch<" << Enum << ">(Str)\n";
349 
350   for (const auto &R : Records) {
351     BaseRecord Rec{R};
352     if (ImplicitAsUnknown && R->getValueAsBit("isImplicit")) {
353       OS << "    .Case(\"" << Rec.getName() << "\"," << Prefix
354          << DefaultRec.getFormattedName() << ")\n";
355     } else {
356       OS << "    .Case(\"" << Rec.getName() << "\"," << Prefix
357          << Rec.getFormattedName() << ")\n";
358     }
359   }
360   OS << "    .Default(" << Prefix << DefaultRec.getFormattedName() << ");\n";
361   OS << "}\n";
362 }
363 
364 void GenerateCaseForVersionedClauses(const std::vector<Record *> &Clauses,
365                                      raw_ostream &OS, StringRef DirectiveName,
366                                      DirectiveLanguage &DirLang,
367                                      llvm::StringSet<> &Cases) {
368   for (const auto &C : Clauses) {
369     VersionedClause VerClause{C};
370 
371     const auto ClauseFormattedName = VerClause.getClause().getFormattedName();
372 
373     if (Cases.find(ClauseFormattedName) == Cases.end()) {
374       Cases.insert(ClauseFormattedName);
375       OS << "        case " << DirLang.getClausePrefix() << ClauseFormattedName
376          << ":\n";
377       OS << "          return " << VerClause.getMinVersion()
378          << " <= Version && " << VerClause.getMaxVersion() << " >= Version;\n";
379     }
380   }
381 }
382 
383 // Generate the isAllowedClauseForDirective function implementation.
384 void GenerateIsAllowedClause(const std::vector<Record *> &Directives,
385                              raw_ostream &OS, DirectiveLanguage &DirLang) {
386   OS << "\n";
387   OS << "bool llvm::" << DirLang.getCppNamespace()
388      << "::isAllowedClauseForDirective("
389      << "Directive D, Clause C, unsigned Version) {\n";
390   OS << "  assert(unsigned(D) <= llvm::" << DirLang.getCppNamespace()
391      << "::Directive_enumSize);\n";
392   OS << "  assert(unsigned(C) <= llvm::" << DirLang.getCppNamespace()
393      << "::Clause_enumSize);\n";
394 
395   OS << "  switch (D) {\n";
396 
397   for (const auto &D : Directives) {
398     Directive Dir{D};
399 
400     OS << "    case " << DirLang.getDirectivePrefix() << Dir.getFormattedName()
401        << ":\n";
402     if (Dir.getAllowedClauses().size() == 0 &&
403         Dir.getAllowedOnceClauses().size() == 0 &&
404         Dir.getAllowedExclusiveClauses().size() == 0 &&
405         Dir.getRequiredClauses().size() == 0) {
406       OS << "      return false;\n";
407     } else {
408       OS << "      switch (C) {\n";
409 
410       llvm::StringSet<> Cases;
411 
412       GenerateCaseForVersionedClauses(Dir.getAllowedClauses(), OS,
413                                       Dir.getName(), DirLang, Cases);
414 
415       GenerateCaseForVersionedClauses(Dir.getAllowedOnceClauses(), OS,
416                                       Dir.getName(), DirLang, Cases);
417 
418       GenerateCaseForVersionedClauses(Dir.getAllowedExclusiveClauses(), OS,
419                                       Dir.getName(), DirLang, Cases);
420 
421       GenerateCaseForVersionedClauses(Dir.getRequiredClauses(), OS,
422                                       Dir.getName(), DirLang, Cases);
423 
424       OS << "        default:\n";
425       OS << "          return false;\n";
426       OS << "      }\n"; // End of clauses switch
427     }
428     OS << "      break;\n";
429   }
430 
431   OS << "  }\n"; // End of directives switch
432   OS << "  llvm_unreachable(\"Invalid " << DirLang.getName()
433      << " Directive kind\");\n";
434   OS << "}\n"; // End of function isAllowedClauseForDirective
435 }
436 
437 // Generate a simple enum set with the give clauses.
438 void GenerateClauseSet(const std::vector<Record *> &Clauses, raw_ostream &OS,
439                        StringRef ClauseSetPrefix, Directive &Dir,
440                        DirectiveLanguage &DirLang) {
441 
442   OS << "\n";
443   OS << "  static " << DirLang.getClauseEnumSetClass() << " " << ClauseSetPrefix
444      << DirLang.getDirectivePrefix() << Dir.getFormattedName() << " {\n";
445 
446   for (const auto &C : Clauses) {
447     VersionedClause VerClause{C};
448     OS << "    llvm::" << DirLang.getCppNamespace()
449        << "::Clause::" << DirLang.getClausePrefix()
450        << VerClause.getClause().getFormattedName() << ",\n";
451   }
452   OS << "  };\n";
453 }
454 
455 // Generate an enum set for the 4 kinds of clauses linked to a directive.
456 void GenerateDirectiveClauseSets(const std::vector<Record *> &Directives,
457                                  raw_ostream &OS, DirectiveLanguage &DirLang) {
458 
459   IfDefScope Scope("GEN_FLANG_DIRECTIVE_CLAUSE_SETS", OS);
460 
461   OS << "\n";
462   OS << "namespace llvm {\n";
463 
464   // Open namespaces defined in the directive language.
465   llvm::SmallVector<StringRef, 2> Namespaces;
466   llvm::SplitString(DirLang.getCppNamespace(), Namespaces, "::");
467   for (auto Ns : Namespaces)
468     OS << "namespace " << Ns << " {\n";
469 
470   for (const auto &D : Directives) {
471     Directive Dir{D};
472 
473     OS << "\n";
474     OS << "  // Sets for " << Dir.getName() << "\n";
475 
476     GenerateClauseSet(Dir.getAllowedClauses(), OS, "allowedClauses_", Dir,
477                       DirLang);
478     GenerateClauseSet(Dir.getAllowedOnceClauses(), OS, "allowedOnceClauses_",
479                       Dir, DirLang);
480     GenerateClauseSet(Dir.getAllowedExclusiveClauses(), OS,
481                       "allowedExclusiveClauses_", Dir, DirLang);
482     GenerateClauseSet(Dir.getRequiredClauses(), OS, "requiredClauses_", Dir,
483                       DirLang);
484   }
485 
486   // Closing namespaces
487   for (auto Ns : llvm::reverse(Namespaces))
488     OS << "} // namespace " << Ns << "\n";
489 
490   OS << "} // namespace llvm\n";
491 }
492 
493 // Generate a map of directive (key) with DirectiveClauses struct as values.
494 // The struct holds the 4 sets of enumeration for the 4 kinds of clauses
495 // allowances (allowed, allowed once, allowed exclusive and required).
496 void GenerateDirectiveClauseMap(const std::vector<Record *> &Directives,
497                                 raw_ostream &OS, DirectiveLanguage &DirLang) {
498 
499   IfDefScope Scope("GEN_FLANG_DIRECTIVE_CLAUSE_MAP", OS);
500 
501   OS << "\n";
502   OS << "{\n";
503 
504   for (const auto &D : Directives) {
505     Directive Dir{D};
506     OS << "  {llvm::" << DirLang.getCppNamespace()
507        << "::Directive::" << DirLang.getDirectivePrefix()
508        << Dir.getFormattedName() << ",\n";
509     OS << "    {\n";
510     OS << "      llvm::" << DirLang.getCppNamespace() << "::allowedClauses_"
511        << DirLang.getDirectivePrefix() << Dir.getFormattedName() << ",\n";
512     OS << "      llvm::" << DirLang.getCppNamespace() << "::allowedOnceClauses_"
513        << DirLang.getDirectivePrefix() << Dir.getFormattedName() << ",\n";
514     OS << "      llvm::" << DirLang.getCppNamespace()
515        << "::allowedExclusiveClauses_" << DirLang.getDirectivePrefix()
516        << Dir.getFormattedName() << ",\n";
517     OS << "      llvm::" << DirLang.getCppNamespace() << "::requiredClauses_"
518        << DirLang.getDirectivePrefix() << Dir.getFormattedName() << ",\n";
519     OS << "    }\n";
520     OS << "  },\n";
521   }
522 
523   OS << "}\n";
524 }
525 
526 // Generate classes entry for Flang clauses in the Flang parse-tree
527 // If the clause as a non-generic class, no entry is generated.
528 // If the clause does not hold a value, an EMPTY_CLASS is used.
529 // If the clause class is generic then a WRAPPER_CLASS is used. When the value
530 // is optional, the value class is wrapped into a std::optional.
531 void GenerateFlangClauseParserClass(const std::vector<Record *> &Clauses,
532                                     raw_ostream &OS) {
533 
534   IfDefScope Scope("GEN_FLANG_CLAUSE_PARSER_CLASSES", OS);
535 
536   OS << "\n";
537 
538   for (const auto &C : Clauses) {
539     Clause Clause{C};
540     // Clause has a non generic class.
541     if (!Clause.getFlangClass().empty())
542       continue;
543     // G
544     if (!Clause.getFlangClassValue().empty()) {
545       if (Clause.isValueOptional()) {
546         OS << "WRAPPER_CLASS(" << Clause.getFormattedParserClassName()
547            << ", std::optional<" << Clause.getFlangClassValue() << ">);\n";
548       } else {
549         OS << "WRAPPER_CLASS(" << Clause.getFormattedParserClassName() << ", "
550            << Clause.getFlangClassValue() << ");\n";
551       }
552     } else {
553       OS << "EMPTY_CLASS(" << Clause.getFormattedParserClassName() << ");\n";
554     }
555   }
556 }
557 
558 // Generate a list of the different clause classes for Flang.
559 void GenerateFlangClauseParserClassList(const std::vector<Record *> &Clauses,
560                                         raw_ostream &OS) {
561 
562   IfDefScope Scope("GEN_FLANG_CLAUSE_PARSER_CLASSES_LIST", OS);
563 
564   OS << "\n";
565   llvm::interleaveComma(Clauses, OS, [&](Record *C) {
566     Clause Clause{C};
567     if (Clause.getFlangClass().empty())
568       OS << Clause.getFormattedParserClassName() << "\n";
569     else
570       OS << Clause.getFlangClass() << "\n";
571   });
572 }
573 
574 // Generate dump node list for the clauses holding a generic class name.
575 void GenerateFlangClauseDump(const std::vector<Record *> &Clauses,
576                              const DirectiveLanguage &DirLang,
577                              raw_ostream &OS) {
578 
579   IfDefScope Scope("GEN_FLANG_DUMP_PARSE_TREE_CLAUSES", OS);
580 
581   OS << "\n";
582   for (const auto &C : Clauses) {
583     Clause Clause{C};
584     // Clause has a non generic class.
585     if (!Clause.getFlangClass().empty())
586       continue;
587 
588     OS << "NODE(" << DirLang.getFlangClauseBaseClass() << ", "
589        << Clause.getFormattedParserClassName() << ")\n";
590   }
591 }
592 
593 // Generate the implemenation section for the enumeration in the directive
594 // language
595 void EmitDirectivesFlangImpl(const std::vector<Record *> &Directives,
596                              const std::vector<Record *> &Clauses,
597                              raw_ostream &OS,
598                              DirectiveLanguage &DirectiveLanguage) {
599 
600   GenerateDirectiveClauseSets(Directives, OS, DirectiveLanguage);
601 
602   GenerateDirectiveClauseMap(Directives, OS, DirectiveLanguage);
603 
604   GenerateFlangClauseParserClass(Clauses, OS);
605 
606   GenerateFlangClauseParserClassList(Clauses, OS);
607 
608   GenerateFlangClauseDump(Clauses, DirectiveLanguage, OS);
609 }
610 
611 // Generate the implemenation section for the enumeration in the directive
612 // language.
613 void EmitDirectivesGen(RecordKeeper &Records, raw_ostream &OS) {
614 
615   const auto &DirectiveLanguages =
616       Records.getAllDerivedDefinitions("DirectiveLanguage");
617 
618   if (DirectiveLanguages.size() != 1) {
619     PrintError("A single definition of DirectiveLanguage is needed.");
620     return;
621   }
622 
623   const auto &Directives = Records.getAllDerivedDefinitions("Directive");
624   const auto &Clauses = Records.getAllDerivedDefinitions("Clause");
625   DirectiveLanguage DirectiveLanguage{DirectiveLanguages[0]};
626   EmitDirectivesFlangImpl(Directives, Clauses, OS, DirectiveLanguage);
627 }
628 
629 // Generate the implemenation for the enumeration in the directive
630 // language. This code can be included in library.
631 void EmitDirectivesImpl(RecordKeeper &Records, raw_ostream &OS) {
632 
633   const auto &DirectiveLanguages =
634       Records.getAllDerivedDefinitions("DirectiveLanguage");
635 
636   if (DirectiveLanguages.size() != 1) {
637     PrintError("A single definition of DirectiveLanguage is needed.");
638     return;
639   }
640 
641   const auto &Directives = Records.getAllDerivedDefinitions("Directive");
642 
643   DirectiveLanguage DirLang = DirectiveLanguage{DirectiveLanguages[0]};
644 
645   const auto &Clauses = Records.getAllDerivedDefinitions("Clause");
646 
647   if (!DirLang.getIncludeHeader().empty())
648     OS << "#include \"" << DirLang.getIncludeHeader() << "\"\n\n";
649 
650   OS << "#include \"llvm/ADT/StringRef.h\"\n";
651   OS << "#include \"llvm/ADT/StringSwitch.h\"\n";
652   OS << "#include \"llvm/Support/ErrorHandling.h\"\n";
653   OS << "\n";
654   OS << "using namespace llvm;\n";
655   llvm::SmallVector<StringRef, 2> Namespaces;
656   llvm::SplitString(DirLang.getCppNamespace(), Namespaces, "::");
657   for (auto Ns : Namespaces)
658     OS << "using namespace " << Ns << ";\n";
659 
660   // getDirectiveKind(StringRef Str)
661   GenerateGetKind(Directives, OS, "Directive", DirLang,
662                   DirLang.getDirectivePrefix(), /*ImplicitAsUnknown=*/false);
663 
664   // getDirectiveName(Directive Kind)
665   GenerateGetName(Directives, OS, "Directive", DirLang,
666                   DirLang.getDirectivePrefix());
667 
668   // getClauseKind(StringRef Str)
669   GenerateGetKind(Clauses, OS, "Clause", DirLang, DirLang.getClausePrefix(),
670                   /*ImplicitAsUnknown=*/true);
671 
672   // getClauseName(Clause Kind)
673   GenerateGetName(Clauses, OS, "Clause", DirLang, DirLang.getClausePrefix());
674 
675   // isAllowedClauseForDirective(Directive D, Clause C, unsigned Version)
676   GenerateIsAllowedClause(Directives, OS, DirLang);
677 }
678 
679 } // namespace llvm
680