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