# open3d_make_ispc_instruction_sets(<ispc_isas>)
#
# Sets up ISPC instruction sets based on the following precedence rules
# and stores them into the <ispc_isas> variable.
#   1. All common instruction sets if BUILD_COMMON_ISPC_ISAS=ON
#   2. User-defined instruction sets
#   3. Instruction sets detected on the current machine
function(open3d_make_ispc_instruction_sets ispc_isas)
    unset(${ispc_isas})

    if(BUILD_COMMON_ISPC_ISAS)
        # ISAs are defined in the format: [ISA]-i[MASK_SIZE]x[GANG_SIZE].
        #
        # List of all supported targets (generated by ispc --help):
        #   sse2-i32x4, sse2-i32x8, sse4-i8x16, sse4-i16x8,
        #   sse4-i32x4, sse4-i32x8, avx1-i32x4, avx1-i32x8,
        #   avx1-i32x16, avx1-i64x4, avx2-i8x32, avx2-i16x16,
        #   avx2-i32x4, avx2-i32x8, avx2-i32x16, avx2-i64x4,
        #   avx512knl-i32x16, avx512skx-i32x8, avx512skx-i32x16,
        #   avx512skx-i8x64, avx512skx-i16x32, neon-i8x16,
        #   neon-i16x8, neon-i32x4, neon-i32x8, genx-x8, genx-x16
        if(LINUX_AARCH64)
            set(${ispc_isas} neon-i32x4)
        else()
            set(${ispc_isas} sse2-i32x4 sse4-i32x4 avx1-i32x8 avx2-i32x8 avx512knl-i32x16 avx512skx-i32x16)
        endif()
    else()
        if(CMAKE_ISPC_INSTRUCTION_SETS)
            set(${ispc_isas} ${CMAKE_ISPC_INSTRUCTION_SETS})
            message(STATUS "Building with user-provided instruction sets")
        else()
            if(LINUX_AARCH64)
                # Only one choice for ARM
                set(${ispc_isas} neon-i32x4)
            else()
                # Only consider x86 ISAs
                set(ISPC_CANDIDATE_ISAS sse2-i32x4 sse4-i32x4 avx1-i32x8 avx2-i32x8 avx512knl-i32x16 avx512skx-i32x16)

                # Simulate try_run() on this small project with 2 source files
                execute_process(
                    COMMAND ${CMAKE_COMMAND}
                        -G "${CMAKE_GENERATOR}"
                        -B "${CMAKE_BINARY_DIR}/cmake/ispc_isas"
                        -S "${CMAKE_CURRENT_SOURCE_DIR}/cmake/ispc_isas"
                        "-DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}"
                        "-DCMAKE_ISPC_COMPILER=${CMAKE_ISPC_COMPILER}"
                        "-DCMAKE_ISPC_INSTRUCTION_SETS=${ISPC_CANDIDATE_ISAS}"
                        "-DISPC_USE_LEGACY_EMULATION=${ISPC_USE_LEGACY_EMULATION}"
                        "-DISPC_PRINT_LEGACY_COMPILE_COMMANDS=${ISPC_PRINT_LEGACY_COMPILE_COMMANDS}"
                    OUTPUT_QUIET
                )

                execute_process(COMMAND ${CMAKE_COMMAND} --build "${CMAKE_BINARY_DIR}/cmake/ispc_isas"
                    OUTPUT_QUIET
                )

                find_program(ISPC_ISAS_EXECUTABLE
                    ispc_isas
                    PATHS "${CMAKE_BINARY_DIR}/cmake/ispc_isas"
                    PATH_SUFFIXES "Debug" "Release"
                    REQUIRED
                )

                execute_process(COMMAND ${ISPC_ISAS_EXECUTABLE}
                    OUTPUT_VARIABLE DETECTED_ISAS
                )

                message(STATUS "Building with detected instruction sets")
                set(${ispc_isas} ${DETECTED_ISAS})
            endif()
        endif()
    endif()

    set(${ispc_isas} ${${ispc_isas}} PARENT_SCOPE)

endfunction()
