From 59f17a7d4f42fa330557e36d18f8b5f82a2c5e30 Mon Sep 17 00:00:00 2001 From: Siva Chandra Reddy Date: Tue, 28 Jul 2020 16:07:32 -0700 Subject: [PATCH] [libc][NFC] Move tablegen indexer class into a util library of its own. This class is currently used by two tools: HdrGen and PrototypeTestGen. We will be adding more tools based on this class so it is convenient to keep it in a util library of its own. --- libc/utils/CMakeLists.txt | 1 + libc/utils/HdrGen/CMakeLists.txt | 3 + .../HdrGen/PrototypeTestGen/CMakeLists.txt | 4 +- .../PrototypeTestGen/PrototypeTestGen.cpp | 2 +- libc/utils/HdrGen/PublicAPICommand.cpp | 146 +---------------- libc/utils/HdrGen/PublicAPICommand.h | 61 +------ libc/utils/LibcTableGenUtil/APIIndexer.cpp | 154 ++++++++++++++++++ libc/utils/LibcTableGenUtil/APIIndexer.h | 66 ++++++++ libc/utils/LibcTableGenUtil/CMakeLists.txt | 7 + 9 files changed, 238 insertions(+), 206 deletions(-) create mode 100644 libc/utils/LibcTableGenUtil/APIIndexer.cpp create mode 100644 libc/utils/LibcTableGenUtil/APIIndexer.h create mode 100644 libc/utils/LibcTableGenUtil/CMakeLists.txt diff --git a/libc/utils/CMakeLists.txt b/libc/utils/CMakeLists.txt index c6e877fceef7c..ec1308927bf92 100644 --- a/libc/utils/CMakeLists.txt +++ b/libc/utils/CMakeLists.txt @@ -1,5 +1,6 @@ add_subdirectory(CPP) add_subdirectory(FPUtil) +add_subdirectory(LibcTableGenUtil) add_subdirectory(HdrGen) add_subdirectory(MPFRWrapper) add_subdirectory(testutils) diff --git a/libc/utils/HdrGen/CMakeLists.txt b/libc/utils/HdrGen/CMakeLists.txt index 65c2d65c79181..8aaaa965acbfe 100644 --- a/libc/utils/HdrGen/CMakeLists.txt +++ b/libc/utils/HdrGen/CMakeLists.txt @@ -12,4 +12,7 @@ add_tablegen(libc-hdrgen llvm-libc PublicAPICommand.h ) +target_include_directories(libc-hdrgen PRIVATE ${LIBC_SOURCE_DIR}) +target_link_libraries(libc-hdrgen PRIVATE LibcTableGenUtil) + add_subdirectory(PrototypeTestGen) diff --git a/libc/utils/HdrGen/PrototypeTestGen/CMakeLists.txt b/libc/utils/HdrGen/PrototypeTestGen/CMakeLists.txt index e4ad5c209cd9e..c90fde76dd58c 100644 --- a/libc/utils/HdrGen/PrototypeTestGen/CMakeLists.txt +++ b/libc/utils/HdrGen/PrototypeTestGen/CMakeLists.txt @@ -1,5 +1,5 @@ add_tablegen(libc-prototype-testgen llvm-libc PrototypeTestGen.cpp - ../PublicAPICommand.cpp - ../Command.cpp ) +target_link_libraries(libc-prototype-testgen PRIVATE LibcTableGenUtil) +target_include_directories(libc-prototype-testgen PRIVATE ${LIBC_SOURCE_DIR}) diff --git a/libc/utils/HdrGen/PrototypeTestGen/PrototypeTestGen.cpp b/libc/utils/HdrGen/PrototypeTestGen/PrototypeTestGen.cpp index aad451a8de225..918b520d3910a 100644 --- a/libc/utils/HdrGen/PrototypeTestGen/PrototypeTestGen.cpp +++ b/libc/utils/HdrGen/PrototypeTestGen/PrototypeTestGen.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include "../PublicAPICommand.h" +#include "utils/LibcTableGenUtil/APIIndexer.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/CommandLine.h" diff --git a/libc/utils/HdrGen/PublicAPICommand.cpp b/libc/utils/HdrGen/PublicAPICommand.cpp index 11b825831e883..87b188ca8c02b 100644 --- a/libc/utils/HdrGen/PublicAPICommand.cpp +++ b/libc/utils/HdrGen/PublicAPICommand.cpp @@ -8,32 +8,13 @@ #include "PublicAPICommand.h" +#include "utils/LibcTableGenUtil/APIIndexer.h" + #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/SourceMgr.h" -#include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" -static const char NamedTypeClassName[] = "NamedType"; -static const char PtrTypeClassName[] = "PtrType"; -static const char RestrictedPtrTypeClassName[] = "RestrictedPtrType"; -static const char ConstTypeClassName[] = "ConstType"; -static const char StructTypeClassName[] = "Struct"; - -static const char StandardSpecClassName[] = "StandardSpec"; -static const char PublicAPIClassName[] = "PublicAPI"; - -static bool isa(llvm::Record *Def, llvm::Record *TypeClass) { - llvm::RecordRecTy *RecordType = Def->getType(); - llvm::ArrayRef Classes = RecordType->getClasses(); - // We want exact types. That is, we don't want the classes listed in - // spec.td to be subclassed. Hence, we do not want the record |Def| - // to be of more than one class type.. - if (Classes.size() != 1) - return false; - return Classes[0] == TypeClass; -} - // Text blocks for macro definitions and type decls can be indented to // suit the surrounding tablegen listing. We need to dedent such blocks // before writing them out. @@ -59,129 +40,6 @@ static void dedentAndWrite(llvm::StringRef Text, llvm::raw_ostream &OS) { namespace llvm_libc { -bool APIIndexer::isaNamedType(llvm::Record *Def) { - return isa(Def, NamedTypeClass); -} - -bool APIIndexer::isaStructType(llvm::Record *Def) { - return isa(Def, StructClass); -} - -bool APIIndexer::isaPtrType(llvm::Record *Def) { - return isa(Def, PtrTypeClass); -} - -bool APIIndexer::isaConstType(llvm::Record *Def) { - return isa(Def, ConstTypeClass); -} - -bool APIIndexer::isaRestrictedPtrType(llvm::Record *Def) { - return isa(Def, RestrictedPtrTypeClass); -} - -bool APIIndexer::isaStandardSpec(llvm::Record *Def) { - return isa(Def, StandardSpecClass); -} - -bool APIIndexer::isaPublicAPI(llvm::Record *Def) { - return isa(Def, PublicAPIClass); -} - -std::string APIIndexer::getTypeAsString(llvm::Record *TypeRecord) { - if (isaNamedType(TypeRecord) || isaStructType(TypeRecord)) { - return std::string(TypeRecord->getValueAsString("Name")); - } else if (isaPtrType(TypeRecord)) { - return getTypeAsString(TypeRecord->getValueAsDef("PointeeType")) + " *"; - } else if (isaConstType(TypeRecord)) { - return std::string("const ") + - getTypeAsString(TypeRecord->getValueAsDef("UnqualifiedType")); - } else if (isaRestrictedPtrType(TypeRecord)) { - return getTypeAsString(TypeRecord->getValueAsDef("PointeeType")) + - " *__restrict"; - } else { - llvm::PrintFatalError(TypeRecord->getLoc(), "Invalid type.\n"); - } -} - -void APIIndexer::indexStandardSpecDef(llvm::Record *StandardSpec) { - auto HeaderSpecList = StandardSpec->getValueAsListOfDefs("Headers"); - for (llvm::Record *HeaderSpec : HeaderSpecList) { - llvm::StringRef Header = HeaderSpec->getValueAsString("Name"); - if (!StdHeader.hasValue() || Header == StdHeader) { - PublicHeaders.emplace(Header); - auto MacroSpecList = HeaderSpec->getValueAsListOfDefs("Macros"); - // TODO: Trigger a fatal error on duplicate specs. - for (llvm::Record *MacroSpec : MacroSpecList) - MacroSpecMap[std::string(MacroSpec->getValueAsString("Name"))] = - MacroSpec; - - auto TypeSpecList = HeaderSpec->getValueAsListOfDefs("Types"); - for (llvm::Record *TypeSpec : TypeSpecList) - TypeSpecMap[std::string(TypeSpec->getValueAsString("Name"))] = TypeSpec; - - auto FunctionSpecList = HeaderSpec->getValueAsListOfDefs("Functions"); - for (llvm::Record *FunctionSpec : FunctionSpecList) { - FunctionSpecMap[std::string(FunctionSpec->getValueAsString("Name"))] = - FunctionSpec; - } - - auto EnumerationSpecList = - HeaderSpec->getValueAsListOfDefs("Enumerations"); - for (llvm::Record *EnumerationSpec : EnumerationSpecList) { - EnumerationSpecMap[std::string( - EnumerationSpec->getValueAsString("Name"))] = EnumerationSpec; - } - } - } -} - -void APIIndexer::indexPublicAPIDef(llvm::Record *PublicAPI) { - // While indexing the public API, we do not check if any of the entities - // requested is from an included standard. Such a check is done while - // generating the API. - auto MacroDefList = PublicAPI->getValueAsListOfDefs("Macros"); - for (llvm::Record *MacroDef : MacroDefList) - MacroDefsMap[std::string(MacroDef->getValueAsString("Name"))] = MacroDef; - - auto TypeDeclList = PublicAPI->getValueAsListOfDefs("TypeDeclarations"); - for (llvm::Record *TypeDecl : TypeDeclList) - TypeDeclsMap[std::string(TypeDecl->getValueAsString("Name"))] = TypeDecl; - - auto StructList = PublicAPI->getValueAsListOfStrings("Structs"); - for (llvm::StringRef StructName : StructList) - Structs.insert(std::string(StructName)); - - auto FunctionList = PublicAPI->getValueAsListOfStrings("Functions"); - for (llvm::StringRef FunctionName : FunctionList) - Functions.insert(std::string(FunctionName)); - - auto EnumerationList = PublicAPI->getValueAsListOfStrings("Enumerations"); - for (llvm::StringRef EnumerationName : EnumerationList) - Enumerations.insert(std::string(EnumerationName)); -} - -void APIIndexer::index(llvm::RecordKeeper &Records) { - NamedTypeClass = Records.getClass(NamedTypeClassName); - PtrTypeClass = Records.getClass(PtrTypeClassName); - RestrictedPtrTypeClass = Records.getClass(RestrictedPtrTypeClassName); - StructClass = Records.getClass(StructTypeClassName); - ConstTypeClass = Records.getClass(ConstTypeClassName); - StandardSpecClass = Records.getClass(StandardSpecClassName); - PublicAPIClass = Records.getClass(PublicAPIClassName); - - const auto &DefsMap = Records.getDefs(); - for (auto &Pair : DefsMap) { - llvm::Record *Def = Pair.second.get(); - if (isaStandardSpec(Def)) - indexStandardSpecDef(Def); - if (isaPublicAPI(Def)) { - if (!StdHeader.hasValue() || - Def->getValueAsString("HeaderName") == StdHeader) - indexPublicAPIDef(Def); - } - } -} - void writeAPIFromIndex(APIIndexer &G, llvm::raw_ostream &OS) { for (auto &Pair : G.MacroDefsMap) { const std::string &Name = Pair.first; diff --git a/libc/utils/HdrGen/PublicAPICommand.h b/libc/utils/HdrGen/PublicAPICommand.h index c95ad525647a7..bfe2e5f5d0075 100644 --- a/libc/utils/HdrGen/PublicAPICommand.h +++ b/libc/utils/HdrGen/PublicAPICommand.h @@ -12,10 +12,8 @@ #include "Command.h" #include "llvm/ADT/StringRef.h" - -#include -#include -#include +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Record.h" namespace llvm { @@ -36,61 +34,6 @@ class PublicAPICommand : public Command { const Command::ErrorReporter &Reporter) const override; }; -class APIIndexer { -private: - llvm::Optional StdHeader; - - // TableGen classes in spec.td. - llvm::Record *NamedTypeClass; - llvm::Record *PtrTypeClass; - llvm::Record *RestrictedPtrTypeClass; - llvm::Record *ConstTypeClass; - llvm::Record *StructClass; - llvm::Record *StandardSpecClass; - llvm::Record *PublicAPIClass; - - bool isaNamedType(llvm::Record *Def); - bool isaStructType(llvm::Record *Def); - bool isaPtrType(llvm::Record *Def); - bool isaConstType(llvm::Record *Def); - bool isaRestrictedPtrType(llvm::Record *Def); - bool isaStandardSpec(llvm::Record *Def); - bool isaPublicAPI(llvm::Record *Def); - - void indexStandardSpecDef(llvm::Record *StandardSpec); - void indexPublicAPIDef(llvm::Record *PublicAPI); - void index(llvm::RecordKeeper &Records); - -public: - using NameToRecordMapping = std::unordered_map; - using NameSet = std::unordered_set; - - // This indexes all headers, not just a specified one. - explicit APIIndexer(llvm::RecordKeeper &Records) : StdHeader(llvm::None) { - index(Records); - } - - APIIndexer(llvm::StringRef Header, llvm::RecordKeeper &Records) - : StdHeader(Header) { - index(Records); - } - - // Mapping from names to records defining them. - NameToRecordMapping MacroSpecMap; - NameToRecordMapping TypeSpecMap; - NameToRecordMapping EnumerationSpecMap; - NameToRecordMapping FunctionSpecMap; - NameToRecordMapping MacroDefsMap; - NameToRecordMapping TypeDeclsMap; - - NameSet Structs; - NameSet Enumerations; - NameSet Functions; - NameSet PublicHeaders; - - std::string getTypeAsString(llvm::Record *TypeRecord); -}; - } // namespace llvm_libc #endif // LLVM_LIBC_UTILS_HDRGEN_PUBLICAPICOMMAND_H diff --git a/libc/utils/LibcTableGenUtil/APIIndexer.cpp b/libc/utils/LibcTableGenUtil/APIIndexer.cpp new file mode 100644 index 0000000000000..934d713f905e5 --- /dev/null +++ b/libc/utils/LibcTableGenUtil/APIIndexer.cpp @@ -0,0 +1,154 @@ + +#include "APIIndexer.h" + +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Record.h" + +namespace llvm_libc { + +static const char NamedTypeClassName[] = "NamedType"; +static const char PtrTypeClassName[] = "PtrType"; +static const char RestrictedPtrTypeClassName[] = "RestrictedPtrType"; +static const char ConstTypeClassName[] = "ConstType"; +static const char StructTypeClassName[] = "Struct"; + +static const char StandardSpecClassName[] = "StandardSpec"; +static const char PublicAPIClassName[] = "PublicAPI"; + +static bool isa(llvm::Record *Def, llvm::Record *TypeClass) { + llvm::RecordRecTy *RecordType = Def->getType(); + llvm::ArrayRef Classes = RecordType->getClasses(); + // We want exact types. That is, we don't want the classes listed in + // spec.td to be subclassed. Hence, we do not want the record |Def| + // to be of more than one class type.. + if (Classes.size() != 1) + return false; + return Classes[0] == TypeClass; +} + +bool APIIndexer::isaNamedType(llvm::Record *Def) { + return isa(Def, NamedTypeClass); +} + +bool APIIndexer::isaStructType(llvm::Record *Def) { + return isa(Def, StructClass); +} + +bool APIIndexer::isaPtrType(llvm::Record *Def) { + return isa(Def, PtrTypeClass); +} + +bool APIIndexer::isaConstType(llvm::Record *Def) { + return isa(Def, ConstTypeClass); +} + +bool APIIndexer::isaRestrictedPtrType(llvm::Record *Def) { + return isa(Def, RestrictedPtrTypeClass); +} + +bool APIIndexer::isaStandardSpec(llvm::Record *Def) { + return isa(Def, StandardSpecClass); +} + +bool APIIndexer::isaPublicAPI(llvm::Record *Def) { + return isa(Def, PublicAPIClass); +} + +std::string APIIndexer::getTypeAsString(llvm::Record *TypeRecord) { + if (isaNamedType(TypeRecord) || isaStructType(TypeRecord)) { + return std::string(TypeRecord->getValueAsString("Name")); + } else if (isaPtrType(TypeRecord)) { + return getTypeAsString(TypeRecord->getValueAsDef("PointeeType")) + " *"; + } else if (isaConstType(TypeRecord)) { + return std::string("const ") + + getTypeAsString(TypeRecord->getValueAsDef("UnqualifiedType")); + } else if (isaRestrictedPtrType(TypeRecord)) { + return getTypeAsString(TypeRecord->getValueAsDef("PointeeType")) + + " *__restrict"; + } else { + llvm::PrintFatalError(TypeRecord->getLoc(), "Invalid type.\n"); + } +} + +void APIIndexer::indexStandardSpecDef(llvm::Record *StandardSpec) { + auto HeaderSpecList = StandardSpec->getValueAsListOfDefs("Headers"); + for (llvm::Record *HeaderSpec : HeaderSpecList) { + llvm::StringRef Header = HeaderSpec->getValueAsString("Name"); + if (!StdHeader.hasValue() || Header == StdHeader) { + PublicHeaders.emplace(Header); + auto MacroSpecList = HeaderSpec->getValueAsListOfDefs("Macros"); + // TODO: Trigger a fatal error on duplicate specs. + for (llvm::Record *MacroSpec : MacroSpecList) + MacroSpecMap[std::string(MacroSpec->getValueAsString("Name"))] = + MacroSpec; + + auto TypeSpecList = HeaderSpec->getValueAsListOfDefs("Types"); + for (llvm::Record *TypeSpec : TypeSpecList) + TypeSpecMap[std::string(TypeSpec->getValueAsString("Name"))] = TypeSpec; + + auto FunctionSpecList = HeaderSpec->getValueAsListOfDefs("Functions"); + for (llvm::Record *FunctionSpec : FunctionSpecList) { + FunctionSpecMap[std::string(FunctionSpec->getValueAsString("Name"))] = + FunctionSpec; + } + + auto EnumerationSpecList = + HeaderSpec->getValueAsListOfDefs("Enumerations"); + for (llvm::Record *EnumerationSpec : EnumerationSpecList) { + EnumerationSpecMap[std::string( + EnumerationSpec->getValueAsString("Name"))] = EnumerationSpec; + } + } + } +} + +void APIIndexer::indexPublicAPIDef(llvm::Record *PublicAPI) { + // While indexing the public API, we do not check if any of the entities + // requested is from an included standard. Such a check is done while + // generating the API. + auto MacroDefList = PublicAPI->getValueAsListOfDefs("Macros"); + for (llvm::Record *MacroDef : MacroDefList) + MacroDefsMap[std::string(MacroDef->getValueAsString("Name"))] = MacroDef; + + auto TypeDeclList = PublicAPI->getValueAsListOfDefs("TypeDeclarations"); + for (llvm::Record *TypeDecl : TypeDeclList) + TypeDeclsMap[std::string(TypeDecl->getValueAsString("Name"))] = TypeDecl; + + auto StructList = PublicAPI->getValueAsListOfStrings("Structs"); + for (llvm::StringRef StructName : StructList) + Structs.insert(std::string(StructName)); + + auto FunctionList = PublicAPI->getValueAsListOfStrings("Functions"); + for (llvm::StringRef FunctionName : FunctionList) + Functions.insert(std::string(FunctionName)); + + auto EnumerationList = PublicAPI->getValueAsListOfStrings("Enumerations"); + for (llvm::StringRef EnumerationName : EnumerationList) + Enumerations.insert(std::string(EnumerationName)); +} + +void APIIndexer::index(llvm::RecordKeeper &Records) { + NamedTypeClass = Records.getClass(NamedTypeClassName); + PtrTypeClass = Records.getClass(PtrTypeClassName); + RestrictedPtrTypeClass = Records.getClass(RestrictedPtrTypeClassName); + StructClass = Records.getClass(StructTypeClassName); + ConstTypeClass = Records.getClass(ConstTypeClassName); + StandardSpecClass = Records.getClass(StandardSpecClassName); + PublicAPIClass = Records.getClass(PublicAPIClassName); + + const auto &DefsMap = Records.getDefs(); + for (auto &Pair : DefsMap) { + llvm::Record *Def = Pair.second.get(); + if (isaStandardSpec(Def)) + indexStandardSpecDef(Def); + if (isaPublicAPI(Def)) { + if (!StdHeader.hasValue() || + Def->getValueAsString("HeaderName") == StdHeader) + indexPublicAPIDef(Def); + } + } +} + +} // namespace llvm_libc diff --git a/libc/utils/LibcTableGenUtil/APIIndexer.h b/libc/utils/LibcTableGenUtil/APIIndexer.h new file mode 100644 index 0000000000000..a0f0acf600d81 --- /dev/null +++ b/libc/utils/LibcTableGenUtil/APIIndexer.h @@ -0,0 +1,66 @@ + +#include "llvm/ADT/StringRef.h" +#include "llvm/TableGen/Record.h" + +#include +#include +#include + +namespace llvm_libc { + +class APIIndexer { +private: + llvm::Optional StdHeader; + + // TableGen classes in spec.td. + llvm::Record *NamedTypeClass; + llvm::Record *PtrTypeClass; + llvm::Record *RestrictedPtrTypeClass; + llvm::Record *ConstTypeClass; + llvm::Record *StructClass; + llvm::Record *StandardSpecClass; + llvm::Record *PublicAPIClass; + + bool isaNamedType(llvm::Record *Def); + bool isaStructType(llvm::Record *Def); + bool isaPtrType(llvm::Record *Def); + bool isaConstType(llvm::Record *Def); + bool isaRestrictedPtrType(llvm::Record *Def); + bool isaStandardSpec(llvm::Record *Def); + bool isaPublicAPI(llvm::Record *Def); + + void indexStandardSpecDef(llvm::Record *StandardSpec); + void indexPublicAPIDef(llvm::Record *PublicAPI); + void index(llvm::RecordKeeper &Records); + +public: + using NameToRecordMapping = std::unordered_map; + using NameSet = std::unordered_set; + + // This indexes all headers, not just a specified one. + explicit APIIndexer(llvm::RecordKeeper &Records) : StdHeader(llvm::None) { + index(Records); + } + + APIIndexer(llvm::StringRef Header, llvm::RecordKeeper &Records) + : StdHeader(Header) { + index(Records); + } + + // Mapping from names to records defining them. + NameToRecordMapping MacroSpecMap; + NameToRecordMapping TypeSpecMap; + NameToRecordMapping EnumerationSpecMap; + NameToRecordMapping FunctionSpecMap; + NameToRecordMapping MacroDefsMap; + NameToRecordMapping TypeDeclsMap; + + NameSet Structs; + NameSet Enumerations; + NameSet Functions; + NameSet PublicHeaders; + + std::string getTypeAsString(llvm::Record *TypeRecord); +}; + +} // namespace llvm_libc diff --git a/libc/utils/LibcTableGenUtil/CMakeLists.txt b/libc/utils/LibcTableGenUtil/CMakeLists.txt new file mode 100644 index 0000000000000..ae887a8bdb03a --- /dev/null +++ b/libc/utils/LibcTableGenUtil/CMakeLists.txt @@ -0,0 +1,7 @@ +add_llvm_library( + LibcTableGenUtil + APIIndexer.cpp + APIIndexer.h + LINK_COMPONENTS Support +) +target_include_directories(LibcTableGenUtil PUBLIC ${LIBC_SOURCE_DIR})