diff --git a/libc/utils/CMakeLists.txt b/libc/utils/CMakeLists.txt --- a/libc/utils/CMakeLists.txt +++ b/libc/utils/CMakeLists.txt @@ -4,4 +4,5 @@ add_subdirectory(HdrGen) add_subdirectory(MPFRWrapper) add_subdirectory(testutils) +add_subdirectory(tools) add_subdirectory(UnitTest) diff --git a/libc/utils/LibcTableGenUtil/APIIndexer.h b/libc/utils/LibcTableGenUtil/APIIndexer.h --- a/libc/utils/LibcTableGenUtil/APIIndexer.h +++ b/libc/utils/LibcTableGenUtil/APIIndexer.h @@ -65,6 +65,8 @@ NameToRecordMapping MacroDefsMap; NameToRecordMapping TypeDeclsMap; + std::unordered_map FunctionToHeaderMap; + NameSet Structs; NameSet Enumerations; NameSet Functions; diff --git a/libc/utils/LibcTableGenUtil/APIIndexer.cpp b/libc/utils/LibcTableGenUtil/APIIndexer.cpp --- a/libc/utils/LibcTableGenUtil/APIIndexer.cpp +++ b/libc/utils/LibcTableGenUtil/APIIndexer.cpp @@ -97,8 +97,9 @@ auto FunctionSpecList = HeaderSpec->getValueAsListOfDefs("Functions"); for (llvm::Record *FunctionSpec : FunctionSpecList) { - FunctionSpecMap[std::string(FunctionSpec->getValueAsString("Name"))] = - FunctionSpec; + auto FunctionName = std::string(FunctionSpec->getValueAsString("Name")); + FunctionSpecMap[FunctionName] = FunctionSpec; + FunctionToHeaderMap[FunctionName] = std::string(Header); } auto EnumerationSpecList = diff --git a/libc/utils/tools/CMakeLists.txt b/libc/utils/tools/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/libc/utils/tools/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(WrapperGen) diff --git a/libc/utils/tools/WrapperGen/CMakeLists.txt b/libc/utils/tools/WrapperGen/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/libc/utils/tools/WrapperGen/CMakeLists.txt @@ -0,0 +1,8 @@ +set(LLVM_LINK_COMPONENTS Support) + +add_tablegen(libc-wrappergen llvm-libc + Main.cpp +) + +target_include_directories(libc-wrappergen PRIVATE ${LIBC_SOURCE_DIR}) +target_link_libraries(libc-wrappergen PRIVATE LibcTableGenUtil) diff --git a/libc/utils/tools/WrapperGen/Main.cpp b/libc/utils/tools/WrapperGen/Main.cpp new file mode 100644 --- /dev/null +++ b/libc/utils/tools/WrapperGen/Main.cpp @@ -0,0 +1,72 @@ +//===-- "main" function of libc-wrappergen --------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "utils/LibcTableGenUtil/APIIndexer.h" + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Main.h" + +#include +#include + +llvm::cl::opt + FunctionName("name", llvm::cl::desc("Name of the function to be wrapped."), + llvm::cl::value_desc(""), llvm::cl::Required); + +static bool WrapperGenMain(llvm::raw_ostream &OS, llvm::RecordKeeper &Records) { + llvm_libc::APIIndexer Indexer(Records); + auto Iter = Indexer.FunctionSpecMap.find(FunctionName); + if (Iter == Indexer.FunctionSpecMap.end()) { + llvm::PrintFatalError("Function '" + FunctionName + + "' not found in any standard spec."); + } + + // To avoid all confusion, we include the implementation header using the + // full path (relative the libc directory.) + std::string Header = Indexer.FunctionToHeaderMap[FunctionName]; + auto RelPath = llvm::StringRef(Header).drop_back(2); // Drop the ".h" suffix. + OS << "#include \"src/" << RelPath << "/" << FunctionName << ".h\"\n"; + + auto &NameSpecPair = *Iter; + llvm::Record *FunctionSpec = NameSpecPair.second; + llvm::Record *RetValSpec = FunctionSpec->getValueAsDef("Return"); + llvm::Record *ReturnType = RetValSpec->getValueAsDef("ReturnType"); + OS << "extern \"C\" " << Indexer.getTypeAsString(ReturnType) << " " + << FunctionName << "("; + + auto ArgsList = FunctionSpec->getValueAsListOfDefs("Args"); + std::stringstream CallArgs; + std::string ArgPrefix("__arg"); + for (size_t i = 0; i < ArgsList.size(); ++i) { + llvm::Record *ArgType = ArgsList[i]->getValueAsDef("ArgType"); + auto TypeName = Indexer.getTypeAsString(ArgType); + OS << TypeName << " " << ArgPrefix << i; + CallArgs << ArgPrefix << i; + if (i < ArgsList.size() - 1) { + OS << ", "; + CallArgs << ", "; + } + } + + // TODO: Arg types of the C++ implementation functions need not + // match the standard types. Either handle such differences here, or + // avoid such a thing in the implementations. + OS << ") {\n" + << " return __llvm_libc::" << FunctionName << "(" << CallArgs.str() + << ");\n" + << "}\n"; + + return false; +} + +int main(int argc, char *argv[]) { + llvm::cl::ParseCommandLineOptions(argc, argv); + return TableGenMain(argv[0], WrapperGenMain); +}