Add reflection queries for thread local size and ssbo auto-binding

New command line option --shift-ssbo-binding mirrors --shift-ubo-binding, etc.

New reflection query getLocalSize(int dim) queries local size, e.g, CS threads.
diff --git a/StandAlone/StandAlone.cpp b/StandAlone/StandAlone.cpp
index cf04afd..3c36025 100644
--- a/StandAlone/StandAlone.cpp
+++ b/StandAlone/StandAlone.cpp
@@ -169,6 +169,7 @@
 std::array<unsigned int, EShLangCount> baseTextureBinding;
 std::array<unsigned int, EShLangCount> baseImageBinding;
 std::array<unsigned int, EShLangCount> baseUboBinding;
+std::array<unsigned int, EShLangCount> baseSsboBinding;
 
 //
 // Create the default name for saving a binary if -o is not provided.
@@ -258,6 +259,7 @@
     baseTextureBinding.fill(0);
     baseImageBinding.fill(0);
     baseUboBinding.fill(0);
+    baseSsboBinding.fill(0);
 
     ExecutableName = argv[0];
     NumWorkItems = argc;  // will include some empties where the '-' options were, but it doesn't matter, they'll be 0
@@ -292,6 +294,10 @@
                                lowerword == "shift-ubo-binding"  ||
                                lowerword == "sub") {
                         ProcessBindingBase(argc, argv, baseUboBinding);
+                    } else if (lowerword == "shift-ssbo-bindings" ||  // synonyms
+                               lowerword == "shift-ssbo-binding"  ||
+                               lowerword == "sbb") {
+                        ProcessBindingBase(argc, argv, baseSsboBinding);
                     } else if (lowerword == "auto-map-bindings" ||  // synonyms
                                lowerword == "auto-map-binding"  ||
                                lowerword == "amb") {
@@ -582,6 +588,7 @@
         shader->setShiftTextureBinding(baseTextureBinding[compUnit.stage]);
         shader->setShiftImageBinding(baseImageBinding[compUnit.stage]);
         shader->setShiftUboBinding(baseUboBinding[compUnit.stage]);
+        shader->setShiftSsboBinding(baseSsboBinding[compUnit.stage]);
         shader->setFlattenUniformArrays((Options & EOptionFlattenUniformArrays) != 0);
         shader->setNoStorageFormat((Options & EOptionNoStorageFormat) != 0);
 
@@ -984,6 +991,9 @@
            "  --shift-UBO-binding [stage] num         set base binding number for UBOs\n"
            "  --sub [stage] num                       synonym for --shift-UBO-binding\n"
            "\n"
+           "  --shift-ssbo-binding [stage] num        set base binding number for SSBOs\n"
+           "  --sbb [stage] num                       synonym for --shift-ssbo-binding\n"
+           "\n"
            "  --auto-map-bindings                     automatically bind uniform variables without\n"
            "                                          explicit bindings.\n"
            "  --amb                                   synonym for --auto-map-bindings\n"
diff --git a/Test/baseResults/spv.ssbo.autoassign.frag.out b/Test/baseResults/spv.ssbo.autoassign.frag.out
new file mode 100644
index 0000000..6502faf
--- /dev/null
+++ b/Test/baseResults/spv.ssbo.autoassign.frag.out
@@ -0,0 +1,153 @@
+spv.ssbo.autoassign.frag
+// Module Version 10000
+// Generated by (magic number): 80001
+// Id's are bound by 95
+
+                              Capability Shader
+               1:             ExtInstImport  "GLSL.std.450"
+                              MemoryModel Logical GLSL450
+                              EntryPoint Fragment 4  "main" 88 91
+                              ExecutionMode 4 OriginUpperLeft
+                              Name 4  "main"
+                              Name 11  "@main(vf4;"
+                              Name 10  "pos"
+                              Name 13  "vTmp"
+                              Name 14  "BufType"
+                              MemberName 14(BufType) 0  "va"
+                              MemberName 14(BufType) 1  "vb"
+                              Name 16  "SB0"
+                              MemberName 16(SB0) 0  "SB0"
+                              Name 18  ""
+                              Name 26  "TestCB"
+                              MemberName 26(TestCB) 0  "W"
+                              MemberName 26(TestCB) 1  "H"
+                              Name 28  ""
+                              Name 55  "SB1"
+                              MemberName 55(SB1) 0  "SB1"
+                              Name 57  ""
+                              Name 86  "pos"
+                              Name 88  "pos"
+                              Name 91  "@entryPointOutput"
+                              Name 92  "param"
+                              MemberDecorate 14(BufType) 0 NonWritable
+                              MemberDecorate 14(BufType) 0 Offset 0
+                              MemberDecorate 14(BufType) 1 NonWritable
+                              MemberDecorate 14(BufType) 1 Offset 16
+                              Decorate 15 ArrayStride 32
+                              MemberDecorate 16(SB0) 0 NonWritable
+                              MemberDecorate 16(SB0) 0 Offset 0
+                              Decorate 16(SB0) BufferBlock
+                              Decorate 18 DescriptorSet 0
+                              Decorate 18 Binding 30
+                              MemberDecorate 26(TestCB) 0 Offset 0
+                              MemberDecorate 26(TestCB) 1 Offset 4
+                              Decorate 26(TestCB) Block
+                              Decorate 28 DescriptorSet 0
+                              Decorate 28 Binding 15
+                              Decorate 54 ArrayStride 32
+                              MemberDecorate 55(SB1) 0 Offset 0
+                              Decorate 55(SB1) BufferBlock
+                              Decorate 57 DescriptorSet 0
+                              Decorate 57 Binding 31
+                              Decorate 88(pos) Location 0
+                              Decorate 91(@entryPointOutput) Location 0
+               2:             TypeVoid
+               3:             TypeFunction 2
+               6:             TypeFloat 32
+               7:             TypeVector 6(float) 4
+               8:             TypePointer Function 7(fvec4)
+               9:             TypeFunction 7(fvec4) 8(ptr)
+     14(BufType):             TypeStruct 7(fvec4) 7(fvec4)
+              15:             TypeRuntimeArray 14(BufType)
+         16(SB0):             TypeStruct 15
+              17:             TypePointer Uniform 16(SB0)
+              18:     17(ptr) Variable Uniform
+              19:             TypeInt 32 1
+              20:     19(int) Constant 0
+              21:             TypeInt 32 0
+              22:     21(int) Constant 1
+              23:             TypePointer Function 6(float)
+      26(TestCB):             TypeStruct 21(int) 21(int)
+              27:             TypePointer Uniform 26(TestCB)
+              28:     27(ptr) Variable Uniform
+              29:             TypePointer Uniform 21(int)
+              34:     21(int) Constant 0
+              38:             TypePointer Uniform 7(fvec4)
+              50:     19(int) Constant 1
+              54:             TypeRuntimeArray 14(BufType)
+         55(SB1):             TypeStruct 54
+              56:             TypePointer Uniform 55(SB1)
+              57:     56(ptr) Variable Uniform
+              87:             TypePointer Input 7(fvec4)
+         88(pos):     87(ptr) Variable Input
+              90:             TypePointer Output 7(fvec4)
+91(@entryPointOutput):     90(ptr) Variable Output
+         4(main):           2 Function None 3
+               5:             Label
+         86(pos):      8(ptr) Variable Function
+       92(param):      8(ptr) Variable Function
+              89:    7(fvec4) Load 88(pos)
+                              Store 86(pos) 89
+              93:    7(fvec4) Load 86(pos)
+                              Store 92(param) 93
+              94:    7(fvec4) FunctionCall 11(@main(vf4;) 92(param)
+                              Store 91(@entryPointOutput) 94
+                              Return
+                              FunctionEnd
+  11(@main(vf4;):    7(fvec4) Function None 9
+         10(pos):      8(ptr) FunctionParameter
+              12:             Label
+        13(vTmp):      8(ptr) Variable Function
+              24:     23(ptr) AccessChain 10(pos) 22
+              25:    6(float) Load 24
+              30:     29(ptr) AccessChain 28 20
+              31:     21(int) Load 30
+              32:    6(float) ConvertUToF 31
+              33:    6(float) FMul 25 32
+              35:     23(ptr) AccessChain 10(pos) 34
+              36:    6(float) Load 35
+              37:    6(float) FAdd 33 36
+              39:     38(ptr) AccessChain 18 20 37 20
+              40:    7(fvec4) Load 39
+              41:     23(ptr) AccessChain 10(pos) 22
+              42:    6(float) Load 41
+              43:     29(ptr) AccessChain 28 20
+              44:     21(int) Load 43
+              45:    6(float) ConvertUToF 44
+              46:    6(float) FMul 42 45
+              47:     23(ptr) AccessChain 10(pos) 34
+              48:    6(float) Load 47
+              49:    6(float) FAdd 46 48
+              51:     38(ptr) AccessChain 18 20 49 50
+              52:    7(fvec4) Load 51
+              53:    7(fvec4) FAdd 40 52
+                              Store 13(vTmp) 53
+              58:     23(ptr) AccessChain 10(pos) 22
+              59:    6(float) Load 58
+              60:     29(ptr) AccessChain 28 20
+              61:     21(int) Load 60
+              62:    6(float) ConvertUToF 61
+              63:    6(float) FMul 59 62
+              64:     23(ptr) AccessChain 10(pos) 34
+              65:    6(float) Load 64
+              66:    6(float) FAdd 63 65
+              67:     38(ptr) AccessChain 57 20 66 20
+              68:    7(fvec4) Load 67
+              69:     23(ptr) AccessChain 10(pos) 22
+              70:    6(float) Load 69
+              71:     29(ptr) AccessChain 28 20
+              72:     21(int) Load 71
+              73:    6(float) ConvertUToF 72
+              74:    6(float) FMul 70 73
+              75:     23(ptr) AccessChain 10(pos) 34
+              76:    6(float) Load 75
+              77:    6(float) FAdd 74 76
+              78:     38(ptr) AccessChain 57 20 77 50
+              79:    7(fvec4) Load 78
+              80:    7(fvec4) FAdd 68 79
+              81:    7(fvec4) Load 13(vTmp)
+              82:    7(fvec4) FAdd 81 80
+                              Store 13(vTmp) 82
+              83:    7(fvec4) Load 13(vTmp)
+                              ReturnValue 83
+                              FunctionEnd
diff --git a/Test/spv.ssbo.autoassign.frag b/Test/spv.ssbo.autoassign.frag
new file mode 100644
index 0000000..073be45
--- /dev/null
+++ b/Test/spv.ssbo.autoassign.frag
@@ -0,0 +1,24 @@
+
+cbuffer TestCB
+{ 
+    uint W;
+    uint H;
+}; 
+
+struct BufType 
+{ 
+    float4 va; 
+    float4 vb; 
+};
+
+StructuredBuffer < BufType > SB0; 
+RWStructuredBuffer < BufType > SB1;
+
+float4 main(float4 pos : POS) : SV_Target0
+{ 
+    float4 vTmp = SB0[pos.y * W + pos.x].va + SB0[pos.y * W + pos.x].vb;
+
+    vTmp += SB1[pos.y * W + pos.x].va + SB1[pos.y * W + pos.x].vb;
+
+    return vTmp;
+} 
diff --git a/glslang/MachineIndependent/ShaderLang.cpp b/glslang/MachineIndependent/ShaderLang.cpp
index b0e5513..5a8f679 100644
--- a/glslang/MachineIndependent/ShaderLang.cpp
+++ b/glslang/MachineIndependent/ShaderLang.cpp
@@ -1557,6 +1557,7 @@
 void TShader::setShiftTextureBinding(unsigned int base) { intermediate->setShiftTextureBinding(base); }
 void TShader::setShiftImageBinding(unsigned int base)   { intermediate->setShiftImageBinding(base); }
 void TShader::setShiftUboBinding(unsigned int base)     { intermediate->setShiftUboBinding(base); }
+void TShader::setShiftSsboBinding(unsigned int base)    { intermediate->setShiftSsboBinding(base); }
 void TShader::setAutoMapBindings(bool map)              { intermediate->setAutoMapBindings(map); }
 void TShader::setFlattenUniformArrays(bool flatten)     { intermediate->setFlattenUniformArrays(flatten); }
 void TShader::setNoStorageFormat(bool useUnknownFormat) { intermediate->setNoStorageFormat(useUnknownFormat); }
@@ -1784,6 +1785,7 @@
 const TType* TProgram::getAttributeTType(int index) const    { return reflection->getAttribute(index).getType(); }
 const TType* TProgram::getUniformTType(int index) const      { return reflection->getUniform(index).getType(); }
 const TType* TProgram::getUniformBlockTType(int index) const { return reflection->getUniformBlock(index).getType(); }
+unsigned TProgram::getLocalSize(int dim) const               { return reflection->getLocalSize(dim); }
 
 void TProgram::dumpReflection()                      { reflection->dump(); }
 
diff --git a/glslang/MachineIndependent/iomapper.cpp b/glslang/MachineIndependent/iomapper.cpp
index 04868f1..07aa476 100644
--- a/glslang/MachineIndependent/iomapper.cpp
+++ b/glslang/MachineIndependent/iomapper.cpp
@@ -122,7 +122,7 @@
 
     virtual void visitSymbol(TIntermSymbol* base)
     {
-        if (base->getQualifier().storage == EvqUniform) {
+        if (base->getType().getQualifier().isUniformOrBuffer()) {
             TVarEntryInfo ent = { base->getId(), base, !traverseAll };
             TVarLiveMap::iterator at = std::lower_bound(varLiveList.begin(), varLiveList.end(), ent, TVarEntryInfo::TOrderById());
             if (at != varLiveList.end() && at->id == ent.id)
@@ -227,6 +227,7 @@
     int baseTextureBinding;
     int baseImageBinding;
     int baseUboBinding;
+    int baseSsboBinding;
     bool doAutoMapping;
     typedef std::vector<int> TSlotSet;
     typedef std::unordered_map<int, TSlotSet> TSlotSetMap;
@@ -281,8 +282,11 @@
                     return checkEmpty(set, baseTextureBinding + type.getQualifier().layoutBinding);
             }
 
-            if (type.getQualifier().isUniformOrBuffer())
+            if (type.getQualifier().storage == EvqUniform)
                 return checkEmpty(set, baseUboBinding + type.getQualifier().layoutBinding);
+
+            if (type.getQualifier().storage == EvqBuffer)
+                return checkEmpty(set, baseSsboBinding + type.getQualifier().layoutBinding);
         }
         return true;
     }
@@ -308,8 +312,11 @@
                     return reserveSlot(set, baseTextureBinding + type.getQualifier().layoutBinding);
             }
 
-            if (type.getQualifier().isUniformOrBuffer())
+            if (type.getQualifier().storage == EvqUniform)
                 return reserveSlot(set, baseUboBinding + type.getQualifier().layoutBinding);
+
+            if (type.getQualifier().storage == EvqBuffer)
+                return reserveSlot(set, baseSsboBinding + type.getQualifier().layoutBinding);
         } else if (is_live && doAutoMapping) {
             // find free slot, the caller did make sure it passes all vars with binding
             // first and now all are passed that do not have a binding and needs one
@@ -325,8 +332,11 @@
                     return getFreeSlot(set, baseTextureBinding);
             }
 
-            if (type.getQualifier().isUniformOrBuffer())
+            if (type.getQualifier().storage == EvqUniform)
                 return getFreeSlot(set, baseUboBinding);
+
+            if (type.getQualifier().storage == EvqBuffer)
+                return getFreeSlot(set, baseSsboBinding);
         }
 
         return -1;
