summaryrefslogtreecommitdiff
path: root/tools/slang-test
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2025-04-28 11:42:22 -0700
committerGitHub <noreply@github.com>2025-04-28 11:42:22 -0700
commitc39c29bf4c52a85d7c83cc8b66ae45e265f9e078 (patch)
tree969339828d49d7db92ed9294a17bd34cc021db84 /tools/slang-test
parent8f6c6e333c06ae1c3b9f00396563c14a2ae09b4d (diff)
Add Slang Byte Code generation and interpreter. (#6896)
* Add Slang Byte Code generation and interpreter. * Fix compile issues. * format code * More compile fix. * Fix clang issue. * Fix more clang issues. * Another clang fix. * Fix clang issues. * Fix another clang issue. * Fix wasm build. * Update building.md * Fix test-server. * Fix compile error. * Fix bug. --------- Co-authored-by: slangbot <186143334+slangbot@users.noreply.github.com>
Diffstat (limited to 'tools/slang-test')
-rw-r--r--tools/slang-test/slang-test-main.cpp83
-rw-r--r--tools/slang-test/slangi-tool-impl.h234
-rw-r--r--tools/slang-test/slangi-tool.cpp10
-rw-r--r--tools/slang-test/slangi-tool.h19
4 files changed, 344 insertions, 2 deletions
diff --git a/tools/slang-test/slang-test-main.cpp b/tools/slang-test/slang-test-main.cpp
index 3f7e41cf6..c0697b4a4 100644
--- a/tools/slang-test/slang-test-main.cpp
+++ b/tools/slang-test/slang-test-main.cpp
@@ -28,6 +28,7 @@
#include "options.h"
#include "parse-diagnostic-util.h"
#include "slangc-tool.h"
+#include "slangi-tool.h"
#include "test-context.h"
#include "test-reporter.h"
@@ -860,7 +861,7 @@ Result spawnAndWaitSharedLibrary(
stdWriters.setWriter(SLANG_WRITER_CHANNEL_STD_ERROR, &stdError);
stdWriters.setWriter(SLANG_WRITER_CHANNEL_STD_OUTPUT, &stdOut);
- if (exeName == "slangc")
+ if (exeName == "slangc" || exeName == "slangi")
{
stdWriters.setWriter(SLANG_WRITER_CHANNEL_DIAGNOSTIC, &stdError);
}
@@ -902,7 +903,7 @@ Result spawnAndWaitProxy(
// Get the name of the thing to execute
String exeName = Path::getFileNameWithoutExt(inCmdLine.m_executableLocation.m_pathOrName);
- if (exeName == "slangc")
+ if (exeName == "slangc" || exeName == "slangi")
{
// If the test is slangc there is a command line version we can just directly use
// return spawnAndWaitExe(context, testPath, inCmdLine, outRes);
@@ -1065,6 +1066,7 @@ static PassThroughFlags _getPassThroughFlagsForTarget(SlangCompileTarget target)
case SLANG_CUDA_SOURCE:
case SLANG_METAL:
case SLANG_WGSL:
+ case SLANG_HOST_VM:
{
return 0;
}
@@ -1303,6 +1305,10 @@ static SlangResult _extractTestRequirements(const CommandLine& cmdLine, TestRequ
{
return _extractSlangCTestRequirements(cmdLine, ioInfo);
}
+ else if (exeName == "slangi")
+ {
+ return SLANG_OK;
+ }
else if (exeName == "slang-reflection-test")
{
return _extractReflectionTestRequirements(cmdLine, ioInfo);
@@ -1562,6 +1568,12 @@ String findExpectedPath(const TestInput& input, const char* postFix)
return "";
}
+static SlangResult _initSlangInterpreter(TestContext* context, CommandLine& ioCmdLine)
+{
+ ioCmdLine.setExecutableLocation(ExecutableLocation(context->options.binDir, "slangi"));
+ return SLANG_OK;
+}
+
static SlangResult _initSlangCompiler(TestContext* context, CommandLine& ioCmdLine)
{
ioCmdLine.setExecutableLocation(ExecutableLocation(context->options.binDir, "slangc"));
@@ -2373,6 +2385,67 @@ TestResult runSimpleLineTest(TestContext* context, TestInput& input)
return _validateOutput(context, input, actualOutput, false);
}
+TestResult runInterpreterTest(TestContext* context, TestInput& input)
+{
+ // need to execute the stand-alone Slang compiler on the file, and compare its output to what we
+ // expect
+ auto outputStem = input.outputStem;
+
+ CommandLine cmdLine;
+
+ List<String> args;
+
+ for (Index i = 0; i < input.testOptions->args.getCount(); i++)
+ {
+ auto& arg = input.testOptions->args[i];
+ if (arg == "-disasm")
+ cmdLine.addArg(arg);
+ else if (arg == "-entry")
+ {
+ cmdLine.addArg(arg);
+ i++;
+ if (i < input.testOptions->args.getCount())
+ {
+ cmdLine.addArg(input.testOptions->args[i]);
+ }
+ }
+ else
+ {
+ args.add(arg);
+ }
+ }
+
+ cmdLine.addArg(input.filePath);
+
+ for (auto arg : args)
+ {
+ cmdLine.addArg(arg);
+ }
+
+ if (SLANG_FAILED(_initSlangInterpreter(context, cmdLine)))
+ {
+ return TestResult::Ignored;
+ }
+
+ ExecuteResult exeRes;
+ TEST_RETURN_ON_DONE(spawnAndWait(context, outputStem, input.spawnType, cmdLine, exeRes));
+
+ if (context->isCollectingRequirements())
+ {
+ return TestResult::Pass;
+ }
+
+ String actualOutput = getOutput(exeRes);
+
+ return _validateOutput(
+ context,
+ input,
+ actualOutput,
+ false,
+ "result code = 0\nstandard error = {\n}\nstandard output = {\n}\n",
+ [&input](auto e, auto a) { return _areResultsEqual(input.testOptions->type, e, a); });
+}
+
TestResult runCompile(TestContext* context, TestInput& input)
{
auto outputStem = input.outputStem;
@@ -3952,6 +4025,7 @@ static const TestCommandInfo s_testCommandInfos[] = {
{"SIMPLE", &runSimpleTest, 0},
{"SIMPLE_EX", &runSimpleTest, 0},
{"SIMPLE_LINE", &runSimpleLineTest, 0},
+ {"INTERPRET", &runInterpreterTest, 0},
{"REFLECTION", &runReflectionTest, 0},
{"CPU_REFLECTION", &runReflectionTest, 0},
{"COMMAND_LINE_SIMPLE", &runSimpleCompareCommandLineTest, 0},
@@ -4851,6 +4925,11 @@ SlangResult innerMain(int argc, char** argv)
context.setInnerMainFunc("slangc", &SlangCTool::innerMain);
}
+ {
+ // We can set the slangc command line tool, to just use the function defined here
+ context.setInnerMainFunc("slangi", &SlangITool::innerMain);
+ }
+
SLANG_RETURN_ON_FAIL(
Options::parse(argc, argv, &categorySet, StdWriters::getError(), &context.options));
diff --git a/tools/slang-test/slangi-tool-impl.h b/tools/slang-test/slangi-tool-impl.h
new file mode 100644
index 000000000..b442800f2
--- /dev/null
+++ b/tools/slang-test/slangi-tool-impl.h
@@ -0,0 +1,234 @@
+namespace SlangITool
+{
+static void printCallback(const char* message, void* userData)
+{
+ auto stdWriters = (StdWriters*)userData;
+ if (stdWriters)
+ {
+ stdWriters->getOut().print("%s", message);
+ }
+}
+
+static SlangResult compileAndInterpret(
+ slang::IGlobalSession* sharedSession,
+ StdWriters* stdWriters,
+ UnownedStringSlice fileName,
+ const char* entryPointName,
+ bool disasm,
+ int argc,
+ const char* const* argv)
+{
+ auto maybePrintDiagnostic = [&](const ComPtr<slang::IBlob>& diagnosticBlob)
+ {
+ if (diagnosticBlob)
+ {
+ const char* diagText = (const char*)diagnosticBlob->getBufferPointer();
+ stdWriters->getError().print("%s\n", diagText);
+ }
+ };
+
+ ComPtr<slang::IGlobalSession> globalSession;
+ SLANG_RETURN_ON_FAIL(slang_createGlobalSession(SLANG_API_VERSION, globalSession.writeRef()));
+ slang::TargetDesc targetDesc = {};
+ targetDesc.format = SLANG_HOST_VM;
+ slang::SessionDesc sessionDesc = {};
+ sessionDesc.targetCount = 1;
+ sessionDesc.targets = &targetDesc;
+ sessionDesc.compilerOptionEntryCount = 0;
+ String pathName = Path::getParentDirectory(fileName);
+ String moduleName = Path::getFileNameWithoutExt(fileName);
+ const char* searchPaths[] = {pathName.getBuffer()};
+ if (pathName.getLength())
+ {
+ sessionDesc.searchPathCount = 1;
+ sessionDesc.searchPaths = searchPaths;
+ }
+ ComPtr<slang::ISession> session;
+ SLANG_RETURN_ON_FAIL(globalSession->createSession(sessionDesc, session.writeRef()));
+
+ ComPtr<slang::IBlob> diagnosticBlob;
+ auto module = session->loadModule(moduleName.getBuffer(), diagnosticBlob.writeRef());
+ if (!module)
+ {
+ maybePrintDiagnostic(diagnosticBlob);
+ return SLANG_FAIL;
+ }
+ ComPtr<slang::IEntryPoint> entryPoint;
+ if (SLANG_FAILED(module->findAndCheckEntryPoint(
+ entryPointName,
+ SLANG_STAGE_DISPATCH,
+ entryPoint.writeRef(),
+ diagnosticBlob.writeRef())))
+ {
+ maybePrintDiagnostic(diagnosticBlob);
+ return SLANG_FAIL;
+ }
+
+ ComPtr<slang::IComponentType> compositeComponent;
+ slang::IComponentType* components[] = {module, entryPoint.get()};
+ if (SLANG_FAILED(session->createCompositeComponentType(
+ components,
+ 2,
+ compositeComponent.writeRef(),
+ diagnosticBlob.writeRef())))
+ {
+ maybePrintDiagnostic(diagnosticBlob);
+ return SLANG_FAIL;
+ }
+
+ ComPtr<slang::IComponentType> linkedProgram;
+ if (SLANG_FAILED(compositeComponent->link(linkedProgram.writeRef(), diagnosticBlob.writeRef())))
+ {
+ maybePrintDiagnostic(diagnosticBlob);
+ return SLANG_FAIL;
+ }
+ ComPtr<slang::IBlob> code;
+
+ if (SLANG_FAILED(linkedProgram->getTargetCode(0, code.writeRef(), diagnosticBlob.writeRef())))
+ {
+ maybePrintDiagnostic(diagnosticBlob);
+ return SLANG_FAIL;
+ }
+
+ if (code->getBufferSize() == 0)
+ {
+ return SLANG_FAIL;
+ }
+
+ if (disasm)
+ {
+ ComPtr<slang::IBlob> disasmBlob;
+ if (SLANG_FAILED(slang_disassembleByteCode(code, disasmBlob.writeRef())))
+ {
+ maybePrintDiagnostic(diagnosticBlob);
+ return SLANG_FAIL;
+ }
+ const char* disasmText = (const char*)disasmBlob->getBufferPointer();
+ stdWriters->getOut().print("%s\n", disasmText);
+ return SLANG_OK;
+ }
+
+ // Create a byte code runner and interpret the code.
+ ComPtr<slang::IByteCodeRunner> runner;
+ slang::ByteCodeRunnerDesc runnerDesc = {};
+ SLANG_RETURN_ON_FAIL(slang_createByteCodeRunner(&runnerDesc, runner.writeRef()));
+ runner->setPrintCallback(printCallback, stdWriters);
+
+ if (SLANG_FAILED(runner->loadModule(code)))
+ {
+ runner->getErrorString(diagnosticBlob.writeRef());
+ maybePrintDiagnostic(diagnosticBlob);
+ }
+ auto funcIndex = runner->findFunctionByName(entryPointName);
+ if (funcIndex < 0)
+ {
+ stdWriters->getError().print("Function '%s' not found in byte code.\n", entryPointName);
+ return SLANG_FAIL;
+ }
+
+ if (SLANG_FAILED(runner->selectFunctionByIndex((uint32_t)funcIndex)))
+ {
+ runner->getErrorString(diagnosticBlob.writeRef());
+ maybePrintDiagnostic(diagnosticBlob);
+ return SLANG_FAIL;
+ }
+
+ struct Arguments
+ {
+ uint32_t argc;
+ const char* const* argv;
+ };
+ Arguments args;
+ args.argc = argc;
+ args.argv = argv;
+ void* arguments = nullptr;
+ size_t argSize = 0;
+ slang::ByteCodeFuncInfo funcInfo;
+ if (SLANG_FAILED(runner->getFunctionInfo((uint32_t)funcIndex, &funcInfo)))
+ {
+ runner->getErrorString(diagnosticBlob.writeRef());
+ maybePrintDiagnostic(diagnosticBlob);
+ return SLANG_FAIL;
+ }
+ if (funcInfo.parameterCount == 2)
+ {
+ arguments = &args;
+ argSize = sizeof(Arguments);
+ }
+ if (SLANG_FAILED(runner->execute(arguments, argSize)))
+ {
+ runner->getErrorString(diagnosticBlob.writeRef());
+ maybePrintDiagnostic(diagnosticBlob);
+ return SLANG_FAIL;
+ }
+ return SLANG_OK;
+}
+
+SlangResult innerMain(
+ StdWriters* stdWriters,
+ slang::IGlobalSession* sharedSession,
+ int argc,
+ const char* const* argv)
+{
+ StdWriters::setSingleton(stdWriters);
+
+ // Assume we will used the shared session
+ ComPtr<slang::IGlobalSession> session(sharedSession);
+
+ // The sharedSession always has a pre-loaded core module.
+ // This differed test checks if the command line has an option to setup the core module.
+ // If so we *don't* use the sharedSession, and create a new session without the core module just
+ // for this compilation.
+ if (TestToolUtil::hasDeferredCoreModule(Index(argc - 1), argv + 1))
+ {
+ SLANG_RETURN_ON_FAIL(
+ slang_createGlobalSessionWithoutCoreModule(SLANG_API_VERSION, session.writeRef()));
+ }
+
+ String entryPointName = toSlice("main");
+ UnownedStringSlice fileName;
+ bool disasm = false;
+ int innerArgIndex = 0;
+ if (argc < 2)
+ {
+ return SLANG_FAIL;
+ }
+ for (auto i = 1; i < argc; i++)
+ {
+ auto arg = UnownedStringSlice(argv[i]);
+ if (arg == "-entry")
+ {
+ entryPointName = UnownedStringSlice(argv[++i]);
+ }
+ else if (arg == "-disasm")
+ {
+ disasm = true;
+ }
+ else if (arg.startsWith("-"))
+ {
+ return SLANG_FAIL;
+ }
+ else
+ {
+ fileName = arg;
+ innerArgIndex = i;
+ break;
+ }
+ }
+ if (!fileName.getLength())
+ {
+ return SLANG_FAIL;
+ }
+
+ auto result = compileAndInterpret(
+ session,
+ stdWriters,
+ fileName,
+ entryPointName.getBuffer(),
+ disasm,
+ argc - innerArgIndex,
+ argv + innerArgIndex);
+
+ return result;
+}
+} // namespace SlangITool
diff --git a/tools/slang-test/slangi-tool.cpp b/tools/slang-test/slangi-tool.cpp
new file mode 100644
index 000000000..ef9d311f7
--- /dev/null
+++ b/tools/slang-test/slangi-tool.cpp
@@ -0,0 +1,10 @@
+// test-context.cpp
+#include "slangi-tool.h"
+
+#include "../../source/core/slang-exception.h"
+#include "../../source/core/slang-io.h"
+#include "../../source/core/slang-test-tool-util.h"
+
+using namespace Slang;
+
+#include "slangi-tool-impl.h"
diff --git a/tools/slang-test/slangi-tool.h b/tools/slang-test/slangi-tool.h
new file mode 100644
index 000000000..1cba47018
--- /dev/null
+++ b/tools/slang-test/slangi-tool.h
@@ -0,0 +1,19 @@
+// slangi-tool.h
+
+#ifndef SLANGI_TOOL_H_INCLUDED
+#define SLANGI_TOOL_H_INCLUDED
+
+#include "../../source/core/slang-std-writers.h"
+
+/* The slangi 'tool' interface, such that slangc like functionality is available directly without
+invoking slangc command line tool, or need for a dll/shared library. */
+namespace SlangITool
+{
+SlangResult innerMain(
+ Slang::StdWriters* stdWriters,
+ SlangSession* session,
+ int argc,
+ const char* const* argv);
+};
+
+#endif // SLANGI_TOOL_H_INCLUDED