浏览代码

Merge topic 'ispc_improvements'

a020787a9b ISPC: Support generation for multiple instruction sets
5a1750017e ISPC: Add compiler launcher support

Acked-by: Kitware Robot <[email protected]>
Merge-request: !5173
Brad King 5 年之前
父节点
当前提交
d0ccc7cf2a
共有 62 个文件被更改,包括 633 次插入13 次删除
  1. 1 0
      Help/manual/cmake-properties.7.rst
  2. 1 0
      Help/manual/cmake-variables.7.rst
  3. 21 0
      Help/prop_tgt/ISPC_INSTRUCTION_SETS.rst
  4. 1 1
      Help/prop_tgt/LANG_COMPILER_LAUNCHER.rst
  5. 9 0
      Help/variable/CMAKE_ISPC_INSTRUCTION_SETS.rst
  6. 1 1
      Help/variable/CMAKE_LANG_COMPILER_LAUNCHER.rst
  7. 5 0
      Modules/CMakeISPCInformation.cmake
  8. 2 0
      Source/cmCoreTryCompile.cxx
  9. 55 0
      Source/cmGeneratorTarget.cxx
  10. 9 0
      Source/cmGeneratorTarget.h
  11. 6 0
      Source/cmGlobalNinjaGenerator.cxx
  12. 60 2
      Source/cmLocalGenerator.cxx
  13. 5 0
      Source/cmLocalGenerator.h
  14. 17 3
      Source/cmMakefileTargetGenerator.cxx
  15. 6 1
      Source/cmNinjaNormalTargetGenerator.cxx
  16. 14 1
      Source/cmNinjaTargetGenerator.cxx
  17. 2 0
      Source/cmTarget.cxx
  18. 3 0
      Tests/ISPC/CMakeLists.txt
  19. 22 0
      Tests/ISPC/ChainedStaticLibraries/CMakeLists.txt
  20. 17 0
      Tests/ISPC/ChainedStaticLibraries/extra.cxx
  21. 12 0
      Tests/ISPC/ChainedStaticLibraries/extra.ispc
  22. 15 0
      Tests/ISPC/ChainedStaticLibraries/main.cxx
  23. 12 0
      Tests/ISPC/ChainedStaticLibraries/simple.ispc
  24. 1 0
      Tests/ISPC/Defines/CMakeLists.txt
  25. 20 0
      Tests/ISPC/DynamicLibrary/CMakeLists.txt
  26. 17 0
      Tests/ISPC/DynamicLibrary/extra.cxx
  27. 12 0
      Tests/ISPC/DynamicLibrary/extra.ispc
  28. 15 0
      Tests/ISPC/DynamicLibrary/main.cxx
  29. 12 0
      Tests/ISPC/DynamicLibrary/simple.ispc
  30. 45 0
      Tests/ISPC/ObjectGenex/CMakeLists.txt
  31. 87 0
      Tests/ISPC/ObjectGenex/main.cxx
  32. 12 0
      Tests/ISPC/ObjectGenex/simple.ispc
  33. 3 2
      Tests/ISPC/ObjectLibrary/CMakeLists.txt
  34. 9 2
      Tests/RunCMake/CMakeLists.txt
  35. 1 0
      Tests/RunCMake/CompilerLauncher/ISPC-Build-stdout.txt
  36. 4 0
      Tests/RunCMake/CompilerLauncher/ISPC-common.cmake
  37. 1 0
      Tests/RunCMake/CompilerLauncher/ISPC-env-Build-stdout.txt
  38. 1 0
      Tests/RunCMake/CompilerLauncher/ISPC-env-launch-Build-stdout.txt
  39. 1 0
      Tests/RunCMake/CompilerLauncher/ISPC-env.cmake
  40. 1 0
      Tests/RunCMake/CompilerLauncher/ISPC-launch-Build-stdout.txt
  41. 3 0
      Tests/RunCMake/CompilerLauncher/ISPC-launch-env.cmake
  42. 3 0
      Tests/RunCMake/CompilerLauncher/ISPC-launch.cmake
  43. 2 0
      Tests/RunCMake/CompilerLauncher/ISPC.cmake
  44. 3 0
      Tests/RunCMake/CompilerLauncher/RunCMakeTest.cmake
  45. 4 0
      Tests/RunCMake/CompilerLauncher/test.ispc
  46. 11 0
      Tests/RunCMake/install/FILES-EXTRA_ISPC_TARGET_OBJECTS-all-check.cmake
  47. 4 0
      Tests/RunCMake/install/FILES-EXTRA_ISPC_TARGET_OBJECTS.cmake
  48. 5 0
      Tests/RunCMake/install/RunCMakeTest.cmake
  49. 4 0
      Tests/RunCMake/install/obj1.ispc
  50. 4 0
      Tests/RunCMake/install/obj2.ispc
  51. 1 0
      Tests/RunCMake/try_compile/ISPCDuplicateTarget-stderr.txt
  52. 8 0
      Tests/RunCMake/try_compile/ISPCDuplicateTarget.cmake
  53. 1 0
      Tests/RunCMake/try_compile/ISPCDuplicateTargetNinja-result.txt
  54. 1 0
      Tests/RunCMake/try_compile/ISPCDuplicateTargetNinja-stderr.txt
  55. 11 0
      Tests/RunCMake/try_compile/ISPCDuplicateTargetNinja.cmake
  56. 1 0
      Tests/RunCMake/try_compile/ISPCInvalidTarget-stderr.txt
  57. 7 0
      Tests/RunCMake/try_compile/ISPCInvalidTarget.cmake
  58. 1 0
      Tests/RunCMake/try_compile/ISPCTargets-stderr.txt
  59. 1 0
      Tests/RunCMake/try_compile/ISPCTargets-stdout.txt
  60. 7 0
      Tests/RunCMake/try_compile/ISPCTargets.cmake
  61. 9 0
      Tests/RunCMake/try_compile/RunCMakeTest.cmake
  62. 4 0
      Tests/RunCMake/try_compile/src.ispc

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

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

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

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

+ 21 - 0
Help/prop_tgt/ISPC_INSTRUCTION_SETS.rst

@@ -0,0 +1,21 @@
+ISPC_INSTRUCTION_SETS
+---------------------
+
+.. versionadded:: 3.19
+
+List of instruction set architectures to generate code for.
+
+This property is initialized by the value of the :variable:`CMAKE_ISPC_INSTRUCTION_SETS`
+variable if it is set when a target is created.
+
+The ``ISPC_INSTRUCTION_SETS`` target property must be used when generating for multiple
+instruction sets so that CMake can track what object files will be generated.
+
+Examples
+^^^^^^^^
+
+.. code-block:: cmake
+
+  set_property(TARGET tgt PROPERTY ISPC_INSTRUCTION_SETS avx2-i32x4 avx512skx-i32x835)
+
+Generates code for avx2 and avx512skx target architectures.

+ 1 - 1
Help/prop_tgt/LANG_COMPILER_LAUNCHER.rst

@@ -4,7 +4,7 @@
 .. versionadded:: 3.4
 .. versionadded:: 3.4
 
 
 This property is implemented only when ``<LANG>`` is ``C``, ``CXX``,
 This property is implemented only when ``<LANG>`` is ``C``, ``CXX``,
