From 9dfd4b8358077bdbe8e2f9388572b5376c370f5d Mon Sep 17 00:00:00 2001 From: greg-lunarg Date: Wed, 15 May 2019 17:43:23 -0600 Subject: [PATCH] Bindless Validation: Instrument descriptor-based loads and stores (#2583) Essentially, support UBOs and SSBOs, scalar and array (sized and unsized). --- source/opt/inst_bindless_check_pass.cpp | 140 +- source/opt/inst_bindless_check_pass.h | 10 +- test/opt/inst_bindless_check_test.cpp | 1600 +++++++++++++++++++++++ 3 files changed, 1704 insertions(+), 46 deletions(-) diff --git a/source/opt/inst_bindless_check_pass.cpp b/source/opt/inst_bindless_check_pass.cpp index 47c81347c..2eeab46e1 100644 --- a/source/opt/inst_bindless_check_pass.cpp +++ b/source/opt/inst_bindless_check_pass.cpp @@ -29,6 +29,7 @@ static const int kSpvAccessChainIndex0IdInIdx = 1; static const int kSpvTypePointerTypeIdInIdx = 1; static const int kSpvTypeArrayLengthIdInIdx = 1; static const int kSpvConstantValueInIdx = 0; +static const int kSpvVariableStorageClassInIdx = 0; } // anonymous namespace @@ -59,36 +60,42 @@ uint32_t InstBindlessCheckPass::GenDebugReadInit(uint32_t var_id, uint32_t InstBindlessCheckPass::CloneOriginalReference( ref_analysis* ref, InstructionBuilder* builder) { - // Clone descriptor load - Instruction* load_inst = get_def_use_mgr()->GetDef(ref->load_id); - Instruction* new_load_inst = - builder->AddLoad(load_inst->type_id(), - load_inst->GetSingleWordInOperand(kSpvLoadPtrIdInIdx)); - uid2offset_[new_load_inst->unique_id()] = uid2offset_[load_inst->unique_id()]; - uint32_t new_load_id = new_load_inst->result_id(); - get_decoration_mgr()->CloneDecorations(load_inst->result_id(), new_load_id); - uint32_t new_image_id = new_load_id; - // Clone Image/SampledImage with new load, if needed - if (ref->image_id != 0) { - Instruction* image_inst = get_def_use_mgr()->GetDef(ref->image_id); - if (image_inst->opcode() == SpvOp::SpvOpSampledImage) { - Instruction* new_image_inst = builder->AddBinaryOp( - image_inst->type_id(), SpvOpSampledImage, new_load_id, - image_inst->GetSingleWordInOperand(kSpvSampledImageSamplerIdInIdx)); - uid2offset_[new_image_inst->unique_id()] = - uid2offset_[image_inst->unique_id()]; - new_image_id = new_image_inst->result_id(); - } else { - assert(image_inst->opcode() == SpvOp::SpvOpImage && "expecting OpImage"); - Instruction* new_image_inst = - builder->AddUnaryOp(image_inst->type_id(), SpvOpImage, new_load_id); - uid2offset_[new_image_inst->unique_id()] = - uid2offset_[image_inst->unique_id()]; - new_image_id = new_image_inst->result_id(); + // If original is image based, start by cloning descriptor load + uint32_t new_image_id = 0; + if (ref->desc_load_id != 0) { + Instruction* desc_load_inst = get_def_use_mgr()->GetDef(ref->desc_load_id); + Instruction* new_load_inst = builder->AddLoad( + desc_load_inst->type_id(), + desc_load_inst->GetSingleWordInOperand(kSpvLoadPtrIdInIdx)); + uid2offset_[new_load_inst->unique_id()] = + uid2offset_[desc_load_inst->unique_id()]; + uint32_t new_load_id = new_load_inst->result_id(); + get_decoration_mgr()->CloneDecorations(desc_load_inst->result_id(), + new_load_id); + new_image_id = new_load_id; + // Clone Image/SampledImage with new load, if needed + if (ref->image_id != 0) { + Instruction* image_inst = get_def_use_mgr()->GetDef(ref->image_id); + if (image_inst->opcode() == SpvOp::SpvOpSampledImage) { + Instruction* new_image_inst = builder->AddBinaryOp( + image_inst->type_id(), SpvOpSampledImage, new_load_id, + image_inst->GetSingleWordInOperand(kSpvSampledImageSamplerIdInIdx)); + uid2offset_[new_image_inst->unique_id()] = + uid2offset_[image_inst->unique_id()]; + new_image_id = new_image_inst->result_id(); + } else { + assert(image_inst->opcode() == SpvOp::SpvOpImage && + "expecting OpImage"); + Instruction* new_image_inst = + builder->AddUnaryOp(image_inst->type_id(), SpvOpImage, new_load_id); + uid2offset_[new_image_inst->unique_id()] = + uid2offset_[image_inst->unique_id()]; + new_image_id = new_image_inst->result_id(); + } + get_decoration_mgr()->CloneDecorations(ref->image_id, new_image_id); } - get_decoration_mgr()->CloneDecorations(ref->image_id, new_image_id); } - // Clone original reference using new image code + // Clone original reference std::unique_ptr new_ref_inst(ref->ref_inst->Clone(context())); uint32_t ref_result_id = ref->ref_inst->result_id(); uint32_t new_ref_id = 0; @@ -96,7 +103,9 @@ uint32_t InstBindlessCheckPass::CloneOriginalReference( new_ref_id = TakeNextId(); new_ref_inst->SetResultId(new_ref_id); } - new_ref_inst->SetInOperand(kSpvImageSampleImageIdInIdx, {new_image_id}); + // Update new ref with new image if created + if (new_image_id != 0) + new_ref_inst->SetInOperand(kSpvImageSampleImageIdInIdx, {new_image_id}); // Register new reference and add to new block Instruction* added_inst = builder->AddInstruction(std::move(new_ref_inst)); uid2offset_[added_inst->unique_id()] = @@ -106,7 +115,7 @@ uint32_t InstBindlessCheckPass::CloneOriginalReference( return new_ref_id; } -uint32_t InstBindlessCheckPass::GetDescriptorValueId(Instruction* inst) { +uint32_t InstBindlessCheckPass::GetImageId(Instruction* inst) { switch (inst->opcode()) { case SpvOp::SpvOpImageSampleImplicitLod: case SpvOp::SpvOpImageSampleExplicitLod: @@ -147,27 +156,77 @@ uint32_t InstBindlessCheckPass::GetDescriptorValueId(Instruction* inst) { return 0; } +Instruction* InstBindlessCheckPass::GetDescriptorTypeInst( + Instruction* var_inst) { + uint32_t var_type_id = var_inst->type_id(); + Instruction* var_type_inst = get_def_use_mgr()->GetDef(var_type_id); + uint32_t desc_type_id = + var_type_inst->GetSingleWordInOperand(kSpvTypePointerTypeIdInIdx); + return get_def_use_mgr()->GetDef(desc_type_id); +} + bool InstBindlessCheckPass::AnalyzeDescriptorReference(Instruction* ref_inst, ref_analysis* ref) { - ref->image_id = GetDescriptorValueId(ref_inst); + ref->ref_inst = ref_inst; + if (ref_inst->opcode() == SpvOpLoad || ref_inst->opcode() == SpvOpStore) { + ref->desc_load_id = 0; + ref->ptr_id = ref_inst->GetSingleWordInOperand(kSpvLoadPtrIdInIdx); + Instruction* ptr_inst = get_def_use_mgr()->GetDef(ref->ptr_id); + if (ptr_inst->opcode() != SpvOp::SpvOpAccessChain) return false; + ref->var_id = ptr_inst->GetSingleWordInOperand(kSpvAccessChainBaseIdInIdx); + Instruction* var_inst = get_def_use_mgr()->GetDef(ref->var_id); + if (var_inst->opcode() != SpvOp::SpvOpVariable) return false; + uint32_t storage_class = + var_inst->GetSingleWordInOperand(kSpvVariableStorageClassInIdx); + switch (storage_class) { + case SpvStorageClassUniform: + case SpvStorageClassUniformConstant: + case SpvStorageClassStorageBuffer: + break; + default: + return false; + break; + } + Instruction* desc_type_inst = GetDescriptorTypeInst(var_inst); + switch (desc_type_inst->opcode()) { + case SpvOpTypeArray: + case SpvOpTypeRuntimeArray: + // A load through a descriptor array will have at least 3 operands. We + // do not want to instrument loads of descriptors here which are part of + // an image-based reference. + if (ptr_inst->NumInOperands() < 3) return false; + ref->index_id = + ptr_inst->GetSingleWordInOperand(kSpvAccessChainIndex0IdInIdx); + break; + default: + ref->index_id = 0; + break; + } + return true; + } + // Reference is not load or store. If not an image-based reference, return. + ref->image_id = GetImageId(ref_inst); if (ref->image_id == 0) return false; Instruction* image_inst = get_def_use_mgr()->GetDef(ref->image_id); + Instruction* desc_load_inst = nullptr; if (image_inst->opcode() == SpvOp::SpvOpSampledImage) { - ref->load_id = + ref->desc_load_id = image_inst->GetSingleWordInOperand(kSpvSampledImageImageIdInIdx); + desc_load_inst = get_def_use_mgr()->GetDef(ref->desc_load_id); } else if (image_inst->opcode() == SpvOp::SpvOpImage) { - ref->load_id = + ref->desc_load_id = image_inst->GetSingleWordInOperand(kSpvImageSampledImageIdInIdx); + desc_load_inst = get_def_use_mgr()->GetDef(ref->desc_load_id); } else { - ref->load_id = ref->image_id; + ref->desc_load_id = ref->image_id; + desc_load_inst = image_inst; ref->image_id = 0; } - Instruction* load_inst = get_def_use_mgr()->GetDef(ref->load_id); - if (load_inst->opcode() != SpvOp::SpvOpLoad) { + if (desc_load_inst->opcode() != SpvOp::SpvOpLoad) { // TODO(greg-lunarg): Handle additional possibilities? return false; } - ref->ptr_id = load_inst->GetSingleWordInOperand(kSpvLoadPtrIdInIdx); + ref->ptr_id = desc_load_inst->GetSingleWordInOperand(kSpvLoadPtrIdInIdx); Instruction* ptr_inst = get_def_use_mgr()->GetDef(ref->ptr_id); if (ptr_inst->opcode() == SpvOp::SpvOpVariable) { ref->index_id = 0; @@ -189,7 +248,6 @@ bool InstBindlessCheckPass::AnalyzeDescriptorReference(Instruction* ref_inst, // TODO(greg-lunarg): Handle additional possibilities? return false; } - ref->ref_inst = ref_inst; return true; } @@ -260,11 +318,7 @@ void InstBindlessCheckPass::GenBoundsCheckCode( // If index and bound both compile-time constants and index < bound, // return without changing Instruction* var_inst = get_def_use_mgr()->GetDef(ref.var_id); - uint32_t var_type_id = var_inst->type_id(); - Instruction* var_type_inst = get_def_use_mgr()->GetDef(var_type_id); - uint32_t desc_type_id = - var_type_inst->GetSingleWordInOperand(kSpvTypePointerTypeIdInIdx); - Instruction* desc_type_inst = get_def_use_mgr()->GetDef(desc_type_id); + Instruction* desc_type_inst = GetDescriptorTypeInst(var_inst); uint32_t length_id = 0; if (desc_type_inst->opcode() == SpvOpTypeArray) { length_id = diff --git a/source/opt/inst_bindless_check_pass.h b/source/opt/inst_bindless_check_pass.h index 79c34f1fc..5e9921e2f 100644 --- a/source/opt/inst_bindless_check_pass.h +++ b/source/opt/inst_bindless_check_pass.h @@ -118,6 +118,7 @@ class InstBindlessCheckPass : public InstrumentPass { // AnalyzeDescriptorReference. It is necessary and sufficient for further // analysis and regeneration of the reference. typedef struct ref_analysis { + uint32_t desc_load_id; uint32_t image_id; uint32_t load_id; uint32_t ptr_id; @@ -131,9 +132,12 @@ class InstBindlessCheckPass : public InstrumentPass { uint32_t CloneOriginalReference(ref_analysis* ref, InstructionBuilder* builder); - // If |inst| references through a descriptor, (ie references into an image - // or buffer), return the id of the value it references. Else return 0. - uint32_t GetDescriptorValueId(Instruction* inst); + // If |inst| references through an image, return the id of the image it + // references through. Else return 0. + uint32_t GetImageId(Instruction* inst); + + // Get descriptor type inst of variable |var_inst|. + Instruction* GetDescriptorTypeInst(Instruction* var_inst); // Analyze descriptor reference |ref_inst| and save components into |ref|. // Return true if |ref_inst| is a descriptor reference, false otherwise. diff --git a/test/opt/inst_bindless_check_test.cpp b/test/opt/inst_bindless_check_test.cpp index 88d5f196d..94a37cfe2 100644 --- a/test/opt/inst_bindless_check_test.cpp +++ b/test/opt/inst_bindless_check_test.cpp @@ -2626,6 +2626,1606 @@ OpFunctionEnd SinglePassRunAndMatch(text, true); } +TEST_F(InstBindlessTest, InstBoundsAndInitLoadUnsizedUBOArray) { + // #version 450 + // #extension GL_EXT_nonuniform_qualifier : enable + // + // layout(location=0) in nonuniformEXT flat int nu_ii; + // layout(location=0) out float b; + // + // layout(binding=3) uniform uname { float a; } uniformBuffer[]; + // + // void main() + // { + // b = uniformBuffer[nu_ii].a; + // } + + const std::string defs_before = + R"(OpCapability Shader +OpCapability ShaderNonUniformEXT +OpCapability RuntimeDescriptorArrayEXT +OpCapability UniformBufferArrayNonUniformIndexingEXT +OpExtension "SPV_EXT_descriptor_indexing" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %b %nu_ii +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 450 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpName %main "main" +OpName %b "b" +OpName %uname "uname" +OpMemberName %uname 0 "a" +OpName %uniformBuffer "uniformBuffer" +OpName %nu_ii "nu_ii" +OpDecorate %b Location 0 +OpMemberDecorate %uname 0 Offset 0 +OpDecorate %uname Block +OpDecorate %uniformBuffer DescriptorSet 0 +OpDecorate %uniformBuffer Binding 3 +OpDecorate %nu_ii Flat +OpDecorate %nu_ii Location 0 +OpDecorate %nu_ii NonUniformEXT +OpDecorate %16 NonUniformEXT +OpDecorate %20 NonUniformEXT +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%_ptr_Output_float = OpTypePointer Output %float +%b = OpVariable %_ptr_Output_float Output +%uname = OpTypeStruct %float +%_runtimearr_uname = OpTypeRuntimeArray %uname +%_ptr_Uniform__runtimearr_uname = OpTypePointer Uniform %_runtimearr_uname +%uniformBuffer = OpVariable %_ptr_Uniform__runtimearr_uname Uniform +%int = OpTypeInt 32 1 +%_ptr_Input_int = OpTypePointer Input %int +%nu_ii = OpVariable %_ptr_Input_int Input +%int_0 = OpConstant %int 0 +%_ptr_Uniform_float = OpTypePointer Uniform %float +)"; + + const std::string defs_after = + R"(OpCapability Shader +OpCapability ShaderNonUniformEXT +OpCapability RuntimeDescriptorArrayEXT +OpCapability UniformBufferArrayNonUniformIndexingEXT +OpExtension "SPV_EXT_descriptor_indexing" +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %b %nu_ii %gl_FragCoord +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 450 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpName %main "main" +OpName %b "b" +OpName %uname "uname" +OpMemberName %uname 0 "a" +OpName %uniformBuffer "uniformBuffer" +OpName %nu_ii "nu_ii" +OpDecorate %b Location 0 +OpMemberDecorate %uname 0 Offset 0 +OpDecorate %uname Block +OpDecorate %uniformBuffer DescriptorSet 0 +OpDecorate %uniformBuffer Binding 3 +OpDecorate %nu_ii Flat +OpDecorate %nu_ii Location 0 +OpDecorate %nu_ii NonUniformEXT +OpDecorate %7 NonUniformEXT +OpDecorate %102 NonUniformEXT +OpDecorate %_runtimearr_uint ArrayStride 4 +OpDecorate %_struct_31 Block +OpMemberDecorate %_struct_31 0 Offset 0 +OpDecorate %33 DescriptorSet 7 +OpDecorate %33 Binding 1 +OpDecorate %130 NonUniformEXT +OpDecorate %_struct_55 Block +OpMemberDecorate %_struct_55 0 Offset 0 +OpMemberDecorate %_struct_55 1 Offset 4 +OpDecorate %57 DescriptorSet 7 +OpDecorate %57 Binding 0 +OpDecorate %gl_FragCoord BuiltIn FragCoord +OpDecorate %127 NonUniformEXT +%void = OpTypeVoid +%10 = OpTypeFunction %void +%float = OpTypeFloat 32 +%_ptr_Output_float = OpTypePointer Output %float +%b = OpVariable %_ptr_Output_float Output +%uname = OpTypeStruct %float +%_runtimearr_uname = OpTypeRuntimeArray %uname +%_ptr_Uniform__runtimearr_uname = OpTypePointer Uniform %_runtimearr_uname +%uniformBuffer = OpVariable %_ptr_Uniform__runtimearr_uname Uniform +%int = OpTypeInt 32 1 +%_ptr_Input_int = OpTypePointer Input %int +%nu_ii = OpVariable %_ptr_Input_int Input +%int_0 = OpConstant %int 0 +%_ptr_Uniform_float = OpTypePointer Uniform %float +%uint = OpTypeInt 32 0 +%uint_0 = OpConstant %uint 0 +%uint_1 = OpConstant %uint 1 +%uint_3 = OpConstant %uint 3 +%26 = OpTypeFunction %uint %uint %uint +%_runtimearr_uint = OpTypeRuntimeArray %uint +%_struct_31 = OpTypeStruct %_runtimearr_uint +%_ptr_StorageBuffer__struct_31 = OpTypePointer StorageBuffer %_struct_31 +%33 = OpVariable %_ptr_StorageBuffer__struct_31 StorageBuffer +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint +%bool = OpTypeBool +%49 = OpTypeFunction %void %uint %uint %uint %uint +%_struct_55 = OpTypeStruct %uint %_runtimearr_uint +%_ptr_StorageBuffer__struct_55 = OpTypePointer StorageBuffer %_struct_55 +%57 = OpVariable %_ptr_StorageBuffer__struct_55 StorageBuffer +%uint_9 = OpConstant %uint 9 +%uint_4 = OpConstant %uint 4 +%uint_23 = OpConstant %uint 23 +%uint_2 = OpConstant %uint 2 +%v4float = OpTypeVector %float 4 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%gl_FragCoord = OpVariable %_ptr_Input_v4float Input +%v4uint = OpTypeVector %uint 4 +%uint_5 = OpConstant %uint 5 +%uint_6 = OpConstant %uint 6 +%uint_7 = OpConstant %uint 7 +%uint_8 = OpConstant %uint 8 +%uint_45 = OpConstant %uint 45 +%101 = OpConstantNull %float +%105 = OpTypeFunction %uint %uint %uint %uint %uint +)"; + + const std::string func_before = + R"(%main = OpFunction %void None %3 +%5 = OpLabel +%16 = OpLoad %int %nu_ii +%19 = OpAccessChain %_ptr_Uniform_float %uniformBuffer %16 %int_0 +%20 = OpLoad %float %19 +OpStore %b %20 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%main = OpFunction %void None %10 +%19 = OpLabel +%7 = OpLoad %int %nu_ii +%20 = OpAccessChain %_ptr_Uniform_float %uniformBuffer %7 %int_0 +%40 = OpFunctionCall %uint %25 %uint_1 %uint_3 +%42 = OpULessThan %bool %7 %40 +OpSelectionMerge %43 None +OpBranchConditional %42 %44 %45 +%44 = OpLabel +%103 = OpBitcast %uint %7 +%122 = OpFunctionCall %uint %104 %uint_0 %uint_0 %uint_3 %103 +%123 = OpINotEqual %bool %122 %uint_0 +OpSelectionMerge %124 None +OpBranchConditional %123 %125 %126 +%125 = OpLabel +%127 = OpLoad %float %20 +OpBranch %124 +%126 = OpLabel +%128 = OpBitcast %uint %7 +%129 = OpFunctionCall %void %48 %uint_45 %uint_1 %128 %uint_0 +OpBranch %124 +%124 = OpLabel +%130 = OpPhi %float %127 %125 %101 %126 +OpBranch %43 +%45 = OpLabel +%47 = OpBitcast %uint %7 +%100 = OpFunctionCall %void %48 %uint_45 %uint_0 %47 %40 +OpBranch %43 +%43 = OpLabel +%102 = OpPhi %float %130 %124 %101 %45 +OpStore %b %102 +OpReturn +OpFunctionEnd +)"; + + const std::string new_funcs = + R"(%25 = OpFunction %uint None %26 +%27 = OpFunctionParameter %uint +%28 = OpFunctionParameter %uint +%29 = OpLabel +%35 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %27 +%36 = OpLoad %uint %35 +%37 = OpIAdd %uint %36 %28 +%38 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %37 +%39 = OpLoad %uint %38 +OpReturnValue %39 +OpFunctionEnd +%48 = OpFunction %void None %49 +%50 = OpFunctionParameter %uint +%51 = OpFunctionParameter %uint +%52 = OpFunctionParameter %uint +%53 = OpFunctionParameter %uint +%54 = OpLabel +%58 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_0 +%61 = OpAtomicIAdd %uint %58 %uint_4 %uint_0 %uint_9 +%62 = OpIAdd %uint %61 %uint_9 +%63 = OpArrayLength %uint %57 1 +%64 = OpULessThanEqual %bool %62 %63 +OpSelectionMerge %65 None +OpBranchConditional %64 %66 %65 +%66 = OpLabel +%67 = OpIAdd %uint %61 %uint_0 +%68 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %67 +OpStore %68 %uint_9 +%70 = OpIAdd %uint %61 %uint_1 +%71 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %70 +OpStore %71 %uint_23 +%73 = OpIAdd %uint %61 %uint_2 +%74 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %73 +OpStore %74 %50 +%75 = OpIAdd %uint %61 %uint_3 +%76 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %75 +OpStore %76 %uint_4 +%80 = OpLoad %v4float %gl_FragCoord +%82 = OpBitcast %v4uint %80 +%83 = OpCompositeExtract %uint %82 0 +%84 = OpIAdd %uint %61 %uint_4 +%85 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %84 +OpStore %85 %83 +%86 = OpCompositeExtract %uint %82 1 +%88 = OpIAdd %uint %61 %uint_5 +%89 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %88 +OpStore %89 %86 +%91 = OpIAdd %uint %61 %uint_6 +%92 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %91 +OpStore %92 %51 +%94 = OpIAdd %uint %61 %uint_7 +%95 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %94 +OpStore %95 %52 +%97 = OpIAdd %uint %61 %uint_8 +%98 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %97 +OpStore %98 %53 +OpBranch %65 +%65 = OpLabel +OpReturn +OpFunctionEnd +%104 = OpFunction %uint None %105 +%106 = OpFunctionParameter %uint +%107 = OpFunctionParameter %uint +%108 = OpFunctionParameter %uint +%109 = OpFunctionParameter %uint +%110 = OpLabel +%111 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %106 +%112 = OpLoad %uint %111 +%113 = OpIAdd %uint %112 %107 +%114 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %113 +%115 = OpLoad %uint %114 +%116 = OpIAdd %uint %115 %108 +%117 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %116 +%118 = OpLoad %uint %117 +%119 = OpIAdd %uint %118 %109 +%120 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %119 +%121 = OpLoad %uint %120 +OpReturnValue %121 +OpFunctionEnd +)"; + + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + defs_before + func_before, defs_after + func_after + new_funcs, true, + true); +} + +TEST_F(InstBindlessTest, InstBoundsAndInitLoadUnsizedSSBOArrayDeprecated) { + // #version 450 + // #extension GL_EXT_nonuniform_qualifier : enable + // + // layout(location=0) in nonuniformEXT flat int nu_ii; + // layout(location=0) out float b; + // + // layout(binding=3) buffer bname { float b; } storageBuffer[]; + // + // void main() + // { + // b = storageBuffer[nu_ii].b; + // } + + const std::string defs_before = + R"(OpCapability Shader +OpCapability ShaderNonUniformEXT +OpCapability RuntimeDescriptorArrayEXT +OpCapability UniformBufferArrayNonUniformIndexingEXT +OpExtension "SPV_EXT_descriptor_indexing" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %b %nu_ii +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 450 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpName %main "main" +OpName %b "b" +OpName %bname "bname" +OpMemberName %bname 0 "a" +OpName %storageBuffer "storageBuffer" +OpName %nu_ii "nu_ii" +OpDecorate %b Location 0 +OpMemberDecorate %bname 0 Offset 0 +OpDecorate %bname BufferBlock +OpDecorate %storageBuffer DescriptorSet 0 +OpDecorate %storageBuffer Binding 3 +OpDecorate %nu_ii Flat +OpDecorate %nu_ii Location 0 +OpDecorate %nu_ii NonUniformEXT +OpDecorate %16 NonUniformEXT +OpDecorate %20 NonUniformEXT +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%_ptr_Output_float = OpTypePointer Output %float +%b = OpVariable %_ptr_Output_float Output +%bname = OpTypeStruct %float +%_runtimearr_bname = OpTypeRuntimeArray %bname +%_ptr_Uniform__runtimearr_bname = OpTypePointer Uniform %_runtimearr_bname +%storageBuffer = OpVariable %_ptr_Uniform__runtimearr_bname Uniform +%int = OpTypeInt 32 1 +%_ptr_Input_int = OpTypePointer Input %int +%nu_ii = OpVariable %_ptr_Input_int Input +%int_0 = OpConstant %int 0 +%_ptr_Uniform_float = OpTypePointer Uniform %float +)"; + + const std::string defs_after = + R"(OpCapability Shader +OpCapability ShaderNonUniformEXT +OpCapability RuntimeDescriptorArrayEXT +OpCapability UniformBufferArrayNonUniformIndexingEXT +OpExtension "SPV_EXT_descriptor_indexing" +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %b %nu_ii %gl_FragCoord +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 450 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpName %main "main" +OpName %b "b" +OpName %bname "bname" +OpMemberName %bname 0 "a" +OpName %storageBuffer "storageBuffer" +OpName %nu_ii "nu_ii" +OpDecorate %b Location 0 +OpMemberDecorate %bname 0 Offset 0 +OpDecorate %bname BufferBlock +OpDecorate %storageBuffer DescriptorSet 0 +OpDecorate %storageBuffer Binding 3 +OpDecorate %nu_ii Flat +OpDecorate %nu_ii Location 0 +OpDecorate %nu_ii NonUniformEXT +OpDecorate %7 NonUniformEXT +OpDecorate %102 NonUniformEXT +OpDecorate %_runtimearr_uint ArrayStride 4 +OpDecorate %_struct_31 Block +OpMemberDecorate %_struct_31 0 Offset 0 +OpDecorate %33 DescriptorSet 7 +OpDecorate %33 Binding 1 +OpDecorate %130 NonUniformEXT +OpDecorate %_struct_55 Block +OpMemberDecorate %_struct_55 0 Offset 0 +OpMemberDecorate %_struct_55 1 Offset 4 +OpDecorate %57 DescriptorSet 7 +OpDecorate %57 Binding 0 +OpDecorate %gl_FragCoord BuiltIn FragCoord +OpDecorate %127 NonUniformEXT +%void = OpTypeVoid +%10 = OpTypeFunction %void +%float = OpTypeFloat 32 +%_ptr_Output_float = OpTypePointer Output %float +%b = OpVariable %_ptr_Output_float Output +%bname = OpTypeStruct %float +%_runtimearr_bname = OpTypeRuntimeArray %bname +%_ptr_Uniform__runtimearr_bname = OpTypePointer Uniform %_runtimearr_bname +%storageBuffer = OpVariable %_ptr_Uniform__runtimearr_bname Uniform +%int = OpTypeInt 32 1 +%_ptr_Input_int = OpTypePointer Input %int +%nu_ii = OpVariable %_ptr_Input_int Input +%int_0 = OpConstant %int 0 +%_ptr_Uniform_float = OpTypePointer Uniform %float +%uint = OpTypeInt 32 0 +%uint_0 = OpConstant %uint 0 +%uint_1 = OpConstant %uint 1 +%uint_3 = OpConstant %uint 3 +%26 = OpTypeFunction %uint %uint %uint +%_runtimearr_uint = OpTypeRuntimeArray %uint +%_struct_31 = OpTypeStruct %_runtimearr_uint +%_ptr_StorageBuffer__struct_31 = OpTypePointer StorageBuffer %_struct_31 +%33 = OpVariable %_ptr_StorageBuffer__struct_31 StorageBuffer +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint +%bool = OpTypeBool +%49 = OpTypeFunction %void %uint %uint %uint %uint +%_struct_55 = OpTypeStruct %uint %_runtimearr_uint +%_ptr_StorageBuffer__struct_55 = OpTypePointer StorageBuffer %_struct_55 +%57 = OpVariable %_ptr_StorageBuffer__struct_55 StorageBuffer +%uint_9 = OpConstant %uint 9 +%uint_4 = OpConstant %uint 4 +%uint_23 = OpConstant %uint 23 +%uint_2 = OpConstant %uint 2 +%v4float = OpTypeVector %float 4 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%gl_FragCoord = OpVariable %_ptr_Input_v4float Input +%v4uint = OpTypeVector %uint 4 +%uint_5 = OpConstant %uint 5 +%uint_6 = OpConstant %uint 6 +%uint_7 = OpConstant %uint 7 +%uint_8 = OpConstant %uint 8 +%uint_45 = OpConstant %uint 45 +%101 = OpConstantNull %float +%105 = OpTypeFunction %uint %uint %uint %uint %uint +)"; + + const std::string func_before = + R"(%main = OpFunction %void None %3 +%5 = OpLabel +%16 = OpLoad %int %nu_ii +%19 = OpAccessChain %_ptr_Uniform_float %storageBuffer %16 %int_0 +%20 = OpLoad %float %19 +OpStore %b %20 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%main = OpFunction %void None %10 +%19 = OpLabel +%7 = OpLoad %int %nu_ii +%20 = OpAccessChain %_ptr_Uniform_float %storageBuffer %7 %int_0 +%40 = OpFunctionCall %uint %25 %uint_1 %uint_3 +%42 = OpULessThan %bool %7 %40 +OpSelectionMerge %43 None +OpBranchConditional %42 %44 %45 +%44 = OpLabel +%103 = OpBitcast %uint %7 +%122 = OpFunctionCall %uint %104 %uint_0 %uint_0 %uint_3 %103 +%123 = OpINotEqual %bool %122 %uint_0 +OpSelectionMerge %124 None +OpBranchConditional %123 %125 %126 +%125 = OpLabel +%127 = OpLoad %float %20 +OpBranch %124 +%126 = OpLabel +%128 = OpBitcast %uint %7 +%129 = OpFunctionCall %void %48 %uint_45 %uint_1 %128 %uint_0 +OpBranch %124 +%124 = OpLabel +%130 = OpPhi %float %127 %125 %101 %126 +OpBranch %43 +%45 = OpLabel +%47 = OpBitcast %uint %7 +%100 = OpFunctionCall %void %48 %uint_45 %uint_0 %47 %40 +OpBranch %43 +%43 = OpLabel +%102 = OpPhi %float %130 %124 %101 %45 +OpStore %b %102 +OpReturn +OpFunctionEnd +)"; + + const std::string new_funcs = + R"(%25 = OpFunction %uint None %26 +%27 = OpFunctionParameter %uint +%28 = OpFunctionParameter %uint +%29 = OpLabel +%35 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %27 +%36 = OpLoad %uint %35 +%37 = OpIAdd %uint %36 %28 +%38 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %37 +%39 = OpLoad %uint %38 +OpReturnValue %39 +OpFunctionEnd +%48 = OpFunction %void None %49 +%50 = OpFunctionParameter %uint +%51 = OpFunctionParameter %uint +%52 = OpFunctionParameter %uint +%53 = OpFunctionParameter %uint +%54 = OpLabel +%58 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_0 +%61 = OpAtomicIAdd %uint %58 %uint_4 %uint_0 %uint_9 +%62 = OpIAdd %uint %61 %uint_9 +%63 = OpArrayLength %uint %57 1 +%64 = OpULessThanEqual %bool %62 %63 +OpSelectionMerge %65 None +OpBranchConditional %64 %66 %65 +%66 = OpLabel +%67 = OpIAdd %uint %61 %uint_0 +%68 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %67 +OpStore %68 %uint_9 +%70 = OpIAdd %uint %61 %uint_1 +%71 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %70 +OpStore %71 %uint_23 +%73 = OpIAdd %uint %61 %uint_2 +%74 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %73 +OpStore %74 %50 +%75 = OpIAdd %uint %61 %uint_3 +%76 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %75 +OpStore %76 %uint_4 +%80 = OpLoad %v4float %gl_FragCoord +%82 = OpBitcast %v4uint %80 +%83 = OpCompositeExtract %uint %82 0 +%84 = OpIAdd %uint %61 %uint_4 +%85 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %84 +OpStore %85 %83 +%86 = OpCompositeExtract %uint %82 1 +%88 = OpIAdd %uint %61 %uint_5 +%89 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %88 +OpStore %89 %86 +%91 = OpIAdd %uint %61 %uint_6 +%92 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %91 +OpStore %92 %51 +%94 = OpIAdd %uint %61 %uint_7 +%95 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %94 +OpStore %95 %52 +%97 = OpIAdd %uint %61 %uint_8 +%98 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %97 +OpStore %98 %53 +OpBranch %65 +%65 = OpLabel +OpReturn +OpFunctionEnd +%104 = OpFunction %uint None %105 +%106 = OpFunctionParameter %uint +%107 = OpFunctionParameter %uint +%108 = OpFunctionParameter %uint +%109 = OpFunctionParameter %uint +%110 = OpLabel +%111 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %106 +%112 = OpLoad %uint %111 +%113 = OpIAdd %uint %112 %107 +%114 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %113 +%115 = OpLoad %uint %114 +%116 = OpIAdd %uint %115 %108 +%117 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %116 +%118 = OpLoad %uint %117 +%119 = OpIAdd %uint %118 %109 +%120 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %119 +%121 = OpLoad %uint %120 +OpReturnValue %121 +OpFunctionEnd +)"; + + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + defs_before + func_before, defs_after + func_after + new_funcs, true, + true); +} + +TEST_F(InstBindlessTest, InstBoundsAndInitLoadUnsizedSSBOArray) { + // Same as Deprecated but declaring as StorageBuffer Block + + const std::string defs_before = + R"(OpCapability Shader +OpCapability ShaderNonUniformEXT +OpCapability RuntimeDescriptorArrayEXT +OpCapability StorageBufferArrayNonUniformIndexingEXT +OpExtension "SPV_EXT_descriptor_indexing" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %b %nu_ii +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 450 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpName %main "main" +OpName %b "b" +OpName %bname "bname" +OpMemberName %bname 0 "a" +OpName %storageBuffer "storageBuffer" +OpName %nu_ii "nu_ii" +OpDecorate %b Location 0 +OpMemberDecorate %bname 0 Offset 0 +OpDecorate %bname Block +OpDecorate %storageBuffer DescriptorSet 0 +OpDecorate %storageBuffer Binding 3 +OpDecorate %nu_ii Flat +OpDecorate %nu_ii Location 0 +OpDecorate %nu_ii NonUniformEXT +OpDecorate %16 NonUniformEXT +OpDecorate %20 NonUniformEXT +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%_ptr_Output_float = OpTypePointer Output %float +%b = OpVariable %_ptr_Output_float Output +%bname = OpTypeStruct %float +%_runtimearr_bname = OpTypeRuntimeArray %bname +%_ptr_StorageBuffer__runtimearr_bname = OpTypePointer StorageBuffer %_runtimearr_bname +%storageBuffer = OpVariable %_ptr_StorageBuffer__runtimearr_bname StorageBuffer +%int = OpTypeInt 32 1 +%_ptr_Input_int = OpTypePointer Input %int +%nu_ii = OpVariable %_ptr_Input_int Input +%int_0 = OpConstant %int 0 +%_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float +)"; + + const std::string defs_after = + R"(OpCapability Shader +OpCapability ShaderNonUniformEXT +OpCapability RuntimeDescriptorArrayEXT +OpCapability StorageBufferArrayNonUniformIndexingEXT +OpExtension "SPV_EXT_descriptor_indexing" +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %b %nu_ii %gl_FragCoord +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 450 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpName %main "main" +OpName %b "b" +OpName %bname "bname" +OpMemberName %bname 0 "a" +OpName %storageBuffer "storageBuffer" +OpName %nu_ii "nu_ii" +OpDecorate %b Location 0 +OpMemberDecorate %bname 0 Offset 0 +OpDecorate %bname Block +OpDecorate %storageBuffer DescriptorSet 0 +OpDecorate %storageBuffer Binding 3 +OpDecorate %nu_ii Flat +OpDecorate %nu_ii Location 0 +OpDecorate %nu_ii NonUniformEXT +OpDecorate %7 NonUniformEXT +OpDecorate %102 NonUniformEXT +OpDecorate %_runtimearr_uint ArrayStride 4 +OpDecorate %_struct_31 Block +OpMemberDecorate %_struct_31 0 Offset 0 +OpDecorate %33 DescriptorSet 7 +OpDecorate %33 Binding 1 +OpDecorate %130 NonUniformEXT +OpDecorate %_struct_55 Block +OpMemberDecorate %_struct_55 0 Offset 0 +OpMemberDecorate %_struct_55 1 Offset 4 +OpDecorate %57 DescriptorSet 7 +OpDecorate %57 Binding 0 +OpDecorate %gl_FragCoord BuiltIn FragCoord +OpDecorate %127 NonUniformEXT +%void = OpTypeVoid +%10 = OpTypeFunction %void +%float = OpTypeFloat 32 +%_ptr_Output_float = OpTypePointer Output %float +%b = OpVariable %_ptr_Output_float Output +%bname = OpTypeStruct %float +%_runtimearr_bname = OpTypeRuntimeArray %bname +%_ptr_StorageBuffer__runtimearr_bname = OpTypePointer StorageBuffer %_runtimearr_bname +%storageBuffer = OpVariable %_ptr_StorageBuffer__runtimearr_bname StorageBuffer +%int = OpTypeInt 32 1 +%_ptr_Input_int = OpTypePointer Input %int +%nu_ii = OpVariable %_ptr_Input_int Input +%int_0 = OpConstant %int 0 +%_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float +%uint = OpTypeInt 32 0 +%uint_0 = OpConstant %uint 0 +%uint_1 = OpConstant %uint 1 +%uint_3 = OpConstant %uint 3 +%26 = OpTypeFunction %uint %uint %uint +%_runtimearr_uint = OpTypeRuntimeArray %uint +%_struct_31 = OpTypeStruct %_runtimearr_uint +%_ptr_StorageBuffer__struct_31 = OpTypePointer StorageBuffer %_struct_31 +%33 = OpVariable %_ptr_StorageBuffer__struct_31 StorageBuffer +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint +%bool = OpTypeBool +%49 = OpTypeFunction %void %uint %uint %uint %uint +%_struct_55 = OpTypeStruct %uint %_runtimearr_uint +%_ptr_StorageBuffer__struct_55 = OpTypePointer StorageBuffer %_struct_55 +%57 = OpVariable %_ptr_StorageBuffer__struct_55 StorageBuffer +%uint_9 = OpConstant %uint 9 +%uint_4 = OpConstant %uint 4 +%uint_23 = OpConstant %uint 23 +%uint_2 = OpConstant %uint 2 +%v4float = OpTypeVector %float 4 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%gl_FragCoord = OpVariable %_ptr_Input_v4float Input +%v4uint = OpTypeVector %uint 4 +%uint_5 = OpConstant %uint 5 +%uint_6 = OpConstant %uint 6 +%uint_7 = OpConstant %uint 7 +%uint_8 = OpConstant %uint 8 +%uint_45 = OpConstant %uint 45 +%101 = OpConstantNull %float +%105 = OpTypeFunction %uint %uint %uint %uint %uint +)"; + + const std::string func_before = + R"(%main = OpFunction %void None %3 +%5 = OpLabel +%16 = OpLoad %int %nu_ii +%19 = OpAccessChain %_ptr_StorageBuffer_float %storageBuffer %16 %int_0 +%20 = OpLoad %float %19 +OpStore %b %20 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%main = OpFunction %void None %10 +%19 = OpLabel +%7 = OpLoad %int %nu_ii +%20 = OpAccessChain %_ptr_StorageBuffer_float %storageBuffer %7 %int_0 +%40 = OpFunctionCall %uint %25 %uint_1 %uint_3 +%42 = OpULessThan %bool %7 %40 +OpSelectionMerge %43 None +OpBranchConditional %42 %44 %45 +%44 = OpLabel +%103 = OpBitcast %uint %7 +%122 = OpFunctionCall %uint %104 %uint_0 %uint_0 %uint_3 %103 +%123 = OpINotEqual %bool %122 %uint_0 +OpSelectionMerge %124 None +OpBranchConditional %123 %125 %126 +%125 = OpLabel +%127 = OpLoad %float %20 +OpBranch %124 +%126 = OpLabel +%128 = OpBitcast %uint %7 +%129 = OpFunctionCall %void %48 %uint_45 %uint_1 %128 %uint_0 +OpBranch %124 +%124 = OpLabel +%130 = OpPhi %float %127 %125 %101 %126 +OpBranch %43 +%45 = OpLabel +%47 = OpBitcast %uint %7 +%100 = OpFunctionCall %void %48 %uint_45 %uint_0 %47 %40 +OpBranch %43 +%43 = OpLabel +%102 = OpPhi %float %130 %124 %101 %45 +OpStore %b %102 +OpReturn +OpFunctionEnd +)"; + + const std::string new_funcs = + R"(%25 = OpFunction %uint None %26 +%27 = OpFunctionParameter %uint +%28 = OpFunctionParameter %uint +%29 = OpLabel +%35 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %27 +%36 = OpLoad %uint %35 +%37 = OpIAdd %uint %36 %28 +%38 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %37 +%39 = OpLoad %uint %38 +OpReturnValue %39 +OpFunctionEnd +%48 = OpFunction %void None %49 +%50 = OpFunctionParameter %uint +%51 = OpFunctionParameter %uint +%52 = OpFunctionParameter %uint +%53 = OpFunctionParameter %uint +%54 = OpLabel +%58 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_0 +%61 = OpAtomicIAdd %uint %58 %uint_4 %uint_0 %uint_9 +%62 = OpIAdd %uint %61 %uint_9 +%63 = OpArrayLength %uint %57 1 +%64 = OpULessThanEqual %bool %62 %63 +OpSelectionMerge %65 None +OpBranchConditional %64 %66 %65 +%66 = OpLabel +%67 = OpIAdd %uint %61 %uint_0 +%68 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %67 +OpStore %68 %uint_9 +%70 = OpIAdd %uint %61 %uint_1 +%71 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %70 +OpStore %71 %uint_23 +%73 = OpIAdd %uint %61 %uint_2 +%74 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %73 +OpStore %74 %50 +%75 = OpIAdd %uint %61 %uint_3 +%76 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %75 +OpStore %76 %uint_4 +%80 = OpLoad %v4float %gl_FragCoord +%82 = OpBitcast %v4uint %80 +%83 = OpCompositeExtract %uint %82 0 +%84 = OpIAdd %uint %61 %uint_4 +%85 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %84 +OpStore %85 %83 +%86 = OpCompositeExtract %uint %82 1 +%88 = OpIAdd %uint %61 %uint_5 +%89 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %88 +OpStore %89 %86 +%91 = OpIAdd %uint %61 %uint_6 +%92 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %91 +OpStore %92 %51 +%94 = OpIAdd %uint %61 %uint_7 +%95 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %94 +OpStore %95 %52 +%97 = OpIAdd %uint %61 %uint_8 +%98 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %97 +OpStore %98 %53 +OpBranch %65 +%65 = OpLabel +OpReturn +OpFunctionEnd +%104 = OpFunction %uint None %105 +%106 = OpFunctionParameter %uint +%107 = OpFunctionParameter %uint +%108 = OpFunctionParameter %uint +%109 = OpFunctionParameter %uint +%110 = OpLabel +%111 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %106 +%112 = OpLoad %uint %111 +%113 = OpIAdd %uint %112 %107 +%114 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %113 +%115 = OpLoad %uint %114 +%116 = OpIAdd %uint %115 %108 +%117 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %116 +%118 = OpLoad %uint %117 +%119 = OpIAdd %uint %118 %109 +%120 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %119 +%121 = OpLoad %uint %120 +OpReturnValue %121 +OpFunctionEnd +)"; + + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + defs_before + func_before, defs_after + func_after + new_funcs, true, + true); +} + +TEST_F(InstBindlessTest, InstInitLoadUBOScalar) { + // #version 450 + // #extension GL_EXT_nonuniform_qualifier : enable + // + // layout(location=0) out float b; + // layout(binding=3) uniform uname { float a; } uniformBuffer; + // + // void main() + // { + // b = uniformBuffer.a; + // } + + const std::string defs_before = + R"(OpCapability Shader +OpExtension "SPV_EXT_descriptor_indexing" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %b +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 450 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpName %main "main" +OpName %b "b" +OpName %uname "uname" +OpMemberName %uname 0 "a" +OpName %uniformBuffer "uniformBuffer" +OpDecorate %b Location 0 +OpMemberDecorate %uname 0 Offset 0 +OpDecorate %uname Block +OpDecorate %uniformBuffer DescriptorSet 0 +OpDecorate %uniformBuffer Binding 3 +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%_ptr_Output_float = OpTypePointer Output %float +%b = OpVariable %_ptr_Output_float Output +%uname = OpTypeStruct %float +%_ptr_Uniform_uname = OpTypePointer Uniform %uname +%uniformBuffer = OpVariable %_ptr_Uniform_uname Uniform +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%_ptr_Uniform_float = OpTypePointer Uniform %float +)"; + + const std::string defs_after = + R"(OpCapability Shader +OpExtension "SPV_EXT_descriptor_indexing" +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %b %gl_FragCoord +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 450 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpName %main "main" +OpName %b "b" +OpName %uname "uname" +OpMemberName %uname 0 "a" +OpName %uniformBuffer "uniformBuffer" +OpDecorate %b Location 0 +OpMemberDecorate %uname 0 Offset 0 +OpDecorate %uname Block +OpDecorate %uniformBuffer DescriptorSet 0 +OpDecorate %uniformBuffer Binding 3 +OpDecorate %_runtimearr_uint ArrayStride 4 +OpDecorate %_struct_28 Block +OpMemberDecorate %_struct_28 0 Offset 0 +OpDecorate %30 DescriptorSet 7 +OpDecorate %30 Binding 1 +OpDecorate %_struct_58 Block +OpMemberDecorate %_struct_58 0 Offset 0 +OpMemberDecorate %_struct_58 1 Offset 4 +OpDecorate %60 DescriptorSet 7 +OpDecorate %60 Binding 0 +OpDecorate %gl_FragCoord BuiltIn FragCoord +%void = OpTypeVoid +%7 = OpTypeFunction %void +%float = OpTypeFloat 32 +%_ptr_Output_float = OpTypePointer Output %float +%b = OpVariable %_ptr_Output_float Output +%uname = OpTypeStruct %float +%_ptr_Uniform_uname = OpTypePointer Uniform %uname +%uniformBuffer = OpVariable %_ptr_Uniform_uname Uniform +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%_ptr_Uniform_float = OpTypePointer Uniform %float +%uint = OpTypeInt 32 0 +%uint_0 = OpConstant %uint 0 +%uint_3 = OpConstant %uint 3 +%21 = OpTypeFunction %uint %uint %uint %uint %uint +%_runtimearr_uint = OpTypeRuntimeArray %uint +%_struct_28 = OpTypeStruct %_runtimearr_uint +%_ptr_StorageBuffer__struct_28 = OpTypePointer StorageBuffer %_struct_28 +%30 = OpVariable %_ptr_StorageBuffer__struct_28 StorageBuffer +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint +%bool = OpTypeBool +%uint_1 = OpConstant %uint 1 +%52 = OpTypeFunction %void %uint %uint %uint %uint +%_struct_58 = OpTypeStruct %uint %_runtimearr_uint +%_ptr_StorageBuffer__struct_58 = OpTypePointer StorageBuffer %_struct_58 +%60 = OpVariable %_ptr_StorageBuffer__struct_58 StorageBuffer +%uint_9 = OpConstant %uint 9 +%uint_4 = OpConstant %uint 4 +%uint_23 = OpConstant %uint 23 +%uint_2 = OpConstant %uint 2 +%v4float = OpTypeVector %float 4 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%gl_FragCoord = OpVariable %_ptr_Input_v4float Input +%v4uint = OpTypeVector %uint 4 +%uint_5 = OpConstant %uint 5 +%uint_6 = OpConstant %uint 6 +%uint_7 = OpConstant %uint 7 +%uint_8 = OpConstant %uint 8 +%uint_32 = OpConstant %uint 32 +%104 = OpConstantNull %float +)"; + + const std::string func_before = + R"(%main = OpFunction %void None %3 +%5 = OpLabel +%15 = OpAccessChain %_ptr_Uniform_float %uniformBuffer %int_0 +%16 = OpLoad %float %15 +OpStore %b %16 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%main = OpFunction %void None %7 +%14 = OpLabel +%15 = OpAccessChain %_ptr_Uniform_float %uniformBuffer %int_0 +%43 = OpFunctionCall %uint %20 %uint_0 %uint_0 %uint_3 %uint_0 +%45 = OpINotEqual %bool %43 %uint_0 +OpSelectionMerge %47 None +OpBranchConditional %45 %48 %49 +%48 = OpLabel +%50 = OpLoad %float %15 +OpBranch %47 +%49 = OpLabel +%103 = OpFunctionCall %void %51 %uint_32 %uint_1 %uint_0 %uint_0 +OpBranch %47 +%47 = OpLabel +%105 = OpPhi %float %50 %48 %104 %49 +OpStore %b %105 +OpReturn +OpFunctionEnd +)"; + + const std::string new_funcs = + R"(%20 = OpFunction %uint None %21 +%22 = OpFunctionParameter %uint +%23 = OpFunctionParameter %uint +%24 = OpFunctionParameter %uint +%25 = OpFunctionParameter %uint +%26 = OpLabel +%32 = OpAccessChain %_ptr_StorageBuffer_uint %30 %uint_0 %22 +%33 = OpLoad %uint %32 +%34 = OpIAdd %uint %33 %23 +%35 = OpAccessChain %_ptr_StorageBuffer_uint %30 %uint_0 %34 +%36 = OpLoad %uint %35 +%37 = OpIAdd %uint %36 %24 +%38 = OpAccessChain %_ptr_StorageBuffer_uint %30 %uint_0 %37 +%39 = OpLoad %uint %38 +%40 = OpIAdd %uint %39 %25 +%41 = OpAccessChain %_ptr_StorageBuffer_uint %30 %uint_0 %40 +%42 = OpLoad %uint %41 +OpReturnValue %42 +OpFunctionEnd +%51 = OpFunction %void None %52 +%53 = OpFunctionParameter %uint +%54 = OpFunctionParameter %uint +%55 = OpFunctionParameter %uint +%56 = OpFunctionParameter %uint +%57 = OpLabel +%61 = OpAccessChain %_ptr_StorageBuffer_uint %60 %uint_0 +%64 = OpAtomicIAdd %uint %61 %uint_4 %uint_0 %uint_9 +%65 = OpIAdd %uint %64 %uint_9 +%66 = OpArrayLength %uint %60 1 +%67 = OpULessThanEqual %bool %65 %66 +OpSelectionMerge %68 None +OpBranchConditional %67 %69 %68 +%69 = OpLabel +%70 = OpIAdd %uint %64 %uint_0 +%71 = OpAccessChain %_ptr_StorageBuffer_uint %60 %uint_1 %70 +OpStore %71 %uint_9 +%73 = OpIAdd %uint %64 %uint_1 +%74 = OpAccessChain %_ptr_StorageBuffer_uint %60 %uint_1 %73 +OpStore %74 %uint_23 +%76 = OpIAdd %uint %64 %uint_2 +%77 = OpAccessChain %_ptr_StorageBuffer_uint %60 %uint_1 %76 +OpStore %77 %53 +%78 = OpIAdd %uint %64 %uint_3 +%79 = OpAccessChain %_ptr_StorageBuffer_uint %60 %uint_1 %78 +OpStore %79 %uint_4 +%83 = OpLoad %v4float %gl_FragCoord +%85 = OpBitcast %v4uint %83 +%86 = OpCompositeExtract %uint %85 0 +%87 = OpIAdd %uint %64 %uint_4 +%88 = OpAccessChain %_ptr_StorageBuffer_uint %60 %uint_1 %87 +OpStore %88 %86 +%89 = OpCompositeExtract %uint %85 1 +%91 = OpIAdd %uint %64 %uint_5 +%92 = OpAccessChain %_ptr_StorageBuffer_uint %60 %uint_1 %91 +OpStore %92 %89 +%94 = OpIAdd %uint %64 %uint_6 +%95 = OpAccessChain %_ptr_StorageBuffer_uint %60 %uint_1 %94 +OpStore %95 %54 +%97 = OpIAdd %uint %64 %uint_7 +%98 = OpAccessChain %_ptr_StorageBuffer_uint %60 %uint_1 %97 +OpStore %98 %55 +%100 = OpIAdd %uint %64 %uint_8 +%101 = OpAccessChain %_ptr_StorageBuffer_uint %60 %uint_1 %100 +OpStore %101 %56 +OpBranch %68 +%68 = OpLabel +OpReturn +OpFunctionEnd +)"; + + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + defs_before + func_before, defs_after + func_after + new_funcs, true, + true); +} + +TEST_F(InstBindlessTest, InstBoundsInitStoreUnsizedSSBOArray) { + // #version 450 + // #extension GL_EXT_nonuniform_qualifier : enable + // + // layout(location=0) in nonuniformEXT flat int nu_ii; + // layout(location=1) in float b; + // + // layout(binding=4) buffer bname { float b; } storageBuffer[]; + // + // void main() + // { + // storageBuffer[nu_ii].b = b; + // } + + const std::string defs_before = + R"(OpCapability Shader +OpCapability ShaderNonUniformEXT +OpCapability RuntimeDescriptorArrayEXT +OpCapability StorageBufferArrayNonUniformIndexingEXT +OpExtension "SPV_EXT_descriptor_indexing" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %nu_ii %b +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 450 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpName %main "main" +OpName %bname "bname" +OpMemberName %bname 0 "b" +OpName %storageBuffer "storageBuffer" +OpName %nu_ii "nu_ii" +OpName %b "b" +OpMemberDecorate %bname 0 Offset 0 +OpDecorate %bname BufferBlock +OpDecorate %storageBuffer DescriptorSet 0 +OpDecorate %storageBuffer Binding 4 +OpDecorate %nu_ii Flat +OpDecorate %nu_ii Location 0 +OpDecorate %nu_ii NonUniformEXT +OpDecorate %14 NonUniformEXT +OpDecorate %b Location 1 +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%bname = OpTypeStruct %float +%_runtimearr_bname = OpTypeRuntimeArray %bname +%_ptr_Uniform__runtimearr_bname = OpTypePointer Uniform %_runtimearr_bname +%storageBuffer = OpVariable %_ptr_Uniform__runtimearr_bname Uniform +%int = OpTypeInt 32 1 +%_ptr_Input_int = OpTypePointer Input %int +%nu_ii = OpVariable %_ptr_Input_int Input +%int_0 = OpConstant %int 0 +%_ptr_Input_float = OpTypePointer Input %float +%b = OpVariable %_ptr_Input_float Input +%_ptr_Uniform_float = OpTypePointer Uniform %float +)"; + + const std::string defs_after = + R"(OpCapability Shader +OpCapability ShaderNonUniformEXT +OpCapability RuntimeDescriptorArrayEXT +OpCapability StorageBufferArrayNonUniformIndexingEXT +OpExtension "SPV_EXT_descriptor_indexing" +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %nu_ii %b %gl_FragCoord +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 450 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpName %main "main" +OpName %bname "bname" +OpMemberName %bname 0 "b" +OpName %storageBuffer "storageBuffer" +OpName %nu_ii "nu_ii" +OpName %b "b" +OpMemberDecorate %bname 0 Offset 0 +OpDecorate %bname BufferBlock +OpDecorate %storageBuffer DescriptorSet 0 +OpDecorate %storageBuffer Binding 4 +OpDecorate %nu_ii Flat +OpDecorate %nu_ii Location 0 +OpDecorate %nu_ii NonUniformEXT +OpDecorate %7 NonUniformEXT +OpDecorate %b Location 1 +OpDecorate %_runtimearr_uint ArrayStride 4 +OpDecorate %_struct_31 Block +OpMemberDecorate %_struct_31 0 Offset 0 +OpDecorate %33 DescriptorSet 7 +OpDecorate %33 Binding 1 +OpDecorate %_struct_54 Block +OpMemberDecorate %_struct_54 0 Offset 0 +OpMemberDecorate %_struct_54 1 Offset 4 +OpDecorate %56 DescriptorSet 7 +OpDecorate %56 Binding 0 +OpDecorate %gl_FragCoord BuiltIn FragCoord +%void = OpTypeVoid +%9 = OpTypeFunction %void +%float = OpTypeFloat 32 +%bname = OpTypeStruct %float +%_runtimearr_bname = OpTypeRuntimeArray %bname +%_ptr_Uniform__runtimearr_bname = OpTypePointer Uniform %_runtimearr_bname +%storageBuffer = OpVariable %_ptr_Uniform__runtimearr_bname Uniform +%int = OpTypeInt 32 1 +%_ptr_Input_int = OpTypePointer Input %int +%nu_ii = OpVariable %_ptr_Input_int Input +%int_0 = OpConstant %int 0 +%_ptr_Input_float = OpTypePointer Input %float +%b = OpVariable %_ptr_Input_float Input +%_ptr_Uniform_float = OpTypePointer Uniform %float +%uint = OpTypeInt 32 0 +%uint_0 = OpConstant %uint 0 +%uint_1 = OpConstant %uint 1 +%uint_4 = OpConstant %uint 4 +%26 = OpTypeFunction %uint %uint %uint +%_runtimearr_uint = OpTypeRuntimeArray %uint +%_struct_31 = OpTypeStruct %_runtimearr_uint +%_ptr_StorageBuffer__struct_31 = OpTypePointer StorageBuffer %_struct_31 +%33 = OpVariable %_ptr_StorageBuffer__struct_31 StorageBuffer +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint +%bool = OpTypeBool +%48 = OpTypeFunction %void %uint %uint %uint %uint +%_struct_54 = OpTypeStruct %uint %_runtimearr_uint +%_ptr_StorageBuffer__struct_54 = OpTypePointer StorageBuffer %_struct_54 +%56 = OpVariable %_ptr_StorageBuffer__struct_54 StorageBuffer +%uint_9 = OpConstant %uint 9 +%uint_23 = OpConstant %uint 23 +%uint_2 = OpConstant %uint 2 +%uint_3 = OpConstant %uint 3 +%v4float = OpTypeVector %float 4 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%gl_FragCoord = OpVariable %_ptr_Input_v4float Input +%v4uint = OpTypeVector %uint 4 +%uint_5 = OpConstant %uint 5 +%uint_6 = OpConstant %uint 6 +%uint_7 = OpConstant %uint 7 +%uint_8 = OpConstant %uint 8 +%uint_45 = OpConstant %uint 45 +%102 = OpTypeFunction %uint %uint %uint %uint %uint +)"; + + const std::string func_before = + R"(%main = OpFunction %void None %3 +%5 = OpLabel +%14 = OpLoad %int %nu_ii +%18 = OpLoad %float %b +%20 = OpAccessChain %_ptr_Uniform_float %storageBuffer %14 %int_0 +OpStore %20 %18 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%main = OpFunction %void None %9 +%18 = OpLabel +%7 = OpLoad %int %nu_ii +%19 = OpLoad %float %b +%20 = OpAccessChain %_ptr_Uniform_float %storageBuffer %7 %int_0 +%40 = OpFunctionCall %uint %25 %uint_1 %uint_4 +%42 = OpULessThan %bool %7 %40 +OpSelectionMerge %43 None +OpBranchConditional %42 %44 %45 +%44 = OpLabel +%100 = OpBitcast %uint %7 +%119 = OpFunctionCall %uint %101 %uint_0 %uint_0 %uint_4 %100 +%120 = OpINotEqual %bool %119 %uint_0 +OpSelectionMerge %121 None +OpBranchConditional %120 %122 %123 +%122 = OpLabel +OpStore %20 %19 +OpBranch %121 +%123 = OpLabel +%124 = OpBitcast %uint %7 +%125 = OpFunctionCall %void %47 %uint_45 %uint_1 %124 %uint_0 +OpBranch %121 +%121 = OpLabel +OpBranch %43 +%45 = OpLabel +%46 = OpBitcast %uint %7 +%99 = OpFunctionCall %void %47 %uint_45 %uint_0 %46 %40 +OpBranch %43 +%43 = OpLabel +OpReturn +OpFunctionEnd +)"; + + const std::string new_funcs = + R"(%25 = OpFunction %uint None %26 +%27 = OpFunctionParameter %uint +%28 = OpFunctionParameter %uint +%29 = OpLabel +%35 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %27 +%36 = OpLoad %uint %35 +%37 = OpIAdd %uint %36 %28 +%38 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %37 +%39 = OpLoad %uint %38 +OpReturnValue %39 +OpFunctionEnd +%47 = OpFunction %void None %48 +%49 = OpFunctionParameter %uint +%50 = OpFunctionParameter %uint +%51 = OpFunctionParameter %uint +%52 = OpFunctionParameter %uint +%53 = OpLabel +%57 = OpAccessChain %_ptr_StorageBuffer_uint %56 %uint_0 +%59 = OpAtomicIAdd %uint %57 %uint_4 %uint_0 %uint_9 +%60 = OpIAdd %uint %59 %uint_9 +%61 = OpArrayLength %uint %56 1 +%62 = OpULessThanEqual %bool %60 %61 +OpSelectionMerge %63 None +OpBranchConditional %62 %64 %63 +%64 = OpLabel +%65 = OpIAdd %uint %59 %uint_0 +%66 = OpAccessChain %_ptr_StorageBuffer_uint %56 %uint_1 %65 +OpStore %66 %uint_9 +%68 = OpIAdd %uint %59 %uint_1 +%69 = OpAccessChain %_ptr_StorageBuffer_uint %56 %uint_1 %68 +OpStore %69 %uint_23 +%71 = OpIAdd %uint %59 %uint_2 +%72 = OpAccessChain %_ptr_StorageBuffer_uint %56 %uint_1 %71 +OpStore %72 %49 +%74 = OpIAdd %uint %59 %uint_3 +%75 = OpAccessChain %_ptr_StorageBuffer_uint %56 %uint_1 %74 +OpStore %75 %uint_4 +%79 = OpLoad %v4float %gl_FragCoord +%81 = OpBitcast %v4uint %79 +%82 = OpCompositeExtract %uint %81 0 +%83 = OpIAdd %uint %59 %uint_4 +%84 = OpAccessChain %_ptr_StorageBuffer_uint %56 %uint_1 %83 +OpStore %84 %82 +%85 = OpCompositeExtract %uint %81 1 +%87 = OpIAdd %uint %59 %uint_5 +%88 = OpAccessChain %_ptr_StorageBuffer_uint %56 %uint_1 %87 +OpStore %88 %85 +%90 = OpIAdd %uint %59 %uint_6 +%91 = OpAccessChain %_ptr_StorageBuffer_uint %56 %uint_1 %90 +OpStore %91 %50 +%93 = OpIAdd %uint %59 %uint_7 +%94 = OpAccessChain %_ptr_StorageBuffer_uint %56 %uint_1 %93 +OpStore %94 %51 +%96 = OpIAdd %uint %59 %uint_8 +%97 = OpAccessChain %_ptr_StorageBuffer_uint %56 %uint_1 %96 +OpStore %97 %52 +OpBranch %63 +%63 = OpLabel +OpReturn +OpFunctionEnd +%101 = OpFunction %uint None %102 +%103 = OpFunctionParameter %uint +%104 = OpFunctionParameter %uint +%105 = OpFunctionParameter %uint +%106 = OpFunctionParameter %uint +%107 = OpLabel +%108 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %103 +%109 = OpLoad %uint %108 +%110 = OpIAdd %uint %109 %104 +%111 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %110 +%112 = OpLoad %uint %111 +%113 = OpIAdd %uint %112 %105 +%114 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %113 +%115 = OpLoad %uint %114 +%116 = OpIAdd %uint %115 %106 +%117 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %116 +%118 = OpLoad %uint %117 +OpReturnValue %118 +OpFunctionEnd +)"; + + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + defs_before + func_before, defs_after + func_after + new_funcs, true, + true); +} + +TEST_F(InstBindlessTest, InstBoundsInitLoadSizedUBOArray) { + // #version 450 + // #extension GL_EXT_nonuniform_qualifier : enable + // + // layout(location=0) in nonuniformEXT flat int nu_ii; + // layout(location=0) out float b; + // + // layout(binding=3) uniform uname { float a; } uniformBuffer[128]; + // + // void main() + // { + // b = uniformBuffer[nu_ii].a; + // } + + const std::string defs_before = + R"(OpCapability Shader +OpCapability ShaderNonUniformEXT +OpCapability UniformBufferArrayNonUniformIndexingEXT +OpExtension "SPV_EXT_descriptor_indexing" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %b %nu_ii +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 450 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpName %main "main" +OpName %b "b" +OpName %uname "uname" +OpMemberName %uname 0 "a" +OpName %uniformBuffer "uniformBuffer" +OpName %nu_ii "nu_ii" +OpDecorate %b Location 0 +OpMemberDecorate %uname 0 Offset 0 +OpDecorate %uname Block +OpDecorate %uniformBuffer DescriptorSet 0 +OpDecorate %uniformBuffer Binding 3 +OpDecorate %nu_ii Flat +OpDecorate %nu_ii Location 0 +OpDecorate %nu_ii NonUniformEXT +OpDecorate %18 NonUniformEXT +OpDecorate %22 NonUniformEXT +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%_ptr_Output_float = OpTypePointer Output %float +%b = OpVariable %_ptr_Output_float Output +%uname = OpTypeStruct %float +%uint = OpTypeInt 32 0 +%uint_128 = OpConstant %uint 128 +%_arr_uname_uint_128 = OpTypeArray %uname %uint_128 +%_ptr_Uniform__arr_uname_uint_128 = OpTypePointer Uniform %_arr_uname_uint_128 +%uniformBuffer = OpVariable %_ptr_Uniform__arr_uname_uint_128 Uniform +%int = OpTypeInt 32 1 +%_ptr_Input_int = OpTypePointer Input %int +%nu_ii = OpVariable %_ptr_Input_int Input +%int_0 = OpConstant %int 0 +%_ptr_Uniform_float = OpTypePointer Uniform %float +)"; + + const std::string defs_after = + R"(OpCapability Shader +OpCapability ShaderNonUniformEXT +OpCapability UniformBufferArrayNonUniformIndexingEXT +OpExtension "SPV_EXT_descriptor_indexing" +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %b %nu_ii %gl_FragCoord +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 450 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpName %main "main" +OpName %b "b" +OpName %uname "uname" +OpMemberName %uname 0 "a" +OpName %uniformBuffer "uniformBuffer" +OpName %nu_ii "nu_ii" +OpDecorate %b Location 0 +OpMemberDecorate %uname 0 Offset 0 +OpDecorate %uname Block +OpDecorate %uniformBuffer DescriptorSet 0 +OpDecorate %uniformBuffer Binding 3 +OpDecorate %nu_ii Flat +OpDecorate %nu_ii Location 0 +OpDecorate %nu_ii NonUniformEXT +OpDecorate %7 NonUniformEXT +OpDecorate %89 NonUniformEXT +OpDecorate %120 NonUniformEXT +OpDecorate %_runtimearr_uint ArrayStride 4 +OpDecorate %_struct_39 Block +OpMemberDecorate %_struct_39 0 Offset 0 +OpMemberDecorate %_struct_39 1 Offset 4 +OpDecorate %41 DescriptorSet 7 +OpDecorate %41 Binding 0 +OpDecorate %gl_FragCoord BuiltIn FragCoord +OpDecorate %_struct_98 Block +OpMemberDecorate %_struct_98 0 Offset 0 +OpDecorate %100 DescriptorSet 7 +OpDecorate %100 Binding 1 +OpDecorate %117 NonUniformEXT +%void = OpTypeVoid +%10 = OpTypeFunction %void +%float = OpTypeFloat 32 +%_ptr_Output_float = OpTypePointer Output %float +%b = OpVariable %_ptr_Output_float Output +%uname = OpTypeStruct %float +%uint = OpTypeInt 32 0 +%uint_128 = OpConstant %uint 128 +%_arr_uname_uint_128 = OpTypeArray %uname %uint_128 +%_ptr_Uniform__arr_uname_uint_128 = OpTypePointer Uniform %_arr_uname_uint_128 +%uniformBuffer = OpVariable %_ptr_Uniform__arr_uname_uint_128 Uniform +%int = OpTypeInt 32 1 +%_ptr_Input_int = OpTypePointer Input %int +%nu_ii = OpVariable %_ptr_Input_int Input +%int_0 = OpConstant %int 0 +%_ptr_Uniform_float = OpTypePointer Uniform %float +%uint_0 = OpConstant %uint 0 +%bool = OpTypeBool +%32 = OpTypeFunction %void %uint %uint %uint %uint +%_runtimearr_uint = OpTypeRuntimeArray %uint +%_struct_39 = OpTypeStruct %uint %_runtimearr_uint +%_ptr_StorageBuffer__struct_39 = OpTypePointer StorageBuffer %_struct_39 +%41 = OpVariable %_ptr_StorageBuffer__struct_39 StorageBuffer +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint +%uint_9 = OpConstant %uint 9 +%uint_4 = OpConstant %uint 4 +%uint_1 = OpConstant %uint 1 +%uint_23 = OpConstant %uint 23 +%uint_2 = OpConstant %uint 2 +%uint_3 = OpConstant %uint 3 +%v4float = OpTypeVector %float 4 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%gl_FragCoord = OpVariable %_ptr_Input_v4float Input +%v4uint = OpTypeVector %uint 4 +%uint_5 = OpConstant %uint 5 +%uint_6 = OpConstant %uint 6 +%uint_7 = OpConstant %uint 7 +%uint_8 = OpConstant %uint 8 +%uint_46 = OpConstant %uint 46 +%88 = OpConstantNull %float +%92 = OpTypeFunction %uint %uint %uint %uint %uint +%_struct_98 = OpTypeStruct %_runtimearr_uint +%_ptr_StorageBuffer__struct_98 = OpTypePointer StorageBuffer %_struct_98 +%100 = OpVariable %_ptr_StorageBuffer__struct_98 StorageBuffer +)"; + + const std::string func_before = + R"(%main = OpFunction %void None %3 +%5 = OpLabel +%18 = OpLoad %int %nu_ii +%21 = OpAccessChain %_ptr_Uniform_float %uniformBuffer %18 %int_0 +%22 = OpLoad %float %21 +OpStore %b %22 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%main = OpFunction %void None %10 +%21 = OpLabel +%7 = OpLoad %int %nu_ii +%22 = OpAccessChain %_ptr_Uniform_float %uniformBuffer %7 %int_0 +%25 = OpULessThan %bool %7 %uint_128 +OpSelectionMerge %26 None +OpBranchConditional %25 %27 %28 +%27 = OpLabel +%90 = OpBitcast %uint %7 +%112 = OpFunctionCall %uint %91 %uint_0 %uint_0 %uint_3 %90 +%113 = OpINotEqual %bool %112 %uint_0 +OpSelectionMerge %114 None +OpBranchConditional %113 %115 %116 +%115 = OpLabel +%117 = OpLoad %float %22 +OpBranch %114 +%116 = OpLabel +%118 = OpBitcast %uint %7 +%119 = OpFunctionCall %void %31 %uint_46 %uint_1 %118 %uint_0 +OpBranch %114 +%114 = OpLabel +%120 = OpPhi %float %117 %115 %88 %116 +OpBranch %26 +%28 = OpLabel +%30 = OpBitcast %uint %7 +%87 = OpFunctionCall %void %31 %uint_46 %uint_0 %30 %uint_128 +OpBranch %26 +%26 = OpLabel +%89 = OpPhi %float %120 %114 %88 %28 +OpStore %b %89 +OpReturn +OpFunctionEnd +)"; + + const std::string new_funcs = + R"(%31 = OpFunction %void None %32 +%33 = OpFunctionParameter %uint +%34 = OpFunctionParameter %uint +%35 = OpFunctionParameter %uint +%36 = OpFunctionParameter %uint +%37 = OpLabel +%43 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 +%46 = OpAtomicIAdd %uint %43 %uint_4 %uint_0 %uint_9 +%47 = OpIAdd %uint %46 %uint_9 +%48 = OpArrayLength %uint %41 1 +%49 = OpULessThanEqual %bool %47 %48 +OpSelectionMerge %50 None +OpBranchConditional %49 %51 %50 +%51 = OpLabel +%52 = OpIAdd %uint %46 %uint_0 +%54 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_1 %52 +OpStore %54 %uint_9 +%56 = OpIAdd %uint %46 %uint_1 +%57 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_1 %56 +OpStore %57 %uint_23 +%59 = OpIAdd %uint %46 %uint_2 +%60 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_1 %59 +OpStore %60 %33 +%62 = OpIAdd %uint %46 %uint_3 +%63 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_1 %62 +OpStore %63 %uint_4 +%67 = OpLoad %v4float %gl_FragCoord +%69 = OpBitcast %v4uint %67 +%70 = OpCompositeExtract %uint %69 0 +%71 = OpIAdd %uint %46 %uint_4 +%72 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_1 %71 +OpStore %72 %70 +%73 = OpCompositeExtract %uint %69 1 +%75 = OpIAdd %uint %46 %uint_5 +%76 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_1 %75 +OpStore %76 %73 +%78 = OpIAdd %uint %46 %uint_6 +%79 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_1 %78 +OpStore %79 %34 +%81 = OpIAdd %uint %46 %uint_7 +%82 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_1 %81 +OpStore %82 %35 +%84 = OpIAdd %uint %46 %uint_8 +%85 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_1 %84 +OpStore %85 %36 +OpBranch %50 +%50 = OpLabel +OpReturn +OpFunctionEnd +%91 = OpFunction %uint None %92 +%93 = OpFunctionParameter %uint +%94 = OpFunctionParameter %uint +%95 = OpFunctionParameter %uint +%96 = OpFunctionParameter %uint +%97 = OpLabel +%101 = OpAccessChain %_ptr_StorageBuffer_uint %100 %uint_0 %93 +%102 = OpLoad %uint %101 +%103 = OpIAdd %uint %102 %94 +%104 = OpAccessChain %_ptr_StorageBuffer_uint %100 %uint_0 %103 +%105 = OpLoad %uint %104 +%106 = OpIAdd %uint %105 %95 +%107 = OpAccessChain %_ptr_StorageBuffer_uint %100 %uint_0 %106 +%108 = OpLoad %uint %107 +%109 = OpIAdd %uint %108 %96 +%110 = OpAccessChain %_ptr_StorageBuffer_uint %100 %uint_0 %109 +%111 = OpLoad %uint %110 +OpReturnValue %111 +OpFunctionEnd +)"; + + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + defs_before + func_before, defs_after + func_after + new_funcs, true, + true); +} + // TODO(greg-lunarg): Add tests to verify handling of these cases: // // Compute shader