summaryrefslogtreecommitdiffstats
path: root/tools
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
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')
-rw-r--r--tools/CMakeLists.txt13
-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
-rw-r--r--tools/slang-unit-test/unit-test-slang-vm.cpp102
-rw-r--r--tools/slangi/main.cpp232
-rw-r--r--tools/test-server/test-server-main.cpp7
8 files changed, 698 insertions, 2 deletions
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
index 18a50d357..53698726b 100644
--- a/tools/CMakeLists.txt
+++ b/tools/CMakeLists.txt
@@ -96,6 +96,19 @@ if(SLANG_ENABLE_SLANGD)
)
endif()
+#
+# Slang Interpreter
+#
+if(SLANG_ENABLE_SLANGI)
+ slang_add_target(
+ slangi
+ EXECUTABLE
+ LINK_WITH_PRIVATE core compiler-core slang
+ INSTALL
+ EXPORT_SET_NAME SlangTargets
+ )
+endif()
+
if(SLANG_ENABLE_GFX)
#
# `platform` contains all the platform abstractions for a GUI application.
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
diff --git a/tools/slang-unit-test/unit-test-slang-vm.cpp b/tools/slang-unit-test/unit-test-slang-vm.cpp
new file mode 100644
index 000000000..0f5e0f9f3
--- /dev/null
+++ b/tools/slang-unit-test/unit-test-slang-vm.cpp
@@ -0,0 +1,102 @@
+// unit-test-slang-vm.cpp
+
+#include "core/slang-memory-file-system.h"
+#include "slang-com-ptr.h"
+#include "slang.h"
+#include "unit-test/slang-unit-test.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+using namespace Slang;
+
+SLANG_UNIT_TEST(slangVM)
+{
+ const char* testSource = R"(
+ int one() { return 1; }
+ int sum(int x)
+ {
+ int result = 0;
+ for (int i = 0; i <= x; i++)
+ {
+ result += i;
+ }
+ return result + one();
+ }
+ [shader("dispatch")]
+ int dispatchMain(uniform int2 v, out int c)
+ {
+ int a = v.x;
+ int b = v.y;
+ int tmp = 0;
+ if (a > 0)
+ tmp = a + b;
+ else
+ tmp = b - a;
+ tmp += sum(b);
+ c = tmp;
+ return 100;
+ }
+ )";
+
+ // Create Slang session and compile code.
+ ComPtr<slang::IBlob> code;
+ String disasmText;
+ {
+ ComPtr<slang::IGlobalSession> globalSession;
+ SLANG_CHECK(
+ slang_createGlobalSession(SLANG_API_VERSION, globalSession.writeRef()) == SLANG_OK);
+ slang::TargetDesc targetDesc = {};
+ targetDesc.format = SLANG_HOST_VM;
+ slang::SessionDesc sessionDesc = {};
+ sessionDesc.targetCount = 1;
+ sessionDesc.targets = &targetDesc;
+ sessionDesc.compilerOptionEntryCount = 0;
+
+ ComPtr<slang::ISession> session;
+ SLANG_CHECK(globalSession->createSession(sessionDesc, session.writeRef()) == SLANG_OK);
+
+ ComPtr<slang::IBlob> diagnosticBlob;
+ auto module = session->loadModuleFromSourceString(
+ "test",
+ "test.slang",
+ testSource,
+ diagnosticBlob.writeRef());
+ SLANG_CHECK(module != nullptr);
+
+ ComPtr<slang::IComponentType> linkedProgram;
+ module->link(linkedProgram.writeRef());
+
+
+ linkedProgram->getTargetCode(0, code.writeRef(), diagnosticBlob.writeRef());
+
+ SLANG_CHECK(code->getBufferSize() > 0);
+
+ ComPtr<slang::IBlob> disasmBlob;
+ SLANG_CHECK(slang_disassembleByteCode(code, disasmBlob.writeRef()) == SLANG_OK);
+ disasmText = (const char*)disasmBlob->getBufferPointer();
+ SLANG_CHECK(disasmText.indexOf("ret") != -1);
+ }
+
+ // Create a byte code runner and interpret the code.
+ ComPtr<slang::IByteCodeRunner> runner;
+ slang::ByteCodeRunnerDesc runnerDesc = {};
+ SLANG_CHECK(slang_createByteCodeRunner(&runnerDesc, runner.writeRef()) == SLANG_OK);
+ SLANG_CHECK(runner->loadModule(code) == SLANG_OK);
+ SLANG_CHECK(runner->selectFunctionByIndex(0) == SLANG_OK);
+ struct Params
+ {
+ int a;
+ int b;
+ int* result;
+ };
+ int result = 0;
+ Params params = {1, 2, &result};
+ SLANG_CHECK(runner->execute(&params, sizeof(params)) == SLANG_OK);
+ SLANG_CHECK(result == 7);
+
+ size_t returnValSize = 0;
+ int* returnVal = (int*)runner->getReturnValue(&returnValSize);
+ SLANG_CHECK(returnValSize == sizeof(int));
+ SLANG_CHECK(*returnVal == 100);
+}
diff --git a/tools/slangi/main.cpp b/tools/slangi/main.cpp
new file mode 100644
index 000000000..2ef680324
--- /dev/null
+++ b/tools/slangi/main.cpp
@@ -0,0 +1,232 @@
+// main.cpp
+
+// This file implements the entry point for `slangi`, an interpreter for the Slang language.
+
+#include "../../source/core/slang-basic.h"
+#include "core/slang-io.h"
+#include "slang-com-ptr.h"
+#include "slang.h"
+
+using namespace Slang;
+using namespace slang;
+
+void printUsage()
+{
+ printf("Slang Interpreter (Experimental)\n");
+ printf("Compile and interpret Slang code.\n");
+ printf("Usage: slangi [options] <filename>\n");
+ printf("Options:\n");
+ printf(" -entry <name> Specify the entry point function name to run. (default: main)\n");
+ printf(" -disasm Disassemble the bytecode after compilation.\n");
+ printf(" -help Show this help message\n");
+}
+
+void maybePrintDiagnostic(const ComPtr<slang::IBlob>& diagnosticBlob)
+{
+ if (diagnosticBlob)
+ {
+ const char* diagText = (const char*)diagnosticBlob->getBufferPointer();
+ fprintf(stderr, "%s\n", diagText);
+ }
+}
+
+SlangResult compileAndInterpret(
+ UnownedStringSlice fileName,
+ const char* entryPointName,
+ bool disasm,
+ int argc,
+ const char* const* argv)
+{
+ 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();
+ printf("%s\n", disasmText);
+ }
+
+ // 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()));
+ if (SLANG_FAILED(runner->loadModule(code)))
+ {
+ runner->getErrorString(diagnosticBlob.writeRef());
+ maybePrintDiagnostic(diagnosticBlob);
+ }
+ auto funcIndex = runner->findFunctionByName(entryPointName);
+ if (funcIndex < 0)
+ {
+ printf("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;
+ }
+ size_t returnValueSize = 0;
+ void* returnVal = runner->getReturnValue(&returnValueSize);
+ SlangResult result = SLANG_OK;
+ memcpy(&result, returnVal, returnValueSize);
+ return result;
+}
+
+int main(int argc, const char* const* argv)
+{
+ String entryPointName = toSlice("main");
+ UnownedStringSlice fileName;
+ bool disasm = false;
+ int innerArgIndex = 0;
+ if (argc < 2)
+ {
+ printUsage();
+ return 0;
+ }
+ for (auto i = 1; i < argc; i++)
+ {
+ auto arg = UnownedStringSlice(argv[i]);
+ if (arg == "-entry")
+ {
+ entryPointName = UnownedStringSlice(argv[++i]);
+ }
+ else if (arg == "-help" || arg == "--help")
+ {
+ printUsage();
+ return 0;
+ }
+ else if (arg == "-disasm")
+ {
+ disasm = true;
+ }
+ else if (arg.startsWith("-"))
+ {
+ fprintf(stderr, "Unknown option: %s\n", arg.begin());
+ printUsage();
+ return -1;
+ }
+ else
+ {
+ fileName = arg;
+ innerArgIndex = i;
+ break;
+ }
+ }
+ if (!fileName.getLength())
+ {
+ printUsage();
+ return 0;
+ }
+
+ auto result = compileAndInterpret(
+ fileName,
+ entryPointName.getBuffer(),
+ disasm,
+ argc - innerArgIndex,
+ argv + innerArgIndex);
+ slang::shutdown();
+ return result;
+}
diff --git a/tools/test-server/test-server-main.cpp b/tools/test-server/test-server-main.cpp
index 633a23d7e..63535ec92 100644
--- a/tools/test-server/test-server-main.cpp
+++ b/tools/test-server/test-server-main.cpp
@@ -188,6 +188,9 @@ SlangResult innerMain(
} // namespace SlangCTool
+// SlangITool
+#include "../slang-test/slangi-tool-impl.h"
+
/* !!!!!!!!!!!!!!!!!!!!!!!!!!!! TestServer !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
SlangResult TestServer::init(int argc, const char* const* argv)
@@ -308,6 +311,10 @@ TestServer::InnerMainFunc TestServer::getToolFunction(const String& name, Diagno
{
return &SlangCTool::innerMain;
}
+ else if (name == "slangi")
+ {
+ return &SlangITool::innerMain;
+ }
StringBuilder sharedLibToolBuilder;
sharedLibToolBuilder.append(name);