summaryrefslogtreecommitdiffstats
path: root/tools/slang-test/slang-test-main.cpp
diff options
context:
space:
mode:
authorJay Kwak <82421531+jkwak-work@users.noreply.github.com>2025-08-28 10:45:07 -0700
committerGitHub <noreply@github.com>2025-08-28 17:45:07 +0000
commitc19e2e92ae8e713225262a17f39a438cd511d416 (patch)
tree7c78e65d3c826c52b527c71500a72ecb18754254 /tools/slang-test/slang-test-main.cpp
parent3dc466487d489f09c835bdd872eb130cdc5784ea (diff)
Remove the embedded source to avoid self-matching in slang-test (#8305)
When `SIMPLE` type test is used with `-g[1-3]` option, the filecheck pattern will most likely to match to the string itself on the embedded source code rather than match to the emitted spirv-asm code. This commit avoids the problem by removing the embedded source code. This commit also provides an option to keep the embedded source code, `-preserve-embedded-source`. The source code removal is happening in two steps: 1. iterate all output lines and find SPIRV-ASM in the following pattern: `%N = OpExtInst %void %M DebugSource %fileId %sourceId`. And then, store the "%sourceId" value to identify which SPIRV instructions are for the embedded source code. 2. iterate all output lines again to find the `%sourceId = OpString "...."` and replace the whole string with the following string, ``` %1 = OpString "// slang-test removed the embedded source // Use `-preserve-embedded-source` to keep it explicitly " ``` This change revealed problems in the existing tests: - tests/bugs/spirv-debug-info.slang : The expected text was missing and it had to be added. The file also had Carrage-Return character on all lines and the pre-commit git hook removed them. - tests/spirv/debug-info.slang : the expected keyword DebugValue had to change to DebugDeclare, because that's what we get with ToT. - tests/spirv/debug-value-dynamic-index.slang : This test is currently failing, and it will pass once DebugLocalVariable instruction missing for parameter of the entry point function #7693 is resolved. --------- Co-authored-by: slangbot <ellieh+slangbot@nvidia.com>
Diffstat (limited to 'tools/slang-test/slang-test-main.cpp')
-rw-r--r--tools/slang-test/slang-test-main.cpp107
1 files changed, 105 insertions, 2 deletions
diff --git a/tools/slang-test/slang-test-main.cpp b/tools/slang-test/slang-test-main.cpp
index 3f707b5e5..6c0de13ec 100644
--- a/tools/slang-test/slang-test-main.cpp
+++ b/tools/slang-test/slang-test-main.cpp
@@ -54,6 +54,9 @@ SLANG_RHI_EXPORT_AGILITY_SDK
using namespace Slang;
+// Constants for slang-test specific options
+static const char* kPreserveEmbeddedSourceOption = "-preserve-embedded-source";
+
// Options for a particular test
struct TestOptions
{
@@ -1531,7 +1534,94 @@ ToolReturnCode spawnAndWait(
return getReturnCode(outExeRes);
}
-String getOutput(const ExecuteResult& exeRes)
+// Remove embedded source code from SPIR-V assembly output to prevent filecheck from matching
+// against embedded source instead of actual SPIR-V instructions
+String removeEmbeddedSourceFromSPIRV(const String& spirvOutput)
+{
+ StringBuilder filteredOutput;
+ List<UnownedStringSlice> lines;
+ StringUtil::calcLines(spirvOutput.getUnownedSlice(), lines);
+
+ if (spirvOutput.endsWith("\n"))
+ {
+ // The last empty line should be removed,
+ // because `StringUtil::calcLines()` turns "A\nB\n" into three lines; not two.
+ SLANG_ASSERT(lines[lines.getCount() - 1] == "");
+ lines.setCount(lines.getCount() - 1);
+ }
+
+ // First pass: Find OpString IDs that are referenced by DebugSource
+ List<String> sourceStringIds;
+ for (const auto& line : lines)
+ {
+ UnownedStringSlice trimmedLine = line.trim();
+
+ if (trimmedLine.indexOf(UnownedStringSlice(" DebugSource ")) == Index(-1))
+ continue;
+
+ // Extract the last parameter which is the source string ID
+ // Pattern: %4 = OpExtInst %void %2 DebugSource %5 %1
+ List<UnownedStringSlice> tokens;
+ StringUtil::split(trimmedLine, ' ', tokens);
+
+ // The last token should be the source string ID
+ UnownedStringSlice lastToken = tokens.getLast();
+ if (lastToken.startsWith(UnownedStringSlice("%")))
+ {
+ sourceStringIds.add(String(lastToken));
+ }
+ }
+
+ // Second pass: Process embedded source strings to replace content with informative message
+ bool insideSourceString = false;
+ for (const auto& line : lines)
+ {
+ UnownedStringSlice trimmedLine = line.trim();
+
+ if (!insideSourceString)
+ {
+ Index equalPos = trimmedLine.indexOf(UnownedStringSlice(" = OpString"));
+ if (equalPos != Index(-1) && trimmedLine.startsWith(UnownedStringSlice("%")))
+ {
+ String currentStringId = String(trimmedLine.head(equalPos));
+ if (sourceStringIds.contains(currentStringId))
+ {
+ insideSourceString = true;
+ Index quotePos = line.indexOf('\"');
+ if (quotePos != Index(-1))
+ {
+ filteredOutput.append(String(line.head(quotePos + 1)));
+ filteredOutput.append("// slang-test removed the embedded source\n");
+ filteredOutput.append("// Use `");
+ filteredOutput.append(kPreserveEmbeddedSourceOption);
+ filteredOutput.append("` to keep it explicitly\n\"\n");
+ }
+ continue;
+ }
+ }
+ }
+
+ if (insideSourceString)
+ {
+ if (trimmedLine.endsWith("\"") &&
+ (trimmedLine.getLength() < 2 || trimmedLine[trimmedLine.getLength() - 2] != '\\'))
+ {
+ insideSourceString = false;
+ }
+
+ // skip the embedded source lines
+ continue;
+ }
+
+ // Add this line to the filtered output
+ filteredOutput.append(line);
+ filteredOutput.append("\n");
+ }
+
+ return filteredOutput.produceString();
+}
+
+String getOutput(const ExecuteResult& exeRes, bool removeEmbeddedSource = false)
{
ExecuteResult::ResultCode resultCode = exeRes.resultCode;
@@ -1539,6 +1629,12 @@ String getOutput(const ExecuteResult& exeRes)
String standardError = exeRes.standardError;
String debugLayer = exeRes.debugLayer;
+ // Apply embedded source removal to standard output if requested
+ if (removeEmbeddedSource)
+ {
+ standardOuptut = removeEmbeddedSourceFromSPIRV(standardOuptut);
+ }
+
// We construct a single output string that captures the results
StringBuilder actualOutputBuilder;
actualOutputBuilder.append("result code = ");
@@ -2325,6 +2421,9 @@ TestResult runSimpleTest(TestContext* context, TestInput& input)
for (auto arg : input.testOptions->args)
{
+ // Filter out slang-test specific options that shouldn't be passed to slangc
+ if (arg == kPreserveEmbeddedSourceOption)
+ continue;
cmdLine.addArg(arg);
}
@@ -2366,7 +2465,11 @@ TestResult runSimpleTest(TestContext* context, TestInput& input)
exeRes = runExeRes;
}
- String actualOutput = getOutput(exeRes);
+ bool needToRemoveEmbeddedSource =
+ ((target == SLANG_SPIRV || target == SLANG_SPIRV_ASM) &&
+ input.testOptions->args.indexOf(kPreserveEmbeddedSourceOption) == Index(-1));
+
+ String actualOutput = getOutput(exeRes, needToRemoveEmbeddedSource);
return _validateOutput(
context,