@@ -351,6 +361,7 @@
         intermediate.getShiftTextureBinding() == 0 &&
         intermediate.getShiftImageBinding() == 0 &&
         intermediate.getShiftUboBinding() == 0 &&
+        intermediate.getShiftSsboBinding() == 0 &&
         intermediate.getAutoMapBindings() == false &&
         resolver == nullptr)
         return true;
@@ -369,6 +380,7 @@
         defaultResolver.baseTextureBinding = intermediate.getShiftTextureBinding();
         defaultResolver.baseImageBinding = intermediate.getShiftImageBinding();
         defaultResolver.baseUboBinding = intermediate.getShiftUboBinding();
+        defaultResolver.baseSsboBinding = intermediate.getShiftSsboBinding();
         defaultResolver.doAutoMapping = intermediate.getAutoMapBindings();
 
         resolver = &defaultResolver;
diff --git a/glslang/MachineIndependent/localintermediate.h b/glslang/MachineIndependent/localintermediate.h
index 14193f5..34940a6 100644
--- a/glslang/MachineIndependent/localintermediate.h
+++ b/glslang/MachineIndependent/localintermediate.h
@@ -174,6 +174,7 @@
         shiftTextureBinding(0),
         shiftImageBinding(0),
         shiftUboBinding(0),
