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/assembly_builder.h"
23 #include "test/opt/pass_fixture.h"
24 #include "test/opt/pass_utils.h"
25
26 namespace spvtools {
27 namespace opt {
28 namespace {
29
30 static const std::string kOutputDecorations = R"(
31 ; CHECK: OpDecorate [[output_buffer_type:%inst_buff_addr_OutputBuffer]] Block
32 ; CHECK: OpMemberDecorate [[output_buffer_type]] 0 Offset 0
33 ; CHECK: OpMemberDecorate [[output_buffer_type]] 1 Offset 4
34 ; CHECK: OpDecorate [[output_buffer_var:%\w+]] DescriptorSet 7
35 ; CHECK: OpDecorate [[output_buffer_var]] Binding 0
36 )";
37
38 static const std::string kOutputGlobals = R"(
39 ; CHECK: [[output_buffer_type]] = OpTypeStruct %uint %_runtimearr_uint
40 ; CHECK: [[output_ptr_type:%\w+]] = OpTypePointer StorageBuffer [[output_buffer_type]]
41 ; CHECK: [[output_buffer_var]] = OpVariable [[output_ptr_type]] StorageBuffer
42 )";
43
44 static const std::string kStreamWrite4Begin = R"(
45 ; CHECK: {{%\w+}} = OpFunction %void None {{%\w+}}
46 ; CHECK: [[param_1:%\w+]] = OpFunctionParameter %uint
47 ; CHECK: [[param_2:%\w+]] = OpFunctionParameter %uint
48 ; CHECK: [[param_3:%\w+]] = OpFunctionParameter %uint
49 ; CHECK: [[param_4:%\w+]] = OpFunctionParameter %uint
50 ; CHECK: {{%\w+}} = OpLabel
51 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_0
52 ; CHECK: {{%\w+}} = OpAtomicIAdd %uint {{%\w+}} %uint_4 %uint_0 %uint_10
53 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_10
54 ; CHECK: {{%\w+}} = OpArrayLength %uint [[output_buffer_var]] 1
55 ; CHECK: {{%\w+}} = OpULessThanEqual %bool {{%\w+}} {{%\w+}}
56 ; CHECK: OpSelectionMerge {{%\w+}} None
57 ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
58 ; CHECK: {{%\w+}} = OpLabel
59 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_0
60 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_1 {{%\w+}}
61 ; CHECK: OpStore {{%\w+}} %uint_10
62 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_1
63 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_1 {{%\w+}}
64 ; CHECK: OpStore {{%\w+}} %uint_23
65 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_2
66 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_1 {{%\w+}}
67 ; CHECK: OpStore {{%\w+}} [[param_1]]
68 )";
69
70 static const std::string kStreamWrite4End = R"(
71 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_7
72 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_1 {{%\w+}}
73 ; CHECK: OpStore {{%\w+}} [[param_2]]
74 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_8
75 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_1 {{%\w+}}
76 ; CHECK: OpStore {{%\w+}} [[param_3]]
77 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_9
78 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_1 {{%\w+}}
79 ; CHECK: OpStore {{%\w+}} [[param_4]]
80 ; CHECK: OpBranch {{%\w+}}
81 ; CHECK: {{%\w+}} = OpLabel
82 ; CHECK: OpReturn
83 ; CHECK: OpFunctionEnd
84 )";
85
86 // clang-format off
87 static const std::string kStreamWrite4Frag = kStreamWrite4Begin + R"(
88 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3
89 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_1 {{%\w+}}
90 ; CHECK: OpStore {{%\w+}} %uint_4
91 ; CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
92 ; CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
93 ; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
94 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_4
95 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_1 {{%\w+}}
96 ; CHECK: OpStore {{%\w+}} {{%\w+}}
97 ; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
98 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_5
99 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_1 {{%\w+}}
100 ; CHECK: OpStore {{%\w+}} {{%\w+}}
101 )" + kStreamWrite4End;
102
103 static const std::string kStreamWrite4Compute = kStreamWrite4Begin + R"(
104 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3
105 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_1 {{%\w+}}
106 ; CHECK: OpStore {{%\w+}} %uint_5
107 ; CHECK: {{%\w+}} = OpLoad %v3uint %gl_GlobalInvocationID
108 ; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
109 ; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
110 ; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2
111 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_4
112 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_1 {{%\w+}}
113 ; CHECK: OpStore {{%\w+}} {{%\w+}}
114 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_5
115 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_1 {{%\w+}}
116 ; CHECK: OpStore {{%\w+}} {{%\w+}}
117 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_6
118 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_1 {{%\w+}}
119 ; CHECK: OpStore {{%\w+}} {{%\w+}}
120 )" + kStreamWrite4End;
121 // clang-format on
122
123 static const std::string kInputDecorations = R"(
124 ; CHECK: OpDecorate [[input_buffer_type:%inst_buff_addr_InputBuffer]] Block
125 ; CHECK: OpMemberDecorate [[input_buffer_type]] 0 Offset 0
126 ; CHECK: OpDecorate [[input_buffer_var:%\w+]] DescriptorSet 7
127 ; CHECK: OpDecorate [[input_buffer_var]] Binding 2
128 )";
129
130 static const std::string kInputGlobals = R"(
131 ; CHECK: [[input_buffer_type]] = OpTypeStruct %_runtimearr_ulong
132 ; CHECK: [[input_ptr_type:%\w+]] = OpTypePointer StorageBuffer [[input_buffer_type]]
133 ; CHECK: [[input_buffer_var]] = OpVariable [[input_ptr_type]] StorageBuffer
134 )";
135
136 static const std::string kSearchAndTest = R"(
137 ; CHECK: {{%\w+}} = OpFunction %bool None {{%\w+}}
138 ; CHECK: [[param_1:%\w+]] = OpFunctionParameter %ulong
139 ; CHECK: [[param_2:%\w+]] = OpFunctionParameter %uint
140 ; CHECK: {{%\w+}} = OpLabel
141 ; CHECK: OpBranch {{%\w+}}
142 ; CHECK: {{%\w+}} = OpLabel
143 ; CHECK: {{%\w+}} = OpPhi %uint %uint_1 {{%\w+}} {{%\w+}} {{%\w+}}
144 ; CHECK: OpLoopMerge {{%\w+}} {{%\w+}} None
145 ; CHECK: OpBranch {{%\w+}}
146 ; CHECK: {{%\w+}} = OpLabel
147 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_1
148 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_ulong [[input_buffer_var]] %uint_0 {{%\w+}}
149 ; CHECK: {{%\w+}} = OpLoad %ulong {{%\w+}}
150 ; CHECK: {{%\w+}} = OpUGreaterThan %bool {{%\w+}} [[param_1]]
151 ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
152 ; CHECK: {{%\w+}} = OpLabel
153 ; CHECK: {{%\w+}} = OpISub %uint {{%\w+}} %uint_1
154 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_ulong [[input_buffer_var]] %uint_0 {{%\w+}}
155 ; CHECK: {{%\w+}} = OpLoad %ulong {{%\w+}}
156 ; CHECK: {{%\w+}} = OpISub %ulong [[param_1]] {{%\w+}}
157 ; CHECK: {{%\w+}} = OpUConvert %ulong [[param_2]]
158 ; CHECK: {{%\w+}} = OpIAdd %ulong {{%\w+}} {{%\w+}}
159 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_ulong [[input_buffer_var]] %uint_0 %uint_0
160 ; CHECK: {{%\w+}} = OpLoad %ulong {{%\w+}}
161 ; CHECK: {{%\w+}} = OpUConvert %uint {{%\w+}}
162 ; CHECK: {{%\w+}} = OpISub %uint {{%\w+}} %uint_1
163 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} {{%\w+}}
164 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_ulong [[input_buffer_var]] %uint_0 {{%\w+}}
165 ; CHECK: {{%\w+}} = OpLoad %ulong {{%\w+}}
166 ; CHECK: {{%\w+}} = OpULessThanEqual %bool {{%\w+}} {{%\w+}}
167 ; CHECK: OpReturnValue {{%\w+}}
168 ; CHECK: OpFunctionEnd
169 )";
170 // clang-format on
171
172 using InstBuffAddrTest = PassTest<::testing::Test>;
173
TEST_F(InstBuffAddrTest,InstPhysicalStorageBufferStore)174 TEST_F(InstBuffAddrTest, InstPhysicalStorageBufferStore) {
175 // #version 450
176 // #extension GL_EXT_buffer_reference : enable
177 //
178 // layout(buffer_reference, buffer_reference_align = 16) buffer bufStruct;
179 //
180 // layout(set = 0, binding = 0) uniform ufoo {
181 // bufStruct data;
182 // uint offset;
183 // } u_info;
184 //
185 // layout(buffer_reference, std140) buffer bufStruct {
186 // layout(offset = 0) int a[2];
187 // layout(offset = 32) int b;
188 // };
189 //
190 // void main() {
191 // u_info.data.b = 0xca7;
192 // }
193
194 const std::string defs = R"(
195 OpCapability Shader
196 OpCapability PhysicalStorageBufferAddresses
197 ; CHECK: OpCapability Int64
198 OpExtension "SPV_EXT_physical_storage_buffer"
199 ; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class"
200 %1 = OpExtInstImport "GLSL.std.450"
201 OpMemoryModel PhysicalStorageBuffer64 GLSL450
202 OpEntryPoint GLCompute %main "main"
203 ; CHECK: OpEntryPoint GLCompute %main "main" %gl_GlobalInvocationID
204 OpExecutionMode %main LocalSize 1 1 1
205 OpSource GLSL 450
206 OpSourceExtension "GL_EXT_buffer_reference"
207 OpName %main "main"
208 OpName %ufoo "ufoo"
209 OpMemberName %ufoo 0 "data"
210 OpMemberName %ufoo 1 "offset"
211 OpName %bufStruct "bufStruct"
212 OpMemberName %bufStruct 0 "a"
213 OpMemberName %bufStruct 1 "b"
214 OpName %u_info "u_info"
215 )";
216
217 // clang-format off
218 const std::string decorates = R"(
219 OpMemberDecorate %ufoo 0 Offset 0
220 OpMemberDecorate %ufoo 1 Offset 8
221 OpDecorate %ufoo Block
222 OpDecorate %_arr_int_uint_2 ArrayStride 16
223 OpMemberDecorate %bufStruct 0 Offset 0
224 OpMemberDecorate %bufStruct 1 Offset 32
225 OpDecorate %bufStruct Block
226 OpDecorate %u_info DescriptorSet 0
227 OpDecorate %u_info Binding 0
228 ; CHECK: OpDecorate %_runtimearr_ulong ArrayStride 8
229 )" + kInputDecorations + R"(
230 ; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4
231 )" + kOutputDecorations + R"(
232 ; CHECK: OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId
233 )";
234
235 const std::string globals = R"(
236 %void = OpTypeVoid
237 %3 = OpTypeFunction %void
238 OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_bufStruct PhysicalStorageBuffer
239 %uint = OpTypeInt 32 0
240 %ufoo = OpTypeStruct %_ptr_PhysicalStorageBuffer_bufStruct %uint
241 %int = OpTypeInt 32 1
242 %uint_2 = OpConstant %uint 2
243 %_arr_int_uint_2 = OpTypeArray %int %uint_2
244 %bufStruct = OpTypeStruct %_arr_int_uint_2 %int
245 %_ptr_PhysicalStorageBuffer_bufStruct = OpTypePointer PhysicalStorageBuffer %bufStruct
246 %_ptr_Uniform_ufoo = OpTypePointer Uniform %ufoo
247 %u_info = OpVariable %_ptr_Uniform_ufoo Uniform
248 %int_0 = OpConstant %int 0
249 %_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct = OpTypePointer Uniform %_ptr_PhysicalStorageBuffer_bufStruct
250 %int_1 = OpConstant %int 1
251 %int_3239 = OpConstant %int 3239
252 %_ptr_PhysicalStorageBuffer_int = OpTypePointer PhysicalStorageBuffer %int
253 ; CHECK: %ulong = OpTypeInt 64 0
254 ; CHECK: %uint_4 = OpConstant %uint 4
255 ; CHECK: %bool = OpTypeBool
256 ; CHECK: %28 = OpTypeFunction %bool %ulong %uint
257 ; CHECK: %uint_1 = OpConstant %uint 1
258 ; CHECK: %_runtimearr_ulong = OpTypeRuntimeArray %ulong
259 )" + kInputGlobals + R"(
260 ; CHECK: %_ptr_StorageBuffer_ulong = OpTypePointer StorageBuffer %ulong
261 ; CHECK: %uint_0 = OpConstant %uint 0
262 ; CHECK: %uint_32 = OpConstant %uint 32
263 ; CHECK: %70 = OpTypeFunction %void %uint %uint %uint %uint
264 ; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint
265 )" + kOutputGlobals + R"(
266 ; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
267 ; CHECK: %uint_10 = OpConstant %uint 10
268 ; CHECK: %uint_23 = OpConstant %uint 23
269 ; CHECK: %uint_5 = OpConstant %uint 5
270 ; CHECK: %uint_3 = OpConstant %uint 3
271 ; CHECK: %v3uint = OpTypeVector %uint 3
272 ; CHECK: %_ptr_Input_v3uint = OpTypePointer Input %v3uint
273 ; CHECK: %gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input
274 ; CHECK: %uint_6 = OpConstant %uint 6
275 ; CHECK: %uint_7 = OpConstant %uint 7
276 ; CHECK: %uint_8 = OpConstant %uint 8
277 ; CHECK: %uint_9 = OpConstant %uint 9
278 ; CHECK: %uint_48 = OpConstant %uint 48
279 )";
280 // clang-format off
281
282 const std::string main_func = R"(
283 %main = OpFunction %void None %3
284 %5 = OpLabel
285 %17 = OpAccessChain %_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct %u_info %int_0
286 %18 = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %17
287 %22 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %18 %int_1
288 ; CHECK-NOT: %17 = OpAccessChain %_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct %u_info %int_0
289 ; CHECK-NOT: %18 = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %17
290 ; CHECK-NOT: %22 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %18 %int_1
291 ; CHECK: %20 = OpAccessChain %_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct %u_info %int_0
292 ; CHECK: %21 = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %20
293 ; CHECK: %22 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %21 %int_1
294 ; CHECK: %24 = OpConvertPtrToU %ulong %22
295 ; CHECK: %61 = OpFunctionCall %bool %inst_buff_addr_search_and_test %24 %uint_4
296 ; CHECK: OpSelectionMerge %62 None
297 ; CHECK: OpBranchConditional %61 %63 %64
298 ; CHECK: %63 = OpLabel
299 OpStore %22 %int_3239 Aligned 16
300 ; CHECK: OpStore %22 %int_3239 Aligned 16
301 ; CHECK: OpBranch %62
302 ; CHECK: %64 = OpLabel
303 ; CHECK: %65 = OpUConvert %uint %24
304 ; CHECK: %67 = OpShiftRightLogical %ulong %24 %uint_32
305 ; CHECK: %68 = OpUConvert %uint %67
306 ; CHECK: %124 = OpFunctionCall %void %inst_buff_addr_stream_write_4 %uint_48 %uint_2 %65 %68
307 ; CHECK: OpBranch %62
308 ; CHECK: %62 = OpLabel
309 OpReturn
310 OpFunctionEnd
311 )";
312
313 const std::string output_funcs = kSearchAndTest + kStreamWrite4Compute;
314
315 // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
316 SinglePassRunAndMatch<InstBuffAddrCheckPass>(
317 defs + decorates + globals + main_func + output_funcs, true, 7u, 23u);
318 }
319
TEST_F(InstBuffAddrTest,InstPhysicalStorageBufferLoadAndStore)320 TEST_F(InstBuffAddrTest, InstPhysicalStorageBufferLoadAndStore) {
321 // #version 450
322 // #extension GL_EXT_buffer_reference : enable
323
324 // // forward reference
325 // layout(buffer_reference) buffer blockType;
326
327 // layout(buffer_reference, std430, buffer_reference_align = 16) buffer
328 // blockType {
329 // int x;
330 // blockType next;
331 // };
332
333 // layout(std430) buffer rootBlock {
334 // blockType root;
335 // } r;
336
337 // void main()
338 // {
339 // blockType b = r.root;
340 // b = b.next;
341 // b.x = 531;
342 // }
343
344 const std::string defs = R"(
345 OpCapability Shader
346 OpCapability PhysicalStorageBufferAddresses
347 ; CHECK: OpCapability Int64
348 OpExtension "SPV_EXT_physical_storage_buffer"
349 OpExtension "SPV_KHR_storage_buffer_storage_class"
350 %1 = OpExtInstImport "GLSL.std.450"
351 OpMemoryModel PhysicalStorageBuffer64 GLSL450
352 OpEntryPoint GLCompute %main "main"
353 OpExecutionMode %main LocalSize 1 1 1
354 OpSource GLSL 450
355 OpSourceExtension "GL_EXT_buffer_reference"
356 OpName %main "main"
357 ; CHECK: OpEntryPoint GLCompute %main "main" %gl_GlobalInvocationID
358 OpName %blockType "blockType"
359 OpMemberName %blockType 0 "x"
360 OpMemberName %blockType 1 "next"
361 OpName %rootBlock "rootBlock"
362 OpMemberName %rootBlock 0 "root"
363 OpName %r "r"
364 )";
365
366 // clang-format off
367 const std::string decorates = R"(
368 OpMemberDecorate %blockType 0 Offset 0
369 OpMemberDecorate %blockType 1 Offset 8
370 OpDecorate %blockType Block
371 OpMemberDecorate %rootBlock 0 Offset 0
372 OpDecorate %rootBlock Block
373 OpDecorate %r DescriptorSet 0
374 OpDecorate %r Binding 0
375 ; CHECK: OpDecorate %_runtimearr_ulong ArrayStride 8
376 )" + kInputDecorations + R"(
377 ; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4
378 )" + kOutputDecorations + R"(
379 ; CHECK: OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId
380 )";
381 // clang-format on
382
383 const std::string globals = R"(
384 %void = OpTypeVoid
385 %3 = OpTypeFunction %void
386 OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_blockType PhysicalStorageBuffer
387 %int = OpTypeInt 32 1
388 %blockType = OpTypeStruct %int %_ptr_PhysicalStorageBuffer_blockType
389 %_ptr_PhysicalStorageBuffer_blockType = OpTypePointer PhysicalStorageBuffer %blockType
390 %rootBlock = OpTypeStruct %_ptr_PhysicalStorageBuffer_blockType
391 %_ptr_StorageBuffer_rootBlock = OpTypePointer StorageBuffer %rootBlock
392 %r = OpVariable %_ptr_StorageBuffer_rootBlock StorageBuffer
393 %int_0 = OpConstant %int 0
394 %_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_blockType = OpTypePointer StorageBuffer %_ptr_PhysicalStorageBuffer_blockType
395 %int_1 = OpConstant %int 1
396 %_ptr_PhysicalStorageBuffer__ptr_PhysicalStorageBuffer_blockType = OpTypePointer PhysicalStorageBuffer %_ptr_PhysicalStorageBuffer_blockType
397 %int_531 = OpConstant %int 531
398 %_ptr_PhysicalStorageBuffer_int = OpTypePointer PhysicalStorageBuffer %int
399 )" + kInputGlobals + kOutputGlobals;
400
401 const std::string main_func = R"(
402 %main = OpFunction %void None %3
403 %5 = OpLabel
404 %16 = OpAccessChain %_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_blockType %r %int_0
405 %17 = OpLoad %_ptr_PhysicalStorageBuffer_blockType %16
406 %21 = OpAccessChain %_ptr_PhysicalStorageBuffer__ptr_PhysicalStorageBuffer_blockType %17 %int_1
407 %22 = OpLoad %_ptr_PhysicalStorageBuffer_blockType %21 Aligned 8
408 %26 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %22 %int_0
409 OpStore %26 %int_531 Aligned 16
410 ; CHECK-NOT: %22 = OpLoad %_ptr_PhysicalStorageBuffer_blockType %21 Aligned 8
411 ; CHECK-NOT: %26 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %22 %int_0
412 ; CHECK: %30 = OpConvertPtrToU %ulong %21
413 ; CHECK: %67 = OpFunctionCall %bool %inst_buff_addr_search_and_test %30 %uint_8
414 ; CHECK: OpSelectionMerge %68 None
415 ; CHECK: OpBranchConditional %67 %69 %70
416 ; CHECK: %69 = OpLabel
417 ; CHECK: %71 = OpLoad %_ptr_PhysicalStorageBuffer_blockType %21 Aligned 8
418 ; CHECK: OpBranch %68
419 ; CHECK: %70 = OpLabel
420 ; CHECK: %72 = OpUConvert %uint %30
421 ; CHECK: %74 = OpShiftRightLogical %ulong %30 %uint_32
422 ; CHECK: %75 = OpUConvert %uint %74
423 ; CHECK: %131 = OpFunctionCall %void %inst_buff_addr_stream_write_4 %uint_44 %uint_2 %72 %75
424 ; CHECK: %133 = OpConvertUToPtr %_ptr_PhysicalStorageBuffer_blockType %132
425 ; CHECK: OpBranch %68
426 ; CHECK: %68 = OpLabel
427 ; CHECK: %134 = OpPhi %_ptr_PhysicalStorageBuffer_blockType %71 %69 %133 %70
428 ; CHECK: %26 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %134 %int_0
429 ; CHECK: %135 = OpConvertPtrToU %ulong %26
430 ; CHECK: %136 = OpFunctionCall %bool %inst_buff_addr_search_and_test %135 %uint_4
431 ; CHECK: OpSelectionMerge %137 None
432 ; CHECK: OpBranchConditional %136 %138 %139
433 ; CHECK: %138 = OpLabel
434 ; CHECK: OpStore %26 %int_531 Aligned 16
435 ; CHECK: OpBranch %137
436 ; CHECK: %139 = OpLabel
437 ; CHECK: %140 = OpUConvert %uint %135
438 ; CHECK: %141 = OpShiftRightLogical %ulong %135 %uint_32
439 ; CHECK: %142 = OpUConvert %uint %141
440 ; CHECK: %144 = OpFunctionCall %void %inst_buff_addr_stream_write_4 %uint_46 %uint_2 %140 %142
441 ; CHECK: OpBranch %137
442 ; CHECK: %137 = OpLabel
443 OpReturn
444 OpFunctionEnd
445 )";
446
447 const std::string output_funcs = kSearchAndTest + kStreamWrite4Compute;
448
449 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
450 SinglePassRunAndMatch<InstBuffAddrCheckPass>(
451 defs + decorates + globals + main_func + output_funcs, true, 7u, 23u);
452 }
453
TEST_F(InstBuffAddrTest,StructLoad)454 TEST_F(InstBuffAddrTest, StructLoad) {
455 // #version 450
456 // #extension GL_EXT_buffer_reference : enable
457 // #extension GL_ARB_gpu_shader_int64 : enable
458 // struct Test {
459 // float a;
460 // };
461 //
462 // layout(buffer_reference, std430, buffer_reference_align = 16) buffer
463 // TestBuffer { Test test; };
464 //
465 // Test GetTest(uint64_t ptr) {
466 // return TestBuffer(ptr).test;
467 // }
468 //
469 // void main() {
470 // GetTest(0xe0000000);
471 // }
472
473 const std::string defs =
474 R"(
475 OpCapability Shader
476 OpCapability Int64
477 OpCapability PhysicalStorageBufferAddresses
478 ; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class"
479 %1 = OpExtInstImport "GLSL.std.450"
480 OpMemoryModel PhysicalStorageBuffer64 GLSL450
481 OpEntryPoint Fragment %main "main"
482 ; CHECK: OpEntryPoint Fragment %main "main" %inst_buff_addr_input_buffer %inst_buff_addr_output_buffer %gl_FragCoord
483 OpExecutionMode %main OriginUpperLeft
484 OpSource GLSL 450
485 OpSourceExtension "GL_ARB_gpu_shader_int64"
486 OpSourceExtension "GL_EXT_buffer_reference"
487 OpName %main "main"
488 OpName %Test "Test"
489 OpMemberName %Test 0 "a"
490 OpName %Test_0 "Test"
491 OpMemberName %Test_0 0 "a"
492 OpName %TestBuffer "TestBuffer"
493 OpMemberName %TestBuffer 0 "test"
494 )";
495
496 // clang-format off
497 const std::string decorates = R"(
498 OpMemberDecorate %Test_0 0 Offset 0
499 OpMemberDecorate %TestBuffer 0 Offset 0
500 OpDecorate %TestBuffer Block
501 ; CHECK: OpDecorate %_runtimearr_ulong ArrayStride 8
502 )" + kInputDecorations + R"(
503 ; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4
504 )" + kOutputDecorations + R"(
505 ; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
506 )";
507
508 const std::string globals = R"(
509 %void = OpTypeVoid
510 %3 = OpTypeFunction %void
511 %ulong = OpTypeInt 64 0
512 %float = OpTypeFloat 32
513 %Test = OpTypeStruct %float
514 OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_TestBuffer PhysicalStorageBuffer
515 %Test_0 = OpTypeStruct %float
516 %TestBuffer = OpTypeStruct %Test_0
517 %_ptr_PhysicalStorageBuffer_TestBuffer = OpTypePointer PhysicalStorageBuffer %TestBuffer
518 %int = OpTypeInt 32 1
519 %int_0 = OpConstant %int 0
520 %_ptr_PhysicalStorageBuffer_Test_0 = OpTypePointer PhysicalStorageBuffer %Test_0
521 %ulong_18446744073172680704 = OpConstant %ulong 18446744073172680704
522 ; CHECK: %47 = OpTypeFunction %bool %ulong %uint
523 )" + kInputGlobals + R"(
524 ; CHECK: %90 = OpTypeFunction %void %uint %uint %uint %uint
525 )" + kOutputGlobals + R"(
526 ; CHECK: %143 = OpConstantNull %Test_0
527 )";
528 // clang-format on
529
530 const std::string main_func =
531 R"(
532 %main = OpFunction %void None %3
533 %5 = OpLabel
534 %37 = OpConvertUToPtr %_ptr_PhysicalStorageBuffer_TestBuffer %ulong_18446744073172680704
535 %38 = OpAccessChain %_ptr_PhysicalStorageBuffer_Test_0 %37 %int_0
536 %39 = OpLoad %Test_0 %38 Aligned 16
537 ; CHECK-NOT: %39 = OpLoad %Test_0 %38 Aligned 16
538 ; CHECK: %43 = OpConvertPtrToU %ulong %38
539 ; CHECK: %80 = OpFunctionCall %bool %inst_buff_addr_search_and_test %43 %uint_4
540 ; CHECK: OpSelectionMerge %81 None
541 ; CHECK: OpBranchConditional %80 %82 %83
542 ; CHECK: %82 = OpLabel
543 ; CHECK: %84 = OpLoad %Test_0 %38 Aligned 16
544 ; CHECK: OpBranch %81
545 ; CHECK: %83 = OpLabel
546 ; CHECK: %85 = OpUConvert %uint %43
547 ; CHECK: %87 = OpShiftRightLogical %ulong %43 %uint_32
548 ; CHECK: %88 = OpUConvert %uint %87
549 ; CHECK: %142 = OpFunctionCall %void %inst_buff_addr_stream_write_4 %uint_37 %uint_2 %85 %88
550 ; CHECK: OpBranch %81
551 ; CHECK: %81 = OpLabel
552 ; CHECK: %144 = OpPhi %Test_0 %84 %82 %143 %83
553 %40 = OpCopyLogical %Test %39
554 ; CHECK-NOT: %40 = OpCopyLogical %Test %39
555 ; CHECK: %40 = OpCopyLogical %Test %144
556 OpReturn
557 OpFunctionEnd
558 )";
559
560 const std::string output_funcs = kSearchAndTest + kStreamWrite4Frag;
561
562 SetTargetEnv(SPV_ENV_VULKAN_1_2);
563 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
564 SinglePassRunAndMatch<InstBuffAddrCheckPass>(
565 defs + decorates + globals + main_func + output_funcs, true);
566 }
567
568 } // namespace
569 } // namespace opt
570 } // namespace spvtools
571