Browse Source

Add ISPC compiler support to CMake

Robert Maynard 5 years ago
parent
commit
34cc6acc81

+ 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")

+ 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>")
+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)

+ 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
 {

+ 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);
     }

+ 2 - 1
Source/cmMakefileTargetGenerator.cxx

@@ -734,7 +734,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;
 

+ 3 - 0
Source/cmake.cxx

@@ -201,6 +201,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" });
   }
 }
 
@@ -1971,6 +1972,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

@@ -1479,6 +1479,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)

+ 14 - 0
Tests/ISPC/CMakeLists.txt

@@ -0,0 +1,14 @@
+
+
+macro (add_ispc_test_macro name)
+  add_test_macro("${name}" ${ARGN})
+  set_property(TEST "${name}" APPEND
+    PROPERTY LABELS "ISPC")
+endmacro ()
+
+# set (ISPC_IA_TARGETS "sse2-i32x4,sse4-i32x4,avx1-i32x8,avx2-i32x8,avx512knl-i32x16,avx512skx-i32x16")
+
+add_ispc_test_macro(ISPC.Defines ISPCDefines)
+add_ispc_test_macro(ISPC.ObjectLibrary ISPCObjectLibrary)
+add_ispc_test_macro(ISPC.StaticLibrary ISPCStaticLibrary)
+add_ispc_test_macro(ISPC.TryCompile ISPCTryCompile)

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

@@ -0,0 +1,11 @@
+cmake_minimum_required(VERSION 3.18)
+project(ISPCDefines CXX ISPC)
+
+set(CMAKE_ISPC_FLAGS -DM_PI=3.1415926535f [==[-DSTRUCT_DEFINE=struct{uniform int a]==])
+
+add_executable(ISPCResponseFile
+  main.cxx
+  simple.ispc
+  )
+set_target_properties(ISPCResponseFile PROPERTIES POSITION_INDEPENDENT_CODE ON)
+target_include_directories(ISPCResponseFile PRIVATE  "${CMAKE_CURRENT_BINARY_DIR}")

+ 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;
+    }
+}

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

@@ -0,0 +1,14 @@
+
+cmake_minimum_required(VERSION 3.18)
+project(ISPCObjectLibrary CXX ISPC)
+
+set(CMAKE_NINJA_FORCE_RESPONSE_FILE ON)
+
+add_library(ispc_objects OBJECT simple.ispc)
+
+target_compile_options(ispc_objects PRIVATE "$<$<COMPILE_LANGUAGE:ISPC>:--target=sse2-i32x4;--arch=x86-64>")
+target_include_directories(ispc_objects INTERFACE  "${CMAKE_CURRENT_BINARY_DIR}")
+set_target_properties(ispc_objects PROPERTIES POSITION_INDEPENDENT_CODE ON)
+
+add_executable(ISPCObjectLibrary main.cxx)
+target_link_libraries(ISPCObjectLibrary PRIVATE ispc_objects)

+ 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;
+    }
+}

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

@@ -0,0 +1,24 @@
+
+project(ispc_spaces_in_path)
+
+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(SpacesInPath main.cxx simple.ispc)
+set_target_properties(SpacesInPath PROPERTIES POSITION_INDEPENDENT_CODE ON)
+target_include_directories(SpacesInPath PRIVATE  "${CMAKE_CURRENT_BINARY_DIR}")
+
+target_compile_options(SpacesInPath PRIVATE
+  "$<$<COMPILE_LANGUAGE:ISPC>:--target=sse2-i32x4;--arch=x86-64>")
+
+target_compile_definitions(SpacesInPath PRIVATE
+  "$<$<COMPILE_LANGUAGE:ISPC>:STRUCT_DEFINE=\"struct{uniform int a;varying int b;\";M_PI=3.1415926535f>")
+target_include_directories(SpacesInPath PRIVATE
+  "$<$<COMPILE_LANGUAGE:ISPC>:\"fake path with spaces\">""
+  "$<$<COMPILE_LANGUAGE:ISPC>:\"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;
+    }
+}

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

@@ -0,0 +1,12 @@
+
+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;--arch=x86-64>")
+target_include_directories(ispc_objects INTERFACE  "${CMAKE_CURRENT_BINARY_DIR}")
+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;
+    }
+}