From 0d16228ae22fa2e1a00e62dc099eea08da7717fe Mon Sep 17 00:00:00 2001 From: jarcherNV Date: Fri, 6 Jun 2025 14:30:06 -0700 Subject: Add command line option for separate debug info (#7178) * Add command line option for separate debug info Add command line arg -separate-debug-info which, if provided, produces both a .spv and a .dbg.spv file. The .dbg.spv file contains full debug info and the .spv file has all debug info stripped out. Also add a DebugBuildIdentifier instruction to store a unique hash in both the output files, so they can be more easily matched together. A matching API is provided to allow using the Slang API to retrieve a base and debug SPIRV as well as the debug build identifier string. --- tools/slang-unit-test/unit-test-separate-debug.cpp | 150 +++++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 tools/slang-unit-test/unit-test-separate-debug.cpp (limited to 'tools') diff --git a/tools/slang-unit-test/unit-test-separate-debug.cpp b/tools/slang-unit-test/unit-test-separate-debug.cpp new file mode 100644 index 000000000..42ada97a5 --- /dev/null +++ b/tools/slang-unit-test/unit-test-separate-debug.cpp @@ -0,0 +1,150 @@ +// unit-test-translation-unit-import.cpp + +#include "../../source/core/slang-io.h" +#include "../../source/core/slang-process.h" +#include "slang-com-ptr.h" +#include "slang.h" +#include "unit-test/slang-unit-test.h" + +#include +#include + +using namespace Slang; + +// Test that separate debug info is generated when requested and contains the +// correct instructions. + +SLANG_UNIT_TEST(separateDebug) +{ + // Source for a basic slang shader to compile to spirv. + const char* userSourceBody = R"( + struct TestType + { + float memberA; + float3 memberB; + RWStructuredBuffer memberC; + float getValue() + { + return memberA; + } + } + RWStructuredBuffer result; + void main() + { + TestType t; + t.memberA = 1.0; + t.memberB = float3(1, 2, 3); + t.memberC = result; + var val = t.getValue(); + result[0] = val + t.memberB.x; + } + )"; + String userSource = userSourceBody; + ComPtr globalSession; + SLANG_CHECK(slang_createGlobalSession(SLANG_API_VERSION, globalSession.writeRef()) == SLANG_OK); + + // Setup the target descriptor. + slang::TargetDesc targetDesc = {}; + targetDesc.format = SLANG_SPIRV_ASM; + targetDesc.profile = globalSession->findProfile("spirv_1_5"); + + // Setup the session descriptor. + slang::SessionDesc sessionDesc = {}; + sessionDesc.targetCount = 1; + sessionDesc.targets = &targetDesc; + + // Set the compile options. + slang::CompilerOptionEntry compilerOptions[2]; + compilerOptions[0].name = slang::CompilerOptionName::DebugInformation; + compilerOptions[0].value.kind = slang::CompilerOptionValueKind::Int; + compilerOptions[0].value.intValue0 = 2; + + compilerOptions[1].name = slang::CompilerOptionName::EmitSeparateDebug; + compilerOptions[1].value.kind = slang::CompilerOptionValueKind::Int; + compilerOptions[1].value.intValue0 = 1; + + sessionDesc.compilerOptionEntries = compilerOptions; + sessionDesc.compilerOptionEntryCount = 2; + + ComPtr session; + SLANG_CHECK(globalSession->createSession(sessionDesc, session.writeRef()) == SLANG_OK); + + // Compile the module. + ComPtr diagnosticBlob; + auto module = session->loadModuleFromSourceString( + "m", + "m.slang", + userSourceBody, + diagnosticBlob.writeRef()); + SLANG_CHECK(module != nullptr); + + ComPtr entryPoint; + module->findAndCheckEntryPoint( + "main", + SLANG_STAGE_COMPUTE, + entryPoint.writeRef(), + diagnosticBlob.writeRef()); + SLANG_CHECK(entryPoint != nullptr); + + ComPtr compositeProgram; + slang::IComponentType* components[] = {module, entryPoint.get()}; + session->createCompositeComponentType( + components, + 2, + compositeProgram.writeRef(), + diagnosticBlob.writeRef()); + SLANG_CHECK(compositeProgram != nullptr); + + ComPtr linkedProgram; + compositeProgram->link(linkedProgram.writeRef(), diagnosticBlob.writeRef()); + SLANG_CHECK(linkedProgram != nullptr); + + // Use getEntryPointCompileResult to get the base and debug spirv, and metadata + // containing the debug build identifier. + ComPtr code; + ComPtr debugCode; + ComPtr metadata; + const char* debugBuildIdentifier = nullptr; + + ComPtr compileResult; + auto result = linkedProgram->getEntryPointCompileResult( + 0, + 0, + compileResult.writeRef(), + diagnosticBlob.writeRef()); + SLANG_CHECK(result == SLANG_OK); + SLANG_CHECK(compileResult != nullptr); + SLANG_CHECK(compileResult->getItemCount() == 2); + SLANG_CHECK(compileResult->getItemData(0, code.writeRef()) == SLANG_OK); + SLANG_CHECK(compileResult->getItemData(1, debugCode.writeRef()) == SLANG_OK); + SLANG_CHECK(compileResult->getMetadata(metadata.writeRef()) == SLANG_OK); + + debugBuildIdentifier = metadata->getDebugBuildIdentifier(); + SLANG_CHECK(debugBuildIdentifier != nullptr); + + // Get the data for the stripped SPIRV. + // This is already verified by the separate-debug.slang test but we + // check it here to again to verify that the API is working. + String codeString = static_cast(code->getBufferPointer()); + + // Verify that the code contains DebugBuildIdentifier instruction + // and the correct hash. + SLANG_CHECK(codeString.indexOf("DebugBuildIdentifier") != -1); + SLANG_CHECK(codeString.indexOf(debugBuildIdentifier) != -1); + + // Verify that it does not contain any other debug instructions. + SLANG_CHECK(codeString.indexOf("DebugExpression") == -1); + SLANG_CHECK(codeString.indexOf("DebugTypeMember") == -1); + SLANG_CHECK(codeString.indexOf("DebugScope") == -1); + SLANG_CHECK(codeString.indexOf("DebugLine") == -1); + + // Get the data for the non-stripped debug SPIRV and verify + // that it contains the correct debug instructions. + String debugCodeString = static_cast(debugCode->getBufferPointer()); + SLANG_CHECK(debugCodeString.indexOf("DebugBuildIdentifier") != -1); + SLANG_CHECK(debugCodeString.indexOf(debugBuildIdentifier) != -1); + SLANG_CHECK(debugCodeString.indexOf("DebugExpression") != -1); + SLANG_CHECK(debugCodeString.indexOf("DebugFunctionDefinition") != -1); + SLANG_CHECK(debugCodeString.indexOf("DebugScope") != -1); + SLANG_CHECK(debugCodeString.indexOf("DebugLine") != -1); +} -- cgit v1.2.3