Skip to content

Commit

Permalink
Merge pull request #911 from KhronosGroup/debug-info
Browse files Browse the repository at this point in the history
SPV: Add OpSource shader source code and file name.
  • Loading branch information
johnkslang committed Jun 1, 2017
2 parents 136b1e2 + e485c7a commit 44d2728
Show file tree
Hide file tree
Showing 12 changed files with 500 additions and 39 deletions.
55 changes: 43 additions & 12 deletions SPIRV/GlslangToSpv.cpp
Expand Up @@ -101,7 +101,7 @@ class SpecConstantOpModeGuard {
//
class TGlslangToSpvTraverser : public glslang::TIntermTraverser {
public:
TGlslangToSpvTraverser(const glslang::TIntermediate*, spv::SpvBuildLogger* logger);
TGlslangToSpvTraverser(const glslang::TIntermediate*, spv::SpvBuildLogger* logger, glslang::SpvOptions& options);
virtual ~TGlslangToSpvTraverser() { }

bool visitAggregate(glslang::TVisit, glslang::TIntermAggregate*);
Expand Down Expand Up @@ -179,6 +179,7 @@ class TGlslangToSpvTraverser : public glslang::TIntermTraverser {
spv::Id createShortCircuit(glslang::TOperator, glslang::TIntermTyped& left, glslang::TIntermTyped& right);
spv::Id getExtBuiltins(const char* name);

glslang::SpvOptions& options;
spv::Function* shaderEntry;
spv::Function* currentFunction;
spv::Instruction* entryPoint;
Expand Down Expand Up @@ -851,8 +852,11 @@ bool HasNonLayoutQualifiers(const glslang::TType& type, const glslang::TQualifie
// Implement the TGlslangToSpvTraverser class.
//

TGlslangToSpvTraverser::TGlslangToSpvTraverser(const glslang::TIntermediate* glslangIntermediate, spv::SpvBuildLogger* buildLogger)
: TIntermTraverser(true, false, true), shaderEntry(nullptr), currentFunction(nullptr),
TGlslangToSpvTraverser::TGlslangToSpvTraverser(const glslang::TIntermediate* glslangIntermediate,
spv::SpvBuildLogger* buildLogger, glslang::SpvOptions& options)
: TIntermTraverser(true, false, true),
options(options),
shaderEntry(nullptr), currentFunction(nullptr),
sequenceDepth(0), logger(buildLogger),
builder((glslang::GetKhronosToolId() << 16) | GeneratorVersion, logger),
inEntryPoint(false), entryPointTerminated(false), linkageOnly(false),
Expand All @@ -862,6 +866,11 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(const glslang::TIntermediate* gls

builder.clearAccessChain();
builder.setSource(TranslateSourceLanguage(glslangIntermediate->getSource(), glslangIntermediate->getProfile()), glslangIntermediate->getVersion());
if (options.generateDebugInfo) {
builder.setSourceFile(glslangIntermediate->getSourceFile());
builder.setSourceText(glslangIntermediate->getSourceText());
builder.setEmitOpLines();
}
stdBuiltins = builder.import("GLSL.std.450");
builder.setMemoryModel(spv::AddressingModelLogical, spv::MemoryModelGLSL450);
shaderEntry = builder.makeEntryPoint(glslangIntermediate->getEntryPointName().c_str());
Expand Down Expand Up @@ -1069,6 +1078,8 @@ void TGlslangToSpvTraverser::visitSymbol(glslang::TIntermSymbol* symbol)

bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::TIntermBinary* node)
{
builder.setLine(node->getLoc().line);

SpecConstantOpModeGuard spec_constant_op_mode_setter(&builder);
if (node->getType().getQualifier().isSpecConstant())
spec_constant_op_mode_setter.turnOnSpecConstantOpMode();
Expand Down Expand Up @@ -1256,6 +1267,8 @@ bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::T

bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TIntermUnary* node)
{
builder.setLine(node->getLoc().line);

SpecConstantOpModeGuard spec_constant_op_mode_setter(&builder);
if (node->getType().getQualifier().isSpecConstant())
spec_constant_op_mode_setter.turnOnSpecConstantOpMode();
Expand Down Expand Up @@ -1499,6 +1512,7 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
return false;
case glslang::EOpFunctionCall:
{
builder.setLine(node->getLoc().line);
if (node->isUserDefined())
result = handleUserFunctionCall(node);
// assert(result); // this can happen for bad shaders because the call graph completeness checking is not yet done
Expand Down Expand Up @@ -1605,6 +1619,7 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
case glslang::EOpConstructStruct:
case glslang::EOpConstructTextureSampler:
{
builder.setLine(node->getLoc().line);
std::vector<spv::Id> arguments;
translateArguments(*node, arguments);
spv::Id constructed;
Expand Down Expand Up @@ -1715,6 +1730,7 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
right->traverse(this);
spv::Id rightId = accessChainLoad(right->getType());

builder.setLine(node->getLoc().line);
result = createBinaryOperation(binOp, precision, TranslateNoContractionDecoration(node->getType().getQualifier()),
resultType(), leftId, rightId,
left->getType().getBasicType(), reduceComparison);
Expand Down Expand Up @@ -1787,10 +1803,13 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
glslangOperands[arg]->traverse(this);
if (lvalue)
operands.push_back(builder.accessChainGetLValue());
else
else {
builder.setLine(node->getLoc().line);
operands.push_back(accessChainLoad(glslangOperands[arg]->getAsTyped()->getType()));
}
}

builder.setLine(node->getLoc().line);
if (atomic) {
// Handle all atomics
result = createAtomicOperation(node->getOp(), precision, resultType(), operands, node->getBasicType());
Expand Down Expand Up @@ -1872,6 +1891,8 @@ bool TGlslangToSpvTraverser::visitSelection(glslang::TVisit /* visit */, glslang
node->getFalseBlock()->traverse(this);
spv::Id falseValue = accessChainLoad(node->getTrueBlock()->getAsTyped()->getType());

builder.setLine(node->getLoc().line);

// smear condition to vector, if necessary (AST is always scalar)
if (builder.isVector(trueValue))
condition = builder.smearScalar(spv::NoPrecision, condition,
Expand Down Expand Up @@ -2014,6 +2035,7 @@ bool TGlslangToSpvTraverser::visitLoop(glslang::TVisit /* visit */, glslang::TIn
// by a block-ending branch. But we don't want to put any other body/test
// instructions in it, since the body/test may have arbitrary instructions,
// including merges of its own.
builder.setLine(node->getLoc().line);
builder.setBuildPoint(&blocks.head);
builder.createLoopMerge(&blocks.merge, &blocks.continue_target, control);
if (node->testFirst() && node->getTest()) {
Expand All @@ -2022,8 +2044,7 @@ bool TGlslangToSpvTraverser::visitLoop(glslang::TVisit /* visit */, glslang::TIn

builder.setBuildPoint(&test);
node->getTest()->traverse(this);
spv::Id condition =
accessChainLoad(node->getTest()->getType());
spv::Id condition = accessChainLoad(node->getTest()->getType());
builder.createConditionalBranch(condition, &blocks.body, &blocks.merge);

builder.setBuildPoint(&blocks.body);
Expand All @@ -2038,6 +2059,7 @@ bool TGlslangToSpvTraverser::visitLoop(glslang::TVisit /* visit */, glslang::TIn
node->getTerminal()->traverse(this);
builder.createBranch(&blocks.head);
} else {
builder.setLine(node->getLoc().line);
builder.createBranch(&blocks.body);

breakForLoop.push(true);
Expand Down Expand Up @@ -2072,6 +2094,8 @@ bool TGlslangToSpvTraverser::visitBranch(glslang::TVisit /* visit */, glslang::T
if (node->getExpression())
node->getExpression()->traverse(this);

builder.setLine(node->getLoc().line);

switch (node->getFlowOp()) {
case glslang::EOpKill:
builder.makeDiscard();
Expand Down Expand Up @@ -3049,9 +3073,11 @@ void TGlslangToSpvTraverser::translateArguments(glslang::TIntermUnary& node, std

spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermOperator* node)
{
if (! node->isImage() && ! node->isTexture()) {
if (! node->isImage() && ! node->isTexture())
return spv::NoResult;
}

builder.setLine(node->getLoc().line);

auto resultType = [&node,this]{ return convertGlslangToSpvType(node->getType()); };

// Process a GLSL texturing op (will be SPV image)
Expand Down Expand Up @@ -5561,22 +5587,27 @@ void OutputSpvHex(const std::vector<unsigned int>& spirv, const char* baseName,
//
// Set up the glslang traversal
//
void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv)
void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv, SpvOptions* options)
{
spv::SpvBuildLogger logger;
GlslangToSpv(intermediate, spirv, &logger);
GlslangToSpv(intermediate, spirv, &logger, options);
}

void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv, spv::SpvBuildLogger* logger)
void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv,
spv::SpvBuildLogger* logger, SpvOptions* options)
{
TIntermNode* root = intermediate.getTreeRoot();

if (root == 0)
return;

glslang::SpvOptions defaultOptions;
if (options == nullptr)
options = &defaultOptions;

glslang::GetThreadPoolAllocator().push();

TGlslangToSpvTraverser it(&intermediate, logger);
TGlslangToSpvTraverser it(&intermediate, logger, *options);
root->traverse(&it);
it.finishSpv();
it.dumpSpv(spirv);
Expand Down
11 changes: 9 additions & 2 deletions SPIRV/GlslangToSpv.h
Expand Up @@ -47,9 +47,16 @@

namespace glslang {

struct SpvOptions {
SpvOptions() : generateDebugInfo(false) { }
bool generateDebugInfo;
};

void GetSpirvVersion(std::string&);
void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv);
void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv, spv::SpvBuildLogger* logger);
void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv,
SpvOptions* options = nullptr);
void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv,
spv::SpvBuildLogger* logger, SpvOptions* options = nullptr);
void OutputSpvBin(const std::vector<unsigned int>& spirv, const char* baseName);
void OutputSpvHex(const std::vector<unsigned int>& spirv, const char* baseName, const char* varName);

Expand Down
84 changes: 67 additions & 17 deletions SPIRV/SpvBuilder.cpp
Expand Up @@ -59,6 +59,9 @@ namespace spv {
Builder::Builder(unsigned int magicNumber, SpvBuildLogger* buildLogger) :
source(SourceLanguageUnknown),
sourceVersion(0),
sourceFileStringId(NoResult),
currentLine(0),
emitOpLines(false),
addressModel(AddressingModelLogical),
memoryModel(MemoryModelGLSL450),
builderNumber(magicNumber),
Expand All @@ -84,6 +87,26 @@ Id Builder::import(const char* name)
return import->getResultId();
}

// Emit an OpLine if we've been asked to emit OpLines and the line number
// has changed since the last time, and is a valid line number.
void Builder::setLine(int lineNum)
{
if (lineNum != 0 && lineNum != currentLine) {
currentLine = lineNum;
if (emitOpLines)
addLine(sourceFileStringId, currentLine, 0);
}
}

void Builder::addLine(Id fileName, int lineNum, int column)
{
Instruction* line = new Instruction(OpLine);
line->addIdOperand(fileName);
line->addImmediateOperand(lineNum);
line->addImmediateOperand(column);
buildPoint->addInstruction(std::unique_ptr<Instruction>(line));
}

// For creating new groupedTypes (will return old type if the requested one was already made).
Id Builder::makeVoidType()
{
Expand Down Expand Up @@ -928,17 +951,6 @@ void Builder::addMemberName(Id id, int memberNumber, const char* string)
names.push_back(std::unique_ptr<Instruction>(name));
}

void Builder::addLine(Id target, Id fileName, int lineNum, int column)
{
Instruction* line = new Instruction(OpLine);
line->addIdOperand(target);
line->addIdOperand(fileName);
line->addImmediateOperand(lineNum);
line->addImmediateOperand(column);

lines.push_back(std::unique_ptr<Instruction>(line));
}

void Builder::addDecoration(Id id, Decoration decoration, int num)
{
if (decoration == spv::DecorationMax)
Expand Down Expand Up @@ -2411,12 +2423,8 @@ void Builder::dump(std::vector<unsigned int>& out) const
dumpInstructions(out, executionModes);

// Debug instructions
if (source != SourceLanguageUnknown) {
Instruction sourceInst(0, 0, OpSource);
sourceInst.addImmediateOperand(source);
sourceInst.addImmediateOperand(sourceVersion);
sourceInst.dump(out);
}
dumpInstructions(out, strings);
dumpSourceInstructions(out);
for (int e = 0; e < (int)sourceExtensions.size(); ++e) {
Instruction sourceExtInst(0, 0, OpSourceExtension);
sourceExtInst.addStringOperand(sourceExtensions[e]);
Expand Down Expand Up @@ -2574,6 +2582,48 @@ void Builder::createConditionalBranch(Id condition, Block* thenBlock, Block* els
elseBlock->addPredecessor(buildPoint);
}

// OpSource
// [OpSourceContinued]
// ...
void Builder::dumpSourceInstructions(std::vector<unsigned int>& out) const
{
const int maxWordCount = 0xFFFF;
const int opSourceWordCount = 4;
const int nonNullBytesPerInstruction = 4 * (maxWordCount - opSourceWordCount) - 1;

if (source != SourceLanguageUnknown) {
// OpSource Language Version File Source
Instruction sourceInst(NoResult, NoType, OpSource);
sourceInst.addImmediateOperand(source);
sourceInst.addImmediateOperand(sourceVersion);
// File operand
if (sourceFileStringId != NoResult) {
sourceInst.addIdOperand(sourceFileStringId);
// Source operand
if (sourceText.size() > 0) {
int nextByte = 0;
std::string subString;
while ((int)sourceText.size() - nextByte > 0) {
subString = sourceText.substr(nextByte, nonNullBytesPerInstruction);
if (nextByte == 0) {
// OpSource
sourceInst.addStringOperand(subString.c_str());
sourceInst.dump(out);
} else {
// OpSourcContinued
Instruction sourceContinuedInst(OpSourceContinued);
sourceContinuedInst.addStringOperand(subString.c_str());
sourceContinuedInst.dump(out);
}
nextByte += nonNullBytesPerInstruction;
}
} else
sourceInst.dump(out);
} else
sourceInst.dump(out);
}
}

void Builder::dumpInstructions(std::vector<unsigned int>& out, const std::vector<std::unique_ptr<Instruction> >& instructions) const
{
for (int i = 0; i < (int)instructions.size(); ++i) {
Expand Down
24 changes: 22 additions & 2 deletions SPIRV/SpvBuilder.h
Expand Up @@ -70,7 +70,16 @@ class Builder {
source = lang;
sourceVersion = version;
}
void setSourceFile(const std::string& file)
{
Instruction* fileString = new Instruction(getUniqueId(), NoType, OpString);
fileString->addStringOperand(file.c_str());
sourceFileStringId = fileString->getResultId();
strings.push_back(std::unique_ptr<Instruction>(fileString));
}
void setSourceText(const std::string& text) { sourceText = text; }
void addSourceExtension(const char* ext) { sourceExtensions.push_back(ext); }
void setEmitOpLines() { emitOpLines = true; }
void addExtension(const char* ext) { extensions.insert(ext); }
Id import(const char*);
void setMemoryModel(spv::AddressingModel addr, spv::MemoryModel mem)
Expand All @@ -92,6 +101,12 @@ class Builder {
return id;
}

// Log the current line, and if different than the last one,
// issue a new OpLine, using the current file name.
void setLine(int line);
// Low-level OpLine. See setLine() for a layered helper.
void addLine(Id fileName, int line, int column);

// For creating new types (will return old type if the requested one was already made).
Id makeVoidType();
Id makeBoolType();
Expand Down Expand Up @@ -213,7 +228,6 @@ class Builder {
void addExecutionMode(Function*, ExecutionMode mode, int value1 = -1, int value2 = -1, int value3 = -1);
void addName(Id, const char* name);
void addMemberName(Id, int member, const char* name);
void addLine(Id target, Id fileName, int line, int column);
void addDecoration(Id, Decoration, int num = -1);
void addMemberDecoration(Id, unsigned int member, Decoration, int num = -1);

Expand Down Expand Up @@ -561,10 +575,15 @@ class Builder {
void simplifyAccessChainSwizzle();
void createAndSetNoPredecessorBlock(const char*);
void createSelectionMerge(Block* mergeBlock, unsigned int control);
void dumpSourceInstructions(std::vector<unsigned int>&) const;
void dumpInstructions(std::vector<unsigned int>&, const std::vector<std::unique_ptr<Instruction> >&) const;

SourceLanguage source;
int sourceVersion;
spv::Id sourceFileStringId;
std::string sourceText;
int currentLine;
bool emitOpLines;
std::set<std::string> extensions;
std::vector<const char*> sourceExtensions;
AddressingModel addressModel;
Expand All @@ -579,6 +598,7 @@ class Builder {
AccessChain accessChain;

// special blocks of instructions for output
std::vector<std::unique_ptr<Instruction> > strings;
std::vector<std::unique_ptr<Instruction> > imports;
std::vector<std::unique_ptr<Instruction> > entryPoints;
std::vector<std::unique_ptr<Instruction> > executionModes;
Expand All @@ -599,7 +619,7 @@ class Builder {
// Our loop stack.
std::stack<LoopBlocks> loops;

// The stream for outputing warnings and errors.
// The stream for outputting warnings and errors.
SpvBuildLogger* logger;
}; // end Builder class

Expand Down

0 comments on commit 44d2728

Please sign in to comment.