Fix buffer oob instrumentation for matrix refs (#4025)

Fix buffer oob instrumentation for matrix refs.

Matrix stride decoration is not on matrix type but is a member decoration
on the enclosing struct type. Also correctly apply matrix stride depending
on row or column major.
diff --git a/source/opt/decoration_manager.cpp b/source/opt/decoration_manager.cpp
index a10c992..8b4aee5 100644
--- a/source/opt/decoration_manager.cpp
+++ b/source/opt/decoration_manager.cpp
@@ -487,6 +487,13 @@
   });
 }
 
+bool DecorationManager::FindDecoration(
+    uint32_t id, uint32_t decoration,
+    std::function<bool(const Instruction&)> f) {
+  return !WhileEachDecoration(
+      id, decoration, [&f](const Instruction& inst) { return !f(inst); });
+}
+
 void DecorationManager::CloneDecorations(uint32_t from, uint32_t to) {
   const auto decoration_list = id_to_decoration_insts_.find(from);
   if (decoration_list == id_to_decoration_insts_.end()) return;
diff --git a/source/opt/decoration_manager.h b/source/opt/decoration_manager.h
index 01244f2..e1ae8d5 100644
--- a/source/opt/decoration_manager.h
+++ b/source/opt/decoration_manager.h
@@ -102,6 +102,13 @@
   bool WhileEachDecoration(uint32_t id, uint32_t decoration,
                            std::function<bool(const Instruction&)> f);
 
+  // |f| is run on each decoration instruction for |id| with decoration
+  // |decoration|. Processes all decoration which target |id| either directly or
+  // indirectly through decoration groups. If |f| returns true, iteration is
+  // terminated and this function returns true. Otherwise returns false.
+  bool FindDecoration(uint32_t id, uint32_t decoration,
+                      std::function<bool(const Instruction&)> f);
+
   // Clone all decorations from one id |from|.
   // The cloned decorations are assigned to the given id |to| and are
   // added to the module. The purpose is to decorate cloned instructions.
diff --git a/source/opt/inst_bindless_check_pass.cpp b/source/opt/inst_bindless_check_pass.cpp
index 64d389c..7eb2d1b 100644
--- a/source/opt/inst_bindless_check_pass.cpp
+++ b/source/opt/inst_bindless_check_pass.cpp
@@ -267,34 +267,45 @@
 uint32_t InstBindlessCheckPass::FindStride(uint32_t ty_id,
                                            uint32_t stride_deco) {
   uint32_t stride = 0xdeadbeef;
-  bool found = !get_decoration_mgr()->WhileEachDecoration(
+  bool found = get_decoration_mgr()->FindDecoration(
       ty_id, stride_deco, [&stride](const Instruction& deco_inst) {
         stride = deco_inst.GetSingleWordInOperand(2u);
-        return false;
+        return true;
       });
   USE_ASSERT(found && "stride not found");
   return stride;
 }
 
-uint32_t InstBindlessCheckPass::ByteSize(uint32_t ty_id) {
+uint32_t InstBindlessCheckPass::ByteSize(uint32_t ty_id, uint32_t matrix_stride,
+                                         bool col_major, bool in_matrix) {
   analysis::TypeManager* type_mgr = context()->get_type_mgr();
   const analysis::Type* sz_ty = type_mgr->GetType(ty_id);
   if (sz_ty->kind() == analysis::Type::kPointer) {
     // Assuming PhysicalStorageBuffer pointer
     return 8;
   }
-  uint32_t size = 1;
   if (sz_ty->kind() == analysis::Type::kMatrix) {
+    assert(matrix_stride != 0 && "missing matrix stride");
     const analysis::Matrix* m_ty = sz_ty->AsMatrix();
-    size = m_ty->element_count() * size;
-    uint32_t stride = FindStride(ty_id, SpvDecorationMatrixStride);
-    if (stride != 0) return size * stride;
-    sz_ty = m_ty->element_type();
+    if (col_major) {
+      return m_ty->element_count() * matrix_stride;
+    } else {
+      const analysis::Vector* v_ty = m_ty->element_type()->AsVector();
+      return v_ty->element_count() * matrix_stride;
+    }
   }
+  uint32_t size = 1;
   if (sz_ty->kind() == analysis::Type::kVector) {
     const analysis::Vector* v_ty = sz_ty->AsVector();
-    size = v_ty->element_count() * size;
-    sz_ty = v_ty->element_type();
+    size = v_ty->element_count();
+    const analysis::Type* comp_ty = v_ty->element_type();
+    // if vector in row major matrix, the vector is strided so return the
+    // number of bytes spanned by the vector
+    if (in_matrix && !col_major && matrix_stride > 0) {
+      uint32_t comp_ty_id = type_mgr->GetId(comp_ty);
+      return (size - 1) * matrix_stride + ByteSize(comp_ty_id, 0, false, false);
+    }
+    sz_ty = comp_ty;
   }
   switch (sz_ty->kind()) {
     case analysis::Type::kFloat: {
@@ -333,21 +344,20 @@
   // Process remaining access chain indices
   Instruction* ac_inst = get_def_use_mgr()->GetDef(ref->ptr_id);
   uint32_t curr_ty_id = buff_ty_id;
-  uint32_t sum_id = 0;
+  uint32_t sum_id = 0u;
+  uint32_t matrix_stride = 0u;
+  bool col_major = false;
+  uint32_t matrix_stride_id = 0u;
+  bool in_matrix = false;
   while (ac_in_idx < ac_inst->NumInOperands()) {
     uint32_t curr_idx_id = ac_inst->GetSingleWordInOperand(ac_in_idx);
-    Instruction* curr_idx_inst = get_def_use_mgr()->GetDef(curr_idx_id);
     Instruction* curr_ty_inst = get_def_use_mgr()->GetDef(curr_ty_id);
     uint32_t curr_offset_id = 0;
     switch (curr_ty_inst->opcode()) {
       case SpvOpTypeArray:
-      case SpvOpTypeRuntimeArray:
-      case SpvOpTypeMatrix: {
-        // Get array/matrix stride and multiply by current index
-        uint32_t stride_deco = (curr_ty_inst->opcode() == SpvOpTypeMatrix)
-                                   ? SpvDecorationMatrixStride
-                                   : SpvDecorationArrayStride;
-        uint32_t arr_stride = FindStride(curr_ty_id, stride_deco);
+      case SpvOpTypeRuntimeArray: {
+        // Get array stride and multiply by current index
+        uint32_t arr_stride = FindStride(curr_ty_id, SpvDecorationArrayStride);
         uint32_t arr_stride_id = builder->GetUintConstantId(arr_stride);
         uint32_t curr_idx_32b_id = Gen32BitCvtCode(curr_idx_id, builder);
         Instruction* curr_offset_inst = builder->AddBinaryOp(
@@ -356,34 +366,89 @@
         // Get element type for next step
         curr_ty_id = curr_ty_inst->GetSingleWordInOperand(0);
       } break;
-      case SpvOpTypeVector: {
-        // Stride is size of component type
-        uint32_t comp_ty_id = curr_ty_inst->GetSingleWordInOperand(0u);
-        uint32_t vec_stride = ByteSize(comp_ty_id);
-        uint32_t vec_stride_id = builder->GetUintConstantId(vec_stride);
+      case SpvOpTypeMatrix: {
+        assert(matrix_stride != 0 && "missing matrix stride");
+        matrix_stride_id = builder->GetUintConstantId(matrix_stride);
+        uint32_t vec_ty_id = curr_ty_inst->GetSingleWordInOperand(0);
+        // If column major, multiply column index by matrix stride, otherwise
+        // by vector component size and save matrix stride for vector (row)
+        // index
+        uint32_t col_stride_id;
+        if (col_major) {
+          col_stride_id = matrix_stride_id;
+        } else {
+          Instruction* vec_ty_inst = get_def_use_mgr()->GetDef(vec_ty_id);
+          uint32_t comp_ty_id = vec_ty_inst->GetSingleWordInOperand(0u);
+          uint32_t col_stride = ByteSize(comp_ty_id, 0u, false, false);
+          col_stride_id = builder->GetUintConstantId(col_stride);
+        }
         uint32_t curr_idx_32b_id = Gen32BitCvtCode(curr_idx_id, builder);
         Instruction* curr_offset_inst = builder->AddBinaryOp(
-            GetUintId(), SpvOpIMul, vec_stride_id, curr_idx_32b_id);
+            GetUintId(), SpvOpIMul, col_stride_id, curr_idx_32b_id);
         curr_offset_id = curr_offset_inst->result_id();
         // Get element type for next step
+        curr_ty_id = vec_ty_id;
+        in_matrix = true;
+      } break;
+      case SpvOpTypeVector: {
+        // If inside a row major matrix type, multiply index by matrix stride,
+        // else multiply by component size
+        uint32_t comp_ty_id = curr_ty_inst->GetSingleWordInOperand(0u);
+        uint32_t curr_idx_32b_id = Gen32BitCvtCode(curr_idx_id, builder);
+        if (in_matrix && !col_major) {
+          Instruction* curr_offset_inst = builder->AddBinaryOp(
+              GetUintId(), SpvOpIMul, matrix_stride_id, curr_idx_32b_id);
+          curr_offset_id = curr_offset_inst->result_id();
+        } else {
+          uint32_t comp_ty_sz = ByteSize(comp_ty_id, 0u, false, false);
+          uint32_t comp_ty_sz_id = builder->GetUintConstantId(comp_ty_sz);
+          Instruction* curr_offset_inst = builder->AddBinaryOp(
+              GetUintId(), SpvOpIMul, comp_ty_sz_id, curr_idx_32b_id);
+          curr_offset_id = curr_offset_inst->result_id();
+        }
+        // Get element type for next step
         curr_ty_id = comp_ty_id;
       } break;
       case SpvOpTypeStruct: {
         // Get buffer byte offset for the referenced member
+        Instruction* curr_idx_inst = get_def_use_mgr()->GetDef(curr_idx_id);
         assert(curr_idx_inst->opcode() == SpvOpConstant &&
                "unexpected struct index");
         uint32_t member_idx = curr_idx_inst->GetSingleWordInOperand(0);
         uint32_t member_offset = 0xdeadbeef;
-        bool found = !get_decoration_mgr()->WhileEachDecoration(
+        bool found = get_decoration_mgr()->FindDecoration(
             curr_ty_id, SpvDecorationOffset,
             [&member_idx, &member_offset](const Instruction& deco_inst) {
               if (deco_inst.GetSingleWordInOperand(1u) != member_idx)
-                return true;
+                return false;
               member_offset = deco_inst.GetSingleWordInOperand(3u);
-              return false;
+              return true;
             });
         USE_ASSERT(found && "member offset not found");
         curr_offset_id = builder->GetUintConstantId(member_offset);
+        // Look for matrix stride for this member if there is one. The matrix
+        // stride is not on the matrix type, but in a OpMemberDecorate on the
+        // enclosing struct type at the member index. If none found, reset
+        // stride to 0.
+        found = get_decoration_mgr()->FindDecoration(
+            curr_ty_id, SpvDecorationMatrixStride,
+            [&member_idx, &matrix_stride](const Instruction& deco_inst) {
+              if (deco_inst.GetSingleWordInOperand(1u) != member_idx)
+                return false;
+              matrix_stride = deco_inst.GetSingleWordInOperand(3u);
+              return true;
+            });
+        if (!found) matrix_stride = 0;
+        // Look for column major decoration
+        found = get_decoration_mgr()->FindDecoration(
+            curr_ty_id, SpvDecorationColMajor,
+            [&member_idx, &col_major](const Instruction& deco_inst) {
+              if (deco_inst.GetSingleWordInOperand(1u) != member_idx)
+                return false;
+              col_major = true;
+              return true;
+            });
+        if (!found) col_major = false;
         // Get element type for next step
         curr_ty_id = curr_ty_inst->GetSingleWordInOperand(member_idx);
       } break;
@@ -399,7 +464,7 @@
     ++ac_in_idx;
   }
   // Add in offset of last byte of referenced object
-  uint32_t bsize = ByteSize(curr_ty_id);
+  uint32_t bsize = ByteSize(curr_ty_id, matrix_stride, col_major, in_matrix);
   uint32_t last = bsize - 1;
   uint32_t last_id = builder->GetUintConstantId(last);
   Instruction* sum_inst =
diff --git a/source/opt/inst_bindless_check_pass.h b/source/opt/inst_bindless_check_pass.h
index 50dfd95..29da6f3 100644
--- a/source/opt/inst_bindless_check_pass.h
+++ b/source/opt/inst_bindless_check_pass.h
@@ -132,8 +132,10 @@
     Instruction* ref_inst;
   } ref_analysis;
 
-  // Return size of type |ty_id| in bytes.
-  uint32_t ByteSize(uint32_t ty_id);
+  // Return size of type |ty_id| in bytes. Use |matrix_stride| and |col_major|
+  // for matrix type, or for vector type if vector is |in_matrix|.
+  uint32_t ByteSize(uint32_t ty_id, uint32_t matrix_stride, bool col_major,
+                    bool in_matrix);
 
   // Return stride of type |ty_id| with decoration |stride_deco|. Return 0
   // if not found
diff --git a/test/opt/inst_bindless_check_test.cpp b/test/opt/inst_bindless_check_test.cpp
index 67a4968..691bc9a 100644
--- a/test/opt/inst_bindless_check_test.cpp
+++ b/test/opt/inst_bindless_check_test.cpp
@@ -8474,6 +8474,642 @@
                                                false, true);
 }
 
+TEST_F(InstBindlessTest, UniformMatrixRefRowMajor) {
+  // The buffer-oob row major matrix check
+  //
+  // #version 450
+  // #extension GL_EXT_scalar_block_layout : enable
+  //
+  // layout(location = 0) in highp vec4 a_position;
+  // layout(location = 0) out mediump float v_vtxResult;
+  //
+  // layout(set = 0, binding = 0, std430, row_major) uniform Block
+  // {
+  //    lowp mat4x2 var;
+  // };
+  //
+  // void main (void)
+  // {
+  //    v_vtxResult = var[2][1];
+  // }
+
+  const std::string text = R"(
+               OpCapability Shader
+;CHECK:               OpExtension "SPV_KHR_storage_buffer_storage_class"
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Vertex %main "main" %v_vtxResult %_ %a_position
+;CHECK:               OpEntryPoint Vertex %main "main" %v_vtxResult %_ %a_position %45 %72 %gl_VertexIndex %gl_InstanceIndex
+               OpSource GLSL 450
+               OpSourceExtension "GL_EXT_scalar_block_layout"
+               OpName %main "main"
+               OpName %v_vtxResult "v_vtxResult"
+               OpName %Block "Block"
+               OpMemberName %Block 0 "var"
+               OpName %_ ""
+               OpName %a_position "a_position"
+               OpDecorate %v_vtxResult RelaxedPrecision
+               OpDecorate %v_vtxResult Location 0
+               OpMemberDecorate %Block 0 RowMajor
+               OpMemberDecorate %Block 0 RelaxedPrecision
+               OpMemberDecorate %Block 0 Offset 0
+               OpMemberDecorate %Block 0 MatrixStride 16
+               OpDecorate %Block Block
+               OpDecorate %_ DescriptorSet 0
+               OpDecorate %_ Binding 0
+               OpDecorate %21 RelaxedPrecision
+;CHECK-NOT:           OpDecorate %21 RelaxedPrecision
+;CHECK:               OpDecorate %116 RelaxedPrecision
+               OpDecorate %a_position Location 0
+;CHECK:               OpDecorate %_runtimearr_uint ArrayStride 4
+;CHECK:               OpDecorate %_struct_43 Block
+;CHECK:               OpMemberDecorate %_struct_43 0 Offset 0
+;CHECK:               OpDecorate %45 DescriptorSet 7
+;CHECK:               OpDecorate %45 Binding 1
+;CHECK:               OpDecorate %61 RelaxedPrecision
+;CHECK:               OpDecorate %_struct_70 Block
+;CHECK:               OpMemberDecorate %_struct_70 0 Offset 0
+;CHECK:               OpMemberDecorate %_struct_70 1 Offset 4
+;CHECK:               OpDecorate %72 DescriptorSet 7
+;CHECK:               OpDecorate %72 Binding 0
+;CHECK:               OpDecorate %gl_VertexIndex BuiltIn VertexIndex
+;CHECK:               OpDecorate %gl_InstanceIndex BuiltIn InstanceIndex
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+%_ptr_Output_float = OpTypePointer Output %float
+%v_vtxResult = OpVariable %_ptr_Output_float Output
+    %v2float = OpTypeVector %float 2
+%mat4v2float = OpTypeMatrix %v2float 4
+      %Block = OpTypeStruct %mat4v2float
+%_ptr_Uniform_Block = OpTypePointer Uniform %Block
+          %_ = OpVariable %_ptr_Uniform_Block Uniform
+        %int = OpTypeInt 32 1
+      %int_0 = OpConstant %int 0
+      %int_2 = OpConstant %int 2
+       %uint = OpTypeInt 32 0
+     %uint_1 = OpConstant %uint 1
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+    %v4float = OpTypeVector %float 4
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+ %a_position = OpVariable %_ptr_Input_v4float Input
+;CHECK;     %uint_0 = OpConstant %uint 0
+;CHECK;     %uint_4 = OpConstant %uint 4
+;CHECK;     %uint_3 = OpConstant %uint 3
+;CHECK;         %37 = OpTypeFunction %uint %uint %uint %uint
+;CHECK;%_runtimearr_uint = OpTypeRuntimeArray %uint
+;CHECK; %_struct_43 = OpTypeStruct %_runtimearr_uint
+;CHECK;%_ptr_StorageBuffer__struct_43 = OpTypePointer StorageBuffer %_struct_43
+;CHECK;         %45 = OpVariable %_ptr_StorageBuffer__struct_43 StorageBuffer
+;CHECK;%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
+;CHECK;       %bool = OpTypeBool
+;CHECK;         %63 = OpTypeFunction %void %uint %uint %uint %uint %uint
+;CHECK; %_struct_70 = OpTypeStruct %uint %_runtimearr_uint
+;CHECK;%_ptr_StorageBuffer__struct_70 = OpTypePointer StorageBuffer %_struct_70
+;CHECK;         %72 = OpVariable %_ptr_StorageBuffer__struct_70 StorageBuffer
+;CHECK;    %uint_11 = OpConstant %uint 11
+;CHECK;    %uint_23 = OpConstant %uint 23
+;CHECK;     %uint_2 = OpConstant %uint 2
+;CHECK;%_ptr_Input_uint = OpTypePointer Input %uint
+;CHECK;%gl_VertexIndex = OpVariable %_ptr_Input_uint Input
+;CHECK;%gl_InstanceIndex = OpVariable %_ptr_Input_uint Input
+;CHECK;     %uint_5 = OpConstant %uint 5
+;CHECK;     %uint_7 = OpConstant %uint 7
+;CHECK;     %uint_8 = OpConstant %uint 8
+;CHECK;     %uint_9 = OpConstant %uint 9
+;CHECK;    %uint_10 = OpConstant %uint 10
+;CHECK;    %uint_45 = OpConstant %uint 45
+;CHECK;        %115 = OpConstantNull %float
+;CHECK;    %uint_27 = OpConstant %uint 27
+       %main = OpFunction %void None %3
+          %5 = OpLabel
+;CHECK:         %55 = OpFunctionCall %uint %36 %uint_1 %uint_0 %uint_0
+         %20 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %int_2 %uint_1
+         %21 = OpLoad %float %20
+;CHECK-NOT:     %21 = OpLoad %float %20
+;CHECK:         %30 = OpIMul %uint %uint_4 %int_2
+;CHECK:         %31 = OpIAdd %uint %uint_0 %30
+;CHECK:         %32 = OpIMul %uint %uint_16 %uint_1
+;CHECK:         %33 = OpIAdd %uint %31 %32
+;CHECK:         %35 = OpIAdd %uint %33 %uint_3
+;CHECK:         %57 = OpULessThan %bool %35 %55
+;CHECK:               OpSelectionMerge %58 None
+;CHECK:               OpBranchConditional %57 %59 %60
+;CHECK:         %59 = OpLabel
+;CHECK:         %61 = OpLoad %float %20
+;CHECK:               OpBranch %58
+;CHECK:         %60 = OpLabel
+;CHECK:        %114 = OpFunctionCall %void %62 %uint_45 %uint_3 %uint_0 %35 %55
+;CHECK:               OpBranch %58
+;CHECK:         %58 = OpLabel
+;CHECK:        %116 = OpPhi %float %61 %59 %115 %60
+               OpStore %v_vtxResult %21
+;CHECK-NOT:           OpStore %v_vtxResult %21
+;CHECK:               OpStore %v_vtxResult %116
+               OpReturn
+               OpFunctionEnd
+;CHECK:         %36 = OpFunction %uint None %37
+;CHECK:         %38 = OpFunctionParameter %uint
+;CHECK:         %39 = OpFunctionParameter %uint
+;CHECK:         %40 = OpFunctionParameter %uint
+;CHECK:         %41 = OpLabel
+;CHECK:         %47 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_0 %38
+;CHECK:         %48 = OpLoad %uint %47
+;CHECK:         %49 = OpIAdd %uint %48 %39
+;CHECK:         %50 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_0 %49
+;CHECK:         %51 = OpLoad %uint %50
+;CHECK:         %52 = OpIAdd %uint %51 %40
+;CHECK:         %53 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_0 %52
+;CHECK:         %54 = OpLoad %uint %53
+;CHECK:               OpReturnValue %54
+;CHECK:               OpFunctionEnd
+;CHECK:         %62 = OpFunction %void None %63
+;CHECK:         %64 = OpFunctionParameter %uint
+;CHECK:         %65 = OpFunctionParameter %uint
+;CHECK:         %66 = OpFunctionParameter %uint
+;CHECK:         %67 = OpFunctionParameter %uint
+;CHECK:         %68 = OpFunctionParameter %uint
+;CHECK:         %69 = OpLabel
+;CHECK:         %73 = OpAccessChain %_ptr_StorageBuffer_uint %72 %uint_0
+;CHECK:         %75 = OpAtomicIAdd %uint %73 %uint_4 %uint_0 %uint_11
+;CHECK:         %76 = OpIAdd %uint %75 %uint_11
+;CHECK:         %77 = OpArrayLength %uint %72 1
+;CHECK:         %78 = OpULessThanEqual %bool %76 %77
+;CHECK:               OpSelectionMerge %79 None
+;CHECK:               OpBranchConditional %78 %80 %79
+;CHECK:         %80 = OpLabel
+;CHECK:         %81 = OpIAdd %uint %75 %uint_0
+;CHECK:         %82 = OpAccessChain %_ptr_StorageBuffer_uint %72 %uint_1 %81
+;CHECK:               OpStore %82 %uint_11
+;CHECK:         %84 = OpIAdd %uint %75 %uint_1
+;CHECK:         %85 = OpAccessChain %_ptr_StorageBuffer_uint %72 %uint_1 %84
+;CHECK:               OpStore %85 %uint_23
+;CHECK:         %87 = OpIAdd %uint %75 %uint_2
+;CHECK:         %88 = OpAccessChain %_ptr_StorageBuffer_uint %72 %uint_1 %87
+;CHECK:               OpStore %88 %64
+;CHECK:         %89 = OpIAdd %uint %75 %uint_3
+;CHECK:         %90 = OpAccessChain %_ptr_StorageBuffer_uint %72 %uint_1 %89
+;CHECK:               OpStore %90 %uint_0
+;CHECK:         %93 = OpLoad %uint %gl_VertexIndex
+;CHECK:         %94 = OpIAdd %uint %75 %uint_4
+;CHECK:         %95 = OpAccessChain %_ptr_StorageBuffer_uint %72 %uint_1 %94
+;CHECK:               OpStore %95 %93
+;CHECK:         %97 = OpLoad %uint %gl_InstanceIndex
+;CHECK:         %99 = OpIAdd %uint %75 %uint_5
+;CHECK:        %100 = OpAccessChain %_ptr_StorageBuffer_uint %72 %uint_1 %99
+;CHECK:               OpStore %100 %97
+;CHECK:        %102 = OpIAdd %uint %75 %uint_7
+;CHECK:        %103 = OpAccessChain %_ptr_StorageBuffer_uint %72 %uint_1 %102
+;CHECK:               OpStore %103 %65
+;CHECK:        %105 = OpIAdd %uint %75 %uint_8
+;CHECK:        %106 = OpAccessChain %_ptr_StorageBuffer_uint %72 %uint_1 %105
+;CHECK:               OpStore %106 %66
+;CHECK:        %108 = OpIAdd %uint %75 %uint_9
+;CHECK:        %109 = OpAccessChain %_ptr_StorageBuffer_uint %72 %uint_1 %108
+;CHECK:               OpStore %109 %67
+;CHECK:        %111 = OpIAdd %uint %75 %uint_10
+;CHECK:        %112 = OpAccessChain %_ptr_StorageBuffer_uint %72 %uint_1 %111
+;CHECK:               OpStore %112 %68
+;CHECK:               OpBranch %79
+;CHECK:         %79 = OpLabel
+;CHECK:               OpReturn
+;CHECK:               OpFunctionEnd
+ )";
+
+  SetTargetEnv(SPV_ENV_VULKAN_1_2);
+  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 7u, 23u, false,
+                                               false, true);
+}
+
+TEST_F(InstBindlessTest, UniformMatrixRefColumnMajor) {
+  // The buffer-oob column major matrix check
+  //
+  // #version 450
+  // #extension GL_EXT_scalar_block_layout : enable
+  //
+  // layout(location = 0) in highp vec4 a_position;
+  // layout(location = 0) out mediump float v_vtxResult;
+  //
+  // layout(set = 0, binding = 0, std430, column_major) uniform Block
+  // {
+  //    lowp mat4x2 var;
+  // };
+  //
+  // void main (void)
+  // {
+  //    v_vtxResult = var[2][1];
+  // }
+
+  const std::string text = R"(
+               OpCapability Shader
+;CHECK:               OpExtension "SPV_KHR_storage_buffer_storage_class"
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Vertex %main "main" %v_vtxResult %_ %a_position
+;CHECK:               OpEntryPoint Vertex %main "main" %v_vtxResult %_ %a_position %45 %72 %gl_VertexIndex %gl_InstanceIndex
+               OpSource GLSL 450
+               OpSourceExtension "GL_EXT_scalar_block_layout"
+               OpName %main "main"
+               OpName %v_vtxResult "v_vtxResult"
+               OpName %Block "Block"
+               OpMemberName %Block 0 "var"
+               OpName %_ ""
+               OpName %a_position "a_position"
+               OpDecorate %v_vtxResult RelaxedPrecision
+               OpDecorate %v_vtxResult Location 0
+               OpMemberDecorate %Block 0 ColMajor
+               OpMemberDecorate %Block 0 RelaxedPrecision
+               OpMemberDecorate %Block 0 Offset 0
+               OpMemberDecorate %Block 0 MatrixStride 8
+               OpDecorate %Block Block
+               OpDecorate %_ DescriptorSet 0
+               OpDecorate %_ Binding 0
+               OpDecorate %21 RelaxedPrecision
+;CHECK-NOT:           OpDecorate %21 RelaxedPrecision
+;CHECK:               OpDecorate %115 RelaxedPrecision
+               OpDecorate %a_position Location 0
+;CHECK:               OpDecorate %_runtimearr_uint ArrayStride 4
+;CHECK:               OpDecorate %_struct_43 Block
+;CHECK:               OpMemberDecorate %_struct_43 0 Offset 0
+;CHECK:               OpDecorate %45 DescriptorSet 7
+;CHECK:               OpDecorate %45 Binding 1
+;CHECK:               OpDecorate %61 RelaxedPrecision
+;CHECK:               OpDecorate %_struct_70 Block
+;CHECK:               OpMemberDecorate %_struct_70 0 Offset 0
+;CHECK:               OpMemberDecorate %_struct_70 1 Offset 4
+;CHECK:               OpDecorate %72 DescriptorSet 7
+;CHECK:               OpDecorate %72 Binding 0
+;CHECK:               OpDecorate %gl_VertexIndex BuiltIn VertexIndex
+;CHECK:               OpDecorate %gl_InstanceIndex BuiltIn InstanceIndex
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+%_ptr_Output_float = OpTypePointer Output %float
+%v_vtxResult = OpVariable %_ptr_Output_float Output
+    %v2float = OpTypeVector %float 2
+%mat4v2float = OpTypeMatrix %v2float 4
+      %Block = OpTypeStruct %mat4v2float
+%_ptr_Uniform_Block = OpTypePointer Uniform %Block
+          %_ = OpVariable %_ptr_Uniform_Block Uniform
+        %int = OpTypeInt 32 1
+      %int_0 = OpConstant %int 0
+      %int_2 = OpConstant %int 2
+       %uint = OpTypeInt 32 0
+     %uint_1 = OpConstant %uint 1
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+    %v4float = OpTypeVector %float 4
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+ %a_position = OpVariable %_ptr_Input_v4float Input
+;CHECK:     %uint_0 = OpConstant %uint 0
+;CHECK:     %uint_8 = OpConstant %uint 8
+;CHECK:     %uint_4 = OpConstant %uint 4
+;CHECK:     %uint_3 = OpConstant %uint 3
+;CHECK:         %37 = OpTypeFunction %uint %uint %uint %uint
+;CHECK:%_runtimearr_uint = OpTypeRuntimeArray %uint
+;CHECK: %_struct_43 = OpTypeStruct %_runtimearr_uint
+;CHECK:%_ptr_StorageBuffer__struct_43 = OpTypePointer StorageBuffer %_struct_43
+;CHECK:         %45 = OpVariable %_ptr_StorageBuffer__struct_43 StorageBuffer
+;CHECK:%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
+;CHECK:       %bool = OpTypeBool
+;CHECK:         %63 = OpTypeFunction %void %uint %uint %uint %uint %uint
+;CHECK: %_struct_70 = OpTypeStruct %uint %_runtimearr_uint
+;CHECK:%_ptr_StorageBuffer__struct_70 = OpTypePointer StorageBuffer %_struct_70
+;CHECK:         %72 = OpVariable %_ptr_StorageBuffer__struct_70 StorageBuffer
+;CHECK:    %uint_11 = OpConstant %uint 11
+;CHECK:    %uint_23 = OpConstant %uint 23
+;CHECK:     %uint_2 = OpConstant %uint 2
+;CHECK:%_ptr_Input_uint = OpTypePointer Input %uint
+;CHECK:%gl_VertexIndex = OpVariable %_ptr_Input_uint Input
+;CHECK:%gl_InstanceIndex = OpVariable %_ptr_Input_uint Input
+;CHECK:     %uint_5 = OpConstant %uint 5
+;CHECK:     %uint_7 = OpConstant %uint 7
+;CHECK:     %uint_9 = OpConstant %uint 9
+;CHECK:    %uint_10 = OpConstant %uint 10
+;CHECK:    %uint_45 = OpConstant %uint 45
+%main = OpFunction %void None %3
+          %5 = OpLabel
+;CHECK:         %55 = OpFunctionCall %uint %36 %uint_1 %uint_0 %uint_0
+         %20 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %int_2 %uint_1
+         %21 = OpLoad %float %20
+;CHECK-NOT:     %21 = OpLoad %float %20
+;CHECK:         %29 = OpIMul %uint %uint_8 %int_2
+;CHECK:         %30 = OpIAdd %uint %uint_0 %29
+;CHECK:         %32 = OpIMul %uint %uint_4 %uint_1
+;CHECK:         %33 = OpIAdd %uint %30 %32
+;CHECK:         %35 = OpIAdd %uint %33 %uint_3
+;CHECK:         %57 = OpULessThan %bool %35 %55
+;CHECK:               OpSelectionMerge %58 None
+;CHECK:               OpBranchConditional %57 %59 %60
+;CHECK:         %59 = OpLabel
+;CHECK:         %61 = OpLoad %float %20
+;CHECK:               OpBranch %58
+;CHECK:         %60 = OpLabel
+;CHECK:        %113 = OpFunctionCall %void %62 %uint_45 %uint_3 %uint_0 %35 %55
+;CHECK:               OpBranch %58
+;CHECK:         %58 = OpLabel
+;CHECK:        %115 = OpPhi %float %61 %59 %114 %60
+               OpStore %v_vtxResult %21
+;CHECK-NOT:           OpStore %v_vtxResult %21
+;CHECK:               OpStore %v_vtxResult %115
+               OpReturn
+               OpFunctionEnd
+;CHECK:         %36 = OpFunction %uint None %37
+;CHECK:         %38 = OpFunctionParameter %uint
+;CHECK:         %39 = OpFunctionParameter %uint
+;CHECK:         %40 = OpFunctionParameter %uint
+;CHECK:         %41 = OpLabel
+;CHECK:         %47 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_0 %38
+;CHECK:         %48 = OpLoad %uint %47
+;CHECK:         %49 = OpIAdd %uint %48 %39
+;CHECK:         %50 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_0 %49
+;CHECK:         %51 = OpLoad %uint %50
+;CHECK:         %52 = OpIAdd %uint %51 %40
+;CHECK:         %53 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_0 %52
+;CHECK:         %54 = OpLoad %uint %53
+;CHECK:               OpReturnValue %54
+;CHECK:               OpFunctionEnd
+;CHECK:         %62 = OpFunction %void None %63
+;CHECK:         %64 = OpFunctionParameter %uint
+;CHECK:         %65 = OpFunctionParameter %uint
+;CHECK:         %66 = OpFunctionParameter %uint
+;CHECK:         %67 = OpFunctionParameter %uint
+;CHECK:         %68 = OpFunctionParameter %uint
+;CHECK:         %69 = OpLabel
+;CHECK:         %73 = OpAccessChain %_ptr_StorageBuffer_uint %72 %uint_0
+;CHECK:         %75 = OpAtomicIAdd %uint %73 %uint_4 %uint_0 %uint_11
+;CHECK:         %76 = OpIAdd %uint %75 %uint_11
+;CHECK:         %77 = OpArrayLength %uint %72 1
+;CHECK:         %78 = OpULessThanEqual %bool %76 %77
+;CHECK:               OpSelectionMerge %79 None
+;CHECK:               OpBranchConditional %78 %80 %79
+;CHECK:         %80 = OpLabel
+;CHECK:         %81 = OpIAdd %uint %75 %uint_0
+;CHECK:         %82 = OpAccessChain %_ptr_StorageBuffer_uint %72 %uint_1 %81
+;CHECK:               OpStore %82 %uint_11
+;CHECK:         %84 = OpIAdd %uint %75 %uint_1
+;CHECK:         %85 = OpAccessChain %_ptr_StorageBuffer_uint %72 %uint_1 %84
+;CHECK:               OpStore %85 %uint_23
+;CHECK:         %87 = OpIAdd %uint %75 %uint_2
+;CHECK:         %88 = OpAccessChain %_ptr_StorageBuffer_uint %72 %uint_1 %87
+;CHECK:               OpStore %88 %64
+;CHECK:         %89 = OpIAdd %uint %75 %uint_3
+;CHECK:         %90 = OpAccessChain %_ptr_StorageBuffer_uint %72 %uint_1 %89
+;CHECK:               OpStore %90 %uint_0
+;CHECK:         %93 = OpLoad %uint %gl_VertexIndex
+;CHECK:         %94 = OpIAdd %uint %75 %uint_4
+;CHECK:         %95 = OpAccessChain %_ptr_StorageBuffer_uint %72 %uint_1 %94
+;CHECK:               OpStore %95 %93
+;CHECK:         %97 = OpLoad %uint %gl_InstanceIndex
+;CHECK:         %99 = OpIAdd %uint %75 %uint_5
+;CHECK:        %100 = OpAccessChain %_ptr_StorageBuffer_uint %72 %uint_1 %99
+;CHECK:               OpStore %100 %97
+;CHECK:        %102 = OpIAdd %uint %75 %uint_7
+;CHECK:        %103 = OpAccessChain %_ptr_StorageBuffer_uint %72 %uint_1 %102
+;CHECK:               OpStore %103 %65
+;CHECK:        %104 = OpIAdd %uint %75 %uint_8
+;CHECK:        %105 = OpAccessChain %_ptr_StorageBuffer_uint %72 %uint_1 %104
+;CHECK:               OpStore %105 %66
+;CHECK:        %107 = OpIAdd %uint %75 %uint_9
+;CHECK:        %108 = OpAccessChain %_ptr_StorageBuffer_uint %72 %uint_1 %107
+;CHECK:               OpStore %108 %67
+;CHECK:        %110 = OpIAdd %uint %75 %uint_10
+;CHECK:        %111 = OpAccessChain %_ptr_StorageBuffer_uint %72 %uint_1 %110
+;CHECK:               OpStore %111 %68
+;CHECK:               OpBranch %79
+;CHECK:         %79 = OpLabel
+;CHECK:               OpReturn
+;CHECK:               OpFunctionEnd
+ )";
+
+  SetTargetEnv(SPV_ENV_VULKAN_1_2);
+  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 7u, 23u, false,
+                                               false, true);
+}
+
+TEST_F(InstBindlessTest, UniformMatrixVecRefRowMajor) {
+  // The buffer-oob row major matrix vector ref check
+  //
+  // #version 450
+  // #extension GL_EXT_scalar_block_layout : enable
+  //
+  // layout(location = 0) in highp vec4 a_position;
+  // layout(location = 0) out highp vec2 v_vtxResult;
+  //
+  // layout(set = 0, binding = 0, std430, row_major) uniform Block
+  // {
+  //    lowp mat2 var[3][4];
+  // };
+  //
+  // void main (void)
+  // {
+  //    v_vtxResult = var[2][3][1];
+  // }
+
+  const std::string text = R"(
+               OpCapability Shader
+;CHECK:               OpExtension "SPV_KHR_storage_buffer_storage_class"
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Vertex %main "main" %v_vtxResult %_ %a_position
+;CHECK:               OpEntryPoint Vertex %main "main" %v_vtxResult %_ %a_position %54 %81 %gl_VertexIndex %gl_InstanceIndex
+               OpSource GLSL 450
+               OpSourceExtension "GL_EXT_scalar_block_layout"
+               OpName %main "main"
+               OpName %v_vtxResult "v_vtxResult"
+               OpName %Block "Block"
+               OpMemberName %Block 0 "var"
+               OpName %_ ""
+               OpName %a_position "a_position"
+               OpDecorate %v_vtxResult Location 0
+               OpDecorate %_arr_mat2v2float_uint_4 ArrayStride 32
+               OpDecorate %_arr__arr_mat2v2float_uint_4_uint_3 ArrayStride 128
+               OpMemberDecorate %Block 0 RowMajor
+               OpMemberDecorate %Block 0 RelaxedPrecision
+               OpMemberDecorate %Block 0 Offset 0
+               OpMemberDecorate %Block 0 MatrixStride 16
+               OpDecorate %Block Block
+               OpDecorate %_ DescriptorSet 0
+               OpDecorate %_ Binding 0
+               OpDecorate %26 RelaxedPrecision
+;CHECK-NOT:               OpDecorate %26 RelaxedPrecision
+;CHECK:               OpDecorate %125 RelaxedPrecision
+               OpDecorate %a_position Location 0
+;CHECK:               OpDecorate %_runtimearr_uint ArrayStride 4
+;CHECK:               OpDecorate %_struct_52 Block
+;CHECK:               OpMemberDecorate %_struct_52 0 Offset 0
+;CHECK:               OpDecorate %54 DescriptorSet 7
+;CHECK:               OpDecorate %54 Binding 1
+;CHECK:               OpDecorate %70 RelaxedPrecision
+;CHECK:               OpDecorate %_struct_79 Block
+;CHECK:               OpMemberDecorate %_struct_79 0 Offset 0
+;CHECK:               OpMemberDecorate %_struct_79 1 Offset 4
+;CHECK:               OpDecorate %81 DescriptorSet 7
+;CHECK:               OpDecorate %81 Binding 0
+;CHECK:               OpDecorate %gl_VertexIndex BuiltIn VertexIndex
+;CHECK:               OpDecorate %gl_InstanceIndex BuiltIn InstanceIndex
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+    %v2float = OpTypeVector %float 2
+%_ptr_Output_v2float = OpTypePointer Output %v2float
+%v_vtxResult = OpVariable %_ptr_Output_v2float Output
+%mat2v2float = OpTypeMatrix %v2float 2
+       %uint = OpTypeInt 32 0
+     %uint_4 = OpConstant %uint 4
+%_arr_mat2v2float_uint_4 = OpTypeArray %mat2v2float %uint_4
+     %uint_3 = OpConstant %uint 3
+%_arr__arr_mat2v2float_uint_4_uint_3 = OpTypeArray %_arr_mat2v2float_uint_4 %uint_3
+      %Block = OpTypeStruct %_arr__arr_mat2v2float_uint_4_uint_3
+%_ptr_Uniform_Block = OpTypePointer Uniform %Block
+          %_ = OpVariable %_ptr_Uniform_Block Uniform
+        %int = OpTypeInt 32 1
+      %int_0 = OpConstant %int 0
+      %int_2 = OpConstant %int 2
+      %int_3 = OpConstant %int 3
+      %int_1 = OpConstant %int 1
+%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
+    %v4float = OpTypeVector %float 4
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+ %a_position = OpVariable %_ptr_Input_v4float Input
+;CHECK:     %uint_0 = OpConstant %uint 0
+;CHECK:   %uint_128 = OpConstant %uint 128
+;CHECK:    %uint_32 = OpConstant %uint 32
+;CHECK:    %uint_16 = OpConstant %uint 16
+;CHECK:    %uint_19 = OpConstant %uint 19
+;CHECK:     %uint_1 = OpConstant %uint 1
+;CHECK:         %46 = OpTypeFunction %uint %uint %uint %uint
+;CHECK:%_runtimearr_uint = OpTypeRuntimeArray %uint
+;CHECK: %_struct_52 = OpTypeStruct %_runtimearr_uint
+;CHECK:%_ptr_StorageBuffer__struct_52 = OpTypePointer StorageBuffer %_struct_52
+;CHECK:         %54 = OpVariable %_ptr_StorageBuffer__struct_52 StorageBuffer
+;CHECK:%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
+;CHECK:       %bool = OpTypeBool
+;CHECK:         %72 = OpTypeFunction %void %uint %uint %uint %uint %uint
+;CHECK: %_struct_79 = OpTypeStruct %uint %_runtimearr_uint
+;CHECK:%_ptr_StorageBuffer__struct_79 = OpTypePointer StorageBuffer %_struct_79
+;CHECK:         %81 = OpVariable %_ptr_StorageBuffer__struct_79 StorageBuffer
+;CHECK:    %uint_11 = OpConstant %uint 11
+;CHECK:    %uint_23 = OpConstant %uint 23
+;CHECK:     %uint_2 = OpConstant %uint 2
+;CHECK:%_ptr_Input_uint = OpTypePointer Input %uint
+;CHECK:%gl_VertexIndex = OpVariable %_ptr_Input_uint Input
+;CHECK:%gl_InstanceIndex = OpVariable %_ptr_Input_uint Input
+;CHECK:     %uint_5 = OpConstant %uint 5
+;CHECK:     %uint_7 = OpConstant %uint 7
+;CHECK:     %uint_8 = OpConstant %uint 8
+;CHECK:     %uint_9 = OpConstant %uint 9
+;CHECK:    %uint_10 = OpConstant %uint 10
+;CHECK:    %uint_51 = OpConstant %uint 51
+;CHECK:        %124 = OpConstantNull %v2float
+       %main = OpFunction %void None %3
+          %5 = OpLabel
+;CHECK:         %64 = OpFunctionCall %uint %45 %uint_1 %uint_0 %uint_0
+;CHECK:               OpBranch %31
+;CHECK:         %31 = OpLabel
+;CHECK:               OpBranch %30
+;CHECK:         %30 = OpLabel
+         %25 = OpAccessChain %_ptr_Uniform_v2float %_ %int_0 %int_2 %int_3 %int_1
+         %26 = OpLoad %v2float %25
+               OpStore %v_vtxResult %26
+;CHECK-NOT:         %26 = OpLoad %v2float %25
+;CHECK-NOT:               OpStore %v_vtxResult %26
+;CHECK:         %34 = OpIMul %uint %uint_128 %int_2
+;CHECK:         %35 = OpIAdd %uint %uint_0 %34
+;CHECK:         %37 = OpIMul %uint %uint_32 %int_3
+;CHECK:         %38 = OpIAdd %uint %35 %37
+;CHECK:         %40 = OpIMul %uint %uint_4 %int_1
+;CHECK:         %41 = OpIAdd %uint %38 %40
+;CHECK:         %43 = OpIAdd %uint %41 %uint_19
+;CHECK:         %66 = OpULessThan %bool %43 %64
+;CHECK:               OpSelectionMerge %67 None
+;CHECK:               OpBranchConditional %66 %68 %69
+;CHECK:         %68 = OpLabel
+;CHECK:         %70 = OpLoad %v2float %25
+;CHECK:               OpBranch %67
+;CHECK:         %69 = OpLabel
+;CHECK:        %123 = OpFunctionCall %void %71 %uint_51 %uint_3 %uint_0 %43 %64
+;CHECK:               OpBranch %67
+;CHECK:         %67 = OpLabel
+;CHECK:        %125 = OpPhi %v2float %70 %68 %124 %69
+;CHECK:               OpStore %v_vtxResult %125
+               OpReturn
+               OpFunctionEnd
+;CHECK:         %45 = OpFunction %uint None %46
+;CHECK:         %47 = OpFunctionParameter %uint
+;CHECK:         %48 = OpFunctionParameter %uint
+;CHECK:         %49 = OpFunctionParameter %uint
+;CHECK:         %50 = OpLabel
+;CHECK:         %56 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_0 %47
+;CHECK:         %57 = OpLoad %uint %56
+;CHECK:         %58 = OpIAdd %uint %57 %48
+;CHECK:         %59 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_0 %58
+;CHECK:         %60 = OpLoad %uint %59
+;CHECK:         %61 = OpIAdd %uint %60 %49
+;CHECK:         %62 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_0 %61
+;CHECK:         %63 = OpLoad %uint %62
+;CHECK:               OpReturnValue %63
+;CHECK:               OpFunctionEnd
+;CHECK:         %71 = OpFunction %void None %72
+;CHECK:         %73 = OpFunctionParameter %uint
+;CHECK:         %74 = OpFunctionParameter %uint
+;CHECK:         %75 = OpFunctionParameter %uint
+;CHECK:         %76 = OpFunctionParameter %uint
+;CHECK:         %77 = OpFunctionParameter %uint
+;CHECK:         %78 = OpLabel
+;CHECK:         %82 = OpAccessChain %_ptr_StorageBuffer_uint %81 %uint_0
+;CHECK:         %84 = OpAtomicIAdd %uint %82 %uint_4 %uint_0 %uint_11
+;CHECK:         %85 = OpIAdd %uint %84 %uint_11
+;CHECK:         %86 = OpArrayLength %uint %81 1
+;CHECK:         %87 = OpULessThanEqual %bool %85 %86
+;CHECK:               OpSelectionMerge %88 None
+;CHECK:               OpBranchConditional %87 %89 %88
+;CHECK:         %89 = OpLabel
+;CHECK:         %90 = OpIAdd %uint %84 %uint_0
+;CHECK:         %91 = OpAccessChain %_ptr_StorageBuffer_uint %81 %uint_1 %90
+;CHECK:               OpStore %91 %uint_11
+;CHECK:         %93 = OpIAdd %uint %84 %uint_1
+;CHECK:         %94 = OpAccessChain %_ptr_StorageBuffer_uint %81 %uint_1 %93
+;CHECK:               OpStore %94 %uint_23
+;CHECK:         %96 = OpIAdd %uint %84 %uint_2
+;CHECK:         %97 = OpAccessChain %_ptr_StorageBuffer_uint %81 %uint_1 %96
+;CHECK:               OpStore %97 %73
+;CHECK:         %98 = OpIAdd %uint %84 %uint_3
+;CHECK:         %99 = OpAccessChain %_ptr_StorageBuffer_uint %81 %uint_1 %98
+;CHECK:               OpStore %99 %uint_0
+;CHECK:        %102 = OpLoad %uint %gl_VertexIndex
+;CHECK:        %103 = OpIAdd %uint %84 %uint_4
+;CHECK:        %104 = OpAccessChain %_ptr_StorageBuffer_uint %81 %uint_1 %103
+;CHECK:               OpStore %104 %102
+;CHECK:        %106 = OpLoad %uint %gl_InstanceIndex
+;CHECK:        %108 = OpIAdd %uint %84 %uint_5
+;CHECK:        %109 = OpAccessChain %_ptr_StorageBuffer_uint %81 %uint_1 %108
+;CHECK:               OpStore %109 %106
+;CHECK:        %111 = OpIAdd %uint %84 %uint_7
+;CHECK:        %112 = OpAccessChain %_ptr_StorageBuffer_uint %81 %uint_1 %111
+;CHECK:               OpStore %112 %74
+;CHECK:        %114 = OpIAdd %uint %84 %uint_8
+;CHECK:        %115 = OpAccessChain %_ptr_StorageBuffer_uint %81 %uint_1 %114
+;CHECK:               OpStore %115 %75
+;CHECK:        %117 = OpIAdd %uint %84 %uint_9
+;CHECK:        %118 = OpAccessChain %_ptr_StorageBuffer_uint %81 %uint_1 %117
+;CHECK:               OpStore %118 %76
+;CHECK:        %120 = OpIAdd %uint %84 %uint_10
+;CHECK:        %121 = OpAccessChain %_ptr_StorageBuffer_uint %81 %uint_1 %120
+;CHECK:               OpStore %121 %77
+;CHECK:               OpBranch %88
+;CHECK:         %88 = OpLabel
+;CHECK:               OpReturn
+;CHECK:               OpFunctionEnd
+ )";
+
+  SetTargetEnv(SPV_ENV_VULKAN_1_2);
+  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 7u, 23u, false,
+                                               false, true);
+}
+
 // TODO(greg-lunarg): Add tests to verify handling of these cases:
 //
 //   Compute shader