+        shiftSsboBinding(0),
         autoMapBindings(false),
         flattenUniformArrays(false),
         useUnknownFormat(false)
@@ -207,6 +208,8 @@
     unsigned int getShiftImageBinding() const { return shiftImageBinding; }
     void setShiftUboBinding(unsigned int shift)     { shiftUboBinding = shift; }
     unsigned int getShiftUboBinding()     const { return shiftUboBinding; }
+    void setShiftSsboBinding(unsigned int shift)     { shiftSsboBinding = shift; }
+    unsigned int getShiftSsboBinding()  const { return shiftSsboBinding; }
     void setAutoMapBindings(bool map)               { autoMapBindings = map; }
     bool getAutoMapBindings()             const { return autoMapBindings; }
     void setFlattenUniformArrays(bool flatten)      { flattenUniformArrays = flatten; }
@@ -485,6 +488,7 @@
     unsigned int shiftTextureBinding;
     unsigned int shiftImageBinding;
     unsigned int shiftUboBinding;
+    unsigned int shiftSsboBinding;
     bool autoMapBindings;
     bool flattenUniformArrays;
     bool useUnknownFormat;
diff --git a/glslang/MachineIndependent/reflection.cpp b/glslang/MachineIndependent/reflection.cpp
index 688827d..f3f28f0 100644
--- a/glslang/MachineIndependent/reflection.cpp
+++ b/glslang/MachineIndependent/reflection.cpp
@@ -696,14 +696,27 @@
 // Implement TReflection methods.
 //
 
