[libc] Ignore 'errno' on the GPU and support 'atoi'
authorJoseph Huber <jhuber6@vols.utk.edu>
Mon, 24 Apr 2023 23:28:54 +0000 (18:28 -0500)
committerJoseph Huber <jhuber6@vols.utk.edu>
Tue, 25 Apr 2023 17:41:20 +0000 (12:41 -0500)
The 'errno' value is most likely not useful on the GPU and it prevents
us from providing certain functions on the GPU that depend on it, like
`atoi`. This patch makes the necessary changes to support `errno` by
simple replacing it with a consumer class.

Supporting `errno` on the GPU is possible in some aspects. The first
approach would be to use a buffer of shared memory that has enough space
for all threads. Another option would be to change code generation to
support `thread_local` using `address_space(5)` memory allocated at
kernel launch. The former could look like the following, which could be
implemented in a later patch:

```
template <typename T>
using SharedBuffer = T[gpu::MAX_THREADS] [[clang::address_space(3)]];
template <typename T> struct ErrnoSetter {
  constexpr ErrnoSetter(SharedBuffer<T> &storage) : storage(storage) {}
  SharedBuffer<T> &storage;
  void operator=(const T &val) { storage[gpu::get_thread_id()] = val; }
};

static SharedBuffer<int> thread_local_buffer [[clang::loader_uninitialized]];
ErrnoSetter<int> __llvmlibc_internal_errno(thread_local_buffer);
```

Reviewed By: sivachandra

Differential Revision: https://reviews.llvm.org/D149107

libc/config/gpu/entrypoints.txt
libc/config/gpu/headers.txt
libc/include/errno.h.def
libc/src/errno/libc_errno.cpp
libc/src/errno/libc_errno.h

index 4c78b2f..69af9ff 100644 (file)
@@ -53,6 +53,9 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.string.strstr
     libc.src.string.strtok
     libc.src.string.strtok_r
+
+    # stdlib.h entrypoints
+    libc.src.stdlib.atoi
 )
 
 set(TARGET_LLVMLIBC_ENTRYPOINTS
index 2280244..fd753a4 100644 (file)
@@ -1,4 +1,5 @@
 set(TARGET_PUBLIC_HEADERS
     libc.include.ctype
     libc.include.string
+    libc.include.stdlib
 )
index 580a53f..d8f79dd 100644 (file)
@@ -43,7 +43,9 @@
 #include <llvm-libc-macros/generic-error-number-macros.h>
 #endif
 
+#if !defined(__AMDGPU__) && !defined(__NVPTX__)
 extern _Thread_local int __llvmlibc_errno;
 #define errno __llvmlibc_errno
+#endif
 
 #endif // LLVM_LIBC_ERRNO_H
index b8c276c..26bd9d9 100644 (file)
@@ -6,6 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "src/__support/macros/properties/architectures.h"
+
 namespace __llvm_libc {
 
 extern "C" {
@@ -18,9 +20,17 @@ extern "C" {
 // macro defined in LLVM libc's public errno.h header file.
 // TODO: Use a macro to distinguish full build and overlay build which can be
 //       used to exclude __llvmlibc_errno under overlay build.
+#ifdef LIBC_TARGET_ARCH_IS_GPU
+ErrnoConsumer __llvmlibc_errno;
+#else
 thread_local int __llvmlibc_errno;
+#endif // LIBC_TARGET_ARCH_IS_GPU
+#else
+#ifdef LIBC_TARGET_ARCH_IS_GPU
+ErrnoConsumer __llvmlibc_internal_errno;
 #else
 thread_local int __llvmlibc_internal_errno;
+#endif // LIBC_TARGET_ARCH_IS_GPU
 #endif
 } // extern "C"
 
index 28f8d0d..585da15 100644 (file)
@@ -9,21 +9,42 @@
 #ifndef LLVM_LIBC_SRC_ERRNO_LLVMLIBC_ERRNO_H
 #define LLVM_LIBC_SRC_ERRNO_LLVMLIBC_ERRNO_H
 
+#include "src/__support/macros/properties/architectures.h"
+
 #include <errno.h>
 
+// If we are targeting the GPU we currently don't support 'errno'. We simply
+// consume it.
+#ifdef LIBC_TARGET_ARCH_IS_GPU
+namespace __llvm_libc {
+struct ErrnoConsumer {
+  void operator=(int) {}
+};
+} // namespace __llvm_libc
+#endif
+
 // All of the libc runtime and test code should use the "libc_errno" macro. They
 // should not refer to the "errno" macro directly.
 #ifdef LIBC_COPT_PUBLIC_PACKAGING
+#ifdef LIBC_TARGET_ARCH_IS_GPU
+extern "C" __llvm_libc::ErrnoConsumer __llvmlibc_errno;
+#define libc_errno __llvmlibc_errno
+#else
 // This macro will resolve to errno from the errno.h file included above. Under
 // full build, this will be LLVM libc's errno. In overlay build, it will be
 // system libc's errno.
 #define libc_errno errno
+#endif
 #else
 namespace __llvm_libc {
 
+#ifdef LIBC_TARGET_ARCH_IS_GPU
+extern "C" ErrnoConsumer __llvmlibc_internal_errno;
+#else // LIBC_TARGET_ARCH_IS_GPU
 extern "C" {
 extern thread_local int __llvmlibc_internal_errno;
 } // extern "C"
+#endif
 
 // TODO: After all of libc/src and libc/test are switched over to use
 // libc_errno, this header file will be "shipped" via an add_entrypoint_object