Explorar el Código

Merge topic 'ispc_lang_support'

5ece12b7e4 gitlab-ci: add ISPC to the Fedora CI image
8976817d6d ISPC: Update help documentation to include ISPC
2368f46ba4 ISPC: Support building with the MSVC toolchain
e783bf8aa6 ISPC: Support ISPC header generation byproducts and parallel builds
34cc6acc81 Add ISPC compiler support to CMake
419d70d490 Refactor some swift only logic to be re-used by other languages

Acked-by: Kitware Robot <[email protected]>
Merge-request: !5065
Brad King hace 5 años
padre
commit
f10682b796
Se han modificado 67 ficheros con 1042 adiciones y 40 borrados
  1. 1 0
      .gitlab/ci/configure_fedora31_common.cmake
  2. 1 0
      .gitlab/ci/configure_fedora31_makefiles.cmake
  3. 1 0
      .gitlab/ci/configure_fedora31_ninja.cmake
  4. 1 0
      .gitlab/ci/configure_fedora31_ninja_multi.cmake
  5. 3 0
      .gitlab/ci/docker/fedora31/Dockerfile
  6. 14 0
      .gitlab/ci/docker/fedora31/install_ispc.sh
  7. 1 1
      .gitlab/os-linux.yml
  8. 1 0
      Auxiliary/vim/syntax/cmake.vim
  9. 2 1
      Help/command/enable_language.rst
  10. 1 1
      Help/command/project.rst
  11. 13 0
      Help/envvar/ISPC.rst
  12. 15 0
      Help/envvar/ISPCFLAGS.rst
  13. 2 0
      Help/manual/cmake-env-variables.7.rst
  14. 14 0
      Help/manual/cmake-generator-expressions.7.rst
  15. 1 0
      Help/manual/cmake-properties.7.rst
  16. 1 0
      Help/manual/cmake-variables.7.rst
  17. 1 1
      Help/prop_sf/LANGUAGE.rst
  18. 13 0
      Help/prop_tgt/ISPC_HEADER_DIRECTORY.rst
  19. 11 0
      Help/release/dev/ispc-language-support.rst
  20. 10 0
      Help/variable/CMAKE_ISPC_HEADER_DIRECTORY.rst
  21. 2 1
      Modules/CMakeCompilerIdDetection.cmake
  22. 22 0
      Modules/CMakeDetermineCompilerId.cmake
  23. 96 0
      Modules/CMakeDetermineISPCCompiler.cmake
  24. 1 0
      Modules/CMakeFindBinUtils.cmake
  25. 30 0
      Modules/CMakeISPCCompiler.cmake.in
  26. 20 0
      Modules/CMakeISPCCompilerABI.ispc
  27. 62 0
      Modules/CMakeISPCCompilerId.ispc.in
  28. 56 0
      Modules/CMakeISPCInformation.cmake
  29. 43 0
      Modules/CMakeTestISPCCompiler.cmake
  30. 22 0
      Modules/Compiler/Intel-ISPC.cmake
  31. 8 0
      Modules/Platform/Windows-Intel-ISPC.cmake
  32. 12 0
      Source/cmCoreTryCompile.cxx
  33. 3 2
      Source/cmGeneratorExpressionNode.cxx
  34. 94 28
      Source/cmGeneratorTarget.cxx
  35. 8 0
      Source/cmGeneratorTarget.h
  36. 1 0
      Source/cmGlobalGenerator.cxx
  37. 42 0
      Source/cmGlobalNinjaGenerator.cxx
  38. 6 0
      Source/cmGlobalNinjaGenerator.h
  39. 32 0
      Source/cmLocalGenerator.cxx
  40. 1 0
      Source/cmLocalGenerator.h
  41. 4 2
      Source/cmLocalUnixMakefileGenerator3.cxx
  42. 37 2
      Source/cmMakefileTargetGenerator.cxx
  43. 37 0
      Source/cmNinjaTargetGenerator.cxx
  44. 5 0
      Source/cmRulePlaceholderExpander.cxx
  45. 1 0
      Source/cmRulePlaceholderExpander.h
  46. 1 0
      Source/cmTarget.cxx
  47. 3 0
      Source/cmake.cxx
  48. 3 1
      Source/cmake.h
  49. 4 0
      Tests/CMakeLists.txt
  50. 13 0
      Tests/ISPC/CMakeLists.txt
  51. 15 0
      Tests/ISPC/Defines/CMakeLists.txt
  52. 15 0
      Tests/ISPC/Defines/main.cxx
  53. 15 0
      Tests/ISPC/Defines/simple.ispc
  54. 17 0
      Tests/ISPC/ObjectLibrary/CMakeLists.txt
  55. 17 0
      Tests/ISPC/ObjectLibrary/extra.cxx
  56. 12 0
      Tests/ISPC/ObjectLibrary/extra.ispc
  57. 15 0
      Tests/ISPC/ObjectLibrary/main.cxx
  58. 12 0
      Tests/ISPC/ObjectLibrary/simple.ispc
  59. 28 0
      Tests/ISPC/ResponseAndDefine/CMakeLists.txt
  60. 15 0
      Tests/ISPC/ResponseAndDefine/main.cxx
  61. 16 0
      Tests/ISPC/ResponseAndDefine/simple.ispc
  62. 15 0
      Tests/ISPC/StaticLibrary/CMakeLists.txt
  63. 15 0
      Tests/ISPC/StaticLibrary/main.cxx
  64. 12 0
      Tests/ISPC/StaticLibrary/simple.ispc
  65. 16 0
      Tests/ISPC/TryCompile/CMakeLists.txt
  66. 19 0
      Tests/ISPC/TryCompile/main.cxx
  67. 12 0
      Tests/ISPC/TryCompile/simple.ispc

+ 1 - 0
.gitlab/ci/configure_fedora31_common.cmake

@@ -1,4 +1,5 @@
 set(BUILD_CursesDialog ON CACHE BOOL "")
 set(BUILD_QtDialog ON CACHE BOOL "")
 
+
 include("${CMAKE_CURRENT_LIST_DIR}/configure_common.cmake")

+ 1 - 0
.gitlab/ci/configure_fedora31_makefiles.cmake

@@ -1 +1,2 @@
+set(CMake_TEST_ISPC "ON" CACHE STRING "")
 include("${CMAKE_CURRENT_LIST_DIR}/configure_external_test.cmake")

+ 1 - 0
.gitlab/ci/configure_fedora31_ninja.cmake

@@ -1 +1,2 @@
+set(CMake_TEST_ISPC "ON" CACHE STRING "")
 include("${CMAKE_CURRENT_LIST_DIR}/configure_fedora31_common.cmake")

+ 1 - 0
.gitlab/ci/configure_fedora31_ninja_multi.cmake

@@ -1 +1,2 @@
+set(CMake_TEST_ISPC "ON" CACHE STRING "")
 include("${CMAKE_CURRENT_LIST_DIR}/configure_external_test.cmake")

+ 3 - 0
.gitlab/ci/docker/fedora31/Dockerfile

@@ -3,3 +3,6 @@ MAINTAINER Ben Boeckel <[email protected]>
 
 COPY install_deps.sh /root/install_deps.sh
 RUN sh /root/install_deps.sh
+
+COPY install_ispc.sh /root/install_ispc.sh
+RUN sh /root/install_ispc.sh

+ 14 - 0
.gitlab/ci/docker/fedora31/install_ispc.sh

@@ -0,0 +1,14 @@
+#!/bin/sh
+
+set -e
+
+readonly version="1.13.0"
+readonly sha256sum="8ab1189bd5db596b3eee9d9465d3528b6626a7250675d67102761bb0d284cd21"
+
+readonly filename="ispc-v$version-linux"
+readonly tarball="$filename.tar.gz"
+
+echo "$sha256sum  $tarball" > ispc.sha256sum
+curl -OL "https://github.com/ispc/ispc/releases/download/v$version/$tarball"
+sha256sum --check ispc.sha256sum
+tar --strip-components=1 -C /usr/local -xf "$tarball" "$filename/bin/ispc"

+ 1 - 1
.gitlab/os-linux.yml

@@ -30,7 +30,7 @@
 ### Fedora
 
 .fedora31:
-    image: "kitware/cmake:ci-fedora31-x86_64-2020-06-01"
+    image: "kitware/cmake:ci-fedora31-x86_64-2020-08-18"
 
     variables:
         GIT_CLONE_PATH: "$CI_BUILDS_DIR/cmake ci"

+ 1 - 0
Auxiliary/vim/syntax/cmake.vim

@@ -1048,6 +1048,7 @@ syn keyword cmakeVariable contained
             \ CMAKE_HOST_UNIX
             \ CMAKE_HOST_WIN32
             \ CMAKE_IGNORE_PATH
+            \ CMAKE_ISPC_HEADER_DIRECTORY
             \ CMAKE_IMPORT_LIBRARY_PREFIX
             \ CMAKE_IMPORT_LIBRARY_SUFFIX
             \ CMAKE_INCLUDE_CURRENT_DIR

+ 2 - 1
Help/command/enable_language.rst

@@ -9,7 +9,8 @@ Enable a language (CXX/C/OBJC/OBJCXX/Fortran/etc)
 Enables support for the named language in CMake.  This is
 the same as the :command:`project` command but does not create any of the extra
 variables that are created by the project command.  Example languages
-are ``CXX``, ``C``, ``CUDA``, ``OBJC``, ``OBJCXX``, ``Fortran``, and ``ASM``.
+are ``CXX``, ``C``, ``CUDA``, ``OBJC``, ``OBJCXX``, ``Fortran``,
+``ISPC``, and ``ASM``.
 
 If enabling ``ASM``, enable it last so that CMake can check whether
 compilers for other languages like ``C`` work for assembly too.

+ 1 - 1
Help/command/project.rst

@@ -88,7 +88,7 @@ The options are:
 
   Selects which programming languages are needed to build the project.
   Supported languages include ``C``, ``CXX`` (i.e.  C++), ``CUDA``,
-  ``OBJC`` (i.e. Objective-C), ``OBJCXX``, ``Fortran``, and ``ASM``.
+  ``OBJC`` (i.e. Objective-C), ``OBJCXX``, ``Fortran``, ``ISPC``, and ``ASM``.
   By default ``C`` and ``CXX`` are enabled if no language options are given.
   Specify language ``NONE``, or use the ``LANGUAGES`` keyword and list no languages,
   to skip enabling any languages.

