Merge pull request #1379 from LoopDawg/groupid-fix

HLSL: various SPIR-V compute shader IDs must be 3-vectors of integers
diff --git a/Test/baseResults/hlsl.tristream-append.geom.out b/Test/baseResults/hlsl.tristream-append.geom.out
new file mode 100644
index 0000000..2444cfb
--- /dev/null
+++ b/Test/baseResults/hlsl.tristream-append.geom.out
@@ -0,0 +1,212 @@
+hlsl.tristream-append.geom
+Shader version: 500
+invocations = -1
+max_vertices = 3
+input primitive = triangles
+output primitive = triangle_strip
+0:? Sequence
+0:8  Function Definition: EmitVertex(struct-GSPS_INPUT1;struct-GSPS_INPUT1; ( temp void)
+0:8    Function Parameters: 
+0:8      'output' ( in structure{})
+0:8      'TriStream' ( out structure{})
+0:?     Sequence
+0:9      Sequence
+0:9        Sequence
+0:9          move second child to first child ( temp structure{})
+0:9            'TriStream' ( out structure{})
+0:9            'output' ( in structure{})
+0:9        EmitVertex ( temp void)
+0:14  Function Definition: @main(struct-GSPS_INPUT1[3];struct-GSPS_INPUT1; ( temp void)
+0:14    Function Parameters: 
+0:14      'input' ( in 3-element array of structure{})
+0:14      'TriStream' ( out structure{})
+0:?     Sequence
+0:15      Function Call: EmitVertex(struct-GSPS_INPUT1;struct-GSPS_INPUT1; ( temp void)
+0:15        direct index ( temp structure{})
+0:15          'input' ( in 3-element array of structure{})
+0:15          Constant:
+0:15            0 (const int)
+0:15        'TriStream' ( out structure{})
+0:16      Function Call: EmitVertex(struct-GSPS_INPUT1;struct-GSPS_INPUT1; ( temp void)
+0:16        direct index ( temp structure{})
+0:16          'input' ( in 3-element array of structure{})
+0:16          Constant:
+0:16            1 (const int)
+0:16        'TriStream' ( out structure{})
+0:17      Function Call: EmitVertex(struct-GSPS_INPUT1;struct-GSPS_INPUT1; ( temp void)
+0:17        direct index ( temp structure{})
+0:17          'input' ( in 3-element array of structure{})
+0:17          Constant:
+0:17            2 (const int)
+0:17        'TriStream' ( out structure{})
+0:14  Function Definition: main( ( temp void)
+0:14    Function Parameters: 
+0:?     Sequence
+0:14      move second child to first child ( temp 3-element array of structure{})
+0:?         'input' ( temp 3-element array of structure{})
+0:?         'input' ( in 3-element array of structure{})
+0:14      Function Call: @main(struct-GSPS_INPUT1[3];struct-GSPS_INPUT1; ( temp void)
+0:?         'input' ( temp 3-element array of structure{})
+0:?         'TriStream' ( temp structure{})
+0:?   Linker Objects
+
+
+Linked geometry stage:
+
+
+Shader version: 500
+invocations = 1
+max_vertices = 3
+input primitive = triangles
+output primitive = triangle_strip
+0:? Sequence
+0:8  Function Definition: EmitVertex(struct-GSPS_INPUT1;struct-GSPS_INPUT1; ( temp void)
+0:8    Function Parameters: 
+0:8      'output' ( in structure{})
+0:8      'TriStream' ( out structure{})
+0:?     Sequence
+0:9      Sequence
+0:9        Sequence
+0:9          move second child to first child ( temp structure{})
+0:9            'TriStream' ( out structure{})
+0:9            'output' ( in structure{})
+0:9        EmitVertex ( temp void)
+0:14  Function Definition: @main(struct-GSPS_INPUT1[3];struct-GSPS_INPUT1; ( temp void)
+0:14    Function Parameters: 
+0:14      'input' ( in 3-element array of structure{})
+0:14      'TriStream' ( out structure{})
+0:?     Sequence
+0:15      Function Call: EmitVertex(struct-GSPS_INPUT1;struct-GSPS_INPUT1; ( temp void)
+0:15        direct index ( temp structure{})
+0:15          'input' ( in 3-element array of structure{})
+0:15          Constant:
+0:15            0 (const int)
+0:15        'TriStream' ( out structure{})
+0:16      Function Call: EmitVertex(struct-GSPS_INPUT1;struct-GSPS_INPUT1; ( temp void)
+0:16        direct index ( temp structure{})
+0:16          'input' ( in 3-element array of structure{})
+0:16          Constant:
+0:16            1 (const int)
+0:16        'TriStream' ( out structure{})
+0:17      Function Call: EmitVertex(struct-GSPS_INPUT1;struct-GSPS_INPUT1; ( temp void)
+0:17        direct index ( temp structure{})
+0:17          'input' ( in 3-element array of structure{})
+0:17          Constant:
+0:17            2 (const int)
+0:17        'TriStream' ( out structure{})
+0:14  Function Definition: main( ( temp void)
+0:14    Function Parameters: 
+0:?     Sequence
+0:14      move second child to first child ( temp 3-element array of structure{})
+0:?         'input' ( temp 3-element array of structure{})
+0:?         'input' ( in 3-element array of structure{})
+0:14      Function Call: @main(struct-GSPS_INPUT1[3];struct-GSPS_INPUT1; ( temp void)
+0:?         'input' ( temp 3-element array of structure{})
+0:?         'TriStream' ( temp structure{})
+0:?   Linker Objects
+
+// Module Version 10000
+// Generated by (magic number): 80006
+// Id's are bound by 57
+
+                              Capability Geometry
+               1:             ExtInstImport  "GLSL.std.450"
+                              MemoryModel Logical GLSL450
+                              EntryPoint Geometry 4  "main"
+                              ExecutionMode 4 Triangles
+                              ExecutionMode 4 Invocations 1
+                              ExecutionMode 4 OutputTriangleStrip
+                              ExecutionMode 4 OutputVertices 3
+                              Source HLSL 500
+                              Name 4  "main"
+                              Name 6  "GSPS_INPUT"
+                              Name 11  "EmitVertex(struct-GSPS_INPUT1;struct-GSPS_INPUT1;"
+                              Name 9  "output"
+                              Name 10  "TriStream"
+                              Name 20  "@main(struct-GSPS_INPUT1[3];struct-GSPS_INPUT1;"
+                              Name 18  "input"
+                              Name 19  "TriStream"
+                              Name 23  "TriStream"
+                              Name 27  "param"
+                              Name 30  "param"
+                              Name 34  "param"
+                              Name 37  "param"
+                              Name 41  "param"
+                              Name 44  "param"
+                              Name 47  "input"
+                              Name 49  "input"
+                              Name 51  "TriStream"
+                              Name 52  "param"
+                              Name 54  "param"
+               2:             TypeVoid
+               3:             TypeFunction 2
+   6(GSPS_INPUT):             TypeStruct
+               7:             TypePointer Function 6(GSPS_INPUT)
+               8:             TypeFunction 2 7(ptr) 7(ptr)
+              13:             TypeInt 32 0
+              14:     13(int) Constant 3
+              15:             TypeArray 6(GSPS_INPUT) 14
+              16:             TypePointer Function 15
+              17:             TypeFunction 2 16(ptr) 7(ptr)
+              22:             TypePointer Output 6(GSPS_INPUT)
+   23(TriStream):     22(ptr) Variable Output
+              25:             TypeInt 32 1
+              26:     25(int) Constant 0
+              33:     25(int) Constant 1
+              40:     25(int) Constant 2
+              48:             TypePointer Input 15
+       49(input):     48(ptr) Variable Input
+         4(main):           2 Function None 3
+               5:             Label
+       47(input):     16(ptr) Variable Function
+   51(TriStream):      7(ptr) Variable Function
+       52(param):     16(ptr) Variable Function
+       54(param):      7(ptr) Variable Function
+              50:          15 Load 49(input)
+                              Store 47(input) 50
+              53:          15 Load 47(input)
+                              Store 52(param) 53
+              55:           2 FunctionCall 20(@main(struct-GSPS_INPUT1[3];struct-GSPS_INPUT1;) 52(param) 54(param)
+              56:6(GSPS_INPUT) Load 54(param)
+                              Store 51(TriStream) 56
+                              Return
+                              FunctionEnd
+11(EmitVertex(struct-GSPS_INPUT1;struct-GSPS_INPUT1;):           2 Function None 8
+       9(output):      7(ptr) FunctionParameter
+   10(TriStream):      7(ptr) FunctionParameter
+              12:             Label
+              24:6(GSPS_INPUT) Load 9(output)
+                              Store 23(TriStream) 24
+                              EmitVertex
+                              Return
+                              FunctionEnd
+20(@main(struct-GSPS_INPUT1[3];struct-GSPS_INPUT1;):           2 Function None 17
+       18(input):     16(ptr) FunctionParameter
+   19(TriStream):      7(ptr) FunctionParameter
+              21:             Label
+       27(param):      7(ptr) Variable Function
+       30(param):      7(ptr) Variable Function
+       34(param):      7(ptr) Variable Function
+       37(param):      7(ptr) Variable Function
+       41(param):      7(ptr) Variable Function
+       44(param):      7(ptr) Variable Function
+              28:      7(ptr) AccessChain 18(input) 26
+              29:6(GSPS_INPUT) Load 28
+                              Store 27(param) 29
+              31:           2 FunctionCall 11(EmitVertex(struct-GSPS_INPUT1;struct-GSPS_INPUT1;) 27(param) 30(param)
+              32:6(GSPS_INPUT) Load 30(param)
+                              Store 19(TriStream) 32
+              35:      7(ptr) AccessChain 18(input) 33
+              36:6(GSPS_INPUT) Load 35
+                              Store 34(param) 36
+              38:           2 FunctionCall 11(EmitVertex(struct-GSPS_INPUT1;struct-GSPS_INPUT1;) 34(param) 37(param)
+              39:6(GSPS_INPUT) Load 37(param)
+                              Store 19(TriStream) 39
+              42:      7(ptr) AccessChain 18(input) 40
+              43:6(GSPS_INPUT) Load 42
+                              Store 41(param) 43
+              45:           2 FunctionCall 11(EmitVertex(struct-GSPS_INPUT1;struct-GSPS_INPUT1;) 41(param) 44(param)
+              46:6(GSPS_INPUT) Load 44(param)
+                              Store 19(TriStream) 46
+                              Return
+                              FunctionEnd
diff --git a/Test/hlsl.tristream-append.geom b/Test/hlsl.tristream-append.geom
new file mode 100644
index 0000000..208607d
--- /dev/null
+++ b/Test/hlsl.tristream-append.geom
@@ -0,0 +1,18 @@
+struct GSPS_INPUT
+{
+};
+
+// Test Append() method appearing before declaration of entry point's stream output.
+
+void EmitVertex(in GSPS_INPUT output, inout TriangleStream<GSPS_INPUT> TriStream)
+{
+    TriStream.Append( output );
+}
+
+[maxvertexcount(3)]
+void main( triangle GSPS_INPUT input[3], inout TriangleStream<GSPS_INPUT> TriStream )
+{
+    EmitVertex(input[0], TriStream);
+    EmitVertex(input[1], TriStream);
+    EmitVertex(input[2], TriStream);
+}
diff --git a/gtests/Hlsl.FromFile.cpp b/gtests/Hlsl.FromFile.cpp
index ad76cf3..7cf1cbf 100644
--- a/gtests/Hlsl.FromFile.cpp
+++ b/gtests/Hlsl.FromFile.cpp
@@ -371,6 +371,7 @@
         {"hlsl.targetStruct1.frag", "main"},
         {"hlsl.targetStruct2.frag", "main"},
         {"hlsl.templatetypes.frag", "PixelShaderFunction"},
+        {"hlsl.tristream-append.geom", "main"},
         {"hlsl.tx.bracket.frag", "main"},
         {"hlsl.tx.overload.frag", "main"},
         {"hlsl.type.half.frag", "main"},
diff --git a/hlsl/hlslParseHelper.cpp b/hlsl/hlslParseHelper.cpp
index b776278..e6d29ea 100755
--- a/hlsl/hlslParseHelper.cpp
+++ b/hlsl/hlslParseHelper.cpp
@@ -4490,23 +4490,18 @@
             emit->setLoc(loc);
             emit->setType(TType(EbtVoid));
 
-            // find the matching output
-            if (gsStreamOutput == nullptr) {
-                error(loc, "unable to find output symbol for Append()", "", "");
-                return;
-            }
+            TIntermTyped* data = argAggregate->getSequence()[1]->getAsTyped();
 
-            sequence = intermediate.growAggregate(sequence,
-                                                  handleAssign(loc, EOpAssign,
-                                                               intermediate.addSymbol(*gsStreamOutput, loc),
-                                                               argAggregate->getSequence()[1]->getAsTyped()),
-                                                  loc);
-
+            // This will be patched in finalization during finalizeAppendMethods()
+            sequence = intermediate.growAggregate(sequence, data, loc);
             sequence = intermediate.growAggregate(sequence, emit);
 
             sequence->setOperator(EOpSequence);
             sequence->setLoc(loc);
             sequence->setType(TType(EbtVoid));
+
+            gsAppends.push_back({sequence, loc});
+
             node = sequence;
         }
         break;
@@ -9922,6 +9917,31 @@
     }
 }
 
+// Finalization step: patch append methods to use proper stream output, which isn't known until
+// main is parsed, which could happen after the append method is parsed.
+void HlslParseContext::finalizeAppendMethods()
+{
+    TSourceLoc loc;
+    loc.init();
+
+    // Nothing to do: bypass test for valid stream output.
+    if (gsAppends.empty())
+        return;
+
+    if (gsStreamOutput == nullptr) {
+        error(loc, "unable to find output symbol for Append()", "", "");
+        return;
+    }
+
+    // Patch append sequences, now that we know the stream output symbol.
+    for (auto append = gsAppends.begin(); append != gsAppends.end(); ++append) {
+        append->node->getSequence()[0] = 
+            handleAssign(append->loc, EOpAssign,
+                         intermediate.addSymbol(*gsStreamOutput, append->loc),
+                         append->node->getSequence()[0]->getAsTyped());
+    }
+}
+
 // post-processing
 void HlslParseContext::finish()
 {
@@ -9934,6 +9954,7 @@
     removeUnusedStructBufferCounters();
     addPatchConstantInvocation();
     fixTextureShadowModes();
+    finalizeAppendMethods();
 
     // Communicate out (esp. for command line) that we formed AST that will make
     // illegal AST SPIR-V and it needs transforms to legalize it.
diff --git a/hlsl/hlslParseHelper.h b/hlsl/hlslParseHelper.h
index b16a8c2..32a1923 100755
--- a/hlsl/hlslParseHelper.h
+++ b/hlsl/hlslParseHelper.h
@@ -266,6 +266,7 @@
     TVariable* getSplitNonIoVar(int id) const;
     void addPatchConstantInvocation();
     void fixTextureShadowModes();
+    void finalizeAppendMethods();
     TIntermTyped* makeIntegerIndex(TIntermTyped*);
 
     void fixBuiltInIoType(TType&);
@@ -460,6 +461,17 @@
 
     TVector<tMipsOperatorData> mipsOperatorMipArg;
 
+    // The geometry output stream is not copied out from the entry point as a typical output variable
+    // is.  It's written via EmitVertex (hlsl=Append), which may happen in arbitrary control flow.
+    // For this we need the real output symbol.  Since it may not be known at the time and Append()
+    // method is parsed, the sequence will be patched during finalization.
+    struct tGsAppendData {
+        TIntermAggregate* node;
+        TSourceLoc loc;
+    };
+
+    TVector<tGsAppendData> gsAppends;
+
     // A texture object may be used with shadow and non-shadow samplers, but both may not be
     // alive post-DCE in the same shader.  We do not know at compilation time which are alive: that's
     // only known post-DCE.  If a texture is used both ways, we create two textures, and