From d4c0abdcad60325a2ab3c00a81847e2dbdc927a2 Mon Sep 17 00:00:00 2001
From: Jeremy Gebben <jeremyg@lunarg.com>
Date: Wed, 26 Apr 2023 14:28:01 -0600
Subject: [PATCH] instrument: Change descriptor state storage format (#5178)

Split per-DescriptorSet state into separate memory blocks
which are accessed via an array of buffer device addresses.
This is being done to make it easier to update state for a
single DescriptorSet without rebuilding the old giant flat
buffer.

The new data format is documented as comments in
include/spirv-tools/instrument.hpp
---
 include/spirv-tools/instrument.hpp       |   47 +-
 source/opt/inst_bindless_check_pass.cpp  |  534 ++++++-
 source/opt/inst_bindless_check_pass.h    |   11 +
 source/opt/inst_buff_addr_check_pass.cpp |   18 +
 source/opt/inst_buff_addr_check_pass.h   |    3 +
 source/opt/instrument_pass.cpp           |   13 +
 source/opt/instrument_pass.h             |    5 +-
 source/opt/ir_builder.h                  |    9 +-
 test/opt/inst_bindless_check_test.cpp    | 1854 +++++++++++-----------
 9 files changed, 1527 insertions(+), 967 deletions(-)

diff --git a/include/spirv-tools/instrument.hpp b/include/spirv-tools/instrument.hpp
index a75561b508..2e029e1554 100644
--- a/include/spirv-tools/instrument.hpp
+++ b/include/spirv-tools/instrument.hpp
@@ -217,26 +217,37 @@ static const int kDebugInputBindingBuffAddr = 2;
 // This is the output buffer written by InstDebugPrintfPass.
 static const int kDebugOutputPrintfStream = 3;
 
+// clang-format off
 // Bindless Validation Input Buffer Format
 //
-// An input buffer for bindless validation consists of a single array of
-// unsigned integers we will call Data[]. This array is formatted as follows.
-//
-// At offset kDebugInputBindlessInitOffset in Data[] is a single uint which
-// gives an offset to the start of the bindless initialization data. More
-// specifically, if the following value is zero, we know that the descriptor at
-// (set = s, binding = b, index = i) is not initialized; if the value is
-// non-zero, and the descriptor points to a buffer, the value is the length of
-// the buffer in bytes and can be used to check for out-of-bounds buffer
-// references:
-// Data[ i + Data[ b + Data[ s + Data[ kDebugInputBindlessInitOffset ] ] ] ]
-static const int kDebugInputBindlessInitOffset = 0;
-
-// At offset kDebugInputBindlessOffsetLengths is some number of uints which
-// provide the bindless length data. More specifically, the number of
-// descriptors at (set=s, binding=b) is:
-// Data[ Data[ s + kDebugInputBindlessOffsetLengths ] + b ]
-static const int kDebugInputBindlessOffsetLengths = 1;
+// An input buffer for bindless validation has this structure:
+// GLSL:
+// layout(buffer_reference, std430, buffer_reference_align = 8) buffer DescriptorSetData {
+//     uint num_bindings;
+//     uint data[];
+// };
+//
+// layout(set = 7, binding = 1, std430) buffer inst_bindless_InputBuffer
+// {
+//     DescriptorSetData desc_sets[32];
+// } inst_bindless_input_buffer;
+//
+//
+// To look up the length of a binding:
+//   uint length = inst_bindless_input_buffer[set].data[binding];
+// Scalar bindings have a length of 1.
+//
+// To look up the initialization state of a descriptor in a binding:
+//   uint num_bindings = inst_bindless_input_buffer[set].num_bindings;
+//   uint binding_state_start = inst_bindless_input_buffer[set].data[num_bindings + binding];
+//   uint init_state = inst_bindless_input_buffer[set].data[binding_state_start + index];
+//
+// For scalar bindings, use 0 for the index.
+// clang-format on
+//
+// The size of the inst_bindless_input_buffer array, regardless of how many
+// descriptor sets the device supports.
+static const int kDebugInputBindlessMaxDescSets = 32;
 
 // Buffer Device Address Input Buffer Format
 //
diff --git a/source/opt/inst_bindless_check_pass.cpp b/source/opt/inst_bindless_check_pass.cpp
index cd712f068e..1ea37ab8d8 100644
--- a/source/opt/inst_bindless_check_pass.cpp
+++ b/source/opt/inst_bindless_check_pass.cpp
@@ -16,6 +16,8 @@
 
 #include "inst_bindless_check_pass.h"
 
+#include "source/spirv_constant.h"
+
 namespace spvtools {
 namespace opt {
 namespace {
@@ -40,37 +42,521 @@ constexpr int kSpvTypeImageMS = 4;
 constexpr int kSpvTypeImageSampled = 5;
 }  // namespace
 
+void InstBindlessCheckPass::SetupInputBufferIds() {
+  if (input_buffer_id_ != 0) {
+    return;
+  }
+  AddStorageBufferExt();
+  if (!get_feature_mgr()->HasExtension(kSPV_KHR_physical_storage_buffer)) {
+    context()->AddExtension("SPV_KHR_physical_storage_buffer");
+  }
+  context()->AddCapability(spv::Capability::PhysicalStorageBufferAddresses);
+  Instruction* memory_model = get_module()->GetMemoryModel();
+  // TODO should this be just Physical64?
+  memory_model->SetInOperand(
+      0u, {uint32_t(spv::AddressingModel::PhysicalStorageBuffer64)});
+
+  analysis::DecorationManager* deco_mgr = get_decoration_mgr();
+  analysis::TypeManager* type_mgr = context()->get_type_mgr();
+  constexpr uint32_t width = 32u;
+
+  // declare the DescriptorSetData struct
+  analysis::Struct* desc_set_struct =
+      GetStruct({type_mgr->GetUIntType(), GetUintRuntimeArrayType(width)});
+  desc_set_type_id_ = type_mgr->GetTypeInstruction(desc_set_struct);
+  // By the Vulkan spec, a pre-existing struct containing a RuntimeArray
+  // must be a block, and will therefore be decorated with Block. Therefore
+  // the undecorated type returned here will not be pre-existing and can
+  // safely be decorated. Since this type is now decorated, it is out of
+  // sync with the TypeManager and therefore the TypeManager must be
+  // invalidated after this pass.
+  assert(context()->get_def_use_mgr()->NumUses(desc_set_type_id_) == 0 &&
+         "used struct type returned");
+  deco_mgr->AddDecoration(desc_set_type_id_, uint32_t(spv::Decoration::Block));
+  deco_mgr->AddMemberDecoration(desc_set_type_id_, 0,
+                                uint32_t(spv::Decoration::Offset), 0);
+  deco_mgr->AddMemberDecoration(desc_set_type_id_, 1,
+                                uint32_t(spv::Decoration::Offset), 4);
+  context()->AddDebug2Inst(
+      NewGlobalName(desc_set_type_id_, "DescriptorSetData"));
+  context()->AddDebug2Inst(NewMemberName(desc_set_type_id_, 0, "num_bindings"));
+  context()->AddDebug2Inst(NewMemberName(desc_set_type_id_, 1, "data"));
+
+  // declare buffer address reference to DescriptorSetData
+  desc_set_ptr_id_ = type_mgr->FindPointerToType(
+      desc_set_type_id_, spv::StorageClass::PhysicalStorageBuffer);
+  // runtime array of buffer addresses
+  analysis::Type* rarr_ty = GetArray(type_mgr->GetType(desc_set_ptr_id_),
+                                     kDebugInputBindlessMaxDescSets);
+  deco_mgr->AddDecorationVal(type_mgr->GetId(rarr_ty),
+                             uint32_t(spv::Decoration::ArrayStride), 8u);
+
+  // declare the InputBuffer type, a struct wrapper around the runtime array
+  analysis::Struct* input_buffer_struct = GetStruct({rarr_ty});
+  input_buffer_struct_id_ = type_mgr->GetTypeInstruction(input_buffer_struct);
+  deco_mgr->AddDecoration(input_buffer_struct_id_,
+                          uint32_t(spv::Decoration::Block));
+  deco_mgr->AddMemberDecoration(input_buffer_struct_id_, 0,
+                                uint32_t(spv::Decoration::Offset), 0);
+  context()->AddDebug2Inst(
+      NewGlobalName(input_buffer_struct_id_, "InputBuffer"));
+  context()->AddDebug2Inst(
+      NewMemberName(input_buffer_struct_id_, 0, "desc_sets"));
+
+  input_buffer_ptr_id_ = type_mgr->FindPointerToType(
+      input_buffer_struct_id_, spv::StorageClass::StorageBuffer);
+
+  // declare the input_buffer global variable
+  input_buffer_id_ = TakeNextId();
+
+  const std::vector<Operand> var_operands = {
+      {spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
+       {uint32_t(spv::StorageClass::StorageBuffer)}},
+  };
+  auto new_var_op = spvtools::MakeUnique<Instruction>(
+      context(), spv::Op::OpVariable, input_buffer_ptr_id_, input_buffer_id_,
+      var_operands);
+
+  context()->AddGlobalValue(std::move(new_var_op));
+  context()->AddDebug2Inst(NewGlobalName(input_buffer_id_, "input_buffer"));
+  deco_mgr->AddDecorationVal(
+      input_buffer_id_, uint32_t(spv::Decoration::DescriptorSet), desc_set_);
+  deco_mgr->AddDecorationVal(input_buffer_id_,
+                             uint32_t(spv::Decoration::Binding),
+                             GetInputBufferBinding());
+  if (get_module()->version() >= SPV_SPIRV_VERSION_WORD(1, 4)) {
+    // Add the new buffer to all entry points.
+    for (auto& entry : get_module()->entry_points()) {
+      entry.AddOperand({SPV_OPERAND_TYPE_ID, {input_buffer_id_}});
+      context()->AnalyzeUses(&entry);
+    }
+  }
+}
+
+// clang-format off
+// GLSL:
+// uint inst_bindless_read_binding_length(uint desc_set_idx, uint binding_idx)
+// {
+//     if (desc_set_idx >= inst_bindless_input_buffer.desc_sets.length()) {
+//         return 0;
+//     }
+//
+//     DescriptorSetData set_data = inst_bindless_input_buffer.desc_sets[desc_set_idx];
+//     uvec2 ptr_as_vec = uvec2(set_data);
+//     if ((ptr_as_vec.x == 0u) && (_ptr_as_vec.y == 0u))
+//     {
+//         return 0u;
+//     }
+//     uint num_bindings = set_data.num_bindings;
+//     if (binding_idx >= num_bindings) {
+//         return 0;
+//     }
+//     return set_data.data[binding_idx];
+// }
+// clang-format on
+uint32_t InstBindlessCheckPass::GenDebugReadLengthFunctionId() {
+  if (read_length_func_id_ != 0) {
+    return read_length_func_id_;
+  }
+  SetupInputBufferIds();
+  const analysis::Integer* uint_type = GetInteger(32, false);
+  const std::vector<const analysis::Type*> param_types(2, uint_type);
+
+  const uint32_t func_id = TakeNextId();
+  std::unique_ptr<Function> func =
+      StartFunction(func_id, uint_type, param_types);
+
+  const std::vector<uint32_t> param_ids = AddParameters(*func, param_types);
+
+  // Create block
+  auto new_blk_ptr = MakeUnique<BasicBlock>(NewLabel(TakeNextId()));
+  InstructionBuilder builder(
+      context(), new_blk_ptr.get(),
+      IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
+  Instruction* inst;
+
+  inst = builder.AddBinaryOp(
+      GetBoolId(), spv::Op::OpUGreaterThanEqual, param_ids[0],
+      builder.GetUintConstantId(kDebugInputBindlessMaxDescSets));
+  const uint32_t desc_cmp_id = inst->result_id();
+
+  uint32_t error_blk_id = TakeNextId();
+  uint32_t merge_blk_id = TakeNextId();
+  std::unique_ptr<Instruction> merge_label(NewLabel(merge_blk_id));
+  std::unique_ptr<Instruction> error_label(NewLabel(error_blk_id));
+  (void)builder.AddConditionalBranch(desc_cmp_id, error_blk_id, merge_blk_id,
+                                     merge_blk_id);
+
+  func->AddBasicBlock(std::move(new_blk_ptr));
+
+  // error return
+  new_blk_ptr = MakeUnique<BasicBlock>(std::move(error_label));
+  builder.SetInsertPoint(&*new_blk_ptr);
+  (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue,
+                           builder.GetUintConstantId(0));
+  func->AddBasicBlock(std::move(new_blk_ptr));
+
+  // check descriptor set table entry is non-null
+  new_blk_ptr = MakeUnique<BasicBlock>(std::move(merge_label));
+  builder.SetInsertPoint(&*new_blk_ptr);
+
+  analysis::TypeManager* type_mgr = context()->get_type_mgr();
+  const uint32_t desc_set_ptr_ptr = type_mgr->FindPointerToType(
+      desc_set_ptr_id_, spv::StorageClass::StorageBuffer);
+
+  inst = builder.AddAccessChain(desc_set_ptr_ptr, input_buffer_id_,
+                                {builder.GetUintConstantId(0), param_ids[0]});
+  const uint32_t set_access_chain_id = inst->result_id();
+
+  inst = builder.AddLoad(desc_set_ptr_id_, set_access_chain_id);
+  const uint32_t desc_set_ptr_id = inst->result_id();
+
+  inst =
+      builder.AddUnaryOp(GetVecUintId(2), spv::Op::OpBitcast, desc_set_ptr_id);
+  const uint32_t ptr_as_uvec_id = inst->result_id();
+
+  inst = builder.AddCompositeExtract(GetUintId(), ptr_as_uvec_id, {0});
+  const uint32_t uvec_x = inst->result_id();
+
+  inst = builder.AddBinaryOp(GetBoolId(), spv::Op::OpIEqual, uvec_x,
+                             builder.GetUintConstantId(0));
+  const uint32_t x_is_zero_id = inst->result_id();
+
+  inst = builder.AddCompositeExtract(GetUintId(), ptr_as_uvec_id, {1});
+  const uint32_t uvec_y = inst->result_id();
+
+  inst = builder.AddBinaryOp(GetBoolId(), spv::Op::OpIEqual, uvec_y,
+                             builder.GetUintConstantId(0));
+  const uint32_t y_is_zero_id = inst->result_id();
+
+  inst = builder.AddBinaryOp(GetBoolId(), spv::Op::OpLogicalAnd, x_is_zero_id,
+                             y_is_zero_id);
+  const uint32_t is_null_id = inst->result_id();
+
+  error_blk_id = TakeNextId();
+  merge_blk_id = TakeNextId();
+  merge_label = NewLabel(merge_blk_id);
+  error_label = NewLabel(error_blk_id);
+  (void)builder.AddConditionalBranch(is_null_id, error_blk_id, merge_blk_id,
+                                     merge_blk_id);
+  func->AddBasicBlock(std::move(new_blk_ptr));
+  // error return
+  new_blk_ptr = MakeUnique<BasicBlock>(std::move(error_label));
+  builder.SetInsertPoint(&*new_blk_ptr);
+  (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue,
+                           builder.GetUintConstantId(0));
+  func->AddBasicBlock(std::move(new_blk_ptr));
+
+  // check binding is in range
+  new_blk_ptr = MakeUnique<BasicBlock>(std::move(merge_label));
+  builder.SetInsertPoint(&*new_blk_ptr);
+
+  const uint32_t uint_ptr = type_mgr->FindPointerToType(
+      GetUintId(), spv::StorageClass::PhysicalStorageBuffer);
+
+  inst = builder.AddAccessChain(uint_ptr, desc_set_ptr_id,
+                                {builder.GetUintConstantId(0)});
+  const uint32_t binding_access_chain_id = inst->result_id();
+
+  inst = builder.AddLoad(GetUintId(), binding_access_chain_id, 8);
+  const uint32_t num_bindings_id = inst->result_id();
+
+  inst = builder.AddBinaryOp(GetBoolId(), spv::Op::OpUGreaterThanEqual,
+                             param_ids[1], num_bindings_id);
+  const uint32_t bindings_cmp_id = inst->result_id();
+
+  error_blk_id = TakeNextId();
+  merge_blk_id = TakeNextId();
+  merge_label = NewLabel(merge_blk_id);
+  error_label = NewLabel(error_blk_id);
+  (void)builder.AddConditionalBranch(bindings_cmp_id, error_blk_id,
+                                     merge_blk_id, merge_blk_id);
+  func->AddBasicBlock(std::move(new_blk_ptr));
+  // error return
+  new_blk_ptr = MakeUnique<BasicBlock>(std::move(error_label));
+  builder.SetInsertPoint(&*new_blk_ptr);
+  (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue,
+                           builder.GetUintConstantId(0));
+  func->AddBasicBlock(std::move(new_blk_ptr));
+
+  // read binding length
+  new_blk_ptr = MakeUnique<BasicBlock>(std::move(merge_label));
+  builder.SetInsertPoint(&*new_blk_ptr);
+
+  inst = builder.AddAccessChain(uint_ptr, desc_set_ptr_id,
+                                {{builder.GetUintConstantId(1), param_ids[1]}});
+  const uint32_t length_ac_id = inst->result_id();
+
+  inst = builder.AddLoad(GetUintId(), length_ac_id, sizeof(uint32_t));
+  const uint32_t length_id = inst->result_id();
+
+  (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue, length_id);
+
+  func->AddBasicBlock(std::move(new_blk_ptr));
+  func->SetFunctionEnd(EndFunction());
+
+  context()->AddFunction(std::move(func));
+  context()->AddDebug2Inst(NewGlobalName(func_id, "read_binding_length"));
+
+  read_length_func_id_ = func_id;
+  // Make sure this function doesn't get processed by
+  // InstrumentPass::InstProcessCallTreeFromRoots()
+  param2output_func_id_[2] = func_id;
+  return read_length_func_id_;
+}
+
+// clang-format off
+// GLSL:
+// result = inst_bindless_read_binding_length(desc_set_id, binding_id);
+// clang-format on
 uint32_t InstBindlessCheckPass::GenDebugReadLength(
     uint32_t var_id, InstructionBuilder* builder) {
-  uint32_t desc_set_idx =
-      var2desc_set_[var_id] + kDebugInputBindlessOffsetLengths;
-  uint32_t desc_set_idx_id = builder->GetUintConstantId(desc_set_idx);
-  uint32_t binding_idx_id = builder->GetUintConstantId(var2binding_[var_id]);
-  return GenDebugDirectRead({desc_set_idx_id, binding_idx_id}, builder);
+  const uint32_t func_id = GenDebugReadLengthFunctionId();
+
+  const std::vector<uint32_t> args = {
+      builder->GetUintConstantId(var2desc_set_[var_id]),
+      builder->GetUintConstantId(var2binding_[var_id]),
+  };
+  return GenReadFunctionCall(func_id, args, builder);
 }
 
+// clang-format off
+// GLSL:
+// uint inst_bindless_read_desc_init(uint desc_set_idx, uint binding_idx, uint desc_idx)
+// {
+//     if (desc_set_idx >= uint(inst_bindless_input_buffer.desc_sets.length()))
+//     {
+//         return 0u;
+//     }
+//     DescriptorSetData set_data = inst_bindless_input_buffer.desc_sets[desc_set_idx];
+//     uvec2 ptr_as_vec = uvec2(set_data)
+//     if ((ptr_as_vec .x == 0u) && (ptr_as_vec.y == 0u))
+//     {
+//         return 0u;
+//     }
+//     if (binding_idx >= set_data.num_bindings)
+//     {
+//         return 0u;
+//     }
+//     if (desc_idx >= set_data.data[binding_idx])
+//     {
+//         return 0u;
+//     }
+//     uint desc_records_start = set_data.data[set_data.num_bindings + binding_idx];
+//     return set_data.data[desc_records_start + desc_idx];
+// }
+// clang-format on
+uint32_t InstBindlessCheckPass::GenDebugReadInitFunctionId() {
+  if (read_init_func_id_ != 0) {
+    return read_init_func_id_;
+  }
+  SetupInputBufferIds();
+  const analysis::Integer* uint_type = GetInteger(32, false);
+  const std::vector<const analysis::Type*> param_types(3, uint_type);
+
+  const uint32_t func_id = TakeNextId();
+  std::unique_ptr<Function> func =
+      StartFunction(func_id, uint_type, param_types);
+
+  const std::vector<uint32_t> param_ids = AddParameters(*func, param_types);
+
+  // Create block
+  auto new_blk_ptr = MakeUnique<BasicBlock>(NewLabel(TakeNextId()));
+  InstructionBuilder builder(
+      context(), new_blk_ptr.get(),
+      IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
+  Instruction* inst;
+
+  inst = builder.AddBinaryOp(
+      GetBoolId(), spv::Op::OpUGreaterThanEqual, param_ids[0],
+      builder.GetUintConstantId(kDebugInputBindlessMaxDescSets));
+  const uint32_t desc_cmp_id = inst->result_id();
+
+  uint32_t error_blk_id = TakeNextId();
+  uint32_t merge_blk_id = TakeNextId();
+  std::unique_ptr<Instruction> merge_label(NewLabel(merge_blk_id));
+  std::unique_ptr<Instruction> error_label(NewLabel(error_blk_id));
+  (void)builder.AddConditionalBranch(desc_cmp_id, error_blk_id, merge_blk_id,
+                                     merge_blk_id);
+  func->AddBasicBlock(std::move(new_blk_ptr));
+
+  // error return
+  new_blk_ptr = MakeUnique<BasicBlock>(std::move(error_label));
+  builder.SetInsertPoint(&*new_blk_ptr);
+  (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue,
+                           builder.GetUintConstantId(0));
+  func->AddBasicBlock(std::move(new_blk_ptr));
+
+  // check descriptor set table entry is non-null
+  new_blk_ptr = MakeUnique<BasicBlock>(std::move(merge_label));
+  builder.SetInsertPoint(&*new_blk_ptr);
+
+  analysis::TypeManager* type_mgr = context()->get_type_mgr();
+  const uint32_t desc_set_ptr_ptr = type_mgr->FindPointerToType(
+      desc_set_ptr_id_, spv::StorageClass::StorageBuffer);
+
+  inst = builder.AddAccessChain(desc_set_ptr_ptr, input_buffer_id_,
+                                {builder.GetUintConstantId(0), param_ids[0]});
+  const uint32_t set_access_chain_id = inst->result_id();
+
+  inst = builder.AddLoad(desc_set_ptr_id_, set_access_chain_id);
+  const uint32_t desc_set_ptr_id = inst->result_id();
+
+  inst =
+      builder.AddUnaryOp(GetVecUintId(2), spv::Op::OpBitcast, desc_set_ptr_id);
+  const uint32_t ptr_as_uvec_id = inst->result_id();
+
+  inst = builder.AddCompositeExtract(GetUintId(), ptr_as_uvec_id, {0});
+  const uint32_t uvec_x = inst->result_id();
+
+  inst = builder.AddBinaryOp(GetBoolId(), spv::Op::OpIEqual, uvec_x,
+                             builder.GetUintConstantId(0));
+  const uint32_t x_is_zero_id = inst->result_id();
+
+  inst = builder.AddCompositeExtract(GetUintId(), ptr_as_uvec_id, {1});
+  const uint32_t uvec_y = inst->result_id();
+
+  inst = builder.AddBinaryOp(GetBoolId(), spv::Op::OpIEqual, uvec_y,
+                             builder.GetUintConstantId(0));
+  const uint32_t y_is_zero_id = inst->result_id();
+
+  inst = builder.AddBinaryOp(GetBoolId(), spv::Op::OpLogicalAnd, x_is_zero_id,
+                             y_is_zero_id);
+  const uint32_t is_null_id = inst->result_id();
+
+  error_blk_id = TakeNextId();
+  merge_blk_id = TakeNextId();
+  merge_label = NewLabel(merge_blk_id);
+  error_label = NewLabel(error_blk_id);
+  (void)builder.AddConditionalBranch(is_null_id, error_blk_id, merge_blk_id,
+                                     merge_blk_id);
+  func->AddBasicBlock(std::move(new_blk_ptr));
+  // error return
+  new_blk_ptr = MakeUnique<BasicBlock>(std::move(error_label));
+  builder.SetInsertPoint(&*new_blk_ptr);
+  (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue,
+                           builder.GetUintConstantId(0));
+  func->AddBasicBlock(std::move(new_blk_ptr));
+
+  // check binding is in range
+  new_blk_ptr = MakeUnique<BasicBlock>(std::move(merge_label));
+  builder.SetInsertPoint(&*new_blk_ptr);
+
+  const uint32_t uint_ptr = type_mgr->FindPointerToType(
+      GetUintId(), spv::StorageClass::PhysicalStorageBuffer);
+
+  inst = builder.AddAccessChain(uint_ptr, desc_set_ptr_id,
+                                {builder.GetUintConstantId(0)});
+  const uint32_t binding_access_chain_id = inst->result_id();
+
+  inst = builder.AddLoad(GetUintId(), binding_access_chain_id, 8);
+  const uint32_t num_bindings_id = inst->result_id();
+
+  inst = builder.AddBinaryOp(GetBoolId(), spv::Op::OpUGreaterThanEqual,
+                             param_ids[1], num_bindings_id);
+  const uint32_t bindings_cmp_id = inst->result_id();
+
+  error_blk_id = TakeNextId();
+  merge_blk_id = TakeNextId();
+  merge_label = NewLabel(merge_blk_id);
+  error_label = NewLabel(error_blk_id);
+  (void)builder.AddConditionalBranch(bindings_cmp_id, error_blk_id,
+                                     merge_blk_id, merge_blk_id);
+  func->AddBasicBlock(std::move(new_blk_ptr));
+  // error return
+  new_blk_ptr = MakeUnique<BasicBlock>(std::move(error_label));
+  builder.SetInsertPoint(&*new_blk_ptr);
+  (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue,
+                           builder.GetUintConstantId(0));
+  func->AddBasicBlock(std::move(new_blk_ptr));
+
+  // read binding length
+  new_blk_ptr = MakeUnique<BasicBlock>(std::move(merge_label));
+  builder.SetInsertPoint(&*new_blk_ptr);
+
+  inst = builder.AddAccessChain(uint_ptr, desc_set_ptr_id,
+                                {{builder.GetUintConstantId(1), param_ids[1]}});
+  const uint32_t length_ac_id = inst->result_id();
+
+  inst = builder.AddLoad(GetUintId(), length_ac_id, sizeof(uint32_t));
+  const uint32_t length_id = inst->result_id();
+
+  // Check descriptor index in bounds
+  inst = builder.AddBinaryOp(GetBoolId(), spv::Op::OpUGreaterThanEqual,
+                             param_ids[2], length_id);
+  const uint32_t desc_idx_range_id = inst->result_id();
+
+  error_blk_id = TakeNextId();
+  merge_blk_id = TakeNextId();
+  merge_label = NewLabel(merge_blk_id);
+  error_label = NewLabel(error_blk_id);
+  (void)builder.AddConditionalBranch(desc_idx_range_id, error_blk_id,
+                                     merge_blk_id, merge_blk_id);
+  func->AddBasicBlock(std::move(new_blk_ptr));
+  // Error return
+  new_blk_ptr = MakeUnique<BasicBlock>(std::move(error_label));
+  builder.SetInsertPoint(&*new_blk_ptr);
+  (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue,
+                           builder.GetUintConstantId(0));
+  func->AddBasicBlock(std::move(new_blk_ptr));
+
+  // Read descriptor init status
+  new_blk_ptr = MakeUnique<BasicBlock>(std::move(merge_label));
+  builder.SetInsertPoint(&*new_blk_ptr);
+
+  inst = builder.AddIAdd(GetUintId(), num_bindings_id, param_ids[1]);
+  const uint32_t state_offset_id = inst->result_id();
+
+  inst =
+      builder.AddAccessChain(uint_ptr, desc_set_ptr_id,
+                             {{builder.GetUintConstantId(1), state_offset_id}});
+  const uint32_t state_start_ac_id = inst->result_id();
+
+  inst = builder.AddLoad(GetUintId(), state_start_ac_id, sizeof(uint32_t));
+  const uint32_t state_start_id = inst->result_id();
+
+  inst = builder.AddIAdd(GetUintId(), state_start_id, param_ids[2]);
+  const uint32_t state_entry_id = inst->result_id();
+
+  // Note: length starts from the beginning of the buffer, not the beginning of
+  // the data array
+  inst =
+      builder.AddAccessChain(uint_ptr, desc_set_ptr_id,
+                             {{builder.GetUintConstantId(1), state_entry_id}});
+  const uint32_t init_ac_id = inst->result_id();
+
+  inst = builder.AddLoad(GetUintId(), init_ac_id, sizeof(uint32_t));
+  const uint32_t init_status_id = inst->result_id();
+
+  (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue, init_status_id);
+
+  func->AddBasicBlock(std::move(new_blk_ptr));
+  func->SetFunctionEnd(EndFunction());
+
+  context()->AddFunction(std::move(func));
+  context()->AddDebug2Inst(NewGlobalName(func_id, "read_desc_init"));
+
+  read_init_func_id_ = func_id;
+  // Make sure function doesn't get processed by
+  // InstrumentPass::InstProcessCallTreeFromRoots()
+  param2output_func_id_[3] = func_id;
+  return read_init_func_id_;
+}
+
+// clang-format off
+// GLSL:
+// result = inst_bindless_read_desc_init(desc_set_id, binding_id, desc_idx_id);
+//
+// clang-format on
 uint32_t InstBindlessCheckPass::GenDebugReadInit(uint32_t var_id,
                                                  uint32_t desc_idx_id,
                                                  InstructionBuilder* builder) {
-  uint32_t binding_idx_id = builder->GetUintConstantId(var2binding_[var_id]);
-  uint32_t u_desc_idx_id = GenUintCastCode(desc_idx_id, builder);
-  // If desc index checking is not enabled, we know the offset of initialization
-  // entries is 1, so we can avoid loading this value and just add 1 to the
-  // descriptor set.
-  if (!desc_idx_enabled_) {
-    uint32_t desc_set_idx_id =
-        builder->GetUintConstantId(var2desc_set_[var_id] + 1);
-    return GenDebugDirectRead({desc_set_idx_id, binding_idx_id, u_desc_idx_id},
-                              builder);
-  } else {
-    uint32_t desc_set_base_id =
-        builder->GetUintConstantId(kDebugInputBindlessInitOffset);
-    uint32_t desc_set_idx_id =
-        builder->GetUintConstantId(var2desc_set_[var_id]);
-    return GenDebugDirectRead(
-        {desc_set_base_id, desc_set_idx_id, binding_idx_id, u_desc_idx_id},
-        builder);
-  }
+  const uint32_t func_id = GenDebugReadInitFunctionId();
+  const std::vector<uint32_t> args = {
+      builder->GetUintConstantId(var2desc_set_[var_id]),
+      builder->GetUintConstantId(var2binding_[var_id]),
+      GenUintCastCode(desc_idx_id, builder)};
+  return GenReadFunctionCall(func_id, args, builder);
 }
 
 uint32_t InstBindlessCheckPass::CloneOriginalImage(
diff --git a/source/opt/inst_bindless_check_pass.h b/source/opt/inst_bindless_check_pass.h
index e6e6ef4f98..37d2b29e87 100644
--- a/source/opt/inst_bindless_check_pass.h
+++ b/source/opt/inst_bindless_check_pass.h
@@ -110,10 +110,14 @@ class InstBindlessCheckPass : public InstrumentPass {
       UptrVectorIterator<BasicBlock> ref_block_itr, uint32_t stage_idx,
       std::vector<std::unique_ptr<BasicBlock>>* new_blocks);
 
+  void SetupInputBufferIds();
+  uint32_t GenDebugReadLengthFunctionId();
+
   // 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);
 
+  uint32_t GenDebugReadInitFunctionId();
   // Generate instructions into |builder| to read initialization status of
   // descriptor array |image_id| at |index_id| from debug input buffer and
   // return id of value.
@@ -201,6 +205,13 @@ class InstBindlessCheckPass : public InstrumentPass {
 
   // Mapping from variable to binding
   std::unordered_map<uint32_t, uint32_t> var2binding_;
+
+  uint32_t read_length_func_id_{0};
+  uint32_t read_init_func_id_{0};
+  uint32_t desc_set_type_id_{0};
+  uint32_t desc_set_ptr_id_{0};
+  uint32_t input_buffer_struct_id_{0};
+  uint32_t input_buffer_ptr_id_{0};
 };
 
 }  // namespace opt
diff --git a/source/opt/inst_buff_addr_check_pass.cpp b/source/opt/inst_buff_addr_check_pass.cpp
index c18f91d7fd..495470652f 100644
--- a/source/opt/inst_buff_addr_check_pass.cpp
+++ b/source/opt/inst_buff_addr_check_pass.cpp
@@ -19,6 +19,24 @@
 namespace spvtools {
 namespace opt {
 
+bool InstBuffAddrCheckPass::InstrumentFunction(Function* func,
+                                               uint32_t stage_idx,
+                                               InstProcessFunction& pfn) {
+  // The bindless instrumentation pass adds functions that use
+  // BufferDeviceAddress They should not be instrumented by this pass.
+  Instruction* func_name_inst =
+      context()->GetNames(func->DefInst().result_id()).begin()->second;
+  if (func_name_inst) {
+    static const std::string kPrefix{"inst_bindless_"};
+    std::string func_name = func_name_inst->GetOperand(1).AsString();
+    if (func_name.size() >= kPrefix.size() &&
+        func_name.compare(0, kPrefix.size(), kPrefix) == 0) {
+      return false;
+    }
+  }
+  return InstrumentPass::InstrumentFunction(func, stage_idx, pfn);
+}
+
 uint32_t InstBuffAddrCheckPass::CloneOriginalReference(
     Instruction* ref_inst, InstructionBuilder* builder) {
   // Clone original ref with new result id (if load)
diff --git a/source/opt/inst_buff_addr_check_pass.h b/source/opt/inst_buff_addr_check_pass.h
index fb43c397a5..2ec212bf87 100644
--- a/source/opt/inst_buff_addr_check_pass.h
+++ b/source/opt/inst_buff_addr_check_pass.h
@@ -41,6 +41,9 @@ class InstBuffAddrCheckPass : public InstrumentPass {
 
   const char* name() const override { return "inst-buff-addr-check-pass"; }
 
+  bool InstrumentFunction(Function* func, uint32_t stage_idx,
+                          InstProcessFunction& pfn) override;
+
  private:
   // Return byte alignment of type |type_id|. Must be int, float, vector,
   // matrix, struct, array or physical pointer. Uses std430 alignment.
diff --git a/source/opt/instrument_pass.cpp b/source/opt/instrument_pass.cpp
index c6e405051d..9233ffd7fb 100644
--- a/source/opt/instrument_pass.cpp
+++ b/source/opt/instrument_pass.cpp
@@ -564,6 +564,19 @@ analysis::RuntimeArray* InstrumentPass::GetRuntimeArray(
   return type->AsRuntimeArray();
 }
 
+analysis::Array* InstrumentPass::GetArray(const analysis::Type* element,
+                                          uint32_t length) {
+  uint32_t length_id = context()->get_constant_mgr()->GetUIntConstId(length);
+  analysis::Array::LengthInfo length_info{
+      length_id, {analysis::Array::LengthInfo::Case::kConstant, length}};
+
+  analysis::Array r(element, length_info);
+
+  analysis::Type* type = context()->get_type_mgr()->GetRegisteredType(&r);
+  assert(type && type->AsArray());
+  return type->AsArray();
+}
+
 analysis::Function* InstrumentPass::GetFunction(
     const analysis::Type* return_val,
     const std::vector<const analysis::Type*>& args) {
diff --git a/source/opt/instrument_pass.h b/source/opt/instrument_pass.h
index 13119297cb..4bbbb09813 100644
--- a/source/opt/instrument_pass.h
+++ b/source/opt/instrument_pass.h
@@ -270,6 +270,7 @@ class InstrumentPass : public Pass {
   analysis::Integer* GetInteger(uint32_t width, bool is_signed);
   analysis::Struct* GetStruct(const std::vector<const analysis::Type*>& fields);
   analysis::RuntimeArray* GetRuntimeArray(const analysis::Type* element);
+  analysis::Array* GetArray(const analysis::Type* element, uint32_t size);
   analysis::Function* GetFunction(
       const analysis::Type* return_val,
       const std::vector<const analysis::Type*>& args);
@@ -339,8 +340,8 @@ class InstrumentPass : public Pass {
   // If code is generated for an instruction, replace the instruction's
   // block with the new blocks that are generated. Continue processing at the
   // top of the last new block.
-  bool InstrumentFunction(Function* func, uint32_t stage_idx,
-                          InstProcessFunction& pfn);
+  virtual bool InstrumentFunction(Function* func, uint32_t stage_idx,
+                                  InstProcessFunction& pfn);
 
   // Call |pfn| on all functions in the call tree of the function
   // ids in |roots|.
diff --git a/source/opt/ir_builder.h b/source/opt/ir_builder.h
index 93289a61a7..48e08ee7af 100644
--- a/source/opt/ir_builder.h
+++ b/source/opt/ir_builder.h
@@ -480,9 +480,16 @@ class InstructionBuilder {
     return AddInstruction(std::move(new_inst));
   }
 
-  Instruction* AddLoad(uint32_t type_id, uint32_t base_ptr_id) {
+  Instruction* AddLoad(uint32_t type_id, uint32_t base_ptr_id,
+                       uint32_t alignment = 0) {
     std::vector<Operand> operands;
     operands.push_back({SPV_OPERAND_TYPE_ID, {base_ptr_id}});
+    if (alignment != 0) {
+      operands.push_back(
+          {SPV_OPERAND_TYPE_MEMORY_ACCESS,
+           {static_cast<uint32_t>(spv::MemoryAccessMask::Aligned)}});
+      operands.push_back({SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER, {alignment}});
+    }
 
     // TODO(1841): Handle id overflow.
     std::unique_ptr<Instruction> new_inst(
diff --git a/test/opt/inst_bindless_check_test.cpp b/test/opt/inst_bindless_check_test.cpp
index 5ee6eed492..9fe4f4021a 100644
--- a/test/opt/inst_bindless_check_test.cpp
+++ b/test/opt/inst_bindless_check_test.cpp
@@ -252,6 +252,9 @@ static const std::string kStreamWrite5Vert = kStreamWrite5Begin + R"(
 // clang-format on
 
 static const std::string kInputDecorations = R"(
+; CHECK: OpDecorate [[desc_set_struct:%inst_bindless_DescriptorSetData]] Block
+; CHECK: OpMemberDecorate [[desc_set_struct]] 0 Offset 0
+; CHECK: OpMemberDecorate [[desc_set_struct]] 1 Offset 4
 ; CHECK: OpDecorate [[input_buffer_type:%inst_bindless_InputBuffer]] Block
 ; CHECK: OpMemberDecorate [[input_buffer_type]] 0 Offset 0
 ; CHECK: OpDecorate [[input_buffer_var:%\w+]] DescriptorSet 7
@@ -259,61 +262,90 @@ static const std::string kInputDecorations = R"(
 )";
 
 static const std::string kInputGlobals = R"(
-; CHECK: [[input_buffer_type]] = OpTypeStruct %_runtimearr_uint
+; CHECK: [[desc_set_struct]] = OpTypeStruct %uint %_runtimearr_uint
+; CHECK: [[desc_set_ptr:%\w+]] = OpTypePointer PhysicalStorageBuffer [[desc_set_struct]]
+; CHECK: [[desc_set_ptr_array:%\w+]] = OpTypeArray [[desc_set_ptr]] %uint_32
+; CHECK: [[input_buffer_type]] = OpTypeStruct [[desc_set_ptr_array]]
 ; CHECK: [[input_ptr_type:%\w+]] = OpTypePointer StorageBuffer [[input_buffer_type]]
 ; CHECK: [[input_buffer_var]] = OpVariable [[input_ptr_type]] StorageBuffer
 )";
 
-static const std::string kDirectRead2 = R"(
-; CHECK: %inst_bindless_direct_read_2 = OpFunction %uint None {{%\w+}}
-; CHECK: [[param_1:%\w+]] = OpFunctionParameter %uint
-; CHECK: [[param_2:%\w+]] = OpFunctionParameter %uint
+static const std::string kReadBindingLength = R"(
+; CHECK: %inst_bindless_read_binding_length = OpFunction %uint None {{%\w+}}
+; CHECK: [[bl_desc_set_idx:%\w+]] = OpFunctionParameter %uint
+; CHECK: [[bl_binding_idx:%\w+]] = OpFunctionParameter %uint
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpUGreaterThanEqual %bool [[bl_desc_set_idx]] %uint_32
+; CHECK: OpSelectionMerge {{%\w+}} None
+; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: OpReturnValue %uint_0
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_inst_bindless_DescriptorSetData %inst_bindless_input_buffer %uint_0 [[bl_desc_set_idx]]
+; CHECK: {{%\w+}} = OpLoad %_ptr_PhysicalStorageBuffer_inst_bindless_DescriptorSetData {{%\w+}}
+; CHECK: {{%\w+}} = OpBitcast %v2uint {{%\w+}}
+; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+; CHECK: {{%\w+}} = OpIEqual %bool {{%\w+}} %uint_0
+; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+; CHECK: {{%\w+}} = OpIEqual %bool {{%\w+}} %uint_0
+; CHECK: {{%\w+}} = OpLogicalAnd %bool {{%\w+}} {{%\w+}}
+; CHECK: OpSelectionMerge {{%\w+}} None
+; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: OpReturnValue %uint_0
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpAccessChain %_ptr_PhysicalStorageBuffer_uint {{%\w+}} %uint_0
+; CHECK: {{%\w+}} = OpLoad %uint {{%\w+}} Aligned 8
+; CHECK: {{%\w+}} = OpUGreaterThanEqual %bool [[bl_binding_idx]] {{%\w+}}
+; CHECK: OpSelectionMerge {{%\w+}} None
+; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: OpReturnValue %uint_0
 ; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[input_buffer_var]] %uint_0 [[param_1]]
-; CHECK: {{%\w+}} = OpLoad %uint {{%\w+}}
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} [[param_2]]
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[input_buffer_var]] %uint_0 {{%\w+}}
-; CHECK: {{%\w+}} = OpLoad %uint {{%\w+}}
+; CHECK: {{%\w+}} = OpAccessChain %_ptr_PhysicalStorageBuffer_uint {{%\w+}} %uint_1 [[bl_binding_idx]]
+; CHECK: {{%\w+}} = OpLoad %uint {{%\w+}} Aligned 4
 ; CHECK: OpReturnValue {{%\w+}}
 ; CHECK: OpFunctionEnd
 )";
 
-static const std::string kDirectRead3 = R"(
- ;CHECK: %inst_bindless_direct_read_3 = OpFunction %uint None {{%\w+}}
-; CHECK: [[param_1:%\w+]] = OpFunctionParameter %uint
-; CHECK: [[param_2:%\w+]] = OpFunctionParameter %uint
-; CHECK: [[param_3:%\w+]] = OpFunctionParameter %uint
- ;CHECK: {{%\w+}} = OpLabel
- ;CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[input_buffer_var]] %uint_0 [[param_1]]
- ;CHECK: {{%\w+}} = OpLoad %uint {{%\w+}}
- ;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} [[param_2]]
- ;CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[input_buffer_var]] %uint_0 {{%\w+}}
- ;CHECK: {{%\w+}} = OpLoad %uint {{%\w+}}
- ;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} [[param_3]]
- ;CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[input_buffer_var]] %uint_0 {{%\w+}}
- ;CHECK: {{%\w+}} = OpLoad %uint {{%\w+}}
- ;CHECK: OpReturnValue {{%\w+}}
- ;CHECK: OpFunctionEnd
-)";
-
-static const std::string kDirectRead4 = R"(
-; CHECK: %inst_bindless_direct_read_4 = OpFunction %uint None {{%\w+}}
-; CHECK: [[param_1:%\w+]] = OpFunctionParameter %uint
-; CHECK: [[param_2:%\w+]] = OpFunctionParameter %uint
-; CHECK: [[param_3:%\w+]] = OpFunctionParameter %uint
-; CHECK: [[param_4:%\w+]] = OpFunctionParameter %uint
+static const std::string kReadDescInit = R"(
+; CHECK: %inst_bindless_read_desc_init = OpFunction %uint None {{%\w+}}
+; CHECK: [[di_desc_set_idx:%\w+]] = OpFunctionParameter %uint
+; CHECK: [[di_binding_idx:%\w+]] = OpFunctionParameter %uint
+; CHECK: [[di_desc_idx:%\w+]] = OpFunctionParameter %uint
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpUGreaterThanEqual %bool [[di_desc_set_idx]] %uint_32
+; CHECK: OpSelectionMerge {{%\w+}} None
+; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: OpReturnValue %uint_0
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_inst_bindless_DescriptorSetData %inst_bindless_input_buffer %uint_0 [[di_desc_set_idx]]
+; CHECK: {{%\w+}} = OpLoad %_ptr_PhysicalStorageBuffer_inst_bindless_DescriptorSetData {{%\w+}}
+; CHECK: {{%\w+}} = OpBitcast %v2uint {{%\w+}}
+; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
+; CHECK: {{%\w+}} = OpIEqual %bool {{%\w+}} %uint_0
+; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
+; CHECK: {{%\w+}} = OpIEqual %bool {{%\w+}} %uint_0
+; CHECK: {{%\w+}} = OpLogicalAnd %bool {{%\w+}} {{%\w+}}
+; CHECK: OpSelectionMerge {{%\w+}} None
+; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
 ; CHECK: {{%\w+}} = OpLabel
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[input_buffer_var]] %uint_0 [[param_1]]
-; CHECK: {{%\w+}} = OpLoad %uint {{%\w+}}
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} [[param_2]]
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[input_buffer_var]] %uint_0 {{%\w+}}
-; CHECK: {{%\w+}} = OpLoad %uint {{%\w+}}
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} [[param_3]]
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[input_buffer_var]] %uint_0 {{%\w+}}
-; CHECK: {{%\w+}} = OpLoad %uint {{%\w+}}
-; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} [[param_4]]
-; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[input_buffer_var]] %uint_0 {{%\w+}}
-; CHECK: {{%\w+}} = OpLoad %uint {{%\w+}}
+; CHECK: OpReturnValue %uint_0
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpAccessChain %_ptr_PhysicalStorageBuffer_uint {{%\w+}} %uint_0
+; CHECK: [[di_num_bindings:%\w+]] = OpLoad %uint {{%\w+}} Aligned 8
+; CHECK: {{%\w+}} = OpUGreaterThanEqual %bool [[di_binding_idx]] [[di_num_bindings]]
+; CHECK: OpSelectionMerge {{%\w+}} None
+; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: OpReturnValue %uint_0
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} {{%\w+}}
+; CHECK: {{%\w+}} = OpAccessChain %_ptr_PhysicalStorageBuffer_uint {{%\w+}} %uint_1 {{%\w+}}
+; CHECK: {{%\w+}} = OpLoad %uint {{%\w+}} Aligned 4
+; CHECK: {{%\w+}} = OpAccessChain %_ptr_PhysicalStorageBuffer_uint {{%\w+}} %uint_1 {{%\w+}}
+; CHECK: {{%\w+}} = OpLoad %uint {{%\w+}} Aligned 4
 ; CHECK: OpReturnValue {{%\w+}}
 ; CHECK: OpFunctionEnd
 )";
