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