Commit 0d6791c2 by Ben Clayton

SpirvShader: Add WriteCFGGraphVizDotFile debug function

Spits out a graphviz .dot file describing the control flow of the shader. This is very similar to the output of the spirv-cfg tool in SPIRV-Tools. This is just much easier to use, and allows us to add more bespoke information to the graph in the future. Bug: b/140287657 Change-Id: Id90b065a3599b941b192a5e8105dffac9ba8f566 Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/32952 Kokoro-Result: kokoro <noreply+kokoro@google.com> Reviewed-by: 's avatarNicolas Capens <nicolascapens@google.com> Tested-by: 's avatarBen Clayton <bclayton@google.com>
parent e41e86d0
...@@ -730,6 +730,14 @@ SpirvShader::SpirvShader( ...@@ -730,6 +730,14 @@ SpirvShader::SpirvShader(
it.second.AssignBlockFields(); it.second.AssignBlockFields();
} }
#ifdef SPIRV_SHADER_CFG_GRAPHVIZ_DOT_FILEPATH
{
char path[1024];
snprintf(path, sizeof(path), SPIRV_SHADER_CFG_GRAPHVIZ_DOT_FILEPATH, codeSerialID);
WriteCFGGraphVizDotFile(path);
}
#endif
dbgCreateFile(); dbgCreateFile();
} }
......
...@@ -1214,6 +1214,10 @@ private: ...@@ -1214,6 +1214,10 @@ private:
// Helper for calling rr::Yield with res cast to an rr::Int. // Helper for calling rr::Yield with res cast to an rr::Int.
void Yield(YieldResult res) const; void Yield(YieldResult res) const;
// WriteCFGGraphVizDotFile() writes a graphviz dot file of the shader's
// control flow to the given file path.
void WriteCFGGraphVizDotFile(const char *path) const;
// OpcodeName() returns the name of the opcode op. // OpcodeName() returns the name of the opcode op.
// If NDEBUG is defined, then OpcodeName() will only return the numerical code. // If NDEBUG is defined, then OpcodeName() will only return the numerical code.
static std::string OpcodeName(spv::Op op); static std::string OpcodeName(spv::Op op);
......
...@@ -23,6 +23,9 @@ ...@@ -23,6 +23,9 @@
#include <queue> #include <queue>
#include <fstream>
#include <iostream>
namespace sw { namespace sw {
SpirvShader::Block::Block(InsnIterator begin, InsnIterator end) SpirvShader::Block::Block(InsnIterator begin, InsnIterator end)
...@@ -729,4 +732,83 @@ void SpirvShader::SetActiveLaneMask(RValue<SIMD::Int> mask, EmitState *state) co ...@@ -729,4 +732,83 @@ void SpirvShader::SetActiveLaneMask(RValue<SIMD::Int> mask, EmitState *state) co
dbgUpdateActiveLaneMask(mask, state); dbgUpdateActiveLaneMask(mask, state);
} }
void SpirvShader::WriteCFGGraphVizDotFile(const char *path) const
{
std::ofstream file(path);
file << "digraph D {" << std::endl;
for(auto &func : functions)
{
file << " subgraph cluster_function_" << func.first.value() << " {"
<< std::endl;
file << " label = \"function<" << func.first.value() << ">"
<< (func.first == entryPoint ? " (entry point)" : "")
<< "\"" << std::endl;
for(auto &block : func.second.blocks)
{
file << " block_" << block.first.value() << " ["
<< "shape=circle "
<< "label=\"" << block.first.value() << "\""
<< "]" << std::endl;
}
file << std::endl;
for(auto &block : func.second.blocks)
{
file << " block_" << block.first.value() << " -> {";
bool first = true;
for(auto outs : block.second.outs)
{
if(!first) { file << ", "; }
file << "block_" << outs.value();
first = false;
}
file << "}" << std::endl;
}
file << std::endl;
for(auto &block : func.second.blocks)
{
if(block.second.kind == Block::Loop)
{
if(block.second.mergeBlock != 0)
{
file << " block_" << block.first.value() << " -> "
<< "block_" << block.second.mergeBlock.value()
<< "[label=\"M\" style=dashed color=blue]"
<< std::endl;
}
if(block.second.continueTarget != 0)
{
file << " block_" << block.first.value() << " -> "
<< "block_" << block.second.continueTarget.value()
<< "[label=\"C\" style=dashed color=green]"
<< std::endl;
}
}
}
file << " }" << std::endl;
}
for(auto &func : functions)
{
for(auto &block : func.second.blocks)
{
for(auto insn : block.second)
{
if(insn.opcode() == spv::OpFunctionCall)
{
auto target = getFunction(insn.word(3)).entry;
file << " block_" << block.first.value() << " -> "
<< "block_" << target.value()
<< "[color=\"#00008050\"]"
<< std::endl;
}
}
}
}
file << "}" << std::endl;
}
} // namespace sw } // namespace sw
\ No newline at end of file
...@@ -20,6 +20,13 @@ ...@@ -20,6 +20,13 @@
// reduced to 1 and execution is deterministic. // reduced to 1 and execution is deterministic.
#define SPIRV_SHADER_ENABLE_DBG 0 #define SPIRV_SHADER_ENABLE_DBG 0
// Enable this to write a GraphViz dot file containing a graph of the shader's
// control flow to the given file path. Helpful for diagnosing control-flow
// related issues.
#if 0
# define SPIRV_SHADER_CFG_GRAPHVIZ_DOT_FILEPATH "swiftshader_%d.dot"
#endif
#if SPIRV_SHADER_ENABLE_DBG #if SPIRV_SHADER_ENABLE_DBG
# define SPIRV_SHADER_DBG(fmt, ...) rr::Print(fmt "\n", ##__VA_ARGS__) # define SPIRV_SHADER_DBG(fmt, ...) rr::Print(fmt "\n", ##__VA_ARGS__)
# include "spirv-tools/libspirv.h" # include "spirv-tools/libspirv.h"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment