diff options
| author | Jay Kwak <82421531+jkwak-work@users.noreply.github.com> | 2025-08-28 10:45:07 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-08-28 17:45:07 +0000 |
| commit | c19e2e92ae8e713225262a17f39a438cd511d416 (patch) | |
| tree | 7c78e65d3c826c52b527c71500a72ecb18754254 | |
| parent | 3dc466487d489f09c835bdd872eb130cdc5784ea (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>
| -rw-r--r-- | tests/bugs/spirv-debug-info.slang | 24 | ||||
| -rw-r--r-- | tests/spirv/debug-info.slang | 2 | ||||
| -rw-r--r-- | tests/spirv/debug-value-dynamic-index.slang | 5 | ||||
| -rw-r--r-- | tools/slang-test/slang-test-main.cpp | 107 |
4 files changed, 121 insertions, 17 deletions
diff --git a/tests/bugs/spirv-debug-info.slang b/tests/bugs/spirv-debug-info.slang index 500299057..fe1c4fb05 100644 --- a/tests/bugs/spirv-debug-info.slang +++ b/tests/bugs/spirv-debug-info.slang @@ -1,5 +1,5 @@ -//TEST:SIMPLE(filecheck=CHECK):-target spirv -entry MainPs -stage fragment -profile glsl_450 -g3 -line-directive-mode none -//TEST:SIMPLE(filecheck=CHECK-SPIRV):-target spirv -entry MainPs -stage fragment -profile glsl_450 -g3 -emit-spirv-directly +//TEST:SIMPLE(filecheck=CHECK):-target spirv -entry MainPs -stage fragment -profile glsl_450 -g3 -line-directive-mode none -preserve-embedded-source +//TEST:SIMPLE(filecheck=CHECK-SPIRV):-target spirv -entry MainPs -stage fragment -profile glsl_450 -g3 -emit-spirv-directly -preserve-embedded-source // make sure that the generated spirv has glsl source in it. // CHECK: #version 450 @@ -10,14 +10,14 @@ // CHECK-SPIRV: {{.*}} OpFunction // CHECK-SPIRV: {{.*}} = OpExtInst %void {{.*}} DebugLine -struct PS_OUTPUT -{ - float4 vColor : SV_Target0 ; -} ; +struct PS_OUTPUT +{ + float4 vColor : SV_Target0 ; +} ; -PS_OUTPUT MainPs ( ) -{ - PS_OUTPUT o ; - o . vColor = float4 ( 0 , 0 , 0 , 0 ) ; - return o ; -}
\ No newline at end of file +PS_OUTPUT MainPs ( ) +{ + PS_OUTPUT o ; + o . vColor = float4 ( 0 , 0 , 0 , 0 ) ; + return o ; +} diff --git a/tests/spirv/debug-info.slang b/tests/spirv/debug-info.slang index dc225f8cc..d1107b774 100644 --- a/tests/spirv/debug-info.slang +++ b/tests/spirv/debug-info.slang @@ -27,4 +27,4 @@ void main() // CHECK: DebugFunctionDefinition // CHECK: DebugScope // CHECK: DebugLine -// CHECK: DebugValue +// CHECK: DebugDeclare diff --git a/tests/spirv/debug-value-dynamic-index.slang b/tests/spirv/debug-value-dynamic-index.slang index 591b1f6da..8b4f6b43e 100644 --- a/tests/spirv/debug-value-dynamic-index.slang +++ b/tests/spirv/debug-value-dynamic-index.slang @@ -1,4 +1,5 @@ -//TEST:SIMPLE(filecheck=CHECK):-target spirv -entry main -stage compute -g2 -emit-spirv-directly +// This will be re-enabled when github #7693 is resolved +//DISABLE_TEST:SIMPLE(filecheck=CHECK):-target spirv -entry main -stage compute -g2 -emit-spirv-directly struct TestType { @@ -25,5 +26,5 @@ void main(int id : SV_DispatchThreadID) // CHECK: DebugTypeComposite // CHECK: DebugFunctionDefinition // CHECK: DebugScope +// CHECK: DebugDeclare // CHECK: DebugLine -// CHECK: DebugValue 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, |
