//=- ClangBuiltinsEmitter.cpp - Generate Clang builtin templates-*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This tablegen backend emits Clang's builtin templates. // //===----------------------------------------------------------------------===// #include "TableGenBackends.h" #include "llvm/ADT/StringSet.h" #include "llvm/TableGen/Error.h" #include "llvm/TableGen/TableGenBackend.h" #include using namespace llvm; static std::string TemplateNameList; static std::string CreateBuiltinTemplateParameterList; static llvm::StringSet<> BuiltinClasses; namespace { struct ParserState { size_t UniqueCounter = 0; size_t CurrentDepth = 0; bool EmittedSizeTInfo = false; bool EmittedUint32TInfo = false; }; std::pair ParseTemplateParameterList(ParserState &PS, ArrayRef TemplateArgs) { llvm::SmallVector Params; llvm::StringMap TemplateNameToParmName; std::ostringstream Code; Code << std::boolalpha; size_t Position = 0; for (const Record *Arg : TemplateArgs) { std::string ParmName = "Parm" + std::to_string(PS.UniqueCounter++); if (Arg->isSubClassOf("Template")) { ++PS.CurrentDepth; auto [TemplateCode, TPLName] = ParseTemplateParameterList(PS, Arg->getValueAsListOfDefs("Args")); --PS.CurrentDepth; Code << TemplateCode << " auto *" << ParmName << " = TemplateTemplateParmDecl::Create(C, DC, SourceLocation(), " << PS.CurrentDepth << ", " << Position++ << ", /*ParameterPack=*/false, /*Id=*/nullptr, " "/*Kind=*/TNK_Type_template, /*Typename=*/false, " << TPLName << ");\n"; } else if (Arg->isSubClassOf("Class")) { Code << " auto *" << ParmName << " = TemplateTypeParmDecl::Create(C, DC, SourceLocation(), " "SourceLocation(), " << PS.CurrentDepth << ", " << Position++ << ", /*Id=*/nullptr, /*Typename=*/false, " << Arg->getValueAsBit("IsVariadic") << ");\n"; } else if (Arg->isSubClassOf("NTTP")) { auto Type = Arg->getValueAsString("TypeName"); if (!TemplateNameToParmName.contains(Type.str())) PrintFatalError("Unknown Type Name"); auto TSIName = "TSI" + std::to_string(PS.UniqueCounter++); Code << " auto *" << TSIName << " = C.getTrivialTypeSourceInfo(QualType(" << TemplateNameToParmName[Type.str()] << "->getTypeForDecl(), 0));\n" << " auto *" << ParmName << " = NonTypeTemplateParmDecl::Create(C, DC, SourceLocation(), " "SourceLocation(), " << PS.CurrentDepth << ", " << Position++ << ", /*Id=*/nullptr, " << TSIName << "->getType(), " << Arg->getValueAsBit("IsVariadic") << ", " << TSIName << ");\n"; } else if (Arg->isSubClassOf("BuiltinNTTP")) { std::string SourceInfo; if (Arg->getValueAsString("TypeName") == "size_t") { SourceInfo = "SizeTInfo"; if (!PS.EmittedSizeTInfo) { Code << "TypeSourceInfo *SizeTInfo = " "C.getTrivialTypeSourceInfo(C.getSizeType());\n"; PS.EmittedSizeTInfo = true; } } else if (Arg->getValueAsString("TypeName") == "uint32_t") { SourceInfo = "Uint32TInfo"; if (!PS.EmittedUint32TInfo) { Code << "TypeSourceInfo *Uint32TInfo = " "C.getTrivialTypeSourceInfo(C.UnsignedIntTy);\n"; PS.EmittedUint32TInfo = true; } } else { PrintFatalError("Unknown Type Name"); } Code << " auto *" << ParmName << " = NonTypeTemplateParmDecl::Create(C, DC, SourceLocation(), " "SourceLocation(), " << PS.CurrentDepth << ", " << Position++ << ", /*Id=*/nullptr, " << SourceInfo << "->getType(), " "/*ParameterPack=*/false, " << SourceInfo << ");\n"; } else { PrintFatalError("Unknown Argument Type"); } TemplateNameToParmName[Arg->getValueAsString("Name").str()] = ParmName; Params.emplace_back(std::move(ParmName)); } auto TPLName = "TPL" + std::to_string(PS.UniqueCounter++); Code << " auto *" << TPLName << " = TemplateParameterList::Create(C, SourceLocation(), " "SourceLocation(), {"; if (Params.empty()) { PrintFatalError( "Expected at least one argument in template parameter list"); } bool First = true; for (const auto &e : Params) { if (First) { First = false; Code << e; } else { Code << ", " << e; } } Code << "}, SourceLocation(), nullptr);\n"; return {std::move(Code).str(), std::move(TPLName)}; } static void EmitCreateBuiltinTemplateParameterList(std::vector TemplateArgs, StringRef Name) { using namespace std::string_literals; CreateBuiltinTemplateParameterList += "case BTK"s + std::string{Name} + ": {\n"s; ParserState PS; auto [Code, TPLName] = ParseTemplateParameterList(PS, TemplateArgs); CreateBuiltinTemplateParameterList += Code + "\n return " + TPLName + ";\n"; CreateBuiltinTemplateParameterList += " }\n"; } void EmitBuiltinTemplate(const Record *BuiltinTemplate) { auto Class = BuiltinTemplate->getType()->getAsString(); auto Name = BuiltinTemplate->getName(); std::vector TemplateHead = BuiltinTemplate->getValueAsListOfDefs("TemplateHead"); EmitCreateBuiltinTemplateParameterList(TemplateHead, Name); TemplateNameList += Class + "("; TemplateNameList += Name; TemplateNameList += ")\n"; BuiltinClasses.insert(Class); } void EmitDefaultDefine(llvm::raw_ostream &OS, StringRef Name) { OS << "#ifndef " << Name << "\n"; OS << "#define " << Name << "(NAME)" << " " << "BuiltinTemplate" << "(NAME)\n"; OS << "#endif\n\n"; } void EmitUndef(llvm::raw_ostream &OS, StringRef Name) { OS << "#undef " << Name << "\n"; } } // namespace void clang::EmitClangBuiltinTemplates(const llvm::RecordKeeper &Records, llvm::raw_ostream &OS) { emitSourceFileHeader("Tables and code for Clang's builtin templates", OS); for (const auto *Builtin : Records.getAllDerivedDefinitions("BuiltinTemplate")) EmitBuiltinTemplate(Builtin); for (const auto &ClassEntry : BuiltinClasses) { StringRef Class = ClassEntry.getKey(); if (Class == "BuiltinTemplate") continue; EmitDefaultDefine(OS, Class); } OS << "#if defined(CREATE_BUILTIN_TEMPLATE_PARAMETER_LIST)\n" << CreateBuiltinTemplateParameterList << "#undef CREATE_BUILTIN_TEMPLATE_PARAMETER_LIST\n#else\n" << TemplateNameList << "#undef BuiltinTemplate\n#endif\n"; for (const auto &ClassEntry : BuiltinClasses) { StringRef Class = ClassEntry.getKey(); if (Class == "BuiltinTemplate") continue; EmitUndef(OS, Class); } }