[clang] 2a65d03 - [libc] Add support for creating wrapper headers for offloading in clang
Joseph Huber via cfe-commits
cfe-commits at lists.llvm.org
Fri Jul 7 14:02:43 PDT 2023
Author: Joseph Huber
Date: 2023-07-07T16:02:33-05:00
New Revision: 2a65d0388ca0f1c756f4c1a859cbb9e24b364942
URL: https://github.com/llvm/llvm-project/commit/2a65d0388ca0f1c756f4c1a859cbb9e24b364942
DIFF: https://github.com/llvm/llvm-project/commit/2a65d0388ca0f1c756f4c1a859cbb9e24b364942.diff
LOG: [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
Added:
clang/lib/Headers/llvm_libc_wrappers/ctype.h
clang/lib/Headers/llvm_libc_wrappers/inttypes.h
clang/lib/Headers/llvm_libc_wrappers/llvm-libc-decls/README.txt
clang/lib/Headers/llvm_libc_wrappers/stdio.h
clang/lib/Headers/llvm_libc_wrappers/stdlib.h
clang/lib/Headers/llvm_libc_wrappers/string.h
Modified:
clang/lib/Driver/ToolChains/Clang.cpp
clang/lib/Headers/CMakeLists.txt
clang/test/Driver/gpu-libc-headers.c
libc/cmake/modules/LLVMLibCHeaderRules.cmake
libc/include/CMakeLists.txt
libc/utils/HdrGen/Generator.cpp
libc/utils/HdrGen/Generator.h
libc/utils/HdrGen/Main.cpp
Removed:
################################################################################
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 595cb649603736..e3d7b05d2521c0 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -1181,23 +1181,30 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA,
// If we are compiling for a GPU target we want to override the system headers
// with ones created by the 'libc' project if present.
- // FIXME: We need to find a way to make these headers compatible with the
- // host environment so they can be included from offloading languages. For now
- // these are only active when targeting the GPU with cross-compilation.
if (!Args.hasArg(options::OPT_nostdinc) &&
!Args.hasArg(options::OPT_nogpuinc) &&
!Args.hasArg(options::OPT_nobuiltininc) &&
- C.getActiveOffloadKinds() == Action::OFK_None &&
(getToolChain().getTriple().isNVPTX() ||
getToolChain().getTriple().isAMDGCN())) {
- // Add include/gpu-none-libc/* to our system include path. This lets us use
- // GPU-specific system headers first.
+ // Without an offloading language we will include these headers directly.
+ // Offloading languages will instead only use the declarations stored in
+ // the resource directory at clang/lib/Headers/llvm_libc_wrappers.
+ if (C.getActiveOffloadKinds() == Action::OFK_None) {
SmallString<128> P(llvm::sys::path::parent_path(D.InstalledDir));
llvm::sys::path::append(P, "include");
llvm::sys::path::append(P, "gpu-none-llvm");
CmdArgs.push_back("-c-isystem");
CmdArgs.push_back(Args.MakeArgString(P));
+ } else if (C.getActiveOffloadKinds() == Action::OFK_OpenMP) {
+ // TODO: CUDA / HIP include their own headers for some common functions
+ // implemented here. We'll need to clean those up so they do not conflict.
+ SmallString<128> P(D.ResourceDir);
+ llvm::sys::path::append(P, "include");
+ llvm::sys::path::append(P, "llvm_libc_wrappers");
+ CmdArgs.push_back("-internal-isystem");
+ CmdArgs.push_back(Args.MakeArgString(P));
+ }
}
// If we are offloading to a target via OpenMP we need to include the
diff --git a/clang/lib/Headers/CMakeLists.txt b/clang/lib/Headers/CMakeLists.txt
index 9d6ac8b7e449a1..5a219e234452a9 100644
--- a/clang/lib/Headers/CMakeLists.txt
+++ b/clang/lib/Headers/CMakeLists.txt
@@ -298,6 +298,14 @@ set(openmp_wrapper_files
openmp_wrappers/new
)
+set(llvm_libc_wrapper_files
+ llvm_libc_wrappers/stdio.h
+ llvm_libc_wrappers/stdlib.h
+ llvm_libc_wrappers/string.h
+ llvm_libc_wrappers/ctype.h
+ llvm_libc_wrappers/inttypes.h
+)
+
include(GetClangResourceDir)
get_clang_resource_dir(output_dir PREFIX ${LLVM_LIBRARY_OUTPUT_INTDIR}/.. SUBDIR include)
set(out_files)
@@ -333,7 +341,8 @@ endfunction(clang_generate_header)
# Copy header files from the source directory to the build directory
foreach( f ${files} ${cuda_wrapper_files} ${cuda_wrapper_bits_files}
- ${ppc_wrapper_files} ${openmp_wrapper_files} ${hlsl_files})
+ ${ppc_wrapper_files} ${openmp_wrapper_files} ${hlsl_files}
+ ${llvm_libc_wrapper_files})
copy_header_to_output_dir(${CMAKE_CURRENT_SOURCE_DIR} ${f})
endforeach( f )
@@ -427,6 +436,7 @@ add_dependencies("clang-resource-headers"
"x86-resource-headers"
"opencl-resource-headers"
"openmp-resource-headers"
+ "llvm-libc-resource-headers"
"windows-resource-headers"
"utility-resource-headers")
@@ -453,6 +463,7 @@ add_header_target("x86-resource-headers" "${x86_files}")
# Other header groupings
add_header_target("hlsl-resource-headers" ${hlsl_files})
add_header_target("opencl-resource-headers" ${opencl_files})
+add_header_target("llvm-libc-resource-headers" ${llvm_libc_wrapper_files})
add_header_target("openmp-resource-headers" ${openmp_wrapper_files})
add_header_target("windows-resource-headers" ${windows_only_files})
add_header_target("utility-resource-headers" ${utility_files})
@@ -481,6 +492,11 @@ install(
DESTINATION ${header_install_dir}/ppc_wrappers
COMPONENT clang-resource-headers)
+install(
+ FILES ${llvm_libc_wrapper_files}
+ DESTINATION ${header_install_dir}/llvm_libc_wrappers
+ COMPONENT clang-resource-headers)
+
install(
FILES ${openmp_wrapper_files}
DESTINATION ${header_install_dir}/openmp_wrappers
@@ -636,6 +652,12 @@ install(
EXCLUDE_FROM_ALL
COMPONENT openmp-resource-headers)
+install(
+ FILES ${openmp_wrapper_files}
+ DESTINATION ${header_install_dir}/openmp_wrappers
+ EXCLUDE_FROM_ALL
+ COMPONENT openmp-resource-headers)
+
install(
FILES ${utility_files}
DESTINATION ${header_install_dir}
diff --git a/clang/lib/Headers/llvm_libc_wrappers/ctype.h b/clang/lib/Headers/llvm_libc_wrappers/ctype.h
new file mode 100644
index 00000000000000..e20b7bb58f43b2
--- /dev/null
+++ b/clang/lib/Headers/llvm_libc_wrappers/ctype.h
@@ -0,0 +1,85 @@
+//===-- Wrapper for C standard ctype.h declarations on the GPU ------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __CLANG_LLVM_LIBC_WRAPPERS_CTYPE_H__
+#define __CLANG_LLVM_LIBC_WRAPPERS_CTYPE_H__
+
+#if !defined(_OPENMP) && !defined(__HIP__) && !defined(__CUDA__)
+#error "This file is for GPU offloading compilation only"
+#endif
+
+#include_next <ctype.h>
+
+#if __has_include(<llvm-libc-decls/ctype.h>)
+
+#if defined(__HIP__) || defined(__CUDA__)
+#define __LIBC_ATTRS __attribute__((device))
+#endif
+
+// The GNU headers like to provide these as macros, we need to undefine them so
+// they do not conflict with the following definitions for the GPU.
+
+#pragma push_macro("isalnum")
+#pragma push_macro("isalpha")
+#pragma push_macro("isblank")
+#pragma push_macro("iscntrl")
+#pragma push_macro("isdigit")
+#pragma push_macro("isgraph")
+#pragma push_macro("islower")
+#pragma push_macro("isprint")
+#pragma push_macro("ispunct")
+#pragma push_macro("isspace")
+#pragma push_macro("isupper")
+#pragma push_macro("isxdigit")
+#pragma push_macro("tolower")
+#pragma push_macro("toupper")
+
+#undef isalnum
+#undef isalpha
+#undef iscntrl
+#undef isdigit
+#undef islower
+#undef isgraph
+#undef isprint
+#undef ispunct
+#undef isspace
+#undef isupper
+#undef isblank
+#undef isxdigit
+#undef tolower
+#undef toupper
+
+#pragma omp begin declare target
+
+#include <llvm-libc-decls/ctype.h>
+
+#pragma omp end declare target
+
+// Restore the original macros when compiling on the host.
+#if !defined(__NVPTX__) && !defined(__AMDGPU__)
+#pragma pop_macro("isalnum")
+#pragma pop_macro("isalpha")
+#pragma pop_macro("isblank")
+#pragma pop_macro("iscntrl")
+#pragma pop_macro("isdigit")
+#pragma pop_macro("isgraph")
+#pragma pop_macro("islower")
+#pragma pop_macro("isprint")
+#pragma pop_macro("ispunct")
+#pragma pop_macro("isspace")
+#pragma pop_macro("isupper")
+#pragma pop_macro("isxdigit")
+#pragma pop_macro("tolower")
+#pragma pop_macro("toupper")
+#endif
+
+#undef __LIBC_ATTRS
+
+#endif
+
+#endif // __CLANG_LLVM_LIBC_WRAPPERS_CTYPE_H__
diff --git a/clang/lib/Headers/llvm_libc_wrappers/inttypes.h b/clang/lib/Headers/llvm_libc_wrappers/inttypes.h
new file mode 100644
index 00000000000000..415f1e4b7bcab5
--- /dev/null
+++ b/clang/lib/Headers/llvm_libc_wrappers/inttypes.h
@@ -0,0 +1,34 @@
+//===-- Wrapper for C standard inttypes.h declarations on the GPU ---------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __CLANG_LLVM_LIBC_WRAPPERS_INTTYPES_H__
+#define __CLANG_LLVM_LIBC_WRAPPERS_INTTYPES_H__
+
+#if !defined(_OPENMP) && !defined(__HIP__) && !defined(__CUDA__)
+#error "This file is for GPU offloading compilation only"
+#endif
+
+#include_next <inttypes.h>
+
+#if __has_include(<llvm-libc-decls/inttypes.h>)
+
+#if defined(__HIP__) || defined(__CUDA__)
+#define __LIBC_ATTRS __attribute__((device))
+#endif
+
+#pragma omp begin declare target
+
+#include <llvm-libc-decls/inttypes.h>
+
+#pragma omp end declare target
+
+#undef __LIBC_ATTRS
+
+#endif
+
+#endif // __CLANG_LLVM_LIBC_WRAPPERS_INTTYPES_H__
diff --git a/clang/lib/Headers/llvm_libc_wrappers/llvm-libc-decls/README.txt b/clang/lib/Headers/llvm_libc_wrappers/llvm-libc-decls/README.txt
new file mode 100644
index 00000000000000..e012cd9e293126
--- /dev/null
+++ b/clang/lib/Headers/llvm_libc_wrappers/llvm-libc-decls/README.txt
@@ -0,0 +1,6 @@
+LLVM libc declarations
+======================
+
+This directory will be filled by the `libc` project with declarations that are
+availible on the device. Each declaration will use the `__LIBC_ATTRS` attribute
+to control emission on the device side.
diff --git a/clang/lib/Headers/llvm_libc_wrappers/stdio.h b/clang/lib/Headers/llvm_libc_wrappers/stdio.h
new file mode 100644
index 00000000000000..51b0f0e3307772
--- /dev/null
+++ b/clang/lib/Headers/llvm_libc_wrappers/stdio.h
@@ -0,0 +1,34 @@
+//===-- Wrapper for C standard stdio.h declarations on the GPU ------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __CLANG_LLVM_LIBC_WRAPPERS_STDIO_H__
+#define __CLANG_LLVM_LIBC_WRAPPERS_STDIO_H__
+
+#if !defined(_OPENMP) && !defined(__HIP__) && !defined(__CUDA__)
+#error "This file is for GPU offloading compilation only"
+#endif
+
+#include_next <stdio.h>
+
+#if __has_include(<llvm-libc-decls/stdio.h>)
+
+#if defined(__HIP__) || defined(__CUDA__)
+#define __LIBC_ATTRS __attribute__((device))
+#endif
+
+#pragma omp begin declare target
+
+#include <llvm-libc-decls/stdio.h>
+
+#pragma omp end declare target
+
+#undef __LIBC_ATTRS
+
+#endif
+
+#endif // __CLANG_LLVM_LIBC_WRAPPERS_STDIO_H__
diff --git a/clang/lib/Headers/llvm_libc_wrappers/stdlib.h b/clang/lib/Headers/llvm_libc_wrappers/stdlib.h
new file mode 100644
index 00000000000000..9cb2b4e64aa682
--- /dev/null
+++ b/clang/lib/Headers/llvm_libc_wrappers/stdlib.h
@@ -0,0 +1,42 @@
+//===-- Wrapper for C standard stdlib.h declarations on the GPU -----------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __CLANG_LLVM_LIBC_WRAPPERS_STDLIB_H__
+#define __CLANG_LLVM_LIBC_WRAPPERS_STDLIB_H__
+
+#if !defined(_OPENMP) && !defined(__HIP__) && !defined(__CUDA__)
+#error "This file is for GPU offloading compilation only"
+#endif
+
+#include_next <stdlib.h>
+
+#if __has_include(<llvm-libc-decls/stdlib.h>)
+
+#if defined(__HIP__) || defined(__CUDA__)
+#define __LIBC_ATTRS __attribute__((device))
+#endif
+
+#pragma omp begin declare target
+
+// The LLVM C library uses this type so we forward declare it.
+typedef void (*__atexithandler_t)(void);
+
+// Enforce ABI compatibility with the structs used by the LLVM C library.
+_Static_assert(__builtin_offsetof(div_t, quot) == 0, "ABI mismatch!");
+_Static_assert(__builtin_offsetof(ldiv_t, quot) == 0, "ABI mismatch!");
+_Static_assert(__builtin_offsetof(lldiv_t, quot) == 0, "ABI mismatch!");
+
+#include <llvm-libc-decls/stdlib.h>
+
+#pragma omp end declare target
+
+#undef __LIBC_ATTRS
+
+#endif
+
+#endif // __CLANG_LLVM_LIBC_WRAPPERS_STDLIB_H__
diff --git a/clang/lib/Headers/llvm_libc_wrappers/string.h b/clang/lib/Headers/llvm_libc_wrappers/string.h
new file mode 100644
index 00000000000000..0cab5615ad1300
--- /dev/null
+++ b/clang/lib/Headers/llvm_libc_wrappers/string.h
@@ -0,0 +1,48 @@
+//===-- Wrapper for C standard string.h declarations on the GPU -----------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __CLANG_LLVM_LIBC_WRAPPERS_STRING_H__
+#define __CLANG_LLVM_LIBC_WRAPPERS_STRING_H__
+
+#if !defined(_OPENMP) && !defined(__HIP__) && !defined(__CUDA__)
+#error "This file is for GPU offloading compilation only"
+#endif
+
+// The GNU headers provide non C-standard headers when in C++ mode. Manually
+// undefine it here so that the definitions agree with the C standard for our
+// purposes.
+#ifdef __cplusplus
+extern "C" {
+#pragma push_macro("__cplusplus")
+#undef __cplusplus
+#endif
+
+#include_next <string.h>
+
+#pragma pop_macro("__cplusplus")
+#ifdef __cplusplus
+}
+#endif
+
+#if __has_include(<llvm-libc-decls/string.h>)
+
+#if defined(__HIP__) || defined(__CUDA__)
+#define __LIBC_ATTRS __attribute__((device))
+#endif
+
+#pragma omp begin declare target
+
+#include <llvm-libc-decls/string.h>
+
+#pragma omp end declare target
+
+#undef __LIBC_ATTRS
+
+#endif
+
+#endif // __CLANG_LLVM_LIBC_WRAPPERS_STRING_H__
diff --git a/clang/test/Driver/gpu-libc-headers.c b/clang/test/Driver/gpu-libc-headers.c
index de030e647154c7..c6361b4b892d39 100644
--- a/clang/test/Driver/gpu-libc-headers.c
+++ b/clang/test/Driver/gpu-libc-headers.c
@@ -1,6 +1,14 @@
// REQUIRES: nvptx-registered-target
// REQUIRES: amdgpu-registered-target
+// RUN: %clang -### --target=x86_64-unknown-linux-gnu -fopenmp=libomp --sysroot=./ \
+// RUN: -fopenmp-targets=amdgcn-amd-amdhsa -Xopenmp-target=amdgcn-amd-amdhsa --offload-arch=gfx908 \
+// RUN: -nogpulib %s 2>&1 | FileCheck %s --check-prefix=CHECK-HEADERS
+// RUN: %clang -### --target=x86_64-unknown-linux-gnu -fopenmp=libomp --sysroot=./ \
+// RUN: -fopenmp-targets=nvptx64-nvidia-cuda -Xopenmp-target=nvptx64-nvidia-cuda --offload-arch=sm_70 \
+// RUN: -nogpulib %s 2>&1 | FileCheck %s --check-prefix=CHECK-HEADERS
+// CHECK-HEADERS: "-cc1"{{.*}}"-internal-isystem" "{{.*}}include{{.*}}llvm_libc_wrappers"{{.*}}"-isysroot" "./"
+
// RUN: %clang -### --target=amdgcn-amd-amdhsa -mcpu=gfx1030 -nogpulib \
// RUN: -nogpuinc %s 2>&1 | FileCheck %s --check-prefix=CHECK-HEADERS-DISABLED
// RUN: %clang -### --target=amdgcn-amd-amdhsa -mcpu=gfx1030 -nogpulib \
diff --git a/libc/cmake/modules/LLVMLibCHeaderRules.cmake b/libc/cmake/modules/LLVMLibCHeaderRules.cmake
index 20cf43aafe142a..8aff65d9fcd8b5 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 02a5f54175e9ac..94dc65356dabfa 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 cbfb2db6fa4769..24d22680fe525b 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 eef96ad656f897..76a8a110832112 100644
--- a/libc/utils/HdrGen/Generator.h
+++ b/libc/utils/HdrGen/Generator.h
@@ -52,6 +52,7 @@ class Generator {
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 d1487476637062..d3418f206b10e9 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;
}
More information about the cfe-commits
mailing list