# # Copyright (c) 2018-2023, Intel Corporation # # SPDX-License-Identifier: BSD-3-Clause # # ispc GenerateBuiltins.cmake # find_program(M4_EXECUTABLE m4) if (NOT M4_EXECUTABLE) message(FATAL_ERROR "Failed to find M4 macro processor" ) endif() message(STATUS "M4 macro processor: " ${M4_EXECUTABLE}) if (WIN32) set(TARGET_OS_LIST_FOR_LL "windows" "unix") elseif (UNIX) set(TARGET_OS_LIST_FOR_LL "unix") endif() # Explicitly enumerate .ll and .m4 files included by target .ll files. # This is overly conservative, as they are added to every target .ll file. # But m4 doesn't support building depfile, so explicit enumeration is the # easiest workaround. list(APPEND M4_IMPLICIT_DEPENDENCIES builtins/builtins-cm-32.ll builtins/builtins-cm-64.ll builtins/svml.m4 builtins/target-avx-utils.ll builtins/target-avx-common-8.ll builtins/target-avx-common-16.ll builtins/target-avx1-i64x4base.ll builtins/target-avx512-common-4.ll builtins/target-avx512-common-8.ll builtins/target-avx512-common-16.ll builtins/target-avx512-utils.ll builtins/target-neon-common.ll builtins/target-sse2-common.ll builtins/target-sse4-common.ll builtins/target-xe.ll builtins/util-xe.m4 builtins/util.m4) function(target_ll_to_cpp llFileName bit os_name resultFileName) set(inputFilePath builtins/${llFileName}.ll) set(includePath builtins) string(TOUPPER ${os_name} os_name_macro) # Neon targets constrains: neon-i8x16 and neon-i16x8 are implemented only for 32 bit ARM. if ("${bit}" STREQUAL "64" AND (${llFileName} STREQUAL "target-neon-i8x16" OR ${llFileName} STREQUAL "target-neon-i16x8")) return() endif() # Xe targets are implemented only for 64 bit. string(REGEX MATCH "^target-xe" isXe "${llFileName}") if ("${bit}" STREQUAL "32" AND isXe) return() endif() set(output ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/builtins-${llFileName}-${bit}bit-${os_name}.cpp) add_custom_command( OUTPUT ${output} COMMAND ${M4_EXECUTABLE} -I${includePath} -DLLVM_VERSION=${LLVM_VERSION} -DBUILD_OS=${os_name_macro} -DRUNTIME=${bit} ${inputFilePath} | \"${Python3_EXECUTABLE}\" bitcode2cpp.py ${inputFilePath} --type=ispc-target --runtime=${bit} --os=${os_name_macro} --llvm_as ${LLVM_AS_EXECUTABLE} --opaque_flags="${LLVM_TOOLS_OPAQUE_FLAGS}" > ${output} DEPENDS ${inputFilePath} bitcode2cpp.py ${M4_IMPLICIT_DEPENDENCIES} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) set(${resultFileName} ${output} PARENT_SCOPE) set_source_files_properties(${resultFileName} PROPERTIES GENERATED true) endfunction() function(dispatch_ll_to_cpp llFileName os_name resultFileName) set(inputFilePath builtins/${llFileName}.ll) set(output ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/builtins-${llFileName}.cpp) add_custom_command( OUTPUT ${output} COMMAND ${M4_EXECUTABLE} -DLLVM_VERSION=${LLVM_VERSION} ${inputFilePath} | \"${Python3_EXECUTABLE}\" bitcode2cpp.py ${inputFilePath} --type=dispatch --os=${os_name} --llvm_as ${LLVM_AS_EXECUTABLE} --opaque_flags="${LLVM_TOOLS_OPAQUE_FLAGS}" > ${output} DEPENDS ${inputFilePath} bitcode2cpp.py WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) set(${resultFileName} ${output} PARENT_SCOPE) set_source_files_properties(${resultFileName} PROPERTIES GENERATED true) endfunction() function(builtin_to_cpp bit os_name arch supported_archs supported_oses resultFileName) set(inputFilePath builtins/builtins-c-cpu.cpp) set(includePath "") set(SKIP OFF) if (NOT ${arch} IN_LIST supported_archs OR NOT ${os_name} IN_LIST supported_oses) set(SKIP ON) endif() if (( ${os_name} STREQUAL "web" AND NOT ${arch} STREQUAL "wasm") OR (NOT ${os_name} STREQUAL "web" AND ${arch} STREQUAL "wasm")) return() endif() if ("${bit}" STREQUAL "32" AND ${arch} STREQUAL "x86") set(target_arch "i686") elseif ("${bit}" STREQUAL "64" AND ${arch} STREQUAL "x86") set(target_arch "x86_64") elseif ("${bit}" STREQUAL "32" AND ${arch} STREQUAL "arm") set(target_arch "armv7") elseif ("${bit}" STREQUAL "64" AND ${arch} STREQUAL "arm") set(target_arch "aarch64") elseif ("${bit}" STREQUAL "32" AND ${arch} STREQUAL "wasm") set(target_arch "wasm32") elseif ("${bit}" STREQUAL "64" AND ${arch} STREQUAL "wasm") set(target_arch "wasm64") else() message(FATAL_ERROR "Error") endif() # Host to target OS constrains if (WIN32) if (${os_name} STREQUAL "ios") set(SKIP ON) endif() elseif (APPLE) if (${os_name} STREQUAL "windows") set(SKIP ON) elseif (${os_name} STREQUAL "ps4") set(SKIP ON) endif() else() if (${os_name} STREQUAL "windows") set(SKIP ON) elseif (${os_name} STREQUAL "ps4") set(SKIP ON) elseif (${os_name} STREQUAL "ios") set(SKIP ON) endif() endif() # OS to arch constrains if (${os_name} STREQUAL "windows" AND ${arch} STREQUAL "arm" AND "${bit}" STREQUAL "32") set(SKIP ON) endif() if (${os_name} STREQUAL "macos") if (${target_arch} STREQUAL "x86_64") # Fall through (do not set SKIP to OFF!) elseif(${target_arch} STREQUAL "aarch64" AND ISPC_MACOS_ARM_TARGET) set(target_arch "arm64") # Fall through (do not set SKIP to OFF!) else() set(SKIP ON) endif() endif() if (${os_name} STREQUAL "ps4" AND NOT ${target_arch} STREQUAL "x86_64") set(SKIP ON) endif() if (${os_name} STREQUAL "ios") if (${target_arch} STREQUAL "aarch64") set(target_arch "arm64") else() set(SKIP ON) endif() endif() # Return if the target is not supported. if (${SKIP}) return() endif() # Report supported targets. message (STATUS "Enabling target: ${os_name} / ${target_arch}") # Determine triple set(fpic "") set(debian_triple) if (${os_name} STREQUAL "windows") set(triple ${target_arch}-pc-win32) elseif (${os_name} STREQUAL "linux") if (${target_arch} STREQUAL "i686" OR ${target_arch} STREQUAL "x86_64" OR ${target_arch} STREQUAL "aarch64") set(triple ${target_arch}-unknown-linux-gnu) set(debian_triple ${target_arch}-linux-gnu) elseif (${target_arch} STREQUAL "armv7") set(triple ${target_arch}-unknown-linux-gnueabihf) set(debian_triple arm-linux-gnueabihf) else() message(FATAL_ERROR "Error") endif() set(fpic -fPIC) elseif (${os_name} STREQUAL "freebsd") set(triple ${target_arch}-unknown-freebsd) set(fpic -fPIC) elseif (${os_name} STREQUAL "macos") set(triple ${target_arch}-apple-macosx) elseif (${os_name} STREQUAL "android") set(triple ${target_arch}-unknown-linux-android) set(fpic -fPIC) elseif (${os_name} STREQUAL "ios") set(triple ${target_arch}-apple-ios) elseif (${os_name} STREQUAL "ps4") set(triple ${target_arch}-scei-ps) set(fpic -fPIC) elseif (${os_name} STREQUAL "web") set(triple ${target_arch}-unknown-unknown) set(fpic -fPIC) else() message(FATAL_ERROR "Error") endif() # Determine include path if (WIN32) if (${os_name} STREQUAL "windows") set(includePath "") elseif(${os_name} STREQUAL "macos") # -isystemC:/iusers/MacOSX10.14.sdk.tar/MacOSX10.14.sdk/usr/include set(includePath -isystem${ISPC_MACOS_SDK_PATH}/usr/include) else() # -isystemC:/gnuwin32/include/glibc set(includePath -isystem${ISPC_GNUWIN32_PATH}/include/glibc) endif() elseif (APPLE) if (${os_name} STREQUAL "ios") # -isystem/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/usr/include/ set(includePath -isystem${ISPC_IOS_SDK_PATH}/usr/include) elseif (${os_name} STREQUAL "linux" OR ${os_name} STREQUAL "android" OR ${os_name} STREQUAL "freebsd") if (${target_arch} STREQUAL "armv7") # -isystem/Users/Shared/android-ndk-r20/sysroot/usr/include -isystem/Users/Shared/android-ndk-r20/sysroot/usr/include/arm-linux-androideabi set(includePath -isystem${ISPC_ANDROID_NDK_PATH}/sysroot/usr/include -isystem${ISPC_ANDROID_NDK_PATH}/sysroot/usr/include/arm-linux-androideabi) elseif (${target_arch} STREQUAL "aarch64") # -isystem/Users/Shared/android-ndk-r20/sysroot/usr/include -isystem/Users/Shared/android-ndk-r20/sysroot/usr/include/aarch64-linux-android set(includePath -isystem${ISPC_ANDROID_NDK_PATH}/sysroot/usr/include -isystem${ISPC_ANDROID_NDK_PATH}/sysroot/usr/include/aarch64-linux-android) elseif(${target_arch} STREQUAL "i686") # -isystem/Users/Shared/android-ndk-r20/sysroot/usr/include -isystem/Users/Shared/android-ndk-r20/sysroot/usr/include/i686-linux-android set(includePath -isystem${ISPC_ANDROID_NDK_PATH}/sysroot/usr/include -isystem${ISPC_ANDROID_NDK_PATH}/sysroot/usr/include/i686-linux-android) else() # -isystem/Users/Shared/android-ndk-r20/sysroot/usr/include -isystem/Users/Shared/android-ndk-r20/sysroot/usr/include/x86_64-linux-android set(includePath -isystem${ISPC_ANDROID_NDK_PATH}/sysroot/usr/include -isystem${ISPC_ANDROID_NDK_PATH}/sysroot/usr/include/x86_64-linux-android) endif() elseif (${os_name} STREQUAL "macos") set(includePath -isystem${ISPC_MACOS_SDK_PATH}/usr/include) endif() else() if (${os_name} STREQUAL "macos") # -isystem/iusers/MacOSX10.14.sdk.tar/MacOSX10.14.sdk/usr/include set(includePath -isystem${ISPC_MACOS_SDK_PATH}/usr/include) elseif(NOT ${debian_triple} STREQUAL "") # When compiling on Linux, there are two way to support cross targets: # - add "foreign" architecture to the set of supported architectures and install corresponding toolchain. # For example on aarch64: "dpkg --add-architecture armhf" and "apt-get install libc6-dev:armhf". # In this case the headers will be installed in /usr/include/arm-linux-gnueabihf and will be # automatically picked up by clang. # - install cross library. For example: "apt-get install libc6-dev-armhf-cross". # In this case headers will be installed in /usr/arm-linux-gnueabihf/include and will not be picked up # by clang by default. So the following line adds such path explicitly. If this path doesn't exist and # the headers can be found in other locations, this should not be a problem. set(includePath -isystem/usr/${debian_triple}/include) endif() endif() # Compose target flags set(target_flags --target=${triple} ${fpic} ${includePath}) set(output ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/builtins-cpp-${bit}-${os_name}-${target_arch}.cpp) if (${os_name} STREQUAL "web") if("${bit}" STREQUAL "64") list(APPEND emcc_flags "-sMEMORY64") endif() add_custom_command( OUTPUT ${output} COMMAND ${EMCC_EXECUTABLE} -DWASM -s WASM_OBJECT_FILES=0 ${emcc_flags} ${ISPC_OPAQUE_FLAGS} -I${CMAKE_SOURCE_DIR} -c ${inputFilePath} --std=gnu++17 -emit-llvm -c -o - | (\"${LLVM_DIS_EXECUTABLE}\" ${LLVM_TOOLS_OPAQUE_FLAGS} - || echo "builtins-c-*.cpp compile error") | \"${Python3_EXECUTABLE}\" bitcode2cpp.py c --type=builtins-c --runtime=${bit} --os=${os_name} --arch=${target_arch} --llvm_as ${LLVM_AS_EXECUTABLE} --opaque_flags="${LLVM_TOOLS_OPAQUE_FLAGS}" > ${output} DEPENDS ${inputFilePath} bitcode2cpp.py WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) else() add_custom_command( OUTPUT ${output} COMMAND ${CLANGPP_EXECUTABLE} ${target_flags} -I${CMAKE_SOURCE_DIR} -m${bit} -emit-llvm ${ISPC_OPAQUE_FLAGS} --std=gnu++17 -c ${inputFilePath} -o - | (\"${LLVM_DIS_EXECUTABLE}\" ${LLVM_TOOLS_OPAQUE_FLAGS} - || echo "builtins-c-*.cpp compile error") | \"${Python3_EXECUTABLE}\" bitcode2cpp.py c --type=builtins-c --runtime=${bit} --os=${os_name} --arch=${target_arch} --llvm_as ${LLVM_AS_EXECUTABLE} --opaque_flags="${LLVM_TOOLS_OPAQUE_FLAGS}" > ${output} DEPENDS ${inputFilePath} bitcode2cpp.py WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) endif() set(${resultFileName} ${output} PARENT_SCOPE) set_source_files_properties(${resultFileName} PROPERTIES GENERATED true) endfunction() function(builtin_xe_to_cpp bit resultFileName) set(inputFilePath builtins/builtins-cm-${bit}.ll) set(SKIP OFF) if (WIN32) set(os_name "windows") elseif (APPLE) set(SKIP ON) else () set(os_name "linux") endif() set(target_arch "xe64") if (NOT "${bit}" STREQUAL "64") set(SKIP ON) endif() if (NOT SKIP) set(output ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/builtins-cm-${bit}.cpp) add_custom_command( OUTPUT ${output} COMMAND cat ${inputFilePath} | \"${Python3_EXECUTABLE}\" bitcode2cpp.py cm --type=builtins-c --runtime=${bit} --os=${os_name} --arch=${target_arch} --llvm_as ${LLVM_AS_EXECUTABLE} --opaque_flags="${LLVM_TOOLS_OPAQUE_FLAGS}" > ${output} DEPENDS ${inputFilePath} bitcode2cpp.py WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) set(${resultFileName} ${output} PARENT_SCOPE) set_source_files_properties(${resultFileName} PROPERTIES GENERATED true) endif() endfunction() function (generate_target_builtins resultList) # Dispatch module for macOS and all the rest of targets. if (${LLVM_VERSION_NUMBER} VERSION_GREATER_EQUAL "14.0.0") dispatch_ll_to_cpp(dispatch "linux" output_generic) else() dispatch_ll_to_cpp(dispatch-no-spr "linux" output_generic) endif() dispatch_ll_to_cpp(dispatch-macos "macos" output_macos) list(APPEND tmpList ${output_generic} ${output_macos}) if(MSVC) # Group generated files inside Visual Studio source_group("Generated Builtins" FILES ${output_generic} ${output_macos}) endif() # "Regular" targets, targeting specific real ISA: sse/avx/neon set(regular_targets ${ARGN}) list(FILTER regular_targets EXCLUDE REGEX wasm) foreach (ispc_target ${regular_targets}) foreach (bit 32 64) foreach (os_name ${TARGET_OS_LIST_FOR_LL}) target_ll_to_cpp(target-${ispc_target} ${bit} ${os_name} output${os_name}${bit}) list(APPEND tmpList ${output${os_name}${bit}}) if(MSVC) # Group generated files inside Visual Studio source_group("Generated Builtins" FILES ${output${os_name}${bit}}) endif() endforeach() endforeach() endforeach() # WASM targets. if (WASM_ENABLED) set(wasm_targets ${ARGN}) list(FILTER wasm_targets INCLUDE REGEX wasm) foreach (wasm_target ${wasm_targets}) target_ll_to_cpp(target-${wasm_target} 32 web outputweb32) target_ll_to_cpp(target-${wasm_target} 64 web outputweb64) list(APPEND tmpList ${outputweb32} ${outputweb64}) if(MSVC) source_group("Generated Builtins" FILES ${outputweb32} ${outputweb64}) endif() endforeach() endif() # Return the list set(${resultList} ${tmpList} PARENT_SCOPE) endfunction() function (generate_common_builtins resultList) # Supported architectures if (X86_ENABLED) list (APPEND supported_archs "x86") endif() if (ARM_ENABLED) list (APPEND supported_archs "arm") endif() if (WASM_ENABLED) list (APPEND supported_archs "wasm") list (APPEND supported_oses "web") endif() # Supported OSes. if (ISPC_WINDOWS_TARGET) list (APPEND supported_oses "windows") endif() if (ISPC_LINUX_TARGET) list (APPEND supported_oses "linux") endif() if (ISPC_FREEBSD_TARGET) list (APPEND supported_oses "freebsd") endif() if (ISPC_MACOS_TARGET) list (APPEND supported_oses "macos") endif() if (ISPC_ANDROID_TARGET) list (APPEND supported_oses "android") endif() if (ISPC_IOS_TARGET) list (APPEND supported_oses "ios") endif() if (ISPC_PS_TARGET) list (APPEND supported_oses "ps4") endif() message (STATUS "ISPC will be built with support of ${supported_oses} for ${supported_archs}") foreach (bit 32 64) foreach (os_name "windows" "linux" "freebsd" "macos" "android" "ios" "ps4" "web") foreach (arch "x86" "arm" "wasm") builtin_to_cpp(${bit} ${os_name} ${arch} "${supported_archs}" "${supported_oses}" res${bit}${os_name}${arch}) list(APPEND tmpList ${res${bit}${os_name}${arch}} ) if(MSVC) # Group generated files inside Visual Studio source_group("Generated Builtins" FILES ${res${bit}${os_name}${arch}}) endif() endforeach() endforeach() endforeach() if (XE_ENABLED) set(bit 64) builtin_xe_to_cpp(${bit} res_xe_${bit}) list(APPEND tmpList ${res_xe_${bit}} ) if(MSVC) # Group generated files inside Visual Studio source_group("Generated Builtins" FILES ${res_xe_${bit}}) endif() endif() set(${resultList} ${tmpList} PARENT_SCOPE) endfunction()