Instrument: Change output buffer offset definitions (#4961)

Add a flags field at the first offset within this buffer.
Define flags to allow buffer OOB checking to be enabled or
disabled at run time. This is to support VK_EXT_pipeline_robustnes.
This commit is contained in:
Jeremy Gebben 2022-11-10 10:35:18 -07:00 committed by GitHub
parent 996d4c021f
commit 68e8327f29
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 135 additions and 615 deletions

View File

@ -36,16 +36,25 @@ namespace spvtools {
// generated by InstrumentPass::GenDebugStreamWrite. This method is utilized // generated by InstrumentPass::GenDebugStreamWrite. This method is utilized
// by InstBindlessCheckPass, InstBuffAddrCheckPass, and InstDebugPrintfPass. // by InstBindlessCheckPass, InstBuffAddrCheckPass, and InstDebugPrintfPass.
// //
// The first member of the debug output buffer contains the next available word // The 1st member of the debug output buffer contains a set of flags
// controlling the behavior of instrumentation code.
static const int kDebugOutputFlagsOffset = 0;
// Values stored at kDebugOutputFlagsOffset
enum kInstFlags : unsigned int {
kInstBufferOOBEnable = 0x1,
};
// The 2nd member of the debug output buffer contains the next available word
// in the data stream to be written. Shaders will atomically read and update // in the data stream to be written. Shaders will atomically read and update
// this value so as not to overwrite each others records. This value must be // this value so as not to overwrite each others records. This value must be
// initialized to zero // initialized to zero
static const int kDebugOutputSizeOffset = 0; static const int kDebugOutputSizeOffset = 1;
// The second member of the output buffer is the start of the stream of records // The 3rd member of the output buffer is the start of the stream of records
// written by the instrumented shaders. Each record represents a validation // written by the instrumented shaders. Each record represents a validation
// error. The format of the records is documented below. // error. The format of the records is documented below.
static const int kDebugOutputDataOffset = 1; static const int kDebugOutputDataOffset = 2;
// Common Stream Record Offsets // Common Stream Record Offsets
// //

View File

@ -554,7 +554,7 @@ uint32_t InstrumentPass::GetOutputBufferId() {
analysis::Type* reg_uint_rarr_ty = GetUintRuntimeArrayType(32); analysis::Type* reg_uint_rarr_ty = GetUintRuntimeArrayType(32);
analysis::Integer uint_ty(32, false); analysis::Integer uint_ty(32, false);
analysis::Type* reg_uint_ty = type_mgr->GetRegisteredType(&uint_ty); analysis::Type* reg_uint_ty = type_mgr->GetRegisteredType(&uint_ty);
analysis::Struct buf_ty({reg_uint_ty, reg_uint_rarr_ty}); analysis::Struct buf_ty({reg_uint_ty, reg_uint_ty, reg_uint_rarr_ty});
analysis::Type* reg_buf_ty = type_mgr->GetRegisteredType(&buf_ty); analysis::Type* reg_buf_ty = type_mgr->GetRegisteredType(&buf_ty);
uint32_t obufTyId = type_mgr->GetTypeInstruction(reg_buf_ty); uint32_t obufTyId = type_mgr->GetTypeInstruction(reg_buf_ty);
// By the Vulkan spec, a pre-existing struct containing a RuntimeArray // By the Vulkan spec, a pre-existing struct containing a RuntimeArray
@ -566,10 +566,12 @@ uint32_t InstrumentPass::GetOutputBufferId() {
assert(context()->get_def_use_mgr()->NumUses(obufTyId) == 0 && assert(context()->get_def_use_mgr()->NumUses(obufTyId) == 0 &&
"used struct type returned"); "used struct type returned");
deco_mgr->AddDecoration(obufTyId, uint32_t(spv::Decoration::Block)); deco_mgr->AddDecoration(obufTyId, uint32_t(spv::Decoration::Block));
deco_mgr->AddMemberDecoration(obufTyId, kDebugOutputSizeOffset, deco_mgr->AddMemberDecoration(obufTyId, kDebugOutputFlagsOffset,
uint32_t(spv::Decoration::Offset), 0); uint32_t(spv::Decoration::Offset), 0);
deco_mgr->AddMemberDecoration(obufTyId, kDebugOutputDataOffset, deco_mgr->AddMemberDecoration(obufTyId, kDebugOutputSizeOffset,
uint32_t(spv::Decoration::Offset), 4); uint32_t(spv::Decoration::Offset), 4);
deco_mgr->AddMemberDecoration(obufTyId, kDebugOutputDataOffset,
uint32_t(spv::Decoration::Offset), 8);
uint32_t obufTyPtrId_ = uint32_t obufTyPtrId_ =
type_mgr->FindPointerToType(obufTyId, spv::StorageClass::StorageBuffer); type_mgr->FindPointerToType(obufTyId, spv::StorageClass::StorageBuffer);
output_buffer_id_ = TakeNextId(); output_buffer_id_ = TakeNextId();
@ -579,8 +581,9 @@ uint32_t InstrumentPass::GetOutputBufferId() {
{uint32_t(spv::StorageClass::StorageBuffer)}}})); {uint32_t(spv::StorageClass::StorageBuffer)}}}));
context()->AddGlobalValue(std::move(newVarOp)); context()->AddGlobalValue(std::move(newVarOp));
context()->AddDebug2Inst(NewGlobalName(obufTyId, "OutputBuffer")); context()->AddDebug2Inst(NewGlobalName(obufTyId, "OutputBuffer"));
context()->AddDebug2Inst(NewMemberName(obufTyId, 0, "written_count")); context()->AddDebug2Inst(NewMemberName(obufTyId, 0, "flags"));
context()->AddDebug2Inst(NewMemberName(obufTyId, 1, "data")); context()->AddDebug2Inst(NewMemberName(obufTyId, 1, "written_count"));
context()->AddDebug2Inst(NewMemberName(obufTyId, 2, "data"));
context()->AddDebug2Inst(NewGlobalName(output_buffer_id_, "output_buffer")); context()->AddDebug2Inst(NewGlobalName(output_buffer_id_, "output_buffer"));
deco_mgr->AddDecorationVal( deco_mgr->AddDecorationVal(
output_buffer_id_, uint32_t(spv::Decoration::DescriptorSet), desc_set_); output_buffer_id_, uint32_t(spv::Decoration::DescriptorSet), desc_set_);