@@ -589,20 +621,20 @@ OpDecorate %_entryPointOutput_vColor Location 0
 OpStore %_entryPointOutput_vColor %37
 ; CHECK-NOT: %37 = OpImageSampleImplicitLod %v4float %36 %30
 ; CHECK-NOT: OpStore %_entryPointOutput_vColor %37
-; CHECK: %40 = OpULessThan %bool %32 %uint_128
-; CHECK: OpSelectionMerge %41 None
-; CHECK: OpBranchConditional %40 %42 %43
-; CHECK: %42 = OpLabel
-; CHECK: %44 = OpLoad %16 %33
-; CHECK: %45 = OpSampledImage %26 %44 %35
-; CHECK: %46 = OpImageSampleImplicitLod %v4float %45 %30
-; CHECK: OpBranch %41
-; CHECK: %43 = OpLabel
+; CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} %uint_128
+; CHECK: OpSelectionMerge {{%\w+}} None
+; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpLoad %16 %33
+; CHECK: {{%\w+}} = OpSampledImage %26 {{%\w+}} %35
+; CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %30
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
 ; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_56 %uint_0 %32 %uint_128
-; CHECK: OpBranch %41
-; CHECK: %41 = OpLabel
-; CHECK: %104 = OpPhi %v4float %46 %42 [[null_v4float]] %43
-; CHECK: OpStore %_entryPointOutput_vColor %104
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: [[phi_result:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
+; CHECK: OpStore %_entryPointOutput_vColor [[phi_result]]
 OpReturn
 OpFunctionEnd
 )";
@@ -1566,12 +1598,7 @@ OpDecorate %_entryPointOutput_vColor Location 0
 %i_vTextureCoords = OpVariable %_ptr_Input_v2float Input
 %_ptr_Output_v4float = OpTypePointer Output %v4float
 %_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output
-; CHECK: %41 = OpTypeFunction %uint %uint %uint
-; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint
-)" + kInputGlobals + R"(
-; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
-; CHECK: %bool = OpTypeBool
-)" + kOutputGlobals + R"(
+)" + kInputGlobals + kOutputGlobals + R"(
 ; CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
 ; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
 ; CHECK: %v4uint = OpTypeVector %uint 4
@@ -1593,39 +1620,40 @@ OpDecorate %_entryPointOutput_vColor Location 0
 OpStore %_entryPointOutput_vColor %71
 ; CHECK-NOT: %71 = OpImageSampleImplicitLod %v4float %68 %53
 ; CHECK-NOT: OpStore %_entryPointOutput_vColor %71
-; CHECK: %55 = OpFunctionCall %uint %inst_bindless_direct_read_2 %uint_2 %uint_2
-; CHECK: %57 = OpULessThan %bool %32 %55
-; CHECK: OpSelectionMerge %58 None
-; CHECK: OpBranchConditional %57 %59 %60
-; CHECK: %59 = OpLabel
-; CHECK: %61 = OpLoad %16 %33
-; CHECK: %62 = OpSampledImage %26 %61 %35
-; CHECK: %136 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_1 %uint_2 %32
-; CHECK: %137 = OpULessThan %bool %uint_0 %136
-; CHECK: OpSelectionMerge %138 None
-; CHECK: OpBranchConditional %137 %139 %140
-; CHECK: %139 = OpLabel
-; CHECK: %141 = OpLoad %16 %33
-; CHECK: %142 = OpSampledImage %26 %141 %35
-; CHECK: %143 = OpImageSampleImplicitLod %v4float %142 %30
-; CHECK: OpBranch %138
-; CHECK: %140 = OpLabel
-; CHECK: %144 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_59 %uint_1 %32 %uint_0
-; CHECK: OpBranch %138
-; CHECK: %138 = OpLabel
-; CHECK: [[phi_result_1:%\w+]] = OpPhi %v4float %143 %139 [[null_v4float]] %140
-; CHECK: OpBranch %58
-; CHECK: %60 = OpLabel
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_59 %uint_0 %32 %55
-; CHECK: OpBranch %58
-; CHECK: %58 = OpLabel
-; CHECK: [[phi_result_2:%\w+]] = OpPhi %v4float [[phi_result_1]] %138 [[null_v4float]] %60
+; CHECK: [[length_result:%\w+]] = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_1 %uint_2
+; CHECK: {{%\w+}} = OpULessThan %bool %32 [[length_result]]
+; CHECK: OpSelectionMerge {{%\w+}} None
+; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpLoad %16 %33
+; CHECK: {{%\w+}} = OpSampledImage %26 {{%\w+}} %35
+; CHECK: [[state_result:%\w+]] = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_1 %uint_2 %32
+; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 [[state_result]]
+; CHECK: OpSelectionMerge {{%\w+}} None
+; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpLoad %16 %33
+; CHECK: {{%\w+}} = OpSampledImage %26 {{%\w+}} %35
+; CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %30
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_59 %uint_1 %32 %uint_0
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: [[phi_result_1:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_59 %uint_0 %32 {{%\w+}}
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: [[phi_result_2:%\w+]] = OpPhi %v4float [[phi_result_1]] {{%\w+}} [[null_v4float]] {{%\w+}}
 ; CHECK: OpStore %_entryPointOutput_vColor [[phi_result_2]]
 OpReturn
 OpFunctionEnd
 )";
 
-  const std::string new_funcs = kDirectRead2 + kStreamWrite4Frag + kDirectRead4;
+  const std::string new_funcs =
+      kReadBindingLength + kStreamWrite4Frag + kReadDescInit;
 
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   SinglePassRunAndMatch<InstBindlessCheckPass>(defs + main_func + new_funcs,
@@ -1681,13 +1709,7 @@ OpDecorate %_entryPointOutput_vColor Location 0
 %i_vTextureCoords = OpVariable %_ptr_Input_v2float Input
 %_ptr_Output_v4float = OpTypePointer Output %v4float
 %_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output
-; CHECK: %uint = OpTypeInt 32 0
-; CHECK: %28 = OpTypeFunction %uint %uint %uint %uint %uint
-; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint
-)" + kInputGlobals + R"(
-; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
-; CHECK: %bool = OpTypeBool
-)" + kOutputGlobals + R"(
+)" + kInputGlobals + kOutputGlobals + R"(
 ; CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
 ; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
 ; CHECK: %v4uint = OpTypeVector %uint 4
@@ -1706,26 +1728,26 @@ OpDecorate %_entryPointOutput_vColor Location 0
 OpStore %_entryPointOutput_vColor %24
 ; CHECK-NOT: %24 = OpImageSampleImplicitLod %v4float %23 %20
 ; CHECK-NOT: OpStore %_entryPointOutput_vColor %24
-; CHECK: %50 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_0 %uint_0
-; CHECK: %52 = OpULessThan %bool %uint_0 %50
-; CHECK: OpSelectionMerge %54 None
-; CHECK: OpBranchConditional %52 %55 %56
-; CHECK: %55 = OpLabel
-; CHECK: %57 = OpLoad %12 %g_tColor
-; CHECK: %58 = OpSampledImage %16 %57 %22
-; CHECK: %59 = OpImageSampleImplicitLod %v4float %58 %20
-; CHECK: OpBranch %54
-; CHECK: %56 = OpLabel
+; CHECK: [[state_result:%\w+]] = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0
+; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 [[state_result]]
+; CHECK: OpSelectionMerge {{%\w+}} None
+; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpLoad %12 %g_tColor
+; CHECK: {{%\w+}} = OpSampledImage %16 {{%\w+}} %22
+; CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %20
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
 ; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_39 %uint_1 %uint_0 %uint_0
-; CHECK: OpBranch %54
-; CHECK: %54 = OpLabel
-; CHECK: [[phi_result:%\w+]] = OpPhi %v4float %59 %55 [[null_v4float]] %56
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: [[phi_result:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
 ; CHECK: OpStore %_entryPointOutput_vColor [[phi_result]]
 OpReturn
 OpFunctionEnd
 )";
 
-  const std::string new_funcs = kDirectRead4 + kStreamWrite4Frag;
+  const std::string new_funcs = kReadDescInit + kStreamWrite4Frag;
 
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   SinglePassRunAndMatch<InstBindlessCheckPass>(defs + main_func + new_funcs,
@@ -1896,10 +1918,10 @@ OpDecorate %16 NonUniform
 OpDecorate %20 NonUniform
 ; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4
 )" + kInputDecorations + R"(
-; CHECK: OpDecorate %130 NonUniform
+; CHECK: OpDecorate {{%\w+}} NonUniform
 )" + kOutputDecorations + R"(
 ; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
-; CHECK: OpDecorate %127 NonUniform
+; CHECK: OpDecorate {{%\w+}} NonUniform
 %void = OpTypeVoid
 %3 = OpTypeFunction %void
 %float = OpTypeFloat 32
@@ -1914,13 +1936,7 @@ OpDecorate %20 NonUniform
 %nu_ii = OpVariable %_ptr_Input_int Input
 %int_0 = OpConstant %int 0
 %_ptr_Uniform_float = OpTypePointer Uniform %float
-; CHECK: %uint = OpTypeInt 32 0
-; CHECK: %26 = OpTypeFunction %uint %uint %uint
-; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint
-)" + kInputGlobals + R"(
-; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
-; CHECK: %bool = OpTypeBool
-)" + kOutputGlobals + R"(
+)" + kInputGlobals + kOutputGlobals + R"(
 ; CHECK: %v4float = OpTypeVector %float 4
 ; CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
 ; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
@@ -1938,38 +1954,39 @@ OpDecorate %20 NonUniform
 OpStore %b %20
 ; CHECK-NOT: %20 = OpLoad %float %19
 ; CHECK-NOT: OpStore %b %20
-; CHECK: %40 = OpFunctionCall %uint %inst_bindless_direct_read_2 %uint_1 %uint_3
-; CHECK: %42 = OpULessThan %bool %7 %40
-; CHECK: OpSelectionMerge %43 None
-; CHECK: OpBranchConditional %42 %44 %45
-; CHECK: %44 = OpLabel
-; CHECK: %103 = OpBitcast %uint %7
-; CHECK: %122 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_3 %103
-; CHECK: %123 = OpULessThan %bool %uint_0 %122
-; CHECK: OpSelectionMerge %124 None
-; CHECK: OpBranchConditional %123 %125 %126
-; CHECK: %125 = OpLabel
-; CHECK: %127 = OpLoad %float %20
-; CHECK: OpBranch %124
-; CHECK: %126 = OpLabel
-; CHECK: %128 = OpBitcast %uint %7
-; CHECK: %129 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_45 %uint_1 %128 %uint_0
-; CHECK: OpBranch %124
-; CHECK: %124 = OpLabel
-; CHECK: [[phi_result_1:%\w+]] = OpPhi %float %127 %125 [[null_float]] %126
-; CHECK: OpBranch %43
-; CHECK: %45 = OpLabel
+; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_0 %uint_3
+; CHECK: {{%\w+}} = OpULessThan %bool %7 {{%\w+}}
+; CHECK: OpSelectionMerge {{%\w+}} None
+; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpBitcast %uint %7
+; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_3 {{%\w+}}
+; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
+; CHECK: OpSelectionMerge {{%\w+}} None
+; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpLoad %float %20
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpBitcast %uint %7
+; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_45 %uint_1 {{%\w+}} %uint_0
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: [[phi_result_1:%\w+]] = OpPhi %float {{%\w+}} {{%\w+}} [[null_float]] {{%\w+}}
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
 ; CHECK: [[bitcast_result:%\w+]] = OpBitcast %uint %7
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_45 %uint_0 [[bitcast_result]] %40
-; CHECK: OpBranch %43
-; CHECK: %43 = OpLabel
-; CHECK: [[phi_result_2:%\w+]] = OpPhi %float [[phi_result_1]] %124 [[null_float]] %45
+; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_45 %uint_0 [[bitcast_result]] {{%\w+}}
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: [[phi_result_2:%\w+]] = OpPhi %float [[phi_result_1]] {{%\w+}} [[null_float]] {{%\w+}}
 ; CHECK: OpStore %b [[phi_result_2]]
 OpReturn
 OpFunctionEnd
 )";
 
-  const std::string new_funcs = kDirectRead2 + kStreamWrite4Frag + kDirectRead4;
+  const std::string new_funcs =
+      kReadBindingLength + kStreamWrite4Frag + kReadDescInit;
 
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   SinglePassRunAndMatch<InstBindlessCheckPass>(defs + main_func + new_funcs,
@@ -2023,11 +2040,8 @@ OpDecorate %nu_ii NonUniform
 OpDecorate %16 NonUniform
 OpDecorate %20 NonUniform
 ; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4
-)" + kInputDecorations + R"(
-; CHECK: OpDecorate %130 NonUniform
-)" + kOutputDecorations + R"(
+)" + kInputDecorations + kOutputDecorations + R"(
 ; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
-; CHECK: OpDecorate %127 NonUniform
 %void = OpTypeVoid
 %3 = OpTypeFunction %void
 %float = OpTypeFloat 32
@@ -2043,12 +2057,8 @@ OpDecorate %20 NonUniform
 %int_0 = OpConstant %int 0
 %_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
 ; CHECK: %uint = OpTypeInt 32 0
-; CHECK: %26 = OpTypeFunction %uint %uint %uint
 ; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint
-)" + kInputGlobals + R"(
-; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
-; CHECK: %bool = OpTypeBool
-)" + kOutputGlobals + R"(
+)" + kInputGlobals + kOutputGlobals + R"(
 ; CHECK: %v4float = OpTypeVector %float 4
 ; CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
 ; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
@@ -2066,38 +2076,39 @@ OpDecorate %20 NonUniform
 OpStore %b %20
 ; CHECK-NOT: %20 = OpLoad %float %19
 ; CHECK-NOT: OpStore %b %20
-; CHECK: %40 = OpFunctionCall %uint %inst_bindless_direct_read_2 %uint_1 %uint_3
-; CHECK: %42 = OpULessThan %bool %7 %40
-; CHECK: OpSelectionMerge %43 None
-; CHECK: OpBranchConditional %42 %44 %45
-; CHECK: %44 = OpLabel
+; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_0 %uint_3
+; CHECK: {{%\w+}} = OpULessThan %bool %7 {{%\w+}}
+; CHECK: OpSelectionMerge {{%\w+}} None
+; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
 ; CHECK: [[bitcast_result_1:%\w+]] = OpBitcast %uint %7
-; CHECK: %122 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_3 [[bitcast_result_1]]
-; CHECK: %123 = OpULessThan %bool %uint_0 %122
-; CHECK: OpSelectionMerge %124 None
-; CHECK: OpBranchConditional %123 %125 %126
-; CHECK: %125 = OpLabel
-; CHECK: %127 = OpLoad %float %20
-; CHECK: OpBranch %124
-; CHECK: %126 = OpLabel
-; CHECK: %128 = OpBitcast %uint %7
-; CHECK: %129 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_45 %uint_1 %128 %uint_0
-; CHECK: OpBranch %124
-; CHECK: %124 = OpLabel
-; CHECK: [[phi_result_1:%\w+]] = OpPhi %float %127 %125 [[null_float]] %126
-; CHECK: OpBranch %43
-; CHECK: %45 = OpLabel
+; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_3 [[bitcast_result_1]]
+; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
+; CHECK: OpSelectionMerge {{%\w+}} None
+; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpLoad %float %20
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpBitcast %uint %7
+; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_45 %uint_1 {{%\w+}} %uint_0
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: [[phi_result_1:%\w+]] = OpPhi %float {{%\w+}} {{%\w+}} [[null_float]] {{%\w+}}
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
 ; CHECK: [[bitcast_result_2:%\w+]] = OpBitcast %uint %7
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_45 %uint_0 [[bitcast_result_2]] %40
-; CHECK: OpBranch %43
-; CHECK: %43 = OpLabel
-; CHECK: [[phi_result_2:%\w+]] = OpPhi %float [[phi_result_1]] %124 [[null_float]] %45
+; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_45 %uint_0 [[bitcast_result_2]] {{%\w+}}
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: [[phi_result_2:%\w+]] = OpPhi %float [[phi_result_1]] {{%\w+}} [[null_float]] {{%\w+}}
 ; CHECK: OpStore %b [[phi_result_2]]
 OpReturn
 OpFunctionEnd
 )";
 
-  const std::string new_funcs = kDirectRead2 + kStreamWrite4Frag + kDirectRead4;
+  const std::string new_funcs =
+      kReadBindingLength + kStreamWrite4Frag + kReadDescInit;
 
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   SinglePassRunAndMatch<InstBindlessCheckPass>(defs + main_func + new_funcs,
@@ -2141,10 +2152,10 @@ OpDecorate %16 NonUniform
 OpDecorate %20 NonUniform
 ; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4
 )" + kInputDecorations + R"(
-; CHECK: OpDecorate %130 NonUniform
+; CHECK: OpDecorate {{%\w+}} NonUniform
 )" + kOutputDecorations + R"(
 ; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
-; CHECK: OpDecorate %127 NonUniform
+; CHECK: OpDecorate {{%\w+}} NonUniform
 %void = OpTypeVoid
 %3 = OpTypeFunction %void
 %float = OpTypeFloat 32
@@ -2159,13 +2170,7 @@ OpDecorate %20 NonUniform
 %nu_ii = OpVariable %_ptr_Input_int Input
 %int_0 = OpConstant %int 0
 %_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
-; CHECK: %uint = OpTypeInt 32 0
-; CHECK: %26 = OpTypeFunction %uint %uint %uint
-; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint
-)" + kInputGlobals + R"(
-; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
-; CHECK: %bool = OpTypeBool
-)" + kOutputGlobals + R"(
+)" + kInputGlobals + kOutputGlobals + R"(
 ; CHECK: %v4float = OpTypeVector %float 4
 ; CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
 ; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
@@ -2183,38 +2188,39 @@ OpDecorate %20 NonUniform
 OpStore %b %20
 ; CHECK-NOT: %20 = OpLoad %float %19
 ; CHECK-NOT: OpStore %b %20
-; CHECK: %40 = OpFunctionCall %uint %inst_bindless_direct_read_2 %uint_1 %uint_3
-; CHECK: %42 = OpULessThan %bool %7 %40
-; CHECK: OpSelectionMerge %43 None
-; CHECK: OpBranchConditional %42 %44 %45
-; CHECK: %44 = OpLabel
-; CHECK: %103 = OpBitcast %uint %7
-; CHECK: %122 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_3 %103
-; CHECK: %123 = OpULessThan %bool %uint_0 %122
-; CHECK: OpSelectionMerge %124 None
-; CHECK: OpBranchConditional %123 %125 %126
-; CHECK: %125 = OpLabel
-; CHECK: %127 = OpLoad %float %20
-; CHECK: OpBranch %124
-; CHECK: %126 = OpLabel
-; CHECK: %128 = OpBitcast %uint %7
-; CHECK: %129 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_45 %uint_1 %128 %uint_0
-; CHECK: OpBranch %124
-; CHECK: %124 = OpLabel
-; CHECK: [[phi_result_1:%\w+]] = OpPhi %float %127 %125 [[null_float]] %126
-; CHECK: OpBranch %43
-; CHECK: %45 = OpLabel
+; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_0 %uint_3
+; CHECK: {{%\w+}} = OpULessThan %bool %7 {{%\w+}}
+; CHECK: OpSelectionMerge {{%\w+}} None
+; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpBitcast %uint %7
+; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_3 {{%\w+}}
+; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
+; CHECK: OpSelectionMerge {{%\w+}} None
+; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpLoad %float %20
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpBitcast %uint %7
+; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_45 %uint_1 {{%\w+}} %uint_0
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: [[phi_result_1:%\w+]] = OpPhi %float {{%\w+}} {{%\w+}} [[null_float]] {{%\w+}}
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
 ; CHECK: [[bitcast_result:%\w+]] = OpBitcast %uint %7
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_45 %uint_0 [[bitcast_result]] %40
-; CHECK: OpBranch %43
-; CHECK: %43 = OpLabel
-; CHECK: [[phi_result_2:%\w+]] = OpPhi %float [[phi_result_1]] %124 [[null_float]] %45
+; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_45 %uint_0 [[bitcast_result]] {{%\w+}}
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: [[phi_result_2:%\w+]] = OpPhi %float [[phi_result_1]] {{%\w+}} [[null_float]] {{%\w+}}
 ; CHECK: OpStore %b [[phi_result_2]]
 OpReturn
 OpFunctionEnd
 )";
 
-  const std::string new_funcs = kDirectRead2 + kStreamWrite4Frag + kDirectRead4;
+  const std::string new_funcs =
+      kReadBindingLength + kStreamWrite4Frag + kReadDescInit;
 
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   SinglePassRunAndMatch<InstBindlessCheckPass>(defs + main_func + new_funcs,
@@ -2273,12 +2279,8 @@ OpDecorate %uniformBuffer Binding 3
 ; CHECK: %int = OpTypeInt 32 1
 ; CHECK: %_ptr_Uniform_float = OpTypePointer Uniform %float
 ; CHECK: %uint = OpTypeInt 32 0
-; CHECK: %21 = OpTypeFunction %uint %uint %uint %uint %uint
 ; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint
-)" + kInputGlobals + R"(
-; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
-; CHECK: %bool = OpTypeBool
-)" + kOutputGlobals + R"(
+)" + kInputGlobals + kOutputGlobals + R"(
 ; CHECK: %v4float = OpTypeVector %float 4
 ; CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
 ; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
@@ -2295,24 +2297,24 @@ OpDecorate %uniformBuffer Binding 3
 OpStore %b %16
 ; CHECK-NOT: %16 = OpLoad %float %15
 ; CHECK-NOT: OpStore %b %16
-; CHECK: %43 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_3 %uint_0
-; CHECK: %45 = OpULessThan %bool %uint_0 %43
-; CHECK: OpSelectionMerge %47 None
-; CHECK: OpBranchConditional %45 %48 %49
-; CHECK: %48 = OpLabel
-; CHECK: %50 = OpLoad %float %15
-; CHECK: OpBranch %47
-; CHECK: %49 = OpLabel
+; CHECK: [[check_result:%\w+]] = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_3 %uint_0
+; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 [[check_result]]
+; CHECK: OpSelectionMerge {{%\w+}} None
+; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpLoad %float %15
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
 ; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_32 %uint_1 %uint_0 %uint_0
-; CHECK: OpBranch %47
-; CHECK: %47 = OpLabel
-; CHECK: [[phi_result:%\w+]] = OpPhi %float %50 %48 [[null_float]] %49
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: [[phi_result:%\w+]] = OpPhi %float {{%\w+}} {{%\w+}} [[null_float]] {{%\w+}}
 ; CHECK: OpStore %b [[phi_result]]
 OpReturn
 OpFunctionEnd
 )";
 
-  const std::string new_funcs = kDirectRead4 + kStreamWrite4Frag;
+  const std::string new_funcs = kReadDescInit + kStreamWrite4Frag;
 
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   SinglePassRunAndMatch<InstBindlessCheckPass>(defs + main_func + new_funcs,
@@ -2383,7 +2385,6 @@ OpDecorate %b Location 1
 )" + kInputGlobals + kOutputGlobals + R"(
 ; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
 ; CHECK: %v4uint = OpTypeVector %uint 4
-; CHECK: %102 = OpTypeFunction %uint %uint %uint %uint %uint
 )";
   // clang-format on
 
@@ -2395,35 +2396,36 @@ OpDecorate %b Location 1
 %20 = OpAccessChain %_ptr_Uniform_float %storageBuffer %14 %int_0
 OpStore %20 %18
 ; CHECK-NOT: OpStore %20 %18
-; CHECK: %40 = OpFunctionCall %uint %inst_bindless_direct_read_2 %uint_1 %uint_4
-; CHECK: %42 = OpULessThan %bool %7 %40
-; CHECK: OpSelectionMerge %43 None
-; CHECK: OpBranchConditional %42 %44 %45
-; CHECK: %44 = OpLabel
-; CHECK: %100 = OpBitcast %uint %7
-; CHECK: %119 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_4 %100
-; CHECK: %120 = OpULessThan %bool %uint_0 %119
-; CHECK: OpSelectionMerge %121 None
-; CHECK: OpBranchConditional %120 %122 %123
-; CHECK: %122 = OpLabel
+; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_0 %uint_4
+; CHECK: {{%\w+}} = OpULessThan %bool %7 {{%\w+}}
+; CHECK: OpSelectionMerge {{%\w+}} None
+; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpBitcast %uint %7
+; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_4 {{%\w+}}
+; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
+; CHECK: OpSelectionMerge {{%\w+}} None
+; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
 ; CHECK: OpStore %20 %19
-; CHECK: OpBranch %121
-; CHECK: %123 = OpLabel
-; CHECK: %124 = OpBitcast %uint %7
-; CHECK: %125 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_45 %uint_1 %124 %uint_0
-; CHECK: OpBranch %121
-; CHECK: %121 = OpLabel
-; CHECK: OpBranch %43
-; CHECK: %45 = OpLabel
-; CHECK: %46 = OpBitcast %uint %7
-; CHECK: %99 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_45 %uint_0 %46 %40
-; CHECK: OpBranch %43
-; CHECK: %43 = OpLabel
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpBitcast %uint %7
+; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_45 %uint_1 {{%\w+}} %uint_0
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpBitcast %uint %7
+; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_45 %uint_0 {{%\w+}} {{%\w+}}
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
 OpReturn
 OpFunctionEnd
 )";
 
-  const std::string new_funcs = kDirectRead2 + kStreamWrite4Frag + kDirectRead4;
+  const std::string new_funcs =
+      kReadBindingLength + kStreamWrite4Frag + kReadDescInit;
 
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   SinglePassRunAndMatch<InstBindlessCheckPass>(defs + main_func + new_funcs,
@@ -2479,7 +2481,7 @@ OpDecorate %22 NonUniform
 )" + kOutputDecorations + R"(
 ; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
 )" + kInputDecorations + R"(
-; CHECK: OpDecorate %117 NonUniform
+; CHECK: OpDecorate [[load_result:%\w+]] NonUniform
 %void = OpTypeVoid
 %3 = OpTypeFunction %void
 %float = OpTypeFloat 32
@@ -2514,37 +2516,37 @@ OpDecorate %22 NonUniform
 OpStore %b %22
 ; CHECK-NOT: %22 = OpLoad %float %21
 ; CHECK-NOT: OpStore %b %22
-; CHECK: %25 = OpULessThan %bool %7 %uint_128
-; CHECK: OpSelectionMerge %26 None
-; CHECK: OpBranchConditional %25 %27 %28
-; CHECK: %27 = OpLabel
-; CHECK: %90 = OpBitcast %uint %7
-; CHECK: %112 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_3 %90
-; CHECK: %113 = OpULessThan %bool %uint_0 %112
-; CHECK: OpSelectionMerge %114 None
-; CHECK: OpBranchConditional %113 %115 %116
-; CHECK: %115 = OpLabel
-; CHECK: %117 = OpLoad %float %22
-; CHECK: OpBranch %114
-; CHECK: %116 = OpLabel
-; CHECK: %118 = OpBitcast %uint %7
-; CHECK: %119 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_46 %uint_1 %118 %uint_0
-; CHECK: OpBranch %114
-; CHECK: %114 = OpLabel
-; CHECK: [[phi_result_1:%\w+]] = OpPhi %float %117 %115 [[null_float]] %116
-; CHECK: OpBranch %26
-; CHECK: %28 = OpLabel
+; CHECK: {{%\w+}} = OpULessThan %bool %7 %uint_128
+; CHECK: OpSelectionMerge {{%\w+}} None
+; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpBitcast %uint %7
+; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_3 {{%\w+}}
+; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
+; CHECK: OpSelectionMerge {{%\w+}} None
+; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: [[load_result]] = OpLoad %float %22
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpBitcast %uint %7
+; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_46 %uint_1 {{%\w+}} %uint_0
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: [[phi_result_1:%\w+]] = OpPhi %float {{%\w+}} {{%\w+}} [[null_float]] {{%\w+}}
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
 ; CHECK: [[bitcast_result:%\w+]] = OpBitcast %uint %7
 ; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_46 %uint_0 [[bitcast_result]] %uint_128
-; CHECK: OpBranch %26
-; CHECK: %26 = OpLabel
-; CHECK: [[phi_result_2:%\w+]] = OpPhi %float [[phi_result_1]] %114 [[null_float]] %28
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: [[phi_result_2:%\w+]] = OpPhi %float [[phi_result_1]] {{%\w+}} [[null_float]] {{%\w+}}
 ; CHECK: OpStore %b [[phi_result_2]]
 OpReturn
 OpFunctionEnd
 )";
 
-  const std::string new_funcs = kStreamWrite4Frag + kDirectRead4;
+  const std::string new_funcs = kStreamWrite4Frag + kReadDescInit;
 
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   SinglePassRunAndMatch<InstBindlessCheckPass>(defs + main_func + new_funcs,
@@ -2643,64 +2645,64 @@ OpDecorate %images NonWritable
 %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
 OpStore %31 %29
 ; CHECK-NOT: OpStore %31 %29
-; CHECK: %132 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_0 %uint_0
-; CHECK: %133 = OpULessThan %bool %uint_0 %132
-; CHECK: OpSelectionMerge %134 None
-; CHECK: OpBranchConditional %133 %135 %136
-; CHECK: %135 = OpLabel
-; CHECK: %137 = OpLoad %uint %25
-; CHECK: OpBranch %134
-; CHECK: %136 = OpLabel
+; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0
+; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
+; CHECK: OpSelectionMerge {{%\w+}} None
+; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpLoad %uint %25
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
 ; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_47 %uint_1 %uint_0 %uint_0
-; CHECK: OpBranch %134
-; CHECK: %134 = OpLabel
-; CHECK: [[phi_result_1:%\w+]] = OpPhi %uint %137 %135 [[null_uint]] %136
-; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images %141
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: [[phi_result_1:%\w+]] = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}}
+; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images {{%\w+}}
 ; CHECK: %28 = OpLoad %13 %27
-; CHECK: %48 = OpFunctionCall %uint %inst_bindless_direct_read_2 %uint_1 %uint_1
-; CHECK: %50 = OpULessThan %bool %141 %48
-; CHECK: OpSelectionMerge %51 None
-; CHECK: OpBranchConditional %50 %52 %53
-; CHECK: %52 = OpLabel
-; CHECK: %54 = OpLoad %13 %27
-; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_1 [[phi_result_1]]
-; CHECK: %143 = OpULessThan %bool %uint_0 %142
-; CHECK: OpSelectionMerge %144 None
-; CHECK: OpBranchConditional %143 %145 %146
-; CHECK: %145 = OpLabel
-; CHECK: %147 = OpLoad %13 %27
-; CHECK: %148 = OpImageRead %v4float %147 %20
-; CHECK: OpBranch %144
-; CHECK: %146 = OpLabel
-; CHECK: %149 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_50 %uint_1 %141 %uint_0
-; CHECK: OpBranch %144
-; CHECK: %144 = OpLabel
-; CHECK: [[phi_result_2:%\w+]] = OpPhi %v4float %148 %145 [[null_v4float]] %146
-; CHECK: OpBranch %51
-; CHECK: %53 = OpLabel
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_50 %uint_0 %141 %48
-; CHECK: OpBranch %51
-; CHECK: %51 = OpLabel
-; CHECK: %113 = OpPhi %v4float [[phi_result_2]] %144 [[null_v4float]] %53
-; CHECK: %30 = OpCompositeExtract %float %113 0
-; CHECK: %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
-; CHECK: %151 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_0 %uint_0
-; CHECK: %152 = OpULessThan %bool %uint_0 %151
-; CHECK: OpSelectionMerge %153 None
-; CHECK: OpBranchConditional %152 %154 %155
-; CHECK: %154 = OpLabel
-; CHECK: OpStore %31 %30
-; CHECK: OpBranch %153
-; CHECK: %155 = OpLabel
-; CHECK: %157 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_53 %uint_1 %uint_0 %uint_0
-; CHECK: OpBranch %153
-; CHECK: %153 = OpLabel
+; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_0 %uint_1
+; CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\w+}}
+; CHECK: OpSelectionMerge {{%\w+}} None
+; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpLoad %13 %27
+; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_1 [[phi_result_1]]
+; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
+; CHECK: OpSelectionMerge {{%\w+}} None
+; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpLoad %13 %27
+; CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_50 %uint_1 {{%\w+}} %uint_0
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: [[phi_result_2:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_50 %uint_0 {{%\w+}} {{%\w+}}
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpPhi %v4float [[phi_result_2]] {{%\w+}} [[null_v4float]] {{%\w+}}
+; CHECK: {{%\w+}} = OpCompositeExtract %float {{%\w+}} 0
+; CHECK: {{%\w+}} = OpAccessChain %_ptr_Uniform_float %sbo %int_1
+; CHECK: [[desc_state_result:%\w+]] = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0
+; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 [[desc_state_result]]
+; CHECK: OpSelectionMerge {{%\w+}} None
+; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: OpStore {{%\w+}} {{%\w+}}
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_53 %uint_1 %uint_0 %uint_0
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
 OpReturn
 OpFunctionEnd
 )";
 
   const std::string new_funcs =
-      kDirectRead2 + kStreamWrite4Compute + kDirectRead4;
+      kReadBindingLength + kStreamWrite4Compute + kReadDescInit;
 
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   SinglePassRunAndMatch<InstBindlessCheckPass>(defs + main_func + new_funcs,
@@ -2796,63 +2798,64 @@ OpDecorate %images NonWritable
 %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
 OpStore %31 %29
 ; CHECK-NOT: OpStore %31 %29
-; CHECK: %133 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_0 %uint_0
-; CHECK: %134 = OpULessThan %bool %uint_0 %133
-; CHECK: OpSelectionMerge %135 None
-; CHECK: OpBranchConditional %134 %136 %137
-; CHECK: %136 = OpLabel
-; CHECK: %138 = OpLoad %uint %25
-; CHECK: OpBranch %135
-; CHECK: %137 = OpLabel
+; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0
+; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
+; CHECK: OpSelectionMerge {{%\w+}} None
+; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpLoad %uint %25
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
 ; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_48 %uint_1 %uint_0 %uint_0
-; CHECK: OpBranch %135
-; CHECK: %135 = OpLabel
-; CHECK: %142 = OpPhi %uint %138 %136 [[null_uint]] %137
-; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images %142
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}}
+; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images {{%\w+}}
 ; CHECK: %28 = OpLoad %13 %27
