ISPC: Support generation for multiple instruction sets

This commit is contained in:
Robert Maynard
2020-07-28 14:52:36 -04:00
parent 5a1750017e
commit a020787a9b
48 changed files with 595 additions and 8 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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.

View File

@@ -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.

View File

@@ -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);

View File

@@ -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);

View File

@@ -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;

View File

@@ -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());
}
}
};

View File

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

View File

@@ -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

View File

@@ -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();
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -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");

View File

@@ -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)

View File

@@ -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)

View File

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

View File

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

View File

@@ -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]);
}

View File

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

View File

@@ -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]==])

View File

@@ -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)

View File

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

View File

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

View File

@@ -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]);
}

View File

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

View File

@@ -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)

View File

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

View File

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

View File

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

View File

@@ -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}

View File

@@ -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()

View File

@@ -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)

View File

@@ -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)

View File

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

View File

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

View File

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

View File

@@ -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}")

View File

@@ -0,0 +1 @@
1

View File

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

View File

@@ -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()

View File

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

View File

@@ -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}")

View File

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

View File

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

View File

@@ -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}")

View File

@@ -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()

View File

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