| 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(val: PS.UniqueCounter++); |
| 47 | if (Arg->isSubClassOf(Name: "Template" )) { |
| 48 | ++PS.CurrentDepth; |
| 49 | auto [TemplateCode, TPLName] = |
| 50 | ParseTemplateParameterList(PS, TemplateArgs: Arg->getValueAsListOfDefs(FieldName: "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(Name: "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(FieldName: "IsVariadic" ) << ");\n" ; |
| 64 | } else if (Arg->isSubClassOf(Name: "NTTP" )) { |
| 65 | auto Type = Arg->getValueAsString(FieldName: "TypeName" ); |
| 66 | |
| 67 | if (!TemplateNameToParmName.contains(Key: Type.str())) |
| 68 | PrintFatalError(Msg: "Unknown Type Name" ); |
| 69 | |
| 70 | auto TSIName = "TSI" + std::to_string(val: 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(FieldName: "IsVariadic" ) |
| 78 | << ", " << TSIName << ");\n" ; |
| 79 | } else if (Arg->isSubClassOf(Name: "BuiltinNTTP" )) { |
| 80 | std::string SourceInfo; |
| 81 | if (Arg->getValueAsString(FieldName: "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(FieldName: "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(Msg: "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(Msg: "Unknown Argument Type" ); |
| 108 | } |
| 109 | |
| 110 | TemplateNameToParmName[Arg->getValueAsString(FieldName: "Name" ).str()] = ParmName; |
| 111 | Params.emplace_back(Args: std::move(ParmName)); |
| 112 | } |
| 113 | |
| 114 | auto TPLName = "TPL" + std::to_string(val: PS.UniqueCounter++); |
| 115 | Code << " auto *" << TPLName |
| 116 | << " = TemplateParameterList::Create(C, SourceLocation(), " |
| 117 | "SourceLocation(), {" ; |
| 118 | |
| 119 | if (Params.empty()) { |
| 120 | PrintFatalError( |
| 121 | Msg: "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(FieldName: "TemplateHead" ); |
| 158 | |
| 159 | EmitCreateBuiltinTemplateParameterList(TemplateArgs: TemplateHead, Name); |
| 160 | |
| 161 | TemplateNameList += Class + "(" ; |
| 162 | TemplateNameList += Name; |
| 163 | TemplateNameList += ")\n" ; |
| 164 | |
| 165 | BuiltinClasses.insert(key: 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(Desc: "Tables and code for Clang's builtin templates" , OS); |
| 183 | |
| 184 | for (const auto *Builtin : |
| 185 | Records.getAllDerivedDefinitions(ClassName: "BuiltinTemplate" )) |
| 186 | EmitBuiltinTemplate(BuiltinTemplate: Builtin); |
| 187 | |
| 188 | for (const auto &ClassEntry : BuiltinClasses) { |
| 189 | StringRef Class = ClassEntry.getKey(); |
| 190 | if (Class == "BuiltinTemplate" ) |
| 191 | continue; |
| 192 | EmitDefaultDefine(OS, Name: 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, Name: Class); |
| 205 | } |
| 206 | } |
| 207 | |