-; CHECK: %48 = OpFunctionCall %uint %inst_bindless_direct_read_2 %uint_1 %uint_1
-; CHECK: %50 = OpULessThan %bool %142 %48
-; CHECK: OpSelectionMerge %51 None
-; CHECK: OpBranchConditional %50 %52 %53
-; CHECK: %52 = OpLabel
-; CHECK: %54 = OpLoad %13 %27
-; CHECK: %143 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_1 %142
-; CHECK: %144 = OpULessThan %bool %uint_0 %143
-; CHECK: OpSelectionMerge %145 None
-; CHECK: OpBranchConditional %144 %146 %147
-; CHECK: %146 = OpLabel
-; CHECK: %148 = OpLoad %13 %27
-; CHECK: %149 = OpImageRead %v4float %148 %20
-; CHECK: OpBranch %145
-; CHECK: %147 = OpLabel
-; CHECK: %150 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_1 %142 %uint_0
-; CHECK: OpBranch %145
-; CHECK: %145 = OpLabel
-; CHECK: %151 = OpPhi %v4float %149 %146 [[null_v4float]] %147
-; CHECK: OpBranch %51
-; CHECK: %53 = OpLabel
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_0 %142 %48
-; CHECK: OpBranch %51
-; CHECK: %51 = OpLabel
-; CHECK: %114 = OpPhi %v4float %151 %145 [[null_v4float]] %53
-; CHECK: %30 = OpCompositeExtract %float %114 0
+; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_0 %uint_1
+; CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\w+}}
+; CHECK: OpSelectionMerge {{%\w+}} None
+; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpLoad %13 %27
+; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_1 {{%\w+}}
+; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
+; CHECK: OpSelectionMerge {{%\w+}} None
+; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpLoad %13 %27
+; CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_1 {{%\w+}} %uint_0
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_0 {{%\w+}} {{%\w+}}
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
+; CHECK: %30 = OpCompositeExtract %float {{%\w+}} 0
 ; CHECK: %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
