Skip to content

Commit

Permalink
[libc][NFC] Move tablegen indexer class into a util library of its own.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Siva Chandra Reddy committed Jul 28, 2020
1 parent f14472a commit 59f17a7
Show file tree
Hide file tree
Showing 9 changed files with 238 additions and 206 deletions.
1 change: 1 addition & 0 deletions 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)
Expand Down
3 changes: 3 additions & 0 deletions libc/utils/HdrGen/CMakeLists.txt
Expand Up @@ -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)
4 changes: 2 additions & 2 deletions 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})
2 changes: 1 addition & 1 deletion libc/utils/HdrGen/PrototypeTestGen/PrototypeTestGen.cpp
Expand Up @@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//

#include "../PublicAPICommand.h"
#include "utils/LibcTableGenUtil/APIIndexer.h"

#include "llvm/ADT/StringRef.h"
#include "llvm/Support/CommandLine.h"
Expand Down
146 changes: 2 additions & 144 deletions libc/utils/HdrGen/PublicAPICommand.cpp
Expand Up @@ -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<llvm::Record *> 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.
Expand All @@ -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;
Expand Down
61 changes: 2 additions & 59 deletions libc/utils/HdrGen/PublicAPICommand.h
Expand Up @@ -12,10 +12,8 @@
#include "Command.h"

#include "llvm/ADT/StringRef.h"

#include <string>
#include <unordered_map>
#include <unordered_set>
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"

namespace llvm {

Expand All @@ -36,61 +34,6 @@ class PublicAPICommand : public Command {
const Command::ErrorReporter &Reporter) const override;
};

class APIIndexer {
private:
llvm::Optional<llvm::StringRef> 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<std::string, llvm::Record *>;
using NameSet = std::unordered_set<std::string>;

// 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

0 comments on commit 59f17a7

Please sign in to comment.