xref: /freebsd/contrib/llvm-project/llvm/utils/TableGen/DirectiveEmitter.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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/TableGen/DirectiveEmitter.h"
15 #include "llvm/ADT/DenseMap.h"
16 #include "llvm/ADT/DenseSet.h"
17 #include "llvm/ADT/STLExtras.h"
18 #include "llvm/ADT/SmallVector.h"
19 #include "llvm/ADT/StringSet.h"
20 #include "llvm/ADT/StringSwitch.h"
21 #include "llvm/TableGen/Error.h"
22 #include "llvm/TableGen/Record.h"
23 #include "llvm/TableGen/TableGenBackend.h"
24 
25 #include <numeric>
26 #include <vector>
27 
28 using namespace llvm;
29 
30 namespace {
31 // Simple RAII helper for defining ifdef-undef-endif scopes.
32 class IfDefScope {
33 public:
IfDefScope(StringRef Name,raw_ostream & OS)34   IfDefScope(StringRef Name, raw_ostream &OS) : Name(Name), OS(OS) {
35     OS << "#ifdef " << Name << "\n"
36        << "#undef " << Name << "\n";
37   }
38 
~IfDefScope()39   ~IfDefScope() { OS << "\n#endif // " << Name << "\n\n"; }
40 
41 private:
42   StringRef Name;
43   raw_ostream &OS;
44 };
45 } // namespace
46 
47 // Generate enum class. Entries are emitted in the order in which they appear
48 // in the `Records` vector.
GenerateEnumClass(const std::vector<Record * > & Records,raw_ostream & OS,StringRef Enum,StringRef Prefix,const DirectiveLanguage & DirLang,bool ExportEnums)49 static void GenerateEnumClass(const std::vector<Record *> &Records,
50                               raw_ostream &OS, StringRef Enum, StringRef Prefix,
51                               const DirectiveLanguage &DirLang,
52                               bool ExportEnums) {
53   OS << "\n";
54   OS << "enum class " << Enum << " {\n";
55   for (const auto &R : Records) {
56     BaseRecord Rec{R};
57     OS << "  " << Prefix << Rec.getFormattedName() << ",\n";
58   }
59   OS << "};\n";
60   OS << "\n";
61   OS << "static constexpr std::size_t " << Enum
62      << "_enumSize = " << Records.size() << ";\n";
63 
64   // Make the enum values available in the defined namespace. This allows us to
65   // write something like Enum_X if we have a `using namespace <CppNamespace>`.
66   // At the same time we do not loose the strong type guarantees of the enum
67   // class, that is we cannot pass an unsigned as Directive without an explicit
68   // cast.
69   if (ExportEnums) {
70     OS << "\n";
71     for (const auto &R : Records) {
72       BaseRecord Rec{R};
73       OS << "constexpr auto " << Prefix << Rec.getFormattedName() << " = "
74          << "llvm::" << DirLang.getCppNamespace() << "::" << Enum
75          << "::" << Prefix << Rec.getFormattedName() << ";\n";
76     }
77   }
78 }
79 
80 // Generate enums for values that clauses can take.
81 // 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)82 static void GenerateEnumClauseVal(const std::vector<Record *> &Records,
83                                   raw_ostream &OS,
84                                   const DirectiveLanguage &DirLang,
85                                   std::string &EnumHelperFuncs) {
86   for (const auto &R : Records) {
87     Clause C{R};
88     const auto &ClauseVals = C.getClauseVals();
89     if (ClauseVals.size() <= 0)
90       continue;
91 
92     const auto &EnumName = C.getEnumName();
93     if (EnumName.size() == 0) {
94       PrintError("enumClauseValue field not set in Clause" +
95                  C.getFormattedName() + ".");
96       return;
97     }
98 
99     OS << "\n";
100     OS << "enum class " << EnumName << " {\n";
101     for (const auto &CV : ClauseVals) {
102       ClauseVal CVal{CV};
103       OS << "  " << CV->getName() << "=" << CVal.getValue() << ",\n";
104     }
105     OS << "};\n";
106 
107     if (DirLang.hasMakeEnumAvailableInNamespace()) {
108       OS << "\n";
109       for (const auto &CV : ClauseVals) {
110         OS << "constexpr auto " << CV->getName() << " = "
111            << "llvm::" << DirLang.getCppNamespace() << "::" << EnumName
112            << "::" << CV->getName() << ";\n";
113       }
114       EnumHelperFuncs += (llvm::Twine(EnumName) + llvm::Twine(" get") +
115                           llvm::Twine(EnumName) + llvm::Twine("(StringRef);\n"))
116                              .str();
117 
118       EnumHelperFuncs +=
119           (llvm::Twine("llvm::StringRef get") + llvm::Twine(DirLang.getName()) +
120            llvm::Twine(EnumName) + llvm::Twine("Name(") +
121            llvm::Twine(EnumName) + llvm::Twine(");\n"))
122               .str();
123     }
124   }
125 }
126 
HasDuplicateClauses(const std::vector<Record * > & Clauses,const Directive & Directive,llvm::StringSet<> & CrtClauses)127 static bool HasDuplicateClauses(const std::vector<Record *> &Clauses,
128                                 const Directive &Directive,
129                                 llvm::StringSet<> &CrtClauses) {
130   bool HasError = false;
131   for (const auto &C : Clauses) {
132     VersionedClause VerClause{C};
133     const auto insRes = CrtClauses.insert(VerClause.getClause().getName());
134     if (!insRes.second) {
135       PrintError("Clause " + VerClause.getClause().getRecordName() +
136                  " already defined on directive " + Directive.getRecordName());
137       HasError = true;
138     }
139   }
140   return HasError;
141 }
142 
143 // Check for duplicate clauses in lists. Clauses cannot appear twice in the
144 // three allowed list. Also, since required implies allowed, clauses cannot
145 // appear in both the allowedClauses and requiredClauses lists.
146 static bool
HasDuplicateClausesInDirectives(const std::vector<Record * > & Directives)147 HasDuplicateClausesInDirectives(const std::vector<Record *> &Directives) {
148   bool HasDuplicate = false;
149   for (const auto &D : Directives) {
150     Directive Dir{D};
151     llvm::StringSet<> Clauses;
152     // Check for duplicates in the three allowed lists.
153     if (HasDuplicateClauses(Dir.getAllowedClauses(), Dir, Clauses) ||
154         HasDuplicateClauses(Dir.getAllowedOnceClauses(), Dir, Clauses) ||
155         HasDuplicateClauses(Dir.getAllowedExclusiveClauses(), Dir, Clauses)) {
156       HasDuplicate = true;
157     }
158     // Check for duplicate between allowedClauses and required
159     Clauses.clear();
160     if (HasDuplicateClauses(Dir.getAllowedClauses(), Dir, Clauses) ||
161         HasDuplicateClauses(Dir.getRequiredClauses(), Dir, Clauses)) {
162       HasDuplicate = true;
163     }
164     if (HasDuplicate)
165       PrintFatalError("One or more clauses are defined multiple times on"
166                       " directive " +
167                       Dir.getRecordName());
168   }
169 
170   return HasDuplicate;
171 }
172 
173 // Check consitency of records. Return true if an error has been detected.
174 // Return false if the records are valid.
HasValidityErrors() const175 bool DirectiveLanguage::HasValidityErrors() const {
176   if (getDirectiveLanguages().size() != 1) {
177     PrintFatalError("A single definition of DirectiveLanguage is needed.");
178     return true;
179   }
180 
181   return HasDuplicateClausesInDirectives(getDirectives());
182 }
183 
184 // Count the maximum number of leaf constituents per construct.
GetMaxLeafCount(const DirectiveLanguage & DirLang)185 static size_t GetMaxLeafCount(const DirectiveLanguage &DirLang) {
186   size_t MaxCount = 0;
187   for (Record *R : DirLang.getDirectives()) {
188     size_t Count = Directive{R}.getLeafConstructs().size();
189     MaxCount = std::max(MaxCount, Count);
190   }
191   return MaxCount;
192 }
193 
194 // Generate the declaration section for the enumeration in the directive
195 // language
EmitDirectivesDecl(RecordKeeper & Records,raw_ostream & OS)196 static void EmitDirectivesDecl(RecordKeeper &Records, raw_ostream &OS) {
197   const auto DirLang = DirectiveLanguage{Records};
198   if (DirLang.HasValidityErrors())
199     return;
200 
201   OS << "#ifndef LLVM_" << DirLang.getName() << "_INC\n";
202   OS << "#define LLVM_" << DirLang.getName() << "_INC\n";
203   OS << "\n#include \"llvm/ADT/ArrayRef.h\"\n";
204 
205   if (DirLang.hasEnableBitmaskEnumInNamespace())
206     OS << "#include \"llvm/ADT/BitmaskEnum.h\"\n";
207 
208   OS << "#include <cstddef>\n"; // for size_t
209   OS << "\n";
210   OS << "namespace llvm {\n";
211   OS << "class StringRef;\n";
212 
213   // Open namespaces defined in the directive language
214   llvm::SmallVector<StringRef, 2> Namespaces;
215   llvm::SplitString(DirLang.getCppNamespace(), Namespaces, "::");
216   for (auto Ns : Namespaces)
217     OS << "namespace " << Ns << " {\n";
218 
219   if (DirLang.hasEnableBitmaskEnumInNamespace())
220     OS << "\nLLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();\n";
221 
222   // Emit Directive associations
223   std::vector<Record *> associations;
224   llvm::copy_if(
225       DirLang.getAssociations(), std::back_inserter(associations),
226       // Skip the "special" value
227       [](const Record *Def) { return Def->getName() != "AS_FromLeaves"; });
228   GenerateEnumClass(associations, OS, "Association",
229                     /*Prefix=*/"", DirLang, /*ExportEnums=*/false);
230 
231   GenerateEnumClass(DirLang.getCategories(), OS, "Category", /*Prefix=*/"",
232                     DirLang, /*ExportEnums=*/false);
233 
234   // Emit Directive enumeration
235   GenerateEnumClass(DirLang.getDirectives(), OS, "Directive",
236                     DirLang.getDirectivePrefix(), DirLang,
237                     DirLang.hasMakeEnumAvailableInNamespace());
238 
239   // Emit Clause enumeration
240   GenerateEnumClass(DirLang.getClauses(), OS, "Clause",
241                     DirLang.getClausePrefix(), DirLang,
242                     DirLang.hasMakeEnumAvailableInNamespace());
243 
244   // Emit ClauseVal enumeration
245   std::string EnumHelperFuncs;
246   GenerateEnumClauseVal(DirLang.getClauses(), OS, DirLang, EnumHelperFuncs);
247 
248   // Generic function signatures
249   OS << "\n";
250   OS << "// Enumeration helper functions\n";
251   OS << "Directive get" << DirLang.getName()
252      << "DirectiveKind(llvm::StringRef Str);\n";
253   OS << "\n";
254   OS << "llvm::StringRef get" << DirLang.getName()
255      << "DirectiveName(Directive D);\n";
256   OS << "\n";
257   OS << "Clause get" << DirLang.getName()
258      << "ClauseKind(llvm::StringRef Str);\n";
259   OS << "\n";
260   OS << "llvm::StringRef get" << DirLang.getName() << "ClauseName(Clause C);\n";
261   OS << "\n";
262   OS << "/// Return true if \\p C is a valid clause for \\p D in version \\p "
263      << "Version.\n";
264   OS << "bool isAllowedClauseForDirective(Directive D, "
265      << "Clause C, unsigned Version);\n";
266   OS << "\n";
267   OS << "constexpr std::size_t getMaxLeafCount() { return "
268      << GetMaxLeafCount(DirLang) << "; }\n";
269   OS << "Association getDirectiveAssociation(Directive D);\n";
270   OS << "Category getDirectiveCategory(Directive D);\n";
271   if (EnumHelperFuncs.length() > 0) {
272     OS << EnumHelperFuncs;
273     OS << "\n";
274   }
275 
276   // Closing namespaces
277   for (auto Ns : llvm::reverse(Namespaces))
278     OS << "} // namespace " << Ns << "\n";
279 
280   OS << "} // namespace llvm\n";
281 
282   OS << "#endif // LLVM_" << DirLang.getName() << "_INC\n";
283 }
284 
285 // 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)286 static void GenerateGetName(const std::vector<Record *> &Records,
287                             raw_ostream &OS, StringRef Enum,
288                             const DirectiveLanguage &DirLang,
289                             StringRef Prefix) {
290   OS << "\n";
291   OS << "llvm::StringRef llvm::" << DirLang.getCppNamespace() << "::get"
292      << DirLang.getName() << Enum << "Name(" << Enum << " Kind) {\n";
293   OS << "  switch (Kind) {\n";
294   for (const auto &R : Records) {
295     BaseRecord Rec{R};
296     OS << "    case " << Prefix << Rec.getFormattedName() << ":\n";
297     OS << "      return \"";
298     if (Rec.getAlternativeName().empty())
299       OS << Rec.getName();
300     else
301       OS << Rec.getAlternativeName();
302     OS << "\";\n";
303   }
304   OS << "  }\n"; // switch
305   OS << "  llvm_unreachable(\"Invalid " << DirLang.getName() << " " << Enum
306      << " kind\");\n";
307   OS << "}\n";
308 }
309 
310 // 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)311 static void GenerateGetKind(const std::vector<Record *> &Records,
312                             raw_ostream &OS, StringRef Enum,
313                             const DirectiveLanguage &DirLang, StringRef Prefix,
314                             bool ImplicitAsUnknown) {
315 
316   auto DefaultIt = llvm::find_if(
317       Records, [](Record *R) { return R->getValueAsBit("isDefault") == true; });
318 
319   if (DefaultIt == Records.end()) {
320     PrintError("At least one " + Enum + " must be defined as default.");
321     return;
322   }
323 
324   BaseRecord DefaultRec{(*DefaultIt)};
325 
326   OS << "\n";
327   OS << Enum << " llvm::" << DirLang.getCppNamespace() << "::get"
328      << DirLang.getName() << Enum << "Kind(llvm::StringRef Str) {\n";
329   OS << "  return llvm::StringSwitch<" << Enum << ">(Str)\n";
330 
331   for (const auto &R : Records) {
332     BaseRecord Rec{R};
333     if (ImplicitAsUnknown && R->getValueAsBit("isImplicit")) {
334       OS << "    .Case(\"" << Rec.getName() << "\"," << Prefix
335          << DefaultRec.getFormattedName() << ")\n";
336     } else {
337       OS << "    .Case(\"" << Rec.getName() << "\"," << Prefix
338          << Rec.getFormattedName() << ")\n";
339     }
340   }
341   OS << "    .Default(" << Prefix << DefaultRec.getFormattedName() << ");\n";
342   OS << "}\n";
343 }
344 
345 // Generate function implementation for get<ClauseVal>Kind(StringRef Str)
GenerateGetKindClauseVal(const DirectiveLanguage & DirLang,raw_ostream & OS)346 static void GenerateGetKindClauseVal(const DirectiveLanguage &DirLang,
347                                      raw_ostream &OS) {
348   for (const auto &R : DirLang.getClauses()) {
349     Clause C{R};
350     const auto &ClauseVals = C.getClauseVals();
351     if (ClauseVals.size() <= 0)
352       continue;
353 
354     auto DefaultIt = llvm::find_if(ClauseVals, [](Record *CV) {
355       return CV->getValueAsBit("isDefault") == true;
356     });
357 
358     if (DefaultIt == ClauseVals.end()) {
359       PrintError("At least one val in Clause " + C.getFormattedName() +
360                  " must be defined as default.");
361       return;
362     }
363     const auto DefaultName = (*DefaultIt)->getName();
364 
365     const auto &EnumName = C.getEnumName();
366     if (EnumName.size() == 0) {
367       PrintError("enumClauseValue field not set in Clause" +
368                  C.getFormattedName() + ".");
369       return;
370     }
371 
372     OS << "\n";
373     OS << EnumName << " llvm::" << DirLang.getCppNamespace() << "::get"
374        << EnumName << "(llvm::StringRef Str) {\n";
375     OS << "  return llvm::StringSwitch<" << EnumName << ">(Str)\n";
376     for (const auto &CV : ClauseVals) {
377       ClauseVal CVal{CV};
378       OS << "    .Case(\"" << CVal.getFormattedName() << "\"," << CV->getName()
379          << ")\n";
380     }
381     OS << "    .Default(" << DefaultName << ");\n";
382     OS << "}\n";
383 
384     OS << "\n";
385     OS << "llvm::StringRef llvm::" << DirLang.getCppNamespace() << "::get"
386        << DirLang.getName() << EnumName
387        << "Name(llvm::" << DirLang.getCppNamespace() << "::" << EnumName
388        << " x) {\n";
389     OS << "  switch (x) {\n";
390     for (const auto &CV : ClauseVals) {
391       ClauseVal CVal{CV};
392       OS << "    case " << CV->getName() << ":\n";
393       OS << "      return \"" << CVal.getFormattedName() << "\";\n";
394     }
395     OS << "  }\n"; // switch
396     OS << "  llvm_unreachable(\"Invalid " << DirLang.getName() << " "
397        << EnumName << " kind\");\n";
398     OS << "}\n";
399   }
400 }
401 
402 static void
GenerateCaseForVersionedClauses(const std::vector<Record * > & Clauses,raw_ostream & OS,StringRef DirectiveName,const DirectiveLanguage & DirLang,llvm::StringSet<> & Cases)403 GenerateCaseForVersionedClauses(const std::vector<Record *> &Clauses,
404                                 raw_ostream &OS, StringRef DirectiveName,
405                                 const DirectiveLanguage &DirLang,
406                                 llvm::StringSet<> &Cases) {
407   for (const auto &C : Clauses) {
408     VersionedClause VerClause{C};
409 
410     const auto ClauseFormattedName = VerClause.getClause().getFormattedName();
411 
412     if (Cases.insert(ClauseFormattedName).second) {
413       OS << "        case " << DirLang.getClausePrefix() << ClauseFormattedName
414          << ":\n";
415       OS << "          return " << VerClause.getMinVersion()
416          << " <= Version && " << VerClause.getMaxVersion() << " >= Version;\n";
417     }
418   }
419 }
420 
GetDirectiveName(const DirectiveLanguage & DirLang,const Record * Rec)421 static std::string GetDirectiveName(const DirectiveLanguage &DirLang,
422                                     const Record *Rec) {
423   Directive Dir{Rec};
424   return (llvm::Twine("llvm::") + DirLang.getCppNamespace() +
425           "::" + DirLang.getDirectivePrefix() + Dir.getFormattedName())
426       .str();
427 }
428 
GetDirectiveType(const DirectiveLanguage & DirLang)429 static std::string GetDirectiveType(const DirectiveLanguage &DirLang) {
430   return (llvm::Twine("llvm::") + DirLang.getCppNamespace() + "::Directive")
431       .str();
432 }
433 
434 // Generate the isAllowedClauseForDirective function implementation.
GenerateIsAllowedClause(const DirectiveLanguage & DirLang,raw_ostream & OS)435 static void GenerateIsAllowedClause(const DirectiveLanguage &DirLang,
436                                     raw_ostream &OS) {
437   OS << "\n";
438   OS << "bool llvm::" << DirLang.getCppNamespace()
439      << "::isAllowedClauseForDirective("
440      << "Directive D, Clause C, unsigned Version) {\n";
441   OS << "  assert(unsigned(D) <= llvm::" << DirLang.getCppNamespace()
442      << "::Directive_enumSize);\n";
443   OS << "  assert(unsigned(C) <= llvm::" << DirLang.getCppNamespace()
444      << "::Clause_enumSize);\n";
445 
446   OS << "  switch (D) {\n";
447 
448   for (const auto &D : DirLang.getDirectives()) {
449     Directive Dir{D};
450 
451     OS << "    case " << DirLang.getDirectivePrefix() << Dir.getFormattedName()
452        << ":\n";
453     if (Dir.getAllowedClauses().size() == 0 &&
454         Dir.getAllowedOnceClauses().size() == 0 &&
455         Dir.getAllowedExclusiveClauses().size() == 0 &&
456         Dir.getRequiredClauses().size() == 0) {
457       OS << "      return false;\n";
458     } else {
459       OS << "      switch (C) {\n";
460 
461       llvm::StringSet<> Cases;
462 
463       GenerateCaseForVersionedClauses(Dir.getAllowedClauses(), OS,
464                                       Dir.getName(), DirLang, Cases);
465 
466       GenerateCaseForVersionedClauses(Dir.getAllowedOnceClauses(), OS,
467                                       Dir.getName(), DirLang, Cases);
468 
469       GenerateCaseForVersionedClauses(Dir.getAllowedExclusiveClauses(), OS,
470                                       Dir.getName(), DirLang, Cases);
471 
472       GenerateCaseForVersionedClauses(Dir.getRequiredClauses(), OS,
473                                       Dir.getName(), DirLang, Cases);
474 
475       OS << "        default:\n";
476       OS << "          return false;\n";
477       OS << "      }\n"; // End of clauses switch
478     }
479     OS << "      break;\n";
480   }
481 
482   OS << "  }\n"; // End of directives switch
483   OS << "  llvm_unreachable(\"Invalid " << DirLang.getName()
484      << " Directive kind\");\n";
485   OS << "}\n"; // End of function isAllowedClauseForDirective
486 }
487 
EmitLeafTable(const DirectiveLanguage & DirLang,raw_ostream & OS,StringRef TableName)488 static void EmitLeafTable(const DirectiveLanguage &DirLang, raw_ostream &OS,
489                           StringRef TableName) {
490   // The leaf constructs are emitted in a form of a 2D table, where each
491   // row corresponds to a directive (and there is a row for each directive).
492   //
493   // Each row consists of
494   // - the id of the directive itself,
495   // - number of leaf constructs that will follow (0 for leafs),
496   // - ids of the leaf constructs (none if the directive is itself a leaf).
497   // The total number of these entries is at most MaxLeafCount+2. If this
498   // number is less than that, it is padded to occupy exactly MaxLeafCount+2
499   // entries in memory.
500   //
501   // The rows are stored in the table in the lexicographical order. This
502   // is intended to enable binary search when mapping a sequence of leafs
503   // back to the compound directive.
504   // The consequence of that is that in order to find a row corresponding
505   // to the given directive, we'd need to scan the first element of each
506   // row. To avoid this, an auxiliary ordering table is created, such that
507   //   row for Dir_A = table[auxiliary[Dir_A]].
508 
509   std::vector<Record *> Directives = DirLang.getDirectives();
510   DenseMap<Record *, int> DirId; // Record * -> llvm::omp::Directive
511 
512   for (auto [Idx, Rec] : llvm::enumerate(Directives))
513     DirId.insert(std::make_pair(Rec, Idx));
514 
515   using LeafList = std::vector<int>;
516   int MaxLeafCount = GetMaxLeafCount(DirLang);
517 
518   // The initial leaf table, rows order is same as directive order.
519   std::vector<LeafList> LeafTable(Directives.size());
520   for (auto [Idx, Rec] : llvm::enumerate(Directives)) {
521     Directive Dir{Rec};
522     std::vector<Record *> Leaves = Dir.getLeafConstructs();
523 
524     auto &List = LeafTable[Idx];
525     List.resize(MaxLeafCount + 2);
526     List[0] = Idx;           // The id of the directive itself.
527     List[1] = Leaves.size(); // The number of leaves to follow.
528 
529     for (int I = 0; I != MaxLeafCount; ++I)
530       List[I + 2] =
531           static_cast<size_t>(I) < Leaves.size() ? DirId.at(Leaves[I]) : -1;
532   }
533 
534   // Some Fortran directives are delimited, i.e. they have the form of
535   // "directive"---"end directive". If "directive" is a compound construct,
536   // then the set of leaf constituents will be nonempty and the same for
537   // both directives. Given this set of leafs, looking up the corresponding
538   // compound directive should return "directive", and not "end directive".
539   // To avoid this problem, gather all "end directives" at the end of the
540   // leaf table, and only do the search on the initial segment of the table
541   // that excludes the "end directives".
542   // It's safe to find all directives whose names begin with "end ". The
543   // problem only exists for compound directives, like "end do simd".
544   // All existing directives with names starting with "end " are either
545   // "end directives" for an existing "directive", or leaf directives
546   // (such as "end declare target").
547   DenseSet<int> EndDirectives;
548   for (auto [Rec, Id] : DirId) {
549     if (Directive{Rec}.getName().starts_with_insensitive("end "))
550       EndDirectives.insert(Id);
551   }
552 
553   // Avoid sorting the vector<vector> array, instead sort an index array.
554   // It will also be useful later to create the auxiliary indexing array.
555   std::vector<int> Ordering(Directives.size());
556   std::iota(Ordering.begin(), Ordering.end(), 0);
557 
558   llvm::sort(Ordering, [&](int A, int B) {
559     auto &LeavesA = LeafTable[A];
560     auto &LeavesB = LeafTable[B];
561     int DirA = LeavesA[0], DirB = LeavesB[0];
562     // First of all, end directives compare greater than non-end directives.
563     int IsEndA = EndDirectives.count(DirA), IsEndB = EndDirectives.count(DirB);
564     if (IsEndA != IsEndB)
565       return IsEndA < IsEndB;
566     if (LeavesA[1] == 0 && LeavesB[1] == 0)
567       return DirA < DirB;
568     return std::lexicographical_compare(&LeavesA[2], &LeavesA[2] + LeavesA[1],
569                                         &LeavesB[2], &LeavesB[2] + LeavesB[1]);
570   });
571 
572   // Emit the table
573 
574   // The directives are emitted into a scoped enum, for which the underlying
575   // type is `int` (by default). The code above uses `int` to store directive
576   // ids, so make sure that we catch it when something changes in the
577   // underlying type.
578   std::string DirectiveType = GetDirectiveType(DirLang);
579   OS << "\nstatic_assert(sizeof(" << DirectiveType << ") == sizeof(int));\n";
580 
581   OS << "[[maybe_unused]] static const " << DirectiveType << ' ' << TableName
582      << "[][" << MaxLeafCount + 2 << "] = {\n";
583   for (size_t I = 0, E = Directives.size(); I != E; ++I) {
584     auto &Leaves = LeafTable[Ordering[I]];
585     OS << "    {" << GetDirectiveName(DirLang, Directives[Leaves[0]]);
586     OS << ", static_cast<" << DirectiveType << ">(" << Leaves[1] << "),";
587     for (size_t I = 2, E = Leaves.size(); I != E; ++I) {
588       int Idx = Leaves[I];
589       if (Idx >= 0)
590         OS << ' ' << GetDirectiveName(DirLang, Directives[Leaves[I]]) << ',';
591       else
592         OS << " static_cast<" << DirectiveType << ">(-1),";
593     }
594     OS << "},\n";
595   }
596   OS << "};\n\n";
597 
598   // Emit a marker where the first "end directive" is.
599   auto FirstE = llvm::find_if(Ordering, [&](int RowIdx) {
600     return EndDirectives.count(LeafTable[RowIdx][0]);
601   });
602   OS << "[[maybe_unused]] static auto " << TableName
603      << "EndDirective = " << TableName << " + "
604      << std::distance(Ordering.begin(), FirstE) << ";\n\n";
605 
606   // Emit the auxiliary index table: it's the inverse of the `Ordering`
607   // table above.
608   OS << "[[maybe_unused]] static const int " << TableName << "Ordering[] = {\n";
609   OS << "   ";
610   std::vector<int> Reverse(Ordering.size());
611   for (int I = 0, E = Ordering.size(); I != E; ++I)
612     Reverse[Ordering[I]] = I;
613   for (int Idx : Reverse)
614     OS << ' ' << Idx << ',';
615   OS << "\n};\n";
616 }
617 
GenerateGetDirectiveAssociation(const DirectiveLanguage & DirLang,raw_ostream & OS)618 static void GenerateGetDirectiveAssociation(const DirectiveLanguage &DirLang,
619                                             raw_ostream &OS) {
620   enum struct Association {
621     None = 0, // None should be the smallest value.
622     Block,    // The values of the rest don't matter.
623     Declaration,
624     Delimited,
625     Loop,
626     Separating,
627     FromLeaves,
628     Invalid,
629   };
630 
631   std::vector<Record *> associations = DirLang.getAssociations();
632 
633   auto getAssocValue = [](StringRef name) -> Association {
634     return StringSwitch<Association>(name)
635         .Case("AS_Block", Association::Block)
636         .Case("AS_Declaration", Association::Declaration)
637         .Case("AS_Delimited", Association::Delimited)
638         .Case("AS_Loop", Association::Loop)
639         .Case("AS_None", Association::None)
640         .Case("AS_Separating", Association::Separating)
641         .Case("AS_FromLeaves", Association::FromLeaves)
642         .Default(Association::Invalid);
643   };
644 
645   auto getAssocName = [&](Association A) -> StringRef {
646     if (A != Association::Invalid && A != Association::FromLeaves) {
647       auto F = llvm::find_if(associations, [&](const Record *R) {
648         return getAssocValue(R->getName()) == A;
649       });
650       if (F != associations.end())
651         return (*F)->getValueAsString("name"); // enum name
652     }
653     llvm_unreachable("Unexpected association value");
654   };
655 
656   auto errorPrefixFor = [&](Directive D) -> std::string {
657     return (Twine("Directive '") + D.getName() + "' in namespace '" +
658             DirLang.getCppNamespace() + "' ")
659         .str();
660   };
661 
662   auto reduce = [&](Association A, Association B) -> Association {
663     if (A > B)
664       std::swap(A, B);
665 
666     // Calculate the result using the following rules:
667     //   x + x = x
668     //   AS_None + x = x
669     //   AS_Block + AS_Loop = AS_Loop
670     if (A == Association::None || A == B)
671       return B;
672     if (A == Association::Block && B == Association::Loop)
673       return B;
674     if (A == Association::Loop && B == Association::Block)
675       return A;
676     return Association::Invalid;
677   };
678 
679   llvm::DenseMap<const Record *, Association> AsMap;
680 
681   auto compAssocImpl = [&](const Record *R, auto &&Self) -> Association {
682     if (auto F = AsMap.find(R); F != AsMap.end())
683       return F->second;
684 
685     Directive D{R};
686     Association AS = getAssocValue(D.getAssociation()->getName());
687     if (AS == Association::Invalid) {
688       PrintFatalError(errorPrefixFor(D) +
689                       "has an unrecognized value for association: '" +
690                       D.getAssociation()->getName() + "'");
691     }
692     if (AS != Association::FromLeaves) {
693       AsMap.insert(std::make_pair(R, AS));
694       return AS;
695     }
696     // Compute the association from leaf constructs.
697     std::vector<Record *> leaves = D.getLeafConstructs();
698     if (leaves.empty()) {
699       llvm::errs() << D.getName() << '\n';
700       PrintFatalError(errorPrefixFor(D) +
701                       "requests association to be computed from leaves, "
702                       "but it has no leaves");
703     }
704 
705     Association Result = Self(leaves[0], Self);
706     for (int I = 1, E = leaves.size(); I < E; ++I) {
707       Association A = Self(leaves[I], Self);
708       Association R = reduce(Result, A);
709       if (R == Association::Invalid) {
710         PrintFatalError(errorPrefixFor(D) +
711                         "has leaves with incompatible association values: " +
712                         getAssocName(A) + " and " + getAssocName(R));
713       }
714       Result = R;
715     }
716 
717     assert(Result != Association::Invalid);
718     assert(Result != Association::FromLeaves);
719     AsMap.insert(std::make_pair(R, Result));
720     return Result;
721   };
722 
723   for (Record *R : DirLang.getDirectives())
724     compAssocImpl(R, compAssocImpl); // Updates AsMap.
725 
726   OS << '\n';
727 
728   auto getQualifiedName = [&](StringRef Formatted) -> std::string {
729     return (llvm::Twine("llvm::") + DirLang.getCppNamespace() +
730             "::Directive::" + DirLang.getDirectivePrefix() + Formatted)
731         .str();
732   };
733 
734   std::string DirectiveTypeName =
735       std::string("llvm::") + DirLang.getCppNamespace().str() + "::Directive";
736   std::string AssociationTypeName =
737       std::string("llvm::") + DirLang.getCppNamespace().str() + "::Association";
738 
739   OS << AssociationTypeName << " llvm::" << DirLang.getCppNamespace()
740      << "::getDirectiveAssociation(" << DirectiveTypeName << " Dir) {\n";
741   OS << "  switch (Dir) {\n";
742   for (Record *R : DirLang.getDirectives()) {
743     if (auto F = AsMap.find(R); F != AsMap.end()) {
744       Directive Dir{R};
745       OS << "  case " << getQualifiedName(Dir.getFormattedName()) << ":\n";
746       OS << "    return " << AssociationTypeName
747          << "::" << getAssocName(F->second) << ";\n";
748     }
749   }
750   OS << "  } // switch (Dir)\n";
751   OS << "  llvm_unreachable(\"Unexpected directive\");\n";
752   OS << "}\n";
753 }
754 
GenerateGetDirectiveCategory(const DirectiveLanguage & DirLang,raw_ostream & OS)755 static void GenerateGetDirectiveCategory(const DirectiveLanguage &DirLang,
756                                          raw_ostream &OS) {
757   std::string LangNamespace = "llvm::" + DirLang.getCppNamespace().str();
758   std::string CategoryTypeName = LangNamespace + "::Category";
759   std::string CategoryNamespace = CategoryTypeName + "::";
760 
761   OS << '\n';
762   OS << CategoryTypeName << ' ' << LangNamespace << "::getDirectiveCategory("
763      << GetDirectiveType(DirLang) << " Dir) {\n";
764   OS << "  switch (Dir) {\n";
765 
766   for (Record *R : DirLang.getDirectives()) {
767     Directive D{R};
768     OS << "  case " << GetDirectiveName(DirLang, R) << ":\n";
769     OS << "    return " << CategoryNamespace
770        << D.getCategory()->getValueAsString("name") << ";\n";
771   }
772   OS << "  } // switch (Dir)\n";
773   OS << "  llvm_unreachable(\"Unexpected directive\");\n";
774   OS << "}\n";
775 }
776 
777 // 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)778 static void GenerateClauseSet(const std::vector<Record *> &Clauses,
779                               raw_ostream &OS, StringRef ClauseSetPrefix,
780                               Directive &Dir,
781                               const DirectiveLanguage &DirLang) {
782 
783   OS << "\n";
784   OS << "  static " << DirLang.getClauseEnumSetClass() << " " << ClauseSetPrefix
785      << DirLang.getDirectivePrefix() << Dir.getFormattedName() << " {\n";
786 
787   for (const auto &C : Clauses) {
788     VersionedClause VerClause{C};
789     OS << "    llvm::" << DirLang.getCppNamespace()
790        << "::Clause::" << DirLang.getClausePrefix()
791        << VerClause.getClause().getFormattedName() << ",\n";
792   }
793   OS << "  };\n";
794 }
795 
796 // Generate an enum set for the 4 kinds of clauses linked to a directive.
GenerateDirectiveClauseSets(const DirectiveLanguage & DirLang,raw_ostream & OS)797 static void GenerateDirectiveClauseSets(const DirectiveLanguage &DirLang,
798                                         raw_ostream &OS) {
799 
800   IfDefScope Scope("GEN_FLANG_DIRECTIVE_CLAUSE_SETS", OS);
801 
802   OS << "\n";
803   OS << "namespace llvm {\n";
804 
805   // Open namespaces defined in the directive language.
806   llvm::SmallVector<StringRef, 2> Namespaces;
807   llvm::SplitString(DirLang.getCppNamespace(), Namespaces, "::");
808   for (auto Ns : Namespaces)
809     OS << "namespace " << Ns << " {\n";
810 
811   for (const auto &D : DirLang.getDirectives()) {
812     Directive Dir{D};
813 
814     OS << "\n";
815     OS << "  // Sets for " << Dir.getName() << "\n";
816 
817     GenerateClauseSet(Dir.getAllowedClauses(), OS, "allowedClauses_", Dir,
818                       DirLang);
819     GenerateClauseSet(Dir.getAllowedOnceClauses(), OS, "allowedOnceClauses_",
820                       Dir, DirLang);
821     GenerateClauseSet(Dir.getAllowedExclusiveClauses(), OS,
822                       "allowedExclusiveClauses_", Dir, DirLang);
823     GenerateClauseSet(Dir.getRequiredClauses(), OS, "requiredClauses_", Dir,
824                       DirLang);
825   }
826 
827   // Closing namespaces
828   for (auto Ns : llvm::reverse(Namespaces))
829     OS << "} // namespace " << Ns << "\n";
830 
831   OS << "} // namespace llvm\n";
832 }
833 
834 // Generate a map of directive (key) with DirectiveClauses struct as values.
835 // The struct holds the 4 sets of enumeration for the 4 kinds of clauses
836 // allowances (allowed, allowed once, allowed exclusive and required).
GenerateDirectiveClauseMap(const DirectiveLanguage & DirLang,raw_ostream & OS)837 static void GenerateDirectiveClauseMap(const DirectiveLanguage &DirLang,
838                                        raw_ostream &OS) {
839 
840   IfDefScope Scope("GEN_FLANG_DIRECTIVE_CLAUSE_MAP", OS);
841 
842   OS << "\n";
843   OS << "{\n";
844 
845   for (const auto &D : DirLang.getDirectives()) {
846     Directive Dir{D};
847     OS << "  {llvm::" << DirLang.getCppNamespace()
848        << "::Directive::" << DirLang.getDirectivePrefix()
849        << Dir.getFormattedName() << ",\n";
850     OS << "    {\n";
851     OS << "      llvm::" << DirLang.getCppNamespace() << "::allowedClauses_"
852        << DirLang.getDirectivePrefix() << Dir.getFormattedName() << ",\n";
853     OS << "      llvm::" << DirLang.getCppNamespace() << "::allowedOnceClauses_"
854        << DirLang.getDirectivePrefix() << Dir.getFormattedName() << ",\n";
855     OS << "      llvm::" << DirLang.getCppNamespace()
856        << "::allowedExclusiveClauses_" << DirLang.getDirectivePrefix()
857        << Dir.getFormattedName() << ",\n";
858     OS << "      llvm::" << DirLang.getCppNamespace() << "::requiredClauses_"
859        << DirLang.getDirectivePrefix() << Dir.getFormattedName() << ",\n";
860     OS << "    }\n";
861     OS << "  },\n";
862   }
863 
864   OS << "}\n";
865 }
866 
867 // Generate classes entry for Flang clauses in the Flang parse-tree
868 // If the clause as a non-generic class, no entry is generated.
869 // If the clause does not hold a value, an EMPTY_CLASS is used.
870 // If the clause class is generic then a WRAPPER_CLASS is used. When the value
871 // is optional, the value class is wrapped into a std::optional.
GenerateFlangClauseParserClass(const DirectiveLanguage & DirLang,raw_ostream & OS)872 static void GenerateFlangClauseParserClass(const DirectiveLanguage &DirLang,
873                                            raw_ostream &OS) {
874 
875   IfDefScope Scope("GEN_FLANG_CLAUSE_PARSER_CLASSES", OS);
876 
877   OS << "\n";
878 
879   for (const auto &C : DirLang.getClauses()) {
880     Clause Clause{C};
881     if (!Clause.getFlangClass().empty()) {
882       OS << "WRAPPER_CLASS(" << Clause.getFormattedParserClassName() << ", ";
883       if (Clause.isValueOptional() && Clause.isValueList()) {
884         OS << "std::optional<std::list<" << Clause.getFlangClass() << ">>";
885       } else if (Clause.isValueOptional()) {
886         OS << "std::optional<" << Clause.getFlangClass() << ">";
887       } else if (Clause.isValueList()) {
888         OS << "std::list<" << Clause.getFlangClass() << ">";
889       } else {
890         OS << Clause.getFlangClass();
891       }
892     } else {
893       OS << "EMPTY_CLASS(" << Clause.getFormattedParserClassName();
894     }
895     OS << ");\n";
896   }
897 }
898 
899 // Generate a list of the different clause classes for Flang.
GenerateFlangClauseParserClassList(const DirectiveLanguage & DirLang,raw_ostream & OS)900 static void GenerateFlangClauseParserClassList(const DirectiveLanguage &DirLang,
901                                                raw_ostream &OS) {
902 
903   IfDefScope Scope("GEN_FLANG_CLAUSE_PARSER_CLASSES_LIST", OS);
904 
905   OS << "\n";
906   llvm::interleaveComma(DirLang.getClauses(), OS, [&](Record *C) {
907     Clause Clause{C};
908     OS << Clause.getFormattedParserClassName() << "\n";
909   });
910 }
911 
912 // Generate dump node list for the clauses holding a generic class name.
GenerateFlangClauseDump(const DirectiveLanguage & DirLang,raw_ostream & OS)913 static void GenerateFlangClauseDump(const DirectiveLanguage &DirLang,
914                                     raw_ostream &OS) {
915 
916   IfDefScope Scope("GEN_FLANG_DUMP_PARSE_TREE_CLAUSES", OS);
917 
918   OS << "\n";
919   for (const auto &C : DirLang.getClauses()) {
920     Clause Clause{C};
921     OS << "NODE(" << DirLang.getFlangClauseBaseClass() << ", "
922        << Clause.getFormattedParserClassName() << ")\n";
923   }
924 }
925 
926 // Generate Unparse functions for clauses classes in the Flang parse-tree
927 // If the clause is a non-generic class, no entry is generated.
GenerateFlangClauseUnparse(const DirectiveLanguage & DirLang,raw_ostream & OS)928 static void GenerateFlangClauseUnparse(const DirectiveLanguage &DirLang,
929                                        raw_ostream &OS) {
930 
931   IfDefScope Scope("GEN_FLANG_CLAUSE_UNPARSE", OS);
932 
933   OS << "\n";
934 
935   for (const auto &C : DirLang.getClauses()) {
936     Clause Clause{C};
937     if (!Clause.getFlangClass().empty()) {
938       if (Clause.isValueOptional() && Clause.getDefaultValue().empty()) {
939         OS << "void Unparse(const " << DirLang.getFlangClauseBaseClass()
940            << "::" << Clause.getFormattedParserClassName() << " &x) {\n";
941         OS << "  Word(\"" << Clause.getName().upper() << "\");\n";
942 
943         OS << "  Walk(\"(\", x.v, \")\");\n";
944         OS << "}\n";
945       } else if (Clause.isValueOptional()) {
946         OS << "void Unparse(const " << DirLang.getFlangClauseBaseClass()
947            << "::" << Clause.getFormattedParserClassName() << " &x) {\n";
948         OS << "  Word(\"" << Clause.getName().upper() << "\");\n";
949         OS << "  Put(\"(\");\n";
950         OS << "  if (x.v.has_value())\n";
951         if (Clause.isValueList())
952           OS << "    Walk(x.v, \",\");\n";
953         else
954           OS << "    Walk(x.v);\n";
955         OS << "  else\n";
956         OS << "    Put(\"" << Clause.getDefaultValue() << "\");\n";
957         OS << "  Put(\")\");\n";
958         OS << "}\n";
959       } else {
960         OS << "void Unparse(const " << DirLang.getFlangClauseBaseClass()
961            << "::" << Clause.getFormattedParserClassName() << " &x) {\n";
962         OS << "  Word(\"" << Clause.getName().upper() << "\");\n";
963         OS << "  Put(\"(\");\n";
964         if (Clause.isValueList())
965           OS << "  Walk(x.v, \",\");\n";
966         else
967           OS << "  Walk(x.v);\n";
968         OS << "  Put(\")\");\n";
969         OS << "}\n";
970       }
971     } else {
972       OS << "void Before(const " << DirLang.getFlangClauseBaseClass()
973          << "::" << Clause.getFormattedParserClassName() << " &) { Word(\""
974          << Clause.getName().upper() << "\"); }\n";
975     }
976   }
977 }
978 
979 // Generate check in the Enter functions for clauses classes.
GenerateFlangClauseCheckPrototypes(const DirectiveLanguage & DirLang,raw_ostream & OS)980 static void GenerateFlangClauseCheckPrototypes(const DirectiveLanguage &DirLang,
981                                                raw_ostream &OS) {
982 
983   IfDefScope Scope("GEN_FLANG_CLAUSE_CHECK_ENTER", OS);
984 
985   OS << "\n";
986   for (const auto &C : DirLang.getClauses()) {
987     Clause Clause{C};
988     OS << "void Enter(const parser::" << DirLang.getFlangClauseBaseClass()
989        << "::" << Clause.getFormattedParserClassName() << " &);\n";
990   }
991 }
992 
993 // Generate the mapping for clauses between the parser class and the
994 // corresponding clause Kind
GenerateFlangClauseParserKindMap(const DirectiveLanguage & DirLang,raw_ostream & OS)995 static void GenerateFlangClauseParserKindMap(const DirectiveLanguage &DirLang,
996                                              raw_ostream &OS) {
997 
998   IfDefScope Scope("GEN_FLANG_CLAUSE_PARSER_KIND_MAP", OS);
999 
1000   OS << "\n";
1001   for (const auto &C : DirLang.getClauses()) {
1002     Clause Clause{C};
1003     OS << "if constexpr (std::is_same_v<A, parser::"
1004        << DirLang.getFlangClauseBaseClass()
1005        << "::" << Clause.getFormattedParserClassName();
1006     OS << ">)\n";
1007     OS << "  return llvm::" << DirLang.getCppNamespace()
1008        << "::Clause::" << DirLang.getClausePrefix() << Clause.getFormattedName()
1009        << ";\n";
1010   }
1011 
1012   OS << "llvm_unreachable(\"Invalid " << DirLang.getName()
1013      << " Parser clause\");\n";
1014 }
1015 
compareClauseName(Record * R1,Record * R2)1016 static bool compareClauseName(Record *R1, Record *R2) {
1017   Clause C1{R1};
1018   Clause C2{R2};
1019   return (C1.getName() > C2.getName());
1020 }
1021 
1022 // Generate the parser for the clauses.
GenerateFlangClausesParser(const DirectiveLanguage & DirLang,raw_ostream & OS)1023 static void GenerateFlangClausesParser(const DirectiveLanguage &DirLang,
1024                                        raw_ostream &OS) {
1025   std::vector<Record *> Clauses = DirLang.getClauses();
1026   // Sort clauses in reverse alphabetical order so with clauses with same
1027   // beginning, the longer option is tried before.
1028   llvm::sort(Clauses, compareClauseName);
1029   IfDefScope Scope("GEN_FLANG_CLAUSES_PARSER", OS);
1030   OS << "\n";
1031   unsigned index = 0;
1032   unsigned lastClauseIndex = DirLang.getClauses().size() - 1;
1033   OS << "TYPE_PARSER(\n";
1034   for (const auto &C : Clauses) {
1035     Clause Clause{C};
1036     if (Clause.getAliases().empty()) {
1037       OS << "  \"" << Clause.getName() << "\"";
1038     } else {
1039       OS << "  ("
1040          << "\"" << Clause.getName() << "\"_tok";
1041       for (StringRef alias : Clause.getAliases()) {
1042         OS << " || \"" << alias << "\"_tok";
1043       }
1044       OS << ")";
1045     }
1046 
1047     OS << " >> construct<" << DirLang.getFlangClauseBaseClass()
1048        << ">(construct<" << DirLang.getFlangClauseBaseClass()
1049        << "::" << Clause.getFormattedParserClassName() << ">(";
1050     if (Clause.getFlangClass().empty()) {
1051       OS << "))";
1052       if (index != lastClauseIndex)
1053         OS << " ||";
1054       OS << "\n";
1055       ++index;
1056       continue;
1057     }
1058 
1059     if (Clause.isValueOptional())
1060       OS << "maybe(";
1061     OS << "parenthesized(";
1062     if (Clause.isValueList())
1063       OS << "nonemptyList(";
1064 
1065     if (!Clause.getPrefix().empty())
1066       OS << "\"" << Clause.getPrefix() << ":\" >> ";
1067 
1068     // The common Flang parser are used directly. Their name is identical to
1069     // the Flang class with first letter as lowercase. If the Flang class is
1070     // not a common class, we assume there is a specific Parser<>{} with the
1071     // Flang class name provided.
1072     llvm::SmallString<128> Scratch;
1073     StringRef Parser =
1074         llvm::StringSwitch<StringRef>(Clause.getFlangClass())
1075             .Case("Name", "name")
1076             .Case("ScalarIntConstantExpr", "scalarIntConstantExpr")
1077             .Case("ScalarIntExpr", "scalarIntExpr")
1078             .Case("ScalarExpr", "scalarExpr")
1079             .Case("ScalarLogicalExpr", "scalarLogicalExpr")
1080             .Default(("Parser<" + Clause.getFlangClass() + ">{}")
1081                          .toStringRef(Scratch));
1082     OS << Parser;
1083     if (!Clause.getPrefix().empty() && Clause.isPrefixOptional())
1084       OS << " || " << Parser;
1085     if (Clause.isValueList()) // close nonemptyList(.
1086       OS << ")";
1087     OS << ")"; // close parenthesized(.
1088 
1089     if (Clause.isValueOptional()) // close maybe(.
1090       OS << ")";
1091     OS << "))";
1092     if (index != lastClauseIndex)
1093       OS << " ||";
1094     OS << "\n";
1095     ++index;
1096   }
1097   OS << ")\n";
1098 }
1099 
1100 // Generate the implementation section for the enumeration in the directive
1101 // language
EmitDirectivesFlangImpl(const DirectiveLanguage & DirLang,raw_ostream & OS)1102 static void EmitDirectivesFlangImpl(const DirectiveLanguage &DirLang,
1103                                     raw_ostream &OS) {
1104 
1105   GenerateDirectiveClauseSets(DirLang, OS);
1106 
1107   GenerateDirectiveClauseMap(DirLang, OS);
1108 
1109   GenerateFlangClauseParserClass(DirLang, OS);
1110 
1111   GenerateFlangClauseParserClassList(DirLang, OS);
1112 
1113   GenerateFlangClauseDump(DirLang, OS);
1114 
1115   GenerateFlangClauseUnparse(DirLang, OS);
1116 
1117   GenerateFlangClauseCheckPrototypes(DirLang, OS);
1118 
1119   GenerateFlangClauseParserKindMap(DirLang, OS);
1120 
1121   GenerateFlangClausesParser(DirLang, OS);
1122 }
1123 
GenerateClauseClassMacro(const DirectiveLanguage & DirLang,raw_ostream & OS)1124 static void GenerateClauseClassMacro(const DirectiveLanguage &DirLang,
1125                                      raw_ostream &OS) {
1126   // Generate macros style information for legacy code in clang
1127   IfDefScope Scope("GEN_CLANG_CLAUSE_CLASS", OS);
1128 
1129   OS << "\n";
1130 
1131   OS << "#ifndef CLAUSE\n";
1132   OS << "#define CLAUSE(Enum, Str, Implicit)\n";
1133   OS << "#endif\n";
1134   OS << "#ifndef CLAUSE_CLASS\n";
1135   OS << "#define CLAUSE_CLASS(Enum, Str, Class)\n";
1136   OS << "#endif\n";
1137   OS << "#ifndef CLAUSE_NO_CLASS\n";
1138   OS << "#define CLAUSE_NO_CLASS(Enum, Str)\n";
1139   OS << "#endif\n";
1140   OS << "\n";
1141   OS << "#define __CLAUSE(Name, Class)                      \\\n";
1142   OS << "  CLAUSE(" << DirLang.getClausePrefix()
1143      << "##Name, #Name, /* Implicit */ false) \\\n";
1144   OS << "  CLAUSE_CLASS(" << DirLang.getClausePrefix()
1145      << "##Name, #Name, Class)\n";
1146   OS << "#define __CLAUSE_NO_CLASS(Name)                    \\\n";
1147   OS << "  CLAUSE(" << DirLang.getClausePrefix()
1148      << "##Name, #Name, /* Implicit */ false) \\\n";
1149   OS << "  CLAUSE_NO_CLASS(" << DirLang.getClausePrefix() << "##Name, #Name)\n";
1150   OS << "#define __IMPLICIT_CLAUSE_CLASS(Name, Str, Class)  \\\n";
1151   OS << "  CLAUSE(" << DirLang.getClausePrefix()
1152      << "##Name, Str, /* Implicit */ true)    \\\n";
1153   OS << "  CLAUSE_CLASS(" << DirLang.getClausePrefix()
1154      << "##Name, Str, Class)\n";
1155   OS << "#define __IMPLICIT_CLAUSE_NO_CLASS(Name, Str)      \\\n";
1156   OS << "  CLAUSE(" << DirLang.getClausePrefix()
1157      << "##Name, Str, /* Implicit */ true)    \\\n";
1158   OS << "  CLAUSE_NO_CLASS(" << DirLang.getClausePrefix() << "##Name, Str)\n";
1159   OS << "\n";
1160 
1161   for (const auto &R : DirLang.getClauses()) {
1162     Clause C{R};
1163     if (C.getClangClass().empty()) { // NO_CLASS
1164       if (C.isImplicit()) {
1165         OS << "__IMPLICIT_CLAUSE_NO_CLASS(" << C.getFormattedName() << ", \""
1166            << C.getFormattedName() << "\")\n";
1167       } else {
1168         OS << "__CLAUSE_NO_CLASS(" << C.getFormattedName() << ")\n";
1169       }
1170     } else { // CLASS
1171       if (C.isImplicit()) {
1172         OS << "__IMPLICIT_CLAUSE_CLASS(" << C.getFormattedName() << ", \""
1173            << C.getFormattedName() << "\", " << C.getClangClass() << ")\n";
1174       } else {
1175         OS << "__CLAUSE(" << C.getFormattedName() << ", " << C.getClangClass()
1176            << ")\n";
1177       }
1178     }
1179   }
1180 
1181   OS << "\n";
1182   OS << "#undef __IMPLICIT_CLAUSE_NO_CLASS\n";
1183   OS << "#undef __IMPLICIT_CLAUSE_CLASS\n";
1184   OS << "#undef __CLAUSE_NO_CLASS\n";
1185   OS << "#undef __CLAUSE\n";
1186   OS << "#undef CLAUSE_NO_CLASS\n";
1187   OS << "#undef CLAUSE_CLASS\n";
1188   OS << "#undef CLAUSE\n";
1189 }
1190 
1191 // Generate the implemenation for the enumeration in the directive
1192 // language. This code can be included in library.
EmitDirectivesBasicImpl(const DirectiveLanguage & DirLang,raw_ostream & OS)1193 void EmitDirectivesBasicImpl(const DirectiveLanguage &DirLang,
1194                              raw_ostream &OS) {
1195   IfDefScope Scope("GEN_DIRECTIVES_IMPL", OS);
1196 
1197   OS << "\n#include \"llvm/Support/ErrorHandling.h\"\n";
1198 
1199   // getDirectiveKind(StringRef Str)
1200   GenerateGetKind(DirLang.getDirectives(), OS, "Directive", DirLang,
1201                   DirLang.getDirectivePrefix(), /*ImplicitAsUnknown=*/false);
1202 
1203   // getDirectiveName(Directive Kind)
1204   GenerateGetName(DirLang.getDirectives(), OS, "Directive", DirLang,
1205                   DirLang.getDirectivePrefix());
1206 
1207   // getClauseKind(StringRef Str)
1208   GenerateGetKind(DirLang.getClauses(), OS, "Clause", DirLang,
1209                   DirLang.getClausePrefix(),
1210                   /*ImplicitAsUnknown=*/true);
1211 
1212   // getClauseName(Clause Kind)
1213   GenerateGetName(DirLang.getClauses(), OS, "Clause", DirLang,
1214                   DirLang.getClausePrefix());
1215 
1216   // get<ClauseVal>Kind(StringRef Str)
1217   GenerateGetKindClauseVal(DirLang, OS);
1218 
1219   // isAllowedClauseForDirective(Directive D, Clause C, unsigned Version)
1220   GenerateIsAllowedClause(DirLang, OS);
1221 
1222   // getDirectiveAssociation(Directive D)
1223   GenerateGetDirectiveAssociation(DirLang, OS);
1224 
1225   // getDirectiveCategory(Directive D)
1226   GenerateGetDirectiveCategory(DirLang, OS);
1227 
1228   // Leaf table for getLeafConstructs, etc.
1229   EmitLeafTable(DirLang, OS, "LeafConstructTable");
1230 }
1231 
1232 // Generate the implemenation section for the enumeration in the directive
1233 // language.
EmitDirectivesImpl(RecordKeeper & Records,raw_ostream & OS)1234 static void EmitDirectivesImpl(RecordKeeper &Records, raw_ostream &OS) {
1235   const auto DirLang = DirectiveLanguage{Records};
1236   if (DirLang.HasValidityErrors())
1237     return;
1238 
1239   EmitDirectivesFlangImpl(DirLang, OS);
1240 
1241   GenerateClauseClassMacro(DirLang, OS);
1242 
1243   EmitDirectivesBasicImpl(DirLang, OS);
1244 }
1245 
1246 static TableGen::Emitter::Opt
1247     X("gen-directive-decl", EmitDirectivesDecl,
1248       "Generate directive related declaration code (header file)");
1249 
1250 static TableGen::Emitter::Opt
1251     Y("gen-directive-impl", EmitDirectivesImpl,
1252       "Generate directive related implementation code");
1253