summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/cpu-target.md9
-rw-r--r--source/core/slang-gcc-compiler-util.cpp21
-rw-r--r--source/slang/slang-compiler.cpp42
-rw-r--r--tests/cpp-compiler/c-compile-pass-through-shared-library.c24
-rw-r--r--tools/slang-test/slang-test-main.cpp240
-rw-r--r--tools/slang-test/test-context.cpp7
-rw-r--r--tools/slang-test/test-context.h1
7 files changed, 207 insertions, 137 deletions
diff --git a/docs/cpu-target.md b/docs/cpu-target.md
index f86b7d6c5..a0b4f0180 100644
--- a/docs/cpu-target.md
+++ b/docs/cpu-target.md
@@ -15,10 +15,9 @@ Slang has preliminary support for producing CPU source and binaries.
These limitations apply to Slang source, with C/C++ the limitations are whatever the compiler requires
-* Only supports 64 bit targets (specifically it assumes all pointers are 64 bit)
* Barriers are not supported (making these work would require an ABI change)
* Atomics are not supported
-* Complex resource types (such as say Texture2d) are work in progress
+* Complex resource types (such as Texture2d) are work in progress
* Out of bounds access to resources has undefined behavior
* ParameterBlocks are not currently supported
@@ -37,7 +36,9 @@ SLANG_PASS_THROUGH_GENERIC_C_CPP, ///< Generic C or C++ compiler, whic
Sometimes it is not important which C/C++ compiler is used, and this can be specified via the 'Generic C/C++' option. This will aim to use the compiler that is most likely binary compatible with the compiler that was used to build the slang binary being used.
-To make it possible for slang to produce CPU code, we now need a mechanism to convert slang code into C/C++. The first iteration only supports C++ generation. If source is desired instead of a binary this can be specified via the SlangCompileTarget. These can be specified on the slangc command line as `-target c` or `-target cpp`
+To make it possible for slang to produce CPU code, we now need a mechanism to convert slang code into C/C++. The first iteration only supports C++ generation. If source is desired instead of a binary this can be specified via the SlangCompileTarget. These can be specified on the slangc command line as `-target c` or `-target cpp`.
+
+Note that when using the 'pass through' mode for a CPU based target it is currently necessary to set an entry point, even though it's basically ignored.
In the API the `SlangCompileTarget`s are
@@ -65,7 +66,7 @@ Under the covers when slang is used to generate a binary via a C/C++ compiler, i
Executing CPU Code
==================
-In typically slang operation when code is compiled it produces either source or a binary that can then be loaded by another API such as a rendering API. With CPU code the binary produced could be saved to a file and then executed as an exe or a shared library/dll. In practice though it is not uncommon to want to be able to execute compiled code immediately. Having to save off to a file and then load again can be awkward. It is also not necessarily the case that code needs to be saved to a file to be executed.
+In typical slang operation when code is compiled it produces either source or a binary that can then be loaded by another API such as a rendering API. With CPU code the binary produced could be saved to a file and then executed as an exe or a shared library/dll. In practice though it is not uncommon to want to be able to execute compiled code immediately. Having to save off to a file and then load again can be awkward. It is also not necessarily the case that code needs to be saved to a file to be executed.
To handle being able call code directly, code can be compiled using the SLANG_HOST_CALLABLE code target type. To access the code that has been produced use the function
diff --git a/source/core/slang-gcc-compiler-util.cpp b/source/core/slang-gcc-compiler-util.cpp
index c48e779d1..b7cc85cb3 100644
--- a/source/core/slang-gcc-compiler-util.cpp
+++ b/source/core/slang-gcc-compiler-util.cpp
@@ -184,6 +184,16 @@ static SlangResult _parseGCCFamilyLine(const UnownedStringSlice& line, LineParse
outLineParseResult = LineParseResult::Start;
return SLANG_OK;
}
+
+ if (SLANG_SUCCEEDED(_parseErrorType(split0, outMsg.type)))
+ {
+ // Command line errors can be just contain 'error:' etc. Can be seen on apple/clang
+ outMsg.stage = OutputMessage::Stage::Compile;
+ outMsg.text = split[1].trim();
+ outLineParseResult = LineParseResult::Single;
+ return SLANG_OK;
+ }
+
outLineParseResult = LineParseResult::Ignore;
return SLANG_OK;
}
@@ -193,8 +203,9 @@ static SlangResult _parseGCCFamilyLine(const UnownedStringSlice& line, LineParse
const auto split1 = split[1].trim();
const auto text = split[2].trim();
- // Check for special handling for clang
- if (split0.startsWith(UnownedStringSlice::fromLiteral("clang")))
+ // Check for special handling for clang (Can be Clang or clang apparently)
+ if (split0.startsWith(UnownedStringSlice::fromLiteral("clang")) ||
+ split0.startsWith(UnownedStringSlice::fromLiteral("Clang")) )
{
// Extract the type
SLANG_RETURN_ON_FAIL(_parseErrorType(split[1].trim(), outMsg.type));
@@ -387,11 +398,11 @@ static SlangResult _parseGCCFamilyLine(const UnownedStringSlice& line, LineParse
/* static */SlangResult GCCCompilerUtil::calcArgs(const CompileOptions& options, CommandLine& cmdLine)
{
PlatformKind platformKind = (options.platform == PlatformKind::Unknown) ? PlatformUtil::getPlatformKind() : options.platform;
-
- cmdLine.addArg("-fvisibility=hidden");
-
+
if (options.sourceType == SourceType::CPP)
{
+ cmdLine.addArg("-fvisibility=hidden");
+
// Need C++14 for partial specialization
cmdLine.addArg("-std=c++14");
}
diff --git a/source/slang/slang-compiler.cpp b/source/slang/slang-compiler.cpp
index 8ead63784..5b8643b02 100644
--- a/source/slang/slang-compiler.cpp
+++ b/source/slang/slang-compiler.cpp
@@ -768,7 +768,7 @@ namespace Slang
return result;
}
- void reportExternalCompileError(const char* compilerName, SlangResult res, const UnownedStringSlice& diagnostic, DiagnosticSink* sink)
+ void reportExternalCompileError(const char* compilerName, Severity severity, SlangResult res, const UnownedStringSlice& diagnostic, DiagnosticSink* sink)
{
StringBuilder builder;
if (compilerName)
@@ -792,10 +792,15 @@ namespace Slang
PlatformUtil::appendResult(res, builder);
}
+ sink->diagnoseRaw(severity, builder.getUnownedSlice());
+ }
+
+ void reportExternalCompileError(const char* compilerName, SlangResult res, const UnownedStringSlice& diagnostic, DiagnosticSink* sink)
+ {
// TODO(tfoley): need a better policy for how we translate diagnostics
// back into the Slang world (although we should always try to generate
// HLSL that doesn't produce any diagnostics...)
- sink->diagnoseRaw(SLANG_FAILED(res) ? Severity::Error : Severity::Warning, builder.getUnownedSlice());
+ reportExternalCompileError(compilerName, SLANG_FAILED(res) ? Severity::Error : Severity::Warning, res, diagnostic, sink);
}
static String _getDisplayPath(DiagnosticSink* sink, SourceFile* sourceFile)
@@ -1341,10 +1346,16 @@ SlangResult dissassembleDXILUsingDXC(
CPPCompiler::CompileOptions options;
+ // Set the source type
+ options.sourceType = (rawSourceLanguage == SourceLanguage::C) ? CPPCompiler::SourceType::C : CPPCompiler::SourceType::CPP;
+
// Generate a path a temporary filename for output module
String modulePath;
SLANG_RETURN_ON_FAIL(File::generateTemporary(UnownedStringSlice::fromLiteral("slang-generated"), modulePath));
+ // Remove the temporary path/file when done
+ temporaryFileSet.add(modulePath);
+
options.modulePath = modulePath;
options.sourceFiles.add(compileSourcePath);
@@ -1483,17 +1494,36 @@ SlangResult dissassembleDXILUsingDXC(
builder << "link ";
}
+ //
+ Severity severity = Severity::Error;
+
switch (msg.type)
{
- case OutputMessage::Type::Error: builder << "error"; break;
- case OutputMessage::Type::Unknown: builder << "warning"; break;
- case OutputMessage::Type::Info: builder << "info"; break;
+ case OutputMessage::Type::Unknown:
+ case OutputMessage::Type::Error:
+ {
+ severity = Severity::Error;
+ builder << "error";
+ break;
+ }
+ case OutputMessage::Type::Warning:
+ {
+ severity = Severity::Warning;
+ builder << "warning";
+ break;
+ }
+ case OutputMessage::Type::Info:
+ {
+ severity = Severity::Note;
+ builder << "info";
+ break;
+ }
default: break;
}
builder << " " << msg.code << ": " << msg.text;
- reportExternalCompileError(compilerText.getBuffer(), SLANG_OK, builder.getUnownedSlice(), sink);
+ reportExternalCompileError(compilerText.getBuffer(), severity, SLANG_OK, builder.getUnownedSlice(), sink);
}
}
diff --git a/tests/cpp-compiler/c-compile-pass-through-shared-library.c b/tests/cpp-compiler/c-compile-pass-through-shared-library.c
new file mode 100644
index 000000000..9f33bc430
--- /dev/null
+++ b/tests/cpp-compiler/c-compile-pass-through-shared-library.c
@@ -0,0 +1,24 @@
+//TEST(smoke,shared-library):CPP_COMPILER_COMPILE: -pass-through c -entry test -target callable
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#if defined(_MSC_VER)
+# define DLL_EXPORT __declspec(dllexport)
+#else
+# define DLL_EXPORT __attribute__((__visibility__("default")))
+#endif
+
+#ifdef __cplusplus
+#define EXTERN_C extern "C"
+#else
+#define EXTERN_C
+#endif
+
+EXTERN_C DLL_EXPORT int test(int intValue, const char* textValue, char* outTextValue)
+{
+ strcpy(outTextValue, textValue);
+ return intValue;
+}
+
diff --git a/tools/slang-test/slang-test-main.cpp b/tools/slang-test/slang-test-main.cpp
index 8137733ee..99a139e3c 100644
--- a/tools/slang-test/slang-test-main.cpp
+++ b/tools/slang-test/slang-test-main.cpp
@@ -1326,11 +1326,18 @@ static String _calcSummary(const CPPCompiler::Output& inOutput)
return builder;
}
-static TestResult runCPPCompilerCompile(TestContext* context, TestInput& input)
+static String _calcModulePath(const TestInput& input)
{
- CPPCompilerSet* compilerSet = context->getCPPCompilerSet();
- CPPCompiler* compiler = compilerSet ? compilerSet->getDefaultCompiler() : nullptr;
+ // Make the module name the same as the source file
+ auto filePath = input.filePath;
+ String directory = Path::getParentDirectory(input.outputStem);
+ String moduleName = Path::getFileNameWithoutExt(filePath);
+ return Path::combine(directory, moduleName);
+}
+static TestResult runCPPCompilerCompile(TestContext* context, TestInput& input)
+{
+ CPPCompiler* compiler = context->getDefaultCPPCompiler();
if (!compiler)
{
return TestResult::Ignored;
@@ -1344,7 +1351,6 @@ static TestResult runCPPCompilerCompile(TestContext* context, TestInput& input)
_initSlangCompiler(context, cmdLine);
cmdLine.addArg(input.filePath);
-
for (auto arg : input.testOptions->args)
{
cmdLine.addArg(arg);
@@ -1352,29 +1358,26 @@ static TestResult runCPPCompilerCompile(TestContext* context, TestInput& input)
ExecuteResult exeRes;
TEST_RETURN_ON_DONE(spawnAndWait(context, outputStem, input.spawnType, cmdLine, exeRes));
-
if (context->isCollectingRequirements())
{
return TestResult::Pass;
}
+ // Dump out what happened
+ {
+ String actualOutputPath = outputStem + ".actual";
+ Slang::File::writeAllText(actualOutputPath, getOutput(exeRes));
+ }
+
if (exeRes.resultCode != 0)
{
return TestResult::Fail;
}
- String actualOutput = exeRes.standardOutput;
+ String modulePath = _calcModulePath(input);
- // Make the module name the same as the source file
- auto filePath = input.filePath;
- String directory = Path::getParentDirectory(input.outputStem);
- String moduleName = Path::getFileNameWithoutExt(filePath);
- String ext = Path::getFileExt(filePath);
- String modulePath = Path::combine(directory, moduleName);
-
- UnownedStringSlice targetExt = UnownedStringSlice::fromLiteral("c");
-
// Find the target
+ UnownedStringSlice targetExt = UnownedStringSlice::fromLiteral("c");
Index index = cmdLine.findArgIndex(UnownedStringSlice::fromLiteral("-target"));
if (index >= 0 && index + 1 < cmdLine.getArgCount())
{
@@ -1389,6 +1392,8 @@ static TestResult runCPPCompilerCompile(TestContext* context, TestInput& input)
options.includePaths.add("tests/cross-compile");
+ String actualOutput = exeRes.standardOutput;
+
// Create a filename to write this out to
String cppSource = modulePath + "." + targetExt;
Slang::File::writeAllText(cppSource, actualOutput);
@@ -1420,11 +1425,9 @@ static TestResult runCPPCompilerCompile(TestContext* context, TestInput& input)
return TestResult::Pass;
}
-static TestResult runCPPCompilerExecute(TestContext* context, TestInput& input)
+static TestResult runCPPCompilerSharedLibrary(TestContext* context, TestInput& input)
{
- CPPCompilerSet* compilerSet = context->getCPPCompilerSet();
- CPPCompiler* compiler = compilerSet ? compilerSet->getDefaultCompiler() : nullptr;
-
+ CPPCompiler* compiler = context->getDefaultCPPCompiler();
if (!compiler)
{
return TestResult::Ignored;
@@ -1436,101 +1439,110 @@ static TestResult runCPPCompilerExecute(TestContext* context, TestInput& input)
return TestResult::Pass;
}
- auto filePath = input.filePath;
auto outputStem = input.outputStem;
+ auto filePath = input.filePath;
String actualOutputPath = outputStem + ".actual";
File::remove(actualOutputPath);
// Make the module name the same as the source file
- String directory = Path::getParentDirectory(input.outputStem);
- String moduleName = Path::getFileNameWithoutExt(filePath);
+ String modulePath = _calcModulePath(input);
String ext = Path::getFileExt(filePath);
- String modulePath = Path::combine(directory, moduleName);
// Remove the binary..
- {
- StringBuilder moduleExePath;
- moduleExePath << modulePath;
- moduleExePath << ProcessUtil::getExecutableSuffix();
- File::remove(moduleExePath);
- }
+ String sharedLibraryPath = SharedLibrary::calcPlatformPath(modulePath.getUnownedSlice());
+ File::remove(sharedLibraryPath);
// Set up the compilation options
CPPCompiler::CompileOptions options;
options.sourceType = (ext == "c") ? CPPCompiler::SourceType::C : CPPCompiler::SourceType::CPP;
+ // Build a shared library
+ options.targetType = CPPCompiler::TargetType::SharedLibrary;
+
// Compile this source
options.sourceFiles.add(filePath);
options.modulePath = modulePath;
+ options.includePaths.add(".");
+
CPPCompiler::Output output;
if (SLANG_FAILED(compiler->compile(options, output)))
{
return TestResult::Fail;
}
- String actualOutput;
-
- // If the actual compilation failed, then the output will be
if (SLANG_FAILED(output.result))
{
- actualOutput = _calcSummary(output);
- }
- else
- {
- // Execute the binary and see what we get
-
- CommandLine cmdLine;
+ // Compilation failed
+ String actualOutput = _calcSummary(output);
- StringBuilder exePath;
- exePath << modulePath << ProcessUtil::getExecutableSuffix();
+ // Write the output
+ Slang::File::writeAllText(actualOutputPath, actualOutput);
- cmdLine.setExecutablePath(exePath);
+ // Check that they are the same
+ {
+ // Read the expected
+ String expectedOutput;
+ try
+ {
+ String expectedOutputPath = outputStem + ".expected";
+ expectedOutput = Slang::File::readAllText(expectedOutputPath);
+ }
+ catch (Slang::IOException)
+ {
+ }
- ExecuteResult exeRes;
- if (SLANG_FAILED(ProcessUtil::execute(cmdLine, exeRes)))
+ // Compare if they are the same
+ if (!StringUtil::areLinesEqual(actualOutput.getUnownedSlice(), expectedOutput.getUnownedSlice()))
+ {
+ context->reporter->dumpOutputDifference(expectedOutput, actualOutput);
+ return TestResult::Fail;
+ }
+ }
+ }
+ else
+ {
+ SharedLibrary::Handle handle;
+ if (SLANG_FAILED(SharedLibrary::loadWithPlatformPath(sharedLibraryPath.getBuffer(), handle)))
{
return TestResult::Fail;
}
- // Write the output, and compare to expected
- actualOutput = getOutput(exeRes);
- }
+ const int inValue = 10;
+ const char inBuffer[] = "Hello World!";
- // Write the output
- Slang::File::writeAllText(actualOutputPath, actualOutput);
+ char buffer[128] = "";
+ int value = 0;
- // Check that they are the same
- {
- // Read the expected
- String expectedOutput;
- try
+ typedef int(*TestFunc)(int intValue, const char* textValue, char* outTextValue);
+
+ // We could capture output if we passed in a ISlangWriter - but for that to work we'd need a
+ TestFunc testFunc = (TestFunc)SharedLibrary::findFuncByName(handle, "test");
+ if (testFunc)
{
- String expectedOutputPath = outputStem + ".expected";
- expectedOutput = Slang::File::readAllText(expectedOutputPath);
+ value = testFunc(inValue, inBuffer, buffer);
}
- catch (Slang::IOException)
+ else
{
+ printf("Unable to access 'test' function\n");
}
- // Compare if they are the same
- if (!StringUtil::areLinesEqual(actualOutput.getUnownedSlice(), expectedOutput.getUnownedSlice()))
+ SharedLibrary::unload(handle);
+
+ if (!(inValue == value && strcmp(inBuffer, buffer) == 0))
{
- context->reporter->dumpOutputDifference(expectedOutput, actualOutput);
return TestResult::Fail;
}
}
-
+
return TestResult::Pass;
}
-static TestResult runCPPCompilerSharedLibrary(TestContext* context, TestInput& input)
+static TestResult runCPPCompilerExecute(TestContext* context, TestInput& input)
{
- CPPCompilerSet* compilerSet = context->getCPPCompilerSet();
- CPPCompiler* compiler = compilerSet ? compilerSet->getDefaultCompiler() : nullptr;
-
+ CPPCompiler* compiler = context->getDefaultCPPCompiler();
if (!compiler)
{
return TestResult::Ignored;
@@ -1549,100 +1561,84 @@ static TestResult runCPPCompilerSharedLibrary(TestContext* context, TestInput& i
File::remove(actualOutputPath);
// Make the module name the same as the source file
- String directory = Path::getParentDirectory(input.outputStem);
- String moduleName = Path::getFileNameWithoutExt(filePath);
String ext = Path::getFileExt(filePath);
-
- String modulePath = Path::combine(directory, moduleName);
-
- // Remove the binary..
- String sharedLibraryPath = SharedLibrary::calcPlatformPath(modulePath.getUnownedSlice());
- File::remove(sharedLibraryPath);
+ String modulePath = _calcModulePath(input);
+ // Remove the binary..
+ {
+ StringBuilder moduleExePath;
+ moduleExePath << modulePath;
+ moduleExePath << ProcessUtil::getExecutableSuffix();
+ File::remove(moduleExePath);
+ }
+
// Set up the compilation options
CPPCompiler::CompileOptions options;
options.sourceType = (ext == "c") ? CPPCompiler::SourceType::C : CPPCompiler::SourceType::CPP;
-
- // Build a shared library
- options.targetType = CPPCompiler::TargetType::SharedLibrary;
// Compile this source
options.sourceFiles.add(filePath);
options.modulePath = modulePath;
- options.includePaths.add(".");
-
CPPCompiler::Output output;
if (SLANG_FAILED(compiler->compile(options, output)))
{
return TestResult::Fail;
}
+ String actualOutput;
+
+ // If the actual compilation failed, then the output will be
if (SLANG_FAILED(output.result))
{
- // Compilation failed
- String actualOutput = _calcSummary(output);
-
- // Write the output
- Slang::File::writeAllText(actualOutputPath, actualOutput);
-
- // Check that they are the same
- {
- // Read the expected
- String expectedOutput;
- try
- {
- String expectedOutputPath = outputStem + ".expected";
- expectedOutput = Slang::File::readAllText(expectedOutputPath);
- }
- catch (Slang::IOException)
- {
- }
-
- // Compare if they are the same
- if (!StringUtil::areLinesEqual(actualOutput.getUnownedSlice(), expectedOutput.getUnownedSlice()))
- {
- context->reporter->dumpOutputDifference(expectedOutput, actualOutput);
- return TestResult::Fail;
- }
- }
+ actualOutput = _calcSummary(output);
}
else
{
- SharedLibrary::Handle handle;
- if (SLANG_FAILED(SharedLibrary::loadWithPlatformPath(sharedLibraryPath.getBuffer(), handle)))
+ // Execute the binary and see what we get
+
+ CommandLine cmdLine;
+
+ StringBuilder exePath;
+ exePath << modulePath << ProcessUtil::getExecutableSuffix();
+
+ cmdLine.setExecutablePath(exePath);
+
+ ExecuteResult exeRes;
+ if (SLANG_FAILED(ProcessUtil::execute(cmdLine, exeRes)))
{
return TestResult::Fail;
}
- const int inValue = 10;
- const char inBuffer[] = "Hello World!";
-
- char buffer[128] = "";
- int value = 0;
+ // Write the output, and compare to expected
+ actualOutput = getOutput(exeRes);
+ }
- typedef int (*TestFunc)(int intValue, const char* textValue, char* outTextValue);
+ // Write the output
+ Slang::File::writeAllText(actualOutputPath, actualOutput);
- // We could capture output if we passed in a ISlangWriter - but for that to work we'd need a
- TestFunc testFunc = (TestFunc)SharedLibrary::findFuncByName(handle, "test");
- if (testFunc)
+ // Check that they are the same
+ {
+ // Read the expected
+ String expectedOutput;
+ try
{
- value = testFunc(inValue, inBuffer, buffer);
+ String expectedOutputPath = outputStem + ".expected";
+ expectedOutput = Slang::File::readAllText(expectedOutputPath);
}
- else
+ catch (Slang::IOException)
{
- printf("Unable to access 'test' function\n");
}
- SharedLibrary::unload(handle);
-
- if (!(inValue == value && strcmp(inBuffer, buffer) == 0))
+ // Compare if they are the same
+ if (!StringUtil::areLinesEqual(actualOutput.getUnownedSlice(), expectedOutput.getUnownedSlice()))
{
+ context->reporter->dumpOutputDifference(expectedOutput, actualOutput);
return TestResult::Fail;
}
}
-
+
return TestResult::Pass;
}
diff --git a/tools/slang-test/test-context.cpp b/tools/slang-test/test-context.cpp
index 5581ab6db..5da998f03 100644
--- a/tools/slang-test/test-context.cpp
+++ b/tools/slang-test/test-context.cpp
@@ -102,3 +102,10 @@ CPPCompilerSet* TestContext::getCPPCompilerSet()
}
return cppCompilerSet;
}
+
+Slang::CPPCompiler* TestContext::getDefaultCPPCompiler()
+{
+ CPPCompilerSet* set = getCPPCompilerSet();
+ return set ? set->getDefaultCompiler() : nullptr;
+}
+
diff --git a/tools/slang-test/test-context.h b/tools/slang-test/test-context.h
index a66047687..66486e7bc 100644
--- a/tools/slang-test/test-context.h
+++ b/tools/slang-test/test-context.h
@@ -93,6 +93,7 @@ class TestContext
/// Get compiler factory
Slang::CPPCompilerSet* getCPPCompilerSet();
+ Slang::CPPCompiler* getDefaultCPPCompiler();
/// Ctor
TestContext();