Merge pull request #1011 from LoopDawg/pragma-pack-matrix

HLSL: implement #pragma pack_matrix(layout)
diff --git a/Test/baseResults/hlsl.flattenOpaque.frag.out b/Test/baseResults/hlsl.flattenOpaque.frag.out
index 392ff72..90b28c4 100755
--- a/Test/baseResults/hlsl.flattenOpaque.frag.out
+++ b/Test/baseResults/hlsl.flattenOpaque.frag.out
@@ -81,6 +81,9 @@
 0:35        Function Call: @main( ( temp 4-component vector of float)
 0:?   Linker Objects
 0:?     'tex' ( uniform texture2D)
+0:?     's2D' ( uniform sampler)
+0:?     's2D' ( uniform sampler)
+0:?     'tex' ( uniform texture2D)
 0:?     '@entryPointOutput' (layout( location=0) out 4-component vector of float)
 
 
@@ -169,6 +172,9 @@
 0:35        Function Call: @main( ( temp 4-component vector of float)
 0:?   Linker Objects
 0:?     'tex' ( uniform texture2D)
+0:?     's2D' ( uniform sampler)
+0:?     's2D' ( uniform sampler)
+0:?     'tex' ( uniform texture2D)
 0:?     '@entryPointOutput' (layout( location=0) out 4-component vector of float)
 
 // Module Version 10000
diff --git a/Test/baseResults/hlsl.structarray.flatten.frag.out b/Test/baseResults/hlsl.structarray.flatten.frag.out
index d70af80..c58f6b8 100644
--- a/Test/baseResults/hlsl.structarray.flatten.frag.out
+++ b/Test/baseResults/hlsl.structarray.flatten.frag.out
@@ -46,18 +46,33 @@
 0:?   Linker Objects
 0:?     'g_samp' ( uniform sampler)
 0:?     'g_tex' ( uniform texture1D)
+0:?     'samp' ( uniform sampler)
+0:?     'tex' ( uniform texture1D)
+0:?     'nonopaque_thing' ( uniform int)
+0:?     'g_texdata_array[0].samp' ( uniform sampler)
+0:?     'g_texdata_array[0].tex' ( uniform texture1D)
+0:?     'g_texdata_array[0].nonopaque_thing' ( uniform int)
+0:?     'g_texdata_array[1].samp' ( uniform sampler)
+0:?     'g_texdata_array[1].tex' ( uniform texture1D)
+0:?     'g_texdata_array[1].nonopaque_thing' ( uniform int)
+0:?     'g_texdata_array[2].samp' ( uniform sampler)
+0:?     'g_texdata_array[2].tex' ( uniform texture1D)
+0:?     'g_texdata_array[2].nonopaque_thing' ( uniform int)
 0:?     'g_texdata_array2[0].samp[0]' ( uniform sampler)
 0:?     'g_texdata_array2[0].samp[1]' ( uniform sampler)
 0:?     'g_texdata_array2[0].tex[0]' ( uniform texture1D)
 0:?     'g_texdata_array2[0].tex[1]' ( uniform texture1D)
+0:?     'g_texdata_array2[0].nonopaque_thing' ( uniform int)
 0:?     'g_texdata_array2[1].samp[0]' ( uniform sampler)
 0:?     'g_texdata_array2[1].samp[1]' ( uniform sampler)
 0:?     'g_texdata_array2[1].tex[0]' ( uniform texture1D)
 0:?     'g_texdata_array2[1].tex[1]' ( uniform texture1D)
+0:?     'g_texdata_array2[1].nonopaque_thing' ( uniform int)
 0:?     'g_texdata_array2[2].samp[0]' ( uniform sampler)
 0:?     'g_texdata_array2[2].samp[1]' ( uniform sampler)
 0:?     'g_texdata_array2[2].tex[0]' ( uniform texture1D)
 0:?     'g_texdata_array2[2].tex[1]' ( uniform texture1D)
+0:?     'g_texdata_array2[2].nonopaque_thing' ( uniform int)
 0:?     'color' (layout( location=0) out 4-component vector of float)
 
 
@@ -111,23 +126,38 @@
 0:?   Linker Objects
 0:?     'g_samp' ( uniform sampler)
 0:?     'g_tex' ( uniform texture1D)
+0:?     'samp' ( uniform sampler)
+0:?     'tex' ( uniform texture1D)
+0:?     'nonopaque_thing' ( uniform int)
+0:?     'g_texdata_array[0].samp' ( uniform sampler)
+0:?     'g_texdata_array[0].tex' ( uniform texture1D)
+0:?     'g_texdata_array[0].nonopaque_thing' ( uniform int)
+0:?     'g_texdata_array[1].samp' ( uniform sampler)
+0:?     'g_texdata_array[1].tex' ( uniform texture1D)
+0:?     'g_texdata_array[1].nonopaque_thing' ( uniform int)
+0:?     'g_texdata_array[2].samp' ( uniform sampler)
+0:?     'g_texdata_array[2].tex' ( uniform texture1D)
+0:?     'g_texdata_array[2].nonopaque_thing' ( uniform int)
 0:?     'g_texdata_array2[0].samp[0]' ( uniform sampler)
 0:?     'g_texdata_array2[0].samp[1]' ( uniform sampler)
 0:?     'g_texdata_array2[0].tex[0]' ( uniform texture1D)
 0:?     'g_texdata_array2[0].tex[1]' ( uniform texture1D)
+0:?     'g_texdata_array2[0].nonopaque_thing' ( uniform int)
 0:?     'g_texdata_array2[1].samp[0]' ( uniform sampler)
 0:?     'g_texdata_array2[1].samp[1]' ( uniform sampler)
 0:?     'g_texdata_array2[1].tex[0]' ( uniform texture1D)
 0:?     'g_texdata_array2[1].tex[1]' ( uniform texture1D)
+0:?     'g_texdata_array2[1].nonopaque_thing' ( uniform int)
 0:?     'g_texdata_array2[2].samp[0]' ( uniform sampler)
 0:?     'g_texdata_array2[2].samp[1]' ( uniform sampler)
 0:?     'g_texdata_array2[2].tex[0]' ( uniform texture1D)
 0:?     'g_texdata_array2[2].tex[1]' ( uniform texture1D)
+0:?     'g_texdata_array2[2].nonopaque_thing' ( uniform int)
 0:?     'color' (layout( location=0) out 4-component vector of float)
 
 // Module Version 10000
 // Generated by (magic number): 80001
-// Id's are bound by 66
+// Id's are bound by 78
 
                               Capability Shader
                               Capability Sampled1D
@@ -152,16 +182,27 @@
                               Name 51  "color"
                               Name 54  "g_samp"
                               Name 55  "g_tex"
-                              Name 56  "g_texdata_array2[0].samp[0]"
-                              Name 57  "g_texdata_array2[0].samp[1]"
-                              Name 58  "g_texdata_array2[0].tex[0]"
-                              Name 59  "g_texdata_array2[0].tex[1]"
-                              Name 60  "g_texdata_array2[1].samp[1]"
-                              Name 61  "g_texdata_array2[1].tex[1]"
-                              Name 62  "g_texdata_array2[2].samp[0]"
-                              Name 63  "g_texdata_array2[2].samp[1]"
-                              Name 64  "g_texdata_array2[2].tex[0]"
-                              Name 65  "g_texdata_array2[2].tex[1]"
+                              Name 57  "nonopaque_thing"
+                              Name 58  "g_texdata_array[0].samp"
+                              Name 59  "g_texdata_array[0].tex"
+                              Name 60  "g_texdata_array[0].nonopaque_thing"
+                              Name 61  "g_texdata_array[1].nonopaque_thing"
+                              Name 62  "g_texdata_array[2].samp"
+                              Name 63  "g_texdata_array[2].tex"
+                              Name 64  "g_texdata_array[2].nonopaque_thing"
+                              Name 65  "g_texdata_array2[0].samp[0]"
+                              Name 66  "g_texdata_array2[0].samp[1]"
+                              Name 67  "g_texdata_array2[0].tex[0]"
+                              Name 68  "g_texdata_array2[0].tex[1]"
+                              Name 69  "g_texdata_array2[0].nonopaque_thing"
+                              Name 70  "g_texdata_array2[1].samp[1]"
+                              Name 71  "g_texdata_array2[1].tex[1]"
+                              Name 72  "g_texdata_array2[1].nonopaque_thing"
+                              Name 73  "g_texdata_array2[2].samp[0]"
+                              Name 74  "g_texdata_array2[2].samp[1]"
+                              Name 75  "g_texdata_array2[2].tex[0]"
+                              Name 76  "g_texdata_array2[2].tex[1]"
+                              Name 77  "g_texdata_array2[2].nonopaque_thing"
                               Decorate 18(tex) DescriptorSet 0
                               Decorate 22(samp) DescriptorSet 0
                               Decorate 28(g_texdata_array[1].tex) DescriptorSet 0
@@ -171,16 +212,20 @@
                               Decorate 51(color) Location 0
                               Decorate 54(g_samp) DescriptorSet 0
                               Decorate 55(g_tex) DescriptorSet 0
-                              Decorate 56(g_texdata_array2[0].samp[0]) DescriptorSet 0
-                              Decorate 57(g_texdata_array2[0].samp[1]) DescriptorSet 0
-                              Decorate 58(g_texdata_array2[0].tex[0]) DescriptorSet 0
-                              Decorate 59(g_texdata_array2[0].tex[1]) DescriptorSet 0
-                              Decorate 60(g_texdata_array2[1].samp[1]) DescriptorSet 0
-                              Decorate 61(g_texdata_array2[1].tex[1]) DescriptorSet 0
-                              Decorate 62(g_texdata_array2[2].samp[0]) DescriptorSet 0
-                              Decorate 63(g_texdata_array2[2].samp[1]) DescriptorSet 0
-                              Decorate 64(g_texdata_array2[2].tex[0]) DescriptorSet 0
-                              Decorate 65(g_texdata_array2[2].tex[1]) DescriptorSet 0
+                              Decorate 58(g_texdata_array[0].samp) DescriptorSet 0
+                              Decorate 59(g_texdata_array[0].tex) DescriptorSet 0
+                              Decorate 62(g_texdata_array[2].samp) DescriptorSet 0
+                              Decorate 63(g_texdata_array[2].tex) DescriptorSet 0
+                              Decorate 65(g_texdata_array2[0].samp[0]) DescriptorSet 0
+                              Decorate 66(g_texdata_array2[0].samp[1]) DescriptorSet 0
+                              Decorate 67(g_texdata_array2[0].tex[0]) DescriptorSet 0
+                              Decorate 68(g_texdata_array2[0].tex[1]) DescriptorSet 0
+                              Decorate 70(g_texdata_array2[1].samp[1]) DescriptorSet 0
+                              Decorate 71(g_texdata_array2[1].tex[1]) DescriptorSet 0
+                              Decorate 73(g_texdata_array2[2].samp[0]) DescriptorSet 0
+                              Decorate 74(g_texdata_array2[2].samp[1]) DescriptorSet 0
+                              Decorate 75(g_texdata_array2[2].tex[0]) DescriptorSet 0
+                              Decorate 76(g_texdata_array2[2].tex[1]) DescriptorSet 0
                2:             TypeVoid
                3:             TypeFunction 2
                6:             TypeFloat 32
@@ -209,16 +254,28 @@
        51(color):     50(ptr) Variable Output
       54(g_samp):     21(ptr) Variable UniformConstant
        55(g_tex):     17(ptr) Variable UniformConstant
-56(g_texdata_array2[0].samp[0]):     21(ptr) Variable UniformConstant
-57(g_texdata_array2[0].samp[1]):     21(ptr) Variable UniformConstant
-58(g_texdata_array2[0].tex[0]):     17(ptr) Variable UniformConstant
-59(g_texdata_array2[0].tex[1]):     17(ptr) Variable UniformConstant
-60(g_texdata_array2[1].samp[1]):     21(ptr) Variable UniformConstant
-61(g_texdata_array2[1].tex[1]):     17(ptr) Variable UniformConstant
-62(g_texdata_array2[2].samp[0]):     21(ptr) Variable UniformConstant
-63(g_texdata_array2[2].samp[1]):     21(ptr) Variable UniformConstant
-64(g_texdata_array2[2].tex[0]):     17(ptr) Variable UniformConstant
-65(g_texdata_array2[2].tex[1]):     17(ptr) Variable UniformConstant
+              56:             TypePointer UniformConstant 14(int)
+57(nonopaque_thing):     56(ptr) Variable UniformConstant
+58(g_texdata_array[0].samp):     21(ptr) Variable UniformConstant
+59(g_texdata_array[0].tex):     17(ptr) Variable UniformConstant
+60(g_texdata_array[0].nonopaque_thing):     56(ptr) Variable UniformConstant
+61(g_texdata_array[1].nonopaque_thing):     56(ptr) Variable UniformConstant
+62(g_texdata_array[2].samp):     21(ptr) Variable UniformConstant
+63(g_texdata_array[2].tex):     17(ptr) Variable UniformConstant
+64(g_texdata_array[2].nonopaque_thing):     56(ptr) Variable UniformConstant
+65(g_texdata_array2[0].samp[0]):     21(ptr) Variable UniformConstant
+66(g_texdata_array2[0].samp[1]):     21(ptr) Variable UniformConstant
+67(g_texdata_array2[0].tex[0]):     17(ptr) Variable UniformConstant
+68(g_texdata_array2[0].tex[1]):     17(ptr) Variable UniformConstant
+69(g_texdata_array2[0].nonopaque_thing):     56(ptr) Variable UniformConstant
+70(g_texdata_array2[1].samp[1]):     21(ptr) Variable UniformConstant
+71(g_texdata_array2[1].tex[1]):     17(ptr) Variable UniformConstant
+72(g_texdata_array2[1].nonopaque_thing):     56(ptr) Variable UniformConstant
+73(g_texdata_array2[2].samp[0]):     21(ptr) Variable UniformConstant
+74(g_texdata_array2[2].samp[1]):     21(ptr) Variable UniformConstant
+75(g_texdata_array2[2].tex[0]):     17(ptr) Variable UniformConstant
+76(g_texdata_array2[2].tex[1]):     17(ptr) Variable UniformConstant
+77(g_texdata_array2[2].nonopaque_thing):     56(ptr) Variable UniformConstant
          4(main):           2 Function None 3
                5:             Label
    46(ps_output):      9(ptr) Variable Function
diff --git a/Test/baseResults/hlsl.structin.vert.out b/Test/baseResults/hlsl.structin.vert.out
index 1256eec..87749e2 100755
--- a/Test/baseResults/hlsl.structin.vert.out
+++ b/Test/baseResults/hlsl.structin.vert.out
@@ -155,8 +155,6 @@
 0:?     'd' (layout( location=0) in 4-component vector of float)
 0:?     'm[0]' (layout( location=1) in 4-component vector of float)
 0:?     'm[1]' (layout( location=2) in 4-component vector of float)
-0:?     'm[0]' (layout( location=1) in 4-component vector of float)
-0:?     'm[1]' (layout( location=2) in 4-component vector of float)
 0:?     'coord' (layout( location=3) in 4-component vector of float)
 0:?     'b' (layout( location=4) in 4-component vector of float)
 0:?     'e' (layout( location=5) in 4-component vector of float)
@@ -321,8 +319,6 @@
 0:?     'd' (layout( location=0) in 4-component vector of float)
 0:?     'm[0]' (layout( location=1) in 4-component vector of float)
 0:?     'm[1]' (layout( location=2) in 4-component vector of float)
-0:?     'm[0]' (layout( location=1) in 4-component vector of float)
-0:?     'm[1]' (layout( location=2) in 4-component vector of float)
 0:?     'coord' (layout( location=3) in 4-component vector of float)
 0:?     'b' (layout( location=4) in 4-component vector of float)
 0:?     'e' (layout( location=5) in 4-component vector of float)
diff --git a/hlsl/hlslParseHelper.cpp b/hlsl/hlslParseHelper.cpp
index 6ca5d2e..32d1067 100755
--- a/hlsl/hlslParseHelper.cpp
+++ b/hlsl/hlslParseHelper.cpp
@@ -1128,7 +1128,7 @@
 {
     // Create a new variable:
     TType& splitType = split(*variable.getType().clone(), variable.getName());
-    splitIoVars[variable.getUniqueId()] = makeInternalVariable(variable.getName(), splitType);
+    splitNonIoVars[variable.getUniqueId()] = makeInternalVariable(variable.getName(), splitType);
 }
 
 // Recursive implementation of split().
@@ -1191,7 +1191,7 @@
 }
 
 // Top level variable flattening: construct data
-void HlslParseContext::flatten(const TVariable& variable)
+void HlslParseContext::flatten(const TVariable& variable, bool linkage)
 {
     const TType& type = variable.getType();
 
@@ -1200,7 +1200,7 @@
                                                                type.getQualifier().layoutLocation)));
 
     // the item is a map pair, so first->second is the TFlattenData itself.
