1 // Copyright (c) 2022 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/pass_fixture.h"
19 #include "test/opt/pass_utils.h"
20
21 namespace spvtools {
22 namespace opt {
23 namespace {
24
25 struct ExecutionModelAndBuiltIn {
26 const char* execution_model;
27 const char* built_in;
28 const bool use_v4uint;
29 };
30
31 using AddVolatileDecorationTest =
32 PassTest<::testing::TestWithParam<ExecutionModelAndBuiltIn>>;
33
TEST_P(AddVolatileDecorationTest,InMain)34 TEST_P(AddVolatileDecorationTest, InMain) {
35 const auto& tc = GetParam();
36 const std::string execution_model(tc.execution_model);
37 const std::string built_in(tc.built_in);
38 const std::string var_type =
39 tc.use_v4uint ? "%_ptr_Input_v4uint" : "%_ptr_Input_uint";
40 const std::string var_load_type = tc.use_v4uint ? "%v4uint" : "%uint";
41
42 const std::string text =
43 std::string(R"(OpCapability RuntimeDescriptorArray
44 OpCapability RayTracingKHR
45 OpCapability SubgroupBallotKHR
46 OpExtension "SPV_EXT_descriptor_indexing"
47 OpExtension "SPV_KHR_ray_tracing"
48 OpExtension "SPV_KHR_shader_ballot"
49 %1 = OpExtInstImport "GLSL.std.450"
50 OpMemoryModel Logical GLSL450
51 OpEntryPoint )") +
52 execution_model + std::string(R"( %main "main" %var
53 OpSource GLSL 460
54 OpSourceExtension "GL_EXT_nonuniform_qualifier"
55 OpSourceExtension "GL_KHR_ray_tracing"
56 OpName %main "main"
57 OpName %fn "fn"
58 OpName %StorageBuffer "StorageBuffer"
59 OpMemberName %StorageBuffer 0 "index"
60 OpMemberName %StorageBuffer 1 "red"
61 OpName %sbo "sbo"
62 OpName %images "images"
63 OpMemberDecorate %StorageBuffer 0 Offset 0
64 OpMemberDecorate %StorageBuffer 1 Offset 4
65 OpDecorate %StorageBuffer BufferBlock
66 OpDecorate %sbo DescriptorSet 0
67 OpDecorate %sbo Binding 0
68 OpDecorate %images DescriptorSet 0
69 OpDecorate %images Binding 1
70 OpDecorate %images NonWritable
71 )") + std::string(R"(
72 ; CHECK: OpDecorate [[var:%\w+]] BuiltIn )") +
73 built_in + std::string(R"(
74 ; CHECK: OpDecorate [[var]] Volatile
75 OpDecorate %var BuiltIn )") + built_in + std::string(R"(
76 %void = OpTypeVoid
77 %3 = OpTypeFunction %void
78 %uint = OpTypeInt 32 0
79 %float = OpTypeFloat 32
80 %StorageBuffer = OpTypeStruct %uint %float
81 %_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer
82 %sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform
83 %int = OpTypeInt 32 1
84 %int_1 = OpConstant %int 1
85 %13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f
86 %_runtimearr_13 = OpTypeRuntimeArray %13
87 %_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13
88 %images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant
89 %_ptr_Input_uint = OpTypePointer Input %uint
90 %v4uint = OpTypeVector %uint 4
91 %_ptr_Input_v4uint = OpTypePointer Input %v4uint
92 %var = OpVariable )") +
93 var_type + std::string(R"( Input
94 %int_0 = OpConstant %int 0
95 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
96 %_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13
97 %v2int = OpTypeVector %int 2
98 %25 = OpConstantComposite %v2int %int_0 %int_0
99 %v4float = OpTypeVector %float 4
100 %uint_0 = OpConstant %uint 0
101 %_ptr_Uniform_float = OpTypePointer Uniform %float
102 %main = OpFunction %void None %3
103 %5 = OpLabel
104 %19 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0
105 %20 = OpLoad %uint %19
106 %load = OpLoad )") + var_load_type + std::string(R"( %var
107 %22 = OpAccessChain %_ptr_UniformConstant_13 %images %20
108 %23 = OpLoad %13 %22
109 %27 = OpImageRead %v4float %23 %25
110 %29 = OpCompositeExtract %float %27 0
111 %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
112 OpStore %31 %29
113 %32 = OpFunctionCall %void %fn
114 OpReturn
115 OpFunctionEnd
116 %fn = OpFunction %void None %3
117 %33 = OpLabel
118 OpReturn
119 OpFunctionEnd
120 )");
121
122 SinglePassRunAndMatch<SpreadVolatileSemantics>(text, true);
123 }
124
125 INSTANTIATE_TEST_SUITE_P(
126 AddVolatileDecoration, AddVolatileDecorationTest,
127 ::testing::ValuesIn(std::vector<ExecutionModelAndBuiltIn>{
128 {"RayGenerationKHR", "SubgroupSize", false},
129 {"RayGenerationKHR", "SubgroupLocalInvocationId", false},
130 {"RayGenerationKHR", "SubgroupEqMask", true},
131 {"ClosestHitKHR", "SubgroupLocalInvocationId", true},
132 {"IntersectionKHR", "SubgroupEqMask", true},
133 {"MissKHR", "SubgroupGeMask", true},
134 {"CallableKHR", "SubgroupGtMask", true},
135 {"RayGenerationKHR", "SubgroupLeMask", true},
136 }));
137
138 using SetLoadVolatileTest =
139 PassTest<::testing::TestWithParam<ExecutionModelAndBuiltIn>>;
140
TEST_P(SetLoadVolatileTest,InMain)141 TEST_P(SetLoadVolatileTest, InMain) {
142 const auto& tc = GetParam();
143 const std::string execution_model(tc.execution_model);
144 const std::string built_in(tc.built_in);
145
146 const std::string var_type =
147 tc.use_v4uint ? "%_ptr_Input_v4uint" : "%_ptr_Input_uint";
148 const std::string var_value = tc.use_v4uint ? std::string(R"(
149 ; CHECK: [[ptr:%\w+]] = OpAccessChain %_ptr_Input_uint [[var]] %int_0
150 ; CHECK: OpLoad {{%\w+}} [[ptr]] Volatile
151 %ptr = OpAccessChain %_ptr_Input_uint %var %int_0
152 %var_value = OpLoad %uint %ptr)")
153 : std::string(R"(
154 ; CHECK: OpLoad {{%\w+}} [[var]] Volatile
155 %var_value = OpLoad %uint %var)");
156
157 const std::string text = std::string(R"(OpCapability RuntimeDescriptorArray
158 OpCapability RayTracingKHR
159 OpCapability SubgroupBallotKHR
160 OpCapability VulkanMemoryModel
161 OpExtension "SPV_KHR_vulkan_memory_model"
162 OpExtension "SPV_EXT_descriptor_indexing"
163 OpExtension "SPV_KHR_ray_tracing"
164 OpExtension "SPV_KHR_shader_ballot"
165 OpMemoryModel Logical Vulkan
166 OpEntryPoint )") + execution_model +
167 std::string(R"( %main "main" %var
168 OpName %main "main"
169 OpName %StorageBuffer "StorageBuffer"
170 OpMemberName %StorageBuffer 0 "index"
171 OpMemberName %StorageBuffer 1 "red"
172 OpName %sbo "sbo"
173 OpName %images "images"
174 OpMemberDecorate %StorageBuffer 0 Offset 0
175 OpMemberDecorate %StorageBuffer 1 Offset 4
176 OpDecorate %StorageBuffer BufferBlock
177 OpDecorate %sbo DescriptorSet 0
178 OpDecorate %sbo Binding 0
179 OpDecorate %images DescriptorSet 0
180 OpDecorate %images Binding 1
181 OpDecorate %images NonWritable
182 )") + std::string(R"(
183 ; CHECK: OpDecorate [[var:%\w+]] BuiltIn )") +
184 built_in + std::string(R"(
185 OpDecorate %var BuiltIn )") + built_in +
186 std::string(R"(
187 %void = OpTypeVoid
188 %3 = OpTypeFunction %void
189 %uint = OpTypeInt 32 0
190 %float = OpTypeFloat 32
191 %StorageBuffer = OpTypeStruct %uint %float
192 %_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer
193 %sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform
194 %int = OpTypeInt 32 1
195 %int_1 = OpConstant %int 1
196 %13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f
197 %_runtimearr_13 = OpTypeRuntimeArray %13
198 %_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13
199 %images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant
200 %_ptr_Input_uint = OpTypePointer Input %uint
201 %v4uint = OpTypeVector %uint 4
202 %_ptr_Input_v4uint = OpTypePointer Input %v4uint
203 %var = OpVariable )") + var_type +
204 std::string(R"( Input
205 %int_0 = OpConstant %int 0
206 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
207 %_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13
208 %v2int = OpTypeVector %int 2
209 %25 = OpConstantComposite %v2int %int_0 %int_0
210 %v4float = OpTypeVector %float 4
211 %uint_0 = OpConstant %uint 0
212 %_ptr_Uniform_float = OpTypePointer Uniform %float
213 %main = OpFunction %void None %3
214 %5 = OpLabel
215 %19 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0
216 %20 = OpLoad %uint %19
217 )") + var_value + std::string(R"(
218 %test = OpIAdd %uint %var_value %20
219 %22 = OpAccessChain %_ptr_UniformConstant_13 %images %test
220 %23 = OpLoad %13 %22
221 %27 = OpImageRead %v4float %23 %25
222 %29 = OpCompositeExtract %float %27 0
223 %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
224 OpStore %31 %29
225 OpReturn
226 OpFunctionEnd
227 )");
228
229 SinglePassRunAndMatch<SpreadVolatileSemantics>(text, true);
230 }
231
232 INSTANTIATE_TEST_SUITE_P(
233 SetLoadVolatile, SetLoadVolatileTest,
234 ::testing::ValuesIn(std::vector<ExecutionModelAndBuiltIn>{
235 {"RayGenerationKHR", "SubgroupSize", false},
236 {"RayGenerationKHR", "SubgroupLocalInvocationId", false},
237 {"RayGenerationKHR", "SubgroupEqMask", true},
238 {"ClosestHitKHR", "SubgroupLocalInvocationId", true},
239 {"IntersectionKHR", "SubgroupEqMask", true},
240 {"MissKHR", "SubgroupGeMask", true},
241 {"CallableKHR", "SubgroupGtMask", true},
242 {"RayGenerationKHR", "SubgroupLeMask", true},
243 }));
244
245 using VolatileSpreadTest = PassTest<::testing::Test>;
246
TEST_F(VolatileSpreadTest,SpreadVolatileForHelperInvocation)247 TEST_F(VolatileSpreadTest, SpreadVolatileForHelperInvocation) {
248 const std::string text =
249 R"(
250 OpCapability Shader
251 OpCapability DemoteToHelperInvocation
252 OpMemoryModel Logical GLSL450
253 OpEntryPoint Fragment %main "main" %var
254 OpExecutionMode %main OriginUpperLeft
255
256 ; CHECK: OpDecorate [[var:%\w+]] BuiltIn HelperInvocation
257 ; CHECK: OpDecorate [[var]] Volatile
258 OpDecorate %var BuiltIn HelperInvocation
259
260 %bool = OpTypeBool
261 %void = OpTypeVoid
262 %void_fn = OpTypeFunction %void
263 %_ptr_Input_bool = OpTypePointer Input %bool
264 %var = OpVariable %_ptr_Input_bool Input
265 %main = OpFunction %void None %void_fn
266 %entry = OpLabel
267 %load = OpLoad %bool %var
268 OpDemoteToHelperInvocation
269 OpReturn
270 OpFunctionEnd
271 )";
272
273 SetTargetEnv(SPV_ENV_UNIVERSAL_1_6);
274 SinglePassRunAndMatch<SpreadVolatileSemantics>(text, true);
275 }
276
TEST_F(VolatileSpreadTest,MultipleExecutionModel)277 TEST_F(VolatileSpreadTest, MultipleExecutionModel) {
278 const std::string text =
279 R"(
280 OpCapability RuntimeDescriptorArray
281 OpCapability RayTracingKHR
282 OpCapability SubgroupBallotKHR
283 OpExtension "SPV_EXT_descriptor_indexing"
284 OpExtension "SPV_KHR_ray_tracing"
285 OpExtension "SPV_KHR_shader_ballot"
286 %1 = OpExtInstImport "GLSL.std.450"
287 OpMemoryModel Logical GLSL450
288 OpEntryPoint RayGenerationKHR %RayGeneration "RayGeneration" %var
289 OpEntryPoint GLCompute %compute "Compute" %gl_LocalInvocationIndex
290 OpExecutionMode %compute LocalSize 16 16 1
291 OpSource GLSL 460
292 OpSourceExtension "GL_EXT_nonuniform_qualifier"
293 OpSourceExtension "GL_KHR_ray_tracing"
294 OpName %RayGeneration "RayGeneration"
295 OpName %StorageBuffer "StorageBuffer"
296 OpMemberName %StorageBuffer 0 "index"
297 OpMemberName %StorageBuffer 1 "red"
298 OpName %sbo "sbo"
299 OpName %images "images"
300 OpMemberDecorate %StorageBuffer 0 Offset 0
301 OpMemberDecorate %StorageBuffer 1 Offset 4
302 OpDecorate %gl_LocalInvocationIndex BuiltIn LocalInvocationIndex
303 OpDecorate %StorageBuffer BufferBlock
304 OpDecorate %sbo DescriptorSet 0
305 OpDecorate %sbo Binding 0
306 OpDecorate %images DescriptorSet 0
307 OpDecorate %images Binding 1
308 OpDecorate %images NonWritable
309
310 ; CHECK: OpEntryPoint RayGenerationNV {{%\w+}} "RayGeneration" [[var:%\w+]]
311 ; CHECK: OpDecorate [[var]] BuiltIn SubgroupSize
312 ; CHECK: OpDecorate [[var]] Volatile
313 ; CHECK-NOT: OpDecorate {{%\w+}} Volatile
314 OpDecorate %var BuiltIn SubgroupSize
315
316 %void = OpTypeVoid
317 %3 = OpTypeFunction %void
318 %uint = OpTypeInt 32 0
319 %float = OpTypeFloat 32
320 %StorageBuffer = OpTypeStruct %uint %float
321 %_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer
322 %sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform
323 %int = OpTypeInt 32 1
324 %int_1 = OpConstant %int 1
325 %13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f
326 %_runtimearr_13 = OpTypeRuntimeArray %13
327 %_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13
328 %images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant
329 %_ptr_Input_uint = OpTypePointer Input %uint
330 %var = OpVariable %_ptr_Input_uint Input
331 %int_0 = OpConstant %int 0
332 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
333 %_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13
334 %v2int = OpTypeVector %int 2
335 %25 = OpConstantComposite %v2int %int_0 %int_0
336 %v4float = OpTypeVector %float 4
337 %uint_0 = OpConstant %uint 0
338 %uint_1 = OpConstant %uint 1
339 %_ptr_Uniform_float = OpTypePointer Uniform %float
340 %gl_LocalInvocationIndex = OpVariable %_ptr_Input_uint Input
341 %_ptr_Workgroup_uint = OpTypePointer Workgroup %uint
342 %shared = OpVariable %_ptr_Workgroup_uint Workgroup
343
344 %RayGeneration = OpFunction %void None %3
345 %5 = OpLabel
346 %19 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0
347 %20 = OpLoad %uint %var
348 %22 = OpAccessChain %_ptr_UniformConstant_13 %images %20
349 %23 = OpLoad %13 %22
350 %27 = OpImageRead %v4float %23 %25
351 %29 = OpCompositeExtract %float %27 0
352 %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
353 OpStore %31 %29
354 OpReturn
355 OpFunctionEnd
356
357 %compute = OpFunction %void None %3
358 %66 = OpLabel
359 %62 = OpLoad %uint %gl_LocalInvocationIndex
360 %61 = OpAtomicIAdd %uint %shared %uint_1 %uint_0 %62
361 OpReturn
362 OpFunctionEnd
363 )";
364
365 SinglePassRunAndMatch<SpreadVolatileSemantics>(text, true);
366 }
367
TEST_F(VolatileSpreadTest,VarUsedInMultipleEntryPoints)368 TEST_F(VolatileSpreadTest, VarUsedInMultipleEntryPoints) {
369 const std::string text =
370 R"(
371 OpCapability RuntimeDescriptorArray
372 OpCapability RayTracingKHR
373 OpCapability SubgroupBallotKHR
374 OpExtension "SPV_EXT_descriptor_indexing"
375 OpExtension "SPV_KHR_ray_tracing"
376 OpExtension "SPV_KHR_shader_ballot"
377 %1 = OpExtInstImport "GLSL.std.450"
378 OpMemoryModel Logical GLSL450
379 OpEntryPoint RayGenerationKHR %RayGeneration "RayGeneration" %var
380 OpEntryPoint ClosestHitKHR %ClosestHit "ClosestHit" %var
381 OpSource GLSL 460
382 OpSourceExtension "GL_EXT_nonuniform_qualifier"
383 OpSourceExtension "GL_KHR_ray_tracing"
384 OpName %RayGeneration "RayGeneration"
385 OpName %ClosestHit "ClosestHit"
386 OpName %StorageBuffer "StorageBuffer"
387 OpMemberName %StorageBuffer 0 "index"
388 OpMemberName %StorageBuffer 1 "red"
389 OpName %sbo "sbo"
390 OpName %images "images"
391 OpMemberDecorate %StorageBuffer 0 Offset 0
392 OpMemberDecorate %StorageBuffer 1 Offset 4
393 OpDecorate %gl_LocalInvocationIndex BuiltIn LocalInvocationIndex
394 OpDecorate %StorageBuffer BufferBlock
395 OpDecorate %sbo DescriptorSet 0
396 OpDecorate %sbo Binding 0
397 OpDecorate %images DescriptorSet 0
398 OpDecorate %images Binding 1
399 OpDecorate %images NonWritable
400
401 ; CHECK: OpEntryPoint RayGenerationNV {{%\w+}} "RayGeneration" [[var:%\w+]]
402 ; CHECK: OpEntryPoint ClosestHitNV {{%\w+}} "ClosestHit" [[var]]
403 ; CHECK: OpDecorate [[var]] BuiltIn SubgroupSize
404 ; CHECK: OpDecorate [[var]] Volatile
405 ; CHECK-NOT: OpDecorate {{%\w+}} Volatile
406 OpDecorate %var BuiltIn SubgroupSize
407
408 %void = OpTypeVoid
409 %3 = OpTypeFunction %void
410 %uint = OpTypeInt 32 0
411 %float = OpTypeFloat 32
412 %StorageBuffer = OpTypeStruct %uint %float
413 %_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer
414 %sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform
415 %int = OpTypeInt 32 1
416 %int_1 = OpConstant %int 1
417 %13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f
418 %_runtimearr_13 = OpTypeRuntimeArray %13
419 %_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13
420 %images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant
421 %_ptr_Input_uint = OpTypePointer Input %uint
422 %var = OpVariable %_ptr_Input_uint Input
423 %int_0 = OpConstant %int 0
424 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
425 %_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13
426 %v2int = OpTypeVector %int 2
427 %25 = OpConstantComposite %v2int %int_0 %int_0
428 %v4float = OpTypeVector %float 4
429 %uint_0 = OpConstant %uint 0
430 %uint_1 = OpConstant %uint 1
431 %_ptr_Uniform_float = OpTypePointer Uniform %float
432 %gl_LocalInvocationIndex = OpVariable %_ptr_Input_uint Input
433 %_ptr_Workgroup_uint = OpTypePointer Workgroup %uint
434 %shared = OpVariable %_ptr_Workgroup_uint Workgroup
435
436 %RayGeneration = OpFunction %void None %3
437 %5 = OpLabel
438 %19 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0
439 %20 = OpLoad %uint %var
440 %22 = OpAccessChain %_ptr_UniformConstant_13 %images %20
441 %23 = OpLoad %13 %22
442 %27 = OpImageRead %v4float %23 %25
443 %29 = OpCompositeExtract %float %27 0
444 %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
445 OpStore %31 %29
446 OpReturn
447 OpFunctionEnd
448
449 %ClosestHit = OpFunction %void None %3
450 %45 = OpLabel
451 %49 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0
452 %40 = OpLoad %uint %var
453 %42 = OpAccessChain %_ptr_UniformConstant_13 %images %40
454 %43 = OpLoad %13 %42
455 %47 = OpImageRead %v4float %43 %25
456 %59 = OpCompositeExtract %float %47 0
457 %51 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
458 OpStore %51 %59
459 OpReturn
460 OpFunctionEnd
461 )";
462
463 SinglePassRunAndMatch<SpreadVolatileSemantics>(text, true);
464 }
465
466 class VolatileSpreadErrorTest : public PassTest<::testing::Test> {
467 public:
VolatileSpreadErrorTest()468 VolatileSpreadErrorTest()
469 : consumer_([this](spv_message_level_t level, const char*,
470 const spv_position_t& position, const char* message) {
471 if (!error_message_.empty()) error_message_ += "\n";
472 switch (level) {
473 case SPV_MSG_FATAL:
474 case SPV_MSG_INTERNAL_ERROR:
475 case SPV_MSG_ERROR:
476 error_message_ += "ERROR";
477 break;
478 case SPV_MSG_WARNING:
479 error_message_ += "WARNING";
480 break;
481 case SPV_MSG_INFO:
482 error_message_ += "INFO";
483 break;
484 case SPV_MSG_DEBUG:
485 error_message_ += "DEBUG";
486 break;
487 }
488 error_message_ +=
489 ": " + std::to_string(position.index) + ": " + message;
490 }) {}
491
RunPass(const std::string & text)492 Pass::Status RunPass(const std::string& text) {
493 std::unique_ptr<IRContext> context_ =
494 spvtools::BuildModule(SPV_ENV_UNIVERSAL_1_2, consumer_, text);
495 if (!context_.get()) return Pass::Status::Failure;
496
497 PassManager manager;
498 manager.SetMessageConsumer(consumer_);
499 manager.AddPass<SpreadVolatileSemantics>();
500
501 return manager.Run(context_.get());
502 }
503
GetErrorMessage() const504 std::string GetErrorMessage() const { return error_message_; }
505
TearDown()506 void TearDown() override { error_message_.clear(); }
507
508 private:
509 spvtools::MessageConsumer consumer_;
510 std::string error_message_;
511 };
512
TEST_F(VolatileSpreadErrorTest,VarUsedInMultipleExecutionModelError)513 TEST_F(VolatileSpreadErrorTest, VarUsedInMultipleExecutionModelError) {
514 const std::string text =
515 R"(
516 OpCapability RuntimeDescriptorArray
517 OpCapability RayTracingKHR
518 OpCapability SubgroupBallotKHR
519 OpExtension "SPV_EXT_descriptor_indexing"
520 OpExtension "SPV_KHR_ray_tracing"
521 OpExtension "SPV_KHR_shader_ballot"
522 %1 = OpExtInstImport "GLSL.std.450"
523 OpMemoryModel Logical GLSL450
524 OpEntryPoint RayGenerationKHR %RayGeneration "RayGeneration" %var
525 OpEntryPoint GLCompute %compute "Compute" %gl_LocalInvocationIndex %var
526 OpExecutionMode %compute LocalSize 16 16 1
527 OpSource GLSL 460
528 OpSourceExtension "GL_EXT_nonuniform_qualifier"
529 OpSourceExtension "GL_KHR_ray_tracing"
530 OpName %RayGeneration "RayGeneration"
531 OpName %StorageBuffer "StorageBuffer"
532 OpMemberName %StorageBuffer 0 "index"
533 OpMemberName %StorageBuffer 1 "red"
534 OpName %sbo "sbo"
535 OpName %images "images"
536 OpMemberDecorate %StorageBuffer 0 Offset 0
537 OpMemberDecorate %StorageBuffer 1 Offset 4
538 OpDecorate %gl_LocalInvocationIndex BuiltIn LocalInvocationIndex
539 OpDecorate %StorageBuffer BufferBlock
540 OpDecorate %sbo DescriptorSet 0
541 OpDecorate %sbo Binding 0
542 OpDecorate %images DescriptorSet 0
543 OpDecorate %images Binding 1
544 OpDecorate %images NonWritable
545 OpDecorate %var BuiltIn SubgroupSize
546 %void = OpTypeVoid
547 %3 = OpTypeFunction %void
548 %uint = OpTypeInt 32 0
549 %float = OpTypeFloat 32
550 %StorageBuffer = OpTypeStruct %uint %float
551 %_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer
552 %sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform
553 %int = OpTypeInt 32 1
554 %int_1 = OpConstant %int 1
555 %13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f
556 %_runtimearr_13 = OpTypeRuntimeArray %13
557 %_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13
558 %images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant
559 %_ptr_Input_uint = OpTypePointer Input %uint
560 %var = OpVariable %_ptr_Input_uint Input
561 %int_0 = OpConstant %int 0
562 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
563 %_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13
564 %v2int = OpTypeVector %int 2
565 %25 = OpConstantComposite %v2int %int_0 %int_0
566 %v4float = OpTypeVector %float 4
567 %uint_0 = OpConstant %uint 0
568 %uint_1 = OpConstant %uint 1
569 %_ptr_Uniform_float = OpTypePointer Uniform %float
570 %gl_LocalInvocationIndex = OpVariable %_ptr_Input_uint Input
571 %_ptr_Workgroup_uint = OpTypePointer Workgroup %uint
572 %shared = OpVariable %_ptr_Workgroup_uint Workgroup
573
574 %RayGeneration = OpFunction %void None %3
575 %5 = OpLabel
576 %19 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0
577 %20 = OpLoad %uint %var
578 %22 = OpAccessChain %_ptr_UniformConstant_13 %images %20
579 %23 = OpLoad %13 %22
580 %27 = OpImageRead %v4float %23 %25
581 %29 = OpCompositeExtract %float %27 0
582 %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
583 OpStore %31 %29
584 OpReturn
585 OpFunctionEnd
586
587 %compute = OpFunction %void None %3
588 %66 = OpLabel
589 %62 = OpLoad %uint %gl_LocalInvocationIndex
590 %63 = OpLoad %uint %var
591 %64 = OpIAdd %uint %62 %63
592 %61 = OpAtomicIAdd %uint %shared %uint_1 %uint_0 %64
593 OpReturn
594 OpFunctionEnd
595 )";
596
597 EXPECT_EQ(RunPass(text), Pass::Status::Failure);
598 const char expected_error[] =
599 "ERROR: 0: Variable is a target for Volatile semantics for an entry "
600 "point, but it is not for another entry point";
601 EXPECT_STREQ(GetErrorMessage().substr(0, sizeof(expected_error) - 1).c_str(),
602 expected_error);
603 }
604
TEST_F(VolatileSpreadErrorTest,VarUsedInMultipleReverseOrderExecutionModelError)605 TEST_F(VolatileSpreadErrorTest,
606 VarUsedInMultipleReverseOrderExecutionModelError) {
607 const std::string text =
608 R"(
609 OpCapability RuntimeDescriptorArray
610 OpCapability RayTracingKHR
611 OpCapability SubgroupBallotKHR
612 OpExtension "SPV_EXT_descriptor_indexing"
613 OpExtension "SPV_KHR_ray_tracing"
614 OpExtension "SPV_KHR_shader_ballot"
615 %1 = OpExtInstImport "GLSL.std.450"
616 OpMemoryModel Logical GLSL450
617 OpEntryPoint GLCompute %compute "Compute" %gl_LocalInvocationIndex %var
618 OpEntryPoint RayGenerationKHR %RayGeneration "RayGeneration" %var
619 OpExecutionMode %compute LocalSize 16 16 1
620 OpSource GLSL 460
621 OpSourceExtension "GL_EXT_nonuniform_qualifier"
622 OpSourceExtension "GL_KHR_ray_tracing"
623 OpName %RayGeneration "RayGeneration"
624 OpName %StorageBuffer "StorageBuffer"
625 OpMemberName %StorageBuffer 0 "index"
626 OpMemberName %StorageBuffer 1 "red"
627 OpName %sbo "sbo"
628 OpName %images "images"
629 OpMemberDecorate %StorageBuffer 0 Offset 0
630 OpMemberDecorate %StorageBuffer 1 Offset 4
631 OpDecorate %gl_LocalInvocationIndex BuiltIn LocalInvocationIndex
632 OpDecorate %StorageBuffer BufferBlock
633 OpDecorate %sbo DescriptorSet 0
634 OpDecorate %sbo Binding 0
635 OpDecorate %images DescriptorSet 0
636 OpDecorate %images Binding 1
637 OpDecorate %images NonWritable
638 OpDecorate %var BuiltIn SubgroupSize
639 %void = OpTypeVoid
640 %3 = OpTypeFunction %void
641 %uint = OpTypeInt 32 0
642 %float = OpTypeFloat 32
643 %StorageBuffer = OpTypeStruct %uint %float
644 %_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer
645 %sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform
646 %int = OpTypeInt 32 1
647 %int_1 = OpConstant %int 1
648 %13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f
649 %_runtimearr_13 = OpTypeRuntimeArray %13
650 %_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13
651 %images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant
652 %_ptr_Input_uint = OpTypePointer Input %uint
653 %var = OpVariable %_ptr_Input_uint Input
654 %int_0 = OpConstant %int 0
655 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
656 %_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13
657 %v2int = OpTypeVector %int 2
658 %25 = OpConstantComposite %v2int %int_0 %int_0
659 %v4float = OpTypeVector %float 4
660 %uint_0 = OpConstant %uint 0
661 %uint_1 = OpConstant %uint 1
662 %_ptr_Uniform_float = OpTypePointer Uniform %float
663 %gl_LocalInvocationIndex = OpVariable %_ptr_Input_uint Input
664 %_ptr_Workgroup_uint = OpTypePointer Workgroup %uint
665 %shared = OpVariable %_ptr_Workgroup_uint Workgroup
666
667 %RayGeneration = OpFunction %void None %3
668 %5 = OpLabel
669 %19 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0
670 %20 = OpLoad %uint %var
671 %22 = OpAccessChain %_ptr_UniformConstant_13 %images %20
672 %23 = OpLoad %13 %22
673 %27 = OpImageRead %v4float %23 %25
674 %29 = OpCompositeExtract %float %27 0
675 %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
676 OpStore %31 %29
677 OpReturn
678 OpFunctionEnd
679
680 %compute = OpFunction %void None %3
681 %66 = OpLabel
682 %62 = OpLoad %uint %gl_LocalInvocationIndex
683 %63 = OpLoad %uint %var
684 %64 = OpIAdd %uint %62 %63
685 %61 = OpAtomicIAdd %uint %shared %uint_1 %uint_0 %64
686 OpReturn
687 OpFunctionEnd
688 )";
689
690 EXPECT_EQ(RunPass(text), Pass::Status::Failure);
691 const char expected_error[] =
692 "ERROR: 0: Variable is a target for Volatile semantics for an entry "
693 "point, but it is not for another entry point";
694 EXPECT_STREQ(GetErrorMessage().substr(0, sizeof(expected_error) - 1).c_str(),
695 expected_error);
696 }
697
TEST_F(VolatileSpreadErrorTest,FunctionNotInlined)698 TEST_F(VolatileSpreadErrorTest, FunctionNotInlined) {
699 const std::string text =
700 R"(
701 OpCapability RuntimeDescriptorArray
702 OpCapability RayTracingKHR
703 OpCapability SubgroupBallotKHR
704 OpExtension "SPV_EXT_descriptor_indexing"
705 OpExtension "SPV_KHR_ray_tracing"
706 OpExtension "SPV_KHR_shader_ballot"
707 %1 = OpExtInstImport "GLSL.std.450"
708 OpMemoryModel Logical GLSL450
709 OpEntryPoint RayGenerationKHR %RayGeneration "RayGeneration" %var
710 OpEntryPoint ClosestHitKHR %ClosestHit "ClosestHit" %var
711 OpSource GLSL 460
712 OpSourceExtension "GL_EXT_nonuniform_qualifier"
713 OpSourceExtension "GL_KHR_ray_tracing"
714 OpName %RayGeneration "RayGeneration"
715 OpName %ClosestHit "ClosestHit"
716 OpName %StorageBuffer "StorageBuffer"
717 OpMemberName %StorageBuffer 0 "index"
718 OpMemberName %StorageBuffer 1 "red"
719 OpName %sbo "sbo"
720 OpName %images "images"
721 OpMemberDecorate %StorageBuffer 0 Offset 0
722 OpMemberDecorate %StorageBuffer 1 Offset 4
723 OpDecorate %gl_LocalInvocationIndex BuiltIn LocalInvocationIndex
724 OpDecorate %StorageBuffer BufferBlock
725 OpDecorate %sbo DescriptorSet 0
726 OpDecorate %sbo Binding 0
727 OpDecorate %images DescriptorSet 0
728 OpDecorate %images Binding 1
729 OpDecorate %images NonWritable
730 OpDecorate %var BuiltIn SubgroupSize
731 %void = OpTypeVoid
732 %3 = OpTypeFunction %void
733 %uint = OpTypeInt 32 0
734 %float = OpTypeFloat 32
735 %StorageBuffer = OpTypeStruct %uint %float
736 %_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer
737 %sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform
738 %int = OpTypeInt 32 1
739 %int_1 = OpConstant %int 1
740 %13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f
741 %_runtimearr_13 = OpTypeRuntimeArray %13
742 %_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13
743 %images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant
744 %_ptr_Input_uint = OpTypePointer Input %uint
745 %var = OpVariable %_ptr_Input_uint Input
746 %int_0 = OpConstant %int 0
747 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
748 %_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13
749 %v2int = OpTypeVector %int 2
750 %25 = OpConstantComposite %v2int %int_0 %int_0
751 %v4float = OpTypeVector %float 4
752 %uint_0 = OpConstant %uint 0
753 %uint_1 = OpConstant %uint 1
754 %_ptr_Uniform_float = OpTypePointer Uniform %float
755 %gl_LocalInvocationIndex = OpVariable %_ptr_Input_uint Input
756 %_ptr_Workgroup_uint = OpTypePointer Workgroup %uint
757 %shared = OpVariable %_ptr_Workgroup_uint Workgroup
758
759 %RayGeneration = OpFunction %void None %3
760 %5 = OpLabel
761 %19 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0
762 %20 = OpLoad %uint %19
763 %22 = OpAccessChain %_ptr_UniformConstant_13 %images %20
764 %23 = OpLoad %13 %22
765 %27 = OpImageRead %v4float %23 %25
766 %29 = OpCompositeExtract %float %27 0
767 %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
768 OpStore %31 %29
769 OpReturn
770 OpFunctionEnd
771
772 %NotInlined = OpFunction %void None %3
773 %32 = OpLabel
774 OpReturn
775 OpFunctionEnd
776
777 %ClosestHit = OpFunction %void None %3
778 %45 = OpLabel
779 %49 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0
780 %40 = OpLoad %uint %49
781 %42 = OpAccessChain %_ptr_UniformConstant_13 %images %40
782 %43 = OpLoad %13 %42
783 %47 = OpImageRead %v4float %43 %25
784 %59 = OpCompositeExtract %float %47 0
785 %51 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
786 OpStore %51 %59
787 OpReturn
788 OpFunctionEnd
789 )";
790
791 EXPECT_EQ(RunPass(text), Pass::Status::SuccessWithoutChange);
792 }
793
TEST_F(VolatileSpreadErrorTest,VarNotUsedInEntryPointForVolatile)794 TEST_F(VolatileSpreadErrorTest, VarNotUsedInEntryPointForVolatile) {
795 const std::string text =
796 R"(
797 OpCapability RuntimeDescriptorArray
798 OpCapability RayTracingKHR
799 OpCapability SubgroupBallotKHR
800 OpExtension "SPV_EXT_descriptor_indexing"
801 OpExtension "SPV_KHR_ray_tracing"
802 OpExtension "SPV_KHR_shader_ballot"
803 %1 = OpExtInstImport "GLSL.std.450"
804 OpMemoryModel Logical GLSL450
805 OpEntryPoint RayGenerationKHR %RayGeneration "RayGeneration" %var
806 OpEntryPoint GLCompute %compute "Compute" %gl_LocalInvocationIndex %var
807 OpExecutionMode %compute LocalSize 16 16 1
808 OpSource GLSL 460
809 OpSourceExtension "GL_EXT_nonuniform_qualifier"
810 OpSourceExtension "GL_KHR_ray_tracing"
811 OpName %RayGeneration "RayGeneration"
812 OpName %StorageBuffer "StorageBuffer"
813 OpMemberName %StorageBuffer 0 "index"
814 OpMemberName %StorageBuffer 1 "red"
815 OpName %sbo "sbo"
816 OpName %images "images"
817 OpMemberDecorate %StorageBuffer 0 Offset 0
818 OpMemberDecorate %StorageBuffer 1 Offset 4
819 OpDecorate %gl_LocalInvocationIndex BuiltIn LocalInvocationIndex
820 OpDecorate %StorageBuffer BufferBlock
821 OpDecorate %sbo DescriptorSet 0
822 OpDecorate %sbo Binding 0
823 OpDecorate %images DescriptorSet 0
824 OpDecorate %images Binding 1
825 OpDecorate %images NonWritable
826
827 ; CHECK-NOT: OpDecorate {{%\w+}} Volatile
828
829 OpDecorate %var BuiltIn SubgroupSize
830 %void = OpTypeVoid
831 %3 = OpTypeFunction %void
832 %uint = OpTypeInt 32 0
833 %float = OpTypeFloat 32
834 %StorageBuffer = OpTypeStruct %uint %float
835 %_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer
836 %sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform
837 %int = OpTypeInt 32 1
838 %int_1 = OpConstant %int 1
839 %13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f
840 %_runtimearr_13 = OpTypeRuntimeArray %13
841 %_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13
842 %images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant
843 %_ptr_Input_uint = OpTypePointer Input %uint
844 %var = OpVariable %_ptr_Input_uint Input
845 %int_0 = OpConstant %int 0
846 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
847 %_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13
848 %v2int = OpTypeVector %int 2
849 %25 = OpConstantComposite %v2int %int_0 %int_0
850 %v4float = OpTypeVector %float 4
851 %uint_0 = OpConstant %uint 0
852 %uint_1 = OpConstant %uint 1
853 %_ptr_Uniform_float = OpTypePointer Uniform %float
854 %gl_LocalInvocationIndex = OpVariable %_ptr_Input_uint Input
855 %_ptr_Workgroup_uint = OpTypePointer Workgroup %uint
856 %shared = OpVariable %_ptr_Workgroup_uint Workgroup
857
858 %RayGeneration = OpFunction %void None %3
859 %5 = OpLabel
860 %19 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0
861 %20 = OpLoad %uint %19
862 %22 = OpAccessChain %_ptr_UniformConstant_13 %images %20
863 %23 = OpLoad %13 %22
864 %27 = OpImageRead %v4float %23 %25
865 %29 = OpCompositeExtract %float %27 0
866 %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1
867 OpStore %31 %29
868 OpReturn
869 OpFunctionEnd
870
871 %compute = OpFunction %void None %3
872 %66 = OpLabel
873 %62 = OpLoad %uint %gl_LocalInvocationIndex
874 %63 = OpLoad %uint %var
875 %64 = OpIAdd %uint %62 %63
876 %61 = OpAtomicIAdd %uint %shared %uint_1 %uint_0 %64
877 OpReturn
878 OpFunctionEnd
879 )";
880
881 SinglePassRunAndMatch<SpreadVolatileSemantics>(text, true);
882 }
883
TEST_F(VolatileSpreadTest,RecursivelySpreadVolatile)884 TEST_F(VolatileSpreadTest, RecursivelySpreadVolatile) {
885 const std::string text =
886 R"(
887 OpCapability RuntimeDescriptorArray
888 OpCapability RayTracingKHR
889 OpCapability SubgroupBallotKHR
890 OpCapability VulkanMemoryModel
891 OpExtension "SPV_KHR_vulkan_memory_model"
892 OpExtension "SPV_EXT_descriptor_indexing"
893 OpExtension "SPV_KHR_ray_tracing"
894 OpExtension "SPV_KHR_shader_ballot"
895 %1 = OpExtInstImport "GLSL.std.450"
896 OpMemoryModel Logical Vulkan
897 OpEntryPoint RayGenerationKHR %RayGeneration "RayGeneration" %var0 %var1
898 OpSource GLSL 460
899 OpSourceExtension "GL_EXT_nonuniform_qualifier"
900 OpSourceExtension "GL_KHR_ray_tracing"
901 OpName %RayGeneration "RayGeneration"
902 OpName %StorageBuffer "StorageBuffer"
903 OpMemberName %StorageBuffer 0 "index"
904 OpMemberName %StorageBuffer 1 "red"
905 OpName %sbo "sbo"
906 OpName %images "images"
907 OpMemberDecorate %StorageBuffer 0 Offset 0
908 OpMemberDecorate %StorageBuffer 1 Offset 4
909 OpDecorate %StorageBuffer BufferBlock
910 OpDecorate %sbo DescriptorSet 0
911 OpDecorate %sbo Binding 0
912 OpDecorate %images DescriptorSet 0
913 OpDecorate %images Binding 1
914 OpDecorate %images NonWritable
915
916 ; CHECK: OpDecorate [[var0:%\w+]] BuiltIn SubgroupEqMask
917 ; CHECK: OpDecorate [[var1:%\w+]] BuiltIn SubgroupGeMask
918 OpDecorate %var0 BuiltIn SubgroupEqMask
919 OpDecorate %var1 BuiltIn SubgroupGeMask
920
921 %void = OpTypeVoid
922 %3 = OpTypeFunction %void
923 %uint = OpTypeInt 32 0
924 %float = OpTypeFloat 32
925 %StorageBuffer = OpTypeStruct %uint %float
926 %_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer
927 %sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform
928 %int = OpTypeInt 32 1
929 %int_1 = OpConstant %int 1
930 %13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f
931 %_runtimearr_13 = OpTypeRuntimeArray %13
932 %_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13
933 %images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant
934 %v4uint = OpTypeVector %uint 4
935 %_ptr_Input_v4uint = OpTypePointer Input %v4uint
936 %_ptr_Input_uint = OpTypePointer Input %uint
937 %var0 = OpVariable %_ptr_Input_v4uint Input
938 %var1 = OpVariable %_ptr_Input_v4uint Input
939 %int_0 = OpConstant %int 0
940 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
941 %_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13
942 %v2int = OpTypeVector %int 2
943 %25 = OpConstantComposite %v2int %int_0 %int_0
944 %v4float = OpTypeVector %float 4
945 %uint_0 = OpConstant %uint 0
946 %uint_1 = OpConstant %uint 1
947 %_ptr_Uniform_float = OpTypePointer Uniform %float
948
949 %RayGeneration = OpFunction %void None %3
950 %5 = OpLabel
951
952 ; CHECK: [[ptr0:%\w+]] = OpAccessChain %_ptr_Input_uint [[var0]] %int_0
953 ; CHECK: OpLoad {{%\w+}} [[ptr0]] Volatile
954 %19 = OpAccessChain %_ptr_Input_uint %var0 %int_0
955 %20 = OpLoad %uint %19
956
957 %22 = OpAccessChain %_ptr_UniformConstant_13 %images %20
958 %23 = OpLoad %13 %22
959 %27 = OpImageRead %v4float %23 %25
960 %29 = OpCompositeExtract %float %27 0
961 %31 = OpAccessChain %_ptr_Uniform_float %sbo %uint_1
962
963 ; CHECK: OpLoad {{%\w+}} [[ptr0]] Volatile
964 %24 = OpLoad %uint %19
965
966 ; CHECK: [[var2:%\w+]] = OpCopyObject %_ptr_Input_v4uint [[var0]]
967 ; CHECK: [[ptr2:%\w+]] = OpAccessChain %_ptr_Input_uint [[var2]] %int_1
968 ; CHECK: OpLoad {{%\w+}} [[ptr2]] Volatile
969 %18 = OpCopyObject %_ptr_Input_v4uint %var0
970 %21 = OpAccessChain %_ptr_Input_uint %18 %int_1
971 %26 = OpLoad %uint %21
972
973 %28 = OpIAdd %uint %24 %26
974 %30 = OpConvertUToF %float %28
975
976 ; CHECK: [[ptr1:%\w+]] = OpAccessChain %_ptr_Input_uint [[var1]] %int_1
977 ; CHECK: OpLoad {{%\w+}} [[ptr1]] Volatile
978 %32 = OpAccessChain %_ptr_Input_uint %var1 %int_1
979 %33 = OpLoad %uint %32
980
981 %34 = OpConvertUToF %float %33
982 %35 = OpFAdd %float %34 %30
983 %36 = OpFAdd %float %35 %29
984 OpStore %31 %36
985 OpReturn
986 OpFunctionEnd
987 )";
988
989 SinglePassRunAndMatch<SpreadVolatileSemantics>(text, true);
990 }
991
TEST_F(VolatileSpreadTest,SpreadVolatileOnlyForTargetEntryPoints)992 TEST_F(VolatileSpreadTest, SpreadVolatileOnlyForTargetEntryPoints) {
993 const std::string text =
994 R"(
995 OpCapability RuntimeDescriptorArray
996 OpCapability RayTracingKHR
997 OpCapability SubgroupBallotKHR
998 OpCapability VulkanMemoryModel
999 OpCapability VulkanMemoryModelDeviceScopeKHR
1000 OpExtension "SPV_KHR_vulkan_memory_model"
1001 OpExtension "SPV_EXT_descriptor_indexing"
1002 OpExtension "SPV_KHR_ray_tracing"
1003 OpExtension "SPV_KHR_shader_ballot"
1004 %1 = OpExtInstImport "GLSL.std.450"
1005 OpMemoryModel Logical Vulkan
1006 OpEntryPoint RayGenerationKHR %RayGeneration "RayGeneration" %var0 %var1
1007 OpEntryPoint GLCompute %compute "Compute" %var0 %var1
1008 OpExecutionMode %compute LocalSize 16 16 1
1009 OpSource GLSL 460
1010 OpSourceExtension "GL_EXT_nonuniform_qualifier"
1011 OpSourceExtension "GL_KHR_ray_tracing"
1012 OpName %RayGeneration "RayGeneration"
1013 OpName %StorageBuffer "StorageBuffer"
1014 OpMemberName %StorageBuffer 0 "index"
1015 OpMemberName %StorageBuffer 1 "red"
1016 OpName %sbo "sbo"
1017 OpName %images "images"
1018 OpMemberDecorate %StorageBuffer 0 Offset 0
1019 OpMemberDecorate %StorageBuffer 1 Offset 4
1020 OpDecorate %StorageBuffer BufferBlock
1021 OpDecorate %sbo DescriptorSet 0
1022 OpDecorate %sbo Binding 0
1023 OpDecorate %images DescriptorSet 0
1024 OpDecorate %images Binding 1
1025 OpDecorate %images NonWritable
1026
1027 ; CHECK: OpDecorate [[var0:%\w+]] BuiltIn SubgroupEqMask
1028 ; CHECK: OpDecorate [[var1:%\w+]] BuiltIn SubgroupGeMask
1029 OpDecorate %var0 BuiltIn SubgroupEqMask
1030 OpDecorate %var1 BuiltIn SubgroupGeMask
1031
1032 %void = OpTypeVoid
1033 %3 = OpTypeFunction %void
1034 %uint = OpTypeInt 32 0
1035 %float = OpTypeFloat 32
1036 %StorageBuffer = OpTypeStruct %uint %float
1037 %_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer
1038 %sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform
1039 %int = OpTypeInt 32 1
1040 %int_1 = OpConstant %int 1
1041 %13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f
1042 %_runtimearr_13 = OpTypeRuntimeArray %13
1043 %_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13
1044 %images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant
1045 %v4uint = OpTypeVector %uint 4
1046 %_ptr_Input_v4uint = OpTypePointer Input %v4uint
1047 %_ptr_Input_uint = OpTypePointer Input %uint
1048 %var0 = OpVariable %_ptr_Input_v4uint Input
1049 %var1 = OpVariable %_ptr_Input_v4uint Input
1050 %int_0 = OpConstant %int 0
1051 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
1052 %_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13
1053 %v2int = OpTypeVector %int 2
1054 %25 = OpConstantComposite %v2int %int_0 %int_0
1055 %v4float = OpTypeVector %float 4
1056 %uint_0 = OpConstant %uint 0
1057 %uint_1 = OpConstant %uint 1
1058 %_ptr_Uniform_float = OpTypePointer Uniform %float
1059 %_ptr_Workgroup_uint = OpTypePointer Workgroup %uint
1060 %shared = OpVariable %_ptr_Workgroup_uint Workgroup
1061
1062 %RayGeneration = OpFunction %void None %3
1063 %5 = OpLabel
1064
1065 ; CHECK: [[ptr0:%\w+]] = OpAccessChain %_ptr_Input_uint [[var0]] %int_0
1066 ; CHECK: OpLoad {{%\w+}} [[ptr0]] Volatile
1067 %19 = OpAccessChain %_ptr_Input_uint %var0 %int_0
1068 %20 = OpLoad %uint %19
1069
1070 %22 = OpAccessChain %_ptr_UniformConstant_13 %images %20
1071 %23 = OpLoad %13 %22
1072 %27 = OpImageRead %v4float %23 %25
1073 %29 = OpCompositeExtract %float %27 0
1074 %31 = OpAccessChain %_ptr_Uniform_float %sbo %uint_1
1075
1076 ; CHECK: OpLoad {{%\w+}} [[ptr0]] Volatile
1077 %24 = OpLoad %uint %19
1078
1079 ; CHECK: [[var2:%\w+]] = OpCopyObject %_ptr_Input_v4uint [[var0]]
1080 ; CHECK: [[ptr2:%\w+]] = OpAccessChain %_ptr_Input_uint [[var2]] %int_1
1081 ; CHECK: OpLoad {{%\w+}} [[ptr2]] Volatile
1082 %18 = OpCopyObject %_ptr_Input_v4uint %var0
1083 %21 = OpAccessChain %_ptr_Input_uint %18 %int_1
1084 %26 = OpLoad %uint %21
1085
1086 %28 = OpIAdd %uint %24 %26
1087 %30 = OpConvertUToF %float %28
1088
1089 ; CHECK: [[ptr1:%\w+]] = OpAccessChain %_ptr_Input_uint [[var1]] %int_1
1090 ; CHECK: OpLoad {{%\w+}} [[ptr1]] Volatile
1091 %32 = OpAccessChain %_ptr_Input_uint %var1 %int_1
1092 %33 = OpLoad %uint %32
1093
1094 %34 = OpConvertUToF %float %33
1095 %35 = OpFAdd %float %34 %30
1096 %36 = OpFAdd %float %35 %29
1097 OpStore %31 %36
1098 OpReturn
1099 OpFunctionEnd
1100
1101 %compute = OpFunction %void None %3
1102 %66 = OpLabel
1103
1104 ; CHECK-NOT: OpLoad {{%\w+}} {{%\w+}} Volatile
1105 %62 = OpLoad %v4uint %var0
1106 %63 = OpLoad %v4uint %var1
1107 %64 = OpIAdd %v4uint %62 %63
1108 %65 = OpCompositeExtract %uint %64 0
1109 %61 = OpAtomicIAdd %uint %shared %uint_1 %uint_0 %65
1110 OpReturn
1111 OpFunctionEnd
1112 )";
1113
1114 SinglePassRunAndMatch<SpreadVolatileSemantics>(text, true);
1115 }
1116
TEST_F(VolatileSpreadTest,SkipIfItHasNoExecutionModel)1117 TEST_F(VolatileSpreadTest, SkipIfItHasNoExecutionModel) {
1118 const std::string text = R"(
1119 OpCapability Shader
1120 OpCapability Linkage
1121 OpMemoryModel Logical GLSL450
1122 %2 = OpTypeVoid
1123 %3 = OpTypeFunction %2
1124 %4 = OpFunction %2 None %3
1125 %5 = OpLabel
1126 OpReturn
1127 OpFunctionEnd
1128 )";
1129
1130 Pass::Status status;
1131 std::tie(std::ignore, status) =
1132 SinglePassRunToBinary<SpreadVolatileSemantics>(text,
1133 /* skip_nop = */ false);
1134 EXPECT_EQ(status, Pass::Status::SuccessWithoutChange);
1135 }
1136
TEST_F(VolatileSpreadTest,NoInlinedfuncCalls)1137 TEST_F(VolatileSpreadTest, NoInlinedfuncCalls) {
1138 const std::string text = R"(
1139 OpCapability RayTracingNV
1140 OpCapability VulkanMemoryModel
1141 OpCapability GroupNonUniform
1142 OpExtension "SPV_NV_ray_tracing"
1143 OpExtension "SPV_KHR_vulkan_memory_model"
1144 OpMemoryModel Logical Vulkan
1145 OpEntryPoint RayGenerationNV %main "main" %SubgroupSize
1146 OpSource HLSL 630
1147 OpName %main "main"
1148 OpName %src_main "src.main"
1149 OpName %bb_entry "bb.entry"
1150 OpName %func0 "func0"
1151 OpName %bb_entry_0 "bb.entry"
1152 OpName %func2 "func2"
1153 OpName %bb_entry_1 "bb.entry"
1154 OpName %param_var_count "param.var.count"
1155 OpName %func1 "func1"
1156 OpName %bb_entry_2 "bb.entry"
1157 OpName %func3 "func3"
1158 OpName %count "count"
1159 OpName %bb_entry_3 "bb.entry"
1160 OpDecorate %SubgroupSize BuiltIn SubgroupSize
1161 %uint = OpTypeInt 32 0
1162 %_ptr_Input_uint = OpTypePointer Input %uint
1163 %void = OpTypeVoid
1164 %6 = OpTypeFunction %void
1165 %_ptr_Function_uint = OpTypePointer Function %uint
1166 %25 = OpTypeFunction %void %_ptr_Function_uint
1167 %SubgroupSize = OpVariable %_ptr_Input_uint Input
1168 %main = OpFunction %void None %6
1169 %7 = OpLabel
1170 %8 = OpFunctionCall %void %src_main
1171 OpReturn
1172 OpFunctionEnd
1173 %src_main = OpFunction %void None %6
1174 %bb_entry = OpLabel
1175 %11 = OpFunctionCall %void %func0
1176 OpReturn
1177 OpFunctionEnd
1178 %func0 = OpFunction %void DontInline %6
1179 %bb_entry_0 = OpLabel
1180 %14 = OpFunctionCall %void %func2
1181 %16 = OpFunctionCall %void %func1
1182 OpReturn
1183 OpFunctionEnd
1184 %func2 = OpFunction %void DontInline %6
1185 %bb_entry_1 = OpLabel
1186 %param_var_count = OpVariable %_ptr_Function_uint Function
1187 ; CHECK: {{%\w+}} = OpLoad %uint %SubgroupSize Volatile
1188 %21 = OpLoad %uint %SubgroupSize
1189 OpStore %param_var_count %21
1190 %22 = OpFunctionCall %void %func3 %param_var_count
1191 OpReturn
1192 OpFunctionEnd
1193 %func1 = OpFunction %void DontInline %6
1194 %bb_entry_2 = OpLabel
1195 OpReturn
1196 OpFunctionEnd
1197 %func3 = OpFunction %void DontInline %25
1198 %count = OpFunctionParameter %_ptr_Function_uint
1199 %bb_entry_3 = OpLabel
1200 OpReturn
1201 OpFunctionEnd
1202 )";
1203 SinglePassRunAndMatch<SpreadVolatileSemantics>(text, true);
1204 }
1205
TEST_F(VolatileSpreadErrorTest,NoInlinedMultiEntryfuncCalls)1206 TEST_F(VolatileSpreadErrorTest, NoInlinedMultiEntryfuncCalls) {
1207 const std::string text = R"(
1208 OpCapability RayTracingNV
1209 OpCapability SubgroupBallotKHR
1210 OpExtension "SPV_NV_ray_tracing"
1211 OpExtension "SPV_KHR_shader_ballot"
1212 %1 = OpExtInstImport "GLSL.std.450"
1213 OpMemoryModel Logical GLSL450
1214 OpEntryPoint RayGenerationNV %main "main" %SubgroupSize
1215 OpEntryPoint GLCompute %main2 "main2" %gl_LocalInvocationIndex %SubgroupSize
1216 OpSource HLSL 630
1217 OpName %main "main"
1218 OpName %bb_entry "bb.entry"
1219 OpName %main2 "main2"
1220 OpName %bb_entry_0 "bb.entry"
1221 OpName %func "func"
1222 OpName %count "count"
1223 OpName %bb_entry_1 "bb.entry"
1224 OpDecorate %gl_LocalInvocationIndex BuiltIn LocalInvocationIndex
1225 OpDecorate %SubgroupSize BuiltIn SubgroupSize
1226 %uint = OpTypeInt 32 0
1227 %uint_0 = OpConstant %uint 0
1228 %_ptr_Input_uint = OpTypePointer Input %uint
1229 %float = OpTypeFloat 32
1230 %v4float = OpTypeVector %float 4
1231 %void = OpTypeVoid
1232 %12 = OpTypeFunction %void
1233 %_ptr_Function_uint = OpTypePointer Function %uint
1234 %_ptr_Function_v4float = OpTypePointer Function %v4float
1235 %29 = OpTypeFunction %void %_ptr_Function_v4float
1236 %34 = OpTypeFunction %void %_ptr_Function_uint
1237 %SubgroupSize = OpVariable %_ptr_Input_uint Input
1238 %gl_LocalInvocationIndex = OpVariable %_ptr_Input_uint Input
1239 %main = OpFunction %void None %12
1240 %bb_entry = OpLabel
1241 %20 = OpFunctionCall %void %func
1242 OpReturn
1243 OpFunctionEnd
1244 %main2 = OpFunction %void None %12
1245 %bb_entry_0 = OpLabel
1246 %33 = OpFunctionCall %void %func
1247 OpReturn
1248 OpFunctionEnd
1249 %func = OpFunction %void DontInline %12
1250 %bb_entry_1 = OpLabel
1251 %count = OpVariable %_ptr_Function_uint Function
1252 %35 = OpLoad %uint %SubgroupSize
1253 OpStore %count %35
1254 OpReturn
1255 OpFunctionEnd
1256 )";
1257 EXPECT_EQ(RunPass(text), Pass::Status::Failure);
1258 const char expected_error[] =
1259 "ERROR: 0: Variable is a target for Volatile semantics for an entry "
1260 "point, but it is not for another entry point";
1261 EXPECT_STREQ(GetErrorMessage().substr(0, sizeof(expected_error) - 1).c_str(),
1262 expected_error);
1263 }
1264
1265 } // namespace
1266 } // namespace opt
1267 } // namespace spvtools
1268