aboutsummaryrefslogtreecommitdiff
path: root/libc
diff options
context:
space:
mode:
authorJoseph Huber <jhuber6@vols.utk.edu>2023-07-07 09:27:35 -0500
committerJoseph Huber <jhuber6@vols.utk.edu>2023-07-07 16:02:33 -0500
commit2a65d0388ca0f1c756f4c1a859cbb9e24b364942 (patch)
tree2c05f6d4afaa578e52c5c1981064fe6a01bd4f95 /libc
parent310f83961269a574d753932dc5f0c8fd44027781 (diff)
downloadllvm-2a65d0388ca0f1c756f4c1a859cbb9e24b364942.zip
llvm-2a65d0388ca0f1c756f4c1a859cbb9e24b364942.tar.gz
llvm-2a65d0388ca0f1c756f4c1a859cbb9e24b364942.tar.bz2
[libc] Add support for creating wrapper headers for offloading in clang
This is an alternate approach to the patches proposed in D153897 and D153794. Rather than exporting a single header that can be included on the GPU in all circumstances, this patch chooses to instead generate a separate set of headers that only provides the declarations. This can then be used by external tooling to set up what's on the GPU. This leaves room for header hacks for offloading languages without needing to worry about the `libc` implementation. Currently this generates a set of headers that only contain the declarations. These will then be installed to a new clang resource directory called `llvm_libc_wrappers/` which will house the shim code. We can then automaticlaly include this from `clang` when offloading to wrap around the headers while specifying what's on the GPU. Reviewed By: jdoerfert, JonChesterfield Differential Revision: https://reviews.llvm.org/D154036
Diffstat (limited to 'libc')
-rw-r--r--libc/cmake/modules/LLVMLibCHeaderRules.cmake20
-rw-r--r--libc/include/CMakeLists.txt22
-rw-r--r--libc/utils/HdrGen/Generator.cpp75
-rw-r--r--libc/utils/HdrGen/Generator.h1
-rw-r--r--libc/utils/HdrGen/Main.cpp8
5 files changed, 124 insertions, 2 deletions
diff --git a/libc/cmake/modules/LLVMLibCHeaderRules.cmake b/libc/cmake/modules/LLVMLibCHeaderRules.cmake
index 20cf43a..8aff65d 100644
--- a/libc/cmake/modules/LLVMLibCHeaderRules.cmake
+++ b/libc/cmake/modules/LLVMLibCHeaderRules.cmake
@@ -131,6 +131,23 @@ function(add_gen_header target_name)
${hdrgen_deps}
)
+ if(LIBC_TARGET_ARCHITECTURE_IS_GPU)
+ file(MAKE_DIRECTORY ${LIBC_INCLUDE_DIR}/llvm-libc-decls)
+ set(decl_out_file ${LIBC_INCLUDE_DIR}/llvm-libc-decls/${relative_path})
+ add_custom_command(
+ OUTPUT ${decl_out_file}
+ COMMAND ${hdrgen_exe} -o ${decl_out_file}
+ --header ${ADD_GEN_HDR_GEN_HDR} --def ${in_file} --export-decls
+ ${replacement_params} -I ${LIBC_SOURCE_DIR} ${ENTRYPOINT_NAME_LIST_ARG}
+ ${LIBC_SOURCE_DIR}/config/${LIBC_TARGET_OS}/api.td
+
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ DEPENDS ${in_file} ${fq_data_files} ${td_includes}
+ ${LIBC_SOURCE_DIR}/config/${LIBC_TARGET_OS}/api.td
+ ${hdrgen_deps}
+ )
+ endif()
+
if(ADD_GEN_HDR_DEPENDS)
get_fq_deps_list(fq_deps_list ${ADD_GEN_HDR_DEPENDS})
# Dependencies of a add_header target can only be another add_gen_header target
@@ -144,13 +161,14 @@ function(add_gen_header target_name)
endif()
add_custom_target(
${fq_target_name}
- DEPENDS ${out_file} ${fq_deps_list}
+ DEPENDS ${out_file} ${fq_deps_list} ${decl_out_file}
)
set_target_properties(
${fq_target_name}
PROPERTIES
HEADER_FILE_PATH ${out_file}
+ DECLS_FILE_PATH "${decl_out_file}"
DEPS "${fq_deps_list}"
)
endfunction(add_gen_header)
diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt
index 02a5f54..94dc6535 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -3,6 +3,11 @@ set(LIBC_INCLUDE_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
include(LLVMLibCHeaderRules)
+# The GPU build wants to install files in the compiler's resource directory.
+if(LIBC_TARGET_ARCHITECTURE_IS_GPU)
+ include(GetClangResourceDir)
+endif()
+
add_subdirectory(llvm-libc-macros)
add_subdirectory(llvm-libc-types)
@@ -539,4 +544,21 @@ foreach(target IN LISTS all_install_header_targets)
install(FILES ${header_file}
DESTINATION ${LIBC_INSTALL_INCLUDE_DIR}/${nested_dir}
COMPONENT libc-headers)
+ # The GPU optionally provides the supported declarations externally so
+ # offloading languages like CUDA and OpenMP know what is supported by libc. We
+ # install these in the compiler's resource directory at a preset location.
+ if(LIBC_TARGET_ARCHITECTURE_IS_GPU AND PACKAGE_VERSION)
+ get_target_property(decls_file ${target} DECLS_FILE_PATH)
+ if(NOT decls_file)
+ continue()
+ endif()
+ get_clang_resource_dir(resource_dir SUBDIR include)
+ file(RELATIVE_PATH relative_path ${LIBC_INCLUDE_BINARY_DIR} ${decls_file})
+ get_filename_component(nested_dir ${relative_path} DIRECTORY)
+ set(install_dir
+ ${CMAKE_INSTALL_PREFIX}/${resource_dir}/llvm_libc_wrappers/${nested_dir})
+ install(FILES ${decls_file}
+ DESTINATION ${install_dir}
+ COMPONENT libc-headers)
+ endif()
endforeach()
diff --git a/libc/utils/HdrGen/Generator.cpp b/libc/utils/HdrGen/Generator.cpp
index cbfb2db..24d2268 100644
--- a/libc/utils/HdrGen/Generator.cpp
+++ b/libc/utils/HdrGen/Generator.cpp
@@ -10,6 +10,7 @@
#include "IncludeFileCommand.h"
#include "PublicAPICommand.h"
+#include "utils/LibcTableGenUtil/APIIndexer.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -116,4 +117,78 @@ void Generator::generate(llvm::raw_ostream &OS, llvm::RecordKeeper &Records) {
}
}
+void Generator::generateDecls(llvm::raw_ostream &OS,
+ llvm::RecordKeeper &Records) {
+
+ OS << "//===-- C standard declarations for " << StdHeader << " "
+ << std::string(80 - (42 + StdHeader.size()), '-') << "===//\n"
+ << "//\n"
+ << "// Part of the LLVM Project, under the Apache License v2.0 with LLVM "
+ "Exceptions.\n"
+ << "// See https://llvm.org/LICENSE.txt for license information.\n"
+ << "// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n"
+ << "//\n"
+ << "//"
+ "===-------------------------------------------------------------------"
+ "---===//\n\n";
+
+ std::string HeaderGuard(StdHeader.size(), '\0');
+ llvm::transform(StdHeader, HeaderGuard.begin(), [](const char C) -> char {
+ return !isalnum(C) ? '_' : llvm::toUpper(C);
+ });
+ OS << "#ifndef __LLVM_LIBC_DECLARATIONS_" << HeaderGuard << "\n"
+ << "#define __LLVM_LIBC_DECLARATIONS_" << HeaderGuard << "\n\n";
+
+ OS << "#ifndef __LIBC_ATTRS\n"
+ << "#define __LIBC_ATTRS\n"
+ << "#endif\n\n";
+
+ OS << "#ifdef __cplusplus\n"
+ << "extern \"C\" {\n"
+ << "#endif\n\n";
+
+ APIIndexer G(StdHeader, Records);
+ for (auto &Name : EntrypointNameList) {
+ // Filter out functions not exported by this header.
+ if (G.FunctionSpecMap.find(Name) == G.FunctionSpecMap.end())
+ continue;
+
+ llvm::Record *FunctionSpec = G.FunctionSpecMap[Name];
+ llvm::Record *RetValSpec = FunctionSpec->getValueAsDef("Return");
+ llvm::Record *ReturnType = RetValSpec->getValueAsDef("ReturnType");
+
+ OS << G.getTypeAsString(ReturnType) << " " << Name << "(";
+
+ auto ArgsList = FunctionSpec->getValueAsListOfDefs("Args");
+ for (size_t i = 0; i < ArgsList.size(); ++i) {
+ llvm::Record *ArgType = ArgsList[i]->getValueAsDef("ArgType");
+ OS << G.getTypeAsString(ArgType);
+ if (i < ArgsList.size() - 1)
+ OS << ", ";
+ }
+
+ OS << ") __LIBC_ATTRS;\n\n";
+ }
+
+ // Make another pass over entrypoints to emit object declarations.
+ for (const auto &Name : EntrypointNameList) {
+ if (G.ObjectSpecMap.find(Name) == G.ObjectSpecMap.end())
+ continue;
+ llvm::Record *ObjectSpec = G.ObjectSpecMap[Name];
+ auto Type = ObjectSpec->getValueAsString("Type");
+ OS << "extern " << Type << " " << Name << " __LIBC_ATTRS;\n";
+ }
+
+ // Emit a final newline if we emitted any object declarations.
+ if (llvm::any_of(EntrypointNameList, [&](const std::string &Name) {
+ return G.ObjectSpecMap.find(Name) != G.ObjectSpecMap.end();
+ }))
+ OS << "\n";
+
+ OS << "#ifdef __cplusplus\n"
+ << "}\n"
+ << "#endif\n\n";
+ OS << "#endif\n";
+}
+
} // namespace llvm_libc
diff --git a/libc/utils/HdrGen/Generator.h b/libc/utils/HdrGen/Generator.h
index eef96ad..76a8a11 100644
--- a/libc/utils/HdrGen/Generator.h
+++ b/libc/utils/HdrGen/Generator.h
@@ -52,6 +52,7 @@ public:
ArgMap(Map) {}
void generate(llvm::raw_ostream &OS, llvm::RecordKeeper &Records);
+ void generateDecls(llvm::raw_ostream &OS, llvm::RecordKeeper &Records);
};
} // namespace llvm_libc
diff --git a/libc/utils/HdrGen/Main.cpp b/libc/utils/HdrGen/Main.cpp
index d148747..d3418f2 100644
--- a/libc/utils/HdrGen/Main.cpp
+++ b/libc/utils/HdrGen/Main.cpp
@@ -32,6 +32,9 @@ llvm::cl::list<std::string> EntrypointNamesOption(
llvm::cl::list<std::string> ReplacementValues(
"args", llvm::cl::desc("Command separated <argument name>=<value> pairs."),
llvm::cl::value_desc("<name=value>[,name=value]"));
+llvm::cl::opt<bool> ExportDecls(
+ "export-decls",
+ llvm::cl::desc("Output a new header containing only the entrypoints."));
void ParseArgValuePairs(std::unordered_map<std::string, std::string> &Map) {
for (std::string &R : ReplacementValues) {
@@ -48,7 +51,10 @@ bool HeaderGeneratorMain(llvm::raw_ostream &OS, llvm::RecordKeeper &Records) {
std::unordered_map<std::string, std::string> ArgMap;
ParseArgValuePairs(ArgMap);
Generator G(HeaderDefFile, EntrypointNamesOption, StandardHeader, ArgMap);
- G.generate(OS, Records);
+ if (ExportDecls)
+ G.generateDecls(OS, Records);
+ else
+ G.generate(OS, Records);
return false;
}