1 // Copyright (c) 2019 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <string>
16
17 #include "gmock/gmock.h"
18 #include "test/opt/assembly_builder.h"
19 #include "test/opt/pass_fixture.h"
20 #include "test/opt/pass_utils.h"
21
22 namespace spvtools {
23 namespace opt {
24 namespace {
25
26 using FixStorageClassTest = PassTest<::testing::Test>;
27
TEST_F(FixStorageClassTest,FixAccessChain)28 TEST_F(FixStorageClassTest, FixAccessChain) {
29 const std::string text = R"(
30 ; CHECK: OpAccessChain %_ptr_Workgroup_float
31 ; CHECK: OpAccessChain %_ptr_Uniform_float
32 OpCapability Shader
33 OpMemoryModel Logical GLSL450
34 OpEntryPoint GLCompute %1 "testMain" %gl_GlobalInvocationID %gl_LocalInvocationID %gl_WorkGroupID
35 OpExecutionMode %1 LocalSize 8 8 1
36 OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId
37 OpDecorate %gl_LocalInvocationID BuiltIn LocalInvocationId
38 OpDecorate %gl_WorkGroupID BuiltIn WorkgroupId
39 OpDecorate %8 DescriptorSet 0
40 OpDecorate %8 Binding 0
41 OpDecorate %_runtimearr_float ArrayStride 4
42 OpMemberDecorate %_struct_7 0 Offset 0
43 OpDecorate %_struct_7 BufferBlock
44 %int = OpTypeInt 32 1
45 %int_0 = OpConstant %int 0
46 %float = OpTypeFloat 32
47 %float_2 = OpConstant %float 2
48 %uint = OpTypeInt 32 0
49 %uint_10 = OpConstant %uint 10
50 %_arr_float_uint_10 = OpTypeArray %float %uint_10
51 %ptr = OpTypePointer Function %_arr_float_uint_10
52 %_arr__arr_float_uint_10_uint_10 = OpTypeArray %_arr_float_uint_10 %uint_10
53 %_struct_5 = OpTypeStruct %_arr__arr_float_uint_10_uint_10
54 %_ptr_Workgroup__struct_5 = OpTypePointer Workgroup %_struct_5
55 %_runtimearr_float = OpTypeRuntimeArray %float
56 %_struct_7 = OpTypeStruct %_runtimearr_float
57 %_ptr_Uniform__struct_7 = OpTypePointer Uniform %_struct_7
58 %v3uint = OpTypeVector %uint 3
59 %_ptr_Input_v3uint = OpTypePointer Input %v3uint
60 %void = OpTypeVoid
61 %30 = OpTypeFunction %void
62 %_ptr_Function_float = OpTypePointer Function %float
63 %_ptr_Uniform_float = OpTypePointer Uniform %float
64 %6 = OpVariable %_ptr_Workgroup__struct_5 Workgroup
65 %8 = OpVariable %_ptr_Uniform__struct_7 Uniform
66 %gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input
67 %gl_LocalInvocationID = OpVariable %_ptr_Input_v3uint Input
68 %gl_WorkGroupID = OpVariable %_ptr_Input_v3uint Input
69 %1 = OpFunction %void None %30
70 %38 = OpLabel
71 %44 = OpLoad %v3uint %gl_LocalInvocationID
72 %50 = OpAccessChain %_ptr_Function_float %6 %int_0 %int_0 %int_0
73 %51 = OpLoad %float %50
74 %52 = OpFMul %float %float_2 %51
75 OpStore %50 %52
76 %55 = OpLoad %float %50
77 %59 = OpCompositeExtract %uint %44 0
78 %60 = OpAccessChain %_ptr_Uniform_float %8 %int_0 %59
79 OpStore %60 %55
80 OpReturn
81 OpFunctionEnd
82 )";
83
84 SinglePassRunAndMatch<FixStorageClass>(text, false);
85 }
86
TEST_F(FixStorageClassTest,FixLinkedAccessChain)87 TEST_F(FixStorageClassTest, FixLinkedAccessChain) {
88 const std::string text = R"(
89 ; CHECK: OpAccessChain %_ptr_Workgroup__arr_float_uint_10
90 ; CHECK: OpAccessChain %_ptr_Workgroup_float
91 ; CHECK: OpAccessChain %_ptr_Uniform_float
92 OpCapability Shader
93 OpMemoryModel Logical GLSL450
94 OpEntryPoint GLCompute %1 "testMain" %gl_GlobalInvocationID %gl_LocalInvocationID %gl_WorkGroupID
95 OpExecutionMode %1 LocalSize 8 8 1
96 OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId
97 OpDecorate %gl_LocalInvocationID BuiltIn LocalInvocationId
98 OpDecorate %gl_WorkGroupID BuiltIn WorkgroupId
99 OpDecorate %5 DescriptorSet 0
100 OpDecorate %5 Binding 0
101 OpDecorate %_runtimearr_float ArrayStride 4
102 OpMemberDecorate %_struct_7 0 Offset 0
103 OpDecorate %_struct_7 BufferBlock
104 %int = OpTypeInt 32 1
105 %int_0 = OpConstant %int 0
106 %float = OpTypeFloat 32
107 %float_2 = OpConstant %float 2
108 %uint = OpTypeInt 32 0
109 %uint_10 = OpConstant %uint 10
110 %_arr_float_uint_10 = OpTypeArray %float %uint_10
111 %_ptr_Function__arr_float_uint_10 = OpTypePointer Function %_arr_float_uint_10
112 %_ptr = OpTypePointer Function %_arr_float_uint_10
113 %_arr__arr_float_uint_10_uint_10 = OpTypeArray %_arr_float_uint_10 %uint_10
114 %_struct_17 = OpTypeStruct %_arr__arr_float_uint_10_uint_10
115 %_ptr_Workgroup__struct_17 = OpTypePointer Workgroup %_struct_17
116 %_runtimearr_float = OpTypeRuntimeArray %float
117 %_struct_7 = OpTypeStruct %_runtimearr_float
118 %_ptr_Uniform__struct_7 = OpTypePointer Uniform %_struct_7
119 %v3uint = OpTypeVector %uint 3
120 %_ptr_Input_v3uint = OpTypePointer Input %v3uint
121 %void = OpTypeVoid
122 %23 = OpTypeFunction %void
123 %_ptr_Function_float = OpTypePointer Function %float
124 %_ptr_Uniform_float = OpTypePointer Uniform %float
125 %27 = OpVariable %_ptr_Workgroup__struct_17 Workgroup
126 %5 = OpVariable %_ptr_Uniform__struct_7 Uniform
127 %gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input
128 %gl_LocalInvocationID = OpVariable %_ptr_Input_v3uint Input
129 %gl_WorkGroupID = OpVariable %_ptr_Input_v3uint Input
130 %1 = OpFunction %void None %23
131 %28 = OpLabel
132 %29 = OpLoad %v3uint %gl_LocalInvocationID
133 %30 = OpAccessChain %_ptr_Function__arr_float_uint_10 %27 %int_0 %int_0
134 %31 = OpAccessChain %_ptr_Function_float %30 %int_0
135 %32 = OpLoad %float %31
136 %33 = OpFMul %float %float_2 %32
137 OpStore %31 %33
138 %34 = OpLoad %float %31
139 %35 = OpCompositeExtract %uint %29 0
140 %36 = OpAccessChain %_ptr_Uniform_float %5 %int_0 %35
141 OpStore %36 %34
142 OpReturn
143 OpFunctionEnd
144 )";
145
146 SinglePassRunAndMatch<FixStorageClass>(text, false);
147 }
148
TEST_F(FixStorageClassTest,FixCopyObject)149 TEST_F(FixStorageClassTest, FixCopyObject) {
150 const std::string text = R"(
151 ; CHECK: OpCopyObject %_ptr_Workgroup__struct_17
152 ; CHECK: OpAccessChain %_ptr_Workgroup_float
153 ; CHECK: OpAccessChain %_ptr_Uniform_float
154 OpCapability Shader
155 OpMemoryModel Logical GLSL450
156 OpEntryPoint GLCompute %1 "testMain" %gl_GlobalInvocationID %gl_LocalInvocationID %gl_WorkGroupID
157 OpExecutionMode %1 LocalSize 8 8 1
158 OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId
159 OpDecorate %gl_LocalInvocationID BuiltIn LocalInvocationId
160 OpDecorate %gl_WorkGroupID BuiltIn WorkgroupId
161 OpDecorate %8 DescriptorSet 0
162 OpDecorate %8 Binding 0
163 OpDecorate %_runtimearr_float ArrayStride 4
164 OpMemberDecorate %_struct_7 0 Offset 0
165 OpDecorate %_struct_7 BufferBlock
166 %int = OpTypeInt 32 1
167 %int_0 = OpConstant %int 0
168 %float = OpTypeFloat 32
169 %float_2 = OpConstant %float 2
170 %uint = OpTypeInt 32 0
171 %uint_10 = OpConstant %uint 10
172 %_arr_float_uint_10 = OpTypeArray %float %uint_10
173 %ptr = OpTypePointer Function %_arr_float_uint_10
174 %_arr__arr_float_uint_10_uint_10 = OpTypeArray %_arr_float_uint_10 %uint_10
175 %_struct_17 = OpTypeStruct %_arr__arr_float_uint_10_uint_10
176 %_ptr_Workgroup__struct_17 = OpTypePointer Workgroup %_struct_17
177 %_ptr_Function__struct_17 = OpTypePointer Function %_struct_17
178 %_runtimearr_float = OpTypeRuntimeArray %float
179 %_struct_7 = OpTypeStruct %_runtimearr_float
180 %_ptr_Uniform__struct_7 = OpTypePointer Uniform %_struct_7
181 %v3uint = OpTypeVector %uint 3
182 %_ptr_Input_v3uint = OpTypePointer Input %v3uint
183 %void = OpTypeVoid
184 %30 = OpTypeFunction %void
185 %_ptr_Function_float = OpTypePointer Function %float
186 %_ptr_Uniform_float = OpTypePointer Uniform %float
187 %6 = OpVariable %_ptr_Workgroup__struct_17 Workgroup
188 %8 = OpVariable %_ptr_Uniform__struct_7 Uniform
189 %gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input
190 %gl_LocalInvocationID = OpVariable %_ptr_Input_v3uint Input
191 %gl_WorkGroupID = OpVariable %_ptr_Input_v3uint Input
192 %1 = OpFunction %void None %30
193 %38 = OpLabel
194 %44 = OpLoad %v3uint %gl_LocalInvocationID
195 %cp = OpCopyObject %_ptr_Function__struct_17 %6
196 %50 = OpAccessChain %_ptr_Function_float %cp %int_0 %int_0 %int_0
197 %51 = OpLoad %float %50
198 %52 = OpFMul %float %float_2 %51
199 OpStore %50 %52
200 %55 = OpLoad %float %50
201 %59 = OpCompositeExtract %uint %44 0
202 %60 = OpAccessChain %_ptr_Uniform_float %8 %int_0 %59
203 OpStore %60 %55
204 OpReturn
205 OpFunctionEnd
206 )";
207
208 SinglePassRunAndMatch<FixStorageClass>(text, false);
209 }
210
TEST_F(FixStorageClassTest,FixPhiInSelMerge)211 TEST_F(FixStorageClassTest, FixPhiInSelMerge) {
212 const std::string text = R"(
213 ; CHECK: OpPhi %_ptr_Workgroup__struct_19
214 ; CHECK: OpAccessChain %_ptr_Workgroup_float
215 ; CHECK: OpAccessChain %_ptr_Uniform_float
216 OpCapability Shader
217 OpMemoryModel Logical GLSL450
218 OpEntryPoint GLCompute %1 "testMain" %gl_GlobalInvocationID %gl_LocalInvocationID %gl_WorkGroupID
219 OpExecutionMode %1 LocalSize 8 8 1
220 OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId
221 OpDecorate %gl_LocalInvocationID BuiltIn LocalInvocationId
222 OpDecorate %gl_WorkGroupID BuiltIn WorkgroupId
223 OpDecorate %5 DescriptorSet 0
224 OpDecorate %5 Binding 0
225 OpDecorate %_runtimearr_float ArrayStride 4
226 OpMemberDecorate %_struct_7 0 Offset 0
227 OpDecorate %_struct_7 BufferBlock
228 %bool = OpTypeBool
229 %true = OpConstantTrue %bool
230 %int = OpTypeInt 32 1
231 %int_0 = OpConstant %int 0
232 %float = OpTypeFloat 32
233 %float_2 = OpConstant %float 2
234 %uint = OpTypeInt 32 0
235 %uint_10 = OpConstant %uint 10
236 %_arr_float_uint_10 = OpTypeArray %float %uint_10
237 %_ptr_Function__arr_float_uint_10 = OpTypePointer Function %_arr_float_uint_10
238 %_arr__arr_float_uint_10_uint_10 = OpTypeArray %_arr_float_uint_10 %uint_10
239 %_struct_19 = OpTypeStruct %_arr__arr_float_uint_10_uint_10
240 %_ptr_Workgroup__struct_19 = OpTypePointer Workgroup %_struct_19
241 %_ptr_Function__struct_19 = OpTypePointer Function %_struct_19
242 %_runtimearr_float = OpTypeRuntimeArray %float
243 %_struct_7 = OpTypeStruct %_runtimearr_float
244 %_ptr_Uniform__struct_7 = OpTypePointer Uniform %_struct_7
245 %v3uint = OpTypeVector %uint 3
246 %_ptr_Input_v3uint = OpTypePointer Input %v3uint
247 %void = OpTypeVoid
248 %25 = OpTypeFunction %void
249 %_ptr_Function_float = OpTypePointer Function %float
250 %_ptr_Uniform_float = OpTypePointer Uniform %float
251 %28 = OpVariable %_ptr_Workgroup__struct_19 Workgroup
252 %29 = OpVariable %_ptr_Workgroup__struct_19 Workgroup
253 %5 = OpVariable %_ptr_Uniform__struct_7 Uniform
254 %gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input
255 %gl_LocalInvocationID = OpVariable %_ptr_Input_v3uint Input
256 %gl_WorkGroupID = OpVariable %_ptr_Input_v3uint Input
257 %1 = OpFunction %void None %25
258 %30 = OpLabel
259 OpSelectionMerge %31 None
260 OpBranchConditional %true %32 %31
261 %32 = OpLabel
262 OpBranch %31
263 %31 = OpLabel
264 %33 = OpPhi %_ptr_Function__struct_19 %28 %30 %29 %32
265 %34 = OpLoad %v3uint %gl_LocalInvocationID
266 %35 = OpAccessChain %_ptr_Function_float %33 %int_0 %int_0 %int_0
267 %36 = OpLoad %float %35
268 %37 = OpFMul %float %float_2 %36
269 OpStore %35 %37
270 %38 = OpLoad %float %35
271 %39 = OpCompositeExtract %uint %34 0
272 %40 = OpAccessChain %_ptr_Uniform_float %5 %int_0 %39
273 OpStore %40 %38
274 OpReturn
275 OpFunctionEnd
276 )";
277
278 SinglePassRunAndMatch<FixStorageClass>(text, false);
279 }
280
TEST_F(FixStorageClassTest,FixPhiInLoop)281 TEST_F(FixStorageClassTest, FixPhiInLoop) {
282 const std::string text = R"(
283 ; CHECK: OpPhi %_ptr_Workgroup__struct_19
284 ; CHECK: OpAccessChain %_ptr_Workgroup_float
285 ; CHECK: OpAccessChain %_ptr_Uniform_float
286 OpCapability Shader
287 OpMemoryModel Logical GLSL450
288 OpEntryPoint GLCompute %1 "testMain" %gl_GlobalInvocationID %gl_LocalInvocationID %gl_WorkGroupID
289 OpExecutionMode %1 LocalSize 8 8 1
290 OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId
291 OpDecorate %gl_LocalInvocationID BuiltIn LocalInvocationId
292 OpDecorate %gl_WorkGroupID BuiltIn WorkgroupId
293 OpDecorate %5 DescriptorSet 0
294 OpDecorate %5 Binding 0
295 OpDecorate %_runtimearr_float ArrayStride 4
296 OpMemberDecorate %_struct_7 0 Offset 0
297 OpDecorate %_struct_7 BufferBlock
298 %bool = OpTypeBool
299 %true = OpConstantTrue %bool
300 %int = OpTypeInt 32 1
301 %int_0 = OpConstant %int 0
302 %float = OpTypeFloat 32
303 %float_2 = OpConstant %float 2
304 %uint = OpTypeInt 32 0
305 %uint_10 = OpConstant %uint 10
306 %_arr_float_uint_10 = OpTypeArray %float %uint_10
307 %_ptr_Function__arr_float_uint_10 = OpTypePointer Function %_arr_float_uint_10
308 %_arr__arr_float_uint_10_uint_10 = OpTypeArray %_arr_float_uint_10 %uint_10
309 %_struct_19 = OpTypeStruct %_arr__arr_float_uint_10_uint_10
310 %_ptr_Workgroup__struct_19 = OpTypePointer Workgroup %_struct_19
311 %_ptr_Function__struct_19 = OpTypePointer Function %_struct_19
312 %_runtimearr_float = OpTypeRuntimeArray %float
313 %_struct_7 = OpTypeStruct %_runtimearr_float
314 %_ptr_Uniform__struct_7 = OpTypePointer Uniform %_struct_7
315 %v3uint = OpTypeVector %uint 3
316 %_ptr_Input_v3uint = OpTypePointer Input %v3uint
317 %void = OpTypeVoid
318 %25 = OpTypeFunction %void
319 %_ptr_Function_float = OpTypePointer Function %float
320 %_ptr_Uniform_float = OpTypePointer Uniform %float
321 %28 = OpVariable %_ptr_Workgroup__struct_19 Workgroup
322 %29 = OpVariable %_ptr_Workgroup__struct_19 Workgroup
323 %5 = OpVariable %_ptr_Uniform__struct_7 Uniform
324 %gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input
325 %gl_LocalInvocationID = OpVariable %_ptr_Input_v3uint Input
326 %gl_WorkGroupID = OpVariable %_ptr_Input_v3uint Input
327 %1 = OpFunction %void None %25
328 %30 = OpLabel
329 OpSelectionMerge %31 None
330 OpBranchConditional %true %32 %31
331 %32 = OpLabel
332 OpBranch %31
333 %31 = OpLabel
334 %33 = OpPhi %_ptr_Function__struct_19 %28 %30 %29 %32
335 %34 = OpLoad %v3uint %gl_LocalInvocationID
336 %35 = OpAccessChain %_ptr_Function_float %33 %int_0 %int_0 %int_0
337 %36 = OpLoad %float %35
338 %37 = OpFMul %float %float_2 %36
339 OpStore %35 %37
340 %38 = OpLoad %float %35
341 %39 = OpCompositeExtract %uint %34 0
342 %40 = OpAccessChain %_ptr_Uniform_float %5 %int_0 %39
343 OpStore %40 %38
344 OpReturn
345 OpFunctionEnd
346 )";
347
348 SinglePassRunAndMatch<FixStorageClass>(text, false);
349 }
350
TEST_F(FixStorageClassTest,DontChangeFunctionCalls)351 TEST_F(FixStorageClassTest, DontChangeFunctionCalls) {
352 const std::string text = R"(OpCapability Shader
353 OpMemoryModel Logical GLSL450
354 OpEntryPoint GLCompute %1 "testMain"
355 OpExecutionMode %1 LocalSize 8 8 1
356 OpDecorate %2 DescriptorSet 0
357 OpDecorate %2 Binding 0
358 %int = OpTypeInt 32 1
359 %_ptr_Function_int = OpTypePointer Function %int
360 %_ptr_Workgroup_int = OpTypePointer Workgroup %int
361 %_ptr_Uniform_int = OpTypePointer Uniform %int
362 %void = OpTypeVoid
363 %8 = OpTypeFunction %void
364 %9 = OpTypeFunction %_ptr_Uniform_int %_ptr_Function_int
365 %10 = OpVariable %_ptr_Workgroup_int Workgroup
366 %2 = OpVariable %_ptr_Uniform_int Uniform
367 %1 = OpFunction %void None %8
368 %11 = OpLabel
369 %12 = OpFunctionCall %_ptr_Uniform_int %13 %10
370 OpReturn
371 OpFunctionEnd
372 %13 = OpFunction %_ptr_Uniform_int None %9
373 %14 = OpFunctionParameter %_ptr_Function_int
374 %15 = OpLabel
375 OpReturnValue %2
376 OpFunctionEnd
377 )";
378
379 SinglePassRunAndCheck<FixStorageClass>(text, text, false, false);
380 }
381
TEST_F(FixStorageClassTest,FixSelect)382 TEST_F(FixStorageClassTest, FixSelect) {
383 const std::string text = R"(
384 ; CHECK: OpSelect %_ptr_Workgroup__struct_19
385 ; CHECK: OpAccessChain %_ptr_Workgroup_float
386 ; CHECK: OpAccessChain %_ptr_Uniform_float
387 OpCapability Shader
388 OpMemoryModel Logical GLSL450
389 OpEntryPoint GLCompute %1 "testMain" %gl_GlobalInvocationID %gl_LocalInvocationID %gl_WorkGroupID
390 OpExecutionMode %1 LocalSize 8 8 1
391 OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId
392 OpDecorate %gl_LocalInvocationID BuiltIn LocalInvocationId
393 OpDecorate %gl_WorkGroupID BuiltIn WorkgroupId
394 OpDecorate %5 DescriptorSet 0
395 OpDecorate %5 Binding 0
396 OpDecorate %_runtimearr_float ArrayStride 4
397 OpMemberDecorate %_struct_7 0 Offset 0
398 OpDecorate %_struct_7 BufferBlock
399 %bool = OpTypeBool
400 %true = OpConstantTrue %bool
401 %int = OpTypeInt 32 1
402 %int_0 = OpConstant %int 0
403 %float = OpTypeFloat 32
404 %float_2 = OpConstant %float 2
405 %uint = OpTypeInt 32 0
406 %uint_10 = OpConstant %uint 10
407 %_arr_float_uint_10 = OpTypeArray %float %uint_10
408 %_ptr_Function__arr_float_uint_10 = OpTypePointer Function %_arr_float_uint_10
409 %_arr__arr_float_uint_10_uint_10 = OpTypeArray %_arr_float_uint_10 %uint_10
410 %_struct_19 = OpTypeStruct %_arr__arr_float_uint_10_uint_10
411 %_ptr_Workgroup__struct_19 = OpTypePointer Workgroup %_struct_19
412 %_ptr_Function__struct_19 = OpTypePointer Function %_struct_19
413 %_runtimearr_float = OpTypeRuntimeArray %float
414 %_struct_7 = OpTypeStruct %_runtimearr_float
415 %_ptr_Uniform__struct_7 = OpTypePointer Uniform %_struct_7
416 %v3uint = OpTypeVector %uint 3
417 %_ptr_Input_v3uint = OpTypePointer Input %v3uint
418 %void = OpTypeVoid
419 %25 = OpTypeFunction %void
420 %_ptr_Function_float = OpTypePointer Function %float
421 %_ptr_Uniform_float = OpTypePointer Uniform %float
422 %28 = OpVariable %_ptr_Workgroup__struct_19 Workgroup
423 %29 = OpVariable %_ptr_Workgroup__struct_19 Workgroup
424 %5 = OpVariable %_ptr_Uniform__struct_7 Uniform
425 %gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input
426 %gl_LocalInvocationID = OpVariable %_ptr_Input_v3uint Input
427 %gl_WorkGroupID = OpVariable %_ptr_Input_v3uint Input
428 %1 = OpFunction %void None %25
429 %30 = OpLabel
430 %33 = OpSelect %_ptr_Function__struct_19 %true %28 %29
431 %34 = OpLoad %v3uint %gl_LocalInvocationID
432 %35 = OpAccessChain %_ptr_Function_float %33 %int_0 %int_0 %int_0
433 %36 = OpLoad %float %35
434 %37 = OpFMul %float %float_2 %36
435 OpStore %35 %37
436 %38 = OpLoad %float %35
437 %39 = OpCompositeExtract %uint %34 0
438 %40 = OpAccessChain %_ptr_Uniform_float %5 %int_0 %39
439 OpStore %40 %38
440 OpReturn
441 OpFunctionEnd
442 )";
443
444 SinglePassRunAndMatch<FixStorageClass>(text, false);
445 }
446
TEST_F(FixStorageClassTest,BitCast)447 TEST_F(FixStorageClassTest, BitCast) {
448 const std::string text = R"(OpCapability VariablePointersStorageBuffer
449 OpMemoryModel Logical GLSL450
450 OpEntryPoint GLCompute %1 "main"
451 %void = OpTypeVoid
452 %3 = OpTypeFunction %void
453 %_ptr_Output_void = OpTypePointer Output %void
454 %_ptr_Private__ptr_Output_void = OpTypePointer Private %_ptr_Output_void
455 %6 = OpVariable %_ptr_Private__ptr_Output_void Private
456 %1 = OpFunction %void Inline %3
457 %7 = OpLabel
458 %8 = OpBitcast %_ptr_Output_void %6
459 OpReturn
460 OpFunctionEnd
461 )";
462
463 SinglePassRunAndCheck<FixStorageClass>(text, text, false);
464 }
465
TEST_F(FixStorageClassTest,FixLinkedAccessChain2)466 TEST_F(FixStorageClassTest, FixLinkedAccessChain2) {
467 // This case is similar to FixLinkedAccessChain. The difference is that the
468 // first OpAccessChain instruction starts as workgroup storage class. Only
469 // the second one needs to change.
470 const std::string text = R"(
471 ; CHECK: OpAccessChain %_ptr_Workgroup__arr_float_uint_10
472 ; CHECK: OpAccessChain %_ptr_Workgroup_float
473 ; CHECK: OpAccessChain %_ptr_Uniform_float
474 OpCapability Shader
475 OpMemoryModel Logical GLSL450
476 OpEntryPoint GLCompute %1 "testMain" %gl_GlobalInvocationID %gl_LocalInvocationID %gl_WorkGroupID
477 OpExecutionMode %1 LocalSize 8 8 1
478 OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId
479 OpDecorate %gl_LocalInvocationID BuiltIn LocalInvocationId
480 OpDecorate %gl_WorkGroupID BuiltIn WorkgroupId
481 OpDecorate %5 DescriptorSet 0
482 OpDecorate %5 Binding 0
483 OpDecorate %_runtimearr_float ArrayStride 4
484 OpMemberDecorate %_struct_7 0 Offset 0
485 OpDecorate %_struct_7 BufferBlock
486 %int = OpTypeInt 32 1
487 %int_0 = OpConstant %int 0
488 %float = OpTypeFloat 32
489 %float_2 = OpConstant %float 2
490 %uint = OpTypeInt 32 0
491 %uint_10 = OpConstant %uint 10
492 %_arr_float_uint_10 = OpTypeArray %float %uint_10
493 %_ptr_Workgroup__arr_float_uint_10 = OpTypePointer Workgroup %_arr_float_uint_10
494 %_ptr = OpTypePointer Function %_arr_float_uint_10
495 %_arr__arr_float_uint_10_uint_10 = OpTypeArray %_arr_float_uint_10 %uint_10
496 %_struct_17 = OpTypeStruct %_arr__arr_float_uint_10_uint_10
497 %_ptr_Workgroup__struct_17 = OpTypePointer Workgroup %_struct_17
498 %_runtimearr_float = OpTypeRuntimeArray %float
499 %_struct_7 = OpTypeStruct %_runtimearr_float
500 %_ptr_Uniform__struct_7 = OpTypePointer Uniform %_struct_7
501 %v3uint = OpTypeVector %uint 3
502 %_ptr_Input_v3uint = OpTypePointer Input %v3uint
503 %void = OpTypeVoid
504 %23 = OpTypeFunction %void
505 %_ptr_Function_float = OpTypePointer Function %float
506 %_ptr_Uniform_float = OpTypePointer Uniform %float
507 %27 = OpVariable %_ptr_Workgroup__struct_17 Workgroup
508 %5 = OpVariable %_ptr_Uniform__struct_7 Uniform
509 %gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input
510 %gl_LocalInvocationID = OpVariable %_ptr_Input_v3uint Input
511 %gl_WorkGroupID = OpVariable %_ptr_Input_v3uint Input
512 %1 = OpFunction %void None %23
513 %28 = OpLabel
514 %29 = OpLoad %v3uint %gl_LocalInvocationID
515 %30 = OpAccessChain %_ptr_Workgroup__arr_float_uint_10 %27 %int_0 %int_0
516 %31 = OpAccessChain %_ptr_Function_float %30 %int_0
517 %32 = OpLoad %float %31
518 %33 = OpFMul %float %float_2 %32
519 OpStore %31 %33
520 %34 = OpLoad %float %31
521 %35 = OpCompositeExtract %uint %29 0
522 %36 = OpAccessChain %_ptr_Uniform_float %5 %int_0 %35
523 OpStore %36 %34
524 OpReturn
525 OpFunctionEnd
526 )";
527
528 SinglePassRunAndMatch<FixStorageClass>(text, false);
529 }
530
TEST_F(FixStorageClassTest,AllowImageFormatMismatch)531 TEST_F(FixStorageClassTest, AllowImageFormatMismatch) {
532 const std::string text = R"(OpCapability Shader
533 OpCapability SampledBuffer
534 OpCapability ImageBuffer
535 OpMemoryModel Logical GLSL450
536 OpEntryPoint GLCompute %main "main"
537 OpExecutionMode %main LocalSize 1 1 1
538 OpSource HLSL 600
539 OpName %type_buffer_image "type.buffer.image"
540 OpName %Buf "Buf"
541 OpName %main "main"
542 OpName %src_main "src.main"
543 OpName %bb_entry "bb.entry"
544 OpName %type_buffer_image_0 "type.buffer.image"
545 OpName %b "b"
546 OpDecorate %Buf DescriptorSet 0
547 OpDecorate %Buf Binding 0
548 %float = OpTypeFloat 32
549 %type_buffer_image = OpTypeImage %float Buffer 2 0 0 2 Rgba16f
550 %_ptr_UniformConstant_type_buffer_image = OpTypePointer UniformConstant %type_buffer_image
551 %void = OpTypeVoid
552 %11 = OpTypeFunction %void
553 %type_buffer_image_0 = OpTypeImage %float Buffer 2 0 0 2 Rgba32f
554 %_ptr_Function_type_buffer_image_0 = OpTypePointer Function %type_buffer_image_0
555 %Buf = OpVariable %_ptr_UniformConstant_type_buffer_image UniformConstant
556 %main = OpFunction %void None %11
557 %13 = OpLabel
558 %14 = OpFunctionCall %void %src_main
559 OpReturn
560 OpFunctionEnd
561 %src_main = OpFunction %void None %11
562 %bb_entry = OpLabel
563 %b = OpVariable %_ptr_Function_type_buffer_image_0 Function
564 %15 = OpLoad %type_buffer_image %Buf
565 OpStore %b %15
566 OpReturn
567 OpFunctionEnd
568 )";
569
570 SinglePassRunAndCheck<FixStorageClass>(text, text, false, false);
571 }
572
573 using FixTypeTest = PassTest<::testing::Test>;
574
TEST_F(FixTypeTest,FixAccessChain)575 TEST_F(FixTypeTest, FixAccessChain) {
576 const std::string text = R"(
577 ; CHECK: [[ac1:%\w+]] = OpAccessChain %_ptr_Uniform_S %A %int_0 %uint_0
578 ; CHECK: [[ac2:%\w+]] = OpAccessChain %_ptr_Uniform_T [[ac1]] %int_0
579 OpCapability Shader
580 OpMemoryModel Logical GLSL450
581 OpEntryPoint GLCompute %main "main"
582 OpExecutionMode %main LocalSize 1 1 1
583 OpSource HLSL 600
584 OpName %type_RWStructuredBuffer_S "type.RWStructuredBuffer.S"
585 OpName %S "S"
586 OpMemberName %S 0 "t"
587 OpName %T "T"
588 OpMemberName %T 0 "a"
589 OpName %A "A"
590 OpName %type_ACSBuffer_counter "type.ACSBuffer.counter"
591 OpMemberName %type_ACSBuffer_counter 0 "counter"
592 OpName %counter_var_A "counter.var.A"
593 OpName %main "main"
594 OpName %S_0 "S"
595 OpMemberName %S_0 0 "t"
596 OpName %T_0 "T"
597 OpMemberName %T_0 0 "a"
598 OpDecorate %A DescriptorSet 0
599 OpDecorate %A Binding 0
600 OpDecorate %counter_var_A DescriptorSet 0
601 OpDecorate %counter_var_A Binding 1
602 OpMemberDecorate %T 0 Offset 0
603 OpMemberDecorate %S 0 Offset 0
604 OpDecorate %_runtimearr_S ArrayStride 4
605 OpMemberDecorate %type_RWStructuredBuffer_S 0 Offset 0
606 OpDecorate %type_RWStructuredBuffer_S BufferBlock
607 OpMemberDecorate %type_ACSBuffer_counter 0 Offset 0
608 OpDecorate %type_ACSBuffer_counter BufferBlock
609 %int = OpTypeInt 32 1
610 %int_0 = OpConstant %int 0
611 %uint = OpTypeInt 32 0
612 %uint_0 = OpConstant %uint 0
613 %T = OpTypeStruct %int
614 %S = OpTypeStruct %T
615 %_runtimearr_S = OpTypeRuntimeArray %S
616 %type_RWStructuredBuffer_S = OpTypeStruct %_runtimearr_S
617 %_ptr_Uniform_type_RWStructuredBuffer_S = OpTypePointer Uniform %type_RWStructuredBuffer_S
618 %type_ACSBuffer_counter = OpTypeStruct %int
619 %_ptr_Uniform_type_ACSBuffer_counter = OpTypePointer Uniform %type_ACSBuffer_counter
620 %void = OpTypeVoid
621 %18 = OpTypeFunction %void
622 %T_0 = OpTypeStruct %int
623 %S_0 = OpTypeStruct %T_0
624 %_ptr_Function_S_0 = OpTypePointer Function %S_0
625 %_ptr_Uniform_S = OpTypePointer Uniform %S
626 %_ptr_Uniform_T = OpTypePointer Uniform %T
627 %22 = OpTypeFunction %T_0 %_ptr_Function_S_0
628 %_ptr_Function_T_0 = OpTypePointer Function %T_0
629 %A = OpVariable %_ptr_Uniform_type_RWStructuredBuffer_S Uniform
630 %counter_var_A = OpVariable %_ptr_Uniform_type_ACSBuffer_counter Uniform
631 %main = OpFunction %void None %18
632 %24 = OpLabel
633 %25 = OpVariable %_ptr_Function_T_0 Function
634 %26 = OpVariable %_ptr_Function_S_0 Function
635 %27 = OpAccessChain %_ptr_Uniform_S %A %int_0 %uint_0
636 %28 = OpAccessChain %_ptr_Function_T_0 %27 %int_0
637 OpReturn
638 OpFunctionEnd
639 )";
640
641 SinglePassRunAndMatch<FixStorageClass>(text, false);
642 }
643
TEST_F(FixTypeTest,FixLoad)644 TEST_F(FixTypeTest, FixLoad) {
645 const std::string text = R"(
646 ; CHECK: [[ac1:%\w+]] = OpAccessChain %_ptr_Uniform_S %A %int_0 %uint_0
647 ; CHECK: [[ac2:%\w+]] = OpAccessChain %_ptr_Uniform_T [[ac1]] %int_0
648 ; CHECK: [[ld:%\w+]] = OpLoad %T [[ac2]]
649 OpCapability Shader
650 OpMemoryModel Logical GLSL450
651 OpEntryPoint GLCompute %main "main"
652 OpExecutionMode %main LocalSize 1 1 1
653 OpSource HLSL 600
654 OpName %type_RWStructuredBuffer_S "type.RWStructuredBuffer.S"
655 OpName %S "S"
656 OpMemberName %S 0 "t"
657 OpName %T "T"
658 OpMemberName %T 0 "a"
659 OpName %A "A"
660 OpName %type_ACSBuffer_counter "type.ACSBuffer.counter"
661 OpMemberName %type_ACSBuffer_counter 0 "counter"
662 OpName %counter_var_A "counter.var.A"
663 OpName %main "main"
664 OpName %S_0 "S"
665 OpMemberName %S_0 0 "t"
666 OpName %T_0 "T"
667 OpMemberName %T_0 0 "a"
668 OpDecorate %A DescriptorSet 0
669 OpDecorate %A Binding 0
670 OpDecorate %counter_var_A DescriptorSet 0
671 OpDecorate %counter_var_A Binding 1
672 OpMemberDecorate %T 0 Offset 0
673 OpMemberDecorate %S 0 Offset 0
674 OpDecorate %_runtimearr_S ArrayStride 4
675 OpMemberDecorate %type_RWStructuredBuffer_S 0 Offset 0
676 OpDecorate %type_RWStructuredBuffer_S BufferBlock
677 OpMemberDecorate %type_ACSBuffer_counter 0 Offset 0
678 OpDecorate %type_ACSBuffer_counter BufferBlock
679 %int = OpTypeInt 32 1
680 %int_0 = OpConstant %int 0
681 %uint = OpTypeInt 32 0
682 %uint_0 = OpConstant %uint 0
683 %T = OpTypeStruct %int
684 %S = OpTypeStruct %T
685 %_runtimearr_S = OpTypeRuntimeArray %S
686 %type_RWStructuredBuffer_S = OpTypeStruct %_runtimearr_S
687 %_ptr_Uniform_type_RWStructuredBuffer_S = OpTypePointer Uniform %type_RWStructuredBuffer_S
688 %type_ACSBuffer_counter = OpTypeStruct %int
689 %_ptr_Uniform_type_ACSBuffer_counter = OpTypePointer Uniform %type_ACSBuffer_counter
690 %void = OpTypeVoid
691 %18 = OpTypeFunction %void
692 %T_0 = OpTypeStruct %int
693 %S_0 = OpTypeStruct %T_0
694 %_ptr_Function_S_0 = OpTypePointer Function %S_0
695 %_ptr_Uniform_S = OpTypePointer Uniform %S
696 %_ptr_Uniform_T = OpTypePointer Uniform %T
697 %22 = OpTypeFunction %T_0 %_ptr_Function_S_0
698 %_ptr_Function_T_0 = OpTypePointer Function %T_0
699 %A = OpVariable %_ptr_Uniform_type_RWStructuredBuffer_S Uniform
700 %counter_var_A = OpVariable %_ptr_Uniform_type_ACSBuffer_counter Uniform
701 %main = OpFunction %void None %18
702 %24 = OpLabel
703 %25 = OpVariable %_ptr_Function_T_0 Function
704 %26 = OpVariable %_ptr_Function_S_0 Function
705 %27 = OpAccessChain %_ptr_Uniform_S %A %int_0 %uint_0
706 %28 = OpAccessChain %_ptr_Uniform_T %27 %int_0
707 %29 = OpLoad %T_0 %28
708 OpReturn
709 OpFunctionEnd
710 )";
711
712 SinglePassRunAndMatch<FixStorageClass>(text, false);
713 }
714
TEST_F(FixTypeTest,FixStore)715 TEST_F(FixTypeTest, FixStore) {
716 const std::string text = R"(
717 ; CHECK: [[ld:%\w+]] = OpLoad %T
718 ; CHECK: OpStore
719 OpCapability Shader
720 OpMemoryModel Logical GLSL450
721 OpEntryPoint GLCompute %main "main"
722 OpExecutionMode %main LocalSize 1 1 1
723 OpSource HLSL 600
724 OpName %type_RWStructuredBuffer_S "type.RWStructuredBuffer.S"
725 OpName %S "S"
726 OpMemberName %S 0 "t"
727 OpName %T "T"
728 OpMemberName %T 0 "a"
729 OpName %A "A"
730 OpName %type_ACSBuffer_counter "type.ACSBuffer.counter"
731 OpMemberName %type_ACSBuffer_counter 0 "counter"
732 OpName %counter_var_A "counter.var.A"
733 OpName %main "main"
734 OpName %S_0 "S"
735 OpMemberName %S_0 0 "t"
736 OpName %T_0 "T"
737 OpMemberName %T_0 0 "a"
738 OpDecorate %A DescriptorSet 0
739 OpDecorate %A Binding 0
740 OpDecorate %counter_var_A DescriptorSet 0
741 OpDecorate %counter_var_A Binding 1
742 OpMemberDecorate %T 0 Offset 0
743 OpMemberDecorate %S 0 Offset 0
744 OpDecorate %_runtimearr_S ArrayStride 4
745 OpMemberDecorate %type_RWStructuredBuffer_S 0 Offset 0
746 OpDecorate %type_RWStructuredBuffer_S BufferBlock
747 OpMemberDecorate %type_ACSBuffer_counter 0 Offset 0
748 OpDecorate %type_ACSBuffer_counter BufferBlock
749 %int = OpTypeInt 32 1
750 %int_0 = OpConstant %int 0
751 %uint = OpTypeInt 32 0
752 %uint_0 = OpConstant %uint 0
753 %T = OpTypeStruct %int
754 %S = OpTypeStruct %T
755 %_runtimearr_S = OpTypeRuntimeArray %S
756 %type_RWStructuredBuffer_S = OpTypeStruct %_runtimearr_S
757 %_ptr_Uniform_type_RWStructuredBuffer_S = OpTypePointer Uniform %type_RWStructuredBuffer_S
758 %type_ACSBuffer_counter = OpTypeStruct %int
759 %_ptr_Uniform_type_ACSBuffer_counter = OpTypePointer Uniform %type_ACSBuffer_counter
760 %void = OpTypeVoid
761 %18 = OpTypeFunction %void
762 %T_0 = OpTypeStruct %int
763 %S_0 = OpTypeStruct %T_0
764 %_ptr_Function_S_0 = OpTypePointer Function %S_0
765 %_ptr_Uniform_S = OpTypePointer Uniform %S
766 %_ptr_Uniform_T = OpTypePointer Uniform %T
767 %22 = OpTypeFunction %T_0 %_ptr_Function_S_0
768 %_ptr_Function_T_0 = OpTypePointer Function %T_0
769 %A = OpVariable %_ptr_Uniform_type_RWStructuredBuffer_S Uniform
770 %counter_var_A = OpVariable %_ptr_Uniform_type_ACSBuffer_counter Uniform
771 %main = OpFunction %void None %18
772 %24 = OpLabel
773 %25 = OpVariable %_ptr_Function_T_0 Function
774 %26 = OpVariable %_ptr_Function_S_0 Function
775 %27 = OpAccessChain %_ptr_Uniform_S %A %int_0 %uint_0
776 %28 = OpAccessChain %_ptr_Uniform_T %27 %int_0
777 %29 = OpLoad %T %28
778 OpStore %25 %29
779 OpReturn
780 OpFunctionEnd
781 )";
782
783 SinglePassRunAndMatch<FixStorageClass>(text, false);
784 }
785
TEST_F(FixTypeTest,FixSelect)786 TEST_F(FixTypeTest, FixSelect) {
787 const std::string text = R"(
788 ; CHECK: OpSelect %_ptr_Uniform__struct_3
789 OpCapability Shader
790 OpMemoryModel Logical GLSL450
791 OpEntryPoint GLCompute %1 "main"
792 OpExecutionMode %1 LocalSize 1 1 1
793 OpSource HLSL 600
794 OpDecorate %2 DescriptorSet 0
795 OpDecorate %2 Binding 0
796 OpMemberDecorate %_struct_3 0 Offset 0
797 OpDecorate %_runtimearr__struct_3 ArrayStride 4
798 OpMemberDecorate %_struct_5 0 Offset 0
799 OpDecorate %_struct_5 BufferBlock
800 %uint = OpTypeInt 32 0
801 %uint_0 = OpConstant %uint 0
802 %uint_1 = OpConstant %uint 1
803 %_struct_3 = OpTypeStruct %uint
804 %_runtimearr__struct_3 = OpTypeRuntimeArray %_struct_3
805 %_struct_5 = OpTypeStruct %_runtimearr__struct_3
806 %_ptr_Uniform__struct_5 = OpTypePointer Uniform %_struct_5
807 %void = OpTypeVoid
808 %11 = OpTypeFunction %void
809 %_struct_12 = OpTypeStruct %uint
810 %_ptr_Function__struct_12 = OpTypePointer Function %_struct_12
811 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
812 %bool = OpTypeBool
813 %_ptr_Uniform__struct_3 = OpTypePointer Uniform %_struct_3
814 %2 = OpVariable %_ptr_Uniform__struct_5 Uniform
815 %1 = OpFunction %void None %11
816 %17 = OpLabel
817 %18 = OpAccessChain %_ptr_Uniform_uint %2 %uint_0 %uint_0 %uint_0
818 %19 = OpLoad %uint %18
819 %20 = OpSGreaterThan %bool %19 %uint_0
820 %21 = OpAccessChain %_ptr_Uniform__struct_3 %2 %uint_0 %uint_0
821 %22 = OpAccessChain %_ptr_Uniform__struct_3 %2 %uint_0 %uint_1
822 %23 = OpSelect %_ptr_Function__struct_12 %20 %21 %22
823 OpReturn
824 OpFunctionEnd
825 )";
826
827 SinglePassRunAndMatch<FixStorageClass>(text, false);
828 }
829
TEST_F(FixTypeTest,FixPhiInLoop)830 TEST_F(FixTypeTest, FixPhiInLoop) {
831 const std::string text = R"(
832 ; CHECK: [[ac_init:%\w+]] = OpAccessChain %_ptr_Uniform__struct_3
833 ; CHECK: [[ac_phi:%\w+]] = OpPhi %_ptr_Uniform__struct_3 [[ac_init]] {{%\w+}} [[ac_update:%\w+]] {{%\w+}}
834 ; CHECK: [[ac_update]] = OpPtrAccessChain %_ptr_Uniform__struct_3 [[ac_phi]] %int_1
835 OpCapability Shader
836 OpMemoryModel Logical GLSL450
837 OpEntryPoint GLCompute %1 "main"
838 OpExecutionMode %1 LocalSize 1 1 1
839 OpSource HLSL 600
840 OpDecorate %2 DescriptorSet 0
841 OpDecorate %2 Binding 0
842 OpMemberDecorate %_struct_3 0 Offset 0
843 OpDecorate %_runtimearr__struct_3 ArrayStride 4
844 OpMemberDecorate %_struct_5 0 Offset 0
845 OpDecorate %_struct_5 BufferBlock
846 %int = OpTypeInt 32 1
847 %int_0 = OpConstant %int 0
848 %int_1 = OpConstant %int 1
849 %_struct_3 = OpTypeStruct %int
850 %_struct_9 = OpTypeStruct %int
851 %_runtimearr__struct_3 = OpTypeRuntimeArray %_struct_3
852 %_struct_5 = OpTypeStruct %_runtimearr__struct_3
853 %_ptr_Uniform__struct_5 = OpTypePointer Uniform %_struct_5
854 %void = OpTypeVoid
855 %12 = OpTypeFunction %void
856 %bool = OpTypeBool
857 %_ptr_Uniform__struct_3 = OpTypePointer Uniform %_struct_3
858 %_ptr_Function__struct_9 = OpTypePointer Function %_struct_9
859 %2 = OpVariable %_ptr_Uniform__struct_5 Uniform
860 %1 = OpFunction %void None %12
861 %16 = OpLabel
862 %17 = OpAccessChain %_ptr_Uniform__struct_3 %2 %int_0 %int_0
863 OpBranch %18
864 %18 = OpLabel
865 %20 = OpPhi %_ptr_Function__struct_9 %17 %16 %21 %22
866 %23 = OpUndef %bool
867 OpLoopMerge %24 %22 None
868 OpBranchConditional %23 %22 %24
869 %22 = OpLabel
870 %21 = OpPtrAccessChain %_ptr_Function__struct_9 %20 %int_1
871 OpBranch %18
872 %24 = OpLabel
873 OpReturn
874 OpFunctionEnd
875 )";
876
877 SinglePassRunAndMatch<FixStorageClass>(text, false);
878 }
879
880 } // namespace
881 } // namespace opt
882 } // namespace spvtools
883