-``Fortran``, ``OBJC``, ``OBJCXX``, or ``CUDA``.
+``Fortran``, ``ISPC``, ``OBJC``, ``OBJCXX``, or ``CUDA``.
 
 
 Specify a :ref:`semicolon-separated list <CMake Language Lists>` containing a command line
 Specify a :ref:`semicolon-separated list <CMake Language Lists>` containing a command line
 for a compiler launching tool. The :ref:`Makefile Generators` and the
 for a compiler launching tool. The :ref:`Makefile Generators` and the

+ 9 - 0
Help/variable/CMAKE_ISPC_INSTRUCTION_SETS.rst

@@ -0,0 +1,9 @@
+CMAKE_ISPC_INSTRUCTION_SETS
+---------------------------
+
+.. versionadded:: 3.19
+
+Default value for :prop_tgt:`ISPC_INSTRUCTION_SETS` property of targets.
+
+This variable is used to initialize the :prop_tgt:`ISPC_INSTRUCTION_SETS` property
+on all targets. See the target property for additional information.

+ 1 - 1
Help/variable/CMAKE_LANG_COMPILER_LAUNCHER.rst

@@ -6,7 +6,7 @@ CMAKE_<LANG>_COMPILER_LAUNCHER
 Default value for :prop_tgt:`<LANG>_COMPILER_LAUNCHER` target property.
 Default value for :prop_tgt:`<LANG>_COMPILER_LAUNCHER` target property.
 This variable is used to initialize the property on each target as it is
 This variable is used to initialize the property on each target as it is
 created.  This is done only when ``<LANG>`` is ``C``, ``CXX``, ``Fortran``,
 created.  This is done only when ``<LANG>`` is ``C``, ``CXX``, ``Fortran``,
-``OBJC``, ``OBJCXX``, or ``CUDA``.
+``ISPC``, ``OBJC``, ``OBJCXX``, or ``CUDA``.
 
 
 This variable is initialized to the :envvar:`CMAKE_<LANG>_COMPILER_LAUNCHER`
 This variable is initialized to the :envvar:`CMAKE_<LANG>_COMPILER_LAUNCHER`
 environment variable if it is set.
 environment variable if it is set.

+ 5 - 0
Modules/CMakeISPCInformation.cmake

@@ -32,6 +32,11 @@ if(CMAKE_ISPC_STANDARD_LIBRARIES_INIT)
   mark_as_advanced(CMAKE_ISPC_STANDARD_LIBRARIES)
   mark_as_advanced(CMAKE_ISPC_STANDARD_LIBRARIES)
 endif()
 endif()
 
 
+if(NOT CMAKE_ISPC_COMPILER_LAUNCHER AND DEFINED ENV{CMAKE_ISPC_COMPILER_LAUNCHER})
+  set(CMAKE_ISPC_COMPILER_LAUNCHER "$ENV{CMAKE_ISPC_COMPILER_LAUNCHER}"
+    CACHE STRING "Compiler launcher for ISPC.")
+endif()
+
 include(CMakeCommonLanguageInclude)
 include(CMakeCommonLanguageInclude)
 
 
 # now define the following rules:
 # now define the following rules:

+ 2 - 0
Source/cmCoreTryCompile.cxx

@@ -200,6 +200,7 @@ SETUP_LANGUAGE(swift_properties, Swift);
 std::string const kCMAKE_CUDA_ARCHITECTURES = "CMAKE_CUDA_ARCHITECTURES";
 std::string const kCMAKE_CUDA_ARCHITECTURES = "CMAKE_CUDA_ARCHITECTURES";
 std::string const kCMAKE_CUDA_RUNTIME_LIBRARY = "CMAKE_CUDA_RUNTIME_LIBRARY";
 std::string const kCMAKE_CUDA_RUNTIME_LIBRARY = "CMAKE_CUDA_RUNTIME_LIBRARY";
 std::string const kCMAKE_ENABLE_EXPORTS = "CMAKE_ENABLE_EXPORTS";
 std::string const kCMAKE_ENABLE_EXPORTS = "CMAKE_ENABLE_EXPORTS";
+std::string const kCMAKE_ISPC_INSTRUCTION_SETS = "CMAKE_ISPC_INSTRUCTION_SETS";
 std::string const kCMAKE_LINK_SEARCH_END_STATIC =
 std::string const kCMAKE_LINK_SEARCH_END_STATIC =
   "CMAKE_LINK_SEARCH_END_STATIC";
   "CMAKE_LINK_SEARCH_END_STATIC";
 std::string const kCMAKE_LINK_SEARCH_START_STATIC =
 std::string const kCMAKE_LINK_SEARCH_START_STATIC =
@@ -716,6 +717,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
       vars.insert(kCMAKE_CUDA_ARCHITECTURES);
       vars.insert(kCMAKE_CUDA_ARCHITECTURES);
       vars.insert(kCMAKE_CUDA_RUNTIME_LIBRARY);
       vars.insert(kCMAKE_CUDA_RUNTIME_LIBRARY);
       vars.insert(kCMAKE_ENABLE_EXPORTS);
       vars.insert(kCMAKE_ENABLE_EXPORTS);
+      vars.insert(kCMAKE_ISPC_INSTRUCTION_SETS);
       vars.insert(kCMAKE_LINK_SEARCH_END_STATIC);
       vars.insert(kCMAKE_LINK_SEARCH_END_STATIC);
       vars.insert(kCMAKE_LINK_SEARCH_START_STATIC);
       vars.insert(kCMAKE_LINK_SEARCH_START_STATIC);
       vars.insert(kCMAKE_OSX_ARCHITECTURES);
       vars.insert(kCMAKE_OSX_ARCHITECTURES);

+ 55 - 0
Source/cmGeneratorTarget.cxx

@@ -3302,6 +3302,27 @@ void cmGeneratorTarget::AddCUDAArchitectureFlags(std::string& flags) const
   }
   }
 }
 }
 
 
