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 LoopModifier
315 generateEnumClass(Records: DirLang.getLoopModifiers(), OS, Enum: "LoopModifier",
316 Prefix: DirLang.getLoopModifierPrefix(),
317 ExportEnums: DirLang.hasMakeEnumAvailableInNamespace());
318
319 // Emit ClauseVals enumeration
320 std::string EnumHelperFuncs;
321 generateClauseEnumVal(Records: DirLang.getClauses(), OS, DirLang, EnumHelperFuncs);
322
323 // Emit constexpr functions.
324 emitDirectivesConstexprImpl(DirLang, OS);
325
326 // Generic function signatures
327 OS << "\n";
328 OS << "// Enumeration helper functions\n";
329
330 OS << "LLVM_ABI std::pair<Directive, directive::VersionRange> get" << Lang
331 << "DirectiveKindAndVersions(StringRef Str);\n";
332
333 OS << "inline Directive get" << Lang << "DirectiveKind(StringRef Str) {\n";
334 OS << " return get" << Lang << "DirectiveKindAndVersions(Str).first;\n";
335 OS << "}\n";
336 OS << "\n";
337
338 OS << "LLVM_ABI StringRef get" << Lang
339 << "DirectiveName(Directive D, unsigned Ver = 0);\n";
340 OS << "\n";
341
342 OS << "LLVM_ABI std::pair<Clause, directive::VersionRange> get" << Lang
343 << "ClauseKindAndVersions(StringRef Str);\n";
344 OS << "\n";
345
346 OS << "inline Clause get" << Lang << "ClauseKind(StringRef Str) {\n";
347 OS << " return get" << Lang << "ClauseKindAndVersions(Str).first;\n";
348 OS << "}\n";
349 OS << "\n";
350
351 OS << "LLVM_ABI StringRef get" << Lang
352 << "ClauseName(Clause C, unsigned Ver = 0);\n";
353 OS << "\n";
354
355 OS << "/// Return true if \\p C is a valid clause for \\p D in version \\p "
356 << "Version.\n";
357 OS << "LLVM_ABI bool isAllowedClauseForDirective(Directive D, "
358 << "Clause C, unsigned Version);\n";
359 OS << "\n";
360 OS << "constexpr std::size_t getMaxLeafCount() { return "
361 << getMaxLeafCount(DirLang) << "; }\n";
362 OS << "LLVM_ABI bool isAllowedLoopModifier(Directive D, LoopModifier "
363 "LM);\n";
364 OS << "LLVM_ABI StringRef getLoopModifierName(LoopModifier LM, unsigned "
365 "Ver = 0);\n";
366 OS << EnumHelperFuncs;
367 } // close DirLangNS
368
369 // These specializations need to be in ::llvm.
370 for (StringRef Enum :
371 {"Association", "Category", "Directive", "Clause", "LoopModifier"}) {
372 OS << "\n";
373 OS << "template <> struct enum_iteration_traits<"
374 << DirLang.getCppNamespace() << "::" << Enum << "> {\n";
375 OS << " static constexpr bool is_iterable = true;\n";
376 OS << "};\n";
377 }
378}
379
380// Given a list of spellings (for a given clause/directive), order them
381// in a way that allows the use of binary search to locate a spelling
382// for a specified version.
383static std::vector<Spelling::Value>
384orderSpellings(ArrayRef<Spelling::Value> Spellings) {
385 std::vector<Spelling::Value> List(Spellings.begin(), Spellings.end());
386
387 llvm::stable_sort(Range&: List,
388 C: [](const Spelling::Value &A, const Spelling::Value &B) {
389 return A.Versions < B.Versions;
390 });
391 return List;
392}
393
394// Generate function implementation for get<Enum>Name(StringRef Str)
395static void generateGetName(ArrayRef<const Record *> Records, raw_ostream &OS,
396 StringRef Enum, const DirectiveLanguage &DirLang,
397 StringRef LangName, StringRef Prefix) {
398 std::string Qual = getQualifier(DirLang);
399 OS << "\n";
400 OS << "llvm::StringRef " << Qual << "get" << LangName << Enum << "Name("
401 << Qual << Enum << " Kind, unsigned Version) {\n";
402 OS << " switch (Kind) {\n";
403 for (const Record *R : Records) {
404 BaseRecord Rec(R);
405 std::string Ident = getIdentifierName(Rec: R, Prefix);
406 OS << " case " << Ident << ":";
407 std::vector<Spelling::Value> Spellings(orderSpellings(Spellings: Rec.getSpellings()));
408 assert(Spellings.size() != 0 && "No spellings for this item");
409 if (Spellings.size() == 1) {
410 OS << "\n";
411 OS << " return \"" << Spellings.front().Name << "\";\n";
412 } else {
413 OS << " {\n";
414 std::string SpellingsName = Ident + "_spellings";
415 OS << " static constexpr llvm::directive::Spelling " << SpellingsName
416 << "[] = {\n";
417 for (auto &S : Spellings) {
418 OS << " {\"" << S.Name << "\", {" << S.Versions.Min << ", "
419 << S.Versions.Max << "}},\n";
420 }
421 OS << " };\n";
422 OS << " return llvm::directive::FindName(" << SpellingsName
423 << ", Version);\n";
424 OS << " }\n";
425 }
426 }
427 OS << " }\n"; // switch
428 OS << " llvm_unreachable(\"Invalid " << LangName << " " << Enum
429 << " kind\");\n";
430 OS << "}\n";
431}
432
433// Generate function implementation for get<Enum>KindAndVersions(StringRef Str)
434static void generateGetKind(ArrayRef<const Record *> Records, raw_ostream &OS,
435 StringRef Enum, const DirectiveLanguage &DirLang,
436 StringRef Prefix, bool ImplicitAsUnknown) {
437
438 const auto *DefaultIt = find_if(
439 Range&: Records, P: [](const Record *R) { return R->getValueAsBit(FieldName: "isDefault"); });
440
441 if (DefaultIt == Records.end()) {
442 PrintError(Msg: "At least one " + Enum + " must be defined as default.");
443 return;
444 }
445
446 BaseRecord DefaultRec(*DefaultIt);
447 std::string Qual = getQualifier(DirLang);
448 std::string DefaultName = getIdentifierName(Rec: *DefaultIt, Prefix);
449
450 // std::pair<<Enum>, VersionRange>
451 // get<DirLang><Enum>KindAndVersions(StringRef Str);
452 OS << "\n";
453 OS << "std::pair<" << Qual << Enum << ", llvm::directive::VersionRange> "
454 << Qual << "get" << DirLang.getName() << Enum
455 << "KindAndVersions(llvm::StringRef Str) {\n";
456 OS << " directive::VersionRange All; // Default-initialized to \"all "
457 "versions\"\n";
458 OS << " return StringSwitch<std::pair<" << Enum << ", "
459 << "directive::VersionRange>>(Str)\n";
460
461 directive::VersionRange All;
462
463 for (const Record *R : Records) {
464 BaseRecord Rec(R);
465 std::string Ident = ImplicitAsUnknown && R->getValueAsBit(FieldName: "isImplicit")
466 ? DefaultName
467 : getIdentifierName(Rec: R, Prefix);
468
469 for (auto &[Name, Versions] : Rec.getSpellings()) {
470 OS << " .Case(\"" << Name << "\", {" << Ident << ", ";
471 if (Versions.Min == All.Min && Versions.Max == All.Max)
472 OS << "All})\n";
473 else
474 OS << "{" << Versions.Min << ", " << Versions.Max << "}})\n";
475 }
476 }
477 OS << " .Default({" << DefaultName << ", All});\n";
478 OS << "}\n";
479}
480
481// Generate function implementations for
482// <enumClauseValue> get<enumClauseValue>(StringRef Str) and
483// StringRef get<enumClauseValue>Name(<enumClauseValue>)
484static void generateGetClauseVal(const DirectiveLanguage &DirLang,
485 raw_ostream &OS) {
486 StringRef Lang = DirLang.getName();
487 std::string Qual = getQualifier(DirLang);
488
489 for (const Clause C : DirLang.getClauses()) {
490 const auto &ClauseVals = C.getClauseVals();
491 if (ClauseVals.size() <= 0)
492 continue;
493
494 auto DefaultIt = find_if(Range: ClauseVals, P: [](const Record *CV) {
495 return CV->getValueAsBit(FieldName: "isDefault");
496 });
497
498 if (DefaultIt == ClauseVals.end()) {
499 PrintError(Msg: "At least one val in Clause " + C.getRecordName() +
500 " must be defined as default.");
501 return;
502 }
503 const auto DefaultName = (*DefaultIt)->getName();
504
505 StringRef Enum = C.getEnumName();
506 if (Enum.empty()) {
507 PrintError(Msg: "enumClauseValue field not set in Clause" + C.getRecordName() +
508 ".");
509 return;
510 }
511
512 OS << "\n";
513 OS << Qual << Enum << " " << Qual << "get" << Enum
514 << "(llvm::StringRef Str) {\n";
515 OS << " return StringSwitch<" << Enum << ">(Str)\n";
516 for (const EnumVal Val : ClauseVals) {
517 OS << " .Case(\"" << Val.getFormattedName() << "\","
518 << Val.getRecordName() << ")\n";
519 }
520 OS << " .Default(" << DefaultName << ");\n";
521 OS << "}\n";
522
523 OS << "\n";
524 OS << "llvm::StringRef " << Qual << "get" << Lang << Enum << "Name(" << Qual
525 << Enum << " x) {\n";
526 OS << " switch (x) {\n";
527 for (const EnumVal Val : ClauseVals) {
528 OS << " case " << Val.getRecordName() << ":\n";
529 OS << " return \"" << Val.getFormattedName() << "\";\n";
530 }
531 OS << " }\n"; // switch
532 OS << " llvm_unreachable(\"Invalid " << Lang << " " << Enum
533 << " kind\");\n";
534 OS << "}\n";
535 }
536}
537
538static void generateCaseForVersionedClauses(ArrayRef<const Record *> VerClauses,
539 raw_ostream &OS,
540 const DirectiveLanguage &DirLang,
541 StringSet<> &Cases) {
542 StringRef Prefix = DirLang.getClausePrefix();
543 for (const Record *R : VerClauses) {
544 VersionedClause VerClause(R);
545 std::string Name =
546 getIdentifierName(Rec: VerClause.getClause().getRecord(), Prefix);
547 if (Cases.insert(key: Name).second) {
548 OS << " case " << Name << ":\n";
549 OS << " return " << VerClause.getMinVersion()
550 << " <= Version && " << VerClause.getMaxVersion() << " >= Version;\n";
551 }
552 }
553}
554
555// Generate the isAllowedClauseForDirective function implementation.
556static void generateIsAllowedClause(const DirectiveLanguage &DirLang,
557 raw_ostream &OS) {
558 std::string Qual = getQualifier(DirLang);
559
560 OS << "\n";
561 OS << "bool " << Qual << "isAllowedClauseForDirective(" << Qual
562 << "Directive D, " << Qual << "Clause C, unsigned Version) {\n";
563 OS << " assert(unsigned(D) <= Directive_enumSize);\n";
564 OS << " assert(unsigned(C) <= Clause_enumSize);\n";
565
566 OS << " switch (D) {\n";
567
568 StringRef Prefix = DirLang.getDirectivePrefix();
569 for (const Record *R : DirLang.getDirectives()) {
570 Directive Dir(R);
571 OS << " case " << getIdentifierName(Rec: R, Prefix) << ":\n";
572 if (Dir.getAllowedClauses().empty() &&
573 Dir.getAllowedOnceClauses().empty() &&
574 Dir.getAllowedExclusiveClauses().empty() &&
575 Dir.getRequiredClauses().empty()) {
576 OS << " return false;\n";
577 } else {
578 OS << " switch (C) {\n";
579
580 StringSet<> Cases;
581
582 generateCaseForVersionedClauses(VerClauses: Dir.getAllowedClauses(), OS, DirLang,
583 Cases);
584
585 generateCaseForVersionedClauses(VerClauses: Dir.getAllowedOnceClauses(), OS, DirLang,
586 Cases);
587
588 generateCaseForVersionedClauses(VerClauses: Dir.getAllowedExclusiveClauses(), OS,
589 DirLang, Cases);
590
591 generateCaseForVersionedClauses(VerClauses: Dir.getRequiredClauses(), OS, DirLang,
592 Cases);
593
594 OS << " default:\n";
595 OS << " return false;\n";
596 OS << " }\n"; // End of clauses switch
597 }
598 OS << " break;\n";
599 }
600
601 OS << " }\n"; // End of directives switch
602 OS << " llvm_unreachable(\"Invalid " << DirLang.getName()
603 << " Directive kind\");\n";
604 OS << "}\n"; // End of function isAllowedClauseForDirective
605}
606
607static void emitLeafTable(const DirectiveLanguage &DirLang, raw_ostream &OS,
608 StringRef TableName) {
609 // The leaf constructs are emitted in a form of a 2D table, where each
610 // row corresponds to a directive (and there is a row for each directive).
611 //
612 // Each row consists of
613 // - the id of the directive itself,
614 // - number of leaf constructs that will follow (0 for leafs),
615 // - ids of the leaf constructs (none if the directive is itself a leaf).
616 // The total number of these entries is at most MaxLeafCount+2. If this
617 // number is less than that, it is padded to occupy exactly MaxLeafCount+2
618 // entries in memory.
619 //
620 // The rows are stored in the table in the lexicographical order. This
621 // is intended to enable binary search when mapping a sequence of leafs
622 // back to the compound directive.
623 // The consequence of that is that in order to find a row corresponding
624 // to the given directive, we'd need to scan the first element of each
625 // row. To avoid this, an auxiliary ordering table is created, such that
626 // row for Dir_A = table[auxiliary[Dir_A]].
627
628 ArrayRef<const Record *> Directives = DirLang.getDirectives();
629 DenseMap<const Record *, int> DirId; // Record * -> llvm::omp::Directive
630
631 for (auto [Idx, Rec] : enumerate(First&: Directives))
632 DirId.try_emplace(Key: Rec, Args&: Idx);
633
634 using LeafList = std::vector<int>;
635 int MaxLeafCount = getMaxLeafCount(DirLang);
636
637 // The initial leaf table, rows order is same as directive order.
638 std::vector<LeafList> LeafTable(Directives.size());
639 for (auto [Idx, Rec] : enumerate(First&: Directives)) {
640 Directive Dir(Rec);
641 std::vector<const Record *> Leaves = Dir.getLeafConstructs();
642
643 auto &List = LeafTable[Idx];
644 List.resize(new_size: MaxLeafCount + 2);
645 List[0] = Idx; // The id of the directive itself.
646 List[1] = Leaves.size(); // The number of leaves to follow.
647
648 for (int I = 0; I != MaxLeafCount; ++I)
649 List[I + 2] =
650 static_cast<size_t>(I) < Leaves.size() ? DirId.at(Val: Leaves[I]) : -1;
651 }
652
653 // Some Fortran directives are delimited, i.e. they have the form of
654 // "directive"---"end directive". If "directive" is a compound construct,
655 // then the set of leaf constituents will be nonempty and the same for
656 // both directives. Given this set of leafs, looking up the corresponding
657 // compound directive should return "directive", and not "end directive".
658 // To avoid this problem, gather all "end directives" at the end of the
659 // leaf table, and only do the search on the initial segment of the table
660 // that excludes the "end directives".
661 // It's safe to find all directives whose names begin with "end ". The
662 // problem only exists for compound directives, like "end do simd".
663 // All existing directives with names starting with "end " are either
664 // "end directives" for an existing "directive", or leaf directives
665 // (such as "end declare target").
666 DenseSet<int> EndDirectives;
667 for (auto [Rec, Id] : DirId) {
668 // FIXME: This will need to recognize different spellings for different
669 // versions.
670 StringRef Name = Directive(Rec).getSpellingForIdentifier();
671 if (Name.starts_with_insensitive(Prefix: "end "))
672 EndDirectives.insert(V: Id);
673 }
674
675 // Avoid sorting the vector<vector> array, instead sort an index array.
676 // It will also be useful later to create the auxiliary indexing array.
677 std::vector<int> Ordering(Directives.size());
678 std::iota(first: Ordering.begin(), last: Ordering.end(), value: 0);
679
680 llvm::sort(C&: Ordering, Comp: [&](int A, int B) {
681 auto &LeavesA = LeafTable[A];
682 auto &LeavesB = LeafTable[B];
683 int DirA = LeavesA[0], DirB = LeavesB[0];
684 // First of all, end directives compare greater than non-end directives.
685 bool IsEndA = EndDirectives.contains(V: DirA);
686 bool IsEndB = EndDirectives.contains(V: DirB);
687 if (IsEndA != IsEndB)
688 return IsEndA < IsEndB;
689 if (LeavesA[1] == 0 && LeavesB[1] == 0)
690 return DirA < DirB;
691 return std::lexicographical_compare(first1: &LeavesA[2], last1: &LeavesA[2] + LeavesA[1],
692 first2: &LeavesB[2], last2: &LeavesB[2] + LeavesB[1]);
693 });
694
695 // Emit the table
696
697 // The directives are emitted into a scoped enum, for which the underlying
698 // type is `int` (by default). The code above uses `int` to store directive
699 // ids, so make sure that we catch it when something changes in the
700 // underlying type.
701 StringRef Prefix = DirLang.getDirectivePrefix();
702 std::string Qual = getQualifier(DirLang);
703 std::string DirectiveType = Qual + "Directive";
704 OS << "\nstatic_assert(sizeof(" << DirectiveType << ") == sizeof(int));\n";
705
706 OS << "[[maybe_unused]] static const " << DirectiveType << ' ' << TableName
707 << "[][" << MaxLeafCount + 2 << "] = {\n";
708 for (size_t I = 0, E = Directives.size(); I != E; ++I) {
709 auto &Leaves = LeafTable[Ordering[I]];
710 OS << " {" << Qual << getIdentifierName(Rec: Directives[Leaves[0]], Prefix);
711 OS << ", static_cast<" << DirectiveType << ">(" << Leaves[1] << "),";
712 for (size_t I = 2, E = Leaves.size(); I != E; ++I) {
713 int Idx = Leaves[I];
714 if (Idx >= 0)
715 OS << ' ' << Qual << getIdentifierName(Rec: Directives[Leaves[I]], Prefix)
716 << ',';
717 else
718 OS << " static_cast<" << DirectiveType << ">(-1),";
719 }
720 OS << "},\n";
721 }
722 OS << "};\n\n";
723
724 // Emit a marker where the first "end directive" is.
725 auto FirstE = find_if(Range&: Ordering, P: [&](int RowIdx) {
726 return EndDirectives.contains(V: LeafTable[RowIdx][0]);
727 });
728 OS << "[[maybe_unused]] static auto " << TableName
729 << "EndDirective = " << TableName << " + "
730 << std::distance(first: Ordering.begin(), last: FirstE) << ";\n\n";
731
732 // Emit the auxiliary index table: it's the inverse of the `Ordering`
733 // table above.
734 OS << "[[maybe_unused]] static const int " << TableName << "Ordering[] = {\n";
735 OS << " ";
736 std::vector<int> Reverse(Ordering.size());
737 for (int I = 0, E = Ordering.size(); I != E; ++I)
738 Reverse[Ordering[I]] = I;
739 for (int Idx : Reverse)
740 OS << ' ' << Idx << ',';
741 OS << "\n};\n";
742}
743
744static void generateGetDirectiveAssociation(const DirectiveLanguage &DirLang,
745 raw_ostream &OS) {
746 enum struct Association {
747 None = 0, // None should be the smallest value.
748 Block, // If the order of the rest of these changes, update the
749 Declaration, // 'Reduce' function below.
750 Delimited,
751 LoopNest,
752 LoopSeq,
753 Separating,
754 FromLeaves,
755 Invalid,
756 };
757
758 ArrayRef<const Record *> Associations = DirLang.getAssociations();
759
760 auto GetAssocValue = [](StringRef Name) -> Association {
761 return StringSwitch<Association>(Name)
762 .Case(S: "AS_Block", Value: Association::Block)
763 .Case(S: "AS_Declaration", Value: Association::Declaration)
764 .Case(S: "AS_Delimited", Value: Association::Delimited)
765 .Case(S: "AS_LoopNest", Value: Association::LoopNest)
766 .Case(S: "AS_LoopSeq", Value: Association::LoopSeq)
767 .Case(S: "AS_None", Value: Association::None)
768 .Case(S: "AS_Separating", Value: Association::Separating)
769 .Case(S: "AS_FromLeaves", Value: Association::FromLeaves)
770 .Default(Value: Association::Invalid);
771 };
772
773 auto GetAssocName = [&](Association A) -> StringRef {
774 if (A != Association::Invalid && A != Association::FromLeaves) {
775 const auto *F = find_if(Range&: Associations, P: [&](const Record *R) {
776 return GetAssocValue(R->getName()) == A;
777 });
778 if (F != Associations.end())
779 return (*F)->getValueAsString(FieldName: "name"); // enum name
780 }
781 llvm_unreachable("Unexpected association value");
782 };
783
784 auto ErrorPrefixFor = [&](Directive D) -> std::string {
785 return (Twine("Directive '") + D.getRecordName() + "' in namespace '" +
786 DirLang.getCppNamespace() + "' ")
787 .str();
788 };
789
790 auto Reduce = [&](Association A, Association B) -> Association {
791 if (A > B)
792 std::swap(a&: A, b&: B);
793
794 // Calculate the result using the following rules:
795 // x + x = x
796 // AS_None + x = x
797 // AS_Block + AS_Loop{Nest|Seq} = AS_Loop{Nest|Seq}
798 if (A == Association::None || A == B)
799 return B;
800 if (A == Association::Block &&
801 (B == Association::LoopNest || B == Association::LoopSeq))
802 return B;
803 return Association::Invalid;
804 };
805
806 DenseMap<const Record *, Association> AsMap;
807
808 auto CompAssocImpl = [&](const Record *R, auto &&Self) -> Association {
809 if (auto F = AsMap.find(Val: R); F != AsMap.end())
810 return F->second;
811
812 Directive D(R);
813 Association AS = GetAssocValue(D.getAssociation()->getName());
814 if (AS == Association::Invalid) {
815 PrintFatalError(Msg: ErrorPrefixFor(D) +
816 "has an unrecognized value for association: '" +
817 D.getAssociation()->getName() + "'");
818 }
819 if (AS != Association::FromLeaves) {
820 AsMap.try_emplace(Key: R, Args&: AS);
821 return AS;
822 }
823 // Compute the association from leaf constructs.
824 std::vector<const Record *> Leaves = D.getLeafConstructs();
825 if (Leaves.empty()) {
826 PrintFatalError(Msg: ErrorPrefixFor(D) +
827 "requests association to be computed from leaves, "
828 "but it has no leaves");
829 }
830
831 Association Result = Self(Leaves[0], Self);
832 for (int I = 1, E = Leaves.size(); I < E; ++I) {
833 Association A = Self(Leaves[I], Self);
834 Association R = Reduce(Result, A);
835 if (R == Association::Invalid) {
836 PrintFatalError(Msg: ErrorPrefixFor(D) +
837 "has leaves with incompatible association values: " +
838 GetAssocName(A) + " and " + GetAssocName(R));
839 }
840 Result = R;
841 }
842
843 assert(Result != Association::Invalid);
844 assert(Result != Association::FromLeaves);
845 AsMap.try_emplace(Key: R, Args&: Result);
846 return Result;
847 };
848
849 for (const Record *R : DirLang.getDirectives())
850 CompAssocImpl(R, CompAssocImpl); // Updates AsMap.
851
852 StringRef Prefix = DirLang.getDirectivePrefix();
853
854 OS << "constexpr Association getDirectiveAssociation(Directive Dir) {\n";
855 OS << " switch (Dir) {\n";
856 for (const Record *R : DirLang.getDirectives()) {
857 if (auto F = AsMap.find(Val: R); F != AsMap.end()) {
858 OS << " case " << getIdentifierName(Rec: R, Prefix) << ":\n";
859 OS << " return Association::" << GetAssocName(F->second) << ";\n";
860 }
861 }
862 OS << " } // switch (Dir)\n";
863 OS << "#if !defined(__clang__) && defined(__GNUC__) && __GNUC__ < 9\n";
864 OS << " abort();\n";
865 OS << "#else\n";
866 OS << " llvm_unreachable(\"Unexpected directive\");\n";
867 OS << "#endif\n";
868 OS << "}\n";
869}
870
871static void generateGetDirectiveCategory(const DirectiveLanguage &DirLang,
872 raw_ostream &OS) {
873 OS << "constexpr Category getDirectiveCategory(Directive Dir) {\n";
874 OS << " switch (Dir) {\n";
875
876 StringRef Prefix = DirLang.getDirectivePrefix();
877
878 for (const Record *R : DirLang.getDirectives()) {
879 Directive D(R);
880 OS << " case " << getIdentifierName(Rec: R, Prefix) << ":\n";
881 OS << " return Category::" << D.getCategory()->getValueAsString(FieldName: "name")
882 << ";\n";
883 }
884 OS << " } // switch (Dir)\n";
885 OS << "#if !defined(__clang__) && defined(__GNUC__) && __GNUC__ < 9\n";
886 OS << " abort();\n";
887 OS << "#else\n";
888 OS << " llvm_unreachable(\"Unexpected directive\");\n";
889 OS << "#endif\n";
890 OS << "}\n";
891}
892
893static void generateGetDirectiveLanguages(const DirectiveLanguage &DirLang,
894 raw_ostream &OS) {
895 OS << "constexpr SourceLanguage getDirectiveLanguages(Directive D) {\n";
896 OS << " switch (D) {\n";
897
898 StringRef Prefix = DirLang.getDirectivePrefix();
899
900 for (const Record *R : DirLang.getDirectives()) {
901 Directive D(R);
902 OS << " case " << getIdentifierName(Rec: R, Prefix) << ":\n";
903 OS << " return ";
904 llvm::interleave(
905 c: D.getSourceLanguages(), os&: OS,
906 each_fn: [&](const Record *L) {
907 StringRef N = L->getValueAsString(FieldName: "name");
908 OS << "SourceLanguage::" << BaseRecord::getSnakeName(Name: N);
909 },
910 separator: " | ");
911 OS << ";\n";
912 }
913 OS << " } // switch(D)\n";
914 OS << "#if !defined(__clang__) && defined(__GNUC__) && __GNUC__ < 9\n";
915 OS << " abort();\n";
916 OS << "#else\n";
917 OS << " llvm_unreachable(\"Unexpected directive\");\n";
918 OS << "#endif\n";
919 OS << "}\n";
920}
921
922// Generate the isAllowedLoopModifier function implementation.
923static void generateIsAllowedLoopModifier(const DirectiveLanguage &DirLang,
924 raw_ostream &OS) {
925 std::string Qual = getQualifier(DirLang);
926
927 OS << "\n";
928 OS << "bool " << Qual << "isAllowedLoopModifier(" << Qual << "Directive D, "
929 << Qual << "LoopModifier LM) {\n";
930 OS << " assert(unsigned(D) <= Directive_enumSize);\n";
931
932 OS << " switch (D) {\n";
933
934 StringRef DPrefix = DirLang.getDirectivePrefix();
935 StringRef LMPrefix = DirLang.getLoopModifierPrefix();
936 for (const Record *R : DirLang.getDirectives()) {
937 Directive Dir(R);
938 OS << " case " << getIdentifierName(Rec: R, Prefix: DPrefix) << ":\n";
939 if (Dir.getAllowedLoopModifiers().empty()) {
940 OS << " return false;\n";
941 } else {
942 OS << " switch (LM) {\n";
943
944 for (const Record *LMR : Dir.getAllowedLoopModifiers()) {
945 std::string Name = getIdentifierName(Rec: LMR, Prefix: LMPrefix);
946 OS << " case LoopModifier::" << Name << ":\n";
947 OS << " return true;\n";
948 }
949
950 OS << " default:\n";
951 OS << " return false;\n";
952 OS << " }\n"; // End of modifier switch
953 }
954 OS << " break;\n";
955 }
956
957 OS << " }\n"; // End of directives switch
958 OS << " llvm_unreachable(\"Invalid " << DirLang.getName()
959 << " Directive kind\");\n";
960 OS << "}\n"; // End of function isAllowedLoopModifier
961}
962
963// Generate a simple enum set with the give clauses.
964static void generateClauseSet(ArrayRef<const Record *> VerClauses,
965 raw_ostream &OS, StringRef ClauseSetPrefix,
966 const Directive &Dir,
967 const DirectiveLanguage &DirLang, Frontend FE) {
968
969 OS << "\n";
970 OS << "static " << DirLang.getClauseEnumSetClass() << " " << ClauseSetPrefix
971 << DirLang.getDirectivePrefix() << Dir.getFormattedName() << " {\n";
972
973 StringRef Prefix = DirLang.getClausePrefix();
974
975 for (const VersionedClause VerClause : VerClauses) {
976 Clause C = VerClause.getClause();
977 if (FE == Frontend::Flang) {
978 OS << " Clause::" << getIdentifierName(Rec: C.getRecord(), Prefix) << ",\n";
979 } else {
980 assert(FE == Frontend::Clang);
981 assert(DirLang.getName() == "OpenACC");
982 OS << " OpenACCClauseKind::" << C.getClangAccSpelling() << ",\n";
983 }
984 }
985 OS << "};\n";
986}
987
988// Generate an enum set for the 4 kinds of clauses linked to a directive.
989static void generateDirectiveClauseSets(const DirectiveLanguage &DirLang,
990 Frontend FE, raw_ostream &OS) {
991 IfDefEmitter Scope(OS, "GEN_" + getFESpelling(FE).upper() +
992 "_DIRECTIVE_CLAUSE_SETS");
993
994 std::string Namespace =
995 getFESpelling(FE: FE == Frontend::Flang ? Frontend::LLVM : FE).str();
996 // The namespace has to be different for clang vs flang, as 2 structs with the
997 // same name but different layout is UB. So just put the 'clang' on in the
998 // clang namespace.
999 // Additionally, open namespaces defined in the directive language.
1000 if (!DirLang.getCppNamespace().empty())
1001 Namespace += "::" + DirLang.getCppNamespace().str();
1002 NamespaceEmitter NS(OS, Namespace);
1003
1004 for (const Directive Dir : DirLang.getDirectives()) {
1005 OS << "// Sets for " << Dir.getSpellingForIdentifier() << "\n";
1006
1007 generateClauseSet(VerClauses: Dir.getAllowedClauses(), OS, ClauseSetPrefix: "allowedClauses_", Dir,
1008 DirLang, FE);
1009 generateClauseSet(VerClauses: Dir.getAllowedOnceClauses(), OS, ClauseSetPrefix: "allowedOnceClauses_",
1010 Dir, DirLang, FE);
1011 generateClauseSet(VerClauses: Dir.getAllowedExclusiveClauses(), OS,
1012 ClauseSetPrefix: "allowedExclusiveClauses_", Dir, DirLang, FE);
1013 generateClauseSet(VerClauses: Dir.getRequiredClauses(), OS, ClauseSetPrefix: "requiredClauses_", Dir,
1014 DirLang, FE);
1015 }
1016}
1017
1018// Generate a map of directive (key) with DirectiveClauses struct as values.
1019// The struct holds the 4 sets of enumeration for the 4 kinds of clauses
1020// allowances (allowed, allowed once, allowed exclusive and required).
1021static void generateDirectiveClauseMap(const DirectiveLanguage &DirLang,
1022 Frontend FE, raw_ostream &OS) {
1023 IfDefEmitter Scope(OS, "GEN_" + getFESpelling(FE).upper() +
1024 "_DIRECTIVE_CLAUSE_MAP");
1025
1026 OS << "{\n";
1027
1028 // The namespace has to be different for clang vs flang, as 2 structs with the
1029 // same name but different layout is UB. So just put the 'clang' on in the
1030 // clang namespace.
1031 std::string Qual =
1032 getQualifier(DirLang, FE: FE == Frontend::Flang ? Frontend::LLVM : FE);
1033 StringRef Prefix = DirLang.getDirectivePrefix();
1034
1035 for (const Record *R : DirLang.getDirectives()) {
1036 Directive Dir(R);
1037 std::string Name = getIdentifierName(Rec: R, Prefix);
1038
1039 OS << " {";
1040 if (FE == Frontend::Flang) {
1041 OS << Qual << "Directive::" << Name << ",\n";
1042 } else {
1043 assert(FE == Frontend::Clang);
1044 assert(DirLang.getName() == "OpenACC");
1045 OS << "clang::OpenACCDirectiveKind::" << Dir.getClangAccSpelling()
1046 << ",\n";
1047 }
1048
1049 OS << " {\n";
1050 OS << " " << Qual << "allowedClauses_" << Name << ",\n";
1051 OS << " " << Qual << "allowedOnceClauses_" << Name << ",\n";
1052 OS << " " << Qual << "allowedExclusiveClauses_" << Name << ",\n";
1053 OS << " " << Qual << "requiredClauses_" << Name << ",\n";
1054 OS << " }\n";
1055 OS << " },\n";
1056 }
1057
1058 OS << "}\n";
1059}
1060
1061// Generate classes entry for Flang clauses in the Flang parse-tree
1062// If the clause as a non-generic class, no entry is generated.
1063// If the clause does not hold a value, an EMPTY_CLASS is used.
1064// If the clause class is generic then a WRAPPER_CLASS is used. When the value
1065// is optional, the value class is wrapped into a std::optional.
1066static void generateFlangClauseParserClass(const DirectiveLanguage &DirLang,
1067 raw_ostream &OS) {
1068
1069 IfDefEmitter Scope(OS, "GEN_FLANG_CLAUSE_PARSER_CLASSES");
1070
1071 for (const Clause Clause : DirLang.getClauses()) {
1072 if (!Clause.getFlangClass().empty()) {
1073 OS << "WRAPPER_CLASS(" << Clause.getFormattedParserClassName() << ", ";
1074 if (Clause.isValueOptional() && Clause.isValueList()) {
1075 OS << "std::optional<std::list<" << Clause.getFlangClass() << ">>";
1076 } else if (Clause.isValueOptional()) {
1077 OS << "std::optional<" << Clause.getFlangClass() << ">";
1078 } else if (Clause.isValueList()) {
1079 OS << "std::list<" << Clause.getFlangClass() << ">";
1080 } else {
1081 OS << Clause.getFlangClass();
1082 }
1083 } else {
1084 OS << "EMPTY_CLASS(" << Clause.getFormattedParserClassName();
1085 }
1086 OS << ");\n";
1087 }
1088}
1089
1090// Generate a list of the different clause classes for Flang.
1091static void generateFlangClauseParserClassList(const DirectiveLanguage &DirLang,
1092 raw_ostream &OS) {
1093
1094 IfDefEmitter Scope(OS, "GEN_FLANG_CLAUSE_PARSER_CLASSES_LIST");
1095
1096 interleaveComma(c: DirLang.getClauses(), os&: OS, each_fn: [&](const Record *C) {
1097 Clause Clause(C);
1098 OS << Clause.getFormattedParserClassName() << "\n";
1099 });
1100}
1101
1102// Generate dump node list for the clauses holding a generic class name.
1103static void generateFlangClauseDump(const DirectiveLanguage &DirLang,
1104 raw_ostream &OS) {
1105
1106 IfDefEmitter Scope(OS, "GEN_FLANG_DUMP_PARSE_TREE_CLAUSES");
1107
1108 for (const Clause Clause : DirLang.getClauses()) {
1109 OS << "NODE(" << DirLang.getFlangClauseBaseClass() << ", "
1110 << Clause.getFormattedParserClassName() << ")\n";
1111 }
1112}
1113
1114// Generate Unparse functions for clauses classes in the Flang parse-tree
1115// If the clause is a non-generic class, no entry is generated.
1116static void generateFlangClauseUnparse(const DirectiveLanguage &DirLang,
1117 raw_ostream &OS) {
1118
1119 IfDefEmitter Scope(OS, "GEN_FLANG_CLAUSE_UNPARSE");
1120
1121 StringRef Base = DirLang.getFlangClauseBaseClass();
1122
1123 for (const Clause Clause : DirLang.getClauses()) {
1124 if (Clause.skipFlangUnparser())
1125 continue;
1126 // The unparser doesn't know the effective version, so just pick some
1127 // spelling.
1128 StringRef SomeSpelling = Clause.getSpellingForIdentifier();
1129 std::string Parser = Clause.getFormattedParserClassName();
1130 std::string Upper = SomeSpelling.upper();
1131
1132 if (!Clause.getFlangClass().empty()) {
1133 if (Clause.isValueOptional() && Clause.getDefaultValue().empty()) {
1134 OS << "void Unparse(const " << Base << "::" << Parser << " &x) {\n";
1135 OS << " Word(\"" << Upper << "\");\n";
1136
1137 OS << " Walk(\"(\", x.v, \")\");\n";
1138 OS << "}\n";
1139 } else if (Clause.isValueOptional()) {
1140 OS << "void Unparse(const " << Base << "::" << Parser << " &x) {\n";
1141 OS << " Word(\"" << Upper << "\");\n";
1142 OS << " Put(\"(\");\n";
1143 OS << " if (x.v.has_value())\n";
1144 if (Clause.isValueList())
1145 OS << " Walk(x.v, \",\");\n";
1146 else
1147 OS << " Walk(x.v);\n";
1148 OS << " else\n";
1149 OS << " Put(\"" << Clause.getDefaultValue() << "\");\n";
1150 OS << " Put(\")\");\n";
1151 OS << "}\n";
1152 } else {
1153 OS << "void Unparse(const " << Base << "::" << Parser << " &x) {\n";
1154 OS << " Word(\"" << Upper << "\");\n";
1155 OS << " Put(\"(\");\n";
1156 if (Clause.isValueList())
1157 OS << " Walk(x.v, \",\");\n";
1158 else
1159 OS << " Walk(x.v);\n";
1160 OS << " Put(\")\");\n";
1161 OS << "}\n";
1162 }
1163 } else {
1164 OS << "void Before(const " << Base << "::" << Parser << " &) { Word(\""
1165 << Upper << "\"); }\n";
1166 }
1167 }
1168}
1169
1170// Generate check in the Enter functions for clauses classes.
1171static void generateFlangClauseCheckPrototypes(const DirectiveLanguage &DirLang,
1172 raw_ostream &OS) {
1173
1174 IfDefEmitter Scope(OS, "GEN_FLANG_CLAUSE_CHECK_ENTER");
1175
1176 for (const Clause Clause : DirLang.getClauses()) {
1177 OS << "void Enter(const parser::" << DirLang.getFlangClauseBaseClass()
1178 << "::" << Clause.getFormattedParserClassName() << " &);\n";
1179 }
1180}
1181
1182// Generate the mapping for clauses between the parser class and the
1183// corresponding clause Kind
1184static void generateFlangClauseParserKindMap(const DirectiveLanguage &DirLang,
1185 raw_ostream &OS) {
1186
1187 IfDefEmitter Scope(OS, "GEN_FLANG_CLAUSE_PARSER_KIND_MAP");
1188
1189 StringRef Prefix = DirLang.getClausePrefix();
1190 std::string Qual = getQualifier(DirLang);
1191
1192 for (const Record *R : DirLang.getClauses()) {
1193 Clause C(R);
1194 OS << "if constexpr (std::is_same_v<A, parser::"
1195 << DirLang.getFlangClauseBaseClass()
1196 << "::" << C.getFormattedParserClassName();
1197 OS << ">)\n";
1198 OS << " return " << Qual << "Clause::" << getIdentifierName(Rec: R, Prefix)
1199 << ";\n";
1200 }
1201
1202 OS << "llvm_unreachable(\"Invalid " << DirLang.getName()
1203 << " Parser clause\");\n";
1204}
1205
1206// Generate the parser for the clauses.
1207static void generateFlangClausesParser(const DirectiveLanguage &DirLang,
1208 raw_ostream &OS) {
1209 std::vector<const Record *> Clauses = DirLang.getClauses();
1210 // Sort clauses in the reverse alphabetical order with respect to their
1211 // names and aliases, so that longer names are tried before shorter ones.
1212 std::vector<RecordWithSpelling> Names = getSpellings(Records: Clauses);
1213 llvm::sort(C&: Names, Comp: [](const auto &A, const auto &B) {
1214 return A.second.Name > B.second.Name;
1215 });
1216 IfDefEmitter Scope(OS, "GEN_FLANG_CLAUSES_PARSER");
1217 StringRef Base = DirLang.getFlangClauseBaseClass();
1218
1219 unsigned LastIndex = Names.size() - 1;
1220 OS << "TYPE_PARSER(\n";
1221 for (auto [Index, RecSp] : llvm::enumerate(First&: Names)) {
1222 auto [R, S] = RecSp;
1223 Clause C(R);
1224
1225 StringRef FlangClass = C.getFlangClass();
1226 OS << " \"" << S.Name << "\" >> construct<" << Base << ">(construct<"
1227 << Base << "::" << C.getFormattedParserClassName() << ">(";
1228 if (FlangClass.empty()) {
1229 OS << "))";
1230 if (Index != LastIndex)
1231 OS << " ||";
1232 OS << "\n";
1233 continue;
1234 }
1235
1236 if (C.isValueOptional())
1237 OS << "maybe(";
1238 OS << "parenthesized(";
1239 if (C.isValueList())
1240 OS << "nonemptyList(";
1241
1242 if (!C.getPrefix().empty())
1243 OS << "\"" << C.getPrefix() << ":\" >> ";
1244
1245 // The common Flang parser are used directly. Their name is identical to
1246 // the Flang class with first letter as lowercase. If the Flang class is
1247 // not a common class, we assume there is a specific Parser<>{} with the
1248 // Flang class name provided.
1249 SmallString<128> Scratch;
1250 StringRef Parser =
1251 StringSwitch<StringRef>(FlangClass)
1252 .Case(S: "Name", Value: "name")
1253 .Case(S: "ScalarIntConstantExpr", Value: "scalarIntConstantExpr")
1254 .Case(S: "ScalarIntExpr", Value: "scalarIntExpr")
1255 .Case(S: "ScalarExpr", Value: "scalarExpr")
1256 .Case(S: "ScalarLogicalExpr", Value: "scalarLogicalExpr")
1257 .Default(Value: ("Parser<" + FlangClass + ">{}").toStringRef(Out&: Scratch));
1258 OS << Parser;
1259 if (!C.getPrefix().empty() && C.isPrefixOptional())
1260 OS << " || " << Parser;
1261 if (C.isValueList()) // close nonemptyList(.
1262 OS << ")";
1263 OS << ")"; // close parenthesized(.
1264
1265 if (C.isValueOptional()) // close maybe(.
1266 OS << ")";
1267 OS << "))";
1268 if (Index != LastIndex)
1269 OS << " ||";
1270 OS << "\n";
1271 }
1272 OS << ")\n";
1273}
1274
1275// Generate the implementation section for the enumeration in the directive
1276// language
1277static void emitDirectivesClangImpl(const DirectiveLanguage &DirLang,
1278 raw_ostream &OS) {
1279 // Currently we only have work to do for OpenACC, so skip otherwise.
1280 if (DirLang.getName() != "OpenACC")
1281 return;
1282
1283 generateDirectiveClauseSets(DirLang, FE: Frontend::Clang, OS);
1284 generateDirectiveClauseMap(DirLang, FE: Frontend::Clang, OS);
1285}
1286// Generate the implementation section for the enumeration in the directive
1287// language
1288static void emitDirectivesFlangImpl(const DirectiveLanguage &DirLang,
1289 raw_ostream &OS) {
1290 generateDirectiveClauseSets(DirLang, FE: Frontend::Flang, OS);
1291
1292 generateDirectiveClauseMap(DirLang, FE: Frontend::Flang, OS);
1293
1294 generateFlangClauseParserClass(DirLang, OS);
1295
1296 generateFlangClauseParserClassList(DirLang, OS);
1297
1298 generateFlangClauseDump(DirLang, OS);
1299
1300 generateFlangClauseUnparse(DirLang, OS);
1301
1302 generateFlangClauseCheckPrototypes(DirLang, OS);
1303
1304 generateFlangClauseParserKindMap(DirLang, OS);
1305
1306 generateFlangClausesParser(DirLang, OS);
1307}
1308
1309static void generateClauseClassMacro(const DirectiveLanguage &DirLang,
1310 raw_ostream &OS) {
1311 // Generate macros style information for legacy code in clang
1312 IfDefEmitter Scope(OS, "GEN_CLANG_CLAUSE_CLASS");
1313
1314 StringRef Prefix = DirLang.getClausePrefix();
1315
1316 OS << "#ifndef CLAUSE\n";
1317 OS << "#define CLAUSE(Enum, Str, Implicit)\n";
1318 OS << "#endif\n";
1319 OS << "#ifndef CLAUSE_CLASS\n";
1320 OS << "#define CLAUSE_CLASS(Enum, Str, Class)\n";
1321 OS << "#endif\n";
1322 OS << "#ifndef CLAUSE_NO_CLASS\n";
1323 OS << "#define CLAUSE_NO_CLASS(Enum, Str)\n";
1324 OS << "#endif\n";
1325 OS << "\n";
1326 OS << "#define __CLAUSE(Name, Class) \\\n";
1327 OS << " CLAUSE(" << Prefix << "##Name, #Name, /* Implicit */ false) \\\n";
1328 OS << " CLAUSE_CLASS(" << Prefix << "##Name, #Name, Class)\n";
1329 OS << "#define __CLAUSE_NO_CLASS(Name) \\\n";
1330 OS << " CLAUSE(" << Prefix << "##Name, #Name, /* Implicit */ false) \\\n";
1331 OS << " CLAUSE_NO_CLASS(" << Prefix << "##Name, #Name)\n";
1332 OS << "#define __IMPLICIT_CLAUSE_CLASS(Name, Str, Class) \\\n";
1333 OS << " CLAUSE(" << Prefix << "##Name, Str, /* Implicit */ true) \\\n";
1334 OS << " CLAUSE_CLASS(" << Prefix << "##Name, Str, Class)\n";
1335 OS << "#define __IMPLICIT_CLAUSE_NO_CLASS(Name, Str) \\\n";
1336 OS << " CLAUSE(" << Prefix << "##Name, Str, /* Implicit */ true) \\\n";
1337 OS << " CLAUSE_NO_CLASS(" << Prefix << "##Name, Str)\n";
1338 OS << "\n";
1339
1340 for (const Clause C : DirLang.getClauses()) {
1341 std::string Name = C.getFormattedName();
1342 if (C.getClangClass().empty()) { // NO_CLASS
1343 if (C.isImplicit()) {
1344 OS << "__IMPLICIT_CLAUSE_NO_CLASS(" << Name << ", \"" << Name
1345 << "\")\n";
1346 } else {
1347 OS << "__CLAUSE_NO_CLASS(" << Name << ")\n";
1348 }
1349 } else { // CLASS
1350 if (C.isImplicit()) {
1351 OS << "__IMPLICIT_CLAUSE_CLASS(" << Name << ", \"" << Name << "\", "
1352 << C.getClangClass() << ")\n";
1353 } else {
1354 OS << "__CLAUSE(" << Name << ", " << C.getClangClass() << ")\n";
1355 }
1356 }
1357 }
1358
1359 OS << "\n";
1360 OS << "#undef __IMPLICIT_CLAUSE_NO_CLASS\n";
1361 OS << "#undef __IMPLICIT_CLAUSE_CLASS\n";
1362 OS << "#undef __CLAUSE_NO_CLASS\n";
1363 OS << "#undef __CLAUSE\n";
1364 OS << "#undef CLAUSE_NO_CLASS\n";
1365 OS << "#undef CLAUSE_CLASS\n";
1366 OS << "#undef CLAUSE\n";
1367}
1368
1369static void emitDirectivesConstexprImpl(const DirectiveLanguage &DirLang,
1370 raw_ostream &OS) {
1371 OS << "// Constexpr functions.\n";
1372 OS << "\n";
1373 generateGetDirectiveAssociation(DirLang, OS);
1374 OS << "\n";
1375 generateGetDirectiveCategory(DirLang, OS);
1376 OS << "\n";
1377 generateGetDirectiveLanguages(DirLang, OS);
1378}
1379
1380// Generate the implemenation for the enumeration in the directive
1381// language. This code can be included in library.
1382void emitDirectivesBasicImpl(const DirectiveLanguage &DirLang,
1383 raw_ostream &OS) {
1384 IfDefEmitter Scope(OS, "GEN_DIRECTIVES_IMPL");
1385
1386 StringRef DPrefix = DirLang.getDirectivePrefix();
1387 StringRef CPrefix = DirLang.getClausePrefix();
1388
1389 OS << "#include \"llvm/Frontend/Directive/Spelling.h\"\n";
1390 OS << "#include \"llvm/Support/ErrorHandling.h\"\n";
1391 OS << "#include <utility>\n";
1392
1393 // getDirectiveKind(StringRef Str)
1394 generateGetKind(Records: DirLang.getDirectives(), OS, Enum: "Directive", DirLang, Prefix: DPrefix,
1395 /*ImplicitAsUnknown=*/false);
1396
1397 // getDirectiveName(Directive Kind)
1398 generateGetName(Records: DirLang.getDirectives(), OS, Enum: "Directive", DirLang,
1399 LangName: DirLang.getName(), Prefix: DPrefix);
1400
1401 // getClauseKind(StringRef Str)
1402 generateGetKind(Records: DirLang.getClauses(), OS, Enum: "Clause", DirLang, Prefix: CPrefix,
1403 /*ImplicitAsUnknown=*/true);
1404
1405 // getClauseName(Clause Kind)
1406 generateGetName(Records: DirLang.getClauses(), OS, Enum: "Clause", DirLang,
1407 LangName: DirLang.getName(), Prefix: CPrefix);
1408
1409 // <enumClauseValue> get<enumClauseValue>(StringRef Str) ; string -> value
1410 // StringRef get<enumClauseValue>Name(<enumClauseValue>) ; value -> string
1411 generateGetClauseVal(DirLang, OS);
1412
1413 // isAllowedClauseForDirective(Directive D, Clause C, unsigned Version)
1414 generateIsAllowedClause(DirLang, OS);
1415
1416 // isAllowedLoopModifier(Directive D, LoopModifier LM)
1417 generateIsAllowedLoopModifier(DirLang, OS);
1418
1419 // getLoopModifierName(LoopModifier Kind)
1420 generateGetName(Records: DirLang.getLoopModifiers(), OS, Enum: "LoopModifier", DirLang, LangName: "",
1421 Prefix: DirLang.getLoopModifierPrefix());
1422
1423 // Leaf table for getLeafConstructs, etc.
1424 emitLeafTable(DirLang, OS, TableName: "LeafConstructTable");
1425}
1426
1427// Generate the implemenation section for the enumeration in the directive
1428// language.
1429static void emitDirectivesImpl(const RecordKeeper &Records, raw_ostream &OS) {
1430 const auto DirLang = DirectiveLanguage(Records);
1431 if (DirLang.HasValidityErrors())
1432 return;
1433
1434 emitDirectivesFlangImpl(DirLang, OS);
1435
1436 emitDirectivesClangImpl(DirLang, OS);
1437
1438 generateClauseClassMacro(DirLang, OS);
1439
1440 emitDirectivesBasicImpl(DirLang, OS);
1441}
1442
1443static TableGen::Emitter::Opt
1444 X("gen-directive-decl", emitDirectivesDecl,
1445 "Generate directive related declaration code (header file)");
1446
1447static TableGen::Emitter::Opt
1448 Y("gen-directive-impl", emitDirectivesImpl,
1449 "Generate directive related implementation code");
1450