# Converts a list of relative source paths to absolute paths and exports # it to the parent scope. macro(libclc_configure_source_list variable path) set(${variable} ${ARGN}) list(TRANSFORM ${variable} PREPEND "${path}/") set(${variable} ${${variable}} PARENT_SCOPE) endmacro() # Appends a compile option to the given source files. Paths are relative # to `path` and the property is set in the top-level libclc directory scope. macro(libclc_configure_source_options path option) set(_option_srcs ${ARGN}) list(TRANSFORM _option_srcs PREPEND "${path}/") set_property(SOURCE ${_option_srcs} DIRECTORY ${LIBCLC_SOURCE_DIR} APPEND PROPERTY COMPILE_OPTIONS ${option} ) endmacro() # Merges OpenCL C source file lists with priority deduplication. # # All arguments after the output variable name are treated as source file # paths. When multiple files share the same basename, the last occurrence # wins. This allows target-specific files to automatically override generic # ones. function(libclc_merge_sources output) set(all_sources ${ARGN}) set(result) set(seen_names) list(REVERSE all_sources) foreach(f ${all_sources}) get_filename_component(name "${f}" NAME) if(NOT name IN_LIST seen_names) list(APPEND seen_names "${name}") list(PREPEND result "${f}") endif() endforeach() set(${output} ${result} PARENT_SCOPE) endfunction() # Creates a static library target for libclc builtins. Derives include # directories to locate `.inc` files in the same directory. function(add_libclc_builtin_library target_name) cmake_parse_arguments(ARG "" "FOLDER" "SOURCES;COMPILE_OPTIONS;INCLUDE_DIRS;COMPILE_DEFINITIONS" ${ARGN} ) set(_inc_dirs) foreach(f ${ARG_SOURCES}) get_filename_component(dir ${f} DIRECTORY) list(APPEND _inc_dirs ${dir}) endforeach() list(REMOVE_DUPLICATES _inc_dirs) add_library(${target_name} STATIC ${ARG_SOURCES}) target_compile_options(${target_name} PRIVATE ${ARG_COMPILE_OPTIONS}) target_include_directories(${target_name} PRIVATE ${ARG_INCLUDE_DIRS} ${_inc_dirs} ) target_compile_definitions(${target_name} PRIVATE ${ARG_COMPILE_DEFINITIONS}) set_target_properties(${target_name} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} FOLDER ${ARG_FOLDER} ) endfunction() # Links one or more libclc builtin libraries together, optionally # internalizing dependencies, then produces a final .bc or .spv file. function(link_libclc_builtin_library target_name) cmake_parse_arguments(ARG "" "ARCH;TRIPLE;FOLDER;OUTPUT_FILENAME" "LIBRARIES;INTERNALIZE_LIBRARIES;OPT_FLAGS" ${ARGN} ) if(NOT ARG_OUTPUT_FILENAME) message(FATAL_ERROR "OUTPUT_FILENAME is required for link_libclc_builtin_library") endif() if(NOT ARG_LIBRARIES) message(FATAL_ERROR "LIBRARIES is required for link_libclc_builtin_library") endif() set(library_dir ${LIBCLC_OUTPUT_LIBRARY_DIR}/${ARG_TRIPLE}) file(MAKE_DIRECTORY ${library_dir}) set(linked_bc ${CMAKE_CURRENT_BINARY_DIR}/${target_name}.linked.bc) set(link_cmd ${llvm-link_exe}) foreach(lib ${ARG_LIBRARIES}) list(APPEND link_cmd $) endforeach() if(ARG_INTERNALIZE_LIBRARIES) list(APPEND link_cmd --internalize --only-needed) foreach(lib ${ARG_INTERNALIZE_LIBRARIES}) list(APPEND link_cmd $) endforeach() endif() list(APPEND link_cmd -o ${linked_bc}) set(link_deps ${llvm-link_target} ${ARG_LIBRARIES} ${ARG_INTERNALIZE_LIBRARIES} ) add_custom_command(OUTPUT ${linked_bc} COMMAND ${link_cmd} DEPENDS ${link_deps} ) if(ARG_ARCH STREQUAL spirv OR ARG_ARCH STREQUAL spirv64) # SPIR-V targets produce a .spv file from the linked bitcode. set(builtins_lib ${library_dir}/${ARG_OUTPUT_FILENAME}.spv) if(LIBCLC_USE_SPIRV_BACKEND) add_custom_command(OUTPUT ${builtins_lib} COMMAND ${CMAKE_CLC_COMPILER} -c --target=${ARG_TRIPLE} -mllvm --spirv-ext=+SPV_KHR_fma -x ir -o ${builtins_lib} ${linked_bc} DEPENDS ${linked_bc} ) else() add_custom_command(OUTPUT ${builtins_lib} COMMAND ${llvm-spirv_exe} --spirv-max-version=1.1 --spirv-ext=+SPV_KHR_fma -o ${builtins_lib} ${linked_bc} DEPENDS ${linked_bc} ) endif() else() # All other targets produce an optimized .bc file. set(builtins_lib ${library_dir}/${ARG_OUTPUT_FILENAME}.bc) add_custom_command(OUTPUT ${builtins_lib} COMMAND ${opt_exe} ${ARG_OPT_FLAGS} -o ${builtins_lib} ${linked_bc} DEPENDS ${opt_target} ${linked_bc} ) endif() add_custom_target(${target_name} ALL DEPENDS ${builtins_lib}) set_target_properties(${target_name} PROPERTIES TARGET_FILE ${builtins_lib} FOLDER ${ARG_FOLDER} ) endfunction() # Builds a builtins library from sources, links it with any internalized # dependencies via link_libclc_builtin_library, and adds a verification test # for unresolved symbols. function(add_libclc_library target_name) cmake_parse_arguments(ARG "" "ARCH;TRIPLE;TARGET_TRIPLE;OUTPUT_FILENAME;PARENT_TARGET" "SOURCES;COMPILE_OPTIONS;INCLUDE_DIRS;COMPILE_DEFINITIONS;INTERNALIZE_LIBRARIES;OPT_FLAGS" ${ARGN} ) if(NOT ARG_OUTPUT_FILENAME) message(FATAL_ERROR "OUTPUT_FILENAME is required for add_libclc_library") endif() if(NOT ARG_PARENT_TARGET) message(FATAL_ERROR "PARENT_TARGET is required for add_libclc_library") endif() if(NOT ARG_SOURCES) message(FATAL_ERROR "SOURCES is required for add_libclc_library") endif() set(builtins_target ${target_name}_clc_builtins) add_libclc_builtin_library(${builtins_target} SOURCES ${ARG_SOURCES} COMPILE_OPTIONS ${ARG_COMPILE_OPTIONS} INCLUDE_DIRS ${ARG_INCLUDE_DIRS} COMPILE_DEFINITIONS ${ARG_COMPILE_DEFINITIONS} FOLDER "libclc/Device IR/Intermediate" ) link_libclc_builtin_library(${target_name} ARCH ${ARG_ARCH} TRIPLE ${ARG_TRIPLE} LIBRARIES ${builtins_target} INTERNALIZE_LIBRARIES ${ARG_INTERNALIZE_LIBRARIES} OPT_FLAGS ${ARG_OPT_FLAGS} OUTPUT_FILENAME "${ARG_OUTPUT_FILENAME}" FOLDER "libclc/Device IR/Library" ) add_dependencies(${ARG_PARENT_TARGET} ${target_name}) set(builtins_file $) install(FILES ${builtins_file} DESTINATION ${LIBCLC_INSTALL_DIR}/${ARG_TRIPLE} COMPONENT ${ARG_PARENT_TARGET} ) endfunction()