diff --git a/libc/CMakeLists.txt b/libc/CMakeLists.txt --- a/libc/CMakeLists.txt +++ b/libc/CMakeLists.txt @@ -23,13 +23,6 @@ # 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_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 @@ 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 @@ # 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 --- 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 --- a/libc/cmake/modules/LLVMLibCObjectRules.cmake +++ b/libc/cmake/modules/LLVMLibCObjectRules.cmake @@ -50,6 +50,17 @@ 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 --- /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 + }]; +} + +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 --- /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 --- /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 --- 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 --- 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 --- a/libc/src/string/memory_utils/bcmp_implementations.h +++ b/libc/src/string/memory_utils/bcmp_implementations.h @@ -166,6 +166,8 @@ 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 --- a/libc/src/string/memory_utils/memcmp_implementations.h +++ b/libc/src/string/memory_utils/memcmp_implementations.h @@ -138,6 +138,8 @@ #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 --- a/libc/src/string/memory_utils/memcpy_implementations.h +++ b/libc/src/string/memory_utils/memcpy_implementations.h @@ -126,6 +126,8 @@ 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 --- a/libc/src/string/memory_utils/memmove_implementations.h +++ b/libc/src/string/memory_utils/memmove_implementations.h @@ -103,6 +103,8 @@ } #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 --- a/libc/src/string/memory_utils/memset_implementations.h +++ b/libc/src/string/memory_utils/memset_implementations.h @@ -106,6 +106,8 @@ return inline_memset_aarch64(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 --- a/libc/utils/CMakeLists.txt +++ b/libc/utils/CMakeLists.txt @@ -2,7 +2,7 @@ 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()