[libc-commits] [libc] 55151e1 - [libc] Add initial support for a libc implementation for the GPU

Joseph Huber via libc-commits libc-commits at lists.llvm.org
Tue Nov 29 12:52:06 PST 2022


Author: Joseph Huber
Date: 2022-11-29T14:51:54-06:00
New Revision: 55151e138db1b0c95a97ce14d2dfaf86bb6f713f

URL: https://github.com/llvm/llvm-project/commit/55151e138db1b0c95a97ce14d2dfaf86bb6f713f
DIFF: https://github.com/llvm/llvm-project/commit/55151e138db1b0c95a97ce14d2dfaf86bb6f713f.diff

LOG: [libc] Add initial support for a libc implementation for the GPU

This patch contains the initial support for building LLVM's libc as a
target for the GPU. Currently this only supports a handful of very basic
functions that can be implemented without an operating system. The GPU
code is build using the existing OpenMP toolchain. This allows us to
minimally change the existing codebase and get a functioning static
library. This patch allows users to create a static library called
`libcgpu.a` that contains fat binaries containing device IR.

Current limitations are the lack of test support and the fact that only
one target OS can be built at a time. That is, the user cannot get a
`libc` for Linux and one for the GPU simultaneously.

This introduces two new CMake variables to control the behavior
`LLVM_LIBC_TARET_OS` is exported so the user can now specify it to equal
`"gpu"`. `LLVM_LIBC_GPU_ARCHITECTURES` is also used to configure how
many targets to build for at once.

Depends on D138607

Reviewed By: sivachandra

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

Added: 
    libc/config/gpu/api.td
    libc/config/gpu/entrypoints.txt
    libc/config/gpu/headers.txt

Modified: 
    libc/CMakeLists.txt
    libc/cmake/modules/LLVMLibCArchitectures.cmake
    libc/cmake/modules/LLVMLibCObjectRules.cmake
    libc/src/__support/architectures.h
    libc/src/__support/common.h
    libc/src/string/memory_utils/bcmp_implementations.h
    libc/src/string/memory_utils/memcmp_implementations.h
    libc/src/string/memory_utils/memcpy_implementations.h
    libc/src/string/memory_utils/memmove_implementations.h
    libc/src/string/memory_utils/memset_implementations.h
    libc/utils/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/libc/CMakeLists.txt b/libc/CMakeLists.txt
index 377c871eb2428..2d2cc42655d42 100644
--- a/libc/CMakeLists.txt
+++ b/libc/CMakeLists.txt
@@ -23,13 +23,6 @@ endif()
 # Path libc/scripts directory.
 set(LIBC_BUILD_SCRIPTS_DIR "${LIBC_SOURCE_DIR}/utils/build_scripts")
 
-set(LIBC_TARGET_OS ${CMAKE_SYSTEM_NAME})
-string(TOLOWER ${LIBC_TARGET_OS} LIBC_TARGET_OS)
-
-# Defines LIBC_TARGET_ARCHITECTURE and associated macros.
-include(LLVMLibCArchitectures)
-include(LLVMLibCCheckMPFR)
-
 # Flags to pass down to the compiler while building the libc functions.
 set(LIBC_COMPILE_OPTIONS_DEFAULT "" CACHE STRING "Architecture to tell clang to optimize for (e.g. -march=... or -mcpu=...)")
 
