Merge pull request #1381 from LoopDawg/coverage_array

HLSL: require coverage mask to be arrayed output.
diff --git a/Test/baseResults/hlsl.coverage.frag.out b/Test/baseResults/hlsl.coverage.frag.out
new file mode 100644
index 0000000..8fc6abf
--- /dev/null
+++ b/Test/baseResults/hlsl.coverage.frag.out
@@ -0,0 +1,204 @@
+hlsl.coverage.frag
+Shader version: 500
+gl_FragCoord origin is upper left
+0:? Sequence
+0:15  Function Definition: @main(struct-PS_INPUT1; ( temp structure{ temp 4-component vector of float vColor,  temp uint nCoverageMask})
+0:15    Function Parameters: 
+0:15      'i' ( in structure{})
+0:?     Sequence
+0:17      move second child to first child ( temp 4-component vector of float)
+0:17        vColor: direct index for structure ( temp 4-component vector of float)
+0:17          'o' ( temp structure{ temp 4-component vector of float vColor,  temp uint nCoverageMask})
+0:17          Constant:
+0:17            0 (const int)
+0:?         Constant:
+0:?           1.000000
+0:?           0.000000
+0:?           0.000000
+0:?           1.000000
+0:18      move second child to first child ( temp uint)
+0:18        nCoverageMask: direct index for structure ( temp uint)
+0:18          'o' ( temp structure{ temp 4-component vector of float vColor,  temp uint nCoverageMask})
+0:18          Constant:
+0:18            1 (const int)
+0:18        Constant:
+0:18          0 (const uint)
+0:19      Branch: Return with expression
+0:19        'o' ( temp structure{ temp 4-component vector of float vColor,  temp uint nCoverageMask})
+0:15  Function Definition: main( ( temp void)
+0:15    Function Parameters: 
+0:?     Sequence
+0:15      Sequence
+0:15        move second child to first child ( temp structure{})
+0:?           'i' ( temp structure{})
+0:?           'i' ( in structure{})
+0:15      Sequence
+0:15        move second child to first child ( temp structure{ temp 4-component vector of float vColor,  temp uint nCoverageMask})
+0:15          'flattenTemp' ( temp structure{ temp 4-component vector of float vColor,  temp uint nCoverageMask})
+0:15          Function Call: @main(struct-PS_INPUT1; ( temp structure{ temp 4-component vector of float vColor,  temp uint nCoverageMask})
+0:?             'i' ( temp structure{})
+0:15        move second child to first child ( temp 4-component vector of float)
+0:?           '@entryPointOutput.vColor' (layout( location=0) out 4-component vector of float)
+0:15          vColor: direct index for structure ( temp 4-component vector of float)
+0:15            'flattenTemp' ( temp structure{ temp 4-component vector of float vColor,  temp uint nCoverageMask})
+0:15            Constant:
+0:15              0 (const int)
+0:15        move second child to first child ( temp uint)
+0:15          direct index ( out uint SampleMaskIn)
+0:?             '@entryPointOutput.nCoverageMask' ( out 1-element array of uint SampleMaskIn)
+0:15            Constant:
+0:15              0 (const int)
+0:15          nCoverageMask: direct index for structure ( temp uint)
+0:15            'flattenTemp' ( temp structure{ temp 4-component vector of float vColor,  temp uint nCoverageMask})
+0:15            Constant:
+0:15              1 (const int)
+0:?   Linker Objects
+0:?     '@entryPointOutput.nCoverageMask' ( out 1-element array of uint SampleMaskIn)
+0:?     '@entryPointOutput.vColor' (layout( location=0) out 4-component vector of float)
+
+
+Linked fragment stage:
+
+
+Shader version: 500
+gl_FragCoord origin is upper left
+0:? Sequence
+0:15  Function Definition: @main(struct-PS_INPUT1; ( temp structure{ temp 4-component vector of float vColor,  temp uint nCoverageMask})
+0:15    Function Parameters: 
+0:15      'i' ( in structure{})
+0:?     Sequence
+0:17      move second child to first child ( temp 4-component vector of float)
+0:17        vColor: direct index for structure ( temp 4-component vector of float)
+0:17          'o' ( temp structure{ temp 4-component vector of float vColor,  temp uint nCoverageMask})
+0:17          Constant:
+0:17            0 (const int)
+0:?         Constant:
+0:?           1.000000
+0:?           0.000000
+0:?           0.000000
+0:?           1.000000
+0:18      move second child to first child ( temp uint)
+0:18        nCoverageMask: direct index for structure ( temp uint)
+0:18          'o' ( temp structure{ temp 4-component vector of float vColor,  temp uint nCoverageMask})
+0:18          Constant:
+0:18            1 (const int)
+0:18        Constant:
+0:18          0 (const uint)
+0:19      Branch: Return with expression
+0:19        'o' ( temp structure{ temp 4-component vector of float vColor,  temp uint nCoverageMask})
+0:15  Function Definition: main( ( temp void)
+0:15    Function Parameters: 
+0:?     Sequence
+0:15      Sequence
+0:15        move second child to first child ( temp structure{})
+0:?           'i' ( temp structure{})
+0:?           'i' ( in structure{})
+0:15      Sequence
+0:15        move second child to first child ( temp structure{ temp 4-component vector of float vColor,  temp uint nCoverageMask})
+0:15          'flattenTemp' ( temp structure{ temp 4-component vector of float vColor,  temp uint nCoverageMask})
+0:15          Function Call: @main(struct-PS_INPUT1; ( temp structure{ temp 4-component vector of float vColor,  temp uint nCoverageMask})
+0:?             'i' ( temp structure{})
+0:15        move second child to first child ( temp 4-component vector of float)
+0:?           '@entryPointOutput.vColor' (layout( location=0) out 4-component vector of float)
+0:15          vColor: direct index for structure ( temp 4-component vector of float)
+0:15            'flattenTemp' ( temp structure{ temp 4-component vector of float vColor,  temp uint nCoverageMask})
+0:15            Constant:
+0:15              0 (const int)
+0:15        move second child to first child ( temp uint)
+0:15          direct index ( out uint SampleMaskIn)
+0:?             '@entryPointOutput.nCoverageMask' ( out 1-element array of uint SampleMaskIn)
+0:15            Constant:
+0:15              0 (const int)
+0:15          nCoverageMask: direct index for structure ( temp uint)
+0:15            'flattenTemp' ( temp structure{ temp 4-component vector of float vColor,  temp uint nCoverageMask})
+0:15            Constant:
+0:15              1 (const int)
+0:?   Linker Objects
+0:?     '@entryPointOutput.nCoverageMask' ( out 1-element array of uint SampleMaskIn)
+0:?     '@entryPointOutput.vColor' (layout( location=0) out 4-component vector of float)
+
+// Module Version 10000
+// Generated by (magic number): 80006
+// Id's are bound by 52
+
+                              Capability Shader
+               1:             ExtInstImport  "GLSL.std.450"
+                              MemoryModel Logical GLSL450
+                              EntryPoint Fragment 4  "main" 41 47
+                              ExecutionMode 4 OriginUpperLeft
+                              Source HLSL 500
+                              Name 4  "main"
+                              Name 6  "PS_INPUT"
+                              Name 11  "PS_OUTPUT"
+                              MemberName 11(PS_OUTPUT) 0  "vColor"
+                              MemberName 11(PS_OUTPUT) 1  "nCoverageMask"
+                              Name 14  "@main(struct-PS_INPUT1;"
+                              Name 13  "i"
+                              Name 17  "o"
+                              Name 32  "i"
+                              Name 34  "i"
+                              Name 36  "flattenTemp"
+                              Name 37  "param"
+                              Name 41  "@entryPointOutput.vColor"
+                              Name 47  "@entryPointOutput.nCoverageMask"
+                              Decorate 41(@entryPointOutput.vColor) Location 0
+                              Decorate 47(@entryPointOutput.nCoverageMask) BuiltIn SampleMask
+               2:             TypeVoid
+               3:             TypeFunction 2
+     6(PS_INPUT):             TypeStruct
+               7:             TypePointer Function 6(PS_INPUT)
+               8:             TypeFloat 32
+               9:             TypeVector 8(float) 4
+              10:             TypeInt 32 0
+   11(PS_OUTPUT):             TypeStruct 9(fvec4) 10(int)
+              12:             TypeFunction 11(PS_OUTPUT) 7(ptr)
+              16:             TypePointer Function 11(PS_OUTPUT)
+              18:             TypeInt 32 1
+              19:     18(int) Constant 0
+              20:    8(float) Constant 1065353216
+              21:    8(float) Constant 0
+              22:    9(fvec4) ConstantComposite 20 21 21 20
+              23:             TypePointer Function 9(fvec4)
+              25:     18(int) Constant 1
+              26:     10(int) Constant 0
+              27:             TypePointer Function 10(int)
+              33:             TypePointer Input 6(PS_INPUT)
+           34(i):     33(ptr) Variable Input
+              40:             TypePointer Output 9(fvec4)
+41(@entryPointOutput.vColor):     40(ptr) Variable Output
+              44:     10(int) Constant 1
+              45:             TypeArray 10(int) 44
+              46:             TypePointer Output 45
+47(@entryPointOutput.nCoverageMask):     46(ptr) Variable Output
+              50:             TypePointer Output 10(int)
+         4(main):           2 Function None 3
+               5:             Label
+           32(i):      7(ptr) Variable Function
+ 36(flattenTemp):     16(ptr) Variable Function
+       37(param):      7(ptr) Variable Function
+              35: 6(PS_INPUT) Load 34(i)
+                              Store 32(i) 35
+              38: 6(PS_INPUT) Load 32(i)
+                              Store 37(param) 38
+              39:11(PS_OUTPUT) FunctionCall 14(@main(struct-PS_INPUT1;) 37(param)
+                              Store 36(flattenTemp) 39
+              42:     23(ptr) AccessChain 36(flattenTemp) 19
+              43:    9(fvec4) Load 42
+                              Store 41(@entryPointOutput.vColor) 43
+              48:     27(ptr) AccessChain 36(flattenTemp) 25
+              49:     10(int) Load 48
+              51:     50(ptr) AccessChain 47(@entryPointOutput.nCoverageMask) 19
+                              Store 51 49
+                              Return
+                              FunctionEnd
+14(@main(struct-PS_INPUT1;):11(PS_OUTPUT) Function None 12
+           13(i):      7(ptr) FunctionParameter
+              15:             Label
+           17(o):     16(ptr) Variable Function
+              24:     23(ptr) AccessChain 17(o) 19
+                              Store 24 22
+              28:     27(ptr) AccessChain 17(o) 25
+                              Store 28 26
+              29:11(PS_OUTPUT) Load 17(o)
+                              ReturnValue 29
+                              FunctionEnd
diff --git a/Test/baseResults/hlsl.inoutquals.frag.out b/Test/baseResults/hlsl.inoutquals.frag.out
index 0a8e597..8eef84e 100644
--- a/Test/baseResults/hlsl.inoutquals.frag.out
+++ b/Test/baseResults/hlsl.inoutquals.frag.out
@@ -93,13 +93,16 @@
 0:16            Constant:
 0:16              1 (const int)
 0:16      move second child to first child ( temp int)
-0:?         'sampleMask' ( out int SampleMaskIn)
+0:16        direct index ( out int SampleMaskIn)
+0:?           'sampleMask' ( out 1-element array of int SampleMaskIn)
+0:16          Constant:
+0:16            0 (const int)
 0:?         'sampleMask' ( temp int)
 0:?   Linker Objects
 0:?     '@entryPointOutput.Depth' ( out float FragDepth)
 0:?     '@entryPointOutput.Color' (layout( location=0) out 4-component vector of float)
 0:?     'inpos' ( noperspective in 4-component vector of float FragCoord)
-0:?     'sampleMask' ( out int SampleMaskIn)
+0:?     'sampleMask' ( out 1-element array of int SampleMaskIn)
 
 
 Linked fragment stage:
@@ -199,22 +202,25 @@
 0:16            Constant:
 0:16              1 (const int)
 0:16      move second child to first child ( temp int)
-0:?         'sampleMask' ( out int SampleMaskIn)
+0:16        direct index ( out int SampleMaskIn)
+0:?           'sampleMask' ( out 1-element array of int SampleMaskIn)
+0:16          Constant:
+0:16            0 (const int)
 0:?         'sampleMask' ( temp int)
 0:?   Linker Objects
 0:?     '@entryPointOutput.Depth' ( out float FragDepth)
 0:?     '@entryPointOutput.Color' (layout( location=0) out 4-component vector of float)
 0:?     'inpos' ( noperspective in 4-component vector of float FragCoord)
-0:?     'sampleMask' ( out int SampleMaskIn)
+0:?     'sampleMask' ( out 1-element array of int SampleMaskIn)
 
 // Module Version 10000
 // Generated by (magic number): 80006
-// Id's are bound by 88
+// Id's are bound by 92
 
                               Capability Shader
                1:             ExtInstImport  "GLSL.std.450"
                               MemoryModel Logical GLSL450
-                              EntryPoint Fragment 4  "main" 68 78 82 86
+                              EntryPoint Fragment 4  "main" 68 78 82 88
                               ExecutionMode 4 OriginUpperLeft
                               ExecutionMode 4 DepthReplacing
                               Source HLSL 500
@@ -246,12 +252,12 @@
                               Name 74  "param"
                               Name 78  "@entryPointOutput.Color"
                               Name 82  "@entryPointOutput.Depth"
-                              Name 86  "sampleMask"
+                              Name 88  "sampleMask"
                               Decorate 68(inpos) NoPerspective
                               Decorate 68(inpos) BuiltIn FragCoord
                               Decorate 78(@entryPointOutput.Color) Location 0
                               Decorate 82(@entryPointOutput.Depth) BuiltIn FragDepth
-                              Decorate 86(sampleMask) BuiltIn SampleMask
+                              Decorate 88(sampleMask) BuiltIn SampleMask
                2:             TypeVoid
                3:             TypeFunction 2
                6:             TypeFloat 32
@@ -278,8 +284,11 @@
 78(@entryPointOutput.Color):     77(ptr) Variable Output
               81:             TypePointer Output 6(float)
 82(@entryPointOutput.Depth):     81(ptr) Variable Output
-              85:             TypePointer Output 17(int)
-  86(sampleMask):     85(ptr) Variable Output
+              85:     42(int) Constant 1
+              86:             TypeArray 17(int) 85
+              87:             TypePointer Output 86
+  88(sampleMask):     87(ptr) Variable Output
+              90:             TypePointer Output 17(int)
          4(main):           2 Function None 3
                5:             Label
        66(inpos):     16(ptr) Variable Function
@@ -301,8 +310,9 @@
               83:      7(ptr) AccessChain 70(flattenTemp) 59
               84:    6(float) Load 83
                               Store 82(@entryPointOutput.Depth) 84
-              87:     17(int) Load 71(sampleMask)
-                              Store 86(sampleMask) 87
+              89:     17(int) Load 71(sampleMask)
+              91:     90(ptr) AccessChain 88(sampleMask) 53
+                              Store 91 89
                               Return
                               FunctionEnd
 13(MyFunc(f1;f1;f1;f1;):           2 Function None 8
diff --git a/Test/hlsl.coverage.frag b/Test/hlsl.coverage.frag
new file mode 100644
index 0000000..c6cd019
--- /dev/null
+++ b/Test/hlsl.coverage.frag
@@ -0,0 +1,20 @@
+
+// Verify that coverage mask is an array, as required by SPIR-V.
+
+struct PS_INPUT
+{
+};
+
+struct PS_OUTPUT
+{
+    float4 vColor : SV_Target0;
+    uint nCoverageMask : SV_Coverage;
+};
+
+PS_OUTPUT main( PS_INPUT i )
+{
+    PS_OUTPUT o;
+    o.vColor = float4(1.0, 0.0, 0.0, 1.0);
+    o.nCoverageMask = 0;
+    return o;
+}
diff --git a/gtests/Hlsl.FromFile.cpp b/gtests/Hlsl.FromFile.cpp
index 7cf1cbf..390e3d3 100644
--- a/gtests/Hlsl.FromFile.cpp
+++ b/gtests/Hlsl.FromFile.cpp
@@ -148,6 +148,7 @@
         {"hlsl.constructArray.vert", "main"},
         {"hlsl.constructexpr.frag", "main"},
         {"hlsl.constructimat.frag", "main"},
+        {"hlsl.coverage.frag", "main"},
         {"hlsl.depthGreater.frag", "PixelShaderFunction"},
         {"hlsl.depthLess.frag", "PixelShaderFunction"},
         {"hlsl.discard.frag", "PixelShaderFunction"},
diff --git a/hlsl/hlslParseHelper.cpp b/hlsl/hlslParseHelper.cpp
index e6d29ea..3ef9a5a 100755
--- a/hlsl/hlslParseHelper.cpp
+++ b/hlsl/hlslParseHelper.cpp
@@ -1481,6 +1481,14 @@
     case EbvTessLevelOuter: requiredArraySize = 4; break;
     case EbvTessLevelInner: requiredArraySize = 2; break;
 
+    case EbvSampleMask:
+        {
+            // Promote scalar to array of size 1.  Leave existing arrays alone.
+            if (!type.isArray())
+                requiredArraySize = 1;
+            break;
+        }
+
     case EbvWorkGroupId:        requiredVectorSize = 3; break;
     case EbvGlobalInvocationId: requiredVectorSize = 3; break;
     case EbvLocalInvocationId:  requiredVectorSize = 3; break;
@@ -2700,6 +2708,15 @@
         } else if (assignsClipPos(left)) {
             // Position can require special handling: see comment above assignPosition
             return assignPosition(loc, op, left, right);
+        } else if (left->getQualifier().builtIn == EbvSampleMask) {
+            // Certain builtins are required to be arrayed outputs in SPIR-V, but may internally be scalars
+            // in the shader.  Copy the scalar RHS into the LHS array element zero, if that happens.
+            if (left->isArray() && !right->isArray()) {
+                const TType derefType(left->getType(), 0);
+                left = intermediate.addIndex(EOpIndexDirect, left, intermediate.addConstantUnion(0, loc), loc);
+                left->setType(derefType);
+                // Fall through to add assign.
+            }
         }
 
         return intermediate.addAssign(op, left, right, loc);