+void cmGeneratorTarget::AddISPCTargetFlags(std::string& flags) const
+{
+  const std::string& property = this->GetSafeProperty("ISPC_INSTRUCTION_SETS");
+
+  // If ISPC_TARGET is false we don't add any architectures.
+  if (cmIsOff(property)) {
+    return;
+  }
+
+  std::string const& compiler =
+    this->Makefile->GetSafeDefinition("CMAKE_ISPC_COMPILER_ID");
+
+  if (compiler == "Intel") {
+    std::vector<std::string> targets;
+    cmExpandList(property, targets);
+    if (!targets.empty()) {
+      flags += cmStrCat(" --target=", cmWrap("", targets, "", ","));
+    }
+  }
+}
+
 void cmGeneratorTarget::AddCUDAToolkitFlags(std::string& flags) const
 void cmGeneratorTarget::AddCUDAToolkitFlags(std::string& flags) const
 {
 {
   std::string const& compiler =
   std::string const& compiler =
@@ -5067,6 +5088,11 @@ void cmGeneratorTarget::GetTargetObjectNames(
     assert(!map_it->second.empty());
     assert(!map_it->second.empty());
     objects.push_back(map_it->second);
     objects.push_back(map_it->second);
   }
   }
+
+  auto ispcObjects = this->GetGeneratedISPCObjects(config);
+  for (std::string const& output : ispcObjects) {
+    objects.push_back(cmSystemTools::GetFilenameName(output));
+  }
 }
 }
 
 
 bool cmGeneratorTarget::StrictTargetComparison::operator()(
 bool cmGeneratorTarget::StrictTargetComparison::operator()(
@@ -6038,6 +6064,35 @@ std::vector<std::string> cmGeneratorTarget::GetGeneratedISPCHeaders(
   return iter->second;
   return iter->second;
 }
 }
 
 
+void cmGeneratorTarget::AddISPCGeneratedObject(std::vector<std::string>&& objs,
+                                               std::string const& config)
+{
+  std::string config_upper;
+  if (!config.empty()) {
+    config_upper = cmSystemTools::UpperCase(config);
+  }
+  auto iter = this->ISPCGeneratedObjects.find(config_upper);
+  if (iter == this->ISPCGeneratedObjects.end()) {
+    this->ISPCGeneratedObjects.insert({ config_upper, objs });
+  } else {
+    iter->second.insert(iter->second.end(), objs.begin(), objs.end());
+  }
+}
+
+std::vector<std::string> cmGeneratorTarget::GetGeneratedISPCObjects(
+  std::string const& config) const
+{
+  std::string config_upper;
+  if (!config.empty()) {
+    config_upper = cmSystemTools::UpperCase(config);
+  }
+  auto iter = this->ISPCGeneratedObjects.find(config_upper);
+  if (iter == this->ISPCGeneratedObjects.end()) {
+    return std::vector<std::string>{};
+  }
+  return iter->second;
+}
+
 std::string cmGeneratorTarget::GetFrameworkVersion() const
 std::string cmGeneratorTarget::GetFrameworkVersion() const
 {
 {
   assert(this->GetType() != cmStateEnums::INTERFACE_LIBRARY);
   assert(this->GetType() != cmStateEnums::INTERFACE_LIBRARY);

+ 9 - 0
Source/cmGeneratorTarget.h

@@ -448,6 +448,8 @@ public:
   void AddCUDAArchitectureFlags(std::string& flags) const;
   void AddCUDAArchitectureFlags(std::string& flags) const;
   void AddCUDAToolkitFlags(std::string& flags) const;
   void AddCUDAToolkitFlags(std::string& flags) const;
 
 
+  void AddISPCTargetFlags(std::string& flags) const;
+
   std::string GetFeatureSpecificLinkRuleVariable(
   std::string GetFeatureSpecificLinkRuleVariable(
     std::string const& var, std::string const& lang,
     std::string const& var, std::string const& lang,
     std::string const& config) const;
     std::string const& config) const;
@@ -820,6 +822,11 @@ public:
   std::vector<std::string> GetGeneratedISPCHeaders(
   std::vector<std::string> GetGeneratedISPCHeaders(
     std::string const& config) const;
     std::string const& config) const;
 
 
+  void AddISPCGeneratedObject(std::vector<std::string>&& objs,
+                              std::string const& config);
+  std::vector<std::string> GetGeneratedISPCObjects(
+    std::string const& config) const;
+
 private:
 private:
   void AddSourceCommon(const std::string& src, bool before = false);
   void AddSourceCommon(const std::string& src, bool before = false);
 
 
@@ -1000,6 +1007,8 @@ private:
 
 
   std::unordered_map<std::string, std::vector<std::string>>
   std::unordered_map<std::string, std::vector<std::string>>
     ISPCGeneratedHeaders;
     ISPCGeneratedHeaders;
+  std::unordered_map<std::string, std::vector<std::string>>
+    ISPCGeneratedObjects;
 
 
   bool IsLinkLookupScope(std::string const& n,
   bool IsLinkLookupScope(std::string const& n,
                          cmLocalGenerator const*& lg) const;
                          cmLocalGenerator const*& lg) const;

+ 6 - 0
Source/cmGlobalNinjaGenerator.cxx

@@ -1165,6 +1165,12 @@ void cmGlobalNinjaGenerator::AppendTargetDepends(
                          gg->MapToNinjaPath());
                          gg->MapToNinjaPath());
           outputDeps.insert(outputDeps.end(), headers.begin(), headers.end());
           outputDeps.insert(outputDeps.end(), headers.begin(), headers.end());
         }
         }
+        auto objs = depTarget->GetGeneratedISPCObjects(targetConfig);
+        if (!objs.empty()) {
+          std::transform(objs.begin(), objs.end(), objs.begin(),
+                         gg->MapToNinjaPath());
+          outputDeps.insert(outputDeps.end(), objs.begin(), objs.end());
+        }
       }
       }
     };
     };
 
 

+ 60 - 2
Source/cmLocalGenerator.cxx

@@ -1966,6 +1966,8 @@ void cmLocalGenerator::AddLanguageFlags(std::string& flags,
           "See CMake issue #20726.");
           "See CMake issue #20726.");
       }
       }
     }
     }
+  } else if (lang == "ISPC") {
+    target->AddISPCTargetFlags(flags);
   }
   }
   // Add VFS Overlay for Clang compiliers
   // Add VFS Overlay for Clang compiliers
   if (compiler == "Clang") {
   if (compiler == "Clang") {
@@ -2428,7 +2430,17 @@ void cmLocalGenerator::AppendFlagEscape(std::string& flags,
 
 
 void cmLocalGenerator::AddISPCDependencies(cmGeneratorTarget* target)
 void cmLocalGenerator::AddISPCDependencies(cmGeneratorTarget* target)
 {
 {
-  //
+  std::vector<std::string> enabledLanguages =
+    this->GetState()->GetEnabledLanguages();
+  if (std::find(enabledLanguages.begin(), enabledLanguages.end(), "ISPC") ==
+      enabledLanguages.end()) {
+    return;
+  }
+
+  std::vector<std::string> ispcSuffixes =
+    detail::ComputeISPCObjectSuffixes(target);
+  const bool extra_objects = (ispcSuffixes.size() > 1);
+
   std::vector<std::string> configsList =
   std::vector<std::string> configsList =
     this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
     this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
   for (std::string const& config : configsList) {
   for (std::string const& config : configsList) {
@@ -2442,7 +2454,8 @@ void cmLocalGenerator::AddISPCDependencies(cmGeneratorTarget* target)
     std::vector<cmSourceFile*> sources;
     std::vector<cmSourceFile*> sources;
     target->GetSourceFiles(sources, config);
     target->GetSourceFiles(sources, config);
 
 
-    // build up the list of ispc headers that this target is generating
+    // build up the list of ispc headers and extra objects that this target is
+    // generating
     for (cmSourceFile const* sf : sources) {
     for (cmSourceFile const* sf : sources) {
       // Generate this object file's rule file.
       // Generate this object file's rule file.
       const std::string& lang = sf->GetLanguage();
       const std::string& lang = sf->GetLanguage();
@@ -2453,6 +2466,11 @@ void cmLocalGenerator::AddISPCDependencies(cmGeneratorTarget* target)
 
 
         auto headerPath = cmStrCat(perConfigDir, '/', ispcSource, ".h");
         auto headerPath = cmStrCat(perConfigDir, '/', ispcSource, ".h");
         target->AddISPCGeneratedHeader(headerPath, config);
         target->AddISPCGeneratedHeader(headerPath, config);
+        if (extra_objects) {
+          std::vector<std::string> objs = detail::ComputeISPCExtraObjects(
+            objectName, perConfigDir, ispcSuffixes);
+          target->AddISPCGeneratedObject(std::move(objs), config);
+        }
       }
       }
     }
     }
   }
   }
@@ -4028,4 +4046,44 @@ void AddUtilityCommand(cmLocalGenerator& lg, const cmListFileBacktrace& lfbt,
     target->AddSource(force.NameCMP0049);
     target->AddSource(force.NameCMP0049);
   }
   }
 }
 }
