Add texel buffer out-of-bounds checking instrumentation (#4038)

This instruments ImageRead, ImageWrite and ImageFetch when applied to
texel buffers.

Also add new (but not yet generated) buffer OOB error codes differentiated
for VUID classification.
diff --git a/include/spirv-tools/instrument.hpp b/include/spirv-tools/instrument.hpp
index 9c01cb6..2b47a56 100644
--- a/include/spirv-tools/instrument.hpp
+++ b/include/spirv-tools/instrument.hpp
@@ -171,6 +171,10 @@
 static const int kInstErrorBindlessUninit = 1;
 static const int kInstErrorBuffAddrUnallocRef = 2;
 static const int kInstErrorBindlessBuffOOB = 3;
+static const int kInstErrorBuffOOBUniform = 4;
+static const int kInstErrorBuffOOBStorage = 5;
+static const int kInstErrorBuffOOBUniformTexel = 6;
+static const int kInstErrorBuffOOBStorageTexel = 7;
 
 // Direct Input Buffer Offsets
 //
diff --git a/include/spirv-tools/optimizer.hpp b/include/spirv-tools/optimizer.hpp
index f12774d..27352b2 100644
--- a/include/spirv-tools/optimizer.hpp
+++ b/include/spirv-tools/optimizer.hpp
@@ -747,12 +747,16 @@
 // The instrumentation will read and write buffers in debug
 // descriptor set |desc_set|. It will write |shader_id| in each output record
 // to identify the shader module which generated the record.
-// |input_length_enable| controls instrumentation of runtime descriptor array
-// references, and |input_init_enable| controls instrumentation of descriptor
-// initialization checking, both of which require input buffer support.
+// |desc_length_enable| controls instrumentation of runtime descriptor array
+// references, |desc_init_enable| controls instrumentation of descriptor
+// initialization checking, and |buff_oob_enable| controls instrumentation
+// of storage and uniform buffer bounds checking, all of which require input
+// buffer support. |texbuff_oob_enable| controls instrumentation of texel
+// buffers, which does not require input buffer support.
 Optimizer::PassToken CreateInstBindlessCheckPass(
-    uint32_t desc_set, uint32_t shader_id, bool input_length_enable = false,
-    bool input_init_enable = false, bool input_buff_oob_enable = false);
+    uint32_t desc_set, uint32_t shader_id, bool desc_length_enable = false,
+    bool desc_init_enable = false, bool buff_oob_enable = false,
+    bool texbuff_oob_enable = false);
 
 // Create a pass to instrument physical buffer address checking
 // This pass instruments all physical buffer address references to check that
diff --git a/source/opt/inst_bindless_check_pass.cpp b/source/opt/inst_bindless_check_pass.cpp
index 7eb2d1b..b94d9ff 100644
--- a/source/opt/inst_bindless_check_pass.cpp
+++ b/source/opt/inst_bindless_check_pass.cpp
@@ -23,13 +23,17 @@
 static const int kSpvSampledImageImageIdInIdx = 0;
 static const int kSpvSampledImageSamplerIdInIdx = 1;
 static const int kSpvImageSampledImageIdInIdx = 0;
+static const int kSpvCopyObjectOperandIdInIdx = 0;
 static const int kSpvLoadPtrIdInIdx = 0;
 static const int kSpvAccessChainBaseIdInIdx = 0;
 static const int kSpvAccessChainIndex0IdInIdx = 1;
 static const int kSpvTypeArrayLengthIdInIdx = 1;
 static const int kSpvConstantValueInIdx = 0;
 static const int kSpvVariableStorageClassInIdx = 0;
-
+static const int kSpvTypeImageDim = 1;
+static const int kSpvTypeImageDepth = 2;
+static const int kSpvTypeImageArrayed = 3;
+static const int kSpvTypeImageMS = 4;
 }  // anonymous namespace
 
 // Avoid unused variable warning/error on Linux
@@ -75,42 +79,51 @@
   }
 }
 