+ 13 - 0
Help/envvar/ISPC.rst

@@ -0,0 +1,13 @@
+ISPC
+-------
+
+.. versionadded:: 3.19
+
+.. include:: ENV_VAR.txt
+
+Preferred executable for compiling ``ISPC`` language files. Will only be used by
+CMake on the first configuration to determine ``ISPC`` compiler, after which the
+value for ``ISPC`` is stored in the cache as
+:variable:`CMAKE_ISPC_COMPILER <CMAKE_<LANG>_COMPILER>`. For any configuration
+run (including the first), the environment variable will be ignored if the
+:variable:`CMAKE_ISPC_COMPILER <CMAKE_<LANG>_COMPILER>` variable is defined.

+ 15 - 0
Help/envvar/ISPCFLAGS.rst

@@ -0,0 +1,15 @@
+ISPCFLAGS
+---------
+
+.. versionadded:: 3.19
+
+.. include:: ENV_VAR.txt
+
+Default compilation flags to be used when compiling ``ISPC`` files. Will only be
+used by CMake on the first configuration to determine ``ISPC`` default
+compilation flags, after which the value for ``ISPCFLAGS`` is stored in the
+cache as :variable:`CMAKE_ISPC_FLAGS <CMAKE_<LANG>_FLAGS>`. For any configuration
+run (including the first), the environment variable will be ignored if
+the :variable:`CMAKE_ISPC_FLAGS <CMAKE_<LANG>_FLAGS>` variable is defined.
+
+See also :variable:`CMAKE_ISPC_FLAGS_INIT <CMAKE_<LANG>_FLAGS_INIT>`.

+ 2 - 0
Help/manual/cmake-env-variables.7.rst

@@ -63,6 +63,8 @@ Environment Variables for Languages
    /envvar/CXXFLAGS
    /envvar/FC
    /envvar/FFLAGS
+   /envvar/ISPC
+   /envvar/ISPCFLAGS
    /envvar/OBJC
    /envvar/OBJCXX
    /envvar/RC

+ 14 - 0
Help/manual/cmake-generator-expressions.7.rst

@@ -146,6 +146,11 @@ Variable Queries
   ``1`` if the CMake's compiler id of the Fortran compiler matches any one
   of the entries in ``compiler_ids``, otherwise ``0``.
   See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable.
+``$<ISPC_COMPILER_ID:compiler_ids>``
+  where ``compiler_ids`` is a comma-separated list.
+  ``1`` if the CMake's compiler id of the ISPC compiler matches any one
+  of the entries in ``compiler_ids``, otherwise ``0``.
+  See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable.
 ``$<C_COMPILER_VERSION:version>``
   ``1`` if the version of the C compiler matches ``version``, otherwise ``0``.
   See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable.
@@ -164,6 +169,9 @@ Variable Queries
 ``$<Fortran_COMPILER_VERSION:version>``
   ``1`` if the version of the Fortran compiler matches ``version``, otherwise ``0``.
   See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable.
+``$<ISPC_COMPILER_VERSION:version>``
+  ``1`` if the version of the ISPC compiler matches ``version``, otherwise ``0``.
+  See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable.
 ``$<TARGET_POLICY:policy>``
   ``1`` if the ``policy`` was NEW when the 'head' target was created,
   else ``0``.  If the ``policy`` was not set, the warning message for the policy
@@ -543,6 +551,9 @@ Variable Queries
 ``$<Fortran_COMPILER_ID>``
   The CMake's compiler id of the Fortran compiler used.
   See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable.
+``$<ISPC_COMPILER_ID>``
+  The CMake's compiler id of the ISPC compiler used.
+  See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable.
 ``$<C_COMPILER_VERSION>``
   The version of the C compiler used.
   See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable.
@@ -561,6 +572,9 @@ Variable Queries
 ``$<Fortran_COMPILER_VERSION>``
   The version of the Fortran compiler used.
   See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable.