+
+std::vector<std::string> ComputeISPCObjectSuffixes(cmGeneratorTarget* target)
+{
+  const std::string& targetProperty =
+    target->GetSafeProperty("ISPC_INSTRUCTION_SETS");
+  std::vector<std::string> ispcTargets;
+
+  if (!cmIsOff(targetProperty)) {
+    cmExpandList(targetProperty, ispcTargets);
+    for (auto& ispcTarget : ispcTargets) {
+      // transform targets into the suffixes
+      auto pos = ispcTarget.find('-');
+      auto target_suffix = ispcTarget.substr(0, pos);
+      if (target_suffix ==
+          "avx1") { // when targetting avx1 ISPC uses the 'avx' output string
+        target_suffix = "avx";
+      }
+      ispcTarget = target_suffix;
+    }
+  }
+  return ispcTargets;
+}
+
+std::vector<std::string> ComputeISPCExtraObjects(
+  std::string const& objectName, std::string const& buildDirectory,
+  std::vector<std::string> const& ispcSuffixes)
+{
+  std::vector<std::string> computedObjects;
+  computedObjects.reserve(ispcSuffixes.size());
+
+  auto extension = cmSystemTools::GetFilenameLastExtension(objectName);
+  auto objNameNoExt =
+    cmSystemTools::GetFilenameWithoutLastExtension(objectName);
+  for (const auto& ispcTarget : ispcSuffixes) {
+    computedObjects.emplace_back(
+      cmStrCat(buildDirectory, "/", objNameNoExt, "_", ispcTarget, extension));
+  }
+
+  return computedObjects;
+}
 }
 }

+ 5 - 0
Source/cmLocalGenerator.h

@@ -594,4 +594,9 @@ void AddUtilityCommand(cmLocalGenerator& lg, const cmListFileBacktrace& lfbt,
                        bool escapeOldStyle, const char* comment,
                        bool escapeOldStyle, const char* comment,
                        bool uses_terminal, bool command_expand_lists,
                        bool uses_terminal, bool command_expand_lists,
                        const std::string& job_pool, bool stdPipesUTF8);
                        const std::string& job_pool, bool stdPipesUTF8);
+
+std::vector<std::string> ComputeISPCObjectSuffixes(cmGeneratorTarget* target);
+std::vector<std::string> ComputeISPCExtraObjects(
+  std::string const& objectName, std::string const& buildDirectory,
+  std::vector<std::string> const& ispcSuffixes);
 }
 }

+ 17 - 3
Source/cmMakefileTargetGenerator.cxx

@@ -197,6 +197,17 @@ void cmMakefileTargetGenerator::WriteTargetBuildRules()
     }
     }
   }
   }
 
 
+  std::string currentBinDir =
+    this->LocalGenerator->GetCurrentBinaryDirectory();
+
+  // Look for ISPC extra object files generated by this target
+  auto ispcAdditionalObjs =
+    this->GeneratorTarget->GetGeneratedISPCObjects(this->GetConfigName());
+  for (std::string const& ispcObj : ispcAdditionalObjs) {
+    this->CleanFiles.insert(this->LocalGenerator->MaybeConvertToRelativePath(
+      currentBinDir, ispcObj));
+  }
+
   // add custom commands to the clean rules?
   // add custom commands to the clean rules?
   bool clean = cmIsOff(this->Makefile->GetProperty("CLEAN_NO_CUSTOM"));
   bool clean = cmIsOff(this->Makefile->GetProperty("CLEAN_NO_CUSTOM"));
 
 
@@ -205,8 +216,6 @@ void cmMakefileTargetGenerator::WriteTargetBuildRules()
   std::vector<cmSourceFile const*> customCommands;
   std::vector<cmSourceFile const*> customCommands;
   this->GeneratorTarget->GetCustomCommands(customCommands,
   this->GeneratorTarget->GetCustomCommands(customCommands,
                                            this->GetConfigName());
                                            this->GetConfigName());