+uint32_t InstBindlessCheckPass::CloneOriginalImage(
+    uint32_t old_image_id, InstructionBuilder* builder) {
+  Instruction* new_image_inst;
+  Instruction* old_image_inst = get_def_use_mgr()->GetDef(old_image_id);
+  if (old_image_inst->opcode() == SpvOpLoad) {
+    new_image_inst = builder->AddLoad(
+        old_image_inst->type_id(),
+        old_image_inst->GetSingleWordInOperand(kSpvLoadPtrIdInIdx));
+  } else if (old_image_inst->opcode() == SpvOp::SpvOpSampledImage) {
+    uint32_t clone_id = CloneOriginalImage(
+        old_image_inst->GetSingleWordInOperand(kSpvSampledImageImageIdInIdx),
+        builder);
+    new_image_inst = builder->AddBinaryOp(
+        old_image_inst->type_id(), SpvOpSampledImage, clone_id,
+        old_image_inst->GetSingleWordInOperand(kSpvSampledImageSamplerIdInIdx));
+  } else if (old_image_inst->opcode() == SpvOp::SpvOpImage) {
+    uint32_t clone_id = CloneOriginalImage(
+        old_image_inst->GetSingleWordInOperand(kSpvImageSampledImageIdInIdx),
+        builder);
+    new_image_inst =
+        builder->AddUnaryOp(old_image_inst->type_id(), SpvOpImage, clone_id);
+  } else {
+    assert(old_image_inst->opcode() == SpvOp::SpvOpCopyObject &&
+           "expecting OpCopyObject");
+    uint32_t clone_id = CloneOriginalImage(
+        old_image_inst->GetSingleWordInOperand(kSpvCopyObjectOperandIdInIdx),
+        builder);
+    // Since we are cloning, no need to create new copy
+    new_image_inst = get_def_use_mgr()->GetDef(clone_id);
+  }
+  uid2offset_[new_image_inst->unique_id()] =
+      uid2offset_[old_image_inst->unique_id()];
+  uint32_t new_image_id = new_image_inst->result_id();
+  get_decoration_mgr()->CloneDecorations(old_image_id, new_image_id);
+  return new_image_id;
+}
+
 uint32_t InstBindlessCheckPass::CloneOriginalReference(
     ref_analysis* ref, InstructionBuilder* builder) {
   // If original is image based, start by cloning descriptor load
   uint32_t new_image_id = 0;
   if (ref->desc_load_id != 0) {
-    Instruction* desc_load_inst = get_def_use_mgr()->GetDef(ref->desc_load_id);
-    Instruction* new_load_inst = builder->AddLoad(
-        desc_load_inst->type_id(),
-        desc_load_inst->GetSingleWordInOperand(kSpvLoadPtrIdInIdx));
-    uid2offset_[new_load_inst->unique_id()] =
-        uid2offset_[desc_load_inst->unique_id()];
-    uint32_t new_load_id = new_load_inst->result_id();
-    get_decoration_mgr()->CloneDecorations(desc_load_inst->result_id(),
-                                           new_load_id);
-    new_image_id = new_load_id;
-    // Clone Image/SampledImage with new load, if needed
-    if (ref->image_id != 0) {
-      Instruction* image_inst = get_def_use_mgr()->GetDef(ref->image_id);
-      if (image_inst->opcode() == SpvOp::SpvOpSampledImage) {
-        Instruction* new_image_inst = builder->AddBinaryOp(
-            image_inst->type_id(), SpvOpSampledImage, new_load_id,
-            image_inst->GetSingleWordInOperand(kSpvSampledImageSamplerIdInIdx));
-        uid2offset_[new_image_inst->unique_id()] =
-            uid2offset_[image_inst->unique_id()];
-        new_image_id = new_image_inst->result_id();
-      } else {
-        assert(image_inst->opcode() == SpvOp::SpvOpImage &&
-               "expecting OpImage");
-        Instruction* new_image_inst =
-            builder->AddUnaryOp(image_inst->type_id(), SpvOpImage, new_load_id);
-        uid2offset_[new_image_inst->unique_id()] =
-            uid2offset_[image_inst->unique_id()];
-        new_image_id = new_image_inst->result_id();
-      }
-      get_decoration_mgr()->CloneDecorations(ref->image_id, new_image_id);
-    }
+    uint32_t old_image_id =
+        ref->ref_inst->GetSingleWordInOperand(kSpvImageSampleImageIdInIdx);
+    new_image_id = CloneOriginalImage(old_image_id, builder);
   }
   // Clone original reference
   std::unique_ptr<Instruction> new_ref_inst(ref->ref_inst->Clone(context()));
@@ -220,25 +233,28 @@
   // Reference is not load or store. If not an image-based reference, return.
   ref->image_id = GetImageId(ref_inst);
   if (ref->image_id == 0) return false;
-  Instruction* image_inst = get_def_use_mgr()->GetDef(ref->image_id);
-  Instruction* desc_load_inst = nullptr;
-  if (image_inst->opcode() == SpvOp::SpvOpSampledImage) {
-    ref->desc_load_id =
-        image_inst->GetSingleWordInOperand(kSpvSampledImageImageIdInIdx);
-    desc_load_inst = get_def_use_mgr()->GetDef(ref->desc_load_id);
-  } else if (image_inst->opcode() == SpvOp::SpvOpImage) {
-    ref->desc_load_id =
-        image_inst->GetSingleWordInOperand(kSpvImageSampledImageIdInIdx);
-    desc_load_inst = get_def_use_mgr()->GetDef(ref->desc_load_id);
-  } else {
-    ref->desc_load_id = ref->image_id;
-    desc_load_inst = image_inst;
-    ref->image_id = 0;
+  // Search for descriptor load
+  uint32_t desc_load_id = ref->image_id;
+  Instruction* desc_load_inst;
+  for (;;) {
+    desc_load_inst = get_def_use_mgr()->GetDef(desc_load_id);
+    if (desc_load_inst->opcode() == SpvOp::SpvOpSampledImage)
+      desc_load_id =
+          desc_load_inst->GetSingleWordInOperand(kSpvSampledImageImageIdInIdx);
+    else if (desc_load_inst->opcode() == SpvOp::SpvOpImage)
+      desc_load_id =
+          desc_load_inst->GetSingleWordInOperand(kSpvImageSampledImageIdInIdx);
+    else if (desc_load_inst->opcode() == SpvOp::SpvOpCopyObject)
+      desc_load_id =
+          desc_load_inst->GetSingleWordInOperand(kSpvCopyObjectOperandIdInIdx);
+    else
+      break;
   }
   if (desc_load_inst->opcode() != SpvOp::SpvOpLoad) {
     // TODO(greg-lunarg): Handle additional possibilities?
     return false;
   }
+  ref->desc_load_id = desc_load_id;
   ref->ptr_id = desc_load_inst->GetSingleWordInOperand(kSpvLoadPtrIdInIdx);
   Instruction* ptr_inst = get_def_use_mgr()->GetDef(ref->ptr_id);
   if (ptr_inst->opcode() == SpvOp::SpvOpVariable) {
@@ -508,7 +524,7 @@
     GenDebugStreamWrite(uid2offset_[ref->ref_inst->unique_id()], stage_idx,
                         {error_id, u_index_id, u_offset_id, u_length_id},
                         &builder);
-  } else if (buffer_bounds_enabled_) {
+  } else if (buffer_bounds_enabled_ || texel_buffer_enabled_) {
     // Uninitialized Descriptor - Return additional unused zero so all error
     // modes will use same debug stream write function
     uint32_t u_length_id = GenUintCastCode(length_id, &builder);
@@ -661,12 +677,77 @@
   MovePostludeCode(ref_block_itr, back_blk_ptr);
 }
 
+void InstBindlessCheckPass::GenTexBuffCheckCode(
+    BasicBlock::iterator ref_inst_itr,
+    UptrVectorIterator<BasicBlock> ref_block_itr, uint32_t stage_idx,
+    std::vector<std::unique_ptr<BasicBlock>>* new_blocks) {
+  // Only process OpImageRead and OpImageWrite with no optional operands
+  Instruction* ref_inst = &*ref_inst_itr;
+  SpvOp op = ref_inst->opcode();
+  uint32_t num_in_oprnds = ref_inst->NumInOperands();
+  if (!((op == SpvOpImageRead && num_in_oprnds == 2) ||
+        (op == SpvOpImageFetch && num_in_oprnds == 2) ||
+        (op == SpvOpImageWrite && num_in_oprnds == 3)))
+    return;
+  // Pull components from descriptor reference
+  ref_analysis ref;
+  if (!AnalyzeDescriptorReference(ref_inst, &ref)) return;
+  // Only process if image is texel buffer
+  Instruction* image_inst = get_def_use_mgr()->GetDef(ref.image_id);
+  uint32_t image_ty_id = image_inst->type_id();
+  Instruction* image_ty_inst = get_def_use_mgr()->GetDef(image_ty_id);
+  if (image_ty_inst->GetSingleWordInOperand(kSpvTypeImageDim) != SpvDimBuffer)
+    return;
+  if (image_ty_inst->GetSingleWordInOperand(kSpvTypeImageDepth) != 0) return;
+  if (image_ty_inst->GetSingleWordInOperand(kSpvTypeImageArrayed) != 0) return;
+  if (image_ty_inst->GetSingleWordInOperand(kSpvTypeImageMS) != 0) return;
+  // Enable ImageQuery Capability if not yet enabled
+  if (!get_feature_mgr()->HasCapability(SpvCapabilityImageQuery)) {
+    std::unique_ptr<Instruction> cap_image_query_inst(new Instruction(
+        context(), SpvOpCapability, 0, 0,
+        std::initializer_list<Operand>{
+            {SPV_OPERAND_TYPE_CAPABILITY, {SpvCapabilityImageQuery}}}));
+    get_def_use_mgr()->AnalyzeInstDefUse(&*cap_image_query_inst);
+    context()->AddCapability(std::move(cap_image_query_inst));
+  }
+  // Move original block's preceding instructions into first new block
+  std::unique_ptr<BasicBlock> new_blk_ptr;
+  MovePreludeCode(ref_inst_itr, ref_block_itr, &new_blk_ptr);
+  InstructionBuilder builder(
+      context(), &*new_blk_ptr,
+      IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
+  new_blocks->push_back(std::move(new_blk_ptr));
+  // Get texel coordinate
+  uint32_t coord_id =
+      GenUintCastCode(ref_inst->GetSingleWordInOperand(1), &builder);
+  // If index id not yet set, binding is single descriptor, so set index to
+  // constant 0.
+  if (ref.desc_idx_id == 0) ref.desc_idx_id = builder.GetUintConstantId(0u);
+  // Get texel buffer size.
+  Instruction* size_inst =
+      builder.AddUnaryOp(GetUintId(), SpvOpImageQuerySize, ref.image_id);
+  uint32_t size_id = size_inst->result_id();
+  // Generate runtime initialization/bounds test code with true branch
+  // being full reference and false branch being debug output and zero
+  // for the referenced value.
+  Instruction* ult_inst =
+      builder.AddBinaryOp(GetBoolId(), SpvOpULessThan, coord_id, size_id);
+  uint32_t error_id = builder.GetUintConstantId(kInstErrorBindlessBuffOOB);
+  GenCheckCode(ult_inst->result_id(), error_id, coord_id, size_id, stage_idx,
+               &ref, new_blocks);
+  // Move original block's remaining code into remainder/merge block and add
+  // to new blocks
+  BasicBlock* back_blk_ptr = &*new_blocks->back();
+  MovePostludeCode(ref_block_itr, back_blk_ptr);
+}
+
 void InstBindlessCheckPass::InitializeInstBindlessCheck() {
   // Initialize base class
   InitializeInstrument();
-  // If runtime array length support enabled, create variable mappings. Length
-  // support is always enabled if descriptor init check is enabled.
-  if (desc_idx_enabled_ || buffer_bounds_enabled_)
+  // If runtime array length support or buffer bounds checking are enabled,
+  // create variable mappings. Length support is always enabled if descriptor
+  // init check is enabled.
+  if (desc_idx_enabled_ || buffer_bounds_enabled_ || texel_buffer_enabled_)
     for (auto& anno : get_module()->annotations())
       if (anno.opcode() == SpvOpDecorate) {
         if (anno.GetSingleWordInOperand(1u) == SpvDecorationDescriptorSet)
@@ -689,8 +770,8 @@
       };
   bool modified = InstProcessEntryPointCallTree(pfn);
   if (desc_init_enabled_ || buffer_bounds_enabled_) {
-    // Perform descriptor initialization check on each entry point function in
-    // module
+    // Perform descriptor initialization and/or buffer bounds check on each
+    // entry point function in module
     pfn = [this](BasicBlock::iterator ref_inst_itr,
                  UptrVectorIterator<BasicBlock> ref_block_itr,
                  uint32_t stage_idx,
@@ -700,6 +781,18 @@
     };
     modified |= InstProcessEntryPointCallTree(pfn);
   }
+  if (texel_buffer_enabled_) {
+    // Perform texel buffer bounds check on each entry point function in
+    // module. Generate after descriptor bounds and initialization checks.
+    pfn = [this](BasicBlock::iterator ref_inst_itr,
+                 UptrVectorIterator<BasicBlock> ref_block_itr,
+                 uint32_t stage_idx,
+                 std::vector<std::unique_ptr<BasicBlock>>* new_blocks) {
+      return GenTexBuffCheckCode(ref_inst_itr, ref_block_itr, stage_idx,
+                                 new_blocks);
+    };
+    modified |= InstProcessEntryPointCallTree(pfn);
+  }
   return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange;
 }
 
diff --git a/source/opt/inst_bindless_check_pass.h b/source/opt/inst_bindless_check_pass.h
index 29da6f3..4335bad 100644
--- a/source/opt/inst_bindless_check_pass.h
+++ b/source/opt/inst_bindless_check_pass.h
@@ -28,24 +28,16 @@
 // external design may change as the layer evolves.
 class InstBindlessCheckPass : public InstrumentPass {
  public:
-  // Old interface to support testing pre-buffer-overrun capability
-  InstBindlessCheckPass(uint32_t desc_set, uint32_t shader_id,
-                        bool desc_idx_enable, bool desc_init_enable)
-      : InstrumentPass(desc_set, shader_id, kInstValidationIdBindless, false),
-        desc_idx_enabled_(desc_idx_enable),
-        desc_init_enabled_(desc_init_enable),
-        buffer_bounds_enabled_(false) {}
-
-  // New interface supporting buffer overrun checking
   InstBindlessCheckPass(uint32_t desc_set, uint32_t shader_id,
                         bool desc_idx_enable, bool desc_init_enable,
-                        bool buffer_bounds_enable)
-      : InstrumentPass(
-            desc_set, shader_id, kInstValidationIdBindless,
-            desc_idx_enable || desc_init_enable || buffer_bounds_enable),
+                        bool buffer_bounds_enable, bool texel_buffer_enable,
+                        bool opt_direct_reads)
+      : InstrumentPass(desc_set, shader_id, kInstValidationIdBindless,
+                       opt_direct_reads),
         desc_idx_enabled_(desc_idx_enable),
         desc_init_enabled_(desc_init_enable),
-        buffer_bounds_enabled_(buffer_bounds_enable) {}
+        buffer_bounds_enabled_(buffer_bounds_enable),
+        texel_buffer_enabled_(texel_buffer_enable) {}
 
   ~InstBindlessCheckPass() override = default;
 
@@ -63,6 +55,10 @@
   // checks that the referenced descriptor has been initialized, if the
   // SPV_EXT_descriptor_indexing extension is enabled, and initialized large
   // enough to handle the reference, if RobustBufferAccess is disabled.
+  // GenDescInitCheckCode checks for uniform and storage buffer overrun.
+  // GenTexBuffCheckCode checks for texel buffer overrun and should be
+  // run after GenDescInitCheckCode to first make sure that the descriptor
+  // is initialized because it uses OpImageQuerySize on the descriptor.
   //
   // The functions are designed to be passed to
   // InstrumentPass::InstProcessEntryPointCallTree(), which applies the
@@ -109,6 +105,11 @@
       UptrVectorIterator<BasicBlock> ref_block_itr, uint32_t stage_idx,
       std::vector<std::unique_ptr<BasicBlock>>* new_blocks);
 
+  void GenTexBuffCheckCode(
+      BasicBlock::iterator ref_inst_itr,
+      UptrVectorIterator<BasicBlock> ref_block_itr, uint32_t stage_idx,
+      std::vector<std::unique_ptr<BasicBlock>>* new_blocks);
+
   // Generate instructions into |builder| to read length of runtime descriptor
   // array |var_id| from debug input buffer and return id of value.
   uint32_t GenDebugReadLength(uint32_t var_id, InstructionBuilder* builder);
@@ -144,6 +145,10 @@
   // Generate index of last byte referenced by buffer reference |ref|
   uint32_t GenLastByteIdx(ref_analysis* ref, InstructionBuilder* builder);
 
+  // Clone original image computation starting at |image_id| into |builder|.
+  // This may generate more than one instruction if neccessary.
+  uint32_t CloneOriginalImage(uint32_t image_id, InstructionBuilder* builder);
+
   // Clone original original reference encapsulated by |ref| into |builder|.
   // This may generate more than one instruction if neccessary.
   uint32_t CloneOriginalReference(ref_analysis* ref,
@@ -184,9 +189,12 @@
   // Enable instrumentation of descriptor initialization checking
   bool desc_init_enabled_;
 
-  // Enable instrumentation of buffer overrun checking
+  // Enable instrumentation of uniform and storage buffer overrun checking
   bool buffer_bounds_enabled_;
 
+  // Enable instrumentation of texel buffer overrun checking
+  bool texel_buffer_enabled_;
+
   // Mapping from variable to descriptor set
   std::unordered_map<uint32_t, uint32_t> var2desc_set_;
 
diff --git a/source/opt/optimizer.cpp b/source/opt/optimizer.cpp
index 1ded2ee..8726ff9 100644
--- a/source/opt/optimizer.cpp
+++ b/source/opt/optimizer.cpp
@@ -425,7 +425,7 @@
     RegisterPass(CreateBlockMergePass());
     RegisterPass(CreateAggressiveDCEPass());
   } else if (pass_name == "inst-buff-oob-check") {
-    RegisterPass(CreateInstBindlessCheckPass(7, 23, false, false, true));
+    RegisterPass(CreateInstBindlessCheckPass(7, 23, false, false, true, true));
     RegisterPass(CreateSimplificationPass());
     RegisterPass(CreateDeadBranchElimPass());
     RegisterPass(CreateBlockMergePass());
@@ -892,15 +892,14 @@
       MakeUnique<opt::UpgradeMemoryModel>());
 }
 
-Optimizer::PassToken CreateInstBindlessCheckPass(uint32_t desc_set,
-                                                 uint32_t shader_id,
-                                                 bool input_length_enable,
-                                                 bool input_init_enable,
-                                                 bool input_buff_oob_enable) {
+Optimizer::PassToken CreateInstBindlessCheckPass(
+    uint32_t desc_set, uint32_t shader_id, bool desc_length_enable,
+    bool desc_init_enable, bool buff_oob_enable, bool texbuff_oob_enable) {
   return MakeUnique<Optimizer::PassToken::Impl>(
       MakeUnique<opt::InstBindlessCheckPass>(
-          desc_set, shader_id, input_length_enable, input_init_enable,
-          input_buff_oob_enable));
+          desc_set, shader_id, desc_length_enable, desc_init_enable,
+          buff_oob_enable, texbuff_oob_enable,
+          desc_length_enable || desc_init_enable || buff_oob_enable));
 }
 
 Optimizer::PassToken CreateInstDebugPrintfPass(uint32_t desc_set,
diff --git a/test/opt/inst_bindless_check_test.cpp b/test/opt/inst_bindless_check_test.cpp
index 691bc9a..f189962 100644
--- a/test/opt/inst_bindless_check_test.cpp
+++ b/test/opt/inst_bindless_check_test.cpp
@@ -105,8 +105,8 @@
 )";
 
   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  SinglePassRunAndCheck<InstBindlessCheckPass>(before, before, true, true, 7u,
-                                               23u, false, false);
+  SinglePassRunAndCheck<InstBindlessCheckPass>(
+      before, before, true, true, 7u, 23u, false, false, false, false, false);
 }
 
 TEST_F(InstBindlessTest, NoInstrumentNonBindless) {
@@ -183,7 +183,8 @@
 
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   SinglePassRunAndCheck<InstBindlessCheckPass>(whole_file, whole_file, true,
-                                               true, 7u, 23u, false, false);
+                                               true, 7u, 23u, false, false,
+                                               false, false, false);
 }
 
 TEST_F(InstBindlessTest, Simple) {
@@ -412,7 +413,7 @@
           func_pt2_before,
       entry_after + names_annots + new_annots + consts_types_vars +
           new_consts_types_vars + func_pt1 + func_pt2_after + output_func,
-      true, true, 7u, 23u, false, false);
+      true, true, 7u, 23u, false, false, false, false, false);
 }
 
 TEST_F(InstBindlessTest, InstrumentMultipleInstructions) {
@@ -707,7 +708,7 @@
   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   SinglePassRunAndCheck<InstBindlessCheckPass>(
       defs_before + func_before, defs_after + func_after + output_func, true,
-      true, 7u, 23u, false, false);
+      true, 7u, 23u, false, false, false, false, false);
 }
 
 TEST_F(InstBindlessTest, InstrumentOpImage) {
@@ -935,7 +936,7 @@
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   SinglePassRunAndCheck<InstBindlessCheckPass>(
       defs_before + func_before, defs_after + func_after + output_func, true,
-      true, 7u, 23u, false, false);
+      true, 7u, 23u, false, false, false, false, false);
 }
 
 TEST_F(InstBindlessTest, InstrumentSampledImage) {
@@ -1158,7 +1159,7 @@
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   SinglePassRunAndCheck<InstBindlessCheckPass>(
       defs_before + func_before, defs_after + func_after + output_func, true,
-      true, 7u, 23u, false, false);
+      true, 7u, 23u, false, false, false, false, false);
 }
 
 TEST_F(InstBindlessTest, InstrumentImageWrite) {
@@ -1383,7 +1384,7 @@
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   SinglePassRunAndCheck<InstBindlessCheckPass>(
       defs_before + func_before, defs_after + func_after + output_func, true,
-      true, 7u, 23u, false, false);
+      true, 7u, 23u, false, false, false, false, false);
 }
 
 TEST_F(InstBindlessTest, InstrumentVertexSimple) {
@@ -1657,7 +1658,7 @@
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   SinglePassRunAndCheck<InstBindlessCheckPass>(
       defs_before + func_before, defs_after + func_after + output_func, true,
-      true, 7u, 23u, false, false);
+      true, 7u, 23u, false, false, false, false, false);
 }
 
 TEST_F(InstBindlessTest, InstrumentTeseSimple) {
@@ -1933,7 +1934,7 @@
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   SinglePassRunAndCheck<InstBindlessCheckPass>(
       defs_before + func_before, defs_after + func_after + output_func, true,
-      true, 7u, 23u, false, false);
+      true, 7u, 23u, false, false, false, false, false);
 }
 
 TEST_F(InstBindlessTest, MultipleDebugFunctions) {
@@ -2261,7 +2262,7 @@
   SinglePassRunAndCheck<InstBindlessCheckPass>(
       defs_before + func1_before + func2_before,
       defs_after + func1_after + func2_after + output_func, true, true, 7u, 23u,
-      false, false);
+      false, false, false, false, false);
 }
 
 TEST_F(InstBindlessTest, RuntimeArray) {
@@ -2557,7 +2558,7 @@
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   SinglePassRunAndCheck<InstBindlessCheckPass>(
       defs_before + func_before, defs_after + func_after + new_funcs, true,
-      true, 7u, 23u, true, true);
+      true, 7u, 23u, true, true, false, false, false);
 }
 
 TEST_F(InstBindlessTest, InstrumentInitCheckOnScalarDescriptor) {
@@ -2793,7 +2794,7 @@
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   SinglePassRunAndCheck<InstBindlessCheckPass>(
       defs_before + func_before, defs_after + func_after + new_funcs, true,
-      true, 7u, 23u, true, true);
+      true, 7u, 23u, true, true, false, false, false);
 }
 
 TEST_F(InstBindlessTest, SPV14AddToEntryPoint) {
@@ -2849,7 +2850,8 @@
 )";
 
   SetTargetEnv(SPV_ENV_VULKAN_1_1_SPIRV_1_4);