+// Track any required attribute reflection, such as compute shader numthreads.
+//
+void TReflection::buildAttributeReflection(EShLanguage stage, const TIntermediate& intermediate)
+{
+    if (stage == EShLangCompute) {
+        // Remember thread dimensions
+        for (int dim=0; dim<3; ++dim)
+            localSize[dim] = intermediate.getLocalSize(dim);
+    }
+}
+
 // Merge live symbols from 'intermediate' into the existing reflection database.
 //
 // Returns false if the input is too malformed to do this.
-bool TReflection::addStage(EShLanguage, const TIntermediate& intermediate)
+bool TReflection::addStage(EShLanguage stage, const TIntermediate& intermediate)
 {
     if (intermediate.getNumEntryPoints() != 1 || intermediate.isRecursive())
         return false;
 
+    buildAttributeReflection(stage, intermediate);
+
     TReflectionTraverser it(intermediate, *this);
 
     // put the entry point on the list of functions to process
@@ -736,6 +749,16 @@
         indexToAttribute[i].dump();
     printf("\n");
 
+    if (getLocalSize(0) > 1) {
+        static const char* axis[] = { "X", "Y", "Z" };
+
+        for (int dim=0; dim<3; ++dim)
+            if (getLocalSize(dim) > 1)
+                printf("Local size %s: %d\n", axis[dim], getLocalSize(dim));
+
+        printf("\n");
+    }
+
     // printf("Live names\n");
     // for (TNameToIndex::const_iterator it = nameToIndex.begin(); it != nameToIndex.end(); ++it)
     //    printf("%s: %d\n", it->first.c_str(), it->second);
diff --git a/glslang/MachineIndependent/reflection.h b/glslang/MachineIndependent/reflection.h
index bae131c..c80d3ea 100644
--- a/glslang/MachineIndependent/reflection.h
+++ b/glslang/MachineIndependent/reflection.h
@@ -89,7 +89,12 @@
 // The full reflection database
 class TReflection {
 public:
-    TReflection() : badReflection(TObjectReflection::badReflection()) { }
+    TReflection() : badReflection(TObjectReflection::badReflection())
+    { 
+        for (int dim=0; dim<3; ++dim)
+            localSize[dim] = 0;
+    }
+
     virtual ~TReflection() {}
 
     // grow the reflection stage by stage
@@ -135,11 +140,16 @@
             return it->second;
     }
 
+    // Thread local size
+    unsigned getLocalSize(int dim) const { return dim <= 2 ? localSize[dim] : 0; }
+
     void dump();
 
 protected:
     friend class glslang::TReflectionTraverser;
 
+    void buildAttributeReflection(EShLanguage, const TIntermediate&);
+
     // Need a TString hash: typedef std::unordered_map<TString, int> TNameToIndex;
     typedef std::map<TString, int> TNameToIndex;
     typedef std::vector<TObjectReflection> TMapIndexToReflection;
@@ -149,6 +159,8 @@
     TMapIndexToReflection indexToUniform;
     TMapIndexToReflection indexToUniformBlock;
     TMapIndexToReflection indexToAttribute;
+
+    unsigned int localSize[3];
 };
 
 } // end namespace glslang
