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