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