-  std::string currentBinDir =
-    this->LocalGenerator->GetCurrentBinaryDirectory();
   for (cmSourceFile const* sf : customCommands) {
   for (cmSourceFile const* sf : customCommands) {
     cmCustomCommandGenerator ccg(*sf->GetCustomCommand(),
     cmCustomCommandGenerator ccg(*sf->GetCustomCommand(),
                                  this->GetConfigName(), this->LocalGenerator);
                                  this->GetConfigName(), this->LocalGenerator);
@@ -832,7 +841,7 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
     std::string compilerLauncher;
     std::string compilerLauncher;
     if (!compileCommands.empty() &&
     if (!compileCommands.empty() &&
         (lang == "C" || lang == "CXX" || lang == "Fortran" || lang == "CUDA" ||
         (lang == "C" || lang == "CXX" || lang == "Fortran" || lang == "CUDA" ||
-         lang == "OBJC" || lang == "OBJCXX")) {
+         lang == "ISPC" || lang == "OBJC" || lang == "OBJCXX")) {
       std::string const clauncher_prop = lang + "_COMPILER_LAUNCHER";
       std::string const clauncher_prop = lang + "_COMPILER_LAUNCHER";
       cmProp clauncher = this->GeneratorTarget->GetProperty(clauncher_prop);
       cmProp clauncher = this->GeneratorTarget->GetProperty(clauncher_prop);
       if (cmNonempty(clauncher)) {
       if (cmNonempty(clauncher)) {
@@ -1494,6 +1503,11 @@ void cmMakefileTargetGenerator::WriteObjectsStrings(
   for (std::string const& obj : this->ExternalObjects) {
   for (std::string const& obj : this->ExternalObjects) {
     helper.Feed(obj);
     helper.Feed(obj);
   }
   }
+  auto ispcAdditionalObjs =
+    this->GeneratorTarget->GetGeneratedISPCObjects(this->GetConfigName());
+  for (std::string const& obj : ispcAdditionalObjs) {
+    helper.Feed(obj);
+  }
   helper.Done();
   helper.Done();
 }
 }
 
 

+ 6 - 1
Source/cmNinjaNormalTargetGenerator.cxx

@@ -911,11 +911,16 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement(
       linkBuild.ExplicitDeps.push_back(
       linkBuild.ExplicitDeps.push_back(
         this->ConvertToNinjaPath(this->GetSourceFilePath(source)));
         this->ConvertToNinjaPath(this->GetSourceFilePath(source)));
     }
     }
-
     linkBuild.Outputs.push_back(vars["SWIFT_MODULE"]);
     linkBuild.Outputs.push_back(vars["SWIFT_MODULE"]);
   } else {
   } else {
     linkBuild.ExplicitDeps = this->GetObjects(config);
     linkBuild.ExplicitDeps = this->GetObjects(config);
   }
   }
+
+  std::vector<std::string> extraISPCObjects =
+    this->GetGeneratorTarget()->GetGeneratedISPCObjects(config);
+  std::transform(extraISPCObjects.begin(), extraISPCObjects.end(),
+                 std::back_inserter(linkBuild.ExplicitDeps), MapToNinjaPath());
+
   linkBuild.ImplicitDeps =
   linkBuild.ImplicitDeps =
     this->ComputeLinkDeps(this->TargetLinkLanguage(config), config);
     this->ComputeLinkDeps(this->TargetLinkLanguage(config), config);
 
 

+ 14 - 1
Source/cmNinjaTargetGenerator.cxx

@@ -813,7 +813,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang,
   std::string compilerLauncher;
   std::string compilerLauncher;
   if (!compileCmds.empty() &&
   if (!compileCmds.empty() &&
       (lang == "C" || lang == "CXX" || lang == "Fortran" || lang == "CUDA" ||
       (lang == "C" || lang == "CXX" || lang == "Fortran" || lang == "CUDA" ||
-       lang == "OBJC" || lang == "OBJCXX")) {
+       lang == "ISPC" || lang == "OBJC" || lang == "OBJCXX")) {
     std::string const clauncher_prop = cmStrCat(lang, "_COMPILER_LAUNCHER");
     std::string const clauncher_prop = cmStrCat(lang, "_COMPILER_LAUNCHER");
     cmProp clauncher = this->GeneratorTarget->GetProperty(clauncher_prop);
     cmProp clauncher = this->GeneratorTarget->GetProperty(clauncher_prop);
     if (cmNonempty(clauncher)) {
     if (cmNonempty(clauncher)) {
@@ -1398,6 +1398,19 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
     // Make sure ninja knows how to clean the generated header
     // Make sure ninja knows how to clean the generated header
     this->GetGlobalGenerator()->AddAdditionalCleanFile(ispcHeader, config);
     this->GetGlobalGenerator()->AddAdditionalCleanFile(ispcHeader, config);
 
 
+    auto ispcSuffixes =
+      detail::ComputeISPCObjectSuffixes(this->GeneratorTarget);
+    if (ispcSuffixes.size() > 1) {
+      auto ispcSideEfffectObjects = detail::ComputeISPCExtraObjects(
+        objectName, ispcDirectory, ispcSuffixes);
+
+      for (auto sideEffect : ispcSideEfffectObjects) {
+        sideEffect = this->ConvertToNinjaPath(sideEffect);
+        objBuild.ImplicitOuts.emplace_back(sideEffect);
+        this->GetGlobalGenerator()->AddAdditionalCleanFile(sideEffect, config);
+      }
+    }
+
     vars["ISPC_HEADER_FILE"] =
     vars["ISPC_HEADER_FILE"] =
       this->GetLocalGenerator()->ConvertToOutputFormat(
       this->GetLocalGenerator()->ConvertToOutputFormat(
         ispcHeader, cmOutputConverter::SHELL);
         ispcHeader, cmOutputConverter::SHELL);

+ 2 - 0
Source/cmTarget.cxx

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

+ 3 - 0
Tests/ISPC/CMakeLists.txt

@@ -6,7 +6,10 @@ macro (add_ispc_test_macro name)
     PROPERTY LABELS "ISPC")
     PROPERTY LABELS "ISPC")
 endmacro ()
 endmacro ()
 
 
+add_ispc_test_macro(ISPC.ChainedStaticLibraries ISPCChainedStaticLibraries)
 add_ispc_test_macro(ISPC.Defines ISPCDefines)
 add_ispc_test_macro(ISPC.Defines ISPCDefines)
+add_ispc_test_macro(ISPC.DynamicLibrary ISPCDynamicLibrary)
+add_ispc_test_macro(ISPC.ObjectGenex ISPCObjectGenex)
 add_ispc_test_macro(ISPC.ObjectLibrary ISPCObjectLibrary)
 add_ispc_test_macro(ISPC.ObjectLibrary ISPCObjectLibrary)
 add_ispc_test_macro(ISPC.ResponseAndDefine ISPCResponseAndDefine)
 add_ispc_test_macro(ISPC.ResponseAndDefine ISPCResponseAndDefine)
 add_ispc_test_macro(ISPC.StaticLibrary ISPCStaticLibrary)
 add_ispc_test_macro(ISPC.StaticLibrary ISPCStaticLibrary)

+ 22 - 0
Tests/ISPC/ChainedStaticLibraries/CMakeLists.txt

@@ -0,0 +1,22 @@
+
+cmake_minimum_required(VERSION 3.18)
+project(ISPCChainedStaticLibraries CXX ISPC)
+
+if(CMAKE_SIZEOF_VOID_P EQUAL 4)
+  set(CMAKE_ISPC_FLAGS "--arch=x86")
+endif()
+
+
+add_library(ispc_objects1 STATIC extra.ispc extra.cxx)
+add_library(ispc_objects2 STATIC simple.ispc)
+
+set_target_properties(ispc_objects1 PROPERTIES POSITION_INDEPENDENT_CODE ON)
+set_target_properties(ispc_objects1 PROPERTIES ISPC_INSTRUCTION_SETS "avx1-i32x16;avx2-i32x4")
+
+set_target_properties(ispc_objects2 PROPERTIES POSITION_INDEPENDENT_CODE ON)
+set_target_properties(ispc_objects2 PROPERTIES ISPC_INSTRUCTION_SETS "avx1-i32x16")
+
+target_link_libraries(ispc_objects2 PRIVATE ispc_objects1)
+
+add_executable(ISPCChainedStaticLibraries main.cxx)
+target_link_libraries(ISPCChainedStaticLibraries PUBLIC ispc_objects2)

+ 17 - 0
Tests/ISPC/ChainedStaticLibraries/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/ChainedStaticLibraries/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/ChainedStaticLibraries/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/ChainedStaticLibraries/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;
+    }
+}

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

@@ -1,6 +1,7 @@
 cmake_minimum_required(VERSION 3.18)
 cmake_minimum_required(VERSION 3.18)
 project(ISPCDefines CXX ISPC)
 project(ISPCDefines CXX ISPC)
 
 
+set(CMAKE_ISPC_INSTRUCTION_SETS "sse2-i32x4;sse4-i16x8;avx1-i32x16;avx2-i32x4;avx512knl-i32x16;avx512skx-i32x8")
 set(CMAKE_ISPC_FLAGS -DM_PI=3.1415926535f)
 set(CMAKE_ISPC_FLAGS -DM_PI=3.1415926535f)
 add_compile_definitions([==[STRUCT_DEFINE=struct{uniform int a]==])
 add_compile_definitions([==[STRUCT_DEFINE=struct{uniform int a]==])
 
 

+ 20 - 0
Tests/ISPC/DynamicLibrary/CMakeLists.txt

@@ -0,0 +1,20 @@
+
+cmake_minimum_required(VERSION 3.18)
+project(ISPCDynamicLibrary CXX ISPC)
+
+if(CMAKE_SIZEOF_VOID_P EQUAL 4)
+  set(CMAKE_ISPC_FLAGS "--arch=x86")
+endif()
+
+
+add_library(ispc_objects1 STATIC extra.ispc extra.cxx)
+add_library(ispc_objects2 SHARED simple.ispc)
+
+set_target_properties(ispc_objects1 PROPERTIES POSITION_INDEPENDENT_CODE ON)
+set_target_properties(ispc_objects1 PROPERTIES ISPC_INSTRUCTION_SETS "avx1-i32x16;avx2-i32x4")
+set_target_properties(ispc_objects2 PROPERTIES ISPC_INSTRUCTION_SETS "avx1-i32x16")
+
+target_link_libraries(ispc_objects2 PRIVATE ispc_objects1)
+
+add_executable(ISPCDynamicLibrary main.cxx)
+target_link_libraries(ISPCDynamicLibrary PUBLIC ispc_objects2)

+ 17 - 0
Tests/ISPC/DynamicLibrary/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/DynamicLibrary/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/DynamicLibrary/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/DynamicLibrary/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;
+    }
+}

+ 45 - 0
Tests/ISPC/ObjectGenex/CMakeLists.txt

@@ -0,0 +1,45 @@
+cmake_minimum_required(VERSION 3.18)
+project(ISPCObjectGenex CXX ISPC)
+
+set(CMAKE_ISPC_INSTRUCTION_SETS "sse2-i32x4;sse4-i16x8;avx1-i32x16;avx2-i32x4;avx512knl-i32x16;avx512skx-i32x8")
+
+add_library(ispc_objects OBJECT
+  simple.ispc
+  )
+target_compile_definitions(ispc_objects PRIVATE
+  $<$<COMPILE_LANG_AND_ID:ISPC,Intel>:M_PI=3.1415926535f>
+)
+set_target_properties(ispc_objects PROPERTIES POSITION_INDEPENDENT_CODE ON)
+if(CMAKE_SIZEOF_VOID_P EQUAL 4)
+  set_source_files_properties(simple.ispc PROPERTIES COMPILE_OPTIONS "--arch=x86")
+endif()
+
+
+#Test ObjectFiles with file(GENERATE)
+file(GENERATE
+     OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/gen_$<LOWER_CASE:$<CONFIG>/>path_to_objs.h
+     CONTENT [[
+#ifndef path_to_objs
+#define path_to_objs
+
+#include <string>
+
+static std::string obj_paths = "$<TARGET_OBJECTS:ispc_objects>";
+
+#endif
+
+]]
+)
+
+
+add_executable(ISPCObjectGenex main.cxx)
+add_dependencies(ISPCObjectGenex ispc_objects)
+
+list(LENGTH CMAKE_ISPC_INSTRUCTION_SETS numberOfTargets)
+math(EXPR numberOfTargets "${numberOfTargets}+1")
+target_compile_definitions(ISPCObjectGenex PRIVATE
+    "ExpectedISPCObjects=${numberOfTargets}"
+    "CONFIG_TYPE=gen_$<LOWER_CASE:$<CONFIG>>"
+    )
+target_include_directories(ISPCObjectGenex PRIVATE ${CMAKE_CURRENT_BINARY_DIR} )
+target_compile_features(ISPCObjectGenex PRIVATE cxx_std_11)

+ 87 - 0
Tests/ISPC/ObjectGenex/main.cxx

@@ -0,0 +1,87 @@
+#include <stdio.h>
+
+/*
+  Define GENERATED_HEADER macro to allow c++ files to include headers
+  generated based on different configuration types.
+*/
+
+/* clang-format off */
+#define GENERATED_HEADER(x) GENERATED_HEADER0(CONFIG_TYPE/x)
+/* clang-format on */
+#define GENERATED_HEADER0(x) GENERATED_HEADER1(x)
+#define GENERATED_HEADER1(x) <x>
+
+#include GENERATED_HEADER(path_to_objs.h)
+
+#include <vector>
+std::vector<std::string> expandList(std::string const& arg)
+{
+  std::vector<std::string> output;
+  // If argument is empty or no `;` just copy the current string
+  if (arg.empty() || arg.find(';') == std::string::npos) {
+    output.emplace_back(arg);
+    return output;
+  }
+
+  std::string newArg;
+  // Break the string at non-escaped semicolons not nested in [].
+  int squareNesting = 0;
+  auto last = arg.begin();
+  auto const cend = arg.end();
+  for (auto c = last; c != cend; ++c) {
+    switch (*c) {
+      case '\\': {
+        // We only want to allow escaping of semicolons.  Other
+        // escapes should not be processed here.
+        auto cnext = c + 1;
+        if ((cnext != cend) && *cnext == ';') {
+          newArg.append(last, c);
+          // Skip over the escape character
+          last = cnext;
+          c = cnext;
+        }
+      } break;
+      case '[': {
+        ++squareNesting;
+      } break;
+      case ']': {
+        --squareNesting;
+      } break;
+      case ';': {
+        // Break the string here if we are not nested inside square
+        // brackets.
+        if (squareNesting == 0) {
+          newArg.append(last, c);
+          // Skip over the semicolon
+          last = c + 1;
+          if (!newArg.empty()) {
+            // Add the last argument if the string is not empty.
+            output.push_back(newArg);
+            newArg.clear();
+          }
+        }
+      } break;
+      default: {
+        // Just append this character.
+      } break;
+    }
+  }
+  newArg.append(last, cend);
+  if (!newArg.empty()) {
+    // Add the last argument if the string is not empty.
+    output.push_back(std::move(newArg));
+  }
+
+  return output;
+}
+
+int main()
+{
+  // determine that the number of object files specified in obj_paths
+  // is equal to the number of arch's
+
+  std::vector<std::string> paths = expandList(obj_paths);
+  const bool correctSize = (paths.size() == ExpectedISPCObjects);
+
+  return (correctSize) ? 0 : 1;
+}

+ 12 - 0
Tests/ISPC/ObjectGenex/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 < M_PI)
+            v = v * v;
+        else
+            v = sqrt(v);
+        vout[index] = v;
+    }
+}