-; CHECK: %152 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_0 %uint_0
-; CHECK: %153 = OpULessThan %bool %uint_0 %152
-; CHECK: OpSelectionMerge %154 None
-; CHECK: OpBranchConditional %153 %155 %156
-; CHECK: %155 = OpLabel
+; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0
+; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
+; CHECK: OpSelectionMerge {{%\w+}} None
+; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
 ; CHECK: OpStore %31 %30
-; CHECK: OpBranch %154
-; CHECK: %156 = OpLabel
-; CHECK: %158 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_54 %uint_1 %uint_0 %uint_0
-; CHECK: OpBranch %154
-; CHECK: %154 = OpLabel
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_54 %uint_1 %uint_0 %uint_0
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
 OpReturn
 OpFunctionEnd
 )";
 
-  const std::string new_funcs = kDirectRead2 + kStreamWrite4Ray + kDirectRead4;
+  const std::string new_funcs =
+      kReadBindingLength + kStreamWrite4Ray + kReadDescInit;
 
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   SinglePassRunAndMatch<InstBindlessCheckPass>(defs + main_func + new_funcs,
@@ -2949,63 +2952,64 @@ OpDecorate %images NonWritable
 %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
 OpStore %31 %29
 ; CHECK-NOT: OpStore %31 %29
-; CHECK: %133 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_0 %uint_0
-; CHECK: %134 = OpULessThan %bool %uint_0 %133
-; CHECK: OpSelectionMerge %135 None
-; CHECK: OpBranchConditional %134 %136 %137
-; CHECK: %136 = OpLabel
-; CHECK: %138 = OpLoad %uint %25
-; CHECK: OpBranch %135
-; CHECK: %137 = OpLabel
+; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0
+; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
+; CHECK: OpSelectionMerge {{%\w+}} None
+; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpLoad %uint %25
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
 ; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_48 %uint_1 %uint_0 %uint_0
-; CHECK: OpBranch %135
-; CHECK: %135 = OpLabel
-; CHECK: %142 = OpPhi %uint %138 %136 [[null_uint]] %137
-; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images %142
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}}
+; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images {{%\w+}}
 ; CHECK: %28 = OpLoad %13 %27
