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