-    flatten(variable, type, entry.first->second, "");
+    flatten(variable, type, entry.first->second, "", linkage);
 }
 
 // Recursively flatten the given variable at the provided type, building the flattenData as we go.
@@ -1231,14 +1231,14 @@
 // so the 4th flattened member in traversal order is ours.
 //
 int HlslParseContext::flatten(const TVariable& variable, const TType& type,
-                              TFlattenData& flattenData, TString name)
+                              TFlattenData& flattenData, TString name, bool linkage)
 {
     // If something is an arrayed struct, the array flattener will recursively call flatten()
     // to then flatten the struct, so this is an "if else": we don't do both.
     if (type.isArray())
-        return flattenArray(variable, type, flattenData, name);
+        return flattenArray(variable, type, flattenData, name, linkage);
     else if (type.isStruct())
-        return flattenStruct(variable, type, flattenData, name);
+        return flattenStruct(variable, type, flattenData, name, linkage);
     else {
         assert(0); // should never happen
         return -1;
@@ -1248,7 +1248,7 @@
 // Add a single flattened member to the flattened data being tracked for the composite
 // Returns true for the final flattening level.
 int HlslParseContext::addFlattenedMember(const TVariable& variable, const TType& type, TFlattenData& flattenData,
-                                         const TString& memberName, bool track)
+                                         const TString& memberName, bool linkage)
 {
     if (isFinalFlattening(type)) {
         // This is as far as we flatten.  Insert the variable.
@@ -1274,13 +1274,13 @@
         flattenData.offsets.push_back(static_cast<int>(flattenData.members.size()));
         flattenData.members.push_back(memberVariable);
 
-        if (track)
+        if (linkage)
             trackLinkage(*memberVariable);
 
-        return static_cast<int>(flattenData.offsets.size())-1; // location of the member reference
+        return static_cast<int>(flattenData.offsets.size()) - 1; // location of the member reference
     } else {
         // Further recursion required
-        return flatten(variable, type, flattenData, memberName);
+        return flatten(variable, type, flattenData, memberName, linkage);
     }
 }
 
@@ -1289,7 +1289,7 @@
 //
 // Assumes shouldFlatten() or equivalent was called first.
 int HlslParseContext::flattenStruct(const TVariable& variable, const TType& type,
-                                    TFlattenData& flattenData, TString name)
+                                    TFlattenData& flattenData, TString name, bool linkage)
 {
     assert(type.isStruct());
 
@@ -1304,7 +1304,7 @@
         TType& dereferencedType = *members[member].type;
         const TString memberName = name + (name.empty() ? "" : ".") + dereferencedType.getFieldName();
 
-        const int mpos = addFlattenedMember(variable, dereferencedType, flattenData, memberName, false);
+        const int mpos = addFlattenedMember(variable, dereferencedType, flattenData, memberName, linkage);
         flattenData.offsets[pos++] = mpos;
     }
 