-  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 7u, 23u, true, true);
+  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 7u, 23u, true, true,
+                                               false, false, false);
 }
 
 TEST_F(InstBindlessTest, SPV14AddToEntryPoints) {
@@ -2907,7 +2909,8 @@
 )";
 
   SetTargetEnv(SPV_ENV_VULKAN_1_1_SPIRV_1_4);
-  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 7u, 23u, true, true);
+  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 7u, 23u, true, true,
+                                               false, false, false);
 }
 
 TEST_F(InstBindlessTest, InstBoundsAndInitLoadUnsizedUBOArray) {
@@ -3188,7 +3191,7 @@
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   SinglePassRunAndCheck<InstBindlessCheckPass>(
       defs_before + func_before, defs_after + func_after + new_funcs, true,
-      true, 7u, 23u, true, true);
+      true, 7u, 23u, true, true, false, false, false);
 }
 
 TEST_F(InstBindlessTest, InstBoundsAndInitLoadUnsizedSSBOArrayDeprecated) {
@@ -3469,7 +3472,7 @@
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   SinglePassRunAndCheck<InstBindlessCheckPass>(
       defs_before + func_before, defs_after + func_after + new_funcs, true,
-      true, 7u, 23u, true, true);
+      true, 7u, 23u, true, true, false, false, false);
 }
 
 TEST_F(InstBindlessTest, InstBoundsAndInitLoadUnsizedSSBOArray) {
@@ -3739,7 +3742,7 @@
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   SinglePassRunAndCheck<InstBindlessCheckPass>(
       defs_before + func_before, defs_after + func_after + new_funcs, true,
-      true, 7u, 23u, true, true);
+      true, 7u, 23u, true, true, false, false, false);
 }
 
 TEST_F(InstBindlessTest, InstInitLoadUBOScalar) {
@@ -3964,7 +3967,7 @@
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   SinglePassRunAndCheck<InstBindlessCheckPass>(
       defs_before + func_before, defs_after + func_after + new_funcs, true,
-      true, 7u, 23u, true, true);
+      true, 7u, 23u, true, true, false, false, false);
 }
 
 TEST_F(InstBindlessTest, InstBoundsInitStoreUnsizedSSBOArray) {
@@ -4238,7 +4241,7 @@
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   SinglePassRunAndCheck<InstBindlessCheckPass>(
       defs_before + func_before, defs_after + func_after + new_funcs, true,
-      true, 7u, 23u, true, true);
+      true, 7u, 23u, true, true, false, false, false);
 }
 
 TEST_F(InstBindlessTest, InstBoundsInitLoadSizedUBOArray) {
@@ -4507,7 +4510,7 @@
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   SinglePassRunAndCheck<InstBindlessCheckPass>(
       defs_before + func_before, defs_after + func_after + new_funcs, true,
-      true, 7u, 23u, true, true);
+      true, 7u, 23u, true, true, false, false, false);
 }
 
 TEST_F(InstBindlessTest,
@@ -4829,7 +4832,7 @@
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   SinglePassRunAndCheck<InstBindlessCheckPass>(
       defs_before + func_before, defs_after + func_after + new_funcs, true,
-      true, 7u, 23u, true, true);
+      true, 7u, 23u, true, true, false, false, false);
 }
 
 TEST_F(InstBindlessTest,
@@ -5153,7 +5156,7 @@
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   SinglePassRunAndCheck<InstBindlessCheckPass>(
       defs_before + func_before, defs_after + func_after + new_funcs, true,
-      true, 7u, 23u, true, true);
+      true, 7u, 23u, true, true, false, false, false);
 }
 
 TEST_F(InstBindlessTest,
@@ -5477,7 +5480,7 @@
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   SinglePassRunAndCheck<InstBindlessCheckPass>(
       defs_before + func_before, defs_after + func_after + new_funcs, true,
-      true, 7u, 23u, true, true);
+      true, 7u, 23u, true, true, false, false, false);
 }
 
 TEST_F(InstBindlessTest,
@@ -5801,7 +5804,7 @@
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   SinglePassRunAndCheck<InstBindlessCheckPass>(
       defs_before + func_before, defs_after + func_after + new_funcs, true,
-      true, 7u, 23u, true, true);
+      true, 7u, 23u, true, true, false, false, false);
 }
 
 TEST_F(InstBindlessTest,
@@ -6125,7 +6128,7 @@
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   SinglePassRunAndCheck<InstBindlessCheckPass>(
       defs_before + func_before, defs_after + func_after + new_funcs, true,
-      true, 7u, 23u, true, true);
+      true, 7u, 23u, true, true, false, false, false);
 }
 
 TEST_F(InstBindlessTest,
@@ -6449,7 +6452,7 @@
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   SinglePassRunAndCheck<InstBindlessCheckPass>(
       defs_before + func_before, defs_after + func_after + new_funcs, true,
-      true, 7u, 23u, true, true);
+      true, 7u, 23u, true, true, false, false, false);
 }
 
 TEST_F(InstBindlessTest,
@@ -6773,7 +6776,7 @@
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   SinglePassRunAndCheck<InstBindlessCheckPass>(
       defs_before + func_before, defs_after + func_after + new_funcs, true,
-      true, 7u, 23u, true, true);
+      true, 7u, 23u, true, true, false, false, false);
 }
 
 TEST_F(InstBindlessTest, InstBoundsInitSameBlockOpReplication) {
@@ -7182,7 +7185,7 @@
   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   SinglePassRunAndCheck<InstBindlessCheckPass>(
       defs_before + func_before, defs_after + func_after + new_funcs, true,
-      true, 7u, 23u, true, true);
+      true, 7u, 23u, true, true, false, false, false);
 }
 
 TEST_F(InstBindlessTest, MultipleUniformNonAggregateRefsNoDescInit) {
@@ -7456,7 +7459,7 @@
   SetTargetEnv(SPV_ENV_VULKAN_1_2);
   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 7u, 23u, false,
-                                               false, true);
+                                               false, true, false, true);
 }
 
 TEST_F(InstBindlessTest, UniformArrayRefNoDescInit) {
@@ -7721,7 +7724,7 @@
   SetTargetEnv(SPV_ENV_VULKAN_1_2);
   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 7u, 23u, false,
-                                               false, true);
+                                               false, true, false, true);
 }
 
 TEST_F(InstBindlessTest, UniformArrayRefWithDescInit) {
@@ -7978,7 +7981,7 @@
   SetTargetEnv(SPV_ENV_VULKAN_1_2);
   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 7u, 23u, true, true,
-                                               true);
+                                               true, false, true);
 }
 
 TEST_F(InstBindlessTest, Descriptor16BitIdxRef) {
@@ -8201,7 +8204,7 @@
   SetTargetEnv(SPV_ENV_VULKAN_1_2);
   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 7u, 23u, true, true,
-                                               false);
+                                               false, false, true);
 }
 
 TEST_F(InstBindlessTest, UniformArray16bitIdxRef) {
@@ -8471,7 +8474,7 @@
   SetTargetEnv(SPV_ENV_VULKAN_1_2);
   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 7u, 23u, false,
-                                               false, true);
+                                               false, true, false, true);
 }
 
 TEST_F(InstBindlessTest, UniformMatrixRefRowMajor) {
@@ -8679,7 +8682,7 @@
   SetTargetEnv(SPV_ENV_VULKAN_1_2);
   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 7u, 23u, false,
-                                               false, true);
+                                               false, true, false, true);
 }
 
 TEST_F(InstBindlessTest, UniformMatrixRefColumnMajor) {
@@ -8885,7 +8888,7 @@
   SetTargetEnv(SPV_ENV_VULKAN_1_2);
   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 7u, 23u, false,
-                                               false, true);
+                                               false, true, false, true);
 }
 
 TEST_F(InstBindlessTest, UniformMatrixVecRefRowMajor) {
@@ -9107,7 +9110,860 @@
   SetTargetEnv(SPV_ENV_VULKAN_1_2);
   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 7u, 23u, false,
-                                               false, true);
+                                               false, true, false, true);
+}
+
+TEST_F(InstBindlessTest, ImageBufferOOBRead) {
+  // Texel buffer (imagebuffer) oob check for ImageRead
+  //
+  // #version 450
+  // layout(set=3, binding=7, r32f) uniform readonly imageBuffer s;
+  // layout(location=11) out vec4 x;
+  // layout(location=13) in flat int ii;
+  //
+  // void main(){
+  //    x = imageLoad(s, ii);
+  // }
+
+  const std::string text = R"(
+                          OpCapability Shader
+                          OpCapability ImageBuffer
+;CHECK:                   OpCapability ImageQuery
+;CHECK:                   OpExtension "SPV_KHR_storage_buffer_storage_class"
+                     %1 = OpExtInstImport "GLSL.std.450"
+                          OpMemoryModel Logical GLSL450
+                          OpEntryPoint Fragment %main "main" %x %s %ii
+                          OpExecutionMode %main OriginUpperLeft
+                          OpSource GLSL 450
+                          OpName %main "main"
+                          OpName %x "x"
+                          OpName %s "s"
+                          OpName %ii "ii"
+                          OpDecorate %x Location 11
+                          OpDecorate %s DescriptorSet 3
+                          OpDecorate %s Binding 7
+                          OpDecorate %s NonWritable
+                          OpDecorate %ii Flat
+                          OpDecorate %ii Location 13
+;CHECK:                   OpDecorate %_runtimearr_uint ArrayStride 4
+;CHECK:                   OpDecorate %_struct_43 Block
+;CHECK:                   OpMemberDecorate %_struct_43 0 Offset 0
+;CHECK:                   OpMemberDecorate %_struct_43 1 Offset 4
+;CHECK:                   OpDecorate %45 DescriptorSet 7
+;CHECK:                   OpDecorate %45 Binding 0
+;CHECK:                   OpDecorate %gl_FragCoord BuiltIn FragCoord
+                  %void = OpTypeVoid
+                     %3 = OpTypeFunction %void
+                 %float = OpTypeFloat 32
+               %v4float = OpTypeVector %float 4
+           %_ptr_Output_v4float = OpTypePointer Output %v4float
+                     %x = OpVariable %_ptr_Output_v4float Output
+                    %10 = OpTypeImage %float Buffer 0 0 0 2 R32f
+           %_ptr_UniformConstant_10 = OpTypePointer UniformConstant %10
+                     %s = OpVariable %_ptr_UniformConstant_10 UniformConstant
+                   %int = OpTypeInt 32 1
+           %_ptr_Input_int = OpTypePointer Input %int
+                    %ii = OpVariable %_ptr_Input_int Input
+;CHECK:           %uint = OpTypeInt 32 0
+;CHECK:         %uint_0 = OpConstant %uint 0
+;CHECK:           %bool = OpTypeBool
+;CHECK:         %uint_3 = OpConstant %uint 3
+;CHECK:             %35 = OpTypeFunction %void %uint %uint %uint %uint %uint
+;CHECK:    %_runtimearr_uint = OpTypeRuntimeArray %uint
+;CHECK:     %_struct_43 = OpTypeStruct %uint %_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:        %uint_11 = OpConstant %uint 11
+;CHECK:         %uint_4 = OpConstant %uint 4
+;CHECK:         %uint_1 = OpConstant %uint 1
+;CHECK:        %uint_23 = OpConstant %uint 23
+;CHECK:         %uint_2 = OpConstant %uint 2
+;CHECK:    %_ptr_Input_v4float = OpTypePointer Input %v4float
+;CHECK:    %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
+;CHECK:         %v4uint = OpTypeVector %uint 4
+;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_33 = OpConstant %uint 33
+;CHECK:             %93 = OpConstantNull %v4float
+                  %main = OpFunction %void None %3
+                     %5 = OpLabel
+;CHECK:                   OpBranch %21
+;CHECK:             %21 = OpLabel
+;CHECK:                   OpBranch %20
+;CHECK:             %20 = OpLabel
+;CHECK:                   OpBranch %19
+;CHECK:             %19 = OpLabel
+                    %13 = OpLoad %10 %s
+                    %17 = OpLoad %int %ii
+                    %18 = OpImageRead %v4float %13 %17
+                          OpStore %x %18
+;CHECK-NOT:         %18 = OpImageRead %v4float %13 %17
+;CHECK-NOT:               OpStore %x %18
+;CHECK:             %23 = OpBitcast %uint %17
+;CHECK:             %25 = OpImageQuerySize %uint %13
+;CHECK:             %27 = OpULessThan %bool %23 %25
+;CHECK:                   OpSelectionMerge %29 None
+;CHECK:                   OpBranchConditional %27 %30 %31
+;CHECK:             %30 = OpLabel
+;CHECK:             %32 = OpLoad %10 %s
+;CHECK:             %33 = OpImageRead %v4float %32 %17
+;CHECK:                   OpBranch %29
+;CHECK:             %31 = OpLabel
+;CHECK:             %92 = OpFunctionCall %void %34 %uint_33 %uint_3 %uint_0 %23 %25
+;CHECK:                   OpBranch %29
+;CHECK:             %29 = OpLabel
+;CHECK:             %94 = OpPhi %v4float %33 %30 %93 %31
+;CHECK:                   OpStore %x %94
+                          OpReturn
+                          OpFunctionEnd
+;CHECK:             %34 = OpFunction %void None %35
+;CHECK:             %36 = OpFunctionParameter %uint
+;CHECK:             %37 = OpFunctionParameter %uint
+;CHECK:             %38 = OpFunctionParameter %uint
+;CHECK:             %39 = OpFunctionParameter %uint
+;CHECK:             %40 = OpFunctionParameter %uint
+;CHECK:             %41 = OpLabel
+;CHECK:             %47 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_0
+;CHECK:             %50 = OpAtomicIAdd %uint %47 %uint_4 %uint_0 %uint_11
+;CHECK:             %51 = OpIAdd %uint %50 %uint_11
+;CHECK:             %52 = OpArrayLength %uint %45 1
+;CHECK:             %53 = OpULessThanEqual %bool %51 %52
+;CHECK:                   OpSelectionMerge %54 None
+;CHECK:                   OpBranchConditional %53 %55 %54
+;CHECK:             %55 = OpLabel
+;CHECK:             %56 = OpIAdd %uint %50 %uint_0
+;CHECK:             %58 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %56
+;CHECK:                   OpStore %58 %uint_11
+;CHECK:             %60 = OpIAdd %uint %50 %uint_1
+;CHECK:             %61 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %60
+;CHECK:                   OpStore %61 %uint_23
+;CHECK:             %63 = OpIAdd %uint %50 %uint_2
+;CHECK:             %64 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %63
+;CHECK:                   OpStore %64 %36
+;CHECK:             %65 = OpIAdd %uint %50 %uint_3
+;CHECK:             %66 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %65
+;CHECK:                   OpStore %66 %uint_4
+;CHECK:             %69 = OpLoad %v4float %gl_FragCoord
+;CHECK:             %71 = OpBitcast %v4uint %69
+;CHECK:             %72 = OpCompositeExtract %uint %71 0
+;CHECK:             %73 = OpIAdd %uint %50 %uint_4
+;CHECK:             %74 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %73
+;CHECK:                   OpStore %74 %72
+;CHECK:             %75 = OpCompositeExtract %uint %71 1
+;CHECK:             %77 = OpIAdd %uint %50 %uint_5
+;CHECK:             %78 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %77
+;CHECK:                   OpStore %78 %75
+;CHECK:             %80 = OpIAdd %uint %50 %uint_7
+;CHECK:             %81 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %80
+;CHECK:                   OpStore %81 %37
+;CHECK:             %83 = OpIAdd %uint %50 %uint_8
+;CHECK:             %84 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %83
+;CHECK:                   OpStore %84 %38
+;CHECK:             %86 = OpIAdd %uint %50 %uint_9
+;CHECK:             %87 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %86
+;CHECK:                   OpStore %87 %39
+;CHECK:             %89 = OpIAdd %uint %50 %uint_10
+;CHECK:             %90 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %89
+;CHECK:                   OpStore %90 %40
+;CHECK:                   OpBranch %54
+;CHECK:             %54 = 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, true, true);
+}
+
+TEST_F(InstBindlessTest, ImageBufferOOBWrite) {
+  // Texel buffer (imagebuffer) oob check for ImageWrite
+  //
+  // #version 450
+  // layout(set=3, binding=7, r32f) uniform readonly imageBuffer s;
+  // layout(location=11) out vec4 x;
+  // layout(location=13) in flat int ii;
+  //
+  // void main(){
+  //    imageStore(s, ii, x);
+  // }
+
+  const std::string text = R"(
+                          OpCapability Shader
+                          OpCapability ImageBuffer
+;CHECK:                   OpCapability ImageQuery
+;CHECK:                   OpExtension "SPV_KHR_storage_buffer_storage_class"
+                     %1 = OpExtInstImport "GLSL.std.450"
+                          OpMemoryModel Logical GLSL450
+                          OpEntryPoint Fragment %main "main" %s %ii %x
+;CHECK:                   OpEntryPoint Fragment %main "main" %s %ii %x %44 %gl_FragCoord
+                          OpExecutionMode %main OriginUpperLeft
+                          OpSource GLSL 450
+                          OpName %main "main"
+                          OpName %s "s"
+                          OpName %ii "ii"
+                          OpName %x "x"
+                          OpDecorate %s DescriptorSet 3
+                          OpDecorate %s Binding 7
+                          OpDecorate %s NonReadable
+                          OpDecorate %ii Flat
+                          OpDecorate %ii Location 13
+                          OpDecorate %x Location 11
+;CHECK:                   OpDecorate %_runtimearr_uint ArrayStride 4
+;CHECK:                   OpDecorate %_struct_42 Block
+;CHECK:                   OpMemberDecorate %_struct_42 0 Offset 0
+;CHECK:                   OpMemberDecorate %_struct_42 1 Offset 4
+;CHECK:                   OpDecorate %44 DescriptorSet 7
+;CHECK:                   OpDecorate %44 Binding 0
+;CHECK:                   OpDecorate %gl_FragCoord BuiltIn FragCoord
+                  %void = OpTypeVoid
+                     %3 = OpTypeFunction %void
+                 %float = OpTypeFloat 32
+                     %7 = OpTypeImage %float Buffer 0 0 0 2 R32f
+           %_ptr_UniformConstant_7 = OpTypePointer UniformConstant %7
+                     %s = OpVariable %_ptr_UniformConstant_7 UniformConstant
+                   %int = OpTypeInt 32 1
+           %_ptr_Input_int = OpTypePointer Input %int
+                    %ii = OpVariable %_ptr_Input_int Input
+               %v4float = OpTypeVector %float 4
+           %_ptr_Output_v4float = OpTypePointer Output %v4float
+                     %x = OpVariable %_ptr_Output_v4float Output
+;CHECK:           %uint = OpTypeInt 32 0
+;CHECK:         %uint_0 = OpConstant %uint 0
+;CHECK:           %bool = OpTypeBool
+;CHECK:         %uint_3 = OpConstant %uint 3
+;CHECK:             %34 = OpTypeFunction %void %uint %uint %uint %uint %uint
+;CHECK:    %_runtimearr_uint = OpTypeRuntimeArray %uint
+;CHECK:     %_struct_42 = OpTypeStruct %uint %_runtimearr_uint
+;CHECK:    %_ptr_StorageBuffer__struct_42 = OpTypePointer StorageBuffer %_struct_42
+;CHECK:             %44 = OpVariable %_ptr_StorageBuffer__struct_42 StorageBuffer
+;CHECK:    %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
+;CHECK:        %uint_11 = OpConstant %uint 11
+;CHECK:         %uint_4 = OpConstant %uint 4
+;CHECK:         %uint_1 = OpConstant %uint 1
+;CHECK:        %uint_23 = OpConstant %uint 23
+;CHECK:         %uint_2 = OpConstant %uint 2
+;CHECK:    %_ptr_Input_v4float = OpTypePointer Input %v4float
+;CHECK:    %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
+;CHECK:         %v4uint = OpTypeVector %uint 4
+;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_34 = OpConstant %uint 34
+                  %main = OpFunction %void None %3
+                     %5 = OpLabel
+;CHECK:                   OpBranch %21
+;CHECK:             %21 = OpLabel
+;CHECK:                   OpBranch %20
+;CHECK:             %20 = OpLabel
+;CHECK:                   OpBranch %19
+;CHECK:             %19 = OpLabel
+                    %10 = OpLoad %7 %s
+                    %14 = OpLoad %int %ii
+                    %18 = OpLoad %v4float %x
+                          OpImageWrite %10 %14 %18
+;CHECK-NOT:               OpImageWrite %10 %14 %18
+;CHECK:             %23 = OpBitcast %uint %14
+;CHECK:             %25 = OpImageQuerySize %uint %10
+;CHECK:             %27 = OpULessThan %bool %23 %25
+;CHECK:                   OpSelectionMerge %29 None
+;CHECK:                   OpBranchConditional %27 %30 %31
+;CHECK:             %30 = OpLabel
+;CHECK:             %32 = OpLoad %7 %s
+;CHECK:                   OpImageWrite %32 %14 %18
+;CHECK:                   OpBranch %29
+;CHECK:             %31 = OpLabel
+;CHECK:             %91 = OpFunctionCall %void %33 %uint_34 %uint_3 %uint_0 %23 %25
+;CHECK:                   OpBranch %29
+;CHECK:             %29 = OpLabel
+                          OpReturn
+                          OpFunctionEnd
+;CHECK:             %33 = OpFunction %void None %34
+;CHECK:             %35 = OpFunctionParameter %uint
+;CHECK:             %36 = OpFunctionParameter %uint
+;CHECK:             %37 = OpFunctionParameter %uint
+;CHECK:             %38 = OpFunctionParameter %uint
+;CHECK:             %39 = OpFunctionParameter %uint
+;CHECK:             %40 = OpLabel
+;CHECK:             %46 = OpAccessChain %_ptr_StorageBuffer_uint %44 %uint_0
+;CHECK:             %49 = OpAtomicIAdd %uint %46 %uint_4 %uint_0 %uint_11
+;CHECK:             %50 = OpIAdd %uint %49 %uint_11
+;CHECK:             %51 = OpArrayLength %uint %44 1
+;CHECK:             %52 = OpULessThanEqual %bool %50 %51
+;CHECK:                   OpSelectionMerge %53 None
+;CHECK:                   OpBranchConditional %52 %54 %53
+;CHECK:             %54 = OpLabel
+;CHECK:             %55 = OpIAdd %uint %49 %uint_0
+;CHECK:             %57 = OpAccessChain %_ptr_StorageBuffer_uint %44 %uint_1 %55
+;CHECK:                   OpStore %57 %uint_11
+;CHECK:             %59 = OpIAdd %uint %49 %uint_1
+;CHECK:             %60 = OpAccessChain %_ptr_StorageBuffer_uint %44 %uint_1 %59
+;CHECK:                   OpStore %60 %uint_23
+;CHECK:             %62 = OpIAdd %uint %49 %uint_2
+;CHECK:             %63 = OpAccessChain %_ptr_StorageBuffer_uint %44 %uint_1 %62
+;CHECK:                   OpStore %63 %35
+;CHECK:             %64 = OpIAdd %uint %49 %uint_3
+;CHECK:             %65 = OpAccessChain %_ptr_StorageBuffer_uint %44 %uint_1 %64
+;CHECK:                   OpStore %65 %uint_4
+;CHECK:             %68 = OpLoad %v4float %gl_FragCoord
+;CHECK:             %70 = OpBitcast %v4uint %68
+;CHECK:             %71 = OpCompositeExtract %uint %70 0
+;CHECK:             %72 = OpIAdd %uint %49 %uint_4
+;CHECK:             %73 = OpAccessChain %_ptr_StorageBuffer_uint %44 %uint_1 %72
+;CHECK:                   OpStore %73 %71
+;CHECK:             %74 = OpCompositeExtract %uint %70 1
+;CHECK:             %76 = OpIAdd %uint %49 %uint_5
+;CHECK:             %77 = OpAccessChain %_ptr_StorageBuffer_uint %44 %uint_1 %76
+;CHECK:                   OpStore %77 %74
+;CHECK:             %79 = OpIAdd %uint %49 %uint_7
+;CHECK:             %80 = OpAccessChain %_ptr_StorageBuffer_uint %44 %uint_1 %79
+;CHECK:                   OpStore %80 %36
+;CHECK:             %82 = OpIAdd %uint %49 %uint_8
+;CHECK:             %83 = OpAccessChain %_ptr_StorageBuffer_uint %44 %uint_1 %82
+;CHECK:                   OpStore %83 %37
+;CHECK:             %85 = OpIAdd %uint %49 %uint_9
+;CHECK:             %86 = OpAccessChain %_ptr_StorageBuffer_uint %44 %uint_1 %85
+;CHECK:                   OpStore %86 %38
+;CHECK:             %88 = OpIAdd %uint %49 %uint_10
+;CHECK:             %89 = OpAccessChain %_ptr_StorageBuffer_uint %44 %uint_1 %88
+;CHECK:                   OpStore %89 %39
+;CHECK:                   OpBranch %53
+;CHECK:             %53 = 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, true, true);
+}
+
+TEST_F(InstBindlessTest, TextureBufferOOBFetch) {
+  // Texel buffer (texturebuffer) oob check for ImageFetch
+  //
+  // #version 450
+  // layout(set=3, binding=7) uniform textureBuffer s;
+  // layout(location=11) out vec4 x;
+  // layout(location=13) in flat int ii;
+  //
+  // void main(){
+  //    x = texelFetch(s, ii);
+  // }
+
+  const std::string text = R"(
+                          OpCapability Shader
+                          OpCapability SampledBuffer
+;CHECK:                   OpCapability ImageQuery
+;CHECK:                   OpExtension "SPV_KHR_storage_buffer_storage_class"
+                     %1 = OpExtInstImport "GLSL.std.450"
+                          OpMemoryModel Logical GLSL450
+                          OpEntryPoint Fragment %main "main" %x %s %ii
+;CHECK:                   OpEntryPoint Fragment %main "main" %x %s %ii %45 %gl_FragCoord
+                          OpExecutionMode %main OriginUpperLeft
+                          OpSource GLSL 450
+                          OpName %main "main"
+                          OpName %x "x"
+                          OpName %s "s"
+                          OpName %ii "ii"
+                          OpDecorate %x Location 11
+                          OpDecorate %s DescriptorSet 3
+                          OpDecorate %s Binding 7
+                          OpDecorate %ii Flat
+                          OpDecorate %ii Location 13
+;CHECK:                   OpDecorate %_runtimearr_uint ArrayStride 4
+;CHECK:                   OpDecorate %_struct_43 Block
+;CHECK:                   OpMemberDecorate %_struct_43 0 Offset 0
+;CHECK:                   OpMemberDecorate %_struct_43 1 Offset 4
+;CHECK:                   OpDecorate %45 DescriptorSet 7
+;CHECK:                   OpDecorate %45 Binding 0
+;CHECK:                   OpDecorate %gl_FragCoord BuiltIn FragCoord
+                  %void = OpTypeVoid
+                     %3 = OpTypeFunction %void
+                 %float = OpTypeFloat 32
+               %v4float = OpTypeVector %float 4
+           %_ptr_Output_v4float = OpTypePointer Output %v4float
+                     %x = OpVariable %_ptr_Output_v4float Output
+                    %10 = OpTypeImage %float Buffer 0 0 0 1 Unknown
+           %_ptr_UniformConstant_10 = OpTypePointer UniformConstant %10
+                     %s = OpVariable %_ptr_UniformConstant_10 UniformConstant
+                   %int = OpTypeInt 32 1
+           %_ptr_Input_int = OpTypePointer Input %int
+                    %ii = OpVariable %_ptr_Input_int Input
+;CHECK:           %uint = OpTypeInt 32 0
+;CHECK:         %uint_0 = OpConstant %uint 0
+;CHECK:           %bool = OpTypeBool
+;CHECK:         %uint_3 = OpConstant %uint 3
+;CHECK:             %35 = OpTypeFunction %void %uint %uint %uint %uint %uint
+;CHECK:    %_runtimearr_uint = OpTypeRuntimeArray %uint
+;CHECK:     %_struct_43 = OpTypeStruct %uint %_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:        %uint_11 = OpConstant %uint 11
+;CHECK:         %uint_4 = OpConstant %uint 4
+;CHECK:         %uint_1 = OpConstant %uint 1
+;CHECK:        %uint_23 = OpConstant %uint 23
+;CHECK:         %uint_2 = OpConstant %uint 2
+;CHECK:    %_ptr_Input_v4float = OpTypePointer Input %v4float
+;CHECK:    %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
+;CHECK:         %v4uint = OpTypeVector %uint 4
+;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_32 = OpConstant %uint 32
+;CHECK:             %93 = OpConstantNull %v4float
+                  %main = OpFunction %void None %3
+                     %5 = OpLabel
+;CHECK:                   OpBranch %21
+;CHECK:             %21 = OpLabel
+;CHECK:                   OpBranch %20
+;CHECK:             %20 = OpLabel
+;CHECK:                   OpBranch %19
+;CHECK:             %19 = OpLabel
+                    %13 = OpLoad %10 %s
+                    %17 = OpLoad %int %ii
+                    %18 = OpImageFetch %v4float %13 %17
+                          OpStore %x %18
+;CHECK-NOT:         %18 = OpImageFetch %v4float %13 %17
+;CHECK-NOT:               OpStore %x %18
+;CHECK:             %23 = OpBitcast %uint %17
+;CHECK:             %25 = OpImageQuerySize %uint %13
+;CHECK:             %27 = OpULessThan %bool %23 %25
+;CHECK:                   OpSelectionMerge %29 None
+;CHECK:                   OpBranchConditional %27 %30 %31
+;CHECK:             %30 = OpLabel
+;CHECK:             %32 = OpLoad %10 %s
+;CHECK:             %33 = OpImageFetch %v4float %32 %17
+;CHECK:                   OpBranch %29
+;CHECK:             %31 = OpLabel
+;CHECK:             %92 = OpFunctionCall %void %34 %uint_32 %uint_3 %uint_0 %23 %25
+;CHECK:                   OpBranch %29
+;CHECK:             %29 = OpLabel
+;CHECK:             %94 = OpPhi %v4float %33 %30 %93 %31
+;CHECK:                   OpStore %x %94
+                          OpReturn
+                          OpFunctionEnd
+;CHECK:             %34 = OpFunction %void None %35
+;CHECK:             %36 = OpFunctionParameter %uint
+;CHECK:             %37 = OpFunctionParameter %uint
+;CHECK:             %38 = OpFunctionParameter %uint
+;CHECK:             %39 = OpFunctionParameter %uint
+;CHECK:             %40 = OpFunctionParameter %uint
+;CHECK:             %41 = OpLabel
+;CHECK:             %47 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_0
+;CHECK:             %50 = OpAtomicIAdd %uint %47 %uint_4 %uint_0 %uint_11
+;CHECK:             %51 = OpIAdd %uint %50 %uint_11
+;CHECK:             %52 = OpArrayLength %uint %45 1
+;CHECK:             %53 = OpULessThanEqual %bool %51 %52
+;CHECK:                   OpSelectionMerge %54 None
+;CHECK:                   OpBranchConditional %53 %55 %54
+;CHECK:             %55 = OpLabel
+;CHECK:             %56 = OpIAdd %uint %50 %uint_0
+;CHECK:             %58 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %56
+;CHECK:                   OpStore %58 %uint_11
+;CHECK:             %60 = OpIAdd %uint %50 %uint_1
+;CHECK:             %61 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %60
+;CHECK:                   OpStore %61 %uint_23
+;CHECK:             %63 = OpIAdd %uint %50 %uint_2
+;CHECK:             %64 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %63
+;CHECK:                   OpStore %64 %36
+;CHECK:             %65 = OpIAdd %uint %50 %uint_3
+;CHECK:             %66 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %65
+;CHECK:                   OpStore %66 %uint_4
+;CHECK:             %69 = OpLoad %v4float %gl_FragCoord
+;CHECK:             %71 = OpBitcast %v4uint %69
+;CHECK:             %72 = OpCompositeExtract %uint %71 0
+;CHECK:             %73 = OpIAdd %uint %50 %uint_4
+;CHECK:             %74 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %73
+;CHECK:                   OpStore %74 %72
+;CHECK:             %75 = OpCompositeExtract %uint %71 1
+;CHECK:             %77 = OpIAdd %uint %50 %uint_5
+;CHECK:             %78 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %77
+;CHECK:                   OpStore %78 %75
+;CHECK:             %80 = OpIAdd %uint %50 %uint_7
+;CHECK:             %81 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %80
+;CHECK:                   OpStore %81 %37
+;CHECK:             %83 = OpIAdd %uint %50 %uint_8
+;CHECK:             %84 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %83
+;CHECK:                   OpStore %84 %38
+;CHECK:             %86 = OpIAdd %uint %50 %uint_9
+;CHECK:             %87 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %86
+;CHECK:                   OpStore %87 %39
+;CHECK:             %89 = OpIAdd %uint %50 %uint_10
+;CHECK:             %90 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %89
+;CHECK:                   OpStore %90 %40
+;CHECK:                   OpBranch %54
+;CHECK:             %54 = 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, true, true);
+}
+
+TEST_F(InstBindlessTest, SamplerBufferOOBFetch) {
+  // Texel buffer (samplerbuffer) oob check for ImageFetch
+  //
+  // #version 450
+  // layout(set=3, binding=7) uniform samplerBuffer s;
+  // layout(location=11) out vec4 x;
+  // layout(location=13) in flat int ii;
+  //
+  // void main(){
+  //    x = texelFetch(s, ii);
+  // }
+
+  const std::string text = R"(
+                          OpCapability Shader
+                          OpCapability SampledBuffer
+;CHECK:                   OpCapability ImageQuery
+;CHECK:                   OpExtension "SPV_KHR_storage_buffer_storage_class"
+                     %1 = OpExtInstImport "GLSL.std.450"
+                          OpMemoryModel Logical GLSL450
+                          OpEntryPoint Fragment %main "main" %x %s %ii
+;CHECK:                   OpEntryPoint Fragment %main "main" %x %s %ii %48 %gl_FragCoord
+                          OpExecutionMode %main OriginUpperLeft
+                          OpSource GLSL 450
+                          OpName %main "main"
+                          OpName %x "x"
+                          OpName %s "s"
+                          OpName %ii "ii"
+                          OpDecorate %x Location 11
+                          OpDecorate %s DescriptorSet 3
+                          OpDecorate %s Binding 7
+                          OpDecorate %ii Flat
+                          OpDecorate %ii Location 13
+;CHECK:                   OpDecorate %_runtimearr_uint ArrayStride 4
+;CHECK:                   OpDecorate %_struct_46 Block
+;CHECK:                   OpMemberDecorate %_struct_46 0 Offset 0
+;CHECK:                   OpMemberDecorate %_struct_46 1 Offset 4
+;CHECK:                   OpDecorate %48 DescriptorSet 7
+;CHECK:                   OpDecorate %48 Binding 0
+;CHECK:                   OpDecorate %gl_FragCoord BuiltIn FragCoord
+                  %void = OpTypeVoid
+                     %3 = OpTypeFunction %void
+                 %float = OpTypeFloat 32
+               %v4float = OpTypeVector %float 4
+           %_ptr_Output_v4float = OpTypePointer Output %v4float
+                     %x = OpVariable %_ptr_Output_v4float Output
+                    %10 = OpTypeImage %float Buffer 0 0 0 1 Unknown
+                    %11 = OpTypeSampledImage %10
+           %_ptr_UniformConstant_11 = OpTypePointer UniformConstant %11
+                     %s = OpVariable %_ptr_UniformConstant_11 UniformConstant
+                   %int = OpTypeInt 32 1
+           %_ptr_Input_int = OpTypePointer Input %int
+                    %ii = OpVariable %_ptr_Input_int Input
+;CHECK:           %uint = OpTypeInt 32 0
+;CHECK:         %uint_0 = OpConstant %uint 0
+;CHECK:           %bool = OpTypeBool
+;CHECK:         %uint_3 = OpConstant %uint 3
+;CHECK:             %38 = OpTypeFunction %void %uint %uint %uint %uint %uint
+;CHECK:    %_runtimearr_uint = OpTypeRuntimeArray %uint
+;CHECK:     %_struct_46 = OpTypeStruct %uint %_runtimearr_uint
+;CHECK:    %_ptr_StorageBuffer__struct_46 = OpTypePointer StorageBuffer %_struct_46
+;CHECK:             %48 = OpVariable %_ptr_StorageBuffer__struct_46 StorageBuffer
+;CHECK:    %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
+;CHECK:        %uint_11 = OpConstant %uint 11
+;CHECK:         %uint_4 = OpConstant %uint 4
+;CHECK:         %uint_1 = OpConstant %uint 1
+;CHECK:        %uint_23 = OpConstant %uint 23
+;CHECK:         %uint_2 = OpConstant %uint 2
+;CHECK:    %_ptr_Input_v4float = OpTypePointer Input %v4float
+;CHECK:    %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
+;CHECK:         %v4uint = OpTypeVector %uint 4
+;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_34 = OpConstant %uint 34
+;CHECK:             %96 = OpConstantNull %v4float
+                  %main = OpFunction %void None %3
+                     %5 = OpLabel
+;CHECK:                   OpBranch %23
+;CHECK:             %23 = OpLabel
+;CHECK:                   OpBranch %22
+;CHECK:             %22 = OpLabel
+;CHECK:                   OpBranch %21
+;CHECK:             %21 = OpLabel
+                    %14 = OpLoad %11 %s
+                    %18 = OpLoad %int %ii
+                    %19 = OpImage %10 %14
+                    %20 = OpImageFetch %v4float %19 %18
+                          OpStore %x %20
+;CHECK-NOT:         %20 = OpImageFetch %v4float %19 %18
+;CHECK-NOT:               OpStore %x %20
+;CHECK:             %25 = OpBitcast %uint %18
+;CHECK:             %27 = OpImageQuerySize %uint %19
+;CHECK:             %29 = OpULessThan %bool %25 %27
+;CHECK:                   OpSelectionMerge %31 None
+;CHECK:                   OpBranchConditional %29 %32 %33
+;CHECK:             %32 = OpLabel
+;CHECK:             %34 = OpLoad %11 %s
+;CHECK:             %35 = OpImage %10 %34
+;CHECK:             %36 = OpImageFetch %v4float %35 %18
+;CHECK:                   OpBranch %31
+;CHECK:             %33 = OpLabel
+;CHECK:             %95 = OpFunctionCall %void %37 %uint_34 %uint_3 %uint_0 %25 %27
+;CHECK:                   OpBranch %31
+;CHECK:             %31 = OpLabel
+;CHECK:             %97 = OpPhi %v4float %36 %32 %96 %33
+;CHECK:                   OpStore %x %97
+                          OpReturn
+                          OpFunctionEnd
+;CHECK:             %37 = OpFunction %void None %38
+;CHECK:             %39 = OpFunctionParameter %uint
+;CHECK:             %40 = OpFunctionParameter %uint
+;CHECK:             %41 = OpFunctionParameter %uint
+;CHECK:             %42 = OpFunctionParameter %uint
+;CHECK:             %43 = OpFunctionParameter %uint
+;CHECK:             %44 = OpLabel
+;CHECK:             %50 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_0
+;CHECK:             %53 = OpAtomicIAdd %uint %50 %uint_4 %uint_0 %uint_11
+;CHECK:             %54 = OpIAdd %uint %53 %uint_11
+;CHECK:             %55 = OpArrayLength %uint %48 1
+;CHECK:             %56 = OpULessThanEqual %bool %54 %55
+;CHECK:                   OpSelectionMerge %57 None
+;CHECK:                   OpBranchConditional %56 %58 %57
+;CHECK:             %58 = OpLabel
+;CHECK:             %59 = OpIAdd %uint %53 %uint_0
+;CHECK:             %61 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %59
+;CHECK:                   OpStore %61 %uint_11
+;CHECK:             %63 = OpIAdd %uint %53 %uint_1
+;CHECK:             %64 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %63
+;CHECK:                   OpStore %64 %uint_23
+;CHECK:             %66 = OpIAdd %uint %53 %uint_2
+;CHECK:             %67 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %66
+;CHECK:                   OpStore %67 %39
+;CHECK:             %68 = OpIAdd %uint %53 %uint_3
+;CHECK:             %69 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %68
+;CHECK:                   OpStore %69 %uint_4
+;CHECK:             %72 = OpLoad %v4float %gl_FragCoord
+;CHECK:             %74 = OpBitcast %v4uint %72
+;CHECK:             %75 = OpCompositeExtract %uint %74 0
+;CHECK:             %76 = OpIAdd %uint %53 %uint_4
+;CHECK:             %77 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %76
+;CHECK:                   OpStore %77 %75
+;CHECK:             %78 = OpCompositeExtract %uint %74 1
+;CHECK:             %80 = OpIAdd %uint %53 %uint_5
+;CHECK:             %81 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %80
+;CHECK:                   OpStore %81 %78
+;CHECK:             %83 = OpIAdd %uint %53 %uint_7
+;CHECK:             %84 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %83
+;CHECK:                   OpStore %84 %40
+;CHECK:             %86 = OpIAdd %uint %53 %uint_8
+;CHECK:             %87 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %86
+;CHECK:                   OpStore %87 %41
+;CHECK:             %89 = OpIAdd %uint %53 %uint_9
+;CHECK:             %90 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %89
+;CHECK:                   OpStore %90 %42
+;CHECK:             %92 = OpIAdd %uint %53 %uint_10
+;CHECK:             %93 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %92
+;CHECK:                   OpStore %93 %43
+;CHECK:                   OpBranch %57
+;CHECK:             %57 = 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, true, true);
+}
+
+TEST_F(InstBindlessTest, SamplerBufferConstructorOOBFetch) {
+  // Texel buffer (samplerbuffer constructor) oob check for ImageFetch
+  //
+  // #version 450
+  // layout(set=3, binding=7) uniform textureBuffer tBuf;
+  // layout(set=3, binding=8) uniform sampler s;
+  // layout(location=11) out vec4 x;
+  // layout(location=13) in flat int ii;
+  //
+  // void main(){
+  //    x = texelFetch(samplerBuffer(tBuf, s), ii);
+  // }
+
+  const std::string text = R"(
+                          OpCapability Shader
+                          OpCapability SampledBuffer
+;CHECK:                   OpCapability ImageQuery
+;CHECK:                   OpExtension "SPV_KHR_storage_buffer_storage_class"
+                     %1 = OpExtInstImport "GLSL.std.450"
+                          OpMemoryModel Logical GLSL450
+                          OpEntryPoint Fragment %main "main" %x %tBuf %s %ii
+;CHECK:                   OpEntryPoint Fragment %main "main" %x %tBuf %s %ii %54 %gl_FragCoord
+                          OpExecutionMode %main OriginUpperLeft
+                          OpSource GLSL 450
+                          OpName %main "main"
+                          OpName %x "x"
+                          OpName %tBuf "tBuf"
+                          OpName %s "s"
+                          OpName %ii "ii"
+                          OpDecorate %x Location 11
+                          OpDecorate %tBuf DescriptorSet 3
+                          OpDecorate %tBuf Binding 7
+                          OpDecorate %s DescriptorSet 3
+                          OpDecorate %s Binding 8
+                          OpDecorate %ii Flat
+                          OpDecorate %ii Location 13
+;CHECK:                   OpDecorate %_runtimearr_uint ArrayStride 4
+;CHECK:                   OpDecorate %_struct_52 Block
+;CHECK:                   OpMemberDecorate %_struct_52 0 Offset 0
+;CHECK:                   OpMemberDecorate %_struct_52 1 Offset 4
+;CHECK:                   OpDecorate %54 DescriptorSet 7
+;CHECK:                   OpDecorate %54 Binding 0
+;CHECK:                   OpDecorate %gl_FragCoord BuiltIn FragCoord
+                  %void = OpTypeVoid
+                     %3 = OpTypeFunction %void
+                 %float = OpTypeFloat 32
+               %v4float = OpTypeVector %float 4
+           %_ptr_Output_v4float = OpTypePointer Output %v4float
+                     %x = OpVariable %_ptr_Output_v4float Output
+                    %10 = OpTypeImage %float Buffer 0 0 0 1 Unknown
+           %_ptr_UniformConstant_10 = OpTypePointer UniformConstant %10
+                  %tBuf = OpVariable %_ptr_UniformConstant_10 UniformConstant
+                    %14 = OpTypeSampler
+           %_ptr_UniformConstant_14 = OpTypePointer UniformConstant %14
+                     %s = OpVariable %_ptr_UniformConstant_14 UniformConstant
+                    %18 = OpTypeSampledImage %10
+                   %int = OpTypeInt 32 1
+           %_ptr_Input_int = OpTypePointer Input %int
+                    %ii = OpVariable %_ptr_Input_int Input
+;CHECK:           %uint = OpTypeInt 32 0
+;CHECK:         %uint_0 = OpConstant %uint 0
+;CHECK:           %bool = OpTypeBool
+;CHECK:         %uint_3 = OpConstant %uint 3
+;CHECK:             %44 = OpTypeFunction %void %uint %uint %uint %uint %uint
+;CHECK:    %_runtimearr_uint = OpTypeRuntimeArray %uint
+;CHECK:     %_struct_52 = OpTypeStruct %uint %_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:        %uint_11 = OpConstant %uint 11
+;CHECK:         %uint_4 = OpConstant %uint 4
+;CHECK:         %uint_1 = OpConstant %uint 1
+;CHECK:        %uint_23 = OpConstant %uint 23
+;CHECK:         %uint_2 = OpConstant %uint 2
+;CHECK:    %_ptr_Input_v4float = OpTypePointer Input %v4float
+;CHECK:    %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
+;CHECK:         %v4uint = OpTypeVector %uint 4
+;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_42 = OpConstant %uint 42
+;CHECK:            %102 = OpConstantNull %v4float
+                  %main = OpFunction %void None %3
+                     %5 = OpLabel
+;CHECK:                   OpBranch %28
+;CHECK:             %28 = OpLabel
+;CHECK:                   OpBranch %27
+;CHECK:             %27 = OpLabel
+;CHECK:                   OpBranch %26
+;CHECK:             %26 = OpLabel
+                    %13 = OpLoad %10 %tBuf
+                    %17 = OpLoad %14 %s
+                    %19 = OpSampledImage %18 %13 %17
+                    %23 = OpLoad %int %ii
+                    %24 = OpImage %10 %19
+                    %25 = OpImageFetch %v4float %24 %23
+                          OpStore %x %25
+;CHECK-NOT:         %25 = OpImageFetch %v4float %24 %23
+;CHECK-NOT:               OpStore %x %25
+;CHECK:             %30 = OpBitcast %uint %23
+;CHECK:             %32 = OpImageQuerySize %uint %24
+;CHECK:             %34 = OpULessThan %bool %30 %32
+;CHECK:                   OpSelectionMerge %36 None
+;CHECK:                   OpBranchConditional %34 %37 %38
+;CHECK:             %37 = OpLabel
+;CHECK:             %39 = OpLoad %10 %tBuf
+;CHECK:             %40 = OpSampledImage %18 %39 %17
+;CHECK:             %41 = OpImage %10 %40
+;CHECK:             %42 = OpImageFetch %v4float %41 %23
+;CHECK:                   OpBranch %36
+;CHECK:             %38 = OpLabel
+;CHECK:            %101 = OpFunctionCall %void %43 %uint_42 %uint_3 %uint_0 %30 %32
+;CHECK:                   OpBranch %36
+;CHECK:             %36 = OpLabel
+;CHECK:            %103 = OpPhi %v4float %42 %37 %102 %38
+;CHECK:                   OpStore %x %103
+                          OpReturn
+                          OpFunctionEnd
+;CHECK:             %43 = OpFunction %void None %44
+;CHECK:             %45 = OpFunctionParameter %uint
+;CHECK:             %46 = OpFunctionParameter %uint
+;CHECK:             %47 = OpFunctionParameter %uint
+;CHECK:             %48 = OpFunctionParameter %uint
+;CHECK:             %49 = OpFunctionParameter %uint
+;CHECK:             %50 = OpLabel
+;CHECK:             %56 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_0
+;CHECK:             %59 = OpAtomicIAdd %uint %56 %uint_4 %uint_0 %uint_11
+;CHECK:             %60 = OpIAdd %uint %59 %uint_11
+;CHECK:             %61 = OpArrayLength %uint %54 1
+;CHECK:             %62 = OpULessThanEqual %bool %60 %61
+;CHECK:                   OpSelectionMerge %63 None
+;CHECK:                   OpBranchConditional %62 %64 %63
+;CHECK:             %64 = OpLabel
+;CHECK:             %65 = OpIAdd %uint %59 %uint_0
+;CHECK:             %67 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %65
+;CHECK:                   OpStore %67 %uint_11
+;CHECK:             %69 = OpIAdd %uint %59 %uint_1
+;CHECK:             %70 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %69
+;CHECK:                   OpStore %70 %uint_23
+;CHECK:             %72 = OpIAdd %uint %59 %uint_2
+;CHECK:             %73 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %72
+;CHECK:                   OpStore %73 %45
+;CHECK:             %74 = OpIAdd %uint %59 %uint_3
+;CHECK:             %75 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %74
+;CHECK:                   OpStore %75 %uint_4
+;CHECK:             %78 = OpLoad %v4float %gl_FragCoord
+;CHECK:             %80 = OpBitcast %v4uint %78
+;CHECK:             %81 = OpCompositeExtract %uint %80 0
+;CHECK:             %82 = OpIAdd %uint %59 %uint_4
+;CHECK:             %83 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %82
+;CHECK:                   OpStore %83 %81
+;CHECK:             %84 = OpCompositeExtract %uint %80 1
+;CHECK:             %86 = OpIAdd %uint %59 %uint_5
+;CHECK:             %87 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %86
+;CHECK:                   OpStore %87 %84
+;CHECK:             %89 = OpIAdd %uint %59 %uint_7
+;CHECK:             %90 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %89
+;CHECK:                   OpStore %90 %46
+;CHECK:             %92 = OpIAdd %uint %59 %uint_8
+;CHECK:             %93 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %92
+;CHECK:                   OpStore %93 %47
+;CHECK:             %95 = OpIAdd %uint %59 %uint_9
+;CHECK:             %96 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %95
+;CHECK:                   OpStore %96 %48
+;CHECK:             %98 = OpIAdd %uint %59 %uint_10
+;CHECK:             %99 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %98
+;CHECK:                   OpStore %99 %49
+;CHECK:                   OpBranch %63
+;CHECK:             %63 = 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, true, true);
 }
 
 // TODO(greg-lunarg): Add tests to verify handling of these cases: