xref: /freebsd-src/contrib/llvm-project/llvm/utils/TableGen/DirectiveEmitter.cpp (revision 5ffd83dbcc34f10e07f6d3e968ae6365869615f4)
1*5ffd83dbSDimitry Andric //===- DirectiveEmitter.cpp - Directive Language Emitter ------------------===//
2*5ffd83dbSDimitry Andric //
3*5ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*5ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*5ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*5ffd83dbSDimitry Andric //
7*5ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
8*5ffd83dbSDimitry Andric //
9*5ffd83dbSDimitry Andric // DirectiveEmitter uses the descriptions of directives and clauses to construct
10*5ffd83dbSDimitry Andric // common code declarations to be used in Frontends.
11*5ffd83dbSDimitry Andric //
12*5ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
13*5ffd83dbSDimitry Andric 
14*5ffd83dbSDimitry Andric #include "llvm/ADT/STLExtras.h"
15*5ffd83dbSDimitry Andric #include "llvm/ADT/SmallVector.h"
16*5ffd83dbSDimitry Andric #include "llvm/ADT/StringExtras.h"
17*5ffd83dbSDimitry Andric #include "llvm/ADT/StringSet.h"
18*5ffd83dbSDimitry Andric #include "llvm/TableGen/Error.h"
19*5ffd83dbSDimitry Andric #include "llvm/TableGen/Record.h"
20*5ffd83dbSDimitry Andric #include "llvm/TableGen/TableGenBackend.h"
21*5ffd83dbSDimitry Andric 
22*5ffd83dbSDimitry Andric using namespace llvm;
23*5ffd83dbSDimitry Andric 
24*5ffd83dbSDimitry Andric namespace {
25*5ffd83dbSDimitry Andric // Simple RAII helper for defining ifdef-undef-endif scopes.
26*5ffd83dbSDimitry Andric class IfDefScope {
27*5ffd83dbSDimitry Andric public:
28*5ffd83dbSDimitry Andric   IfDefScope(StringRef Name, raw_ostream &OS) : Name(Name), OS(OS) {
29*5ffd83dbSDimitry Andric     OS << "#ifdef " << Name << "\n"
30*5ffd83dbSDimitry Andric        << "#undef " << Name << "\n";
31*5ffd83dbSDimitry Andric   }
32*5ffd83dbSDimitry Andric 
33*5ffd83dbSDimitry Andric   ~IfDefScope() { OS << "\n#endif // " << Name << "\n\n"; }
34*5ffd83dbSDimitry Andric 
35*5ffd83dbSDimitry Andric private:
36*5ffd83dbSDimitry Andric   StringRef Name;
37*5ffd83dbSDimitry Andric   raw_ostream &OS;
38*5ffd83dbSDimitry Andric };
39*5ffd83dbSDimitry Andric } // end anonymous namespace
40*5ffd83dbSDimitry Andric 
41*5ffd83dbSDimitry Andric namespace llvm {
42*5ffd83dbSDimitry Andric 
43*5ffd83dbSDimitry Andric // Get Directive or Clause name formatted by replacing whitespaces with
44*5ffd83dbSDimitry Andric // underscores.
45*5ffd83dbSDimitry Andric std::string getFormattedName(StringRef Name) {
46*5ffd83dbSDimitry Andric   std::string N = Name.str();
47*5ffd83dbSDimitry Andric   std::replace(N.begin(), N.end(), ' ', '_');
48*5ffd83dbSDimitry Andric   return N;
49*5ffd83dbSDimitry Andric }
50*5ffd83dbSDimitry Andric 
51*5ffd83dbSDimitry Andric // Generate enum class
52*5ffd83dbSDimitry Andric void GenerateEnumClass(const std::vector<Record *> &Records, raw_ostream &OS,
53*5ffd83dbSDimitry Andric                        StringRef Enum, StringRef Prefix, StringRef CppNamespace,
54*5ffd83dbSDimitry Andric                        bool MakeEnumAvailableInNamespace) {
55*5ffd83dbSDimitry Andric   OS << "\n";
56*5ffd83dbSDimitry Andric   OS << "enum class " << Enum << " {\n";
57*5ffd83dbSDimitry Andric   for (const auto &R : Records) {
58*5ffd83dbSDimitry Andric     const auto Name = R->getValueAsString("name");
59*5ffd83dbSDimitry Andric     OS << "  " << Prefix << getFormattedName(Name) << ",\n";
60*5ffd83dbSDimitry Andric   }
61*5ffd83dbSDimitry Andric   OS << "};\n";
62*5ffd83dbSDimitry Andric   OS << "\n";
63*5ffd83dbSDimitry Andric   OS << "static constexpr std::size_t " << Enum
64*5ffd83dbSDimitry Andric      << "_enumSize = " << Records.size() << ";\n";
65*5ffd83dbSDimitry Andric 
66*5ffd83dbSDimitry Andric   // Make the enum values available in the defined namespace. This allows us to
67*5ffd83dbSDimitry Andric   // write something like Enum_X if we have a `using namespace <CppNamespace>`.
68*5ffd83dbSDimitry Andric   // At the same time we do not loose the strong type guarantees of the enum
69*5ffd83dbSDimitry Andric   // class, that is we cannot pass an unsigned as Directive without an explicit
70*5ffd83dbSDimitry Andric   // cast.
71*5ffd83dbSDimitry Andric   if (MakeEnumAvailableInNamespace) {
72*5ffd83dbSDimitry Andric     OS << "\n";
73*5ffd83dbSDimitry Andric     for (const auto &R : Records) {
74*5ffd83dbSDimitry Andric       const auto FormattedName = getFormattedName(R->getValueAsString("name"));
75*5ffd83dbSDimitry Andric       OS << "constexpr auto " << Prefix << FormattedName << " = "
76*5ffd83dbSDimitry Andric          << "llvm::" << CppNamespace << "::" << Enum << "::" << Prefix
77*5ffd83dbSDimitry Andric          << FormattedName << ";\n";
78*5ffd83dbSDimitry Andric     }
79*5ffd83dbSDimitry Andric   }
80*5ffd83dbSDimitry Andric }
81*5ffd83dbSDimitry Andric 
82*5ffd83dbSDimitry Andric // Generate the declaration section for the enumeration in the directive
83*5ffd83dbSDimitry Andric // language
84*5ffd83dbSDimitry Andric void EmitDirectivesDecl(RecordKeeper &Records, raw_ostream &OS) {
85*5ffd83dbSDimitry Andric 
86*5ffd83dbSDimitry Andric   const auto &DirectiveLanguages =
87*5ffd83dbSDimitry Andric       Records.getAllDerivedDefinitions("DirectiveLanguage");
88*5ffd83dbSDimitry Andric 
89*5ffd83dbSDimitry Andric   if (DirectiveLanguages.size() != 1) {
90*5ffd83dbSDimitry Andric     PrintError("A single definition of DirectiveLanguage is needed.");
91*5ffd83dbSDimitry Andric     return;
92*5ffd83dbSDimitry Andric   }
93*5ffd83dbSDimitry Andric 
94*5ffd83dbSDimitry Andric   const auto &DirectiveLanguage = DirectiveLanguages[0];
95*5ffd83dbSDimitry Andric   StringRef LanguageName = DirectiveLanguage->getValueAsString("name");
96*5ffd83dbSDimitry Andric   StringRef DirectivePrefix =
97*5ffd83dbSDimitry Andric       DirectiveLanguage->getValueAsString("directivePrefix");
98*5ffd83dbSDimitry Andric   StringRef ClausePrefix = DirectiveLanguage->getValueAsString("clausePrefix");
99*5ffd83dbSDimitry Andric   StringRef CppNamespace = DirectiveLanguage->getValueAsString("cppNamespace");
100*5ffd83dbSDimitry Andric   bool MakeEnumAvailableInNamespace =
101*5ffd83dbSDimitry Andric       DirectiveLanguage->getValueAsBit("makeEnumAvailableInNamespace");
102*5ffd83dbSDimitry Andric   bool EnableBitmaskEnumInNamespace =
103*5ffd83dbSDimitry Andric       DirectiveLanguage->getValueAsBit("enableBitmaskEnumInNamespace");
104*5ffd83dbSDimitry Andric 
105*5ffd83dbSDimitry Andric   OS << "#ifndef LLVM_" << LanguageName << "_INC\n";
106*5ffd83dbSDimitry Andric   OS << "#define LLVM_" << LanguageName << "_INC\n";
107*5ffd83dbSDimitry Andric 
108*5ffd83dbSDimitry Andric   if (EnableBitmaskEnumInNamespace)
109*5ffd83dbSDimitry Andric     OS << "\n#include \"llvm/ADT/BitmaskEnum.h\"\n";
110*5ffd83dbSDimitry Andric 
111*5ffd83dbSDimitry Andric   OS << "\n";
112*5ffd83dbSDimitry Andric   OS << "namespace llvm {\n";
113*5ffd83dbSDimitry Andric   OS << "class StringRef;\n";
114*5ffd83dbSDimitry Andric 
115*5ffd83dbSDimitry Andric   // Open namespaces defined in the directive language
116*5ffd83dbSDimitry Andric   llvm::SmallVector<StringRef, 2> Namespaces;
117*5ffd83dbSDimitry Andric   llvm::SplitString(CppNamespace, Namespaces, "::");
118*5ffd83dbSDimitry Andric   for (auto Ns : Namespaces)
119*5ffd83dbSDimitry Andric     OS << "namespace " << Ns << " {\n";
120*5ffd83dbSDimitry Andric 
121*5ffd83dbSDimitry Andric   if (EnableBitmaskEnumInNamespace)
122*5ffd83dbSDimitry Andric     OS << "\nLLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();\n";
123*5ffd83dbSDimitry Andric 
124*5ffd83dbSDimitry Andric   // Emit Directive enumeration
125*5ffd83dbSDimitry Andric   const auto &Directives = Records.getAllDerivedDefinitions("Directive");
126*5ffd83dbSDimitry Andric   GenerateEnumClass(Directives, OS, "Directive", DirectivePrefix, CppNamespace,
127*5ffd83dbSDimitry Andric                     MakeEnumAvailableInNamespace);
128*5ffd83dbSDimitry Andric 
129*5ffd83dbSDimitry Andric   // Emit Clause enumeration
130*5ffd83dbSDimitry Andric   const auto &Clauses = Records.getAllDerivedDefinitions("Clause");
131*5ffd83dbSDimitry Andric   GenerateEnumClass(Clauses, OS, "Clause", ClausePrefix, CppNamespace,
132*5ffd83dbSDimitry Andric                     MakeEnumAvailableInNamespace);
133*5ffd83dbSDimitry Andric 
134*5ffd83dbSDimitry Andric   // Generic function signatures
135*5ffd83dbSDimitry Andric   OS << "\n";
136*5ffd83dbSDimitry Andric   OS << "// Enumeration helper functions\n";
137*5ffd83dbSDimitry Andric   OS << "Directive get" << LanguageName
138*5ffd83dbSDimitry Andric      << "DirectiveKind(llvm::StringRef Str);\n";
139*5ffd83dbSDimitry Andric   OS << "\n";
140*5ffd83dbSDimitry Andric   OS << "llvm::StringRef get" << LanguageName
141*5ffd83dbSDimitry Andric      << "DirectiveName(Directive D);\n";
142*5ffd83dbSDimitry Andric   OS << "\n";
143*5ffd83dbSDimitry Andric   OS << "Clause get" << LanguageName << "ClauseKind(llvm::StringRef Str);\n";
144*5ffd83dbSDimitry Andric   OS << "\n";
145*5ffd83dbSDimitry Andric   OS << "llvm::StringRef get" << LanguageName << "ClauseName(Clause C);\n";
146*5ffd83dbSDimitry Andric   OS << "\n";
147*5ffd83dbSDimitry Andric   OS << "/// Return true if \\p C is a valid clause for \\p D in version \\p "
148*5ffd83dbSDimitry Andric      << "Version.\n";
149*5ffd83dbSDimitry Andric   OS << "bool isAllowedClauseForDirective(Directive D, "
150*5ffd83dbSDimitry Andric      << "Clause C, unsigned Version);\n";
151*5ffd83dbSDimitry Andric   OS << "\n";
152*5ffd83dbSDimitry Andric 
153*5ffd83dbSDimitry Andric   // Closing namespaces
154*5ffd83dbSDimitry Andric   for (auto Ns : llvm::reverse(Namespaces))
155*5ffd83dbSDimitry Andric     OS << "} // namespace " << Ns << "\n";
156*5ffd83dbSDimitry Andric 
157*5ffd83dbSDimitry Andric   OS << "} // namespace llvm\n";
158*5ffd83dbSDimitry Andric 
159*5ffd83dbSDimitry Andric   OS << "#endif // LLVM_" << LanguageName << "_INC\n";
160*5ffd83dbSDimitry Andric }
161*5ffd83dbSDimitry Andric 
162*5ffd83dbSDimitry Andric // Generate function implementation for get<Enum>Name(StringRef Str)
163*5ffd83dbSDimitry Andric void GenerateGetName(const std::vector<Record *> &Records, raw_ostream &OS,
164*5ffd83dbSDimitry Andric                      StringRef Enum, StringRef Prefix, StringRef LanguageName,
165*5ffd83dbSDimitry Andric                      StringRef Namespace) {
166*5ffd83dbSDimitry Andric   OS << "\n";
167*5ffd83dbSDimitry Andric   OS << "llvm::StringRef llvm::" << Namespace << "::get" << LanguageName << Enum
168*5ffd83dbSDimitry Andric      << "Name(" << Enum << " Kind) {\n";
169*5ffd83dbSDimitry Andric   OS << "  switch (Kind) {\n";
170*5ffd83dbSDimitry Andric   for (const auto &R : Records) {
171*5ffd83dbSDimitry Andric     const auto Name = R->getValueAsString("name");
172*5ffd83dbSDimitry Andric     const auto AlternativeName = R->getValueAsString("alternativeName");
173*5ffd83dbSDimitry Andric     OS << "    case " << Prefix << getFormattedName(Name) << ":\n";
174*5ffd83dbSDimitry Andric     OS << "      return \"";
175*5ffd83dbSDimitry Andric     if (AlternativeName.empty())
176*5ffd83dbSDimitry Andric       OS << Name;
177*5ffd83dbSDimitry Andric     else
178*5ffd83dbSDimitry Andric       OS << AlternativeName;
179*5ffd83dbSDimitry Andric     OS << "\";\n";
180*5ffd83dbSDimitry Andric   }
181*5ffd83dbSDimitry Andric   OS << "  }\n"; // switch
182*5ffd83dbSDimitry Andric   OS << "  llvm_unreachable(\"Invalid " << LanguageName << " " << Enum
183*5ffd83dbSDimitry Andric      << " kind\");\n";
184*5ffd83dbSDimitry Andric   OS << "}\n";
185*5ffd83dbSDimitry Andric }
186*5ffd83dbSDimitry Andric 
187*5ffd83dbSDimitry Andric // Generate function implementation for get<Enum>Kind(StringRef Str)
188*5ffd83dbSDimitry Andric void GenerateGetKind(const std::vector<Record *> &Records, raw_ostream &OS,
189*5ffd83dbSDimitry Andric                      StringRef Enum, StringRef Prefix, StringRef LanguageName,
190*5ffd83dbSDimitry Andric                      StringRef Namespace, bool ImplicitAsUnknown) {
191*5ffd83dbSDimitry Andric 
192*5ffd83dbSDimitry Andric   auto DefaultIt = std::find_if(Records.begin(), Records.end(), [](Record *R) {
193*5ffd83dbSDimitry Andric     return R->getValueAsBit("isDefault") == true;
194*5ffd83dbSDimitry Andric   });
195*5ffd83dbSDimitry Andric 
196*5ffd83dbSDimitry Andric   if (DefaultIt == Records.end()) {
197*5ffd83dbSDimitry Andric     PrintError("A least one " + Enum + " must be defined as default.");
198*5ffd83dbSDimitry Andric     return;
199*5ffd83dbSDimitry Andric   }
200*5ffd83dbSDimitry Andric 
201*5ffd83dbSDimitry Andric   const auto FormattedDefaultName =
202*5ffd83dbSDimitry Andric       getFormattedName((*DefaultIt)->getValueAsString("name"));
203*5ffd83dbSDimitry Andric 
204*5ffd83dbSDimitry Andric   OS << "\n";
205*5ffd83dbSDimitry Andric   OS << Enum << " llvm::" << Namespace << "::get" << LanguageName << Enum
206*5ffd83dbSDimitry Andric      << "Kind(llvm::StringRef Str) {\n";
207*5ffd83dbSDimitry Andric   OS << "  return llvm::StringSwitch<" << Enum << ">(Str)\n";
208*5ffd83dbSDimitry Andric 
209*5ffd83dbSDimitry Andric   for (const auto &R : Records) {
210*5ffd83dbSDimitry Andric     const auto Name = R->getValueAsString("name");
211*5ffd83dbSDimitry Andric     if (ImplicitAsUnknown && R->getValueAsBit("isImplicit")) {
212*5ffd83dbSDimitry Andric       OS << "    .Case(\"" << Name << "\"," << Prefix << FormattedDefaultName
213*5ffd83dbSDimitry Andric          << ")\n";
214*5ffd83dbSDimitry Andric     } else {
215*5ffd83dbSDimitry Andric       OS << "    .Case(\"" << Name << "\"," << Prefix << getFormattedName(Name)
216*5ffd83dbSDimitry Andric          << ")\n";
217*5ffd83dbSDimitry Andric     }
218*5ffd83dbSDimitry Andric   }
219*5ffd83dbSDimitry Andric   OS << "    .Default(" << Prefix << FormattedDefaultName << ");\n";
220*5ffd83dbSDimitry Andric   OS << "}\n";
221*5ffd83dbSDimitry Andric }
222*5ffd83dbSDimitry Andric 
223*5ffd83dbSDimitry Andric void GenerateCaseForVersionedClauses(const std::vector<Record *> &Clauses,
224*5ffd83dbSDimitry Andric                                      raw_ostream &OS, StringRef DirectiveName,
225*5ffd83dbSDimitry Andric                                      StringRef DirectivePrefix,
226*5ffd83dbSDimitry Andric                                      StringRef ClausePrefix,
227*5ffd83dbSDimitry Andric                                      llvm::StringSet<> &Cases) {
228*5ffd83dbSDimitry Andric   for (const auto &C : Clauses) {
229*5ffd83dbSDimitry Andric     const auto MinVersion = C->getValueAsInt("minVersion");
230*5ffd83dbSDimitry Andric     const auto MaxVersion = C->getValueAsInt("maxVersion");
231*5ffd83dbSDimitry Andric     const auto SpecificClause = C->getValueAsDef("clause");
232*5ffd83dbSDimitry Andric     const auto ClauseName =
233*5ffd83dbSDimitry Andric         getFormattedName(SpecificClause->getValueAsString("name"));
234*5ffd83dbSDimitry Andric 
235*5ffd83dbSDimitry Andric     if (Cases.find(ClauseName) == Cases.end()) {
236*5ffd83dbSDimitry Andric       Cases.insert(ClauseName);
237*5ffd83dbSDimitry Andric       OS << "        case " << ClausePrefix << ClauseName << ":\n";
238*5ffd83dbSDimitry Andric       OS << "          return " << MinVersion << " <= Version && " << MaxVersion
239*5ffd83dbSDimitry Andric          << " >= Version;\n";
240*5ffd83dbSDimitry Andric     }
241*5ffd83dbSDimitry Andric   }
242*5ffd83dbSDimitry Andric }
243*5ffd83dbSDimitry Andric 
244*5ffd83dbSDimitry Andric // Generate the isAllowedClauseForDirective function implementation.
245*5ffd83dbSDimitry Andric void GenerateIsAllowedClause(const std::vector<Record *> &Directives,
246*5ffd83dbSDimitry Andric                              raw_ostream &OS, StringRef LanguageName,
247*5ffd83dbSDimitry Andric                              StringRef DirectivePrefix, StringRef ClausePrefix,
248*5ffd83dbSDimitry Andric                              StringRef CppNamespace) {
249*5ffd83dbSDimitry Andric   OS << "\n";
250*5ffd83dbSDimitry Andric   OS << "bool llvm::" << CppNamespace << "::isAllowedClauseForDirective("
251*5ffd83dbSDimitry Andric      << "Directive D, Clause C, unsigned Version) {\n";
252*5ffd83dbSDimitry Andric   OS << "  assert(unsigned(D) <= llvm::" << CppNamespace
253*5ffd83dbSDimitry Andric      << "::Directive_enumSize);\n";
254*5ffd83dbSDimitry Andric   OS << "  assert(unsigned(C) <= llvm::" << CppNamespace
255*5ffd83dbSDimitry Andric      << "::Clause_enumSize);\n";
256*5ffd83dbSDimitry Andric 
257*5ffd83dbSDimitry Andric   OS << "  switch (D) {\n";
258*5ffd83dbSDimitry Andric 
259*5ffd83dbSDimitry Andric   for (const auto &D : Directives) {
260*5ffd83dbSDimitry Andric 
261*5ffd83dbSDimitry Andric     const auto DirectiveName = D->getValueAsString("name");
262*5ffd83dbSDimitry Andric     const auto &AllowedClauses = D->getValueAsListOfDefs("allowedClauses");
263*5ffd83dbSDimitry Andric     const auto &AllowedOnceClauses =
264*5ffd83dbSDimitry Andric         D->getValueAsListOfDefs("allowedOnceClauses");
265*5ffd83dbSDimitry Andric     const auto &AllowedExclusiveClauses =
266*5ffd83dbSDimitry Andric         D->getValueAsListOfDefs("allowedExclusiveClauses");
267*5ffd83dbSDimitry Andric     const auto &RequiredClauses = D->getValueAsListOfDefs("requiredClauses");
268*5ffd83dbSDimitry Andric 
269*5ffd83dbSDimitry Andric     OS << "    case " << DirectivePrefix << getFormattedName(DirectiveName)
270*5ffd83dbSDimitry Andric        << ":\n";
271*5ffd83dbSDimitry Andric     if (AllowedClauses.size() == 0 && AllowedOnceClauses.size() == 0 &&
272*5ffd83dbSDimitry Andric         AllowedExclusiveClauses.size() == 0 && RequiredClauses.size() == 0) {
273*5ffd83dbSDimitry Andric       OS << "      return false;\n";
274*5ffd83dbSDimitry Andric     } else {
275*5ffd83dbSDimitry Andric       OS << "      switch (C) {\n";
276*5ffd83dbSDimitry Andric 
277*5ffd83dbSDimitry Andric       llvm::StringSet<> Cases;
278*5ffd83dbSDimitry Andric 
279*5ffd83dbSDimitry Andric       GenerateCaseForVersionedClauses(AllowedClauses, OS, DirectiveName,
280*5ffd83dbSDimitry Andric                                       DirectivePrefix, ClausePrefix, Cases);
281*5ffd83dbSDimitry Andric 
282*5ffd83dbSDimitry Andric       GenerateCaseForVersionedClauses(AllowedOnceClauses, OS, DirectiveName,
283*5ffd83dbSDimitry Andric                                       DirectivePrefix, ClausePrefix, Cases);
284*5ffd83dbSDimitry Andric 
285*5ffd83dbSDimitry Andric       GenerateCaseForVersionedClauses(AllowedExclusiveClauses, OS,
286*5ffd83dbSDimitry Andric                                       DirectiveName, DirectivePrefix,
287*5ffd83dbSDimitry Andric                                       ClausePrefix, Cases);
288*5ffd83dbSDimitry Andric 
289*5ffd83dbSDimitry Andric       GenerateCaseForVersionedClauses(RequiredClauses, OS, DirectiveName,
290*5ffd83dbSDimitry Andric                                       DirectivePrefix, ClausePrefix, Cases);
291*5ffd83dbSDimitry Andric 
292*5ffd83dbSDimitry Andric       OS << "        default:\n";
293*5ffd83dbSDimitry Andric       OS << "          return false;\n";
294*5ffd83dbSDimitry Andric       OS << "      }\n"; // End of clauses switch
295*5ffd83dbSDimitry Andric     }
296*5ffd83dbSDimitry Andric     OS << "      break;\n";
297*5ffd83dbSDimitry Andric   }
298*5ffd83dbSDimitry Andric 
299*5ffd83dbSDimitry Andric   OS << "  }\n"; // End of directives switch
300*5ffd83dbSDimitry Andric   OS << "  llvm_unreachable(\"Invalid " << LanguageName
301*5ffd83dbSDimitry Andric      << " Directive kind\");\n";
302*5ffd83dbSDimitry Andric   OS << "}\n"; // End of function isAllowedClauseForDirective
303*5ffd83dbSDimitry Andric }
304*5ffd83dbSDimitry Andric 
305*5ffd83dbSDimitry Andric // Generate a simple enum set with the give clauses.
306*5ffd83dbSDimitry Andric void GenerateClauseSet(const std::vector<Record *> &Clauses, raw_ostream &OS,
307*5ffd83dbSDimitry Andric                        StringRef ClauseEnumSetClass, StringRef ClauseSetPrefix,
308*5ffd83dbSDimitry Andric                        StringRef DirectiveName, StringRef DirectivePrefix,
309*5ffd83dbSDimitry Andric                        StringRef ClausePrefix, StringRef CppNamespace) {
310*5ffd83dbSDimitry Andric 
311*5ffd83dbSDimitry Andric   OS << "\n";
312*5ffd83dbSDimitry Andric   OS << "  static " << ClauseEnumSetClass << " " << ClauseSetPrefix
313*5ffd83dbSDimitry Andric      << DirectivePrefix << getFormattedName(DirectiveName) << " {\n";
314*5ffd83dbSDimitry Andric 
315*5ffd83dbSDimitry Andric   for (const auto &C : Clauses) {
316*5ffd83dbSDimitry Andric     const auto SpecificClause = C->getValueAsDef("clause");
317*5ffd83dbSDimitry Andric     const auto ClauseName = SpecificClause->getValueAsString("name");
318*5ffd83dbSDimitry Andric     OS << "    llvm::" << CppNamespace << "::Clause::" << ClausePrefix
319*5ffd83dbSDimitry Andric        << getFormattedName(ClauseName) << ",\n";
320*5ffd83dbSDimitry Andric   }
321*5ffd83dbSDimitry Andric   OS << "  };\n";
322*5ffd83dbSDimitry Andric }
323*5ffd83dbSDimitry Andric 
324*5ffd83dbSDimitry Andric // Generate an enum set for the 4 kinds of clauses linked to a directive.
325*5ffd83dbSDimitry Andric void GenerateDirectiveClauseSets(const std::vector<Record *> &Directives,
326*5ffd83dbSDimitry Andric                                  raw_ostream &OS, StringRef LanguageName,
327*5ffd83dbSDimitry Andric                                  StringRef ClauseEnumSetClass,
328*5ffd83dbSDimitry Andric                                  StringRef DirectivePrefix,
329*5ffd83dbSDimitry Andric                                  StringRef ClausePrefix,
330*5ffd83dbSDimitry Andric                                  StringRef CppNamespace) {
331*5ffd83dbSDimitry Andric 
332*5ffd83dbSDimitry Andric   IfDefScope Scope("GEN_FLANG_DIRECTIVE_CLAUSE_SETS", OS);
333*5ffd83dbSDimitry Andric 
334*5ffd83dbSDimitry Andric   OS << "\n";
335*5ffd83dbSDimitry Andric   OS << "namespace llvm {\n";
336*5ffd83dbSDimitry Andric 
337*5ffd83dbSDimitry Andric   // Open namespaces defined in the directive language.
338*5ffd83dbSDimitry Andric   llvm::SmallVector<StringRef, 2> Namespaces;
339*5ffd83dbSDimitry Andric   llvm::SplitString(CppNamespace, Namespaces, "::");
340*5ffd83dbSDimitry Andric   for (auto Ns : Namespaces)
341*5ffd83dbSDimitry Andric     OS << "namespace " << Ns << " {\n";
342*5ffd83dbSDimitry Andric 
343*5ffd83dbSDimitry Andric   for (const auto &D : Directives) {
344*5ffd83dbSDimitry Andric     const auto DirectiveName = D->getValueAsString("name");
345*5ffd83dbSDimitry Andric 
346*5ffd83dbSDimitry Andric     const auto &AllowedClauses = D->getValueAsListOfDefs("allowedClauses");
347*5ffd83dbSDimitry Andric     const auto &AllowedOnceClauses =
348*5ffd83dbSDimitry Andric         D->getValueAsListOfDefs("allowedOnceClauses");
349*5ffd83dbSDimitry Andric     const auto &AllowedExclusiveClauses =
350*5ffd83dbSDimitry Andric         D->getValueAsListOfDefs("allowedExclusiveClauses");
351*5ffd83dbSDimitry Andric     const auto &RequiredClauses = D->getValueAsListOfDefs("requiredClauses");
352*5ffd83dbSDimitry Andric 
353*5ffd83dbSDimitry Andric     OS << "\n";
354*5ffd83dbSDimitry Andric     OS << "  // Sets for " << DirectiveName << "\n";
355*5ffd83dbSDimitry Andric 
356*5ffd83dbSDimitry Andric     GenerateClauseSet(AllowedClauses, OS, ClauseEnumSetClass, "allowedClauses_",
357*5ffd83dbSDimitry Andric                       DirectiveName, DirectivePrefix, ClausePrefix,
358*5ffd83dbSDimitry Andric                       CppNamespace);
359*5ffd83dbSDimitry Andric     GenerateClauseSet(AllowedOnceClauses, OS, ClauseEnumSetClass,
360*5ffd83dbSDimitry Andric                       "allowedOnceClauses_", DirectiveName, DirectivePrefix,
361*5ffd83dbSDimitry Andric                       ClausePrefix, CppNamespace);
362*5ffd83dbSDimitry Andric     GenerateClauseSet(AllowedExclusiveClauses, OS, ClauseEnumSetClass,
363*5ffd83dbSDimitry Andric                       "allowedExclusiveClauses_", DirectiveName,
364*5ffd83dbSDimitry Andric                       DirectivePrefix, ClausePrefix, CppNamespace);
365*5ffd83dbSDimitry Andric     GenerateClauseSet(RequiredClauses, OS, ClauseEnumSetClass,
366*5ffd83dbSDimitry Andric                       "requiredClauses_", DirectiveName, DirectivePrefix,
367*5ffd83dbSDimitry Andric                       ClausePrefix, CppNamespace);
368*5ffd83dbSDimitry Andric   }
369*5ffd83dbSDimitry Andric 
370*5ffd83dbSDimitry Andric   // Closing namespaces
371*5ffd83dbSDimitry Andric   for (auto Ns : llvm::reverse(Namespaces))
372*5ffd83dbSDimitry Andric     OS << "} // namespace " << Ns << "\n";
373*5ffd83dbSDimitry Andric 
374*5ffd83dbSDimitry Andric   OS << "} // namespace llvm\n";
375*5ffd83dbSDimitry Andric }
376*5ffd83dbSDimitry Andric 
377*5ffd83dbSDimitry Andric // Generate a map of directive (key) with DirectiveClauses struct as values.
378*5ffd83dbSDimitry Andric // The struct holds the 4 sets of enumeration for the 4 kinds of clauses
379*5ffd83dbSDimitry Andric // allowances (allowed, allowed once, allowed exclusive and required).
380*5ffd83dbSDimitry Andric void GenerateDirectiveClauseMap(const std::vector<Record *> &Directives,
381*5ffd83dbSDimitry Andric                                 raw_ostream &OS, StringRef LanguageName,
382*5ffd83dbSDimitry Andric                                 StringRef ClauseEnumSetClass,
383*5ffd83dbSDimitry Andric                                 StringRef DirectivePrefix,
384*5ffd83dbSDimitry Andric                                 StringRef ClausePrefix,
385*5ffd83dbSDimitry Andric                                 StringRef CppNamespace) {
386*5ffd83dbSDimitry Andric 
387*5ffd83dbSDimitry Andric   IfDefScope Scope("GEN_FLANG_DIRECTIVE_CLAUSE_MAP", OS);
388*5ffd83dbSDimitry Andric 
389*5ffd83dbSDimitry Andric   OS << "\n";
390*5ffd83dbSDimitry Andric   OS << "struct " << LanguageName << "DirectiveClauses {\n";
391*5ffd83dbSDimitry Andric   OS << "  const " << ClauseEnumSetClass << " allowed;\n";
392*5ffd83dbSDimitry Andric   OS << "  const " << ClauseEnumSetClass << " allowedOnce;\n";
393*5ffd83dbSDimitry Andric   OS << "  const " << ClauseEnumSetClass << " allowedExclusive;\n";
394*5ffd83dbSDimitry Andric   OS << "  const " << ClauseEnumSetClass << " requiredOneOf;\n";
395*5ffd83dbSDimitry Andric   OS << "};\n";
396*5ffd83dbSDimitry Andric 
397*5ffd83dbSDimitry Andric   OS << "\n";
398*5ffd83dbSDimitry Andric 
399*5ffd83dbSDimitry Andric   OS << "std::unordered_map<llvm::" << CppNamespace << "::Directive, "
400*5ffd83dbSDimitry Andric      << LanguageName << "DirectiveClauses>\n";
401*5ffd83dbSDimitry Andric   OS << "    directiveClausesTable = {\n";
402*5ffd83dbSDimitry Andric 
403*5ffd83dbSDimitry Andric   for (const auto &D : Directives) {
404*5ffd83dbSDimitry Andric     const auto FormattedDirectiveName =
405*5ffd83dbSDimitry Andric         getFormattedName(D->getValueAsString("name"));
406*5ffd83dbSDimitry Andric     OS << "  {llvm::" << CppNamespace << "::Directive::" << DirectivePrefix
407*5ffd83dbSDimitry Andric        << FormattedDirectiveName << ",\n";
408*5ffd83dbSDimitry Andric     OS << "    {\n";
409*5ffd83dbSDimitry Andric     OS << "      llvm::" << CppNamespace << "::allowedClauses_"
410*5ffd83dbSDimitry Andric        << DirectivePrefix << FormattedDirectiveName << ",\n";
411*5ffd83dbSDimitry Andric     OS << "      llvm::" << CppNamespace << "::allowedOnceClauses_"
412*5ffd83dbSDimitry Andric        << DirectivePrefix << FormattedDirectiveName << ",\n";
413*5ffd83dbSDimitry Andric     OS << "      llvm::" << CppNamespace << "::allowedExclusiveClauses_"
414*5ffd83dbSDimitry Andric        << DirectivePrefix << FormattedDirectiveName << ",\n";
415*5ffd83dbSDimitry Andric     OS << "      llvm::" << CppNamespace << "::requiredClauses_"
416*5ffd83dbSDimitry Andric        << DirectivePrefix << FormattedDirectiveName << ",\n";
417*5ffd83dbSDimitry Andric     OS << "    }\n";
418*5ffd83dbSDimitry Andric     OS << "  },\n";
419*5ffd83dbSDimitry Andric   }
420*5ffd83dbSDimitry Andric 
421*5ffd83dbSDimitry Andric   OS << "};\n";
422*5ffd83dbSDimitry Andric }
423*5ffd83dbSDimitry Andric 
424*5ffd83dbSDimitry Andric // Generate the implemenation section for the enumeration in the directive
425*5ffd83dbSDimitry Andric // language
426*5ffd83dbSDimitry Andric void EmitDirectivesFlangImpl(const std::vector<Record *> &Directives,
427*5ffd83dbSDimitry Andric                              raw_ostream &OS, StringRef LanguageName,
428*5ffd83dbSDimitry Andric                              StringRef ClauseEnumSetClass,
429*5ffd83dbSDimitry Andric                              StringRef DirectivePrefix, StringRef ClausePrefix,
430*5ffd83dbSDimitry Andric                              StringRef CppNamespace) {
431*5ffd83dbSDimitry Andric 
432*5ffd83dbSDimitry Andric   GenerateDirectiveClauseSets(Directives, OS, LanguageName, ClauseEnumSetClass,
433*5ffd83dbSDimitry Andric                               DirectivePrefix, ClausePrefix, CppNamespace);
434*5ffd83dbSDimitry Andric 
435*5ffd83dbSDimitry Andric   GenerateDirectiveClauseMap(Directives, OS, LanguageName, ClauseEnumSetClass,
436*5ffd83dbSDimitry Andric                              DirectivePrefix, ClausePrefix, CppNamespace);
437*5ffd83dbSDimitry Andric }
438*5ffd83dbSDimitry Andric 
439*5ffd83dbSDimitry Andric // Generate the implemenation section for the enumeration in the directive
440*5ffd83dbSDimitry Andric // language.
441*5ffd83dbSDimitry Andric void EmitDirectivesGen(RecordKeeper &Records, raw_ostream &OS) {
442*5ffd83dbSDimitry Andric 
443*5ffd83dbSDimitry Andric   const auto &DirectiveLanguages =
444*5ffd83dbSDimitry Andric       Records.getAllDerivedDefinitions("DirectiveLanguage");
445*5ffd83dbSDimitry Andric 
446*5ffd83dbSDimitry Andric   if (DirectiveLanguages.size() != 1) {
447*5ffd83dbSDimitry Andric     PrintError("A single definition of DirectiveLanguage is needed.");
448*5ffd83dbSDimitry Andric     return;
449*5ffd83dbSDimitry Andric   }
450*5ffd83dbSDimitry Andric 
451*5ffd83dbSDimitry Andric   const auto &DirectiveLanguage = DirectiveLanguages[0];
452*5ffd83dbSDimitry Andric   StringRef DirectivePrefix =
453*5ffd83dbSDimitry Andric       DirectiveLanguage->getValueAsString("directivePrefix");
454*5ffd83dbSDimitry Andric   StringRef LanguageName = DirectiveLanguage->getValueAsString("name");
455*5ffd83dbSDimitry Andric   StringRef ClausePrefix = DirectiveLanguage->getValueAsString("clausePrefix");
456*5ffd83dbSDimitry Andric   StringRef CppNamespace = DirectiveLanguage->getValueAsString("cppNamespace");
457*5ffd83dbSDimitry Andric   StringRef ClauseEnumSetClass =
458*5ffd83dbSDimitry Andric       DirectiveLanguage->getValueAsString("clauseEnumSetClass");
459*5ffd83dbSDimitry Andric 
460*5ffd83dbSDimitry Andric   const auto &Directives = Records.getAllDerivedDefinitions("Directive");
461*5ffd83dbSDimitry Andric 
462*5ffd83dbSDimitry Andric   EmitDirectivesFlangImpl(Directives, OS, LanguageName, ClauseEnumSetClass,
463*5ffd83dbSDimitry Andric                           DirectivePrefix, ClausePrefix, CppNamespace);
464*5ffd83dbSDimitry Andric }
465*5ffd83dbSDimitry Andric 
466*5ffd83dbSDimitry Andric // Generate the implemenation for the enumeration in the directive
467*5ffd83dbSDimitry Andric // language. This code can be included in library.
468*5ffd83dbSDimitry Andric void EmitDirectivesImpl(RecordKeeper &Records, raw_ostream &OS) {
469*5ffd83dbSDimitry Andric 
470*5ffd83dbSDimitry Andric   const auto &DirectiveLanguages =
471*5ffd83dbSDimitry Andric       Records.getAllDerivedDefinitions("DirectiveLanguage");
472*5ffd83dbSDimitry Andric 
473*5ffd83dbSDimitry Andric   if (DirectiveLanguages.size() != 1) {
474*5ffd83dbSDimitry Andric     PrintError("A single definition of DirectiveLanguage is needed.");
475*5ffd83dbSDimitry Andric     return;
476*5ffd83dbSDimitry Andric   }
477*5ffd83dbSDimitry Andric 
478*5ffd83dbSDimitry Andric   const auto &DirectiveLanguage = DirectiveLanguages[0];
479*5ffd83dbSDimitry Andric   StringRef DirectivePrefix =
480*5ffd83dbSDimitry Andric       DirectiveLanguage->getValueAsString("directivePrefix");
481*5ffd83dbSDimitry Andric   StringRef LanguageName = DirectiveLanguage->getValueAsString("name");
482*5ffd83dbSDimitry Andric   StringRef ClausePrefix = DirectiveLanguage->getValueAsString("clausePrefix");
483*5ffd83dbSDimitry Andric   StringRef CppNamespace = DirectiveLanguage->getValueAsString("cppNamespace");
484*5ffd83dbSDimitry Andric   const auto &Directives = Records.getAllDerivedDefinitions("Directive");
485*5ffd83dbSDimitry Andric   const auto &Clauses = Records.getAllDerivedDefinitions("Clause");
486*5ffd83dbSDimitry Andric 
487*5ffd83dbSDimitry Andric   StringRef IncludeHeader =
488*5ffd83dbSDimitry Andric       DirectiveLanguage->getValueAsString("includeHeader");
489*5ffd83dbSDimitry Andric 
490*5ffd83dbSDimitry Andric   if (!IncludeHeader.empty())
491*5ffd83dbSDimitry Andric     OS << "#include \"" << IncludeHeader << "\"\n\n";
492*5ffd83dbSDimitry Andric 
493*5ffd83dbSDimitry Andric   OS << "#include \"llvm/ADT/StringRef.h\"\n";
494*5ffd83dbSDimitry Andric   OS << "#include \"llvm/ADT/StringSwitch.h\"\n";
495*5ffd83dbSDimitry Andric   OS << "#include \"llvm/Support/ErrorHandling.h\"\n";
496*5ffd83dbSDimitry Andric   OS << "\n";
497*5ffd83dbSDimitry Andric   OS << "using namespace llvm;\n";
498*5ffd83dbSDimitry Andric   llvm::SmallVector<StringRef, 2> Namespaces;
499*5ffd83dbSDimitry Andric   llvm::SplitString(CppNamespace, Namespaces, "::");
500*5ffd83dbSDimitry Andric   for (auto Ns : Namespaces)
501*5ffd83dbSDimitry Andric     OS << "using namespace " << Ns << ";\n";
502*5ffd83dbSDimitry Andric 
503*5ffd83dbSDimitry Andric   // getDirectiveKind(StringRef Str)
504*5ffd83dbSDimitry Andric   GenerateGetKind(Directives, OS, "Directive", DirectivePrefix, LanguageName,
505*5ffd83dbSDimitry Andric                   CppNamespace, /*ImplicitAsUnknown=*/false);
506*5ffd83dbSDimitry Andric 
507*5ffd83dbSDimitry Andric   // getDirectiveName(Directive Kind)
508*5ffd83dbSDimitry Andric   GenerateGetName(Directives, OS, "Directive", DirectivePrefix, LanguageName,
509*5ffd83dbSDimitry Andric                   CppNamespace);
510*5ffd83dbSDimitry Andric 
511*5ffd83dbSDimitry Andric   // getClauseKind(StringRef Str)
512*5ffd83dbSDimitry Andric   GenerateGetKind(Clauses, OS, "Clause", ClausePrefix, LanguageName,
513*5ffd83dbSDimitry Andric                   CppNamespace, /*ImplicitAsUnknown=*/true);
514*5ffd83dbSDimitry Andric 
515*5ffd83dbSDimitry Andric   // getClauseName(Clause Kind)
516*5ffd83dbSDimitry Andric   GenerateGetName(Clauses, OS, "Clause", ClausePrefix, LanguageName,
517*5ffd83dbSDimitry Andric                   CppNamespace);
518*5ffd83dbSDimitry Andric 
519*5ffd83dbSDimitry Andric   // isAllowedClauseForDirective(Directive D, Clause C, unsigned Version)
520*5ffd83dbSDimitry Andric   GenerateIsAllowedClause(Directives, OS, LanguageName, DirectivePrefix,
521*5ffd83dbSDimitry Andric                           ClausePrefix, CppNamespace);
522*5ffd83dbSDimitry Andric }
523*5ffd83dbSDimitry Andric 
524*5ffd83dbSDimitry Andric } // namespace llvm
525