From 5621ace93b7665051f7e7c8a2fa68ceaf285ff8d Mon Sep 17 00:00:00 2001 From: Jay Kwak <82421531+jkwak-work@users.noreply.github.com> Date: Tue, 7 Jan 2025 01:35:47 -0800 Subject: Use disassemble API from SPIRV-Tools (#6001) * Use disassemble API from SPIRV-Tools This commit uses C API version of SPIRV disassemble function rather than calling spirv-dis.exe. This allows us to use a correct version of SPIRV disassble function that Slangc.exe is using. The implementation is mostly copied from external/spirv-tools/tools/dis/dis.cpp, which is a source file for building spirv-dis.exe. This commit also includes a fix for a bug in RPC communication to `test-server`. When an RPC connection to `test-server.exe` is reused and the second test abruptly fails due to a compile error or SPIRV validation error, the output from the first test run was incorrectly reused as the output for the second test. This commit resets the RPC result before waiting for the response so that even when the RPC connection is erratically disconnected, the result from the previous run will not be reused incorrectly. Some of the tests appear to be relying on this type of behavior. By using an option, `-skip-spirv-validation`, the RPC connection will continue without an interruption. --- source/compiler-core/slang-downstream-compiler.h | 10 ++++++ source/compiler-core/slang-glslang-compiler.cpp | 20 ++++++++++- source/compiler-core/slang-json-rpc-connection.cpp | 4 +++ source/slang-glslang/slang-glslang.cpp | 31 ++++++++++++++++ source/slang-glslang/slang-glslang.h | 1 + source/slang-llvm/slang-llvm.cpp | 7 ++++ source/slang/slang-diagnostic-defs.h | 6 +--- source/slang/slang-emit-spirv.cpp | 1 - source/slang/slang-emit.cpp | 20 ++++------- source/slang/slang-spirv-val.cpp | 41 ---------------------- source/slang/slang-spirv-val.h | 10 ------ tests/diagnostics/illegal-func-decl.slang | 4 +-- .../language-feature/capability/capability3.slang | 4 +-- .../language-feature/capability/capability7.slang | 2 +- ...conflicting-profile-stage-for-entry-point.slang | 4 +-- 15 files changed, 87 insertions(+), 78 deletions(-) delete mode 100644 source/slang/slang-spirv-val.cpp delete mode 100644 source/slang/slang-spirv-val.h diff --git a/source/compiler-core/slang-downstream-compiler.h b/source/compiler-core/slang-downstream-compiler.h index c0cc868d1..82aaef107 100644 --- a/source/compiler-core/slang-downstream-compiler.h +++ b/source/compiler-core/slang-downstream-compiler.h @@ -337,6 +337,9 @@ public: /// Validate and return the result virtual SLANG_NO_THROW SlangResult SLANG_MCALL validate(const uint32_t* contents, int contentsSize) = 0; + /// Disassemble and print to stdout + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + disassemble(const uint32_t* contents, int contentsSize) = 0; /// True if underlying compiler uses file system to communicate source virtual SLANG_NO_THROW bool SLANG_MCALL isFileBased() = 0; @@ -374,6 +377,13 @@ public: SLANG_UNUSED(contentsSize); return SLANG_FAIL; } + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + disassemble(const uint32_t* contents, int contentsSize) SLANG_OVERRIDE + { + SLANG_UNUSED(contents); + SLANG_UNUSED(contentsSize); + return SLANG_FAIL; + } DownstreamCompilerBase(const Desc& desc) : m_desc(desc) diff --git a/source/compiler-core/slang-glslang-compiler.cpp b/source/compiler-core/slang-glslang-compiler.cpp index 5550ac8ad..b619f468f 100644 --- a/source/compiler-core/slang-glslang-compiler.cpp +++ b/source/compiler-core/slang-glslang-compiler.cpp @@ -47,6 +47,8 @@ public: SLANG_OVERRIDE; virtual SLANG_NO_THROW SlangResult SLANG_MCALL validate(const uint32_t* contents, int contentsSize) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + disassemble(const uint32_t* contents, int contentsSize) SLANG_OVERRIDE; /// Must be called before use SlangResult init(ISlangSharedLibrary* library); @@ -63,6 +65,7 @@ protected: glslang_CompileFunc_1_1 m_compile_1_1 = nullptr; glslang_CompileFunc_1_2 m_compile_1_2 = nullptr; glslang_ValidateSPIRVFunc m_validate = nullptr; + glslang_DisassembleSPIRVFunc m_disassemble = nullptr; ComPtr m_sharedLibrary; @@ -75,7 +78,8 @@ SlangResult GlslangDownstreamCompiler::init(ISlangSharedLibrary* library) m_compile_1_1 = (glslang_CompileFunc_1_1)library->findFuncByName("glslang_compile_1_1"); m_compile_1_2 = (glslang_CompileFunc_1_2)library->findFuncByName("glslang_compile_1_2"); m_validate = (glslang_ValidateSPIRVFunc)library->findFuncByName("glslang_validateSPIRV"); - + m_disassemble = + (glslang_DisassembleSPIRVFunc)library->findFuncByName("glslang_disassembleSPIRV"); if (m_compile_1_0 == nullptr && m_compile_1_1 == nullptr && m_compile_1_2 == nullptr) { @@ -305,6 +309,20 @@ SlangResult GlslangDownstreamCompiler::validate(const uint32_t* contents, int co return SLANG_FAIL; } +SlangResult GlslangDownstreamCompiler::disassemble(const uint32_t* contents, int contentsSize) +{ + if (m_disassemble == nullptr) + { + return SLANG_FAIL; + } + + if (m_disassemble(contents, contentsSize)) + { + return SLANG_OK; + } + return SLANG_FAIL; +} + bool GlslangDownstreamCompiler::canConvert(const ArtifactDesc& from, const ArtifactDesc& to) { // Can only disassemble blobs that are SPIR-V diff --git a/source/compiler-core/slang-json-rpc-connection.cpp b/source/compiler-core/slang-json-rpc-connection.cpp index 79ffc9583..fbbd23d75 100644 --- a/source/compiler-core/slang-json-rpc-connection.cpp +++ b/source/compiler-core/slang-json-rpc-connection.cpp @@ -273,6 +273,10 @@ SlangResult JSONRPCConnection::sendCall( SlangResult JSONRPCConnection::waitForResult(Int timeOutInMs) { + // Invalidate m_jsonRoot before waitForResult, because when waitForResult fail, + // we don't want to use the result from the previous read. + m_jsonRoot.reset(); + SLANG_RETURN_ON_FAIL(m_connection->waitForResult(timeOutInMs)); return tryReadMessage(); } diff --git a/source/slang-glslang/slang-glslang.cpp b/source/slang-glslang/slang-glslang.cpp index 4abcada62..ca45be05b 100644 --- a/source/slang-glslang/slang-glslang.cpp +++ b/source/slang-glslang/slang-glslang.cpp @@ -182,6 +182,37 @@ extern "C" return tools.Validate(contents, contentsSize, options); } +// Disassemble the given SPIRV-ASM instructions. +extern "C" +#ifdef _MSC_VER + _declspec(dllexport) +#else + __attribute__((__visibility__("default"))) +#endif + bool glslang_disassembleSPIRV(const uint32_t* contents, int contentsSize) +{ + static const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_5; + + uint32_t options = SPV_BINARY_TO_TEXT_OPTION_NONE; + options |= SPV_BINARY_TO_TEXT_OPTION_COMMENT; + options |= SPV_BINARY_TO_TEXT_OPTION_PRINT; + options |= SPV_BINARY_TO_TEXT_OPTION_COLOR; + + spv_diagnostic diagnostic = nullptr; + spv_context context = spvContextCreate(kDefaultEnvironment); + spv_result_t error = + spvBinaryToText(context, contents, contentsSize, options, nullptr, &diagnostic); + spvContextDestroy(context); + if (error) + { + spvDiagnosticPrint(diagnostic); + spvDiagnosticDestroy(diagnostic); + return false; + } + + return true; +} + // Apply the SPIRV-Tools optimizer to generated SPIR-V based on the desired optimization level // TODO: add flag for optimizing SPIR-V size as well static void glslang_optimizeSPIRV( diff --git a/source/slang-glslang/slang-glslang.h b/source/slang-glslang/slang-glslang.h index cfeed975a..7b955c5af 100644 --- a/source/slang-glslang/slang-glslang.h +++ b/source/slang-glslang/slang-glslang.h @@ -156,5 +156,6 @@ typedef int (*glslang_CompileFunc_1_0)(glslang_CompileRequest_1_0* request); typedef int (*glslang_CompileFunc_1_1)(glslang_CompileRequest_1_1* request); typedef int (*glslang_CompileFunc_1_2)(glslang_CompileRequest_1_2* request); typedef bool (*glslang_ValidateSPIRVFunc)(const uint32_t* contents, int contentsSize); +typedef bool (*glslang_DisassembleSPIRVFunc)(const uint32_t* contents, int contentsSize); #endif diff --git a/source/slang-llvm/slang-llvm.cpp b/source/slang-llvm/slang-llvm.cpp index 990f99f74..86565a485 100644 --- a/source/slang-llvm/slang-llvm.cpp +++ b/source/slang-llvm/slang-llvm.cpp @@ -140,6 +140,13 @@ public: SLANG_UNUSED(contentsSize); return SLANG_FAIL; } + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + disassemble(const uint32_t* contents, int contentsSize) SLANG_OVERRIDE + { + SLANG_UNUSED(contents); + SLANG_UNUSED(contentsSize); + return SLANG_FAIL; + } LLVMDownstreamCompiler() : m_desc( diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h index 9d08d5b73..821a895bc 100644 --- a/source/slang/slang-diagnostic-defs.h +++ b/source/slang/slang-diagnostic-defs.h @@ -2562,11 +2562,7 @@ DIAGNOSTIC( Internal, serialDebugVerificationFailed, "Verification of serial debug information failed.") -DIAGNOSTIC( - 99999, - Internal, - spirvValidationFailed, - "Validation of generated SPIR-V failed. SPIRV generated: \n$0") +DIAGNOSTIC(99999, Internal, spirvValidationFailed, "Validation of generated SPIR-V failed.") DIAGNOSTIC( 99999, diff --git a/source/slang/slang-emit-spirv.cpp b/source/slang/slang-emit-spirv.cpp index 676a16228..d8c479cd1 100644 --- a/source/slang/slang-emit-spirv.cpp +++ b/source/slang/slang-emit-spirv.cpp @@ -12,7 +12,6 @@ #include "slang-ir-util.h" #include "slang-ir.h" #include "slang-lookup-spirv.h" -#include "slang-spirv-val.h" #include "spirv/unified1/spirv.h" #include diff --git a/source/slang/slang-emit.cpp b/source/slang/slang-emit.cpp index f9118bb45..7ea2fef88 100644 --- a/source/slang/slang-emit.cpp +++ b/source/slang/slang-emit.cpp @@ -104,7 +104,6 @@ #include "slang-legalize-types.h" #include "slang-lower-to-ir.h" #include "slang-mangle.h" -#include "slang-spirv-val.h" #include "slang-syntax.h" #include "slang-type-layout.h" #include "slang-visitor.h" @@ -1942,18 +1941,16 @@ SlangResult emitSPIRVForEntryPointsDirectly( ArtifactUtil::createArtifactForCompileTarget(asExternal(codeGenContext->getTargetFormat())); artifact->addRepresentationUnknown(ListBlob::moveCreate(spirv)); -#if 0 - // Dump the unoptimized SPIRV after lowering from slang IR -> SPIRV - String err; String dis; - disassembleSPIRV(spirv, err, dis); - printf("%s", dis.begin()); -#endif - IDownstreamCompiler* compiler = codeGenContext->getSession()->getOrLoadDownstreamCompiler( PassThroughMode::SpirvOpt, codeGenContext->getSink()); if (compiler) { +#if 0 + // Dump the unoptimized SPIRV after lowering from slang IR -> SPIRV + compiler->disassemble((uint32_t*)spirv.getBuffer(), int(spirv.getCount() / 4)); +#endif + if (!codeGenContext->shouldSkipSPIRVValidation()) { StringBuilder runSpirvValEnvVar; @@ -1966,13 +1963,10 @@ SlangResult emitSPIRVForEntryPointsDirectly( (uint32_t*)spirv.getBuffer(), int(spirv.getCount() / 4)))) { - String err; - String dis; - disassembleSPIRV(spirv, err, dis); + compiler->disassemble((uint32_t*)spirv.getBuffer(), int(spirv.getCount() / 4)); codeGenContext->getSink()->diagnoseWithoutSourceView( SourceLoc{}, - Diagnostics::spirvValidationFailed, - dis); + Diagnostics::spirvValidationFailed); } } } diff --git a/source/slang/slang-spirv-val.cpp b/source/slang/slang-spirv-val.cpp deleted file mode 100644 index e2b4da46c..000000000 --- a/source/slang/slang-spirv-val.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include "slang-spirv-val.h" - -namespace Slang -{ - -SlangResult disassembleSPIRV(const List& spirv, String& outErr, String& outDis) -{ - // Set up our process - CommandLine commandLine; - commandLine.m_executableLocation.setName("spirv-dis"); - commandLine.addArg("--comment"); - commandLine.addArg("--color"); - RefPtr p; - - // If we failed to even start the process, then validation isn't available - SLANG_RETURN_ON_FAIL(Process::create(commandLine, 0, p)); - const auto in = p->getStream(StdStreamType::In); - const auto out = p->getStream(StdStreamType::Out); - const auto err = p->getStream(StdStreamType::ErrorOut); - - List outData; - List outErrData; - SLANG_RETURN_ON_FAIL( - StreamUtil::readAndWrite(in, spirv.getArrayView(), out, outData, err, outErrData)); - - SLANG_RETURN_ON_FAIL(p->waitForTermination(10)); - - outDis = String( - reinterpret_cast(outData.begin()), - reinterpret_cast(outData.end())); - - outErr = String( - reinterpret_cast(outErrData.begin()), - reinterpret_cast(outErrData.end())); - - const auto ret = p->getReturnValue(); - return ret == 0 ? SLANG_OK : SLANG_FAIL; -} - - -} // namespace Slang diff --git a/source/slang/slang-spirv-val.h b/source/slang/slang-spirv-val.h deleted file mode 100644 index 01e111f91..000000000 --- a/source/slang/slang-spirv-val.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include "slang-compiler.h" - -#include - -namespace Slang -{ -SlangResult disassembleSPIRV(const List& spirv, String& outErr, String& outDis); -} diff --git a/tests/diagnostics/illegal-func-decl.slang b/tests/diagnostics/illegal-func-decl.slang index 0ec73dc27..64199a791 100644 --- a/tests/diagnostics/illegal-func-decl.slang +++ b/tests/diagnostics/illegal-func-decl.slang @@ -6,9 +6,9 @@ //TEST:COMPILE: tests/diagnostics/illegal-func-decl-module.slang -o tests/diagnostics/illegal-func-decl-module.slang-module //DIAGNOSTIC_TEST:SIMPLE(filecheck=CHECK1): -r tests/diagnostics/illegal-func-decl-module.slang-module -DTEST1 -target spirv -o illegal-func-decl.spv -//DIAGNOSTIC_TEST:SIMPLE(filecheck=CHECK2): -r tests/diagnostics/illegal-func-decl-module.slang-module -DTEST2 -target spirv -o illegal-func-decl.spv +//DIAGNOSTIC_TEST:SIMPLE(filecheck=CHECK2): -r tests/diagnostics/illegal-func-decl-module.slang-module -DTEST2 -target spirv -o illegal-func-decl.spv -skip-spirv-validation //DIAGNOSTIC_TEST:SIMPLE(filecheck=CHECK3): -r tests/diagnostics/illegal-func-decl-module.slang-module -DTEST3 -target spirv -o illegal-func-decl.spv -//DIAGNOSTIC_TEST:SIMPLE(filecheck=CHECK4): -r tests/diagnostics/illegal-func-decl-module.slang-module -DTEST4 -target spirv -o illegal-func-decl.spv +//DIAGNOSTIC_TEST:SIMPLE(filecheck=CHECK4): -r tests/diagnostics/illegal-func-decl-module.slang-module -DTEST4 -target spirv -o illegal-func-decl.spv -skip-spirv-validation #ifdef TEST1 // CHECK1: ([[# @LINE+1]]): error 45001: unresolved external symbol 'libraryFunction'. diff --git a/tests/language-feature/capability/capability3.slang b/tests/language-feature/capability/capability3.slang index 67099a1da..4091b9c93 100644 --- a/tests/language-feature/capability/capability3.slang +++ b/tests/language-feature/capability/capability3.slang @@ -1,5 +1,5 @@ //TEST:SIMPLE(filecheck=CHECK): -target spirv -emit-spirv-directly -entry main -stage compute -//TEST:SIMPLE(filecheck=CHECK_IGNORE_CAPS): -target spirv -emit-spirv-directly -entry main -stage compute -ignore-capabilities +//TEST:SIMPLE(filecheck=CHECK_IGNORE_CAPS): -target spirv -emit-spirv-directly -entry main -stage compute -ignore-capabilities -skip-spirv-validation // CHECK_IGNORE_CAPS-NOT: error 36108 // Test that capabilities can be declared on module. @@ -39,4 +39,4 @@ void main() { use1(); use2(); -} \ No newline at end of file +} diff --git a/tests/language-feature/capability/capability7.slang b/tests/language-feature/capability/capability7.slang index 21f3d68e4..011112a34 100644 --- a/tests/language-feature/capability/capability7.slang +++ b/tests/language-feature/capability/capability7.slang @@ -1,5 +1,5 @@ //TEST:SIMPLE(filecheck=CHECK): -target glsl -entry computeMain -stage compute -profile sm_5_0 -//TEST:SIMPLE(filecheck=CHECK_IGNORE_CAPS): -target glsl -emit-spirv-directly -entry computeMain -stage compute -profile sm_5_0 -ignore-capabilities +//TEST:SIMPLE(filecheck=CHECK_IGNORE_CAPS): -target glsl -emit-spirv-directly -entry computeMain -stage compute -profile sm_5_0 -ignore-capabilities -skip-spirv-validation // Test that we diagnose simplified capabilities // CHECK_IGNORE_CAPS-NOT: error 36104 diff --git a/tests/language-feature/capability/conflicting-profile-stage-for-entry-point.slang b/tests/language-feature/capability/conflicting-profile-stage-for-entry-point.slang index 9cc06347f..a888e7cf9 100644 --- a/tests/language-feature/capability/conflicting-profile-stage-for-entry-point.slang +++ b/tests/language-feature/capability/conflicting-profile-stage-for-entry-point.slang @@ -3,7 +3,7 @@ //TEST:SIMPLE(filecheck=CHECK): -target spirv -entry vsmain -profile vs_6_0 //TEST:SIMPLE(filecheck=CHECK): -target spirv -entry psmain -profile vs_6_0 -ignore-capabilities -//TEST:SIMPLE(filecheck=CHECK): -target spirv -entry vsmain -profile ps_6_0 -ignore-capabilities +//TEST:SIMPLE(filecheck=CHECK): -target spirv -entry vsmain -profile ps_6_0 -ignore-capabilities -skip-spirv-validation // CHECK_ERROR: warning 36112 // CHECK-NOT: warning 36112 @@ -33,4 +33,4 @@ VSOutput vsmain(float3 PositionOS : POSITION, float3 Color : COLOR0) float4 psmain(VSOutput input) : SV_TARGET { return float4(input.Color, 1); -} \ No newline at end of file +} -- cgit v1.2.3