@@ -1316,7 +1316,7 @@
 //
 // Assumes shouldFlatten() or equivalent was called first.
 int HlslParseContext::flattenArray(const TVariable& variable, const TType& type,
-                                   TFlattenData& flattenData, TString name)
+                                   TFlattenData& flattenData, TString name, bool linkage)
 {
     assert(type.isArray() && !type.isImplicitlySizedArray());
 
@@ -1335,7 +1335,7 @@
         char elementNumBuf[20];  // sufficient for MAXINT
         snprintf(elementNumBuf, sizeof(elementNumBuf)-1, "[%d]", element);
         const int mpos = addFlattenedMember(variable, dereferencedType, flattenData,
-                                            name + elementNumBuf, true);
+                                            name + elementNumBuf, linkage);
 
         flattenData.offsets[pos++] = mpos;
     }
@@ -1397,13 +1397,13 @@
 }
 
 // Find and return the split IO TVariable for id, or nullptr if none.
-TVariable* HlslParseContext::getSplitIoVar(int id) const
+TVariable* HlslParseContext::getSplitNonIoVar(int id) const
 {
-    const auto splitIoVar = splitIoVars.find(id);
-    if (splitIoVar == splitIoVars.end())
+    const auto splitNonIoVar = splitNonIoVars.find(id);
+    if (splitNonIoVar == splitNonIoVars.end())
         return nullptr;
 
-    return splitIoVar->second;
+    return splitNonIoVar->second;
 }
 
 // Pass through to base class after remembering built-in mappings.