-; CHECK: %48 = OpFunctionCall %uint %inst_bindless_direct_read_2 %uint_1 %uint_1
-; CHECK: %50 = OpULessThan %bool %142 %48
-; CHECK: OpSelectionMerge %51 None
-; CHECK: OpBranchConditional %50 %52 %53
-; CHECK: %52 = OpLabel
-; CHECK: %54 = OpLoad %13 %27
-; CHECK: %143 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_1 %142
-; CHECK: %144 = OpULessThan %bool %uint_0 %143
-; CHECK: OpSelectionMerge %145 None
-; CHECK: OpBranchConditional %144 %146 %147
-; CHECK: %146 = OpLabel
-; CHECK: %148 = OpLoad %13 %27
-; CHECK: %149 = OpImageRead %v4float %148 %20
-; CHECK: OpBranch %145
-; CHECK: %147 = OpLabel
-; CHECK: %150 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_1 %142 %uint_0
-; CHECK: OpBranch %145
-; CHECK: %145 = OpLabel
-; CHECK: %151 = OpPhi %v4float %149 %146 [[null_v4float]] %147
-; CHECK: OpBranch %51
-; CHECK: %53 = OpLabel
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_0 %142 %48
-; CHECK: OpBranch %51
-; CHECK: %51 = OpLabel
-; CHECK: %114 = OpPhi %v4float %151 %145 [[null_v4float]] %53
-; CHECK: %30 = OpCompositeExtract %float %114 0
+; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_0 %uint_1
+; CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\w+}}
+; CHECK: OpSelectionMerge {{%\w+}} None
+; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpLoad %13 %27
+; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_1 {{%\w+}}
+; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
+; CHECK: OpSelectionMerge {{%\w+}} None
+; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpLoad %13 %27
+; CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_1 {{%\w+}} %uint_0
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_0 {{%\w+}} {{%\w+}}
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
+; CHECK: %30 = OpCompositeExtract %float {{%\w+}} 0
 ; CHECK: %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
-; CHECK: %152 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_0 %uint_0
-; CHECK: %153 = OpULessThan %bool %uint_0 %152
-; CHECK: OpSelectionMerge %154 None
-; CHECK: OpBranchConditional %153 %155 %156
-; CHECK: %155 = OpLabel
+; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0
+; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
+; CHECK: OpSelectionMerge {{%\w+}} None
+; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
 ; CHECK: OpStore %31 %30
-; CHECK: OpBranch %154
-; CHECK: %156 = OpLabel
-; CHECK: %158 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_54 %uint_1 %uint_0 %uint_0
-; CHECK: OpBranch %154
-; CHECK: %154 = OpLabel
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_54 %uint_1 %uint_0 %uint_0
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
 OpReturn
 OpFunctionEnd
 )";
 
-  const std::string new_funcs = kDirectRead2 + kStreamWrite4Ray + kDirectRead4;
+  const std::string new_funcs =
+      kReadBindingLength + kStreamWrite4Ray + kReadDescInit;
 
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   SinglePassRunAndMatch<InstBindlessCheckPass>(defs + main_func + new_funcs,
@@ -3102,63 +3106,64 @@ OpDecorate %images NonWritable
 %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
 OpStore %31 %29
 ; CHECK-NOT: OpStore %31 %29
-; CHECK: %133 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_0 %uint_0
-; CHECK: %134 = OpULessThan %bool %uint_0 %133
-; CHECK: OpSelectionMerge %135 None
-; CHECK: OpBranchConditional %134 %136 %137
-; CHECK: %136 = OpLabel
-; CHECK: %138 = OpLoad %uint %25
-; CHECK: OpBranch %135
-; CHECK: %137 = OpLabel
+; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0
+; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
+; CHECK: OpSelectionMerge {{%\w+}} None
+; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpLoad %uint %25
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
 ; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_48 %uint_1 %uint_0 %uint_0
-; CHECK: OpBranch %135
-; CHECK: %135 = OpLabel
-; CHECK: %142 = OpPhi %uint %138 %136 [[null_uint]] %137
-; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images %142
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}}
+; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images {{%\w+}}
 ; CHECK: %28 = OpLoad %13 %27
