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