summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libc/utils/CMakeLists.txt1
-rw-r--r--libc/utils/LibcTableGenUtil/APIIndexer.cpp5
-rw-r--r--libc/utils/LibcTableGenUtil/APIIndexer.h2
-rw-r--r--libc/utils/tools/CMakeLists.txt1
-rw-r--r--libc/utils/tools/WrapperGen/CMakeLists.txt8
-rw-r--r--libc/utils/tools/WrapperGen/Main.cpp72
6 files changed, 87 insertions, 2 deletions
diff --git a/libc/utils/CMakeLists.txt b/libc/utils/CMakeLists.txt
index ec1308927bf9..a55182065d20 100644
--- a/libc/utils/CMakeLists.txt
+++ b/libc/utils/CMakeLists.txt
@@ -4,4 +4,5 @@ add_subdirectory(LibcTableGenUtil)
add_subdirectory(HdrGen)
add_subdirectory(MPFRWrapper)
add_subdirectory(testutils)
+add_subdirectory(tools)
add_subdirectory(UnitTest)
diff --git a/libc/utils/LibcTableGenUtil/APIIndexer.cpp b/libc/utils/LibcTableGenUtil/APIIndexer.cpp
index 6ef9a6576b87..16aef5880bff 100644
--- a/libc/utils/LibcTableGenUtil/APIIndexer.cpp
+++ b/libc/utils/LibcTableGenUtil/APIIndexer.cpp
@@ -97,8 +97,9 @@ void APIIndexer::indexStandardSpecDef(llvm::Record *StandardSpec) {
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/LibcTableGenUtil/APIIndexer.h b/libc/utils/LibcTableGenUtil/APIIndexer.h
index 8fa87113610e..7b4d62a38c61 100644
--- a/libc/utils/LibcTableGenUtil/APIIndexer.h
+++ b/libc/utils/LibcTableGenUtil/APIIndexer.h
@@ -65,6 +65,8 @@ public:
NameToRecordMapping MacroDefsMap;
NameToRecordMapping TypeDeclsMap;
+ std::unordered_map<std::string, std::string> FunctionToHeaderMap;
+
NameSet Structs;
NameSet Enumerations;
NameSet Functions;
diff --git a/libc/utils/tools/CMakeLists.txt b/libc/utils/tools/CMakeLists.txt
new file mode 100644
index 000000000000..e975b7f293af
--- /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
index 000000000000..fe8ffcce94a5
--- /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
index 000000000000..ae606d1b66fa
--- /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 <sstream>
+#include <string>
+
+llvm::cl::opt<std::string>
+ FunctionName("name", llvm::cl::desc("Name of the function to be wrapped."),
+ llvm::cl::value_desc("<function name>"), 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);
+}