diff options
author | Robert Maynard <robert.maynard@kitware.com> | 2020-07-28 14:52:36 -0400 |
---|---|---|
committer | Robert Maynard <robert.maynard@kitware.com> | 2020-09-04 08:37:07 -0400 |
commit | a020787a9b7ede3aa490345bd446e469fb1713d2 (patch) | |
tree | f96ef2b1d84515fda4288ffaf39e9abfb8c9cc1a | |
parent | 5a1750017e65727660167ae1953746a3fd3d2c7b (diff) | |
download | cmake-a020787a9b7ede3aa490345bd446e469fb1713d2.tar.gz |
ISPC: Support generation for multiple instruction sets
48 files changed, 595 insertions, 8 deletions
diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst index 8efaf8d6c8..73130b626c 100644 --- a/Help/manual/cmake-properties.7.rst +++ b/Help/manual/cmake-properties.7.rst @@ -259,6 +259,7 @@ Properties on Targets /prop_tgt/INTERPROCEDURAL_OPTIMIZATION /prop_tgt/IOS_INSTALL_COMBINED /prop_tgt/ISPC_HEADER_DIRECTORY + /prop_tgt/ISPC_INSTRUCTION_SETS /prop_tgt/JOB_POOL_COMPILE /prop_tgt/JOB_POOL_LINK /prop_tgt/JOB_POOL_PRECOMPILE_HEADER diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst index c0762578a1..f7760184c8 100644 --- a/Help/manual/cmake-variables.7.rst +++ b/Help/manual/cmake-variables.7.rst @@ -512,6 +512,7 @@ Variables for Languages /variable/CMAKE_Fortran_MODDIR_FLAG /variable/CMAKE_Fortran_MODOUT_FLAG /variable/CMAKE_ISPC_HEADER_DIRECTORY + /variable/CMAKE_ISPC_INSTRUCTION_SETS /variable/CMAKE_LANG_ANDROID_TOOLCHAIN_MACHINE /variable/CMAKE_LANG_ANDROID_TOOLCHAIN_PREFIX /variable/CMAKE_LANG_ANDROID_TOOLCHAIN_SUFFIX diff --git a/Help/prop_tgt/ISPC_INSTRUCTION_SETS.rst b/Help/prop_tgt/ISPC_INSTRUCTION_SETS.rst new file mode 100644 index 0000000000..cad116f8f7 --- /dev/null +++ b/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. diff --git a/Help/variable/CMAKE_ISPC_INSTRUCTION_SETS.rst b/Help/variable/CMAKE_ISPC_INSTRUCTION_SETS.rst new file mode 100644 index 0000000000..8a6005e35e --- /dev/null +++ b/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. diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx index 6af34291c5..77a6d4bf01 100644 --- a/Source/cmCoreTryCompile.cxx +++ b/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_RUNTIME_LIBRARY = "CMAKE_CUDA_RUNTIME_LIBRARY"; 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 = "CMAKE_LINK_SEARCH_END_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_RUNTIME_LIBRARY); vars.insert(kCMAKE_ENABLE_EXPORTS); + vars.insert(kCMAKE_ISPC_INSTRUCTION_SETS); vars.insert(kCMAKE_LINK_SEARCH_END_STATIC); vars.insert(kCMAKE_LINK_SEARCH_START_STATIC); vars.insert(kCMAKE_OSX_ARCHITECTURES); diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 05c8cc8fff..a298682949 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/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 { std::string const& compiler = @@ -5071,6 +5092,11 @@ void cmGeneratorTarget::GetTargetObjectNames( assert(!map_it->second.empty()); 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()( @@ -6042,6 +6068,35 @@ std::vector<std::string> cmGeneratorTarget::GetGeneratedISPCHeaders( 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 { assert(this->GetType() != cmStateEnums::INTERFACE_LIBRARY); diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index 246eedead8..95da16969a 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -449,6 +449,8 @@ public: void AddCUDAArchitectureFlags(std::string& flags) const; void AddCUDAToolkitFlags(std::string& flags) const; + void AddISPCTargetFlags(std::string& flags) const; + std::string GetFeatureSpecificLinkRuleVariable( std::string const& var, std::string const& lang, std::string const& config) const; @@ -821,6 +823,11 @@ public: std::vector<std::string> GetGeneratedISPCHeaders( 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: void AddSourceCommon(const std::string& src, bool before = false); @@ -1001,6 +1008,8 @@ private: std::unordered_map<std::string, std::vector<std::string>> ISPCGeneratedHeaders; + std::unordered_map<std::string, std::vector<std::string>> + ISPCGeneratedObjects; bool IsLinkLookupScope(std::string const& n, cmLocalGenerator const*& lg) const; diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index e3a51ddee4..006925d143 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -1165,6 +1165,12 @@ void cmGlobalNinjaGenerator::AppendTargetDepends( gg->MapToNinjaPath()); 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()); + } } }; diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index f76770ab79..0ec0757a48 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -1966,6 +1966,8 @@ void cmLocalGenerator::AddLanguageFlags(std::string& flags, "See CMake issue #20726."); } } + } else if (lang == "ISPC") { + target->AddISPCTargetFlags(flags); } // Add VFS Overlay for Clang compiliers if (compiler == "Clang") { @@ -2428,7 +2430,17 @@ void cmLocalGenerator::AppendFlagEscape(std::string& flags, 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 = this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); for (std::string const& config : configsList) { @@ -2442,7 +2454,8 @@ void cmLocalGenerator::AddISPCDependencies(cmGeneratorTarget* target) std::vector<cmSourceFile*> sources; 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) { // Generate this object file's rule file. const std::string& lang = sf->GetLanguage(); @@ -2453,6 +2466,11 @@ void cmLocalGenerator::AddISPCDependencies(cmGeneratorTarget* target) auto headerPath = cmStrCat(perConfigDir, '/', ispcSource, ".h"); 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); } } + +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; +} } diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h index cf2bce1afb..0f03440afe 100644 --- a/Source/cmLocalGenerator.h +++ b/Source/cmLocalGenerator.h @@ -595,6 +595,11 @@ void AddUtilityCommand(cmLocalGenerator& lg, const cmListFileBacktrace& lfbt, bool escapeOldStyle, const char* comment, bool uses_terminal, bool command_expand_lists, 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); } #endif diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index ee9742963b..ebfddb934b 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/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? bool clean = cmIsOff(this->Makefile->GetProperty("CLEAN_NO_CUSTOM")); @@ -205,8 +216,6 @@ void cmMakefileTargetGenerator::WriteTargetBuildRules() std::vector<cmSourceFile const*> customCommands; this->GeneratorTarget->GetCustomCommands(customCommands, this->GetConfigName()); - std::string currentBinDir = - this->LocalGenerator->GetCurrentBinaryDirectory(); for (cmSourceFile const* sf : customCommands) { cmCustomCommandGenerator ccg(*sf->GetCustomCommand(), this->GetConfigName(), this->LocalGenerator); @@ -1494,6 +1503,11 @@ void cmMakefileTargetGenerator::WriteObjectsStrings( for (std::string const& obj : this->ExternalObjects) { helper.Feed(obj); } + auto ispcAdditionalObjs = + this->GeneratorTarget->GetGeneratedISPCObjects(this->GetConfigName()); + for (std::string const& obj : ispcAdditionalObjs) { + helper.Feed(obj); + } helper.Done(); } diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx index 59f5e25eb9..210b36e1d4 100644 --- a/Source/cmNinjaNormalTargetGenerator.cxx +++ b/Source/cmNinjaNormalTargetGenerator.cxx @@ -911,11 +911,16 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement( linkBuild.ExplicitDeps.push_back( this->ConvertToNinjaPath(this->GetSourceFilePath(source))); } - linkBuild.Outputs.push_back(vars["SWIFT_MODULE"]); } else { 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 = this->ComputeLinkDeps(this->TargetLinkLanguage(config), config); diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index b19b620c7f..accdcf1680 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -1398,6 +1398,19 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( // Make sure ninja knows how to clean the generated header 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"] = this->GetLocalGenerator()->ConvertToOutputFormat( ispcHeader, cmOutputConverter::SHELL); diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 63df96a770..b3e498f517 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -369,6 +369,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, initProp("JOB_POOL_PRECOMPILE_HEADER"); initProp("ISPC_COMPILER_LAUNCHER"); initProp("ISPC_HEADER_DIRECTORY"); + initProp("ISPC_INSTRUCTION_SETS"); initProp("LINK_SEARCH_START_STATIC"); initProp("LINK_SEARCH_END_STATIC"); initProp("Swift_LANGUAGE_VERSION"); diff --git a/Tests/ISPC/CMakeLists.txt b/Tests/ISPC/CMakeLists.txt index ca5a79b0cb..c13271a81f 100644 --- a/Tests/ISPC/CMakeLists.txt +++ b/Tests/ISPC/CMakeLists.txt @@ -6,7 +6,10 @@ macro (add_ispc_test_macro name) PROPERTY LABELS "ISPC") endmacro () +add_ispc_test_macro(ISPC.ChainedStaticLibraries ISPCChainedStaticLibraries) 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.ResponseAndDefine ISPCResponseAndDefine) add_ispc_test_macro(ISPC.StaticLibrary ISPCStaticLibrary) diff --git a/Tests/ISPC/ChainedStaticLibraries/CMakeLists.txt b/Tests/ISPC/ChainedStaticLibraries/CMakeLists.txt new file mode 100644 index 0000000000..bf0b57e87f --- /dev/null +++ b/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) diff --git a/Tests/ISPC/ChainedStaticLibraries/extra.cxx b/Tests/ISPC/ChainedStaticLibraries/extra.cxx new file mode 100644 index 0000000000..88ef3a7957 --- /dev/null +++ b/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; +} diff --git a/Tests/ISPC/ChainedStaticLibraries/extra.ispc b/Tests/ISPC/ChainedStaticLibraries/extra.ispc new file mode 100644 index 0000000000..5a4a442499 --- /dev/null +++ b/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; + } +} diff --git a/Tests/ISPC/ChainedStaticLibraries/main.cxx b/Tests/ISPC/ChainedStaticLibraries/main.cxx new file mode 100644 index 0000000000..4f1c9be3d3 --- /dev/null +++ b/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]); +} diff --git a/Tests/ISPC/ChainedStaticLibraries/simple.ispc b/Tests/ISPC/ChainedStaticLibraries/simple.ispc new file mode 100644 index 0000000000..70cb58885f --- /dev/null +++ b/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; + } +} diff --git a/Tests/ISPC/Defines/CMakeLists.txt b/Tests/ISPC/Defines/CMakeLists.txt index 5155106ea7..764580458e 100644 --- a/Tests/ISPC/Defines/CMakeLists.txt +++ b/Tests/ISPC/Defines/CMakeLists.txt @@ -1,6 +1,7 @@ cmake_minimum_required(VERSION 3.18) 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) add_compile_definitions([==[STRUCT_DEFINE=struct{uniform int a]==]) diff --git a/Tests/ISPC/DynamicLibrary/CMakeLists.txt b/Tests/ISPC/DynamicLibrary/CMakeLists.txt new file mode 100644 index 0000000000..59f875ec6c --- /dev/null +++ b/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) diff --git a/Tests/ISPC/DynamicLibrary/extra.cxx b/Tests/ISPC/DynamicLibrary/extra.cxx new file mode 100644 index 0000000000..88ef3a7957 --- /dev/null +++ b/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; +} diff --git a/Tests/ISPC/DynamicLibrary/extra.ispc b/Tests/ISPC/DynamicLibrary/extra.ispc new file mode 100644 index 0000000000..5a4a442499 --- /dev/null +++ b/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; + } +} diff --git a/Tests/ISPC/DynamicLibrary/main.cxx b/Tests/ISPC/DynamicLibrary/main.cxx new file mode 100644 index 0000000000..4f1c9be3d3 --- /dev/null +++ b/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]); +} diff --git a/Tests/ISPC/DynamicLibrary/simple.ispc b/Tests/ISPC/DynamicLibrary/simple.ispc new file mode 100644 index 0000000000..70cb58885f --- /dev/null +++ b/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; + } +} diff --git a/Tests/ISPC/ObjectGenex/CMakeLists.txt b/Tests/ISPC/ObjectGenex/CMakeLists.txt new file mode 100644 index 0000000000..bc0cbf6fca --- /dev/null +++ b/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) diff --git a/Tests/ISPC/ObjectGenex/main.cxx b/Tests/ISPC/ObjectGenex/main.cxx new file mode 100644 index 0000000000..143e74e13a --- /dev/null +++ b/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; +} diff --git a/Tests/ISPC/ObjectGenex/simple.ispc b/Tests/ISPC/ObjectGenex/simple.ispc new file mode 100644 index 0000000000..a76b76cfee --- /dev/null +++ b/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; + } +} diff --git a/Tests/ISPC/ObjectLibrary/CMakeLists.txt b/Tests/ISPC/ObjectLibrary/CMakeLists.txt index 333ad66cfc..4767d7e65f 100644 --- a/Tests/ISPC/ObjectLibrary/CMakeLists.txt +++ b/Tests/ISPC/ObjectLibrary/CMakeLists.txt @@ -7,11 +7,12 @@ 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>") +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 ISPC_INSTRUCTION_SETS "sse2-i32x4;sse4-i8x16") + add_executable(ISPCObjectLibrary main.cxx extra.cxx) target_link_libraries(ISPCObjectLibrary PRIVATE ispc_objects) diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index 35a6ab5c24..906fa8cbf9 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -386,6 +386,7 @@ function(add_RunCMake_test_try_compile) CMAKE_CXX_COMPILER_VERSION CMAKE_CXX_STANDARD_DEFAULT CMake_TEST_CUDA + CMake_TEST_ISPC CMake_TEST_FILESYSTEM_1S CMAKE_OBJC_STANDARD_DEFAULT CMAKE_OBJCXX_STANDARD_DEFAULT @@ -396,7 +397,7 @@ function(add_RunCMake_test_try_compile) endforeach() add_RunCMake_test(try_compile) set_property(TEST RunCMake.try_compile APPEND - PROPERTY LABELS "CUDA") + PROPERTY LABELS "CUDA;ISPC") endfunction() add_RunCMake_test_try_compile() @@ -551,7 +552,10 @@ add_RunCMake_test(install -DNO_NAMELINK=${NO_NAMELINK} -DCYGWIN=${CYGWIN} -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME} -DCMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG=${CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG} -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 -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID} diff --git a/Tests/RunCMake/install/FILES-EXTRA_ISPC_TARGET_OBJECTS-all-check.cmake b/Tests/RunCMake/install/FILES-EXTRA_ISPC_TARGET_OBJECTS-all-check.cmake new file mode 100644 index 0000000000..8750a76850 --- /dev/null +++ b/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() diff --git a/Tests/RunCMake/install/FILES-EXTRA_ISPC_TARGET_OBJECTS.cmake b/Tests/RunCMake/install/FILES-EXTRA_ISPC_TARGET_OBJECTS.cmake new file mode 100644 index 0000000000..ad542ed828 --- /dev/null +++ b/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) diff --git a/Tests/RunCMake/install/RunCMakeTest.cmake b/Tests/RunCMake/install/RunCMakeTest.cmake index d83a07cdbe..3573fbd6e9 100644 --- a/Tests/RunCMake/install/RunCMakeTest.cmake +++ b/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) endif() +if(CMake_TEST_ISPC) + run_install_test(FILES-EXTRA_ISPC_TARGET_OBJECTS) +endif() + + run_install_test(TARGETS-InstallFromSubDir) run_install_test(TARGETS-OPTIONAL) run_install_test(FILES-OPTIONAL) diff --git a/Tests/RunCMake/install/obj1.ispc b/Tests/RunCMake/install/obj1.ispc new file mode 100644 index 0000000000..0dc983c3fb --- /dev/null +++ b/Tests/RunCMake/install/obj1.ispc @@ -0,0 +1,4 @@ + +float func1(float a, float b) { + return a + b / 2.; +} diff --git a/Tests/RunCMake/install/obj2.ispc b/Tests/RunCMake/install/obj2.ispc new file mode 100644 index 0000000000..7b2aeb97ff --- /dev/null +++ b/Tests/RunCMake/install/obj2.ispc @@ -0,0 +1,4 @@ + +float func2(float a, float b) { + return a + b / 2.; +} diff --git a/Tests/RunCMake/try_compile/ISPCDuplicateTarget-stderr.txt b/Tests/RunCMake/try_compile/ISPCDuplicateTarget-stderr.txt new file mode 100644 index 0000000000..7dcb1de785 --- /dev/null +++ b/Tests/RunCMake/try_compile/ISPCDuplicateTarget-stderr.txt @@ -0,0 +1 @@ +.*Error: Can't compile to multiple variants of avx512skx target!.* diff --git a/Tests/RunCMake/try_compile/ISPCDuplicateTarget.cmake b/Tests/RunCMake/try_compile/ISPCDuplicateTarget.cmake new file mode 100644 index 0000000000..6d29069cdc --- /dev/null +++ b/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}") diff --git a/Tests/RunCMake/try_compile/ISPCDuplicateTargetNinja-result.txt b/Tests/RunCMake/try_compile/ISPCDuplicateTargetNinja-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/try_compile/ISPCDuplicateTargetNinja-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/try_compile/ISPCDuplicateTargetNinja-stderr.txt b/Tests/RunCMake/try_compile/ISPCDuplicateTargetNinja-stderr.txt new file mode 100644 index 0000000000..99248bfea6 --- /dev/null +++ b/Tests/RunCMake/try_compile/ISPCDuplicateTargetNinja-stderr.txt @@ -0,0 +1 @@ +.*ninja: error: .* multiple rules generate.*src.ispc_avx512skx.o.* diff --git a/Tests/RunCMake/try_compile/ISPCDuplicateTargetNinja.cmake b/Tests/RunCMake/try_compile/ISPCDuplicateTargetNinja.cmake new file mode 100644 index 0000000000..7f59c1451b --- /dev/null +++ b/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() diff --git a/Tests/RunCMake/try_compile/ISPCInvalidTarget-stderr.txt b/Tests/RunCMake/try_compile/ISPCInvalidTarget-stderr.txt new file mode 100644 index 0000000000..44543addd5 --- /dev/null +++ b/Tests/RunCMake/try_compile/ISPCInvalidTarget-stderr.txt @@ -0,0 +1 @@ +.*Error: Incorrect targets: avxknl-i32x16.* diff --git a/Tests/RunCMake/try_compile/ISPCInvalidTarget.cmake b/Tests/RunCMake/try_compile/ISPCInvalidTarget.cmake new file mode 100644 index 0000000000..c1ab6f24ec --- /dev/null +++ b/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}") diff --git a/Tests/RunCMake/try_compile/ISPCTargets-stderr.txt b/Tests/RunCMake/try_compile/ISPCTargets-stderr.txt new file mode 100644 index 0000000000..72e0a018a4 --- /dev/null +++ b/Tests/RunCMake/try_compile/ISPCTargets-stderr.txt @@ -0,0 +1 @@ +.*Linking ISPC static library* diff --git a/Tests/RunCMake/try_compile/ISPCTargets-stdout.txt b/Tests/RunCMake/try_compile/ISPCTargets-stdout.txt new file mode 100644 index 0000000000..a731d52b8c --- /dev/null +++ b/Tests/RunCMake/try_compile/ISPCTargets-stdout.txt @@ -0,0 +1 @@ +.*Detecting ISPC compiler ABI info - done.* diff --git a/Tests/RunCMake/try_compile/ISPCTargets.cmake b/Tests/RunCMake/try_compile/ISPCTargets.cmake new file mode 100644 index 0000000000..0d3bd4369c --- /dev/null +++ b/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}") diff --git a/Tests/RunCMake/try_compile/RunCMakeTest.cmake b/Tests/RunCMake/try_compile/RunCMakeTest.cmake index 82c55ccb6c..5b849bf8a9 100644 --- a/Tests/RunCMake/try_compile/RunCMakeTest.cmake +++ b/Tests/RunCMake/try_compile/RunCMakeTest.cmake @@ -51,6 +51,15 @@ endif() if(CMake_TEST_CUDA) run_cmake(CudaStandard) 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) run_cmake(CStandardGNU) endif() diff --git a/Tests/RunCMake/try_compile/src.ispc b/Tests/RunCMake/try_compile/src.ispc new file mode 100644 index 0000000000..b061f40a5f --- /dev/null +++ b/Tests/RunCMake/try_compile/src.ispc @@ -0,0 +1,4 @@ + +float func(float a, float b) { + return a + b / 2.; +} |