+``$<ISPC_COMPILER_VERSION>``
+  The version of the ISPC compiler used.
+  See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable.
 ``$<COMPILE_LANGUAGE>``
   The compile language of source files when evaluating compile options.
   See :ref:`the related boolean expression

+ 1 - 0
Help/manual/cmake-properties.7.rst

@@ -258,6 +258,7 @@ Properties on Targets
    /prop_tgt/INTERPROCEDURAL_OPTIMIZATION_CONFIG
    /prop_tgt/INTERPROCEDURAL_OPTIMIZATION
    /prop_tgt/IOS_INSTALL_COMBINED
+   /prop_tgt/ISPC_HEADER_DIRECTORY
    /prop_tgt/JOB_POOL_COMPILE
    /prop_tgt/JOB_POOL_LINK
    /prop_tgt/JOB_POOL_PRECOMPILE_HEADER

+ 1 - 0
Help/manual/cmake-variables.7.rst

@@ -510,6 +510,7 @@ Variables for Languages
    /variable/CMAKE_Fortran_MODDIR_DEFAULT
    /variable/CMAKE_Fortran_MODDIR_FLAG
    /variable/CMAKE_Fortran_MODOUT_FLAG
+   /variable/CMAKE_ISPC_HEADER_DIRECTORY
    /variable/CMAKE_LANG_ANDROID_TOOLCHAIN_MACHINE
    /variable/CMAKE_LANG_ANDROID_TOOLCHAIN_PREFIX
    /variable/CMAKE_LANG_ANDROID_TOOLCHAIN_SUFFIX

+ 1 - 1
Help/prop_sf/LANGUAGE.rst

@@ -6,6 +6,6 @@ What programming language is the file.
 A property that can be set to indicate what programming language the
 source file is.  If it is not set the language is determined based on
 the file extension.  Typical values are ``CXX`` (i.e.  C++), ``C``,
-``CSharp``, ``CUDA``, ``Fortran``, and ``ASM``.  Setting this
+``CSharp``, ``CUDA``, ``Fortran``, ``ISPC``, and ``ASM``.  Setting this
 property for a file means this file will be compiled.  Do not set this
 for headers or files that should not be compiled.

+ 13 - 0
Help/prop_tgt/ISPC_HEADER_DIRECTORY.rst

@@ -0,0 +1,13 @@
+ISPC_HEADER_DIRECTORY
+---------------------
+
+.. versionadded:: 3.19
+
+Specify relative output directory for ISPC headers provided by the target.
+
+If the target contains ISPC source files, this specifies the directory in which
+the generated headers will be placed. Relative paths are treated with respect to
+the value of :variable:`CMAKE_CURRENT_BINARY_DIR`. When this property is not set, the
+headers will be placed a generator defined build directory. If the variable
+:variable:`CMAKE_ISPC_HEADER_DIRECTORY` is set when a target is created
+its value is used to initialize this property.

+ 11 - 0
Help/release/dev/ispc-language-support.rst

@@ -0,0 +1,11 @@
+cmake-ispc-support
+------------------
+
+
+* CMake learned to support ``ISPC`` as a first-class language that can be
+  enabled via the :command:`project` and :command:`enable_language` commands.
+
+* ``ISPC`` is currently supported by the :ref:`Makefile Generators`
+  and the :generator:`Ninja` generator on Linux, macOS, and Windows.
+
+* The Intel ISPC compiler (``ispc``) is supported.

+ 10 - 0
Help/variable/CMAKE_ISPC_HEADER_DIRECTORY.rst

@@ -0,0 +1,10 @@
+CMAKE_ISPC_HEADER_DIRECTORY
+----------------------------
+
+.. versionadded:: 3.19
+
+ISPC generated header output directory.
+
+This variable is used to initialize the :prop_tgt:`ISPC_HEADER_DIRECTORY`
+property on all the targets.  See the target property for additional
+information.

+ 2 - 1
Modules/CMakeCompilerIdDetection.cmake

@@ -13,7 +13,8 @@ endfunction()
 
 function(compiler_id_detection outvar lang)
 
-  if (NOT lang STREQUAL Fortran AND NOT lang STREQUAL CSharp)
+  if (NOT lang STREQUAL Fortran AND NOT lang STREQUAL CSharp
+      AND NOT lang STREQUAL ISPC)
     file(GLOB lang_files
       "${CMAKE_ROOT}/Modules/Compiler/*-DetermineCompiler.cmake")
     set(nonlang CXX)

+ 22 - 0
Modules/CMakeDetermineCompilerId.cmake

@@ -110,6 +110,28 @@ function(CMAKE_DETERMINE_COMPILER_ID lang flagvar src)
     endif()
   endif()
 
+  # For ISPC we need to explicitly query the version.
+  if(lang STREQUAL "ISPC"
+     AND CMAKE_${lang}_COMPILER
+     AND NOT CMAKE_${lang}_COMPILER_VERSION)
+    execute_process(
+      COMMAND "${CMAKE_${lang}_COMPILER}"
+      --version
+      OUTPUT_VARIABLE output ERROR_VARIABLE output
+      RESULT_VARIABLE result
+      TIMEOUT 10
+    )
+    file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+      "Running the ${lang} compiler: \"${CMAKE_${lang}_COMPILER}\" -version\n"
+      "${output}\n"
+      )
+
+    if(output MATCHES [[ISPC\), ([0-9]+\.[0-9]+(\.[0-9]+)?)]])
+      set(CMAKE_${lang}_COMPILER_VERSION "${CMAKE_MATCH_1}")
+    endif()
+  endif()
+
+
   if (COMPILER_QNXNTO AND CMAKE_${lang}_COMPILER_ID STREQUAL "GNU")
     execute_process(
       COMMAND "${CMAKE_${lang}_COMPILER}"

+ 96 - 0
Modules/CMakeDetermineISPCCompiler.cmake

@@ -0,0 +1,96 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# determine the compiler to use for ISPC programs
+
+include(${CMAKE_ROOT}/Modules/CMakeDetermineCompiler.cmake)
+
+if( NOT (("${CMAKE_GENERATOR}" MATCHES "Make") OR ("${CMAKE_GENERATOR}" MATCHES "Ninja")) )
+  message(FATAL_ERROR "ISPC language not currently supported by \"${CMAKE_GENERATOR}\" generator")
+endif()
+
+# Load system-specific compiler preferences for this language.
+include(Platform/${CMAKE_SYSTEM_NAME}-Determine-ISPC OPTIONAL)
+include(Platform/${CMAKE_SYSTEM_NAME}-ISPC OPTIONAL)
+if(NOT CMAKE_ISPC_COMPILER_NAMES)
+  set(CMAKE_ISPC_COMPILER_NAMES ispc)
+endif()
+
+
+if(NOT CMAKE_ISPC_COMPILER)
+
+  set(CMAKE_ISPC_COMPILER_INIT NOTFOUND)
+
+  # prefer the environment variable CC
+  if(NOT $ENV{ISPC} STREQUAL "")
+    get_filename_component(CMAKE_ISPC_COMPILER_INIT $ENV{ISPC} PROGRAM PROGRAM_ARGS CMAKE_ISPC_FLAGS_ENV_INIT)
+    if(CMAKE_ISPC_FLAGS_ENV_INIT)
+      set(CMAKE_ISPC_COMPILER_ARG1 "${CMAKE_ISPC_FLAGS_ENV_INIT}" CACHE STRING "First argument to ISPC compiler")
+    endif()
+    if(NOT EXISTS ${CMAKE_ISPC_COMPILER_INIT})
+      message(FATAL_ERROR "Could not find compiler set in environment variable ISPC:\n$ENV{ISPC}.")
+    endif()
+  endif()
+
+  # next try prefer the compiler specified by the generator
+  if(CMAKE_GENERATOR_ISPC)
+    if(NOT CMAKE_ISPC_COMPILER_INIT)
+      set(CMAKE_ISPC_COMPILER_INIT ${CMAKE_GENERATOR_ISPC})
+    endif()
+  endif()
+
+  # finally list compilers to try
+  if(NOT CMAKE_ISPC_COMPILER_INIT)
+    set(CMAKE_ISPC_COMPILER_LIST ${_CMAKE_TOOLCHAIN_PREFIX}ispc ispc)
+  endif()
+
+  # Find the compiler.
+  _cmake_find_compiler(ISPC)
+
+else()
+  _cmake_find_compiler_path(ISPC)
+endif()
+mark_as_advanced(CMAKE_ISPC_COMPILER)
+
+if(NOT CMAKE_ISPC_COMPILER_ID_RUN)
+set(CMAKE_ISPC_COMPILER_ID_RUN 1)
+
+  # Try to identify the compiler.
+  set(CMAKE_ISPC_COMPILER_ID)
+  set(CMAKE_ISPC_PLATFORM_ID)
+
+
+  set(CMAKE_ISPC_COMPILER_ID_TEST_FLAGS_FIRST
+  # setup logic to make sure ISPC outputs a file
+  "-o cmake_ispc_output"
+  )
+
+  include(${CMAKE_ROOT}/Modules/CMakeDetermineCompilerId.cmake)
+  CMAKE_DETERMINE_COMPILER_ID(ISPC ISPCFLAGS CMakeISPCCompilerId.ispc)
+
+  _cmake_find_compiler_sysroot(ISPC)
+endif()
+
+if (NOT _CMAKE_TOOLCHAIN_LOCATION)
+  get_filename_component(_CMAKE_TOOLCHAIN_LOCATION "${CMAKE_ISPC_COMPILER}" PATH)
+endif ()
+
+set(_CMAKE_PROCESSING_LANGUAGE "ISPC")
+include(CMakeFindBinUtils)
+include(Compiler/${CMAKE_ISPC_COMPILER_ID}-FindBinUtils OPTIONAL)
+unset(_CMAKE_PROCESSING_LANGUAGE)
+
+if(CMAKE_ISPC_COMPILER_ID_VENDOR_MATCH)
+  set(_SET_CMAKE_ISPC_COMPILER_ID_VENDOR_MATCH
+    "set(CMAKE_ISPC_COMPILER_ID_VENDOR_MATCH [==[${CMAKE_ISPC_COMPILER_ID_VENDOR_MATCH}]==])")
+else()
+  set(_SET_CMAKE_ISPC_COMPILER_ID_VENDOR_MATCH "")
+endif()
+
+
+# configure variables set in this file for fast reload later on
+configure_file(${CMAKE_ROOT}/Modules/CMakeISPCCompiler.cmake.in
+  ${CMAKE_PLATFORM_INFO_DIR}/CMakeISPCCompiler.cmake @ONLY)
+
+set(CMAKE_ISPC_COMPILER_ENV_VAR "ISPC")

+ 1 - 0
Modules/CMakeFindBinUtils.cmake

@@ -66,6 +66,7 @@ if(("x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_SIMULATE_ID}" STREQUAL "xMSVC" AND
    OR "x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ID}" STREQUAL "xMSVC"
    OR (CMAKE_HOST_WIN32 AND "x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ID}" STREQUAL "xPGI")
    OR (CMAKE_HOST_WIN32 AND "x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ID}" STREQUAL "xNVIDIA")
+   OR (CMAKE_HOST_WIN32 AND "x${_CMAKE_PROCESSING_LANGUAGE}" STREQUAL "xISPC")
    OR (CMAKE_GENERATOR MATCHES "Visual Studio"
        AND NOT CMAKE_VS_PLATFORM_NAME STREQUAL "Tegra-Android"))
 

+ 30 - 0
Modules/CMakeISPCCompiler.cmake.in

@@ -0,0 +1,30 @@
+set(CMAKE_ISPC_COMPILER "@CMAKE_ISPC_COMPILER@")
+set(CMAKE_ISPC_COMPILER_ARG1 "@CMAKE_ISPC_COMPILER_ARG1@")
+set(CMAKE_ISPC_COMPILER_ID "@CMAKE_ISPC_COMPILER_ID@")
+set(CMAKE_ISPC_COMPILER_VERSION "@CMAKE_ISPC_COMPILER_VERSION@")
+set(CMAKE_ISPC_COMPILER_VERSION_INTERNAL "@CMAKE_ISPC_COMPILER_VERSION_INTERNAL@")
+
+set(CMAKE_ISPC_PLATFORM_ID "@CMAKE_ISPC_PLATFORM_ID@")
+set(CMAKE_ISPC_SIMULATE_ID "@CMAKE_ISPC_SIMULATE_ID@")
+set(CMAKE_ISPC_COMPILER_FRONTEND_VARIANT "@CMAKE_ISPC_COMPILER_FRONTEND_VARIANT@")
+set(CMAKE_ISPC_SIMULATE_VERSION "@CMAKE_ISPC_SIMULATE_VERSION@")
+
+set(CMAKE_AR "@CMAKE_AR@")
+set(CMAKE_ISPC_COMPILER_AR "@CMAKE_ISPC_COMPILER_AR@")
+set(CMAKE_RANLIB "@CMAKE_RANLIB@")
+set(CMAKE_ISPC_COMPILER_RANLIB "@CMAKE_ISPC_COMPILER_RANLIB@")
+
+set(CMAKE_ISPC_COMPILER_LOADED 1)
+set(CMAKE_ISPC_COMPILER_WORKS @CMAKE_ISPC_COMPILER_WORKS@)
+set(CMAKE_ISPC_ABI_COMPILED @CMAKE_ISPC_ABI_COMPILED@)
+
+set(CMAKE_ISPC_COMPILER_ENV_VAR "ISPC")
+
+set(CMAKE_ISPC_COMPILER_ID_RUN 1)
+set(CMAKE_ISPC_SOURCE_FILE_EXTENSIONS ispc)
+set(CMAKE_ISPC_IGNORE_EXTENSIONS o;O)
+
+set(CMAKE_ISPC_LINKER_PREFERENCE 0)
+set(CMAKE_ISPC_LINKER_PREFERENCE_PROPAGATES 0)
+
+@CMAKE_ISPC_COMPILER_CUSTOM_CODE@

+ 20 - 0
Modules/CMakeISPCCompilerABI.ispc

@@ -0,0 +1,20 @@
+
+export void ispcCompilerABI() {
+
+#if defined(__GNU__) && defined(__ELF__) && defined(__ARM_EABI__)
+  print("INFO:abi[ELF ARMEABI]");
+  static char const info_abi[] =
+#elif defined(__GNU__) && defined(__ELF__) && defined(__ARMEB__)
+  print("INFO:abi[ELF ARM]");
+#elif defined(__GNU__) && defined(__ELF__) && defined(__ARMEL__)
+  print("INFO:abi[ELF ARM]");
+
+#elif defined(__linux__) && defined(__ELF__) && defined(__amd64__) &&         \
+  defined(__ILP32__)
+print("INFO:abi[ELF X32]");
+
+#elif defined(__ELF__)
+print("INFO:abi[ELF]");
+#endif
+
+}

+ 62 - 0
Modules/CMakeISPCCompilerId.ispc.in

@@ -0,0 +1,62 @@
+
+export void ispcCompilerId() {
+
+// Identify the compiler
+#if defined(ISPC)
+  print("INFO:compiler[Intel]");
+#endif
+
+// Identify the platform
+#if defined(__linux) || defined(__linux__) || defined(linux)
+  print("INFO:platform[Linux]");
+#elif defined(__CYGWIN__)
+  print("INFO:platform[Cygwin]");
+#elif defined(__MINGW32__)
+  print("INFO:platform[MinGW]");
+#elif defined(__APPLE__)
+  print("INFO:platform[Darwin]");
+#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
+  print("INFO:platform[Windows]");
+#elif defined(__FreeBSD__) || defined(__FreeBSD)
+  print("INFO:platform[FreeBSD]");
+#elif defined(__NetBSD__) || defined(__NetBSD)
+  print("INFO:platform[NetBSD]");
+#elif defined(__OpenBSD__) || defined(__OPENBSD)
+  print("INFO:platform[OpenBSD]");
+#elif defined(__sun) || defined(sun)
+  print("INFO:platform[SunOS]");
+#elif defined(_AIX) || defined(__AIX) || defined(__AIX__) || defined(__aix) || defined(__aix__)
+  print("INFO:platform[AIX]");
+#elif defined(__hpux) || defined(__hpux__)
+  print("INFO:platform[HP-UX]");
+#elif defined(__HAIKU__)
+  print("INFO:platform[Haiku]");
+#elif defined(__BeOS) || defined(__BEOS__) || defined(_BEOS)
+  print("INFO:platform[BeOS]");
+#elif defined(__QNX__) || defined(__QNXNTO__)
+  print("INFO:platform[QNX]");
+#elif defined(__tru64) || defined(_tru64) || defined(__TRU64__)
+  print("INFO:platform[Tru64]");
+#elif defined(__riscos) || defined(__riscos__)
+  print("INFO:platform[RISCos]");
+#elif defined(__sinix) || defined(__sinix__) || defined(__SINIX__)
+  print("INFO:platform[SINIX]");
+#elif defined(__UNIX_SV__)
+  print("INFO:platform[UNIX_SV]");
+#elif defined(__bsdos__)
+  print("INFO:platform[BSDOS]");
+#elif defined(_MPRAS) || defined(MPRAS)
+  print("INFO:platform[MP-RAS]");
+#elif defined(__osf) || defined(__osf__)
+  print("INFO:platform[OSF1]");
+#elif defined(_SCO_SV) || defined(SCO_SV) || defined(sco_sv)
+  print("INFO:platform[SCO_SV]");
+#elif defined(__ultrix) || defined(__ultrix__) || defined(_ULTRIX)
+  print("INFO:platform[ULTRIX]");
+#elif defined(__XENIX__) || defined(_XENIX) || defined(XENIX)
+  print("INFO:platform[Xenix]");
+#else
+  print("INFO:platform[]");
+#endif
+
+}

+ 56 - 0
Modules/CMakeISPCInformation.cmake

@@ -0,0 +1,56 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+set(CMAKE_ISPC_OUTPUT_EXTENSION .o)
+set(CMAKE_INCLUDE_FLAG_ISPC "-I")
+
+# Load compiler-specific information.
+if(CMAKE_ISPC_COMPILER_ID)
+  include(Compiler/${CMAKE_ISPC_COMPILER_ID}-ISPC OPTIONAL)
+endif()
+
+# load the system- and compiler specific files
+if(CMAKE_ISPC_COMPILER_ID)
+  # load a hardware specific file, mostly useful for embedded compilers
+  if(CMAKE_SYSTEM_PROCESSOR)
+    include(Platform/${CMAKE_EFFECTIVE_SYSTEM_NAME}-${CMAKE_ISPC_COMPILER_ID}-ISPC-${CMAKE_SYSTEM_PROCESSOR} OPTIONAL)
+  endif()
+  include(Platform/${CMAKE_EFFECTIVE_SYSTEM_NAME}-${CMAKE_ISPC_COMPILER_ID}-ISPC OPTIONAL)
+endif()
+
+# add the flags to the cache based
+# on the initial values computed in the platform/*.cmake files
+# use _INIT variables so that this only happens the first time
+# and you can set these flags in the cmake cache
+set(CMAKE_ISPC_FLAGS_INIT "$ENV{ISPCFLAGS} ${CMAKE_ISPC_FLAGS_INIT}")
+
+cmake_initialize_per_config_variable(CMAKE_ISPC_FLAGS "Flags used by the ISPC compiler")
+
+if(CMAKE_ISPC_STANDARD_LIBRARIES_INIT)
+  set(CMAKE_ISPC_STANDARD_LIBRARIES "${CMAKE_ISPC_STANDARD_LIBRARIES_INIT}"
+    CACHE STRING "Libraries linked by default with all ISPC applications.")
+  mark_as_advanced(CMAKE_ISPC_STANDARD_LIBRARIES)
+endif()
+
+include(CMakeCommonLanguageInclude)
+
+# now define the following rules:
+# CMAKE_ISPC_COMPILE_OBJECT
+
+# Create a static archive incrementally for large object file counts.
+if(NOT DEFINED CMAKE_ISPC_ARCHIVE_CREATE)
+  set(CMAKE_ISPC_ARCHIVE_CREATE "<CMAKE_AR> qc <TARGET> <LINK_FLAGS> <OBJECTS>")
+endif()
+if(NOT DEFINED CMAKE_ISPC_ARCHIVE_APPEND)
+  set(CMAKE_ISPC_ARCHIVE_APPEND "<CMAKE_AR> q <TARGET> <LINK_FLAGS> <OBJECTS>")
+endif()
+if(NOT DEFINED CMAKE_ISPC_ARCHIVE_FINISH)
+  set(CMAKE_ISPC_ARCHIVE_FINISH "<CMAKE_RANLIB> <TARGET>")
+endif()
+
+if(NOT CMAKE_ISPC_COMPILE_OBJECT)
+  set(CMAKE_ISPC_COMPILE_OBJECT
+    "<CMAKE_ISPC_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> --emit-obj <SOURCE> -h <ISPC_HEADER>")
+endif()
+
+set(CMAKE_ISPC_INFORMATION_LOADED 1)

+ 43 - 0
Modules/CMakeTestISPCCompiler.cmake

@@ -0,0 +1,43 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+
+if(CMAKE_ISPC_COMPILER_FORCED)
+  # The compiler configuration was forced by the user.
+  # Assume the user has configured all compiler information.
+  set(CMAKE_ISPC_COMPILER_WORKS TRUE)
+  return()
+endif()
+
+include(CMakeTestCompilerCommon)
+
+# Make sure we try to compile as a STATIC_LIBRARY
+set(__CMAKE_SAVED_TRY_COMPILE_TARGET_TYPE ${CMAKE_TRY_COMPILE_TARGET_TYPE})
+set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
+
+# # Try to identify the ABI and configure it into CMakeISPCCompiler.cmake
+include(${CMAKE_ROOT}/Modules/CMakeDetermineCompilerABI.cmake)
+CMAKE_DETERMINE_COMPILER_ABI(ISPC ${CMAKE_ROOT}/Modules/CMakeISPCCompilerABI.ispc)
+if(CMAKE_ISPC_ABI_COMPILED)
+#   # The compiler worked so skip dedicated test below.
+  set(CMAKE_ISPC_COMPILER_WORKS TRUE)
+  message(STATUS "Check for working ISPC compiler: ${CMAKE_ISPC_COMPILER} - skipped")
+endif()
+
+# Re-configure to save learned information.
+configure_file(
+  ${CMAKE_ROOT}/Modules/CMakeISPCCompiler.cmake.in
+  ${CMAKE_PLATFORM_INFO_DIR}/CMakeISPCCompiler.cmake
+  @ONLY
+  )
+include(${CMAKE_PLATFORM_INFO_DIR}/CMakeISPCCompiler.cmake)
+
+if(CMAKE_ISPC_SIZEOF_DATA_PTR)
+  foreach(f ${CMAKE_ISPC_ABI_FILES})
+    include(${f})
+  endforeach()
+  unset(CMAKE_ISPC_ABI_FILES)
+endif()
+
+set(CMAKE_TRY_COMPILE_TARGET_TYPE ${__CMAKE_SAVED_TRY_COMPILE_TARGET_TYPE})

+ 22 - 0
Modules/Compiler/Intel-ISPC.cmake

@@ -0,0 +1,22 @@
+include(Compiler/CMakeCommonCompilerMacros)
+
+# Not aware of any verbose flag for ISPC
+#set(CMAKE_ISPC_VERBOSE_FLAG )
+
+set(CMAKE_DEPFILE_FLAGS_ISPC "-M -MT <OBJECT> -MF <DEPFILE>")
+
+string(APPEND CMAKE_ISPC_FLAGS_INIT " ")
+string(APPEND CMAKE_ISPC_FLAGS_DEBUG_INIT "-O0 -g")
+string(APPEND CMAKE_ISPC_FLAGS_RELEASE_INIT " -O3 -DNDEBUG")
+string(APPEND CMAKE_ISPC_FLAGS_MINSIZEREL_INIT " -O1 -DNDEBUG")
+string(APPEND CMAKE_ISPC_FLAGS_RELWITHDEBINFO_INIT " -O2 -g -DNDEBUG")
+
+set(CMAKE_ISPC_COMPILE_OPTIONS_PIE --pic)
+set(CMAKE_ISPC_COMPILE_OPTIONS_PIC --pic)
+
+set(CMAKE_INCLUDE_SYSTEM_FLAG_ISPC -isystem=)
+
+set(CMAKE_ISPC_RESPONSE_FILE_FLAG "@")
+set(CMAKE_ISPC_USE_RESPONSE_FILE_FOR_INCLUDES 1)
+set(CMAKE_ISPC_USE_RESPONSE_FILE_FOR_LIBRARIES 1)
+set(CMAKE_ISPC_USE_RESPONSE_FILE_FOR_OBJECTS 1)

+ 8 - 0
Modules/Platform/Windows-Intel-ISPC.cmake

@@ -0,0 +1,8 @@
+
+if(CMAKE_VERBOSE_MAKEFILE)
+  set(CMAKE_CL_NOLOGO)
+else()
+  set(CMAKE_CL_NOLOGO "/nologo")
+endif()
+
+set(CMAKE_ISPC_CREATE_STATIC_LIBRARY  "<CMAKE_AR> ${CMAKE_CL_NOLOGO} <LINK_FLAGS> /out:<TARGET> <OBJECTS> ")

+ 12 - 0
Source/cmCoreTryCompile.cxx

@@ -192,6 +192,8 @@ SETUP_LANGUAGE(objc_properties, OBJC);
 // NOLINTNEXTLINE(bugprone-suspicious-missing-comma)
 SETUP_LANGUAGE(objcxx_properties, OBJCXX);
 // NOLINTNEXTLINE(bugprone-suspicious-missing-comma)
+SETUP_LANGUAGE(ispc_properties, ISPC);
+// NOLINTNEXTLINE(bugprone-suspicious-missing-comma)
 SETUP_LANGUAGE(swift_properties, Swift);
 #undef SETUP_LANGUAGE
 
@@ -499,6 +501,12 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
       }
     }
 
+    // when the only language is ISPC we know that the output
+    // type must by a static library
+    if (testLangs.size() == 1 && testLangs.count("ISPC") == 1) {
+      targetType = cmStateEnums::STATIC_LIBRARY;
+    }
+
     std::string const tcConfig =
       this->Makefile->GetSafeDefinition("CMAKE_TRY_COMPILE_CONFIGURATION");
 
@@ -702,6 +710,8 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
       vars.insert(
         &objcxx_properties[lang_property_start],
         &objcxx_properties[lang_property_start + lang_property_size]);
+      vars.insert(&ispc_properties[lang_property_start],
+                  &ispc_properties[lang_property_start + lang_property_size]);
       vars.insert(&swift_properties[lang_property_start],
                   &swift_properties[lang_property_start + lang_property_size]);
       vars.insert(kCMAKE_CUDA_ARCHITECTURES);
@@ -744,6 +754,8 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
         vars.insert(
           &objcxx_properties[pie_property_start],
           &objcxx_properties[pie_property_start + pie_property_size]);
+        vars.insert(&ispc_properties[pie_property_start],
+                    &ispc_properties[pie_property_start + pie_property_size]);
         vars.insert(&swift_properties[pie_property_start],
                     &swift_properties[pie_property_start + pie_property_size]);
       }

+ 3 - 2
Source/cmGeneratorExpressionNode.cxx

@@ -715,7 +715,8 @@ struct CompilerIdNode : public cmGeneratorExpressionNode
 
 static const CompilerIdNode cCompilerIdNode("C"), cxxCompilerIdNode("CXX"),
   cudaCompilerIdNode("CUDA"), objcCompilerIdNode("OBJC"),
-  objcxxCompilerIdNode("OBJCXX"), fortranCompilerIdNode("Fortran");
+  objcxxCompilerIdNode("OBJCXX"), fortranCompilerIdNode("Fortran"),
+  ispcCompilerIdNode("ISPC");
 
 struct CompilerVersionNode : public cmGeneratorExpressionNode
 {
@@ -780,7 +781,7 @@ struct CompilerVersionNode : public cmGeneratorExpressionNode
 static const CompilerVersionNode cCompilerVersionNode("C"),
   cxxCompilerVersionNode("CXX"), cudaCompilerVersionNode("CUDA"),
   objcCompilerVersionNode("OBJC"), objcxxCompilerVersionNode("OBJCXX"),
-  fortranCompilerVersionNode("Fortran");
+  fortranCompilerVersionNode("Fortran"), ispcCompilerVersionNode("ISPC");
 
 struct PlatformIdNode : public cmGeneratorExpressionNode
 {

+ 94 - 28
Source/cmGeneratorTarget.cxx

@@ -1363,18 +1363,25 @@ std::string cmGeneratorTarget::EvaluateInterfaceProperty(
 }
 
 namespace {
-std::string AddSwiftInterfaceIncludeDirectories(
+
+enum class IncludeDirectoryFallBack
+{
+  BINARY,
+  OBJECT
+};
+
+std::string AddLangSpecificInterfaceIncludeDirectories(
   const cmGeneratorTarget* root, const cmGeneratorTarget* target,
-  const std::string& config, cmGeneratorExpressionDAGChecker* context)
+  const std::string& lang, const std::string& config,
+  const std::string& propertyName, IncludeDirectoryFallBack mode,
+  cmGeneratorExpressionDAGChecker* context)
 {
   cmGeneratorExpressionDAGChecker dag{ target->GetBacktrace(), target,
-                                       "Swift_MODULE_DIRECTORY", nullptr,
-                                       context };
+                                       propertyName, nullptr, context };
   switch (dag.Check()) {
     case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
-      dag.ReportError(nullptr,
-                      "$<TARGET_PROPERTY:" + target->GetName() +
-                        ",Swift_MODULE_DIRECTORY>");
+      dag.ReportError(
+        nullptr, "$<TARGET_PROPERTY:" + target->GetName() + ",propertyName");
       CM_FALLTHROUGH;
     case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE:
       // No error. We just skip cyclic references.
@@ -1390,13 +1397,16 @@ std::string AddSwiftInterfaceIncludeDirectories(
         target->GetLinkInterfaceLibraries(config, root, true)) {
     for (const cmLinkItem& library : interface->Libraries) {
       if (const cmGeneratorTarget* dependency = library.Target) {
-        if (cm::contains(dependency->GetAllConfigCompileLanguages(),
-                         "Swift")) {
-          std::string value =
-            dependency->GetSafeProperty("Swift_MODULE_DIRECTORY");
+        if (cm::contains(dependency->GetAllConfigCompileLanguages(), lang)) {
+          auto* lg = dependency->GetLocalGenerator();
+          std::string value = dependency->GetSafeProperty(propertyName);
           if (value.empty()) {
-            value =
-              dependency->GetLocalGenerator()->GetCurrentBinaryDirectory();
+            if (mode == IncludeDirectoryFallBack::BINARY) {
+              value = lg->GetCurrentBinaryDirectory();
+            } else if (mode == IncludeDirectoryFallBack::OBJECT) {
+              value = cmStrCat(lg->GetCurrentBinaryDirectory(), '/',
+                               lg->GetTargetDirectory(dependency));
+            }
           }
 
           if (!directories.empty()) {
@@ -1410,35 +1420,39 @@ std::string AddSwiftInterfaceIncludeDirectories(
   return directories;
 }
 
-void AddSwiftImplicitIncludeDirectories(
-  const cmGeneratorTarget* target, const std::string& config,
-  EvaluatedTargetPropertyEntries& entries)
+void AddLangSpecificImplicitIncludeDirectories(
+  const cmGeneratorTarget* target, const std::string& lang,
+  const std::string& config, const std::string& propertyName,
+  IncludeDirectoryFallBack mode, EvaluatedTargetPropertyEntries& entries)
 {
   if (const auto* libraries = target->GetLinkImplementationLibraries(config)) {
     cmGeneratorExpressionDAGChecker dag{ target->GetBacktrace(), target,
-                                         "Swift_MODULE_DIRECTORY", nullptr,
-                                         nullptr };
+                                         propertyName, nullptr, nullptr };
 
     for (const cmLinkImplItem& library : libraries->Libraries) {
       if (const cmGeneratorTarget* dependency = library.Target) {
         if (!dependency->IsInBuildSystem()) {
           continue;
         }
-        if (cm::contains(dependency->GetAllConfigCompileLanguages(),
-                         "Swift")) {
+        if (cm::contains(dependency->GetAllConfigCompileLanguages(), lang)) {
+          auto* lg = dependency->GetLocalGenerator();
           EvaluatedTargetPropertyEntry entry{ library, library.Backtrace };
 
-          if (cmProp val = dependency->GetProperty("Swift_MODULE_DIRECTORY")) {
+          if (cmProp val = dependency->GetProperty(propertyName)) {
             entry.Values.emplace_back(*val);
           } else {
-            entry.Values.emplace_back(
-              dependency->GetLocalGenerator()->GetCurrentBinaryDirectory());
+            if (mode == IncludeDirectoryFallBack::BINARY) {
+              entry.Values.emplace_back(lg->GetCurrentBinaryDirectory());
+            } else if (mode == IncludeDirectoryFallBack::OBJECT) {
+              entry.Values.emplace_back(
+                dependency->GetObjectDirectory(config));
+            }
           }
 
-          cmExpandList(AddSwiftInterfaceIncludeDirectories(target, dependency,
-                                                           config, &dag),
-                       entry.Values);
-
+          cmExpandList(
+            AddLangSpecificInterfaceIncludeDirectories(
+              target, dependency, lang, config, propertyName, mode, &dag),
+            entry.Values);
           entries.Entries.emplace_back(std::move(entry));
         }
       }
@@ -3482,7 +3496,28 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetIncludeDirectories(
     this, config, lang, &dagChecker, this->IncludeDirectoriesEntries);
 
   if (lang == "Swift") {
-    AddSwiftImplicitIncludeDirectories(this, config, entries);
+    AddLangSpecificImplicitIncludeDirectories(
+      this, lang, config, "Swift_MODULE_DIRECTORY",
+      IncludeDirectoryFallBack::BINARY, entries);
+  }
+
+  if (this->CanCompileSources() && (lang != "Swift" && lang != "Fortran")) {
+
+    const std::string propertyName = "ISPC_HEADER_DIRECTORY";
+
+    // If this target has ISPC sources make sure to add the header
+    // directory to other compilation units
+    if (cm::contains(this->GetAllConfigCompileLanguages(), "ISPC")) {
+      if (cmProp val = this->GetProperty(propertyName)) {
+        includes.emplace_back(*val);
+      } else {
+        includes.emplace_back(this->GetObjectDirectory(config));
+      }
+    }
+
+    AddLangSpecificImplicitIncludeDirectories(
+      this, "ISPC", config, propertyName, IncludeDirectoryFallBack::OBJECT,
+      entries);
   }
 
   AddInterfaceEntries(this, config, "INTERFACE_INCLUDE_DIRECTORIES", lang,
@@ -5976,6 +6011,37 @@ std::string cmGeneratorTarget::CreateFortranModuleDirectory(
   return mod_dir;
 }
 
+void cmGeneratorTarget::AddISPCGeneratedHeader(std::string const& header,
+                                               std::string const& config)
+{
+  std::string config_upper;
+  if (!config.empty()) {
+    config_upper = cmSystemTools::UpperCase(config);
+  }
+  auto iter = this->ISPCGeneratedHeaders.find(config_upper);
+  if (iter == this->ISPCGeneratedHeaders.end()) {
+    std::vector<std::string> headers;
+    headers.emplace_back(header);
+    this->ISPCGeneratedHeaders.insert({ config_upper, headers });
+  } else {
+    iter->second.emplace_back(header);
+  }
+}
+
+std::vector<std::string> cmGeneratorTarget::GetGeneratedISPCHeaders(
+  std::string const& config) const
+{
+  std::string config_upper;
+  if (!config.empty()) {
+    config_upper = cmSystemTools::UpperCase(config);
+  }
+  auto iter = this->ISPCGeneratedHeaders.find(config_upper);
+  if (iter == this->ISPCGeneratedHeaders.end()) {
+    return std::vector<std::string>{};
+  }
+  return iter->second;
+}
+
 std::string cmGeneratorTarget::GetFrameworkVersion() const
 {
   assert(this->GetType() != cmStateEnums::INTERFACE_LIBRARY);

+ 8 - 0
Source/cmGeneratorTarget.h

@@ -816,6 +816,11 @@ public:
 
   const std::string& GetSourcesProperty() const;
 
+  void AddISPCGeneratedHeader(std::string const& header,
+                              std::string const& config);
+  std::vector<std::string> GetGeneratedISPCHeaders(
+    std::string const& config) const;
+
 private:
   void AddSourceCommon(const std::string& src, bool before = false);
 
@@ -994,6 +999,9 @@ private:
 
   std::unordered_set<std::string> UnityBatchedSourceFiles;
 
+  std::unordered_map<std::string, std::vector<std::string>>
+    ISPCGeneratedHeaders;
+
   bool IsLinkLookupScope(std::string const& n,
                          cmLocalGenerator const*& lg) const;
 

+ 1 - 0
Source/cmGlobalGenerator.cxx

@@ -1601,6 +1601,7 @@ bool cmGlobalGenerator::AddAutomaticSources()
         continue;
       }
       lg->AddUnityBuild(gt.get());
+      lg->AddISPCDependencies(gt.get());
       // Targets that re-use a PCH are handled below.
       if (!gt->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM")) {
         lg->AddPchDependencies(gt.get());

+ 42 - 0
Source/cmGlobalNinjaGenerator.cxx

@@ -680,6 +680,9 @@ void cmGlobalNinjaGenerator::CheckNinjaFeatures()
   this->NinjaSupportsRestatTool = !cmSystemTools::VersionCompare(
     cmSystemTools::OP_LESS, this->NinjaVersion.c_str(),
     RequiredNinjaVersionForRestatTool().c_str());
+  this->NinjaSupportsMultipleOutputs = !cmSystemTools::VersionCompare(
+    cmSystemTools::OP_LESS, this->NinjaVersion.c_str(),
+    RequiredNinjaVersionForMultipleOutputs().c_str());
 }
 
 bool cmGlobalNinjaGenerator::CheckLanguages(
@@ -688,6 +691,9 @@ bool cmGlobalNinjaGenerator::CheckLanguages(
   if (cm::contains(languages, "Fortran")) {
     return this->CheckFortran(mf);
   }
+  if (cm::contains(languages, "ISPC")) {
+    return this->CheckISPC(mf);
+  }
   if (cm::contains(languages, "Swift")) {
     const std::string architectures =
       mf->GetSafeDefinition("CMAKE_OSX_ARCHITECTURES");
@@ -721,6 +727,25 @@ bool cmGlobalNinjaGenerator::CheckFortran(cmMakefile* mf) const
   return false;
 }
 
+bool cmGlobalNinjaGenerator::CheckISPC(cmMakefile* mf) const
+{
+  if (this->NinjaSupportsMultipleOutputs) {
+    return true;
+  }
+
+  std::ostringstream e;
+  /* clang-format off */
+  e <<
+    "The Ninja generator does not support ISPC using Ninja version\n"
+    "  " << this->NinjaVersion << "\n"
+    "due to lack of required features.  Ninja 1.10 or higher is required."
+    ;
+  /* clang-format on */
+  mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+  cmSystemTools::SetFatalErrorOccured();
+  return false;
+}
+
 void cmGlobalNinjaGenerator::EnableLanguage(
   std::vector<std::string> const& langs, cmMakefile* mf, bool optional)
 {
@@ -1127,6 +1152,21 @@ void cmGlobalNinjaGenerator::AppendTargetDepends(
     }
   } else {
     cmNinjaDeps outs;
+
+    auto computeISPCOuputs = [](cmGlobalNinjaGenerator* gg,
+                                cmGeneratorTarget const* depTarget,
+                                cmNinjaDeps& outputDeps,
+                                const std::string& targetConfig) {
+      if (depTarget->CanCompileSources()) {
+        auto headers = depTarget->GetGeneratedISPCHeaders(targetConfig);
+        if (!headers.empty()) {
+          std::transform(headers.begin(), headers.end(), headers.begin(),
+                         gg->MapToNinjaPath());
+          outputDeps.insert(outputDeps.end(), headers.begin(), headers.end());
+        }
+      }
+    };
+
     for (cmTargetDepend const& targetDep :
          this->GetTargetDirectDepends(target)) {
       if (!targetDep->IsInBuildSystem()) {
@@ -1134,8 +1174,10 @@ void cmGlobalNinjaGenerator::AppendTargetDepends(
       }
       if (targetDep.IsCross()) {
         this->AppendTargetOutputs(targetDep, outs, fileConfig, depends);
+        computeISPCOuputs(this, targetDep, outs, fileConfig);
       } else {
         this->AppendTargetOutputs(targetDep, outs, config, depends);
+        computeISPCOuputs(this, targetDep, outs, config);
       }
     }
     std::sort(outs.begin(), outs.end());

+ 6 - 0
Source/cmGlobalNinjaGenerator.h

@@ -370,6 +370,10 @@ public:
     return "1.10";
   }
   static std::string RequiredNinjaVersionForCleanDeadTool() { return "1.10"; }
+  static std::string RequiredNinjaVersionForMultipleOutputs()
+  {
+    return "1.10";
+  }
   bool SupportsConsolePool() const;
   bool SupportsImplicitOuts() const;
   bool SupportsManifestRestat() const;
@@ -447,6 +451,7 @@ private:
   bool CheckLanguages(std::vector<std::string> const& languages,
                       cmMakefile* mf) const override;
   bool CheckFortran(cmMakefile* mf) const;
+  bool CheckISPC(cmMakefile* mf) const;
 
   void CloseCompileCommandsStream();
 
@@ -533,6 +538,7 @@ private:
   bool NinjaSupportsRestatTool = false;
   bool NinjaSupportsUnconditionalRecompactTool = false;
   bool NinjaSupportsCleanDeadTool = false;
+  bool NinjaSupportsMultipleOutputs = false;
 
 private:
   void InitOutputPathPrefix();

+ 32 - 0
Source/cmLocalGenerator.cxx

@@ -2426,6 +2426,38 @@ void cmLocalGenerator::AppendFlagEscape(std::string& flags,
     this->EscapeForShell(rawFlag, false, false, false, this->IsNinjaMulti()));
 }
 
+void cmLocalGenerator::AddISPCDependencies(cmGeneratorTarget* target)
+{
+  //
+  std::vector<std::string> configsList =
+    this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
+  for (std::string const& config : configsList) {
+
+    std::string perConfigDir = target->GetObjectDirectory(config);
+    if (cmProp prop = target->GetProperty("ISPC_HEADER_DIRECTORY")) {
+      perConfigDir = cmSystemTools::CollapseFullPath(
+        cmStrCat(this->GetBinaryDirectory(), '/', *prop));
+    }
+
+    std::vector<cmSourceFile*> sources;
+    target->GetSourceFiles(sources, config);
+
+    // build up the list of ispc headers that this target is generating
+    for (cmSourceFile const* sf : sources) {
+      // Generate this object file's rule file.
+      const std::string& lang = sf->GetLanguage();
+      if (lang == "ISPC") {
+        std::string const& objectName = target->GetObjectName(sf);
+        std::string ispcSource =
+          cmSystemTools::GetFilenameWithoutLastExtension(objectName);
+
+        auto headerPath = cmStrCat(perConfigDir, '/', ispcSource, ".h");
+        target->AddISPCGeneratedHeader(headerPath, config);
+      }
+    }
+  }
+}
+
 void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target)
 {
   std::vector<std::string> configsList =

+ 1 - 0
Source/cmLocalGenerator.h

@@ -133,6 +133,7 @@ public:
                            const std::vector<BT<std::string>>& newFlags) const;
   virtual void AppendFlagEscape(std::string& flags,
                                 const std::string& rawFlag) const;
+  void AddISPCDependencies(cmGeneratorTarget* target);
   void AddPchDependencies(cmGeneratorTarget* target);
   void AddUnityBuild(cmGeneratorTarget* target);
   void AppendIPOLinkerFlags(std::string& flags, cmGeneratorTarget* target,

+ 4 - 2
Source/cmLocalUnixMakefileGenerator3.cxx

@@ -235,7 +235,8 @@ void cmLocalUnixMakefileGenerator3::WriteLocalMakefile()
 
     for (LocalObjectEntry const& entry : localObjectFile.second) {
       if (entry.Language == "C" || entry.Language == "CXX" ||
-          entry.Language == "CUDA" || entry.Language == "Fortran") {
+          entry.Language == "CUDA" || entry.Language == "Fortran" ||
+          entry.Language == "ISPC") {
         // Right now, C, C++, Fortran and CUDA have both a preprocessor and the
         // ability to generate assembly code
         lang_has_preprocessor = true;
@@ -1444,7 +1445,8 @@ bool cmLocalUnixMakefileGenerator3::ScanDependencies(
     // Create the scanner for this language
     std::unique_ptr<cmDepends> scanner;
     if (lang == "C" || lang == "CXX" || lang == "RC" || lang == "ASM" ||
-        lang == "OBJC" || lang == "OBJCXX" || lang == "CUDA") {
+        lang == "OBJC" || lang == "OBJCXX" || lang == "CUDA" ||
+        lang == "ISPC") {
       // TODO: Handle RC (resource files) dependencies correctly.
       scanner = cm::make_unique<cmDependsC>(this, targetDir, lang, &validDeps);
     }

+ 37 - 2
Source/cmMakefileTargetGenerator.cxx

@@ -268,6 +268,7 @@ void cmMakefileTargetGenerator::WriteTargetBuildRules()
       this->ExternalObjects.push_back(objectFileName);
     }
   }
+
   std::vector<cmSourceFile const*> objectSources;
   this->GeneratorTarget->GetObjectSources(objectSources,
                                           this->GetConfigName());
@@ -525,6 +526,14 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
     }
   }
 
+  if (lang != "ISPC") {
+    auto const& headers =
+      this->GeneratorTarget->GetGeneratedISPCHeaders(config);
+    if (!headers.empty()) {
+      depends.insert(depends.end(), headers.begin(), headers.end());
+    }
+  }
+
   std::string relativeObj =
     cmStrCat(this->LocalGenerator->GetHomeRelativeOutputPath(), obj);
   // Write the build rule.
@@ -552,6 +561,23 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
     this->AppendFortranPreprocessFlags(flags, source);
   }
 
+  std::string ispcHeaderRelative;
+  std::string ispcHeaderForShell;
+  if (lang == "ISPC") {
+    std::string ispcSource =
+      cmSystemTools::GetFilenameWithoutLastExtension(objectName);
+
+    std::string directory = this->GeneratorTarget->GetObjectDirectory(config);
+    if (cmProp prop =
+          this->GeneratorTarget->GetProperty("ISPC_HEADER_DIRECTORY")) {
+      directory =
+        cmStrCat(this->LocalGenerator->GetBinaryDirectory(), '/', *prop);
+    }
+    ispcHeaderRelative = cmStrCat(directory, '/', ispcSource, ".h");
+    ispcHeaderForShell = this->LocalGenerator->ConvertToOutputFormat(
+      ispcHeaderRelative, cmOutputConverter::SHELL);
+  }
+
   // Add flags from source file properties.
   const std::string COMPILE_FLAGS("COMPILE_FLAGS");
   if (cmProp cflags = source.GetProperty(COMPILE_FLAGS)) {
@@ -717,6 +743,7 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
     cmOutputConverter::SHELL);
   vars.ObjectFileDir = objectFileDir.c_str();
   vars.Flags = flags.c_str();
+  vars.ISPCHeader = ispcHeaderForShell.c_str();
 
   std::string definesString = cmStrCat("$(", lang, "_DEFINES)");
 
@@ -735,7 +762,8 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
   // ability to export compile commands
   bool lang_has_preprocessor =
     ((lang == "C") || (lang == "CXX") || (lang == "OBJC") ||
-     (lang == "OBJCXX") || (lang == "Fortran") || (lang == "CUDA"));
+     (lang == "OBJCXX") || (lang == "Fortran") || (lang == "CUDA") ||
+     lang == "ISPC");
   bool const lang_has_assembly = lang_has_preprocessor;
   bool const lang_can_export_cmds = lang_has_preprocessor;
 
@@ -910,9 +938,16 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
     if (!evaluated_outputs.empty()) {
       // Register these as extra files to clean.
       cmExpandList(evaluated_outputs, outputs);
-      this->CleanFiles.insert(outputs.begin() + 1, outputs.end());
     }
   }
+  if (!ispcHeaderRelative
+         .empty()) { // can't move ispcHeader as vars is using it
+    outputs.emplace_back(ispcHeaderRelative);
+  }
+
+  if (outputs.size() > 1) {
+    this->CleanFiles.insert(outputs.begin() + 1, outputs.end());
+  }
 
   // Write the rule.
   this->WriteMakeRule(*this->BuildFileStream, nullptr, outputs, depends,

+ 37 - 0
Source/cmNinjaTargetGenerator.cxx

@@ -631,6 +631,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang,
   vars.TargetCompilePDB = "$TARGET_COMPILE_PDB";
   vars.ObjectDir = "$OBJECT_DIR";
   vars.ObjectFileDir = "$OBJECT_FILE_DIR";
+  vars.ISPCHeader = "$ISPC_HEADER_FILE";
 
   cmMakefile* mf = this->GetMakefile();
 
@@ -1369,6 +1370,42 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
 
   objBuild.RspFile = cmStrCat(objectFileName, ".rsp");
 
+  if (language == "ISPC") {
+    std::string const& objectName =
+      this->GeneratorTarget->GetObjectName(source);
+    std::string ispcSource =
+      cmSystemTools::GetFilenameWithoutLastExtension(objectName);
+
+    std::string ispcDirectory = objectFileDir;
+    if (cmProp prop =
+          this->GeneratorTarget->GetProperty("ISPC_HEADER_DIRECTORY")) {
+      ispcDirectory = *prop;
+    }
+    ispcDirectory =
+      cmStrCat(this->LocalGenerator->GetBinaryDirectory(), '/', ispcDirectory);
+
+    std::string ispcHeader = cmStrCat(ispcDirectory, '/', ispcSource, ".h");
+    ispcHeader = this->ConvertToNinjaPath(ispcHeader);
+
+    // Make sure ninja knows what command generates the header
+    objBuild.ImplicitOuts.push_back(ispcHeader);
+
+    // Make sure ninja knows how to clean the generated header
+    this->GetGlobalGenerator()->AddAdditionalCleanFile(ispcHeader, config);
+
+    vars["ISPC_HEADER_FILE"] =
+      this->GetLocalGenerator()->ConvertToOutputFormat(
+        ispcHeader, cmOutputConverter::SHELL);
+  } else {
+    auto headers = this->GeneratorTarget->GetGeneratedISPCHeaders(config);
+    if (!headers.empty()) {
+      std::transform(headers.begin(), headers.end(), headers.begin(),
+                     MapToNinjaPath());
+      objBuild.OrderOnlyDeps.insert(objBuild.OrderOnlyDeps.end(),
+                                    headers.begin(), headers.end());
+    }
+  }
+
   if (language == "Swift") {
     this->EmitSwiftDependencyInfo(source, config);
   } else {

+ 5 - 0
Source/cmRulePlaceholderExpander.cxx

@@ -90,6 +90,11 @@ std::string cmRulePlaceholderExpander::ExpandRuleVariable(
       return replaceValues.AIXExports;
     }
   }
+  if (replaceValues.ISPCHeader) {
+    if (variable == "ISPC_HEADER") {
+      return replaceValues.ISPCHeader;
+    }
+  }
   if (replaceValues.Defines && variable == "DEFINES") {
     return replaceValues.Defines;
   }

+ 1 - 0
Source/cmRulePlaceholderExpander.h

@@ -64,6 +64,7 @@ public:
     const char* SwiftModuleName;
     const char* SwiftOutputFileMap;
     const char* SwiftSources;
+    const char* ISPCHeader;
   };
 
   // Expand rule variables in CMake of the type found in language rules

+ 1 - 0
Source/cmTarget.cxx

@@ -366,6 +366,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
     initProp("JOB_POOL_COMPILE");
     initProp("JOB_POOL_LINK");
     initProp("JOB_POOL_PRECOMPILE_HEADER");
+    initProp("ISPC_HEADER_DIRECTORY");
     initProp("LINK_SEARCH_START_STATIC");
     initProp("LINK_SEARCH_END_STATIC");
     initProp("Swift_LANGUAGE_VERSION");

+ 3 - 0
Source/cmake.cxx

@@ -205,6 +205,7 @@ cmake::cmake(Role role, cmState::Mode mode)
     setupExts(this->CudaFileExtensions, { "cu" });
     setupExts(this->FortranFileExtensions,
               { "f", "F", "for", "f77", "f90", "f95", "f03" });
+    setupExts(this->ISPCFileExtensions, { "ispc" });
   }
 }
 
@@ -1978,6 +1979,8 @@ std::vector<std::string> cmake::GetAllExtensions() const
   // cuda extensions are also in SourceFileExtensions so we ignore it here
   allExt.insert(allExt.end(), this->FortranFileExtensions.ordered.begin(),
                 this->FortranFileExtensions.ordered.end());
+  allExt.insert(allExt.end(), this->ISPCFileExtensions.ordered.begin(),
+                this->ISPCFileExtensions.ordered.end());
   return allExt;
 }
 

+ 3 - 1
Source/cmake.h

@@ -268,7 +268,8 @@ public:
   {
     return this->CLikeSourceFileExtensions.Test(ext) ||
       this->CudaFileExtensions.Test(ext) ||
-      this->FortranFileExtensions.Test(ext);
+      this->FortranFileExtensions.Test(ext) ||
+      this->ISPCFileExtensions.Test(ext);
   }
 
   bool IsACLikeSourceExtension(cm::string_view ext) const
@@ -617,6 +618,7 @@ private:
   FileExtensions CLikeSourceFileExtensions;
   FileExtensions HeaderFileExtensions;
   FileExtensions CudaFileExtensions;
+  FileExtensions ISPCFileExtensions;
   FileExtensions FortranFileExtensions;
   bool ClearBuildSystem = false;
   bool DebugTryCompile = false;

+ 4 - 0
Tests/CMakeLists.txt

@@ -1483,6 +1483,10 @@ ${CMake_SOURCE_DIR}/Utilities/Release/push.bash --dir dev -- '${CMake_BUILD_NIGH
     add_subdirectory(CudaOnly)
   endif()
 
+  if(CMake_TEST_ISPC)
+    add_subdirectory(ISPC)
+  endif()
+
   if(CMake_TEST_FindGTest)
     add_subdirectory(FindGTest)
     add_subdirectory(GoogleTest)

+ 13 - 0
Tests/ISPC/CMakeLists.txt

@@ -0,0 +1,13 @@
+
+
+macro (add_ispc_test_macro name)
+  add_test_macro("${name}" ${ARGN})
+  set_property(TEST "${name}" APPEND
+    PROPERTY LABELS "ISPC")
+endmacro ()
+
+add_ispc_test_macro(ISPC.Defines ISPCDefines)
+add_ispc_test_macro(ISPC.ObjectLibrary ISPCObjectLibrary)
+add_ispc_test_macro(ISPC.ResponseAndDefine ISPCResponseAndDefine)
+add_ispc_test_macro(ISPC.StaticLibrary ISPCStaticLibrary)
+add_ispc_test_macro(ISPC.TryCompile ISPCTryCompile)

+ 15 - 0
Tests/ISPC/Defines/CMakeLists.txt

@@ -0,0 +1,15 @@
+cmake_minimum_required(VERSION 3.18)
+project(ISPCDefines CXX ISPC)
+
+set(CMAKE_ISPC_FLAGS -DM_PI=3.1415926535f)
+add_compile_definitions([==[STRUCT_DEFINE=struct{uniform int a]==])
+
+add_executable(ISPCDefines
+  main.cxx
+  simple.ispc
+  )
+
+set_target_properties(ISPCDefines PROPERTIES POSITION_INDEPENDENT_CODE ON)
+if(CMAKE_SIZEOF_VOID_P EQUAL 4)
+  set_source_files_properties(simple.ispc PROPERTIES COMPILE_OPTIONS "--arch=x86")
+endif()

+ 15 - 0
Tests/ISPC/Defines/main.cxx

@@ -0,0 +1,15 @@
+#include <stdio.h>
+
+#include "simple.ispc.h"
+
+int main()
+{
+  float vin[16], vout[16];
+  for (int i = 0; i < 16; ++i)
+    vin[i] = i;
+
+  ispc::simple(vin, vout, 16);
+
+  for (int i = 0; i < 16; ++i)
+    printf("%d: simple(%f) = %f\n", i, vin[i], vout[i]);
+}

+ 15 - 0
Tests/ISPC/Defines/simple.ispc

@@ -0,0 +1,15 @@
+
+//textual error if STRUCT_DEFINE not set
+STRUCT_DEFINE;};
+
+export void simple(uniform float vin[], uniform float vout[],
+                   uniform int count) {
+    foreach (index = 0 ... count) {
+        float v = vin[index];
+        if (v < M_PI)
+            v = v * v;
+        else
+            v = sqrt(v);
+        vout[index] = v;
+    }
+}

+ 17 - 0
Tests/ISPC/ObjectLibrary/CMakeLists.txt

@@ -0,0 +1,17 @@
+
+cmake_minimum_required(VERSION 3.18)
+project(ISPCObjectLibrary CXX ISPC)
+
+set(CMAKE_NINJA_FORCE_RESPONSE_FILE ON)
+if(CMAKE_SIZEOF_VOID_P EQUAL 4)
+  set(CMAKE_ISPC_FLAGS "--arch=x86")
+endif()
+
+add_library(ispc_objects OBJECT simple.ispc extra.ispc)
+
+target_compile_options(ispc_objects PRIVATE "$<$<COMPILE_LANGUAGE:ISPC>:--target=sse2-i32x4>")
+
+set_target_properties(ispc_objects PROPERTIES POSITION_INDEPENDENT_CODE ON)
+
+add_executable(ISPCObjectLibrary main.cxx extra.cxx)
+target_link_libraries(ISPCObjectLibrary PRIVATE ispc_objects)

+ 17 - 0
Tests/ISPC/ObjectLibrary/extra.cxx

@@ -0,0 +1,17 @@
+#include <stdio.h>
+
+#include "extra.ispc.h"
+
+int extra()
+{
+  float vin[16], vout[16];
+  for (int i = 0; i < 16; ++i)
+    vin[i] = i;
+
+  ispc::extra(vin, vout, 16);
+
+  for (int i = 0; i < 16; ++i)
+    printf("%d: extra(%f) = %f\n", i, vin[i], vout[i]);
+
+  return 0;
+}

+ 12 - 0
Tests/ISPC/ObjectLibrary/extra.ispc

@@ -0,0 +1,12 @@
+
+export void extra(uniform float vin[], uniform float vout[],
+                   uniform int count) {
+    foreach (index = 0 ... count) {
+        float v = vin[index];
+        if (v < 3.)
+            v = v * v;
+        else
+            v = sqrt(v);
+        vout[index] = v;
+    }
+}

+ 15 - 0
Tests/ISPC/ObjectLibrary/main.cxx

@@ -0,0 +1,15 @@
+#include <stdio.h>
+
+#include "simple.ispc.h"
+
+int main()
+{
+  float vin[16], vout[16];
+  for (int i = 0; i < 16; ++i)
+    vin[i] = i;
+
+  ispc::simple(vin, vout, 16);
+
+  for (int i = 0; i < 16; ++i)
+    printf("%d: simple(%f) = %f\n", i, vin[i], vout[i]);
+}

+ 12 - 0
Tests/ISPC/ObjectLibrary/simple.ispc

@@ -0,0 +1,12 @@
+
+export void simple(uniform float vin[], uniform float vout[],
+                   uniform int count) {
+    foreach (index = 0 ... count) {
+        float v = vin[index];
+        if (v < 3.)
+            v = v * v;
+        else
+            v = sqrt(v);
+        vout[index] = v;
+    }
+}

+ 28 - 0
Tests/ISPC/ResponseAndDefine/CMakeLists.txt

@@ -0,0 +1,28 @@
+cmake_minimum_required(VERSION 3.18)
+project(ispc_spaces_in_path ISPC CXX)
+
+set(CMAKE_NINJA_FORCE_RESPONSE_FILE ON)
+
+# Make sure we can handle an arg file with tricky defines including spaces in -I include
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/path with spaces/simple_include.h"
+"
+  typedef float FLOAT_TYPE;
+"
+)
+
+add_executable(ISPCResponseAndDefine main.cxx simple.ispc)
+set_target_properties(ISPCResponseAndDefine PROPERTIES POSITION_INDEPENDENT_CODE ON)
+target_include_directories(ISPCResponseAndDefine PRIVATE  "${CMAKE_CURRENT_BINARY_DIR}")
+
+target_compile_options(ISPCResponseAndDefine PRIVATE "$<$<COMPILE_LANGUAGE:ISPC>:--target=sse2-i32x4>")
+if(CMAKE_SIZEOF_VOID_P EQUAL 4)
+  target_compile_options(ISPCResponseAndDefine PRIVATE "$<$<COMPILE_LANGUAGE:ISPC>:--arch=x86>")
+endif()
+
+
+
+target_compile_definitions(ISPCResponseAndDefine PRIVATE
+  "$<$<COMPILE_LANGUAGE:ISPC>:STRUCT_DEFINE=struct{uniform int a>;M_PI=3.14159f")
+target_include_directories(ISPCResponseAndDefine PRIVATE
+  "$<$<COMPILE_LANGUAGE:ISPC>:${CMAKE_CURRENT_BINARY_DIR}/fake path with spaces>"
+  "$<$<COMPILE_LANGUAGE:ISPC>:${CMAKE_CURRENT_BINARY_DIR}/path with spaces>")

+ 15 - 0
Tests/ISPC/ResponseAndDefine/main.cxx

@@ -0,0 +1,15 @@
+#include <stdio.h>
+
+#include "simple.ispc.h"
+
+int main()
+{
+  float vin[16], vout[16];
+  for (int i = 0; i < 16; ++i)
+    vin[i] = i;
+
+  ispc::simple(vin, vout, 16);
+
+  for (int i = 0; i < 16; ++i)
+    printf("%d: simple(%f) = %f\n", i, vin[i], vout[i]);
+}

+ 16 - 0
Tests/ISPC/ResponseAndDefine/simple.ispc

@@ -0,0 +1,16 @@
+
+STRUCT_DEFINE;};
+
+#include "simple_include.h"
+
+export void simple(uniform FLOAT_TYPE vin[], uniform FLOAT_TYPE vout[],
+                   uniform int count) {
+    foreach (index = 0 ... count) {
+        FLOAT_TYPE v = vin[index];
+        if (v < M_PI)
+            v = v * v;
+        else
+            v = sqrt(v);
+        vout[index] = v;
+    }
+}

+ 15 - 0
Tests/ISPC/StaticLibrary/CMakeLists.txt

@@ -0,0 +1,15 @@
+
+cmake_minimum_required(VERSION 3.18)
+project(ISPCStaticLibrary CXX ISPC)
+
+add_library(ispc_objects STATIC simple.ispc)
+
+target_compile_options(ispc_objects PRIVATE "$<$<COMPILE_LANGUAGE:ISPC>:--target=sse2-i32x4>")
+if(CMAKE_SIZEOF_VOID_P EQUAL 4)
+  target_compile_options(ispc_objects PRIVATE "$<$<COMPILE_LANGUAGE:ISPC>:--arch=x86>")
+endif()
+
+set_target_properties(ispc_objects PROPERTIES POSITION_INDEPENDENT_CODE ON)
+
+add_executable(ISPCStaticLibrary main.cxx)
+target_link_libraries(ISPCStaticLibrary PRIVATE ispc_objects)

+ 15 - 0
Tests/ISPC/StaticLibrary/main.cxx

@@ -0,0 +1,15 @@
+#include <stdio.h>
+
+#include "simple.ispc.h"
+
+int main()
+{
+  float vin[16], vout[16];
+  for (int i = 0; i < 16; ++i)
+    vin[i] = i;
+
+  ispc::simple(vin, vout, 16);
+
+  for (int i = 0; i < 16; ++i)
+    printf("%d: simple(%f) = %f\n", i, vin[i], vout[i]);
+}

+ 12 - 0
Tests/ISPC/StaticLibrary/simple.ispc

@@ -0,0 +1,12 @@
+
+export void simple(uniform float vin[], uniform float vout[],
+                   uniform int count) {
+    foreach (index = 0 ... count) {
+        float v = vin[index];
+        if (v < 3.)
+            v = v * v;
+        else
+            v = sqrt(v);
+        vout[index] = v;
+    }
+}

+ 16 - 0
Tests/ISPC/TryCompile/CMakeLists.txt

@@ -0,0 +1,16 @@
+
+cmake_minimum_required(VERSION 3.18)
+project(ISPCTryCompile ISPC CXX)
+
+set(CMAKE_NINJA_FORCE_RESPONSE_FILE ON)
+if(CMAKE_SIZEOF_VOID_P EQUAL 4)
+  set(CMAKE_ISPC_FLAGS "--arch=x86")
+endif()
+
+#Verify we can use try_compile with ISPC
+try_compile(result "${CMAKE_CURRENT_BINARY_DIR}"
+        SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/simple.ispc"
+        COPY_FILE "${CMAKE_CURRENT_BINARY_DIR}/result.o")
+
+add_executable(ISPCTryCompile main.cxx )
+target_link_libraries(ISPCTryCompile "${CMAKE_CURRENT_BINARY_DIR}/result.o")

+ 19 - 0
Tests/ISPC/TryCompile/main.cxx

@@ -0,0 +1,19 @@
+#include <stdio.h>
+
+namespace ispc {
+extern "C" {
+void simple(float*, float*, int);
+}
+}
+
+int main()
+{
+  float vin[16], vout[16];
+  for (int i = 0; i < 16; ++i)
+    vin[i] = i;
+
+  ispc::simple(vin, vout, 16);
+
+  for (int i = 0; i < 16; ++i)
+    printf("%d: simple(%f) = %f\n", i, vin[i], vout[i]);
+}

+ 12 - 0
Tests/ISPC/TryCompile/simple.ispc

@@ -0,0 +1,12 @@
+
+export void simple(uniform float vin[], uniform float vout[],
+                   uniform int count) {
+    foreach (index = 0 ... count) {
+        float v = vin[index];
+        if (v < 3.)
+            v = v * v;
+        else
+            v = sqrt(v);
+        vout[index] = v;
+    }
+}