-; CHECK: %48 = OpFunctionCall %uint %inst_bindless_direct_read_2 %uint_1 %uint_1
-; CHECK: %50 = OpULessThan %bool %142 %48
-; CHECK: OpSelectionMerge %51 None
-; CHECK: OpBranchConditional %50 %52 %53
-; CHECK: %52 = OpLabel
-; CHECK: %54 = OpLoad %13 %27
-; CHECK: %143 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_1 %142
-; CHECK: %144 = OpULessThan %bool %uint_0 %143
-; CHECK: OpSelectionMerge %145 None
-; CHECK: OpBranchConditional %144 %146 %147
-; CHECK: %146 = OpLabel
-; CHECK: %148 = OpLoad %13 %27
-; CHECK: %149 = OpImageRead %v4float %148 %20
-; CHECK: OpBranch %145
-; CHECK: %147 = OpLabel
-; CHECK: %150 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_1 %142 %uint_0
-; CHECK: OpBranch %145
-; CHECK: %145 = OpLabel
-; CHECK: %151 = OpPhi %v4float %149 %146 [[null_v4float]] %147
-; CHECK: OpBranch %51
-; CHECK: %53 = OpLabel
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_0 %142 %48
-; CHECK: OpBranch %51
-; CHECK: %51 = OpLabel
-; CHECK: %114 = OpPhi %v4float %151 %145 [[null_v4float]] %53
-; CHECK: %30 = OpCompositeExtract %float %114 0
+; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_0 %uint_1
+; CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\w+}}
+; CHECK: OpSelectionMerge {{%\w+}} None
+; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpLoad %13 %27
+; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_1 {{%\w+}}
+; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
+; CHECK: OpSelectionMerge {{%\w+}} None
+; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpLoad %13 %27
+; CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_1 {{%\w+}} %uint_0
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_0 {{%\w+}} {{%\w+}}
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
+; CHECK: %30 = OpCompositeExtract %float {{%\w+}} 0
 ; CHECK: %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
-; CHECK: %152 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_0 %uint_0
-; CHECK: %153 = OpULessThan %bool %uint_0 %152
-; CHECK: OpSelectionMerge %154 None
-; CHECK: OpBranchConditional %153 %155 %156
-; CHECK: %155 = OpLabel
+; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0
+; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
+; CHECK: OpSelectionMerge {{%\w+}} None
+; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
 ; CHECK: OpStore %31 %30
-; CHECK: OpBranch %154
-; CHECK: %156 = OpLabel
-; CHECK: %158 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_54 %uint_1 %uint_0 %uint_0
-; CHECK: OpBranch %154
-; CHECK: %154 = OpLabel
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_54 %uint_1 %uint_0 %uint_0
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
 OpReturn
 OpFunctionEnd
 )";
 
-  const std::string new_funcs = kDirectRead2 + kStreamWrite4Ray + kDirectRead4;
+  const std::string new_funcs =
+      kReadBindingLength + kStreamWrite4Ray + kReadDescInit;
 
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   SinglePassRunAndMatch<InstBindlessCheckPass>(defs + main_func + new_funcs,
@@ -3255,63 +3260,64 @@ OpDecorate %images NonWritable
 %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
 OpStore %31 %29
 ; CHECK-NOT: OpStore %31 %29
-; CHECK: %133 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_0 %uint_0
-; CHECK: %134 = OpULessThan %bool %uint_0 %133
-; CHECK: OpSelectionMerge %135 None
-; CHECK: OpBranchConditional %134 %136 %137
-; CHECK: %136 = OpLabel
-; CHECK: %138 = OpLoad %uint %25
-; CHECK: OpBranch %135
-; CHECK: %137 = OpLabel
+; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0
+; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
+; CHECK: OpSelectionMerge {{%\w+}} None
+; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpLoad %uint %25
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
 ; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_48 %uint_1 %uint_0 %uint_0
-; CHECK: OpBranch %135
-; CHECK: %135 = OpLabel
-; CHECK: %142 = OpPhi %uint %138 %136 [[null_uint]] %137
-; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images %142
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: [[phi_result:%\w+]] = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}}
+; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images [[phi_result]]
 ; CHECK: %28 = OpLoad %13 %27
-; CHECK: %48 = OpFunctionCall %uint %inst_bindless_direct_read_2 %uint_1 %uint_1
-; CHECK: %50 = OpULessThan %bool %142 %48
-; CHECK: OpSelectionMerge %51 None
-; CHECK: OpBranchConditional %50 %52 %53
-; CHECK: %52 = OpLabel
-; CHECK: %54 = OpLoad %13 %27
-; CHECK: %143 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_1 %142
-; CHECK: %144 = OpULessThan %bool %uint_0 %143
-; CHECK: OpSelectionMerge %145 None
-; CHECK: OpBranchConditional %144 %146 %147
-; CHECK: %146 = OpLabel
-; CHECK: %148 = OpLoad %13 %27
-; CHECK: %149 = OpImageRead %v4float %148 %20
-; CHECK: OpBranch %145
-; CHECK: %147 = OpLabel
-; CHECK: %150 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_1 %142 %uint_0
-; CHECK: OpBranch %145
-; CHECK: %145 = OpLabel
-; CHECK: %151 = OpPhi %v4float %149 %146 [[null_v4float]] %147
-; CHECK: OpBranch %51
-; CHECK: %53 = OpLabel
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_0 %142 %48
-; CHECK: OpBranch %51
-; CHECK: %51 = OpLabel
-; CHECK: %114 = OpPhi %v4float %151 %145 [[null_v4float]] %53
-; CHECK: %30 = OpCompositeExtract %float %114 0
+; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_0 %uint_1
+; CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\w+}}
+; CHECK: OpSelectionMerge {{%\w+}} None
+; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpLoad %13 %27
+; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_1 {{%\w+}}
+; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
+; CHECK: OpSelectionMerge {{%\w+}} None
+; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpLoad %13 %27
+; CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_1 {{%\w+}} %uint_0
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_0 {{%\w+}} {{%\w+}}
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
+; CHECK: %30 = OpCompositeExtract %float {{%\w+}} 0
 ; CHECK: %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
-; CHECK: %152 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_0 %uint_0
-; CHECK: %153 = OpULessThan %bool %uint_0 %152
-; CHECK: OpSelectionMerge %154 None
-; CHECK: OpBranchConditional %153 %155 %156
-; CHECK: %155 = OpLabel
+; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0
+; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
+; CHECK: OpSelectionMerge {{%\w+}} None
+; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
 ; CHECK: OpStore %31 %30
-; CHECK: OpBranch %154
-; CHECK: %156 = OpLabel
-; CHECK: %158 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_54 %uint_1 %uint_0 %uint_0
-; CHECK: OpBranch %154
-; CHECK: %154 = OpLabel
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_54 %uint_1 %uint_0 %uint_0
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
 OpReturn
 OpFunctionEnd
 )";
 
-  const std::string new_funcs = kDirectRead2 + kStreamWrite4Ray + kDirectRead4;
+  const std::string new_funcs =
+      kReadBindingLength + kStreamWrite4Ray + kReadDescInit;
 
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   SinglePassRunAndMatch<InstBindlessCheckPass>(defs + main_func + new_funcs,
@@ -3408,63 +3414,64 @@ OpDecorate %images NonWritable
 %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
 OpStore %31 %29
 ; CHECK-NOT OpStore %31 %29
-; CHECK: %133 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_0 %uint_0
-; CHECK: %134 = OpULessThan %bool %uint_0 %133
-; CHECK: OpSelectionMerge %135 None
-; CHECK: OpBranchConditional %134 %136 %137
-; CHECK: %136 = OpLabel
-; CHECK: %138 = OpLoad %uint %25
-; CHECK: OpBranch %135
-; CHECK: %137 = OpLabel
+; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0
+; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
+; CHECK: OpSelectionMerge {{%\w+}} None
+; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpLoad %uint %25
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
 ; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_48 %uint_1 %uint_0 %uint_0
-; CHECK: OpBranch %135
-; CHECK: %135 = OpLabel
-; CHECK: %142 = OpPhi %uint %138 %136 [[null_uint]] %137
-; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images %142
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: [[phi_result:%\w+]] = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}}
+; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images [[phi_result]]
 ; CHECK: %28 = OpLoad %13 %27
-; CHECK: %48 = OpFunctionCall %uint %inst_bindless_direct_read_2 %uint_1 %uint_1
-; CHECK: %50 = OpULessThan %bool %142 %48
-; CHECK: OpSelectionMerge %51 None
-; CHECK: OpBranchConditional %50 %52 %53
-; CHECK: %52 = OpLabel
-; CHECK: %54 = OpLoad %13 %27
-; CHECK: %143 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_1 %142
-; CHECK: %144 = OpULessThan %bool %uint_0 %143
-; CHECK: OpSelectionMerge %145 None
-; CHECK: OpBranchConditional %144 %146 %147
-; CHECK: %146 = OpLabel
-; CHECK: %148 = OpLoad %13 %27
-; CHECK: %149 = OpImageRead %v4float %148 %20
-; CHECK: OpBranch %145
-; CHECK: %147 = OpLabel
-; CHECK: %150 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_1 %142 %uint_0
-; CHECK: OpBranch %145
-; CHECK: %145 = OpLabel
-; CHECK: %151 = OpPhi %v4float %149 %146 [[null_v4float]] %147
-; CHECK: OpBranch %51
-; CHECK: %53 = OpLabel
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_0 %142 %48
-; CHECK: OpBranch %51
-; CHECK: %51 = OpLabel
-; CHECK: %114 = OpPhi %v4float %151 %145 [[null_v4float]] %53
-; CHECK: %30 = OpCompositeExtract %float %114 0
+; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_0 %uint_1
+; CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\w+}}
+; CHECK: OpSelectionMerge {{%\w+}} None
+; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpLoad %13 %27
+; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_1 {{%\w+}}
+; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
+; CHECK: OpSelectionMerge {{%\w+}} None
+; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpLoad %13 %27
+; CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_1 {{%\w+}} %uint_0
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_0 {{%\w+}} {{%\w+}}
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
+; CHECK: %30 = OpCompositeExtract %float {{%\w+}} 0
 ; CHECK: %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
-; CHECK: %152 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_0 %uint_0
-; CHECK: %153 = OpULessThan %bool %uint_0 %152
-; CHECK: OpSelectionMerge %154 None
-; CHECK: OpBranchConditional %153 %155 %156
-; CHECK: %155 = OpLabel
+; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0
+; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
+; CHECK: OpSelectionMerge {{%\w+}} None
+; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
 ; CHECK: OpStore %31 %30
-; CHECK: OpBranch %154
-; CHECK: %156 = OpLabel
-; CHECK: %158 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_54 %uint_1 %uint_0 %uint_0
-; CHECK: OpBranch %154
-; CHECK: %154 = OpLabel
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_54 %uint_1 %uint_0 %uint_0
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
 OpReturn
 OpFunctionEnd
 )";
 
-  const std::string new_funcs = kDirectRead2 + kStreamWrite4Ray + kDirectRead4;
+  const std::string new_funcs =
+      kReadBindingLength + kStreamWrite4Ray + kReadDescInit;
 
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   SinglePassRunAndMatch<InstBindlessCheckPass>(defs + main_func + new_funcs,
@@ -3560,63 +3567,64 @@ OpDecorate %images NonWritable
 %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
 OpStore %31 %29
 ; CHECK-NOT: OpStore %31 %29
-; CHECK: %133 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_0 %uint_0
-; CHECK: %134 = OpULessThan %bool %uint_0 %133
-; CHECK: OpSelectionMerge %135 None
-; CHECK: OpBranchConditional %134 %136 %137
-; CHECK: %136 = OpLabel
-; CHECK: %138 = OpLoad %uint %25
-; CHECK: OpBranch %135
-; CHECK: %137 = OpLabel
+; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0
+; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
+; CHECK: OpSelectionMerge {{%\w+}} None
+; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpLoad %uint %25
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
 ; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_48 %uint_1 %uint_0 %uint_0
-; CHECK: OpBranch %135
-; CHECK: %135 = OpLabel
-; CHECK: %142 = OpPhi %uint %138 %136 [[null_uint]] %137
-; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images %142
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}}
+; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images {{%\w+}}
 ; CHECK: %28 = OpLoad %13 %27
-; CHECK: %48 = OpFunctionCall %uint %inst_bindless_direct_read_2 %uint_1 %uint_1
-; CHECK: %50 = OpULessThan %bool %142 %48
-; CHECK: OpSelectionMerge %51 None
-; CHECK: OpBranchConditional %50 %52 %53
-; CHECK: %52 = OpLabel
-; CHECK: %54 = OpLoad %13 %27
-; CHECK: %143 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_1 %142
-; CHECK: %144 = OpULessThan %bool %uint_0 %143
-; CHECK: OpSelectionMerge %145 None
-; CHECK: OpBranchConditional %144 %146 %147
-; CHECK: %146 = OpLabel
-; CHECK: %148 = OpLoad %13 %27
-; CHECK: %149 = OpImageRead %v4float %148 %20
-; CHECK: OpBranch %145
-; CHECK: %147 = OpLabel
-; CHECK: %150 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_1 %142 %uint_0
-; CHECK: OpBranch %145
-; CHECK: %145 = OpLabel
-; CHECK: %151 = OpPhi %v4float %149 %146 [[null_v4float]] %147
-; CHECK: OpBranch %51
-; CHECK: %53 = OpLabel
-; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_0 %142 %48
-; CHECK: OpBranch %51
-; CHECK: %51 = OpLabel
-; CHECK: %114 = OpPhi %v4float %151 %145 [[null_v4float]] %53
-; CHECK: %30 = OpCompositeExtract %float %114 0
+; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_0 %uint_1
+; CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\w+}}
+; CHECK: OpSelectionMerge {{%\w+}} None
+; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpLoad %13 %27
+; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_1 {{%\w+}}
+; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
+; CHECK: OpSelectionMerge {{%\w+}} None
+; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpLoad %13 %27
+; CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_1 {{%\w+}} %uint_0
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_0 {{%\w+}} {{%\w+}}
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
+; CHECK: %30 = OpCompositeExtract %float {{%\w+}} 0
 ; CHECK: %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
-; CHECK: %152 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_0 %uint_0
-; CHECK: %153 = OpULessThan %bool %uint_0 %152
-; CHECK: OpSelectionMerge %154 None
-; CHECK: OpBranchConditional %153 %155 %156
-; CHECK: %155 = OpLabel
+; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0
+; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
+; CHECK: OpSelectionMerge {{%\w+}} None
+; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
 ; CHECK: OpStore %31 %30
-; CHECK: OpBranch %154
-; CHECK: %156 = OpLabel
-; CHECK: %158 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_54 %uint_1 %uint_0 %uint_0
-; CHECK: OpBranch %154
-; CHECK: %154 = OpLabel
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_54 %uint_1 %uint_0 %uint_0
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
 OpReturn
 OpFunctionEnd
 )";
 
-  const std::string new_funcs = kDirectRead2 + kStreamWrite4Ray + kDirectRead4;
+  const std::string new_funcs =
+      kReadBindingLength + kStreamWrite4Ray + kReadDescInit;
 
   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   SinglePassRunAndMatch<InstBindlessCheckPass>(defs + main_func + new_funcs,
@@ -3696,7 +3704,7 @@ OpDecorate %outColor Location 0
 )" + kOutputDecorations + R"(
 ; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
 )" + kInputDecorations + R"(
-; CHECK: OpDecorate %151 NonUniform
+; CHECK: OpDecorate [[desc_state_result:%\w+]] NonUniform
 %void = OpTypeVoid
 %3 = OpTypeFunction %void
 %int = OpTypeInt 32 1
@@ -3761,35 +3769,35 @@ OpStore %x %36
 %50 = OpImageSampleImplicitLod %v4float %41 %49
 %51 = OpCompositeExtract %float %50 0
 ; CHECK-NOT: %51 = OpCompositeExtract %float %50 0
-; CHECK: %157 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_0 %uint_0
-; CHECK: %158 = OpULessThan %bool %uint_0 %157
-; CHECK: OpSelectionMerge %159 None
-; CHECK: OpBranchConditional %158 %160 %161
-; CHECK: %160 = OpLabel
-; CHECK: %162 = OpLoad %v2float %47
-; CHECK: OpBranch %159
-; CHECK: %161 = OpLabel
+; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0
+; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
+; CHECK: OpSelectionMerge {{%\w+}} None
+; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpLoad %v2float %47
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
 ; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_87 %uint_1 %uint_0 %uint_0
-; CHECK: OpBranch %159
-; CHECK: %159 = OpLabel
-; CHECK: %166 = OpPhi %v2float %162 %160 [[null_v2float]] %161
-; CHECK: %49 = OpFMul %v2float %42 %166
-; CHECK: %167 = OpSampledImage %27 %39 %40
-; CHECK: %168 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_2 %uint_0
-; CHECK: %169 = OpULessThan %bool %uint_0 %168
-; CHECK: OpSelectionMerge %170 None
-; CHECK: OpBranchConditional %169 %171 %172
-; CHECK: %171 = OpLabel
-; CHECK: %173 = OpLoad %13 %uniformTex
-; CHECK: %174 = OpSampledImage %27 %173 %40
-; CHECK: %175 = OpImageSampleImplicitLod %v4float %174 %49
-; CHECK: OpBranch %170
-; CHECK: %172 = OpLabel
-; CHECK: %177 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_89 %uint_1 %uint_0 %uint_0
-; CHECK: OpBranch %170
-; CHECK: %170 = OpLabel
-; CHECK: %178 = OpPhi %v4float %175 %171 [[null_v4float]] %172
-; CHECK: %51 = OpCompositeExtract %float %178 0
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpPhi %v2float {{%\w+}} {{%\w+}} [[null_v2float]] {{%\w+}}
+; CHECK: %49 = OpFMul %v2float %42 {{%\w+}}
+; CHECK: {{%\w+}} = OpSampledImage %27 %39 %40
+; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_2 %uint_0
+; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
+; CHECK: OpSelectionMerge {{%\w+}} None
+; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpLoad %13 %uniformTex
+; CHECK: {{%\w+}} = OpSampledImage %27 {{%\w+}} %40
+; CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %49
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_89 %uint_1 %uint_0 %uint_0
+; CHECK: OpBranch {{%\w+}}
+; CHECK: {{%\w+}} = OpLabel
+; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
+; CHECK: %51 = OpCompositeExtract %float {{%\w+}} 0
 OpStore %y %51
 %54 = OpLoad %float %x
 %55 = OpLoad %float %y
@@ -3799,7 +3807,7 @@ OpReturn
 OpFunctionEnd
 )";
 