@@ -58,6 +51,31 @@ option(LLVM_LIBC_FULL_BUILD "Build and test LLVM libc as if it is the full libc"
 option(LLVM_LIBC_IMPLEMENTATION_DEFINED_TEST_BEHAVIOR "Build LLVM libc tests assuming our implementation-defined behavior" ON)
 option(LLVM_LIBC_ENABLE_LINTING "Enables linting of libc source files" OFF)
 
+# Set up the target architectures to build for the GPU
+set(ALL_GPU_ARCHITECTURES "sm_35;sm_37;sm_50;sm_52;sm_53;sm_60;sm_61;sm_62;sm_70;sm_72;sm_75;sm_80;sm_86;gfx700;gfx701;gfx801;gfx803;gfx900;gfx902;gfx906;gfx908;gfx90a;gfx90c;gfx940;gfx1010;gfx1030;gfx1031;gfx1032;gfx1033;gfx1034;gfx1035;gfx1036;gfx1100;gfx1101;gfx1102;gfx1103")
+set(LLVM_LIBC_GPU_ARCHITECTURES ${ALL_GPU_ARCHITECTURES} CACHE STRING "List of GPU architectures to support in LLVM libc")
+if (LLVM_LIBC_GPU_ARCHITECTURES STREQUAL "all")
+  set(LIBC_GPU_ARCHITECTURES ${ALL_GPU_ARCHITECTURES})
+else()
+  set(LIBC_GPU_ARCHITECTURES ${LLVM_LIBC_GPU_ARCHITECTURES})
+endif()
+
+set(LLVM_LIBC_TARGET_OS ${CMAKE_SYSTEM_NAME} CACHE STRING "Target operating system for LLVM libc")
+string(TOLOWER ${LLVM_LIBC_TARGET_OS} LIBC_TARGET_OS)
+
+# Defines LIBC_TARGET_ARCHITECTURE and associated macros.
+include(LLVMLibCArchitectures)
+include(LLVMLibCCheckMPFR)
+
+# Ensure the compiler is a valid clang when building the GPU target.
+if(LIBC_TARGET_ARCHITECTURE_IS_GPU AND NOT (CMAKE_CXX_COMPILER_ID MATCHES "[Cc]lang" AND 
+  ${CMAKE_CXX_COMPILER_VERSION} VERSION_EQUAL "${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}.${LLVM_VERSION_PATCH}"))
+  message(FATAL_ERROR "Cannot build GPU library, CMake compiler '${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION}' is not `Clang ${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}.${LLVM_VERSION_PATCH}`")
+endif()
+if(LIBC_TARGET_ARCHITECTURE_IS_GPU AND NOT LLVM_LIBC_FULL_BUILD)
+  message(FATAL_ERROR "Cannot build GPU library, LLVM_LIBC_FULL_BUILD must be enabled")
+endif()
+
 if(LLVM_LIBC_CLANG_TIDY)
   set(LLVM_LIBC_ENABLE_LINTING ON)
 endif()
@@ -156,7 +174,11 @@ if(LLVM_LIBC_FULL_BUILD)
   set(LIBC_COMPONENT libc)
   set(LIBC_INSTALL_DEPENDS "libc;install-libc-headers;libc-startup")
   set(LIBC_INSTALL_TARGET install-libc)
-  set(LIBC_ARCHIVE_NAME c)
+  if(LIBC_TARGET_ARCHITECTURE_IS_GPU)
+    set(LIBC_ARCHIVE_NAME cgpu)
+  else()
+    set(LIBC_ARCHIVE_NAME c)
+  endif()
 else()
   set(LIBC_TARGET llvmlibc)
   set(LIBC_COMPONENT llvmlibc)
@@ -179,8 +201,9 @@ endif()
 # The lib and test directories are added at the very end as tests
 # and libraries potentially draw from the components present in all
 # of the other directories.
+# TODO: Add testing support for the libc GPU target.
 add_subdirectory(lib)
-if(LLVM_INCLUDE_TESTS)
+if(LLVM_INCLUDE_TESTS AND NOT LIBC_TARGET_ARCHITECTURE_IS_GPU)
   add_subdirectory(test)
   add_subdirectory(fuzzing)
 endif()

diff  --git a/libc/cmake/modules/LLVMLibCArchitectures.cmake b/libc/cmake/modules/LLVMLibCArchitectures.cmake
index 8d49054ed048b..9da74c4410d84 100644
--- a/libc/cmake/modules/LLVMLibCArchitectures.cmake
+++ b/libc/cmake/modules/LLVMLibCArchitectures.cmake
@@ -2,7 +2,10 @@
 # Architecture definitions
 # ------------------------------------------------------------------------------
 
-if(CMAKE_SYSTEM_PROCESSOR MATCHES "^mips")
+if(LIBC_TARGET_OS MATCHES "gpu")
+  set(LIBC_TARGET_ARCHITECTURE_IS_GPU TRUE)
+  set(LIBC_TARGET_ARCHITECTURE "gpu")
+elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^mips")
   set(LIBC_TARGET_ARCHITECTURE_IS_MIPS TRUE)
   set(LIBC_TARGET_ARCHITECTURE "mips")
 elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^arm")

diff  --git a/libc/cmake/modules/LLVMLibCObjectRules.cmake b/libc/cmake/modules/LLVMLibCObjectRules.cmake
index e3919ec71f6c6..1ececa200f804 100644
--- a/libc/cmake/modules/LLVMLibCObjectRules.cmake
+++ b/libc/cmake/modules/LLVMLibCObjectRules.cmake
@@ -50,6 +50,17 @@ function(_get_common_compile_options output_var flags)
       list(APPEND compile_options "/arch:AVX2")
     endif()
   endif()
+  if (LIBC_TARGET_ARCHITECTURE_IS_GPU)
+    list(APPEND compile_options "-fopenmp")
+    list(APPEND compile_options "-fopenmp-cuda-mode")
+    foreach(gpu_arch ${LIBC_GPU_ARCHITECTURES})
+      list(APPEND compile_options "--offload-arch=${gpu_arch}")
+    endforeach()
+    list(APPEND compile_options "-nogpulib")
+    list(APPEND compile_options "-nogpuinc")
+    list(APPEND compile_options "-fvisibility=hidden")
+    list(APPEND compile_options "-foffload-lto")
+  endif()
   set(${output_var} ${compile_options} PARENT_SCOPE)
 endfunction()
 

diff  --git a/libc/config/gpu/api.td b/libc/config/gpu/api.td
new file mode 100644
index 0000000000000..2acae4a4e81b0
--- /dev/null
+++ b/libc/config/gpu/api.td
@@ -0,0 +1,18 @@
+include "config/public_api.td"
+
+include "spec/stdc.td"
+
+def NullMacro : MacroDef<"NULL"> {
+  let Defn = [{
+    #define __need_NULL
+    #include <stddef.h>
+  }];
+}
+
+def StringAPI : PublicAPI<"string.h"> {
+  let Types = ["size_t"];
+
+  let Macros = [
+    NullMacro,
+  ];
+}

diff  --git a/libc/config/gpu/entrypoints.txt b/libc/config/gpu/entrypoints.txt
new file mode 100644
index 0000000000000..8b058df246c6a
--- /dev/null
+++ b/libc/config/gpu/entrypoints.txt
@@ -0,0 +1,56 @@
+set(TARGET_LIBC_ENTRYPOINTS
+    # ctype.h entrypoints
+    libc.src.ctype.isalnum
+    libc.src.ctype.isalpha
+    libc.src.ctype.isascii
+    libc.src.ctype.isblank
+    libc.src.ctype.iscntrl
+    libc.src.ctype.isdigit
+    libc.src.ctype.isgraph
+    libc.src.ctype.islower
+    libc.src.ctype.isprint
+    libc.src.ctype.ispunct
+    libc.src.ctype.isspace
+    libc.src.ctype.isupper
+    libc.src.ctype.isxdigit
+    libc.src.ctype.toascii
+    libc.src.ctype.tolower
+    libc.src.ctype.toupper
+
+    # string.h entrypoints
+    libc.src.string.bcmp
+    libc.src.string.bzero
+    libc.src.string.memccpy
+    libc.src.string.memchr
+    libc.src.string.memcmp
+    libc.src.string.memcpy
+    libc.src.string.memmove
+    libc.src.string.mempcpy
+    libc.src.string.memrchr
+    libc.src.string.memset
+    libc.src.string.stpcpy
+    libc.src.string.stpncpy
+    libc.src.string.strcat
+    libc.src.string.strchr
+    libc.src.string.strcmp
+    libc.src.string.strcpy
+    libc.src.string.strcspn
+    libc.src.string.strlcat
+    libc.src.string.strlcpy
+    libc.src.string.strlen
+    libc.src.string.strncat
+    libc.src.string.strncmp
+    libc.src.string.strncpy
+    libc.src.string.strnlen
+    libc.src.string.strpbrk
+    libc.src.string.strrchr
+    libc.src.string.strspn
+    libc.src.string.strstr
+    libc.src.string.strtok
+    libc.src.string.strtok_r
+)
+
+set(TARGET_LLVMLIBC_ENTRYPOINTS
+  ${TARGET_LIBC_ENTRYPOINTS}
+)
+

diff  --git a/libc/config/gpu/headers.txt b/libc/config/gpu/headers.txt
new file mode 100644
index 0000000000000..2280244883de4
--- /dev/null
+++ b/libc/config/gpu/headers.txt
@@ -0,0 +1,4 @@
+set(TARGET_PUBLIC_HEADERS
+    libc.include.ctype
+    libc.include.string
+)

diff  --git a/libc/src/__support/architectures.h b/libc/src/__support/architectures.h
index 23c60a418af9d..d3106daf12caa 100644
--- a/libc/src/__support/architectures.h
+++ b/libc/src/__support/architectures.h
@@ -9,7 +9,19 @@
 #ifndef LLVM_LIBC_SUPPORT_ARCHITECTURES_H
 #define LLVM_LIBC_SUPPORT_ARCHITECTURES_H
 
-#if defined(__pnacl__) || defined(__CLR_VER)
+#if defined(__AMDGPU__)
+#define LLVM_LIBC_ARCH_AMDGPU
+#endif
+
+#if defined(__NVPTX__)
+#define LLVM_LIBC_ARCH_NVPTX
+#endif
+
+#if defined(LLVM_LIBC_ARCH_NVPTX) || defined(LLVM_LIBC_ARCH_AMDGPU)
+#define LLVM_LIBC_ARCH_GPU
+#endif
+
+#if defined(__pnacl__) || defined(__CLR_VER) || defined(LLVM_LIBC_ARCH_GPU)
 #define LLVM_LIBC_ARCH_VM
 #endif
 

diff  --git a/libc/src/__support/common.h b/libc/src/__support/common.h
index 9e28be0ea5f75..6ab9940b71ac1 100644
--- a/libc/src/__support/common.h
+++ b/libc/src/__support/common.h
@@ -25,8 +25,20 @@
 #define LLVM_LIBC_FUNCTION_ATTR
 #endif
 
+// We use OpenMP to declare these functions on the device.
+#define STR(X) #X
+#define LLVM_LIBC_DECLARE_DEVICE(name)                                         \
+  _Pragma(STR(omp declare target to(name) device_type(nohost)))
+
+// GPU targets do not support aliasing and must be declared on the device.
+#if defined(LLVM_LIBC_PUBLIC_PACKAGING) && defined(_OPENMP)
+#define LLVM_LIBC_FUNCTION(type, name, arglist)                                \
+  LLVM_LIBC_FUNCTION_ATTR decltype(__llvm_libc::name)                          \
+      __##name##_impl__ __asm__(#name);                                        \
+  LLVM_LIBC_DECLARE_DEVICE(__##name##_impl__)                                  \
+  type __##name##_impl__ arglist
 // MacOS needs to be excluded because it does not support aliasing.
-#if defined(LLVM_LIBC_PUBLIC_PACKAGING) && (!defined(__APPLE__))
+#elif defined(LLVM_LIBC_PUBLIC_PACKAGING) && (!defined(__APPLE__))
 #define LLVM_LIBC_FUNCTION(type, name, arglist)                                \
   LLVM_LIBC_FUNCTION_ATTR decltype(__llvm_libc::name)                          \
       __##name##_impl__ __asm__(#name);                                        \

diff  --git a/libc/src/string/memory_utils/bcmp_implementations.h b/libc/src/string/memory_utils/bcmp_implementations.h
index 7a7054b3376f9..e7ded19d12066 100644
--- a/libc/src/string/memory_utils/bcmp_implementations.h
+++ b/libc/src/string/memory_utils/bcmp_implementations.h
@@ -166,6 +166,8 @@ static inline BcmpReturnType inline_bcmp(CPtr p1, CPtr p2, size_t count) {
   return inline_bcmp_aarch64(p1, p2, count);
 #elif defined(LLVM_LIBC_ARCH_ARM)
   return inline_bcmp_embedded_tiny(p1, p2, count);
+#elif defined(LLVM_LIBC_ARCH_GPU)
+  return inline_bcmp_embedded_tiny(p1, p2, count);
 #else
 #error "Unsupported platform"
 #endif

diff  --git a/libc/src/string/memory_utils/memcmp_implementations.h b/libc/src/string/memory_utils/memcmp_implementations.h
index b3258b9607a00..33fbd7ca92fb0 100644
--- a/libc/src/string/memory_utils/memcmp_implementations.h
+++ b/libc/src/string/memory_utils/memcmp_implementations.h
@@ -138,6 +138,8 @@ static inline MemcmpReturnType inline_memcmp(CPtr p1, CPtr p2, size_t count) {
 #endif
 #elif defined(LLVM_LIBC_ARCH_ARM)
   return inline_memcmp_embedded_tiny(p1, p2, count);
+#elif defined(LLVM_LIBC_ARCH_GPU)
+  return inline_memcmp_embedded_tiny(p1, p2, count);
 #else
 #error "Unsupported platform"
 #endif

diff  --git a/libc/src/string/memory_utils/memcpy_implementations.h b/libc/src/string/memory_utils/memcpy_implementations.h
index 2fa32e3b6110d..8d8ba6f4e9d6a 100644
--- a/libc/src/string/memory_utils/memcpy_implementations.h
+++ b/libc/src/string/memory_utils/memcpy_implementations.h
@@ -126,6 +126,8 @@ static inline void inline_memcpy(Ptr __restrict dst, CPtr __restrict src,
   return inline_memcpy_aarch64(dst, src, count);
 #elif defined(LLVM_LIBC_ARCH_ARM)
   return inline_memcpy_embedded_tiny(dst, src, count);
+#elif defined(LLVM_LIBC_ARCH_GPU)
+  return inline_memcpy_embedded_tiny(dst, src, count);
 #else
 #error "Unsupported platform"
 #endif

diff  --git a/libc/src/string/memory_utils/memmove_implementations.h b/libc/src/string/memory_utils/memmove_implementations.h
index 91f77a67bf2bc..dfea5fa5900c4 100644
--- a/libc/src/string/memory_utils/memmove_implementations.h
+++ b/libc/src/string/memory_utils/memmove_implementations.h
@@ -103,6 +103,8 @@ static inline void inline_memmove(Ptr dst, CPtr src, size_t count) {
   }
 #elif defined(LLVM_LIBC_ARCH_ARM)
   return inline_memmove_embedded_tiny(dst, src, count);
+#elif defined(LLVM_LIBC_ARCH_GPU)
+  return inline_memmove_embedded_tiny(dst, src, count);
 #else
 #error "Unsupported platform"
 #endif

diff  --git a/libc/src/string/memory_utils/memset_implementations.h b/libc/src/string/memory_utils/memset_implementations.h
index 75ecf164a2b0f..58779f7b1f88f 100644
--- a/libc/src/string/memory_utils/memset_implementations.h
+++ b/libc/src/string/memory_utils/memset_implementations.h
@@ -106,6 +106,8 @@ inline static void inline_memset(Ptr dst, uint8_t value, size_t count) {
   return inline_memset_aarch64<kMaxSize>(dst, value, count);
 #elif defined(LLVM_LIBC_ARCH_ARM)
   return inline_memset_embedded_tiny(dst, value, count);
+#elif defined(LLVM_LIBC_ARCH_GPU)
+  return inline_memset_embedded_tiny(dst, value, count);
 #else
 #error "Unsupported platform"
 #endif

diff  --git a/libc/utils/CMakeLists.txt b/libc/utils/CMakeLists.txt
index 80da547924c14..ef1754165c91a 100644
--- a/libc/utils/CMakeLists.txt
+++ b/libc/utils/CMakeLists.txt
@@ -2,7 +2,7 @@ add_subdirectory(MPFRWrapper)
 add_subdirectory(testutils)
 add_subdirectory(UnitTest)
 
-if(LLVM_LIBC_FULL_BUILD)
+if(LLVM_LIBC_FULL_BUILD AND NOT LIBC_TARGET_ARCHITECTURE_IS_GPU)
   add_subdirectory(IntegrationTest)
   add_subdirectory(tools)
 endif()


        


More information about the libc-commits mailing list