1 //===- DirectiveEmitter.cpp - Directive Language Emitter ------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // DirectiveEmitter uses the descriptions of directives and clauses to construct
10 // common code declarations to be used in Frontends.
12 //===----------------------------------------------------------------------===//
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"
31 // Simple RAII helper for defining ifdef-undef-endif scopes.
34 IfDefScope(StringRef Name
, raw_ostream
&OS
) : Name(Name
), OS(OS
) {
35 OS
<< "#ifdef " << Name
<< "\n"
36 << "#undef " << Name
<< "\n";
39 ~IfDefScope() { OS
<< "\n#endif // " << Name
<< "\n\n"; }
47 // Generate enum class. Entries are emitted in the order in which they appear
48 // in the `Records` vector.
49 static void generateEnumClass(ArrayRef
<const Record
*> Records
, raw_ostream
&OS
,
50 StringRef Enum
, StringRef Prefix
,
51 const DirectiveLanguage
&DirLang
,
54 OS
<< "enum class " << Enum
<< " {\n";
55 for (const auto &R
: Records
) {
57 OS
<< " " << Prefix
<< Rec
.getFormattedName() << ",\n";
61 OS
<< "static constexpr std::size_t " << Enum
62 << "_enumSize = " << Records
.size() << ";\n";
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
71 for (const auto &R
: Records
) {
73 OS
<< "constexpr auto " << Prefix
<< Rec
.getFormattedName() << " = "
74 << "llvm::" << DirLang
.getCppNamespace() << "::" << Enum
75 << "::" << Prefix
<< Rec
.getFormattedName() << ";\n";
80 // Generate enums for values that clauses can take.
81 // Also generate function declarations for get<Enum>Name(StringRef Str).
82 static void generateEnumClauseVal(ArrayRef
<const Record
*> Records
,
84 const DirectiveLanguage
&DirLang
,
85 std::string
&EnumHelperFuncs
) {
86 for (const auto &R
: Records
) {
88 const auto &ClauseVals
= C
.getClauseVals();
89 if (ClauseVals
.size() <= 0)
92 const auto &EnumName
= C
.getEnumName();
93 if (EnumName
.empty()) {
94 PrintError("enumClauseValue field not set in Clause" +
95 C
.getFormattedName() + ".");
100 OS
<< "enum class " << EnumName
<< " {\n";
101 for (const ClauseVal CVal
: ClauseVals
)
102 OS
<< " " << CVal
.getRecordName() << "=" << CVal
.getValue() << ",\n";
105 if (DirLang
.hasMakeEnumAvailableInNamespace()) {
107 for (const auto &CV
: ClauseVals
) {
108 OS
<< "constexpr auto " << CV
->getName() << " = "
109 << "llvm::" << DirLang
.getCppNamespace() << "::" << EnumName
110 << "::" << CV
->getName() << ";\n";
112 EnumHelperFuncs
+= (Twine("LLVM_ABI ") + Twine(EnumName
) + Twine(" get") +
113 Twine(EnumName
) + Twine("(StringRef);\n"))
117 (Twine("LLVM_ABI llvm::StringRef get") + Twine(DirLang
.getName()) +
118 Twine(EnumName
) + Twine("Name(") + Twine(EnumName
) + Twine(");\n"))
124 static bool hasDuplicateClauses(ArrayRef
<const Record
*> Clauses
,
125 const Directive
&Directive
,
126 StringSet
<> &CrtClauses
) {
127 bool HasError
= false;
128 for (const VersionedClause VerClause
: Clauses
) {
129 const auto InsRes
= CrtClauses
.insert(VerClause
.getClause().getName());
130 if (!InsRes
.second
) {
131 PrintError("Clause " + VerClause
.getClause().getRecordName() +
132 " already defined on directive " + Directive
.getRecordName());
139 // Check for duplicate clauses in lists. Clauses cannot appear twice in the
140 // three allowed list. Also, since required implies allowed, clauses cannot
141 // appear in both the allowedClauses and requiredClauses lists.
143 hasDuplicateClausesInDirectives(ArrayRef
<const Record
*> Directives
) {
144 bool HasDuplicate
= false;
145 for (const Directive Dir
: Directives
) {
147 // Check for duplicates in the three allowed lists.
148 if (hasDuplicateClauses(Dir
.getAllowedClauses(), Dir
, Clauses
) ||
149 hasDuplicateClauses(Dir
.getAllowedOnceClauses(), Dir
, Clauses
) ||
150 hasDuplicateClauses(Dir
.getAllowedExclusiveClauses(), Dir
, Clauses
)) {
153 // Check for duplicate between allowedClauses and required
155 if (hasDuplicateClauses(Dir
.getAllowedClauses(), Dir
, Clauses
) ||
156 hasDuplicateClauses(Dir
.getRequiredClauses(), Dir
, Clauses
)) {
160 PrintFatalError("One or more clauses are defined multiple times on"
162 Dir
.getRecordName());
168 // Check consitency of records. Return true if an error has been detected.
169 // Return false if the records are valid.
170 bool DirectiveLanguage::HasValidityErrors() const {
171 if (getDirectiveLanguages().size() != 1) {
172 PrintFatalError("A single definition of DirectiveLanguage is needed.");
176 return hasDuplicateClausesInDirectives(getDirectives());
179 // Count the maximum number of leaf constituents per construct.
180 static size_t getMaxLeafCount(const DirectiveLanguage
&DirLang
) {
182 for (const Directive D
: DirLang
.getDirectives())
183 MaxCount
= std::max(MaxCount
, D
.getLeafConstructs().size());
187 // Generate the declaration section for the enumeration in the directive
189 static void emitDirectivesDecl(const RecordKeeper
&Records
, raw_ostream
&OS
) {
190 const auto DirLang
= DirectiveLanguage(Records
);
191 if (DirLang
.HasValidityErrors())
194 OS
<< "#ifndef LLVM_" << DirLang
.getName() << "_INC\n";
195 OS
<< "#define LLVM_" << DirLang
.getName() << "_INC\n";
196 OS
<< "\n#include \"llvm/ADT/ArrayRef.h\"\n";
198 if (DirLang
.hasEnableBitmaskEnumInNamespace())
199 OS
<< "#include \"llvm/ADT/BitmaskEnum.h\"\n";
201 OS
<< "#include \"llvm/Support/Compiler.h\"\n";
202 OS
<< "#include <cstddef>\n"; // for size_t
204 OS
<< "namespace llvm {\n";
205 OS
<< "class StringRef;\n";
207 // Open namespaces defined in the directive language
208 SmallVector
<StringRef
, 2> Namespaces
;
209 SplitString(DirLang
.getCppNamespace(), Namespaces
, "::");
210 for (auto Ns
: Namespaces
)
211 OS
<< "namespace " << Ns
<< " {\n";
213 if (DirLang
.hasEnableBitmaskEnumInNamespace())
214 OS
<< "\nLLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();\n";
216 // Emit Directive associations
217 std::vector
<const Record
*> Associations
;
218 copy_if(DirLang
.getAssociations(), std::back_inserter(Associations
),
219 // Skip the "special" value
220 [](const Record
*Def
) { return Def
->getName() != "AS_FromLeaves"; });
221 generateEnumClass(Associations
, OS
, "Association",
222 /*Prefix=*/"", DirLang
, /*ExportEnums=*/false);
224 generateEnumClass(DirLang
.getCategories(), OS
, "Category", /*Prefix=*/"",
225 DirLang
, /*ExportEnums=*/false);
227 // Emit Directive enumeration
228 generateEnumClass(DirLang
.getDirectives(), OS
, "Directive",
229 DirLang
.getDirectivePrefix(), DirLang
,
230 DirLang
.hasMakeEnumAvailableInNamespace());
232 // Emit Clause enumeration
233 generateEnumClass(DirLang
.getClauses(), OS
, "Clause",
234 DirLang
.getClausePrefix(), DirLang
,
235 DirLang
.hasMakeEnumAvailableInNamespace());
237 // Emit ClauseVal enumeration
238 std::string EnumHelperFuncs
;
239 generateEnumClauseVal(DirLang
.getClauses(), OS
, DirLang
, EnumHelperFuncs
);
241 // Generic function signatures
243 OS
<< "// Enumeration helper functions\n";
244 OS
<< "LLVM_ABI Directive get" << DirLang
.getName()
245 << "DirectiveKind(llvm::StringRef Str);\n";
247 OS
<< "LLVM_ABI llvm::StringRef get" << DirLang
.getName()
248 << "DirectiveName(Directive D);\n";
250 OS
<< "LLVM_ABI Clause get" << DirLang
.getName()
251 << "ClauseKind(llvm::StringRef Str);\n";
253 OS
<< "LLVM_ABI llvm::StringRef get" << DirLang
.getName()
254 << "ClauseName(Clause C);\n";
256 OS
<< "/// Return true if \\p C is a valid clause for \\p D in version \\p "
258 OS
<< "LLVM_ABI bool isAllowedClauseForDirective(Directive D, "
259 << "Clause C, unsigned Version);\n";
261 OS
<< "constexpr std::size_t getMaxLeafCount() { return "
262 << getMaxLeafCount(DirLang
) << "; }\n";
263 OS
<< "LLVM_ABI Association getDirectiveAssociation(Directive D);\n";
264 OS
<< "LLVM_ABI Category getDirectiveCategory(Directive D);\n";
265 if (EnumHelperFuncs
.length() > 0) {
266 OS
<< EnumHelperFuncs
;
270 // Closing namespaces
271 for (auto Ns
: reverse(Namespaces
))
272 OS
<< "} // namespace " << Ns
<< "\n";
274 OS
<< "} // namespace llvm\n";
276 OS
<< "#endif // LLVM_" << DirLang
.getName() << "_INC\n";
279 // Generate function implementation for get<Enum>Name(StringRef Str)
280 static void generateGetName(ArrayRef
<const Record
*> Records
, raw_ostream
&OS
,
281 StringRef Enum
, const DirectiveLanguage
&DirLang
,
284 OS
<< "llvm::StringRef llvm::" << DirLang
.getCppNamespace() << "::get"
285 << DirLang
.getName() << Enum
<< "Name(" << Enum
<< " Kind) {\n";
286 OS
<< " switch (Kind) {\n";
287 for (const BaseRecord Rec
: Records
) {
288 OS
<< " case " << Prefix
<< Rec
.getFormattedName() << ":\n";
290 if (Rec
.getAlternativeName().empty())
293 OS
<< Rec
.getAlternativeName();
296 OS
<< " }\n"; // switch
297 OS
<< " llvm_unreachable(\"Invalid " << DirLang
.getName() << " " << Enum
302 // Generate function implementation for get<Enum>Kind(StringRef Str)
303 static void generateGetKind(ArrayRef
<const Record
*> Records
, raw_ostream
&OS
,
304 StringRef Enum
, const DirectiveLanguage
&DirLang
,
305 StringRef Prefix
, bool ImplicitAsUnknown
) {
307 const auto *DefaultIt
= find_if(
308 Records
, [](const Record
*R
) { return R
->getValueAsBit("isDefault"); });
310 if (DefaultIt
== Records
.end()) {
311 PrintError("At least one " + Enum
+ " must be defined as default.");
315 BaseRecord
DefaultRec(*DefaultIt
);
318 OS
<< Enum
<< " llvm::" << DirLang
.getCppNamespace() << "::get"
319 << DirLang
.getName() << Enum
<< "Kind(llvm::StringRef Str) {\n";
320 OS
<< " return llvm::StringSwitch<" << Enum
<< ">(Str)\n";
322 for (const auto &R
: Records
) {
324 if (ImplicitAsUnknown
&& R
->getValueAsBit("isImplicit")) {
325 OS
<< " .Case(\"" << Rec
.getName() << "\"," << Prefix
326 << DefaultRec
.getFormattedName() << ")\n";
328 OS
<< " .Case(\"" << Rec
.getName() << "\"," << Prefix
329 << Rec
.getFormattedName() << ")\n";
332 OS
<< " .Default(" << Prefix
<< DefaultRec
.getFormattedName() << ");\n";
336 // Generate function implementation for get<ClauseVal>Kind(StringRef Str)
337 static void generateGetKindClauseVal(const DirectiveLanguage
&DirLang
,
339 for (const Clause C
: DirLang
.getClauses()) {
340 const auto &ClauseVals
= C
.getClauseVals();
341 if (ClauseVals
.size() <= 0)
344 auto DefaultIt
= find_if(ClauseVals
, [](const Record
*CV
) {
345 return CV
->getValueAsBit("isDefault");
348 if (DefaultIt
== ClauseVals
.end()) {
349 PrintError("At least one val in Clause " + C
.getFormattedName() +
350 " must be defined as default.");
353 const auto DefaultName
= (*DefaultIt
)->getName();
355 const auto &EnumName
= C
.getEnumName();
356 if (EnumName
.empty()) {
357 PrintError("enumClauseValue field not set in Clause" +
358 C
.getFormattedName() + ".");
363 OS
<< EnumName
<< " llvm::" << DirLang
.getCppNamespace() << "::get"
364 << EnumName
<< "(llvm::StringRef Str) {\n";
365 OS
<< " return llvm::StringSwitch<" << EnumName
<< ">(Str)\n";
366 for (const auto &CV
: ClauseVals
) {
368 OS
<< " .Case(\"" << CVal
.getFormattedName() << "\"," << CV
->getName()
371 OS
<< " .Default(" << DefaultName
<< ");\n";
375 OS
<< "llvm::StringRef llvm::" << DirLang
.getCppNamespace() << "::get"
376 << DirLang
.getName() << EnumName
377 << "Name(llvm::" << DirLang
.getCppNamespace() << "::" << EnumName
379 OS
<< " switch (x) {\n";
380 for (const auto &CV
: ClauseVals
) {
382 OS
<< " case " << CV
->getName() << ":\n";
383 OS
<< " return \"" << CVal
.getFormattedName() << "\";\n";
385 OS
<< " }\n"; // switch
386 OS
<< " llvm_unreachable(\"Invalid " << DirLang
.getName() << " "
387 << EnumName
<< " kind\");\n";
392 static void generateCaseForVersionedClauses(ArrayRef
<const Record
*> Clauses
,
394 StringRef DirectiveName
,
395 const DirectiveLanguage
&DirLang
,
396 StringSet
<> &Cases
) {
397 for (const VersionedClause VerClause
: Clauses
) {
398 const auto ClauseFormattedName
= VerClause
.getClause().getFormattedName();
400 if (Cases
.insert(ClauseFormattedName
).second
) {
401 OS
<< " case " << DirLang
.getClausePrefix() << ClauseFormattedName
403 OS
<< " return " << VerClause
.getMinVersion()
404 << " <= Version && " << VerClause
.getMaxVersion() << " >= Version;\n";
409 static std::string
getDirectiveName(const DirectiveLanguage
&DirLang
,
412 return (Twine("llvm::") + DirLang
.getCppNamespace() +
413 "::" + DirLang
.getDirectivePrefix() + Dir
.getFormattedName())
417 static std::string
getDirectiveType(const DirectiveLanguage
&DirLang
) {
418 return (Twine("llvm::") + DirLang
.getCppNamespace() + "::Directive").str();
421 // Generate the isAllowedClauseForDirective function implementation.
422 static void generateIsAllowedClause(const DirectiveLanguage
&DirLang
,
425 OS
<< "bool llvm::" << DirLang
.getCppNamespace()
426 << "::isAllowedClauseForDirective("
427 << "Directive D, Clause C, unsigned Version) {\n";
428 OS
<< " assert(unsigned(D) <= llvm::" << DirLang
.getCppNamespace()
429 << "::Directive_enumSize);\n";
430 OS
<< " assert(unsigned(C) <= llvm::" << DirLang
.getCppNamespace()
431 << "::Clause_enumSize);\n";
433 OS
<< " switch (D) {\n";
435 for (const Directive Dir
: DirLang
.getDirectives()) {
436 OS
<< " case " << DirLang
.getDirectivePrefix() << Dir
.getFormattedName()
438 if (Dir
.getAllowedClauses().empty() &&
439 Dir
.getAllowedOnceClauses().empty() &&
440 Dir
.getAllowedExclusiveClauses().empty() &&
441 Dir
.getRequiredClauses().empty()) {
442 OS
<< " return false;\n";
444 OS
<< " switch (C) {\n";
448 generateCaseForVersionedClauses(Dir
.getAllowedClauses(), OS
,
449 Dir
.getName(), DirLang
, Cases
);
451 generateCaseForVersionedClauses(Dir
.getAllowedOnceClauses(), OS
,
452 Dir
.getName(), DirLang
, Cases
);
454 generateCaseForVersionedClauses(Dir
.getAllowedExclusiveClauses(), OS
,
455 Dir
.getName(), DirLang
, Cases
);
457 generateCaseForVersionedClauses(Dir
.getRequiredClauses(), OS
,
458 Dir
.getName(), DirLang
, Cases
);
461 OS
<< " return false;\n";
462 OS
<< " }\n"; // End of clauses switch
467 OS
<< " }\n"; // End of directives switch
468 OS
<< " llvm_unreachable(\"Invalid " << DirLang
.getName()
469 << " Directive kind\");\n";
470 OS
<< "}\n"; // End of function isAllowedClauseForDirective
473 static void emitLeafTable(const DirectiveLanguage
&DirLang
, raw_ostream
&OS
,
474 StringRef TableName
) {
475 // The leaf constructs are emitted in a form of a 2D table, where each
476 // row corresponds to a directive (and there is a row for each directive).
478 // Each row consists of
479 // - the id of the directive itself,
480 // - number of leaf constructs that will follow (0 for leafs),
481 // - ids of the leaf constructs (none if the directive is itself a leaf).
482 // The total number of these entries is at most MaxLeafCount+2. If this
483 // number is less than that, it is padded to occupy exactly MaxLeafCount+2
484 // entries in memory.
486 // The rows are stored in the table in the lexicographical order. This
487 // is intended to enable binary search when mapping a sequence of leafs
488 // back to the compound directive.
489 // The consequence of that is that in order to find a row corresponding
490 // to the given directive, we'd need to scan the first element of each
491 // row. To avoid this, an auxiliary ordering table is created, such that
492 // row for Dir_A = table[auxiliary[Dir_A]].
494 ArrayRef
<const Record
*> Directives
= DirLang
.getDirectives();
495 DenseMap
<const Record
*, int> DirId
; // Record * -> llvm::omp::Directive
497 for (auto [Idx
, Rec
] : enumerate(Directives
))
498 DirId
.insert(std::make_pair(Rec
, Idx
));
500 using LeafList
= std::vector
<int>;
501 int MaxLeafCount
= getMaxLeafCount(DirLang
);
503 // The initial leaf table, rows order is same as directive order.
504 std::vector
<LeafList
> LeafTable(Directives
.size());
505 for (auto [Idx
, Rec
] : enumerate(Directives
)) {
507 std::vector
<const Record
*> Leaves
= Dir
.getLeafConstructs();
509 auto &List
= LeafTable
[Idx
];
510 List
.resize(MaxLeafCount
+ 2);
511 List
[0] = Idx
; // The id of the directive itself.
512 List
[1] = Leaves
.size(); // The number of leaves to follow.
514 for (int I
= 0; I
!= MaxLeafCount
; ++I
)
516 static_cast<size_t>(I
) < Leaves
.size() ? DirId
.at(Leaves
[I
]) : -1;
519 // Some Fortran directives are delimited, i.e. they have the form of
520 // "directive"---"end directive". If "directive" is a compound construct,
521 // then the set of leaf constituents will be nonempty and the same for
522 // both directives. Given this set of leafs, looking up the corresponding
523 // compound directive should return "directive", and not "end directive".
524 // To avoid this problem, gather all "end directives" at the end of the
525 // leaf table, and only do the search on the initial segment of the table
526 // that excludes the "end directives".
527 // It's safe to find all directives whose names begin with "end ". The
528 // problem only exists for compound directives, like "end do simd".
529 // All existing directives with names starting with "end " are either
530 // "end directives" for an existing "directive", or leaf directives
531 // (such as "end declare target").
532 DenseSet
<int> EndDirectives
;
533 for (auto [Rec
, Id
] : DirId
) {
534 if (Directive(Rec
).getName().starts_with_insensitive("end "))
535 EndDirectives
.insert(Id
);
538 // Avoid sorting the vector<vector> array, instead sort an index array.
539 // It will also be useful later to create the auxiliary indexing array.
540 std::vector
<int> Ordering(Directives
.size());
541 std::iota(Ordering
.begin(), Ordering
.end(), 0);
543 sort(Ordering
, [&](int A
, int B
) {
544 auto &LeavesA
= LeafTable
[A
];
545 auto &LeavesB
= LeafTable
[B
];
546 int DirA
= LeavesA
[0], DirB
= LeavesB
[0];
547 // First of all, end directives compare greater than non-end directives.
548 int IsEndA
= EndDirectives
.count(DirA
), IsEndB
= EndDirectives
.count(DirB
);
549 if (IsEndA
!= IsEndB
)
550 return IsEndA
< IsEndB
;
551 if (LeavesA
[1] == 0 && LeavesB
[1] == 0)
553 return std::lexicographical_compare(&LeavesA
[2], &LeavesA
[2] + LeavesA
[1],
554 &LeavesB
[2], &LeavesB
[2] + LeavesB
[1]);
559 // The directives are emitted into a scoped enum, for which the underlying
560 // type is `int` (by default). The code above uses `int` to store directive
561 // ids, so make sure that we catch it when something changes in the
563 std::string DirectiveType
= getDirectiveType(DirLang
);
564 OS
<< "\nstatic_assert(sizeof(" << DirectiveType
<< ") == sizeof(int));\n";
566 OS
<< "[[maybe_unused]] static const " << DirectiveType
<< ' ' << TableName
567 << "[][" << MaxLeafCount
+ 2 << "] = {\n";
568 for (size_t I
= 0, E
= Directives
.size(); I
!= E
; ++I
) {
569 auto &Leaves
= LeafTable
[Ordering
[I
]];
570 OS
<< " {" << getDirectiveName(DirLang
, Directives
[Leaves
[0]]);
571 OS
<< ", static_cast<" << DirectiveType
<< ">(" << Leaves
[1] << "),";
572 for (size_t I
= 2, E
= Leaves
.size(); I
!= E
; ++I
) {
575 OS
<< ' ' << getDirectiveName(DirLang
, Directives
[Leaves
[I
]]) << ',';
577 OS
<< " static_cast<" << DirectiveType
<< ">(-1),";
583 // Emit a marker where the first "end directive" is.
584 auto FirstE
= find_if(Ordering
, [&](int RowIdx
) {
585 return EndDirectives
.count(LeafTable
[RowIdx
][0]);
587 OS
<< "[[maybe_unused]] static auto " << TableName
588 << "EndDirective = " << TableName
<< " + "
589 << std::distance(Ordering
.begin(), FirstE
) << ";\n\n";
591 // Emit the auxiliary index table: it's the inverse of the `Ordering`
593 OS
<< "[[maybe_unused]] static const int " << TableName
<< "Ordering[] = {\n";
595 std::vector
<int> Reverse(Ordering
.size());
596 for (int I
= 0, E
= Ordering
.size(); I
!= E
; ++I
)
597 Reverse
[Ordering
[I
]] = I
;
598 for (int Idx
: Reverse
)
599 OS
<< ' ' << Idx
<< ',';
603 static void generateGetDirectiveAssociation(const DirectiveLanguage
&DirLang
,
605 enum struct Association
{
606 None
= 0, // None should be the smallest value.
607 Block
, // The values of the rest don't matter.
616 ArrayRef
<const Record
*> Associations
= DirLang
.getAssociations();
618 auto GetAssocValue
= [](StringRef Name
) -> Association
{
619 return StringSwitch
<Association
>(Name
)
620 .Case("AS_Block", Association::Block
)
621 .Case("AS_Declaration", Association::Declaration
)
622 .Case("AS_Delimited", Association::Delimited
)
623 .Case("AS_Loop", Association::Loop
)
624 .Case("AS_None", Association::None
)
625 .Case("AS_Separating", Association::Separating
)
626 .Case("AS_FromLeaves", Association::FromLeaves
)
627 .Default(Association::Invalid
);
630 auto GetAssocName
= [&](Association A
) -> StringRef
{
631 if (A
!= Association::Invalid
&& A
!= Association::FromLeaves
) {
632 const auto *F
= find_if(Associations
, [&](const Record
*R
) {
633 return GetAssocValue(R
->getName()) == A
;
635 if (F
!= Associations
.end())
636 return (*F
)->getValueAsString("name"); // enum name
638 llvm_unreachable("Unexpected association value");
641 auto ErrorPrefixFor
= [&](Directive D
) -> std::string
{
642 return (Twine("Directive '") + D
.getName() + "' in namespace '" +
643 DirLang
.getCppNamespace() + "' ")
647 auto Reduce
= [&](Association A
, Association B
) -> Association
{
651 // Calculate the result using the following rules:
654 // AS_Block + AS_Loop = AS_Loop
655 if (A
== Association::None
|| A
== B
)
657 if (A
== Association::Block
&& B
== Association::Loop
)
659 if (A
== Association::Loop
&& B
== Association::Block
)
661 return Association::Invalid
;
664 DenseMap
<const Record
*, Association
> AsMap
;
666 auto CompAssocImpl
= [&](const Record
*R
, auto &&Self
) -> Association
{
667 if (auto F
= AsMap
.find(R
); F
!= AsMap
.end())
671 Association AS
= GetAssocValue(D
.getAssociation()->getName());
672 if (AS
== Association::Invalid
) {
673 PrintFatalError(ErrorPrefixFor(D
) +
674 "has an unrecognized value for association: '" +
675 D
.getAssociation()->getName() + "'");
677 if (AS
!= Association::FromLeaves
) {
678 AsMap
.insert(std::make_pair(R
, AS
));
681 // Compute the association from leaf constructs.
682 std::vector
<const Record
*> Leaves
= D
.getLeafConstructs();
683 if (Leaves
.empty()) {
684 errs() << D
.getName() << '\n';
685 PrintFatalError(ErrorPrefixFor(D
) +
686 "requests association to be computed from leaves, "
687 "but it has no leaves");
690 Association Result
= Self(Leaves
[0], Self
);
691 for (int I
= 1, E
= Leaves
.size(); I
< E
; ++I
) {
692 Association A
= Self(Leaves
[I
], Self
);
693 Association R
= Reduce(Result
, A
);
694 if (R
== Association::Invalid
) {
695 PrintFatalError(ErrorPrefixFor(D
) +
696 "has leaves with incompatible association values: " +
697 GetAssocName(A
) + " and " + GetAssocName(R
));
702 assert(Result
!= Association::Invalid
);
703 assert(Result
!= Association::FromLeaves
);
704 AsMap
.insert(std::make_pair(R
, Result
));
708 for (const Record
*R
: DirLang
.getDirectives())
709 CompAssocImpl(R
, CompAssocImpl
); // Updates AsMap.
713 auto GetQualifiedName
= [&](StringRef Formatted
) -> std::string
{
714 return (Twine("llvm::") + DirLang
.getCppNamespace() +
715 "::Directive::" + DirLang
.getDirectivePrefix() + Formatted
)
719 std::string DirectiveTypeName
=
720 "llvm::" + DirLang
.getCppNamespace().str() + "::Directive";
721 std::string AssociationTypeName
=
722 "llvm::" + DirLang
.getCppNamespace().str() + "::Association";
724 OS
<< AssociationTypeName
<< " llvm::" << DirLang
.getCppNamespace()
725 << "::getDirectiveAssociation(" << DirectiveTypeName
<< " Dir) {\n";
726 OS
<< " switch (Dir) {\n";
727 for (const Record
*R
: DirLang
.getDirectives()) {
728 if (auto F
= AsMap
.find(R
); F
!= AsMap
.end()) {
730 OS
<< " case " << GetQualifiedName(Dir
.getFormattedName()) << ":\n";
731 OS
<< " return " << AssociationTypeName
732 << "::" << GetAssocName(F
->second
) << ";\n";
735 OS
<< " } // switch (Dir)\n";
736 OS
<< " llvm_unreachable(\"Unexpected directive\");\n";
740 static void generateGetDirectiveCategory(const DirectiveLanguage
&DirLang
,
742 std::string LangNamespace
= "llvm::" + DirLang
.getCppNamespace().str();
743 std::string CategoryTypeName
= LangNamespace
+ "::Category";
744 std::string CategoryNamespace
= CategoryTypeName
+ "::";
747 OS
<< CategoryTypeName
<< ' ' << LangNamespace
<< "::getDirectiveCategory("
748 << getDirectiveType(DirLang
) << " Dir) {\n";
749 OS
<< " switch (Dir) {\n";
751 for (const Record
*R
: DirLang
.getDirectives()) {
753 OS
<< " case " << getDirectiveName(DirLang
, R
) << ":\n";
754 OS
<< " return " << CategoryNamespace
755 << D
.getCategory()->getValueAsString("name") << ";\n";
757 OS
<< " } // switch (Dir)\n";
758 OS
<< " llvm_unreachable(\"Unexpected directive\");\n";
762 // Generate a simple enum set with the give clauses.
763 static void generateClauseSet(ArrayRef
<const Record
*> Clauses
, raw_ostream
&OS
,
764 StringRef ClauseSetPrefix
, const Directive
&Dir
,
765 const DirectiveLanguage
&DirLang
) {
768 OS
<< " static " << DirLang
.getClauseEnumSetClass() << " " << ClauseSetPrefix
769 << DirLang
.getDirectivePrefix() << Dir
.getFormattedName() << " {\n";
771 for (const auto &C
: Clauses
) {
772 VersionedClause
VerClause(C
);
773 OS
<< " llvm::" << DirLang
.getCppNamespace()
774 << "::Clause::" << DirLang
.getClausePrefix()
775 << VerClause
.getClause().getFormattedName() << ",\n";
780 // Generate an enum set for the 4 kinds of clauses linked to a directive.
781 static void generateDirectiveClauseSets(const DirectiveLanguage
&DirLang
,
784 IfDefScope
Scope("GEN_FLANG_DIRECTIVE_CLAUSE_SETS", OS
);
787 OS
<< "namespace llvm {\n";
789 // Open namespaces defined in the directive language.
790 SmallVector
<StringRef
, 2> Namespaces
;
791 SplitString(DirLang
.getCppNamespace(), Namespaces
, "::");
792 for (auto Ns
: Namespaces
)
793 OS
<< "namespace " << Ns
<< " {\n";
795 for (const Directive Dir
: DirLang
.getDirectives()) {
797 OS
<< " // Sets for " << Dir
.getName() << "\n";
799 generateClauseSet(Dir
.getAllowedClauses(), OS
, "allowedClauses_", Dir
,
801 generateClauseSet(Dir
.getAllowedOnceClauses(), OS
, "allowedOnceClauses_",
803 generateClauseSet(Dir
.getAllowedExclusiveClauses(), OS
,
804 "allowedExclusiveClauses_", Dir
, DirLang
);
805 generateClauseSet(Dir
.getRequiredClauses(), OS
, "requiredClauses_", Dir
,
809 // Closing namespaces
810 for (auto Ns
: reverse(Namespaces
))
811 OS
<< "} // namespace " << Ns
<< "\n";
813 OS
<< "} // namespace llvm\n";
816 // Generate a map of directive (key) with DirectiveClauses struct as values.
817 // The struct holds the 4 sets of enumeration for the 4 kinds of clauses
818 // allowances (allowed, allowed once, allowed exclusive and required).
819 static void generateDirectiveClauseMap(const DirectiveLanguage
&DirLang
,
822 IfDefScope
Scope("GEN_FLANG_DIRECTIVE_CLAUSE_MAP", OS
);
827 for (const Directive Dir
: DirLang
.getDirectives()) {
828 OS
<< " {llvm::" << DirLang
.getCppNamespace()
829 << "::Directive::" << DirLang
.getDirectivePrefix()
830 << Dir
.getFormattedName() << ",\n";
832 OS
<< " llvm::" << DirLang
.getCppNamespace() << "::allowedClauses_"
833 << DirLang
.getDirectivePrefix() << Dir
.getFormattedName() << ",\n";
834 OS
<< " llvm::" << DirLang
.getCppNamespace() << "::allowedOnceClauses_"
835 << DirLang
.getDirectivePrefix() << Dir
.getFormattedName() << ",\n";
836 OS
<< " llvm::" << DirLang
.getCppNamespace()
837 << "::allowedExclusiveClauses_" << DirLang
.getDirectivePrefix()
838 << Dir
.getFormattedName() << ",\n";
839 OS
<< " llvm::" << DirLang
.getCppNamespace() << "::requiredClauses_"
840 << DirLang
.getDirectivePrefix() << Dir
.getFormattedName() << ",\n";
848 // Generate classes entry for Flang clauses in the Flang parse-tree
849 // If the clause as a non-generic class, no entry is generated.
850 // If the clause does not hold a value, an EMPTY_CLASS is used.
851 // If the clause class is generic then a WRAPPER_CLASS is used. When the value
852 // is optional, the value class is wrapped into a std::optional.
853 static void generateFlangClauseParserClass(const DirectiveLanguage
&DirLang
,
856 IfDefScope
Scope("GEN_FLANG_CLAUSE_PARSER_CLASSES", OS
);
860 for (const Clause Clause
: DirLang
.getClauses()) {
861 if (!Clause
.getFlangClass().empty()) {
862 OS
<< "WRAPPER_CLASS(" << Clause
.getFormattedParserClassName() << ", ";
863 if (Clause
.isValueOptional() && Clause
.isValueList()) {
864 OS
<< "std::optional<std::list<" << Clause
.getFlangClass() << ">>";
865 } else if (Clause
.isValueOptional()) {
866 OS
<< "std::optional<" << Clause
.getFlangClass() << ">";
867 } else if (Clause
.isValueList()) {
868 OS
<< "std::list<" << Clause
.getFlangClass() << ">";
870 OS
<< Clause
.getFlangClass();
873 OS
<< "EMPTY_CLASS(" << Clause
.getFormattedParserClassName();
879 // Generate a list of the different clause classes for Flang.
880 static void generateFlangClauseParserClassList(const DirectiveLanguage
&DirLang
,
883 IfDefScope
Scope("GEN_FLANG_CLAUSE_PARSER_CLASSES_LIST", OS
);
886 interleaveComma(DirLang
.getClauses(), OS
, [&](const Record
*C
) {
888 OS
<< Clause
.getFormattedParserClassName() << "\n";
892 // Generate dump node list for the clauses holding a generic class name.
893 static void generateFlangClauseDump(const DirectiveLanguage
&DirLang
,
896 IfDefScope
Scope("GEN_FLANG_DUMP_PARSE_TREE_CLAUSES", OS
);
899 for (const Clause Clause
: DirLang
.getClauses()) {
900 OS
<< "NODE(" << DirLang
.getFlangClauseBaseClass() << ", "
901 << Clause
.getFormattedParserClassName() << ")\n";
905 // Generate Unparse functions for clauses classes in the Flang parse-tree
906 // If the clause is a non-generic class, no entry is generated.
907 static void generateFlangClauseUnparse(const DirectiveLanguage
&DirLang
,
910 IfDefScope
Scope("GEN_FLANG_CLAUSE_UNPARSE", OS
);
914 for (const Clause Clause
: DirLang
.getClauses()) {
915 if (!Clause
.getFlangClass().empty()) {
916 if (Clause
.isValueOptional() && Clause
.getDefaultValue().empty()) {
917 OS
<< "void Unparse(const " << DirLang
.getFlangClauseBaseClass()
918 << "::" << Clause
.getFormattedParserClassName() << " &x) {\n";
919 OS
<< " Word(\"" << Clause
.getName().upper() << "\");\n";
921 OS
<< " Walk(\"(\", x.v, \")\");\n";
923 } else if (Clause
.isValueOptional()) {
924 OS
<< "void Unparse(const " << DirLang
.getFlangClauseBaseClass()
925 << "::" << Clause
.getFormattedParserClassName() << " &x) {\n";
926 OS
<< " Word(\"" << Clause
.getName().upper() << "\");\n";
927 OS
<< " Put(\"(\");\n";
928 OS
<< " if (x.v.has_value())\n";
929 if (Clause
.isValueList())
930 OS
<< " Walk(x.v, \",\");\n";
932 OS
<< " Walk(x.v);\n";
934 OS
<< " Put(\"" << Clause
.getDefaultValue() << "\");\n";
935 OS
<< " Put(\")\");\n";
938 OS
<< "void Unparse(const " << DirLang
.getFlangClauseBaseClass()
939 << "::" << Clause
.getFormattedParserClassName() << " &x) {\n";
940 OS
<< " Word(\"" << Clause
.getName().upper() << "\");\n";
941 OS
<< " Put(\"(\");\n";
942 if (Clause
.isValueList())
943 OS
<< " Walk(x.v, \",\");\n";
945 OS
<< " Walk(x.v);\n";
946 OS
<< " Put(\")\");\n";
950 OS
<< "void Before(const " << DirLang
.getFlangClauseBaseClass()
951 << "::" << Clause
.getFormattedParserClassName() << " &) { Word(\""
952 << Clause
.getName().upper() << "\"); }\n";
957 // Generate check in the Enter functions for clauses classes.
958 static void generateFlangClauseCheckPrototypes(const DirectiveLanguage
&DirLang
,
961 IfDefScope
Scope("GEN_FLANG_CLAUSE_CHECK_ENTER", OS
);
964 for (const Clause Clause
: DirLang
.getClauses()) {
965 OS
<< "void Enter(const parser::" << DirLang
.getFlangClauseBaseClass()
966 << "::" << Clause
.getFormattedParserClassName() << " &);\n";
970 // Generate the mapping for clauses between the parser class and the
971 // corresponding clause Kind
972 static void generateFlangClauseParserKindMap(const DirectiveLanguage
&DirLang
,
975 IfDefScope
Scope("GEN_FLANG_CLAUSE_PARSER_KIND_MAP", OS
);
978 for (const Clause Clause
: DirLang
.getClauses()) {
979 OS
<< "if constexpr (std::is_same_v<A, parser::"
980 << DirLang
.getFlangClauseBaseClass()
981 << "::" << Clause
.getFormattedParserClassName();
983 OS
<< " return llvm::" << DirLang
.getCppNamespace()
984 << "::Clause::" << DirLang
.getClausePrefix() << Clause
.getFormattedName()
988 OS
<< "llvm_unreachable(\"Invalid " << DirLang
.getName()
989 << " Parser clause\");\n";
992 static bool compareClauseName(const Record
*R1
, const Record
*R2
) {
995 return (C1
.getName() > C2
.getName());
998 // Generate the parser for the clauses.
999 static void generateFlangClausesParser(const DirectiveLanguage
&DirLang
,
1001 std::vector
<const Record
*> Clauses
= DirLang
.getClauses();
1002 // Sort clauses in reverse alphabetical order so with clauses with same
1003 // beginning, the longer option is tried before.
1004 sort(Clauses
, compareClauseName
);
1005 IfDefScope
Scope("GEN_FLANG_CLAUSES_PARSER", OS
);
1008 unsigned LastClauseIndex
= Clauses
.size() - 1;
1009 OS
<< "TYPE_PARSER(\n";
1010 for (const Clause Clause
: Clauses
) {
1011 if (Clause
.getAliases().empty()) {
1012 OS
<< " \"" << Clause
.getName() << "\"";
1015 << "\"" << Clause
.getName() << "\"_tok";
1016 for (StringRef Alias
: Clause
.getAliases()) {
1017 OS
<< " || \"" << Alias
<< "\"_tok";
1022 OS
<< " >> construct<" << DirLang
.getFlangClauseBaseClass()
1023 << ">(construct<" << DirLang
.getFlangClauseBaseClass()
1024 << "::" << Clause
.getFormattedParserClassName() << ">(";
1025 if (Clause
.getFlangClass().empty()) {
1027 if (Index
!= LastClauseIndex
)
1034 if (Clause
.isValueOptional())
1036 OS
<< "parenthesized(";
1037 if (Clause
.isValueList())
1038 OS
<< "nonemptyList(";
1040 if (!Clause
.getPrefix().empty())
1041 OS
<< "\"" << Clause
.getPrefix() << ":\" >> ";
1043 // The common Flang parser are used directly. Their name is identical to
1044 // the Flang class with first letter as lowercase. If the Flang class is
1045 // not a common class, we assume there is a specific Parser<>{} with the
1046 // Flang class name provided.
1047 SmallString
<128> Scratch
;
1049 StringSwitch
<StringRef
>(Clause
.getFlangClass())
1050 .Case("Name", "name")
1051 .Case("ScalarIntConstantExpr", "scalarIntConstantExpr")
1052 .Case("ScalarIntExpr", "scalarIntExpr")
1053 .Case("ScalarExpr", "scalarExpr")
1054 .Case("ScalarLogicalExpr", "scalarLogicalExpr")
1055 .Default(("Parser<" + Clause
.getFlangClass() + ">{}")
1056 .toStringRef(Scratch
));
1058 if (!Clause
.getPrefix().empty() && Clause
.isPrefixOptional())
1059 OS
<< " || " << Parser
;
1060 if (Clause
.isValueList()) // close nonemptyList(.
1062 OS
<< ")"; // close parenthesized(.
1064 if (Clause
.isValueOptional()) // close maybe(.
1067 if (Index
!= LastClauseIndex
)
1075 // Generate the implementation section for the enumeration in the directive
1077 static void emitDirectivesFlangImpl(const DirectiveLanguage
&DirLang
,
1079 generateDirectiveClauseSets(DirLang
, OS
);
1081 generateDirectiveClauseMap(DirLang
, OS
);
1083 generateFlangClauseParserClass(DirLang
, OS
);
1085 generateFlangClauseParserClassList(DirLang
, OS
);
1087 generateFlangClauseDump(DirLang
, OS
);
1089 generateFlangClauseUnparse(DirLang
, OS
);
1091 generateFlangClauseCheckPrototypes(DirLang
, OS
);
1093 generateFlangClauseParserKindMap(DirLang
, OS
);
1095 generateFlangClausesParser(DirLang
, OS
);
1098 static void generateClauseClassMacro(const DirectiveLanguage
&DirLang
,
1100 // Generate macros style information for legacy code in clang
1101 IfDefScope
Scope("GEN_CLANG_CLAUSE_CLASS", OS
);
1105 OS
<< "#ifndef CLAUSE\n";
1106 OS
<< "#define CLAUSE(Enum, Str, Implicit)\n";
1108 OS
<< "#ifndef CLAUSE_CLASS\n";
1109 OS
<< "#define CLAUSE_CLASS(Enum, Str, Class)\n";
1111 OS
<< "#ifndef CLAUSE_NO_CLASS\n";
1112 OS
<< "#define CLAUSE_NO_CLASS(Enum, Str)\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";
1135 for (const Clause C
: DirLang
.getClauses()) {
1136 if (C
.getClangClass().empty()) { // NO_CLASS
1137 if (C
.isImplicit()) {
1138 OS
<< "__IMPLICIT_CLAUSE_NO_CLASS(" << C
.getFormattedName() << ", \""
1139 << C
.getFormattedName() << "\")\n";
1141 OS
<< "__CLAUSE_NO_CLASS(" << C
.getFormattedName() << ")\n";
1144 if (C
.isImplicit()) {
1145 OS
<< "__IMPLICIT_CLAUSE_CLASS(" << C
.getFormattedName() << ", \""
1146 << C
.getFormattedName() << "\", " << C
.getClangClass() << ")\n";
1148 OS
<< "__CLAUSE(" << C
.getFormattedName() << ", " << C
.getClangClass()
1155 OS
<< "#undef __IMPLICIT_CLAUSE_NO_CLASS\n";
1156 OS
<< "#undef __IMPLICIT_CLAUSE_CLASS\n";
1157 OS
<< "#undef __CLAUSE_NO_CLASS\n";
1158 OS
<< "#undef __CLAUSE\n";
1159 OS
<< "#undef CLAUSE_NO_CLASS\n";
1160 OS
<< "#undef CLAUSE_CLASS\n";
1161 OS
<< "#undef CLAUSE\n";
1164 // Generate the implemenation for the enumeration in the directive
1165 // language. This code can be included in library.
1166 void emitDirectivesBasicImpl(const DirectiveLanguage
&DirLang
,
1168 IfDefScope
Scope("GEN_DIRECTIVES_IMPL", OS
);
1170 OS
<< "\n#include \"llvm/Support/ErrorHandling.h\"\n";
1172 // getDirectiveKind(StringRef Str)
1173 generateGetKind(DirLang
.getDirectives(), OS
, "Directive", DirLang
,
1174 DirLang
.getDirectivePrefix(), /*ImplicitAsUnknown=*/false);
1176 // getDirectiveName(Directive Kind)
1177 generateGetName(DirLang
.getDirectives(), OS
, "Directive", DirLang
,
1178 DirLang
.getDirectivePrefix());
1180 // getClauseKind(StringRef Str)
1181 generateGetKind(DirLang
.getClauses(), OS
, "Clause", DirLang
,
1182 DirLang
.getClausePrefix(),
1183 /*ImplicitAsUnknown=*/true);
1185 // getClauseName(Clause Kind)
1186 generateGetName(DirLang
.getClauses(), OS
, "Clause", DirLang
,
1187 DirLang
.getClausePrefix());
1189 // get<ClauseVal>Kind(StringRef Str)
1190 generateGetKindClauseVal(DirLang
, OS
);
1192 // isAllowedClauseForDirective(Directive D, Clause C, unsigned Version)
1193 generateIsAllowedClause(DirLang
, OS
);
1195 // getDirectiveAssociation(Directive D)
1196 generateGetDirectiveAssociation(DirLang
, OS
);
1198 // getDirectiveCategory(Directive D)
1199 generateGetDirectiveCategory(DirLang
, OS
);
1201 // Leaf table for getLeafConstructs, etc.
1202 emitLeafTable(DirLang
, OS
, "LeafConstructTable");
1205 // Generate the implemenation section for the enumeration in the directive
1207 static void emitDirectivesImpl(const RecordKeeper
&Records
, raw_ostream
&OS
) {
1208 const auto DirLang
= DirectiveLanguage(Records
);
1209 if (DirLang
.HasValidityErrors())
1212 emitDirectivesFlangImpl(DirLang
, OS
);
1214 generateClauseClassMacro(DirLang
, OS
);
1216 emitDirectivesBasicImpl(DirLang
, OS
);
1219 static TableGen::Emitter::Opt
1220 X("gen-directive-decl", emitDirectivesDecl
,
1221 "Generate directive related declaration code (header file)");
1223 static TableGen::Emitter::Opt
1224 Y("gen-directive-impl", emitDirectivesImpl
,
1225 "Generate directive related implementation code");