-  const std::string new_funcs = kStreamWrite4Frag + kDirectRead4;
+  const std::string new_funcs = kStreamWrite4Frag + kReadDescInit;
 
   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   SinglePassRunAndMatch<InstBindlessCheckPass>(defs + main_func + new_funcs,
@@ -3919,7 +3927,7 @@ TEST_F(InstBindlessTest, MultipleUniformNonAggregateRefsNoDescInit) {
  ;CHECK:        [[null_v2float:%\w+]] = OpConstantNull %v2float
      %MainPs = OpFunction %void None %3
           %5 = OpLabel
- ;CHECK: %140 = OpFunctionCall %uint %inst_bindless_direct_read_3 %uint_1 %uint_1 %uint_0
+ ;CHECK: [[desc_state_result:%\w+]] = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_1 %uint_0
  ;CHECK:        OpBranch %117
  ;CHECK: %117 = OpLabel
  ;CHECK:        OpBranch %116
@@ -3934,40 +3942,40 @@ TEST_F(InstBindlessTest, MultipleUniformNonAggregateRefsNoDescInit) {
          %86 = OpAccessChain %_ptr_Uniform_v2float %__0 %int_0
          %87 = OpLoad %v2float %86
  ;CHECK-NOT:     %87 = OpLoad %v2float %86
- ;CHECK:        %119 = OpIAdd %uint %uint_0 %uint_7
- ;CHECK:        %141 = OpULessThan %bool %119 %140
- ;CHECK:               OpSelectionMerge %143 None
- ;CHECK:               OpBranchConditional %141 %144 %145
- ;CHECK:        %144 = OpLabel
- ;CHECK:        %146 = OpLoad %v2float %86
- ;CHECK:               OpBranch %143
- ;CHECK:        %145 = OpLabel
- ;CHECK:        {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_71 %uint_4 %uint_0 %119 %140
- ;CHECK:               OpBranch %143
- ;CHECK:        %143 = OpLabel
- ;CHECK:        %203 = OpPhi %v2float %146 %144 [[null_v2float]] %145
+ ;CHECK: %119 = OpIAdd %uint %uint_0 %uint_7
+ ;CHECK: {{%\w+}} = OpULessThan %bool %119 [[desc_state_result]]
+ ;CHECK: OpSelectionMerge {{%\w+}} None
+ ;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+ ;CHECK: {{%\w+}} = OpLabel
+ ;CHECK: {{%\w+}} = OpLoad %v2float %86
+ ;CHECK: OpBranch {{%\w+}}
+ ;CHECK: {{%\w+}} = OpLabel
+ ;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_71 %uint_4 %uint_0 %119 {{%\w+}}
+ ;CHECK: OpBranch {{%\w+}}
+ ;CHECK: {{%\w+}} = OpLabel
+ ;CHECK: {{%\w+}} = OpPhi %v2float {{%\w+}} {{%\w+}} [[null_v2float]] {{%\w+}}
                OpBranch %91
          %88 = OpLabel
          %89 = OpAccessChain %_ptr_Uniform_v2float %__0 %int_1
          %90 = OpLoad %v2float %89
  ;CHECK-NOT:     %90 = OpLoad %v2float %89
- ;CHECK:        %204 = OpIAdd %uint %uint_8 %uint_7
- ;CHECK:        %205 = OpULessThan %bool %204 %140
- ;CHECK:               OpSelectionMerge %206 None
- ;CHECK:               OpBranchConditional %205 %207 %208
- ;CHECK:        %207 = OpLabel
- ;CHECK:        %209 = OpLoad %v2float %89
- ;CHECK:               OpBranch %206
- ;CHECK:        %208 = OpLabel
- ;CHECK:        %211 = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_75 %uint_4 %uint_0 %204 %140
- ;CHECK:               OpBranch %206
- ;CHECK:        %206 = OpLabel
- ;CHECK:        %212 = OpPhi %v2float %209 %207 [[null_v2float]] %208
+ ;CHECK: {{%\w+}} = OpIAdd %uint %uint_8 %uint_7
+ ;CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\w+}}
+ ;CHECK: OpSelectionMerge {{%\w+}} None
+ ;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+ ;CHECK: {{%\w+}} = OpLabel
+ ;CHECK: {{%\w+}} = OpLoad %v2float %89
+ ;CHECK: OpBranch {{%\w+}}
+ ;CHECK: {{%\w+}} = OpLabel
+ ;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_75 %uint_4 %uint_0 {{%\w+}} {{%\w+}}
+ ;CHECK: OpBranch {{%\w+}}
+ ;CHECK: {{%\w+}} = OpLabel
+ ;CHECK: {{%\w+}} = OpPhi %v2float {{%\w+}} {{%\w+}} [[null_v2float]] {{%\w+}}
                OpBranch %91
          %91 = OpLabel
         %115 = OpPhi %v2float %87 %85 %90 %88
  ;CHECK-NOT:       %115 = OpPhi %v2float %87 %85 %90 %88
- ;CHECK:           %115 = OpPhi %v2float %203 %143 %212 %206
+ ;CHECK: %115 = OpPhi %v2float {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}}
          %95 = OpFAdd %v2float %69 %115
          %96 = OpLoad %49 %g_tColor
          %97 = OpLoad %53 %g_sAniso
@@ -3976,7 +3984,7 @@ TEST_F(InstBindlessTest, MultipleUniformNonAggregateRefsNoDescInit) {
                OpStore %_entryPointOutput_vColor %100
                OpReturn
                OpFunctionEnd
-)" + kDirectRead3 + kStreamWrite5Frag;
+)" + kReadDescInit + kStreamWrite5Frag;
   // clang-format on
 
   SetTargetEnv(SPV_ENV_VULKAN_1_2);
@@ -4106,35 +4114,35 @@ TEST_F(InstBindlessTest, UniformArrayRefNoDescInit) {
 ;CHECK:        [[null_v2float:%\w+]] = OpConstantNull %v2float
      %MainPs = OpFunction %void None %3
           %5 = OpLabel
-;CHECK:        %123 = OpFunctionCall %uint %inst_bindless_direct_read_3 %uint_1 %uint_2 %uint_0
-;CHECK:               OpBranch %93
-;CHECK:         %93 = OpLabel
-;CHECK:               OpBranch %92
-;CHECK:         %92 = OpLabel
+;CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_2 %uint_0
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
          %66 = OpLoad %v2float %i_vTextureCoords
          %79 = OpAccessChain %_ptr_PushConstant_uint %__0 %int_0
          %80 = OpLoad %uint %79
          %81 = OpAccessChain %_ptr_Uniform_v2float %_ %int_0 %80 %int_2
          %82 = OpLoad %v2float %81
 ;CHECK-NOT:     %82 = OpLoad %v2float %81
-;CHECK:         %96 = OpIMul %uint %uint_80 %80
-;CHECK:         %97 = OpIAdd %uint %uint_0 %96
-;CHECK:         %99 = OpIAdd %uint %97 %uint_64
-;CHECK:        %101 = OpIAdd %uint %99 %uint_7
-;CHECK:        %125 = OpULessThan %bool %101 %123
-;CHECK:               OpSelectionMerge %127 None
-;CHECK:               OpBranchConditional %125 %128 %129
-;CHECK:        %128 = OpLabel
-;CHECK:        %130 = OpLoad %v2float %81
-;CHECK:               OpBranch %127
-;CHECK:        %129 = OpLabel
-;CHECK:        {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_78 %uint_4 %uint_0 %101 %123
-;CHECK:               OpBranch %127
-;CHECK:        %127 = OpLabel
-;CHECK:        %186 = OpPhi %v2float %130 %128 [[null_v2float]] %129
+;CHECK: {{%\w+}} = OpIMul %uint %uint_80 %80
+;CHECK: {{%\w+}} = OpIAdd %uint %uint_0 {{%\w+}}
+;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_64
+;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_7
+;CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\w+}}
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpLoad %v2float %81
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_78 %uint_4 %uint_0 {{%\w+}} {{%\w+}}
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpPhi %v2float {{%\w+}} {{%\w+}} [[null_v2float]] {{%\w+}}
          %86 = OpFAdd %v2float %66 %82
 ;CHECK-NOT:         %86 = OpFAdd %v2float %66 %82
-;CHECK:             %86 = OpFAdd %v2float %66 %186
+;CHECK:             %86 = OpFAdd %v2float %66 {{%\w+}}
          %87 = OpLoad %46 %g_tColor
          %88 = OpLoad %50 %g_sAniso
          %89 = OpSampledImage %54 %87 %88
@@ -4142,7 +4150,7 @@ TEST_F(InstBindlessTest, UniformArrayRefNoDescInit) {
                OpStore %_entryPointOutput_vColor %91
                OpReturn
                OpFunctionEnd
-)" + kDirectRead3 + kStreamWrite5Frag;
+)" + kReadDescInit + kStreamWrite5Frag;
   // clang-format on
 
   SetTargetEnv(SPV_ENV_VULKAN_1_2);