diff --git a/glslang/Public/ShaderLang.h b/glslang/Public/ShaderLang.h
index d2f4e1b..8628dff 100644
--- a/glslang/Public/ShaderLang.h
+++ b/glslang/Public/ShaderLang.h
@@ -310,6 +310,7 @@
     void setShiftTextureBinding(unsigned int base);
     void setShiftImageBinding(unsigned int base);
     void setShiftUboBinding(unsigned int base);
+    void setShiftSsboBinding(unsigned int base);
     void setAutoMapBindings(bool map);
     void setFlattenUniformArrays(bool flatten);
     void setNoStorageFormat(bool useUnknownFormat);
@@ -514,6 +515,7 @@
     int getUniformBufferOffset(int index) const;           // can be used for glGetActiveUniformsiv(GL_UNIFORM_OFFSET)
     int getUniformArraySize(int index) const;              // can be used for glGetActiveUniformsiv(GL_UNIFORM_SIZE)
     int getNumLiveAttributes() const;                      // can be used for glGetProgramiv(GL_ACTIVE_ATTRIBUTES)
+    unsigned getLocalSize(int dim) const;                  // return dim'th local size
     const char *getAttributeName(int index) const;         // can be used for glGetActiveAttrib()
     int getAttributeType(int index) const;                 // can be used for glGetActiveAttrib()
     const TType* getUniformTType(int index) const;         // returns a TType*
