summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJay Kwak <82421531+jkwak-work@users.noreply.github.com>2024-07-17 17:00:05 -0700
committerGitHub <noreply@github.com>2024-07-17 17:00:05 -0700
commit32b1e25e359f8daf5254301dca8be308e8e1e2ab (patch)
tree2dd2bf7324b771c4a0aa989194a9b1d3b219af18
parent2db15080085856ed9b5f20642dbb354aac59a888 (diff)
Use slang-glslang.dll for spirv-validation (#4642)
* Use slang-glslang.dll for spirv-validation This change replaces the use of "spirv-val.exe" with an API call to "spvtools::SpirvTools::Validate()". Closes #4610
-rw-r--r--source/compiler-core/slang-downstream-compiler.h3
-rw-r--r--source/compiler-core/slang-glslang-compiler.cpp17
-rw-r--r--source/slang-glslang/slang-glslang.cpp20
-rw-r--r--source/slang-glslang/slang-glslang.h1
-rw-r--r--source/slang-llvm/slang-llvm.cpp3
-rw-r--r--source/slang/slang-emit-spirv.cpp17
-rw-r--r--source/slang/slang-emit.cpp16
-rw-r--r--source/slang/slang-spirv-val.cpp41
-rw-r--r--source/slang/slang-spirv-val.h1
9 files changed, 59 insertions, 60 deletions
diff --git a/source/compiler-core/slang-downstream-compiler.h b/source/compiler-core/slang-downstream-compiler.h
index 14e924f8b..95793eaa3 100644
--- a/source/compiler-core/slang-downstream-compiler.h
+++ b/source/compiler-core/slang-downstream-compiler.h
@@ -309,6 +309,8 @@ public:
virtual SLANG_NO_THROW SlangResult SLANG_MCALL convert(IArtifact* from, const ArtifactDesc& to, IArtifact** outArtifact) = 0;
/// Get the version of this compiler
virtual SLANG_NO_THROW SlangResult SLANG_MCALL getVersionString(slang::IBlob** outVersionString) = 0;
+ /// Validate and return the result
+ virtual SLANG_NO_THROW SlangResult SLANG_MCALL validate(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;
@@ -327,6 +329,7 @@ public:
virtual SLANG_NO_THROW bool SLANG_MCALL canConvert(const ArtifactDesc& from, const ArtifactDesc& to) SLANG_OVERRIDE { SLANG_UNUSED(from); SLANG_UNUSED(to); return false; }
virtual SLANG_NO_THROW SlangResult SLANG_MCALL convert(IArtifact* from, const ArtifactDesc& to, IArtifact** outArtifact) SLANG_OVERRIDE;
virtual SLANG_NO_THROW SlangResult SLANG_MCALL getVersionString(slang::IBlob** outVersionString) SLANG_OVERRIDE { *outVersionString = nullptr; return SLANG_FAIL; }
+ virtual SLANG_NO_THROW SlangResult SLANG_MCALL validate(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 e0a537757..9ef8e7fb4 100644
--- a/source/compiler-core/slang-glslang-compiler.cpp
+++ b/source/compiler-core/slang-glslang-compiler.cpp
@@ -48,6 +48,7 @@ public:
virtual SLANG_NO_THROW SlangResult SLANG_MCALL convert(IArtifact* from, const ArtifactDesc& to, IArtifact** outArtifact) SLANG_OVERRIDE;
virtual SLANG_NO_THROW bool SLANG_MCALL isFileBased() SLANG_OVERRIDE { return false; }
virtual SLANG_NO_THROW SlangResult SLANG_MCALL getVersionString(slang::IBlob** outVersionString) SLANG_OVERRIDE;
+ virtual SLANG_NO_THROW SlangResult SLANG_MCALL validate(const uint32_t* contents, int contentsSize) SLANG_OVERRIDE;
/// Must be called before use
SlangResult init(ISlangSharedLibrary* library);
@@ -61,6 +62,7 @@ protected:
glslang_CompileFunc_1_0 m_compile_1_0 = nullptr;
glslang_CompileFunc_1_1 m_compile_1_1 = nullptr;
glslang_CompileFunc_1_2 m_compile_1_2 = nullptr;
+ glslang_ValidateSPIRVFunc m_validate = nullptr;
ComPtr<ISlangSharedLibrary> m_sharedLibrary;
@@ -72,6 +74,7 @@ SlangResult GlslangDownstreamCompiler::init(ISlangSharedLibrary* library)
m_compile_1_0 = (glslang_CompileFunc_1_0)library->findFuncByName("glslang_compile");
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");
if (m_compile_1_0 == nullptr && m_compile_1_1 == nullptr && m_compile_1_2 == nullptr)
@@ -281,6 +284,20 @@ SlangResult GlslangDownstreamCompiler::compile(const CompileOptions& inOptions,
return SLANG_OK;
}
+SlangResult GlslangDownstreamCompiler::validate(const uint32_t* contents, int contentsSize)
+{
+ if (m_validate == nullptr)
+ {
+ return SLANG_FAIL;
+ }
+
+ if (m_validate(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/slang-glslang/slang-glslang.cpp b/source/slang-glslang/slang-glslang.cpp
index cdbc95031..8ae85b631 100644
--- a/source/slang-glslang/slang-glslang.cpp
+++ b/source/slang-glslang/slang-glslang.cpp
@@ -145,6 +145,26 @@ struct SPIRVOptimizationDiagnostic
std::string message;
};
+// Validate the given SPIRV-ASM instructions.
+extern "C"
+#ifdef _MSC_VER
+_declspec(dllexport)
+#else
+__attribute__((__visibility__("default")))
+#endif
+bool glslang_validateSPIRV(const uint32_t* contents, int contentsSize)
+{
+ spv_target_env target_env = SPV_ENV_VULKAN_1_3;
+
+ spvtools::ValidatorOptions options;
+ options.SetScalarBlockLayout(true);
+
+ spvtools::SpirvTools tools(target_env);
+ //tools.SetMessageConsumer(spvtools::utils::CLIMessageConsumer);
+
+ return tools.Validate(contents, contentsSize, options);
+}
+
// 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(spv_target_env targetEnv, const glslang_CompileRequest_1_2& request, std::vector<SPIRVOptimizationDiagnostic>& outDiags, std::vector<unsigned int>& ioSpirv)
diff --git a/source/slang-glslang/slang-glslang.h b/source/slang-glslang/slang-glslang.h
index 68c24d889..00205a114 100644
--- a/source/slang-glslang/slang-glslang.h
+++ b/source/slang-glslang/slang-glslang.h
@@ -147,5 +147,6 @@ inline void glslang_CompileRequest_1_2::set(const glslang_CompileRequest_1_1& in
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);
#endif
diff --git a/source/slang-llvm/slang-llvm.cpp b/source/slang-llvm/slang-llvm.cpp
index 0c14fbeb6..b84a79340 100644
--- a/source/slang-llvm/slang-llvm.cpp
+++ b/source/slang-llvm/slang-llvm.cpp
@@ -121,7 +121,7 @@ using namespace llvm::orc;
using namespace Slang;
-class LLVMDownstreamCompiler : public IDownstreamCompiler, ComBaseObject
+class LLVMDownstreamCompiler : public ComBaseObject, public IDownstreamCompiler
{
public:
typedef ComBaseObject Super;
@@ -139,6 +139,7 @@ public:
virtual SLANG_NO_THROW SlangResult SLANG_MCALL convert(IArtifact* from, const ArtifactDesc& to, IArtifact** outArtifact) SLANG_OVERRIDE;
virtual SLANG_NO_THROW bool SLANG_MCALL isFileBased() SLANG_OVERRIDE { return false; }
virtual SLANG_NO_THROW SlangResult SLANG_MCALL getVersionString(slang::IBlob** outVersionString) SLANG_OVERRIDE;
+ virtual SLANG_NO_THROW SlangResult SLANG_MCALL validate(const uint32_t* contents, int contentsSize) SLANG_OVERRIDE { SLANG_UNUSED(contents); SLANG_UNUSED(contentsSize); return SLANG_FAIL; }
LLVMDownstreamCompiler():
m_desc(SLANG_PASS_THROUGH_LLVM, SemanticVersion(LLVM_VERSION_MAJOR, LLVM_VERSION_MINOR, LLVM_VERSION_PATCH))
diff --git a/source/slang/slang-emit-spirv.cpp b/source/slang/slang-emit-spirv.cpp
index 1040017da..6b84668e3 100644
--- a/source/slang/slang-emit-spirv.cpp
+++ b/source/slang/slang-emit-spirv.cpp
@@ -6576,23 +6576,6 @@ SlangResult emitSPIRVFromIR(
(uint8_t const*) context.m_words.getBuffer(),
context.m_words.getCount() * Index(sizeof(context.m_words[0])));
- StringBuilder runSpirvValEnvVar;
- PlatformUtil::getEnvironmentVariable(UnownedStringSlice("SLANG_RUN_SPIRV_VALIDATION"), runSpirvValEnvVar);
- if (runSpirvValEnvVar.getUnownedSlice() == "1"
- && !codeGenContext->shouldSkipSPIRVValidation())
- {
- const auto validationResult = debugValidateSPIRV(spirvOut);
- // If validation isn't available, don't say it failed, it's just a debug
- // feature so we can skip
- if (SLANG_FAILED(validationResult) && validationResult != SLANG_E_NOT_AVAILABLE)
- {
- codeGenContext->getSink()->diagnoseWithoutSourceView(
- SourceLoc{},
- Diagnostics::spirvValidationFailed
- );
- return validationResult;
- }
- }
return SLANG_OK;
}
diff --git a/source/slang/slang-emit.cpp b/source/slang/slang-emit.cpp
index cb8460173..679d8ce88 100644
--- a/source/slang/slang-emit.cpp
+++ b/source/slang/slang-emit.cpp
@@ -1704,6 +1704,22 @@ SlangResult emitSPIRVForEntryPointsDirectly(
PassThroughMode::SpirvOpt, codeGenContext->getSink());
if (compiler)
{
+ if (!codeGenContext->shouldSkipSPIRVValidation())
+ {
+ StringBuilder runSpirvValEnvVar;
+ PlatformUtil::getEnvironmentVariable(UnownedStringSlice("SLANG_RUN_SPIRV_VALIDATION"), runSpirvValEnvVar);
+ if (runSpirvValEnvVar.getUnownedSlice() == "1")
+ {
+ if (SLANG_FAILED(compiler->validate((uint32_t*)spirv.getBuffer(), int(spirv.getCount()/4))))
+ {
+ codeGenContext->getSink()->diagnoseWithoutSourceView(
+ SourceLoc{},
+ Diagnostics::spirvValidationFailed
+ );
+ }
+ }
+ }
+
ComPtr<IArtifact> optimizedArtifact;
DownstreamCompileOptions downstreamOptions;
downstreamOptions.sourceArtifacts = makeSlice(artifact.readRef(), 1);
diff --git a/source/slang/slang-spirv-val.cpp b/source/slang/slang-spirv-val.cpp
index faacb9c59..585ff5c94 100644
--- a/source/slang/slang-spirv-val.cpp
+++ b/source/slang/slang-spirv-val.cpp
@@ -38,46 +38,5 @@ SlangResult disassembleSPIRV(const List<uint8_t>& spirv, String& outErr, String&
return ret == 0 ? SLANG_OK : SLANG_FAIL;
}
-SlangResult debugValidateSPIRV(const List<uint8_t>& spirv)
-{
- // Set up our process
- CommandLine commandLine;
- commandLine.m_executableLocation.setName("spirv-val");
- commandLine.addArg("--target-env");
- commandLine.addArg("vulkan1.3");
- commandLine.addArg("--scalar-block-layout");
- RefPtr<Process> p;
- const auto createResult = Process::create(commandLine, 0, p);
- // If we failed to even start the process, then validation isn't available
- if(SLANG_FAILED(createResult))
- return SLANG_E_NOT_AVAILABLE;
- const auto in = p->getStream(StdStreamType::In);
- const auto out = p->getStream(StdStreamType::Out);
- const auto err = p->getStream(StdStreamType::ErrorOut);
-
- List<Byte> outData;
- List<Byte> errData;
- SLANG_RETURN_ON_FAIL(StreamUtil::readAndWrite(in, spirv.getArrayView(), out, outData, err, errData));
-
- // Wait for it to finish
- if(!p->waitForTermination(1000))
- return SLANG_FAIL;
-
- // If we failed, dump the spirv first.
- const auto ret = p->getReturnValue();
- if(ret != 0)
- {
- String spirvDisErr;
- String spirvDis;
- disassembleSPIRV(spirv, spirvDisErr, spirvDis);
- fwrite(spirvDisErr.getBuffer(), spirvDisErr.getLength(), 1, stderr);
- fwrite(spirvDis.getBuffer(), spirvDis.getLength(), 1, stderr);
- }
-
- fwrite(outData.getBuffer(), outData.getCount(), 1, stderr);
- fwrite(errData.getBuffer(), errData.getCount(), 1, stderr);
-
- return ret == 0 ? SLANG_OK : SLANG_FAIL;
-}
}
diff --git a/source/slang/slang-spirv-val.h b/source/slang/slang-spirv-val.h
index 7ee55693a..bb0730849 100644
--- a/source/slang/slang-spirv-val.h
+++ b/source/slang/slang-spirv-val.h
@@ -5,7 +5,6 @@
namespace Slang
{
-SlangResult debugValidateSPIRV(const List<uint8_t>& spirv);
SlangResult disassembleSPIRV(const List<uint8_t>& spirv, String& outErr, String& outDis);
}