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