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> 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 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 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 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 175 void EmitUndef(llvm::raw_ostream &OS, StringRef Name) { 176 OS << "#undef " << Name << "\n"; 177 } 178 } // namespace 179 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