Merge pull request #991 from LoopDawg/resource-set-binding-fix

HLSL: Fix crash with --resource-set-binding [n] (global form, not per-register form)
diff --git a/SPIRV/GlslangToSpv.cpp b/SPIRV/GlslangToSpv.cpp
index 2899a74..b65d6ed 100755
--- a/SPIRV/GlslangToSpv.cpp
+++ b/SPIRV/GlslangToSpv.cpp
@@ -2914,6 +2914,13 @@
 // Make all the functions, skeletally, without actually visiting their bodies.
 void TGlslangToSpvTraverser::makeFunctions(const glslang::TIntermSequence& glslFunctions)
 {
+    const auto getParamDecorations = [](std::vector<spv::Decoration>& decorations, const glslang::TType& type) {
+        spv::Decoration paramPrecision = TranslatePrecisionDecoration(type);
+        if (paramPrecision != spv::NoPrecision)
+            decorations.push_back(paramPrecision);
+        TranslateMemoryDecoration(type.getQualifier(), decorations);
+    };
+
     for (int f = 0; f < (int)glslFunctions.size(); ++f) {
         glslang::TIntermAggregate* glslFunction = glslFunctions[f]->getAsAggregate();
         if (! glslFunction || glslFunction->getOp() != glslang::EOpFunction || isShaderEntryPoint(glslFunction))
@@ -2934,11 +2941,13 @@
         //   GLSL has copy-in/copy-out semantics.  They can be handled though with a pointer to a copy.
 
         std::vector<spv::Id> paramTypes;
-        std::vector<spv::Decoration> paramPrecisions;
+        std::vector<std::vector<spv::Decoration>> paramDecorations; // list of decorations per parameter
         glslang::TIntermSequence& parameters = glslFunction->getSequence()[0]->getAsAggregate()->getSequence();
 
-        bool implicitThis = (int)parameters.size() > 0 && parameters[0]->getAsSymbolNode()->getName() == glslangIntermediate->implicitThisName;
+        bool implicitThis = (int)parameters.size() > 0 && parameters[0]->getAsSymbolNode()->getName() ==
+                                                          glslangIntermediate->implicitThisName;
 
+        paramDecorations.resize(parameters.size());
         for (int p = 0; p < (int)parameters.size(); ++p) {
             const glslang::TType& paramType = parameters[p]->getAsTyped()->getType();
             spv::Id typeId = convertGlslangToSpvType(paramType);
@@ -2952,14 +2961,15 @@
                 typeId = builder.makePointer(spv::StorageClassFunction, typeId);
             else
                 rValueParameters.insert(parameters[p]->getAsSymbolNode()->getId());
-            paramPrecisions.push_back(TranslatePrecisionDecoration(paramType));
+            getParamDecorations(paramDecorations[p], paramType);
             paramTypes.push_back(typeId);
         }
 
         spv::Block* functionBlock;
         spv::Function *function = builder.makeFunctionEntry(TranslatePrecisionDecoration(glslFunction->getType()),
                                                             convertGlslangToSpvType(glslFunction->getType()),
-                                                            glslFunction->getName().c_str(), paramTypes, paramPrecisions, &functionBlock);
+                                                            glslFunction->getName().c_str(), paramTypes,
+                                                            paramDecorations, &functionBlock);
         if (implicitThis)
             function->setImplicitThis();
 
diff --git a/SPIRV/SpvBuilder.cpp b/SPIRV/SpvBuilder.cpp
index 11e9fe6..d472eb5 100644
--- a/SPIRV/SpvBuilder.cpp
+++ b/SPIRV/SpvBuilder.cpp
@@ -983,16 +983,16 @@
 
     Block* entry;
     std::vector<Id> params;
-    std::vector<Decoration> precisions;
+    std::vector<std::vector<Decoration>> decorations;
 
-    entryPointFunction = makeFunctionEntry(NoPrecision, makeVoidType(), entryPoint, params, precisions, &entry);
+    entryPointFunction = makeFunctionEntry(NoPrecision, makeVoidType(), entryPoint, params, decorations, &entry);
 
     return entryPointFunction;
 }
 
 // Comments in header
 Function* Builder::makeFunctionEntry(Decoration precision, Id returnType, const char* name,
-                                     const std::vector<Id>& paramTypes, const std::vector<Decoration>& precisions, Block **entry)
+                                     const std::vector<Id>& paramTypes, const std::vector<std::vector<Decoration>>& decorations, Block **entry)
 {
     // Make the function and initial instructions in it
     Id typeId = makeFunctionType(returnType, paramTypes);
@@ -1001,8 +1001,10 @@
 
     // Set up the precisions
     setPrecision(function->getId(), precision);
-    for (unsigned p = 0; p < (unsigned)precisions.size(); ++p)
-        setPrecision(firstParamId + p, precisions[p]);
+    for (unsigned p = 0; p < (unsigned)decorations.size(); ++p) {
+        for (int d = 0; d < (int)decorations[p].size(); ++d)
+            addDecoration(firstParamId + p, decorations[p][d]);
+    }
 
     // CFG
     if (entry) {
diff --git a/SPIRV/SpvBuilder.h b/SPIRV/SpvBuilder.h
index 2b17ba6..3a94919 100755
--- a/SPIRV/SpvBuilder.h
+++ b/SPIRV/SpvBuilder.h
@@ -247,7 +247,7 @@
     // Return the function, pass back the entry.
     // The returned pointer is only valid for the lifetime of this builder.
     Function* makeFunctionEntry(Decoration precision, Id returnType, const char* name, const std::vector<Id>& paramTypes,
-                                const std::vector<Decoration>& precisions, Block **entry = 0);
+                                const std::vector<std::vector<Decoration>>& precisions, Block **entry = 0);
 
     // Create a return. An 'implicit' return is one not appearing in the source
     // code.  In the case of an implicit return, no post-return block is inserted.
diff --git a/Test/baseResults/hlsl.flattenOpaqueInit.vert.out b/Test/baseResults/hlsl.flattenOpaqueInit.vert.out
new file mode 100755
index 0000000..774260f
--- /dev/null
+++ b/Test/baseResults/hlsl.flattenOpaqueInit.vert.out
@@ -0,0 +1,132 @@
+hlsl.flattenOpaqueInit.vert
+Shader version: 500
+0:? Sequence
+0:5  Function Definition: lookUp(struct-FxaaTex-p1-t211; ( temp 4-component vector of float)
+0:5    Function Parameters: 
+0:?       'smpl' ( in sampler)
+0:?       'tex' ( in texture2D)
+0:?     Sequence
+0:6      Branch: Return with expression
+0:6        texture ( temp 4-component vector of float)
+0:6          Construct combined texture-sampler ( temp sampler2D)
+0:?             'tex' ( in texture2D)
+0:?             'smpl' ( in sampler)
+0:?           Constant:
+0:?             0.300000
+0:?             0.400000
+0:10  Function Definition: @main( ( temp 4-component vector of float)
+0:10    Function Parameters: 
+0:?     Sequence
+0:12      Branch: Return with expression
+0:12        Function Call: lookUp(struct-FxaaTex-p1-t211; ( temp 4-component vector of float)
+0:?           'g_tInputTexture_sampler' ( uniform sampler)
+0:?           'g_tInputTexture' ( uniform texture2D)
+0:10  Function Definition: main( ( temp void)
+0:10    Function Parameters: 
+0:?     Sequence
+0:10      move second child to first child ( temp 4-component vector of float)
+0:?         '@entryPointOutput' (layout( location=0) out 4-component vector of float)
+0:10        Function Call: @main( ( temp 4-component vector of float)
+0:?   Linker Objects
+0:?     'g_tInputTexture_sampler' ( uniform sampler)
+0:?     'g_tInputTexture' ( uniform texture2D)
+0:?     '@entryPointOutput' (layout( location=0) out 4-component vector of float)
+
+
+Linked vertex stage:
+
+
+Shader version: 500
+0:? Sequence
+0:5  Function Definition: lookUp(struct-FxaaTex-p1-t211; ( temp 4-component vector of float)
+0:5    Function Parameters: 
+0:?       'smpl' ( in sampler)
+0:?       'tex' ( in texture2D)
+0:?     Sequence
+0:6      Branch: Return with expression
+0:6        texture ( temp 4-component vector of float)
+0:6          Construct combined texture-sampler ( temp sampler2D)
+0:?             'tex' ( in texture2D)
+0:?             'smpl' ( in sampler)
+0:?           Constant:
+0:?             0.300000
+0:?             0.400000
+0:10  Function Definition: @main( ( temp 4-component vector of float)
+0:10    Function Parameters: 
+0:?     Sequence
+0:12      Branch: Return with expression
+0:12        Function Call: lookUp(struct-FxaaTex-p1-t211; ( temp 4-component vector of float)
+0:?           'g_tInputTexture_sampler' ( uniform sampler)
+0:?           'g_tInputTexture' ( uniform texture2D)
+0:10  Function Definition: main( ( temp void)
+0:10    Function Parameters: 
+0:?     Sequence
+0:10      move second child to first child ( temp 4-component vector of float)
+0:?         '@entryPointOutput' (layout( location=0) out 4-component vector of float)
+0:10        Function Call: @main( ( temp 4-component vector of float)
+0:?   Linker Objects
+0:?     'g_tInputTexture_sampler' ( uniform sampler)
+0:?     'g_tInputTexture' ( uniform texture2D)
+0:?     '@entryPointOutput' (layout( location=0) out 4-component vector of float)
+
+// Module Version 10000
+// Generated by (magic number): 80001
+// Id's are bound by 40
+
+                              Capability Shader
+               1:             ExtInstImport  "GLSL.std.450"
+                              MemoryModel Logical GLSL450
+                              EntryPoint Vertex 4  "main" 38
+                              Source HLSL 500
+                              Name 4  "main"
+                              Name 15  "lookUp(struct-FxaaTex-p1-t211;"
+                              Name 13  "smpl"
+                              Name 14  "tex"
+                              Name 18  "@main("
+                              Name 32  "g_tInputTexture_sampler"
+                              Name 33  "g_tInputTexture"
+                              Name 38  "@entryPointOutput"
+                              Decorate 32(g_tInputTexture_sampler) DescriptorSet 0
+                              Decorate 33(g_tInputTexture) DescriptorSet 0
+                              Decorate 38(@entryPointOutput) Location 0
+               2:             TypeVoid
+               3:             TypeFunction 2
+               6:             TypeSampler
+               7:             TypePointer UniformConstant 6
+               8:             TypeFloat 32
+               9:             TypeImage 8(float) 2D sampled format:Unknown
+              10:             TypePointer UniformConstant 9
+              11:             TypeVector 8(float) 4
+              12:             TypeFunction 11(fvec4) 7(ptr) 10(ptr)
+              17:             TypeFunction 11(fvec4)
+              22:             TypeSampledImage 9
+              24:             TypeVector 8(float) 2
+              25:    8(float) Constant 1050253722
+              26:    8(float) Constant 1053609165
+              27:   24(fvec2) ConstantComposite 25 26
+              28:    8(float) Constant 0
+32(g_tInputTexture_sampler):      7(ptr) Variable UniformConstant
+33(g_tInputTexture):     10(ptr) Variable UniformConstant
+              37:             TypePointer Output 11(fvec4)
+38(@entryPointOutput):     37(ptr) Variable Output
+         4(main):           2 Function None 3
+               5:             Label
+              39:   11(fvec4) FunctionCall 18(@main()
+                              Store 38(@entryPointOutput) 39
+                              Return
+                              FunctionEnd
+15(lookUp(struct-FxaaTex-p1-t211;):   11(fvec4) Function None 12
+        13(smpl):      7(ptr) FunctionParameter
+         14(tex):     10(ptr) FunctionParameter
+              16:             Label
+              20:           9 Load 14(tex)
+              21:           6 Load 13(smpl)
+              23:          22 SampledImage 20 21
+              29:   11(fvec4) ImageSampleExplicitLod 23 27 Lod 28
+                              ReturnValue 29
+                              FunctionEnd
+      18(@main():   11(fvec4) Function None 17
+              19:             Label
+              34:   11(fvec4) FunctionCall 15(lookUp(struct-FxaaTex-p1-t211;) 32(g_tInputTexture_sampler) 33(g_tInputTexture)
+                              ReturnValue 34
+                              FunctionEnd
diff --git a/Test/baseResults/hlsl.flattenOpaqueInitMix.vert.out b/Test/baseResults/hlsl.flattenOpaqueInitMix.vert.out
new file mode 100755
index 0000000..3deaddd
--- /dev/null
+++ b/Test/baseResults/hlsl.flattenOpaqueInitMix.vert.out
@@ -0,0 +1,159 @@
+hlsl.flattenOpaqueInitMix.vert
+Shader version: 500
+0:? Sequence
+0:5  Function Definition: lookUp(struct-FxaaTex-p1-t21-f11; ( temp 4-component vector of float)
+0:5    Function Parameters: 
+0:?       'smpl' ( in sampler)
+0:?       'tex' ( in texture2D)
+0:?       'f' ( in float)
+0:?     Sequence
+0:6      Branch: Return with expression
+0:6        texture ( temp 4-component vector of float)
+0:6          Construct combined texture-sampler ( temp sampler2D)
+0:?             'tex' ( in texture2D)
+0:?             'smpl' ( in sampler)
+0:?           Construct vec2 ( temp 2-component vector of float)
+0:?             'f' ( in float)
+0:?             'f' ( in float)
+0:10  Function Definition: @main( ( temp 4-component vector of float)
+0:10    Function Parameters: 
+0:?     Sequence
+0:11      Sequence
+0:?         Sequence
+0:11          move second child to first child ( temp float)
+0:?             'f' ( temp float)
+0:11            Constant:
+0:11              0.500000
+0:12      Branch: Return with expression
+0:12        Function Call: lookUp(struct-FxaaTex-p1-t21-f11; ( temp 4-component vector of float)
+0:?           'g_tInputTexture_sampler' ( uniform sampler)
+0:?           'g_tInputTexture' ( uniform texture2D)
+0:?           'f' ( temp float)
+0:10  Function Definition: main( ( temp void)
+0:10    Function Parameters: 
+0:?     Sequence
+0:10      move second child to first child ( temp 4-component vector of float)
+0:?         '@entryPointOutput' (layout( location=0) out 4-component vector of float)
+0:10        Function Call: @main( ( temp 4-component vector of float)
+0:?   Linker Objects
+0:?     'g_tInputTexture_sampler' ( uniform sampler)
+0:?     'g_tInputTexture' ( uniform texture2D)
+0:?     '@entryPointOutput' (layout( location=0) out 4-component vector of float)
+
+
+Linked vertex stage:
+
+
+Shader version: 500
+0:? Sequence
+0:5  Function Definition: lookUp(struct-FxaaTex-p1-t21-f11; ( temp 4-component vector of float)
+0:5    Function Parameters: 
+0:?       'smpl' ( in sampler)
+0:?       'tex' ( in texture2D)
+0:?       'f' ( in float)
+0:?     Sequence
+0:6      Branch: Return with expression
+0:6        texture ( temp 4-component vector of float)
+0:6          Construct combined texture-sampler ( temp sampler2D)
+0:?             'tex' ( in texture2D)
+0:?             'smpl' ( in sampler)
+0:?           Construct vec2 ( temp 2-component vector of float)
+0:?             'f' ( in float)
+0:?             'f' ( in float)
+0:10  Function Definition: @main( ( temp 4-component vector of float)
+0:10    Function Parameters: 
+0:?     Sequence
+0:11      Sequence
+0:?         Sequence
+0:11          move second child to first child ( temp float)
+0:?             'f' ( temp float)
+0:11            Constant:
+0:11              0.500000
+0:12      Branch: Return with expression
+0:12        Function Call: lookUp(struct-FxaaTex-p1-t21-f11; ( temp 4-component vector of float)
+0:?           'g_tInputTexture_sampler' ( uniform sampler)
+0:?           'g_tInputTexture' ( uniform texture2D)
+0:?           'f' ( temp float)
+0:10  Function Definition: main( ( temp void)
+0:10    Function Parameters: 
+0:?     Sequence
+0:10      move second child to first child ( temp 4-component vector of float)
+0:?         '@entryPointOutput' (layout( location=0) out 4-component vector of float)
+0:10        Function Call: @main( ( temp 4-component vector of float)
+0:?   Linker Objects
+0:?     'g_tInputTexture_sampler' ( uniform sampler)
+0:?     'g_tInputTexture' ( uniform texture2D)
+0:?     '@entryPointOutput' (layout( location=0) out 4-component vector of float)
+
+// Module Version 10000
+// Generated by (magic number): 80001
+// Id's are bound by 46
+
+                              Capability Shader
+               1:             ExtInstImport  "GLSL.std.450"
+                              MemoryModel Logical GLSL450
+                              EntryPoint Vertex 4  "main" 44
+                              Source HLSL 500
+                              Name 4  "main"
+                              Name 17  "lookUp(struct-FxaaTex-p1-t21-f11;"
+                              Name 14  "smpl"
+                              Name 15  "tex"
+                              Name 16  "f"
+                              Name 20  "@main("
+                              Name 34  "f"
+                              Name 36  "g_tInputTexture_sampler"
+                              Name 37  "g_tInputTexture"
+                              Name 38  "param"
+                              Name 44  "@entryPointOutput"
+                              Decorate 36(g_tInputTexture_sampler) DescriptorSet 0
+                              Decorate 37(g_tInputTexture) DescriptorSet 0
+                              Decorate 44(@entryPointOutput) Location 0
+               2:             TypeVoid
+               3:             TypeFunction 2
+               6:             TypeSampler
+               7:             TypePointer UniformConstant 6
+               8:             TypeFloat 32
+               9:             TypeImage 8(float) 2D sampled format:Unknown
+              10:             TypePointer UniformConstant 9
+              11:             TypePointer Function 8(float)
+              12:             TypeVector 8(float) 4
+              13:             TypeFunction 12(fvec4) 7(ptr) 10(ptr) 11(ptr)
+              19:             TypeFunction 12(fvec4)
+              24:             TypeSampledImage 9
+              28:             TypeVector 8(float) 2
+              30:    8(float) Constant 0
+              35:    8(float) Constant 1056964608
+36(g_tInputTexture_sampler):      7(ptr) Variable UniformConstant
+37(g_tInputTexture):     10(ptr) Variable UniformConstant
+              43:             TypePointer Output 12(fvec4)
+44(@entryPointOutput):     43(ptr) Variable Output
+         4(main):           2 Function None 3
+               5:             Label
+              45:   12(fvec4) FunctionCall 20(@main()
+                              Store 44(@entryPointOutput) 45
+                              Return
+                              FunctionEnd
+17(lookUp(struct-FxaaTex-p1-t21-f11;):   12(fvec4) Function None 13
+        14(smpl):      7(ptr) FunctionParameter
+         15(tex):     10(ptr) FunctionParameter
+           16(f):     11(ptr) FunctionParameter
+              18:             Label
+              22:           9 Load 15(tex)
+              23:           6 Load 14(smpl)
+              25:          24 SampledImage 22 23
+              26:    8(float) Load 16(f)
+              27:    8(float) Load 16(f)
+              29:   28(fvec2) CompositeConstruct 26 27
+              31:   12(fvec4) ImageSampleExplicitLod 25 29 Lod 30
+                              ReturnValue 31
+                              FunctionEnd
+      20(@main():   12(fvec4) Function None 19
+              21:             Label
+           34(f):     11(ptr) Variable Function
+       38(param):     11(ptr) Variable Function
+                              Store 34(f) 35
+              39:    8(float) Load 34(f)
+                              Store 38(param) 39
+              40:   12(fvec4) FunctionCall 17(lookUp(struct-FxaaTex-p1-t21-f11;) 36(g_tInputTexture_sampler) 37(g_tInputTexture) 38(param)
+                              ReturnValue 40
+                              FunctionEnd
diff --git a/Test/baseResults/hlsl.structbuffer.fn.frag.out b/Test/baseResults/hlsl.structbuffer.fn.frag.out
index 63aaa62..2e2a44f 100644
--- a/Test/baseResults/hlsl.structbuffer.fn.frag.out
+++ b/Test/baseResults/hlsl.structbuffer.fn.frag.out
@@ -184,6 +184,7 @@
                               MemberDecorate 9 0 NonWritable
                               MemberDecorate 9 0 Offset 0
                               Decorate 9 BufferBlock
+                              Decorate 13(sb) NonWritable
                               Decorate 17 ArrayStride 16
                               MemberDecorate 18 0 Offset 0
                               Decorate 18 BufferBlock
diff --git a/Test/baseResults/hlsl.structbuffer.fn2.comp.out b/Test/baseResults/hlsl.structbuffer.fn2.comp.out
index 686a0a2..cb12ba5 100644
--- a/Test/baseResults/hlsl.structbuffer.fn2.comp.out
+++ b/Test/baseResults/hlsl.structbuffer.fn2.comp.out
@@ -166,6 +166,7 @@
                               MemberDecorate 9 0 NonWritable
                               MemberDecorate 9 0 Offset 0
                               Decorate 9 BufferBlock
+                              Decorate 14(buffer) NonWritable
                               Decorate 44(g_input) DescriptorSet 0
                               Decorate 44(g_input) Binding 0
                               Decorate 50(g_output) DescriptorSet 0
diff --git a/Test/baseResults/spv.paramMemory.frag.out b/Test/baseResults/spv.paramMemory.frag.out
new file mode 100755
index 0000000..8b98b49
--- /dev/null
+++ b/Test/baseResults/spv.paramMemory.frag.out
@@ -0,0 +1,137 @@
+spv.paramMemory.frag
+// Module Version 10000
+// Generated by (magic number): 80001
+// Id's are bound by 69
+
+                              Capability Shader
+                              Capability StorageImageReadWithoutFormat
+                              Capability StorageImageWriteWithoutFormat
+               1:             ExtInstImport  "GLSL.std.450"
+                              MemoryModel Logical GLSL450
+                              EntryPoint Fragment 4  "main" 27 66
+                              ExecutionMode 4 OriginUpperLeft
+                              Source ESSL 310
+                              Name 4  "main"
+                              Name 16  "image_load(I21;vi2;"
+                              Name 14  "image"
+                              Name 15  "coords"
+                              Name 23  "image_store(I21;vi2;vf4;"
+                              Name 20  "image"
+                              Name 21  "coords"
+                              Name 22  "data"
+                              Name 27  "in_coords"
+                              Name 35  "read1"
+                              Name 38  "image1"
+                              Name 39  "param"
+                              Name 42  "read2"
+                              Name 45  "image2"
+                              Name 46  "param"
+                              Name 49  "image3"
+                              Name 53  "param"
+                              Name 55  "param"
+                              Name 57  "image4"
+                              Name 61  "param"
+                              Name 63  "param"
+                              Name 66  "out_color"
+                              Decorate 14(image) Coherent
+                              Decorate 14(image) NonWritable
+                              Decorate 20(image) Coherent
+                              Decorate 20(image) NonReadable
+                              Decorate 27(in_coords) Flat
+                              Decorate 27(in_coords) Location 0
+                              Decorate 38(image1) DescriptorSet 0
+                              Decorate 38(image1) Binding 0
+                              Decorate 38(image1) Coherent
+                              Decorate 38(image1) NonWritable
+                              Decorate 45(image2) DescriptorSet 0
+                              Decorate 45(image2) Binding 2
+                              Decorate 45(image2) NonWritable
+                              Decorate 49(image3) DescriptorSet 0
+                              Decorate 49(image3) Binding 1
+                              Decorate 49(image3) Coherent
+                              Decorate 49(image3) NonReadable
+                              Decorate 57(image4) DescriptorSet 0
+                              Decorate 57(image4) Binding 3
+                              Decorate 57(image4) NonReadable
+                              Decorate 66(out_color) Location 0
+               2:             TypeVoid
+               3:             TypeFunction 2
+               6:             TypeFloat 32
+               7:             TypeImage 6(float) 2D nonsampled format:Unknown
+               8:             TypePointer UniformConstant 7
+               9:             TypeInt 32 1
+              10:             TypeVector 9(int) 2
+              11:             TypePointer Function 10(ivec2)
+              12:             TypeVector 6(float) 4
+              13:             TypeFunction 12(fvec4) 8(ptr) 11(ptr)
+              18:             TypePointer Function 12(fvec4)
+              19:             TypeFunction 2 8(ptr) 11(ptr) 18(ptr)
+              26:             TypePointer Input 10(ivec2)
+   27(in_coords):     26(ptr) Variable Input
+              36:             TypeImage 6(float) 2D nonsampled format:Rgba32f
+              37:             TypePointer UniformConstant 36
+      38(image1):     37(ptr) Variable UniformConstant
+              43:             TypeImage 6(float) 2D nonsampled format:Rgba16f
+              44:             TypePointer UniformConstant 43
+      45(image2):     44(ptr) Variable UniformConstant
+      49(image3):     37(ptr) Variable UniformConstant
+              51:    6(float) Constant 1056964608
+      57(image4):     44(ptr) Variable UniformConstant
+              59:    6(float) Constant 1073741824
+              65:             TypePointer Output 12(fvec4)
+   66(out_color):     65(ptr) Variable Output
+              67:    6(float) Constant 0
+              68:   12(fvec4) ConstantComposite 67 67 67 67
+         4(main):           2 Function None 3
+               5:             Label
+       35(read1):     18(ptr) Variable Function
+       39(param):     11(ptr) Variable Function
+       42(read2):     18(ptr) Variable Function
+       46(param):     11(ptr) Variable Function
+       53(param):     11(ptr) Variable Function
+       55(param):     18(ptr) Variable Function
+       61(param):     11(ptr) Variable Function
+       63(param):     18(ptr) Variable Function
+              40:   10(ivec2) Load 27(in_coords)
+                              Store 39(param) 40
+              41:   12(fvec4) FunctionCall 16(image_load(I21;vi2;) 38(image1) 39(param)
+                              Store 35(read1) 41
+              47:   10(ivec2) Load 27(in_coords)
+                              Store 46(param) 47
+              48:   12(fvec4) FunctionCall 16(image_load(I21;vi2;) 45(image2) 46(param)
+                              Store 42(read2) 48
+              50:   12(fvec4) Load 35(read1)
+              52:   12(fvec4) VectorTimesScalar 50 51
+              54:   10(ivec2) Load 27(in_coords)
+                              Store 53(param) 54
+                              Store 55(param) 52
+              56:           2 FunctionCall 23(image_store(I21;vi2;vf4;) 49(image3) 53(param) 55(param)
+              58:   12(fvec4) Load 42(read2)
+              60:   12(fvec4) VectorTimesScalar 58 59
+              62:   10(ivec2) Load 27(in_coords)
+                              Store 61(param) 62
+                              Store 63(param) 60
+              64:           2 FunctionCall 23(image_store(I21;vi2;vf4;) 57(image4) 61(param) 63(param)
+                              Store 66(out_color) 68
+                              Return
+                              FunctionEnd
+16(image_load(I21;vi2;):   12(fvec4) Function None 13
+       14(image):      8(ptr) FunctionParameter
+      15(coords):     11(ptr) FunctionParameter
+              17:             Label
+              25:           7 Load 14(image)
+              28:   10(ivec2) Load 27(in_coords)
+              29:   12(fvec4) ImageRead 25 28
+                              ReturnValue 29
+                              FunctionEnd
+23(image_store(I21;vi2;vf4;):           2 Function None 19
+       20(image):      8(ptr) FunctionParameter
+      21(coords):     11(ptr) FunctionParameter
+        22(data):     18(ptr) FunctionParameter
+              24:             Label
+              32:           7 Load 20(image)
+              33:   10(ivec2) Load 27(in_coords)
+              34:   12(fvec4) Load 22(data)
+                              ImageWrite 32 33 34
+                              Return
+                              FunctionEnd
diff --git a/Test/hlsl.flattenOpaqueInit.vert b/Test/hlsl.flattenOpaqueInit.vert
new file mode 100644
index 0000000..5efb02e
--- /dev/null
+++ b/Test/hlsl.flattenOpaqueInit.vert
@@ -0,0 +1,13 @@
+struct FxaaTex { SamplerState smpl; Texture2D tex; };

+SamplerState g_tInputTexture_sampler; Texture2D g_tInputTexture;

+

+float4 lookUp(FxaaTex tex)

+{

+    return tex.tex.Sample(tex.smpl, float2(0.3, 0.4));

+}

+

+float4 main() : SV_TARGET0

+{

+    FxaaTex tex = { g_tInputTexture_sampler, g_tInputTexture };

+    return lookUp(tex);

+}
\ No newline at end of file
diff --git a/Test/hlsl.flattenOpaqueInitMix.vert b/Test/hlsl.flattenOpaqueInitMix.vert
new file mode 100644
index 0000000..2e712ee
--- /dev/null
+++ b/Test/hlsl.flattenOpaqueInitMix.vert
@@ -0,0 +1,13 @@
+struct FxaaTex { SamplerState smpl; Texture2D tex; float f; };

+SamplerState g_tInputTexture_sampler; Texture2D g_tInputTexture;

+

+float4 lookUp(FxaaTex tex)

+{

+    return tex.tex.Sample(tex.smpl, float2(tex.f, tex.f));

+}

+

+float4 main() : SV_TARGET0

+{

+    FxaaTex tex = { g_tInputTexture_sampler, g_tInputTexture, 0.5 };

+    return lookUp(tex);

+}
\ No newline at end of file
diff --git a/Test/spv.paramMemory.frag b/Test/spv.paramMemory.frag
new file mode 100644
index 0000000..79d2fe5
--- /dev/null
+++ b/Test/spv.paramMemory.frag
@@ -0,0 +1,30 @@
+#version 310 es
+
+readonly coherent uniform layout(set = 0, binding = 0, rgba32f) highp image2D image1;
+readonly uniform layout(set = 0, binding = 2, rgba16f) highp image2D image2;
+writeonly coherent uniform layout(set = 0, binding = 1, rgba32f) highp image2D image3;
+writeonly uniform layout(set = 0, binding = 3, rgba16f) highp image2D image4;
+
+flat in layout(location = 0) highp ivec2 in_coords;
+out layout(location = 0) highp vec4 out_color;
+
+highp vec4 image_load(readonly coherent highp image2D image, highp ivec2 coords)
+{
+	return imageLoad(image, in_coords);
+}
+
+void image_store(writeonly coherent highp image2D image, highp ivec2 coords, highp vec4 data)
+{
+	imageStore(image, in_coords, data);
+}
+
+void main()
+{
+	highp vec4 read1 = image_load(image1, in_coords);
+	highp vec4 read2 = image_load(image2, in_coords);
+	
+	image_store(image3, in_coords, read1*0.5);
+	image_store(image4, in_coords, read2*2.0);
+
+	out_color = vec4(0.0);
+}
diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp
index 46ddee8..1d56c1f 100644
--- a/glslang/MachineIndependent/ParseHelper.cpp
+++ b/glslang/MachineIndependent/ParseHelper.cpp
@@ -1386,7 +1386,6 @@
         unaryArg = callNode.getAsUnaryNode()->getOperand();
         arg0 = unaryArg;
     }
-    const TIntermSequence& aggArgs = *argp;  // only valid when unaryArg is nullptr
 
     switch (callNode.getOp()) {
     case EOpTextureGather:
@@ -1417,7 +1416,7 @@
                 profileRequires(loc, ~EEsProfile, 400, E_GL_ARB_texture_gather, feature);
             else
                 profileRequires(loc, ~EEsProfile, 400, E_GL_ARB_gpu_shader5, feature);
-            if (! aggArgs[fnCandidate[0].type->getSampler().shadow ? 3 : 2]->getAsConstantUnion())
+            if (! (*argp)[fnCandidate[0].type->getSampler().shadow ? 3 : 2]->getAsConstantUnion())
                 profileRequires(loc, EEsProfile, 0, Num_AEP_gpu_shader5, AEP_gpu_shader5, "non-constant offset argument");
             if (! fnCandidate[0].type->getSampler().shadow)
                 compArg = 3;
@@ -1427,7 +1426,7 @@
             if (! fnCandidate[0].type->getSampler().shadow)
                 compArg = 3;
             // check for constant offsets
-            if (! aggArgs[fnCandidate[0].type->getSampler().shadow ? 3 : 2]->getAsConstantUnion())
+            if (! (*argp)[fnCandidate[0].type->getSampler().shadow ? 3 : 2]->getAsConstantUnion())
                 error(loc, "must be a compile-time constant:", feature, "offsets argument");
             break;
         default:
@@ -1435,8 +1434,8 @@
         }
 
         if (compArg > 0 && compArg < fnCandidate.getParamCount()) {
-            if (aggArgs[compArg]->getAsConstantUnion()) {
-                int value = aggArgs[compArg]->getAsConstantUnion()->getConstArray()[0].getIConst();
+            if ((*argp)[compArg]->getAsConstantUnion()) {
+                int value = (*argp)[compArg]->getAsConstantUnion()->getConstArray()[0].getIConst();
                 if (value < 0 || value > 3)
                     error(loc, "must be 0, 1, 2, or 3:", feature, "component argument");
             } else
@@ -1518,12 +1517,12 @@
         }
 
         if (arg > 0) {
-            if (! aggArgs[arg]->getAsConstantUnion())
+            if (! (*argp)[arg]->getAsConstantUnion())
                 error(loc, "argument must be compile-time constant", "texel offset", "");
             else {
-                const TType& type = aggArgs[arg]->getAsTyped()->getType();
+                const TType& type = (*argp)[arg]->getAsTyped()->getType();
                 for (int c = 0; c < type.getVectorSize(); ++c) {
-                    int offset = aggArgs[arg]->getAsConstantUnion()->getConstArray()[c].getIConst();
+                    int offset = (*argp)[arg]->getAsConstantUnion()->getConstArray()[c].getIConst();
                     if (offset > resources.maxProgramTexelOffset || offset < resources.minProgramTexelOffset)
                         error(loc, "value is out of range:", "texel offset", "[gl_MinProgramTexelOffset, gl_MaxProgramTexelOffset]");
                 }
diff --git a/glslang/MachineIndependent/ShaderLang.cpp b/glslang/MachineIndependent/ShaderLang.cpp
index 26f81bd..93f1568 100644
--- a/glslang/MachineIndependent/ShaderLang.cpp
+++ b/glslang/MachineIndependent/ShaderLang.cpp
@@ -1836,6 +1836,7 @@
 const char* TProgram::getUniformBlockName(int index) const   { return reflection->getUniformBlock(index).name.c_str(); }
 int TProgram::getUniformBlockSize(int index) const           { return reflection->getUniformBlock(index).size; }
 int TProgram::getUniformIndex(const char* name) const        { return reflection->getIndex(name); }
+int TProgram::getUniformBinding(int index) const             { return reflection->getUniform(index).getBinding(); }
 int TProgram::getUniformBlockIndex(int index) const          { return reflection->getUniform(index).index; }
 int TProgram::getUniformBlockCounterIndex(int index) const   { return reflection->getUniformBlock(index).counterIndex; }
 int TProgram::getUniformType(int index) const                { return reflection->getUniform(index).glDefineType; }
diff --git a/glslang/MachineIndependent/reflection.h b/glslang/MachineIndependent/reflection.h
index 7a1cc8e..fedfbe8 100644
--- a/glslang/MachineIndependent/reflection.h
+++ b/glslang/MachineIndependent/reflection.h
@@ -59,7 +59,15 @@
         name(pName), offset(pOffset),
         glDefineType(pGLDefineType), size(pSize), index(pIndex), counterIndex(-1), type(pType.clone()) { }
 
-    void dump() const {
+    const TType* const getType() const { return type; }
+    int getBinding() const
+    {
+        if (type == nullptr || !type->getQualifier().hasBinding())
+            return -1;
+        return type->getQualifier().layoutBinding;
+    }
+    void dump() const
+    {
         printf("%s: offset %d, type %x, size %d, index %d, binding %d",
                name.c_str(), offset, glDefineType, size, index, getBinding() );
 
@@ -68,8 +76,7 @@
 
         printf("\n");
     }
-
-    const TType* const getType() const { return type; }
+    static TObjectReflection badReflection() { return TObjectReflection(); }
 
     TString name;
     int offset;
@@ -78,15 +85,7 @@
     int index;
     int counterIndex;
 
-    static TObjectReflection badReflection() { return TObjectReflection(); }
-
 protected:
-    int getBinding() const {
-        if (type == nullptr || type->getQualifier().layoutBinding == TQualifier::layoutBindingEnd)
-            return -1;
-        return type->getQualifier().layoutBinding;
-    }
-
     TObjectReflection() : offset(-1), glDefineType(-1), size(-1), index(-1), type(nullptr) { }
 
     const TType* type;
diff --git a/glslang/Public/ShaderLang.h b/glslang/Public/ShaderLang.h
index 2a02478..12672ee 100644
--- a/glslang/Public/ShaderLang.h
+++ b/glslang/Public/ShaderLang.h
@@ -619,6 +619,7 @@
     const char* getUniformBlockName(int blockIndex) const; // can be used for glGetActiveUniformBlockName()
     int getUniformBlockSize(int blockIndex) const;         // can be used for glGetActiveUniformBlockiv(UNIFORM_BLOCK_DATA_SIZE)
     int getUniformIndex(const char* name) const;           // can be used for glGetUniformIndices()
+    int getUniformBinding(int index) const;                // returns the binding number
     int getUniformBlockIndex(int index) const;             // can be used for glGetActiveUniformsiv(GL_UNIFORM_BLOCK_INDEX)
     int getUniformBlockCounterIndex(int index) const;      // returns block index of associated counter.
     int getUniformType(int index) const;                   // can be used for glGetActiveUniformsiv(GL_UNIFORM_TYPE)
diff --git a/gtests/Hlsl.FromFile.cpp b/gtests/Hlsl.FromFile.cpp
index ea90b62..21f606e 100644
--- a/gtests/Hlsl.FromFile.cpp
+++ b/gtests/Hlsl.FromFile.cpp
@@ -122,6 +122,8 @@
         {"hlsl.float4.frag", "PixelShaderFunction"},
         {"hlsl.flatten.return.frag", "main"},
         {"hlsl.flattenOpaque.frag", "main"},
+        {"hlsl.flattenOpaqueInit.vert", "main"},
+        {"hlsl.flattenOpaqueInitMix.vert", "main"},
         {"hlsl.forLoop.frag", "PixelShaderFunction"},
         {"hlsl.gather.array.dx10.frag", "main"},
         {"hlsl.gather.basic.dx10.frag", "main"},
diff --git a/gtests/Spv.FromFile.cpp b/gtests/Spv.FromFile.cpp
index 268aa0b..dfad30c 100644
--- a/gtests/Spv.FromFile.cpp
+++ b/gtests/Spv.FromFile.cpp
@@ -275,6 +275,7 @@
         "spv.noWorkgroup.comp",
         "spv.offsets.frag",
         "spv.Operations.frag",
+        "spv.paramMemory.frag",
         "spv.precision.frag",
         "spv.prepost.frag",
         "spv.qualifiers.vert",
diff --git a/hlsl/hlslParseHelper.cpp b/hlsl/hlslParseHelper.cpp
index 0c64c71..dc44c36 100755
--- a/hlsl/hlslParseHelper.cpp
+++ b/hlsl/hlslParseHelper.cpp
@@ -506,12 +506,14 @@
 }
 
 // Deal with sampler aliasing: turning assignments into aliases
+// Return a placeholder node for higher-level code that think assignments must
+// generate code.
 TIntermTyped* HlslParseContext::handleSamplerLvalue(const TSourceLoc& loc, const char* op, TIntermTyped*& node)
 {
     // Can only alias an assignment:  "s1 = s2"
     TIntermBinary* binary = node->getAsBinaryNode();
     if (binary == nullptr || node->getAsOperator()->getOp() != EOpAssign ||
-        binary->getLeft() ->getAsSymbolNode() == nullptr ||
+        binary->getLeft()->getAsSymbolNode() == nullptr ||
         binary->getRight()->getAsSymbolNode() == nullptr) {
         error(loc, "can't modify sampler", op, "");
         return node;
@@ -520,11 +522,25 @@
     if (controlFlowNestingLevel > 0)
         warn(loc, "sampler or image aliased under control flow; consumption must be in same path", op, "");
 
+    TIntermTyped* set = setOpaqueLvalue(binary->getLeft(), binary->getRight());
+    if (set == nullptr)
+        warn(loc, "could not create alias for sampler", op, "");
+    else
+        node = set;
+
+    return node;
+}
+
+// Do an opaque assignment that needs to turn into an alias.
+// Return nullptr if it can't be done, otherwise return a placeholder
+// node for higher-level code that think assignments must generate code.
+TIntermTyped* HlslParseContext::setOpaqueLvalue(TIntermTyped* leftTyped, TIntermTyped* rightTyped)
+{
     // Best is if we are aliasing a flattened struct member "S.s1 = s2",
     // in which case we want to update the flattening information with the alias,
     // making everything else work seamlessly.
-    TIntermSymbol* left = binary->getLeft()->getAsSymbolNode();
-    TIntermSymbol* right = binary->getRight()->getAsSymbolNode();
+    TIntermSymbol* left = leftTyped->getAsSymbolNode();
+    TIntermSymbol* right = rightTyped->getAsSymbolNode();
     for (auto fit = flattenMap.begin(); fit != flattenMap.end(); ++fit) {
         for (auto mit = fit->second.members.begin(); mit != fit->second.members.end(); ++mit) {
             if ((*mit)->getUniqueId() == left->getId()) {
@@ -533,15 +549,12 @@
                 (*mit)->setUniqueId(right->getId());
                 // replace node (rest of compiler expects either an error or code to generate)
                 // with pointless access
-                node = binary->getRight();
-                return node;
+                return right;
             }
         }
     }
 
-    warn(loc, "could not create alias for sampler", op, "");
-
-    return node;
+    return nullptr;
 }
 
 void HlslParseContext::handlePragma(const TSourceLoc& loc, const TVector<TString>& tokens)
@@ -2412,6 +2425,34 @@
     return assignList;
 }
 
+// For a declaration with an initializer, where the initialized symbol is flattened,
+// and possibly contains opaque values, such that the initializer should never exist
+// as emitted code, because even creating the initializer would write opaques.
+//
+// Decompose this into individual member-wise assignments, which themselves are
+// expected to then not exist for opaque types, because they will turn into aliases.
+//
+// Return a node that contains the non-aliased assignments that must continue to exist.
+TIntermAggregate* HlslParseContext::flattenedInit(const TSourceLoc& loc, TIntermSymbol* symbol, const TIntermAggregate& initializer)
+{
+    TIntermAggregate* initList = nullptr;
+    // synthesize an access to each member, and then an assignment to it
+    const TTypeList& typeList = *symbol->getType().getStruct();
+    for (int member = 0; member < (int)typeList.size(); ++member) {
+        TIntermTyped* memberInitializer = initializer.getSequence()[member]->getAsTyped();
+        TIntermTyped* flattenedMember = flattenAccess(symbol, member);
+        if (flattenedMember->getType().containsOpaque())
+            setOpaqueLvalue(flattenedMember, memberInitializer);
+        else
+            initList = intermediate.growAggregate(initList, handleAssign(loc, EOpAssign, flattenedMember,
+                                                  memberInitializer));
+    }
+
+    if (initList)
+        initList->setOperator(EOpSequence);
+    return initList;
+}
+
 // Some simple source assignments need to be flattened to a sequence
 // of AST assignments. Catch these and flatten, otherwise, pass through
 // to intermediate.addAssign().
@@ -2449,7 +2490,7 @@
 
     // A temporary to store the right node's value, so we don't keep indirecting into it
     // if it's not a simple symbol.
-    TVariable*     rhsTempVar   = nullptr;
+    TVariable* rhsTempVar = nullptr;
 
     // If the RHS is a simple symbol node, we'll copy it for each member.
     TIntermSymbol* cloneSymNode = nullptr;
@@ -7228,27 +7269,22 @@
             error(loc, "cannot change the type of", "redeclaration", symbol->getName().c_str());
     }
 
-    if (flattenVar)
-        flatten(loc, *symbol->getAsVariable());
-
     if (symbol == nullptr)
         return nullptr;
 
+    if (flattenVar)
+        flatten(loc, *symbol->getAsVariable());
+
+    if (initializer == nullptr)
+        return nullptr;
+
     // Deal with initializer
-    TIntermNode* initNode = nullptr;
-    if (symbol && initializer) {
-        if (flattenVar)
-            error(loc, "flattened array with initializer list unsupported", identifier.c_str(), "");
-
-        TVariable* variable = symbol->getAsVariable();
-        if (variable == nullptr) {
-            error(loc, "initializer requires a variable, not a member", identifier.c_str(), "");
-            return nullptr;
-        }
-        initNode = executeInitializer(loc, initializer, variable);
+    TVariable* variable = symbol->getAsVariable();
+    if (variable == nullptr) {
+        error(loc, "initializer requires a variable, not a member", identifier.c_str(), "");
+        return nullptr;
     }
-
-    return initNode;
+    return executeInitializer(loc, initializer, variable, flattenVar);
 }
 
 // Pick up global defaults from the provide global defaults into dst.
@@ -7314,7 +7350,7 @@
 // Returning nullptr just means there is no code to execute to handle the
 // initializer, which will, for example, be the case for constant initializers.
 //
-TIntermNode* HlslParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyped* initializer, TVariable* variable)
+TIntermNode* HlslParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyped* initializer, TVariable* variable, bool flattened)
 {
     //
     // Identifier must be of type constant, a global, or a temporary, and
@@ -7335,6 +7371,7 @@
     TType skeletalType;
     skeletalType.shallowCopy(variable->getType());
     skeletalType.getQualifier().makeTemporary();
+    TIntermAggregate* initializerList = nullptr;
     if (initializer->getAsAggregate() && initializer->getAsAggregate()->getOp() == EOpNull)
         initializer = convertInitializerList(loc, skeletalType, initializer, nullptr);
     if (initializer == nullptr) {
@@ -7394,11 +7431,20 @@
         // normal assigning of a value to a variable...
         specializationCheck(loc, initializer->getType(), "initializer");
         TIntermSymbol* intermSymbol = intermediate.addSymbol(*variable, loc);
-        TIntermNode* initNode = handleAssign(loc, EOpAssign, intermSymbol, initializer);
-        if (initNode == nullptr)
-            assignError(loc, "=", intermSymbol->getCompleteString(), initializer->getCompleteString());
 
-        return initNode;
+        // If we are flattening, it could be due to setting opaques, which must be handled
+        // as aliases, and the 'initializer' node cannot actually be emitted, because it
+        // itself stores the result of the constructor, and we can't store to opaques.
+        // handleAssign() will emit the initializer.
+        TIntermNode* initNode = nullptr;
+        if (flattened && intermSymbol->getType().containsOpaque())
+            return flattenedInit(loc, intermSymbol, *initializer->getAsAggregate());
+        else {
+            initNode = handleAssign(loc, EOpAssign, intermSymbol, initializer);
+            if (initNode == nullptr)
+                assignError(loc, "=", intermSymbol->getCompleteString(), initializer->getCompleteString());
+            return initNode;
+        }
     }
 
     return nullptr;
diff --git a/hlsl/hlslParseHelper.h b/hlsl/hlslParseHelper.h
index 713e830..2d507c3 100755
--- a/hlsl/hlslParseHelper.h
+++ b/hlsl/hlslParseHelper.h
@@ -87,6 +87,7 @@
     void remapNonEntryPointIO(TFunction& function);
     TIntermNode* handleReturnValue(const TSourceLoc&, TIntermTyped*);
     void handleFunctionArgument(TFunction*, TIntermTyped*& arguments, TIntermTyped* newArg);
+    TIntermAggregate* flattenedInit(const TSourceLoc&, TIntermSymbol*, const TIntermAggregate&);
     TIntermTyped* handleAssign(const TSourceLoc&, TOperator, TIntermTyped* left, TIntermTyped* right);
     TIntermTyped* handleAssignToMatrixSwizzle(const TSourceLoc&, TOperator, TIntermTyped* left, TIntermTyped* right);
     TIntermTyped* handleFunctionCall(const TSourceLoc&, TFunction*, TIntermTyped*);
@@ -191,6 +192,7 @@
     // Apply L-value conversions.  E.g, turning a write to a RWTexture into an ImageStore.
     TIntermTyped* handleLvalue(const TSourceLoc&, const char* op, TIntermTyped*& node);
     TIntermTyped* handleSamplerLvalue(const TSourceLoc&, const char* op, TIntermTyped*& node);
+    TIntermTyped* setOpaqueLvalue(TIntermTyped* left, TIntermTyped* right);
     bool lValueErrorCheck(const TSourceLoc&, const char* op, TIntermTyped*) override;
 
     TLayoutFormat getLayoutFromTxType(const TSourceLoc&, const TType&);
@@ -231,7 +233,7 @@
     TIntermSymbol* makeInternalVariableNode(const TSourceLoc&, const char* name, const TType&) const;
     TVariable* declareNonArray(const TSourceLoc&, const TString& identifier, const TType&, bool track);
     void declareArray(const TSourceLoc&, const TString& identifier, const TType&, TSymbol*&, bool track);
-    TIntermNode* executeInitializer(const TSourceLoc&, TIntermTyped* initializer, TVariable* variable);
+    TIntermNode* executeInitializer(const TSourceLoc&, TIntermTyped* initializer, TVariable* variable, bool flattened);
     TIntermTyped* convertInitializerList(const TSourceLoc&, const TType&, TIntermTyped* initializer, TIntermTyped* scalarInit);
     bool isScalarConstructor(const TIntermNode*);
     TOperator mapAtomicOp(const TSourceLoc& loc, TOperator op, bool isImage);