+ 3 - 2
Tests/ISPC/ObjectLibrary/CMakeLists.txt

@@ -7,11 +7,12 @@ if(CMAKE_SIZEOF_VOID_P EQUAL 4)
   set(CMAKE_ISPC_FLAGS "--arch=x86")
   set(CMAKE_ISPC_FLAGS "--arch=x86")
 endif()
 endif()
 
 
-add_library(ispc_objects OBJECT simple.ispc extra.ispc)
 
 
-target_compile_options(ispc_objects PRIVATE "$<$<COMPILE_LANGUAGE:ISPC>:--target=sse2-i32x4>")
+add_library(ispc_objects OBJECT simple.ispc extra.ispc)
 
 
 set_target_properties(ispc_objects PROPERTIES POSITION_INDEPENDENT_CODE ON)
 set_target_properties(ispc_objects PROPERTIES POSITION_INDEPENDENT_CODE ON)
+set_target_properties(ispc_objects PROPERTIES ISPC_INSTRUCTION_SETS "sse2-i32x4;sse4-i8x16")
+
 
 
 add_executable(ISPCObjectLibrary main.cxx extra.cxx)
 add_executable(ISPCObjectLibrary main.cxx extra.cxx)
 target_link_libraries(ISPCObjectLibrary PRIVATE ispc_objects)
 target_link_libraries(ISPCObjectLibrary PRIVATE ispc_objects)

