SPV: Debug output: Include OpLine information for execution path.
Note that declaratives are not handled, only procedurals.
diff --git a/SPIRV/GlslangToSpv.cpp b/SPIRV/GlslangToSpv.cpp
index a2bd848..e175bfc 100755
--- a/SPIRV/GlslangToSpv.cpp
+++ b/SPIRV/GlslangToSpv.cpp
@@ -869,6 +869,7 @@
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);
@@ -1077,6 +1078,8 @@
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();
@@ -1264,6 +1267,8 @@
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();
@@ -1507,6 +1512,7 @@
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
@@ -1613,6 +1619,7 @@
case glslang::EOpConstructStruct:
case glslang::EOpConstructTextureSampler:
{
+ builder.setLine(node->getLoc().line);
std::vector<spv::Id> arguments;
translateArguments(*node, arguments);
spv::Id constructed;
@@ -1723,6 +1730,7 @@
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);
@@ -1795,10 +1803,13 @@
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());
@@ -1880,6 +1891,8 @@
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,
@@ -2022,6 +2035,7 @@
// 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()) {
@@ -2030,8 +2044,7 @@
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);
@@ -2046,6 +2059,7 @@
node->getTerminal()->traverse(this);
builder.createBranch(&blocks.head);
} else {
+ builder.setLine(node->getLoc().line);
builder.createBranch(&blocks.body);
breakForLoop.push(true);
@@ -2080,6 +2094,8 @@
if (node->getExpression())
node->getExpression()->traverse(this);
+ builder.setLine(node->getLoc().line);
+
switch (node->getFlowOp()) {
case glslang::EOpKill:
builder.makeDiscard();
@@ -3057,9 +3073,11 @@
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)
diff --git a/SPIRV/SpvBuilder.cpp b/SPIRV/SpvBuilder.cpp
index 37c4cb5..ffd17af 100644
--- a/SPIRV/SpvBuilder.cpp
+++ b/SPIRV/SpvBuilder.cpp
@@ -60,6 +60,8 @@
source(SourceLanguageUnknown),
sourceVersion(0),
sourceFileStringId(NoResult),
+ currentLine(0),
+ emitOpLines(false),
addressModel(AddressingModelLogical),
memoryModel(MemoryModelGLSL450),
builderNumber(magicNumber),
@@ -85,6 +87,26 @@
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()
{
@@ -929,17 +951,6 @@
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)
diff --git a/SPIRV/SpvBuilder.h b/SPIRV/SpvBuilder.h
index 42c18b7..60d97e9 100755
--- a/SPIRV/SpvBuilder.h
+++ b/SPIRV/SpvBuilder.h
@@ -79,6 +79,7 @@
}
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)
@@ -100,6 +101,12 @@
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();
@@ -221,7 +228,6 @@
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);
@@ -576,6 +582,8 @@
int sourceVersion;
spv::Id sourceFileStringId;
std::string sourceText;
+ int currentLine;
+ bool emitOpLines;
std::set<std::string> extensions;
std::vector<const char*> sourceExtensions;
AddressingModel addressModel;
diff --git a/Test/baseResults/spv.debugInfo.frag.out b/Test/baseResults/spv.debugInfo.frag.out
index 6e9e208..16f605b 100644
--- a/Test/baseResults/spv.debugInfo.frag.out
+++ b/Test/baseResults/spv.debugInfo.frag.out
@@ -3,12 +3,12 @@
// Module Version 10000
// Generated by (magic number): 80001
-// Id's are bound by 40
+// Id's are bound by 126
Capability Shader
2: ExtInstImport "GLSL.std.450"
MemoryModel Logical GLSL450
- EntryPoint Fragment 5 "main" 17 24
+ EntryPoint Fragment 5 "main" 24 52
ExecutionMode 5 OriginUpperLeft
1: String "spv.debugInfo.frag"
Source GLSL 450 1 "#version 450
@@ -21,79 +21,252 @@
S s;
};
+uniform sampler2D s2d;
+
layout(location = 0) in vec4 inv;
layout(location = 0) out vec4 outv;
-void foo(S s)
+vec4 foo(S s)
{
- outv = s.a * inv;
+ vec4 r = s.a * inv;
+ ++r;
+ if (r.x > 3.0)
+ --r;
+ else
+ r *= 2;
+
+ return r;
}
void main()
{
- foo(s);
+ outv = foo(s);
+ outv += texture(s2d, vec2(0.5));
+
+ switch (s.a) {
+ case 10:
+ ++outv;
+ break;
+ case 20:
+ outv = 2 * outv;
+ ++outv;
+ break;
+ default:
+ --outv;
+ break;
+ }
+
+ for (int i = 0; i < 10; ++i)
+ outv *= 3.0;
+
+ outv.x < 10.0 ?
+ outv = sin(outv) :
+ outv = cos(outv);
}"
Name 5 "main"
Name 8 "S"
MemberName 8(S) 0 "a"
- Name 12 "foo(struct-S-i11;"
- Name 11 "s"
- Name 17 "outv"
+ Name 14 "foo(struct-S-i11;"
+ Name 13 "s"
+ Name 17 "r"
Name 24 "inv"
- Name 27 "S"
- MemberName 27(S) 0 "a"
- Name 28 "ubuf"
- MemberName 28(ubuf) 0 "s"
- Name 30 ""
- Name 31 "S"
- MemberName 31(S) 0 "a"
- Name 33 "param"
- Decorate 17(outv) Location 0
+ Name 52 "outv"
+ Name 53 "S"
+ MemberName 53(S) 0 "a"
+ Name 54 "ubuf"
+ MemberName 54(ubuf) 0 "s"
+ Name 56 ""
+ Name 57 "S"
+ MemberName 57(S) 0 "a"
+ Name 59 "param"
+ Name 69 "s2d"
+ Name 99 "i"
Decorate 24(inv) Location 0
- MemberDecorate 27(S) 0 Offset 0
- MemberDecorate 28(ubuf) 0 Offset 0
- Decorate 28(ubuf) Block
- Decorate 30 DescriptorSet 0
+ Decorate 52(outv) Location 0
+ MemberDecorate 53(S) 0 Offset 0
+ MemberDecorate 54(ubuf) 0 Offset 0
+ Decorate 54(ubuf) Block
+ Decorate 56 DescriptorSet 0
+ Decorate 69(s2d) DescriptorSet 0
3: TypeVoid
4: TypeFunction 3
7: TypeInt 32 1
8(S): TypeStruct 7(int)
9: TypePointer Function 8(S)
- 10: TypeFunction 3 9(ptr)
- 14: TypeFloat 32
- 15: TypeVector 14(float) 4
- 16: TypePointer Output 15(fvec4)
- 17(outv): 16(ptr) Variable Output
+ 10: TypeFloat 32
+ 11: TypeVector 10(float) 4
+ 12: TypeFunction 11(fvec4) 9(ptr)
+ 16: TypePointer Function 11(fvec4)
18: 7(int) Constant 0
19: TypePointer Function 7(int)
- 23: TypePointer Input 15(fvec4)
+ 23: TypePointer Input 11(fvec4)
24(inv): 23(ptr) Variable Input
- 27(S): TypeStruct 7(int)
- 28(ubuf): TypeStruct 27(S)
- 29: TypePointer Uniform 28(ubuf)
- 30: 29(ptr) Variable Uniform
- 31(S): TypeStruct 7(int)
- 32: TypePointer Function 31(S)
- 34: TypePointer Uniform 27(S)
+ 28: 10(float) Constant 1065353216
+ 31: TypeInt 32 0
+ 32: 31(int) Constant 0
+ 33: TypePointer Function 10(float)
+ 36: 10(float) Constant 1077936128
+ 37: TypeBool
+ 45: 10(float) Constant 1073741824
+ 51: TypePointer Output 11(fvec4)
+ 52(outv): 51(ptr) Variable Output
+ 53(S): TypeStruct 7(int)
+ 54(ubuf): TypeStruct 53(S)
+ 55: TypePointer Uniform 54(ubuf)
+ 56: 55(ptr) Variable Uniform
+ 57(S): TypeStruct 7(int)
+ 58: TypePointer Function 57(S)
+ 60: TypePointer Uniform 53(S)
+ 66: TypeImage 10(float) 2D sampled format:Unknown
+ 67: TypeSampledImage 66
+ 68: TypePointer UniformConstant 67
+ 69(s2d): 68(ptr) Variable UniformConstant
+ 71: TypeVector 10(float) 2
+ 72: 10(float) Constant 1056964608
+ 73: 71(fvec2) ConstantComposite 72 72
+ 77: TypePointer Uniform 7(int)
+ 106: 7(int) Constant 10
+ 111: 7(int) Constant 1
+ 114: TypePointer Output 10(float)
+ 117: 10(float) Constant 1092616192
5(main): 3 Function None 4
6: Label
- 33(param): 32(ptr) Variable Function
- 35: 34(ptr) AccessChain 30 18
- 36: 27(S) Load 35
- 37: 7(int) CompositeExtract 36 0
- 38: 19(ptr) AccessChain 33(param) 18
- Store 38 37
- 39: 3 FunctionCall 12(foo(struct-S-i11;) 33(param)
+ 59(param): 58(ptr) Variable Function
+ 99(i): 19(ptr) Variable Function
+ 113: 16(ptr) Variable Function
+ Line 1 30 0
+ 61: 60(ptr) AccessChain 56 18
+ 62: 53(S) Load 61
+ 63: 7(int) CompositeExtract 62 0
+ 64: 19(ptr) AccessChain 59(param) 18
+ Store 64 63
+ 65: 11(fvec4) FunctionCall 14(foo(struct-S-i11;) 59(param)
+ Store 52(outv) 65
+ Line 1 31 0
+ 70: 67 Load 69(s2d)
+ 74: 11(fvec4) ImageSampleImplicitLod 70 73
+ 75: 11(fvec4) Load 52(outv)
+ 76: 11(fvec4) FAdd 75 74
+ Store 52(outv) 76
+ Line 1 33 0
+ 78: 77(ptr) AccessChain 56 18 18
+ 79: 7(int) Load 78
+ SelectionMerge 83 None
+ Switch 79 82
+ case 10: 80
+ case 20: 81
+ 82: Label
+ Line 1 42 0
+ 94: 11(fvec4) Load 52(outv)
+ 95: 11(fvec4) CompositeConstruct 28 28 28 28
+ 96: 11(fvec4) FSub 94 95
+ Store 52(outv) 96
+ Line 1 43 0
+ Branch 83
+ 80: Label
+ Line 1 35 0
+ 84: 11(fvec4) Load 52(outv)
+ 85: 11(fvec4) CompositeConstruct 28 28 28 28
+ 86: 11(fvec4) FAdd 84 85
+ Store 52(outv) 86
+ Line 1 36 0
+ Branch 83
+ 81: Label
+ Line 1 38 0
+ 88: 11(fvec4) Load 52(outv)
+ 89: 11(fvec4) VectorTimesScalar 88 45
+ Store 52(outv) 89
+ Line 1 39 0
+ 90: 11(fvec4) Load 52(outv)
+ 91: 11(fvec4) CompositeConstruct 28 28 28 28
+ 92: 11(fvec4) FAdd 90 91
+ Store 52(outv) 92
+ Line 1 40 0
+ Branch 83
+ 83: Label
+ Line 1 46 0
+ Store 99(i) 18
+ Branch 100
+ 100: Label
+ LoopMerge 102 103 None
+ Branch 104
+ 104: Label
+ 105: 7(int) Load 99(i)
+ 107: 37(bool) SLessThan 105 106
+ BranchConditional 107 101 102
+ 101: Label
+ Line 1 47 0
+ 108: 11(fvec4) Load 52(outv)
+ 109: 11(fvec4) VectorTimesScalar 108 36
+ Store 52(outv) 109
+ Branch 103
+ 103: Label
+ Line 1 46 0
+ 110: 7(int) Load 99(i)
+ 112: 7(int) IAdd 110 111
+ Store 99(i) 112
+ Branch 100
+ 102: Label
+ Line 1 49 0
+ 115: 114(ptr) AccessChain 52(outv) 32
+ 116: 10(float) Load 115
+ 118: 37(bool) FOrdLessThan 116 117
+ SelectionMerge 120 None
+ BranchConditional 118 119 123
+ 119: Label
+ Line 1 50 0
+ 121: 11(fvec4) Load 52(outv)
+ 122: 11(fvec4) ExtInst 2(GLSL.std.450) 13(Sin) 121
+ Store 52(outv) 122
+ Store 113 122
+ Branch 120
+ 123: Label
+ Line 1 51 0
+ 124: 11(fvec4) Load 52(outv)
+ 125: 11(fvec4) ExtInst 2(GLSL.std.450) 14(Cos) 124
+ Store 52(outv) 125
+ Store 113 125
+ Branch 120
+ 120: Label
Return
FunctionEnd
-12(foo(struct-S-i11;): 3 Function None 10
- 11(s): 9(ptr) FunctionParameter
- 13: Label
- 20: 19(ptr) AccessChain 11(s) 18
+14(foo(struct-S-i11;): 11(fvec4) Function None 12
+ 13(s): 9(ptr) FunctionParameter
+ 15: Label
+ 17(r): 16(ptr) Variable Function
+ Line 1 18 0
+ 20: 19(ptr) AccessChain 13(s) 18
21: 7(int) Load 20
- 22: 14(float) ConvertSToF 21
- 25: 15(fvec4) Load 24(inv)
- 26: 15(fvec4) VectorTimesScalar 25 22
- Store 17(outv) 26
- Return
+ 22: 10(float) ConvertSToF 21
+ 25: 11(fvec4) Load 24(inv)
+ 26: 11(fvec4) VectorTimesScalar 25 22
+ Store 17(r) 26
+ Line 1 19 0
+ 27: 11(fvec4) Load 17(r)
+ 29: 11(fvec4) CompositeConstruct 28 28 28 28
+ 30: 11(fvec4) FAdd 27 29
+ Store 17(r) 30
+ Line 1 20 0
+ 34: 33(ptr) AccessChain 17(r) 32
+ 35: 10(float) Load 34
+ 38: 37(bool) FOrdGreaterThan 35 36
+ SelectionMerge 40 None
+ BranchConditional 38 39 44
+ 39: Label
+ Line 1 21 0
+ 41: 11(fvec4) Load 17(r)
+ 42: 11(fvec4) CompositeConstruct 28 28 28 28
+ 43: 11(fvec4) FSub 41 42
+ Store 17(r) 43
+ Branch 40
+ 44: Label
+ Line 1 23 0
+ 46: 11(fvec4) Load 17(r)
+ 47: 11(fvec4) VectorTimesScalar 46 45
+ Store 17(r) 47
+ Branch 40
+ 40: Label
+ Line 1 25 0
+ 48: 11(fvec4) Load 17(r)
+ ReturnValue 48
FunctionEnd
diff --git a/Test/spv.debugInfo.frag b/Test/spv.debugInfo.frag
index e2fc257..3b6cd27 100644
--- a/Test/spv.debugInfo.frag
+++ b/Test/spv.debugInfo.frag
@@ -8,15 +8,45 @@
S s;
};
+uniform sampler2D s2d;
+
layout(location = 0) in vec4 inv;
layout(location = 0) out vec4 outv;
-void foo(S s)
+vec4 foo(S s)
{
- outv = s.a * inv;
+ vec4 r = s.a * inv;
+ ++r;
+ if (r.x > 3.0)
+ --r;
+ else
+ r *= 2;
+
+ return r;
}
void main()
{
- foo(s);
+ outv = foo(s);
+ outv += texture(s2d, vec2(0.5));
+
+ switch (s.a) {
+ case 10:
+ ++outv;
+ break;
+ case 20:
+ outv = 2 * outv;
+ ++outv;
+ break;
+ default:
+ --outv;
+ break;
+ }
+
+ for (int i = 0; i < 10; ++i)
+ outv *= 3.0;
+
+ outv.x < 10.0 ?
+ outv = sin(outv) :
+ outv = cos(outv);
}
\ No newline at end of file