Files
UnrealEngine/Engine/Source/ThirdParty/Intel/ISPC/ispc-1.24.0/ispcrt/cmake/ispc.cmake
2025-05-18 13:04:45 +08:00

684 lines
26 KiB
CMake

## Copyright 2020-2023 Intel Corporation
## SPDX-License-Identifier: BSD-3-Clause
###############################################################################
## Generic ISPC macros/options ################################################
###############################################################################
option(BUILD_GPU "Build GPU code paths?" ON)
set(ISPC_INCLUDE_DIR "")
macro (include_directories_ispc)
list(APPEND ISPC_INCLUDE_DIR ${ARGN})
endmacro ()
set(ISPC_DEFINITIONS "")
macro (add_definitions_ispc)
list(APPEND ISPC_DEFINITIONS ${ARGN})
endmacro ()
# We track DPCPP/ESIMD libraries that an ISPC GPU target links separately to
# make some of the generator expressions easier to write. Instead of having
# to do some list filtering on the single LINK_LIBRARIES property and do some
# name matching heuristics we can just check this property to see if we link
# and DPCPP libraries.
define_property(TARGET PROPERTY ISPC_DPCPP_LINK_LIBRARIES
BRIEF_DOCS "Tracks list of DPCPP libraries linked by an ISPC GPU target"
FULL_DOCS "Tracks list of DPCPP libraries linked by an ISPC GPU target"
)
define_property(TARGET PROPERTY ISPC_DPCPP_LINKING_ESIMD
BRIEF_DOCS "Tracks if the DPCPP libraries linked by the ISPC library are ESIMD"
FULL_DOCS "Tracks if the DPCPP libraries linked by the ISPC library are ESIMD"
)
###############################################################################
## CPU specific macros/options ################################################
###############################################################################
## Find ISPC ##
find_program(ISPC_EXECUTABLE ispc HINTS ${ISPC_DIR_HINT} DOC "Path to the ISPC executable.")
if (NOT ISPC_EXECUTABLE)
message(FATAL_ERROR "Could not find ISPC. Exiting.")
else()
# Execute "ispc --version" and parse the version
execute_process(COMMAND ${ISPC_EXECUTABLE} "--version"
OUTPUT_VARIABLE ISPC_INFO)
string(REGEX MATCH "(.*), ([0-9]*\.[0-9]*\.[0-9]*[a-z]*) (.*)" _ ${ISPC_INFO})
set(ISPC_VERSION ${CMAKE_MATCH_2})
message(STATUS "Found ISPC v${ISPC_VERSION}: ${ISPC_EXECUTABLE}")
# Execute "ispc --help" and parse supported archs
execute_process(COMMAND ${ISPC_EXECUTABLE} "--help"
OUTPUT_VARIABLE ISPC_HELP)
string(REGEX MATCH "--arch={((([a-z,0-9,-])+, |([a-z,0-9,-])+)+)}" _ ${ISPC_HELP})
set(ISPC_ARCHS ${CMAKE_MATCH_1})
if ("${ISPC_ARCHS}" STREQUAL "")
message(WARNING "Can't determine ISPC supported architectures.")
else()
message(STATUS "ISPC supports: ${ISPC_ARCHS}")
string(REPLACE ", " ";" ISPC_ARCHS_LIST ${ISPC_ARCHS})
endif()
endif()
## ISPC config options ##
option(ISPC_FAST_MATH "enable ISPC fast-math optimizations" OFF)
mark_as_advanced(ISPC_FAST_MATH)
set(ISPC_ADDRESSING 32 CACHE STRING "32 vs 64 bit addressing in ispc")
set_property(CACHE ISPC_ADDRESSING PROPERTY STRINGS 32 64)
mark_as_advanced(ISPC_ADDRESSING)
macro(define_ispc_supported_arch ARCH_NAME ARCH_FILTER)
set(ISPC_ARCHS_${ARCH_NAME}_LIST ${ISPC_ARCHS_LIST})
list(FILTER ISPC_ARCHS_${ARCH_NAME}_LIST INCLUDE REGEX ${ARCH_FILTER})
list(LENGTH ISPC_ARCHS_${ARCH_NAME}_LIST ARCH_LENGTH)
if (${ARCH_LENGTH} GREATER 0)
set(ISPC_${ARCH_NAME}_ENABLED TRUE)
endif()
endmacro()
define_ispc_supported_arch(X86 "x86|x86-64")
define_ispc_supported_arch(ARM "arm|aarch64")
define_ispc_supported_arch(XE "xe64")
macro(define_ispc_isa_options ISA_NAME)
set(ISPC_TARGET_${ISA_NAME} ${ARGV1} CACHE STRING "ispc target used for ${ISA_NAME} ISA")
set_property(CACHE ISPC_TARGET_${ISA_NAME} PROPERTY STRINGS ${ARGN} NONE)
#mark_as_advanced(ISPC_TARGET_${ISA_NAME})
endmacro()
if (ISPC_X86_ENABLED)
define_ispc_isa_options(SSE4 sse4-i32x4 sse4-i32x8 sse4-i16x8 sse4-i8x16)
define_ispc_isa_options(AVX avx1-i32x8 avx1-i32x4 avx1-i32x16 avx1-i64x4)
define_ispc_isa_options(AVX2 avx2-i32x8 avx2-i32x4 avx2-i32x16 avx2-i64x4)
define_ispc_isa_options(AVX512KNL avx512knl-x16)
define_ispc_isa_options(AVX512SKX avx512skx-x16 avx512skx-x8)
define_ispc_isa_options(AVX512SPR avx512spr-x16 avx512spr-x8)
endif()
macro(append_ispc_target_list ISA_NAME)
set(_TARGET_NAME ISPC_TARGET_${ISA_NAME})
if (NOT ${_TARGET_NAME} STREQUAL "NONE")
list(APPEND ISPC_TARGET_LIST ${${_TARGET_NAME}})
endif()
unset(_TARGET_NAME)
endmacro()
unset(ISPC_TARGET_LIST)
if (ISPC_X86_ENABLED)
append_ispc_target_list(SSE4)
append_ispc_target_list(AVX)
append_ispc_target_list(AVX2)
append_ispc_target_list(AVX512KNL)
append_ispc_target_list(AVX512SKX)
if (NOT APPLE)
append_ispc_target_list(AVX512SPR)
endif()
endif()
## Macros ##
macro (ispc_read_dependencies ISPC_DEPENDENCIES_FILE)
set(ISPC_DEPENDENCIES "")
if (EXISTS ${ISPC_DEPENDENCIES_FILE})
file(READ ${ISPC_DEPENDENCIES_FILE} contents)
string(REPLACE " " ";" contents "${contents}")
string(REPLACE ";" "\\\\;" contents "${contents}")
string(REPLACE "\n" ";" contents "${contents}")
foreach(dep ${contents})
if (EXISTS ${dep})
set(ISPC_DEPENDENCIES ${ISPC_DEPENDENCIES} ${dep})
endif (EXISTS ${dep})
endforeach(dep ${contents})
endif ()
endmacro()
macro (ispc_compile)
cmake_parse_arguments(ISPC_COMPILE "" "TARGET" "" ${ARGN})
set(ISPC_ADDITIONAL_ARGS "")
# Check if CPU target is passed externally
if (NOT ISPC_TARGET_CPU)
set(ISPC_TARGETS ${ISPC_TARGET_LIST})
else()
set(ISPC_TARGETS ${ISPC_TARGET_CPU})
endif()
set(ISPC_TARGET_EXT ${CMAKE_CXX_OUTPUT_EXTENSION})
string(REPLACE ";" "," ISPC_TARGET_ARGS "${ISPC_TARGETS}")
if (CMAKE_SIZEOF_VOID_P EQUAL 8)
if (${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm64|aarch64")
set(ISPC_ARCHITECTURE "aarch64")
else()
set(ISPC_ARCHITECTURE "x86-64")
endif()
else()
set(ISPC_ARCHITECTURE "x86")
endif()
set(ISPC_TARGET_DIR ${CMAKE_CURRENT_BINARY_DIR})
include_directories(${ISPC_TARGET_DIR})
if(ISPC_INCLUDE_DIR)
string(REPLACE ";" ";-I;" ISPC_INCLUDE_DIR_PARMS "${ISPC_INCLUDE_DIR}")
set(ISPC_INCLUDE_DIR_PARMS "-I" ${ISPC_INCLUDE_DIR_PARMS})
endif()
if (NOT CMAKE_BUILD_TYPE)
set (CMAKE_BUILD_TYPE "Release")
endif()
#CAUTION: -O0/1 -g with ispc seg faults
set(ISPC_FLAGS_DEBUG "-g" CACHE STRING "ISPC Debug flags")
mark_as_advanced(ISPC_FLAGS_DEBUG)
set(ISPC_FLAGS_RELEASE "-O3" CACHE STRING "ISPC Release flags")
mark_as_advanced(ISPC_FLAGS_RELEASE)
set(ISPC_FLAGS_RELWITHDEBINFO "-O2 -g" CACHE STRING "ISPC Release with Debug symbols flags")
mark_as_advanced(ISPC_FLAGS_RELWITHDEBINFO)
if ("${CMAKE_BUILD_TYPE}" STREQUAL "Release")
set(ISPC_OPT_FLAGS ${ISPC_FLAGS_RELEASE})
elseif ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
set(ISPC_OPT_FLAGS ${ISPC_FLAGS_DEBUG})
elseif ("${CMAKE_BUILD_TYPE}" STREQUAL "RelWithDebInfo")
set(ISPC_OPT_FLAGS ${ISPC_FLAGS_RELWITHDEBINFO})
else ()
message(FATAL_ERROR "CMAKE_BUILD_TYPE (${CMAKE_BUILD_TYPE}) allows only the following values: Debug;Release;RelWithDebInfo")
endif()
# turn space sparated list into ';' separated list
string(REPLACE " " ";" ISPC_OPT_FLAGS "${ISPC_OPT_FLAGS}")
if (NOT WIN32)
list(APPEND ISPC_ADDITIONAL_ARGS --pic)
endif()
if (NOT "${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
list(APPEND ISPC_ADDITIONAL_ARGS --opt=disable-assertions)
endif()
if (ISPC_FAST_MATH)
list(APPEND ISPC_ADDITIONAL_ARGS --opt=fast-math)
endif()
# Also set the target-local include directories and defines if
# we were given a target name
set(ISPC_INCLUDE_DIRS_EXPR "")
set(ISPC_COMPILE_DEFINITIONS_EXPR "")
if (NOT "${ISPC_COMPILE_TARGET}" STREQUAL "")
set(ISPC_INCLUDE_DIRS_EXPR
"$<TARGET_PROPERTY:${ISPC_COMPILE_TARGET},INCLUDE_DIRECTORIES>")
set(ISPC_COMPILE_DEFINITIONS_EXPR
"$<TARGET_PROPERTY:${ISPC_COMPILE_TARGET},COMPILE_DEFINITIONS>")
endif()
set(ISPC_OBJECTS "")
foreach(src ${ISPC_COMPILE_UNPARSED_ARGUMENTS})
get_filename_component(fname ${src} NAME_WE)
# The src_relpath will usually be the same as getting the DIRECTORY
# component of the src file name, but we go through the full path
# computation path to handle cases where the src name is an absolute
# file path in some other location, where we need to compute a path to
get_filename_component(src_dir ${src} ABSOLUTE)
file(RELATIVE_PATH src_relpath ${CMAKE_CURRENT_LIST_DIR} ${src_dir})
get_filename_component(src_relpath ${src_relpath} DIRECTORY)
# Remove any relative paths up from the relative path
string(REPLACE "../" "_/" src_relpath "${src_relpath}")
set(outdir "${ISPC_TARGET_DIR}/${src_relpath}")
set(input ${CMAKE_CURRENT_SOURCE_DIR}/${src})
set(ISPC_DEPENDENCIES_FILE ${outdir}/${fname}.dev.idep)
ispc_read_dependencies(${ISPC_DEPENDENCIES_FILE})
set(results "${outdir}/${fname}.dev${ISPC_TARGET_EXT}")
# if we have multiple targets add additional object files
list(LENGTH ISPC_TARGETS NUM_TARGETS)
if (NUM_TARGETS GREATER 1)
foreach(target ${ISPC_TARGETS})
string(REGEX REPLACE "-(i(8|16|32|64))?x(4|8|16|32|64)" "" target ${target})
string(REPLACE "avx1" "avx" target ${target})
list(APPEND results "${outdir}/${fname}.dev_${target}${ISPC_TARGET_EXT}")
endforeach()
endif()
add_custom_command(
OUTPUT ${results} ${outdir}/${fname}_ispc.h
COMMAND ${CMAKE_COMMAND} -E make_directory ${outdir}
COMMAND ${ISPC_EXECUTABLE}
${ISPC_DEFINITIONS}
-I ${CMAKE_CURRENT_SOURCE_DIR}
"$<$<BOOL:${ISPC_INCLUDE_DIRS_EXPR}>:-I$<JOIN:${ISPC_INCLUDE_DIRS_EXPR},;-I>>"
${ISPC_INCLUDE_DIR_PARMS}
"$<$<BOOL:${ISPC_COMPILE_DEFINITIONS_EXPR}>:-D$<JOIN:${ISPC_COMPILE_DEFINITIONS_EXPR},;-D>>"
--arch=${ISPC_ARCHITECTURE}
--addressing=${ISPC_ADDRESSING}
${ISPC_OPT_FLAGS}
--target=${ISPC_TARGET_ARGS}
--woff
${ISPC_ADDITIONAL_ARGS}
-h ${outdir}/${fname}_ispc.h
-MMM ${ISPC_DEPENDENCIES_FILE}
-o ${outdir}/${fname}.dev${ISPC_TARGET_EXT}
${input}
DEPENDS ${input} ${ISPC_DEPENDENCIES}
COMMENT "Building ISPC object ${outdir}/${fname}.dev${ISPC_TARGET_EXT}"
COMMAND_EXPAND_LISTS
VERBATIM
)
set(ISPC_OBJECTS ${ISPC_OBJECTS} ${results})
endforeach()
endmacro()
###############################################################################
## GPU specific macros/options ################################################
###############################################################################
define_ispc_isa_options(XE gen9-x8 gen9-x16 xelp-x8 xelp-x16 xehpc-x16 xehpc-x32 xehpg-x8 xehpg-x16)
set(ISPC_XE_ADDITIONAL_ARGS "" CACHE STRING "extra arguments to pass to ISPC for Xe targets")
function(ispc_gpu_target_add_sources TARGET_NAME PARENT_TARGET_NAME)
# Check If GPU target is passed externally
if (NOT ISPC_TARGET_XE)
set(ISPC_TARGET_XE "gen9-x8")
endif()
if (NOT ISPC_TARGET_DIR)
set(ISPC_TARGET_DIR ${CMAKE_CURRENT_BINARY_DIR})
endif()
set(ISPC_PROGRAM_COUNT 16)
if ("${ISPC_TARGET_XE}" STREQUAL "gen9-x8" OR
"${ISPC_TARGET_XE}" STREQUAL "xelp-x8")
set(ISPC_PROGRAM_COUNT 8)
endif()
set(ISPC_XE_FLAGS_DEBUG "-g" CACHE STRING "ISPC Xe Debug flags")
mark_as_advanced(ISPC_XE_FLAGS_DEBUG)
set(ISPC_XE_FLAGS_RELEASE "-O3" CACHE STRING "ISPC Xe Release flags")
mark_as_advanced(ISPC_XE_FLAGS_RELEASE)
set(ISPC_XE_FLAGS_RELWITHDEBINFO "-O2 -g" CACHE STRING "ISPC Xe Release with Debug symbols flags")
mark_as_advanced(ISPC_XE_FLAGS_RELWITHDEBINFO)
if (NOT CMAKE_BUILD_TYPE)
set (CMAKE_BUILD_TYPE "Release")
endif()
if (WIN32 OR "${CMAKE_BUILD_TYPE}" STREQUAL "Release")
set(ISPC_XE_OPT_FLAGS ${ISPC_XE_FLAGS_RELEASE})
elseif ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
set(ISPC_XE_OPT_FLAGS ${ISPC_XE_FLAGS_DEBUG})
elseif ("${CMAKE_BUILD_TYPE}" STREQUAL "RelWithDebInfo")
set(ISPC_XE_OPT_FLAGS ${ISPC_XE_FLAGS_RELWITHDEBINFO})
else ()
message(FATAL_ERROR "CMAKE_BUILD_TYPE (${CMAKE_BUILD_TYPE}) allows only the following values: Debug;Release;RelWithDebInfo")
endif()
# turn space sparated list into ';' separated list
string(REPLACE " " ";" ISPC_XE_OPT_FLAGS "${ISPC_XE_OPT_FLAGS}")
# Additional flags passed by user
if (NOT ISPC_XE_ADDITIONAL_ARGS)
set(ISPC_XE_ADDITIONAL_ARGS "")
endif()
# Output ISPC module format passed by user
if (NOT ISPC_XE_FORMAT)
set (ISPC_XE_FORMAT "spv")
endif()
if (ISPC_XE_FORMAT STREQUAL "spv")
set(ISPC_GPU_OUTPUT_OPT "--emit-spirv")
set(TARGET_OUTPUT_EXT "spv")
elseif (ISPC_XE_FORMAT STREQUAL "zebin")
set(ISPC_GPU_OUTPUT_OPT "--emit-zebin")
set(TARGET_OUTPUT_EXT "bin")
elseif (ISPC_XE_FORMAT STREQUAL "bc")
set(ISPC_GPU_OUTPUT_OPT "--emit-llvm")
set(TARGET_OUTPUT_EXT "bc")
endif()
# Support old global includes as well
if (ISPC_INCLUDE_DIR)
string(REPLACE ";" ";-I;" ISPC_INCLUDE_DIR_PARMS "${ISPC_INCLUDE_DIR}")
set(ISPC_INCLUDE_DIR_PARMS "-I" ${ISPC_INCLUDE_DIR_PARMS})
endif()
set(ISPC_XE_COMPILE_OUTPUTS "")
set(ISPC_INCLUDE_DIRS_EXPR "$<TARGET_PROPERTY:${TARGET_NAME},INCLUDE_DIRECTORIES>")
set(ISPC_COMPILE_DEFINITIONS_EXPR "$<TARGET_PROPERTY:${TARGET_NAME},COMPILE_DEFINITIONS>")
foreach(src ${ARGN})
get_filename_component(fname ${src} NAME_WE)
get_filename_component(dir ${src} PATH)
# The src_relpath will usually be the same as getting the DIRECTORY
# component of the src file name, but we go through the full path
# computation path to handle cases where the src name is an absolute
# file path in some other location, where we need to compute a path to
get_filename_component(src_dir ${src} ABSOLUTE)
file(RELATIVE_PATH src_relpath ${CMAKE_CURRENT_LIST_DIR} ${src_dir})
get_filename_component(src_relpath ${src_relpath} DIRECTORY)
# Remove any relative paths up from the relative path
string(REPLACE "../" "_/" src_relpath "${src_relpath}")
set(outdir "${ISPC_TARGET_DIR}/${src_relpath}")
set(input ${CMAKE_CURRENT_LIST_DIR}/${dir}/${fname}.ispc)
set(ISPC_DEPENDENCIES_FILE ${outdir}/${fname}.gpu.dev.idep)
ispc_read_dependencies(${ISPC_DEPENDENCIES_FILE})
if (ISPC_XE_FORMAT STREQUAL "spv")
# Add a .tmp suffix so we don't conflict with final SPV target name if it's the same
# as the file
set(result "${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME}_${fname}.tmp.spv")
elseif (ISPC_XE_FORMAT STREQUAL "zebin")
set(result "${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME}_${fname}.tmp.bin")
elseif (ISPC_XE_FORMAT STREQUAL "bc")
set(result "${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME}_${fname}.tmp.bc")
endif()
add_custom_command(
OUTPUT ${result}
DEPENDS ${input} ${ISPC_DEPENDENCIES}
COMMAND ${CMAKE_COMMAND} -E make_directory ${outdir}
COMMAND ${ISPC_EXECUTABLE}
-I ${CMAKE_CURRENT_SOURCE_DIR}
"$<$<BOOL:${ISPC_INCLUDE_DIRS_EXPR}>:-I$<JOIN:${ISPC_INCLUDE_DIRS_EXPR},;-I>>"
${ISPC_INCLUDE_DIR_PARMS}
${ISPC_XE_OPT_FLAGS}
-DISPC_GPU
"$<$<BOOL:${ISPC_COMPILE_DEFINITIONS_EXPR}>:-D$<JOIN:${ISPC_COMPILE_DEFINITIONS_EXPR},;-D>>"
${ISPC_DEFINITIONS}
--addressing=64
--target=${ISPC_TARGET_XE}
${ISPC_GPU_OUTPUT_OPT}
--woff
${ISPC_XE_ADDITIONAL_ARGS}
-o ${result}
${input}
-MMM ${ISPC_DEPENDENCIES_FILE}
COMMENT "Building ISPC GPU object ${result}"
COMMAND_EXPAND_LISTS
VERBATIM
)
set_source_files_properties(${result} PROPERTIES GENERATED true)
list(APPEND ISPC_XE_COMPILE_OUTPUTS ${result})
endforeach()
add_custom_target(${TARGET_NAME} DEPENDS
${ISPC_TARGET_DIR}/${PARENT_TARGET_NAME}.${TARGET_OUTPUT_EXT})
set_target_properties(${TARGET_NAME} PROPERTIES
LIBRARY_OUTPUT_DIRECTORY ${ISPC_TARGET_DIR}
LIBRARY_OUTPUT_NAME ${PARENT_TARGET_NAME}.${TARGET_OUTPUT_EXT}
)
set(LINK_GPU_LIBRARIES_PROP "$<TARGET_PROPERTY:${TARGET_NAME},LINK_LIBRARIES>")
set(LINK_DPCPP_LIBRARIES_PROP "$<TARGET_PROPERTY:${TARGET_NAME},ISPC_DPCPP_LINK_LIBRARIES>")
set(NEEDS_ISPC_LINK_EXPR
"$<OR:$<BOOL:${LINK_GPU_LIBRARIES_PROP}>,$<BOOL:${LINK_DPCPP_LIBRARIES_PROP}>>")
set(LINKS_DPCPP_LIBS "$<BOOL:${LINK_DPCPP_LIBRARIES_PROP}>")
set(LINKS_DPCPP_ESIMD_LIBS
"$<BOOL:$<TARGET_PROPERTY:${TARGET_NAME},ISPC_DPCPP_LINKING_ESIMD>>")
set(LINKS_DPCPP_SCALAR_LIBS
"$<AND:${LINKS_DPCPP_LIBS},$<NOT:${LINKS_DPCPP_ESIMD_LIBS}>>")
# If we have multiple files we need to link, even if we don't link any libraries.
list(LENGTH ISPC_XE_COMPILE_OUTPUTS NUM_ISPC_XE_COMPILE_OUTPUTS)
if (${NUM_ISPC_XE_COMPILE_OUTPUTS} GREATER 1)
set(NEEDS_ISPC_LINK_EXPR 1)
endif()
list(APPEND SYCL_POST_LINK_ARGS
"-split=auto"
"-symbols"
"-lower-esimd"
"-emit-param-info"
"-emit-exported-symbols"
"-spec-const=native"
"-device-globals"
"-O2"
)
list(APPEND SPV_EXTENSIONS
"-all"
"+SPV_EXT_shader_atomic_float_add"
"+SPV_EXT_shader_atomic_float_min_max"
"+SPV_KHR_no_integer_wrap_decoration"
"+SPV_KHR_float_controls"
"+SPV_INTEL_subgroups"
"+SPV_INTEL_media_block_io"
"+SPV_INTEL_fpga_reg"
"+SPV_INTEL_device_side_avc_motion_estimation"
"+SPV_INTEL_fpga_loop_controls"
"+SPV_INTEL_fpga_memory_attributes"
"+SPV_INTEL_fpga_memory_accesses"
"+SPV_INTEL_unstructured_loop_controls"
"+SPV_INTEL_blocking_pipes"
"+SPV_INTEL_io_pipes"
"+SPV_INTEL_function_pointers"
"+SPV_INTEL_kernel_attributes"
"+SPV_INTEL_float_controls2"
"+SPV_INTEL_inline_assembly"
"+SPV_INTEL_optimization_hints"
"+SPV_INTEL_arbitrary_precision_integers"
"+SPV_INTEL_vector_compute"
"+SPV_INTEL_fast_composite"
"+SPV_INTEL_fpga_buffer_location"
"+SPV_INTEL_arbitrary_precision_fixed_point"
"+SPV_INTEL_arbitrary_precision_floating_point"
"+SPV_INTEL_variable_length_array"
"+SPV_INTEL_fp_fast_math_mode"
"+SPV_INTEL_fpga_cluster_attributes"
"+SPV_INTEL_loop_fuse"
"+SPV_INTEL_long_constant_composite"
"+SPV_INTEL_fpga_invocation_pipelining_attributes"
)
string(REPLACE ";" "," SPV_EXT_PARMS "${SPV_EXTENSIONS}")
list(APPEND DPCPP_LLVM_SPIRV_ARGS
"-spirv-debug-info-version=ocl-100"
"-spirv-allow-extra-diexpressions"
"-spirv-allow-unknown-intrinsics=llvm.genx."
# Not all extenstion are supported yet by VC backend
# so list here which are supported
#-spirv-ext=+all
"-spirv-ext=${SPV_EXT_PARMS}"
)
set(TARGET_OUTPUT_FILE "${ISPC_TARGET_DIR}/${PARENT_TARGET_NAME}")
add_custom_command(
DEPENDS
${ISPC_XE_COMPILE_OUTPUTS}
${LINK_GPU_LIBRARIES_PROP}
${LINK_DPCPP_LIBRARIES_PROP}
OUTPUT ${ISPC_TARGET_DIR}/${PARENT_TARGET_NAME}.${TARGET_OUTPUT_EXT}
COMMAND
# True case: we're linking and run ispc link. Args we want separate with a space
# should be separate with a ; here so when the lists are expanded we get the
# desired space separate in the command
# False case: we're just going to copy the file with cmake -E copy
"$<IF:${NEEDS_ISPC_LINK_EXPR},${ISPC_EXECUTABLE};link,cmake;-E;copy>"
# True case arguments for ispc link
"$<${NEEDS_ISPC_LINK_EXPR}:${ISPC_XE_COMPILE_OUTPUTS};${LINK_GPU_LIBRARIES_PROP}>"
"$<${NEEDS_ISPC_LINK_EXPR}:--emit-spirv>"
"$<${NEEDS_ISPC_LINK_EXPR}:-o>"
"$<${NEEDS_ISPC_LINK_EXPR}:${TARGET_OUTPUT_FILE}.spv>"
# False case arguments for cmake -E copy
# We also pick between zebin/spv suffixes here, zebin and spv are both valid
# outputs for single-file targets.
"$<$<NOT:${NEEDS_ISPC_LINK_EXPR}>:${ISPC_XE_COMPILE_OUTPUTS}>"
"$<$<NOT:${NEEDS_ISPC_LINK_EXPR}>:${TARGET_OUTPUT_FILE}.${TARGET_OUTPUT_EXT}>"
# For targets doing DPCPP linking we need to do the dpcpp link step against the
# extracted DPCPP library bitcode and then translate to the final SPV output target
# First we link the bitcode extracted from DPCPP using DPCPP LLVM link.
COMMAND
"$<${LINKS_DPCPP_LIBS}:${DPCPP_LLVM_LINK}>"
${LINK_DPCPP_LIBRARIES_PROP}
"$<${LINKS_DPCPP_LIBS}:-o;${TARGET_OUTPUT_FILE}.linked.dpcpp.bc>"
# Now we run SYCL post link if we're linking against a scalar DPCPP library
# ESIMD linking skips this step
COMMAND
"$<${LINKS_DPCPP_SCALAR_LIBS}:${DPCPP_SYCL_POST_LINK};${TARGET_OUTPUT_FILE}.linked.dpcpp.bc>"
"$<${LINKS_DPCPP_SCALAR_LIBS}:${SYCL_POST_LINK_ARGS}>"
"$<${LINKS_DPCPP_SCALAR_LIBS}:-o;${TARGET_OUTPUT_FILE}.postlink.bc>"
# Now link with ISPC bitcode with DPCPP extracted and post-processed bitcode.
COMMAND
"$<${LINKS_DPCPP_LIBS}:${DPCPP_LLVM_LINK};${result}>"
"$<${LINKS_DPCPP_SCALAR_LIBS}:${TARGET_OUTPUT_FILE}.postlink_0.bc>"
"$<${LINKS_DPCPP_ESIMD_LIBS}:${TARGET_OUTPUT_FILE}.linked.dpcpp.bc>"
"$<${LINKS_DPCPP_LIBS}:-o;${TARGET_OUTPUT_FILE}.linked.bc>"
# And finally back to SPV to the original expected target SPV name
COMMAND
"$<${LINKS_DPCPP_LIBS}:${DPCPP_LLVM_SPIRV}>"
# Pick the right input to llvm-spirv based on if we're linking scalar or esimd
# DPCPP libraries.
"$<${LINKS_DPCPP_SCALAR_LIBS}:${TARGET_OUTPUT_FILE}.linked.bc>"
"$<${LINKS_DPCPP_ESIMD_LIBS}:${TARGET_OUTPUT_FILE}.linked.bc>"
"$<${LINKS_DPCPP_LIBS}:${DPCPP_LLVM_SPIRV_ARGS}>"
"$<${LINKS_DPCPP_LIBS}:-o;${TARGET_OUTPUT_FILE}.spv>"
COMMENT "Making ISPC library ${TARGET_OUTPUT_FILE}.${TARGET_OUTPUT_EXT}"
COMMAND_EXPAND_LISTS
VERBATIM
)
unset(ISPC_PROGRAM_COUNT)
endfunction()
###############################################################################
## Generic kernel compilation #################################################
###############################################################################
# Kept for backwards compatibility with existing CPU projects
function(ispc_target_add_sources name)
## Split-out C/C++ from ISPC files ##
set(ISPC_SOURCES "")
set(OTHER_SOURCES "")
foreach(src ${ARGN})
get_filename_component(ext ${src} EXT)
if (ext STREQUAL ".ispc")
set(ISPC_SOURCES ${ISPC_SOURCES} ${src})
else()
set(OTHER_SOURCES ${OTHER_SOURCES} ${src})
endif()
endforeach()
## Get existing target definitions and include dirs ##
# NOTE(jda) - This needs work: BUILD_INTERFACE vs. INSTALL_INTERFACE isn't
# handled automatically.
#get_property(TARGET_DEFINITIONS TARGET ${name} PROPERTY COMPILE_DEFINITIONS)
#get_property(TARGET_INCLUDES TARGET ${name} PROPERTY INCLUDE_DIRECTORIES)
#set(ISPC_DEFINITIONS ${TARGET_DEFINITIONS})
#set(ISPC_INCLUDE_DIR ${TARGET_INCLUDES})
## Compile ISPC files ##
ispc_compile(${ISPC_SOURCES})
## Set final sources on target ##
get_property(TARGET_SOURCES TARGET ${name} PROPERTY SOURCES)
list(APPEND TARGET_SOURCES ${ISPC_OBJECTS} ${OTHER_SOURCES})
set_target_properties(${name} PROPERTIES SOURCES "${TARGET_SOURCES}")
endfunction()
# Compile ISPC files
function(ispc_cpu_target_add_sources TARGET_NAME)
# We'll only have ISPC files coming through this codepath now
ispc_compile(${ARGN} TARGET ${TARGET_NAME})
## Set final sources on target ##
get_property(TARGET_SOURCES TARGET ${TARGET_NAME} PROPERTY SOURCES)
list(APPEND TARGET_SOURCES ${ISPC_OBJECTS})
set_target_properties(${TARGET_NAME} PROPERTIES SOURCES "${TARGET_SOURCES}")
endfunction()
function(add_ispc_library TARGET_NAME)
if (WIN32)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
endif()
add_library(${TARGET_NAME} SHARED)
set_target_properties(${TARGET_NAME} PROPERTIES LINKER_LANGUAGE CXX)
if (WIN32)
target_link_libraries(${TARGET_NAME} PRIVATE msvcrt.lib)
if (ISPC_BUILD)
target_link_libraries(${TARGET_NAME} PRIVATE ${ISPCRT_LIB})
else()
target_link_libraries(${TARGET_NAME} PRIVATE ispcrt::ispcrt)
endif()
endif()
ispc_cpu_target_add_sources(${TARGET_NAME} ${ARGN})
if (BUILD_GPU)
ispc_gpu_target_add_sources(${TARGET_NAME}_gpu ${TARGET_NAME} ${ARGN})
add_dependencies(${TARGET_NAME} ${TARGET_NAME}_gpu)
# TODO: Do still need to propage up the ISPC program width define
endif()
endfunction()
function(ispc_target_include_directories TARGET_NAME)
get_property(ISPC_TARGET_INCLUDE_DIRS TARGET ${TARGET_NAME} PROPERTY INCLUDE_DIRECTORIES)
# Get the absolute path for each include directory
foreach (dir ${ARGN})
get_filename_component(ABS_PATH ${dir} ABSOLUTE)
list(APPEND ISPC_TARGET_INCLUDE_DIRS ${ABS_PATH})
endforeach()
set_target_properties(${TARGET_NAME}
PROPERTIES INCLUDE_DIRECTORIES "${ISPC_TARGET_INCLUDE_DIRS}")
if (BUILD_GPU)
set_target_properties(${TARGET_NAME}_gpu
PROPERTIES INCLUDE_DIRECTORIES "${ISPC_TARGET_INCLUDE_DIRS}")
endif()
endfunction()
function(ispc_target_link_libraries TARGET_NAME)
# For CPU I think we can just link normally
target_link_libraries(${TARGET_NAME} ${ARGN})
if (BUILD_GPU)
get_property(GPU_LINK_LIBRARIES TARGET ${TARGET_NAME}_gpu PROPERTY LINK_LIBRARIES)
# Get the library file name for each library we want to link
foreach (lib ${ARGN})
if (TARGET ${lib}_gpu)
# TODO: Need to propagate include directories from the targets over as well
# to match CMake public include behavior
get_property(LIB_OUTPUT_PATH TARGET ${lib}_gpu PROPERTY LIBRARY_OUTPUT_DIRECTORY)
get_property(LIB_OUTPUT_NAME TARGET ${lib}_gpu PROPERTY LIBRARY_OUTPUT_NAME)
list(APPEND GPU_LINK_LIBRARIES ${LIB_OUTPUT_PATH}/${LIB_OUTPUT_NAME})
endif()
endforeach()
set_target_properties(${TARGET_NAME}_gpu
PROPERTIES LINK_LIBRARIES "${GPU_LINK_LIBRARIES}")
endif()
endfunction()
function(ispc_target_compile_definitions TARGET_NAME)
get_property(ISPC_TARGET_COMPILE_DEFINITIONS
TARGET ${TARGET_NAME}
PROPERTY COMPILE_DEFINITIONS)
list(APPEND ISPC_TARGET_COMPILE_DEFINITIONS ${ARGN})
set_target_properties(${TARGET_NAME}
PROPERTIES COMPILE_DEFINITIONS "${ISPC_TARGET_COMPILE_DEFINITIONS}")
if (BUILD_GPU)
set_target_properties(${TARGET_NAME}_gpu
PROPERTIES COMPILE_DEFINITIONS "${ISPC_TARGET_COMPILE_DEFINITIONS}")
endif()
endfunction()