1 // Copyright (c) 2019-2022 Valve Corporation
2 // Copyright (c) 2019-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 // Tests ending with V2 use version 2 record format.
18 
19 #include <string>
20 #include <vector>
21 
22 #include "test/opt/pass_fixture.h"
23 #include "test/opt/pass_utils.h"
24 
25 namespace spvtools {
26 namespace opt {
27 namespace {
28 
29 static const std::string kFuncName = "inst_buff_addr_search_and_test";
30 static const std::string kImportDeco = R"(
31 ;CHECK: OpDecorate %)" + kFuncName + R"( LinkageAttributes ")" +
32                                        kFuncName + R"(" Import
33 )";
34 static const std::string kImportStub = R"(
35 ;CHECK: %)" + kFuncName + R"( = OpFunction %bool None {{%\w+}}
36 ;CHECK: OpFunctionEnd
37 )";
38 // clang-format on
39 
40 using InstBuffAddrTest = PassTest<::testing::Test>;
41 
42 TEST_F(InstBuffAddrTest, InstPhysicalStorageBufferStore) {
43   // #version 450
44   // #extension GL_EXT_buffer_reference : enable
45   //
46   // layout(buffer_reference, buffer_reference_align = 16) buffer bufStruct;
47   //
48   // layout(set = 0, binding = 0) uniform ufoo {
49   //     bufStruct data;
50   //     uint offset;
51   // } u_info;
52   //
53   // layout(buffer_reference, std140) buffer bufStruct {
54   //     layout(offset = 0) int a[2];
55   //     layout(offset = 32) int b;
56   // };
57   //
58   // void main() {
59   //     u_info.data.b = 0xca7;
60   // }
61 
62   const std::string defs = R"(
63 OpCapability Shader
64 OpCapability PhysicalStorageBufferAddresses
65 ;CHECK: OpCapability Int64
66 OpExtension "SPV_EXT_physical_storage_buffer"
67 ;CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class"
68 %1 = OpExtInstImport "GLSL.std.450"
69 OpMemoryModel PhysicalStorageBuffer64 GLSL450
70 OpEntryPoint GLCompute %main "main"
71 ;CHECK: OpEntryPoint GLCompute %main "main" %gl_GlobalInvocationID
72 OpExecutionMode %main LocalSize 1 1 1
73 OpSource GLSL 450
74 OpSourceExtension "GL_EXT_buffer_reference"
75 OpName %main "main"
76 OpName %ufoo "ufoo"
77 OpMemberName %ufoo 0 "data"
78 OpMemberName %ufoo 1 "offset"
79 OpName %bufStruct "bufStruct"
80 OpMemberName %bufStruct 0 "a"
81 OpMemberName %bufStruct 1 "b"
82 OpName %u_info "u_info"
83 )";
84 
85   // clang-format off
86   const std::string decorates = R"(
87 OpMemberDecorate %ufoo 0 Offset 0
88 OpMemberDecorate %ufoo 1 Offset 8
89 OpDecorate %ufoo Block
90 OpDecorate %_arr_int_uint_2 ArrayStride 16
91 OpMemberDecorate %bufStruct 0 Offset 0
92 OpMemberDecorate %bufStruct 1 Offset 32
93 OpDecorate %bufStruct Block
94 OpDecorate %u_info DescriptorSet 0
95 OpDecorate %u_info Binding 0
96 )" + kImportDeco + R"(
97 ;CHECK: OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId
98 )";
99 
100   const std::string globals = R"(
101 %void = OpTypeVoid
102 %3 = OpTypeFunction %void
103 OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_bufStruct PhysicalStorageBuffer
104 %uint = OpTypeInt 32 0
105 %ufoo = OpTypeStruct %_ptr_PhysicalStorageBuffer_bufStruct %uint
106 %int = OpTypeInt 32 1
107 %uint_2 = OpConstant %uint 2
108 %_arr_int_uint_2 = OpTypeArray %int %uint_2
109 %bufStruct = OpTypeStruct %_arr_int_uint_2 %int
110 %_ptr_PhysicalStorageBuffer_bufStruct = OpTypePointer PhysicalStorageBuffer %bufStruct
111 %_ptr_Uniform_ufoo = OpTypePointer Uniform %ufoo
112 %u_info = OpVariable %_ptr_Uniform_ufoo Uniform
113 %int_0 = OpConstant %int 0
114 %_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct = OpTypePointer Uniform %_ptr_PhysicalStorageBuffer_bufStruct
115 %int_1 = OpConstant %int 1
116 %int_3239 = OpConstant %int 3239
117 %_ptr_PhysicalStorageBuffer_int = OpTypePointer PhysicalStorageBuffer %int
118 ;CHECK: %ulong = OpTypeInt 64 0
119 ;CHECK: %bool = OpTypeBool
120 ;CHECK: %v3uint = OpTypeVector %uint 3
121 ;CHECK: %_ptr_Input_v3uint = OpTypePointer Input %v3uint
122 ;CHECK: %gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input
123 )";
124 // clang-format off
125 
126   const std::string main_func = R"(
127 %main = OpFunction %void None %3
128 %5 = OpLabel
129 %17 = OpAccessChain %_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct %u_info %int_0
130 %18 = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %17
131 %22 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %18 %int_1
132 ;CHECK-NOT: %17 = OpAccessChain %_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct %u_info %int_0
133 ;CHECK-NOT: %18 = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %17
134 ;CHECK-NOT: %22 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %18 %int_1
135 ;CHECK: %20 = OpAccessChain %_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct %u_info %int_0
136 ;CHECK: %21 = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %20
137 ;CHECK: %22 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %21 %int_1
138 ;CHECK: {{%\w+}} = OpConvertPtrToU %ulong %22
139 ;CHECK: {{%\w+}} = OpLoad %v3uint %gl_GlobalInvocationID
140 ;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
141 ;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
142 ;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
143 ;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5 {{%\w+}} {{%\w+}} {{%\w+}}
144 ;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_49 {{%\w+}} {{%\w+}} %uint_4
145 ;CHECK: OpSelectionMerge {{%\w+}} None
146 ;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
147 ;CHECK: {{%\w+}} = OpLabel
148 OpStore %22 %int_3239 Aligned 16
149 ;CHECK: OpStore %22 %int_3239 Aligned 16
150 ;CHECK: OpBranch {{%\w+}}
151 ;CHECK: {{%\w+}} = OpLabel
152 ;CHECK: OpBranch {{%\w+}}
153 ;CHECK: {{%\w+}} = OpLabel
154 OpReturn
155 OpFunctionEnd
156 )";
157 
158   // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
159   SinglePassRunAndMatch<InstBuffAddrCheckPass>(
160       defs + decorates + globals + kImportStub + main_func, true, 23u);
161 }
162 
163 TEST_F(InstBuffAddrTest, InstPhysicalStorageBufferLoadAndStore) {
164   // #version 450
165   // #extension GL_EXT_buffer_reference : enable
166 
167   // // forward reference
168   // layout(buffer_reference) buffer blockType;
169 
170   // layout(buffer_reference, std430, buffer_reference_align = 16) buffer
171   // blockType {
172   //   int x;
173   //   blockType next;
174   // };
175 
176   // layout(std430) buffer rootBlock {
177   //   blockType root;
178   // } r;
179 
180   // void main()
181   // {
182   //   blockType b = r.root;
183   //   b = b.next;
184   //   b.x = 531;
185   // }
186 
187   const std::string defs = R"(
188 OpCapability Shader
189 OpCapability PhysicalStorageBufferAddresses
190 ;CHECK: OpCapability Int64
191 OpExtension "SPV_EXT_physical_storage_buffer"
192 OpExtension "SPV_KHR_storage_buffer_storage_class"
193 %1 = OpExtInstImport "GLSL.std.450"
194 OpMemoryModel PhysicalStorageBuffer64 GLSL450
195 OpEntryPoint GLCompute %main "main"
196 OpExecutionMode %main LocalSize 1 1 1
197 OpSource GLSL 450
198 OpSourceExtension "GL_EXT_buffer_reference"
199 OpName %main "main"
200 ;CHECK: OpEntryPoint GLCompute %main "main" %gl_GlobalInvocationID
201 OpName %blockType "blockType"
202 OpMemberName %blockType 0 "x"
203 OpMemberName %blockType 1 "next"
204 OpName %rootBlock "rootBlock"
205 OpMemberName %rootBlock 0 "root"
206 OpName %r "r"
207 )";
208 
209 // clang-format off
210   const std::string decorates = R"(
211 OpMemberDecorate %blockType 0 Offset 0
212 OpMemberDecorate %blockType 1 Offset 8
213 OpDecorate %blockType Block
214 OpMemberDecorate %rootBlock 0 Offset 0
215 OpDecorate %rootBlock Block
216 OpDecorate %r DescriptorSet 0
217 OpDecorate %r Binding 0
218 )" + kImportDeco + R"(
219 ;CHECK: OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId
220 )";
221 
222   const std::string globals = R"(
223 %void = OpTypeVoid
224 %3 = OpTypeFunction %void
225 OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_blockType PhysicalStorageBuffer
226 %int = OpTypeInt 32 1
227 %blockType = OpTypeStruct %int %_ptr_PhysicalStorageBuffer_blockType
228 %_ptr_PhysicalStorageBuffer_blockType = OpTypePointer PhysicalStorageBuffer %blockType
229 %rootBlock = OpTypeStruct %_ptr_PhysicalStorageBuffer_blockType
230 %_ptr_StorageBuffer_rootBlock = OpTypePointer StorageBuffer %rootBlock
231 %r = OpVariable %_ptr_StorageBuffer_rootBlock StorageBuffer
232 %int_0 = OpConstant %int 0
233 %_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_blockType = OpTypePointer StorageBuffer %_ptr_PhysicalStorageBuffer_blockType
234 %int_1 = OpConstant %int 1
235 %_ptr_PhysicalStorageBuffer__ptr_PhysicalStorageBuffer_blockType = OpTypePointer PhysicalStorageBuffer %_ptr_PhysicalStorageBuffer_blockType
236 %int_531 = OpConstant %int 531
237 %_ptr_PhysicalStorageBuffer_int = OpTypePointer PhysicalStorageBuffer %int
238 )";
239 
240   const std::string main_func = R"(
241 %main = OpFunction %void None %3
242 %5 = OpLabel
243 %16 = OpAccessChain %_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_blockType %r %int_0
244 %17 = OpLoad %_ptr_PhysicalStorageBuffer_blockType %16
245 %21 = OpAccessChain %_ptr_PhysicalStorageBuffer__ptr_PhysicalStorageBuffer_blockType %17 %int_1
246 %22 = OpLoad %_ptr_PhysicalStorageBuffer_blockType %21 Aligned 8
247 %26 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %22 %int_0
248 OpStore %26 %int_531 Aligned 16
249 ;CHECK-NOT: %22 = OpLoad %_ptr_PhysicalStorageBuffer_blockType %21 Aligned 8
250 ;CHECK-NOT: %26 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %22 %int_0
251 ;CHECK: {{%\w+}} = OpConvertPtrToU %ulong %21
252 ;CHECK: {{%\w+}} = OpLoad %v3uint %gl_GlobalInvocationID
253 ;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
254 ;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
255 ;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
256 ;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5 {{%\w+}} {{%\w+}} {{%\w+}}
257 ;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_45 {{%\w+}} {{%\w+}} %uint_8
258 ;CHECK: OpSelectionMerge {{%\w+}} None
259 ;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
260 ;CHECK: {{%\w+}} = OpLabel
261 ;CHECK: {{%\w+}} = OpLoad %_ptr_PhysicalStorageBuffer_blockType %21 Aligned 8
262 ;CHECK: OpBranch {{%\w+}}
263 ;CHECK: {{%\w+}} = OpLabel
264 ;CHECK: {{%\w+}} = OpConvertUToPtr %_ptr_PhysicalStorageBuffer_blockType %52
265 ;CHECK: OpBranch {{%\w+}}
266 ;CHECK: {{%\w+}} = OpLabel
267 ;CHECK: {{%\w+}} = OpPhi %_ptr_PhysicalStorageBuffer_blockType {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}}
268 ;CHECK: %26 = OpAccessChain %_ptr_PhysicalStorageBuffer_int {{%\w+}} %int_0
269 ;CHECK: {{%\w+}} = OpConvertPtrToU %ulong %26
270 ;CHECK: {{%\w+}} = OpLoad %v3uint %gl_GlobalInvocationID
271 ;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
272 ;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
273 ;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
274 ;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5 {{%\w+}} {{%\w+}} {{%\w+}}
275 ;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_47 {{%\w+}} {{%\w+}} %uint_4
276 ;CHECK: OpSelectionMerge {{%\w+}} None
277 ;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
278 ;CHECK: {{%\w+}} = OpLabel
279 ;CHECK: OpStore %26 %int_531 Aligned 16
280 ;CHECK: OpBranch {{%\w+}}
281 ;CHECK: {{%\w+}} = OpLabel
282 ;CHECK: OpBranch {{%\w+}}
283 ;CHECK: {{%\w+}} = OpLabel
284 OpReturn
285 OpFunctionEnd
286 )";
287   // clang-format on
288 
289   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
290   SinglePassRunAndMatch<InstBuffAddrCheckPass>(
291       defs + decorates + globals + kImportStub + main_func, true, 23u);
292 }
293 
294 TEST_F(InstBuffAddrTest, StructLoad) {
295   // #version 450
296   //   #extension GL_EXT_buffer_reference : enable
297   //   #extension GL_ARB_gpu_shader_int64 : enable
298   //   struct Test {
299   //   float a;
300   // };
301   //
302   // layout(buffer_reference, std430, buffer_reference_align = 16) buffer
303   // TestBuffer { Test test; };
304   //
305   // Test GetTest(uint64_t ptr) {
306   //   return TestBuffer(ptr).test;
307   // }
308   //
309   // void main() {
310   //   GetTest(0xe0000000);
311   // }
312 
313   const std::string defs =
314       R"(
315 OpCapability Shader
316 OpCapability Int64
317 OpCapability PhysicalStorageBufferAddresses
318 ;CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class"
319 %1 = OpExtInstImport "GLSL.std.450"
320 OpMemoryModel PhysicalStorageBuffer64 GLSL450
321 OpEntryPoint Fragment %main "main"
322 ;CHECK: OpEntryPoint Fragment %main "main" %gl_FragCoord
323 OpExecutionMode %main OriginUpperLeft
324 OpSource GLSL 450
325 OpSourceExtension "GL_ARB_gpu_shader_int64"
326 OpSourceExtension "GL_EXT_buffer_reference"
327 OpName %main "main"
328 OpName %Test "Test"
329 OpMemberName %Test 0 "a"
330 OpName %Test_0 "Test"
331 OpMemberName %Test_0 0 "a"
332 OpName %TestBuffer "TestBuffer"
333 OpMemberName %TestBuffer 0 "test"
334 )";
335 
336   // clang-format off
337   const std::string decorates = R"(
338 OpMemberDecorate %Test_0 0 Offset 0
339 OpMemberDecorate %TestBuffer 0 Offset 0
340 OpDecorate %TestBuffer Block
341 )" + kImportDeco + R"(
342 ;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
343 )";
344 
345   const std::string globals = R"(
346 %void = OpTypeVoid
347 %3 = OpTypeFunction %void
348 %ulong = OpTypeInt 64 0
349 %float = OpTypeFloat 32
350 %Test = OpTypeStruct %float
351 OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_TestBuffer PhysicalStorageBuffer
352 %Test_0 = OpTypeStruct %float
353 %TestBuffer = OpTypeStruct %Test_0
354 %_ptr_PhysicalStorageBuffer_TestBuffer = OpTypePointer PhysicalStorageBuffer %TestBuffer
355 %int = OpTypeInt 32 1
356 %int_0 = OpConstant %int 0
357 %_ptr_PhysicalStorageBuffer_Test_0 = OpTypePointer PhysicalStorageBuffer %Test_0
358 %ulong_18446744073172680704 = OpConstant %ulong 18446744073172680704
359 ;CHECK: {{%\w+}} = OpConstantNull %Test_0
360 )";
361 
362   const std::string main_func = R"(
363 %main = OpFunction %void None %3
364 %5 = OpLabel
365 %37 = OpConvertUToPtr %_ptr_PhysicalStorageBuffer_TestBuffer %ulong_18446744073172680704
366 %38 = OpAccessChain %_ptr_PhysicalStorageBuffer_Test_0 %37 %int_0
367 %39 = OpLoad %Test_0 %38 Aligned 16
368 ;CHECK-NOT: %39 = OpLoad %Test_0 %38 Aligned 16
369 ;CHECK: {{%\w+}} = OpConvertPtrToU %ulong %38
370 ;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
371 ;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
372 ;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
373 ;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
374 ;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0
375 ;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_38 {{%\w+}} {{%\w+}} %uint_4
376 ;CHECK: OpSelectionMerge {{%\w+}} None
377 ;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
378 ;CHECK: {{%\w+}} = OpLabel
379 ;CHECK: {{%\w+}} = OpLoad %Test_0 %38 Aligned 16
380 ;CHECK: OpBranch {{%\w+}}
381 ;CHECK: {{%\w+}} = OpLabel
382 ;CHECK: OpBranch {{%\w+}}
383 ;CHECK: {{%\w+}} = OpLabel
384 ;CHECK: [[phi_result:%\w+]] = OpPhi %Test_0 {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}}
385 %40 = OpCopyLogical %Test %39
386 ;CHECK-NOT: %40 = OpCopyLogical %Test %39
387 ;CHECK: %40 = OpCopyLogical %Test [[phi_result]]
388 OpReturn
389 OpFunctionEnd
390 )";
391   // clang-format on
392 
393   SetTargetEnv(SPV_ENV_UNIVERSAL_1_4);
394   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
395   SinglePassRunAndMatch<InstBuffAddrCheckPass>(
396       defs + decorates + globals + kImportStub + main_func, true);
397 }
398 
399 TEST_F(InstBuffAddrTest, PaddedStructLoad) {
400   // #version 450
401   // #extension GL_EXT_buffer_reference : enable
402   // #extension GL_ARB_gpu_shader_int64 : enable
403   // struct Test {
404   //   uvec3 pad_1;  // Offset 0 Size 12
405   //   double pad_2; // Offset 16 Size 8 (alignment requirement)
406   //   float a;      // Offset 24 Size 4
407   // }; // Total Size 28
408   //
409   // layout(buffer_reference, std430, buffer_reference_align = 16) buffer
410   // TestBuffer { Test test; };
411   //
412   // Test GetTest(uint64_t ptr) {
413   //   return TestBuffer(ptr).test;
414   // }
415   //
416   // void main() {
417   //   GetTest(0xe0000000);
418   // }
419 
420   const std::string defs =
421       R"(
422 OpCapability Shader
423 OpCapability Float64
424 OpCapability Int64
425 OpCapability PhysicalStorageBufferAddresses
426 %1 = OpExtInstImport "GLSL.std.450"
427 OpMemoryModel PhysicalStorageBuffer64 GLSL450
428 OpEntryPoint Vertex %main "main"
429 OpSource GLSL 450
430 OpSourceExtension "GL_ARB_gpu_shader_int64"
431 OpSourceExtension "GL_EXT_buffer_reference"
432 OpName %main "main"
433 OpName %Test "Test"
434 OpMemberName %Test 0 "pad_1"
435 OpMemberName %Test 1 "pad_2"
436 OpMemberName %Test 2 "a"
437 OpName %GetTest_u641_ "GetTest(u641;"
438 OpName %ptr "ptr"
439 OpName %Test_0 "Test"
440 OpMemberName %Test_0 0 "pad_1"
441 OpMemberName %Test_0 1 "pad_2"
442 OpMemberName %Test_0 2 "a"
443 OpName %TestBuffer "TestBuffer"
444 OpMemberName %TestBuffer 0 "test"
445 OpName %param "param"
446 )";
447 
448   // clang-format off
449   const std::string decorates = R"(
450 OpDecorate %TestBuffer Block
451 OpMemberDecorate %Test_0 0 Offset 0
452 OpMemberDecorate %Test_0 1 Offset 16
453 OpMemberDecorate %Test_0 2 Offset 24
454 OpMemberDecorate %TestBuffer 0 Offset 0
455 )" + kImportDeco + R"(
456 ;CHECK: OpDecorate %gl_VertexIndex BuiltIn VertexIndex
457 ;CHECK: OpDecorate %gl_InstanceIndex BuiltIn InstanceIndex
458 )";
459 
460   const std::string globals = R"(
461 %void = OpTypeVoid
462 %3 = OpTypeFunction %void
463 %ulong = OpTypeInt 64 0
464 %_ptr_Function_ulong = OpTypePointer Function %ulong
465 %uint = OpTypeInt 32 0
466 %v3uint = OpTypeVector %uint 3
467 %double = OpTypeFloat 64
468 %float = OpTypeFloat 32
469 %Test = OpTypeStruct %v3uint %double %float
470 %13 = OpTypeFunction %Test %_ptr_Function_ulong
471 OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_TestBuffer PhysicalStorageBuffer
472 %Test_0 = OpTypeStruct %v3uint %double %float
473 %TestBuffer = OpTypeStruct %Test_0
474 %_ptr_PhysicalStorageBuffer_TestBuffer = OpTypePointer PhysicalStorageBuffer %TestBuffer
475 %int = OpTypeInt 32 1
476 %int_0 = OpConstant %int 0
477 %_ptr_PhysicalStorageBuffer_Test_0 = OpTypePointer PhysicalStorageBuffer %Test_0
478 %_ptr_Function_Test = OpTypePointer Function %Test
479 %ulong_18446744073172680704 = OpConstant %ulong 18446744073172680704
480 ;CHECK: {{%\w+}} = OpConstantNull %Test_0
481 )";
482 
483   const std::string main_func = R"(
484 %main = OpFunction %void None %3
485 %5 = OpLabel
486 %param = OpVariable %_ptr_Function_ulong Function
487 OpStore %param %ulong_18446744073172680704
488 %35 = OpFunctionCall %Test %GetTest_u641_ %param
489 OpReturn
490 OpFunctionEnd
491 %GetTest_u641_ = OpFunction %Test None %13
492 %ptr = OpFunctionParameter %_ptr_Function_ulong
493 %16 = OpLabel
494 %28 = OpVariable %_ptr_Function_Test Function
495 %17 = OpLoad %ulong %ptr
496 %21 = OpConvertUToPtr %_ptr_PhysicalStorageBuffer_TestBuffer %17
497 %25 = OpAccessChain %_ptr_PhysicalStorageBuffer_Test_0 %21 %int_0
498 %26 = OpLoad %Test_0 %25 Aligned 16
499 %29 = OpCopyLogical %Test %26
500 ;CHECK-NOT: %30 = OpLoad %Test %28
501 ;CHECK-NOT: %26 = OpLoad %Test_0 %25 Aligned 16
502 ;CHECK-NOT: %29 = OpCopyLogical %Test %26
503 ;CHECK: {{%\w+}} = OpConvertPtrToU %ulong %25
504 ;CHECK: {{%\w+}} = OpLoad %uint %gl_VertexIndex
505 ;CHECK: {{%\w+}} = OpLoad %uint %gl_InstanceIndex
506 ;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_0 {{%\w+}} {{%\w+}} %uint_0
507 ;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_63 {{%\w+}} {{%\w+}} %uint_28
508 ;CHECK: OpSelectionMerge {{%\w+}} None
509 ;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
510 ;CHECK: {{%\w+}} = OpLabel
511 ;CHECK: {{%\w+}} = OpLoad %Test_0 %25 Aligned 16
512 ;CHECK: OpBranch {{%\w+}}
513 ;CHECK: {{%\w+}} = OpLabel
514 ;CHECK: OpBranch {{%\w+}}
515 ;CHECK: {{%\w+}} = OpLabel
516 ;CHECK: [[phi_result:%\w+]] = OpPhi %Test_0 {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}}
517 ;CHECK: %29 = OpCopyLogical %Test [[phi_result]]
518 OpStore %28 %29
519 %30 = OpLoad %Test %28
520 OpReturnValue %30
521 OpFunctionEnd
522 )";
523   // clang-format on
524 
525   SetTargetEnv(SPV_ENV_UNIVERSAL_1_4);
526   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
527   SinglePassRunAndMatch<InstBuffAddrCheckPass>(
528       defs + decorates + globals + kImportStub + main_func, true);
529 }
530 
531 TEST_F(InstBuffAddrTest, DeviceBufferAddressOOB) {
532   // #version 450
533   // #extension GL_EXT_buffer_reference : enable
534   //  layout(buffer_reference, buffer_reference_align = 16) buffer bufStruct;
535   // layout(set = 0, binding = 0) uniform ufoo {
536   //     bufStruct data;
537   //     int nWrites;
538   // } u_info;
539   // layout(buffer_reference, std140) buffer bufStruct {
540   //     int a[4];
541   // };
542   // void main() {
543   //     for (int i=0; i < u_info.nWrites; ++i) {
544   //         u_info.data.a[i] = 0xdeadca71;
545   //     }
546   // }
547 
548   // clang-format off
549   const std::string text = R"(
550 OpCapability Shader
551 OpCapability PhysicalStorageBufferAddresses
552 %1 = OpExtInstImport "GLSL.std.450"
553 OpMemoryModel PhysicalStorageBuffer64 GLSL450
554 OpEntryPoint Vertex %main "main" %u_info
555 ;CHECK: OpEntryPoint Vertex %main "main" %u_info %gl_VertexIndex %gl_InstanceIndex
556 OpSource GLSL 450
557 OpSourceExtension "GL_EXT_buffer_reference"
558 OpName %main "main"
559 OpName %i "i"
560 OpName %ufoo "ufoo"
561 OpMemberName %ufoo 0 "data"
562 OpMemberName %ufoo 1 "nWrites"
563 OpName %bufStruct "bufStruct"
564 OpMemberName %bufStruct 0 "a"
565 OpName %u_info "u_info"
566 OpMemberDecorate %ufoo 0 Offset 0
567 OpMemberDecorate %ufoo 1 Offset 8
568 OpDecorate %ufoo Block
569 OpDecorate %_arr_int_uint_4 ArrayStride 16
570 OpMemberDecorate %bufStruct 0 Offset 0
571 OpDecorate %bufStruct Block
572 OpDecorate %u_info DescriptorSet 0
573 OpDecorate %u_info Binding 0
574 )" + kImportDeco + R"(
575 %void = OpTypeVoid
576 %3 = OpTypeFunction %void
577 %int = OpTypeInt 32 1
578 %_ptr_Function_int = OpTypePointer Function %int
579 %int_0 = OpConstant %int 0
580 OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_bufStruct PhysicalStorageBuffer
581 %ufoo = OpTypeStruct %_ptr_PhysicalStorageBuffer_bufStruct %int
582 %uint = OpTypeInt 32 0
583 %uint_4 = OpConstant %uint 4
584 %_arr_int_uint_4 = OpTypeArray %int %uint_4
585 %bufStruct = OpTypeStruct %_arr_int_uint_4
586 %_ptr_PhysicalStorageBuffer_bufStruct = OpTypePointer PhysicalStorageBuffer %bufStruct
587 %_ptr_Uniform_ufoo = OpTypePointer Uniform %ufoo
588 %u_info = OpVariable %_ptr_Uniform_ufoo Uniform
589 %int_1 = OpConstant %int 1
590 %_ptr_Uniform_int = OpTypePointer Uniform %int
591 %bool = OpTypeBool
592 %_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct = OpTypePointer Uniform %_ptr_PhysicalStorageBuffer_bufStruct
593 %int_n559035791 = OpConstant %int -559035791
594 %_ptr_PhysicalStorageBuffer_int = OpTypePointer PhysicalStorageBuffer %int
595 )" + kImportStub + R"(
596 %main = OpFunction %void None %3
597 %5 = OpLabel
598 %i = OpVariable %_ptr_Function_int Function
599 OpStore %i %int_0
600 OpBranch %10
601 %10 = OpLabel
602 OpLoopMerge %12 %13 None
603 OpBranch %14
604 %14 = OpLabel
605 %15 = OpLoad %int %i
606 %26 = OpAccessChain %_ptr_Uniform_int %u_info %int_1
607 %27 = OpLoad %int %26
608 %29 = OpSLessThan %bool %15 %27
609 OpBranchConditional %29 %11 %12
610 %11 = OpLabel
611 %31 = OpAccessChain %_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct %u_info %int_0
612 %32 = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %31
613 %33 = OpLoad %int %i
614 %36 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %32 %int_0 %33
615 OpStore %36 %int_n559035791 Aligned 16
616 ;CHECK: {{%\w+}} = OpConvertPtrToU %ulong %36
617 ;CHECK: {{%\w+}} = OpLoad %uint %gl_VertexIndex
618 ;CHECK: {{%\w+}} = OpLoad %uint %gl_InstanceIndex
619 ;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_0 {{%\w+}} {{%\w+}} %uint_0
620 ;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_63 {{%\w+}} {{%\w+}} %uint_4
621 ;CHECK: OpSelectionMerge {{%\w+}} None
622 ;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
623 ;CHECK: {{%\w+}} = OpLabel
624 ;CHECK: OpStore %36 %int_n559035791 Aligned 16
625 ;CHECK: OpBranch {{%\w+}}
626 ;CHECK: {{%\w+}} = OpLabel
627 ;CHECK: OpBranch {{%\w+}}
628 ;CHECK: {{%\w+}} = OpLabel
629 OpBranch %13
630 %13 = OpLabel
631 %37 = OpLoad %int %i
632 %38 = OpIAdd %int %37 %int_1
633 OpStore %i %38
634 OpBranch %10
635 %12 = OpLabel
636 OpReturn
637 OpFunctionEnd)";
638   // clang-format on
639 
640   SetTargetEnv(SPV_ENV_UNIVERSAL_1_4);
641   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
642   SinglePassRunAndMatch<InstBuffAddrCheckPass>(text, true, 23);
643 }
644 
645 TEST_F(InstBuffAddrTest, UVec3ScalarAddressOOB) {
646   // clang-format off
647   // #version 450
648   //    #extension GL_EXT_buffer_reference : enable
649   //    #extension GL_EXT_scalar_block_layout : enable
650   //    layout(buffer_reference, std430, scalar) readonly buffer IndexBuffer
651   //    {
652   //        uvec3 indices[];
653   //    };
654   //    layout(set = 0, binding = 0) uniform ufoo {
655   //        IndexBuffer data;
656   //        int nReads;
657   //    } u_info;
658   //    void main() {
659   //        uvec3 readvec;
660   //        for (int i=0; i < u_info.nReads; ++i) {
661   //            readvec = u_info.data.indices[i];
662   //        }
663   //    }
664   const std::string text = R"(
665 OpCapability Shader
666 OpCapability PhysicalStorageBufferAddresses
667 %1 = OpExtInstImport "GLSL.std.450"
668 OpMemoryModel PhysicalStorageBuffer64 GLSL450
669 OpEntryPoint Vertex %main "main" %u_info
670 OpSource GLSL 450
671 OpSourceExtension "GL_EXT_buffer_reference"
672 OpSourceExtension "GL_EXT_scalar_block_layout"
673 OpName %main "main"
674 OpName %i "i"
675 OpName %ufoo "ufoo"
676 OpMemberName %ufoo 0 "data"
677 OpMemberName %ufoo 1 "nReads"
678 OpName %IndexBuffer "IndexBuffer"
679 OpMemberName %IndexBuffer 0 "indices"
680 OpName %u_info "u_info"
681 OpName %readvec "readvec"
682 OpMemberDecorate %ufoo 0 Offset 0
683 OpMemberDecorate %ufoo 1 Offset 8
684 OpDecorate %ufoo Block
685 OpDecorate %_runtimearr_v3uint ArrayStride 12
686 OpMemberDecorate %IndexBuffer 0 NonWritable
687 OpMemberDecorate %IndexBuffer 0 Offset 0
688 OpDecorate %IndexBuffer Block
689 OpDecorate %u_info DescriptorSet 0
690 OpDecorate %u_info Binding 0
691 )" + kImportDeco + R"(
692 %void = OpTypeVoid
693 %3 = OpTypeFunction %void
694 %int = OpTypeInt 32 1
695 %_ptr_Function_int = OpTypePointer Function %int
696 %int_0 = OpConstant %int 0
697 OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_IndexBuffer PhysicalStorageBuffer
698 %ufoo = OpTypeStruct %_ptr_PhysicalStorageBuffer_IndexBuffer %int
699 %uint = OpTypeInt 32 0
700 %v3uint = OpTypeVector %uint 3
701 %_runtimearr_v3uint = OpTypeRuntimeArray %v3uint
702 %IndexBuffer = OpTypeStruct %_runtimearr_v3uint
703 %_ptr_PhysicalStorageBuffer_IndexBuffer = OpTypePointer PhysicalStorageBuffer %IndexBuffer
704 %_ptr_Uniform_ufoo = OpTypePointer Uniform %ufoo
705 %u_info = OpVariable %_ptr_Uniform_ufoo Uniform
706 %int_1 = OpConstant %int 1
707 %_ptr_Uniform_int = OpTypePointer Uniform %int
708 %bool = OpTypeBool
709 )" + kImportStub + R"(
710 %_ptr_Function_v3uint = OpTypePointer Function %v3uint
711 %_ptr_Uniform__ptr_PhysicalStorageBuffer_IndexBuffer = OpTypePointer Uniform %_ptr_PhysicalStorageBuffer_IndexBuffer
712 %_ptr_PhysicalStorageBuffer_v3uint = OpTypePointer PhysicalStorageBuffer %v3uint
713 %main = OpFunction %void None %3
714 %5 = OpLabel
715 %i = OpVariable %_ptr_Function_int Function
716 %readvec = OpVariable %_ptr_Function_v3uint Function
717 OpStore %i %int_0
718 OpBranch %10
719 %10 = OpLabel
720 OpLoopMerge %12 %13 None
721 OpBranch %14
722 %14 = OpLabel
723 %15 = OpLoad %int %i
724 %26 = OpAccessChain %_ptr_Uniform_int %u_info %int_1
725 %27 = OpLoad %int %26
726 %29 = OpSLessThan %bool %15 %27
727 OpBranchConditional %29 %11 %12
728 %11 = OpLabel
729 %33 = OpAccessChain %_ptr_Uniform__ptr_PhysicalStorageBuffer_IndexBuffer %u_info %int_0
730 %34 = OpLoad %_ptr_PhysicalStorageBuffer_IndexBuffer %33
731 %35 = OpLoad %int %i
732 %37 = OpAccessChain %_ptr_PhysicalStorageBuffer_v3uint %34 %int_0 %35
733 %38 = OpLoad %v3uint %37 Aligned 4
734 OpStore %readvec %38
735 ;CHECK-NOT: %38 = OpLoad %v3uint %37 Aligned 4
736 ;CHECK-NOT: OpStore %readvec %38
737 ;CHECK: {{%\w+}} = OpConvertPtrToU %ulong %37
738 ;CHECK: {{%\w+}} = OpLoad %uint %gl_VertexIndex
739 ;CHECK: {{%\w+}} = OpLoad %uint %gl_InstanceIndex
740 ;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_0 {{%\w+}} {{%\w+}} %uint_0
741 ;CHECK: [[test_result:%\w+]] = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_67 {{%\w+}} {{%\w+}} %uint_12
742 ;CHECK: OpSelectionMerge {{%\w+}} None
743 ;CHECK: OpBranchConditional [[test_result]] {{%\w+}} {{%\w+}}
744 ;CHECK: {{%\w+}} = OpLabel
745 ;CHECK: {{%\w+}} = OpLoad %v3uint %37 Aligned 4
746 ;CHECK: OpBranch {{%\w+}}
747 ;CHECK: {{%\w+}} = OpLabel
748 ;CHECK: OpBranch {{%\w+}}
749 ;CHECK: {{%\w+}} = OpLabel
750 ;CHECK: [[phi_result:%\w+]] = OpPhi %v3uint {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}}
751 ;CHECK: OpStore %readvec [[phi_result]]
752 OpBranch %13
753 %13 = OpLabel
754 %39 = OpLoad %int %i
755 %40 = OpIAdd %int %39 %int_1
756 OpStore %i %40
757 OpBranch %10
758 %12 = OpLabel
759 OpReturn
760 OpFunctionEnd
761 )";
762   // clang-format on
763 
764   SetTargetEnv(SPV_ENV_UNIVERSAL_1_4);
765   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
766   ValidatorOptions()->scalar_block_layout = true;
767   SinglePassRunAndMatch<InstBuffAddrCheckPass>(text, true, 23);
768 }
769 
770 }  // namespace
771 }  // namespace opt
772 }  // namespace spvtools
773