File diff suppressed because it is too large Load Diff

View File

@ -36,7 +36,7 @@ static const std::string kOutputDecorations = R"(
)"; )";
static const std::string kOutputGlobals = R"( static const std::string kOutputGlobals = R"(
; CHECK: [[output_buffer_type]] = OpTypeStruct %uint %_runtimearr_uint ; CHECK: [[output_buffer_type]] = OpTypeStruct %uint %uint %_runtimearr_uint
; CHECK: [[output_ptr_type:%\w+]] = OpTypePointer StorageBuffer [[output_buffer_type]] ; CHECK: [[output_ptr_type:%\w+]] = OpTypePointer StorageBuffer [[output_buffer_type]]
; CHECK: [[output_buffer_var]] = OpVariable [[output_ptr_type]] StorageBuffer ; CHECK: [[output_buffer_var]] = OpVariable [[output_ptr_type]] StorageBuffer
)"; )";
@ -48,34 +48,34 @@ static const std::string kStreamWrite4Begin = R"(
; CHECK: [[param_3:%\w+]] = OpFunctionParameter %uint ; CHECK: [[param_3:%\w+]] = OpFunctionParameter %uint
; CHECK: [[param_4:%\w+]] = OpFunctionParameter %uint ; CHECK: [[param_4:%\w+]] = OpFunctionParameter %uint
; CHECK: {{%\w+}} = OpLabel ; CHECK: {{%\w+}} = OpLabel
; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_0 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_1
; CHECK: {{%\w+}} = OpAtomicIAdd %uint {{%\w+}} %uint_4 %uint_0 %uint_10 ; CHECK: {{%\w+}} = OpAtomicIAdd %uint {{%\w+}} %uint_4 %uint_0 %uint_10
; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_10 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_10
; CHECK: {{%\w+}} = OpArrayLength %uint [[output_buffer_var]] 1 ; CHECK: {{%\w+}} = OpArrayLength %uint [[output_buffer_var]] 2
; CHECK: {{%\w+}} = OpULessThanEqual %bool {{%\w+}} {{%\w+}} ; CHECK: {{%\w+}} = OpULessThanEqual %bool {{%\w+}} {{%\w+}}
; CHECK: OpSelectionMerge {{%\w+}} None ; CHECK: OpSelectionMerge {{%\w+}} None
; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
; CHECK: {{%\w+}} = OpLabel ; CHECK: {{%\w+}} = OpLabel
; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_0 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_0
; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_1 {{%\w+}} ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
; CHECK: OpStore {{%\w+}} %uint_10 ; CHECK: OpStore {{%\w+}} %uint_10
; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_1 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_1
; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_1 {{%\w+}} ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
; CHECK: OpStore {{%\w+}} %uint_23 ; CHECK: OpStore {{%\w+}} %uint_23
; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_2 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_2
; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_1 {{%\w+}} ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
; CHECK: OpStore {{%\w+}} [[param_1]] ; CHECK: OpStore {{%\w+}} [[param_1]]
)"; )";
static const std::string kStreamWrite4End = R"( static const std::string kStreamWrite4End = R"(
; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_7 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_7
; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_1 {{%\w+}} ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
; CHECK: OpStore {{%\w+}} [[param_2]] ; CHECK: OpStore {{%\w+}} [[param_2]]
; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_8 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_8
; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_1 {{%\w+}} ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
; CHECK: OpStore {{%\w+}} [[param_3]] ; CHECK: OpStore {{%\w+}} [[param_3]]
; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_9 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_9
; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_1 {{%\w+}} ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
; CHECK: OpStore {{%\w+}} [[param_4]] ; CHECK: OpStore {{%\w+}} [[param_4]]
; CHECK: OpBranch {{%\w+}} ; CHECK: OpBranch {{%\w+}}
; CHECK: {{%\w+}} = OpLabel ; CHECK: {{%\w+}} = OpLabel
@ -86,36 +86,36 @@ static const std::string kStreamWrite4End = R"(
// clang-format off // clang-format off
static const std::string kStreamWrite4Frag = kStreamWrite4Begin + R"( static const std::string kStreamWrite4Frag = kStreamWrite4Begin + R"(
; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3
; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_1 {{%\w+}} ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
; CHECK: OpStore {{%\w+}} %uint_4 ; CHECK: OpStore {{%\w+}} %uint_4
; CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord ; CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
; CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}} ; CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 ; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_4 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_4
; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_1 {{%\w+}} ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
; CHECK: OpStore {{%\w+}} {{%\w+}} ; CHECK: OpStore {{%\w+}} {{%\w+}}
; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 ; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_5 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_5
; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_1 {{%\w+}} ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
; CHECK: OpStore {{%\w+}} {{%\w+}} ; CHECK: OpStore {{%\w+}} {{%\w+}}
)" + kStreamWrite4End; )" + kStreamWrite4End;
static const std::string kStreamWrite4Compute = kStreamWrite4Begin + R"( static const std::string kStreamWrite4Compute = kStreamWrite4Begin + R"(
; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3
; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_1 {{%\w+}} ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
; CHECK: OpStore {{%\w+}} %uint_5 ; CHECK: OpStore {{%\w+}} %uint_5
; CHECK: {{%\w+}} = OpLoad %v3uint %gl_GlobalInvocationID ; CHECK: {{%\w+}} = OpLoad %v3uint %gl_GlobalInvocationID
; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 ; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 ; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 ; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_4 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_4
; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_1 {{%\w+}} ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
; CHECK: OpStore {{%\w+}} {{%\w+}} ; CHECK: OpStore {{%\w+}} {{%\w+}}
; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_5 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_5
; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_1 {{%\w+}} ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
; CHECK: OpStore {{%\w+}} {{%\w+}} ; CHECK: OpStore {{%\w+}} {{%\w+}}
; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_6 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_6
; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_1 {{%\w+}} ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}}
; CHECK: OpStore {{%\w+}} {{%\w+}} ; CHECK: OpStore {{%\w+}} {{%\w+}}
)" + kStreamWrite4End; )" + kStreamWrite4End;
// clang-format on // clang-format on
@ -251,31 +251,18 @@ OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_bufStruct PhysicalStorageBuffer
%int_3239 = OpConstant %int 3239 %int_3239 = OpConstant %int 3239
%_ptr_PhysicalStorageBuffer_int = OpTypePointer PhysicalStorageBuffer %int %_ptr_PhysicalStorageBuffer_int = OpTypePointer PhysicalStorageBuffer %int
; CHECK: %ulong = OpTypeInt 64 0 ; CHECK: %ulong = OpTypeInt 64 0
; CHECK: %uint_4 = OpConstant %uint 4
; CHECK: %bool = OpTypeBool ; CHECK: %bool = OpTypeBool
; CHECK: %28 = OpTypeFunction %bool %ulong %uint ; CHECK: %28 = OpTypeFunction %bool %ulong %uint
; CHECK: %uint_1 = OpConstant %uint 1
; CHECK: %_runtimearr_ulong = OpTypeRuntimeArray %ulong ; CHECK: %_runtimearr_ulong = OpTypeRuntimeArray %ulong
)" + kInputGlobals + R"( )" + kInputGlobals + R"(
; CHECK: %_ptr_StorageBuffer_ulong = OpTypePointer StorageBuffer %ulong ; CHECK: %_ptr_StorageBuffer_ulong = OpTypePointer StorageBuffer %ulong
; CHECK: %uint_0 = OpConstant %uint 0
; CHECK: %uint_32 = OpConstant %uint 32
; CHECK: %70 = OpTypeFunction %void %uint %uint %uint %uint ; CHECK: %70 = OpTypeFunction %void %uint %uint %uint %uint
; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint ; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint
)" + kOutputGlobals + R"( )" + kOutputGlobals + R"(
; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint ; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
; CHECK: %uint_10 = OpConstant %uint 10
; CHECK: %uint_23 = OpConstant %uint 23
; CHECK: %uint_5 = OpConstant %uint 5
; CHECK: %uint_3 = OpConstant %uint 3
; CHECK: %v3uint = OpTypeVector %uint 3 ; CHECK: %v3uint = OpTypeVector %uint 3
; CHECK: %_ptr_Input_v3uint = OpTypePointer Input %v3uint ; CHECK: %_ptr_Input_v3uint = OpTypePointer Input %v3uint
; CHECK: %gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input ; CHECK: %gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input
; CHECK: %uint_6 = OpConstant %uint 6
; CHECK: %uint_7 = OpConstant %uint 7
; CHECK: %uint_8 = OpConstant %uint 8
; CHECK: %uint_9 = OpConstant %uint 9
; CHECK: %uint_48 = OpConstant %uint 48
)"; )";
// clang-format off // clang-format off