diff --git a/gtests/Spv.FromFile.cpp b/gtests/Spv.FromFile.cpp
index dabd021..2d3606e 100644
--- a/gtests/Spv.FromFile.cpp
+++ b/gtests/Spv.FromFile.cpp
@@ -48,6 +48,7 @@
     int baseTextureBinding;
     int baseImageBinding;
     int baseUboBinding;
+    int baseSsboBinding;
     bool autoMapBindings;
     bool flattenUniforms;
 };
@@ -129,6 +130,7 @@
                                  GetParam().baseTextureBinding,
                                  GetParam().baseImageBinding,
                                  GetParam().baseUboBinding,
+                                 GetParam().baseSsboBinding,
                                  GetParam().autoMapBindings,
                                  GetParam().flattenUniforms);
 }
@@ -143,6 +145,7 @@
                                  GetParam().baseTextureBinding,
                                  GetParam().baseImageBinding,
                                  GetParam().baseUboBinding,
+                                 GetParam().baseSsboBinding,
                                  GetParam().autoMapBindings,
                                  GetParam().flattenUniforms);
 }
@@ -301,15 +304,16 @@
 INSTANTIATE_TEST_CASE_P(
     Hlsl, HlslIoMap,
     ::testing::ValuesIn(std::vector<IoMapData>{
-        { "spv.register.autoassign.frag", "main_ep", 5, 10, 0, 20, true, false },
-        { "spv.register.noautoassign.frag", "main_ep", 5, 10, 0, 15, false, false },
-        { "spv.register.autoassign-2.frag", "main", 5, 10, 0, 15, true, true },
-        { "spv.buffer.autoassign.frag", "main", 5, 10, 0, 15, true, true },
-        { "spv.rw.autoassign.frag", "main", 5, 10, 20, 15, true, true },
+        { "spv.register.autoassign.frag", "main_ep", 5, 10, 0, 20, 30, true, false },
+        { "spv.register.noautoassign.frag", "main_ep", 5, 10, 0, 15, 30, false, false },
+        { "spv.register.autoassign-2.frag", "main", 5, 10, 0, 15, 30, true, true },
+        { "spv.buffer.autoassign.frag", "main", 5, 10, 0, 15, 30, true, true },
+        { "spv.ssbo.autoassign.frag", "main", 5, 10, 0, 15, 30, true, true },
+        { "spv.rw.autoassign.frag", "main", 5, 10, 20, 15, 30, true, true },
         { "spv.register.autoassign.rangetest.frag", "main", 
                 glslang::TQualifier::layoutBindingEnd-2,
                 glslang::TQualifier::layoutBindingEnd+5,
-                20, true, false },
+                20, 30, true, false },
     }),
     FileNameAsCustomTestSuffixIoMap
 );