@@ -4237,19 +4245,19 @@ TEST_F(InstBindlessTest, UniformArrayRefWithDescInit) {
 %_ptr_Output_v4float = OpTypePointer Output %v4float
 %_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output
 )" + kInputGlobals + kOutputGlobals + R"(
-;CHECK:%_ptr_Input_v4float = OpTypePointer Input %v4float
-;CHECK:%gl_FragCoord = OpVariable %_ptr_Input_v4float Input
-;CHECK:     %v4uint = OpTypeVector %uint 4
-;CHECK:        [[null_v2float:%\w+]] = OpConstantNull %v2float
-;CHECK:        [[null_v4float:%\w+]] = OpConstantNull %v4float
+;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
+;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
+;CHECK: %v4uint = OpTypeVector %uint 4
+;CHECK: [[null_v2float:%\w+]] = OpConstantNull %v2float
+;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
      %MainPs = OpFunction %void None %3
           %5 = OpLabel
-;CHECK:        %126 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_2 %uint_0
-;CHECK:        %191 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_0 %uint_0
-;CHECK:               OpBranch %93
-;CHECK:         %93 = OpLabel
-;CHECK:               OpBranch %92
-;CHECK:         %92 = OpLabel
+;CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_2 %uint_0
+;CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
          %66 = OpLoad %v2float %i_vTextureCoords
          %79 = OpAccessChain %_ptr_PushConstant_uint %__0 %int_0
          %80 = OpLoad %uint %79
@@ -4258,22 +4266,22 @@ TEST_F(InstBindlessTest, UniformArrayRefWithDescInit) {
          %86 = OpFAdd %v2float %66 %82
 ;CHECK-NOT: %82 = OpLoad %v2float %81
 ;CHECK-NOT: %86 = OpFAdd %v2float %66 %82
-;CHECK:         %96 = OpIMul %uint %uint_80 %80
-;CHECK:         %97 = OpIAdd %uint %uint_0 %96
-;CHECK:         %99 = OpIAdd %uint %97 %uint_64
-;CHECK:        %101 = OpIAdd %uint %99 %uint_7
-;CHECK:        %128 = OpULessThan %bool %101 %126
-;CHECK:               OpSelectionMerge %130 None
-;CHECK:               OpBranchConditional %128 %131 %132
-;CHECK:        %131 = OpLabel
-;CHECK:        %133 = OpLoad %v2float %81
-;CHECK:               OpBranch %130
-;CHECK:        %132 = OpLabel
-;CHECK:        {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_78 %uint_4 %uint_0 %101 %126
-;CHECK:               OpBranch %130
-;CHECK:        %130 = OpLabel
-;CHECK:        %190 = OpPhi %v2float %133 %131 [[null_v2float]] %132
-;CHECK:         %86 = OpFAdd %v2float %66 %190
+;CHECK: {{%\w+}} = OpIMul %uint %uint_80 %80
+;CHECK: {{%\w+}} = OpIAdd %uint %uint_0 {{%\w+}}
+;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_64
+;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_7
+;CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\w+}}
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpLoad %v2float %81
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_78 %uint_4 %uint_0 {{%\w+}} {{%\w+}}
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpPhi %v2float {{%\w+}} {{%\w+}} [[null_v2float]] {{%\w+}}
+;CHECK: %86 = OpFAdd %v2float %66 {{%\w+}}
          %87 = OpLoad %46 %g_tColor
          %88 = OpLoad %50 %g_sAniso
          %89 = OpSampledImage %54 %87 %88
@@ -4281,23 +4289,23 @@ TEST_F(InstBindlessTest, UniformArrayRefWithDescInit) {
                OpStore %_entryPointOutput_vColor %91
 ;CHECK-NOT: %91 = OpImageSampleImplicitLod %v4float %89 %86
 ;CHECK-NOT:       OpStore %_entryPointOutput_vColor %91
-;CHECK:        %192 = OpULessThan %bool %uint_0 %191
-;CHECK:               OpSelectionMerge %193 None
-;CHECK:               OpBranchConditional %192 %194 %195
-;CHECK:        %194 = OpLabel
-;CHECK:        %196 = OpLoad %46 %g_tColor
-;CHECK:        %197 = OpSampledImage %54 %196 %88
-;CHECK:        %198 = OpImageSampleImplicitLod %v4float %197 %86
-;CHECK:               OpBranch %193
-;CHECK:        %195 = OpLabel
-;CHECK:        {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_83 %uint_1 %uint_0 %uint_0 %uint_0
-;CHECK:               OpBranch %193
-;CHECK:        %193 = OpLabel
-;CHECK:        %202 = OpPhi %v4float %198 %194 [[null_v4float]] %195
-;CHECK:               OpStore %_entryPointOutput_vColor %202
+;CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpLoad %46 %g_tColor
+;CHECK: {{%\w+}} = OpSampledImage %54 {{%\w+}} %88
+;CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %86
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_83 %uint_1 %uint_0 %uint_0 %uint_0
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
+;CHECK: OpStore %_entryPointOutput_vColor {{%\w+}}
                OpReturn
                OpFunctionEnd
-)" + kDirectRead4 + kStreamWrite5Frag;
+)" + kReadDescInit + kStreamWrite5Frag;
   // clang-format on
 
   SetTargetEnv(SPV_ENV_VULKAN_1_2);
@@ -4394,38 +4402,38 @@ TEST_F(InstBindlessTest, Descriptor16BitIdxRef) {
 ;CHECK-NOT:         %38 = OpImageSampleImplicitLod %v4float %37 %31
 ;CHECK-NOT:               OpStore %_entryPointOutput_vColor %38
 ;CHECK:         %41 = OpUConvert %uint %33
-;CHECK:         %43 = OpULessThan %bool %41 %uint_128
-;CHECK:               OpSelectionMerge %44 None
-;CHECK:               OpBranchConditional %43 %45 %46
-;CHECK:         %45 = OpLabel
-;CHECK:         %47 = OpLoad %16 %34
-;CHECK:         %48 = OpSampledImage %27 %47 %36
-;CHECK:        %109 = OpUConvert %uint %33
-;CHECK:        %131 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_0 %109
-;CHECK:        %132 = OpULessThan %bool %uint_0 %131
-;CHECK:               OpSelectionMerge %133 None
-;CHECK:               OpBranchConditional %132 %134 %135
-;CHECK:        %134 = OpLabel
-;CHECK:        %136 = OpLoad %16 %34
-;CHECK:        %137 = OpSampledImage %27 %136 %36
-;CHECK:        %138 = OpImageSampleImplicitLod %v4float %137 %31
-;CHECK:               OpBranch %133
-;CHECK:        %135 = OpLabel
-;CHECK:        %139 = OpUConvert %uint %33
-;CHECK:        %140 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_60 %uint_1 %139 %uint_0
-;CHECK:               OpBranch %133
-;CHECK:        %133 = OpLabel
-;CHECK:        [[phi_result_1:%\w+]] = OpPhi %v4float %138 %134 [[null_v4float]] %135
+;CHECK:         {{%\w+}} = OpULessThan %bool %41 %uint_128
+;CHECK:               OpSelectionMerge {{%\w+}} None
+;CHECK:               OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK:        {{%\w+}} = OpLabel
+;CHECK:        {{%\w+}} = OpLoad %16 %34
+;CHECK:        {{%\w+}} = OpSampledImage %27 {{%\w+}} %36
+;CHECK:        {{%\w+}} = OpUConvert %uint %33
+;CHECK:        {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 {{%\w+}}
+;CHECK:        {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}}
+;CHECK:               OpSelectionMerge {{%\w+}} None
+;CHECK:               OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK:        {{%\w+}} = OpLabel
+;CHECK:        {{%\w+}} = OpLoad %16 %34
+;CHECK:        {{%\w+}} = OpSampledImage %27 {{%\w+}} %36
+;CHECK:        {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %31
+;CHECK:               OpBranch {{%\w+}}
+;CHECK:        {{%\w+}} = OpLabel
+;CHECK:        {{%\w+}} = OpUConvert %uint %33
+;CHECK:        {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_60 %uint_1 {{%\w+}} %uint_0
+;CHECK:               OpBranch {{%\w+}}
+;CHECK:        {{%\w+}} = OpLabel
+;CHECK:        [[phi_result_1:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
 ;CHECK:               OpBranch %44
 ;CHECK:         %46 = OpLabel
 ;CHECK:        {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_60 %uint_0 %41 %uint_128
 ;CHECK:               OpBranch %44
 ;CHECK:         %44 = OpLabel
-;CHECK:        [[phi_result_2:%\w+]] = OpPhi %v4float [[phi_result_1]] %133 [[null_v4float]] %46
+;CHECK:        [[phi_result_2:%\w+]] = OpPhi %v4float [[phi_result_1]] {{%\w+}} [[null_v4float]] %46
 ;CHECK:               OpStore %_entryPointOutput_vColor [[phi_result_2]]
                OpReturn
                OpFunctionEnd
-)" + kStreamWrite4Frag + kDirectRead4;
+)" + kStreamWrite4Frag + kReadDescInit;
   // clang-format on
 
   SetTargetEnv(SPV_ENV_VULKAN_1_2);
@@ -4558,11 +4566,11 @@ TEST_F(InstBindlessTest, UniformArray16bitIdxRef) {
 ;CHECK:        [[null_v2float:%\w+]] = OpConstantNull %v2float
      %MainPs = OpFunction %void None %14
          %37 = OpLabel
-;CHECK:         %79 = OpFunctionCall %uint %inst_bindless_direct_read_3 %uint_1 %uint_0 %uint_0
-;CHECK:               OpBranch %49
-;CHECK:         %49 = OpLabel
-;CHECK:               OpBranch %48
-;CHECK:         %48 = OpLabel
+;CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
          %38 = OpLoad %v2float %i_vTextureCoords
          %39 = OpAccessChain %_ptr_PushConstant_ushort %__0 %int_0
          %40 = OpLoad %ushort %39
@@ -4571,23 +4579,23 @@ TEST_F(InstBindlessTest, UniformArray16bitIdxRef) {
          %43 = OpFAdd %v2float %38 %42
 ;CHECK-NOT:     %42 = OpLoad %v2float %41
 ;CHECK-NOT:     %43 = OpFAdd %v2float %38 %42
-;CHECK:         %52 = OpUConvert %uint %40
-;CHECK:         %53 = OpIMul %uint %uint_80 %52
-;CHECK:         %54 = OpIAdd %uint %uint_0 %53
-;CHECK:         %56 = OpIAdd %uint %54 %uint_64
-;CHECK:         %58 = OpIAdd %uint %56 %uint_7
-;CHECK:         %81 = OpULessThan %bool %58 %79
-;CHECK:               OpSelectionMerge %83 None
-;CHECK:               OpBranchConditional %81 %84 %85
-;CHECK:         %84 = OpLabel
-;CHECK:         %86 = OpLoad %v2float %41
-;CHECK:               OpBranch %83
-;CHECK:         %85 = OpLabel
-;CHECK:        {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_81 %uint_4 %uint_0 %58 %79
-;CHECK:               OpBranch %83
-;CHECK:         %83 = OpLabel
-;CHECK:        %143 = OpPhi %v2float %86 %84 [[null_v2float]] %85
-;CHECK:         %43 = OpFAdd %v2float %38 %143
+;CHECK: {{%\w+}} = OpUConvert %uint %40
+;CHECK: {{%\w+}} = OpIMul %uint %uint_80 {{%\w+}}
+;CHECK: {{%\w+}} = OpIAdd %uint %uint_0 {{%\w+}}
+;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_64
+;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_7
+;CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\w+}}
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpLoad %v2float %41
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_81 %uint_4 %uint_0 {{%\w+}} {{%\w+}}
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpPhi %v2float {{%\w+}} {{%\w+}} [[null_v2float]] {{%\w+}}
+;CHECK: %43 = OpFAdd %v2float %38 {{%\w+}}
          %44 = OpLoad %30 %g_tColor
          %45 = OpLoad %32 %g_sAniso
          %46 = OpSampledImage %34 %44 %45
@@ -4595,7 +4603,7 @@ TEST_F(InstBindlessTest, UniformArray16bitIdxRef) {
                OpStore %_entryPointOutput_vColor %47
                OpReturn
                OpFunctionEnd
-               )" + kDirectRead3 + kStreamWrite5Frag;
+               )" + kReadDescInit + kStreamWrite5Frag;
   // clang-format on
 
   SetTargetEnv(SPV_ENV_VULKAN_1_2);
@@ -4650,14 +4658,15 @@ TEST_F(InstBindlessTest, UniformMatrixRefRowMajor) {
                OpDecorate %_ Binding 0
                OpDecorate %21 RelaxedPrecision
 ;CHECK-NOT:           OpDecorate %21 RelaxedPrecision
-;CHECK:               OpDecorate %116 RelaxedPrecision
+;CHECK: OpDecorate %v_vtxResult RelaxedPrecision
+;CHECK: OpDecorate [[phi_result:%\w+]] RelaxedPrecision
                OpDecorate %a_position Location 0
-;CHECK:               OpDecorate %_runtimearr_uint ArrayStride 4
+;CHECK: OpDecorate %_runtimearr_uint ArrayStride 4
 )" + kInputDecorations + R"(
-;CHECK:               OpDecorate %61 RelaxedPrecision
+;CHECK: OpDecorate [[load_result:%\w+]] RelaxedPrecision
 )" + kOutputDecorations + R"(
-;CHECK:               OpDecorate %gl_VertexIndex BuiltIn VertexIndex
-;CHECK:               OpDecorate %gl_InstanceIndex BuiltIn InstanceIndex
+;CHECK: OpDecorate %gl_VertexIndex BuiltIn VertexIndex
+;CHECK: OpDecorate %gl_InstanceIndex BuiltIn InstanceIndex
        %void = OpTypeVoid
           %3 = OpTypeFunction %void
       %float = OpTypeFloat 32
@@ -4684,36 +4693,36 @@ TEST_F(InstBindlessTest, UniformMatrixRefRowMajor) {
 ;CHECK: [[null_float:%\w+]] = OpConstantNull %float
        %main = OpFunction %void None %3
           %5 = OpLabel
-;CHECK:         %55 = OpFunctionCall %uint %inst_bindless_direct_read_3 %uint_1 %uint_0 %uint_0
-;CHECK:               OpBranch %26
-;CHECK:         %26 = OpLabel
-;CHECK:               OpBranch %25
-;CHECK:         %25 = OpLabel
+;CHECK: [[desc_state:%\w+]] = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
          %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:        {{\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_45 %uint_4 %uint_0 %35 %55
-;CHECK:               OpBranch %58
-;CHECK:         %58 = OpLabel
-;CHECK:        %116 = OpPhi %float %61 %59 [[null_float]] %60
+;CHECK: {{%\w+}} = OpIMul %uint %uint_4 %int_2
+;CHECK: {{%\w+}} = OpIAdd %uint %uint_0 {{%\w+}}
+;CHECK: {{%\w+}} = OpIMul %uint %uint_16 %uint_1
+;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3
+;CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} [[desc_state]]
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: [[load_result]] = OpLoad %float %20
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_45 %uint_4 %uint_0 {{%\w+}} {{%\w+}}
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: [[phi_result]] = OpPhi %float [[load_result]] {{%\w+}} [[null_float]] {{%\w+}}
                OpStore %v_vtxResult %21
-;CHECK-NOT:           OpStore %v_vtxResult %21
-;CHECK:               OpStore %v_vtxResult %116
+;CHECK-NOT:    OpStore %v_vtxResult %21
+;CHECK:  OpStore %v_vtxResult [[phi_result]]
                OpReturn
                OpFunctionEnd
-               )" + kDirectRead3 + kStreamWrite5Vert;
+               )" + kReadDescInit + kStreamWrite5Vert;
   // clang-format on
 
   SetTargetEnv(SPV_ENV_VULKAN_1_2);
@@ -4767,15 +4776,16 @@ TEST_F(InstBindlessTest, UniformMatrixRefColumnMajor) {
                OpDecorate %_ DescriptorSet 0
                OpDecorate %_ Binding 0
                OpDecorate %21 RelaxedPrecision
-;CHECK-NOT:           OpDecorate %21 RelaxedPrecision
-;CHECK:               OpDecorate %115 RelaxedPrecision
+;CHECK-NOT:    OpDecorate %21 RelaxedPrecision
+;CHECK: OpDecorate %v_vtxResult RelaxedPrecision
+;CHECK: OpDecorate [[phi_result:%\w+]] RelaxedPrecision
                OpDecorate %a_position Location 0
-;CHECK:               OpDecorate %_runtimearr_uint ArrayStride 4
+;CHECK: OpDecorate %_runtimearr_uint ArrayStride 4
 )" + kInputDecorations + R"(
-;CHECK:               OpDecorate %61 RelaxedPrecision
+;CHECK: OpDecorate [[load_result:%\w+]] RelaxedPrecision
 )" + kOutputDecorations + R"(
-;CHECK:               OpDecorate %gl_VertexIndex BuiltIn VertexIndex
-;CHECK:               OpDecorate %gl_InstanceIndex BuiltIn InstanceIndex
+;CHECK: OpDecorate %gl_VertexIndex BuiltIn VertexIndex
+;CHECK: OpDecorate %gl_InstanceIndex BuiltIn InstanceIndex
        %void = OpTypeVoid
           %3 = OpTypeFunction %void
       %float = OpTypeFloat 32
@@ -4802,36 +4812,36 @@ TEST_F(InstBindlessTest, UniformMatrixRefColumnMajor) {
 ;CHECK: [[null_float:%\w+]] = OpConstantNull %float
 %main = OpFunction %void None %3
           %5 = OpLabel
-;CHECK:         %55 = OpFunctionCall %uint %inst_bindless_direct_read_3 %uint_1 %uint_0 %uint_0
-;CHECK:               OpBranch %26
-;CHECK:         %26 = OpLabel
-;CHECK:               OpBranch %25
-;CHECK:         %25 = OpLabel
+;CHECK: [[desc_state:%\w+]] = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0
+;CHECK: OpBranch %26
+;CHECK: %26 = OpLabel
+;CHECK: OpBranch %25
+;CHECK: %25 = OpLabel
          %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:    {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_45 %uint_4 %uint_0 %35 %55
-;CHECK:               OpBranch %58
-;CHECK:         %58 = OpLabel
-;CHECK:        %115 = OpPhi %float %61 %59 [[null_float]] %60
+;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: {{%\w+}} = OpULessThan %bool %35 [[desc_state]]
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK:[[load_result]] = OpLoad %float %20
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_45 %uint_4 %uint_0 %35 {{%\w+}}
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: [[phi_result]] = OpPhi %float [[load_result]] {{%\w+}} [[null_float]] {{%\w+}}
                OpStore %v_vtxResult %21
 ;CHECK-NOT:           OpStore %v_vtxResult %21
-;CHECK:               OpStore %v_vtxResult %115
+;CHECK: OpStore %v_vtxResult [[phi_result]]
                OpReturn
                OpFunctionEnd
-               )" + kDirectRead3 + kStreamWrite5Vert;
+               )" + kReadDescInit + kStreamWrite5Vert;
   // clang-format on
 
   SetTargetEnv(SPV_ENV_VULKAN_1_2);
@@ -4888,14 +4898,14 @@ TEST_F(InstBindlessTest, UniformMatrixVecRefRowMajor) {
                OpDecorate %_ Binding 0
                OpDecorate %26 RelaxedPrecision
 ;CHECK-NOT:               OpDecorate %26 RelaxedPrecision
-;CHECK:               OpDecorate %125 RelaxedPrecision
+;CHECK: OpDecorate [[phi_result:%\w+]] RelaxedPrecision
                OpDecorate %a_position Location 0
-;CHECK:               OpDecorate %_runtimearr_uint ArrayStride 4
+;CHECK: OpDecorate %_runtimearr_uint ArrayStride 4
 )" + kInputDecorations + R"(
-;CHECK:               OpDecorate %70 RelaxedPrecision
+;CHECK: OpDecorate [[load_result:%\w+]] RelaxedPrecision
 )" + kOutputDecorations + R"(
-;CHECK:               OpDecorate %gl_VertexIndex BuiltIn VertexIndex
-;CHECK:               OpDecorate %gl_InstanceIndex BuiltIn InstanceIndex
+;CHECK: OpDecorate %gl_VertexIndex BuiltIn VertexIndex
+;CHECK: OpDecorate %gl_InstanceIndex BuiltIn InstanceIndex
        %void = OpTypeVoid
           %3 = OpTypeFunction %void
       %float = OpTypeFloat 32
@@ -4927,38 +4937,38 @@ TEST_F(InstBindlessTest, UniformMatrixVecRefRowMajor) {
 ;CHECK: [[null_v2float:%\w+]] = OpConstantNull %v2float
        %main = OpFunction %void None %3
           %5 = OpLabel
-;CHECK:         %64 = OpFunctionCall %uint %inst_bindless_direct_read_3 %uint_1 %uint_0 %uint_0
-;CHECK:               OpBranch %31
-;CHECK:         %31 = OpLabel
-;CHECK:               OpBranch %30
-;CHECK:         %30 = OpLabel
+;CHECK: [[desc_state:%\w+]] = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %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:        {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_51 %uint_4 %uint_0 %43 %64
-;CHECK:               OpBranch %67
-;CHECK:         %67 = OpLabel
-;CHECK:        %125 = OpPhi %v2float %70 %68 [[null_v2float]] %69
-;CHECK:               OpStore %v_vtxResult %125
+;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: {{%\w+}} = OpULessThan %bool %43 [[desc_state]]
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: [[load_result]] = OpLoad %v2float %25
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_51 %uint_4 %uint_0 {{%\w+}} {{%\w+}}
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: [[phi_result]] = OpPhi %v2float [[load_result]] {{%\w+}} [[null_v2float]] {{%\w+}}
+;CHECK: OpStore %v_vtxResult [[phi_result]]
                OpReturn
                OpFunctionEnd
-               )" + kDirectRead3 + kStreamWrite5Vert;
+               )" + kReadDescInit + kStreamWrite5Vert;
   // clang-format on
 
   SetTargetEnv(SPV_ENV_VULKAN_1_2);
@@ -5531,13 +5541,13 @@ OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_bufStruct PhysicalStorageBuffer
 R"(%main = OpFunction %void None %3
 %5 = OpLabel
 %i = OpVariable %_ptr_Function_int Function
-;CHECK: OpBranch %137
-;CHECK: %137 = OpLabel
-;CHECK: 65 = OpFunctionCall %uint %inst_bindless_direct_read_3 %uint_1 %uint_0 %uint_0
-;CHECK: OpBranch %40
-;CHECK: 40 = OpLabel
-;CHECK: OpBranch %39
-;CHECK: 39 = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: [[desc_state:%\w+]] = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
 OpStore %i %int_0
 OpBranch %10
 %10 = OpLabel
@@ -5550,41 +5560,41 @@ OpBranch %14
 %29 = OpSLessThan %bool %15 %27
 ;CHECK-NOT: %27 = OpLoad %int %26
 ;CHECK-NOT: %29 = OpSLessThan %bool %15 %27
-;CHECK: 43 = OpIAdd %uint %uint_8 %uint_3
-;CHECK: 66 = OpULessThan %bool %43 %65
-;CHECK: OpSelectionMerge %67 None
-;CHECK: OpBranchConditional %66 %68 %69
-;CHECK: 68 = OpLabel
-;CHECK: 70 = OpLoad %int %26
-;CHECK: OpBranch %67
-;CHECK: 69 = OpLabel
-;CHECK: 122 = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_54 %uint_4 %uint_0 %43 %65
-;CHECK: OpBranch %67
-;CHECK: 67 = OpLabel
-;CHECK: 124 = OpPhi %int %70 %68 %123 %69
-;CHECK: 29 = OpSLessThan %bool %15 %124
+;CHECK: {{%\w+}} = OpIAdd %uint %uint_8 %uint_3
+;CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\w+}}
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: [[load_result:%\w+]] = OpLoad %int %26
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_54 %uint_4 %uint_0 {{%\w+}} {{%\w+}}
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: [[phi_result:%\w+]] = OpPhi %int [[load_result]] {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpSLessThan %bool %15 [[phi_result]]
 OpBranchConditional %29 %11 %12
 %11 = OpLabel
 %31 = OpAccessChain %_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct %u_info %int_0
 %32 = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %31
 ;CHECK-NOT: %32 = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %31
-;CHECK: 125 = OpIAdd %uint %uint_0 %uint_7
-;CHECK: 126 = OpULessThan %bool %125 %65
-;CHECK: OpSelectionMerge %127 None
-;CHECK: OpBranchConditional %126 %128 %129
-;CHECK: 128 = OpLabel
-;CHECK: 130 = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %31
-;CHECK: OpBranch %127
-;CHECK: 129 = OpLabel
-;CHECK: 132 = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_59 %uint_4 %uint_0 %125 %65
-;CHECK: 135 = OpConvertUToPtr %_ptr_PhysicalStorageBuffer_bufStruct %134
-;CHECK: OpBranch %127
-;CHECK: 127 = OpLabel
-;CHECK: 136 = OpPhi %_ptr_PhysicalStorageBuffer_bufStruct %130 %128 %135 %129
+;CHECK: {{%\w+}} = OpIAdd %uint %uint_0 %uint_7
+;CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\w+}}
+;CHECK: OpSelectionMerge {{%\w+}} None
+;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: [[load_result_2:%\w+]] = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %31
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_59 %uint_4 %uint_0 {{%\w+}} {{%\w+}}
+;CHECK: {{%\w+}} = OpConvertUToPtr %_ptr_PhysicalStorageBuffer_bufStruct {{%\w+}}
+;CHECK: OpBranch {{%\w+}}
+;CHECK: {{%\w+}} = OpLabel
+;CHECK: [[phi_result_2:%\w+]] = OpPhi %_ptr_PhysicalStorageBuffer_bufStruct [[load_result_2]] {{%\w+}} {{%\w+}} {{%\w+}}
 %33 = OpLoad %int %i
 %36 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %32 %int_0 %33
 ;CHECK-NOT: %36 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %32 %int_0 %33
-;CHECK: %36 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %136 %int_0 %33
+;CHECK: %36 = OpAccessChain %_ptr_PhysicalStorageBuffer_int [[phi_result_2]] %int_0 %33
 OpStore %36 %int_n559035791 Aligned 16
 OpBranch %13
 %13 = OpLabel
@@ -5595,7 +5605,7 @@ OpBranch %10
 %12 = OpLabel
 OpReturn
 OpFunctionEnd)"
-    + kDirectRead3 + kStreamWrite5Vert;
+    + kReadDescInit + kStreamWrite5Vert;
   // clang-format on
 
   SetTargetEnv(SPV_ENV_VULKAN_1_2);