View File

@ -30,12 +30,13 @@ static const std::string kOutputDecorations = R"(
; CHECK: OpDecorate [[output_buffer_type:%inst_printf_OutputBuffer]] Block ; CHECK: OpDecorate [[output_buffer_type:%inst_printf_OutputBuffer]] Block
; CHECK: OpMemberDecorate [[output_buffer_type]] 0 Offset 0 ; CHECK: OpMemberDecorate [[output_buffer_type]] 0 Offset 0
; CHECK: OpMemberDecorate [[output_buffer_type]] 1 Offset 4 ; CHECK: OpMemberDecorate [[output_buffer_type]] 1 Offset 4
; CHECK: OpMemberDecorate [[output_buffer_type]] 2 Offset 8
; CHECK: OpDecorate [[output_buffer_var:%\w+]] DescriptorSet 7 ; CHECK: OpDecorate [[output_buffer_var:%\w+]] DescriptorSet 7
; CHECK: OpDecorate [[output_buffer_var]] Binding 3 ; CHECK: OpDecorate [[output_buffer_var]] Binding 3
)"; )";
static const std::string kOutputGlobals = R"( static const std::string kOutputGlobals = R"(
; CHECK: [[output_buffer_type]] = OpTypeStruct %uint %_runtimearr_uint ; CHECK: [[output_buffer_type]] = OpTypeStruct %uint %uint %_runtimearr_uint
; CHECK: [[output_ptr_type:%\w+]] = OpTypePointer StorageBuffer [[output_buffer_type]] ; CHECK: [[output_ptr_type:%\w+]] = OpTypePointer StorageBuffer [[output_buffer_type]]
; CHECK: [[output_buffer_var]] = OpVariable [[output_ptr_type]] StorageBuffer ; CHECK: [[output_buffer_var]] = OpVariable [[output_ptr_type]] StorageBuffer
)"; )";
@ -149,60 +150,60 @@ OpFunctionEnd
const std::string output_func = R"( const std::string output_func = R"(
; CHECK: %inst_printf_stream_write_6 = OpFunction %void None %38 ; CHECK: %inst_printf_stream_write_6 = OpFunction %void None %38
; CHECK: %39 = OpFunctionParameter %uint ; CHECK: [[param_1:%\w+]] = OpFunctionParameter %uint
; CHECK: %40 = OpFunctionParameter %uint ; CHECK: [[param_2:%\w+]] = OpFunctionParameter %uint
; CHECK: %41 = OpFunctionParameter %uint ; CHECK: [[param_3:%\w+]] = OpFunctionParameter %uint
; CHECK: %42 = OpFunctionParameter %uint ; CHECK: [[param_4:%\w+]] = OpFunctionParameter %uint
; CHECK: %43 = OpFunctionParameter %uint ; CHECK: [[param_5:%\w+]] = OpFunctionParameter %uint
; CHECK: %44 = OpFunctionParameter %uint ; CHECK: [[param_6:%\w+]] = OpFunctionParameter %uint
; CHECK: %45 = OpLabel ; CHECK: {{%\w+}} = OpLabel
; CHECK: %52 = OpAccessChain %_ptr_StorageBuffer_uint %inst_printf_output_buffer %uint_0 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint %inst_printf_output_buffer %uint_1
; CHECK: %55 = OpAtomicIAdd %uint %52 %uint_4 %uint_0 %uint_12 ; CHECK: {{%\w+}} = OpAtomicIAdd %uint {{%\w+}} %uint_4 %uint_0 %uint_12
; CHECK: %56 = OpIAdd %uint %55 %uint_12 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_12
; CHECK: %57 = OpArrayLength %uint %inst_printf_output_buffer 1 ; CHECK: {{%\w+}} = OpArrayLength %uint %inst_printf_output_buffer 2
; CHECK: %59 = OpULessThanEqual %bool %56 %57 ; CHECK: {{%\w+}} = OpULessThanEqual %bool {{%\w+}} {{%\w+}}
; CHECK: OpSelectionMerge %60 None ; CHECK: OpSelectionMerge {{%\w+}} None
; CHECK: OpBranchConditional %59 %61 %60 ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
; CHECK: %61 = OpLabel ; CHECK: {{%\w+}} = OpLabel
; CHECK: %62 = OpIAdd %uint %55 %uint_0 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_0
; CHECK: %64 = OpAccessChain %_ptr_StorageBuffer_uint %inst_printf_output_buffer %uint_1 %62 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint %inst_printf_output_buffer %uint_2 {{%\w+}}
; CHECK: OpStore %64 %uint_12 ; CHECK: OpStore {{%\w+}} %uint_12
; CHECK: %66 = OpIAdd %uint %55 %uint_1 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_1
; CHECK: %67 = OpAccessChain %_ptr_StorageBuffer_uint %inst_printf_output_buffer %uint_1 %66 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint %inst_printf_output_buffer %uint_2 {{%\w+}}
; CHECK: OpStore %67 %uint_23 ; CHECK: OpStore {{%\w+}} %uint_23
; CHECK: %69 = OpIAdd %uint %55 %uint_2 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_2
; CHECK: %70 = OpAccessChain %_ptr_StorageBuffer_uint %inst_printf_output_buffer %uint_1 %69 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint %inst_printf_output_buffer %uint_2 {{%\w+}}
; CHECK: OpStore %70 %39 ; CHECK: OpStore {{%\w+}} [[param_1]]
; CHECK: %72 = OpIAdd %uint %55 %uint_3 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3
; CHECK: %73 = OpAccessChain %_ptr_StorageBuffer_uint %inst_printf_output_buffer %uint_1 %72 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint %inst_printf_output_buffer %uint_2 {{%\w+}}
; CHECK: OpStore %73 %uint_4 ; CHECK: OpStore {{%\w+}} %uint_4
; CHECK: %76 = OpLoad %v4float %gl_FragCoord ; CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
; CHECK: %78 = OpBitcast %v4uint %76 ; CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
; CHECK: %79 = OpCompositeExtract %uint %78 0 ; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
; CHECK: %80 = OpIAdd %uint %55 %uint_4 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_4
; CHECK: %81 = OpAccessChain %_ptr_StorageBuffer_uint %inst_printf_output_buffer %uint_1 %80 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint %inst_printf_output_buffer %uint_2 {{%\w+}}
; CHECK: OpStore %81 %79 ; CHECK: OpStore {{%\w+}} {{%\w+}}
; CHECK: %82 = OpCompositeExtract %uint %78 1 ; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
; CHECK: %83 = OpIAdd %uint %55 %uint_5 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_5
; CHECK: %84 = OpAccessChain %_ptr_StorageBuffer_uint %inst_printf_output_buffer %uint_1 %83 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint %inst_printf_output_buffer %uint_2 {{%\w+}}
; CHECK: OpStore %84 %82 ; CHECK: OpStore {{%\w+}} {{%\w+}}
; CHECK: %86 = OpIAdd %uint %55 %uint_7 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_7
; CHECK: %87 = OpAccessChain %_ptr_StorageBuffer_uint %inst_printf_output_buffer %uint_1 %86 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint %inst_printf_output_buffer %uint_2 {{%\w+}}
; CHECK: OpStore %87 %40 ; CHECK: OpStore {{%\w+}} [[param_2]]
; CHECK: %89 = OpIAdd %uint %55 %uint_8 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_8
; CHECK: %90 = OpAccessChain %_ptr_StorageBuffer_uint %inst_printf_output_buffer %uint_1 %89 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint %inst_printf_output_buffer %uint_2 {{%\w+}}
; CHECK: OpStore %90 %41 ; CHECK: OpStore {{%\w+}} [[param_3]]
; CHECK: %92 = OpIAdd %uint %55 %uint_9 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_9
; CHECK: %93 = OpAccessChain %_ptr_StorageBuffer_uint %inst_printf_output_buffer %uint_1 %92 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint %inst_printf_output_buffer %uint_2 {{%\w+}}
; CHECK: OpStore %93 %42 ; CHECK: OpStore {{%\w+}} [[param_4]]
; CHECK: %95 = OpIAdd %uint %55 %uint_10 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_10
; CHECK: %96 = OpAccessChain %_ptr_StorageBuffer_uint %inst_printf_output_buffer %uint_1 %95 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint %inst_printf_output_buffer %uint_2 {{%\w+}}
; CHECK: OpStore %96 %43 ; CHECK: OpStore {{%\w+}} [[param_5]]
; CHECK: %98 = OpIAdd %uint %55 %uint_11 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_11
; CHECK: %99 = OpAccessChain %_ptr_StorageBuffer_uint %inst_printf_output_buffer %uint_1 %98 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint %inst_printf_output_buffer %uint_2 {{%\w+}}
; CHECK: OpStore %99 %44 ; CHECK: OpStore {{%\w+}} [[param_6]]
; CHECK: OpBranch %60 ; CHECK: OpBranch {{%\w+}}
; CHECK: %60 = OpLabel ; CHECK: {{%\w+}} = OpLabel
; CHECK: OpReturn ; CHECK: OpReturn
; CHECK: OpFunctionEnd ; CHECK: OpFunctionEnd
)"; )";