Update type for loaded builtin GlobalInvocationID in pass instrumentation (#2705)

When working on descriptor indexing validation for compute shaders, the
gl_GlobalInvocationID builtin was being loaded as uint which would cause
compute shaders instrumented by the bindless check pass to have:

%83 = OpLoad %uint %gl_GlobalInvocationID
%84 = OpCompositeExtract %uint %83 0
%85 = OpCompositeExtract %uint %83 1
%86 = OpCompositeExtract %uint %83 2

which results in validation failures:

error: line 127: Reached non-composite type while indexes still remain
to be traversed.
%84 = OpCompositeExtract %uint %83 0

for trying to extract a uint from a uint.
diff --git a/source/opt/ir_context.cpp b/source/opt/ir_context.cpp
index 081fdbc..11146cf 100644
--- a/source/opt/ir_context.cpp
+++ b/source/opt/ir_context.cpp
@@ -678,12 +678,18 @@
       case SpvBuiltInVertexIndex:
       case SpvBuiltInInstanceIndex:
       case SpvBuiltInPrimitiveId:
-      case SpvBuiltInInvocationId:
-      case SpvBuiltInGlobalInvocationId: {
+      case SpvBuiltInInvocationId: {
         analysis::Integer uint_ty(32, false);
         reg_type = type_mgr->GetRegisteredType(&uint_ty);
         break;
       }
+      case SpvBuiltInGlobalInvocationId: {
+        analysis::Integer uint_ty(32, false);
+        analysis::Type* reg_uint_ty = type_mgr->GetRegisteredType(&uint_ty);
+        analysis::Vector v3uint_ty(reg_uint_ty, 3);
+        reg_type = type_mgr->GetRegisteredType(&v3uint_ty);
+        break;
+      }
       default: {
         assert(false && "unhandled builtin");
         return 0;
diff --git a/test/opt/inst_bindless_check_test.cpp b/test/opt/inst_bindless_check_test.cpp
index 4a0fde8..0848deb 100644
--- a/test/opt/inst_bindless_check_test.cpp
+++ b/test/opt/inst_bindless_check_test.cpp
@@ -8276,6 +8276,328 @@
       true, 7u, 23u, true, true, 2u);
 }
 
+TEST_F(InstBindlessTest,
+       InstBoundsComputeShaderInitLoadVariableSizedSampledImagesArray) {
+  // #version 450
+  // #extension GL_EXT_nonuniform_qualifier : enable
+  //
+  // layout (local_size_x = 1, local_size_y = 1) in;
+  //
+  // layout(set = 0, binding = 0, std140) buffer Input {
+  //   uint index;
+  //   float red;
+  // } sbo;
+  //
+  // layout(set = 0, binding = 1, rgba32f) readonly uniform image2D images[];
+  //
+  // void main()
+  // {
+  //    sbo.red = imageLoad(images[sbo.index], ivec2(0, 0)).r;
+  // }
+
+  const std::string defs_before =
+      R"(OpCapability Shader
+OpCapability RuntimeDescriptorArrayEXT
+OpExtension "SPV_EXT_descriptor_indexing"
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 1 1 1
+OpSource GLSL 450
+OpSourceExtension "GL_EXT_nonuniform_qualifier"
+OpName %main "main"
+OpName %Input "Input"
+OpMemberName %Input 0 "index"
+OpMemberName %Input 1 "red"
+OpName %sbo "sbo"
+OpName %images "images"
+OpMemberDecorate %Input 0 Offset 0
+OpMemberDecorate %Input 1 Offset 4
+OpDecorate %Input BufferBlock
+OpDecorate %sbo DescriptorSet 0
+OpDecorate %sbo Binding 0
+OpDecorate %images DescriptorSet 0
+OpDecorate %images Binding 1
+OpDecorate %images NonWritable
+%void = OpTypeVoid
+%3 = OpTypeFunction %void
+%uint = OpTypeInt 32 0
+%float = OpTypeFloat 32
+%Input = OpTypeStruct %uint %float
+%_ptr_Uniform_Input = OpTypePointer Uniform %Input
+%sbo = OpVariable %_ptr_Uniform_Input Uniform
+%int = OpTypeInt 32 1
+%int_1 = OpConstant %int 1
+%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f
+%_runtimearr_13 = OpTypeRuntimeArray %13
+%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13
+%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant
+%int_0 = OpConstant %int 0
+%_ptr_Uniform_uint = OpTypePointer Uniform %uint
+%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13
+%v2int = OpTypeVector %int 2
+%25 = OpConstantComposite %v2int %int_0 %int_0
+%v4float = OpTypeVector %float 4
+%uint_0 = OpConstant %uint 0
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+)";
+
+  const std::string defs_after =
+      R"(OpCapability Shader
+OpCapability RuntimeDescriptorArrayEXT
+OpExtension "SPV_EXT_descriptor_indexing"
+OpExtension "SPV_KHR_storage_buffer_storage_class"
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main" %gl_GlobalInvocationID
+OpExecutionMode %main LocalSize 1 1 1
+OpSource GLSL 450
+OpSourceExtension "GL_EXT_nonuniform_qualifier"
+OpName %main "main"
+OpName %Input "Input"
+OpMemberName %Input 0 "index"
+OpMemberName %Input 1 "red"
+OpName %sbo "sbo"
+OpName %images "images"
+OpMemberDecorate %Input 0 Offset 0
+OpMemberDecorate %Input 1 Offset 4
+OpDecorate %Input BufferBlock
+OpDecorate %sbo DescriptorSet 0
+OpDecorate %sbo Binding 0
+OpDecorate %images DescriptorSet 0
+OpDecorate %images Binding 1
+OpDecorate %images NonWritable
+OpDecorate %_runtimearr_uint ArrayStride 4
+OpDecorate %_struct_39 Block
+OpMemberDecorate %_struct_39 0 Offset 0
+OpDecorate %41 DescriptorSet 7
+OpDecorate %41 Binding 1
+OpDecorate %_struct_63 Block
+OpMemberDecorate %_struct_63 0 Offset 0
+OpMemberDecorate %_struct_63 1 Offset 4
+OpDecorate %65 DescriptorSet 7
+OpDecorate %65 Binding 0
+OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId
+%void = OpTypeVoid
+%7 = OpTypeFunction %void
+%uint = OpTypeInt 32 0
+%float = OpTypeFloat 32
+%Input = OpTypeStruct %uint %float
+%_ptr_Uniform_Input = OpTypePointer Uniform %Input
+%sbo = OpVariable %_ptr_Uniform_Input Uniform
+%int = OpTypeInt 32 1
+%int_1 = OpConstant %int 1
+%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f
+%_runtimearr_13 = OpTypeRuntimeArray %13
+%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13
+%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant
+%int_0 = OpConstant %int 0
+%_ptr_Uniform_uint = OpTypePointer Uniform %uint
+%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13
+%v2int = OpTypeVector %int 2
+%20 = OpConstantComposite %v2int %int_0 %int_0
+%v4float = OpTypeVector %float 4
+%uint_0 = OpConstant %uint 0
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+%uint_1 = OpConstant %uint 1
+%34 = OpTypeFunction %uint %uint %uint
+%_runtimearr_uint = OpTypeRuntimeArray %uint
+%_struct_39 = OpTypeStruct %_runtimearr_uint
+%_ptr_StorageBuffer__struct_39 = OpTypePointer StorageBuffer %_struct_39
+%41 = OpVariable %_ptr_StorageBuffer__struct_39 StorageBuffer
+%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
+%bool = OpTypeBool
+%57 = OpTypeFunction %void %uint %uint %uint %uint
+%_struct_63 = OpTypeStruct %uint %_runtimearr_uint
+%_ptr_StorageBuffer__struct_63 = OpTypePointer StorageBuffer %_struct_63
+%65 = OpVariable %_ptr_StorageBuffer__struct_63 StorageBuffer
+%uint_10 = OpConstant %uint 10
+%uint_4 = OpConstant %uint 4
+%uint_23 = OpConstant %uint 23
+%uint_2 = OpConstant %uint 2
+%uint_5 = OpConstant %uint 5
+%uint_3 = OpConstant %uint 3
+%v3uint = OpTypeVector %uint 3
+%_ptr_Input_v3uint = OpTypePointer Input %v3uint
+%gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input
+%uint_6 = OpConstant %uint 6
+%uint_7 = OpConstant %uint 7
+%uint_8 = OpConstant %uint 8
+%uint_9 = OpConstant %uint 9
+%uint_50 = OpConstant %uint 50
+%112 = OpConstantNull %v4float
+%115 = OpTypeFunction %uint %uint %uint %uint %uint
+%uint_47 = OpConstant %uint 47
+%140 = OpConstantNull %uint
+%uint_53 = OpConstant %uint 53
+)";
+
+  const std::string func_before =
+      R"(%main = OpFunction %void None %3
+%5 = OpLabel
+%19 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0
+%20 = OpLoad %uint %19
+%22 = OpAccessChain %_ptr_UniformConstant_13 %images %20
+%23 = OpLoad %13 %22
+%27 = OpImageRead %v4float %23 %25
+%29 = OpCompositeExtract %float %27 0
+%31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
+OpStore %31 %29
+OpReturn
+OpFunctionEnd
+)";
+
+  const std::string func_after =
+      R"(%main = OpFunction %void None %7
+%24 = OpLabel
+%25 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0
+%132 = OpFunctionCall %uint %114 %uint_0 %uint_0 %uint_0 %uint_0
+%133 = OpINotEqual %bool %132 %uint_0
+OpSelectionMerge %134 None
+OpBranchConditional %133 %135 %136
+%135 = OpLabel
+%137 = OpLoad %uint %25
+OpBranch %134
+%136 = OpLabel
+%139 = OpFunctionCall %void %56 %uint_47 %uint_1 %uint_0 %uint_0
+OpBranch %134
+%134 = OpLabel
+%141 = OpPhi %uint %137 %135 %140 %136
+%27 = OpAccessChain %_ptr_UniformConstant_13 %images %141
+%28 = OpLoad %13 %27
+%48 = OpFunctionCall %uint %33 %uint_1 %uint_1
+%50 = OpULessThan %bool %141 %48
+OpSelectionMerge %51 None
+OpBranchConditional %50 %52 %53
+%52 = OpLabel
+%54 = OpLoad %13 %27
+%142 = OpFunctionCall %uint %114 %uint_0 %uint_0 %uint_1 %141
+%143 = OpINotEqual %bool %142 %uint_0
+OpSelectionMerge %144 None
+OpBranchConditional %143 %145 %146
+%145 = OpLabel
+%147 = OpLoad %13 %27
+%148 = OpImageRead %v4float %147 %20
+OpBranch %144
+%146 = OpLabel
+%149 = OpFunctionCall %void %56 %uint_50 %uint_1 %141 %uint_0
+OpBranch %144
+%144 = OpLabel
+%150 = OpPhi %v4float %148 %145 %112 %146
+OpBranch %51
+%53 = OpLabel
+%111 = OpFunctionCall %void %56 %uint_50 %uint_0 %141 %48
+OpBranch %51
+%51 = OpLabel
+%113 = OpPhi %v4float %150 %144 %112 %53
+%30 = OpCompositeExtract %float %113 0
+%31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
+%151 = OpFunctionCall %uint %114 %uint_0 %uint_0 %uint_0 %uint_0
+%152 = OpINotEqual %bool %151 %uint_0
+OpSelectionMerge %153 None
+OpBranchConditional %152 %154 %155
+%154 = OpLabel
+OpStore %31 %30
+OpBranch %153
+%155 = OpLabel
+%157 = OpFunctionCall %void %56 %uint_53 %uint_1 %uint_0 %uint_0
+OpBranch %153
+%153 = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  const std::string new_funcs =
+      R"(%33 = OpFunction %uint None %34
+%35 = OpFunctionParameter %uint
+%36 = OpFunctionParameter %uint
+%37 = OpLabel
+%43 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %35
+%44 = OpLoad %uint %43
+%45 = OpIAdd %uint %44 %36
+%46 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %45
+%47 = OpLoad %uint %46
+OpReturnValue %47
+OpFunctionEnd
+%56 = OpFunction %void None %57
+%58 = OpFunctionParameter %uint
+%59 = OpFunctionParameter %uint
+%60 = OpFunctionParameter %uint
+%61 = OpFunctionParameter %uint
+%62 = OpLabel
+%66 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_0
+%69 = OpAtomicIAdd %uint %66 %uint_4 %uint_0 %uint_10
+%70 = OpIAdd %uint %69 %uint_10
+%71 = OpArrayLength %uint %65 1
+%72 = OpULessThanEqual %bool %70 %71
+OpSelectionMerge %73 None
+OpBranchConditional %72 %74 %73
+%74 = OpLabel
+%75 = OpIAdd %uint %69 %uint_0
+%76 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %75
+OpStore %76 %uint_10
+%78 = OpIAdd %uint %69 %uint_1
+%79 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %78
+OpStore %79 %uint_23
+%81 = OpIAdd %uint %69 %uint_2
+%82 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %81
+OpStore %82 %58
+%85 = OpIAdd %uint %69 %uint_3
+%86 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %85
+OpStore %86 %uint_5
+%90 = OpLoad %v3uint %gl_GlobalInvocationID
+%91 = OpCompositeExtract %uint %90 0
+%92 = OpCompositeExtract %uint %90 1
+%93 = OpCompositeExtract %uint %90 2
+%94 = OpIAdd %uint %69 %uint_4
+%95 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %94
+OpStore %95 %91
+%96 = OpIAdd %uint %69 %uint_5
+%97 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %96
+OpStore %97 %92
+%99 = OpIAdd %uint %69 %uint_6
+%100 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %99
+OpStore %100 %93
+%102 = OpIAdd %uint %69 %uint_7
+%103 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %102
+OpStore %103 %59
+%105 = OpIAdd %uint %69 %uint_8
+%106 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %105
+OpStore %106 %60
+%108 = OpIAdd %uint %69 %uint_9
+%109 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %108
+OpStore %109 %61
+OpBranch %73
+%73 = OpLabel
+OpReturn
+OpFunctionEnd
+%114 = OpFunction %uint None %115
+%116 = OpFunctionParameter %uint
+%117 = OpFunctionParameter %uint
+%118 = OpFunctionParameter %uint
+%119 = OpFunctionParameter %uint
+%120 = OpLabel
+%121 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %116
+%122 = OpLoad %uint %121
+%123 = OpIAdd %uint %122 %117
+%124 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %123
+%125 = OpLoad %uint %124
+%126 = OpIAdd %uint %125 %118
+%127 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %126
+%128 = OpLoad %uint %127
+%129 = OpIAdd %uint %128 %119
+%130 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %129
+%131 = OpLoad %uint %130
+OpReturnValue %131
+OpFunctionEnd
+)";
+
+  // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+  SinglePassRunAndCheck<InstBindlessCheckPass>(
+      defs_before + func_before, defs_after + func_after + new_funcs, true,
+      true, 7u, 23u, true, true, 2u);
+}
+
 // TODO(greg-lunarg): Add tests to verify handling of these cases:
 //
 //   Compute shader