@@ -1513,7 +1513,7 @@
         for (auto member = memberList.begin(); member != memberList.end(); ++member)
             assignLocation(**member);
     } else if (wasSplit(variable.getUniqueId())) {
-        TVariable* splitIoVar = getSplitIoVar(variable.getUniqueId());
+        TVariable* splitIoVar = getSplitNonIoVar(variable.getUniqueId());
         assignLocation(*splitIoVar);
     } else {
         assignLocation(variable);
@@ -1648,7 +1648,7 @@
             if (shouldFlatten(variable->getType())) {
                 // Expand the AST parameter nodes (but not the name mangling or symbol table view)
                 // for structures that need to be flattened.
-                flatten(*variable);
+                flatten(*variable, false);
                 const TTypeList* structure = variable->getType().getStruct();
                 for (int mem = 0; mem < (int)structure->size(); ++mem) {
                     paramNodes = intermediate.growAggregate(paramNodes,
@@ -1898,12 +1898,12 @@
             // struct inputs to the vertex stage and outputs from the fragment stage must be flattened
             if ((language == EShLangVertex   && qualifier == EvqVaryingIn) ||
                 (language == EShLangFragment && qualifier == EvqVaryingOut))
-                flatten(variable);
+                flatten(variable, false /* don't track linkage here, it will be tracked in assignToInterface() */);
             // Structs containing built-ins must be split
             else if (variable.getType().containsBuiltIn())
                 split(variable);
             else if (!variable.getType().getQualifier().isArrayedIo(language))
-                flatten(variable);
+                flatten(variable, false);
             //else
                 // TODO: unify split and flatten, so all paths can create flattened I/O
         }
@@ -2674,10 +2674,10 @@
     // If either left or right was a split structure, we must read or write it, but still have to
     // parallel-recurse through the unsplit structure to identify the built-in IO vars.
     if (isSplitLeft)
-        splitLeft = intermediate.addSymbol(*getSplitIoVar(left->getAsSymbolNode()->getId()), loc);
+        splitLeft = intermediate.addSymbol(*getSplitNonIoVar(left->getAsSymbolNode()->getId()), loc);
 
     if (isSplitRight)
-        splitRight = intermediate.addSymbol(*getSplitIoVar(right->getAsSymbolNode()->getId()), loc);
+        splitRight = intermediate.addSymbol(*getSplitNonIoVar(right->getAsSymbolNode()->getId()), loc);
 
     // This makes the whole assignment, recursing through subtypes as needed.
     traverse(left, right, splitLeft, splitRight);
@@ -6143,133 +6143,6 @@
 }
 
 //
-// Either redeclare the requested block, or give an error message why it can't be done.
-//
-// TODO: functionality: explicitly sizing members of redeclared blocks is not giving them an explicit size
-void HlslParseContext::redeclareBuiltinBlock(const TSourceLoc& loc, TTypeList& newTypeList, const TString& blockName,
-                                             const TString* instanceName, TArraySizes* arraySizes)
-{
-    // Redeclaring a built-in block...
-
-    // Blocks with instance names are easy to find, lookup the instance name,
-    // Anonymous blocks need to be found via a member.
-    bool builtIn;
-    TSymbol* block;
-    if (instanceName)
-        block = symbolTable.find(*instanceName, &builtIn);
-    else
-        block = symbolTable.find(newTypeList.front().type->getFieldName(), &builtIn);
-
-    // If the block was not found, this must be a version/profile/stage
-    // that doesn't have it, or the instance name is wrong.
-    const char* errorName = instanceName ? instanceName->c_str() : newTypeList.front().type->getFieldName().c_str();
-    if (block == nullptr) {
-        error(loc, "no declaration found for redeclaration", errorName, "");
-        return;
-    }
-    // Built-in blocks cannot be redeclared more than once, which if happened,
-    // we'd be finding the already redeclared one here, rather than the built in.
-    if (! builtIn) {
-        error(loc, "can only redeclare a built-in block once, and before any use", blockName.c_str(), "");
-        return;
-    }
-
-    // Copy the block to make a writable version, to insert into the block table after editing.
-    block = symbolTable.copyUpDeferredInsert(block);
-
-    if (block->getType().getBasicType() != EbtBlock) {
-        error(loc, "cannot redeclare a non block as a block", errorName, "");
-        return;
-    }
-
-    // Edit and error check the container against the redeclaration
-    //  - remove unused members
-    //  - ensure remaining qualifiers/types match
-    TType& type = block->getWritableType();
-    TTypeList::iterator member = type.getWritableStruct()->begin();
-    size_t numOriginalMembersFound = 0;
-    while (member != type.getStruct()->end()) {
-        // look for match
-        bool found = false;
-        TTypeList::const_iterator newMember;
-        TSourceLoc memberLoc;
-        memberLoc.init();
-        for (newMember = newTypeList.begin(); newMember != newTypeList.end(); ++newMember) {
-            if (member->type->getFieldName() == newMember->type->getFieldName()) {
-                found = true;
-                memberLoc = newMember->loc;
-                break;
-            }
-        }
-
-        if (found) {
-            ++numOriginalMembersFound;
-            // - ensure match between redeclared members' types
-            // - check for things that can't be changed
-            // - update things that can be changed
-            TType& oldType = *member->type;
-            const TType& newType = *newMember->type;
-            if (! newType.sameElementType(oldType))
-                error(memberLoc, "cannot redeclare block member with a different type",
-                      member->type->getFieldName().c_str(), "");
-            if (oldType.isArray() != newType.isArray())
-                error(memberLoc, "cannot change arrayness of redeclared block member",
-                      member->type->getFieldName().c_str(), "");
-            else if (! oldType.sameArrayness(newType) && oldType.isExplicitlySizedArray())
-                error(memberLoc, "cannot change array size of redeclared block member",
-                      member->type->getFieldName().c_str(), "");
-            if (newType.getQualifier().isMemory())
-                error(memberLoc, "cannot add memory qualifier to redeclared block member",
-                      member->type->getFieldName().c_str(), "");
-            if (newType.getQualifier().hasLayout())
-                error(memberLoc, "cannot add layout to redeclared block member",
-                      member->type->getFieldName().c_str(), "");
-            if (newType.getQualifier().patch)
-                error(memberLoc, "cannot add patch to redeclared block member",
-                      member->type->getFieldName().c_str(), "");
-            oldType.getQualifier().centroid = newType.getQualifier().centroid;
-            oldType.getQualifier().sample = newType.getQualifier().sample;
-            oldType.getQualifier().invariant = newType.getQualifier().invariant;
-            oldType.getQualifier().noContraction = newType.getQualifier().noContraction;
-            oldType.getQualifier().smooth = newType.getQualifier().smooth;
-            oldType.getQualifier().flat = newType.getQualifier().flat;
-            oldType.getQualifier().nopersp = newType.getQualifier().nopersp;
-
-            // go to next member
-            ++member;
-        } else {
-            // For missing members of anonymous blocks that have been redeclared,
-            // hide the original (shared) declaration.
-            // Instance-named blocks can just have the member removed.
-            if (instanceName)
-                member = type.getWritableStruct()->erase(member);
-            else {
-                member->type->hideMember();
-                ++member;
-            }
-        }
-    }
-
-    if (numOriginalMembersFound < newTypeList.size())
-        error(loc, "block redeclaration has extra members", blockName.c_str(), "");
-    if (type.isArray() != (arraySizes != nullptr))
-        error(loc, "cannot change arrayness of redeclared block", blockName.c_str(), "");
-    else if (type.isArray()) {
-        if (type.isExplicitlySizedArray() && arraySizes->getOuterSize() == UnsizedArraySize)
-            error(loc, "block already declared with size, can't redeclare as implicitly-sized", blockName.c_str(), "");
-        else if (type.isExplicitlySizedArray() && type.getArraySizes() != *arraySizes)
-            error(loc, "cannot change array size of redeclared block", blockName.c_str(), "");
-        else if (type.isImplicitlySizedArray() && arraySizes->getOuterSize() != UnsizedArraySize)
-            type.changeOuterArraySize(arraySizes->getOuterSize());
-    }
-
-    symbolTable.insert(*block);
-
-    // Save it in the AST for linker use.
-    trackLinkage(*block);
-}
-
-//
 // Generate index to the array element in a structure buffer (SSBO)
 //
 TIntermTyped* HlslParseContext::indexStructBufferContent(const TSourceLoc& loc, TIntermTyped* buffer) const
@@ -7314,7 +7187,7 @@
         return nullptr;
 
     if (flattenVar)
-        flatten(*symbol->getAsVariable());
+        flatten(*symbol->getAsVariable(), symbolTable.atGlobalLevel());
 
     if (initializer == nullptr)
         return nullptr;
@@ -8055,13 +7928,6 @@
         }
     }
 
