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/STLExtras.h"
16 #include "llvm/ADT/SmallVector.h"
17 #include "llvm/ADT/StringSet.h"
18 #include "llvm/ADT/StringSwitch.h"
19 #include "llvm/TableGen/Error.h"
20 #include "llvm/TableGen/Record.h"
21 #include "llvm/TableGen/TableGenBackend.h"
26 // Simple RAII helper for defining ifdef-undef-endif scopes.
29 IfDefScope(StringRef Name
, raw_ostream
&OS
) : Name(Name
), OS(OS
) {
30 OS
<< "#ifdef " << Name
<< "\n"
31 << "#undef " << Name
<< "\n";
34 ~IfDefScope() { OS
<< "\n#endif // " << Name
<< "\n\n"; }
42 // Generate enum class
43 static void GenerateEnumClass(const std::vector
<Record
*> &Records
,
44 raw_ostream
&OS
, StringRef Enum
, StringRef Prefix
,
45 const DirectiveLanguage
&DirLang
) {
47 OS
<< "enum class " << Enum
<< " {\n";
48 for (const auto &R
: Records
) {
50 OS
<< " " << Prefix
<< Rec
.getFormattedName() << ",\n";
54 OS
<< "static constexpr std::size_t " << Enum
55 << "_enumSize = " << Records
.size() << ";\n";
57 // Make the enum values available in the defined namespace. This allows us to
58 // write something like Enum_X if we have a `using namespace <CppNamespace>`.
59 // At the same time we do not loose the strong type guarantees of the enum
60 // class, that is we cannot pass an unsigned as Directive without an explicit
62 if (DirLang
.hasMakeEnumAvailableInNamespace()) {
64 for (const auto &R
: Records
) {
66 OS
<< "constexpr auto " << Prefix
<< Rec
.getFormattedName() << " = "
67 << "llvm::" << DirLang
.getCppNamespace() << "::" << Enum
68 << "::" << Prefix
<< Rec
.getFormattedName() << ";\n";
73 // Generate enums for values that clauses can take.
74 // Also generate function declarations for get<Enum>Name(StringRef Str).
75 static void GenerateEnumClauseVal(const std::vector
<Record
*> &Records
,
77 const DirectiveLanguage
&DirLang
,
78 std::string
&EnumHelperFuncs
) {
79 for (const auto &R
: Records
) {
81 const auto &ClauseVals
= C
.getClauseVals();
82 if (ClauseVals
.size() <= 0)
85 const auto &EnumName
= C
.getEnumName();
86 if (EnumName
.size() == 0) {
87 PrintError("enumClauseValue field not set in Clause" +
88 C
.getFormattedName() + ".");
93 OS
<< "enum class " << EnumName
<< " {\n";
94 for (const auto &CV
: ClauseVals
) {
96 OS
<< " " << CV
->getName() << "=" << CVal
.getValue() << ",\n";
100 if (DirLang
.hasMakeEnumAvailableInNamespace()) {
102 for (const auto &CV
: ClauseVals
) {
103 OS
<< "constexpr auto " << CV
->getName() << " = "
104 << "llvm::" << DirLang
.getCppNamespace() << "::" << EnumName
105 << "::" << CV
->getName() << ";\n";
107 EnumHelperFuncs
+= (llvm::Twine(EnumName
) + llvm::Twine(" get") +
108 llvm::Twine(EnumName
) + llvm::Twine("(StringRef);\n"))
112 (llvm::Twine("llvm::StringRef get") + llvm::Twine(DirLang
.getName()) +
113 llvm::Twine(EnumName
) + llvm::Twine("Name(") +
114 llvm::Twine(EnumName
) + llvm::Twine(");\n"))
120 static bool HasDuplicateClauses(const std::vector
<Record
*> &Clauses
,
121 const Directive
&Directive
,
122 llvm::StringSet
<> &CrtClauses
) {
123 bool HasError
= false;
124 for (const auto &C
: Clauses
) {
125 VersionedClause VerClause
{C
};
126 const auto insRes
= CrtClauses
.insert(VerClause
.getClause().getName());
127 if (!insRes
.second
) {
128 PrintError("Clause " + VerClause
.getClause().getRecordName() +
129 " already defined on directive " + Directive
.getRecordName());
136 // Check for duplicate clauses in lists. Clauses cannot appear twice in the
137 // three allowed list. Also, since required implies allowed, clauses cannot
138 // appear in both the allowedClauses and requiredClauses lists.
140 HasDuplicateClausesInDirectives(const std::vector
<Record
*> &Directives
) {
141 bool HasDuplicate
= false;
142 for (const auto &D
: Directives
) {
144 llvm::StringSet
<> Clauses
;
145 // Check for duplicates in the three allowed lists.
146 if (HasDuplicateClauses(Dir
.getAllowedClauses(), Dir
, Clauses
) ||
147 HasDuplicateClauses(Dir
.getAllowedOnceClauses(), Dir
, Clauses
) ||
148 HasDuplicateClauses(Dir
.getAllowedExclusiveClauses(), Dir
, Clauses
)) {
151 // Check for duplicate between allowedClauses and required
153 if (HasDuplicateClauses(Dir
.getAllowedClauses(), Dir
, Clauses
) ||
154 HasDuplicateClauses(Dir
.getRequiredClauses(), Dir
, Clauses
)) {
158 PrintFatalError("One or more clauses are defined multiple times on"
160 Dir
.getRecordName());
166 // Check consitency of records. Return true if an error has been detected.
167 // Return false if the records are valid.
168 bool DirectiveLanguage::HasValidityErrors() const {
169 if (getDirectiveLanguages().size() != 1) {
170 PrintFatalError("A single definition of DirectiveLanguage is needed.");
174 return HasDuplicateClausesInDirectives(getDirectives());
177 // Generate the declaration section for the enumeration in the directive
179 static void EmitDirectivesDecl(RecordKeeper
&Records
, raw_ostream
&OS
) {
180 const auto DirLang
= DirectiveLanguage
{Records
};
181 if (DirLang
.HasValidityErrors())
184 OS
<< "#ifndef LLVM_" << DirLang
.getName() << "_INC\n";
185 OS
<< "#define LLVM_" << DirLang
.getName() << "_INC\n";
187 if (DirLang
.hasEnableBitmaskEnumInNamespace())
188 OS
<< "\n#include \"llvm/ADT/BitmaskEnum.h\"\n";
191 OS
<< "namespace llvm {\n";
192 OS
<< "class StringRef;\n";
194 // Open namespaces defined in the directive language
195 llvm::SmallVector
<StringRef
, 2> Namespaces
;
196 llvm::SplitString(DirLang
.getCppNamespace(), Namespaces
, "::");
197 for (auto Ns
: Namespaces
)
198 OS
<< "namespace " << Ns
<< " {\n";
200 if (DirLang
.hasEnableBitmaskEnumInNamespace())
201 OS
<< "\nLLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();\n";
203 // Emit Directive enumeration
204 GenerateEnumClass(DirLang
.getDirectives(), OS
, "Directive",
205 DirLang
.getDirectivePrefix(), DirLang
);
207 // Emit Clause enumeration
208 GenerateEnumClass(DirLang
.getClauses(), OS
, "Clause",
209 DirLang
.getClausePrefix(), DirLang
);
211 // Emit ClauseVal enumeration
212 std::string EnumHelperFuncs
;
213 GenerateEnumClauseVal(DirLang
.getClauses(), OS
, DirLang
, EnumHelperFuncs
);
215 // Generic function signatures
217 OS
<< "// Enumeration helper functions\n";
218 OS
<< "Directive get" << DirLang
.getName()
219 << "DirectiveKind(llvm::StringRef Str);\n";
221 OS
<< "llvm::StringRef get" << DirLang
.getName()
222 << "DirectiveName(Directive D);\n";
224 OS
<< "Clause get" << DirLang
.getName()
225 << "ClauseKind(llvm::StringRef Str);\n";
227 OS
<< "llvm::StringRef get" << DirLang
.getName() << "ClauseName(Clause C);\n";
229 OS
<< "/// Return true if \\p C is a valid clause for \\p D in version \\p "
231 OS
<< "bool isAllowedClauseForDirective(Directive D, "
232 << "Clause C, unsigned Version);\n";
234 if (EnumHelperFuncs
.length() > 0) {
235 OS
<< EnumHelperFuncs
;
239 // Closing namespaces
240 for (auto Ns
: llvm::reverse(Namespaces
))
241 OS
<< "} // namespace " << Ns
<< "\n";
243 OS
<< "} // namespace llvm\n";
245 OS
<< "#endif // LLVM_" << DirLang
.getName() << "_INC\n";
248 // Generate function implementation for get<Enum>Name(StringRef Str)
249 static void GenerateGetName(const std::vector
<Record
*> &Records
,
250 raw_ostream
&OS
, StringRef Enum
,
251 const DirectiveLanguage
&DirLang
,
254 OS
<< "llvm::StringRef llvm::" << DirLang
.getCppNamespace() << "::get"
255 << DirLang
.getName() << Enum
<< "Name(" << Enum
<< " Kind) {\n";
256 OS
<< " switch (Kind) {\n";
257 for (const auto &R
: Records
) {
259 OS
<< " case " << Prefix
<< Rec
.getFormattedName() << ":\n";
261 if (Rec
.getAlternativeName().empty())
264 OS
<< Rec
.getAlternativeName();
267 OS
<< " }\n"; // switch
268 OS
<< " llvm_unreachable(\"Invalid " << DirLang
.getName() << " " << Enum
273 // Generate function implementation for get<Enum>Kind(StringRef Str)
274 static void GenerateGetKind(const std::vector
<Record
*> &Records
,
275 raw_ostream
&OS
, StringRef Enum
,
276 const DirectiveLanguage
&DirLang
, StringRef Prefix
,
277 bool ImplicitAsUnknown
) {
279 auto DefaultIt
= llvm::find_if(
280 Records
, [](Record
*R
) { return R
->getValueAsBit("isDefault") == true; });
282 if (DefaultIt
== Records
.end()) {
283 PrintError("At least one " + Enum
+ " must be defined as default.");
287 BaseRecord DefaultRec
{(*DefaultIt
)};
290 OS
<< Enum
<< " llvm::" << DirLang
.getCppNamespace() << "::get"
291 << DirLang
.getName() << Enum
<< "Kind(llvm::StringRef Str) {\n";
292 OS
<< " return llvm::StringSwitch<" << Enum
<< ">(Str)\n";
294 for (const auto &R
: Records
) {
296 if (ImplicitAsUnknown
&& R
->getValueAsBit("isImplicit")) {
297 OS
<< " .Case(\"" << Rec
.getName() << "\"," << Prefix
298 << DefaultRec
.getFormattedName() << ")\n";
300 OS
<< " .Case(\"" << Rec
.getName() << "\"," << Prefix
301 << Rec
.getFormattedName() << ")\n";
304 OS
<< " .Default(" << Prefix
<< DefaultRec
.getFormattedName() << ");\n";
308 // Generate function implementation for get<ClauseVal>Kind(StringRef Str)
309 static void GenerateGetKindClauseVal(const DirectiveLanguage
&DirLang
,
311 for (const auto &R
: DirLang
.getClauses()) {
313 const auto &ClauseVals
= C
.getClauseVals();
314 if (ClauseVals
.size() <= 0)
317 auto DefaultIt
= llvm::find_if(ClauseVals
, [](Record
*CV
) {
318 return CV
->getValueAsBit("isDefault") == true;
321 if (DefaultIt
== ClauseVals
.end()) {
322 PrintError("At least one val in Clause " + C
.getFormattedName() +
323 " must be defined as default.");
326 const auto DefaultName
= (*DefaultIt
)->getName();
328 const auto &EnumName
= C
.getEnumName();
329 if (EnumName
.size() == 0) {
330 PrintError("enumClauseValue field not set in Clause" +
331 C
.getFormattedName() + ".");
336 OS
<< EnumName
<< " llvm::" << DirLang
.getCppNamespace() << "::get"
337 << EnumName
<< "(llvm::StringRef Str) {\n";
338 OS
<< " return llvm::StringSwitch<" << EnumName
<< ">(Str)\n";
339 for (const auto &CV
: ClauseVals
) {
341 OS
<< " .Case(\"" << CVal
.getFormattedName() << "\"," << CV
->getName()
344 OS
<< " .Default(" << DefaultName
<< ");\n";
348 OS
<< "llvm::StringRef llvm::" << DirLang
.getCppNamespace() << "::get"
349 << DirLang
.getName() << EnumName
350 << "Name(llvm::" << DirLang
.getCppNamespace() << "::" << EnumName
352 OS
<< " switch (x) {\n";
353 for (const auto &CV
: ClauseVals
) {
355 OS
<< " case " << CV
->getName() << ":\n";
356 OS
<< " return \"" << CVal
.getFormattedName() << "\";\n";
358 OS
<< " }\n"; // switch
359 OS
<< " llvm_unreachable(\"Invalid " << DirLang
.getName() << " "
360 << EnumName
<< " kind\");\n";
366 GenerateCaseForVersionedClauses(const std::vector
<Record
*> &Clauses
,
367 raw_ostream
&OS
, StringRef DirectiveName
,
368 const DirectiveLanguage
&DirLang
,
369 llvm::StringSet
<> &Cases
) {
370 for (const auto &C
: Clauses
) {
371 VersionedClause VerClause
{C
};
373 const auto ClauseFormattedName
= VerClause
.getClause().getFormattedName();
375 if (Cases
.insert(ClauseFormattedName
).second
) {
376 OS
<< " case " << DirLang
.getClausePrefix() << ClauseFormattedName
378 OS
<< " return " << VerClause
.getMinVersion()
379 << " <= Version && " << VerClause
.getMaxVersion() << " >= Version;\n";
384 // Generate the isAllowedClauseForDirective function implementation.
385 static void GenerateIsAllowedClause(const DirectiveLanguage
&DirLang
,
388 OS
<< "bool llvm::" << DirLang
.getCppNamespace()
389 << "::isAllowedClauseForDirective("
390 << "Directive D, Clause C, unsigned Version) {\n";
391 OS
<< " assert(unsigned(D) <= llvm::" << DirLang
.getCppNamespace()
392 << "::Directive_enumSize);\n";
393 OS
<< " assert(unsigned(C) <= llvm::" << DirLang
.getCppNamespace()
394 << "::Clause_enumSize);\n";
396 OS
<< " switch (D) {\n";
398 for (const auto &D
: DirLang
.getDirectives()) {
401 OS
<< " case " << DirLang
.getDirectivePrefix() << Dir
.getFormattedName()
403 if (Dir
.getAllowedClauses().size() == 0 &&
404 Dir
.getAllowedOnceClauses().size() == 0 &&
405 Dir
.getAllowedExclusiveClauses().size() == 0 &&
406 Dir
.getRequiredClauses().size() == 0) {
407 OS
<< " return false;\n";
409 OS
<< " switch (C) {\n";
411 llvm::StringSet
<> Cases
;
413 GenerateCaseForVersionedClauses(Dir
.getAllowedClauses(), OS
,
414 Dir
.getName(), DirLang
, Cases
);
416 GenerateCaseForVersionedClauses(Dir
.getAllowedOnceClauses(), OS
,
417 Dir
.getName(), DirLang
, Cases
);
419 GenerateCaseForVersionedClauses(Dir
.getAllowedExclusiveClauses(), OS
,
420 Dir
.getName(), DirLang
, Cases
);
422 GenerateCaseForVersionedClauses(Dir
.getRequiredClauses(), OS
,
423 Dir
.getName(), DirLang
, Cases
);
426 OS
<< " return false;\n";
427 OS
<< " }\n"; // End of clauses switch
432 OS
<< " }\n"; // End of directives switch
433 OS
<< " llvm_unreachable(\"Invalid " << DirLang
.getName()
434 << " Directive kind\");\n";
435 OS
<< "}\n"; // End of function isAllowedClauseForDirective
438 // Generate a simple enum set with the give clauses.
439 static void GenerateClauseSet(const std::vector
<Record
*> &Clauses
,
440 raw_ostream
&OS
, StringRef ClauseSetPrefix
,
442 const DirectiveLanguage
&DirLang
) {
445 OS
<< " static " << DirLang
.getClauseEnumSetClass() << " " << ClauseSetPrefix
446 << DirLang
.getDirectivePrefix() << Dir
.getFormattedName() << " {\n";
448 for (const auto &C
: Clauses
) {
449 VersionedClause VerClause
{C
};
450 OS
<< " llvm::" << DirLang
.getCppNamespace()
451 << "::Clause::" << DirLang
.getClausePrefix()
452 << VerClause
.getClause().getFormattedName() << ",\n";
457 // Generate an enum set for the 4 kinds of clauses linked to a directive.
458 static void GenerateDirectiveClauseSets(const DirectiveLanguage
&DirLang
,
461 IfDefScope
Scope("GEN_FLANG_DIRECTIVE_CLAUSE_SETS", OS
);
464 OS
<< "namespace llvm {\n";
466 // Open namespaces defined in the directive language.
467 llvm::SmallVector
<StringRef
, 2> Namespaces
;
468 llvm::SplitString(DirLang
.getCppNamespace(), Namespaces
, "::");
469 for (auto Ns
: Namespaces
)
470 OS
<< "namespace " << Ns
<< " {\n";
472 for (const auto &D
: DirLang
.getDirectives()) {
476 OS
<< " // Sets for " << Dir
.getName() << "\n";
478 GenerateClauseSet(Dir
.getAllowedClauses(), OS
, "allowedClauses_", Dir
,
480 GenerateClauseSet(Dir
.getAllowedOnceClauses(), OS
, "allowedOnceClauses_",
482 GenerateClauseSet(Dir
.getAllowedExclusiveClauses(), OS
,
483 "allowedExclusiveClauses_", Dir
, DirLang
);
484 GenerateClauseSet(Dir
.getRequiredClauses(), OS
, "requiredClauses_", Dir
,
488 // Closing namespaces
489 for (auto Ns
: llvm::reverse(Namespaces
))
490 OS
<< "} // namespace " << Ns
<< "\n";
492 OS
<< "} // namespace llvm\n";
495 // Generate a map of directive (key) with DirectiveClauses struct as values.
496 // The struct holds the 4 sets of enumeration for the 4 kinds of clauses
497 // allowances (allowed, allowed once, allowed exclusive and required).
498 static void GenerateDirectiveClauseMap(const DirectiveLanguage
&DirLang
,
501 IfDefScope
Scope("GEN_FLANG_DIRECTIVE_CLAUSE_MAP", OS
);
506 for (const auto &D
: DirLang
.getDirectives()) {
508 OS
<< " {llvm::" << DirLang
.getCppNamespace()
509 << "::Directive::" << DirLang
.getDirectivePrefix()
510 << Dir
.getFormattedName() << ",\n";
512 OS
<< " llvm::" << DirLang
.getCppNamespace() << "::allowedClauses_"
513 << DirLang
.getDirectivePrefix() << Dir
.getFormattedName() << ",\n";
514 OS
<< " llvm::" << DirLang
.getCppNamespace() << "::allowedOnceClauses_"
515 << DirLang
.getDirectivePrefix() << Dir
.getFormattedName() << ",\n";
516 OS
<< " llvm::" << DirLang
.getCppNamespace()
517 << "::allowedExclusiveClauses_" << DirLang
.getDirectivePrefix()
518 << Dir
.getFormattedName() << ",\n";
519 OS
<< " llvm::" << DirLang
.getCppNamespace() << "::requiredClauses_"
520 << DirLang
.getDirectivePrefix() << Dir
.getFormattedName() << ",\n";
528 // Generate classes entry for Flang clauses in the Flang parse-tree
529 // If the clause as a non-generic class, no entry is generated.
530 // If the clause does not hold a value, an EMPTY_CLASS is used.
531 // If the clause class is generic then a WRAPPER_CLASS is used. When the value
532 // is optional, the value class is wrapped into a std::optional.
533 static void GenerateFlangClauseParserClass(const DirectiveLanguage
&DirLang
,
536 IfDefScope
Scope("GEN_FLANG_CLAUSE_PARSER_CLASSES", OS
);
540 for (const auto &C
: DirLang
.getClauses()) {
542 if (!Clause
.getFlangClass().empty()) {
543 OS
<< "WRAPPER_CLASS(" << Clause
.getFormattedParserClassName() << ", ";
544 if (Clause
.isValueOptional() && Clause
.isValueList()) {
545 OS
<< "std::optional<std::list<" << Clause
.getFlangClass() << ">>";
546 } else if (Clause
.isValueOptional()) {
547 OS
<< "std::optional<" << Clause
.getFlangClass() << ">";
548 } else if (Clause
.isValueList()) {
549 OS
<< "std::list<" << Clause
.getFlangClass() << ">";
551 OS
<< Clause
.getFlangClass();
554 OS
<< "EMPTY_CLASS(" << Clause
.getFormattedParserClassName();
560 // Generate a list of the different clause classes for Flang.
561 static void GenerateFlangClauseParserClassList(const DirectiveLanguage
&DirLang
,
564 IfDefScope
Scope("GEN_FLANG_CLAUSE_PARSER_CLASSES_LIST", OS
);
567 llvm::interleaveComma(DirLang
.getClauses(), OS
, [&](Record
*C
) {
569 OS
<< Clause
.getFormattedParserClassName() << "\n";
573 // Generate dump node list for the clauses holding a generic class name.
574 static void GenerateFlangClauseDump(const DirectiveLanguage
&DirLang
,
577 IfDefScope
Scope("GEN_FLANG_DUMP_PARSE_TREE_CLAUSES", OS
);
580 for (const auto &C
: DirLang
.getClauses()) {
582 OS
<< "NODE(" << DirLang
.getFlangClauseBaseClass() << ", "
583 << Clause
.getFormattedParserClassName() << ")\n";
587 // Generate Unparse functions for clauses classes in the Flang parse-tree
588 // If the clause is a non-generic class, no entry is generated.
589 static void GenerateFlangClauseUnparse(const DirectiveLanguage
&DirLang
,
592 IfDefScope
Scope("GEN_FLANG_CLAUSE_UNPARSE", OS
);
596 for (const auto &C
: DirLang
.getClauses()) {
598 if (!Clause
.getFlangClass().empty()) {
599 if (Clause
.isValueOptional() && Clause
.getDefaultValue().empty()) {
600 OS
<< "void Unparse(const " << DirLang
.getFlangClauseBaseClass()
601 << "::" << Clause
.getFormattedParserClassName() << " &x) {\n";
602 OS
<< " Word(\"" << Clause
.getName().upper() << "\");\n";
604 OS
<< " Walk(\"(\", x.v, \")\");\n";
606 } else if (Clause
.isValueOptional()) {
607 OS
<< "void Unparse(const " << DirLang
.getFlangClauseBaseClass()
608 << "::" << Clause
.getFormattedParserClassName() << " &x) {\n";
609 OS
<< " Word(\"" << Clause
.getName().upper() << "\");\n";
610 OS
<< " Put(\"(\");\n";
611 OS
<< " if (x.v.has_value())\n";
612 if (Clause
.isValueList())
613 OS
<< " Walk(x.v, \",\");\n";
615 OS
<< " Walk(x.v);\n";
617 OS
<< " Put(\"" << Clause
.getDefaultValue() << "\");\n";
618 OS
<< " Put(\")\");\n";
621 OS
<< "void Unparse(const " << DirLang
.getFlangClauseBaseClass()
622 << "::" << Clause
.getFormattedParserClassName() << " &x) {\n";
623 OS
<< " Word(\"" << Clause
.getName().upper() << "\");\n";
624 OS
<< " Put(\"(\");\n";
625 if (Clause
.isValueList())
626 OS
<< " Walk(x.v, \",\");\n";
628 OS
<< " Walk(x.v);\n";
629 OS
<< " Put(\")\");\n";
633 OS
<< "void Before(const " << DirLang
.getFlangClauseBaseClass()
634 << "::" << Clause
.getFormattedParserClassName() << " &) { Word(\""
635 << Clause
.getName().upper() << "\"); }\n";
640 // Generate check in the Enter functions for clauses classes.
641 static void GenerateFlangClauseCheckPrototypes(const DirectiveLanguage
&DirLang
,
644 IfDefScope
Scope("GEN_FLANG_CLAUSE_CHECK_ENTER", OS
);
647 for (const auto &C
: DirLang
.getClauses()) {
649 OS
<< "void Enter(const parser::" << DirLang
.getFlangClauseBaseClass()
650 << "::" << Clause
.getFormattedParserClassName() << " &);\n";
654 // Generate the mapping for clauses between the parser class and the
655 // corresponding clause Kind
656 static void GenerateFlangClauseParserKindMap(const DirectiveLanguage
&DirLang
,
659 IfDefScope
Scope("GEN_FLANG_CLAUSE_PARSER_KIND_MAP", OS
);
662 for (const auto &C
: DirLang
.getClauses()) {
664 OS
<< "if constexpr (std::is_same_v<A, parser::"
665 << DirLang
.getFlangClauseBaseClass()
666 << "::" << Clause
.getFormattedParserClassName();
668 OS
<< " return llvm::" << DirLang
.getCppNamespace()
669 << "::Clause::" << DirLang
.getClausePrefix() << Clause
.getFormattedName()
673 OS
<< "llvm_unreachable(\"Invalid " << DirLang
.getName()
674 << " Parser clause\");\n";
677 static bool compareClauseName(Record
*R1
, Record
*R2
) {
680 return (C1
.getName() > C2
.getName());
683 // Generate the parser for the clauses.
684 static void GenerateFlangClausesParser(const DirectiveLanguage
&DirLang
,
686 std::vector
<Record
*> Clauses
= DirLang
.getClauses();
687 // Sort clauses in reverse alphabetical order so with clauses with same
688 // beginning, the longer option is tried before.
689 llvm::sort(Clauses
, compareClauseName
);
690 IfDefScope
Scope("GEN_FLANG_CLAUSES_PARSER", OS
);
693 unsigned lastClauseIndex
= DirLang
.getClauses().size() - 1;
694 OS
<< "TYPE_PARSER(\n";
695 for (const auto &C
: Clauses
) {
697 if (Clause
.getAliases().empty()) {
698 OS
<< " \"" << Clause
.getName() << "\"";
701 << "\"" << Clause
.getName() << "\"_tok";
702 for (StringRef alias
: Clause
.getAliases()) {
703 OS
<< " || \"" << alias
<< "\"_tok";
708 OS
<< " >> construct<" << DirLang
.getFlangClauseBaseClass()
709 << ">(construct<" << DirLang
.getFlangClauseBaseClass()
710 << "::" << Clause
.getFormattedParserClassName() << ">(";
711 if (Clause
.getFlangClass().empty()) {
713 if (index
!= lastClauseIndex
)
720 if (Clause
.isValueOptional())
722 OS
<< "parenthesized(";
723 if (Clause
.isValueList())
724 OS
<< "nonemptyList(";
726 if (!Clause
.getPrefix().empty())
727 OS
<< "\"" << Clause
.getPrefix() << ":\" >> ";
729 // The common Flang parser are used directly. Their name is identical to
730 // the Flang class with first letter as lowercase. If the Flang class is
731 // not a common class, we assume there is a specific Parser<>{} with the
732 // Flang class name provided.
733 llvm::SmallString
<128> Scratch
;
735 llvm::StringSwitch
<StringRef
>(Clause
.getFlangClass())
736 .Case("Name", "name")
737 .Case("ScalarIntConstantExpr", "scalarIntConstantExpr")
738 .Case("ScalarIntExpr", "scalarIntExpr")
739 .Case("ScalarExpr", "scalarExpr")
740 .Case("ScalarLogicalExpr", "scalarLogicalExpr")
741 .Default(("Parser<" + Clause
.getFlangClass() + ">{}")
742 .toStringRef(Scratch
));
744 if (!Clause
.getPrefix().empty() && Clause
.isPrefixOptional())
745 OS
<< " || " << Parser
;
746 if (Clause
.isValueList()) // close nonemptyList(.
748 OS
<< ")"; // close parenthesized(.
750 if (Clause
.isValueOptional()) // close maybe(.
753 if (index
!= lastClauseIndex
)
761 // Generate the implementation section for the enumeration in the directive
763 static void EmitDirectivesFlangImpl(const DirectiveLanguage
&DirLang
,
766 GenerateDirectiveClauseSets(DirLang
, OS
);
768 GenerateDirectiveClauseMap(DirLang
, OS
);
770 GenerateFlangClauseParserClass(DirLang
, OS
);
772 GenerateFlangClauseParserClassList(DirLang
, OS
);
774 GenerateFlangClauseDump(DirLang
, OS
);
776 GenerateFlangClauseUnparse(DirLang
, OS
);
778 GenerateFlangClauseCheckPrototypes(DirLang
, OS
);
780 GenerateFlangClauseParserKindMap(DirLang
, OS
);
782 GenerateFlangClausesParser(DirLang
, OS
);
785 static void GenerateClauseClassMacro(const DirectiveLanguage
&DirLang
,
787 // Generate macros style information for legacy code in clang
788 IfDefScope
Scope("GEN_CLANG_CLAUSE_CLASS", OS
);
792 OS
<< "#ifndef CLAUSE\n";
793 OS
<< "#define CLAUSE(Enum, Str, Implicit)\n";
795 OS
<< "#ifndef CLAUSE_CLASS\n";
796 OS
<< "#define CLAUSE_CLASS(Enum, Str, Class)\n";
798 OS
<< "#ifndef CLAUSE_NO_CLASS\n";
799 OS
<< "#define CLAUSE_NO_CLASS(Enum, Str)\n";
802 OS
<< "#define __CLAUSE(Name, Class) \\\n";
803 OS
<< " CLAUSE(" << DirLang
.getClausePrefix()
804 << "##Name, #Name, /* Implicit */ false) \\\n";
805 OS
<< " CLAUSE_CLASS(" << DirLang
.getClausePrefix()
806 << "##Name, #Name, Class)\n";
807 OS
<< "#define __CLAUSE_NO_CLASS(Name) \\\n";
808 OS
<< " CLAUSE(" << DirLang
.getClausePrefix()
809 << "##Name, #Name, /* Implicit */ false) \\\n";
810 OS
<< " CLAUSE_NO_CLASS(" << DirLang
.getClausePrefix() << "##Name, #Name)\n";
811 OS
<< "#define __IMPLICIT_CLAUSE_CLASS(Name, Str, Class) \\\n";
812 OS
<< " CLAUSE(" << DirLang
.getClausePrefix()
813 << "##Name, Str, /* Implicit */ true) \\\n";
814 OS
<< " CLAUSE_CLASS(" << DirLang
.getClausePrefix()
815 << "##Name, Str, Class)\n";
816 OS
<< "#define __IMPLICIT_CLAUSE_NO_CLASS(Name, Str) \\\n";
817 OS
<< " CLAUSE(" << DirLang
.getClausePrefix()
818 << "##Name, Str, /* Implicit */ true) \\\n";
819 OS
<< " CLAUSE_NO_CLASS(" << DirLang
.getClausePrefix() << "##Name, Str)\n";
822 for (const auto &R
: DirLang
.getClauses()) {
824 if (C
.getClangClass().empty()) { // NO_CLASS
825 if (C
.isImplicit()) {
826 OS
<< "__IMPLICIT_CLAUSE_NO_CLASS(" << C
.getFormattedName() << ", \""
827 << C
.getFormattedName() << "\")\n";
829 OS
<< "__CLAUSE_NO_CLASS(" << C
.getFormattedName() << ")\n";
832 if (C
.isImplicit()) {
833 OS
<< "__IMPLICIT_CLAUSE_CLASS(" << C
.getFormattedName() << ", \""
834 << C
.getFormattedName() << "\", " << C
.getClangClass() << ")\n";
836 OS
<< "__CLAUSE(" << C
.getFormattedName() << ", " << C
.getClangClass()
843 OS
<< "#undef __IMPLICIT_CLAUSE_NO_CLASS\n";
844 OS
<< "#undef __IMPLICIT_CLAUSE_CLASS\n";
845 OS
<< "#undef __CLAUSE\n";
846 OS
<< "#undef CLAUSE_NO_CLASS\n";
847 OS
<< "#undef CLAUSE_CLASS\n";
848 OS
<< "#undef CLAUSE\n";
851 // Generate the implemenation for the enumeration in the directive
852 // language. This code can be included in library.
853 void EmitDirectivesBasicImpl(const DirectiveLanguage
&DirLang
,
855 IfDefScope
Scope("GEN_DIRECTIVES_IMPL", OS
);
857 // getDirectiveKind(StringRef Str)
858 GenerateGetKind(DirLang
.getDirectives(), OS
, "Directive", DirLang
,
859 DirLang
.getDirectivePrefix(), /*ImplicitAsUnknown=*/false);
861 // getDirectiveName(Directive Kind)
862 GenerateGetName(DirLang
.getDirectives(), OS
, "Directive", DirLang
,
863 DirLang
.getDirectivePrefix());
865 // getClauseKind(StringRef Str)
866 GenerateGetKind(DirLang
.getClauses(), OS
, "Clause", DirLang
,
867 DirLang
.getClausePrefix(),
868 /*ImplicitAsUnknown=*/true);
870 // getClauseName(Clause Kind)
871 GenerateGetName(DirLang
.getClauses(), OS
, "Clause", DirLang
,
872 DirLang
.getClausePrefix());
874 // get<ClauseVal>Kind(StringRef Str)
875 GenerateGetKindClauseVal(DirLang
, OS
);
877 // isAllowedClauseForDirective(Directive D, Clause C, unsigned Version)
878 GenerateIsAllowedClause(DirLang
, OS
);
881 // Generate the implemenation section for the enumeration in the directive
883 static void EmitDirectivesImpl(RecordKeeper
&Records
, raw_ostream
&OS
) {
884 const auto DirLang
= DirectiveLanguage
{Records
};
885 if (DirLang
.HasValidityErrors())
888 EmitDirectivesFlangImpl(DirLang
, OS
);
890 GenerateClauseClassMacro(DirLang
, OS
);
892 EmitDirectivesBasicImpl(DirLang
, OS
);
895 static TableGen::Emitter::Opt
896 X("gen-directive-decl", EmitDirectivesDecl
,
897 "Generate directive related declaration code (header file)");
899 static TableGen::Emitter::Opt
900 Y("gen-directive-impl", EmitDirectivesImpl
,
901 "Generate directive related implementation code");