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

source code of llvm/utils/TableGen/DirectiveEmitter.cpp