-    // This might be a redeclaration of a built-in block.  If so, redeclareBuiltinBlock() will
-    // do all the rest.
-    // if (! symbolTable.atBuiltInLevel() && builtInName(*blockName)) {
-    //    redeclareBuiltinBlock(loc, typeList, *blockName, instanceName, arraySizes);
-    //    return;
-    //}
-
     // Make default block qualification, and adjust the member qualifications
 
     TQualifier defaultQualification;
@@ -8924,7 +8790,6 @@
         }
     };
 
-
     // If we synthesize a built-in interface variable, we must add it to the linkage.
     const auto addToLinkage = [&](const TType& type, const TString* name, TIntermSymbol** symbolNode) {
         if (name == nullptr) {
diff --git a/hlsl/hlslParseHelper.h b/hlsl/hlslParseHelper.h
index f4abea3..b615a13 100755
--- a/hlsl/hlslParseHelper.h
+++ b/hlsl/hlslParseHelper.h
@@ -133,7 +133,6 @@
     void mergeQualifiers(TQualifier& dst, const TQualifier& src);
     int computeSamplerTypeIndex(TSampler&);
     TSymbol* redeclareBuiltinVariable(const TSourceLoc&, const TString&, const TQualifier&, const TShaderQualifiers&);
-    void redeclareBuiltinBlock(const TSourceLoc&, TTypeList& typeList, const TString& blockName, const TString* instanceName, TArraySizes* arraySizes);
     void paramFix(TType& type);
     void specializationCheck(const TSourceLoc&, const TType&, const char* op);
 
@@ -256,19 +255,17 @@
     TType& split(TType& type, TString name, const TType* outerStructType = nullptr);
     void split(const TVariable&);
     bool wasSplit(const TIntermTyped* node) const;
-    bool wasSplit(int id) const { return splitIoVars.find(id) != splitIoVars.end(); }
-    TVariable* getSplitIoVar(const TIntermTyped* node) const;
-    TVariable* getSplitIoVar(const TVariable* var) const;
-    TVariable* getSplitIoVar(int id) const;
+    bool wasSplit(int id) const { return splitNonIoVars.find(id) != splitNonIoVars.end(); }
+    TVariable* getSplitNonIoVar(int id) const;
     void addPatchConstantInvocation();
     TIntermTyped* makeIntegerIndex(TIntermTyped*);
 
     void fixBuiltInIoType(TType&);
 
-    void flatten(const TVariable& variable);
-    int flatten(const TVariable& variable, const TType&, TFlattenData&, TString name);
-    int flattenStruct(const TVariable& variable, const TType&, TFlattenData&, TString name);
-    int flattenArray(const TVariable& variable, const TType&, TFlattenData&, TString name);
+    void flatten(const TVariable& variable, bool linkage);
+    int flatten(const TVariable& variable, const TType&, TFlattenData&, TString name, bool linkage);
+    int flattenStruct(const TVariable& variable, const TType&, TFlattenData&, TString name, bool linkage);
+    int flattenArray(const TVariable& variable, const TType&, TFlattenData&, TString name, bool linkage);
 
     bool hasUniform(const TQualifier& qualifier) const;
     void clearUniform(TQualifier& qualifier);
@@ -382,7 +379,7 @@
     TMap<const TTypeList*, tIoKinds> ioTypeMap;
 
     // Structure splitting data:
-    TMap<int, TVariable*> splitIoVars;  // variables with the built-in interstage IO removed, indexed by unique ID.
+    TMap<int, TVariable*> splitNonIoVars;  // variables with the built-in interstage IO removed, indexed by unique ID.
 
     // Structuredbuffer shared types.  Typically there are only a few.
     TVector<TType*> structBufferTypes;