1// Copyright (c) 2017-2022 Valve Corporation
2// Copyright (c) 2017-2022 LunarG Inc.
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//     http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16// Bindless Check Instrumentation Tests.
17
18#include <string>
19#include <vector>
20
21#include "test/opt/pass_fixture.h"
22#include "test/opt/pass_utils.h"
23
24namespace spvtools {
25namespace opt {
26namespace {
27
28using InstBindlessTest = PassTest<::testing::Test>;
29
30static const std::string kFuncName = "inst_bindless_check_desc";
31
32static const std::string kImportDeco = R"(
33;CHECK: OpDecorate %)" + kFuncName + R"( LinkageAttributes ")" +
34                                       kFuncName + R"(" Import
35)";
36
37static const std::string kImportStub = R"(
38;CHECK: %)" + kFuncName + R"( = OpFunction %bool None {{%\w+}}
39;CHECK: OpFunctionEnd
40)";
41
42TEST_F(InstBindlessTest, Simple) {
43  // Texture2D g_tColor[128];
44  //
45  // layout(push_constant) cbuffer PerViewConstantBuffer_t
46  // {
47  //   uint g_nDataIdx;
48  // };
49  //
50  // SamplerState g_sAniso;
51  //
52  // struct PS_INPUT
53  // {
54  //   float2 vTextureCoords : TEXCOORD2;
55  // };
56  //
57  // struct PS_OUTPUT
58  // {
59  //   float4 vColor : SV_Target0;
60  // };
61  //
62  // PS_OUTPUT MainPs(PS_INPUT i)
63  // {
64  //   PS_OUTPUT ps_output;
65  //   ps_output.vColor =
66  //       g_tColor[ g_nDataIdx ].Sample(g_sAniso, i.vTextureCoords.xy);
67  //   return ps_output;
68  // }
69
70  const std::string entry = R"(
71OpCapability Shader
72;CHECK: OpCapability Linkage
73%1 = OpExtInstImport "GLSL.std.450"
74OpMemoryModel Logical GLSL450
75OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor
76;CHECK: OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord
77OpExecutionMode %MainPs OriginUpperLeft
78OpSource HLSL 500
79)";
80
81  // clang-format off
82  const std::string names_annots = R"(
83OpName %MainPs "MainPs"
84OpName %g_tColor "g_tColor"
85OpName %PerViewConstantBuffer_t "PerViewConstantBuffer_t"
86OpMemberName %PerViewConstantBuffer_t 0 "g_nDataIdx"
87OpName %_ ""
88OpName %g_sAniso "g_sAniso"
89OpName %i_vTextureCoords "i.vTextureCoords"
90OpName %_entryPointOutput_vColor "@entryPointOutput.vColor"
91OpDecorate %g_tColor DescriptorSet 3
92OpDecorate %g_tColor Binding 0
93OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0
94OpDecorate %PerViewConstantBuffer_t Block
95OpDecorate %g_sAniso DescriptorSet 0
96OpDecorate %i_vTextureCoords Location 0
97OpDecorate %_entryPointOutput_vColor Location 0)"
98+ kImportDeco +
99R"(
100;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
101)";
102
103  const std::string consts_types_vars = R"(
104%void = OpTypeVoid
105%10 = OpTypeFunction %void
106%float = OpTypeFloat 32
107%v2float = OpTypeVector %float 2
108%v4float = OpTypeVector %float 4
109%int = OpTypeInt 32 1
110%int_0 = OpConstant %int 0
111%16 = OpTypeImage %float 2D 0 0 0 1 Unknown
112%uint = OpTypeInt 32 0
113%uint_128 = OpConstant %uint 128
114%_arr_16_uint_128 = OpTypeArray %16 %uint_128
115%_ptr_UniformConstant__arr_16_uint_128 = OpTypePointer UniformConstant %_arr_16_uint_128
116%g_tColor = OpVariable %_ptr_UniformConstant__arr_16_uint_128 UniformConstant
117%PerViewConstantBuffer_t = OpTypeStruct %uint
118%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t
119%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant
120%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint
121%_ptr_UniformConstant_16 = OpTypePointer UniformConstant %16
122%24 = OpTypeSampler
123%_ptr_UniformConstant_24 = OpTypePointer UniformConstant %24
124%g_sAniso = OpVariable %_ptr_UniformConstant_24 UniformConstant
125%26 = OpTypeSampledImage %16
126%_ptr_Input_v2float = OpTypePointer Input %v2float
127%i_vTextureCoords = OpVariable %_ptr_Input_v2float Input
128%_ptr_Output_v4float = OpTypePointer Output %v4float
129%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output
130;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
131;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
132;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
133)";
134
135  const std::string main_func = R"(
136%MainPs = OpFunction %void None %10
137%29 = OpLabel
138%30 = OpLoad %v2float %i_vTextureCoords
139%31 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0
140%32 = OpLoad %uint %31
141%33 = OpAccessChain %_ptr_UniformConstant_16 %g_tColor %32
142%34 = OpLoad %16 %33
143%35 = OpLoad %24 %g_sAniso
144%36 = OpSampledImage %26 %34 %35
145%37 = OpImageSampleImplicitLod %v4float %36 %30
146OpStore %_entryPointOutput_vColor %37
147;CHECK-NOT: %37 = OpImageSampleImplicitLod %v4float %36 %30
148;CHECK-NOT: OpStore %_entryPointOutput_vColor %37
149;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_57 {{%\w+}} %uint_3 %uint_0 %32 %uint_0
150;CHECK: OpSelectionMerge {{%\w+}} None
151;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
152;CHECK: {{%\w+}} = OpLabel
153;CHECK: {{%\w+}} = OpLoad %16 %33
154;CHECK: {{%\w+}} = OpSampledImage %26 {{%\w+}} %35
155;CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %30
156;CHECK: OpBranch {{%\w+}}
157;CHECK: {{%\w+}} = OpLabel
158;CHECK: OpBranch {{%\w+}}
159;CHECK: {{%\w+}} = OpLabel
160;CHECK: [[phi_result:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
161;CHECK: OpStore %_entryPointOutput_vColor [[phi_result]]
162OpReturn
163OpFunctionEnd
164)";
165  // clang-format on
166
167  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
168  SinglePassRunAndMatch<InstBindlessCheckPass>(
169      entry + names_annots + consts_types_vars + kImportStub + main_func, true,
170      23u);
171}
172
173TEST_F(InstBindlessTest, InstrumentMultipleInstructions) {
174  // Texture2D g_tColor[128];
175  //
176  // layout(push_constant) cbuffer PerViewConstantBuffer_t
177  // {
178  //   uint g_nDataIdx;
179  //   uint g_nDataIdx2;
180  // };
181  //
182  // SamplerState g_sAniso;
183  //
184  // struct PS_INPUT
185  // {
186  //   float2 vTextureCoords : TEXCOORD2;
187  // };
188  //
189  // struct PS_OUTPUT
190  // {
191  //   float4 vColor : SV_Target0;
192  // };
193  //
194  // PS_OUTPUT MainPs(PS_INPUT i)
195  // {
196  //   PS_OUTPUT ps_output;
197  //
198  //   float t  = g_tColor[g_nDataIdx ].Sample(g_sAniso, i.vTextureCoords.xy);
199  //   float t2 = g_tColor[g_nDataIdx2].Sample(g_sAniso, i.vTextureCoords.xy);
200  //   ps_output.vColor = t + t2;
201  //   return ps_output;
202  // }
203
204  // clang-format off
205  const std::string defs = R"(
206OpCapability Shader
207OpCapability Linkage
208%1 = OpExtInstImport "GLSL.std.450"
209OpMemoryModel Logical GLSL450
210OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor
211;CHECK: OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord
212OpExecutionMode %MainPs OriginUpperLeft
213OpSource HLSL 500
214OpName %MainPs "MainPs"
215OpName %g_tColor "g_tColor"
216OpName %PerViewConstantBuffer_t "PerViewConstantBuffer_t"
217OpMemberName %PerViewConstantBuffer_t 0 "g_nDataIdx"
218OpName %_ ""
219OpName %g_sAniso "g_sAniso"
220OpName %i_vTextureCoords "i.vTextureCoords"
221OpName %_entryPointOutput_vColor "@entryPointOutput.vColor"
222OpDecorate %g_tColor DescriptorSet 3
223OpDecorate %g_tColor Binding 4
224OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0
225OpMemberDecorate %PerViewConstantBuffer_t 1 Offset 4
226OpDecorate %PerViewConstantBuffer_t Block
227OpDecorate %g_sAniso DescriptorSet 3
228OpDecorate %i_vTextureCoords Location 0
229OpDecorate %_entryPointOutput_vColor Location 0
230)" + kImportDeco + R"(
231;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
232%void = OpTypeVoid
233%10 = OpTypeFunction %void
234%float = OpTypeFloat 32
235%v2float = OpTypeVector %float 2
236%v4float = OpTypeVector %float 4
237%int = OpTypeInt 32 1
238%int_0 = OpConstant %int 0
239%int_1 = OpConstant %int 1
240%17 = OpTypeImage %float 2D 0 0 0 1 Unknown
241%uint = OpTypeInt 32 0
242%uint_128 = OpConstant %uint 128
243%_arr_17_uint_128 = OpTypeArray %17 %uint_128
244%_ptr_UniformConstant__arr_17_uint_128 = OpTypePointer UniformConstant %_arr_17_uint_128
245%g_tColor = OpVariable %_ptr_UniformConstant__arr_17_uint_128 UniformConstant
246%PerViewConstantBuffer_t = OpTypeStruct %uint %uint
247%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t
248%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant
249%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint
250%_ptr_UniformConstant_17 = OpTypePointer UniformConstant %17
251%25 = OpTypeSampler
252%_ptr_UniformConstant_25 = OpTypePointer UniformConstant %25
253%g_sAniso = OpVariable %_ptr_UniformConstant_25 UniformConstant
254%27 = OpTypeSampledImage %17
255%_ptr_Input_v2float = OpTypePointer Input %v2float
256%i_vTextureCoords = OpVariable %_ptr_Input_v2float Input
257%_ptr_Output_v4float = OpTypePointer Output %v4float
258%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output
259;CHECK: %v4uint = OpTypeVector %uint 4
260;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
261;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
262;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
263)";
264
265  const std::string main_func = R"(
266%MainPs = OpFunction %void None %10
267%30 = OpLabel
268%31 = OpLoad %v2float %i_vTextureCoords
269%32 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0
270%33 = OpLoad %uint %32
271%34 = OpAccessChain %_ptr_UniformConstant_17 %g_tColor %33
272%35 = OpLoad %17 %34
273%36 = OpLoad %25 %g_sAniso
274%37 = OpSampledImage %27 %35 %36
275%38 = OpImageSampleImplicitLod %v4float %37 %31
276;CHECK-NOT: %38 = OpImageSampleImplicitLod %v4float %37 %31
277;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
278;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
279;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
280;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
281;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
282;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_60 {{%\w+}} %uint_3 %uint_4 %33 %uint_0
283;CHECK: OpSelectionMerge {{%\w+}} None
284;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
285;CHECK: {{%\w+}} = OpLabel
286;CHECK: {{%\w+}} = OpLoad %17 %34
287;CHECK: {{%\w+}} = OpSampledImage %27 {{%\w+}} %36
288;CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %31
289;CHECK: OpBranch {{%\w+}}
290;CHECK: {{%\w+}} = OpLabel
291;CHECK: OpBranch {{%\w+}}
292;CHECK: {{%\w+}} = OpLabel
293;CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
294%39 = OpAccessChain %_ptr_PushConstant_uint %_ %int_1
295%40 = OpLoad %uint %39
296%41 = OpAccessChain %_ptr_UniformConstant_17 %g_tColor %40
297%42 = OpLoad %17 %41
298%43 = OpSampledImage %27 %42 %36
299%44 = OpImageSampleImplicitLod %v4float %43 %31
300%45 = OpFAdd %v4float %38 %44
301;CHECK-NOT: %44 = OpImageSampleImplicitLod %v4float %43 %31
302;CHECK-NOT: %45 = OpFAdd %v4float %38 %44
303;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
304;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
305;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
306;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
307;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
308;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_66 {{%\w+}} %uint_3 %uint_4 %40 %uint_0
309;CHECK: OpSelectionMerge {{%\w+}} None
310;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
311;CHECK: {{%\w+}} = OpLabel
312;CHECK: {{%\w+}} = OpLoad %17 %41
313;CHECK: {{%\w+}} = OpSampledImage %27 {{%\w+}} %36
314;CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %31
315;CHECK: OpBranch {{%\w+}}
316;CHECK: {{%\w+}} = OpLabel
317;CHECK: OpBranch {{%\w+}}
318;CHECK: {{%\w+}} = OpLabel
319;CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
320;CHECK: %45 = OpFAdd %v4float {{%\w+}} {{%\w+}}
321OpStore %_entryPointOutput_vColor %45
322OpReturn
323OpFunctionEnd
324)";
325  // clang-format on
326
327  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
328  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + kImportStub + main_func,
329                                               true, 23u);
330}
331
332TEST_F(InstBindlessTest, InstrumentOpImage) {
333  // This test verifies that the pass will correctly instrument shader
334  // using OpImage. This test was created by editing the SPIR-V
335  // from the Simple test.
336
337  // clang-format off
338  const std::string defs = R"(
339OpCapability Shader
340OpCapability StorageImageReadWithoutFormat
341;CHECK: OpCapability Linkage
342%1 = OpExtInstImport "GLSL.std.450"
343OpMemoryModel Logical GLSL450
344OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor
345;CHECK: OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord
346OpExecutionMode %MainPs OriginUpperLeft
347OpSource HLSL 500
348OpName %MainPs "MainPs"
349OpName %g_tColor "g_tColor"
350OpName %PerViewConstantBuffer_t "PerViewConstantBuffer_t"
351OpMemberName %PerViewConstantBuffer_t 0 "g_nDataIdx"
352OpName %_ ""
353OpName %i_vTextureCoords "i.vTextureCoords"
354OpName %_entryPointOutput_vColor "@entryPointOutput.vColor"
355OpDecorate %g_tColor DescriptorSet 3
356OpDecorate %g_tColor Binding 9
357OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0
358OpDecorate %PerViewConstantBuffer_t Block
359OpDecorate %i_vTextureCoords Location 0
360OpDecorate %_entryPointOutput_vColor Location 0
361)" + kImportDeco + R"(
362;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
363%void = OpTypeVoid
364%3 = OpTypeFunction %void
365%float = OpTypeFloat 32
366%v4float = OpTypeVector %float 4
367%int = OpTypeInt 32 1
368%v2int = OpTypeVector %int 2
369%int_0 = OpConstant %int 0
370%20 = OpTypeImage %float 2D 0 0 0 0 Unknown
371%uint = OpTypeInt 32 0
372%uint_128 = OpConstant %uint 128
373%39 = OpTypeSampledImage %20
374%_arr_39_uint_128 = OpTypeArray %39 %uint_128
375%_ptr_UniformConstant__arr_39_uint_128 = OpTypePointer UniformConstant %_arr_39_uint_128
376%g_tColor = OpVariable %_ptr_UniformConstant__arr_39_uint_128 UniformConstant
377%PerViewConstantBuffer_t = OpTypeStruct %uint
378%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t
379%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant
380%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint
381%_ptr_UniformConstant_39 = OpTypePointer UniformConstant %39
382%_ptr_Input_v2int = OpTypePointer Input %v2int
383%i_vTextureCoords = OpVariable %_ptr_Input_v2int Input
384%_ptr_Output_v4float = OpTypePointer Output %v4float
385%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output
386;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
387;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
388;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
389)";
390
391  const std::string main_func = R"(
392%MainPs = OpFunction %void None %3
393%5 = OpLabel
394%53 = OpLoad %v2int %i_vTextureCoords
395%63 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0
396%64 = OpLoad %uint %63
397%65 = OpAccessChain %_ptr_UniformConstant_39 %g_tColor %64
398%66 = OpLoad %39 %65
399%75 = OpImage %20 %66
400%71 = OpImageRead %v4float %75 %53
401OpStore %_entryPointOutput_vColor %71
402;CHECK-NOT: %71 = OpImageRead %v4float %75 %53
403;CHECK-NOT: OpStore %_entryPointOutput_vColor %71
404;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
405;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
406;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
407;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
408;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
409;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_52 {{%\w+}} %uint_3 %uint_9 %64 %uint_0
410;CHECK: OpSelectionMerge {{%\w+}} None
411;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
412;CHECK: {{%\w+}} = OpLabel
413;CHECK: {{%\w+}} = OpLoad %39 %65
414;CHECK: {{%\w+}} = OpImage %20 {{%\w+}}
415;CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %53
416;CHECK: OpBranch {{%\w+}}
417;CHECK: {{%\w+}} = OpLabel
418;CHECK: OpBranch {{%\w+}}
419;CHECK: {{%\w+}} = OpLabel
420;CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
421;CHECK: OpStore %_entryPointOutput_vColor {{%\w+}}
422OpReturn
423OpFunctionEnd
424)";
425  // clang-format on
426
427  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
428  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + kImportStub + main_func,
429                                               true, 23u);
430}
431
432TEST_F(InstBindlessTest, InstrumentSampledImage) {
433  // This test verifies that the pass will correctly instrument shader
434  // using sampled image. This test was created by editing the SPIR-V
435  // from the Simple test.
436
437  // clang-format off
438  const std::string defs = R"(
439OpCapability Shader
440;CHECK: OpCapability Linkage
441%1 = OpExtInstImport "GLSL.std.450"
442OpMemoryModel Logical GLSL450
443OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor
444;CHECK: OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord
445OpExecutionMode %MainPs OriginUpperLeft
446OpSource HLSL 500
447OpName %MainPs "MainPs"
448OpName %g_tColor "g_tColor"
449OpName %PerViewConstantBuffer_t "PerViewConstantBuffer_t"
450OpMemberName %PerViewConstantBuffer_t 0 "g_nDataIdx"
451OpName %_ ""
452OpName %i_vTextureCoords "i.vTextureCoords"
453OpName %_entryPointOutput_vColor "@entryPointOutput.vColor"
454OpDecorate %g_tColor DescriptorSet 4
455OpDecorate %g_tColor Binding 11
456OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0
457OpDecorate %PerViewConstantBuffer_t Block
458OpDecorate %i_vTextureCoords Location 0
459OpDecorate %_entryPointOutput_vColor Location 0
460)" + kImportDeco + R"(
461;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
462%void = OpTypeVoid
463%3 = OpTypeFunction %void
464%float = OpTypeFloat 32
465%v2float = OpTypeVector %float 2
466%v4float = OpTypeVector %float 4
467%int = OpTypeInt 32 1
468%int_0 = OpConstant %int 0
469%20 = OpTypeImage %float 2D 0 0 0 1 Unknown
470%uint = OpTypeInt 32 0
471%uint_128 = OpConstant %uint 128
472%39 = OpTypeSampledImage %20
473%_arr_39_uint_128 = OpTypeArray %39 %uint_128
474%_ptr_UniformConstant__arr_39_uint_128 = OpTypePointer UniformConstant %_arr_39_uint_128
475%g_tColor = OpVariable %_ptr_UniformConstant__arr_39_uint_128 UniformConstant
476%PerViewConstantBuffer_t = OpTypeStruct %uint
477%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t
478%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant
479%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint
480%_ptr_UniformConstant_39 = OpTypePointer UniformConstant %39
481%_ptr_Input_v2float = OpTypePointer Input %v2float
482%i_vTextureCoords = OpVariable %_ptr_Input_v2float Input
483%_ptr_Output_v4float = OpTypePointer Output %v4float
484%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output
485;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
486;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
487;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
488)";
489
490  const std::string main_func = R"(
491%MainPs = OpFunction %void None %3
492%5 = OpLabel
493%53 = OpLoad %v2float %i_vTextureCoords
494%63 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0
495%64 = OpLoad %uint %63
496%65 = OpAccessChain %_ptr_UniformConstant_39 %g_tColor %64
497%66 = OpLoad %39 %65
498%71 = OpImageSampleImplicitLod %v4float %66 %53
499OpStore %_entryPointOutput_vColor %71
500;CHECK-NOT: %71 = OpImageSampleImplicitLod %v4float %66 %53
501;CHECK-NOT: OpStore %_entryPointOutput_vColor %71
502;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
503;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
504;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
505;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
506;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
507;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_50 {{%\w+}} %uint_4 %uint_11 %64 %uint_0
508;CHECK: OpSelectionMerge {{%\w+}} None
509;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
510;CHECK: {{%\w+}} = OpLabel
511;CHECK: {{%\w+}} = OpLoad %39 %65
512;CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %53
513;CHECK: OpBranch {{%\w+}}
514;CHECK: {{%\w+}} = OpLabel
515;CHECK: OpBranch {{%\w+}}
516;CHECK: {{%\w+}} = OpLabel
517;CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
518;CHECK: OpStore %_entryPointOutput_vColor {{%\w+}}
519OpReturn
520OpFunctionEnd
521)";
522  // clang-format on
523
524  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
525  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + kImportStub + main_func,
526                                               true, 23u);
527}
528
529TEST_F(InstBindlessTest, InstrumentImageWrite) {
530  // This test verifies that the pass will correctly instrument shader
531  // doing bindless image write. This test was created by editing the SPIR-V
532  // from the Simple test.
533
534  // clang-format off
535  const std::string defs = R"(
536OpCapability Shader
537OpCapability StorageImageWriteWithoutFormat
538;CHECK: OpCapability Linkage
539%1 = OpExtInstImport "GLSL.std.450"
540OpMemoryModel Logical GLSL450
541OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor
542;CHECK: OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord
543OpExecutionMode %MainPs OriginUpperLeft
544OpSource HLSL 500
545OpName %MainPs "MainPs"
546OpName %g_tColor "g_tColor"
547OpName %PerViewConstantBuffer_t "PerViewConstantBuffer_t"
548OpMemberName %PerViewConstantBuffer_t 0 "g_nDataIdx"
549OpName %_ ""
550OpName %i_vTextureCoords "i.vTextureCoords"
551OpName %_entryPointOutput_vColor "@entryPointOutput.vColor"
552OpDecorate %g_tColor DescriptorSet 30
553OpDecorate %g_tColor Binding 2
554OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0
555OpDecorate %PerViewConstantBuffer_t Block
556OpDecorate %i_vTextureCoords Location 0
557OpDecorate %_entryPointOutput_vColor Location 0
558)" + kImportDeco + R"(
559;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
560%void = OpTypeVoid
561%3 = OpTypeFunction %void
562%float = OpTypeFloat 32
563%v2float = OpTypeVector %float 2
564%v4float = OpTypeVector %float 4
565%int = OpTypeInt 32 1
566%v2int = OpTypeVector %int 2
567%int_0 = OpConstant %int 0
568%20 = OpTypeImage %float 2D 0 0 0 0 Unknown
569%uint = OpTypeInt 32 0
570%uint_128 = OpConstant %uint 128
571%80 = OpConstantNull %v4float
572%_arr_20_uint_128 = OpTypeArray %20 %uint_128
573%_ptr_UniformConstant__arr_20_uint_128 = OpTypePointer UniformConstant %_arr_20_uint_128
574%g_tColor = OpVariable %_ptr_UniformConstant__arr_20_uint_128 UniformConstant
575%PerViewConstantBuffer_t = OpTypeStruct %uint
576%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t
577%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant
578%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint
579%_ptr_UniformConstant_20 = OpTypePointer UniformConstant %20
580%_ptr_Input_v2int = OpTypePointer Input %v2int
581%i_vTextureCoords = OpVariable %_ptr_Input_v2int Input
582%_ptr_Output_v4float = OpTypePointer Output %v4float
583%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output
584;CHECK: %v4uint = OpTypeVector %uint 4
585;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
586;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
587)";
588
589  const std::string main_func = R"(
590%MainPs = OpFunction %void None %3
591%5 = OpLabel
592%53 = OpLoad %v2int %i_vTextureCoords
593%63 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0
594%64 = OpLoad %uint %63
595%65 = OpAccessChain %_ptr_UniformConstant_20 %g_tColor %64
596%66 = OpLoad %20 %65
597OpImageWrite %66 %53 %80
598OpStore %_entryPointOutput_vColor %80
599;CHECK-NOT: OpImageWrite %66 %53 %80
600;CHECK-NOT: OpStore %_entryPointOutput_vColor %80
601;CHECK: %32 = OpLoad %16 %31
602;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
603;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
604;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
605;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
606;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
607;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_52 {{%\w+}} %uint_30 %uint_2 %30 %uint_0
608;CHECK: OpSelectionMerge {{%\w+}} None
609;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
610;CHECK: {{%\w+}} = OpLabel
611;CHECK: {{%\w+}} = OpLoad %16 %31
612;CHECK: OpImageWrite {{%\w+}} %28 %19
613;CHECK: OpBranch {{%\w+}}
614;CHECK: {{%\w+}} = OpLabel
615;CHECK: OpBranch {{%\w+}}
616;CHECK: {{%\w+}} = OpLabel
617;CHECK: OpStore %_entryPointOutput_vColor %19
618OpReturn
619OpFunctionEnd
620)";
621  // clang-format on
622
623  // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
624  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + kImportStub + main_func,
625                                               true, 23u);
626}
627
628TEST_F(InstBindlessTest, InstrumentVertexSimple) {
629  // This test verifies that the pass will correctly instrument shader
630  // doing bindless image write. This test was created by editing the SPIR-V
631  // from the Simple test.
632
633  // clang-format off
634  const std::string defs = R"(
635OpCapability Shader
636OpCapability Sampled1D
637;CHECK: OpCapability Linkage
638%1 = OpExtInstImport "GLSL.std.450"
639OpMemoryModel Logical GLSL450
640OpEntryPoint Vertex %main "main" %_ %coords2D
641OpSource GLSL 450
642OpName %main "main"
643OpName %lod "lod"
644OpName %coords1D "coords1D"
645OpName %gl_PerVertex "gl_PerVertex"
646OpMemberName %gl_PerVertex 0 "gl_Position"
647OpMemberName %gl_PerVertex 1 "gl_PointSize"
648OpMemberName %gl_PerVertex 2 "gl_ClipDistance"
649OpMemberName %gl_PerVertex 3 "gl_CullDistance"
650OpName %_ ""
651OpName %texSampler1D "texSampler1D"
652OpName %foo "foo"
653OpMemberName %foo 0 "g_idx"
654OpName %__0 ""
655OpName %coords2D "coords2D"
656)" + kImportDeco + R"(
657;CHECK: OpDecorate %gl_VertexIndex BuiltIn VertexIndex
658;CHECK: OpDecorate %gl_InstanceIndex BuiltIn InstanceIndex
659OpMemberDecorate %gl_PerVertex 0 BuiltIn Position
660OpMemberDecorate %gl_PerVertex 1 BuiltIn PointSize
661OpMemberDecorate %gl_PerVertex 2 BuiltIn ClipDistance
662OpMemberDecorate %gl_PerVertex 3 BuiltIn CullDistance
663OpDecorate %gl_PerVertex Block
664OpDecorate %texSampler1D DescriptorSet 2
665OpDecorate %texSampler1D Binding 13
666OpMemberDecorate %foo 0 Offset 0
667OpDecorate %foo Block
668OpDecorate %__0 DescriptorSet 7
669OpDecorate %__0 Binding 5
670OpDecorate %coords2D Location 0
671%void = OpTypeVoid
672%3 = OpTypeFunction %void
673%float = OpTypeFloat 32
674%_ptr_Function_float = OpTypePointer Function %float
675%float_3 = OpConstant %float 3
676%float_1_78900003 = OpConstant %float 1.78900003
677%v4float = OpTypeVector %float 4
678%uint = OpTypeInt 32 0
679%uint_1 = OpConstant %uint 1
680%_arr_float_uint_1 = OpTypeArray %float %uint_1
681%gl_PerVertex = OpTypeStruct %v4float %float %_arr_float_uint_1 %_arr_float_uint_1
682%_ptr_Output_gl_PerVertex = OpTypePointer Output %gl_PerVertex
683%_ = OpVariable %_ptr_Output_gl_PerVertex Output
684%int = OpTypeInt 32 1
685%int_0 = OpConstant %int 0
686%21 = OpTypeImage %float 1D 0 0 0 1 Unknown
687%22 = OpTypeSampledImage %21
688%uint_128 = OpConstant %uint 128
689%_arr_22_uint_128 = OpTypeArray %22 %uint_128
690%_ptr_UniformConstant__arr_22_uint_128 = OpTypePointer UniformConstant %_arr_22_uint_128
691%texSampler1D = OpVariable %_ptr_UniformConstant__arr_22_uint_128 UniformConstant
692%foo = OpTypeStruct %int
693%_ptr_Uniform_foo = OpTypePointer Uniform %foo
694%__0 = OpVariable %_ptr_Uniform_foo Uniform
695%_ptr_Uniform_int = OpTypePointer Uniform %int
696%_ptr_UniformConstant_22 = OpTypePointer UniformConstant %22
697%_ptr_Output_v4float = OpTypePointer Output %v4float
698%v2float = OpTypeVector %float 2
699%_ptr_Input_v2float = OpTypePointer Input %v2float
700%coords2D = OpVariable %_ptr_Input_v2float Input
701;CHECK: %_ptr_Input_uint = OpTypePointer Input %uint
702;CHECK: %gl_VertexIndex = OpVariable %_ptr_Input_uint Input
703;CHECK: %gl_InstanceIndex = OpVariable %_ptr_Input_uint Input
704;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
705)";
706
707  const std::string main_func = R"(
708%main = OpFunction %void None %3
709%5 = OpLabel
710%lod = OpVariable %_ptr_Function_float Function
711%coords1D = OpVariable %_ptr_Function_float Function
712OpStore %lod %float_3
713OpStore %coords1D %float_1_78900003
714%31 = OpAccessChain %_ptr_Uniform_int %__0 %int_0
715%32 = OpLoad %int %31
716%34 = OpAccessChain %_ptr_UniformConstant_22 %texSampler1D %32
717%35 = OpLoad %22 %34
718%36 = OpLoad %float %coords1D
719%37 = OpLoad %float %lod
720%38 = OpImageSampleExplicitLod %v4float %35 %36 Lod %37
721%40 = OpAccessChain %_ptr_Output_v4float %_ %int_0
722OpStore %40 %38
723;CHECK-NOT: %38 = OpImageSampleExplicitLod %v4float %35 %36 Lod %37
724;CHECK-NOT: %40 = OpAccessChain %_ptr_Output_v4float %_ %int_0
725;CHECK-NOT: OpStore %40 %38
726;CHECK: {{%\w+}} = OpLoad %uint %gl_VertexIndex
727;CHECK: {{%\w+}} = OpLoad %uint %gl_InstanceIndex
728;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_0 {{%\w+}} {{%\w+}} %uint_0
729;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_70 {{%\w+}} %uint_7 %uint_5 %uint_0 {{%\w+}}
730;CHECK: OpSelectionMerge {{%\w+}} None
731;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
732;CHECK: {{%\w+}} = OpLabel
733;CHECK: {{%\w+}} = OpLoad %int {{%\w+}}
734;CHECK: OpBranch {{%\w+}}
735;CHECK: {{%\w+}} = OpLabel
736;CHECK: OpBranch {{%\w+}}
737;CHECK: {{%\w+}} = OpLabel
738;CHECK: {{%\w+}} = OpPhi %int {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}}
739;CHECK: {{%\w+}} = OpAccessChain %_ptr_UniformConstant_25 %texSampler1D {{%\w+}}
740;CHECK: {{%\w+}} = OpLoad {{%\w+}} {{%\w+}}
741;CHECK: {{%\w+}} = OpLoad %float %coords1D
742;CHECK: {{%\w+}} = OpLoad %float %lod
743;CHECK: {{%\w+}} = OpLoad %uint %gl_VertexIndex
744;CHECK: {{%\w+}} = OpLoad %uint %gl_InstanceIndex
745;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_0 {{%\w+}} {{%\w+}} %uint_0
746;CHECK: {{%\w+}} = OpBitcast %uint {{%\w+}}
747;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_75 {{%\w+}} %uint_2 %uint_13 {{%\w+}} %uint_0
748;CHECK: OpSelectionMerge {{%\w+}} None
749;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
750;CHECK: {{%\w+}} = OpLabel
751;CHECK: {{%\w+}} = OpLoad %25 %38
752;CHECK: {{%\w+}} = OpImageSampleExplicitLod %v4float {{%\w+}} %40 Lod %41
753;CHECK: OpBranch {{%\w+}}
754;CHECK: {{%\w+}} = OpLabel
755;CHECK: OpBranch {{%\w+}}
756;CHECK: {{%\w+}} = OpLabel
757;CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}}
758;CHECK: %43 = OpAccessChain %_ptr_Output_v4float %_ %int_0
759;CHECK: OpStore %43 {{%\w+}}
760OpReturn
761OpFunctionEnd
762)";
763  // clang-format on
764
765  // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
766  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + kImportStub + main_func,
767                                               true, 23u);
768}
769
770TEST_F(InstBindlessTest, InstrumentTeseSimple) {
771  // This test verifies that the pass will correctly instrument tessellation
772  // evaluation shader doing bindless buffer load.
773  //
774  // clang-format off
775  //
776  // #version 450
777  // #extension GL_EXT_nonuniform_qualifier : enable
778  //
779  // layout(std140, set = 9, binding = 1) uniform ufoo { uint index; } uniform_index_buffer;
780  //
781  // layout(set = 9, binding = 2) buffer bfoo { vec4 val; } adds[11];
782  //
783  // layout(triangles, equal_spacing, cw) in;
784  //
785  // void main() {
786  //   gl_Position = adds[uniform_index_buffer.index].val;
787  // }
788  //
789
790  const std::string defs = R"(
791OpCapability Tessellation
792;CHECK: OpCapability Linkage
793%1 = OpExtInstImport "GLSL.std.450"
794OpMemoryModel Logical GLSL450
795OpEntryPoint TessellationEvaluation %main "main" %_
796;CHECK: OpEntryPoint TessellationEvaluation %main "main" %_ %gl_PrimitiveID %gl_TessCoord
797OpExecutionMode %main Triangles
798OpExecutionMode %main SpacingEqual
799OpExecutionMode %main VertexOrderCw
800OpSource GLSL 450
801OpSourceExtension "GL_EXT_nonuniform_qualifier"
802OpName %main "main"
803OpName %gl_PerVertex "gl_PerVertex"
804OpMemberName %gl_PerVertex 0 "gl_Position"
805OpMemberName %gl_PerVertex 1 "gl_PointSize"
806OpMemberName %gl_PerVertex 2 "gl_ClipDistance"
807OpMemberName %gl_PerVertex 3 "gl_CullDistance"
808OpName %_ ""
809OpName %bfoo "bfoo"
810OpMemberName %bfoo 0 "val"
811OpName %adds "adds"
812OpName %ufoo "ufoo"
813OpMemberName %ufoo 0 "index"
814OpName %uniform_index_buffer "uniform_index_buffer"
815OpMemberDecorate %gl_PerVertex 0 BuiltIn Position
816OpMemberDecorate %gl_PerVertex 1 BuiltIn PointSize
817OpMemberDecorate %gl_PerVertex 2 BuiltIn ClipDistance
818OpMemberDecorate %gl_PerVertex 3 BuiltIn CullDistance
819OpDecorate %gl_PerVertex Block
820OpMemberDecorate %bfoo 0 Offset 0
821OpDecorate %bfoo Block
822OpDecorate %adds DescriptorSet 9
823OpDecorate %adds Binding 1
824OpMemberDecorate %ufoo 0 Offset 0
825OpDecorate %ufoo Block
826OpDecorate %uniform_index_buffer DescriptorSet 9
827OpDecorate %uniform_index_buffer Binding 2
828)" + kImportDeco + R"(
829;CHECK: OpDecorate %gl_PrimitiveID BuiltIn PrimitiveId
830;CHECK: OpDecorate %gl_TessCoord BuiltIn TessCoord
831%void = OpTypeVoid
832%3 = OpTypeFunction %void
833%float = OpTypeFloat 32
834%v4float = OpTypeVector %float 4
835%uint = OpTypeInt 32 0
836%uint_1 = OpConstant %uint 1
837%_arr_float_uint_1 = OpTypeArray %float %uint_1
838%gl_PerVertex = OpTypeStruct %v4float %float %_arr_float_uint_1 %_arr_float_uint_1
839%_ptr_Output_gl_PerVertex = OpTypePointer Output %gl_PerVertex
840%_ = OpVariable %_ptr_Output_gl_PerVertex Output
841%int = OpTypeInt 32 1
842%int_0 = OpConstant %int 0
843%bfoo = OpTypeStruct %v4float
844%uint_11 = OpConstant %uint 11
845%_arr_bfoo_uint_11 = OpTypeArray %bfoo %uint_11
846%_ptr_StorageBuffer__arr_bfoo_uint_11 = OpTypePointer StorageBuffer %_arr_bfoo_uint_11
847%adds = OpVariable %_ptr_StorageBuffer__arr_bfoo_uint_11 StorageBuffer
848%ufoo = OpTypeStruct %uint
849%_ptr_Uniform_ufoo = OpTypePointer Uniform %ufoo
850%uniform_index_buffer = OpVariable %_ptr_Uniform_ufoo Uniform
851%_ptr_Uniform_uint = OpTypePointer Uniform %uint
852%_ptr_StorageBuffer_v4float = OpTypePointer StorageBuffer %v4float
853%_ptr_Output_v4float = OpTypePointer Output %v4float
854;CHECK: %_ptr_Input_uint = OpTypePointer Input %uint
855;CHECK: %gl_PrimitiveID = OpVariable %_ptr_Input_uint Input
856;CHECK: %v3float = OpTypeVector %float 3
857;CHECK: %_ptr_Input_v3float = OpTypePointer Input %v3float
858;CHECK: %gl_TessCoord = OpVariable %_ptr_Input_v3float Input
859;CHECK: %v3uint = OpTypeVector %uint 3
860;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
861)";
862
863  const std::string main_func =
864      R"(
865%main = OpFunction %void None %3
866%5 = OpLabel
867%25 = OpAccessChain %_ptr_Uniform_uint %uniform_index_buffer %int_0
868%26 = OpLoad %uint %25
869%28 = OpAccessChain %_ptr_StorageBuffer_v4float %adds %26 %int_0
870%29 = OpLoad %v4float %28
871;CHECK-NOT: %29 = OpLoad %v4float %28
872;CHECK: {{%\w+}} = OpLoad %uint %gl_PrimitiveID
873;CHECK: {{%\w+}} = OpLoad %v3float %gl_TessCoord
874;CHECK: {{%\w+}} = OpBitcast %v3uint {{%\w+}}
875;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
876;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
877;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_2 {{%\w+}} {{%\w+}} {{%\w+}}
878;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_62 {{%\w+}} %uint_9 %uint_2 %uint_0 {{%\w+}}
879;CHECK: OpSelectionMerge {{%\w+}} None
880;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
881;CHECK: {{%\w+}} = OpLabel
882;CHECK: {{%\w+}} = OpLoad %uint %27
883;CHECK: OpBranch {{%\w+}}
884;CHECK: {{%\w+}} = OpLabel
885;CHECK: OpBranch {{%\w+}}
886;CHECK: {{%\w+}} = OpLabel
887;CHECK: {{%\w+}} = OpPhi %uint {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}}
888%31 = OpAccessChain %_ptr_Output_v4float %_ %int_0
889OpStore %31 %29
890;CHECK-NOT: OpStore %31 %29
891;CHECK: {{%\w+}} = OpLoad %uint %gl_PrimitiveID
892;CHECK: {{%\w+}} = OpLoad %v3float %gl_TessCoord
893;CHECK: {{%\w+}} = OpBitcast %v3uint {{%\w+}}
894;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
895;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
896;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_2 {{%\w+}} {{%\w+}} {{%\w+}}
897;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_64 {{%\w+}} %uint_9 %uint_1 {{%\w+}} {{%\w+}}
898;CHECK: OpSelectionMerge {{%\w+}} None
899;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
900;CHECK: {{%\w+}} = OpLabel
901;CHECK: {{%\w+}} = OpLoad %v4float %29
902;CHECK: OpBranch {{%\w+}}
903;CHECK: {{%\w+}} = OpLabel
904;CHECK: OpBranch {{%\w+}}
905;CHECK: {{%\w+}} = OpLabel
906;CHECK: [[phi_result:%\w+]] = OpPhi {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}}
907;CHECK: %31 = OpAccessChain %_ptr_Output_v4float %_ %int_0
908;CHECK: OpStore %31 [[phi_result]]
909OpReturn
910OpFunctionEnd
911)";
912  // clang-format on
913
914  // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
915  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + kImportStub + main_func,
916                                               true, 23u);
917}
918
919TEST_F(InstBindlessTest, InstrumentTesc) {
920  // This test verifies that the pass will correctly instrument tessellation
921  // control shader
922  //
923  // clang-format off
924  //
925  // #version 450
926  // layout(vertices = 3) out;
927  // layout(set = 0, binding = 0) uniform texture1D _77;
928  // layout(set = 0, binding = 1) uniform sampler _78;
929
930  // layout(location = 1) flat in int _3[];
931  // layout(location = 0) out vec4 _5[3];
932
933  // void main()
934  // {
935  //     float param;
936  //     if (_3[gl_InvocationID] == 0)
937  //     {
938  //         param = 0.0234375;
939  //     }
940  //     else
941  //     {
942  //         param = 1.0156199932098388671875;
943  //     }
944  //     _5[gl_InvocationID] = textureLod(sampler1D(_77, _78), param, 0.0);
945  //     vec4 _203;
946  //     if (gl_InvocationID == 0)
947  //     {
948  //         _203 = gl_in[0].gl_Position;
949  //     }
950  //     else
951  //     {
952  //         _203 = gl_in[2].gl_Position;
953  //     }
954  //     gl_out[gl_InvocationID].gl_Position = _203;
955  //     gl_TessLevelInner[0] = 2.7999999523162841796875;
956  //     gl_TessLevelInner[1] = 2.7999999523162841796875;
957  //     gl_TessLevelOuter[0] = 2.7999999523162841796875;
958  //     gl_TessLevelOuter[1] = 2.7999999523162841796875;
959  //     gl_TessLevelOuter[2] = 2.7999999523162841796875;
960  //     gl_TessLevelOuter[3] = 2.7999999523162841796875;
961  // }
962  //
963  // clang-format on
964  //
965  //
966
967  // clang-format off
968  const std::string defs = R"(
969OpCapability Tessellation
970OpCapability Sampled1D
971;CHECK: OpCapability Linkage
972;CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class"
973;CHECK: OpExtension "SPV_KHR_physical_storage_buffer"
974%1 = OpExtInstImport "GLSL.std.450"
975OpMemoryModel Logical GLSL450
976;CHECK: OpMemoryModel PhysicalStorageBuffer64 GLSL450
977OpEntryPoint TessellationControl %main "main" %_3 %gl_InvocationID %_5 %gl_in %gl_out %gl_TessLevelInner %gl_TessLevelOuter
978;CHECK: OpEntryPoint TessellationControl %main "main" %_3 %gl_InvocationID %_5 %gl_in %gl_out %gl_TessLevelInner %gl_TessLevelOuter %gl_PrimitiveID
979OpExecutionMode %main OutputVertices 3
980OpSource GLSL 450
981OpName %main "main"
982OpName %_3 "_3"
983OpName %gl_InvocationID "gl_InvocationID"
984OpName %param "param"
985OpName %_5 "_5"
986OpName %_77 "_77"
987OpName %_78 "_78"
988OpName %_203 "_203"
989OpName %gl_PerVertex "gl_PerVertex"
990OpMemberName %gl_PerVertex 0 "gl_Position"
991OpMemberName %gl_PerVertex 1 "gl_PointSize"
992OpMemberName %gl_PerVertex 2 "gl_ClipDistance"
993OpMemberName %gl_PerVertex 3 "gl_CullDistance"
994OpName %gl_in "gl_in"
995OpName %gl_PerVertex_0 "gl_PerVertex"
996OpMemberName %gl_PerVertex_0 0 "gl_Position"
997OpMemberName %gl_PerVertex_0 1 "gl_PointSize"
998OpMemberName %gl_PerVertex_0 2 "gl_ClipDistance"
999OpMemberName %gl_PerVertex_0 3 "gl_CullDistance"
1000OpName %gl_out "gl_out"
1001OpName %gl_TessLevelInner "gl_TessLevelInner"
1002OpName %gl_TessLevelOuter "gl_TessLevelOuter"
1003OpDecorate %_3 Flat
1004OpDecorate %_3 Location 1
1005OpDecorate %gl_InvocationID BuiltIn InvocationId
1006OpDecorate %_5 Location 0
1007OpDecorate %_77 DescriptorSet 0
1008OpDecorate %_77 Binding 0
1009OpDecorate %_78 DescriptorSet 0
1010OpDecorate %_78 Binding 1
1011OpMemberDecorate %gl_PerVertex 0 BuiltIn Position
1012OpMemberDecorate %gl_PerVertex 1 BuiltIn PointSize
1013OpMemberDecorate %gl_PerVertex 2 BuiltIn ClipDistance
1014OpMemberDecorate %gl_PerVertex 3 BuiltIn CullDistance
1015OpDecorate %gl_PerVertex Block
1016OpMemberDecorate %gl_PerVertex_0 0 BuiltIn Position
1017OpMemberDecorate %gl_PerVertex_0 1 BuiltIn PointSize
1018OpMemberDecorate %gl_PerVertex_0 2 BuiltIn ClipDistance
1019OpMemberDecorate %gl_PerVertex_0 3 BuiltIn CullDistance
1020OpDecorate %gl_PerVertex_0 Block
1021OpDecorate %gl_TessLevelInner Patch
1022OpDecorate %gl_TessLevelInner BuiltIn TessLevelInner
1023OpDecorate %gl_TessLevelOuter Patch
1024OpDecorate %gl_TessLevelOuter BuiltIn TessLevelOuter
1025%void = OpTypeVoid
1026%3 = OpTypeFunction %void
1027%int = OpTypeInt 32 1
1028%uint = OpTypeInt 32 0
1029%uint_32 = OpConstant %uint 32
1030%_arr_int_uint_32 = OpTypeArray %int %uint_32
1031%_ptr_Input__arr_int_uint_32 = OpTypePointer Input %_arr_int_uint_32
1032%_3 = OpVariable %_ptr_Input__arr_int_uint_32 Input
1033%_ptr_Input_int = OpTypePointer Input %int
1034%gl_InvocationID = OpVariable %_ptr_Input_int Input
1035%int_0 = OpConstant %int 0
1036%bool = OpTypeBool
1037%float = OpTypeFloat 32
1038%_ptr_Function_float = OpTypePointer Function %float
1039%float_0_0234375 = OpConstant %float 0.0234375
1040%float_1_01561999 = OpConstant %float 1.01561999
1041%v4float = OpTypeVector %float 4
1042%uint_3 = OpConstant %uint 3
1043%_arr_v4float_uint_3 = OpTypeArray %v4float %uint_3
1044%_ptr_Output__arr_v4float_uint_3 = OpTypePointer Output %_arr_v4float_uint_3
1045%_5 = OpVariable %_ptr_Output__arr_v4float_uint_3 Output
1046%34 = OpTypeImage %float 1D 0 0 0 1 Unknown
1047%_ptr_UniformConstant_34 = OpTypePointer UniformConstant %34
1048%_77 = OpVariable %_ptr_UniformConstant_34 UniformConstant
1049%38 = OpTypeSampler
1050%_ptr_UniformConstant_38 = OpTypePointer UniformConstant %38
1051%_78 = OpVariable %_ptr_UniformConstant_38 UniformConstant
1052%42 = OpTypeSampledImage %34
1053%float_0 = OpConstant %float 0
1054%_ptr_Output_v4float = OpTypePointer Output %v4float
1055%_ptr_Function_v4float = OpTypePointer Function %v4float
1056%uint_1 = OpConstant %uint 1
1057%_arr_float_uint_1 = OpTypeArray %float %uint_1
1058%gl_PerVertex = OpTypeStruct %v4float %float %_arr_float_uint_1 %_arr_float_uint_1
1059%_arr_gl_PerVertex_uint_32 = OpTypeArray %gl_PerVertex %uint_32
1060%_ptr_Input__arr_gl_PerVertex_uint_32 = OpTypePointer Input %_arr_gl_PerVertex_uint_32
1061%gl_in = OpVariable %_ptr_Input__arr_gl_PerVertex_uint_32 Input
1062%_ptr_Input_v4float = OpTypePointer Input %v4float
1063%int_2 = OpConstant %int 2
1064%gl_PerVertex_0 = OpTypeStruct %v4float %float %_arr_float_uint_1 %_arr_float_uint_1
1065%_arr_gl_PerVertex_0_uint_3 = OpTypeArray %gl_PerVertex_0 %uint_3
1066%_ptr_Output__arr_gl_PerVertex_0_uint_3 = OpTypePointer Output %_arr_gl_PerVertex_0_uint_3
1067%gl_out = OpVariable %_ptr_Output__arr_gl_PerVertex_0_uint_3 Output
1068%uint_2 = OpConstant %uint 2
1069%_arr_float_uint_2 = OpTypeArray %float %uint_2
1070%_ptr_Output__arr_float_uint_2 = OpTypePointer Output %_arr_float_uint_2
1071%gl_TessLevelInner = OpVariable %_ptr_Output__arr_float_uint_2 Output
1072%float_2_79999995 = OpConstant %float 2.79999995
1073%_ptr_Output_float = OpTypePointer Output %float
1074%int_1 = OpConstant %int 1
1075%uint_4 = OpConstant %uint 4
1076%_arr_float_uint_4 = OpTypeArray %float %uint_4
1077%_ptr_Output__arr_float_uint_4 = OpTypePointer Output %_arr_float_uint_4
1078%gl_TessLevelOuter = OpVariable %_ptr_Output__arr_float_uint_4 Output
1079%int_3 = OpConstant %int 3
1080)";
1081
1082  const std::string main_func =
1083      R"(
1084%main = OpFunction %void None %3
1085%5 = OpLabel
1086%param = OpVariable %_ptr_Function_float Function
1087%_203 = OpVariable %_ptr_Function_v4float Function
1088%14 = OpLoad %int %gl_InvocationID
1089%15 = OpAccessChain %_ptr_Input_int %_3 %14
1090%16 = OpLoad %int %15
1091%19 = OpIEqual %bool %16 %int_0
1092OpSelectionMerge %21 None
1093OpBranchConditional %19 %20 %26
1094%20 = OpLabel
1095;CHECK-NOT: %15 = OpAccessChain %_ptr_Input_int %_3 %14
1096;CHECK: OpBranch {{%\w+}}
1097;CHECK: {{%\w+}} = OpLabel
1098;CHECK: {{%\w+}} = OpLoad %int %gl_InvocationID
1099;CHECK: {{%\w+}} = OpAccessChain %_ptr_Input_int %_3 {{%\w+}}
1100;CHECK: {{%\w+}} = OpLoad %int {{%\w+}}
1101;CHECK: {{%\w+}} = OpIEqual %bool {{%\w+}} %int_0
1102;CHECK: OpSelectionMerge {{%\w+}} None
1103;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
1104;CHECK: {{%\w+}} = OpLabel
1105OpStore %param %float_0_0234375
1106OpBranch %21
1107%26 = OpLabel
1108OpStore %param %float_1_01561999
1109OpBranch %21
1110%21 = OpLabel
1111%33 = OpLoad %int %gl_InvocationID
1112%37 = OpLoad %34 %_77
1113%41 = OpLoad %38 %_78
1114%43 = OpSampledImage %42 %37 %41
1115%44 = OpLoad %float %param
1116;CHECK: {{%\w+}} = OpLoad %int %gl_InvocationID
1117;CHECK: {{%\w+}} = OpBitcast %uint {{%\w+}}
1118;CHECK: {{%\w+}} = OpLoad %uint %gl_PrimitiveID
1119;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_1 {{%\w+}} {{%\w+}} %uint_0
1120;CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_check_desc %uint_23 %uint_129 {{%\w+}} %uint_0 %uint_0 %uint_0 %uint_0
1121;CHECK: OpSelectionMerge {{%\w+}} None
1122;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
1123%46 = OpImageSampleExplicitLod %v4float %43 %44 Lod %float_0
1124%48 = OpAccessChain %_ptr_Output_v4float %_5 %33
1125OpStore %48 %46
1126;CHECK-NOT: %48 = OpAccessChain %_ptr_Output_v4float %_5 %33
1127;CHECK-NOT: OpStore %48 %46
1128;CHECK: [[phi_result:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}}
1129;CHECK: [[access_chain:%\w+]] = OpAccessChain %_ptr_Output_v4float %_5 {{%\w+}}
1130;CHECK: OpStore [[access_chain]] [[phi_result]]
1131%49 = OpLoad %int %gl_InvocationID
1132%50 = OpIEqual %bool %49 %int_0
1133OpSelectionMerge %52 None
1134OpBranchConditional %50 %51 %64
1135%51 = OpLabel
1136%62 = OpAccessChain %_ptr_Input_v4float %gl_in %int_0 %int_0
1137%63 = OpLoad %v4float %62
1138OpStore %_203 %63
1139OpBranch %52
1140%64 = OpLabel
1141%66 = OpAccessChain %_ptr_Input_v4float %gl_in %int_2 %int_0
1142%67 = OpLoad %v4float %66
1143OpStore %_203 %67
1144OpBranch %52
1145%52 = OpLabel
1146%72 = OpLoad %int %gl_InvocationID
1147%73 = OpLoad %v4float %_203
1148%74 = OpAccessChain %_ptr_Output_v4float %gl_out %72 %int_0
1149OpStore %74 %73
1150%81 = OpAccessChain %_ptr_Output_float %gl_TessLevelInner %int_0
1151OpStore %81 %float_2_79999995
1152%83 = OpAccessChain %_ptr_Output_float %gl_TessLevelInner %int_1
1153OpStore %83 %float_2_79999995
1154%88 = OpAccessChain %_ptr_Output_float %gl_TessLevelOuter %int_0
1155OpStore %88 %float_2_79999995
1156%89 = OpAccessChain %_ptr_Output_float %gl_TessLevelOuter %int_1
1157OpStore %89 %float_2_79999995
1158%90 = OpAccessChain %_ptr_Output_float %gl_TessLevelOuter %int_2
1159OpStore %90 %float_2_79999995
1160%92 = OpAccessChain %_ptr_Output_float %gl_TessLevelOuter %int_3
1161OpStore %92 %float_2_79999995
1162OpReturn
1163OpFunctionEnd
1164)";
1165  // clang-format on
1166
1167  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1168  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + kImportStub + main_func,
1169                                               true, 23u);
1170}
1171
1172TEST_F(InstBindlessTest, MultipleDebugFunctions) {
1173  // Same source as Simple, but compiled -g and not optimized, especially not
1174  // inlined. The OpSource has had the source extracted for the sake of brevity.
1175
1176  // clang-format off
1177  const std::string defs = R"(
1178OpCapability Shader
1179;CHECK: OpCapability Linkage
1180%2 = OpExtInstImport "GLSL.std.450"
1181OpMemoryModel Logical GLSL450
1182OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor
1183;CHECK: OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord
1184OpExecutionMode %MainPs OriginUpperLeft
1185%1 = OpString "foo5.frag"
1186OpSource HLSL 500 %1
1187OpName %MainPs "MainPs"
1188OpName %PS_INPUT "PS_INPUT"
1189OpMemberName %PS_INPUT 0 "vTextureCoords"
1190OpName %PS_OUTPUT "PS_OUTPUT"
1191OpMemberName %PS_OUTPUT 0 "vColor"
1192OpName %_MainPs_struct_PS_INPUT_vf21_ "@MainPs(struct-PS_INPUT-vf21;"
1193OpName %i "i"
1194OpName %ps_output "ps_output"
1195OpName %g_tColor "g_tColor"
1196OpName %PerViewConstantBuffer_t "PerViewConstantBuffer_t"
1197OpMemberName %PerViewConstantBuffer_t 0 "g_nDataIdx"
1198OpName %_ ""
1199OpName %g_sAniso "g_sAniso"
1200OpName %i_0 "i"
1201OpName %i_vTextureCoords "i.vTextureCoords"
1202OpName %_entryPointOutput_vColor "@entryPointOutput.vColor"
1203OpName %param "param"
1204OpDecorate %g_tColor DescriptorSet 1
1205OpDecorate %g_tColor Binding 2
1206OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0
1207OpDecorate %PerViewConstantBuffer_t Block
1208OpDecorate %g_sAniso DescriptorSet 1
1209OpDecorate %g_sAniso Binding 3
1210OpDecorate %i_vTextureCoords Location 0
1211OpDecorate %_entryPointOutput_vColor Location 0
1212)" + kImportDeco + R"(
1213;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
1214%void = OpTypeVoid
1215%4 = OpTypeFunction %void
1216%float = OpTypeFloat 32
1217%v2float = OpTypeVector %float 2
1218%PS_INPUT = OpTypeStruct %v2float
1219%_ptr_Function_PS_INPUT = OpTypePointer Function %PS_INPUT
1220%v4float = OpTypeVector %float 4
1221%PS_OUTPUT = OpTypeStruct %v4float
1222%13 = OpTypeFunction %PS_OUTPUT %_ptr_Function_PS_INPUT
1223%_ptr_Function_PS_OUTPUT = OpTypePointer Function %PS_OUTPUT
1224%int = OpTypeInt 32 1
1225%int_0 = OpConstant %int 0
1226%21 = OpTypeImage %float 2D 0 0 0 1 Unknown
1227%uint = OpTypeInt 32 0
1228%uint_128 = OpConstant %uint 128
1229%_arr_21_uint_128 = OpTypeArray %21 %uint_128
1230%_ptr_UniformConstant__arr_21_uint_128 = OpTypePointer UniformConstant %_arr_21_uint_128
1231%g_tColor = OpVariable %_ptr_UniformConstant__arr_21_uint_128 UniformConstant
1232%PerViewConstantBuffer_t = OpTypeStruct %uint
1233%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t
1234%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant
1235%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint
1236%_ptr_UniformConstant_21 = OpTypePointer UniformConstant %21
1237%36 = OpTypeSampler
1238%_ptr_UniformConstant_36 = OpTypePointer UniformConstant %36
1239%g_sAniso = OpVariable %_ptr_UniformConstant_36 UniformConstant
1240%40 = OpTypeSampledImage %21
1241%_ptr_Function_v2float = OpTypePointer Function %v2float
1242%_ptr_Function_v4float = OpTypePointer Function %v4float
1243%_ptr_Input_v2float = OpTypePointer Input %v2float
1244%i_vTextureCoords = OpVariable %_ptr_Input_v2float Input
1245%_ptr_Output_v4float = OpTypePointer Output %v4float
1246%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output
1247;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
1248;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
1249;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
1250)";
1251
1252  const std::string func1 = R"(
1253%MainPs = OpFunction %void None %4
1254%6 = OpLabel
1255%i_0 = OpVariable %_ptr_Function_PS_INPUT Function
1256%param = OpVariable %_ptr_Function_PS_INPUT Function
1257OpLine %1 21 0
1258%54 = OpLoad %v2float %i_vTextureCoords
1259%55 = OpAccessChain %_ptr_Function_v2float %i_0 %int_0
1260OpStore %55 %54
1261%59 = OpLoad %PS_INPUT %i_0
1262OpStore %param %59
1263%60 = OpFunctionCall %PS_OUTPUT %_MainPs_struct_PS_INPUT_vf21_ %param
1264%61 = OpCompositeExtract %v4float %60 0
1265OpStore %_entryPointOutput_vColor %61
1266OpReturn
1267OpFunctionEnd
1268)";
1269
1270  const std::string func2 = R"(
1271%_MainPs_struct_PS_INPUT_vf21_ = OpFunction %PS_OUTPUT None %13
1272%i = OpFunctionParameter %_ptr_Function_PS_INPUT
1273%16 = OpLabel
1274%ps_output = OpVariable %_ptr_Function_PS_OUTPUT Function
1275OpLine %1 24 0
1276%31 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0
1277%32 = OpLoad %uint %31
1278%34 = OpAccessChain %_ptr_UniformConstant_21 %g_tColor %32
1279%35 = OpLoad %21 %34
1280%39 = OpLoad %36 %g_sAniso
1281%41 = OpSampledImage %40 %35 %39
1282%43 = OpAccessChain %_ptr_Function_v2float %i %int_0
1283%44 = OpLoad %v2float %43
1284%45 = OpImageSampleImplicitLod %v4float %41 %44
1285;CHECK-NOT: %45 = OpImageSampleImplicitLod %v4float %41 %44
1286;CHECK: {{%\w+}} = OpLoad %v2float {{%\w+}}
1287;CHECK: OpNoLine
1288;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
1289;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
1290;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
1291;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
1292;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
1293;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_128 {{%\w+}} %uint_1 %uint_2 {{%\w+}} %uint_0
1294;CHECK: OpSelectionMerge {{%\w+}} None
1295;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
1296;CHECK: {{%\w+}} = OpLabel
1297;CHECK: {{%\w+}} = OpLoad %27 {{%\w+}}
1298;CHECK: {{%\w+}} = OpSampledImage %37 {{%\w+}} {{%\w+}}
1299;CHECK: OpLine %5 24 0
1300;CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} {{%\w+}}
1301;CHECK: OpNoLine
1302;CHECK: OpBranch {{%\w+}}
1303;CHECK: {{%\w+}} = OpLabel
1304;CHECK: OpBranch {{%\w+}}
1305;CHECK: {{%\w+}} = OpLabel
1306;CHECK: [[phi_result:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
1307%47 = OpAccessChain %_ptr_Function_v4float %ps_output %int_0
1308OpStore %47 %45
1309;CHECK-NOT: OpStore %47 %45
1310;CHECK: [[store_loc:%\w+]] = OpAccessChain %_ptr_Function_v4float %ps_output %int_0
1311;CHECK: OpStore [[store_loc]] [[phi_result]]
1312OpLine %1 25 0
1313%48 = OpLoad %PS_OUTPUT %ps_output
1314OpReturnValue %48
1315OpFunctionEnd
1316)";
1317  // clang-format on
1318
1319  // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1320  SinglePassRunAndMatch<InstBindlessCheckPass>(
1321      defs + kImportStub + func1 + func2, true, 23u);
1322}
1323
1324TEST_F(InstBindlessTest, RuntimeArray) {
1325  // This test verifies that the pass will correctly instrument shader
1326  // with runtime descriptor array. This test was created by editing the
1327  // SPIR-V from the Simple test.
1328
1329  // clang-format off
1330  const std::string defs = R"(
1331OpCapability Shader
1332OpCapability RuntimeDescriptorArray
1333;CHECK: OpCapability Linkage
1334OpExtension "SPV_EXT_descriptor_indexing"
1335%1 = OpExtInstImport "GLSL.std.450"
1336OpMemoryModel Logical GLSL450
1337OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor
1338;CHECK: OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord
1339OpExecutionMode %MainPs OriginUpperLeft
1340OpSource HLSL 500
1341OpName %MainPs "MainPs"
1342OpName %g_tColor "g_tColor"
1343OpName %PerViewConstantBuffer_t "PerViewConstantBuffer_t"
1344OpMemberName %PerViewConstantBuffer_t 0 "g_nDataIdx"
1345OpName %_ ""
1346OpName %g_sAniso "g_sAniso"
1347OpName %i_vTextureCoords "i.vTextureCoords"
1348OpName %_entryPointOutput_vColor "@entryPointOutput.vColor"
1349OpDecorate %g_tColor DescriptorSet 1
1350OpDecorate %g_tColor Binding 2
1351OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0
1352OpDecorate %PerViewConstantBuffer_t Block
1353OpDecorate %g_sAniso DescriptorSet 1
1354OpDecorate %g_sAniso Binding 3
1355OpDecorate %i_vTextureCoords Location 0
1356OpDecorate %_entryPointOutput_vColor Location 0
1357)" + kImportDeco + R"(
1358;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
1359%void = OpTypeVoid
1360%3 = OpTypeFunction %void
1361%float = OpTypeFloat 32
1362%v2float = OpTypeVector %float 2
1363%v4float = OpTypeVector %float 4
1364%int = OpTypeInt 32 1
1365%int_0 = OpConstant %int 0
1366%20 = OpTypeImage %float 2D 0 0 0 1 Unknown
1367%uint = OpTypeInt 32 0
1368%uint_1 = OpConstant %uint 1
1369%_rarr_20 = OpTypeRuntimeArray %20
1370%_ptr_UniformConstant__arr_20 = OpTypePointer UniformConstant %_rarr_20
1371%g_tColor = OpVariable %_ptr_UniformConstant__arr_20 UniformConstant
1372%PerViewConstantBuffer_t = OpTypeStruct %uint
1373%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t
1374%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant
1375%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint
1376%_ptr_UniformConstant_20 = OpTypePointer UniformConstant %20
1377%35 = OpTypeSampler
1378%_ptr_UniformConstant_35 = OpTypePointer UniformConstant %35
1379%g_sAniso = OpVariable %_ptr_UniformConstant_35 UniformConstant
1380%39 = OpTypeSampledImage %20
1381%_ptr_Input_v2float = OpTypePointer Input %v2float
1382%i_vTextureCoords = OpVariable %_ptr_Input_v2float Input
1383%_ptr_Output_v4float = OpTypePointer Output %v4float
1384%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output
1385;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
1386;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
1387;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
1388)";
1389
1390  const std::string main_func = R"(
1391%MainPs = OpFunction %void None %3
1392%5 = OpLabel
1393%53 = OpLoad %v2float %i_vTextureCoords
1394%63 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0
1395%64 = OpLoad %uint %63
1396%65 = OpAccessChain %_ptr_UniformConstant_20 %g_tColor %64
1397%66 = OpLoad %20 %65
1398%67 = OpLoad %35 %g_sAniso
1399%68 = OpSampledImage %39 %66 %67
1400%71 = OpImageSampleImplicitLod %v4float %68 %53
1401OpStore %_entryPointOutput_vColor %71
1402;CHECK-NOT: %71 = OpImageSampleImplicitLod %v4float %68 %53
1403;CHECK-NOT: OpStore %_entryPointOutput_vColor %71
1404;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
1405;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
1406;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
1407;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
1408;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
1409;CHECK: [[check_result:%\w+]] = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_60 {{%\w+}} %uint_1 %uint_2 %32 %uint_0
1410;CHECK: OpSelectionMerge {{%\w+}} None
1411;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
1412;CHECK: {{%\w+}} = OpLabel
1413;CHECK: {{%\w+}} = OpLoad %16 %33
1414;CHECK: {{%\w+}} = OpSampledImage %26 {{%\w+}} %35
1415;CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %30
1416;CHECK: OpBranch {{%\w+}}
1417;CHECK: {{%\w+}} = OpLabel
1418;CHECK: OpBranch {{%\w+}}
1419;CHECK: {{%\w+}} = OpLabel
1420;CHECK: [[phi_result_1:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
1421;CHECK: OpStore %_entryPointOutput_vColor [[phi_result_1]]
1422OpReturn
1423OpFunctionEnd
1424)";
1425  // clang-format on
1426
1427  // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1428  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + kImportStub + main_func,
1429                                               true, 23u);
1430}
1431
1432TEST_F(InstBindlessTest, InstrumentInitCheckOnScalarDescriptor) {
1433  // This test verifies that the pass will correctly instrument vanilla
1434  // texture sample on a scalar descriptor with an initialization check if the
1435  // input_init_enable argument is set to true. This can happen when the
1436  // descriptor indexing extension is enabled in the API but the SPIR-V
1437  // does not have the extension enabled because it does not contain a
1438  // runtime array. This is the same shader as NoInstrumentNonBindless.
1439
1440  // clang-format off
1441  const std::string defs = R"(
1442OpCapability Shader
1443;CHECK: OpCapability Linkage
1444%1 = OpExtInstImport "GLSL.std.450"
1445OpMemoryModel Logical GLSL450
1446OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor
1447;CHECK: OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord
1448OpExecutionMode %MainPs OriginUpperLeft
1449OpSource HLSL 500
1450OpName %MainPs "MainPs"
1451OpName %g_tColor "g_tColor"
1452OpName %g_sAniso "g_sAniso"
1453OpName %i_vTextureCoords "i.vTextureCoords"
1454OpName %_entryPointOutput_vColor "@entryPointOutput.vColor"
1455OpDecorate %g_tColor DescriptorSet 1
1456OpDecorate %g_tColor Binding 2
1457OpDecorate %g_sAniso DescriptorSet 1
1458OpDecorate %g_sAniso Binding 2
1459OpDecorate %i_vTextureCoords Location 0
1460OpDecorate %_entryPointOutput_vColor Location 0
1461)" + kImportDeco + R"(
1462;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
1463%void = OpTypeVoid
1464%8 = OpTypeFunction %void
1465%float = OpTypeFloat 32
1466%v2float = OpTypeVector %float 2
1467%v4float = OpTypeVector %float 4
1468%12 = OpTypeImage %float 2D 0 0 0 1 Unknown
1469%_ptr_UniformConstant_12 = OpTypePointer UniformConstant %12
1470%g_tColor = OpVariable %_ptr_UniformConstant_12 UniformConstant
1471%14 = OpTypeSampler
1472%_ptr_UniformConstant_14 = OpTypePointer UniformConstant %14
1473%g_sAniso = OpVariable %_ptr_UniformConstant_14 UniformConstant
1474%16 = OpTypeSampledImage %12
1475%_ptr_Input_v2float = OpTypePointer Input %v2float
1476%i_vTextureCoords = OpVariable %_ptr_Input_v2float Input
1477%_ptr_Output_v4float = OpTypePointer Output %v4float
1478%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output
1479;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
1480)";
1481
1482  const std::string main_func = R"(
1483%MainPs = OpFunction %void None %8
1484%19 = OpLabel
1485%20 = OpLoad %v2float %i_vTextureCoords
1486%21 = OpLoad %12 %g_tColor
1487%22 = OpLoad %14 %g_sAniso
1488%23 = OpSampledImage %16 %21 %22
1489%24 = OpImageSampleImplicitLod %v4float %23 %20
1490OpStore %_entryPointOutput_vColor %24
1491;CHECK-NOT: %24 = OpImageSampleImplicitLod %v4float %23 %20
1492;CHECK-NOT: OpStore %_entryPointOutput_vColor %24
1493;CHECK: [[check_result:%\w+]] = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_40 {{%\w+}} %uint_1 %uint_2 %uint_0 %uint_0
1494;CHECK: OpSelectionMerge {{%\w+}} None
1495;CHECK: OpBranchConditional [[check_result]] {{%\w+}} {{%\w+}}
1496;CHECK: {{%\w+}} = OpLabel
1497;CHECK: {{%\w+}} = OpLoad %12 %g_tColor
1498;CHECK: {{%\w+}} = OpSampledImage %16 {{%\w+}} %22
1499;CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %20
1500;CHECK: OpBranch {{%\w+}}
1501;CHECK: {{%\w+}} = OpLabel
1502;CHECK: OpBranch {{%\w+}}
1503;CHECK: {{%\w+}} = OpLabel
1504;CHECK: [[phi_result:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
1505;CHECK: OpStore %_entryPointOutput_vColor [[phi_result]]
1506OpReturn
1507OpFunctionEnd
1508)";
1509  // clang-format on
1510
1511  // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1512  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + kImportStub + main_func,
1513                                               true, 23u);
1514}
1515
1516TEST_F(InstBindlessTest, SPV14AddToEntryPoint) {
1517  const std::string text = R"(
1518OpCapability Shader
1519OpExtension "SPV_EXT_descriptor_indexing"
1520OpMemoryModel Logical GLSL450
1521OpEntryPoint Fragment %foo "foo" %gid %image_var %sampler_var
1522;CHECK: OpEntryPoint Fragment {{%\w+}} "foo" {{%\w+}} {{%\w+}} {{%\w+}} %gl_FragCoord
1523OpExecutionMode %foo OriginUpperLeft
1524OpDecorate %image_var DescriptorSet 4
1525OpDecorate %image_var Binding 1
1526OpDecorate %sampler_var DescriptorSet 4
1527OpDecorate %sampler_var Binding 2
1528OpDecorate %gid DescriptorSet 0
1529OpDecorate %gid Binding 2
1530OpDecorate %struct Block
1531OpMemberDecorate %struct 0 Offset 0
1532%void = OpTypeVoid
1533%int = OpTypeInt 32 0
1534%int_0 = OpConstant %int 0
1535%v3int = OpTypeVector %int 3
1536%float = OpTypeFloat 32
1537%v3float = OpTypeVector %float 3
1538%v4float = OpTypeVector %float 4
1539%struct = OpTypeStruct %v3int
1540%ptr_ssbo_struct = OpTypePointer StorageBuffer %struct
1541%ptr_ssbo_v3int = OpTypePointer StorageBuffer %v3int
1542%gid = OpVariable %ptr_ssbo_struct StorageBuffer
1543%image = OpTypeImage %float 3D 0 0 0 1 Unknown
1544%ptr_uc_image = OpTypePointer UniformConstant %image
1545%sampler = OpTypeSampler
1546%ptr_uc_sampler = OpTypePointer UniformConstant %sampler
1547%image_var = OpVariable %ptr_uc_image UniformConstant
1548%sampler_var = OpVariable %ptr_uc_sampler UniformConstant
1549%sampled = OpTypeSampledImage %image
1550%void_fn = OpTypeFunction %void
1551%foo = OpFunction %void None %void_fn
1552%entry = OpLabel
1553%ld_image = OpLoad %image %image_var
1554%ld_sampler = OpLoad %sampler %sampler_var
1555%gep = OpAccessChain %ptr_ssbo_v3int %gid %int_0
1556%ld_gid = OpLoad %v3int %gep
1557%convert = OpConvertUToF %v3float %ld_gid
1558%sampled_image = OpSampledImage %sampled %ld_image %ld_sampler
1559%sample = OpImageSampleImplicitLod %v4float %sampled_image %convert
1560OpReturn
1561OpFunctionEnd
1562)";
1563
1564  SetTargetEnv(SPV_ENV_VULKAN_1_1_SPIRV_1_4);
1565  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 23u);
1566}
1567
1568TEST_F(InstBindlessTest, SPV14AddToEntryPoints) {
1569  const std::string text = R"(
1570OpCapability Shader
1571;CHECK: OpCapability Linkage
1572OpExtension "SPV_EXT_descriptor_indexing"
1573OpMemoryModel Logical GLSL450
1574OpEntryPoint Fragment %foo "foo" %gid %image_var %sampler_var
1575;CHECK: OpEntryPoint Fragment {{%\w+}} "foo" {{%\w+}} {{%\w+}} {{%\w+}} %gl_FragCoord
1576OpEntryPoint Fragment %foo "bar" %gid %image_var %sampler_var
1577;CHECK: OpEntryPoint Fragment {{%\w+}} "bar" {{%\w+}} {{%\w+}} {{%\w+}} %gl_FragCoord
1578OpExecutionMode %foo OriginUpperLeft
1579OpDecorate %image_var DescriptorSet 3
1580OpDecorate %image_var Binding 2
1581OpDecorate %sampler_var DescriptorSet 3
1582OpDecorate %sampler_var Binding 3
1583OpDecorate %gid DescriptorSet 3
1584OpDecorate %gid Binding 4
1585OpDecorate %struct Block
1586OpMemberDecorate %struct 0 Offset 0
1587%void = OpTypeVoid
1588%int = OpTypeInt 32 0
1589%int_0 = OpConstant %int 0
1590%v3int = OpTypeVector %int 3
1591%float = OpTypeFloat 32
1592%v3float = OpTypeVector %float 3
1593%v4float = OpTypeVector %float 4
1594%struct = OpTypeStruct %v3int
1595%ptr_ssbo_struct = OpTypePointer StorageBuffer %struct
1596%ptr_ssbo_v3int = OpTypePointer StorageBuffer %v3int
1597%gid = OpVariable %ptr_ssbo_struct StorageBuffer
1598%image = OpTypeImage %float 3D 0 0 0 1 Unknown
1599%ptr_uc_image = OpTypePointer UniformConstant %image
1600%sampler = OpTypeSampler
1601%ptr_uc_sampler = OpTypePointer UniformConstant %sampler
1602%image_var = OpVariable %ptr_uc_image UniformConstant
1603%sampler_var = OpVariable %ptr_uc_sampler UniformConstant
1604%sampled = OpTypeSampledImage %image
1605%void_fn = OpTypeFunction %void
1606%foo = OpFunction %void None %void_fn
1607%entry = OpLabel
1608%ld_image = OpLoad %image %image_var
1609%ld_sampler = OpLoad %sampler %sampler_var
1610%gep = OpAccessChain %ptr_ssbo_v3int %gid %int_0
1611%ld_gid = OpLoad %v3int %gep
1612%convert = OpConvertUToF %v3float %ld_gid
1613%sampled_image = OpSampledImage %sampled %ld_image %ld_sampler
1614%sample = OpImageSampleImplicitLod %v4float %sampled_image %convert
1615OpReturn
1616OpFunctionEnd
1617)";
1618
1619  SetTargetEnv(SPV_ENV_VULKAN_1_1_SPIRV_1_4);
1620  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 23u);
1621}
1622
1623TEST_F(InstBindlessTest, InstBoundsAndInitLoadUnsizedUBOArray) {
1624  // #version 450
1625  // #extension GL_EXT_nonuniform_qualifier : enable
1626  //
1627  // layout(location=0) in nonuniformEXT flat int nu_ii;
1628  // layout(location=0) out float b;
1629  //
1630  // layout(set = 6, binding=3)  uniform uname { float a; }  uniformBuffer[];
1631  //
1632  // void main()
1633  // {
1634  //     b = uniformBuffer[nu_ii].a;
1635  // }
1636
1637  // clang-format off
1638  const std::string defs = R"(
1639OpCapability Shader
1640OpCapability ShaderNonUniform
1641OpCapability RuntimeDescriptorArray
1642OpCapability UniformBufferArrayNonUniformIndexing
1643;CHECK: OpCapability Linkage
1644OpExtension "SPV_EXT_descriptor_indexing"
1645%1 = OpExtInstImport "GLSL.std.450"
1646OpMemoryModel Logical GLSL450
1647OpEntryPoint Fragment %main "main" %b %nu_ii
1648;CHECK: OpEntryPoint Fragment %main "main" %b %nu_ii %gl_FragCoord
1649OpExecutionMode %main OriginUpperLeft
1650OpSource GLSL 450
1651OpSourceExtension "GL_EXT_nonuniform_qualifier"
1652OpName %main "main"
1653OpName %b "b"
1654OpName %uname "uname"
1655OpMemberName %uname 0 "a"
1656OpName %uniformBuffer "uniformBuffer"
1657OpName %nu_ii "nu_ii"
1658OpDecorate %b Location 0
1659OpMemberDecorate %uname 0 Offset 0
1660OpDecorate %uname Block
1661OpDecorate %uniformBuffer DescriptorSet 6
1662OpDecorate %uniformBuffer Binding 3
1663OpDecorate %nu_ii Flat
1664OpDecorate %nu_ii Location 0
1665OpDecorate %nu_ii NonUniform
1666OpDecorate %16 NonUniform
1667OpDecorate %20 NonUniform
1668;CHECK: OpDecorate {{%\w+}} NonUniform
1669)" + kImportDeco + R"(
1670;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
1671;CHECK: OpDecorate {{%\w+}} NonUniform
1672%void = OpTypeVoid
1673%3 = OpTypeFunction %void
1674%float = OpTypeFloat 32
1675%_ptr_Output_float = OpTypePointer Output %float
1676%b = OpVariable %_ptr_Output_float Output
1677%uname = OpTypeStruct %float
1678%_runtimearr_uname = OpTypeRuntimeArray %uname
1679%_ptr_Uniform__runtimearr_uname = OpTypePointer Uniform %_runtimearr_uname
1680%uniformBuffer = OpVariable %_ptr_Uniform__runtimearr_uname Uniform
1681%int = OpTypeInt 32 1
1682%_ptr_Input_int = OpTypePointer Input %int
1683%nu_ii = OpVariable %_ptr_Input_int Input
1684%int_0 = OpConstant %int 0
1685%_ptr_Uniform_float = OpTypePointer Uniform %float
1686;CHECK: %v4uint = OpTypeVector %uint 4
1687;CHECK: %v4float = OpTypeVector %float 4
1688;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
1689;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
1690;CHECK: [[null_float:%\w+]] = OpConstantNull %float
1691)";
1692
1693  const std::string main_func = R"(
1694%main = OpFunction %void None %3
1695%5 = OpLabel
1696%16 = OpLoad %int %nu_ii
1697%19 = OpAccessChain %_ptr_Uniform_float %uniformBuffer %16 %int_0
1698%20 = OpLoad %float %19
1699OpStore %b %20
1700;CHECK-NOT: %20 = OpLoad %float %19
1701;CHECK-NOT: OpStore %b %20
1702;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
1703;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
1704;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
1705;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
1706;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
1707;CHECK: {{%\w+}} = OpBitcast %uint %7
1708;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_46 {{%\w+}} %uint_6 %uint_3 {{%\w+}} {{%\w+}}
1709;CHECK: OpSelectionMerge {{%\w+}} None
1710;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
1711;CHECK: {{%\w+}} = OpLabel
1712;CHECK: {{%\w+}} = OpLoad %float %20
1713;CHECK: OpBranch {{%\w+}}
1714;CHECK: {{%\w+}} = OpLabel
1715;CHECK: OpBranch {{%\w+}}
1716;CHECK: {{%\w+}} = OpLabel
1717;CHECK: [[phi_result:%\w+]] = OpPhi %float {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}}
1718;CHECK: OpStore %b [[phi_result]]
1719OpReturn
1720OpFunctionEnd
1721)";
1722  // clang-format on
1723
1724  // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1725  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + kImportStub + main_func,
1726                                               true, 23u);
1727}
1728
1729TEST_F(InstBindlessTest, InstBoundsAndInitLoadUnsizedSSBOArrayDeprecated) {
1730  // #version 450
1731  // #extension GL_EXT_nonuniform_qualifier : enable
1732  //
1733  // layout(location=0) in nonuniformEXT flat int nu_ii;
1734  // layout(location=0) out float b;
1735  //
1736  // layout(set = 7, binding=3)  buffer bname { float b; }  storageBuffer[];
1737  //
1738  // void main()
1739  // {
1740  //     b = storageBuffer[nu_ii].b;
1741  // }
1742
1743  // clang-format off
1744  const std::string defs = R"(
1745OpCapability Shader
1746OpCapability ShaderNonUniform
1747OpCapability RuntimeDescriptorArray
1748OpCapability StorageBufferArrayNonUniformIndexing
1749;CHECK: OpCapability Linkage
1750OpExtension "SPV_EXT_descriptor_indexing"
1751%1 = OpExtInstImport "GLSL.std.450"
1752OpMemoryModel Logical GLSL450
1753OpEntryPoint Fragment %main "main" %b %nu_ii
1754;CHECK: OpEntryPoint Fragment %main "main" %b %nu_ii %gl_FragCoord
1755OpExecutionMode %main OriginUpperLeft
1756OpSource GLSL 450
1757OpSourceExtension "GL_EXT_nonuniform_qualifier"
1758OpName %main "main"
1759OpName %b "b"
1760OpName %bname "bname"
1761OpMemberName %bname 0 "a"
1762OpName %storageBuffer "storageBuffer"
1763OpName %nu_ii "nu_ii"
1764OpDecorate %b Location 0
1765OpMemberDecorate %bname 0 Offset 0
1766OpDecorate %bname Block
1767OpDecorate %storageBuffer DescriptorSet 7
1768OpDecorate %storageBuffer Binding 3
1769OpDecorate %nu_ii Flat
1770OpDecorate %nu_ii Location 0
1771OpDecorate %nu_ii NonUniform
1772OpDecorate %16 NonUniform
1773OpDecorate %20 NonUniform
1774)" + kImportDeco + R"(
1775;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
1776%void = OpTypeVoid
1777%3 = OpTypeFunction %void
1778%float = OpTypeFloat 32
1779%_ptr_Output_float = OpTypePointer Output %float
1780%b = OpVariable %_ptr_Output_float Output
1781%bname = OpTypeStruct %float
1782%_runtimearr_bname = OpTypeRuntimeArray %bname
1783%_ptr_StorageBuffer__runtimearr_bname = OpTypePointer StorageBuffer %_runtimearr_bname
1784%storageBuffer = OpVariable %_ptr_StorageBuffer__runtimearr_bname StorageBuffer
1785%int = OpTypeInt 32 1
1786%_ptr_Input_int = OpTypePointer Input %int
1787%nu_ii = OpVariable %_ptr_Input_int Input
1788%int_0 = OpConstant %int 0
1789%_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
1790;CHECK: %uint = OpTypeInt 32 0
1791;CHECK: %v4uint = OpTypeVector %uint 4
1792;CHECK: %v4float = OpTypeVector %float 4
1793;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
1794;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
1795;CHECK: [[null_float:%\w+]] = OpConstantNull %float
1796)";
1797
1798  const std::string main_func = R"(
1799%main = OpFunction %void None %3
1800%5 = OpLabel
1801%16 = OpLoad %int %nu_ii
1802%19 = OpAccessChain %_ptr_StorageBuffer_float %storageBuffer %16 %int_0
1803%20 = OpLoad %float %19
1804OpStore %b %20
1805;CHECK-NOT: %20 = OpLoad %float %19
1806;CHECK-NOT: OpStore %b %20
1807;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
1808;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
1809;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
1810;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
1811;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
1812;CHECK: {{%\w+}} = OpBitcast %uint %7
1813;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_46 {{%\w+}} %uint_7 %uint_3 {{%\w+}} {{%\w+}}
1814;CHECK: OpSelectionMerge {{%\w+}} None
1815;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
1816;CHECK: {{%\w+}} = OpLabel
1817;CHECK: {{%\w+}} = OpLoad %float %20
1818;CHECK: OpBranch {{%\w+}}
1819;CHECK: {{%\w+}} = OpLabel
1820;CHECK: OpBranch {{%\w+}}
1821;CHECK: {{%\w+}} = OpLabel
1822;CHECK: [[phi_result:%\w+]] = OpPhi %float {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}}
1823;CHECK: OpStore %b [[phi_result]]
1824OpReturn
1825OpFunctionEnd
1826)";
1827  // clang-format on
1828
1829  // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1830  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + kImportStub + main_func,
1831                                               true, 23u);
1832}
1833
1834TEST_F(InstBindlessTest, InstBoundsAndInitLoadUnsizedSSBOArray) {
1835  // Same as Deprecated but declaring as StorageBuffer Block
1836
1837  // clang-format off
1838  const std::string defs = R"(
1839OpCapability Shader
1840OpCapability ShaderNonUniform
1841OpCapability RuntimeDescriptorArray
1842OpCapability StorageBufferArrayNonUniformIndexing
1843;CHECK: OpCapability Linkage
1844OpExtension "SPV_EXT_descriptor_indexing"
1845%1 = OpExtInstImport "GLSL.std.450"
1846OpMemoryModel Logical GLSL450
1847OpEntryPoint Fragment %main "main" %b %nu_ii
1848;CHECK: OpEntryPoint Fragment %main "main" %b %nu_ii %gl_FragCoord
1849OpExecutionMode %main OriginUpperLeft
1850OpSource GLSL 450
1851OpSourceExtension "GL_EXT_nonuniform_qualifier"
1852OpName %main "main"
1853OpName %b "b"
1854OpName %bname "bname"
1855OpMemberName %bname 0 "a"
1856OpName %storageBuffer "storageBuffer"
1857OpName %nu_ii "nu_ii"
1858OpDecorate %b Location 0
1859OpMemberDecorate %bname 0 Offset 0
1860OpDecorate %bname Block
1861OpDecorate %storageBuffer DescriptorSet 0
1862OpDecorate %storageBuffer Binding 3
1863OpDecorate %nu_ii Flat
1864OpDecorate %nu_ii Location 0
1865OpDecorate %nu_ii NonUniform
1866OpDecorate %16 NonUniform
1867OpDecorate %20 NonUniform
1868;CHECK: OpDecorate {{%\w+}} NonUniform
1869)" + kImportDeco + R"(
1870;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
1871;CHECK: OpDecorate {{%\w+}} NonUniform
1872%void = OpTypeVoid
1873%3 = OpTypeFunction %void
1874%float = OpTypeFloat 32
1875%_ptr_Output_float = OpTypePointer Output %float
1876%b = OpVariable %_ptr_Output_float Output
1877%bname = OpTypeStruct %float
1878%_runtimearr_bname = OpTypeRuntimeArray %bname
1879%_ptr_StorageBuffer__runtimearr_bname = OpTypePointer StorageBuffer %_runtimearr_bname
1880%storageBuffer = OpVariable %_ptr_StorageBuffer__runtimearr_bname StorageBuffer
1881%int = OpTypeInt 32 1
1882%_ptr_Input_int = OpTypePointer Input %int
1883%nu_ii = OpVariable %_ptr_Input_int Input
1884%int_0 = OpConstant %int 0
1885%_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
1886;CHECK: %v4uint = OpTypeVector %uint 4
1887;CHECK: %v4float = OpTypeVector %float 4
1888;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
1889;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
1890;CHECK: [[null_float:%\w+]] = OpConstantNull %float
1891)";
1892
1893  const std::string main_func = R"(
1894%main = OpFunction %void None %3
1895%5 = OpLabel
1896%16 = OpLoad %int %nu_ii
1897%19 = OpAccessChain %_ptr_StorageBuffer_float %storageBuffer %16 %int_0
1898%20 = OpLoad %float %19
1899OpStore %b %20
1900;CHECK-NOT: %20 = OpLoad %float %19
1901;CHECK-NOT: OpStore %b %20
1902;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
1903;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
1904;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
1905;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
1906;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
1907;CHECK: {{%\w+}} = OpBitcast %uint %7
1908;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_46 {{%\w+}} %uint_0 %uint_3 {{%\w+}} {{%\w+}}
1909;CHECK: OpSelectionMerge {{%\w+}} None
1910;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
1911;CHECK: {{%\w+}} = OpLabel
1912;CHECK: {{%\w+}} = OpLoad %float %20
1913;CHECK: OpBranch {{%\w+}}
1914;CHECK: {{%\w+}} = OpLabel
1915;CHECK: OpBranch {{%\w+}}
1916;CHECK: {{%\w+}} = OpLabel
1917;CHECK: {{%\w+}} = OpPhi %float {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}}
1918;CHECK: OpStore %b {{%\w+}}
1919OpReturn
1920OpFunctionEnd
1921)";
1922  // clang-format on
1923
1924  // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1925  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + kImportStub + main_func,
1926                                               true, 23u);
1927}
1928
1929TEST_F(InstBindlessTest, InstInitLoadUBOScalar) {
1930  // #version 450
1931  // #extension GL_EXT_nonuniform_qualifier : enable
1932  //
1933  // layout(location=0) out float b;
1934  // layout(set=7, binding=3)  uniform uname { float a; }  uniformBuffer;
1935  //
1936  // void main()
1937  // {
1938  //     b = uniformBuffer.a;
1939  // }
1940
1941  // clang-format off
1942  const std::string defs = R"(
1943OpCapability Shader
1944;CHECK: OpCapability Linkage
1945OpExtension "SPV_EXT_descriptor_indexing"
1946%1 = OpExtInstImport "GLSL.std.450"
1947OpMemoryModel Logical GLSL450
1948OpEntryPoint Fragment %main "main" %b
1949;CHECK: OpEntryPoint Fragment %main "main" %b %gl_FragCoord
1950OpExecutionMode %main OriginUpperLeft
1951OpSource GLSL 450
1952OpSourceExtension "GL_EXT_nonuniform_qualifier"
1953OpName %main "main"
1954OpName %b "b"
1955OpName %uname "uname"
1956OpMemberName %uname 0 "a"
1957OpName %uniformBuffer "uniformBuffer"
1958OpDecorate %b Location 0
1959OpMemberDecorate %uname 0 Offset 0
1960OpDecorate %uname Block
1961OpDecorate %uniformBuffer DescriptorSet 7
1962OpDecorate %uniformBuffer Binding 3
1963)" + kImportDeco + R"(
1964;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
1965%void = OpTypeVoid
1966%3 = OpTypeFunction %void
1967%float = OpTypeFloat 32
1968%_ptr_Output_float = OpTypePointer Output %float
1969%b = OpVariable %_ptr_Output_float Output
1970%uname = OpTypeStruct %float
1971%_ptr_Uniform_uname = OpTypePointer Uniform %uname
1972%uniformBuffer = OpVariable %_ptr_Uniform_uname Uniform
1973%int = OpTypeInt 32 1
1974%int_0 = OpConstant %int 0
1975%_ptr_Uniform_float = OpTypePointer Uniform %float
1976;CHECK: %int = OpTypeInt 32 1
1977;CHECK: %_ptr_Uniform_float = OpTypePointer Uniform %float
1978;CHECK: %uint = OpTypeInt 32 0
1979;CHECK: %v4uint = OpTypeVector %uint 4
1980;CHECK: %v4float = OpTypeVector %float 4
1981;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
1982;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
1983;CHECK: [[null_float:%\w+]] = OpConstantNull %float
1984)";
1985
1986  const std::string main_func = R"(
1987%main = OpFunction %void None %3
1988%5 = OpLabel
1989%15 = OpAccessChain %_ptr_Uniform_float %uniformBuffer %int_0
1990%16 = OpLoad %float %15
1991OpStore %b %16
1992;CHECK-NOT: %16 = OpLoad %float %15
1993;CHECK-NOT: OpStore %b %16
1994;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
1995;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
1996;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
1997;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
1998;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
1999;CHECK: [[check_result:%\w+]] = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_33 {{%\w+}} %uint_7 %uint_3 %uint_0 {{%\w+}}
2000;CHECK: OpSelectionMerge {{%\w+}} None
2001;CHECK: OpBranchConditional [[check_result]] {{%\w+}} {{%\w+}}
2002;CHECK: {{%\w+}} = OpLabel
2003;CHECK: {{%\w+}} = OpLoad %float %15
2004;CHECK: OpBranch {{%\w+}}
2005;CHECK: {{%\w+}} = OpLabel
2006;CHECK: OpBranch {{%\w+}}
2007;CHECK: {{%\w+}} = OpLabel
2008;CHECK: [[phi_result:%\w+]] = OpPhi %float {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}}
2009;CHECK: OpStore %b [[phi_result]]
2010OpReturn
2011OpFunctionEnd
2012)";
2013  // clang-format on
2014
2015  // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
2016  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + kImportStub + main_func,
2017                                               true, 23u);
2018}
2019
2020TEST_F(InstBindlessTest, InstBoundsInitStoreUnsizedSSBOArray) {
2021  // #version 450
2022  // #extension GL_EXT_nonuniform_qualifier : enable
2023  //
2024  // layout(location=0) in nonuniformEXT flat int nu_ii;
2025  // layout(location=1) in float b;
2026  //
2027  // layout(set=5, binding=4)  buffer bname { float b; }  storageBuffer[];
2028  //
2029  // void main()
2030  // {
2031  //     storageBuffer[nu_ii].b = b;
2032  // }
2033
2034  // clang-format off
2035  const std::string defs = R"(OpCapability Shader
2036OpCapability ShaderNonUniform
2037OpCapability RuntimeDescriptorArray
2038OpCapability StorageBufferArrayNonUniformIndexing
2039;CHECK: OpCapability Linkage
2040OpExtension "SPV_EXT_descriptor_indexing"
2041%1 = OpExtInstImport "GLSL.std.450"
2042OpMemoryModel Logical GLSL450
2043OpEntryPoint Fragment %main "main" %nu_ii %b
2044;CHECK: OpEntryPoint Fragment %main "main" %nu_ii %b %gl_FragCoord
2045OpExecutionMode %main OriginUpperLeft
2046OpSource GLSL 450
2047OpSourceExtension "GL_EXT_nonuniform_qualifier"
2048OpName %main "main"
2049OpName %bname "bname"
2050OpMemberName %bname 0 "b"
2051OpName %storageBuffer "storageBuffer"
2052OpName %nu_ii "nu_ii"
2053OpName %b "b"
2054OpMemberDecorate %bname 0 Offset 0
2055OpDecorate %bname BufferBlock
2056OpDecorate %storageBuffer DescriptorSet 5
2057OpDecorate %storageBuffer Binding 4
2058OpDecorate %nu_ii Flat
2059OpDecorate %nu_ii Location 0
2060OpDecorate %nu_ii NonUniform
2061OpDecorate %14 NonUniform
2062OpDecorate %b Location 1
2063)" + kImportDeco + R"(
2064;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
2065%void = OpTypeVoid
2066%3 = OpTypeFunction %void
2067%float = OpTypeFloat 32
2068%bname = OpTypeStruct %float
2069%_runtimearr_bname = OpTypeRuntimeArray %bname
2070%_ptr_Uniform__runtimearr_bname = OpTypePointer Uniform %_runtimearr_bname
2071%storageBuffer = OpVariable %_ptr_Uniform__runtimearr_bname Uniform
2072%int = OpTypeInt 32 1
2073%_ptr_Input_int = OpTypePointer Input %int
2074%nu_ii = OpVariable %_ptr_Input_int Input
2075%int_0 = OpConstant %int 0
2076%_ptr_Input_float = OpTypePointer Input %float
2077%b = OpVariable %_ptr_Input_float Input
2078%_ptr_Uniform_float = OpTypePointer Uniform %float
2079;CHECK: %v4uint = OpTypeVector %uint 4
2080;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
2081)";
2082
2083  const std::string main_func = R"(
2084%main = OpFunction %void None %3
2085%5 = OpLabel
2086%14 = OpLoad %int %nu_ii
2087%18 = OpLoad %float %b
2088%20 = OpAccessChain %_ptr_Uniform_float %storageBuffer %14 %int_0
2089OpStore %20 %18
2090;CHECK-NOT: OpStore %20 %18
2091;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
2092;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
2093;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
2094;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
2095;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
2096;CHECK: {{%\w+}} = OpBitcast %uint %7
2097;CHECK: [[check_result:%\w+]] = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_46 {{%\w+}} %uint_5 %uint_4 {{%\w+}} {{%\w+}}
2098;CHECK: OpSelectionMerge {{%\w+}} None
2099;CHECK: OpBranchConditional [[check_result]] {{%\w+}} {{%\w+}}
2100;CHECK: {{%\w+}} = OpLabel
2101;CHECK: OpStore %20 %19
2102;CHECK: OpBranch {{%\w+}}
2103;CHECK: {{%\w+}} = OpLabel
2104;CHECK: OpBranch {{%\w+}}
2105;CHECK: {{%\w+}} = OpLabel
2106OpReturn
2107OpFunctionEnd
2108)";
2109  // clang-format on
2110
2111  // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
2112  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + kImportStub + main_func,
2113                                               true, 23u);
2114}
2115
2116TEST_F(InstBindlessTest, InstBoundsInitLoadSizedUBOArray) {
2117  // #version 450
2118  // #extension GL_EXT_nonuniform_qualifier : enable
2119  //
2120  // layout(location=0) in nonuniformEXT flat int nu_ii;
2121  // layout(location=0) out float b;
2122  //
2123  // layout(set=1, binding=3)  uniform uname { float a; }  uniformBuffer[128];
2124  //
2125  // void main()
2126  // {
2127  //     b = uniformBuffer[nu_ii].a;
2128  // }
2129
2130  // clang-format off
2131  const std::string defs = R"(
2132OpCapability Shader
2133OpCapability ShaderNonUniform
2134OpCapability UniformBufferArrayNonUniformIndexing
2135;CHECK: OpCapability Linkage
2136OpExtension "SPV_EXT_descriptor_indexing"
2137%1 = OpExtInstImport "GLSL.std.450"
2138OpMemoryModel Logical GLSL450
2139OpEntryPoint Fragment %main "main" %b %nu_ii
2140;CHECK: OpEntryPoint Fragment %main "main" %b %nu_ii %gl_FragCoord
2141OpExecutionMode %main OriginUpperLeft
2142OpSource GLSL 450
2143OpSourceExtension "GL_EXT_nonuniform_qualifier"
2144OpName %main "main"
2145OpName %b "b"
2146OpName %uname "uname"
2147OpMemberName %uname 0 "a"
2148OpName %uniformBuffer "uniformBuffer"
2149OpName %nu_ii "nu_ii"
2150OpDecorate %b Location 0
2151OpMemberDecorate %uname 0 Offset 0
2152OpDecorate %uname Block
2153OpDecorate %uniformBuffer DescriptorSet 1
2154OpDecorate %uniformBuffer Binding 3
2155OpDecorate %nu_ii Flat
2156OpDecorate %nu_ii Location 0
2157OpDecorate %nu_ii NonUniform
2158OpDecorate %18 NonUniform
2159OpDecorate %22 NonUniform
2160)" + kImportDeco + R"(
2161;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
2162;CHECK: OpDecorate [[load_result:%\w+]] NonUniform
2163%void = OpTypeVoid
2164%3 = OpTypeFunction %void
2165%float = OpTypeFloat 32
2166%_ptr_Output_float = OpTypePointer Output %float
2167%b = OpVariable %_ptr_Output_float Output
2168%uname = OpTypeStruct %float
2169%uint = OpTypeInt 32 0
2170%uint_128 = OpConstant %uint 128
2171%_arr_uname_uint_128 = OpTypeArray %uname %uint_128
2172%_ptr_Uniform__arr_uname_uint_128 = OpTypePointer Uniform %_arr_uname_uint_128
2173%uniformBuffer = OpVariable %_ptr_Uniform__arr_uname_uint_128 Uniform
2174%int = OpTypeInt 32 1
2175%_ptr_Input_int = OpTypePointer Input %int
2176%nu_ii = OpVariable %_ptr_Input_int Input
2177%int_0 = OpConstant %int 0
2178%_ptr_Uniform_float = OpTypePointer Uniform %float
2179;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
2180;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
2181;CHECK: [[null_float:%\w+]] = OpConstantNull %float
2182)";
2183
2184  const std::string main_func = R"(
2185%main = OpFunction %void None %3
2186%5 = OpLabel
2187%18 = OpLoad %int %nu_ii
2188%21 = OpAccessChain %_ptr_Uniform_float %uniformBuffer %18 %int_0
2189%22 = OpLoad %float %21
2190OpStore %b %22
2191;CHECK-NOT: %22 = OpLoad %float %21
2192;CHECK-NOT: OpStore %b %22
2193;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
2194;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
2195;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
2196;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
2197;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
2198;CHECK: {{%\w+}} = OpBitcast %uint %7
2199;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_47 {{%\w+}} %uint_1 %uint_3 {{%\w+}} {{%\w+}}
2200;CHECK: OpSelectionMerge {{%\w+}} None
2201;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
2202;CHECK: {{%\w+}} = OpLabel
2203;CHECK: {{%\w+}} = OpLoad %float %22
2204;CHECK: OpBranch {{%\w+}}
2205;CHECK: {{%\w+}} = OpLabel
2206;CHECK: OpBranch {{%\w+}}
2207;CHECK: {{%\w+}} = OpLabel
2208;CHECK: {{%\w+}} = OpPhi %float {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}}
2209;CHECK: OpStore %b {{%\w+}}
2210OpReturn
2211OpFunctionEnd
2212)";
2213  // clang-format on
2214
2215  // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
2216  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + kImportStub + main_func,
2217                                               true, 23u);
2218}
2219
2220TEST_F(InstBindlessTest,
2221       InstBoundsComputeShaderInitLoadVariableSizedSampledImagesArray) {
2222  // #version 450
2223  // #extension GL_EXT_nonuniform_qualifier : enable
2224  //
2225  // layout (local_size_x = 1, local_size_y = 1) in;
2226  //
2227  // layout(set = 2, binding = 0, std140) buffer Input {
2228  //   uint index;
2229  //   float red;
2230  // } sbo;
2231  //
2232  // layout(set = 2, binding = 1, rgba32f) readonly uniform image2D images[];
2233  //
2234  // void main()
2235  // {
2236  //    sbo.red = imageLoad(images[sbo.index], ivec2(0, 0)).r;
2237  // }
2238
2239  // clang-format off
2240  const std::string defs = R"(
2241OpCapability Shader
2242OpCapability RuntimeDescriptorArray
2243;CHECK: OpCapability Linkage
2244OpExtension "SPV_EXT_descriptor_indexing"
2245%1 = OpExtInstImport "GLSL.std.450"
2246OpMemoryModel Logical GLSL450
2247OpEntryPoint GLCompute %main "main"
2248;CHECK: OpEntryPoint GLCompute %main "main" %gl_GlobalInvocationID
2249OpExecutionMode %main LocalSize 1 1 1
2250OpSource GLSL 450
2251OpSourceExtension "GL_EXT_nonuniform_qualifier"
2252OpName %main "main"
2253OpName %Input "Input"
2254OpMemberName %Input 0 "index"
2255OpMemberName %Input 1 "red"
2256OpName %sbo "sbo"
2257OpName %images "images"
2258OpMemberDecorate %Input 0 Offset 0
2259OpMemberDecorate %Input 1 Offset 4
2260OpDecorate %Input BufferBlock
2261OpDecorate %sbo DescriptorSet 2
2262OpDecorate %sbo Binding 0
2263OpDecorate %images DescriptorSet 2
2264OpDecorate %images Binding 1
2265OpDecorate %images NonWritable
2266)" + kImportDeco + R"(
2267;CHECK: OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId
2268%void = OpTypeVoid
2269%3 = OpTypeFunction %void
2270%uint = OpTypeInt 32 0
2271%float = OpTypeFloat 32
2272%Input = OpTypeStruct %uint %float
2273%_ptr_Uniform_Input = OpTypePointer Uniform %Input
2274%sbo = OpVariable %_ptr_Uniform_Input Uniform
2275%int = OpTypeInt 32 1
2276%int_1 = OpConstant %int 1
2277%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f
2278%_runtimearr_13 = OpTypeRuntimeArray %13
2279%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13
2280%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant
2281%int_0 = OpConstant %int 0
2282%_ptr_Uniform_uint = OpTypePointer Uniform %uint
2283%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13
2284%v2int = OpTypeVector %int 2
2285%25 = OpConstantComposite %v2int %int_0 %int_0
2286%v4float = OpTypeVector %float 4
2287%uint_0 = OpConstant %uint 0
2288%_ptr_Uniform_float = OpTypePointer Uniform %float
2289;CHECK: %v3uint = OpTypeVector %uint 3
2290;CHECK: %_ptr_Input_v3uint = OpTypePointer Input %v3uint
2291;CHECK: %gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input
2292;CHECK: [[null_uint:%\w+]] = OpConstantNull %uint
2293;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
2294)";
2295
2296  const std::string main_func = R"(
2297%main = OpFunction %void None %3
2298%5 = OpLabel
2299%19 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0
2300%20 = OpLoad %uint %19
2301%22 = OpAccessChain %_ptr_UniformConstant_13 %images %20
2302%23 = OpLoad %13 %22
2303%27 = OpImageRead %v4float %23 %25
2304%29 = OpCompositeExtract %float %27 0
2305%31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
2306OpStore %31 %29
2307;CHECK-NOT: OpStore %31 %29
2308;CHECK: {{%\w+}} = OpLoad %v3uint %gl_GlobalInvocationID
2309;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
2310;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
2311;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
2312;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5 {{%\w+}} {{%\w+}} {{%\w+}}
2313;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_48 {{%\w+}} %uint_2 %uint_0 %uint_0 {{%\w+}}
2314;CHECK: OpSelectionMerge {{%\w+}} None
2315;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
2316;CHECK: {{%\w+}} = OpLabel
2317;CHECK: {{%\w+}} = OpLoad %uint %25
2318;CHECK: OpBranch {{%\w+}}
2319;CHECK: {{%\w+}} = OpLabel
2320;CHECK: OpBranch {{%\w+}}
2321;CHECK: {{%\w+}} = OpLabel
2322;CHECK: {{%\w+}} = OpPhi %uint {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}}
2323;CHECK: {{%\w+}} = OpAccessChain %_ptr_UniformConstant_13 %images {{%\w+}}
2324;CHECK: {{%\w+}} = OpLoad %13 {{%\w+}}
2325;CHECK: {{%\w+}} = OpLoad %v3uint %gl_GlobalInvocationID
2326;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
2327;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
2328;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
2329;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5 {{%\w+}} {{%\w+}} {{%\w+}}
2330;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_51 {{%\w+}} %uint_2 %uint_1 {{%\w+}} %uint_0
2331;CHECK: OpSelectionMerge {{%\w+}} None
2332;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
2333;CHECK: {{%\w+}} = OpLabel
2334;CHECK: {{%\w+}} = OpLoad %13 {{%\w+}}
2335;CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20
2336;CHECK: OpBranch {{%\w+}}
2337;CHECK: {{%\w+}} = OpLabel
2338;CHECK: OpBranch {{%\w+}}
2339;CHECK: {{%\w+}} = OpLabel
2340;CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}}
2341;CHECK: {{%\w+}} = OpCompositeExtract %float {{%\w+}} 0
2342;CHECK: {{%\w+}} = OpAccessChain %_ptr_Uniform_float %sbo %int_1
2343;CHECK: {{%\w+}} = OpLoad %v3uint %gl_GlobalInvocationID
2344;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
2345;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
2346;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
2347;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5 {{%\w+}} {{%\w+}} {{%\w+}}
2348;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_54 {{%\w+}} %uint_2 %uint_0 %uint_0 {{%\w+}}
2349;CHECK: OpSelectionMerge {{%\w+}} None
2350;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
2351;CHECK: {{%\w+}} = OpLabel
2352;CHECK: OpStore %31 {{%\w+}}
2353;CHECK: OpBranch {{%\w+}}
2354;CHECK: {{%\w+}} = OpLabel
2355;CHECK: OpBranch {{%\w+}}
2356;CHECK: {{%\w+}} = OpLabel
2357OpReturn
2358OpFunctionEnd
2359)";
2360  // clang-format on
2361
2362  // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
2363  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + kImportStub + main_func,
2364                                               true, 23u);
2365}
2366
2367TEST_F(InstBindlessTest,
2368       InstBoundsRayGenerationInitLoadVariableSizedSampledImagesArray) {
2369  // #version 460
2370  // #extension GL_EXT_nonuniform_qualifier : require
2371  // #extension GL_NV_ray_tracing : require
2372  //
2373  // layout(set = 3, binding = 1, std140) buffer StorageBuffer {
2374  //   uint index;
2375  //   float red;
2376  // } sbo;
2377  //
2378  // layout(set = 3, binding = 5, rgba32f) readonly uniform image2D images[];
2379  //
2380  // void main()
2381  // {
2382  //    sbo.red = imageLoad(images[sbo.index], ivec2(0, 0)).r;
2383  // }
2384
2385  // clang-format off
2386  const std::string defs = R"(
2387OpCapability RuntimeDescriptorArray
2388OpCapability RayTracingNV
2389;CHECK: OpCapability Linkage
2390OpExtension "SPV_EXT_descriptor_indexing"
2391OpExtension "SPV_NV_ray_tracing"
2392%1 = OpExtInstImport "GLSL.std.450"
2393OpMemoryModel Logical GLSL450
2394OpEntryPoint RayGenerationNV %main "main"
2395;CHECK: OpEntryPoint RayGenerationNV %main "main" [[launch_id:%\w+]]
2396OpSource GLSL 460
2397OpSourceExtension "GL_EXT_nonuniform_qualifier"
2398OpSourceExtension "GL_NV_ray_tracing"
2399OpName %main "main"
2400OpName %StorageBuffer "StorageBuffer"
2401OpMemberName %StorageBuffer 0 "index"
2402OpMemberName %StorageBuffer 1 "red"
2403OpName %sbo "sbo"
2404OpName %images "images"
2405OpMemberDecorate %StorageBuffer 0 Offset 0
2406OpMemberDecorate %StorageBuffer 1 Offset 4
2407OpDecorate %StorageBuffer BufferBlock
2408OpDecorate %sbo DescriptorSet 3
2409OpDecorate %sbo Binding 1
2410OpDecorate %images DescriptorSet 3
2411OpDecorate %images Binding 5
2412OpDecorate %images NonWritable
2413)" + kImportDeco + R"(
2414;CHECK: OpDecorate [[launch_id]] BuiltIn LaunchIdNV
2415%void = OpTypeVoid
2416%3 = OpTypeFunction %void
2417%uint = OpTypeInt 32 0
2418%float = OpTypeFloat 32
2419%StorageBuffer = OpTypeStruct %uint %float
2420%_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer
2421%sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform
2422%int = OpTypeInt 32 1
2423%int_1 = OpConstant %int 1
2424%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f
2425%_runtimearr_13 = OpTypeRuntimeArray %13
2426%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13
2427%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant
2428%int_0 = OpConstant %int 0
2429%_ptr_Uniform_uint = OpTypePointer Uniform %uint
2430%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13
2431%v2int = OpTypeVector %int 2
2432%25 = OpConstantComposite %v2int %int_0 %int_0
2433%v4float = OpTypeVector %float 4
2434%uint_0 = OpConstant %uint 0
2435%_ptr_Uniform_float = OpTypePointer Uniform %float
2436;CHECK: [[null_uint:%\w+]] = OpConstantNull %uint
2437;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
2438)";
2439
2440  const std::string main_func = R"(
2441%main = OpFunction %void None %3
2442%5 = OpLabel
2443%19 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0
2444%20 = OpLoad %uint %19
2445%22 = OpAccessChain %_ptr_UniformConstant_13 %images %20
2446%23 = OpLoad %13 %22
2447%27 = OpImageRead %v4float %23 %25
2448%29 = OpCompositeExtract %float %27 0
2449%31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
2450OpStore %31 %29
2451;CHECK-NOT: OpStore %31 %29
2452;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}}
2453;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
2454;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
2455;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
2456;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5313 {{%\w+}} {{%\w+}} {{%\w+}}
2457;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_49 {{%\w+}} %uint_3 %uint_1 %uint_0 {{%\w+}}
2458;CHECK: OpSelectionMerge {{%\w+}} None
2459;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
2460;CHECK: {{%\w+}} = OpLabel
2461;CHECK: {{%\w+}} = OpLoad %uint %25
2462;CHECK: OpBranch {{%\w+}}
2463;CHECK: {{%\w+}} = OpLabel
2464;CHECK: OpBranch {{%\w+}}
2465;CHECK: {{%\w+}} = OpLabel
2466;CHECK: {{%\w+}} = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}}
2467;CHECK: {{%\w+}} = OpAccessChain %_ptr_UniformConstant_13 %images {{%\w+}}
2468;CHECK: {{%\w+}} = OpLoad %13 {{%\w+}}
2469;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}}
2470;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
2471;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
2472;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
2473;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5313 {{%\w+}} {{%\w+}} {{%\w+}}
2474;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_52 {{%\w+}} %uint_3 %uint_5 {{%\w+}} %uint_0
2475;CHECK: OpSelectionMerge {{%\w+}} None
2476;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
2477;CHECK: {{%\w+}} = OpLabel
2478;CHECK: {{%\w+}} = OpLoad %13 {{%\w+}}
2479;CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20
2480;CHECK: OpBranch {{%\w+}}
2481;CHECK: {{%\w+}} = OpLabel
2482;CHECK: OpBranch {{%\w+}}
2483;CHECK: {{%\w+}} = OpLabel
2484;CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
2485;CHECK: {{%\w+}} = OpCompositeExtract %float {{%\w+}} 0
2486;CHECK: {{%\w+}} = OpAccessChain %_ptr_Uniform_float %sbo %int_1
2487;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}}
2488;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
2489;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
2490;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
2491;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5313 {{%\w+}} {{%\w+}} {{%\w+}}
2492;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_55 {{%\w+}} %uint_3 %uint_1 %uint_0 {{%\w+}}
2493;CHECK: OpSelectionMerge {{%\w+}} None
2494;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
2495;CHECK: {{%\w+}} = OpLabel
2496;CHECK: OpStore {{%\w+}} {{%\w+}}
2497;CHECK: OpBranch {{%\w+}}
2498;CHECK: {{%\w+}} = OpLabel
2499;CHECK: OpBranch {{%\w+}}
2500;CHECK: {{%\w+}} = OpLabel
2501OpReturn
2502OpFunctionEnd
2503)";
2504  // clang-format on
2505
2506  // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
2507  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + kImportStub + main_func,
2508                                               true, 23u);
2509}
2510
2511TEST_F(InstBindlessTest,
2512       InstBoundsIntersectionInitLoadVariableSizedSampledImagesArray) {
2513  // #version 460
2514  // #extension GL_EXT_nonuniform_qualifier : require
2515  // #extension GL_NV_ray_tracing : require
2516  //
2517  // layout(set = 5, binding = 1, std140) buffer StorageBuffer {
2518  //   uint index;
2519  //   float red;
2520  // } sbo;
2521  //
2522  // layout(set = 5, binding = 3, rgba32f) readonly uniform image2D images[];
2523  //
2524  // void main()
2525  // {
2526  //    sbo.red = imageLoad(images[sbo.index], ivec2(0, 0)).r;
2527  // }
2528
2529  // clang-format off
2530  const std::string defs = R"(
2531OpCapability RuntimeDescriptorArray
2532OpCapability RayTracingNV
2533;CHECK: OpCapability Linkage
2534OpExtension "SPV_EXT_descriptor_indexing"
2535OpExtension "SPV_NV_ray_tracing"
2536%1 = OpExtInstImport "GLSL.std.450"
2537OpMemoryModel Logical GLSL450
2538OpEntryPoint IntersectionNV %main "main"
2539;CHECK: OpEntryPoint IntersectionNV %main "main" [[launch_id:%\w+]]
2540OpSource GLSL 460
2541OpSourceExtension "GL_EXT_nonuniform_qualifier"
2542OpSourceExtension "GL_NV_ray_tracing"
2543OpName %main "main"
2544OpName %StorageBuffer "StorageBuffer"
2545OpMemberName %StorageBuffer 0 "index"
2546OpMemberName %StorageBuffer 1 "red"
2547OpName %sbo "sbo"
2548OpName %images "images"
2549OpMemberDecorate %StorageBuffer 0 Offset 0
2550OpMemberDecorate %StorageBuffer 1 Offset 4
2551OpDecorate %StorageBuffer BufferBlock
2552OpDecorate %sbo DescriptorSet 5
2553OpDecorate %sbo Binding 1
2554OpDecorate %images DescriptorSet 5
2555OpDecorate %images Binding 3
2556OpDecorate %images NonWritable
2557)" + kImportDeco + R"(
2558;CHECK: OpDecorate [[launch_id]] BuiltIn LaunchIdNV
2559%void = OpTypeVoid
2560%3 = OpTypeFunction %void
2561%uint = OpTypeInt 32 0
2562%float = OpTypeFloat 32
2563%StorageBuffer = OpTypeStruct %uint %float
2564%_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer
2565%sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform
2566%int = OpTypeInt 32 1
2567%int_1 = OpConstant %int 1
2568%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f
2569%_runtimearr_13 = OpTypeRuntimeArray %13
2570%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13
2571%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant
2572%int_0 = OpConstant %int 0
2573%_ptr_Uniform_uint = OpTypePointer Uniform %uint
2574%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13
2575%v2int = OpTypeVector %int 2
2576%25 = OpConstantComposite %v2int %int_0 %int_0
2577%v4float = OpTypeVector %float 4
2578%uint_0 = OpConstant %uint 0
2579%_ptr_Uniform_float = OpTypePointer Uniform %float
2580;CHECK: [[launch_id]] = OpVariable %_ptr_Input_v3uint Input
2581;CHECK: [[null_uint:%\w+]] = OpConstantNull %uint
2582;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
2583)";
2584
2585  const std::string main_func = R"(
2586%main = OpFunction %void None %3
2587%5 = OpLabel
2588%19 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0
2589%20 = OpLoad %uint %19
2590%22 = OpAccessChain %_ptr_UniformConstant_13 %images %20
2591%23 = OpLoad %13 %22
2592%27 = OpImageRead %v4float %23 %25
2593%29 = OpCompositeExtract %float %27 0
2594%31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
2595OpStore %31 %29
2596;CHECK-NOT: OpStore %31 %29
2597;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}}
2598;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
2599;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
2600;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
2601;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5314 {{%\w+}} {{%\w+}} {{%\w+}}
2602;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_49 {{%\w+}} %uint_5 %uint_1 %uint_0 {{%\w+}}
2603;CHECK: OpSelectionMerge {{%\w+}} None
2604;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
2605;CHECK: {{%\w+}} = OpLabel
2606;CHECK: {{%\w+}} = OpLoad %uint %25
2607;CHECK: OpBranch {{%\w+}}
2608;CHECK: {{%\w+}} = OpLabel
2609;CHECK: OpBranch {{%\w+}}
2610;CHECK: {{%\w+}} = OpLabel
2611;CHECK: {{%\w+}} = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}}
2612;CHECK: {{%\w+}} = OpAccessChain %_ptr_UniformConstant_13 %images {{%\w+}}
2613;CHECK: {{%\w+}} = OpLoad %13 {{%\w+}}
2614;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}}
2615;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
2616;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
2617;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
2618;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5314 {{%\w+}} {{%\w+}} {{%\w+}}
2619;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_52 {{%\w+}} %uint_5 %uint_3 {{%\w+}} %uint_0
2620;CHECK: OpSelectionMerge {{%\w+}} None
2621;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
2622;CHECK: {{%\w+}} = OpLabel
2623;CHECK: {{%\w+}} = OpLoad %13 {{%\w+}}
2624;CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20
2625;CHECK: OpBranch {{%\w+}}
2626;CHECK: {{%\w+}} = OpLabel
2627;CHECK: OpBranch {{%\w+}}
2628;CHECK: {{%\w+}} = OpLabel
2629;CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
2630;CHECK: {{%\w+}} = OpCompositeExtract %float {{%\w+}} 0
2631;CHECK: {{%\w+}} = OpAccessChain %_ptr_Uniform_float %sbo %int_1
2632;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}}
2633;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
2634;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
2635;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
2636;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5314 {{%\w+}} {{%\w+}} {{%\w+}}
2637;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_55 {{%\w+}} %uint_5 %uint_1 %uint_0 {{%\w+}}
2638;CHECK: OpSelectionMerge {{%\w+}} None
2639;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
2640;CHECK: {{%\w+}} = OpLabel
2641;CHECK: OpStore %31 {{%\w+}}
2642;CHECK: OpBranch {{%\w+}}
2643;CHECK: {{%\w+}} = OpLabel
2644;CHECK: OpBranch {{%\w+}}
2645OpReturn
2646OpFunctionEnd
2647)";
2648  // clang-format on
2649
2650  // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
2651  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + kImportStub + main_func,
2652                                               true, 23u);
2653}
2654
2655TEST_F(InstBindlessTest,
2656       InstBoundsAnyHitInitLoadVariableSizedSampledImagesArray) {
2657  // #version 460
2658  // #extension GL_EXT_nonuniform_qualifier : require
2659  // #extension GL_NV_ray_tracing : require
2660  //
2661  // layout(set = 2, binding = 1, std140) buffer StorageBuffer {
2662  //   uint index;
2663  //   float red;
2664  // } sbo;
2665  //
2666  // layout(set = 2, binding = 3, rgba32f) readonly uniform image2D images[];
2667  //
2668  // void main()
2669  // {
2670  //    sbo.red = imageLoad(images[sbo.index], ivec2(0, 0)).r;
2671  // }
2672
2673  // clang-format off
2674  const std::string defs = R"(
2675OpCapability RuntimeDescriptorArray
2676OpCapability RayTracingNV
2677;CHECK: OpCapability Linkage
2678OpExtension "SPV_EXT_descriptor_indexing"
2679OpExtension "SPV_NV_ray_tracing"
2680%1 = OpExtInstImport "GLSL.std.450"
2681OpMemoryModel Logical GLSL450
2682OpEntryPoint AnyHitNV %main "main"
2683;CHECK: OpEntryPoint AnyHitNV %main "main" [[launch_id:%\w+]]
2684OpSource GLSL 460
2685OpSourceExtension "GL_EXT_nonuniform_qualifier"
2686OpSourceExtension "GL_NV_ray_tracing"
2687OpName %main "main"
2688OpName %StorageBuffer "StorageBuffer"
2689OpMemberName %StorageBuffer 0 "index"
2690OpMemberName %StorageBuffer 1 "red"
2691OpName %sbo "sbo"
2692OpName %images "images"
2693OpMemberDecorate %StorageBuffer 0 Offset 0
2694OpMemberDecorate %StorageBuffer 1 Offset 4
2695OpDecorate %StorageBuffer BufferBlock
2696OpDecorate %sbo DescriptorSet 2
2697OpDecorate %sbo Binding 1
2698OpDecorate %images DescriptorSet 2
2699OpDecorate %images Binding 3
2700OpDecorate %images NonWritable
2701)" + kImportDeco + R"(
2702;CHECK: OpDecorate [[launch_id]] BuiltIn LaunchIdNV
2703%void = OpTypeVoid
2704%3 = OpTypeFunction %void
2705%uint = OpTypeInt 32 0
2706%float = OpTypeFloat 32
2707%StorageBuffer = OpTypeStruct %uint %float
2708%_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer
2709%sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform
2710%int = OpTypeInt 32 1
2711%int_1 = OpConstant %int 1
2712%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f
2713%_runtimearr_13 = OpTypeRuntimeArray %13
2714%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13
2715%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant
2716%int_0 = OpConstant %int 0
2717%_ptr_Uniform_uint = OpTypePointer Uniform %uint
2718%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13
2719%v2int = OpTypeVector %int 2
2720%25 = OpConstantComposite %v2int %int_0 %int_0
2721%v4float = OpTypeVector %float 4
2722%uint_0 = OpConstant %uint 0
2723%_ptr_Uniform_float = OpTypePointer Uniform %float
2724;CHECK: [[launch_id]] = OpVariable %_ptr_Input_v3uint Input
2725;CHECK: [[null_uint:%\w+]] = OpConstantNull %uint
2726;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
2727)";
2728
2729  const std::string main_func = R"(
2730%main = OpFunction %void None %3
2731%5 = OpLabel
2732%19 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0
2733%20 = OpLoad %uint %19
2734%22 = OpAccessChain %_ptr_UniformConstant_13 %images %20
2735%23 = OpLoad %13 %22
2736%27 = OpImageRead %v4float %23 %25
2737%29 = OpCompositeExtract %float %27 0
2738%31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
2739OpStore %31 %29
2740;CHECK-NOT: %20 = OpLoad %uint %19
2741;CHECK-NOT: %22 = OpAccessChain %_ptr_UniformConstant_13 %images %20
2742;CHECK-NOT: %23 = OpLoad %13 %22
2743;CHECK-NOT: %27 = OpImageRead %v4float %23 %25
2744;CHECK-NOT: %29 = OpCompositeExtract %float %27 0
2745;CHECK-NOT: %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
2746;CHECK-NOT: OpStore %31 %29
2747;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}}
2748;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
2749;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
2750;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
2751;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5315 {{%\w+}} {{%\w+}} {{%\w+}}
2752;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_49 {{%\w+}} %uint_2 %uint_1 %uint_0 {{%\w+}}
2753;CHECK: OpSelectionMerge {{%\w+}} None
2754;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
2755;CHECK: {{%\w+}} = OpLabel
2756;CHECK: {{%\w+}} = OpLoad %uint %25
2757;CHECK: OpBranch {{%\w+}}
2758;CHECK: {{%\w+}} = OpLabel
2759;CHECK: OpBranch {{%\w+}}
2760;CHECK: {{%\w+}} = OpLabel
2761;CHECK: [[phi_result:%\w+]] = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}}
2762;CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images [[phi_result]]
2763;CHECK: %28 = OpLoad %13 %27
2764;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}}
2765;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
2766;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
2767;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
2768;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5315 {{%\w+}} {{%\w+}} {{%\w+}}
2769;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_52 {{%\w+}} %uint_2 %uint_3 {{%\w+}} %uint_0
2770;CHECK: OpSelectionMerge {{%\w+}} None
2771;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
2772;CHECK: {{%\w+}} = OpLabel
2773;CHECK: {{%\w+}} = OpLoad %13 %27
2774;CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20
2775;CHECK: OpBranch {{%\w+}}
2776;CHECK: {{%\w+}} = OpLabel
2777;CHECK: OpBranch {{%\w+}}
2778;CHECK: {{%\w+}} = OpLabel
2779;CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
2780;CHECK: %30 = OpCompositeExtract %float {{%\w+}} 0
2781;CHECK: %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
2782;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}}
2783;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
2784;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
2785;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
2786;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5315 {{%\w+}} {{%\w+}} {{%\w+}}
2787;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_55 {{%\w+}} %uint_2 %uint_1 %uint_0 {{%\w+}}
2788;CHECK: OpSelectionMerge {{%\w+}} None
2789;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
2790;CHECK: {{%\w+}} = OpLabel
2791;CHECK: OpStore %31 %30
2792;CHECK: OpBranch {{%\w+}}
2793;CHECK: {{%\w+}} = OpLabel
2794;CHECK: OpBranch {{%\w+}}
2795;CHECK: {{%\w+}} = OpLabel
2796OpReturn
2797OpFunctionEnd
2798)";
2799  // clang-format on
2800
2801  // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
2802  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + kImportStub + main_func,
2803                                               true, 23u);
2804}
2805
2806TEST_F(InstBindlessTest,
2807       InstBoundsClosestHitInitLoadVariableSizedSampledImagesArray) {
2808  // #version 460
2809  // #extension GL_EXT_nonuniform_qualifier : require
2810  // #extension GL_NV_ray_tracing : require
2811  //
2812  // layout(set = 1, binding = 2, std140) buffer StorageBuffer {
2813  //   uint index;
2814  //   float red;
2815  // } sbo;
2816  //
2817  // layout(set = 1, binding = 3, rgba32f) readonly uniform image2D images[];
2818  //
2819  // void main()
2820  // {
2821  //    sbo.red = imageLoad(images[sbo.index], ivec2(0, 0)).r;
2822  // }
2823
2824  // clang-format off
2825  const std::string defs = R"(
2826OpCapability RuntimeDescriptorArray
2827OpCapability RayTracingNV
2828;CHECK: OpCapability Linkage
2829OpExtension "SPV_EXT_descriptor_indexing"
2830OpExtension "SPV_NV_ray_tracing"
2831%1 = OpExtInstImport "GLSL.std.450"
2832OpMemoryModel Logical GLSL450
2833OpEntryPoint ClosestHitNV %main "main"
2834;CHECK: OpEntryPoint ClosestHitNV %main "main" [[launch_id:%\w+]]
2835OpSource GLSL 460
2836OpSourceExtension "GL_EXT_nonuniform_qualifier"
2837OpSourceExtension "GL_NV_ray_tracing"
2838OpName %main "main"
2839OpName %StorageBuffer "StorageBuffer"
2840OpMemberName %StorageBuffer 0 "index"
2841OpMemberName %StorageBuffer 1 "red"
2842OpName %sbo "sbo"
2843OpName %images "images"
2844OpMemberDecorate %StorageBuffer 0 Offset 0
2845OpMemberDecorate %StorageBuffer 1 Offset 4
2846OpDecorate %StorageBuffer BufferBlock
2847OpDecorate %sbo DescriptorSet 1
2848OpDecorate %sbo Binding 2
2849OpDecorate %images DescriptorSet 1
2850OpDecorate %images Binding 3
2851OpDecorate %images NonWritable
2852)" + kImportDeco + R"(
2853;CHECK: OpDecorate [[launch_id]] BuiltIn LaunchIdNV
2854%void = OpTypeVoid
2855%3 = OpTypeFunction %void
2856%uint = OpTypeInt 32 0
2857%float = OpTypeFloat 32
2858%StorageBuffer = OpTypeStruct %uint %float
2859%_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer
2860%sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform
2861%int = OpTypeInt 32 1
2862%int_1 = OpConstant %int 1
2863%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f
2864%_runtimearr_13 = OpTypeRuntimeArray %13
2865%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13
2866%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant
2867%int_0 = OpConstant %int 0
2868%_ptr_Uniform_uint = OpTypePointer Uniform %uint
2869%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13
2870%v2int = OpTypeVector %int 2
2871%25 = OpConstantComposite %v2int %int_0 %int_0
2872%v4float = OpTypeVector %float 4
2873%uint_0 = OpConstant %uint 0
2874%_ptr_Uniform_float = OpTypePointer Uniform %float
2875;CHECK: [[launch_id]] = OpVariable %_ptr_Input_v3uint Input
2876;CHECK: [[null_uint:%\w+]] = OpConstantNull %uint
2877;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
2878)";
2879
2880  const std::string main_func = R"(
2881%main = OpFunction %void None %3
2882%5 = OpLabel
2883%19 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0
2884%20 = OpLoad %uint %19
2885%22 = OpAccessChain %_ptr_UniformConstant_13 %images %20
2886%23 = OpLoad %13 %22
2887%27 = OpImageRead %v4float %23 %25
2888%29 = OpCompositeExtract %float %27 0
2889%31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
2890OpStore %31 %29
2891;CHECK-NOT: %20 = OpLoad %uint %19
2892;CHECK-NOT: %22 = OpAccessChain %_ptr_UniformConstant_13 %images %20
2893;CHECK-NOT: %23 = OpLoad %13 %22
2894;CHECK-NOT: %27 = OpImageRead %v4float %23 %25
2895;CHECK-NOT: %29 = OpCompositeExtract %float %27 0
2896;CHECK-NOT: %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
2897;CHECK-NOT: OpStore %31 %29
2898;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}}
2899;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
2900;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
2901;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
2902;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5316 {{%\w+}} {{%\w+}} {{%\w+}}
2903;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_49 {{%\w+}} %uint_1 %uint_2 %uint_0 {{%\w+}}
2904;CHECK: OpSelectionMerge {{%\w+}} None
2905;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
2906;CHECK: {{%\w+}} = OpLabel
2907;CHECK: {{%\w+}} = OpLoad %uint %25
2908;CHECK: OpBranch {{%\w+}}
2909;CHECK: {{%\w+}} = OpLabel
2910;CHECK: OpBranch {{%\w+}}
2911;CHECK: {{%\w+}} = OpLabel
2912;CHECK: [[phi_result:%\w+]] = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}}
2913;CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images [[phi_result]]
2914;CHECK: %28 = OpLoad %13 %27
2915;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}}
2916;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
2917;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
2918;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
2919;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5316 {{%\w+}} {{%\w+}} {{%\w+}}
2920;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_52 {{%\w+}} %uint_1 %uint_3 {{%\w+}} %uint_0
2921;CHECK: OpSelectionMerge {{%\w+}} None
2922;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
2923;CHECK: {{%\w+}} = OpLabel
2924;CHECK: {{%\w+}} = OpLoad %13 %27
2925;CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20
2926;CHECK: OpBranch {{%\w+}}
2927;CHECK: {{%\w+}} = OpLabel
2928;CHECK: OpBranch {{%\w+}}
2929;CHECK: {{%\w+}} = OpLabel
2930;CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
2931;CHECK: %30 = OpCompositeExtract %float {{%\w+}} 0
2932;CHECK: %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
2933;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}}
2934;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
2935;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
2936;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
2937;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5316 {{%\w+}} {{%\w+}} {{%\w+}}
2938;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_55 {{%\w+}} %uint_1 %uint_2 %uint_0 {{%\w+}}
2939;CHECK: OpSelectionMerge {{%\w+}} None
2940;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
2941;CHECK: {{%\w+}} = OpLabel
2942;CHECK: OpStore %31 %30
2943;CHECK: OpBranch {{%\w+}}
2944;CHECK: {{%\w+}} = OpLabel
2945;CHECK: OpBranch {{%\w+}}
2946;CHECK: {{%\w+}} = OpLabel
2947OpReturn
2948OpFunctionEnd
2949)";
2950  // clang-format on
2951
2952  // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
2953  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + kImportStub + main_func,
2954                                               true, 23u);
2955}
2956
2957TEST_F(InstBindlessTest,
2958       InstBoundsMissInitLoadVariableSizedSampledImagesArray) {
2959  // #version 460
2960  // #extension GL_EXT_nonuniform_qualifier : require
2961  // #extension GL_NV_ray_tracing : require
2962  //
2963  // layout(set = 1, binding = 2, std140) buffer StorageBuffer {
2964  //   uint index;
2965  //   float red;
2966  // } sbo;
2967  //
2968  // layout(set = 1, binding = 3, rgba32f) readonly uniform image2D images[];
2969  //
2970  // void main()
2971  // {
2972  //    sbo.red = imageLoad(images[sbo.index], ivec2(0, 0)).r;
2973  // }
2974
2975  // clang-format off
2976  const std::string defs = R"(
2977OpCapability RuntimeDescriptorArray
2978OpCapability RayTracingNV
2979;CHECK: OpCapability Linkage
2980OpExtension "SPV_EXT_descriptor_indexing"
2981OpExtension "SPV_NV_ray_tracing"
2982%1 = OpExtInstImport "GLSL.std.450"
2983OpMemoryModel Logical GLSL450
2984OpEntryPoint MissNV %main "main"
2985;CHECK: OpEntryPoint MissNV %main "main" [[launch_id:%\w+]]
2986OpSource GLSL 460
2987OpSourceExtension "GL_EXT_nonuniform_qualifier"
2988OpSourceExtension "GL_NV_ray_tracing"
2989OpName %main "main"
2990OpName %StorageBuffer "StorageBuffer"
2991OpMemberName %StorageBuffer 0 "index"
2992OpMemberName %StorageBuffer 1 "red"
2993OpName %sbo "sbo"
2994OpName %images "images"
2995OpMemberDecorate %StorageBuffer 0 Offset 0
2996OpMemberDecorate %StorageBuffer 1 Offset 4
2997OpDecorate %StorageBuffer BufferBlock
2998OpDecorate %sbo DescriptorSet 1
2999OpDecorate %sbo Binding 2
3000OpDecorate %images DescriptorSet 1
3001OpDecorate %images Binding 3
3002OpDecorate %images NonWritable
3003)" + kImportDeco + R"(
3004;CHECK: OpDecorate [[launch_id]] BuiltIn LaunchIdNV
3005%void = OpTypeVoid
3006%3 = OpTypeFunction %void
3007%uint = OpTypeInt 32 0
3008%float = OpTypeFloat 32
3009%StorageBuffer = OpTypeStruct %uint %float
3010%_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer
3011%sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform
3012%int = OpTypeInt 32 1
3013%int_1 = OpConstant %int 1
3014%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f
3015%_runtimearr_13 = OpTypeRuntimeArray %13
3016%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13
3017%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant
3018%int_0 = OpConstant %int 0
3019%_ptr_Uniform_uint = OpTypePointer Uniform %uint
3020%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13
3021%v2int = OpTypeVector %int 2
3022%25 = OpConstantComposite %v2int %int_0 %int_0
3023%v4float = OpTypeVector %float 4
3024%uint_0 = OpConstant %uint 0
3025%_ptr_Uniform_float = OpTypePointer Uniform %float
3026;CHECK: [[launch_id]] = OpVariable %_ptr_Input_v3uint Input
3027;CHECK: [[null_uint:%\w+]] = OpConstantNull %uint
3028;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
3029)";
3030
3031  const std::string main_func = R"(
3032%main = OpFunction %void None %3
3033%5 = OpLabel
3034%19 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0
3035%20 = OpLoad %uint %19
3036%22 = OpAccessChain %_ptr_UniformConstant_13 %images %20
3037%23 = OpLoad %13 %22
3038%27 = OpImageRead %v4float %23 %25
3039%29 = OpCompositeExtract %float %27 0
3040%31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
3041OpStore %31 %29
3042;CHECK-NOT: %20 = OpLoad %uint %19
3043;CHECK-NOT: %22 = OpAccessChain %_ptr_UniformConstant_13 %images %20
3044;CHECK-NOT: %27 = OpImageRead %v4float %23 %25
3045;CHECK-NOT: %29 = OpCompositeExtract %float %27 0
3046;CHECK-NOT OpStore %31 %29
3047;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}}
3048;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
3049;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
3050;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
3051;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5317 {{%\w+}} {{%\w+}} {{%\w+}}
3052;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_49 {{%\w+}} %uint_1 %uint_2 %uint_0 {{%\w+}}
3053;CHECK: OpSelectionMerge {{%\w+}} None
3054;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
3055;CHECK: {{%\w+}} = OpLabel
3056;CHECK: {{%\w+}} = OpLoad %uint %25
3057;CHECK: OpBranch {{%\w+}}
3058;CHECK: {{%\w+}} = OpLabel
3059;CHECK: OpBranch {{%\w+}}
3060;CHECK: {{%\w+}} = OpLabel
3061;CHECK: [[phi_result:%\w+]] = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}}
3062;CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images [[phi_result]]
3063;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}}
3064;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
3065;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
3066;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
3067;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5317 {{%\w+}} {{%\w+}} {{%\w+}}
3068;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_52 {{%\w+}} %uint_1 %uint_3 {{%\w+}} %uint_0
3069;CHECK: OpSelectionMerge {{%\w+}} None
3070;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
3071;CHECK: {{%\w+}} = OpLabel
3072;CHECK: {{%\w+}} = OpLoad %13 %27
3073;CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20
3074;CHECK: OpBranch {{%\w+}}
3075;CHECK: {{%\w+}} = OpLabel
3076;CHECK: OpBranch {{%\w+}}
3077;CHECK: {{%\w+}} = OpLabel
3078;CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
3079;CHECK: %30 = OpCompositeExtract %float {{%\w+}} 0
3080;CHECK: %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
3081;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}}
3082;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
3083;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
3084;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
3085;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5317 {{%\w+}} {{%\w+}} {{%\w+}}
3086;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_55 {{%\w+}} %uint_1 %uint_2 %uint_0 {{%\w+}}
3087;CHECK: OpSelectionMerge {{%\w+}} None
3088;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
3089;CHECK: {{%\w+}} = OpLabel
3090;CHECK: OpStore %31 %30
3091;CHECK: OpBranch {{%\w+}}
3092;CHECK: {{%\w+}} = OpLabel
3093;CHECK: OpBranch {{%\w+}}
3094;CHECK: {{%\w+}} = OpLabel
3095OpReturn
3096OpFunctionEnd
3097)";
3098  // clang-format on
3099
3100  // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
3101  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + kImportStub + main_func,
3102                                               true, 23u);
3103}
3104
3105TEST_F(InstBindlessTest,
3106       InstBoundsCallableInitLoadVariableSizedSampledImagesArray) {
3107  // #version 460
3108  // #extension GL_EXT_nonuniform_qualifier : require
3109  // #extension GL_NV_ray_tracing : require
3110  //
3111  // layout(set = 1, binding = 2, std140) buffer StorageBuffer {
3112  //   uint index;
3113  //   float red;
3114  // } sbo;
3115  //
3116  // layout(set = 1, binding = 3, rgba32f) readonly uniform image2D images[];
3117  //
3118  // void main()
3119  // {
3120  //    sbo.red = imageLoad(images[sbo.index], ivec2(0, 0)).r;
3121  // }
3122
3123  // clang-format off
3124  const std::string defs = R"(
3125OpCapability RuntimeDescriptorArray
3126OpCapability RayTracingNV
3127;CHECK: OpCapability Linkage
3128OpExtension "SPV_EXT_descriptor_indexing"
3129OpExtension "SPV_NV_ray_tracing"
3130%1 = OpExtInstImport "GLSL.std.450"
3131OpMemoryModel Logical GLSL450
3132OpEntryPoint CallableNV %main "main"
3133;CHECK: OpEntryPoint CallableNV %main "main" [[launch_id:%\w+]]
3134OpSource GLSL 460
3135OpSourceExtension "GL_EXT_nonuniform_qualifier"
3136OpSourceExtension "GL_NV_ray_tracing"
3137OpName %main "main"
3138OpName %StorageBuffer "StorageBuffer"
3139OpMemberName %StorageBuffer 0 "index"
3140OpMemberName %StorageBuffer 1 "red"
3141OpName %sbo "sbo"
3142OpName %images "images"
3143OpMemberDecorate %StorageBuffer 0 Offset 0
3144OpMemberDecorate %StorageBuffer 1 Offset 4
3145OpDecorate %StorageBuffer BufferBlock
3146OpDecorate %sbo DescriptorSet 1
3147OpDecorate %sbo Binding 2
3148OpDecorate %images DescriptorSet 1
3149OpDecorate %images Binding 3
3150OpDecorate %images NonWritable
3151)" + kImportDeco + R"(
3152;CHECK: OpDecorate [[launch_id]] BuiltIn LaunchIdNV
3153%void = OpTypeVoid
3154%3 = OpTypeFunction %void
3155%uint = OpTypeInt 32 0
3156%float = OpTypeFloat 32
3157%StorageBuffer = OpTypeStruct %uint %float
3158%_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer
3159%sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform
3160%int = OpTypeInt 32 1
3161%int_1 = OpConstant %int 1
3162%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f
3163%_runtimearr_13 = OpTypeRuntimeArray %13
3164%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13
3165%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant
3166%int_0 = OpConstant %int 0
3167%_ptr_Uniform_uint = OpTypePointer Uniform %uint
3168%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13
3169%v2int = OpTypeVector %int 2
3170%25 = OpConstantComposite %v2int %int_0 %int_0
3171%v4float = OpTypeVector %float 4
3172%uint_0 = OpConstant %uint 0
3173%_ptr_Uniform_float = OpTypePointer Uniform %float
3174;CHECK: [[null_uint:%\w+]] = OpConstantNull %uint
3175;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
3176)";
3177
3178  const std::string main_func = R"(
3179%main = OpFunction %void None %3
3180%5 = OpLabel
3181%19 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0
3182%20 = OpLoad %uint %19
3183%22 = OpAccessChain %_ptr_UniformConstant_13 %images %20
3184%23 = OpLoad %13 %22
3185%27 = OpImageRead %v4float %23 %25
3186%29 = OpCompositeExtract %float %27 0
3187;CHECK-NOT: %20 = OpLoad %uint %19
3188;CHECK-NOT: %22 = OpAccessChain %_ptr_UniformConstant_13 %images %20
3189;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}}
3190;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
3191;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
3192;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
3193;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5318 {{%\w+}} {{%\w+}} {{%\w+}}
3194;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_49 {{%\w+}} %uint_1 %uint_2 %uint_0 {{%\w+}}
3195;CHECK: OpSelectionMerge {{%\w+}} None
3196;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
3197;CHECK: {{%\w+}} = OpLabel
3198;CHECK: {{%\w+}} = OpLoad %uint %25
3199;CHECK: OpBranch {{%\w+}}
3200;CHECK: {{%\w+}} = OpLabel
3201;CHECK: OpBranch {{%\w+}}
3202;CHECK: {{%\w+}} = OpLabel
3203;CHECK: {{%\w+}} = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}}
3204;CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images {{%\w+}}
3205;CHECK-NOT: %23 = OpLoad %13 %22
3206;CHECK-NOT: %27 = OpImageRead %v4float %23 %25
3207;CHECK-NOT: %29 = OpCompositeExtract %float %27 0
3208;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}}
3209;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
3210;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
3211;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
3212;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5318 {{%\w+}} {{%\w+}} {{%\w+}}
3213;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_52 {{%\w+}} %uint_1 %uint_3 {{%\w+}} %uint_0
3214;CHECK: OpSelectionMerge {{%\w+}} None
3215;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
3216;CHECK: {{%\w+}} = OpLabel
3217;CHECK: {{%\w+}} = OpLoad %13 %27
3218;CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20
3219;CHECK: OpBranch {{%\w+}}
3220;CHECK: {{%\w+}} = OpLabel
3221;CHECK: OpBranch {{%\w+}}
3222;CHECK: {{%\w+}} = OpLabel
3223;CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
3224;CHECK: %30 = OpCompositeExtract %float {{%\w+}} 0
3225;CHECK: %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
3226%31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
3227OpStore %31 %29
3228;CHECK-NOT: %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
3229;CHECK-NOT: OpStore %31 %29
3230;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}}
3231;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
3232;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
3233;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
3234;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5318 {{%\w+}} {{%\w+}} {{%\w+}}
3235;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_55 {{%\w+}} %uint_1 %uint_2 %uint_0 {{%\w+}}
3236;CHECK: OpSelectionMerge {{%\w+}} None
3237;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
3238;CHECK: {{%\w+}} = OpLabel
3239;CHECK: OpStore %31 %30
3240;CHECK: OpBranch {{%\w+}}
3241;CHECK: {{%\w+}} = OpLabel
3242;CHECK: OpBranch {{%\w+}}
3243;CHECK: {{%\w+}} = OpLabel
3244OpReturn
3245OpFunctionEnd
3246)";
3247  // clang-format on
3248
3249  // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
3250  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + kImportStub + main_func,
3251                                               true, 23u);
3252}
3253
3254TEST_F(InstBindlessTest, InstBoundsInitSameBlockOpReplication) {
3255  // Test that same block ops like OpSampledImage are replicated properly
3256  // where needed.
3257  //
3258  // clang-format off
3259  //
3260  // #version 450 core
3261  // #extension GL_EXT_nonuniform_qualifier : enable
3262  //
3263  // layout(location = 0) in vec2 inTexcoord;
3264  // layout(location = 0) out vec4 outColor;
3265  //
3266  // layout(set = 1, binding = 0) uniform Uniforms {
3267  //   vec2 var0;
3268  // } uniforms;
3269  //
3270  // layout(set = 1, binding = 1) uniform sampler uniformSampler;
3271  // layout(set = 1, binding = 2) uniform texture2D uniformTex;
3272  // layout(set = 1, binding = 3) uniform texture2D uniformTexArr[8];
3273  //
3274  // void main() {
3275  //   int index = 0;
3276  //   float x = texture(sampler2D(uniformTexArr[nonuniformEXT(index)], uniformSampler), inTexcoord.xy).x;
3277  //   float y = texture(sampler2D(uniformTex, uniformSampler), inTexcoord.xy * uniforms.var0.xy).x;
3278  //   outColor = vec4(x, y, 0.0, 0.0);
3279  // }
3280  //
3281
3282  const std::string defs = R"(
3283OpCapability Shader
3284OpCapability ShaderNonUniformEXT
3285OpCapability SampledImageArrayNonUniformIndexingEXT
3286;CHECK: OpCapability Linkage
3287OpExtension "SPV_EXT_descriptor_indexing"
3288%1 = OpExtInstImport "GLSL.std.450"
3289OpMemoryModel Logical GLSL450
3290OpEntryPoint Fragment %main "main" %inTexcoord %outColor
3291;CHECK: OpEntryPoint Fragment %main "main" %inTexcoord %outColor %gl_FragCoord
3292OpExecutionMode %main OriginUpperLeft
3293OpSource GLSL 450
3294OpSourceExtension "GL_EXT_nonuniform_qualifier"
3295OpName %main "main"
3296OpName %index "index"
3297OpName %x "x"
3298OpName %uniformTexArr "uniformTexArr"
3299OpName %uniformSampler "uniformSampler"
3300OpName %inTexcoord "inTexcoord"
3301OpName %y "y"
3302OpName %uniformTex "uniformTex"
3303OpName %Uniforms "Uniforms"
3304OpMemberName %Uniforms 0 "var0"
3305OpName %uniforms "uniforms"
3306OpName %outColor "outColor"
3307OpDecorate %uniformTexArr DescriptorSet 1
3308OpDecorate %uniformTexArr Binding 3
3309OpDecorate %19 NonUniformEXT
3310OpDecorate %22 NonUniformEXT
3311OpDecorate %uniformSampler DescriptorSet 1
3312OpDecorate %uniformSampler Binding 1
3313OpDecorate %inTexcoord Location 0
3314OpDecorate %uniformTex DescriptorSet 1
3315OpDecorate %uniformTex Binding 2
3316OpMemberDecorate %Uniforms 0 Offset 0
3317OpDecorate %Uniforms Block
3318OpDecorate %uniforms DescriptorSet 1
3319OpDecorate %uniforms Binding 0
3320OpDecorate %outColor Location 0
3321;CHECK: OpDecorate {{%\w+}} NonUniform
3322;CHECK: OpDecorate {{%\w+}} NonUniform
3323)" + kImportDeco + R"(
3324;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
3325;CHECK: OpDecorate [[desc_state_result:%\w+]] NonUniform
3326%void = OpTypeVoid
3327%3 = OpTypeFunction %void
3328%int = OpTypeInt 32 1
3329%_ptr_Function_int = OpTypePointer Function %int
3330%int_0 = OpConstant %int 0
3331%float = OpTypeFloat 32
3332%_ptr_Function_float = OpTypePointer Function %float
3333%13 = OpTypeImage %float 2D 0 0 0 1 Unknown
3334%uint = OpTypeInt 32 0
3335%uint_8 = OpConstant %uint 8
3336%_arr_13_uint_8 = OpTypeArray %13 %uint_8
3337%_ptr_UniformConstant__arr_13_uint_8 = OpTypePointer UniformConstant %_arr_13_uint_8
3338%uniformTexArr = OpVariable %_ptr_UniformConstant__arr_13_uint_8 UniformConstant
3339%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13
3340%23 = OpTypeSampler
3341%_ptr_UniformConstant_23 = OpTypePointer UniformConstant %23
3342%uniformSampler = OpVariable %_ptr_UniformConstant_23 UniformConstant
3343%27 = OpTypeSampledImage %13
3344%v2float = OpTypeVector %float 2
3345%_ptr_Input_v2float = OpTypePointer Input %v2float
3346%inTexcoord = OpVariable %_ptr_Input_v2float Input
3347%v4float = OpTypeVector %float 4
3348%uint_0 = OpConstant %uint 0
3349%uniformTex = OpVariable %_ptr_UniformConstant_13 UniformConstant
3350%Uniforms = OpTypeStruct %v2float
3351%_ptr_Uniform_Uniforms = OpTypePointer Uniform %Uniforms
3352%uniforms = OpVariable %_ptr_Uniform_Uniforms Uniform
3353%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
3354%_ptr_Output_v4float = OpTypePointer Output %v4float
3355%outColor = OpVariable %_ptr_Output_v4float Output
3356%float_0 = OpConstant %float 0
3357;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
3358;CHECK: [[null_v2float:%\w+]] = OpConstantNull %v2float
3359)";
3360
3361  const std::string main_func = R"(
3362%main = OpFunction %void None %3
3363%5 = OpLabel
3364%index = OpVariable %_ptr_Function_int Function
3365%x = OpVariable %_ptr_Function_float Function
3366%y = OpVariable %_ptr_Function_float Function
3367OpStore %index %int_0
3368%19 = OpLoad %int %index
3369%21 = OpAccessChain %_ptr_UniformConstant_13 %uniformTexArr %19
3370%22 = OpLoad %13 %21
3371%26 = OpLoad %23 %uniformSampler
3372%28 = OpSampledImage %27 %22 %26
3373%32 = OpLoad %v2float %inTexcoord
3374%34 = OpImageSampleImplicitLod %v4float %28 %32
3375%36 = OpCompositeExtract %float %34 0
3376;CHECK-NOT: %34 = OpImageSampleImplicitLod %v4float %28 %32
3377;CHECK-NOT: %36 = OpCompositeExtract %float %34 0
3378;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
3379;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
3380;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
3381;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
3382;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
3383;CHECK: {{%\w+}} = OpBitcast %uint %19
3384;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_80 {{%\w+}} %uint_1 %uint_3 {{%\w+}} %uint_0
3385;CHECK: OpSelectionMerge {{%\w+}} None
3386;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
3387;CHECK: {{%\w+}} = OpLabel
3388;CHECK: {{%\w+}} = OpLoad %13 %21
3389;CHECK: {{%\w+}} = OpSampledImage %27 {{%\w+}} %26
3390;CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %32
3391;CHECK: OpBranch {{%\w+}}
3392;CHECK: {{%\w+}} = OpLabel
3393;CHECK: OpBranch {{%\w+}}
3394;CHECK: {{%\w+}} = OpLabel
3395;CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
3396OpStore %x %36
3397%39 = OpLoad %13 %uniformTex
3398%40 = OpLoad %23 %uniformSampler
3399%41 = OpSampledImage %27 %39 %40
3400%42 = OpLoad %v2float %inTexcoord
3401%47 = OpAccessChain %_ptr_Uniform_v2float %uniforms %int_0
3402%48 = OpLoad %v2float %47
3403%49 = OpFMul %v2float %42 %48
3404;CHECK-NOT: %48 = OpLoad %v2float %47
3405;CHECK-NOT: %49 = OpFMul %v2float %42 %48
3406;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
3407;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
3408;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
3409;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
3410;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
3411;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_88 {{%\w+}} %uint_1 %uint_0 %uint_0 {{%\w+}}
3412;CHECK: OpSelectionMerge {{%\w+}} None
3413;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
3414;CHECK: {{%\w+}} = OpLabel
3415;CHECK: {{%\w+}} = OpLoad %v2float %47
3416;CHECK: OpBranch {{%\w+}}
3417;CHECK: {{%\w+}} = OpLabel
3418;CHECK: OpBranch {{%\w+}}
3419;CHECK: {{%\w+}} = OpLabel
3420;CHECK: [[phi_result:%\w+]] = OpPhi %v2float {{%\w+}} {{%\w+}} [[null_v2float]] {{%\w+}}
3421;CHECK: %49 = OpFMul %v2float %42 [[phi_result]]
3422%50 = OpImageSampleImplicitLod %v4float %41 %49
3423%51 = OpCompositeExtract %float %50 0
3424OpStore %y %51
3425;CHECK-NOT: %50 = OpImageSampleImplicitLod %v4float %41 %49
3426;CHECK-NOT: %51 = OpCompositeExtract %float %50 0
3427;CHECK: {{%\w+}} = OpSampledImage %27 %39 %40
3428;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
3429;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
3430;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
3431;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
3432;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
3433;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_90 {{%\w+}} %uint_1 %uint_2 %uint_0 %uint_0
3434;CHECK: OpSelectionMerge {{%\w+}} None
3435;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
3436;CHECK: {{%\w+}} = OpLabel
3437;CHECK: {{%\w+}} = OpLoad %13 %uniformTex
3438;CHECK: {{%\w+}} = OpSampledImage %27 {{%\w+}} %40
3439;CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %49
3440;CHECK: OpBranch {{%\w+}}
3441;CHECK: {{%\w+}} = OpLabel
3442;CHECK: OpBranch {{%\w+}}
3443;CHECK: {{%\w+}} = OpLabel
3444;CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
3445;CHECK: %51 = OpCompositeExtract %float {{%\w+}} 0
3446OpStore %y %51
3447%54 = OpLoad %float %x
3448%55 = OpLoad %float %y
3449%57 = OpCompositeConstruct %v4float %54 %55 %float_0 %float_0
3450OpStore %outColor %57
3451OpReturn
3452OpFunctionEnd
3453)";
3454  // clang-format on
3455
3456  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
3457  SinglePassRunAndMatch<InstBindlessCheckPass>(defs + kImportStub + main_func,
3458                                               true, 23u);
3459}
3460
3461TEST_F(InstBindlessTest, MultipleUniformNonAggregateRefsNoDescInit) {
3462  // Check that uniform refs do not go out-of-bounds. All checks use same input
3463  // buffer read function call result at top of function for uniform buffer
3464  // length. Because descriptor indexing is not being checked, we can avoid one
3465  // buffer load.
3466  //
3467  // Texture2D g_tColor;
3468  // SamplerState g_sAniso;
3469  //
3470  // layout(push_constant) cbuffer PerViewPushConst_t { bool g_B; };
3471  //
3472  // cbuffer PerViewConstantBuffer_t {
3473  //   float2 g_TexOff0;
3474  //   float2 g_TexOff1;
3475  // };
3476  //
3477  // struct PS_INPUT {
3478  //   float2 vTextureCoords : TEXCOORD2;
3479  // };
3480  //
3481  // struct PS_OUTPUT {
3482  //   float4 vColor : SV_Target0;
3483  // };
3484  //
3485  // PS_OUTPUT MainPs(PS_INPUT i) {
3486  //   PS_OUTPUT ps_output;
3487  //   float2 off;
3488  //   float2 vtc;
3489  //   if (g_B)
3490  //     off = g_TexOff0;
3491  //   else
3492  //     off = g_TexOff1;
3493  //   vtc = i.vTextureCoords.xy + off;
3494  //   ps_output.vColor = g_tColor.Sample(g_sAniso, vtc);
3495  //   return ps_output;
3496  // }
3497
3498  // clang-format off
3499  const std::string text = R"(
3500OpCapability Shader
3501;CHECK: OpCapability Linkage
3502%1 = OpExtInstImport "GLSL.std.450"
3503OpMemoryModel Logical GLSL450
3504OpEntryPoint Fragment %MainPs "MainPs" %_ %__0 %g_tColor %g_sAniso %i_vTextureCoords %_entryPointOutput_vColor
3505;CHECK: OpEntryPoint Fragment %MainPs "MainPs" %_ %__0 %g_tColor %g_sAniso %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord
3506OpExecutionMode %MainPs OriginUpperLeft
3507OpSource HLSL 500
3508OpName %MainPs "MainPs"
3509OpName %PerViewPushConst_t "PerViewPushConst_t"
3510OpMemberName %PerViewPushConst_t 0 "g_B"
3511OpName %_ ""
3512OpName %PerViewConstantBuffer_t "PerViewConstantBuffer_t"
3513OpMemberName %PerViewConstantBuffer_t 0 "g_TexOff0"
3514OpMemberName %PerViewConstantBuffer_t 1 "g_TexOff1"
3515OpName %__0 ""
3516OpName %g_tColor "g_tColor"
3517OpName %g_sAniso "g_sAniso"
3518OpName %i_vTextureCoords "i.vTextureCoords"
3519OpName %_entryPointOutput_vColor "@entryPointOutput.vColor"
3520OpMemberDecorate %PerViewPushConst_t 0 Offset 0
3521OpDecorate %PerViewPushConst_t Block
3522OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0
3523OpMemberDecorate %PerViewConstantBuffer_t 1 Offset 8
3524OpDecorate %PerViewConstantBuffer_t Block
3525OpDecorate %__0 DescriptorSet 0
3526OpDecorate %__0 Binding 1
3527OpDecorate %g_tColor DescriptorSet 0
3528OpDecorate %g_tColor Binding 0
3529OpDecorate %g_sAniso DescriptorSet 0
3530OpDecorate %g_sAniso Binding 2
3531OpDecorate %i_vTextureCoords Location 0
3532OpDecorate %_entryPointOutput_vColor Location 0
3533)" + kImportDeco + R"(
3534;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
3535%void = OpTypeVoid
3536%3 = OpTypeFunction %void
3537%float = OpTypeFloat 32
3538%v2float = OpTypeVector %float 2
3539%v4float = OpTypeVector %float 4
3540%uint = OpTypeInt 32 0
3541%PerViewPushConst_t = OpTypeStruct %uint
3542%_ptr_PushConstant_PerViewPushConst_t = OpTypePointer PushConstant %PerViewPushConst_t
3543%_ = OpVariable %_ptr_PushConstant_PerViewPushConst_t PushConstant
3544%int = OpTypeInt 32 1
3545%int_0 = OpConstant %int 0
3546%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint
3547%bool = OpTypeBool
3548%uint_0 = OpConstant %uint 0
3549%PerViewConstantBuffer_t = OpTypeStruct %v2float %v2float
3550%_ptr_Uniform_PerViewConstantBuffer_t = OpTypePointer Uniform %PerViewConstantBuffer_t
3551%__0 = OpVariable %_ptr_Uniform_PerViewConstantBuffer_t Uniform
3552%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
3553%int_1 = OpConstant %int 1
3554%49 = OpTypeImage %float 2D 0 0 0 1 Unknown
3555%_ptr_UniformConstant_49 = OpTypePointer UniformConstant %49
3556%g_tColor = OpVariable %_ptr_UniformConstant_49 UniformConstant
3557%53 = OpTypeSampler
3558%_ptr_UniformConstant_53 = OpTypePointer UniformConstant %53
3559%g_sAniso = OpVariable %_ptr_UniformConstant_53 UniformConstant
3560%57 = OpTypeSampledImage %49
3561%_ptr_Input_v2float = OpTypePointer Input %v2float
3562%i_vTextureCoords = OpVariable %_ptr_Input_v2float Input
3563%_ptr_Output_v4float = OpTypePointer Output %v4float
3564%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output
3565;CHECK: %v4uint = OpTypeVector %uint 4
3566;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
3567;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
3568;CHECK: [[null_v2float:%\w+]] = OpConstantNull %v2float
3569 )" + kImportStub + R"(
3570%MainPs = OpFunction %void None %3
3571%5 = OpLabel
3572%69 = OpLoad %v2float %i_vTextureCoords
3573%82 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0
3574%83 = OpLoad %uint %82
3575%84 = OpINotEqual %bool %83 %uint_0
3576OpSelectionMerge %91 None
3577OpBranchConditional %84 %85 %88
3578%85 = OpLabel
3579%86 = OpAccessChain %_ptr_Uniform_v2float %__0 %int_0
3580%87 = OpLoad %v2float %86
3581;CHECK-NOT:     %87 = OpLoad %v2float %86
3582;CHECK: {{%\w+}} = OpLabel
3583;CHECK: {{%\w+}} = OpIAdd %uint %uint_0 %uint_7
3584;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
3585;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
3586;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
3587;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
3588;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
3589;CHECK: [[desc_state_result:%\w+]] = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_72 {{%\w+}} %uint_0 %uint_1 %uint_0 {{%\w+}}
3590;CHECK: OpSelectionMerge {{%\w+}} None
3591;CHECK: OpBranchConditional [[desc_state_result]] {{%\w+}} {{%\w+}}
3592;CHECK: {{%\w+}} = OpLabel
3593;CHECK: {{%\w+}} = OpLoad %v2float %86
3594;CHECK: OpBranch {{%\w+}}
3595;CHECK: {{%\w+}} = OpLabel
3596;CHECK: OpBranch {{%\w+}}
3597;CHECK: {{%\w+}} = OpLabel
3598 ;CHECK: {{%\w+}} = OpPhi %v2float {{%\w+}} {{%\w+}} [[null_v2float]] {{%\w+}}
3599OpBranch %91
3600%88 = OpLabel
3601%89 = OpAccessChain %_ptr_Uniform_v2float %__0 %int_1
3602%90 = OpLoad %v2float %89
3603;CHECK-NOT:     %90 = OpLoad %v2float %89
3604;CHECK: {{%\w+}} = OpIAdd %uint %uint_8 %uint_7
3605;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
3606;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
3607;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
3608;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
3609;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
3610;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_76 {{%\w+}} %uint_0 %uint_1 %uint_0 {{%\w+}}
3611;CHECK: OpSelectionMerge {{%\w+}} None
3612;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
3613;CHECK: {{%\w+}} = OpLabel
3614;CHECK: {{%\w+}} = OpLoad %v2float %89
3615;CHECK: OpBranch {{%\w+}}
3616;CHECK: {{%\w+}} = OpLabel
3617;CHECK: OpBranch {{%\w+}}
3618;CHECK: {{%\w+}} = OpLabel
3619;CHECK: {{%\w+}} = OpPhi %v2float {{%\w+}} {{%\w+}} [[null_v2float]] {{%\w+}}
3620OpBranch %91
3621%91 = OpLabel
3622%115 = OpPhi %v2float %87 %85 %90 %88
3623;CHECK-NOT:       %115 = OpPhi %v2float %87 %85 %90 %88
3624;CHECK: %115 = OpPhi %v2float {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}}
3625%95 = OpFAdd %v2float %69 %115
3626%96 = OpLoad %49 %g_tColor
3627%97 = OpLoad %53 %g_sAniso
3628%98 = OpSampledImage %57 %96 %97
3629%100 = OpImageSampleImplicitLod %v4float %98 %95
3630OpStore %_entryPointOutput_vColor %100
3631OpReturn
3632OpFunctionEnd
3633)";
3634  // clang-format on
3635
3636  SetTargetEnv(SPV_ENV_UNIVERSAL_1_4);
3637  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
3638  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 23u);
3639}
3640
3641TEST_F(InstBindlessTest, UniformArrayRefNoDescInit) {
3642  // Check that uniform array ref does not go out-of-bounds.
3643  //
3644  // Texture2D g_tColor;
3645  // SamplerState g_sAniso;
3646  //
3647  // layout(push_constant) cbuffer PerViewPushConst_t { uint g_c; };
3648  //
3649  // struct PerBatchEnvMapConstantBuffer_t {
3650  //   float4x3 g_matEnvMapWorldToLocal;
3651  //   float4 g_vEnvironmentMapBoxMins;
3652  //   float2 g_TexOff;
3653  // };
3654  //
3655  // cbuffer _BindlessFastEnvMapCB_PS_t {
3656  //   PerBatchEnvMapConstantBuffer_t g_envMapConstants[128];
3657  // };
3658  //
3659  // struct PS_INPUT {
3660  //   float2 vTextureCoords : TEXCOORD2;
3661  // };
3662  //
3663  // struct PS_OUTPUT {
3664  //   float4 vColor : SV_Target0;
3665  // };
3666  //
3667  // PS_OUTPUT MainPs(PS_INPUT i) {
3668  //   PS_OUTPUT ps_output;
3669  //   float2 off;
3670  //   float2 vtc;
3671  //   off = g_envMapConstants[g_c].g_TexOff;
3672  //   vtc = i.vTextureCoords.xy + off;
3673  //   ps_output.vColor = g_tColor.Sample(g_sAniso, vtc);
3674  //   return ps_output;
3675  // }
3676
3677  // clang-format off
3678  const std::string text = R"(
3679OpCapability Shader
3680;CHECK: OpCapability Linkage
3681%1 = OpExtInstImport "GLSL.std.450"
3682OpMemoryModel Logical GLSL450
3683OpEntryPoint Fragment %MainPs "MainPs" %_ %__0 %g_tColor %g_sAniso %i_vTextureCoords %_entryPointOutput_vColor
3684OpExecutionMode %MainPs OriginUpperLeft
3685OpSource HLSL 500
3686OpName %MainPs "MainPs"
3687OpName %PerBatchEnvMapConstantBuffer_t "PerBatchEnvMapConstantBuffer_t"
3688OpMemberName %PerBatchEnvMapConstantBuffer_t 0 "g_matEnvMapWorldToLocal"
3689OpMemberName %PerBatchEnvMapConstantBuffer_t 1 "g_vEnvironmentMapBoxMins"
3690OpMemberName %PerBatchEnvMapConstantBuffer_t 2 "g_TexOff"
3691OpName %_BindlessFastEnvMapCB_PS_t "_BindlessFastEnvMapCB_PS_t"
3692OpMemberName %_BindlessFastEnvMapCB_PS_t 0 "g_envMapConstants"
3693OpName %_ ""
3694OpName %PerViewPushConst_t "PerViewPushConst_t"
3695OpMemberName %PerViewPushConst_t 0 "g_c"
3696OpName %__0 ""
3697OpName %g_tColor "g_tColor"
3698OpName %g_sAniso "g_sAniso"
3699OpName %i_vTextureCoords "i.vTextureCoords"
3700OpName %_entryPointOutput_vColor "@entryPointOutput.vColor"
3701OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 0 RowMajor
3702OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 0 Offset 0
3703OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 0 MatrixStride 16
3704OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 1 Offset 48
3705OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 2 Offset 64
3706OpDecorate %_arr_PerBatchEnvMapConstantBuffer_t_uint_128 ArrayStride 80
3707OpMemberDecorate %_BindlessFastEnvMapCB_PS_t 0 Offset 0
3708OpDecorate %_BindlessFastEnvMapCB_PS_t Block
3709OpDecorate %_ DescriptorSet 0
3710OpDecorate %_ Binding 2
3711OpMemberDecorate %PerViewPushConst_t 0 Offset 0
3712OpDecorate %PerViewPushConst_t Block
3713OpDecorate %g_tColor DescriptorSet 0
3714OpDecorate %g_tColor Binding 0
3715OpDecorate %g_sAniso DescriptorSet 0
3716OpDecorate %g_sAniso Binding 1
3717OpDecorate %i_vTextureCoords Location 0
3718OpDecorate %_entryPointOutput_vColor Location 0
3719)" + kImportDeco + R"(
3720;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
3721%void = OpTypeVoid
3722%3 = OpTypeFunction %void
3723%float = OpTypeFloat 32
3724%v2float = OpTypeVector %float 2
3725%v4float = OpTypeVector %float 4
3726%v3float = OpTypeVector %float 3
3727%mat4v3float = OpTypeMatrix %v3float 4
3728%PerBatchEnvMapConstantBuffer_t = OpTypeStruct %mat4v3float %v4float %v2float
3729%uint = OpTypeInt 32 0
3730%uint_128 = OpConstant %uint 128
3731%_arr_PerBatchEnvMapConstantBuffer_t_uint_128 = OpTypeArray %PerBatchEnvMapConstantBuffer_t %uint_128
3732%_BindlessFastEnvMapCB_PS_t = OpTypeStruct %_arr_PerBatchEnvMapConstantBuffer_t_uint_128
3733%_ptr_Uniform__BindlessFastEnvMapCB_PS_t = OpTypePointer Uniform %_BindlessFastEnvMapCB_PS_t
3734%_ = OpVariable %_ptr_Uniform__BindlessFastEnvMapCB_PS_t Uniform
3735%int = OpTypeInt 32 1
3736%int_0 = OpConstant %int 0
3737%PerViewPushConst_t = OpTypeStruct %uint
3738%_ptr_PushConstant_PerViewPushConst_t = OpTypePointer PushConstant %PerViewPushConst_t
3739%__0 = OpVariable %_ptr_PushConstant_PerViewPushConst_t PushConstant
3740%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint
3741%int_2 = OpConstant %int 2
3742%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
3743%46 = OpTypeImage %float 2D 0 0 0 1 Unknown
3744%_ptr_UniformConstant_46 = OpTypePointer UniformConstant %46
3745%g_tColor = OpVariable %_ptr_UniformConstant_46 UniformConstant
3746%50 = OpTypeSampler
3747%_ptr_UniformConstant_50 = OpTypePointer UniformConstant %50
3748%g_sAniso = OpVariable %_ptr_UniformConstant_50 UniformConstant
3749%54 = OpTypeSampledImage %46
3750%_ptr_Input_v2float = OpTypePointer Input %v2float
3751%i_vTextureCoords = OpVariable %_ptr_Input_v2float Input
3752%_ptr_Output_v4float = OpTypePointer Output %v4float
3753%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output
3754;CHECK: %v4uint = OpTypeVector %uint 4
3755;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
3756;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
3757;CHECK: [[null_v2float:%\w+]] = OpConstantNull %v2float
3758)" + kImportStub + R"(
3759%MainPs = OpFunction %void None %3
3760%5 = OpLabel
3761%66 = OpLoad %v2float %i_vTextureCoords
3762%79 = OpAccessChain %_ptr_PushConstant_uint %__0 %int_0
3763%80 = OpLoad %uint %79
3764%81 = OpAccessChain %_ptr_Uniform_v2float %_ %int_0 %80 %int_2
3765%82 = OpLoad %v2float %81
3766;CHECK-NOT: %82 = OpLoad %v2float %81
3767;CHECK: {{%\w+}} = OpIMul %uint %uint_80 %80
3768;CHECK: {{%\w+}} = OpIAdd %uint %uint_0 {{%\w+}}
3769;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_64
3770;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_7
3771;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
3772;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
3773;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
3774;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
3775;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
3776;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_79 {{%\w+}} %uint_0 %uint_2 %uint_0 {{%\w+}}
3777;CHECK: OpSelectionMerge {{%\w+}} None
3778;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
3779;CHECK: {{%\w+}} = OpLabel
3780;CHECK: {{%\w+}} = OpLoad %v2float %81
3781;CHECK: OpBranch {{%\w+}}
3782;CHECK: {{%\w+}} = OpLabel
3783;CHECK: OpBranch {{%\w+}}
3784;CHECK: {{%\w+}} = OpLabel
3785;CHECK: {{%\w+}} = OpPhi %v2float {{%\w+}} {{%\w+}} [[null_v2float]] {{%\w+}}
3786%86 = OpFAdd %v2float %66 %82
3787;CHECK-NOT: %86 = OpFAdd %v2float %66 %82
3788;CHECK: %86 = OpFAdd %v2float %66 {{%\w+}}
3789%87 = OpLoad %46 %g_tColor
3790%88 = OpLoad %50 %g_sAniso
3791%89 = OpSampledImage %54 %87 %88
3792%91 = OpImageSampleImplicitLod %v4float %89 %86
3793OpStore %_entryPointOutput_vColor %91
3794OpReturn
3795OpFunctionEnd
3796)";
3797  // clang-format on
3798
3799  SetTargetEnv(SPV_ENV_UNIVERSAL_1_4);
3800  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
3801  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 23u);
3802}
3803
3804TEST_F(InstBindlessTest, UniformArrayRefWithDescInit) {
3805  // The buffer-oob and desc-init checks should use the same debug
3806  // output buffer write function.
3807  //
3808  // Same source as UniformArrayRefNoDescInit
3809
3810  // clang-format off
3811  const std::string text = R"(
3812OpCapability Shader
3813;CHECK: OpCapability Linkage
3814%1 = OpExtInstImport "GLSL.std.450"
3815OpMemoryModel Logical GLSL450
3816OpEntryPoint Fragment %MainPs "MainPs" %_ %__0 %g_tColor %g_sAniso %i_vTextureCoords %_entryPointOutput_vColor
3817;CHECK: OpEntryPoint Fragment %MainPs "MainPs" %_ %__0 %g_tColor %g_sAniso %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord
3818OpExecutionMode %MainPs OriginUpperLeft
3819OpSource HLSL 500
3820OpName %MainPs "MainPs"
3821OpName %PerBatchEnvMapConstantBuffer_t "PerBatchEnvMapConstantBuffer_t"
3822OpMemberName %PerBatchEnvMapConstantBuffer_t 0 "g_matEnvMapWorldToLocal"
3823OpMemberName %PerBatchEnvMapConstantBuffer_t 1 "g_vEnvironmentMapBoxMins"
3824OpMemberName %PerBatchEnvMapConstantBuffer_t 2 "g_TexOff"
3825OpName %_BindlessFastEnvMapCB_PS_t "_BindlessFastEnvMapCB_PS_t"
3826OpMemberName %_BindlessFastEnvMapCB_PS_t 0 "g_envMapConstants"
3827OpName %_ ""
3828OpName %PerViewPushConst_t "PerViewPushConst_t"
3829OpMemberName %PerViewPushConst_t 0 "g_c"
3830OpName %__0 ""
3831OpName %g_tColor "g_tColor"
3832OpName %g_sAniso "g_sAniso"
3833OpName %i_vTextureCoords "i.vTextureCoords"
3834OpName %_entryPointOutput_vColor "@entryPointOutput.vColor"
3835OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 0 RowMajor
3836OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 0 Offset 0
3837OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 0 MatrixStride 16
3838OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 1 Offset 48
3839OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 2 Offset 64
3840OpDecorate %_arr_PerBatchEnvMapConstantBuffer_t_uint_128 ArrayStride 80
3841OpMemberDecorate %_BindlessFastEnvMapCB_PS_t 0 Offset 0
3842OpDecorate %_BindlessFastEnvMapCB_PS_t Block
3843OpDecorate %_ DescriptorSet 0
3844OpDecorate %_ Binding 2
3845OpMemberDecorate %PerViewPushConst_t 0 Offset 0
3846OpDecorate %PerViewPushConst_t Block
3847OpDecorate %g_tColor DescriptorSet 0
3848OpDecorate %g_tColor Binding 0
3849OpDecorate %g_sAniso DescriptorSet 0
3850OpDecorate %g_sAniso Binding 1
3851OpDecorate %i_vTextureCoords Location 0
3852OpDecorate %_entryPointOutput_vColor Location 0
3853)" + kImportDeco + R"(
3854;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
3855%void = OpTypeVoid
3856%3 = OpTypeFunction %void
3857%float = OpTypeFloat 32
3858%v2float = OpTypeVector %float 2
3859%v4float = OpTypeVector %float 4
3860%v3float = OpTypeVector %float 3
3861%mat4v3float = OpTypeMatrix %v3float 4
3862%PerBatchEnvMapConstantBuffer_t = OpTypeStruct %mat4v3float %v4float %v2float
3863%uint = OpTypeInt 32 0
3864%uint_128 = OpConstant %uint 128
3865%_arr_PerBatchEnvMapConstantBuffer_t_uint_128 = OpTypeArray %PerBatchEnvMapConstantBuffer_t %uint_128
3866%_BindlessFastEnvMapCB_PS_t = OpTypeStruct %_arr_PerBatchEnvMapConstantBuffer_t_uint_128
3867%_ptr_Uniform__BindlessFastEnvMapCB_PS_t = OpTypePointer Uniform %_BindlessFastEnvMapCB_PS_t
3868%_ = OpVariable %_ptr_Uniform__BindlessFastEnvMapCB_PS_t Uniform
3869%int = OpTypeInt 32 1
3870%int_0 = OpConstant %int 0
3871%PerViewPushConst_t = OpTypeStruct %uint
3872%_ptr_PushConstant_PerViewPushConst_t = OpTypePointer PushConstant %PerViewPushConst_t
3873%__0 = OpVariable %_ptr_PushConstant_PerViewPushConst_t PushConstant
3874%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint
3875%int_2 = OpConstant %int 2
3876%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
3877%46 = OpTypeImage %float 2D 0 0 0 1 Unknown
3878%_ptr_UniformConstant_46 = OpTypePointer UniformConstant %46
3879%g_tColor = OpVariable %_ptr_UniformConstant_46 UniformConstant
3880%50 = OpTypeSampler
3881%_ptr_UniformConstant_50 = OpTypePointer UniformConstant %50
3882%g_sAniso = OpVariable %_ptr_UniformConstant_50 UniformConstant
3883%54 = OpTypeSampledImage %46
3884%_ptr_Input_v2float = OpTypePointer Input %v2float
3885%i_vTextureCoords = OpVariable %_ptr_Input_v2float Input
3886%_ptr_Output_v4float = OpTypePointer Output %v4float
3887%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output
3888;CHECK: %v4uint = OpTypeVector %uint 4
3889;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
3890;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
3891;CHECK: [[null_v2float:%\w+]] = OpConstantNull %v2float
3892;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
3893)" + kImportStub + R"(
3894%MainPs = OpFunction %void None %3
3895%5 = OpLabel
3896%66 = OpLoad %v2float %i_vTextureCoords
3897%79 = OpAccessChain %_ptr_PushConstant_uint %__0 %int_0
3898%80 = OpLoad %uint %79
3899%81 = OpAccessChain %_ptr_Uniform_v2float %_ %int_0 %80 %int_2
3900%82 = OpLoad %v2float %81
3901%86 = OpFAdd %v2float %66 %82
3902;CHECK-NOT: %82 = OpLoad %v2float %81
3903;CHECK-NOT: %86 = OpFAdd %v2float %66 %82
3904;CHECK: {{%\w+}} = OpIMul %uint %uint_80 %80
3905;CHECK: {{%\w+}} = OpIAdd %uint %uint_0 {{%\w+}}
3906;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_64
3907;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_7
3908;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
3909;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
3910;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
3911;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
3912;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
3913;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_79 {{%\w+}} %uint_0 %uint_2 %uint_0 {{%\w+}}
3914;CHECK: OpSelectionMerge {{%\w+}} None
3915;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
3916;CHECK: {{%\w+}} = OpLabel
3917;CHECK: {{%\w+}} = OpLoad %v2float %81
3918;CHECK: OpBranch {{%\w+}}
3919;CHECK: {{%\w+}} = OpLabel
3920;CHECK: OpBranch {{%\w+}}
3921;CHECK: {{%\w+}} = OpLabel
3922;CHECK: {{%\w+}} = OpPhi %v2float {{%\w+}} {{%\w+}} [[null_v2float]] {{%\w+}}
3923;CHECK: %86 = OpFAdd %v2float %66 {{%\w+}}
3924%87 = OpLoad %46 %g_tColor
3925%88 = OpLoad %50 %g_sAniso
3926%89 = OpSampledImage %54 %87 %88
3927%91 = OpImageSampleImplicitLod %v4float %89 %86
3928OpStore %_entryPointOutput_vColor %91
3929;CHECK-NOT: %91 = OpImageSampleImplicitLod %v4float %89 %86
3930;CHECK-NOT:       OpStore %_entryPointOutput_vColor %91
3931;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
3932;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
3933;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
3934;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
3935;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
3936;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_84 {{%\w+}} %uint_0 %uint_0 %uint_0 %uint_0
3937;CHECK: OpSelectionMerge {{%\w+}} None
3938;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
3939;CHECK: {{%\w+}} = OpLabel
3940;CHECK: {{%\w+}} = OpLoad %46 %g_tColor
3941;CHECK: {{%\w+}} = OpSampledImage %54 {{%\w+}} %88
3942;CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %86
3943;CHECK: OpBranch {{%\w+}}
3944;CHECK: {{%\w+}} = OpLabel
3945;CHECK: OpBranch {{%\w+}}
3946;CHECK: {{%\w+}} = OpLabel
3947;CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
3948;CHECK: OpStore %_entryPointOutput_vColor {{%\w+}}
3949OpReturn
3950OpFunctionEnd
3951)";
3952  // clang-format on
3953
3954  SetTargetEnv(SPV_ENV_UNIVERSAL_1_4);
3955  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
3956  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 23u);
3957}
3958
3959TEST_F(InstBindlessTest, Descriptor16BitIdxRef) {
3960  // Check that descriptor indexed with 16bit index is inbounds and
3961  // initialized
3962  //
3963  // Use Simple source with min16uint g_nDataIdx
3964
3965  // clang-format off
3966  const std::string text = R"(
3967OpCapability Shader
3968OpCapability Int16
3969OpCapability StoragePushConstant16
3970;CHECK: OpCapability Linkage
3971%1 = OpExtInstImport "GLSL.std.450"
3972OpMemoryModel Logical GLSL450
3973OpEntryPoint Fragment %MainPs "MainPs" %g_tColor %_ %g_sAniso %i_vTextureCoords %_entryPointOutput_vColor
3974;CHECK: OpEntryPoint Fragment %MainPs "MainPs" %g_tColor %_ %g_sAniso %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord
3975OpExecutionMode %MainPs OriginUpperLeft
3976OpSource HLSL 500
3977OpName %MainPs "MainPs"
3978OpName %g_tColor "g_tColor"
3979OpName %PerViewConstantBuffer_t "PerViewConstantBuffer_t"
3980OpMemberName %PerViewConstantBuffer_t 0 "g_nDataIdx"
3981OpName %_ ""
3982OpName %g_sAniso "g_sAniso"
3983OpName %i_vTextureCoords "i.vTextureCoords"
3984OpName %_entryPointOutput_vColor "@entryPointOutput.vColor"
3985OpDecorate %g_tColor DescriptorSet 1
3986OpDecorate %g_tColor Binding 2
3987OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0
3988OpDecorate %PerViewConstantBuffer_t Block
3989OpDecorate %g_sAniso DescriptorSet 1
3990OpDecorate %g_sAniso Binding 2
3991OpDecorate %i_vTextureCoords Location 0
3992OpDecorate %_entryPointOutput_vColor Location 0
3993)" + kImportDeco + R"(
3994;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
3995%void = OpTypeVoid
3996%10 = OpTypeFunction %void
3997%float = OpTypeFloat 32
3998%v2float = OpTypeVector %float 2
3999%v4float = OpTypeVector %float 4
4000%int = OpTypeInt 32 1
4001%int_0 = OpConstant %int 0
4002%16 = OpTypeImage %float 2D 0 0 0 1 Unknown
4003%uint = OpTypeInt 32 0
4004%uint_128 = OpConstant %uint 128
4005%_arr_16_uint_128 = OpTypeArray %16 %uint_128
4006%_ptr_UniformConstant__arr_16_uint_128 = OpTypePointer UniformConstant %_arr_16_uint_128
4007%g_tColor = OpVariable %_ptr_UniformConstant__arr_16_uint_128 UniformConstant
4008%ushort = OpTypeInt 16 0
4009%PerViewConstantBuffer_t = OpTypeStruct %ushort
4010%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t
4011%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant
4012%_ptr_PushConstant_ushort = OpTypePointer PushConstant %ushort
4013%_ptr_UniformConstant_16 = OpTypePointer UniformConstant %16
4014%25 = OpTypeSampler
4015%_ptr_UniformConstant_25 = OpTypePointer UniformConstant %25
4016%g_sAniso = OpVariable %_ptr_UniformConstant_25 UniformConstant
4017%27 = OpTypeSampledImage %16
4018%_ptr_Input_v2float = OpTypePointer Input %v2float
4019%i_vTextureCoords = OpVariable %_ptr_Input_v2float Input
4020%_ptr_Output_v4float = OpTypePointer Output %v4float
4021%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output
4022;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
4023;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
4024;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
4025)" + kImportStub + R"(
4026%MainPs = OpFunction %void None %10
4027%30 = OpLabel
4028;CHECK:  OpBranch %39
4029;CHECK:  %39 = OpLabel
4030%31 = OpLoad %v2float %i_vTextureCoords
4031%32 = OpAccessChain %_ptr_PushConstant_ushort %_ %int_0
4032%33 = OpLoad %ushort %32
4033%34 = OpAccessChain %_ptr_UniformConstant_16 %g_tColor %33
4034%35 = OpLoad %16 %34
4035%36 = OpLoad %25 %g_sAniso
4036%37 = OpSampledImage %27 %35 %36
4037%38 = OpImageSampleImplicitLod %v4float %37 %31
4038OpStore %_entryPointOutput_vColor %38
4039;CHECK-NOT: %38 = OpImageSampleImplicitLod %v4float %37 %31
4040;CHECK-NOT: OpStore %_entryPointOutput_vColor %38
4041;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
4042;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
4043;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
4044;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
4045;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
4046;CHECK: {{%\w+}} = OpUConvert %uint %33
4047;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_61 {{%\w+}} %uint_1 %uint_2 {{%\w+}} %uint_0
4048;CHECK: OpSelectionMerge {{%\w+}} None
4049;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
4050;CHECK: {{%\w+}} = OpLabel
4051;CHECK: {{%\w+}} = OpLoad %16 %34
4052;CHECK: {{%\w+}} = OpSampledImage %27 {{%\w+}} %36
4053;CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %31
4054;CHECK: OpBranch {{%\w+}}
4055;CHECK: {{%\w+}} = OpLabel
4056;CHECK: OpBranch {{%\w+}}
4057;CHECK: {{%\w+}} = OpLabel
4058;CHECK: [[phi_result:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
4059;CHECK: OpStore %_entryPointOutput_vColor [[phi_result]]
4060OpReturn
4061OpFunctionEnd
4062)";
4063  // clang-format on
4064
4065  SetTargetEnv(SPV_ENV_UNIVERSAL_1_4);
4066  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
4067  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 23u);
4068}
4069
4070TEST_F(InstBindlessTest, UniformArray16bitIdxRef) {
4071  // Check that uniform array ref with 16bit index does not go out-of-bounds.
4072  //
4073  // Texture2D g_tColor;
4074  // SamplerState g_sAniso;
4075  //
4076  // layout(push_constant) cbuffer PerViewPushConst_t { min16uint g_c; };
4077  //
4078  // struct PerBatchEnvMapConstantBuffer_t {
4079  //   float4x3 g_matEnvMapWorldToLocal;
4080  //   float4 g_vEnvironmentMapBoxMins;
4081  //   float2 g_TexOff;
4082  // };
4083  //
4084  // cbuffer _BindlessFastEnvMapCB_PS_t {
4085  //   PerBatchEnvMapConstantBuffer_t g_envMapConstants[128];
4086  // };
4087  //
4088  // struct PS_INPUT {
4089  //   float2 vTextureCoords : TEXCOORD2;
4090  // };
4091  //
4092  // struct PS_OUTPUT {
4093  //   float4 vColor : SV_Target0;
4094  // };
4095  //
4096  // PS_OUTPUT MainPs(PS_INPUT i) {
4097  //   PS_OUTPUT ps_output;
4098  //   float2 off;
4099  //   float2 vtc;
4100  //   off = g_envMapConstants[g_c].g_TexOff;
4101  //   vtc = i.vTextureCoords.xy + off;
4102  //   ps_output.vColor = g_tColor.Sample(g_sAniso, vtc);
4103  //   return ps_output;
4104  // }
4105
4106  // clang-format off
4107  const std::string text = R"(
4108OpCapability Shader
4109OpCapability Int16
4110OpCapability StoragePushConstant16
4111;CHECK: OpCapability Linkage
4112%1 = OpExtInstImport "GLSL.std.450"
4113OpMemoryModel Logical GLSL450
4114OpEntryPoint Fragment %MainPs "MainPs" %_ %__0 %g_tColor %g_sAniso %i_vTextureCoords %_entryPointOutput_vColor
4115;CHECK: OpEntryPoint Fragment %MainPs "MainPs" %_ %__0 %g_tColor %g_sAniso %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord
4116OpExecutionMode %MainPs OriginUpperLeft
4117OpSource HLSL 500
4118OpName %MainPs "MainPs"
4119OpName %PerBatchEnvMapConstantBuffer_t "PerBatchEnvMapConstantBuffer_t"
4120OpMemberName %PerBatchEnvMapConstantBuffer_t 0 "g_matEnvMapWorldToLocal"
4121OpMemberName %PerBatchEnvMapConstantBuffer_t 1 "g_vEnvironmentMapBoxMins"
4122OpMemberName %PerBatchEnvMapConstantBuffer_t 2 "g_TexOff"
4123OpName %_BindlessFastEnvMapCB_PS_t "_BindlessFastEnvMapCB_PS_t"
4124OpMemberName %_BindlessFastEnvMapCB_PS_t 0 "g_envMapConstants"
4125OpName %_ ""
4126OpName %PerViewPushConst_t "PerViewPushConst_t"
4127OpMemberName %PerViewPushConst_t 0 "g_c"
4128OpName %__0 ""
4129OpName %g_tColor "g_tColor"
4130OpName %g_sAniso "g_sAniso"
4131OpName %i_vTextureCoords "i.vTextureCoords"
4132OpName %_entryPointOutput_vColor "@entryPointOutput.vColor"
4133OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 0 RowMajor
4134OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 0 Offset 0
4135OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 0 MatrixStride 16
4136OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 1 Offset 48
4137OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 2 Offset 64
4138OpDecorate %_arr_PerBatchEnvMapConstantBuffer_t_uint_128 ArrayStride 80
4139OpMemberDecorate %_BindlessFastEnvMapCB_PS_t 0 Offset 0
4140OpDecorate %_BindlessFastEnvMapCB_PS_t Block
4141OpDecorate %_ DescriptorSet 0
4142OpDecorate %_ Binding 0
4143OpMemberDecorate %PerViewPushConst_t 0 Offset 0
4144OpDecorate %PerViewPushConst_t Block
4145OpDecorate %g_tColor DescriptorSet 0
4146OpDecorate %g_tColor Binding 0
4147OpDecorate %g_sAniso DescriptorSet 0
4148OpDecorate %g_sAniso Binding 0
4149OpDecorate %i_vTextureCoords Location 0
4150OpDecorate %_entryPointOutput_vColor Location 0
4151)" + kImportDeco + R"(
4152;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
4153%void = OpTypeVoid
4154%14 = OpTypeFunction %void
4155%float = OpTypeFloat 32
4156%v2float = OpTypeVector %float 2
4157%v4float = OpTypeVector %float 4
4158%v3float = OpTypeVector %float 3
4159%mat4v3float = OpTypeMatrix %v3float 4
4160%PerBatchEnvMapConstantBuffer_t = OpTypeStruct %mat4v3float %v4float %v2float
4161%uint = OpTypeInt 32 0
4162%uint_128 = OpConstant %uint 128
4163%_arr_PerBatchEnvMapConstantBuffer_t_uint_128 = OpTypeArray %PerBatchEnvMapConstantBuffer_t %uint_128
4164%_BindlessFastEnvMapCB_PS_t = OpTypeStruct %_arr_PerBatchEnvMapConstantBuffer_t_uint_128
4165%_ptr_Uniform__BindlessFastEnvMapCB_PS_t = OpTypePointer Uniform %_BindlessFastEnvMapCB_PS_t
4166%_ = OpVariable %_ptr_Uniform__BindlessFastEnvMapCB_PS_t Uniform
4167%int = OpTypeInt 32 1
4168%int_0 = OpConstant %int 0
4169%ushort = OpTypeInt 16 0
4170%PerViewPushConst_t = OpTypeStruct %ushort
4171%_ptr_PushConstant_PerViewPushConst_t = OpTypePointer PushConstant %PerViewPushConst_t
4172%__0 = OpVariable %_ptr_PushConstant_PerViewPushConst_t PushConstant
4173%_ptr_PushConstant_ushort = OpTypePointer PushConstant %ushort
4174%int_2 = OpConstant %int 2
4175%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
4176%30 = OpTypeImage %float 2D 0 0 0 1 Unknown
4177%_ptr_UniformConstant_30 = OpTypePointer UniformConstant %30
4178%g_tColor = OpVariable %_ptr_UniformConstant_30 UniformConstant
4179%32 = OpTypeSampler
4180%_ptr_UniformConstant_32 = OpTypePointer UniformConstant %32
4181%g_sAniso = OpVariable %_ptr_UniformConstant_32 UniformConstant
4182%34 = OpTypeSampledImage %30
4183%_ptr_Input_v2float = OpTypePointer Input %v2float
4184%i_vTextureCoords = OpVariable %_ptr_Input_v2float Input
4185%_ptr_Output_v4float = OpTypePointer Output %v4float
4186%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output
4187;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
4188;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
4189;CHECK: [[null_v2float:%\w+]] = OpConstantNull %v2float
4190)" + kImportStub + R"(
4191%MainPs = OpFunction %void None %14
4192%37 = OpLabel
4193%38 = OpLoad %v2float %i_vTextureCoords
4194%39 = OpAccessChain %_ptr_PushConstant_ushort %__0 %int_0
4195%40 = OpLoad %ushort %39
4196%41 = OpAccessChain %_ptr_Uniform_v2float %_ %int_0 %40 %int_2
4197%42 = OpLoad %v2float %41
4198%43 = OpFAdd %v2float %38 %42
4199;CHECK-NOT: %42 = OpLoad %v2float %41
4200;CHECK-NOT: %43 = OpFAdd %v2float %38 %42
4201;CHECK: {{%\w+}} = OpUConvert %uint %40
4202;CHECK: {{%\w+}} = OpIMul %uint %uint_80 {{%\w+}}
4203;CHECK: {{%\w+}} = OpIAdd %uint %uint_0 {{%\w+}}
4204;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_64
4205;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_7
4206;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
4207;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
4208;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
4209;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
4210;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
4211;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_82 {{%\w+}} %uint_0 %uint_0 %uint_0 {{%\w+}}
4212;CHECK: OpSelectionMerge {{%\w+}} None
4213;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
4214;CHECK: {{%\w+}} = OpLabel
4215;CHECK: {{%\w+}} = OpLoad %v2float %41
4216;CHECK: OpBranch {{%\w+}}
4217;CHECK: {{%\w+}} = OpLabel
4218;CHECK: OpBranch {{%\w+}}
4219;CHECK: {{%\w+}} = OpLabel
4220;CHECK: {{%\w+}} = OpPhi %v2float {{%\w+}} {{%\w+}} [[null_v2float]] {{%\w+}}
4221;CHECK: %43 = OpFAdd %v2float %38 {{%\w+}}
4222%44 = OpLoad %30 %g_tColor
4223%45 = OpLoad %32 %g_sAniso
4224%46 = OpSampledImage %34 %44 %45
4225%47 = OpImageSampleImplicitLod %v4float %46 %43
4226OpStore %_entryPointOutput_vColor %47
4227OpReturn
4228OpFunctionEnd
4229)";
4230  // clang-format on
4231
4232  SetTargetEnv(SPV_ENV_UNIVERSAL_1_4);
4233  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
4234  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 23u);
4235}
4236
4237TEST_F(InstBindlessTest, UniformMatrixRefRowMajor) {
4238  // The buffer-oob row major matrix check
4239  //
4240  // #version 450
4241  // #extension GL_EXT_scalar_block_layout : enable
4242  //
4243  // layout(location = 0) in highp vec4 a_position;
4244  // layout(location = 0) out mediump float v_vtxResult;
4245  //
4246  // layout(set = 0, binding = 0, std430, row_major) uniform Block
4247  // {
4248  //    lowp mat4x2 var;
4249  // };
4250  //
4251  // void main (void)
4252  // {
4253  //    v_vtxResult = var[2][1];
4254  // }
4255
4256  // clang-format off
4257  std::string text = R"(
4258OpCapability Shader
4259;CHECK: OpCapability Linkage
4260%1 = OpExtInstImport "GLSL.std.450"
4261OpMemoryModel Logical GLSL450
4262OpEntryPoint Vertex %main "main" %v_vtxResult %_ %a_position
4263;CHECK: OpEntryPoint Vertex %main "main" %v_vtxResult %_ %a_position %gl_VertexIndex %gl_InstanceIndex
4264OpSource GLSL 450
4265OpSourceExtension "GL_EXT_scalar_block_layout"
4266OpName %main "main"
4267OpName %v_vtxResult "v_vtxResult"
4268OpName %Block "Block"
4269OpMemberName %Block 0 "var"
4270OpName %_ ""
4271OpName %a_position "a_position"
4272OpDecorate %v_vtxResult RelaxedPrecision
4273OpDecorate %v_vtxResult Location 0
4274OpMemberDecorate %Block 0 RowMajor
4275OpMemberDecorate %Block 0 RelaxedPrecision
4276OpMemberDecorate %Block 0 Offset 0
4277OpMemberDecorate %Block 0 MatrixStride 16
4278OpDecorate %Block Block
4279OpDecorate %_ DescriptorSet 0
4280OpDecorate %_ Binding 0
4281OpDecorate %21 RelaxedPrecision
4282;CHECK-NOT: OpDecorate %21 RelaxedPrecision
4283;CHECK: OpDecorate %v_vtxResult RelaxedPrecision
4284;CHECK: OpDecorate [[phi_result:%\w+]] RelaxedPrecision
4285OpDecorate %a_position Location 0
4286)" + kImportDeco + R"(
4287;CHECK: OpDecorate %gl_VertexIndex BuiltIn VertexIndex
4288;CHECK: OpDecorate %gl_InstanceIndex BuiltIn InstanceIndex
4289;CHECK: OpDecorate [[load_result:%\w+]] RelaxedPrecision
4290%void = OpTypeVoid
4291%3 = OpTypeFunction %void
4292%float = OpTypeFloat 32
4293%_ptr_Output_float = OpTypePointer Output %float
4294%v_vtxResult = OpVariable %_ptr_Output_float Output
4295%v2float = OpTypeVector %float 2
4296%mat4v2float = OpTypeMatrix %v2float 4
4297%Block = OpTypeStruct %mat4v2float
4298%_ptr_Uniform_Block = OpTypePointer Uniform %Block
4299%_ = OpVariable %_ptr_Uniform_Block Uniform
4300%int = OpTypeInt 32 1
4301%int_0 = OpConstant %int 0
4302%int_2 = OpConstant %int 2
4303%uint = OpTypeInt 32 0
4304%uint_1 = OpConstant %uint 1
4305%_ptr_Uniform_float = OpTypePointer Uniform %float
4306%v4float = OpTypeVector %float 4
4307%_ptr_Input_v4float = OpTypePointer Input %v4float
4308%a_position = OpVariable %_ptr_Input_v4float Input
4309;CHECK: %_ptr_Input_uint = OpTypePointer Input %uint
4310;CHECK: %gl_VertexIndex = OpVariable %_ptr_Input_uint Input
4311;CHECK: %gl_InstanceIndex = OpVariable %_ptr_Input_uint Input
4312;CHECK: [[null_float:%\w+]] = OpConstantNull %float
4313)" + kImportStub + R"(
4314%main = OpFunction %void None %3
4315%5 = OpLabel
4316;CHECK: OpBranch {{%\w+}}
4317;CHECK: {{%\w+}} = OpLabel
4318%20 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %int_2 %uint_1
4319%21 = OpLoad %float %20
4320;CHECK-NOT: %21 = OpLoad %float %20
4321;CHECK: {{%\w+}} = OpIMul %uint %uint_4 %int_2
4322;CHECK: {{%\w+}} = OpIAdd %uint %uint_0 {{%\w+}}
4323;CHECK: {{%\w+}} = OpIMul %uint %uint_16 %uint_1
4324;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} {{%\w+}}
4325;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3
4326;CHECK: {{%\w+}} = OpLoad %uint %gl_VertexIndex
4327;CHECK: {{%\w+}} = OpLoad %uint %gl_InstanceIndex
4328;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_0 {{%\w+}} {{%\w+}} %uint_0
4329;CHECK: [[desc_state:%\w+]] = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_46 {{%\w+}} %uint_0 %uint_0 %uint_0 {{%\w+}}
4330;CHECK: OpSelectionMerge {{%\w+}} None
4331;CHECK: OpBranchConditional [[desc_state]] {{%\w+}} {{%\w+}}
4332;CHECK: {{%\w+}} = OpLabel
4333;CHECK: [[load_result]] = OpLoad %float %20
4334;CHECK: OpBranch {{%\w+}}
4335;CHECK: {{%\w+}} = OpLabel
4336;CHECK: OpBranch {{%\w+}}
4337;CHECK: {{%\w+}} = OpLabel
4338;CHECK: [[phi_result]] = OpPhi %float [[load_result]] {{%\w+}} [[null_float]] {{%\w+}}
4339OpStore %v_vtxResult %21
4340;CHECK-NOT: OpStore %v_vtxResult %21$
4341;CHECK: OpStore %v_vtxResult [[phi_result]]
4342OpReturn
4343OpFunctionEnd
4344)";
4345  // clang-format on
4346
4347  SetTargetEnv(SPV_ENV_UNIVERSAL_1_4);
4348  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
4349  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 23u);
4350}
4351
4352TEST_F(InstBindlessTest, UniformMatrixRefColumnMajor) {
4353  // The buffer-oob column major matrix check
4354  //
4355  // #version 450
4356  // #extension GL_EXT_scalar_block_layout : enable
4357  //
4358  // layout(location = 0) in highp vec4 a_position;
4359  // layout(location = 0) out mediump float v_vtxResult;
4360  //
4361  // layout(set = 0, binding = 0, std430, column_major) uniform Block
4362  // {
4363  //    lowp mat4x2 var;
4364  // };
4365  //
4366  // void main (void)
4367  // {
4368  //    v_vtxResult = var[2][1];
4369  // }
4370
4371  // clang-format off
4372  const std::string text = R"(
4373OpCapability Shader
4374;CHECK: OpCapability Linkage
4375%1 = OpExtInstImport "GLSL.std.450"
4376OpMemoryModel Logical GLSL450
4377OpEntryPoint Vertex %main "main" %v_vtxResult %_ %a_position
4378;CHECK: OpEntryPoint Vertex %main "main" %v_vtxResult %_ %a_position %gl_VertexIndex %gl_InstanceIndex
4379OpSource GLSL 450
4380OpSourceExtension "GL_EXT_scalar_block_layout"
4381OpName %main "main"
4382OpName %v_vtxResult "v_vtxResult"
4383OpName %Block "Block"
4384OpMemberName %Block 0 "var"
4385OpName %_ ""
4386OpName %a_position "a_position"
4387OpDecorate %v_vtxResult RelaxedPrecision
4388OpDecorate %v_vtxResult Location 0
4389OpMemberDecorate %Block 0 ColMajor
4390OpMemberDecorate %Block 0 RelaxedPrecision
4391OpMemberDecorate %Block 0 Offset 0
4392OpMemberDecorate %Block 0 MatrixStride 8
4393OpDecorate %Block Block
4394OpDecorate %_ DescriptorSet 0
4395OpDecorate %_ Binding 0
4396OpDecorate %21 RelaxedPrecision
4397;CHECK-NOT: OpDecorate %21 RelaxedPrecision
4398;CHECK: OpDecorate %v_vtxResult RelaxedPrecision
4399;CHECK: OpDecorate [[phi_result:%\w+]] RelaxedPrecision
4400OpDecorate %a_position Location 0
4401)" + kImportDeco + R"(
4402;CHECK: OpDecorate %gl_VertexIndex BuiltIn VertexIndex
4403;CHECK: OpDecorate %gl_InstanceIndex BuiltIn InstanceIndex
4404;CHECK: OpDecorate [[load_result:%\w+]] RelaxedPrecision
4405%void = OpTypeVoid
4406%3 = OpTypeFunction %void
4407%float = OpTypeFloat 32
4408%_ptr_Output_float = OpTypePointer Output %float
4409%v_vtxResult = OpVariable %_ptr_Output_float Output
4410%v2float = OpTypeVector %float 2
4411%mat4v2float = OpTypeMatrix %v2float 4
4412%Block = OpTypeStruct %mat4v2float
4413%_ptr_Uniform_Block = OpTypePointer Uniform %Block
4414%_ = OpVariable %_ptr_Uniform_Block Uniform
4415%int = OpTypeInt 32 1
4416%int_0 = OpConstant %int 0
4417%int_2 = OpConstant %int 2
4418%uint = OpTypeInt 32 0
4419%uint_1 = OpConstant %uint 1
4420%_ptr_Uniform_float = OpTypePointer Uniform %float
4421%v4float = OpTypeVector %float 4
4422%_ptr_Input_v4float = OpTypePointer Input %v4float
4423%a_position = OpVariable %_ptr_Input_v4float Input
4424;CHECK: %_ptr_Input_uint = OpTypePointer Input %uint
4425;CHECK: %gl_VertexIndex = OpVariable %_ptr_Input_uint Input
4426;CHECK: %gl_InstanceIndex = OpVariable %_ptr_Input_uint Input
4427;CHECK: [[null_float:%\w+]] = OpConstantNull %float
4428)" + kImportStub + R"(
4429%main = OpFunction %void None %3
4430%5 = OpLabel
4431%20 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %int_2 %uint_1
4432%21 = OpLoad %float %20
4433;CHECK-NOT: %21 = OpLoad %float %20
4434;CHECK: OpBranch {{%\w+}}
4435;CHECK: {{%\w+}} = OpLabel
4436;CHECK: {{%\w+}} = OpIMul %uint %uint_8 %int_2
4437;CHECK: {{%\w+}} = OpIAdd %uint %uint_0 {{%\w+}}
4438;CHECK: {{%\w+}} = OpIMul %uint %uint_4 %uint_1
4439;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} {{%\w+}}
4440;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3
4441;CHECK: {{%\w+}} = OpLoad %uint %gl_VertexIndex
4442;CHECK: {{%\w+}} = OpLoad %uint %gl_InstanceIndex
4443;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_0 {{%\w+}} {{%\w+}} %uint_0
4444;CHECK: [[desc_state:%\w+]] = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_46 {{%\w+}} %uint_0 %uint_0 %uint_0 {{%\w+}}
4445;CHECK: OpSelectionMerge {{%\w+}} None
4446;CHECK: OpBranchConditional [[desc_state]] {{%\w+}} {{%\w+}}
4447;CHECK: {{%\w+}} = OpLabel
4448;CHECK:[[load_result]] = OpLoad %float %20
4449;CHECK: OpBranch {{%\w+}}
4450;CHECK: {{%\w+}} = OpLabel
4451;CHECK: OpBranch {{%\w+}}
4452;CHECK: {{%\w+}} = OpLabel
4453;CHECK: [[phi_result]] = OpPhi %float [[load_result]] {{%\w+}} [[null_float]] {{%\w+}}
4454OpStore %v_vtxResult %21
4455;CHECK-NOT: OpStore %v_vtxResult %21$
4456;CHECK: OpStore %v_vtxResult [[phi_result]]
4457OpReturn
4458OpFunctionEnd
4459)";
4460  // clang-format on
4461
4462  SetTargetEnv(SPV_ENV_UNIVERSAL_1_4);
4463  ValidatorOptions()->uniform_buffer_standard_layout = true;
4464  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
4465  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 23u);
4466}
4467
4468TEST_F(InstBindlessTest, UniformMatrixVecRefRowMajor) {
4469  // The buffer-oob row major matrix vector ref check
4470  //
4471  // #version 450
4472  // #extension GL_EXT_scalar_block_layout : enable
4473  //
4474  // layout(location = 0) in highp vec4 a_position;
4475  // layout(location = 0) out highp vec2 v_vtxResult;
4476  //
4477  // layout(set = 3, binding = 7, std430, row_major) uniform Block
4478  // {
4479  //    lowp mat2 var[3][4];
4480  // };
4481  //
4482  // void main (void)
4483  // {
4484  //    v_vtxResult = var[2][3][1];
4485  // }
4486
4487  // clang-format off
4488  const std::string text = R"(
4489OpCapability Shader
4490;CHECK: OpCapability Linkage
4491%1 = OpExtInstImport "GLSL.std.450"
4492OpMemoryModel Logical GLSL450
4493OpEntryPoint Vertex %main "main" %v_vtxResult %_ %a_position
4494;CHECK: OpEntryPoint Vertex %main "main" %v_vtxResult %_ %a_position %gl_VertexIndex %gl_InstanceIndex
4495OpSource GLSL 450
4496OpSourceExtension "GL_EXT_scalar_block_layout"
4497OpName %main "main"
4498OpName %v_vtxResult "v_vtxResult"
4499OpName %Block "Block"
4500OpMemberName %Block 0 "var"
4501OpName %_ ""
4502OpName %a_position "a_position"
4503OpDecorate %v_vtxResult Location 0
4504OpDecorate %_arr_mat2v2float_uint_4 ArrayStride 32
4505OpDecorate %_arr__arr_mat2v2float_uint_4_uint_3 ArrayStride 128
4506OpMemberDecorate %Block 0 RowMajor
4507OpMemberDecorate %Block 0 RelaxedPrecision
4508OpMemberDecorate %Block 0 Offset 0
4509OpMemberDecorate %Block 0 MatrixStride 16
4510OpDecorate %Block Block
4511OpDecorate %_ DescriptorSet 3
4512OpDecorate %_ Binding 7
4513OpDecorate %26 RelaxedPrecision
4514;CHECK-NOT: OpDecorate %26 RelaxedPrecision
4515;CHECK: OpDecorate [[phi_result:%\w+]] RelaxedPrecision
4516OpDecorate %a_position Location 0
4517)" + kImportDeco + R"(
4518;CHECK: OpDecorate %gl_VertexIndex BuiltIn VertexIndex
4519;CHECK: OpDecorate %gl_InstanceIndex BuiltIn InstanceIndex
4520;CHECK: OpDecorate [[load_result:%\w+]] RelaxedPrecision
4521%void = OpTypeVoid
4522%3 = OpTypeFunction %void
4523%float = OpTypeFloat 32
4524%v2float = OpTypeVector %float 2
4525%_ptr_Output_v2float = OpTypePointer Output %v2float
4526%v_vtxResult = OpVariable %_ptr_Output_v2float Output
4527%mat2v2float = OpTypeMatrix %v2float 2
4528%uint = OpTypeInt 32 0
4529%uint_4 = OpConstant %uint 4
4530%_arr_mat2v2float_uint_4 = OpTypeArray %mat2v2float %uint_4
4531%uint_3 = OpConstant %uint 3
4532%_arr__arr_mat2v2float_uint_4_uint_3 = OpTypeArray %_arr_mat2v2float_uint_4 %uint_3
4533%Block = OpTypeStruct %_arr__arr_mat2v2float_uint_4_uint_3
4534%_ptr_Uniform_Block = OpTypePointer Uniform %Block
4535%_ = OpVariable %_ptr_Uniform_Block Uniform
4536%int = OpTypeInt 32 1
4537%int_0 = OpConstant %int 0
4538%int_2 = OpConstant %int 2
4539%int_3 = OpConstant %int 3
4540%int_1 = OpConstant %int 1
4541%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
4542%v4float = OpTypeVector %float 4
4543%_ptr_Input_v4float = OpTypePointer Input %v4float
4544%a_position = OpVariable %_ptr_Input_v4float Input
4545;CHECK: %_ptr_Input_uint = OpTypePointer Input %uint
4546;CHECK: %gl_VertexIndex = OpVariable %_ptr_Input_uint Input
4547;CHECK: %gl_InstanceIndex = OpVariable %_ptr_Input_uint Input
4548;CHECK: [[null_v2float:%\w+]] = OpConstantNull %v2float
4549)" + kImportStub + R"(
4550%main = OpFunction %void None %3
4551%5 = OpLabel
4552%25 = OpAccessChain %_ptr_Uniform_v2float %_ %int_0 %int_2 %int_3 %int_1
4553;CHECK: {{%\w+}} = OpIMul %uint %uint_128 %int_2
4554;CHECK: {{%\w+}} = OpIAdd %uint %uint_0 {{%\w+}}
4555;CHECK: {{%\w+}} = OpIMul %uint %uint_32 %int_3
4556;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} {{%\w+}}
4557;CHECK: {{%\w+}} = OpIMul %uint %uint_4 %int_1
4558;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} {{%\w+}}
4559;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_19
4560;CHECK: {{%\w+}} = OpLoad %uint %gl_VertexIndex
4561;CHECK: {{%\w+}} = OpLoad %uint %gl_InstanceIndex
4562;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_0 {{%\w+}} {{%\w+}} %uint_0
4563;CHECK: [[desc_state:%\w+]] = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_52 {{%\w+}} %uint_3 %uint_7 %uint_0 {{%\w+}}
4564%26 = OpLoad %v2float %25
4565OpStore %v_vtxResult %26
4566;CHECK-NOT: %26 = OpLoad %v2float %25
4567;CHECK-NOT: OpStore %v_vtxResult %26
4568;CHECK: OpSelectionMerge {{%\w+}} None
4569;CHECK: OpBranchConditional [[desc_state]] {{%\w+}} {{%\w+}}
4570;CHECK: {{%\w+}} = OpLabel
4571;CHECK: [[load_result]] = OpLoad %v2float %25
4572;CHECK: OpBranch {{%\w+}}
4573;CHECK: {{%\w+}} = OpLabel
4574;CHECK: OpBranch {{%\w+}}
4575;CHECK: {{%\w+}} = OpLabel
4576;CHECK: [[phi_result]] = OpPhi %v2float [[load_result]] {{%\w+}} [[null_v2float]] {{%\w+}}
4577;CHECK: OpStore %v_vtxResult [[phi_result]]
4578OpReturn
4579OpFunctionEnd
4580)";
4581  // clang-format on
4582
4583  SetTargetEnv(SPV_ENV_UNIVERSAL_1_4);
4584  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
4585  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 23u);
4586}
4587
4588TEST_F(InstBindlessTest, ImageBufferOOBRead) {
4589  // Texel buffer (imagebuffer) oob check for ImageRead
4590  //
4591  // #version 450
4592  // layout(set=3, binding=7, r32f) uniform readonly imageBuffer s;
4593  // layout(location=11) out vec4 x;
4594  // layout(location=13) in flat int ii;
4595  //
4596  // void main(){
4597  //    x = imageLoad(s, ii);
4598  // }
4599
4600  // clang-format off
4601  const std::string text = R"(
4602OpCapability Shader
4603OpCapability ImageBuffer
4604;CHECK: OpCapability Linkage
4605%1 = OpExtInstImport "GLSL.std.450"
4606OpMemoryModel Logical GLSL450
4607OpEntryPoint Fragment %main "main" %x %s %ii
4608OpExecutionMode %main OriginUpperLeft
4609OpSource GLSL 450
4610OpName %main "main"
4611OpName %x "x"
4612OpName %s "s"
4613OpName %ii "ii"
4614OpDecorate %x Location 11
4615OpDecorate %s DescriptorSet 3
4616OpDecorate %s Binding 7
4617OpDecorate %s NonWritable
4618OpDecorate %ii Flat
4619OpDecorate %ii Location 13
4620)" + kImportDeco + R"(
4621;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
4622%void = OpTypeVoid
4623%3 = OpTypeFunction %void
4624%float = OpTypeFloat 32
4625%v4float = OpTypeVector %float 4
4626%_ptr_Output_v4float = OpTypePointer Output %v4float
4627%x = OpVariable %_ptr_Output_v4float Output
4628%10 = OpTypeImage %float Buffer 0 0 0 2 R32f
4629%_ptr_UniformConstant_10 = OpTypePointer UniformConstant %10
4630%s = OpVariable %_ptr_UniformConstant_10 UniformConstant
4631%int = OpTypeInt 32 1
4632%_ptr_Input_int = OpTypePointer Input %int
4633%ii = OpVariable %_ptr_Input_int Input
4634;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
4635;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
4636;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
4637%main = OpFunction %void None %3
4638%5 = OpLabel
4639;CHECK: OpBranch %19
4640;CHECK: %19 = OpLabel
4641%13 = OpLoad %10 %s
4642%17 = OpLoad %int %ii
4643%18 = OpImageRead %v4float %13 %17
4644OpStore %x %18
4645;CHECK-NOT: %18 = OpImageRead %v4float %13 %17
4646;CHECK-NOT: OpStore %x %18
4647;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
4648;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
4649;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
4650;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
4651;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
4652;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_34 {{%\w+}} %uint_3 %uint_7 %uint_0 %22
4653;CHECK: OpSelectionMerge {{%\w+}} None
4654;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
4655;CHECK: {{%\w+}} = OpLabel
4656;CHECK: {{%\w+}} = OpLoad %10 %s
4657;CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %17
4658;CHECK: OpBranch {{%\w+}}
4659;CHECK: {{%\w+}} = OpLabel
4660;CHECK: OpBranch {{%\w+}}
4661;CHECK: {{%\w+}} = OpLabel
4662;CHECK: [[phi_result:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
4663;CHECK: OpStore %x [[phi_result]]
4664OpReturn
4665OpFunctionEnd
4666)";
4667  // clang-format on
4668
4669  SetTargetEnv(SPV_ENV_UNIVERSAL_1_4);
4670  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
4671  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 23u);
4672}
4673
4674TEST_F(InstBindlessTest, ImageBufferOOBWrite) {
4675  // Texel buffer (imagebuffer) oob check for ImageWrite
4676  //
4677  // #version 450
4678  // layout(set=3, binding=7, r32f) uniform readonly imageBuffer s;
4679  // layout(location=11) out vec4 x;
4680  // layout(location=13) in flat int ii;
4681  //
4682  // void main(){
4683  //    imageStore(s, ii, x);
4684  // }
4685
4686  // clang-format off
4687  const std::string text = R"(
4688OpCapability Shader
4689OpCapability ImageBuffer
4690;CHECK: OpCapability Linkage
4691%1 = OpExtInstImport "GLSL.std.450"
4692OpMemoryModel Logical GLSL450
4693OpEntryPoint Fragment %main "main" %s %ii %x
4694;CHECK: OpEntryPoint Fragment %main "main" %s %ii %x %gl_FragCoord
4695OpExecutionMode %main OriginUpperLeft
4696OpSource GLSL 450
4697OpName %main "main"
4698OpName %s "s"
4699OpName %ii "ii"
4700OpName %x "x"
4701OpDecorate %s DescriptorSet 3
4702OpDecorate %s Binding 7
4703OpDecorate %s NonReadable
4704OpDecorate %ii Flat
4705OpDecorate %ii Location 13
4706OpDecorate %x Location 11
4707)" + kImportDeco + R"(
4708;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
4709%void = OpTypeVoid
4710%3 = OpTypeFunction %void
4711%float = OpTypeFloat 32
4712%7 = OpTypeImage %float Buffer 0 0 0 2 R32f
4713%_ptr_UniformConstant_7 = OpTypePointer UniformConstant %7
4714%s = OpVariable %_ptr_UniformConstant_7 UniformConstant
4715%int = OpTypeInt 32 1
4716%_ptr_Input_int = OpTypePointer Input %int
4717%ii = OpVariable %_ptr_Input_int Input
4718%v4float = OpTypeVector %float 4
4719%_ptr_Output_v4float = OpTypePointer Output %v4float
4720%x = OpVariable %_ptr_Output_v4float Output
4721;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
4722;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
4723)" + kImportStub + R"(
4724%main = OpFunction %void None %3
4725%5 = OpLabel
4726;CHECK: {{%\w+}} = OpLabel
4727;CHECK: OpBranch {{%\w+}}
4728;CHECK: %19 = OpLabel
4729%10 = OpLoad %7 %s
4730%14 = OpLoad %int %ii
4731%18 = OpLoad %v4float %x
4732OpImageWrite %10 %14 %18
4733;CHECK-NOT: OpImageWrite %10 %14 %18
4734;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
4735;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
4736;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
4737;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
4738;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
4739;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_35 {{%\w+}} %uint_3 %uint_7 %uint_0 {{%\w+}}
4740;CHECK: OpSelectionMerge {{%\w+}} None
4741;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
4742;CHECK: {{%\w+}} = OpLabel
4743;CHECK: {{%\w+}} = OpLoad %7 %s
4744;CHECK: OpImageWrite {{%\w+}} %14 %18
4745;CHECK: OpBranch {{%\w+}}
4746;CHECK: {{%\w+}} = OpLabel
4747;CHECK: OpBranch {{%\w+}}
4748;CHECK: {{%\w+}} = OpLabel
4749OpReturn
4750OpFunctionEnd
4751)";
4752  // clang-format on
4753
4754  SetTargetEnv(SPV_ENV_UNIVERSAL_1_4);
4755  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
4756  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 23u);
4757}
4758
4759TEST_F(InstBindlessTest, TextureBufferOOBFetch) {
4760  // Texel buffer (texturebuffer) oob check for ImageFetch
4761  //
4762  // #version 450
4763  // layout(set=3, binding=7) uniform textureBuffer s;
4764  // layout(location=11) out vec4 x;
4765  // layout(location=13) in flat int ii;
4766  //
4767  // void main(){
4768  //    x = texelFetch(s, ii);
4769  // }
4770
4771  // clang-format off
4772  const std::string text = R"(
4773OpCapability Shader
4774OpCapability SampledBuffer
4775;CHECK: OpCapability Linkage
4776%1 = OpExtInstImport "GLSL.std.450"
4777OpMemoryModel Logical GLSL450
4778OpEntryPoint Fragment %main "main" %x %s %ii
4779;CHECK: OpEntryPoint Fragment %main "main" %x %s %ii %gl_FragCoord
4780OpExecutionMode %main OriginUpperLeft
4781OpSource GLSL 450
4782OpName %main "main"
4783OpName %x "x"
4784OpName %s "s"
4785OpName %ii "ii"
4786OpDecorate %x Location 11
4787OpDecorate %s DescriptorSet 3
4788OpDecorate %s Binding 7
4789OpDecorate %ii Flat
4790OpDecorate %ii Location 13
4791;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
4792%void = OpTypeVoid
4793%3 = OpTypeFunction %void
4794%float = OpTypeFloat 32
4795%v4float = OpTypeVector %float 4
4796%_ptr_Output_v4float = OpTypePointer Output %v4float
4797%x = OpVariable %_ptr_Output_v4float Output
4798%10 = OpTypeImage %float Buffer 0 0 0 1 Unknown
4799%_ptr_UniformConstant_10 = OpTypePointer UniformConstant %10
4800%s = OpVariable %_ptr_UniformConstant_10 UniformConstant
4801%int = OpTypeInt 32 1
4802%_ptr_Input_int = OpTypePointer Input %int
4803%ii = OpVariable %_ptr_Input_int Input
4804;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
4805;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
4806;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
4807%main = OpFunction %void None %3
4808%5 = OpLabel
4809;CHECK: OpBranch %19
4810;CHECK: %19 = OpLabel
4811%13 = OpLoad %10 %s
4812%17 = OpLoad %int %ii
4813%18 = OpImageFetch %v4float %13 %17
4814OpStore %x %18
4815;CHECK-NOT: %18 = OpImageFetch %v4float %13 %17
4816;CHECK-NOT: OpStore %x %18
4817;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
4818;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
4819;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
4820;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
4821;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
4822;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_33 {{%\w+}} %uint_3 %uint_7 %uint_0 {{%\w+}}
4823;CHECK: OpSelectionMerge {{%\w+}} None
4824;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
4825;CHECK: {{%\w+}} = OpLabel
4826;CHECK: {{%\w+}} = OpLoad %10 %s
4827;CHECK: {{%\w+}} = OpImageFetch %v4float {{%\w+}} %17
4828;CHECK: OpBranch {{%\w+}}
4829;CHECK: {{%\w+}} = OpLabel
4830;CHECK: OpBranch {{%\w+}}
4831;CHECK: {{%\w+}} = OpLabel
4832;CHECK: [[phi_result:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
4833;CHECK: OpStore %x [[phi_result]]
4834OpReturn
4835OpFunctionEnd
4836)";
4837  // clang-format on
4838
4839  SetTargetEnv(SPV_ENV_UNIVERSAL_1_4);
4840  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
4841  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 23u);
4842}
4843
4844TEST_F(InstBindlessTest, SamplerBufferOOBFetch) {
4845  // Texel buffer (samplerbuffer) oob check for ImageFetch
4846  //
4847  // #version 450
4848  // layout(set=3, binding=7) uniform samplerBuffer s;
4849  // layout(location=11) out vec4 x;
4850  // layout(location=13) in flat int ii;
4851  //
4852  // void main(){
4853  //    x = texelFetch(s, ii);
4854  // }
4855
4856  // clang-format off
4857  const std::string text = R"(
4858OpCapability Shader
4859OpCapability SampledBuffer
4860;CHECK: OpCapability Linkage
4861%1 = OpExtInstImport "GLSL.std.450"
4862OpMemoryModel Logical GLSL450
4863OpEntryPoint Fragment %main "main" %x %s %ii
4864;CHECK: OpEntryPoint Fragment %main "main" %x %s %ii %gl_FragCoord
4865OpExecutionMode %main OriginUpperLeft
4866OpSource GLSL 450
4867OpName %main "main"
4868OpName %x "x"
4869OpName %s "s"
4870OpName %ii "ii"
4871OpDecorate %x Location 11
4872OpDecorate %s DescriptorSet 3
4873OpDecorate %s Binding 7
4874OpDecorate %ii Flat
4875OpDecorate %ii Location 13
4876)" + kImportDeco + R"(
4877;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
4878%void = OpTypeVoid
4879%3 = OpTypeFunction %void
4880%float = OpTypeFloat 32
4881%v4float = OpTypeVector %float 4
4882%_ptr_Output_v4float = OpTypePointer Output %v4float
4883%x = OpVariable %_ptr_Output_v4float Output
4884%10 = OpTypeImage %float Buffer 0 0 0 1 Unknown
4885%11 = OpTypeSampledImage %10
4886%_ptr_UniformConstant_11 = OpTypePointer UniformConstant %11
4887%s = OpVariable %_ptr_UniformConstant_11 UniformConstant
4888%int = OpTypeInt 32 1
4889%_ptr_Input_int = OpTypePointer Input %int
4890%ii = OpVariable %_ptr_Input_int Input
4891;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
4892;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
4893;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
4894)" + kImportStub + R"(
4895%main = OpFunction %void None %3
4896%5 = OpLabel
4897;CHECK: OpBranch %21
4898;CHECK: %21 = OpLabel
4899%14 = OpLoad %11 %s
4900%18 = OpLoad %int %ii
4901%19 = OpImage %10 %14
4902%20 = OpImageFetch %v4float %19 %18
4903OpStore %x %20
4904;CHECK-NOT: %20 = OpImageFetch %v4float %19 %18
4905;CHECK-NOT: OpStore %x %20
4906;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
4907;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
4908;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
4909;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
4910;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
4911;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_35 {{%\w+}} %uint_3 %uint_7 %uint_0 {{%\w+}}
4912;CHECK: OpSelectionMerge {{%\w+}} None
4913;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
4914;CHECK: {{%\w+}} = OpLabel
4915;CHECK: {{%\w+}} = OpLoad %11 %s
4916;CHECK: {{%\w+}} = OpImage %10 {{%\w+}}
4917;CHECK: {{%\w+}} = OpImageFetch %v4float {{%\w+}} {{%\w+}}
4918;CHECK: OpBranch {{%\w+}}
4919;CHECK: {{%\w+}} = OpLabel
4920;CHECK: OpBranch {{%\w+}}
4921;CHECK: {{%\w+}} = OpLabel
4922;CHECK: [[phi_result:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
4923;CHECK: OpStore %x [[phi_result]]
4924OpReturn
4925OpFunctionEnd
4926)";
4927  // clang-format on
4928
4929  SetTargetEnv(SPV_ENV_UNIVERSAL_1_4);
4930  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
4931  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 23u);
4932}
4933
4934TEST_F(InstBindlessTest, SamplerBufferConstructorOOBFetch) {
4935  // Texel buffer (samplerbuffer constructor) oob check for ImageFetch
4936  //
4937  // #version 450
4938  // layout(set=3, binding=7) uniform textureBuffer tBuf;
4939  // layout(set=3, binding=8) uniform sampler s;
4940  // layout(location=11) out vec4 x;
4941  // layout(location=13) in flat int ii;
4942  //
4943  // void main(){
4944  //    x = texelFetch(samplerBuffer(tBuf, s), ii);
4945  // }
4946
4947  // clang-format off
4948  const std::string text = R"(
4949OpCapability Shader
4950OpCapability SampledBuffer
4951;CHECK: OpCapability Linkage
4952%1 = OpExtInstImport "GLSL.std.450"
4953OpMemoryModel Logical GLSL450
4954OpEntryPoint Fragment %main "main" %x %tBuf %s %ii
4955;CHECK: OpEntryPoint Fragment %main "main" %x %tBuf %s %ii %gl_FragCoord
4956OpExecutionMode %main OriginUpperLeft
4957OpSource GLSL 450
4958OpName %main "main"
4959OpName %x "x"
4960OpName %tBuf "tBuf"
4961OpName %s "s"
4962OpName %ii "ii"
4963OpDecorate %x Location 11
4964OpDecorate %tBuf DescriptorSet 3
4965OpDecorate %tBuf Binding 7
4966OpDecorate %s DescriptorSet 3
4967OpDecorate %s Binding 8
4968OpDecorate %ii Flat
4969OpDecorate %ii Location 13
4970)" + kImportDeco + R"(
4971;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
4972%void = OpTypeVoid
4973%3 = OpTypeFunction %void
4974%float = OpTypeFloat 32
4975%v4float = OpTypeVector %float 4
4976%_ptr_Output_v4float = OpTypePointer Output %v4float
4977%x = OpVariable %_ptr_Output_v4float Output
4978%10 = OpTypeImage %float Buffer 0 0 0 1 Unknown
4979%_ptr_UniformConstant_10 = OpTypePointer UniformConstant %10
4980%tBuf = OpVariable %_ptr_UniformConstant_10 UniformConstant
4981%14 = OpTypeSampler
4982%_ptr_UniformConstant_14 = OpTypePointer UniformConstant %14
4983%s = OpVariable %_ptr_UniformConstant_14 UniformConstant
4984%18 = OpTypeSampledImage %10
4985%int = OpTypeInt 32 1
4986%_ptr_Input_int = OpTypePointer Input %int
4987%ii = OpVariable %_ptr_Input_int Input
4988;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
4989;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
4990;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float
4991%main = OpFunction %void None %3
4992%5 = OpLabel
4993%13 = OpLoad %10 %tBuf
4994%17 = OpLoad %14 %s
4995%19 = OpSampledImage %18 %13 %17
4996%23 = OpLoad %int %ii
4997%24 = OpImage %10 %19
4998%25 = OpImageFetch %v4float %24 %23
4999OpStore %x %25
5000;CHECK-NOT: %25 = OpImageFetch %v4float %24 %23
5001;CHECK-NOT: OpStore %x %25
5002;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
5003;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
5004;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
5005;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
5006;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
5007;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_43 {{%\w+}} %uint_3 %uint_7 %uint_0 {{%\w+}}
5008;CHECK: OpSelectionMerge {{%\w+}} None
5009;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
5010;CHECK: {{%\w+}} = OpLabel
5011;CHECK: {{%\w+}} = OpLoad %10 %tBuf
5012;CHECK: {{%\w+}} = OpSampledImage %18 {{%\w+}} %17
5013;CHECK: {{%\w+}} = OpImage %10 {{%\w+}}
5014;CHECK: {{%\w+}} = OpImageFetch %v4float {{%\w+}} %23
5015;CHECK: OpBranch {{%\w+}}
5016;CHECK: {{%\w+}} = OpLabel
5017;CHECK: OpBranch {{%\w+}}
5018;CHECK: {{%\w+}} = OpLabel
5019;CHECK: [[phi_result:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}}
5020;CHECK: OpStore %x [[phi_result]]
5021OpReturn
5022OpFunctionEnd
5023)";
5024  // clang-format on
5025
5026  SetTargetEnv(SPV_ENV_UNIVERSAL_1_4);
5027  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
5028  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 23u);
5029}
5030
5031TEST_F(InstBindlessTest, DeviceBufferAddressOOB) {
5032  // #version 450
5033  // #extension GL_EXT_buffer_reference : enable
5034  //  layout(buffer_reference, buffer_reference_align = 16) buffer bufStruct;
5035  // layout(set = 0, binding = 0) uniform ufoo {
5036  //     bufStruct data;
5037  //     int nWrites;
5038  // } u_info;
5039  // layout(buffer_reference, std140) buffer bufStruct {
5040  //     int a[4];
5041  // };
5042  // void main() {
5043  //     for (int i=0; i < u_info.nWrites; ++i) {
5044  //         u_info.data.a[i] = 0xdeadca71;
5045  //     }
5046  // }
5047
5048  // clang-format off
5049  const std::string text = R"(
5050OpCapability Shader
5051OpCapability PhysicalStorageBufferAddresses
5052;CHECK: OpCapability Linkage
5053;CHECK: OpCapability Int64
5054OpExtension "SPV_KHR_physical_storage_buffer"
5055%1 = OpExtInstImport "GLSL.std.450"
5056OpMemoryModel PhysicalStorageBuffer64 GLSL450
5057OpEntryPoint Vertex %main "main" %u_info
5058;CHECK: OpEntryPoint Vertex %main "main" %u_info %gl_VertexIndex %gl_InstanceIndex
5059OpSource GLSL 450
5060OpSourceExtension "GL_EXT_buffer_reference"
5061OpName %main "main"
5062OpName %i "i"
5063OpName %ufoo "ufoo"
5064OpMemberName %ufoo 0 "data"
5065OpMemberName %ufoo 1 "nWrites"
5066OpName %bufStruct "bufStruct"
5067OpMemberName %bufStruct 0 "a"
5068OpName %u_info "u_info"
5069OpMemberDecorate %ufoo 0 Offset 0
5070OpMemberDecorate %ufoo 1 Offset 8
5071OpDecorate %ufoo Block
5072OpDecorate %_arr_int_uint_4 ArrayStride 16
5073OpMemberDecorate %bufStruct 0 Offset 0
5074OpDecorate %bufStruct Block
5075OpDecorate %u_info DescriptorSet 0
5076OpDecorate %u_info Binding 0
5077%void = OpTypeVoid
5078%3 = OpTypeFunction %void
5079%int = OpTypeInt 32 1
5080%_ptr_Function_int = OpTypePointer Function %int
5081%int_0 = OpConstant %int 0
5082OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_bufStruct PhysicalStorageBuffer
5083%ufoo = OpTypeStruct %_ptr_PhysicalStorageBuffer_bufStruct %int
5084%uint = OpTypeInt 32 0
5085%uint_4 = OpConstant %uint 4
5086%_arr_int_uint_4 = OpTypeArray %int %uint_4
5087%bufStruct = OpTypeStruct %_arr_int_uint_4
5088%_ptr_PhysicalStorageBuffer_bufStruct = OpTypePointer PhysicalStorageBuffer %bufStruct
5089%_ptr_Uniform_ufoo = OpTypePointer Uniform %ufoo
5090%u_info = OpVariable %_ptr_Uniform_ufoo Uniform
5091%int_1 = OpConstant %int 1
5092%_ptr_Uniform_int = OpTypePointer Uniform %int
5093%bool = OpTypeBool
5094%_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct = OpTypePointer Uniform %_ptr_PhysicalStorageBuffer_bufStruct
5095%int_n559035791 = OpConstant %int -559035791
5096%_ptr_PhysicalStorageBuffer_int = OpTypePointer PhysicalStorageBuffer %int
5097)" + kImportStub + R"(
5098%main = OpFunction %void None %3
5099%5 = OpLabel
5100%i = OpVariable %_ptr_Function_int Function
5101OpStore %i %int_0
5102OpBranch %10
5103%10 = OpLabel
5104OpLoopMerge %12 %13 None
5105OpBranch %14
5106%14 = OpLabel
5107%15 = OpLoad %int %i
5108%26 = OpAccessChain %_ptr_Uniform_int %u_info %int_1
5109;CHECK: {{%\w+}} = OpIAdd %uint %uint_8 %uint_3
5110;CHECK: {{%\w+}} = OpLoad %uint %gl_VertexIndex
5111;CHECK: {{%\w+}} = OpLoad %uint %gl_InstanceIndex
5112;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_0 {{%\w+}} {{%\w+}} %uint_0
5113;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_56 {{%\w+}} %uint_0 %uint_0 %uint_0 {{%\w+}}
5114;CHECK: OpSelectionMerge {{%\w+}} None
5115;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
5116;CHECK: {{%\w+}} = OpLabel
5117;CHECK: [[load_result:%\w+]] = OpLoad %int %26
5118;CHECK: OpBranch {{%\w+}}
5119;CHECK: {{%\w+}} = OpLabel
5120;CHECK: OpBranch {{%\w+}}
5121;CHECK: {{%\w+}} = OpLabel
5122;CHECK: [[phi_result:%\w+]] = OpPhi %int [[load_result]] {{%\w+}} {{%\w+}} {{%\w+}}
5123%27 = OpLoad %int %26
5124%29 = OpSLessThan %bool %15 %27
5125;CHECK-NOT: %27 = OpLoad %int %26
5126;CHECK-NOT: %29 = OpSLessThan %bool %15 %27
5127;CHECK: %29 = OpSLessThan %bool %15 [[phi_result]]
5128OpBranchConditional %29 %11 %12
5129%11 = OpLabel
5130%31 = OpAccessChain %_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct %u_info %int_0
5131%32 = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %31
5132;CHECK-NOT: %32 = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %31
5133;CHECK: {{%\w+}} = OpIAdd %uint %uint_0 %uint_7
5134;CHECK: {{%\w+}} = OpLoad %uint %gl_VertexIndex
5135;CHECK: {{%\w+}} = OpLoad %uint %gl_InstanceIndex
5136;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_0 {{%\w+}} {{%\w+}} %uint_0
5137;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_61 {{%\w+}} %uint_0 %uint_0 %uint_0 {{%\w+}}
5138;CHECK: OpSelectionMerge {{%\w+}} None
5139;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
5140;CHECK: {{%\w+}} = OpLabel
5141;CHECK: [[load_result_2:%\w+]] = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %31
5142;CHECK: OpBranch {{%\w+}}
5143;CHECK: {{%\w+}} = OpLabel
5144;CHECK: {{%\w+}} = OpConvertUToPtr %_ptr_PhysicalStorageBuffer_bufStruct {{%\w+}}
5145;CHECK: OpBranch {{%\w+}}
5146;CHECK: {{%\w+}} = OpLabel
5147;CHECK: [[phi_result_2:%\w+]] = OpPhi %_ptr_PhysicalStorageBuffer_bufStruct [[load_result_2]] {{%\w+}} {{%\w+}} {{%\w+}}
5148%33 = OpLoad %int %i
5149%36 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %32 %int_0 %33
5150;CHECK-NOT: %36 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %32 %int_0 %33
5151;CHECK: %36 = OpAccessChain %_ptr_PhysicalStorageBuffer_int [[phi_result_2]] %int_0 %33
5152OpStore %36 %int_n559035791 Aligned 16
5153OpBranch %13
5154%13 = OpLabel
5155%37 = OpLoad %int %i
5156%38 = OpIAdd %int %37 %int_1
5157OpStore %i %38
5158OpBranch %10
5159%12 = OpLabel
5160OpReturn
5161OpFunctionEnd)";
5162  // clang-format on
5163
5164  SetTargetEnv(SPV_ENV_UNIVERSAL_1_4);
5165  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
5166  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 23u);
5167}
5168
5169TEST_F(InstBindlessTest, VertexIndexOOB) {
5170  // #version 450
5171  // layout(std140, binding = 0) uniform foo { uint tex_index[1]; }
5172  // uniform_index_buffer; layout(location = 0) out flat uint index; vec2
5173  // vertices[3]; void main() {
5174  //     vertices[0] = vec2(-1.0, -1.0);
5175  //     vertices[1] = vec2( 1.0, -1.0);
5176  //     vertices[2] = vec2( 0.0,  1.0);
5177  //     gl_Position = vec4(vertices[gl_VertexIndex % 3], 0.0, 1.0);
5178  //     index = uniform_index_buffer.tex_index[0];
5179  // }
5180  // clang-format off
5181  const std::string text = R"(
5182OpCapability Shader
5183%1 = OpExtInstImport "GLSL.std.450"
5184OpMemoryModel Logical GLSL450
5185OpEntryPoint Vertex %main "main" %vertices %_ %gl_VertexIndex %index %uniform_index_buffer
5186OpSource GLSL 450
5187OpName %main "main"
5188OpName %vertices "vertices"
5189OpName %gl_PerVertex "gl_PerVertex"
5190OpMemberName %gl_PerVertex 0 "gl_Position"
5191OpMemberName %gl_PerVertex 1 "gl_PointSize"
5192OpMemberName %gl_PerVertex 2 "gl_ClipDistance"
5193OpMemberName %gl_PerVertex 3 "gl_CullDistance"
5194OpName %_ ""
5195OpName %gl_VertexIndex "gl_VertexIndex"
5196OpName %index "index"
5197OpName %foo "foo"
5198OpMemberName %foo 0 "tex_index"
5199OpName %uniform_index_buffer "uniform_index_buffer"
5200OpMemberDecorate %gl_PerVertex 0 BuiltIn Position
5201OpMemberDecorate %gl_PerVertex 1 BuiltIn PointSize
5202OpMemberDecorate %gl_PerVertex 2 BuiltIn ClipDistance
5203OpMemberDecorate %gl_PerVertex 3 BuiltIn CullDistance
5204OpDecorate %gl_PerVertex Block
5205OpDecorate %gl_VertexIndex BuiltIn VertexIndex
5206OpDecorate %index Flat
5207OpDecorate %index Location 0
5208OpDecorate %_arr_uint_uint_1 ArrayStride 16
5209OpMemberDecorate %foo 0 Offset 0
5210OpDecorate %foo Block
5211OpDecorate %uniform_index_buffer DescriptorSet 0
5212OpDecorate %uniform_index_buffer Binding 0
5213%void = OpTypeVoid
5214%3 = OpTypeFunction %void
5215%float = OpTypeFloat 32
5216%v2float = OpTypeVector %float 2
5217%uint = OpTypeInt 32 0
5218%uint_3 = OpConstant %uint 3
5219%_arr_v2float_uint_3 = OpTypeArray %v2float %uint_3
5220%_ptr_Private__arr_v2float_uint_3 = OpTypePointer Private %_arr_v2float_uint_3
5221%vertices = OpVariable %_ptr_Private__arr_v2float_uint_3 Private
5222%int = OpTypeInt 32 1
5223%int_0 = OpConstant %int 0
5224%float_n1 = OpConstant %float -1
5225%16 = OpConstantComposite %v2float %float_n1 %float_n1
5226%_ptr_Private_v2float = OpTypePointer Private %v2float
5227%int_1 = OpConstant %int 1
5228%float_1 = OpConstant %float 1
5229%21 = OpConstantComposite %v2float %float_1 %float_n1
5230%int_2 = OpConstant %int 2
5231%float_0 = OpConstant %float 0
5232%25 = OpConstantComposite %v2float %float_0 %float_1
5233%v4float = OpTypeVector %float 4
5234%uint_1 = OpConstant %uint 1
5235%_arr_float_uint_1 = OpTypeArray %float %uint_1
5236%gl_PerVertex = OpTypeStruct %v4float %float %_arr_float_uint_1 %_arr_float_uint_1
5237%_ptr_Output_gl_PerVertex = OpTypePointer Output %gl_PerVertex
5238%_ = OpVariable %_ptr_Output_gl_PerVertex Output
5239%_ptr_Input_int = OpTypePointer Input %int
5240%gl_VertexIndex = OpVariable %_ptr_Input_int Input
5241%int_3 = OpConstant %int 3
5242%_ptr_Output_v4float = OpTypePointer Output %v4float
5243%_ptr_Output_uint = OpTypePointer Output %uint
5244%index = OpVariable %_ptr_Output_uint Output
5245%_arr_uint_uint_1 = OpTypeArray %uint %uint_1
5246%foo = OpTypeStruct %_arr_uint_uint_1
5247%_ptr_Uniform_foo = OpTypePointer Uniform %foo
5248%uniform_index_buffer = OpVariable %_ptr_Uniform_foo Uniform
5249%_ptr_Uniform_uint = OpTypePointer Uniform %uint
5250)" + kImportStub + R"(
5251%main = OpFunction %void None %3
5252%5 = OpLabel
5253%18 = OpAccessChain %_ptr_Private_v2float %vertices %int_0
5254OpStore %18 %16
5255%22 = OpAccessChain %_ptr_Private_v2float %vertices %int_1
5256OpStore %22 %21
5257%26 = OpAccessChain %_ptr_Private_v2float %vertices %int_2
5258OpStore %26 %25
5259%35 = OpLoad %int %gl_VertexIndex
5260%37 = OpSMod %int %35 %int_3
5261%38 = OpAccessChain %_ptr_Private_v2float %vertices %37
5262%39 = OpLoad %v2float %38
5263%40 = OpCompositeExtract %float %39 0
5264%41 = OpCompositeExtract %float %39 1
5265%42 = OpCompositeConstruct %v4float %40 %41 %float_0 %float_1
5266%44 = OpAccessChain %_ptr_Output_v4float %_ %int_0
5267OpStore %44 %42
5268%52 = OpAccessChain %_ptr_Uniform_uint %uniform_index_buffer %int_0 %int_0
5269%53 = OpLoad %uint %52
5270;CHECK-NOT: %53 = OpLoad %uint %52
5271;CHECK: {{%\w+}} = OpIMul %uint %uint_16 %int_0
5272;CHECK: {{%\w+}} = OpIAdd %uint %uint_0 {{%\w+}}
5273;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3
5274;CHECK: {{%\w+}} = OpLoad %int %gl_VertexIndex
5275;CHECK: {{%\w+}} = OpBitcast %uint {{%\w+}}
5276;CHECK: {{%\w+}} = OpLoad %uint %gl_InstanceIndex
5277;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_0 {{%\w+}} {{%\w+}} %uint_0
5278;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_87 {{%\w+}} %uint_0 %uint_0 %uint_0 {{%\w+}}
5279;CHECK: OpSelectionMerge {{%\w+}} None
5280;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
5281;CHECK: {{%\w+}} = OpLabel
5282;CHECK: {{%\w+}} = OpLoad %uint %52
5283;CHECK: OpBranch {{%\w+}}
5284;CHECK: {{%\w+}} = OpLabel
5285;CHECK: OpBranch {{%\w+}}
5286;CHECK: {{%\w+}} = OpLabel
5287;CHECK: [[phi_result:%\w+]] = OpPhi %uint {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}}
5288;CHECK: OpStore %index [[phi_result]]
5289OpStore %index %53
5290;CHECK-NOT: OpStore %index %53
5291OpReturn
5292;CHECK: OpReturn
5293OpFunctionEnd)";
5294  // clang-format on
5295
5296  SetTargetEnv(SPV_ENV_UNIVERSAL_1_4);
5297  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
5298  SinglePassRunAndMatch<InstBindlessCheckPass>(text, true, 23u);
5299}
5300
5301// TODO(greg-lunarg): Add tests to verify handling of these cases:
5302//
5303//   Compute shader
5304//   Geometry shader
5305//   Tessellation control shader
5306//   Tessellation eval shader
5307//   OpImage
5308//   SampledImage variable
5309
5310}  // namespace
5311}  // namespace opt
5312}  // namespace spvtools
5313