diff --git a/Test/baseResults/hlsl.mip.negative.frag.out b/Test/baseResults/hlsl.mip.negative.frag.out
new file mode 100644
index 0000000000000000000000000000000000000000..36f41377d1d6fc90deaf5bc5a53627a42ec14723
--- /dev/null
+++ b/Test/baseResults/hlsl.mip.negative.frag.out
@@ -0,0 +1,68 @@
+hlsl.mip.negative.frag
+ERROR: 0:5: '' : unterminated mips operator: 
+ERROR: 1 compilation errors.  No code generated.
+
+
+Shader version: 500
+gl_FragCoord origin is upper left
+ERROR: node is still EOpNull!
+0:4  Function Definition: @main( ( temp 4-component vector of float)
+0:4    Function Parameters: 
+0:?     Sequence
+0:?       textureFetch ( temp 4-component vector of float)
+0:5        'g_tTex2df4' ( uniform texture2D)
+0:?         Constant:
+0:?           3 (const uint)
+0:?           4 (const uint)
+0:5        Constant:
+0:5          2 (const int)
+0:7      Branch: Return with expression
+0:7        Constant:
+0:7          0.000000
+0:7          0.000000
+0:7          0.000000
+0:7          0.000000
+0:4  Function Definition: main( ( temp void)
+0:4    Function Parameters: 
+0:?     Sequence
+0:4      move second child to first child ( temp 4-component vector of float)
+0:?         '@entryPointOutput' (layout( location=0) out 4-component vector of float)
+0:4        Function Call: @main( ( temp 4-component vector of float)
+0:?   Linker Objects
+0:?     'g_tTex2df4' ( uniform texture2D)
+0:?     '@entryPointOutput' (layout( location=0) out 4-component vector of float)
+
+
+Linked fragment stage:
+
+
+Shader version: 500
+gl_FragCoord origin is upper left
+ERROR: node is still EOpNull!
+0:4  Function Definition: @main( ( temp 4-component vector of float)
+0:4    Function Parameters: 
+0:?     Sequence
+0:?       textureFetch ( temp 4-component vector of float)
+0:5        'g_tTex2df4' ( uniform texture2D)
+0:?         Constant:
+0:?           3 (const uint)
+0:?           4 (const uint)
+0:5        Constant:
+0:5          2 (const int)
+0:7      Branch: Return with expression
+0:7        Constant:
+0:7          0.000000
+0:7          0.000000
+0:7          0.000000
+0:7          0.000000
+0:4  Function Definition: main( ( temp void)
+0:4    Function Parameters: 
+0:?     Sequence
+0:4      move second child to first child ( temp 4-component vector of float)
+0:?         '@entryPointOutput' (layout( location=0) out 4-component vector of float)
+0:4        Function Call: @main( ( temp 4-component vector of float)
+0:?   Linker Objects
+0:?     'g_tTex2df4' ( uniform texture2D)
+0:?     '@entryPointOutput' (layout( location=0) out 4-component vector of float)
+
+SPIR-V is not generated for failed compile or link
diff --git a/Test/baseResults/hlsl.mip.negative2.frag.out b/Test/baseResults/hlsl.mip.negative2.frag.out
new file mode 100644
index 0000000000000000000000000000000000000000..75cf95fc5a1312ee1245f592400388502c42fa83
--- /dev/null
+++ b/Test/baseResults/hlsl.mip.negative2.frag.out
@@ -0,0 +1,74 @@
+hlsl.mip.negative2.frag
+ERROR: 0:5: 'r' : unexpected operator on texture type:  uniform texture2D
+ERROR: 1 compilation errors.  No code generated.
+
+
+Shader version: 500
+gl_FragCoord origin is upper left
+ERROR: node is still EOpNull!
+0:4  Function Definition: @main( ( temp 4-component vector of float)
+0:4    Function Parameters: 
+0:?     Sequence
+0:5      direct index ( temp float)
+0:5        textureFetch ( temp 4-component vector of float)
+0:5          'g_tTex2df4' ( uniform texture2D)
+0:5          Constant:
+0:5            2 (const int)
+0:5          Constant:
+0:5            0 (const int)
+0:?         Constant:
+0:?           3 (const uint)
+0:?           4 (const uint)
+0:7      Branch: Return with expression
+0:7        Constant:
+0:7          0.000000
+0:7          0.000000
+0:7          0.000000
+0:7          0.000000
+0:4  Function Definition: main( ( temp void)
+0:4    Function Parameters: 
+0:?     Sequence
+0:4      move second child to first child ( temp 4-component vector of float)
+0:?         '@entryPointOutput' (layout( location=0) out 4-component vector of float)
+0:4        Function Call: @main( ( temp 4-component vector of float)
+0:?   Linker Objects
+0:?     'g_tTex2df4' ( uniform texture2D)
+0:?     '@entryPointOutput' (layout( location=0) out 4-component vector of float)
+
+
+Linked fragment stage:
+
+
+Shader version: 500
+gl_FragCoord origin is upper left
+ERROR: node is still EOpNull!
+0:4  Function Definition: @main( ( temp 4-component vector of float)
+0:4    Function Parameters: 
+0:?     Sequence
+0:5      direct index ( temp float)
+0:5        textureFetch ( temp 4-component vector of float)
+0:5          'g_tTex2df4' ( uniform texture2D)
+0:5          Constant:
+0:5            2 (const int)
+0:5          Constant:
+0:5            0 (const int)
+0:?         Constant:
+0:?           3 (const uint)
+0:?           4 (const uint)
+0:7      Branch: Return with expression
+0:7        Constant:
+0:7          0.000000
+0:7          0.000000
+0:7          0.000000
+0:7          0.000000
+0:4  Function Definition: main( ( temp void)
+0:4    Function Parameters: 
+0:?     Sequence
+0:4      move second child to first child ( temp 4-component vector of float)
+0:?         '@entryPointOutput' (layout( location=0) out 4-component vector of float)
+0:4        Function Call: @main( ( temp 4-component vector of float)
+0:?   Linker Objects
+0:?     'g_tTex2df4' ( uniform texture2D)
+0:?     '@entryPointOutput' (layout( location=0) out 4-component vector of float)
+
+SPIR-V is not generated for failed compile or link
diff --git a/Test/baseResults/hlsl.mip.operator.frag.out b/Test/baseResults/hlsl.mip.operator.frag.out
new file mode 100644
index 0000000000000000000000000000000000000000..3c68fd97e0dffe16548c2e7a08ce1b18ce8cecdc
--- /dev/null
+++ b/Test/baseResults/hlsl.mip.operator.frag.out
@@ -0,0 +1,209 @@
+hlsl.mip.operator.frag
+Shader version: 500
+gl_FragCoord origin is upper left
+0:? Sequence
+0:5  Function Definition: @main( ( temp 4-component vector of float)
+0:5    Function Parameters: 
+0:?     Sequence
+0:13      Branch: Return with expression
+0:9        add ( temp 4-component vector of float)
+0:6          add ( temp 4-component vector of float)
+0:?             textureFetch ( temp 4-component vector of float)
+0:6              'g_tTex2df4' ( uniform texture2D)
+0:?               Constant:
+0:?                 3 (const uint)
+0:?                 4 (const uint)
+0:6              Constant:
+0:6                2 (const int)
+0:?             textureFetch ( temp 4-component vector of float)
+0:9              'g_tTex2df4a' ( uniform texture2DArray)
+0:?               Constant:
+0:?                 6 (const uint)
+0:?                 7 (const uint)
+0:?                 8 (const uint)
+0:9              Constant:
+0:9                5 (const uint)
+0:13          textureFetch ( temp 4-component vector of float)
+0:13            'g_tTex2df4' ( uniform texture2D)
+0:13            Convert float to uint ( temp 2-component vector of uint)
+0:13              vector swizzle ( temp 2-component vector of float)
+0:?                 textureFetch ( temp 4-component vector of float)
+0:13                  'g_tTex2df4' ( uniform texture2D)
+0:?                   Constant:
+0:?                     14 (const uint)
+0:?                     15 (const uint)
+0:13                  Constant:
+0:13                    13 (const int)
+0:13                Sequence
+0:13                  Constant:
+0:13                    0 (const int)
+0:13                  Constant:
+0:13                    1 (const int)
+0:13            Convert float to uint ( temp uint)
+0:13              direct index ( temp float)
+0:?                 textureFetch ( temp 4-component vector of float)
+0:13                  'g_tTex2df4' ( uniform texture2D)
+0:?                   Constant:
+0:?                     10 (const uint)
+0:?                     11 (const uint)
+0:13                  Constant:
+0:13                    9 (const int)
+0:13                Constant:
+0:13                  0 (const int)
+0:5  Function Definition: main( ( temp void)
+0:5    Function Parameters: 
+0:?     Sequence
+0:5      move second child to first child ( temp 4-component vector of float)
+0:?         '@entryPointOutput' (layout( location=0) out 4-component vector of float)
+0:5        Function Call: @main( ( temp 4-component vector of float)
+0:?   Linker Objects
+0:?     'g_tTex2df4a' ( uniform texture2DArray)
+0:?     'g_tTex2df4' ( uniform texture2D)
+0:?     '@entryPointOutput' (layout( location=0) out 4-component vector of float)
+
+
+Linked fragment stage:
+
+
+Shader version: 500
+gl_FragCoord origin is upper left
+0:? Sequence
+0:5  Function Definition: @main( ( temp 4-component vector of float)
+0:5    Function Parameters: 
+0:?     Sequence
+0:13      Branch: Return with expression
+0:9        add ( temp 4-component vector of float)
+0:6          add ( temp 4-component vector of float)
+0:?             textureFetch ( temp 4-component vector of float)
+0:6              'g_tTex2df4' ( uniform texture2D)
+0:?               Constant:
+0:?                 3 (const uint)
+0:?                 4 (const uint)
+0:6              Constant:
+0:6                2 (const int)
+0:?             textureFetch ( temp 4-component vector of float)
+0:9              'g_tTex2df4a' ( uniform texture2DArray)
+0:?               Constant:
+0:?                 6 (const uint)
+0:?                 7 (const uint)
+0:?                 8 (const uint)
+0:9              Constant:
+0:9                5 (const uint)
+0:13          textureFetch ( temp 4-component vector of float)
+0:13            'g_tTex2df4' ( uniform texture2D)
+0:13            Convert float to uint ( temp 2-component vector of uint)
+0:13              vector swizzle ( temp 2-component vector of float)
+0:?                 textureFetch ( temp 4-component vector of float)
+0:13                  'g_tTex2df4' ( uniform texture2D)
+0:?                   Constant:
+0:?                     14 (const uint)
+0:?                     15 (const uint)
+0:13                  Constant:
+0:13                    13 (const int)
+0:13                Sequence
+0:13                  Constant:
+0:13                    0 (const int)
+0:13                  Constant:
+0:13                    1 (const int)
+0:13            Convert float to uint ( temp uint)
+0:13              direct index ( temp float)
+0:?                 textureFetch ( temp 4-component vector of float)
+0:13                  'g_tTex2df4' ( uniform texture2D)
+0:?                   Constant:
+0:?                     10 (const uint)
+0:?                     11 (const uint)
+0:13                  Constant:
+0:13                    9 (const int)
+0:13                Constant:
+0:13                  0 (const int)
+0:5  Function Definition: main( ( temp void)
+0:5    Function Parameters: 
+0:?     Sequence
+0:5      move second child to first child ( temp 4-component vector of float)
+0:?         '@entryPointOutput' (layout( location=0) out 4-component vector of float)
+0:5        Function Call: @main( ( temp 4-component vector of float)
+0:?   Linker Objects
+0:?     'g_tTex2df4a' ( uniform texture2DArray)
+0:?     'g_tTex2df4' ( 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 61
+
+                              Capability Shader
+               1:             ExtInstImport  "GLSL.std.450"
+                              MemoryModel Logical GLSL450
+                              EntryPoint Fragment 4  "main" 59
+                              ExecutionMode 4 OriginUpperLeft
+                              Source HLSL 500
+                              Name 4  "main"
+                              Name 9  "@main("
+                              Name 13  "g_tTex2df4"
+                              Name 25  "g_tTex2df4a"
+                              Name 59  "@entryPointOutput"
+                              Decorate 13(g_tTex2df4) DescriptorSet 0
+                              Decorate 25(g_tTex2df4a) DescriptorSet 0
+                              Decorate 59(@entryPointOutput) Location 0
+               2:             TypeVoid
+               3:             TypeFunction 2
+               6:             TypeFloat 32
+               7:             TypeVector 6(float) 4
+               8:             TypeFunction 7(fvec4)
+              11:             TypeImage 6(float) 2D sampled format:Unknown
+              12:             TypePointer UniformConstant 11
+  13(g_tTex2df4):     12(ptr) Variable UniformConstant
+              15:             TypeInt 32 0
+              16:             TypeVector 15(int) 2
+              17:     15(int) Constant 3
+              18:     15(int) Constant 4
+              19:   16(ivec2) ConstantComposite 17 18
+              20:             TypeInt 32 1
+              21:     20(int) Constant 2
+              23:             TypeImage 6(float) 2D array sampled format:Unknown
+              24:             TypePointer UniformConstant 23
+ 25(g_tTex2df4a):     24(ptr) Variable UniformConstant
+              27:             TypeVector 15(int) 3
+              28:     15(int) Constant 6
+              29:     15(int) Constant 7
+              30:     15(int) Constant 8
+              31:   27(ivec3) ConstantComposite 28 29 30
+              32:     15(int) Constant 5
+              37:     15(int) Constant 14
+              38:     15(int) Constant 15
+              39:   16(ivec2) ConstantComposite 37 38
+              40:     20(int) Constant 13
+              42:             TypeVector 6(float) 2
+              46:     15(int) Constant 10
+              47:     15(int) Constant 11
+              48:   16(ivec2) ConstantComposite 46 47
+              49:     20(int) Constant 9
+              51:     15(int) Constant 0
+              58:             TypePointer Output 7(fvec4)
+59(@entryPointOutput):     58(ptr) Variable Output
+         4(main):           2 Function None 3
+               5:             Label
+              60:    7(fvec4) FunctionCall 9(@main()
+                              Store 59(@entryPointOutput) 60
+                              Return
+                              FunctionEnd
+       9(@main():    7(fvec4) Function None 8
+              10:             Label
+              14:          11 Load 13(g_tTex2df4)
+              22:    7(fvec4) ImageFetch 14 19 Lod 21
+              26:          23 Load 25(g_tTex2df4a)
+              33:    7(fvec4) ImageFetch 26 31 Lod 32
+              34:    7(fvec4) FAdd 22 33
+              35:          11 Load 13(g_tTex2df4)
+              36:          11 Load 13(g_tTex2df4)
+              41:    7(fvec4) ImageFetch 36 39 Lod 40
+              43:   42(fvec2) VectorShuffle 41 41 0 1
+              44:   16(ivec2) ConvertFToU 43
+              45:          11 Load 13(g_tTex2df4)
+              50:    7(fvec4) ImageFetch 45 48 Lod 49
+              52:    6(float) CompositeExtract 50 0
+              53:     15(int) ConvertFToU 52
+              54:    7(fvec4) ImageFetch 35 44 Lod 53
+              55:    7(fvec4) FAdd 34 54
+                              ReturnValue 55
+                              FunctionEnd
diff --git a/Test/hlsl.mip.negative.frag b/Test/hlsl.mip.negative.frag
new file mode 100644
index 0000000000000000000000000000000000000000..900d385063a0fd5eb3ceddc80bc713a0f76d3cfe
--- /dev/null
+++ b/Test/hlsl.mip.negative.frag
@@ -0,0 +1,9 @@
+Texture2D          g_tTex2df4;
+
+float4 main() : SV_Target0
+{
+    g_tTex2df4.mips.mips[2][uint2(3, 4)]; // error to chain like this
+
+    return 0;
+}
+    
diff --git a/Test/hlsl.mip.negative2.frag b/Test/hlsl.mip.negative2.frag
new file mode 100644
index 0000000000000000000000000000000000000000..c07179eb28d8cc97e8ed06daa351f0b71fc013e8
--- /dev/null
+++ b/Test/hlsl.mip.negative2.frag
@@ -0,0 +1,9 @@
+Texture2D          g_tTex2df4;
+
+float4 main() : SV_Target0
+{
+    g_tTex2df4.r[2][uint2(3, 4)]; // '.r' not valid on texture object
+
+    return 0;
+}
+    
diff --git a/Test/hlsl.mip.operator.frag b/Test/hlsl.mip.operator.frag
new file mode 100644
index 0000000000000000000000000000000000000000..af4f150136ed42d513225aeb8eb28df608524c88
--- /dev/null
+++ b/Test/hlsl.mip.operator.frag
@@ -0,0 +1,14 @@
+Texture2DArray     g_tTex2df4a;
+Texture2D          g_tTex2df4;
+
+float4 main() : SV_Target0
+{
+    return g_tTex2df4.mips[2][uint2(3, 4)] +
+
+        // test float->uint cast on the mip arg
+        g_tTex2df4a.mips[5.2][uint3(6, 7, 8)] +
+
+        // Test nesting involving .mips operators:
+        //               ....outer operator mip level......     .....outer operator coordinate....
+        g_tTex2df4.mips[ g_tTex2df4.mips[9][uint2(10,11)][0] ][ g_tTex2df4.mips[13][uint2(14,15)].xy ];
+}
diff --git a/Test/remap.specconst.comp b/Test/remap.specconst.comp
new file mode 100644
index 0000000000000000000000000000000000000000..52ac07aa054f7b6b165374345578731bee09654f
--- /dev/null
+++ b/Test/remap.specconst.comp
@@ -0,0 +1,7 @@
+#version 450
+
+layout (local_size_x_id = 0, local_size_y_id = 1, local_size_z_id = 2) in;
+
+shared int foo[gl_WorkGroupSize.x + gl_WorkGroupSize.y * gl_WorkGroupSize.z];
+
+void main () {}
diff --git a/gtests/Hlsl.FromFile.cpp b/gtests/Hlsl.FromFile.cpp
index 7dbed5e0b78a7884e4e243d277a3dcf7ed4a0b36..9612a4cfb5cd1248d5aa9ba9f6b71a0d11efd7a9 100644
--- a/gtests/Hlsl.FromFile.cpp
+++ b/gtests/Hlsl.FromFile.cpp
@@ -177,6 +177,9 @@ INSTANTIATE_TEST_CASE_P(
         {"hlsl.logicalConvert.frag", "main"},
         {"hlsl.logical.unary.frag", "main"},
         {"hlsl.loopattr.frag", "main"},
+        {"hlsl.mip.operator.frag", "main"},
+        {"hlsl.mip.negative.frag", "main"},
+        {"hlsl.mip.negative2.frag", "main"},
         {"hlsl.namespace.frag", "main"},
         {"hlsl.nonint-index.frag", "main"},
         {"hlsl.matNx1.frag", "main"},
diff --git a/hlsl/hlslParseHelper.cpp b/hlsl/hlslParseHelper.cpp
index 54be467662038bffcf18e047179e6b6437c09f77..75115f8379b4eb18ea220f44bec14d82b0e4d269 100755
--- a/hlsl/hlslParseHelper.cpp
+++ b/hlsl/hlslParseHelper.cpp
@@ -677,19 +677,30 @@ TIntermTyped* HlslParseContext::handleBracketOperator(const TSourceLoc& loc, TIn
     if (base->getType().getBasicType() == EbtSampler && !base->isArray()) {
         const TSampler& sampler = base->getType().getSampler();
         if (sampler.isImage() || sampler.isTexture()) {
-            TIntermAggregate* load = new TIntermAggregate(sampler.isImage() ? EOpImageLoad : EOpTextureFetch);
-
-            load->setType(TType(sampler.type, EvqTemporary, sampler.vectorSize));
-            load->setLoc(loc);
-            load->getSequence().push_back(base);
-            load->getSequence().push_back(index);
-
-            // Textures need a MIP.  First indirection is always to mip 0.  If there's another, we'll add it
-            // later.
-            if (sampler.isTexture())
-                load->getSequence().push_back(intermediate.addConstantUnion(0, loc, true));
+            if (! mipsOperatorMipArg.empty() && mipsOperatorMipArg.back().mipLevel == nullptr) {
+                // The first operator[] to a .mips[] sequence is the mip level.  We'll remember it.
+                mipsOperatorMipArg.back().mipLevel = index;
+                return base;  // next [] index is to the same base.
+            } else {
+                TIntermAggregate* load = new TIntermAggregate(sampler.isImage() ? EOpImageLoad : EOpTextureFetch);
+
+                load->setType(TType(sampler.type, EvqTemporary, sampler.vectorSize));
+                load->setLoc(loc);
+                load->getSequence().push_back(base);
+                load->getSequence().push_back(index);
+
+                // Textures need a MIP.  If we saw one go by, use it.  Otherwise, use zero.
+                if (sampler.isTexture()) {
+                    if (! mipsOperatorMipArg.empty()) {
+                        load->getSequence().push_back(mipsOperatorMipArg.back().mipLevel);
+                        mipsOperatorMipArg.pop_back();
+                    } else {
+                        load->getSequence().push_back(intermediate.addConstantUnion(0, loc, true));
+                    }
+                }
 
-            return load;
+                return load;
+            }
         }
     }
 
@@ -874,7 +885,21 @@ TIntermTyped* HlslParseContext::handleDotDereference(const TSourceLoc& loc, TInt
     }
 
     TIntermTyped* result = base;
-    if (base->isVector() || base->isScalar()) {
+
+    if (base->getType().getBasicType() == EbtSampler) {
+        // Handle .mips[mipid][pos] operation on textures
+        const TSampler& sampler = base->getType().getSampler();
+        if (sampler.isTexture() && field == "mips") {
+            // Push a null to signify that we expect a mip level under operator[] next.
+            mipsOperatorMipArg.push_back(tMipsOperatorData(loc, nullptr));
+            // Keep 'result' pointing to 'base', since we expect an operator[] to go by next.
+        } else {
+            if (field == "mips")
+                error(loc, "unexpected texture type for .mips[][] operator:", base->getType().getCompleteString().c_str(), "");
+            else
+                error(loc, "unexpected operator on texture type:", field.c_str(), base->getType().getCompleteString().c_str());
+        }
+    } else if (base->isVector() || base->isScalar()) {
         TSwizzleSelectors<TVectorSelector> selectors;
         parseSwizzleSelector(loc, field, base->getVectorSize(), selectors);
 
@@ -8426,6 +8451,12 @@ void HlslParseContext::removeUnusedStructBufferCounters()
 // post-processing
 void HlslParseContext::finish()
 {
+    // Error check: There was a dangling .mips operator.  These are not nested constructs in the grammar, so
+    // cannot be detected there.  This is not strictly needed in a non-validating parser; it's just helpful.
+    if (! mipsOperatorMipArg.empty()) {
+        error(mipsOperatorMipArg.back().loc, "unterminated mips operator:", "", "");
+    }
+
     removeUnusedStructBufferCounters();
     addPatchConstantInvocation();
     addInterstageIoToLinkage();
diff --git a/hlsl/hlslParseHelper.h b/hlsl/hlslParseHelper.h
index d5cbc0633ba8653451c5a810fba260429dfe38f0..4b5c0b75f004555b461c357063fdc928ac4370fa 100755
--- a/hlsl/hlslParseHelper.h
+++ b/hlsl/hlslParseHelper.h
@@ -429,6 +429,17 @@ protected:
     TVector<TVariable*> implicitThisStack;   // currently active 'this' variables for nested structures
 
     TVariable* gsStreamOutput;               // geometry shader stream outputs, for emit (Append method)
+
+    // This tracks the first (mip level) argument to the .mips[][] operator.  Since this can be nested as
+    // in tx.mips[tx.mips[0][1].x][2], we need a stack.  We also track the TSourceLoc for error reporting 
+    // purposes.
+    struct tMipsOperatorData {
+        tMipsOperatorData(TSourceLoc l, TIntermTyped* m) : loc(l), mipLevel(m) { }
+        TSourceLoc loc;
+        TIntermTyped* mipLevel;
+    };
+
+    TVector<tMipsOperatorData> mipsOperatorMipArg;
 };
 
 // This is the prefix we use for builtin methods to avoid namespace collisions with