+ 9 - 2
Tests/RunCMake/CMakeLists.txt

@@ -387,6 +387,7 @@ function(add_RunCMake_test_try_compile)
       CMAKE_CXX_COMPILER_VERSION
       CMAKE_CXX_COMPILER_VERSION
       CMAKE_CXX_STANDARD_DEFAULT
       CMAKE_CXX_STANDARD_DEFAULT
       CMake_TEST_CUDA
       CMake_TEST_CUDA
+      CMake_TEST_ISPC
       CMake_TEST_FILESYSTEM_1S
       CMake_TEST_FILESYSTEM_1S
       CMAKE_OBJC_STANDARD_DEFAULT
       CMAKE_OBJC_STANDARD_DEFAULT
       CMAKE_OBJCXX_STANDARD_DEFAULT
       CMAKE_OBJCXX_STANDARD_DEFAULT
@@ -397,7 +398,7 @@ function(add_RunCMake_test_try_compile)
   endforeach()
   endforeach()
   add_RunCMake_test(try_compile)
   add_RunCMake_test(try_compile)
   set_property(TEST RunCMake.try_compile APPEND
   set_property(TEST RunCMake.try_compile APPEND
-    PROPERTY LABELS "CUDA")
+    PROPERTY LABELS "CUDA;ISPC")
 endfunction()
 endfunction()
 add_RunCMake_test_try_compile()
 add_RunCMake_test_try_compile()
 
 
@@ -552,7 +553,10 @@ add_RunCMake_test(install -DNO_NAMELINK=${NO_NAMELINK} -DCYGWIN=${CYGWIN}
   -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}
   -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}
   -DCMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG=${CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG}
   -DCMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG=${CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG}
   -DCMAKE_EXECUTABLE_FORMAT=${CMAKE_EXECUTABLE_FORMAT}
   -DCMAKE_EXECUTABLE_FORMAT=${CMAKE_EXECUTABLE_FORMAT}
+  -DCMake_TEST_ISPC=${CMake_TEST_ISPC}
   )
   )
+set_property(TEST RunCMake.install APPEND
+  PROPERTY LABELS "ISPC")
 
 
 add_RunCMake_test(file-GET_RUNTIME_DEPENDENCIES
 add_RunCMake_test(file-GET_RUNTIME_DEPENDENCIES
   -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID}
   -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID}
@@ -630,6 +634,9 @@ if("${CMAKE_GENERATOR}" MATCHES "Make|Ninja")
   if(DEFINED CMake_TEST_CUDA)
   if(DEFINED CMake_TEST_CUDA)
     list(APPEND CompilerLauncher_ARGS -DCMake_TEST_CUDA=${CMake_TEST_CUDA})
     list(APPEND CompilerLauncher_ARGS -DCMake_TEST_CUDA=${CMake_TEST_CUDA})
   endif()
   endif()
+  if(DEFINED CMake_TEST_ISPC)
+    list(APPEND CompilerLauncher_ARGS -DCMake_TEST_ISPC=${CMake_TEST_ISPC})
+  endif()
   if(CMAKE_Fortran_COMPILER)
   if(CMAKE_Fortran_COMPILER)
     list(APPEND CompilerLauncher_ARGS -DCMake_TEST_Fortran=1)
     list(APPEND CompilerLauncher_ARGS -DCMake_TEST_Fortran=1)
   endif()
   endif()
@@ -638,7 +645,7 @@ if("${CMAKE_GENERATOR}" MATCHES "Make|Ninja")
   endif()
   endif()
   add_RunCMake_test(CompilerLauncher)
   add_RunCMake_test(CompilerLauncher)
   set_property(TEST RunCMake.CompilerLauncher APPEND
   set_property(TEST RunCMake.CompilerLauncher APPEND
-    PROPERTY LABELS "CUDA")
+    PROPERTY LABELS "CUDA;ISPC")
   add_RunCMake_test(ctest_labels_for_subprojects)
   add_RunCMake_test(ctest_labels_for_subprojects)
   add_RunCMake_test(CompilerArgs)
   add_RunCMake_test(CompilerArgs)
 endif()
 endif()

+ 1 - 0
Tests/RunCMake/CompilerLauncher/ISPC-Build-stdout.txt

@@ -0,0 +1 @@
+.*-E env USED_LAUNCHER=1.*

+ 4 - 0
Tests/RunCMake/CompilerLauncher/ISPC-common.cmake

@@ -0,0 +1,4 @@
+enable_language(ISPC)
+enable_language(CXX)
+set(CMAKE_VERBOSE_MAKEFILE TRUE)
+add_executable(main main.cxx test.ispc)

+ 1 - 0
Tests/RunCMake/CompilerLauncher/ISPC-env-Build-stdout.txt

@@ -0,0 +1 @@
+.*-E env USED_LAUNCHER=1.*

+ 1 - 0
Tests/RunCMake/CompilerLauncher/ISPC-env-launch-Build-stdout.txt

@@ -0,0 +1 @@
+.*-E env USED_LAUNCHER=1.*

+ 1 - 0
Tests/RunCMake/CompilerLauncher/ISPC-env.cmake

@@ -0,0 +1 @@
+include(ISPC-common.cmake)

+ 1 - 0
Tests/RunCMake/CompilerLauncher/ISPC-launch-Build-stdout.txt

@@ -0,0 +1 @@
+.*-E env USED_LAUNCHER=1.*

+ 3 - 0
Tests/RunCMake/CompilerLauncher/ISPC-launch-env.cmake

@@ -0,0 +1,3 @@
+set(CTEST_USE_LAUNCHERS 1)
+include(CTestUseLaunchers)
+include(ISPC-env.cmake)

+ 3 - 0
Tests/RunCMake/CompilerLauncher/ISPC-launch.cmake

@@ -0,0 +1,3 @@
+set(CTEST_USE_LAUNCHERS 1)
+include(CTestUseLaunchers)
+include(ISPC.cmake)

+ 2 - 0
Tests/RunCMake/CompilerLauncher/ISPC.cmake

@@ -0,0 +1,2 @@
+set(CMAKE_ISPC_COMPILER_LAUNCHER "${CMAKE_COMMAND};-E;env;USED_LAUNCHER=1")
+include(ISPC-common.cmake)

+ 3 - 0
Tests/RunCMake/CompilerLauncher/RunCMakeTest.cmake

@@ -29,6 +29,9 @@ endif()
 if(CMake_TEST_Fortran)
 if(CMake_TEST_Fortran)
   list(APPEND langs Fortran)
   list(APPEND langs Fortran)
 endif()
 endif()
