summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTim Foley <tfoley@nvidia.com>2017-07-13 12:10:08 -0700
committerTim Foley <tfoley@nvidia.com>2017-07-13 13:00:38 -0700
commit6d7be3694fbaae525b2f4463630c35bed487cd5b (patch)
treea9bac151f79bba23df11c90d5906a3009dad29bd
parent4bc59f896c9df970ec27a57c397977fc4721d3cd (diff)
Add support for dumping intermediates for debugging.
Calling: spSetDumpIntermedites(compileRequest, true); will set up a mode where Slang tries to dump every intermediate HLSL, GLSL, DXBC, SPIR-V, etc. file it generates. If SPIR-V or DXBC is requested then we also dump assembly of those. Right now the files are all named as `slang-<counter>.<ext>`, and get dropped in whatever the working directory is, but I'm open to ideas on how to improve that. Note: this change introduces a new binary interface to `glslang`, so pulling it requires an updated `glslang.dll`.
-rw-r--r--slang.h7
-rw-r--r--source/slang/compiler.cpp213
-rw-r--r--source/slang/compiler.h14
-rw-r--r--source/slang/slang.cpp8
-rw-r--r--tools/glslang/glslang.cpp69
-rw-r--r--tools/glslang/glslang.h12
6 files changed, 270 insertions, 53 deletions
diff --git a/slang.h b/slang.h
index 26a8a406f..84dc9d547 100644
--- a/slang.h
+++ b/slang.h
@@ -170,6 +170,13 @@ extern "C"
SlangCompileFlags flags);
/*!
+ @brief Set whether to dump intermediate results (for debugging) or not.
+ */
+ SLANG_API void spSetDumpIntermediates(
+ SlangCompileRequest* request,
+ int enable);
+
+ /*!
@brief Sets the target for code generation.
@param ctx The compilation context.
@param target The code generation target. Possible values are:
diff --git a/source/slang/compiler.cpp b/source/slang/compiler.cpp
index 4c3885ebf..96fccced1 100644
--- a/source/slang/compiler.cpp
+++ b/source/slang/compiler.cpp
@@ -26,6 +26,10 @@
#include <d3dcompiler.h>
#endif
+#ifdef _MSC_VER
+#pragma warning(disable: 4996)
+#endif
+
#ifdef CreateDirectory
#undef CreateDirectory
#endif
@@ -78,8 +82,6 @@ namespace Slang
return Profile::Unknown;
}
-
-
//
String emitHLSLForEntryPoint(
@@ -209,6 +211,7 @@ namespace Slang
}
auto hlslCode = emitHLSLForEntryPoint(entryPoint);
+ maybeDumpIntermediate(entryPoint->compileRequest, hlslCode.Buffer(), CodeGenTarget::HLSL);
ID3DBlob* codeBlob;
ID3DBlob* diagnosticsBlob;
@@ -270,8 +273,10 @@ namespace Slang
}
#endif
- String EmitDXBytecodeAssemblyForEntryPoint(
- EntryPointRequest* entryPoint)
+ String dissassembleDXBC(
+ CompileRequest*,
+ void const* data,
+ size_t size)
{
static pD3DDisassemble D3DDisassemble_ = nullptr;
if (!D3DDisassemble_)
@@ -283,16 +288,15 @@ namespace Slang
assert(D3DDisassemble_);
}
- List<uint8_t> dxbc = EmitDXBytecodeForEntryPoint(entryPoint);
- if (!dxbc.Count())
+ if (!data || !size)
{
return String();
}
ID3DBlob* codeBlob;
HRESULT hr = D3DDisassemble_(
- &dxbc[0],
- dxbc.Count(),
+ data,
+ size,
0,
nullptr,
&codeBlob);
@@ -312,6 +316,21 @@ namespace Slang
return result;
}
+ String EmitDXBytecodeAssemblyForEntryPoint(
+ EntryPointRequest* entryPoint)
+ {
+
+ List<uint8_t> dxbc = EmitDXBytecodeForEntryPoint(entryPoint);
+ if (!dxbc.Count())
+ {
+ return String();
+ }
+
+ String result = dissassembleDXBC(entryPoint->compileRequest, dxbc.Buffer(), dxbc.Count());
+
+ return result;
+ }
+
#if 0
String EmitDXBytecodeAssembly(
ExtraContext& context)
@@ -332,7 +351,6 @@ namespace Slang
}
#endif
-
HMODULE getGLSLCompilerDLL()
{
// TODO(tfoley): let user specify version of glslang DLL to use.
@@ -342,11 +360,11 @@ namespace Slang
return glslCompiler;
}
- int invokeGLSLCompilerForEntryPoint(
- EntryPointRequest* entryPoint,
+
+ int invokeGLSLCompiler(
+ CompileRequest* slangCompileRequest,
glslang_CompileRequest& request)
{
- String rawGLSL = emitGLSLForEntryPoint(entryPoint);
static glslang_CompileFunc glslang_compile = nullptr;
if (!glslang_compile)
@@ -364,10 +382,6 @@ namespace Slang
(*(String*)userData).append((char const*)data, (char const*)data + size);
};
- request.sourcePath = "slang";
- request.sourceText = rawGLSL.begin();
- request.slangStage = (SlangStage)entryPoint->profile.GetStage();
-
request.diagnosticFunc = diagnosticOutputFunc;
request.diagnosticUserData = &diagnosticOutput;
@@ -375,7 +389,7 @@ namespace Slang
if (err)
{
- entryPoint->compileRequest->mSink.diagnoseRaw(
+ slangCompileRequest->mSink.diagnoseRaw(
Severity::Error,
diagnosticOutput.begin());
return err;
@@ -384,54 +398,79 @@ namespace Slang
return 0;
}
-
- List<uint8_t> emitSPIRVForEntryPoint(
- EntryPointRequest* entryPoint)
+ String dissassembleSPIRV(
+ CompileRequest* slangRequest,
+ void const* data,
+ size_t size)
{
- List<uint8_t> output;
+ String output;
auto outputFunc = [](void const* data, size_t size, void* userData)
{
- ((List<uint8_t>*)userData)->AddRange((uint8_t*)data, size);
+ (*(String*)userData).append((char const*)data, (char const*)data + size);
};
glslang_CompileRequest request;
+ request.action = GLSLANG_ACTION_DISSASSEMBLE_SPIRV;
+
+ request.inputBegin = data;
+ request.inputEnd = (char*)data + size;
+
request.outputFunc = outputFunc;
request.outputUserData = &output;
- request.disassembleResult = false;
- int err = invokeGLSLCompilerForEntryPoint(entryPoint, request);
+ int err = invokeGLSLCompiler(slangRequest, request);
if (err)
{
- return List<uint8_t>();
+ String();
}
return output;
}
- String emitSPIRVAssemblyForEntryPoint(
+ List<uint8_t> emitSPIRVForEntryPoint(
EntryPointRequest* entryPoint)
{
- String output;
+ String rawGLSL = emitGLSLForEntryPoint(entryPoint);
+ maybeDumpIntermediate(entryPoint->compileRequest, rawGLSL.Buffer(), CodeGenTarget::GLSL);
+
+ List<uint8_t> output;
auto outputFunc = [](void const* data, size_t size, void* userData)
{
- (*(String*)userData).append((char const*)data, (char const*)data + size);
+ ((List<uint8_t>*)userData)->AddRange((uint8_t*)data, size);
};
glslang_CompileRequest request;
+ request.action = GLSLANG_ACTION_COMPILE_GLSL_TO_SPIRV;
+ request.sourcePath = "slang";
+ request.slangStage = (SlangStage)entryPoint->profile.GetStage();
+
+ request.inputBegin = rawGLSL.begin();
+ request.inputEnd = rawGLSL.end();
+
request.outputFunc = outputFunc;
request.outputUserData = &output;
- request.disassembleResult = true;
- int err = invokeGLSLCompilerForEntryPoint(entryPoint, request);
+ int err = invokeGLSLCompiler(entryPoint->compileRequest, request);
if (err)
{
- String();
+ return List<uint8_t>();
}
return output;
}
+
+ String emitSPIRVAssemblyForEntryPoint(
+ EntryPointRequest* entryPoint)
+ {
+ List<uint8_t> spirv = emitSPIRVForEntryPoint(entryPoint);
+ if (spirv.Count() == 0)
+ return String();
+
+ String result = dissassembleSPIRV(entryPoint->compileRequest, spirv.begin(), spirv.Count());
+ return result;
+ }
#endif
#if 0
@@ -461,12 +500,14 @@ namespace Slang
CompileResult result;
auto compileRequest = entryPoint->compileRequest;
+ auto target = compileRequest->Target;
- switch (compileRequest->Target)
+ switch (target)
{
case CodeGenTarget::HLSL:
{
String code = emitHLSLForEntryPoint(entryPoint);
+ maybeDumpIntermediate(compileRequest, code.Buffer(), target);
result = CompileResult(code);
}
break;
@@ -474,6 +515,7 @@ namespace Slang
case CodeGenTarget::GLSL:
{
String code = emitGLSLForEntryPoint(entryPoint);
+ maybeDumpIntermediate(compileRequest, code.Buffer(), target);
result = CompileResult(code);
}
break;
@@ -481,6 +523,7 @@ namespace Slang
case CodeGenTarget::DXBytecode:
{
List<uint8_t> code = EmitDXBytecodeForEntryPoint(entryPoint);
+ maybeDumpIntermediate(compileRequest, code.Buffer(), code.Count(), target);
result = CompileResult(code);
}
break;
@@ -488,6 +531,7 @@ namespace Slang
case CodeGenTarget::DXBytecodeAssembly:
{
String code = EmitDXBytecodeAssemblyForEntryPoint(entryPoint);
+ maybeDumpIntermediate(compileRequest, code.Buffer(), target);
result = CompileResult(code);
}
break;
@@ -495,6 +539,7 @@ namespace Slang
case CodeGenTarget::SPIRV:
{
List<uint8_t> code = emitSPIRVForEntryPoint(entryPoint);
+ maybeDumpIntermediate(compileRequest, code.Buffer(), code.Count(), target);
result = CompileResult(code);
}
break;
@@ -502,6 +547,7 @@ namespace Slang
case CodeGenTarget::SPIRVAssembly:
{
String code = emitSPIRVAssemblyForEntryPoint(entryPoint);
+ maybeDumpIntermediate(compileRequest, code.Buffer(), target);
result = CompileResult(code);
}
break;
@@ -604,4 +650,107 @@ namespace Slang
}
+ // Debug logic for dumping intermediate outputs
+
+ //
+
+ void dumpIntermediate(
+ CompileRequest*,
+ void const* data,
+ size_t size,
+ char const* ext,
+ bool isBinary)
+ {
+ static int counter = 0;
+ int id = counter++;
+
+ String path;
+ path.append("slang-");
+ path.append(id);
+ path.append(ext);
+
+ FILE* file = fopen(path.Buffer(), isBinary ? "wb" : "w");
+ if (!file) return;
+
+ fwrite(data, size, 1, file);
+ fclose(file);
+ }
+
+ void dumpIntermediateText(
+ CompileRequest* compileRequest,
+ void const* data,
+ size_t size,
+ char const* ext)
+ {
+ dumpIntermediate(compileRequest, data, size, ext, false);
+ }
+
+ void dumpIntermediateBinary(
+ CompileRequest* compileRequest,
+ void const* data,
+ size_t size,
+ char const* ext)
+ {
+ dumpIntermediate(compileRequest, data, size, ext, true);
+ }
+
+ void maybeDumpIntermediate(
+ CompileRequest* compileRequest,
+ void const* data,
+ size_t size,
+ CodeGenTarget target)
+ {
+ if (!compileRequest->shouldDumpIntermediates)
+ return;
+
+ switch (target)
+ {
+ default:
+ break;
+
+ case CodeGenTarget::HLSL:
+ dumpIntermediateText(compileRequest, data, size, ".hlsl");
+ break;
+
+ case CodeGenTarget::GLSL:
+ dumpIntermediateText(compileRequest, data, size, ".glsl");
+ break;
+
+ case CodeGenTarget::SPIRVAssembly:
+ dumpIntermediateText(compileRequest, data, size, ".spv.asm");
+ break;
+
+ case CodeGenTarget::DXBytecodeAssembly:
+ dumpIntermediateText(compileRequest, data, size, ".dxbc.asm");
+ break;
+
+ case CodeGenTarget::SPIRV:
+ dumpIntermediateBinary(compileRequest, data, size, ".spv");
+ {
+ String spirvAssembly = dissassembleSPIRV(compileRequest, data, size);
+ dumpIntermediateText(compileRequest, spirvAssembly.begin(), spirvAssembly.Length(), ".spv.asm");
+ }
+ break;
+
+ case CodeGenTarget::DXBytecode:
+ dumpIntermediateBinary(compileRequest, data, size, ".dxbc");
+ {
+ String dxbcAssembly = dissassembleDXBC(compileRequest, data, size);
+ dumpIntermediateText(compileRequest, dxbcAssembly.begin(), dxbcAssembly.Length(), ".dxbc.asm");
+ }
+ break;
+ }
+ }
+
+ void maybeDumpIntermediate(
+ CompileRequest* compileRequest,
+ char const* text,
+ CodeGenTarget target)
+ {
+ if (!compileRequest->shouldDumpIntermediates)
+ return;
+
+ maybeDumpIntermediate(compileRequest, text, strlen(text), target);
+ }
+
}
diff --git a/source/slang/compiler.h b/source/slang/compiler.h
index 2b440ad85..a7d104b5f 100644
--- a/source/slang/compiler.h
+++ b/source/slang/compiler.h
@@ -207,6 +207,9 @@ namespace Slang
// Compile flags to be shared by all translation units
SlangCompileFlags compileFlags = 0;
+ // Should we dump intermediate results along the way, for debugging?
+ bool shouldDumpIntermediates = false;
+
// Output stuff
DiagnosticSink mSink;
String mDiagnosticOutput;
@@ -277,6 +280,17 @@ namespace Slang
void generateOutput(
CompileRequest* compileRequest);
+
+ // Helper to dump intermediate output when debugging
+ void maybeDumpIntermediate(
+ CompileRequest* compileRequest,
+ void const* data,
+ size_t size,
+ CodeGenTarget target);
+ void maybeDumpIntermediate(
+ CompileRequest* compileRequest,
+ char const* text,
+ CodeGenTarget target);
}
#endif \ No newline at end of file
diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp
index bfc499c1b..89db62ec8 100644
--- a/source/slang/slang.cpp
+++ b/source/slang/slang.cpp
@@ -668,6 +668,14 @@ SLANG_API void spSetCompileFlags(
REQ(request)->compileFlags = flags;
}
+SLANG_API void spSetDumpIntermediates(
+ SlangCompileRequest* request,
+ int enable)
+{
+ REQ(request)->shouldDumpIntermediates = enable != 0;
+}
+
+
SLANG_API void spSetCodeGenTarget(
SlangCompileRequest* request,
int target)
diff --git a/tools/glslang/glslang.cpp b/tools/glslang/glslang.cpp
index f07937b97..98bcf14d6 100644
--- a/tools/glslang/glslang.cpp
+++ b/tools/glslang/glslang.cpp
@@ -78,12 +78,8 @@ static void dumpDiagnostics(
dump(log.c_str(), log.length(), request->diagnosticFunc, request->diagnosticUserData, stderr);
}
-extern "C"
-_declspec(dllexport)
-int glslang_compile(glslang_CompileRequest* request)
+static int glslang_compileGLSLToSPIRV(glslang_CompileRequest* request)
{
- glslang::InitializeProcess();
-
EShLanguage glslangStage;
switch( request->slangStage )
{
@@ -109,12 +105,15 @@ int glslang_compile(glslang_CompileRequest* request)
glslang::TProgram* program = new glslang::TProgram();
auto programPtr = std::unique_ptr<glslang::TProgram>(program);
- int sourceTextLength = (int) strlen(request->sourceText);
+ char const* sourceText = (char const*)request->inputBegin;
+ char const* sourceTextEnd = (char const*)request->inputEnd;
+
+ int sourceTextLength = (int)(sourceTextEnd - sourceText);
shader->setPreamble("#extension GL_GOOGLE_cpp_style_line_directive : require\n");
shader->setStringsWithLengthsAndNames(
- &request->sourceText,
+ &sourceText,
&sourceTextLength,
&request->sourcePath,
1);
@@ -163,20 +162,52 @@ int glslang_compile(glslang_CompileRequest* request)
dumpDiagnostics(request, logger.getAllMessages());
- if (request->disassembleResult)
- {
- std::stringstream spirvAsmStream;
- spv::Disassemble(spirvAsmStream, spirv);
- std::string result = spirvAsmStream.str();
- dump(result.c_str(), result.length(), request->outputFunc, request->outputUserData, stdout);
- }
- else
- {
- dump(spirv.data(), spirv.size() * sizeof(unsigned int), request->outputFunc, request->outputUserData, stdout);
- }
+ dump(spirv.data(), spirv.size() * sizeof(unsigned int), request->outputFunc, request->outputUserData, stdout);
}
- glslang::FinalizeProcess();
+ return 0;
+}
+
+static int glslang_dissassembleSPIRV(glslang_CompileRequest* request)
+{
+ typedef unsigned int SPIRVWord;
+
+ SPIRVWord const* spirvBegin = (SPIRVWord const*)request->inputBegin;
+ SPIRVWord const* spirvEnd = (SPIRVWord const*)request->inputEnd;
+
+ std::vector<SPIRVWord> spirv(spirvBegin, spirvEnd);
+
+ std::stringstream spirvAsmStream;
+ spv::Disassemble(spirvAsmStream, spirv);
+ std::string result = spirvAsmStream.str();
+ dump(result.c_str(), result.length(), request->outputFunc, request->outputUserData, stdout);
return 0;
}
+
+extern "C"
+_declspec(dllexport)
+int glslang_compile(glslang_CompileRequest* request)
+{
+ glslang::InitializeProcess();
+
+ int result = 0;
+ switch(request->action)
+ {
+ default:
+ result = 1;
+ break;
+
+ case GLSLANG_ACTION_COMPILE_GLSL_TO_SPIRV:
+ result = glslang_compileGLSLToSPIRV(request);
+ break;
+
+ case GLSLANG_ACTION_DISSASSEMBLE_SPIRV:
+ result = glslang_dissassembleSPIRV(request);
+ break;
+ }
+
+ glslang::FinalizeProcess();
+
+ return result;
+}
diff --git a/tools/glslang/glslang.h b/tools/glslang/glslang.h
index 8686f019e..f02d43882 100644
--- a/tools/glslang/glslang.h
+++ b/tools/glslang/glslang.h
@@ -4,10 +4,18 @@
typedef void (*glslang_OutputFunc)(void const* data, size_t size, void* userData);
+enum
+{
+ GLSLANG_ACTION_COMPILE_GLSL_TO_SPIRV,
+ GLSLANG_ACTION_DISSASSEMBLE_SPIRV,
+};
+
struct glslang_CompileRequest
{
char const* sourcePath;
- char const* sourceText;
+
+ void const* inputBegin;
+ void const* inputEnd;
glslang_OutputFunc diagnosticFunc;
void* diagnosticUserData;
@@ -17,7 +25,7 @@ struct glslang_CompileRequest
int slangStage;
- bool disassembleResult;
+ unsigned action;
};
typedef int (*glslang_CompileFunc)(glslang_CompileRequest* request);