| cmake_minimum_required(VERSION 3.20.0) |
| |
| if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) |
| project(libclc VERSION 0.2.0 LANGUAGES CXX C) |
| endif() |
| set(LLVM_SUBPROJECT_TITLE "libclc") |
| |
| set(CMAKE_CXX_STANDARD 17) |
| |
| # Add path for custom modules |
| list( INSERT CMAKE_MODULE_PATH 0 "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules" ) |
| |
| enable_language( CLC ) |
| |
| include( AddLibclc ) |
| |
| include( GNUInstallDirs ) |
| |
| set( LIBCLC_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR} ) |
| |
| option( |
| LIBCLC_USE_SPIRV_BACKEND "Build SPIR-V targets with the SPIR-V backend." OFF |
| ) |
| |
| # List of all supported architectures. |
| set( LIBCLC_ARCHS_NVPTX nvptx64 ) |
| set( LIBCLC_ARCHS_AMDGPU amdgpu amdgcn ) |
| set( LIBCLC_ARCHS_SPIRV spirv spirv32 spirv64 ) |
| set( LIBCLC_ARCHS_ALL ${LIBCLC_ARCHS_AMDGPU} ${LIBCLC_ARCHS_NVPTX} ${LIBCLC_ARCHS_SPIRV} ) |
| |
| set(LIBCLC_TARGET ${LLVM_DEFAULT_TARGET_TRIPLE}) |
| |
| if(NOT LIBCLC_TARGET) |
| message(FATAL_ERROR "libclc target is empty\n") |
| endif() |
| |
| # Parse the target triple into arch and OS components. |
| string(REPLACE "-" ";" triple_components ${LIBCLC_TARGET}) |
| list(GET triple_components 0 LIBCLC_TARGET_ARCH) |
| list(GET triple_components 2 LIBCLC_TARGET_OS) |
| |
| if(NOT "${LIBCLC_TARGET_ARCH}" IN_LIST LIBCLC_ARCHS_ALL) |
| message(FATAL_ERROR "Unknown libclc target architecture: ${LIBCLC_TARGET_ARCH}\n" |
| "Target was: ${LIBCLC_TARGET}\n" |
| "Valid architectures are: ${LIBCLC_ARCHS_ALL}\n") |
| endif() |
| |
| if( LIBCLC_STANDALONE_BUILD OR CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR ) |
| set( LIBCLC_STANDALONE_BUILD TRUE ) |
| |
| find_package(LLVM REQUIRED HINTS "${LLVM_CMAKE_DIR}") |
| include(AddLLVM) |
| |
| foreach( tool IN ITEMS llvm-link opt ) |
| find_program( LLVM_TOOL_${tool} ${tool} PATHS ${LLVM_TOOLS_BINARY_DIR} NO_DEFAULT_PATH ) |
| set( ${tool}_exe ${LLVM_TOOL_${tool}} ) |
| set( ${tool}_target ) |
| endforeach() |
| |
| # Setup the paths where libclc runtimes should be stored. |
| set( LIBCLC_OUTPUT_LIBRARY_DIR ${CMAKE_CURRENT_BINARY_DIR} ) |
| set( LIBCLC_INSTALL_DIR ${CMAKE_INSTALL_DATADIR}/clc ) |
| else() |
| set( LIBCLC_STANDALONE_BUILD FALSE ) |
| |
| # Note that we check this later (for both build types) but we can provide a |
| # more useful error message when built in-tree. We assume that LLVM tools are |
| # always available so don't warn here. |
| if( NOT LLVM_RUNTIMES_BUILD AND NOT clang IN_LIST LLVM_ENABLE_PROJECTS ) |
| message(FATAL_ERROR "Clang is not enabled, but is required to build libclc in-tree") |
| endif() |
| |
| # The package version is required to find the resource directory. |
| if( LLVM_PACKAGE_VERSION AND NOT PACKAGE_VERSION ) |
| set( PACKAGE_VERSION "${LLVM_PACKAGE_VERSION}" ) |
| endif() |
| |
| get_host_tool_path( llvm-link LLVM_LINK llvm-link_exe llvm-link_target ) |
| get_host_tool_path( opt OPT opt_exe opt_target ) |
| |
| # Setup the paths where libclc runtimes should be stored. By default, in an |
| # in-tree build we place the libraries in clang's resource driectory. |
| include(GetClangResourceDir) |
| get_clang_resource_dir( LIBCLC_INSTALL_DIR ) |
| cmake_path( APPEND LIBCLC_INSTALL_DIR "lib" ) |
| |
| cmake_path( GET LLVM_LIBRARY_OUTPUT_INTDIR PARENT_PATH LIBCLC_OUTPUT_LIBRARY_DIR ) |
| cmake_path( APPEND LIBCLC_OUTPUT_LIBRARY_DIR ${LIBCLC_INSTALL_DIR} ) |
| endif() |
| |
| if( NOT LIBCLC_USE_SPIRV_BACKEND ) |
| # llvm-spirv is an optional dependency, used to build spirv-* targets when |
| # the SPIR-V backend hasn't been requested. It may be provided in-tree or |
| # externally. |
| if( TARGET llvm-spirv ) |
| get_host_tool_path( llvm-spirv LLVM_SPIRV llvm-spirv_exe llvm-spirv_target ) |
| else() |
| find_program( LLVM_SPIRV llvm-spirv HINTS ${LLVM_TOOLS_BINARY_DIR} ) |
| set( llvm-spirv_exe "${LLVM_SPIRV}" ) |
| endif() |
| endif() |
| |
| message(STATUS "libclc target '${LIBCLC_TARGET}' is enabled") |
| |
| # Map the LLVM target architecture to the standard directory name. |
| if(LIBCLC_TARGET_ARCH IN_LIST LIBCLC_ARCHS_AMDGPU) |
| set(LIBCLC_ARCH_DIR amdgpu) |
| elseif(LIBCLC_TARGET_ARCH IN_LIST LIBCLC_ARCHS_NVPTX) |
| set(LIBCLC_ARCH_DIR nvptx) |
| elseif(LIBCLC_TARGET_ARCH IN_LIST LIBCLC_ARCHS_SPIRV) |
| set(LIBCLC_ARCH_DIR spirv) |
| endif() |
| |
| if(LIBCLC_TARGET_ARCH IN_LIST LIBCLC_ARCHS_SPIRV) |
| if(NOT LIBCLC_TARGET_OS STREQUAL vulkan AND NOT LIBCLC_USE_SPIRV_BACKEND AND NOT llvm-spirv_exe) |
| message(FATAL_ERROR "SPIR-V backend or llvm-spirv is required for libclc ${LIBCLC_TARGET}") |
| endif() |
| endif() |
| |
| foreach( tool IN ITEMS opt llvm-link ) |
| if( NOT EXISTS "${${tool}_exe}" AND "${${tool}_target}" STREQUAL "" ) |
| message( FATAL_ERROR "libclc toolchain incomplete - missing tool ${tool}!" ) |
| endif() |
| endforeach() |
| |
| # Determine the clang target triple. |
| set(clang_triple ${LIBCLC_TARGET}) |
| |
| # Address space values. |
| set(private_addrspace_val 0) |
| set(generic_addrspace_val 0) |
| if(LIBCLC_TARGET_ARCH IN_LIST LIBCLC_ARCHS_AMDGPU) |
| set(private_addrspace_val 5) |
| endif() |
| if(LIBCLC_TARGET_ARCH IN_LIST LIBCLC_ARCHS_SPIRV AND NOT LIBCLC_TARGET_OS STREQUAL vulkan) |
| set(generic_addrspace_val 4) |
| endif() |
| |
| # Target-specific compile flags and defines. |
| set(target_compile_flags) |
| set(target_extra_defines) |
| set(opt_flags -O3) |
| |
| if(LIBCLC_TARGET_ARCH IN_LIST LIBCLC_ARCHS_SPIRV) |
| if(LIBCLC_TARGET_OS STREQUAL vulkan) |
| list(APPEND target_compile_flags -Wno-unknown-assumption -U__opencl_c_int64) |
| else() |
| list(APPEND target_compile_flags -O0 -finline-hint-functions) |
| list(APPEND target_extra_defines CLC_SPIRV) |
| set(opt_flags) |
| endif() |
| elseif(LIBCLC_TARGET_ARCH IN_LIST LIBCLC_ARCHS_AMDGPU) |
| list(APPEND target_compile_flags "SHELL:-Xclang -mcode-object-version=none") |
| endif() |
| if(LIBCLC_TARGET_ARCH IN_LIST LIBCLC_ARCHS_AMDGPU OR LIBCLC_TARGET_ARCH IN_LIST LIBCLC_ARCHS_NVPTX) |
| list(APPEND target_compile_flags -fvisibility=hidden) |
| list(APPEND target_compile_flags "SHELL:-Xclang -fapply-global-visibility-to-externs") |
| endif() |
| |
| # Common compile options shared by CLC and OpenCL libraries. |
| set(compile_flags |
| -flto |
| --target=${clang_triple} |
| -nostdlib |
| -nostdlibinc |
| -cl-no-stdinc |
| -cl-std=CL3.0 |
| -include opencl-c-base.h |
| -Werror=undef |
| -Wall |
| -Wextra |
| -fdiscard-value-names |
| -ffp-contract=fast-honor-pragmas |
| -fdenormal-fp-math=dynamic |
| ${target_compile_flags} |
| ) |
| |
| set(common_defs |
| ${target_extra_defines} |
| __CLC_PRIVATE_ADDRSPACE_VAL=${private_addrspace_val} |
| __CLC_GENERIC_ADDRSPACE_VAL=${generic_addrspace_val} |
| ) |
| |
| add_custom_target(libclc ALL) |
| add_custom_target(libclc-opencl-builtins COMMENT "Build libclc OpenCL builtins") |
| add_dependencies(libclc libclc-opencl-builtins) |
| |
| # Configure the CLC internal builtins library. |
| set(LIBCLC_CLC_TARGET clc) |
| libclc_add_builtin_library(${LIBCLC_CLC_TARGET} |
| COMPILE_OPTIONS ${compile_flags} |
| INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/clc/include |
| COMPILE_DEFINITIONS ${common_defs} |
| SOURCE_SUB_DIR clc |
| FOLDER "libclc/Device IR/CLC" |
| ) |
| |
| # Build, link, and install the final OpenCL builtins library. |
| set(LIBCLC_OPENCL_TARGET opencl) |
| libclc_add_library(libclc-${LIBCLC_TARGET} |
| ARCH ${LIBCLC_TARGET_ARCH} |
| TRIPLE ${clang_triple} |
| TARGET_TRIPLE ${LIBCLC_TARGET} |
| COMPILE_OPTIONS ${compile_flags} "SHELL:-Xclang -fdeclare-opencl-builtins" |
| INCLUDE_DIRS |
| ${CMAKE_CURRENT_SOURCE_DIR}/clc/include |
| ${CMAKE_CURRENT_SOURCE_DIR}/opencl/include |
| COMPILE_DEFINITIONS ${common_defs} |
| INTERNALIZE_LIBRARIES ${LIBCLC_CLC_TARGET} |
| OPT_FLAGS ${opt_flags} |
| SOURCE_TARGET ${LIBCLC_OPENCL_TARGET} |
| SOURCE_SUB_DIR opencl |
| OUTPUT_FILENAME libclc |
| PARENT_TARGET libclc-opencl-builtins |
| ) |
| |
| if(LLVM_INCLUDE_TESTS) |
| add_subdirectory(test) |
| endif() |