1 //===- DirectiveEmitter.cpp - Directive Language Emitter ------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // DirectiveEmitter uses the descriptions of directives and clauses to construct
10 // common code declarations to be used in Frontends.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "llvm/ADT/STLExtras.h"
15 #include "llvm/ADT/SmallVector.h"
16 #include "llvm/ADT/StringExtras.h"
17 #include "llvm/TableGen/Error.h"
18 #include "llvm/TableGen/Record.h"
19 #include "llvm/TableGen/TableGenBackend.h"
20 
21 namespace llvm {
22 void EmitDirectivesEnums(RecordKeeper &Records, raw_ostream &OS) {
23 
24   const auto &DirectiveLanguages =
25       Records.getAllDerivedDefinitions("DirectiveLanguage");
26 
27   if (DirectiveLanguages.size() != 1) {
28     PrintError("A single definition of DirectiveLanguage is needed.");
29     return;
30   }
31 
32   const auto &DirectiveLanguage = DirectiveLanguages[0];
33   StringRef languageName = DirectiveLanguage->getValueAsString("name");
34   StringRef DirectivePrefix =
35       DirectiveLanguage->getValueAsString("directivePrefix");
36   StringRef ClausePrefix = DirectiveLanguage->getValueAsString("clausePrefix");
37   StringRef CppNamespace = DirectiveLanguage->getValueAsString("cppNamespace");
38   bool MakeEnumAvailableInNamespace =
39       DirectiveLanguage->getValueAsBit("makeEnumAvailableInNamespace");
40   bool EnableBitmaskEnumInNamespace =
41       DirectiveLanguage->getValueAsBit("enableBitmaskEnumInNamespace");
42 
43   OS << "#ifndef LLVM_" << languageName << "_INC\n";
44   OS << "#define LLVM_" << languageName << "_INC\n";
45 
46   if (EnableBitmaskEnumInNamespace)
47     OS << "#include \"llvm/ADT/BitmaskEnum.h\"\n";
48 
49   OS << "namespace llvm {\n";
50 
51   // Open namespaces defined in the directive language
52   llvm::SmallVector<StringRef, 2> Namespaces;
53   llvm::SplitString(CppNamespace, Namespaces, "::");
54   for (auto Ns : Namespaces)
55     OS << "namespace " << Ns << " {\n";
56 
57   if (EnableBitmaskEnumInNamespace)
58     OS << "LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();\n";
59 
60   // Emit Directive enumeration
61   OS << "enum class Directive {\n";
62   const auto &Directives = Records.getAllDerivedDefinitions("Directive");
63   for (const auto &D : Directives) {
64     const auto Name = D->getValueAsString("name");
65     std::string N = Name.str();
66     std::replace(N.begin(), N.end(), ' ', '_');
67     OS << DirectivePrefix << N << ",\n";
68   }
69   OS << "};\n";
70 
71   OS << "static constexpr std::size_t Directive_enumSize = "
72      << Directives.size() << ";\n";
73 
74   // Emit Clause enumeration
75   OS << "enum class Clause {\n";
76   const auto &Clauses = Records.getAllDerivedDefinitions("Clause");
77   for (const auto &C : Clauses) {
78     const auto Name = C->getValueAsString("name");
79     OS << ClausePrefix << Name << ",\n";
80   }
81   OS << "};\n";
82 
83   OS << "static constexpr std::size_t Clause_enumSize = " << Clauses.size()
84      << ";\n";
85 
86   // Make the enum values available in the defined namespace. This allows us to
87   // write something like Enum_X if we have a `using namespace <CppNamespace>`.
88   // At the same time we do not loose the strong type guarantees of the enum
89   // class, that is we cannot pass an unsigned as Directive without an explicit
90   // cast.
91   if (MakeEnumAvailableInNamespace) {
92     for (const auto &D : Directives) {
93       const auto Name = D->getValueAsString("name");
94       std::string N = Name.str();
95       std::replace(N.begin(), N.end(), ' ', '_');
96       OS << "constexpr auto " << DirectivePrefix << N << " = " << CppNamespace
97          << "::Directive::" << DirectivePrefix << N << ";\n";
98     }
99 
100     for (const auto &C : Clauses) {
101       const auto Name = C->getValueAsString("name");
102       OS << "constexpr auto " << ClausePrefix << Name << " = " << CppNamespace
103          << "::Clause::" << ClausePrefix << Name << ";\n";
104     }
105   }
106 
107   // Closing namespaces
108   for (auto Ns : llvm::reverse(Namespaces))
109     OS << "} // namespace " << Ns << "\n";
110 
111   OS << "} // namespace llvm\n";
112 
113   OS << "#endif";
114 }
115 } // namespace llvm
116