xref: /freebsd/contrib/llvm-project/clang/utils/TableGen/ClangBuiltinTemplatesEmitter.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
1 //=- ClangBuiltinsEmitter.cpp - Generate Clang builtin templates-*- C++ -*-===//
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 // This tablegen backend emits Clang's builtin templates.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "TableGenBackends.h"
14 #include "llvm/ADT/StringSet.h"
15 #include "llvm/TableGen/Error.h"
16 #include "llvm/TableGen/TableGenBackend.h"
17 
18 #include <sstream>
19 
20 using namespace llvm;
21 
22 static std::string TemplateNameList;
23 static std::string CreateBuiltinTemplateParameterList;
24 
25 static llvm::StringSet<> BuiltinClasses;
26 
27 namespace {
28 struct ParserState {
29   size_t UniqueCounter = 0;
30   size_t CurrentDepth = 0;
31   bool EmittedSizeTInfo = false;
32   bool EmittedUint32TInfo = false;
33 };
34 
35 std::pair<std::string, std::string>
ParseTemplateParameterList(ParserState & PS,ArrayRef<const Record * > TemplateArgs)36 ParseTemplateParameterList(ParserState &PS,
37                            ArrayRef<const Record *> TemplateArgs) {
38   llvm::SmallVector<std::string, 4> Params;
39   llvm::StringMap<std::string> TemplateNameToParmName;
40 
41   std::ostringstream Code;
42   Code << std::boolalpha;
43 
44   size_t Position = 0;
45   for (const Record *Arg : TemplateArgs) {
46     std::string ParmName = "Parm" + std::to_string(PS.UniqueCounter++);
47     if (Arg->isSubClassOf("Template")) {
48       ++PS.CurrentDepth;
49       auto [TemplateCode, TPLName] =
50           ParseTemplateParameterList(PS, Arg->getValueAsListOfDefs("Args"));
51       --PS.CurrentDepth;
52       Code << TemplateCode << " auto *" << ParmName
53            << " = TemplateTemplateParmDecl::Create(C, DC, SourceLocation(), "
54            << PS.CurrentDepth << ", " << Position++
55            << ", /*ParameterPack=*/false, /*Id=*/nullptr, /*Typename=*/false, "
56            << TPLName << ");\n";
57     } else if (Arg->isSubClassOf("Class")) {
58       Code << " auto *" << ParmName
59            << " = TemplateTypeParmDecl::Create(C, DC, SourceLocation(), "
60               "SourceLocation(), "
61            << PS.CurrentDepth << ", " << Position++
62            << ", /*Id=*/nullptr, /*Typename=*/false, "
63            << Arg->getValueAsBit("IsVariadic") << ");\n";
64     } else if (Arg->isSubClassOf("NTTP")) {
65       auto Type = Arg->getValueAsString("TypeName");
66 
67       if (!TemplateNameToParmName.contains(Type.str()))
68         PrintFatalError("Unknown Type Name");
69 
70       auto TSIName = "TSI" + std::to_string(PS.UniqueCounter++);
71       Code << " auto *" << TSIName << " = C.getTrivialTypeSourceInfo(QualType("
72            << TemplateNameToParmName[Type.str()] << "->getTypeForDecl(), 0));\n"
73            << " auto *" << ParmName
74            << " = NonTypeTemplateParmDecl::Create(C, DC, SourceLocation(), "
75               "SourceLocation(), "
76            << PS.CurrentDepth << ", " << Position++ << ", /*Id=*/nullptr, "
77            << TSIName << "->getType(), " << Arg->getValueAsBit("IsVariadic")
78            << ", " << TSIName << ");\n";
79     } else if (Arg->isSubClassOf("BuiltinNTTP")) {
80       std::string SourceInfo;
81       if (Arg->getValueAsString("TypeName") == "size_t") {
82         SourceInfo = "SizeTInfo";
83         if (!PS.EmittedSizeTInfo) {
84           Code << "TypeSourceInfo *SizeTInfo = "
85                   "C.getTrivialTypeSourceInfo(C.getSizeType());\n";
86           PS.EmittedSizeTInfo = true;
87         }
88       } else if (Arg->getValueAsString("TypeName") == "uint32_t") {
89         SourceInfo = "Uint32TInfo";
90         if (!PS.EmittedUint32TInfo) {
91           Code << "TypeSourceInfo *Uint32TInfo = "
92                   "C.getTrivialTypeSourceInfo(C.UnsignedIntTy);\n";
93           PS.EmittedUint32TInfo = true;
94         }
95       } else {
96         PrintFatalError("Unknown Type Name");
97       }
98       Code << " auto *" << ParmName
99            << " = NonTypeTemplateParmDecl::Create(C, DC, SourceLocation(), "
100               "SourceLocation(), "
101            << PS.CurrentDepth << ", " << Position++ << ", /*Id=*/nullptr, "
102            << SourceInfo
103            << "->getType(), "
104               "/*ParameterPack=*/false, "
105            << SourceInfo << ");\n";
106     } else {
107       PrintFatalError("Unknown Argument Type");
108     }
109 
110     TemplateNameToParmName[Arg->getValueAsString("Name").str()] = ParmName;
111     Params.emplace_back(std::move(ParmName));
112   }
113 
114   auto TPLName = "TPL" + std::to_string(PS.UniqueCounter++);
115   Code << " auto *" << TPLName
116        << " = TemplateParameterList::Create(C, SourceLocation(), "
117           "SourceLocation(), {";
118 
119   if (Params.empty()) {
120     PrintFatalError(
121         "Expected at least one argument in template parameter list");
122   }
123 
124   bool First = true;
125   for (const auto &e : Params) {
126     if (First) {
127       First = false;
128       Code << e;
129     } else {
130       Code << ", " << e;
131     }
132   }
133   Code << "}, SourceLocation(), nullptr);\n";
134 
135   return {std::move(Code).str(), std::move(TPLName)};
136 }
137 
138 static void
EmitCreateBuiltinTemplateParameterList(std::vector<const Record * > TemplateArgs,StringRef Name)139 EmitCreateBuiltinTemplateParameterList(std::vector<const Record *> TemplateArgs,
140                                        StringRef Name) {
141   using namespace std::string_literals;
142   CreateBuiltinTemplateParameterList +=
143       "case BTK"s + std::string{Name} + ": {\n"s;
144 
145   ParserState PS;
146   auto [Code, TPLName] = ParseTemplateParameterList(PS, TemplateArgs);
147   CreateBuiltinTemplateParameterList += Code + "\n  return " + TPLName + ";\n";
148 
149   CreateBuiltinTemplateParameterList += "  }\n";
150 }
151 
EmitBuiltinTemplate(const Record * BuiltinTemplate)152 void EmitBuiltinTemplate(const Record *BuiltinTemplate) {
153   auto Class = BuiltinTemplate->getType()->getAsString();
154   auto Name = BuiltinTemplate->getName();
155 
156   std::vector<const Record *> TemplateHead =
157       BuiltinTemplate->getValueAsListOfDefs("TemplateHead");
158 
159   EmitCreateBuiltinTemplateParameterList(TemplateHead, Name);
160 
161   TemplateNameList += Class + "(";
162   TemplateNameList += Name;
163   TemplateNameList += ")\n";
164 
165   BuiltinClasses.insert(Class);
166 }
167 
EmitDefaultDefine(llvm::raw_ostream & OS,StringRef Name)168 void EmitDefaultDefine(llvm::raw_ostream &OS, StringRef Name) {
169   OS << "#ifndef " << Name << "\n";
170   OS << "#define " << Name << "(NAME)" << " " << "BuiltinTemplate"
171      << "(NAME)\n";
172   OS << "#endif\n\n";
173 }
174 
EmitUndef(llvm::raw_ostream & OS,StringRef Name)175 void EmitUndef(llvm::raw_ostream &OS, StringRef Name) {
176   OS << "#undef " << Name << "\n";
177 }
178 } // namespace
179 
EmitClangBuiltinTemplates(const llvm::RecordKeeper & Records,llvm::raw_ostream & OS)180 void clang::EmitClangBuiltinTemplates(const llvm::RecordKeeper &Records,
181                                       llvm::raw_ostream &OS) {
182   emitSourceFileHeader("Tables and code for Clang's builtin templates", OS);
183 
184   for (const auto *Builtin :
185        Records.getAllDerivedDefinitions("BuiltinTemplate"))
186     EmitBuiltinTemplate(Builtin);
187 
188   for (const auto &ClassEntry : BuiltinClasses) {
189     StringRef Class = ClassEntry.getKey();
190     if (Class == "BuiltinTemplate")
191       continue;
192     EmitDefaultDefine(OS, Class);
193   }
194 
195   OS << "#if defined(CREATE_BUILTIN_TEMPLATE_PARAMETER_LIST)\n"
196      << CreateBuiltinTemplateParameterList
197      << "#undef CREATE_BUILTIN_TEMPLATE_PARAMETER_LIST\n#else\n"
198      << TemplateNameList << "#undef BuiltinTemplate\n#endif\n";
199 
200   for (const auto &ClassEntry : BuiltinClasses) {
201     StringRef Class = ClassEntry.getKey();
202     if (Class == "BuiltinTemplate")
203       continue;
204     EmitUndef(OS, Class);
205   }
206 }
207