This is an archive of the discontinued LLVM Phabricator instance.

[libc] Add support for creating wrapper headers for offloading in clang
ClosedPublic

Authored by jhuber6 on Jun 28 2023, 6:21 PM.

Details

Summary

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.

Diff Detail

Event Timeline

jhuber6 created this revision.Jun 28 2023, 6:21 PM
Herald added projects: Restricted Project, Restricted Project. · View Herald TranscriptJun 28 2023, 6:21 PM
jhuber6 requested review of this revision.Jun 28 2023, 6:21 PM
Herald added a project: Restricted Project. · View Herald TranscriptJun 28 2023, 6:21 PM

For reference, here is what one of the newly generated headers looks like that is used.

#ifndef __LLVM_LIBC_DECLARATIONS_STDIO_H
#define __LLVM_LIBC_DECLARATIONS_STDIO_H

#ifndef __LIBC_ATTRS
#define __LIBC_ATTRS
#endif

#ifdef __cplusplus
extern "C" {
#endif

int puts(const char *__restrict) __LIBC_ATTRS;

int fputs(const char *__restrict, FILE *__restrict) __LIBC_ATTRS;

extern FILE * stdin __LIBC_ATTRS;
extern FILE * stdout __LIBC_ATTRS;
extern FILE * stderr __LIBC_ATTRS;

#ifdef __cplusplus
}
#endif

Unfortunately I have already run into a few problems with the re-declarations given the GNU libc headers. Here is the error message when including string.h now,

/home/jhuber/Documents/llvm/clang/lib/clang/17/include/llvm_libc_wrappers/llvm-libc-decls/string.h:54:8: error: 'strstr' is missing exception specification 'noexcept(true)'
   54 | char * strstr(const char *, const char *) __LIBC_ATTRS;
      |        ^
/usr/include/string.h:343:1: note: previous declaration is here
  343 | strstr (const char *__haystack, const char *__needle) __THROW
      | ^
5 errors generated.

This occurs for memchr, strchr, strpbrk, strchr, and strstr. If you define __LIBC_ATTRS to the noexcept(true) you get a different error,

/home/jhuber/Documents/llvm/clang/lib/clang/17/include/llvm_libc_wrappers/llvm-libc-decls/string.h:54:8: error: functions that differ only in their return type cannot be overloaded
   54 | char * strstr(const char *, const char *) __LIBC_ATTRS;
      | ~~~~~~ ^
/usr/include/string.h:343:1: note: previous definition is here
  343 | __extern_always_inline const char *
      |                              ~~~~~~
  344 | strstr (const char *__haystack, const char *__needle) __THROW
      | ^

Looking at the definitions, they look like this in the GNU headers,

extern char *strstr (char *__haystack, const char *__needle)    
     __THROW __asm ("strstr") __attribute_pure__ __nonnull ((1, 2));    
extern const char *strstr (const char *__haystack, const char *__needle)    
     __THROW __asm ("strstr") __attribute_pure__ __nonnull ((1, 2));

Does anyone have any suggestions on working around this? The other supported headers work as far as I can tell.

jhuber6 updated this revision to Diff 535600.Jun 28 2023, 6:55 PM

Hack around the string problem. GNU likes to provide different prototypes for C++. Manually disable this for now. Unsure if this will have reasonable fallout, but it seems bizarre that string.h would define C++ constructs?

jhuber6 updated this revision to Diff 535835.Jun 29 2023, 8:54 AM

Semi-fix hack for string.h and fix ctype.h. string.h required undefining
C++ mode so we didn't use weird GNU C++ handling, which we then still need the
extern "C" for. The cytpe problems come from GNU defining everything as a
macro so it fails to redeclare.

The amount of hacks that just this has required so far is fairly convincing to
me that this is the more correct solution and should be separate from libc.

jhuber6 updated this revision to Diff 535983.Jun 29 2023, 1:42 PM

Add some checks to stdlib.h to ensure ABI compatibility for div functions.

Because this patch makes us always include the LLVM libc repo when offloading,
we mask off the wrappers if they were not installed by libc, so this is simply
a passthrough include header if the user didn't build with LLVM C library for
the GPU.

jhuber6 updated this revision to Diff 537535.Jul 5 2023, 3:59 PM

Fix guard on the headers for offloading languages

The libc specific changes are really minimal straightforward. The GPU side, the clang driver changes etc. need a review by a GPU expert.

libc/include/CMakeLists.txt
8

Where does this come from?

jhuber6 added inline comments.Jul 6 2023, 4:34 AM
libc/include/CMakeLists.txt
8

It's a global CMake module that LLVM provides in cmake/Modules/GetClangResourceDir.cmake. I only expect the GPU build to be done in-tree.

JonChesterfield accepted this revision.Jul 6 2023, 8:21 AM

OK, let's go with this. It's a fairly alarming mess localised quite closely to the language that requires the complexity, minimal damage to libc itself.

This revision is now accepted and ready to land.Jul 6 2023, 8:21 AM
jdoerfert accepted this revision.Jul 6 2023, 9:47 AM

If it compiles, ship it.

jhuber6 updated this revision to Diff 537787.Jul 6 2023, 10:40 AM

Changing this to only apply to OpenMP for now. It breaks CUDA / HIP builds
because they already have forward declarations of things like malloc or
memcpy on the GPU that conflict. We'll need to clean those up later.

This revision was landed with ongoing or failed builds.Jul 6 2023, 4:11 PM
This revision was automatically updated to reflect the committed changes.