+if(CMake_TEST_ISPC)
+  list(APPEND langs ISPC)
+endif()
 if(CMake_TEST_OBJC)
 if(CMake_TEST_OBJC)
   list(APPEND langs OBJC OBJCXX)
   list(APPEND langs OBJC OBJCXX)
 endif()
 endif()

+ 4 - 0
Tests/RunCMake/CompilerLauncher/test.ispc

@@ -0,0 +1,4 @@
+
+float func(float a, float b) {
+     return a + b / 2.;
+}

+ 11 - 0
Tests/RunCMake/install/FILES-EXTRA_ISPC_TARGET_OBJECTS-all-check.cmake

@@ -0,0 +1,11 @@
+
+set(objs obj1 obj2)
+set(targets  sse2 sse4 avx avx2)
+foreach(o IN LISTS objs)
+  set(item "objs/${o}\\.ispc\\.(o|obj)")
+  check_installed("${item}")
+  foreach(t IN LISTS targets)
+    set(item "objs/${o}\\.ispc_${t}\\.(o|obj)")
+    check_installed("${item}")
+  endforeach()
+endforeach()

+ 4 - 0
Tests/RunCMake/install/FILES-EXTRA_ISPC_TARGET_OBJECTS.cmake

@@ -0,0 +1,4 @@
+enable_language(ISPC)
+add_library(objs OBJECT obj1.ispc obj2.ispc)
+set_target_properties(objs PROPERTIES ISPC_INSTRUCTION_SETS "sse2-i32x4;sse4-i16x8;avx1-i32x16;avx2-i32x4")
+install(FILES $<TARGET_OBJECTS:objs> DESTINATION objs)

+ 5 - 0
Tests/RunCMake/install/RunCMakeTest.cmake

@@ -96,6 +96,11 @@ if(NOT RunCMake_GENERATOR STREQUAL "Xcode" OR NOT "$ENV{CMAKE_OSX_ARCHITECTURES}
   run_install_test(FILES-TARGET_OBJECTS)
   run_install_test(FILES-TARGET_OBJECTS)
 endif()
 endif()
 
 
+if(CMake_TEST_ISPC)
+  run_install_test(FILES-EXTRA_ISPC_TARGET_OBJECTS)
+endif()
+
+
 run_install_test(TARGETS-InstallFromSubDir)
 run_install_test(TARGETS-InstallFromSubDir)
 run_install_test(TARGETS-OPTIONAL)
 run_install_test(TARGETS-OPTIONAL)
 run_install_test(FILES-OPTIONAL)
 run_install_test(FILES-OPTIONAL)

+ 4 - 0
Tests/RunCMake/install/obj1.ispc

@@ -0,0 +1,4 @@
+
+float func1(float a, float b) {
+     return a + b / 2.;
+}

+ 4 - 0
Tests/RunCMake/install/obj2.ispc

@@ -0,0 +1,4 @@
+
+float func2(float a, float b) {
+     return a + b / 2.;
+}

+ 1 - 0
Tests/RunCMake/try_compile/ISPCDuplicateTarget-stderr.txt

@@ -0,0 +1 @@
+.*Error: Can't compile to multiple variants of avx512skx target!.*

+ 8 - 0
Tests/RunCMake/try_compile/ISPCDuplicateTarget.cmake

@@ -0,0 +1,8 @@
+enable_language(ISPC)
+set(CMAKE_ISPC_INSTRUCTION_SETS avx512skx-i32x16
+                                avx512skx-i32x16)
+try_compile(result ${CMAKE_CURRENT_BINARY_DIR}
+  SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src.ispc
+  OUTPUT_VARIABLE out
+  )
+message("try_compile output:\n${out}")

+ 1 - 0
Tests/RunCMake/try_compile/ISPCDuplicateTargetNinja-result.txt

@@ -0,0 +1 @@
+1

+ 1 - 0
Tests/RunCMake/try_compile/ISPCDuplicateTargetNinja-stderr.txt

@@ -0,0 +1 @@
+.*ninja: error: .* multiple rules generate.*src.ispc_avx512skx.o.*

+ 11 - 0
Tests/RunCMake/try_compile/ISPCDuplicateTargetNinja.cmake

@@ -0,0 +1,11 @@
+enable_language(ISPC)
+set(CMAKE_ISPC_INSTRUCTION_SETS avx512skx-i32x16
+                                avx512skx-i32x16)
+try_compile(result ${CMAKE_CURRENT_BINARY_DIR}
+  SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src.ispc
+  OUTPUT_VARIABLE out
+  )
+message("try_compile output:\n${out}")
+if(NOT result)
+  message(FATAL_ERROR "making Ninja and Ninja Multi-Config behave the same")
+endif()

+ 1 - 0
Tests/RunCMake/try_compile/ISPCInvalidTarget-stderr.txt

@@ -0,0 +1 @@
+.*Error: Incorrect targets: avxknl-i32x16.*

+ 7 - 0
Tests/RunCMake/try_compile/ISPCInvalidTarget.cmake

@@ -0,0 +1,7 @@
+enable_language(ISPC)
+set(CMAKE_ISPC_INSTRUCTION_SETS "avxknl-i32x16")
+try_compile(result ${CMAKE_CURRENT_BINARY_DIR}
+  SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src.ispc
+  OUTPUT_VARIABLE out
+  )
+message("try_compile output:\n${out}")

+ 1 - 0
Tests/RunCMake/try_compile/ISPCTargets-stderr.txt

@@ -0,0 +1 @@
+.*Linking ISPC static library*

+ 1 - 0
Tests/RunCMake/try_compile/ISPCTargets-stdout.txt

@@ -0,0 +1 @@
+.*Detecting ISPC compiler ABI info - done.*

+ 7 - 0
Tests/RunCMake/try_compile/ISPCTargets.cmake

@@ -0,0 +1,7 @@
+enable_language(ISPC)
+set(CMAKE_ISPC_INSTRUCTION_SETS avx512knl-i32x16 avx512skx-i32x16)
+try_compile(result ${CMAKE_CURRENT_BINARY_DIR}
+  SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src.ispc
+  OUTPUT_VARIABLE out
+  )
+message("try_compile output:\n${out}")

+ 9 - 0
Tests/RunCMake/try_compile/RunCMakeTest.cmake

@@ -51,6 +51,15 @@ endif()
 if(CMake_TEST_CUDA)
 if(CMake_TEST_CUDA)
   run_cmake(CudaStandard)
   run_cmake(CudaStandard)
 endif()
 endif()
+if(CMake_TEST_ISPC)
+  run_cmake(ISPCTargets)
+  run_cmake(ISPCInvalidTarget)
+  set(ninja "")
+  if(RunCMake_GENERATOR MATCHES "Ninja")
+    set(ninja "Ninja")
+  endif()
+  run_cmake(ISPCDuplicateTarget${ninja})
+endif()
 if(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.4)
 if(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.4)
   run_cmake(CStandardGNU)
   run_cmake(CStandardGNU)
 endif()
 endif()

+ 4 - 0
Tests/RunCMake/try_compile/src.ispc

@@ -0,0 +1,4 @@
+
+float func(float a, float b) {
+     return a + b / 2.;
+}