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