@@ -318,8 +322,8 @@
 INSTANTIATE_TEST_CASE_P(
     Hlsl, GlslIoMap,
     ::testing::ValuesIn(std::vector<IoMapData>{
-        { "spv.glsl.register.autoassign.frag", "main", 5, 10, 0, 20, true, false },
-        { "spv.glsl.register.noautoassign.frag", "main", 5, 10, 0, 15, false, false },
+        { "spv.glsl.register.autoassign.frag", "main", 5, 10, 0, 20, 30, true, false },
+        { "spv.glsl.register.noautoassign.frag", "main", 5, 10, 0, 15, 30, false, false },
     }),
     FileNameAsCustomTestSuffixIoMap
 );
diff --git a/gtests/TestFixture.h b/gtests/TestFixture.h
index 6f4afc6..38ec54c 100644
--- a/gtests/TestFixture.h
+++ b/gtests/TestFixture.h
@@ -241,6 +241,7 @@
             int baseTextureBinding,
             int baseImageBinding,
             int baseUboBinding,
+            int baseSsboBinding,
             bool autoMapBindings,
             bool flattenUniformArrays)
     {
@@ -251,6 +252,7 @@
         shader.setShiftTextureBinding(baseTextureBinding);
         shader.setShiftImageBinding(baseImageBinding);
         shader.setShiftUboBinding(baseUboBinding);
+        shader.setShiftSsboBinding(baseSsboBinding);
         shader.setAutoMapBindings(autoMapBindings);
         shader.setFlattenUniformArrays(flattenUniformArrays);
 
@@ -430,6 +432,7 @@
                                       int baseTextureBinding,
                                       int baseImageBinding,
                                       int baseUboBinding,
+                                      int baseSsboBinding,
                                       bool autoMapBindings,
                                       bool flattenUniformArrays)
     {
@@ -443,7 +446,8 @@
 
         const EShMessages controls = DeriveOptions(source, semantics, target);
         GlslangResult result = compileLinkIoMap(testName, input, entryPointName, controls,
-                                                baseSamplerBinding, baseTextureBinding, baseImageBinding, baseUboBinding,
+                                                baseSamplerBinding, baseTextureBinding, baseImageBinding,
+                                                baseUboBinding, baseSsboBinding,
                                                 autoMapBindings,
                                                 flattenUniformArrays);