Skip to content

Commit

Permalink
[libc] Add support for creating wrapper headers for offloading in clang
Browse files Browse the repository at this point in the history
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
  • Loading branch information
jhuber6 committed Jul 7, 2023
1 parent 310f839 commit 2a65d03
Show file tree
Hide file tree
Showing 14 changed files with 417 additions and 9 deletions.
19 changes: 13 additions & 6 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
24 changes: 23 additions & 1 deletion clang/lib/Headers/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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 )

Expand Down Expand Up @@ -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")

Expand All @@ -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})
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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}
Expand Down
85 changes: 85 additions & 0 deletions clang/lib/Headers/llvm_libc_wrappers/ctype.h
Original file line number Diff line number Diff line change
@@ -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__
34 changes: 34 additions & 0 deletions clang/lib/Headers/llvm_libc_wrappers/inttypes.h
Original file line number Diff line number Diff line change
@@ -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__
Original file line number Diff line number Diff line change
@@ -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.
34 changes: 34 additions & 0 deletions clang/lib/Headers/llvm_libc_wrappers/stdio.h
Original file line number Diff line number Diff line change
@@ -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__
42 changes: 42 additions & 0 deletions clang/lib/Headers/llvm_libc_wrappers/stdlib.h
Original file line number Diff line number Diff line change
@@ -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__
48 changes: 48 additions & 0 deletions clang/lib/Headers/llvm_libc_wrappers/string.h
Original file line number Diff line number Diff line change
@@ -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__
8 changes: 8 additions & 0 deletions clang/test/Driver/gpu-libc-headers.c
Original file line number Diff line number Diff line change
@@ -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 \
Expand Down
Loading

0 comments on commit 2a65d03

Please sign in to comment.