• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2017 Google Inc.
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 <sstream>
16 #include <string>
17 
18 #include "gmock/gmock.h"
19 #include "test/unit_spirv.h"
20 #include "test/val/val_fixtures.h"
21 
22 namespace spvtools {
23 namespace val {
24 namespace {
25 
26 using ::testing::HasSubstr;
27 using ::testing::Not;
28 
29 using ValidateAtomics = spvtest::ValidateBase<bool>;
30 
GenerateShaderCodeImpl(const std::string & body,const std::string & capabilities_and_extensions,const std::string & definitions,const std::string & memory_model,const std::string & execution)31 std::string GenerateShaderCodeImpl(
32     const std::string& body, const std::string& capabilities_and_extensions,
33     const std::string& definitions, const std::string& memory_model,
34     const std::string& execution) {
35   std::ostringstream ss;
36   ss << R"(
37 OpCapability Shader
38 )";
39   ss << capabilities_and_extensions;
40   ss << "OpMemoryModel Logical " << memory_model << "\n";
41   ss << execution;
42   ss << R"(
43 %void = OpTypeVoid
44 %func = OpTypeFunction %void
45 %bool = OpTypeBool
46 %f32 = OpTypeFloat 32
47 %u32 = OpTypeInt 32 0
48 %f32vec4 = OpTypeVector %f32 4
49 
50 %f32_0 = OpConstant %f32 0
51 %f32_1 = OpConstant %f32 1
52 %u32_0 = OpConstant %u32 0
53 %u32_1 = OpConstant %u32 1
54 %f32vec4_0000 = OpConstantComposite %f32vec4 %f32_0 %f32_0 %f32_0 %f32_0
55 
56 %cross_device = OpConstant %u32 0
57 %device = OpConstant %u32 1
58 %workgroup = OpConstant %u32 2
59 %subgroup = OpConstant %u32 3
60 %invocation = OpConstant %u32 4
61 %queuefamily = OpConstant %u32 5
62 
63 %relaxed = OpConstant %u32 0
64 %acquire = OpConstant %u32 2
65 %release = OpConstant %u32 4
66 %acquire_release = OpConstant %u32 8
67 %acquire_and_release = OpConstant %u32 6
68 %sequentially_consistent = OpConstant %u32 16
69 %acquire_release_uniform_workgroup = OpConstant %u32 328
70 
71 %f32_ptr = OpTypePointer Workgroup %f32
72 %f32_var = OpVariable %f32_ptr Workgroup
73 
74 %u32_ptr = OpTypePointer Workgroup %u32
75 %u32_var = OpVariable %u32_ptr Workgroup
76 
77 %f32vec4_ptr = OpTypePointer Workgroup %f32vec4
78 %f32vec4_var = OpVariable %f32vec4_ptr Workgroup
79 
80 %f32_ptr_function = OpTypePointer Function %f32
81 )";
82   ss << definitions;
83   ss << R"(
84 %main = OpFunction %void None %func
85 %main_entry = OpLabel
86 )";
87   ss << body;
88   ss << R"(
89 OpReturn
90 OpFunctionEnd)";
91 
92   return ss.str();
93 }
94 
GenerateShaderCode(const std::string & body,const std::string & capabilities_and_extensions="",const std::string & extra_defs="",const std::string & memory_model="GLSL450")95 std::string GenerateShaderCode(
96     const std::string& body,
97     const std::string& capabilities_and_extensions = "",
98     const std::string& extra_defs = "",
99     const std::string& memory_model = "GLSL450") {
100   const std::string execution = R"(
101 OpEntryPoint Fragment %main "main"
102 OpExecutionMode %main OriginUpperLeft
103 )";
104   const std::string defintions = R"(
105 %u64 = OpTypeInt 64 0
106 %s64 = OpTypeInt 64 1
107 
108 %u64_1 = OpConstant %u64 1
109 %s64_1 = OpConstant %s64 1
110 
111 %u64_ptr = OpTypePointer Workgroup %u64
112 %s64_ptr = OpTypePointer Workgroup %s64
113 %u64_var = OpVariable %u64_ptr Workgroup
114 %s64_var = OpVariable %s64_ptr Workgroup
115 )";
116   return GenerateShaderCodeImpl(
117       body, "OpCapability Int64\n" + capabilities_and_extensions,
118       defintions + extra_defs,
119       memory_model, execution);
120 }
121 
GenerateShaderComputeCode(const std::string & body,const std::string & capabilities_and_extensions="",const std::string & memory_model="GLSL450")122 std::string GenerateShaderComputeCode(
123     const std::string& body,
124     const std::string& capabilities_and_extensions = "",
125     const std::string& memory_model = "GLSL450") {
126   const std::string execution = R"(
127 OpEntryPoint GLCompute %main "main"
128 OpExecutionMode %main LocalSize 32 1 1
129 )";
130   const std::string defintions = R"(
131 %u64 = OpTypeInt 64 0
132 %s64 = OpTypeInt 64 1
133 
134 %u64_1 = OpConstant %u64 1
135 %s64_1 = OpConstant %s64 1
136 
137 %u64_ptr = OpTypePointer Workgroup %u64
138 %s64_ptr = OpTypePointer Workgroup %s64
139 %u64_var = OpVariable %u64_ptr Workgroup
140 %s64_var = OpVariable %s64_ptr Workgroup
141 )";
142   return GenerateShaderCodeImpl(
143       body, "OpCapability Int64\n" + capabilities_and_extensions, defintions,
144       memory_model, execution);
145 }
146 
GenerateKernelCode(const std::string & body,const std::string & capabilities_and_extensions="")147 std::string GenerateKernelCode(
148     const std::string& body,
149     const std::string& capabilities_and_extensions = "") {
150   std::ostringstream ss;
151   ss << R"(
152 OpCapability Addresses
153 OpCapability Kernel
154 OpCapability Linkage
155 OpCapability Int64
156 )";
157 
158   ss << capabilities_and_extensions;
159   ss << R"(
160 OpMemoryModel Physical32 OpenCL
161 %void = OpTypeVoid
162 %func = OpTypeFunction %void
163 %bool = OpTypeBool
164 %f32 = OpTypeFloat 32
165 %u32 = OpTypeInt 32 0
166 %u64 = OpTypeInt 64 0
167 %f32vec4 = OpTypeVector %f32 4
168 
169 %f32_0 = OpConstant %f32 0
170 %f32_1 = OpConstant %f32 1
171 %u32_0 = OpConstant %u32 0
172 %u32_1 = OpConstant %u32 1
173 %u64_1 = OpConstant %u64 1
174 %f32vec4_0000 = OpConstantComposite %f32vec4 %f32_0 %f32_0 %f32_0 %f32_0
175 
176 %cross_device = OpConstant %u32 0
177 %device = OpConstant %u32 1
178 %workgroup = OpConstant %u32 2
179 %subgroup = OpConstant %u32 3
180 %invocation = OpConstant %u32 4
181 
182 %relaxed = OpConstant %u32 0
183 %acquire = OpConstant %u32 2
184 %release = OpConstant %u32 4
185 %acquire_release = OpConstant %u32 8
186 %acquire_and_release = OpConstant %u32 6
187 %sequentially_consistent = OpConstant %u32 16
188 %acquire_release_uniform_workgroup = OpConstant %u32 328
189 %acquire_release_atomic_counter_workgroup = OpConstant %u32 1288
190 
191 %f32_ptr = OpTypePointer Workgroup %f32
192 %f32_var = OpVariable %f32_ptr Workgroup
193 
194 %u32_ptr = OpTypePointer Workgroup %u32
195 %u32_var = OpVariable %u32_ptr Workgroup
196 
197 %u64_ptr = OpTypePointer Workgroup %u64
198 %u64_var = OpVariable %u64_ptr Workgroup
199 
200 %f32vec4_ptr = OpTypePointer Workgroup %f32vec4
201 %f32vec4_var = OpVariable %f32vec4_ptr Workgroup
202 
203 %f32_ptr_function = OpTypePointer Function %f32
204 %f32_ptr_uniformconstant = OpTypePointer UniformConstant %f32
205 %f32_uc_var = OpVariable %f32_ptr_uniformconstant UniformConstant
206 
207 %f32_ptr_image = OpTypePointer Image %f32
208 %f32_im_var = OpVariable %f32_ptr_image Image
209 
210 %main = OpFunction %void None %func
211 %main_entry = OpLabel
212 )";
213 
214   ss << body;
215 
216   ss << R"(
217 OpReturn
218 OpFunctionEnd)";
219 
220   return ss.str();
221 }
222 
TEST_F(ValidateAtomics,AtomicLoadShaderSuccess)223 TEST_F(ValidateAtomics, AtomicLoadShaderSuccess) {
224   const std::string body = R"(
225 %val1 = OpAtomicLoad %u32 %u32_var %device %relaxed
226 %val2 = OpAtomicLoad %u32 %u32_var %workgroup %acquire
227 )";
228 
229   CompileSuccessfully(GenerateShaderCode(body));
230   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
231 }
232 
TEST_F(ValidateAtomics,AtomicLoadKernelSuccess)233 TEST_F(ValidateAtomics, AtomicLoadKernelSuccess) {
234   const std::string body = R"(
235 %val1 = OpAtomicLoad %f32 %f32_var %device %relaxed
236 %val2 = OpAtomicLoad %u32 %u32_var %workgroup %sequentially_consistent
237 )";
238 
239   CompileSuccessfully(GenerateKernelCode(body));
240   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
241 }
242 
TEST_F(ValidateAtomics,AtomicLoadInt64ShaderSuccess)243 TEST_F(ValidateAtomics, AtomicLoadInt64ShaderSuccess) {
244   const std::string body = R"(
245 %val1 = OpAtomicLoad %u64 %u64_var %subgroup %sequentially_consistent
246 )";
247 
248   CompileSuccessfully(GenerateShaderCode(body, "OpCapability Int64Atomics\n"));
249   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
250 }
251 
TEST_F(ValidateAtomics,AtomicLoadInt64KernelSuccess)252 TEST_F(ValidateAtomics, AtomicLoadInt64KernelSuccess) {
253   const std::string body = R"(
254 %val1 = OpAtomicLoad %u64 %u64_var %subgroup %acquire
255 )";
256 
257   CompileSuccessfully(GenerateKernelCode(body, "OpCapability Int64Atomics\n"));
258   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
259 }
260 
TEST_F(ValidateAtomics,AtomicLoadInt32VulkanSuccess)261 TEST_F(ValidateAtomics, AtomicLoadInt32VulkanSuccess) {
262   const std::string body = R"(
263 %val1 = OpAtomicLoad %u32 %u32_var %device %relaxed
264 %val2 = OpAtomicLoad %u32 %u32_var %workgroup %acquire
265 %val3 = OpAtomicLoad %u32 %u32_var %invocation %relaxed
266 )";
267 
268   CompileSuccessfully(GenerateShaderComputeCode(body), SPV_ENV_VULKAN_1_0);
269   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
270 }
271 
TEST_F(ValidateAtomics,AtomicAddIntVulkanWrongType1)272 TEST_F(ValidateAtomics, AtomicAddIntVulkanWrongType1) {
273   const std::string body = R"(
274 %val1 = OpAtomicIAdd %f32 %f32_var %device %relaxed %f32_1
275 )";
276 
277   CompileSuccessfully(GenerateShaderCode(body));
278   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
279   EXPECT_THAT(getDiagnosticString(),
280               HasSubstr("AtomicIAdd: "
281                         "expected Result Type to be integer scalar type"));
282 }
283 
TEST_F(ValidateAtomics,AtomicAddIntVulkanWrongType2)284 TEST_F(ValidateAtomics, AtomicAddIntVulkanWrongType2) {
285   const std::string body = R"(
286 %val1 = OpAtomicIAdd %f32vec4 %f32vec4_var %device %relaxed %f32_1
287 )";
288 
289   CompileSuccessfully(GenerateShaderCode(body));
290   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
291   EXPECT_THAT(getDiagnosticString(),
292               HasSubstr("AtomicIAdd: "
293                         "expected Result Type to be integer scalar type"));
294 }
295 
TEST_F(ValidateAtomics,AtomicAddFloatVulkan)296 TEST_F(ValidateAtomics, AtomicAddFloatVulkan) {
297   const std::string body = R"(
298 %val1 = OpAtomicFAddEXT %f32 %f32_var %device %relaxed %f32_1
299 )";
300 
301   CompileSuccessfully(GenerateShaderCode(body));
302   ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY, ValidateInstructions());
303   EXPECT_THAT(
304       getDiagnosticString(),
305       HasSubstr("Opcode AtomicFAddEXT requires one of these capabilities: "
306                 "AtomicFloat32AddEXT AtomicFloat64AddEXT"));
307 }
308 
TEST_F(ValidateAtomics,AtomicMinFloatVulkan)309 TEST_F(ValidateAtomics, AtomicMinFloatVulkan) {
310   const std::string body = R"(
311 %val1 = OpAtomicFMinEXT %f32 %f32_var %device %relaxed %f32_1
312 )";
313 
314   CompileSuccessfully(GenerateShaderCode(body));
315   ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY, ValidateInstructions());
316   EXPECT_THAT(
317       getDiagnosticString(),
318       HasSubstr("Opcode AtomicFMinEXT requires one of these capabilities: "
319                 "AtomicFloat32MinMaxEXT AtomicFloat64MinMaxEXT AtomicFloat16MinMaxEXT"));
320 }
321 
TEST_F(ValidateAtomics,AtomicMaxFloatVulkan)322 TEST_F(ValidateAtomics, AtomicMaxFloatVulkan) {
323   const std::string body = R"(
324 %val1 = OpAtomicFMaxEXT %f32 %f32_var %device %relaxed %f32_1
325 )";
326 
327   CompileSuccessfully(GenerateShaderCode(body));
328   ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY, ValidateInstructions());
329   EXPECT_THAT(
330       getDiagnosticString(),
331       HasSubstr("Opcode AtomicFMaxEXT requires one of these capabilities: "
332                 "AtomicFloat32MinMaxEXT AtomicFloat64MinMaxEXT AtomicFloat16MinMaxEXT"));
333 }
334 
TEST_F(ValidateAtomics,AtomicAddFloatVulkanWrongType1)335 TEST_F(ValidateAtomics, AtomicAddFloatVulkanWrongType1) {
336   const std::string body = R"(
337 %val1 = OpAtomicFAddEXT %f32vec4 %f32vec4_var %device %relaxed %f32_1
338 )";
339   const std::string extra = R"(
340 OpCapability AtomicFloat32AddEXT
341 OpExtension "SPV_EXT_shader_atomic_float_add"
342 )";
343 
344   CompileSuccessfully(GenerateShaderCode(body, extra), SPV_ENV_VULKAN_1_0);
345   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
346   EXPECT_THAT(getDiagnosticString(),
347               HasSubstr("AtomicFAddEXT: "
348                         "expected Result Type to be float scalar type"));
349 }
350 
TEST_F(ValidateAtomics,AtomicMinFloatVulkanWrongType1)351 TEST_F(ValidateAtomics, AtomicMinFloatVulkanWrongType1) {
352   const std::string body = R"(
353 %val1 = OpAtomicFMinEXT %f32vec4 %f32vec4_var %device %relaxed %f32_1
354 )";
355   const std::string extra = R"(
356 OpCapability AtomicFloat32MinMaxEXT
357 OpExtension "SPV_EXT_shader_atomic_float_min_max"
358 )";
359 
360   CompileSuccessfully(GenerateShaderCode(body, extra), SPV_ENV_VULKAN_1_0);
361   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
362   EXPECT_THAT(getDiagnosticString(),
363               HasSubstr("AtomicFMinEXT: "
364                         "expected Result Type to be float scalar type"));
365 }
366 
TEST_F(ValidateAtomics,AtomicMaxFloatVulkanWrongType1)367 TEST_F(ValidateAtomics, AtomicMaxFloatVulkanWrongType1) {
368   const std::string body = R"(
369 %val1 = OpAtomicFMaxEXT %f32vec4 %f32vec4_var %device %relaxed %f32_1
370 )";
371   const std::string extra = R"(
372 OpCapability AtomicFloat32MinMaxEXT
373 OpExtension "SPV_EXT_shader_atomic_float_min_max"
374 )";
375 
376   CompileSuccessfully(GenerateShaderCode(body, extra), SPV_ENV_VULKAN_1_0);
377   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
378   EXPECT_THAT(getDiagnosticString(),
379               HasSubstr("AtomicFMaxEXT: "
380                         "expected Result Type to be float scalar type"));
381 }
382 
TEST_F(ValidateAtomics,AtomicAddFloatVulkanWrongType2)383 TEST_F(ValidateAtomics, AtomicAddFloatVulkanWrongType2) {
384   const std::string body = R"(
385 %val1 = OpAtomicFAddEXT %u32 %u32_var %device %relaxed %u32_1
386 )";
387   const std::string extra = R"(
388 OpCapability AtomicFloat32AddEXT
389 OpExtension "SPV_EXT_shader_atomic_float_add"
390 )";
391 
392   CompileSuccessfully(GenerateShaderCode(body, extra), SPV_ENV_VULKAN_1_0);
393   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
394   EXPECT_THAT(getDiagnosticString(),
395               HasSubstr("AtomicFAddEXT: "
396                         "expected Result Type to be float scalar type"));
397 }
398 
TEST_F(ValidateAtomics,AtomicMinFloatVulkanWrongType2)399 TEST_F(ValidateAtomics, AtomicMinFloatVulkanWrongType2) {
400   const std::string body = R"(
401 %val1 = OpAtomicFMinEXT %u32 %u32_var %device %relaxed %u32_1
402 )";
403   const std::string extra = R"(
404 OpCapability AtomicFloat32MinMaxEXT
405 OpExtension "SPV_EXT_shader_atomic_float_min_max"
406 )";
407 
408   CompileSuccessfully(GenerateShaderCode(body, extra), SPV_ENV_VULKAN_1_0);
409   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
410   EXPECT_THAT(getDiagnosticString(),
411               HasSubstr("AtomicFMinEXT: "
412                         "expected Result Type to be float scalar type"));
413 }
414 
TEST_F(ValidateAtomics,AtomicMaxFloatVulkanWrongType2)415 TEST_F(ValidateAtomics, AtomicMaxFloatVulkanWrongType2) {
416   const std::string body = R"(
417 %val1 = OpAtomicFMaxEXT %u32 %u32_var %device %relaxed %u32_1
418 )";
419   const std::string extra = R"(
420 OpCapability AtomicFloat32MinMaxEXT
421 OpExtension "SPV_EXT_shader_atomic_float_min_max"
422 )";
423 
424   CompileSuccessfully(GenerateShaderCode(body, extra), SPV_ENV_VULKAN_1_0);
425   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
426   EXPECT_THAT(getDiagnosticString(),
427               HasSubstr("AtomicFMaxEXT: "
428                         "expected Result Type to be float scalar type"));
429 }
430 
TEST_F(ValidateAtomics,AtomicAddFloatVulkanWrongType3)431 TEST_F(ValidateAtomics, AtomicAddFloatVulkanWrongType3) {
432   const std::string body = R"(
433 %val1 = OpAtomicFAddEXT %u64 %u64_var %device %relaxed %u64_1
434 )";
435   const std::string extra = R"(
436 OpCapability AtomicFloat32AddEXT
437 OpExtension "SPV_EXT_shader_atomic_float_add"
438 )";
439 
440   CompileSuccessfully(GenerateShaderCode(body, extra), SPV_ENV_VULKAN_1_0);
441   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
442   EXPECT_THAT(getDiagnosticString(),
443               HasSubstr("AtomicFAddEXT: "
444                         "expected Result Type to be float scalar type"));
445 }
446 
TEST_F(ValidateAtomics,AtomicMinFloatVulkanWrongType3)447 TEST_F(ValidateAtomics, AtomicMinFloatVulkanWrongType3) {
448   const std::string body = R"(
449 %val1 = OpAtomicFMinEXT %u64 %u64_var %device %relaxed %u64_1
450 )";
451   const std::string extra = R"(
452 OpCapability AtomicFloat32MinMaxEXT
453 OpExtension "SPV_EXT_shader_atomic_float_min_max"
454 )";
455 
456   CompileSuccessfully(GenerateShaderCode(body, extra), SPV_ENV_VULKAN_1_0);
457   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
458   EXPECT_THAT(getDiagnosticString(),
459               HasSubstr("AtomicFMinEXT: "
460                         "expected Result Type to be float scalar type"));
461 }
462 
TEST_F(ValidateAtomics,AtomicMaxFloatVulkanWrongType3)463 TEST_F(ValidateAtomics, AtomicMaxFloatVulkanWrongType3) {
464   const std::string body = R"(
465 %val1 = OpAtomicFMaxEXT %u64 %u64_var %device %relaxed %u64_1
466 )";
467   const std::string extra = R"(
468 OpCapability AtomicFloat32MinMaxEXT
469 OpExtension "SPV_EXT_shader_atomic_float_min_max"
470 )";
471 
472   CompileSuccessfully(GenerateShaderCode(body, extra), SPV_ENV_VULKAN_1_0);
473   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
474   EXPECT_THAT(getDiagnosticString(),
475               HasSubstr("AtomicFMaxEXT: "
476                         "expected Result Type to be float scalar type"));
477 }
478 
TEST_F(ValidateAtomics,AtomicAddFloatVulkanWrongCapability)479 TEST_F(ValidateAtomics, AtomicAddFloatVulkanWrongCapability) {
480   const std::string body = R"(
481 %val1 = OpAtomicFAddEXT %f32 %f32_var %device %relaxed %f32_1
482 )";
483   const std::string extra = R"(
484 OpCapability AtomicFloat64AddEXT
485 OpExtension "SPV_EXT_shader_atomic_float_add"
486 )";
487 
488   CompileSuccessfully(GenerateShaderCode(body, extra), SPV_ENV_VULKAN_1_0);
489   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
490   EXPECT_THAT(getDiagnosticString(),
491               HasSubstr("AtomicFAddEXT: float add atomics "
492                         "require the AtomicFloat32AddEXT capability"));
493 }
494 
TEST_F(ValidateAtomics,AtomicMinFloatVulkanWrongCapability)495 TEST_F(ValidateAtomics, AtomicMinFloatVulkanWrongCapability) {
496   const std::string body = R"(
497 %val1 = OpAtomicFMinEXT %f32 %f32_var %device %relaxed %f32_1
498 )";
499   const std::string extra = R"(
500 OpCapability AtomicFloat64MinMaxEXT
501 OpExtension "SPV_EXT_shader_atomic_float_min_max"
502 )";
503 
504   CompileSuccessfully(GenerateShaderCode(body, extra), SPV_ENV_VULKAN_1_0);
505   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
506   EXPECT_THAT(getDiagnosticString(),
507               HasSubstr("AtomicFMinEXT: float min/max atomics "
508                         "require the AtomicFloat32MinMaxEXT capability"));
509 }
510 
TEST_F(ValidateAtomics,AtomicMaxFloatVulkanWrongCapability)511 TEST_F(ValidateAtomics, AtomicMaxFloatVulkanWrongCapability) {
512   const std::string body = R"(
513 %val1 = OpAtomicFMaxEXT %f32 %f32_var %device %relaxed %f32_1
514 )";
515   const std::string extra = R"(
516 OpCapability AtomicFloat64MinMaxEXT
517 OpExtension "SPV_EXT_shader_atomic_float_min_max"
518 )";
519 
520   CompileSuccessfully(GenerateShaderCode(body, extra), SPV_ENV_VULKAN_1_0);
521   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
522   EXPECT_THAT(getDiagnosticString(),
523               HasSubstr("AtomicFMaxEXT: float min/max atomics "
524                         "require the AtomicFloat32MinMaxEXT capability"));
525 }
526 
TEST_F(ValidateAtomics,AtomicAddFloatVulkanSuccess)527 TEST_F(ValidateAtomics, AtomicAddFloatVulkanSuccess) {
528   const std::string body = R"(
529 %val1 = OpAtomicFAddEXT %f32 %f32_var %device %relaxed %f32_1
530 %val2 = OpAtomicFAddEXT %f32 %f32_var %invocation %relaxed %f32_1
531 )";
532   const std::string extra = R"(
533 OpCapability AtomicFloat32AddEXT
534 OpExtension "SPV_EXT_shader_atomic_float_add"
535 )";
536 
537   CompileSuccessfully(GenerateShaderCode(body, extra), SPV_ENV_VULKAN_1_0);
538   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
539 }
540 
TEST_F(ValidateAtomics,AtomicMinFloat16VulkanSuccess)541 TEST_F(ValidateAtomics, AtomicMinFloat16VulkanSuccess) {
542   const std::string defs = R"(
543 %f16 = OpTypeFloat 16
544 %f16_1 = OpConstant %f16 1
545 %f16_ptr = OpTypePointer Workgroup %f16
546 %f16_var = OpVariable %f16_ptr Workgroup
547 )";
548   const std::string body = R"(
549 %val1 = OpAtomicFMinEXT %f16 %f16_var %device %relaxed %f16_1
550 )";
551   const std::string extra = R"(
552 OpCapability Float16
553 OpCapability AtomicFloat16MinMaxEXT
554 OpExtension "SPV_EXT_shader_atomic_float_min_max"
555 )";
556 
557   CompileSuccessfully(GenerateShaderCode(body, extra, defs), SPV_ENV_VULKAN_1_0);
558   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
559 }
560 
TEST_F(ValidateAtomics,AtomicMaxFloat16VulkanSuccess)561 TEST_F(ValidateAtomics, AtomicMaxFloat16VulkanSuccess) {
562   const std::string defs = R"(
563 %f16 = OpTypeFloat 16
564 %f16_1 = OpConstant %f16 1
565 %f16_ptr = OpTypePointer Workgroup %f16
566 %f16_var = OpVariable %f16_ptr Workgroup
567 )";
568   const std::string body = R"(
569 %val1 = OpAtomicFMaxEXT %f16 %f16_var %device %relaxed %f16_1
570 )";
571   const std::string extra = R"(
572 OpCapability Float16
573 OpCapability AtomicFloat16MinMaxEXT
574 OpExtension "SPV_EXT_shader_atomic_float_min_max"
575 )";
576 
577   CompileSuccessfully(GenerateShaderCode(body, extra, defs), SPV_ENV_VULKAN_1_0);
578   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
579 }
580 
TEST_F(ValidateAtomics,AtomicMinFloat32VulkanSuccess)581 TEST_F(ValidateAtomics, AtomicMinFloat32VulkanSuccess) {
582   const std::string body = R"(
583 %val1 = OpAtomicFMinEXT %f32 %f32_var %device %relaxed %f32_1
584 )";
585   const std::string extra = R"(
586 OpCapability AtomicFloat32MinMaxEXT
587 OpExtension "SPV_EXT_shader_atomic_float_min_max"
588 )";
589 
590   CompileSuccessfully(GenerateShaderCode(body, extra), SPV_ENV_VULKAN_1_0);
591   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
592 }
593 
TEST_F(ValidateAtomics,AtomicMaxFloat32VulkanSuccess)594 TEST_F(ValidateAtomics, AtomicMaxFloat32VulkanSuccess) {
595   const std::string body = R"(
596 %val1 = OpAtomicFMaxEXT %f32 %f32_var %device %relaxed %f32_1
597 )";
598   const std::string extra = R"(
599 OpCapability AtomicFloat32MinMaxEXT
600 OpExtension "SPV_EXT_shader_atomic_float_min_max"
601 )";
602 
603   CompileSuccessfully(GenerateShaderCode(body, extra), SPV_ENV_VULKAN_1_0);
604   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
605 }
606 
TEST_F(ValidateAtomics,AtomicMinFloat64VulkanSuccess)607 TEST_F(ValidateAtomics, AtomicMinFloat64VulkanSuccess) {
608   const std::string defs = R"(
609 %f64 = OpTypeFloat 64
610 %f64_1 = OpConstant %f64 1
611 %f64_ptr = OpTypePointer Workgroup %f64
612 %f64_var = OpVariable %f64_ptr Workgroup
613 )";
614   const std::string body = R"(
615 %val1 = OpAtomicFMinEXT %f64 %f64_var %device %relaxed %f64_1
616 )";
617   const std::string extra = R"(
618 OpCapability Float64
619 OpCapability AtomicFloat64MinMaxEXT
620 OpExtension "SPV_EXT_shader_atomic_float_min_max"
621 )";
622 
623   CompileSuccessfully(GenerateShaderCode(body, extra, defs), SPV_ENV_VULKAN_1_0);
624   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
625 }
626 
TEST_F(ValidateAtomics,AtomicMaxFloat64VulkanSuccess)627 TEST_F(ValidateAtomics, AtomicMaxFloat64VulkanSuccess) {
628   const std::string defs = R"(
629 %f64 = OpTypeFloat 64
630 %f64_1 = OpConstant %f64 1
631 %f64_ptr = OpTypePointer Workgroup %f64
632 %f64_var = OpVariable %f64_ptr Workgroup
633 )";
634   const std::string body = R"(
635 %val1 = OpAtomicFMaxEXT %f64 %f64_var %device %relaxed %f64_1
636 )";
637   const std::string extra = R"(
638 OpCapability Float64
639 OpCapability AtomicFloat64MinMaxEXT
640 OpExtension "SPV_EXT_shader_atomic_float_min_max"
641 )";
642 
643   CompileSuccessfully(GenerateShaderCode(body, extra, defs), SPV_ENV_VULKAN_1_0);
644   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
645 }
646 
TEST_F(ValidateAtomics,AtomicLoadFloatVulkan)647 TEST_F(ValidateAtomics, AtomicLoadFloatVulkan) {
648   const std::string body = R"(
649 %val1 = OpAtomicLoad %f32 %f32_var %device %relaxed
650 %val2 = OpAtomicLoad %f32 %f32_var %workgroup %acquire
651 )";
652 
653   CompileSuccessfully(GenerateShaderComputeCode(body), SPV_ENV_VULKAN_1_0);
654   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
655 }
656 
TEST_F(ValidateAtomics,AtomicStoreFloatVulkan)657 TEST_F(ValidateAtomics, AtomicStoreFloatVulkan) {
658   const std::string body = R"(
659 OpAtomicStore %f32_var %device %relaxed %f32_1
660 )";
661 
662   CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0);
663   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
664 }
665 
TEST_F(ValidateAtomics,AtomicExchangeFloatVulkan)666 TEST_F(ValidateAtomics, AtomicExchangeFloatVulkan) {
667   const std::string body = R"(
668 %val2 = OpAtomicExchange %f32 %f32_var %device %relaxed %f32_0
669 )";
670 
671   CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0);
672   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
673 }
674 
TEST_F(ValidateAtomics,AtomicLoadInt64WithCapabilityVulkanSuccess)675 TEST_F(ValidateAtomics, AtomicLoadInt64WithCapabilityVulkanSuccess) {
676   const std::string body = R"(
677   %val1 = OpAtomicLoad %u64 %u64_var %device %relaxed
678   %val2 = OpAtomicLoad %u64 %u64_var %workgroup %acquire
679   %val3 = OpAtomicLoad %u64 %u64_var %invocation %relaxed
680   )";
681 
682   CompileSuccessfully(
683       GenerateShaderComputeCode(body, "OpCapability Int64Atomics\n"),
684       SPV_ENV_VULKAN_1_0);
685   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
686 }
687 
TEST_F(ValidateAtomics,AtomicLoadInt64WithoutCapabilityVulkan)688 TEST_F(ValidateAtomics, AtomicLoadInt64WithoutCapabilityVulkan) {
689   const std::string body = R"(
690   %val1 = OpAtomicLoad %u64 %u64_var %device %relaxed
691   %val2 = OpAtomicLoad %u64 %u64_var %workgroup %acquire
692   )";
693 
694   CompileSuccessfully(GenerateShaderComputeCode(body), SPV_ENV_VULKAN_1_0);
695   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
696   EXPECT_THAT(getDiagnosticString(),
697               HasSubstr("64-bit atomics require the Int64Atomics capability"));
698 }
699 
TEST_F(ValidateAtomics,AtomicStoreOpenCLFunctionPointerStorageTypeSuccess)700 TEST_F(ValidateAtomics, AtomicStoreOpenCLFunctionPointerStorageTypeSuccess) {
701   const std::string body = R"(
702 %f32_var_function = OpVariable %f32_ptr_function Function
703 OpAtomicStore %f32_var_function %device %relaxed %f32_1
704 )";
705 
706   CompileSuccessfully(GenerateKernelCode(body), SPV_ENV_OPENCL_1_2);
707   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_OPENCL_1_2));
708 }
709 
TEST_F(ValidateAtomics,AtomicStoreVulkanFunctionPointerStorageType)710 TEST_F(ValidateAtomics, AtomicStoreVulkanFunctionPointerStorageType) {
711   const std::string body = R"(
712 %f32_var_function = OpVariable %f32_ptr_function Function
713 OpAtomicStore %f32_var_function %device %relaxed %f32_1
714 )";
715 
716   CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0);
717   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
718   EXPECT_THAT(getDiagnosticString(),
719               AnyVUID("VUID-StandaloneSpirv-None-04686"));
720   EXPECT_THAT(
721       getDiagnosticString(),
722       HasSubstr("AtomicStore: Vulkan spec only allows storage classes for "
723                 "atomic to be: Uniform, Workgroup, Image, StorageBuffer, or "
724                 "PhysicalStorageBuffer."));
725 }
726 
TEST_F(ValidateAtomics,AtomicStoreFunctionPointerStorageType)727 TEST_F(ValidateAtomics, AtomicStoreFunctionPointerStorageType) {
728   const std::string body = R"(
729 %f32_var_function = OpVariable %f32_ptr_function Function
730 OpAtomicStore %f32_var_function %device %relaxed %f32_1
731 )";
732 
733   CompileSuccessfully(GenerateShaderCode(body));
734   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
735   EXPECT_THAT(getDiagnosticString(),
736               HasSubstr("AtomicStore: Function storage class forbidden when "
737                         "the Shader capability is declared."));
738 }
739 
740 // TODO(atgoo@github.com): the corresponding check fails Vulkan CTS,
741 // reenable once fixed.
TEST_F(ValidateAtomics,DISABLED_AtomicLoadVulkanSubgroup)742 TEST_F(ValidateAtomics, DISABLED_AtomicLoadVulkanSubgroup) {
743   const std::string body = R"(
744 %val1 = OpAtomicLoad %u32 %u32_var %subgroup %acquire
745 )";
746 
747   CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0);
748   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
749   EXPECT_THAT(getDiagnosticString(),
750               HasSubstr("AtomicLoad: in Vulkan environment memory scope is "
751                         "limited to Device, Workgroup and Invocation"));
752 }
753 
TEST_F(ValidateAtomics,AtomicLoadVulkanRelease)754 TEST_F(ValidateAtomics, AtomicLoadVulkanRelease) {
755   const std::string body = R"(
756 %val1 = OpAtomicLoad %u32 %u32_var %workgroup %release
757 )";
758 
759   CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0);
760   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
761   EXPECT_THAT(getDiagnosticString(),
762               AnyVUID("VUID-StandaloneSpirv-OpAtomicLoad-04731"));
763   EXPECT_THAT(
764       getDiagnosticString(),
765       HasSubstr("Vulkan spec disallows OpAtomicLoad with Memory Semantics "
766                 "Release, AcquireRelease and SequentiallyConsistent"));
767 }
768 
TEST_F(ValidateAtomics,AtomicLoadVulkanAcquireRelease)769 TEST_F(ValidateAtomics, AtomicLoadVulkanAcquireRelease) {
770   const std::string body = R"(
771 %val1 = OpAtomicLoad %u32 %u32_var %workgroup %acquire_release
772 )";
773 
774   CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0);
775   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
776   EXPECT_THAT(getDiagnosticString(),
777               AnyVUID("VUID-StandaloneSpirv-OpAtomicLoad-04731"));
778   EXPECT_THAT(
779       getDiagnosticString(),
780       HasSubstr("Vulkan spec disallows OpAtomicLoad with Memory Semantics "
781                 "Release, AcquireRelease and SequentiallyConsistent"));
782 }
783 
TEST_F(ValidateAtomics,AtomicLoadVulkanSequentiallyConsistent)784 TEST_F(ValidateAtomics, AtomicLoadVulkanSequentiallyConsistent) {
785   const std::string body = R"(
786 %val1 = OpAtomicLoad %u32 %u32_var %workgroup %sequentially_consistent
787 )";
788 
789   CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0);
790   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
791   EXPECT_THAT(getDiagnosticString(),
792               AnyVUID("VUID-StandaloneSpirv-OpAtomicLoad-04731"));
793   EXPECT_THAT(
794       getDiagnosticString(),
795       HasSubstr("Vulkan spec disallows OpAtomicLoad with Memory Semantics "
796                 "Release, AcquireRelease and SequentiallyConsistent"));
797 }
798 
TEST_F(ValidateAtomics,AtomicLoadVulkanInvocationSemantics)799 TEST_F(ValidateAtomics, AtomicLoadVulkanInvocationSemantics) {
800   const std::string body = R"(
801 %val1 = OpAtomicLoad %u32 %u32_var %invocation %acquire
802 )";
803 
804   CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0);
805   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
806   EXPECT_THAT(getDiagnosticString(),
807               AnyVUID("VUID-StandaloneSpirv-None-04641"));
808   EXPECT_THAT(
809       getDiagnosticString(),
810       HasSubstr("AtomicLoad: Vulkan specification requires Memory Semantics to "
811                 "be None if used with Invocation Memory Scope"));
812 }
813 
TEST_F(ValidateAtomics,AtomicLoadShaderFloat)814 TEST_F(ValidateAtomics, AtomicLoadShaderFloat) {
815   const std::string body = R"(
816 %val1 = OpAtomicLoad %f32 %f32_var %device %relaxed
817 )";
818 
819   CompileSuccessfully(GenerateShaderCode(body));
820   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
821 }
822 
TEST_F(ValidateAtomics,AtomicLoadVulkanInt64)823 TEST_F(ValidateAtomics, AtomicLoadVulkanInt64) {
824   const std::string body = R"(
825 %val1 = OpAtomicLoad %u64 %u64_var %device %relaxed
826 )";
827 
828   CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0);
829   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
830   EXPECT_THAT(
831       getDiagnosticString(),
832       HasSubstr(
833           "AtomicLoad: 64-bit atomics require the Int64Atomics capability"));
834 }
835 
TEST_F(ValidateAtomics,AtomicLoadKernelInt64)836 TEST_F(ValidateAtomics, AtomicLoadKernelInt64) {
837   const std::string body = R"(
838 %val1 = OpAtomicLoad %u64 %u64_var %device %relaxed
839 )";
840 
841   CompileSuccessfully(GenerateKernelCode(body));
842   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
843   EXPECT_THAT(
844       getDiagnosticString(),
845       HasSubstr(
846           "AtomicLoad: 64-bit atomics require the Int64Atomics capability"));
847 }
848 
TEST_F(ValidateAtomics,AtomicStoreVulkanInt64)849 TEST_F(ValidateAtomics, AtomicStoreVulkanInt64) {
850   const std::string body = R"(
851 OpAtomicStore %u64_var %device %relaxed %u64_1
852 )";
853 
854   CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0);
855   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
856   EXPECT_THAT(
857       getDiagnosticString(),
858       HasSubstr(
859           "AtomicStore: 64-bit atomics require the Int64Atomics capability"));
860 }
861 
TEST_F(ValidateAtomics,AtomicStoreKernelInt64)862 TEST_F(ValidateAtomics, AtomicStoreKernelInt64) {
863   const std::string body = R"(
864 OpAtomicStore %u64_var %device %relaxed %u64_1
865 )";
866 
867   CompileSuccessfully(GenerateKernelCode(body));
868   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
869   EXPECT_THAT(
870       getDiagnosticString(),
871       HasSubstr(
872           "AtomicStore: 64-bit atomics require the Int64Atomics capability"));
873 }
874 
TEST_F(ValidateAtomics,VK_KHR_shader_atomic_int64Success)875 TEST_F(ValidateAtomics, VK_KHR_shader_atomic_int64Success) {
876   const std::string body = R"(
877 %val1 = OpAtomicUMin %u64 %u64_var %device %relaxed %u64_1
878 %val2 = OpAtomicUMax %u64 %u64_var %device %relaxed %u64_1
879 %val3 = OpAtomicSMin %u64 %u64_var %device %relaxed %u64_1
880 %val4 = OpAtomicSMax %u64 %u64_var %device %relaxed %u64_1
881 %val5 = OpAtomicAnd %u64 %u64_var %device %relaxed %u64_1
882 %val6 = OpAtomicOr %u64 %u64_var %device %relaxed %u64_1
883 %val7 = OpAtomicXor %u64 %u64_var %device %relaxed %u64_1
884 %val8 = OpAtomicIAdd %u64 %u64_var %device %relaxed %u64_1
885 %val9 = OpAtomicExchange %u64 %u64_var %device %relaxed %u64_1
886 %val10 = OpAtomicCompareExchange %u64 %u64_var %device %relaxed %relaxed %u64_1 %u64_1
887 
888 %val11 = OpAtomicUMin %s64 %s64_var %device %relaxed %s64_1
889 %val12 = OpAtomicUMax %s64 %s64_var %device %relaxed %s64_1
890 %val13 = OpAtomicSMin %s64 %s64_var %device %relaxed %s64_1
891 %val14 = OpAtomicSMax %s64 %s64_var %device %relaxed %s64_1
892 %val15 = OpAtomicAnd %s64 %s64_var %device %relaxed %s64_1
893 %val16 = OpAtomicOr %s64 %s64_var %device %relaxed %s64_1
894 %val17 = OpAtomicXor %s64 %s64_var %device %relaxed %s64_1
895 %val18 = OpAtomicIAdd %s64 %s64_var %device %relaxed %s64_1
896 %val19 = OpAtomicExchange %s64 %s64_var %device %relaxed %s64_1
897 %val20 = OpAtomicCompareExchange %s64 %s64_var %device %relaxed %relaxed %s64_1 %s64_1
898 
899 %val21 = OpAtomicLoad %u64 %u64_var %device %relaxed
900 %val22 = OpAtomicLoad %s64 %s64_var %device %relaxed
901 
902 OpAtomicStore %u64_var %device %relaxed %u64_1
903 OpAtomicStore %s64_var %device %relaxed %s64_1
904 )";
905 
906   CompileSuccessfully(GenerateShaderCode(body, "OpCapability Int64Atomics\n"),
907                       SPV_ENV_VULKAN_1_0);
908   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
909 }
910 
TEST_F(ValidateAtomics,VK_KHR_shader_atomic_int64MissingCapability)911 TEST_F(ValidateAtomics, VK_KHR_shader_atomic_int64MissingCapability) {
912   const std::string body = R"(
913 %val1 = OpAtomicUMin %u64 %u64_var %device %relaxed %u64_1
914 )";
915 
916   CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0);
917   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
918   EXPECT_THAT(
919       getDiagnosticString(),
920       HasSubstr(
921           "AtomicUMin: 64-bit atomics require the Int64Atomics capability"));
922 }
923 
TEST_F(ValidateAtomics,AtomicLoadWrongResultType)924 TEST_F(ValidateAtomics, AtomicLoadWrongResultType) {
925   const std::string body = R"(
926 %val1 = OpAtomicLoad %f32vec4 %f32vec4_var %device %relaxed
927 )";
928 
929   CompileSuccessfully(GenerateKernelCode(body));
930   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
931   EXPECT_THAT(
932       getDiagnosticString(),
933       HasSubstr("AtomicLoad: "
934                 "expected Result Type to be integer or float scalar type"));
935 }
936 
TEST_F(ValidateAtomics,AtomicLoadWrongPointerType)937 TEST_F(ValidateAtomics, AtomicLoadWrongPointerType) {
938   const std::string body = R"(
939 %val1 = OpAtomicLoad %f32 %f32_ptr %device %relaxed
940 )";
941 
942   CompileSuccessfully(GenerateKernelCode(body));
943   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
944   EXPECT_THAT(getDiagnosticString(),
945               HasSubstr("Operand 27[%_ptr_Workgroup_float] cannot be a type"));
946 }
947 
TEST_F(ValidateAtomics,AtomicLoadWrongPointerDataType)948 TEST_F(ValidateAtomics, AtomicLoadWrongPointerDataType) {
949   const std::string body = R"(
950 %val1 = OpAtomicLoad %u32 %f32_var %device %relaxed
951 )";
952 
953   CompileSuccessfully(GenerateKernelCode(body));
954   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
955   EXPECT_THAT(
956       getDiagnosticString(),
957       HasSubstr("AtomicLoad: "
958                 "expected Pointer to point to a value of type Result Type"));
959 }
960 
TEST_F(ValidateAtomics,AtomicLoadWrongScopeType)961 TEST_F(ValidateAtomics, AtomicLoadWrongScopeType) {
962   const std::string body = R"(
963 %val1 = OpAtomicLoad %f32 %f32_var %f32_1 %relaxed
964 )";
965 
966   CompileSuccessfully(GenerateKernelCode(body));
967   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
968   EXPECT_THAT(getDiagnosticString(),
969               HasSubstr("AtomicLoad: expected scope to be a 32-bit int"));
970 }
971 
TEST_F(ValidateAtomics,AtomicLoadWrongMemorySemanticsType)972 TEST_F(ValidateAtomics, AtomicLoadWrongMemorySemanticsType) {
973   const std::string body = R"(
974 %val1 = OpAtomicLoad %f32 %f32_var %device %u64_1
975 )";
976 
977   CompileSuccessfully(GenerateKernelCode(body));
978   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
979   EXPECT_THAT(
980       getDiagnosticString(),
981       HasSubstr("AtomicLoad: expected Memory Semantics to be a 32-bit int"));
982 }
983 
TEST_F(ValidateAtomics,AtomicStoreKernelSuccess)984 TEST_F(ValidateAtomics, AtomicStoreKernelSuccess) {
985   const std::string body = R"(
986 OpAtomicStore %f32_var %device %relaxed %f32_1
987 OpAtomicStore %u32_var %subgroup %release %u32_1
988 )";
989 
990   CompileSuccessfully(GenerateKernelCode(body));
991   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
992 }
993 
TEST_F(ValidateAtomics,AtomicStoreShaderSuccess)994 TEST_F(ValidateAtomics, AtomicStoreShaderSuccess) {
995   const std::string body = R"(
996 OpAtomicStore %u32_var %device %release %u32_1
997 OpAtomicStore %u32_var %subgroup %sequentially_consistent %u32_1
998 )";
999 
1000   CompileSuccessfully(GenerateShaderCode(body));
1001   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
1002 }
1003 
TEST_F(ValidateAtomics,AtomicStoreVulkanSuccess)1004 TEST_F(ValidateAtomics, AtomicStoreVulkanSuccess) {
1005   const std::string body = R"(
1006 OpAtomicStore %u32_var %device %release %u32_1
1007 OpAtomicStore %u32_var %invocation %relaxed %u32_1
1008 )";
1009 
1010   CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0);
1011   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
1012 }
1013 
TEST_F(ValidateAtomics,AtomicStoreVulkanAcquire)1014 TEST_F(ValidateAtomics, AtomicStoreVulkanAcquire) {
1015   const std::string body = R"(
1016 OpAtomicStore %u32_var %device %acquire %u32_1
1017 )";
1018 
1019   CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0);
1020   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
1021   EXPECT_THAT(getDiagnosticString(),
1022               AnyVUID("VUID-StandaloneSpirv-OpAtomicStore-04730"));
1023   EXPECT_THAT(
1024       getDiagnosticString(),
1025       HasSubstr("Vulkan spec disallows OpAtomicStore with Memory Semantics "
1026                 "Acquire, AcquireRelease and SequentiallyConsistent"));
1027 }
1028 
TEST_F(ValidateAtomics,AtomicStoreVulkanAcquireRelease)1029 TEST_F(ValidateAtomics, AtomicStoreVulkanAcquireRelease) {
1030   const std::string body = R"(
1031 OpAtomicStore %u32_var %device %acquire_release %u32_1
1032 )";
1033 
1034   CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0);
1035   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
1036   EXPECT_THAT(getDiagnosticString(),
1037               AnyVUID("VUID-StandaloneSpirv-OpAtomicStore-04730"));
1038   EXPECT_THAT(
1039       getDiagnosticString(),
1040       HasSubstr("Vulkan spec disallows OpAtomicStore with Memory Semantics "
1041                 "Acquire, AcquireRelease and SequentiallyConsistent"));
1042 }
1043 
TEST_F(ValidateAtomics,AtomicStoreVulkanSequentiallyConsistent)1044 TEST_F(ValidateAtomics, AtomicStoreVulkanSequentiallyConsistent) {
1045   const std::string body = R"(
1046 OpAtomicStore %u32_var %device %sequentially_consistent %u32_1
1047 )";
1048 
1049   CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0);
1050   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
1051   EXPECT_THAT(getDiagnosticString(),
1052               AnyVUID("VUID-StandaloneSpirv-OpAtomicStore-04730"));
1053   EXPECT_THAT(
1054       getDiagnosticString(),
1055       HasSubstr("Vulkan spec disallows OpAtomicStore with Memory Semantics "
1056                 "Acquire, AcquireRelease and SequentiallyConsistent"));
1057 }
1058 
TEST_F(ValidateAtomics,AtomicStoreVulkanInvocationSemantics)1059 TEST_F(ValidateAtomics, AtomicStoreVulkanInvocationSemantics) {
1060   const std::string body = R"(
1061 OpAtomicStore %u32_var %invocation %acquire %u32_1
1062 )";
1063 
1064   CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0);
1065   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
1066   EXPECT_THAT(getDiagnosticString(),
1067               AnyVUID("VUID-StandaloneSpirv-None-04641"));
1068   EXPECT_THAT(
1069       getDiagnosticString(),
1070       HasSubstr("AtomicStore: Vulkan specification requires Memory Semantics "
1071                 "to be None if used with Invocation Memory Scope"));
1072 }
1073 
TEST_F(ValidateAtomics,AtomicStoreWrongPointerType)1074 TEST_F(ValidateAtomics, AtomicStoreWrongPointerType) {
1075   const std::string body = R"(
1076 OpAtomicStore %f32_1 %device %relaxed %f32_1
1077 )";
1078 
1079   CompileSuccessfully(GenerateKernelCode(body));
1080   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1081   EXPECT_THAT(
1082       getDiagnosticString(),
1083       HasSubstr("AtomicStore: expected Pointer to be of type OpTypePointer"));
1084 }
1085 
TEST_F(ValidateAtomics,AtomicStoreWrongPointerDataType)1086 TEST_F(ValidateAtomics, AtomicStoreWrongPointerDataType) {
1087   const std::string body = R"(
1088 OpAtomicStore %f32vec4_var %device %relaxed %f32_1
1089 )";
1090 
1091   CompileSuccessfully(GenerateKernelCode(body));
1092   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1093   EXPECT_THAT(
1094       getDiagnosticString(),
1095       HasSubstr(
1096           "AtomicStore: "
1097           "expected Pointer to be a pointer to integer or float scalar type"));
1098 }
1099 
TEST_F(ValidateAtomics,AtomicStoreWrongPointerStorageTypeForOpenCL)1100 TEST_F(ValidateAtomics, AtomicStoreWrongPointerStorageTypeForOpenCL) {
1101   const std::string body = R"(
1102 OpAtomicStore %f32_im_var %device %relaxed %f32_1
1103 )";
1104 
1105   CompileSuccessfully(GenerateKernelCode(body));
1106   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2));
1107   EXPECT_THAT(
1108       getDiagnosticString(),
1109       HasSubstr("AtomicStore: storage class must be Function, Workgroup, "
1110                 "CrossWorkGroup or Generic in the OpenCL environment."));
1111 }
1112 
TEST_F(ValidateAtomics,AtomicStoreWrongPointerStorageType)1113 TEST_F(ValidateAtomics, AtomicStoreWrongPointerStorageType) {
1114   const std::string body = R"(
1115 OpAtomicStore %f32_uc_var %device %relaxed %f32_1
1116 )";
1117 
1118   CompileSuccessfully(GenerateKernelCode(body));
1119   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1120   EXPECT_THAT(getDiagnosticString(),
1121               HasSubstr("AtomicStore: storage class forbidden by universal "
1122                         "validation rules."));
1123 }
1124 
TEST_F(ValidateAtomics,AtomicStoreWrongScopeType)1125 TEST_F(ValidateAtomics, AtomicStoreWrongScopeType) {
1126   const std::string body = R"(
1127 OpAtomicStore %f32_var %f32_1 %relaxed %f32_1
1128 )";
1129 
1130   CompileSuccessfully(GenerateKernelCode(body));
1131   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1132   EXPECT_THAT(getDiagnosticString(),
1133               HasSubstr("AtomicStore: expected scope to be a 32-bit int\n  "
1134                         "OpAtomicStore %28 %float_1 %uint_0_1 %float_1\n"));
1135 }
1136 
TEST_F(ValidateAtomics,AtomicStoreWrongMemorySemanticsType)1137 TEST_F(ValidateAtomics, AtomicStoreWrongMemorySemanticsType) {
1138   const std::string body = R"(
1139 OpAtomicStore %f32_var %device %f32_1 %f32_1
1140 )";
1141 
1142   CompileSuccessfully(GenerateKernelCode(body));
1143   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1144   EXPECT_THAT(
1145       getDiagnosticString(),
1146       HasSubstr("AtomicStore: expected Memory Semantics to be a 32-bit int"));
1147 }
1148 
TEST_F(ValidateAtomics,AtomicStoreWrongValueType)1149 TEST_F(ValidateAtomics, AtomicStoreWrongValueType) {
1150   const std::string body = R"(
1151 OpAtomicStore %f32_var %device %relaxed %u32_1
1152 )";
1153 
1154   CompileSuccessfully(GenerateKernelCode(body));
1155   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1156   EXPECT_THAT(
1157       getDiagnosticString(),
1158       HasSubstr("AtomicStore: "
1159                 "expected Value type and the type pointed to by Pointer to "
1160                 "be the same"));
1161 }
1162 
TEST_F(ValidateAtomics,AtomicExchangeShaderSuccess)1163 TEST_F(ValidateAtomics, AtomicExchangeShaderSuccess) {
1164   const std::string body = R"(
1165 OpAtomicStore %u32_var %device %relaxed %u32_1
1166 %val2 = OpAtomicExchange %u32 %u32_var %device %relaxed %u32_0
1167 )";
1168 
1169   CompileSuccessfully(GenerateShaderCode(body));
1170   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
1171 }
1172 
TEST_F(ValidateAtomics,AtomicExchangeKernelSuccess)1173 TEST_F(ValidateAtomics, AtomicExchangeKernelSuccess) {
1174   const std::string body = R"(
1175 OpAtomicStore %f32_var %device %relaxed %f32_1
1176 %val2 = OpAtomicExchange %f32 %f32_var %device %relaxed %f32_0
1177 OpAtomicStore %u32_var %device %relaxed %u32_1
1178 %val4 = OpAtomicExchange %u32 %u32_var %device %relaxed %u32_0
1179 )";
1180 
1181   CompileSuccessfully(GenerateKernelCode(body));
1182   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
1183 }
1184 
TEST_F(ValidateAtomics,AtomicExchangeShaderFloat)1185 TEST_F(ValidateAtomics, AtomicExchangeShaderFloat) {
1186   const std::string body = R"(
1187 OpAtomicStore %f32_var %device %relaxed %f32_1
1188 %val2 = OpAtomicExchange %f32 %f32_var %device %relaxed %f32_0
1189 )";
1190 
1191   CompileSuccessfully(GenerateShaderCode(body));
1192   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
1193 }
1194 
TEST_F(ValidateAtomics,AtomicExchangeWrongResultType)1195 TEST_F(ValidateAtomics, AtomicExchangeWrongResultType) {
1196   const std::string body = R"(
1197 OpStore %f32vec4_var %f32vec4_0000
1198 %val2 = OpAtomicExchange %f32vec4 %f32vec4_var %device %relaxed %f32vec4_0000
1199 )";
1200 
1201   CompileSuccessfully(GenerateKernelCode(body));
1202   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1203   EXPECT_THAT(
1204       getDiagnosticString(),
1205       HasSubstr("AtomicExchange: "
1206                 "expected Result Type to be integer or float scalar type"));
1207 }
1208 
TEST_F(ValidateAtomics,AtomicExchangeWrongPointerType)1209 TEST_F(ValidateAtomics, AtomicExchangeWrongPointerType) {
1210   const std::string body = R"(
1211 %val2 = OpAtomicExchange %f32 %f32vec4_ptr %device %relaxed %f32vec4_0000
1212 )";
1213 
1214   CompileSuccessfully(GenerateKernelCode(body));
1215   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1216   EXPECT_THAT(getDiagnosticString(),
1217               HasSubstr("Operand 33[%_ptr_Workgroup_v4float] cannot be a "
1218                         "type"));
1219 }
1220 
TEST_F(ValidateAtomics,AtomicExchangeWrongPointerDataType)1221 TEST_F(ValidateAtomics, AtomicExchangeWrongPointerDataType) {
1222   const std::string body = R"(
1223 OpStore %f32vec4_var %f32vec4_0000
1224 %val2 = OpAtomicExchange %f32 %f32vec4_var %device %relaxed %f32vec4_0000
1225 )";
1226 
1227   CompileSuccessfully(GenerateKernelCode(body));
1228   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1229   EXPECT_THAT(
1230       getDiagnosticString(),
1231       HasSubstr("AtomicExchange: "
1232                 "expected Pointer to point to a value of type Result Type"));
1233 }
1234 
TEST_F(ValidateAtomics,AtomicExchangeWrongScopeType)1235 TEST_F(ValidateAtomics, AtomicExchangeWrongScopeType) {
1236   const std::string body = R"(
1237 OpAtomicStore %f32_var %device %relaxed %f32_1
1238 %val2 = OpAtomicExchange %f32 %f32_var %f32_1 %relaxed %f32_0
1239 )";
1240 
1241   CompileSuccessfully(GenerateKernelCode(body));
1242   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1243   EXPECT_THAT(getDiagnosticString(),
1244               HasSubstr("AtomicExchange: expected scope to be a 32-bit int"));
1245 }
1246 
TEST_F(ValidateAtomics,AtomicExchangeWrongMemorySemanticsType)1247 TEST_F(ValidateAtomics, AtomicExchangeWrongMemorySemanticsType) {
1248   const std::string body = R"(
1249 OpAtomicStore %f32_var %device %relaxed %f32_1
1250 %val2 = OpAtomicExchange %f32 %f32_var %device %f32_1 %f32_0
1251 )";
1252 
1253   CompileSuccessfully(GenerateKernelCode(body));
1254   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1255   EXPECT_THAT(
1256       getDiagnosticString(),
1257       HasSubstr(
1258           "AtomicExchange: expected Memory Semantics to be a 32-bit int"));
1259 }
1260 
TEST_F(ValidateAtomics,AtomicExchangeWrongValueType)1261 TEST_F(ValidateAtomics, AtomicExchangeWrongValueType) {
1262   const std::string body = R"(
1263 OpAtomicStore %f32_var %device %relaxed %f32_1
1264 %val2 = OpAtomicExchange %f32 %f32_var %device %relaxed %u32_0
1265 )";
1266 
1267   CompileSuccessfully(GenerateKernelCode(body));
1268   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1269   EXPECT_THAT(getDiagnosticString(),
1270               HasSubstr("AtomicExchange: "
1271                         "expected Value to be of type Result Type"));
1272 }
1273 
TEST_F(ValidateAtomics,AtomicExchangeVulkanInvocationSemantics)1274 TEST_F(ValidateAtomics, AtomicExchangeVulkanInvocationSemantics) {
1275   const std::string body = R"(
1276 OpAtomicStore %u32_var %invocation %relaxed %u32_1
1277 %val2 = OpAtomicExchange %u32 %u32_var %invocation %acquire %u32_0
1278 )";
1279 
1280   CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0);
1281   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
1282   EXPECT_THAT(getDiagnosticString(),
1283               AnyVUID("VUID-StandaloneSpirv-None-04641"));
1284   EXPECT_THAT(
1285       getDiagnosticString(),
1286       HasSubstr("AtomicExchange: Vulkan specification requires Memory "
1287                 "Semantics to be None if used with Invocation Memory Scope"));
1288 }
1289 
TEST_F(ValidateAtomics,AtomicCompareExchangeShaderSuccess)1290 TEST_F(ValidateAtomics, AtomicCompareExchangeShaderSuccess) {
1291   const std::string body = R"(
1292 OpAtomicStore %u32_var %device %relaxed %u32_1
1293 %val2 = OpAtomicCompareExchange %u32 %u32_var %device %relaxed %relaxed %u32_0 %u32_0
1294 )";
1295 
1296   CompileSuccessfully(GenerateShaderCode(body));
1297   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
1298 }
1299 
TEST_F(ValidateAtomics,AtomicCompareExchangeKernelSuccess)1300 TEST_F(ValidateAtomics, AtomicCompareExchangeKernelSuccess) {
1301   const std::string body = R"(
1302 OpAtomicStore %u32_var %device %relaxed %u32_1
1303 %val2 = OpAtomicCompareExchange %u32 %u32_var %device %relaxed %relaxed %u32_0 %u32_0
1304 )";
1305 
1306   CompileSuccessfully(GenerateKernelCode(body));
1307   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
1308 }
1309 
TEST_F(ValidateAtomics,AtomicCompareExchangeShaderFloat)1310 TEST_F(ValidateAtomics, AtomicCompareExchangeShaderFloat) {
1311   const std::string body = R"(
1312 OpAtomicStore %f32_var %device %relaxed %f32_1
1313 %val1 = OpAtomicCompareExchange %f32 %f32_var %device %relaxed %relaxed %f32_0 %f32_1
1314 )";
1315 
1316   CompileSuccessfully(GenerateShaderCode(body));
1317   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1318   EXPECT_THAT(getDiagnosticString(),
1319               HasSubstr("AtomicCompareExchange: "
1320                         "expected Result Type to be integer scalar type"));
1321 }
1322 
TEST_F(ValidateAtomics,AtomicCompareExchangeWrongResultType)1323 TEST_F(ValidateAtomics, AtomicCompareExchangeWrongResultType) {
1324   const std::string body = R"(
1325 OpStore %f32vec4_var %f32vec4_0000
1326 %val2 = OpAtomicCompareExchange %f32vec4 %f32vec4_var %device %relaxed %relaxed %f32vec4_0000 %f32vec4_0000
1327 )";
1328 
1329   CompileSuccessfully(GenerateKernelCode(body));
1330   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1331   EXPECT_THAT(getDiagnosticString(),
1332               HasSubstr("AtomicCompareExchange: "
1333                         "expected Result Type to be integer scalar type"));
1334 }
1335 
TEST_F(ValidateAtomics,AtomicCompareExchangeWrongPointerType)1336 TEST_F(ValidateAtomics, AtomicCompareExchangeWrongPointerType) {
1337   const std::string body = R"(
1338 %val2 = OpAtomicCompareExchange %f32 %f32vec4_ptr %device %relaxed %relaxed %f32vec4_0000 %f32vec4_0000
1339 )";
1340 
1341   CompileSuccessfully(GenerateKernelCode(body));
1342   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1343   EXPECT_THAT(getDiagnosticString(),
1344               HasSubstr("Operand 33[%_ptr_Workgroup_v4float] cannot be a "
1345                         "type"));
1346 }
1347 
TEST_F(ValidateAtomics,AtomicCompareExchangeWrongPointerDataType)1348 TEST_F(ValidateAtomics, AtomicCompareExchangeWrongPointerDataType) {
1349   const std::string body = R"(
1350 OpStore %f32vec4_var %f32vec4_0000
1351 %val2 = OpAtomicCompareExchange %u32 %f32vec4_var %device %relaxed %relaxed %u32_0 %u32_0
1352 )";
1353 
1354   CompileSuccessfully(GenerateKernelCode(body));
1355   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1356   EXPECT_THAT(
1357       getDiagnosticString(),
1358       HasSubstr("AtomicCompareExchange: "
1359                 "expected Pointer to point to a value of type Result Type"));
1360 }
1361 
TEST_F(ValidateAtomics,AtomicCompareExchangeWrongScopeType)1362 TEST_F(ValidateAtomics, AtomicCompareExchangeWrongScopeType) {
1363   const std::string body = R"(
1364 OpAtomicStore %u64_var %device %relaxed %u64_1
1365 %val2 = OpAtomicCompareExchange %u64 %u64_var %u64_1 %relaxed %relaxed %u32_0 %u32_0
1366 )";
1367 
1368   CompileSuccessfully(GenerateKernelCode(body, "OpCapability Int64Atomics\n"));
1369   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1370   EXPECT_THAT(getDiagnosticString(),
1371               HasSubstr("AtomicCompareExchange: expected scope to be a 32-bit "
1372                         "int"));
1373 }
1374 
TEST_F(ValidateAtomics,AtomicCompareExchangeWrongMemorySemanticsType1)1375 TEST_F(ValidateAtomics, AtomicCompareExchangeWrongMemorySemanticsType1) {
1376   const std::string body = R"(
1377 OpAtomicStore %u32_var %device %relaxed %u32_1
1378 %val2 = OpAtomicCompareExchange %u32 %u32_var %device %f32_1 %relaxed %u32_0 %u32_0
1379 )";
1380 
1381   CompileSuccessfully(GenerateKernelCode(body));
1382   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1383   EXPECT_THAT(getDiagnosticString(),
1384               HasSubstr("AtomicCompareExchange: expected Memory Semantics to "
1385                         "be a 32-bit int"));
1386 }
1387 
TEST_F(ValidateAtomics,AtomicCompareExchangeWrongMemorySemanticsType2)1388 TEST_F(ValidateAtomics, AtomicCompareExchangeWrongMemorySemanticsType2) {
1389   const std::string body = R"(
1390 OpAtomicStore %u32_var %device %relaxed %u32_1
1391 %val2 = OpAtomicCompareExchange %u32 %u32_var %device %relaxed %f32_1 %u32_0 %u32_0
1392 )";
1393 
1394   CompileSuccessfully(GenerateKernelCode(body));
1395   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1396   EXPECT_THAT(getDiagnosticString(),
1397               HasSubstr("AtomicCompareExchange: expected Memory Semantics to "
1398                         "be a 32-bit int"));
1399 }
1400 
TEST_F(ValidateAtomics,AtomicCompareExchangeUnequalRelease)1401 TEST_F(ValidateAtomics, AtomicCompareExchangeUnequalRelease) {
1402   const std::string body = R"(
1403 OpAtomicStore %u32_var %device %relaxed %u32_1
1404 %val2 = OpAtomicCompareExchange %u32 %u32_var %device %relaxed %release %u32_0 %u32_0
1405 )";
1406 
1407   CompileSuccessfully(GenerateKernelCode(body));
1408   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1409   EXPECT_THAT(getDiagnosticString(),
1410               HasSubstr("AtomicCompareExchange: Memory Semantics Release and "
1411                         "AcquireRelease cannot be used for operand Unequal"));
1412 }
1413 
TEST_F(ValidateAtomics,AtomicCompareExchangeWrongValueType)1414 TEST_F(ValidateAtomics, AtomicCompareExchangeWrongValueType) {
1415   const std::string body = R"(
1416 OpAtomicStore %u32_var %device %relaxed %u32_1
1417 %val2 = OpAtomicCompareExchange %u32 %u32_var %device %relaxed %relaxed %f32_1 %u32_0
1418 )";
1419 
1420   CompileSuccessfully(GenerateKernelCode(body));
1421   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1422   EXPECT_THAT(getDiagnosticString(),
1423               HasSubstr("AtomicCompareExchange: "
1424                         "expected Value to be of type Result Type"));
1425 }
1426 
TEST_F(ValidateAtomics,AtomicCompareExchangeWrongComparatorType)1427 TEST_F(ValidateAtomics, AtomicCompareExchangeWrongComparatorType) {
1428   const std::string body = R"(
1429 OpAtomicStore %u32_var %device %relaxed %u32_1
1430 %val2 = OpAtomicCompareExchange %u32 %u32_var %device %relaxed %relaxed %u32_0 %f32_0
1431 )";
1432 
1433   CompileSuccessfully(GenerateKernelCode(body));
1434   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1435   EXPECT_THAT(getDiagnosticString(),
1436               HasSubstr("AtomicCompareExchange: "
1437                         "expected Comparator to be of type Result Type"));
1438 }
1439 
TEST_F(ValidateAtomics,AtomicCompareExchangeWeakSuccess)1440 TEST_F(ValidateAtomics, AtomicCompareExchangeWeakSuccess) {
1441   const std::string body = R"(
1442 OpAtomicStore %u32_var %device %relaxed %u32_1
1443 %val4 = OpAtomicCompareExchangeWeak %u32 %u32_var %device %relaxed %relaxed %u32_0 %u32_0
1444 )";
1445 
1446   CompileSuccessfully(GenerateKernelCode(body));
1447   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
1448 }
1449 
TEST_F(ValidateAtomics,AtomicCompareExchangeWeakWrongResultType)1450 TEST_F(ValidateAtomics, AtomicCompareExchangeWeakWrongResultType) {
1451   const std::string body = R"(
1452 OpAtomicStore %f32_var %device %relaxed %f32_1
1453 %val2 = OpAtomicCompareExchangeWeak %f32 %f32_var %device %relaxed %relaxed %f32_0 %f32_1
1454 )";
1455 
1456   CompileSuccessfully(GenerateKernelCode(body));
1457   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1458   EXPECT_THAT(getDiagnosticString(),
1459               HasSubstr("AtomicCompareExchangeWeak: "
1460                         "expected Result Type to be integer scalar type"));
1461 }
1462 
TEST_F(ValidateAtomics,AtomicCompareExchangeVulkanInvocationSemanticsEqual)1463 TEST_F(ValidateAtomics, AtomicCompareExchangeVulkanInvocationSemanticsEqual) {
1464   const std::string body = R"(
1465 OpAtomicStore %u32_var %device %relaxed %u32_1
1466 %val2 = OpAtomicCompareExchange %u32 %u32_var %invocation %release %relaxed %u32_0 %u32_0
1467 )";
1468 
1469   CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0);
1470   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
1471   EXPECT_THAT(getDiagnosticString(),
1472               AnyVUID("VUID-StandaloneSpirv-None-04641"));
1473   EXPECT_THAT(
1474       getDiagnosticString(),
1475       HasSubstr("AtomicCompareExchange: Vulkan specification requires Memory "
1476                 "Semantics to be None if used with Invocation Memory Scope"));
1477 }
1478 
TEST_F(ValidateAtomics,AtomicCompareExchangeVulkanInvocationSemanticsUnequal)1479 TEST_F(ValidateAtomics, AtomicCompareExchangeVulkanInvocationSemanticsUnequal) {
1480   const std::string body = R"(
1481 OpAtomicStore %u32_var %device %relaxed %u32_1
1482 %val2 = OpAtomicCompareExchange %u32 %u32_var %invocation %relaxed %acquire %u32_0 %u32_0
1483 )";
1484 
1485   CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0);
1486   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
1487   EXPECT_THAT(getDiagnosticString(),
1488               AnyVUID("VUID-StandaloneSpirv-None-04641"));
1489   EXPECT_THAT(
1490       getDiagnosticString(),
1491       HasSubstr("AtomicCompareExchange: Vulkan specification requires Memory "
1492                 "Semantics to be None if used with Invocation Memory Scope"));
1493 }
1494 
TEST_F(ValidateAtomics,AtomicArithmeticsSuccess)1495 TEST_F(ValidateAtomics, AtomicArithmeticsSuccess) {
1496   const std::string body = R"(
1497 OpAtomicStore %u32_var %device %relaxed %u32_1
1498 %val1 = OpAtomicIIncrement %u32 %u32_var %device %acquire_release
1499 %val2 = OpAtomicIDecrement %u32 %u32_var %device %acquire_release
1500 %val3 = OpAtomicIAdd %u32 %u32_var %device %acquire_release %u32_1
1501 %val4 = OpAtomicISub %u32 %u32_var %device %acquire_release %u32_1
1502 %val5 = OpAtomicUMin %u32 %u32_var %device %acquire_release %u32_1
1503 %val6 = OpAtomicUMax %u32 %u32_var %device %acquire_release %u32_1
1504 %val7 = OpAtomicSMin %u32 %u32_var %device %sequentially_consistent %u32_1
1505 %val8 = OpAtomicSMax %u32 %u32_var %device %sequentially_consistent %u32_1
1506 %val9 = OpAtomicAnd %u32 %u32_var %device %sequentially_consistent %u32_1
1507 %val10 = OpAtomicOr %u32 %u32_var %device %sequentially_consistent %u32_1
1508 %val11 = OpAtomicXor %u32 %u32_var %device %sequentially_consistent %u32_1
1509 )";
1510 
1511   CompileSuccessfully(GenerateKernelCode(body));
1512   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
1513 }
1514 
TEST_F(ValidateAtomics,AtomicFlagsSuccess)1515 TEST_F(ValidateAtomics, AtomicFlagsSuccess) {
1516   const std::string body = R"(
1517 OpAtomicFlagClear %u32_var %device %release
1518 %val1 = OpAtomicFlagTestAndSet %bool %u32_var %device %relaxed
1519 )";
1520 
1521   CompileSuccessfully(GenerateKernelCode(body));
1522   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
1523 }
1524 
TEST_F(ValidateAtomics,AtomicFlagTestAndSetWrongResultType)1525 TEST_F(ValidateAtomics, AtomicFlagTestAndSetWrongResultType) {
1526   const std::string body = R"(
1527 %val1 = OpAtomicFlagTestAndSet %u32 %u32_var %device %relaxed
1528 )";
1529 
1530   CompileSuccessfully(GenerateKernelCode(body));
1531   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1532   EXPECT_THAT(getDiagnosticString(),
1533               HasSubstr("AtomicFlagTestAndSet: "
1534                         "expected Result Type to be bool scalar type"));
1535 }
1536 
TEST_F(ValidateAtomics,AtomicFlagTestAndSetNotPointer)1537 TEST_F(ValidateAtomics, AtomicFlagTestAndSetNotPointer) {
1538   const std::string body = R"(
1539 %val1 = OpAtomicFlagTestAndSet %bool %u32_1 %device %relaxed
1540 )";
1541 
1542   CompileSuccessfully(GenerateKernelCode(body));
1543   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1544   EXPECT_THAT(getDiagnosticString(),
1545               HasSubstr("AtomicFlagTestAndSet: "
1546                         "expected Pointer to be of type OpTypePointer"));
1547 }
1548 
TEST_F(ValidateAtomics,AtomicFlagTestAndSetNotIntPointer)1549 TEST_F(ValidateAtomics, AtomicFlagTestAndSetNotIntPointer) {
1550   const std::string body = R"(
1551 %val1 = OpAtomicFlagTestAndSet %bool %f32_var %device %relaxed
1552 )";
1553 
1554   CompileSuccessfully(GenerateKernelCode(body));
1555   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1556   EXPECT_THAT(
1557       getDiagnosticString(),
1558       HasSubstr("AtomicFlagTestAndSet: "
1559                 "expected Pointer to point to a value of 32-bit integer type"));
1560 }
1561 
TEST_F(ValidateAtomics,AtomicFlagTestAndSetNotInt32Pointer)1562 TEST_F(ValidateAtomics, AtomicFlagTestAndSetNotInt32Pointer) {
1563   const std::string body = R"(
1564 %val1 = OpAtomicFlagTestAndSet %bool %u64_var %device %relaxed
1565 )";
1566 
1567   CompileSuccessfully(GenerateKernelCode(body, "OpCapability Int64Atomics\n"));
1568   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1569   EXPECT_THAT(
1570       getDiagnosticString(),
1571       HasSubstr("AtomicFlagTestAndSet: "
1572                 "expected Pointer to point to a value of 32-bit integer type"));
1573 }
1574 
TEST_F(ValidateAtomics,AtomicFlagTestAndSetWrongScopeType)1575 TEST_F(ValidateAtomics, AtomicFlagTestAndSetWrongScopeType) {
1576   const std::string body = R"(
1577 %val1 = OpAtomicFlagTestAndSet %bool %u32_var %u64_1 %relaxed
1578 )";
1579 
1580   CompileSuccessfully(GenerateKernelCode(body));
1581   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1582   EXPECT_THAT(
1583       getDiagnosticString(),
1584       HasSubstr("AtomicFlagTestAndSet: expected scope to be a 32-bit int"));
1585 }
1586 
TEST_F(ValidateAtomics,AtomicFlagTestAndSetWrongMemorySemanticsType)1587 TEST_F(ValidateAtomics, AtomicFlagTestAndSetWrongMemorySemanticsType) {
1588   const std::string body = R"(
1589 %val1 = OpAtomicFlagTestAndSet %bool %u32_var %device %u64_1
1590 )";
1591 
1592   CompileSuccessfully(GenerateKernelCode(body));
1593   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1594   EXPECT_THAT(getDiagnosticString(),
1595               HasSubstr("AtomicFlagTestAndSet: "
1596                         "expected Memory Semantics to be a 32-bit int"));
1597 }
1598 
TEST_F(ValidateAtomics,AtomicFlagClearAcquire)1599 TEST_F(ValidateAtomics, AtomicFlagClearAcquire) {
1600   const std::string body = R"(
1601 OpAtomicFlagClear %u32_var %device %acquire
1602 )";
1603 
1604   CompileSuccessfully(GenerateKernelCode(body));
1605   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1606   EXPECT_THAT(getDiagnosticString(),
1607               HasSubstr("Memory Semantics Acquire and AcquireRelease cannot be "
1608                         "used with AtomicFlagClear"));
1609 }
1610 
TEST_F(ValidateAtomics,AtomicFlagClearNotPointer)1611 TEST_F(ValidateAtomics, AtomicFlagClearNotPointer) {
1612   const std::string body = R"(
1613 OpAtomicFlagClear %u32_1 %device %relaxed
1614 )";
1615 
1616   CompileSuccessfully(GenerateKernelCode(body));
1617   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1618   EXPECT_THAT(getDiagnosticString(),
1619               HasSubstr("AtomicFlagClear: "
1620                         "expected Pointer to be of type OpTypePointer"));
1621 }
1622 
TEST_F(ValidateAtomics,AtomicFlagClearNotIntPointer)1623 TEST_F(ValidateAtomics, AtomicFlagClearNotIntPointer) {
1624   const std::string body = R"(
1625 OpAtomicFlagClear %f32_var %device %relaxed
1626 )";
1627 
1628   CompileSuccessfully(GenerateKernelCode(body));
1629   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1630   EXPECT_THAT(
1631       getDiagnosticString(),
1632       HasSubstr("AtomicFlagClear: "
1633                 "expected Pointer to point to a value of 32-bit integer type"));
1634 }
1635 
TEST_F(ValidateAtomics,AtomicFlagClearNotInt32Pointer)1636 TEST_F(ValidateAtomics, AtomicFlagClearNotInt32Pointer) {
1637   const std::string body = R"(
1638 OpAtomicFlagClear %u64_var %device %relaxed
1639 )";
1640 
1641   CompileSuccessfully(GenerateKernelCode(body, "OpCapability Int64Atomics\n"));
1642   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1643   EXPECT_THAT(
1644       getDiagnosticString(),
1645       HasSubstr("AtomicFlagClear: "
1646                 "expected Pointer to point to a value of 32-bit integer type"));
1647 }
1648 
TEST_F(ValidateAtomics,AtomicFlagClearWrongScopeType)1649 TEST_F(ValidateAtomics, AtomicFlagClearWrongScopeType) {
1650   const std::string body = R"(
1651 OpAtomicFlagClear %u32_var %u64_1 %relaxed
1652 )";
1653 
1654   CompileSuccessfully(GenerateKernelCode(body));
1655   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1656   EXPECT_THAT(getDiagnosticString(),
1657               HasSubstr("AtomicFlagClear: expected scope to be a 32-bit "
1658                         "int\n  OpAtomicFlagClear %30 %ulong_1 %uint_0_1\n"));
1659 }
1660 
TEST_F(ValidateAtomics,AtomicFlagClearWrongMemorySemanticsType)1661 TEST_F(ValidateAtomics, AtomicFlagClearWrongMemorySemanticsType) {
1662   const std::string body = R"(
1663 OpAtomicFlagClear %u32_var %device %u64_1
1664 )";
1665 
1666   CompileSuccessfully(GenerateKernelCode(body));
1667   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1668   EXPECT_THAT(
1669       getDiagnosticString(),
1670       HasSubstr(
1671           "AtomicFlagClear: expected Memory Semantics to be a 32-bit int"));
1672 }
1673 
TEST_F(ValidateAtomics,AtomicIIncrementAcquireAndRelease)1674 TEST_F(ValidateAtomics, AtomicIIncrementAcquireAndRelease) {
1675   const std::string body = R"(
1676 OpAtomicStore %u32_var %device %relaxed %u32_1
1677 %val1 = OpAtomicIIncrement %u32 %u32_var %device %acquire_and_release
1678 )";
1679 
1680   CompileSuccessfully(GenerateKernelCode(body));
1681   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1682   EXPECT_THAT(getDiagnosticString(),
1683               HasSubstr("AtomicIIncrement: Memory Semantics can have at most "
1684                         "one of the following bits set: Acquire, Release, "
1685                         "AcquireRelease or SequentiallyConsistent"));
1686 }
1687 
TEST_F(ValidateAtomics,AtomicUniformMemorySemanticsShader)1688 TEST_F(ValidateAtomics, AtomicUniformMemorySemanticsShader) {
1689   const std::string body = R"(
1690 OpAtomicStore %u32_var %device %relaxed %u32_1
1691 %val1 = OpAtomicIIncrement %u32 %u32_var %device %acquire_release_uniform_workgroup
1692 )";
1693 
1694   CompileSuccessfully(GenerateShaderCode(body));
1695   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
1696 }
1697 
TEST_F(ValidateAtomics,AtomicUniformMemorySemanticsKernel)1698 TEST_F(ValidateAtomics, AtomicUniformMemorySemanticsKernel) {
1699   const std::string body = R"(
1700 OpAtomicStore %u32_var %device %relaxed %u32_1
1701 %val1 = OpAtomicIIncrement %u32 %u32_var %device %acquire_release_uniform_workgroup
1702 )";
1703 
1704   CompileSuccessfully(GenerateKernelCode(body));
1705   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1706   EXPECT_THAT(getDiagnosticString(),
1707               HasSubstr("AtomicIIncrement: Memory Semantics UniformMemory "
1708                         "requires capability Shader"));
1709 }
1710 
1711 // Lack of the AtomicStorage capability is intentionally ignored, see
1712 // https://github.com/KhronosGroup/glslang/issues/1618 for the reasoning why.
TEST_F(ValidateAtomics,AtomicCounterMemorySemanticsNoCapability)1713 TEST_F(ValidateAtomics, AtomicCounterMemorySemanticsNoCapability) {
1714   const std::string body = R"(
1715  OpAtomicStore %u32_var %device %relaxed %u32_1
1716 %val1 = OpAtomicIIncrement %u32 %u32_var %device
1717 %acquire_release_atomic_counter_workgroup
1718 )";
1719 
1720   CompileSuccessfully(GenerateKernelCode(body));
1721   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
1722 }
1723 
TEST_F(ValidateAtomics,AtomicCounterMemorySemanticsWithCapability)1724 TEST_F(ValidateAtomics, AtomicCounterMemorySemanticsWithCapability) {
1725   const std::string body = R"(
1726 OpAtomicStore %u32_var %device %relaxed %u32_1
1727 %val1 = OpAtomicIIncrement %u32 %u32_var %device %acquire_release_atomic_counter_workgroup
1728 )";
1729 
1730   CompileSuccessfully(GenerateKernelCode(body, "OpCapability AtomicStorage\n"));
1731   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
1732 }
1733 
TEST_F(ValidateAtomics,VulkanMemoryModelBanSequentiallyConsistentAtomicLoad)1734 TEST_F(ValidateAtomics, VulkanMemoryModelBanSequentiallyConsistentAtomicLoad) {
1735   const std::string body = R"(
1736 %ld = OpAtomicLoad %u32 %u32_var %workgroup %sequentially_consistent
1737 )";
1738 
1739   const std::string extra = R"(
1740 OpCapability VulkanMemoryModelKHR
1741 OpExtension "SPV_KHR_vulkan_memory_model"
1742 )";
1743 
1744   CompileSuccessfully(GenerateShaderCode(body, extra, "", "VulkanKHR"),
1745                       SPV_ENV_UNIVERSAL_1_3);
1746   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
1747             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1748   EXPECT_THAT(getDiagnosticString(),
1749               HasSubstr("SequentiallyConsistent memory semantics cannot be "
1750                         "used with the VulkanKHR memory model."));
1751 }
1752 
TEST_F(ValidateAtomics,VulkanMemoryModelBanSequentiallyConsistentAtomicStore)1753 TEST_F(ValidateAtomics, VulkanMemoryModelBanSequentiallyConsistentAtomicStore) {
1754   const std::string body = R"(
1755 OpAtomicStore %u32_var %workgroup %sequentially_consistent %u32_0
1756 )";
1757 
1758   const std::string extra = R"(
1759 OpCapability VulkanMemoryModelKHR
1760 OpExtension "SPV_KHR_vulkan_memory_model"
1761 )";
1762 
1763   CompileSuccessfully(GenerateShaderCode(body, extra, "", "VulkanKHR"),
1764                       SPV_ENV_UNIVERSAL_1_3);
1765   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
1766             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1767   EXPECT_THAT(getDiagnosticString(),
1768               HasSubstr("SequentiallyConsistent memory semantics cannot be "
1769                         "used with the VulkanKHR memory model."));
1770 }
1771 
TEST_F(ValidateAtomics,VulkanMemoryModelBanSequentiallyConsistentAtomicExchange)1772 TEST_F(ValidateAtomics,
1773        VulkanMemoryModelBanSequentiallyConsistentAtomicExchange) {
1774   const std::string body = R"(
1775 %ex = OpAtomicExchange %u32 %u32_var %workgroup %sequentially_consistent %u32_0
1776 )";
1777 
1778   const std::string extra = R"(
1779 OpCapability VulkanMemoryModelKHR
1780 OpExtension "SPV_KHR_vulkan_memory_model"
1781 )";
1782 
1783   CompileSuccessfully(GenerateShaderCode(body, extra, "", "VulkanKHR"),
1784                       SPV_ENV_UNIVERSAL_1_3);
1785   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
1786             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1787   EXPECT_THAT(getDiagnosticString(),
1788               HasSubstr("SequentiallyConsistent memory semantics cannot be "
1789                         "used with the VulkanKHR memory model."));
1790 }
1791 
TEST_F(ValidateAtomics,VulkanMemoryModelBanSequentiallyConsistentAtomicCompareExchangeEqual)1792 TEST_F(ValidateAtomics,
1793        VulkanMemoryModelBanSequentiallyConsistentAtomicCompareExchangeEqual) {
1794   const std::string body = R"(
1795 %ex = OpAtomicCompareExchange %u32 %u32_var %workgroup %sequentially_consistent %relaxed %u32_0 %u32_0
1796 )";
1797 
1798   const std::string extra = R"(
1799 OpCapability VulkanMemoryModelKHR
1800 OpExtension "SPV_KHR_vulkan_memory_model"
1801 )";
1802 
1803   CompileSuccessfully(GenerateShaderCode(body, extra, "", "VulkanKHR"),
1804                       SPV_ENV_UNIVERSAL_1_3);
1805   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
1806             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1807   EXPECT_THAT(getDiagnosticString(),
1808               HasSubstr("SequentiallyConsistent memory semantics cannot be "
1809                         "used with the VulkanKHR memory model."));
1810 }
1811 
TEST_F(ValidateAtomics,VulkanMemoryModelBanSequentiallyConsistentAtomicCompareExchangeUnequal)1812 TEST_F(ValidateAtomics,
1813        VulkanMemoryModelBanSequentiallyConsistentAtomicCompareExchangeUnequal) {
1814   const std::string body = R"(
1815 %ex = OpAtomicCompareExchange %u32 %u32_var %workgroup %relaxed %sequentially_consistent %u32_0 %u32_0
1816 )";
1817 
1818   const std::string extra = R"(
1819 OpCapability VulkanMemoryModelKHR
1820 OpExtension "SPV_KHR_vulkan_memory_model"
1821 )";
1822 
1823   CompileSuccessfully(GenerateShaderCode(body, extra, "", "VulkanKHR"),
1824                       SPV_ENV_UNIVERSAL_1_3);
1825   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
1826             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1827   EXPECT_THAT(getDiagnosticString(),
1828               HasSubstr("SequentiallyConsistent memory semantics cannot be "
1829                         "used with the VulkanKHR memory model."));
1830 }
1831 
TEST_F(ValidateAtomics,VulkanMemoryModelBanSequentiallyConsistentAtomicIIncrement)1832 TEST_F(ValidateAtomics,
1833        VulkanMemoryModelBanSequentiallyConsistentAtomicIIncrement) {
1834   const std::string body = R"(
1835 %inc = OpAtomicIIncrement %u32 %u32_var %workgroup %sequentially_consistent
1836 )";
1837 
1838   const std::string extra = R"(
1839 OpCapability VulkanMemoryModelKHR
1840 OpExtension "SPV_KHR_vulkan_memory_model"
1841 )";
1842 
1843   CompileSuccessfully(GenerateShaderCode(body, extra, "", "VulkanKHR"),
1844                       SPV_ENV_UNIVERSAL_1_3);
1845   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
1846             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1847   EXPECT_THAT(getDiagnosticString(),
1848               HasSubstr("SequentiallyConsistent memory semantics cannot be "
1849                         "used with the VulkanKHR memory model."));
1850 }
1851 
TEST_F(ValidateAtomics,VulkanMemoryModelBanSequentiallyConsistentAtomicIDecrement)1852 TEST_F(ValidateAtomics,
1853        VulkanMemoryModelBanSequentiallyConsistentAtomicIDecrement) {
1854   const std::string body = R"(
1855 %dec = OpAtomicIDecrement %u32 %u32_var %workgroup %sequentially_consistent
1856 )";
1857 
1858   const std::string extra = R"(
1859 OpCapability VulkanMemoryModelKHR
1860 OpExtension "SPV_KHR_vulkan_memory_model"
1861 )";
1862 
1863   CompileSuccessfully(GenerateShaderCode(body, extra, "", "VulkanKHR"),
1864                       SPV_ENV_UNIVERSAL_1_3);
1865   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
1866             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1867   EXPECT_THAT(getDiagnosticString(),
1868               HasSubstr("SequentiallyConsistent memory semantics cannot be "
1869                         "used with the VulkanKHR memory model."));
1870 }
1871 
TEST_F(ValidateAtomics,VulkanMemoryModelBanSequentiallyConsistentAtomicIAdd)1872 TEST_F(ValidateAtomics, VulkanMemoryModelBanSequentiallyConsistentAtomicIAdd) {
1873   const std::string body = R"(
1874 %add = OpAtomicIAdd %u32 %u32_var %workgroup %sequentially_consistent %u32_0
1875 )";
1876 
1877   const std::string extra = R"(
1878 OpCapability VulkanMemoryModelKHR
1879 OpExtension "SPV_KHR_vulkan_memory_model"
1880 )";
1881 
1882   CompileSuccessfully(GenerateShaderCode(body, extra, "", "VulkanKHR"),
1883                       SPV_ENV_UNIVERSAL_1_3);
1884   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
1885             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1886   EXPECT_THAT(getDiagnosticString(),
1887               HasSubstr("SequentiallyConsistent memory semantics cannot be "
1888                         "used with the VulkanKHR memory model."));
1889 }
1890 
TEST_F(ValidateAtomics,VulkanMemoryModelBanSequentiallyConsistentAtomicISub)1891 TEST_F(ValidateAtomics, VulkanMemoryModelBanSequentiallyConsistentAtomicISub) {
1892   const std::string body = R"(
1893 %sub = OpAtomicISub %u32 %u32_var %workgroup %sequentially_consistent %u32_0
1894 )";
1895 
1896   const std::string extra = R"(
1897 OpCapability VulkanMemoryModelKHR
1898 OpExtension "SPV_KHR_vulkan_memory_model"
1899 )";
1900 
1901   CompileSuccessfully(GenerateShaderCode(body, extra, "", "VulkanKHR"),
1902                       SPV_ENV_UNIVERSAL_1_3);
1903   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
1904             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1905   EXPECT_THAT(getDiagnosticString(),
1906               HasSubstr("SequentiallyConsistent memory semantics cannot be "
1907                         "used with the VulkanKHR memory model."));
1908 }
1909 
TEST_F(ValidateAtomics,VulkanMemoryModelBanSequentiallyConsistentAtomicSMin)1910 TEST_F(ValidateAtomics, VulkanMemoryModelBanSequentiallyConsistentAtomicSMin) {
1911   const std::string body = R"(
1912 %min = OpAtomicSMin %u32 %u32_var %workgroup %sequentially_consistent %u32_0
1913 )";
1914 
1915   const std::string extra = R"(
1916 OpCapability VulkanMemoryModelKHR
1917 OpExtension "SPV_KHR_vulkan_memory_model"
1918 )";
1919 
1920   CompileSuccessfully(GenerateShaderCode(body, extra, "", "VulkanKHR"),
1921                       SPV_ENV_UNIVERSAL_1_3);
1922   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
1923             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1924   EXPECT_THAT(getDiagnosticString(),
1925               HasSubstr("SequentiallyConsistent memory semantics cannot be "
1926                         "used with the VulkanKHR memory model."));
1927 }
1928 
TEST_F(ValidateAtomics,VulkanMemoryModelBanSequentiallyConsistentAtomicUMin)1929 TEST_F(ValidateAtomics, VulkanMemoryModelBanSequentiallyConsistentAtomicUMin) {
1930   const std::string body = R"(
1931 %min = OpAtomicUMin %u32 %u32_var %workgroup %sequentially_consistent %u32_0
1932 )";
1933 
1934   const std::string extra = R"(
1935 OpCapability VulkanMemoryModelKHR
1936 OpExtension "SPV_KHR_vulkan_memory_model"
1937 )";
1938 
1939   CompileSuccessfully(GenerateShaderCode(body, extra, "", "VulkanKHR"),
1940                       SPV_ENV_UNIVERSAL_1_3);
1941   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
1942             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1943   EXPECT_THAT(getDiagnosticString(),
1944               HasSubstr("SequentiallyConsistent memory semantics cannot be "
1945                         "used with the VulkanKHR memory model."));
1946 }
1947 
TEST_F(ValidateAtomics,VulkanMemoryModelBanSequentiallyConsistentAtomicFMinEXT)1948 TEST_F(ValidateAtomics, VulkanMemoryModelBanSequentiallyConsistentAtomicFMinEXT) {
1949   const std::string body = R"(
1950 %max = OpAtomicFMinEXT %f32 %f32_var %workgroup %sequentially_consistent %f32_0
1951 )";
1952 
1953   const std::string extra = R"(
1954 OpCapability VulkanMemoryModelKHR
1955 OpCapability AtomicFloat32MinMaxEXT
1956 OpExtension "SPV_KHR_vulkan_memory_model"
1957 OpExtension "SPV_EXT_shader_atomic_float_min_max"
1958 )";
1959 
1960   CompileSuccessfully(GenerateShaderCode(body, extra, "", "VulkanKHR"),
1961                       SPV_ENV_UNIVERSAL_1_3);
1962   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
1963             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1964   EXPECT_THAT(getDiagnosticString(),
1965               HasSubstr("SequentiallyConsistent memory semantics cannot be "
1966                         "used with the VulkanKHR memory model."));
1967 }
1968 
TEST_F(ValidateAtomics,VulkanMemoryModelBanSequentiallyConsistentAtomicSMax)1969 TEST_F(ValidateAtomics, VulkanMemoryModelBanSequentiallyConsistentAtomicSMax) {
1970   const std::string body = R"(
1971 %max = OpAtomicSMax %u32 %u32_var %workgroup %sequentially_consistent %u32_0
1972 )";
1973 
1974   const std::string extra = R"(
1975 OpCapability VulkanMemoryModelKHR
1976 OpExtension "SPV_KHR_vulkan_memory_model"
1977 )";
1978 
1979   CompileSuccessfully(GenerateShaderCode(body, extra, "", "VulkanKHR"),
1980                       SPV_ENV_UNIVERSAL_1_3);
1981   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
1982             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1983   EXPECT_THAT(getDiagnosticString(),
1984               HasSubstr("SequentiallyConsistent memory semantics cannot be "
1985                         "used with the VulkanKHR memory model."));
1986 }
1987 
TEST_F(ValidateAtomics,VulkanMemoryModelBanSequentiallyConsistentAtomicUMax)1988 TEST_F(ValidateAtomics, VulkanMemoryModelBanSequentiallyConsistentAtomicUMax) {
1989   const std::string body = R"(
1990 %max = OpAtomicUMax %u32 %u32_var %workgroup %sequentially_consistent %u32_0
1991 )";
1992 
1993   const std::string extra = R"(
1994 OpCapability VulkanMemoryModelKHR
1995 OpExtension "SPV_KHR_vulkan_memory_model"
1996 )";
1997 
1998   CompileSuccessfully(GenerateShaderCode(body, extra, "", "VulkanKHR"),
1999                       SPV_ENV_UNIVERSAL_1_3);
2000   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
2001             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
2002   EXPECT_THAT(getDiagnosticString(),
2003               HasSubstr("SequentiallyConsistent memory semantics cannot be "
2004                         "used with the VulkanKHR memory model."));
2005 }
2006 
TEST_F(ValidateAtomics,VulkanMemoryModelBanSequentiallyConsistentAtomicFMaxEXT)2007 TEST_F(ValidateAtomics, VulkanMemoryModelBanSequentiallyConsistentAtomicFMaxEXT) {
2008   const std::string body = R"(
2009 %max = OpAtomicFMaxEXT %f32 %f32_var %workgroup %sequentially_consistent %f32_0
2010 )";
2011 
2012   const std::string extra = R"(
2013 OpCapability VulkanMemoryModelKHR
2014 OpCapability AtomicFloat32MinMaxEXT
2015 OpExtension "SPV_KHR_vulkan_memory_model"
2016 OpExtension "SPV_EXT_shader_atomic_float_min_max"
2017 )";
2018 
2019   CompileSuccessfully(GenerateShaderCode(body, extra, "", "VulkanKHR"),
2020                       SPV_ENV_UNIVERSAL_1_3);
2021   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
2022             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
2023   EXPECT_THAT(getDiagnosticString(),
2024               HasSubstr("SequentiallyConsistent memory semantics cannot be "
2025                         "used with the VulkanKHR memory model."));
2026 }
2027 
TEST_F(ValidateAtomics,VulkanMemoryModelBanSequentiallyConsistentAtomicAnd)2028 TEST_F(ValidateAtomics, VulkanMemoryModelBanSequentiallyConsistentAtomicAnd) {
2029   const std::string body = R"(
2030 %and = OpAtomicAnd %u32 %u32_var %workgroup %sequentially_consistent %u32_0
2031 )";
2032 
2033   const std::string extra = R"(
2034 OpCapability VulkanMemoryModelKHR
2035 OpExtension "SPV_KHR_vulkan_memory_model"
2036 )";
2037 
2038   CompileSuccessfully(GenerateShaderCode(body, extra, "", "VulkanKHR"),
2039                       SPV_ENV_UNIVERSAL_1_3);
2040   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
2041             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
2042   EXPECT_THAT(getDiagnosticString(),
2043               HasSubstr("SequentiallyConsistent memory semantics cannot be "
2044                         "used with the VulkanKHR memory model."));
2045 }
2046 
TEST_F(ValidateAtomics,VulkanMemoryModelBanSequentiallyConsistentAtomicOr)2047 TEST_F(ValidateAtomics, VulkanMemoryModelBanSequentiallyConsistentAtomicOr) {
2048   const std::string body = R"(
2049 %or = OpAtomicOr %u32 %u32_var %workgroup %sequentially_consistent %u32_0
2050 )";
2051 
2052   const std::string extra = R"(
2053 OpCapability VulkanMemoryModelKHR
2054 OpExtension "SPV_KHR_vulkan_memory_model"
2055 )";
2056 
2057   CompileSuccessfully(GenerateShaderCode(body, extra, "", "VulkanKHR"),
2058                       SPV_ENV_UNIVERSAL_1_3);
2059   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
2060             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
2061   EXPECT_THAT(getDiagnosticString(),
2062               HasSubstr("SequentiallyConsistent memory semantics cannot be "
2063                         "used with the VulkanKHR memory model."));
2064 }
2065 
TEST_F(ValidateAtomics,VulkanMemoryModelBanSequentiallyConsistentAtomicXor)2066 TEST_F(ValidateAtomics, VulkanMemoryModelBanSequentiallyConsistentAtomicXor) {
2067   const std::string body = R"(
2068 %xor = OpAtomicXor %u32 %u32_var %workgroup %sequentially_consistent %u32_0
2069 )";
2070 
2071   const std::string extra = R"(
2072 OpCapability VulkanMemoryModelKHR
2073 OpExtension "SPV_KHR_vulkan_memory_model"
2074 )";
2075 
2076   CompileSuccessfully(GenerateShaderCode(body, extra, "", "VulkanKHR"),
2077                       SPV_ENV_UNIVERSAL_1_3);
2078   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
2079             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
2080   EXPECT_THAT(getDiagnosticString(),
2081               HasSubstr("SequentiallyConsistent memory semantics cannot be "
2082                         "used with the VulkanKHR memory model."));
2083 }
2084 
TEST_F(ValidateAtomics,OutputMemoryKHRRequiresVulkanMemoryModelKHR)2085 TEST_F(ValidateAtomics, OutputMemoryKHRRequiresVulkanMemoryModelKHR) {
2086   const std::string text = R"(
2087 OpCapability Shader
2088 OpMemoryModel Logical GLSL450
2089 OpEntryPoint Fragment %1 "func"
2090 OpExecutionMode %1 OriginUpperLeft
2091 %2 = OpTypeVoid
2092 %3 = OpTypeInt 32 0
2093 %semantics = OpConstant %3 4100
2094 %5 = OpTypeFunction %2
2095 %workgroup = OpConstant %3 2
2096 %ptr = OpTypePointer Workgroup %3
2097 %var = OpVariable %ptr Workgroup
2098 %1 = OpFunction %2 None %5
2099 %7 = OpLabel
2100 OpAtomicStore %var %workgroup %semantics %workgroup
2101 OpReturn
2102 OpFunctionEnd
2103 )";
2104 
2105   CompileSuccessfully(text);
2106   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
2107   EXPECT_THAT(getDiagnosticString(),
2108               HasSubstr("AtomicStore: Memory Semantics OutputMemoryKHR "
2109                         "requires capability VulkanMemoryModelKHR"));
2110 }
2111 
TEST_F(ValidateAtomics,MakeAvailableKHRRequiresVulkanMemoryModelKHR)2112 TEST_F(ValidateAtomics, MakeAvailableKHRRequiresVulkanMemoryModelKHR) {
2113   const std::string text = R"(
2114 OpCapability Shader
2115 OpMemoryModel Logical GLSL450
2116 OpEntryPoint Fragment %1 "func"
2117 OpExecutionMode %1 OriginUpperLeft
2118 %2 = OpTypeVoid
2119 %3 = OpTypeInt 32 0
2120 %semantics = OpConstant %3 8196
2121 %5 = OpTypeFunction %2
2122 %workgroup = OpConstant %3 2
2123 %ptr = OpTypePointer Workgroup %3
2124 %var = OpVariable %ptr Workgroup
2125 %1 = OpFunction %2 None %5
2126 %7 = OpLabel
2127 OpAtomicStore %var %workgroup %semantics %workgroup
2128 OpReturn
2129 OpFunctionEnd
2130 )";
2131 
2132   CompileSuccessfully(text);
2133   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
2134   EXPECT_THAT(getDiagnosticString(),
2135               HasSubstr("AtomicStore: Memory Semantics MakeAvailableKHR "
2136                         "requires capability VulkanMemoryModelKHR"));
2137 }
2138 
TEST_F(ValidateAtomics,MakeVisibleKHRRequiresVulkanMemoryModelKHR)2139 TEST_F(ValidateAtomics, MakeVisibleKHRRequiresVulkanMemoryModelKHR) {
2140   const std::string text = R"(
2141 OpCapability Shader
2142 OpMemoryModel Logical GLSL450
2143 OpEntryPoint Fragment %1 "func"
2144 OpExecutionMode %1 OriginUpperLeft
2145 %2 = OpTypeVoid
2146 %3 = OpTypeInt 32 0
2147 %semantics = OpConstant %3 16386
2148 %5 = OpTypeFunction %2
2149 %workgroup = OpConstant %3 2
2150 %ptr = OpTypePointer Workgroup %3
2151 %var = OpVariable %ptr Workgroup
2152 %1 = OpFunction %2 None %5
2153 %7 = OpLabel
2154 %ld = OpAtomicLoad %3 %var %workgroup %semantics
2155 OpReturn
2156 OpFunctionEnd
2157 )";
2158 
2159   CompileSuccessfully(text);
2160   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
2161   EXPECT_THAT(getDiagnosticString(),
2162               HasSubstr("AtomicLoad: Memory Semantics MakeVisibleKHR requires "
2163                         "capability VulkanMemoryModelKHR"));
2164 }
2165 
TEST_F(ValidateAtomics,MakeAvailableKHRRequiresReleaseSemantics)2166 TEST_F(ValidateAtomics, MakeAvailableKHRRequiresReleaseSemantics) {
2167   const std::string text = R"(
2168 OpCapability Shader
2169 OpCapability VulkanMemoryModelKHR
2170 OpExtension "SPV_KHR_vulkan_memory_model"
2171 OpMemoryModel Logical VulkanKHR
2172 OpEntryPoint Fragment %1 "func"
2173 OpExecutionMode %1 OriginUpperLeft
2174 %2 = OpTypeVoid
2175 %3 = OpTypeInt 32 0
2176 %semantics = OpConstant %3 8448
2177 %5 = OpTypeFunction %2
2178 %workgroup = OpConstant %3 2
2179 %ptr = OpTypePointer Workgroup %3
2180 %var = OpVariable %ptr Workgroup
2181 %1 = OpFunction %2 None %5
2182 %7 = OpLabel
2183 OpAtomicStore %var %workgroup %semantics %workgroup
2184 OpReturn
2185 OpFunctionEnd
2186 )";
2187 
2188   CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3);
2189   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
2190             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
2191   EXPECT_THAT(
2192       getDiagnosticString(),
2193       HasSubstr("AtomicStore: MakeAvailableKHR Memory Semantics also requires "
2194                 "either Release or AcquireRelease Memory Semantics"));
2195 }
2196 
TEST_F(ValidateAtomics,MakeVisibleKHRRequiresAcquireSemantics)2197 TEST_F(ValidateAtomics, MakeVisibleKHRRequiresAcquireSemantics) {
2198   const std::string text = R"(
2199 OpCapability Shader
2200 OpCapability VulkanMemoryModelKHR
2201 OpExtension "SPV_KHR_vulkan_memory_model"
2202 OpMemoryModel Logical VulkanKHR
2203 OpEntryPoint Fragment %1 "func"
2204 OpExecutionMode %1 OriginUpperLeft
2205 %2 = OpTypeVoid
2206 %3 = OpTypeInt 32 0
2207 %semantics = OpConstant %3 16640
2208 %5 = OpTypeFunction %2
2209 %workgroup = OpConstant %3 2
2210 %ptr = OpTypePointer Workgroup %3
2211 %var = OpVariable %ptr Workgroup
2212 %1 = OpFunction %2 None %5
2213 %7 = OpLabel
2214 %ld = OpAtomicLoad %3 %var %workgroup %semantics
2215 OpReturn
2216 OpFunctionEnd
2217 )";
2218 
2219   CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3);
2220   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
2221             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
2222   EXPECT_THAT(
2223       getDiagnosticString(),
2224       HasSubstr("AtomicLoad: MakeVisibleKHR Memory Semantics also requires "
2225                 "either Acquire or AcquireRelease Memory Semantics"));
2226 }
2227 
TEST_F(ValidateAtomics,MakeAvailableKHRRequiresStorageSemantics)2228 TEST_F(ValidateAtomics, MakeAvailableKHRRequiresStorageSemantics) {
2229   const std::string text = R"(
2230 OpCapability Shader
2231 OpCapability VulkanMemoryModelKHR
2232 OpExtension "SPV_KHR_vulkan_memory_model"
2233 OpMemoryModel Logical VulkanKHR
2234 OpEntryPoint Fragment %1 "func"
2235 OpExecutionMode %1 OriginUpperLeft
2236 %2 = OpTypeVoid
2237 %3 = OpTypeInt 32 0
2238 %semantics = OpConstant %3 8196
2239 %5 = OpTypeFunction %2
2240 %workgroup = OpConstant %3 2
2241 %ptr = OpTypePointer Workgroup %3
2242 %var = OpVariable %ptr Workgroup
2243 %1 = OpFunction %2 None %5
2244 %7 = OpLabel
2245 OpAtomicStore %var %workgroup %semantics %workgroup
2246 OpReturn
2247 OpFunctionEnd
2248 )";
2249 
2250   CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3);
2251   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
2252             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
2253   EXPECT_THAT(
2254       getDiagnosticString(),
2255       HasSubstr(
2256           "AtomicStore: expected Memory Semantics to include a storage class"));
2257 }
2258 
TEST_F(ValidateAtomics,MakeVisibleKHRRequiresStorageSemantics)2259 TEST_F(ValidateAtomics, MakeVisibleKHRRequiresStorageSemantics) {
2260   const std::string text = R"(
2261 OpCapability Shader
2262 OpCapability VulkanMemoryModelKHR
2263 OpExtension "SPV_KHR_vulkan_memory_model"
2264 OpMemoryModel Logical VulkanKHR
2265 OpEntryPoint Fragment %1 "func"
2266 OpExecutionMode %1 OriginUpperLeft
2267 %2 = OpTypeVoid
2268 %3 = OpTypeInt 32 0
2269 %semantics = OpConstant %3 16386
2270 %5 = OpTypeFunction %2
2271 %workgroup = OpConstant %3 2
2272 %ptr = OpTypePointer Workgroup %3
2273 %var = OpVariable %ptr Workgroup
2274 %1 = OpFunction %2 None %5
2275 %7 = OpLabel
2276 %ld = OpAtomicLoad %3 %var %workgroup %semantics
2277 OpReturn
2278 OpFunctionEnd
2279 )";
2280 
2281   CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3);
2282   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
2283             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
2284   EXPECT_THAT(
2285       getDiagnosticString(),
2286       HasSubstr(
2287           "AtomicLoad: expected Memory Semantics to include a storage class"));
2288 }
2289 
TEST_F(ValidateAtomics,VulkanMemoryModelAllowsQueueFamilyKHR)2290 TEST_F(ValidateAtomics, VulkanMemoryModelAllowsQueueFamilyKHR) {
2291   const std::string body = R"(
2292 %val = OpAtomicAnd %u32 %u32_var %queuefamily %relaxed %u32_1
2293 )";
2294 
2295   const std::string extra = R"(
2296 OpCapability VulkanMemoryModelKHR
2297 OpExtension "SPV_KHR_vulkan_memory_model"
2298 )";
2299 
2300   CompileSuccessfully(GenerateShaderCode(body, extra, "", "VulkanKHR"),
2301                       SPV_ENV_VULKAN_1_1);
2302   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
2303 }
2304 
TEST_F(ValidateAtomics,NonVulkanMemoryModelDisallowsQueueFamilyKHR)2305 TEST_F(ValidateAtomics, NonVulkanMemoryModelDisallowsQueueFamilyKHR) {
2306   const std::string body = R"(
2307 %val = OpAtomicAnd %u32 %u32_var %queuefamily %relaxed %u32_1
2308 )";
2309 
2310   CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_1);
2311   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_1));
2312   EXPECT_THAT(getDiagnosticString(),
2313               HasSubstr("AtomicAnd: Memory Scope QueueFamilyKHR requires "
2314                         "capability VulkanMemoryModelKHR\n  %42 = OpAtomicAnd "
2315                         "%uint %29 %uint_5 %uint_0_1 %uint_1\n"));
2316 }
2317 
TEST_F(ValidateAtomics,SemanticsSpecConstantShader)2318 TEST_F(ValidateAtomics, SemanticsSpecConstantShader) {
2319   const std::string spirv = R"(
2320 OpCapability Shader
2321 OpMemoryModel Logical GLSL450
2322 OpEntryPoint Fragment %func "func"
2323 OpExecutionMode %func OriginUpperLeft
2324 %void = OpTypeVoid
2325 %int = OpTypeInt 32 0
2326 %spec_const = OpSpecConstant %int 0
2327 %workgroup = OpConstant %int 2
2328 %ptr_int_workgroup = OpTypePointer Workgroup %int
2329 %var = OpVariable %ptr_int_workgroup Workgroup
2330 %voidfn = OpTypeFunction %void
2331 %func = OpFunction %void None %voidfn
2332 %entry = OpLabel
2333 %ld = OpAtomicLoad %int %var %workgroup %spec_const
2334 OpReturn
2335 OpFunctionEnd
2336 )";
2337 
2338   CompileSuccessfully(spirv);
2339   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
2340   EXPECT_THAT(getDiagnosticString(),
2341               HasSubstr("Memory Semantics ids must be OpConstant when Shader "
2342                         "capability is present"));
2343 }
2344 
TEST_F(ValidateAtomics,SemanticsSpecConstantKernel)2345 TEST_F(ValidateAtomics, SemanticsSpecConstantKernel) {
2346   const std::string spirv = R"(
2347 OpCapability Kernel
2348 OpCapability Linkage
2349 OpMemoryModel Logical OpenCL
2350 %void = OpTypeVoid
2351 %int = OpTypeInt 32 0
2352 %spec_const = OpSpecConstant %int 0
2353 %workgroup = OpConstant %int 2
2354 %ptr_int_workgroup = OpTypePointer Workgroup %int
2355 %var = OpVariable %ptr_int_workgroup Workgroup
2356 %voidfn = OpTypeFunction %void
2357 %func = OpFunction %void None %voidfn
2358 %entry = OpLabel
2359 %ld = OpAtomicLoad %int %var %workgroup %spec_const
2360 OpReturn
2361 OpFunctionEnd
2362 )";
2363 
2364   CompileSuccessfully(spirv);
2365   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
2366 }
2367 
TEST_F(ValidateAtomics,ScopeSpecConstantShader)2368 TEST_F(ValidateAtomics, ScopeSpecConstantShader) {
2369   const std::string spirv = R"(
2370 OpCapability Shader
2371 OpMemoryModel Logical GLSL450
2372 OpEntryPoint Fragment %func "func"
2373 OpExecutionMode %func OriginUpperLeft
2374 %void = OpTypeVoid
2375 %int = OpTypeInt 32 0
2376 %spec_const = OpSpecConstant %int 0
2377 %relaxed = OpConstant %int 0
2378 %ptr_int_workgroup = OpTypePointer Workgroup %int
2379 %var = OpVariable %ptr_int_workgroup Workgroup
2380 %voidfn = OpTypeFunction %void
2381 %func = OpFunction %void None %voidfn
2382 %entry = OpLabel
2383 %ld = OpAtomicLoad %int %var %spec_const %relaxed
2384 OpReturn
2385 OpFunctionEnd
2386 )";
2387 
2388   CompileSuccessfully(spirv);
2389   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
2390   EXPECT_THAT(
2391       getDiagnosticString(),
2392       HasSubstr(
2393           "Scope ids must be OpConstant when Shader capability is present"));
2394 }
2395 
TEST_F(ValidateAtomics,ScopeSpecConstantKernel)2396 TEST_F(ValidateAtomics, ScopeSpecConstantKernel) {
2397   const std::string spirv = R"(
2398 OpCapability Kernel
2399 OpCapability Linkage
2400 OpMemoryModel Logical OpenCL
2401 %void = OpTypeVoid
2402 %int = OpTypeInt 32 0
2403 %spec_const = OpSpecConstant %int 0
2404 %relaxed = OpConstant %int 0
2405 %ptr_int_workgroup = OpTypePointer Workgroup %int
2406 %var = OpVariable %ptr_int_workgroup Workgroup
2407 %voidfn = OpTypeFunction %void
2408 %func = OpFunction %void None %voidfn
2409 %entry = OpLabel
2410 %ld = OpAtomicLoad %int %var %spec_const %relaxed
2411 OpReturn
2412 OpFunctionEnd
2413 )";
2414 
2415   CompileSuccessfully(spirv);
2416   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
2417 }
2418 
TEST_F(ValidateAtomics,VulkanMemoryModelDeviceScopeBad)2419 TEST_F(ValidateAtomics, VulkanMemoryModelDeviceScopeBad) {
2420   const std::string body = R"(
2421 %val = OpAtomicAnd %u32 %u32_var %device %relaxed %u32_1
2422 )";
2423 
2424   const std::string extra = R"(OpCapability VulkanMemoryModelKHR
2425 OpExtension "SPV_KHR_vulkan_memory_model"
2426 )";
2427 
2428   CompileSuccessfully(GenerateShaderCode(body, extra, "", "VulkanKHR"),
2429                       SPV_ENV_UNIVERSAL_1_3);
2430   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
2431             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
2432   EXPECT_THAT(
2433       getDiagnosticString(),
2434       HasSubstr("Use of device scope with VulkanKHR memory model requires the "
2435                 "VulkanMemoryModelDeviceScopeKHR capability"));
2436 }
2437 
TEST_F(ValidateAtomics,VulkanMemoryModelDeviceScopeGood)2438 TEST_F(ValidateAtomics, VulkanMemoryModelDeviceScopeGood) {
2439   const std::string body = R"(
2440 %val = OpAtomicAnd %u32 %u32_var %device %relaxed %u32_1
2441 )";
2442 
2443   const std::string extra = R"(OpCapability VulkanMemoryModelKHR
2444 OpCapability VulkanMemoryModelDeviceScopeKHR
2445 OpExtension "SPV_KHR_vulkan_memory_model"
2446 )";
2447 
2448   CompileSuccessfully(GenerateShaderCode(body, extra, "", "VulkanKHR"),
2449                       SPV_ENV_UNIVERSAL_1_3);
2450   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
2451 }
2452 
TEST_F(ValidateAtomics,CompareExchangeWeakV13ValV14Good)2453 TEST_F(ValidateAtomics, CompareExchangeWeakV13ValV14Good) {
2454   const std::string body = R"(
2455 %val1 = OpAtomicCompareExchangeWeak %u32 %u32_var %device %relaxed %relaxed %u32_0 %u32_0
2456 )";
2457 
2458   CompileSuccessfully(GenerateKernelCode(body), SPV_ENV_UNIVERSAL_1_3);
2459   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
2460 }
2461 
TEST_F(ValidateAtomics,CompareExchangeWeakV14Bad)2462 TEST_F(ValidateAtomics, CompareExchangeWeakV14Bad) {
2463   const std::string body = R"(
2464 %val1 = OpAtomicCompareExchangeWeak %u32 %u32_var %device %relaxed %relaxed %u32_0 %u32_0
2465 )";
2466 
2467   CompileSuccessfully(GenerateKernelCode(body), SPV_ENV_UNIVERSAL_1_4);
2468   EXPECT_EQ(SPV_ERROR_WRONG_VERSION,
2469             ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
2470   EXPECT_THAT(
2471       getDiagnosticString(),
2472       HasSubstr(
2473           "AtomicCompareExchangeWeak requires SPIR-V version 1.3 or earlier"));
2474 }
2475 
TEST_F(ValidateAtomics,CompareExchangeVolatileMatch)2476 TEST_F(ValidateAtomics, CompareExchangeVolatileMatch) {
2477   const std::string spirv = R"(
2478 OpCapability Shader
2479 OpCapability VulkanMemoryModelKHR
2480 OpCapability Linkage
2481 OpExtension "SPV_KHR_vulkan_memory_model"
2482 OpMemoryModel Logical VulkanKHR
2483 %void = OpTypeVoid
2484 %int = OpTypeInt 32 0
2485 %int_0 = OpConstant %int 0
2486 %int_1 = OpConstant %int 1
2487 %workgroup = OpConstant %int 2
2488 %volatile = OpConstant %int 32768
2489 %ptr_wg_int = OpTypePointer Workgroup %int
2490 %wg_var = OpVariable %ptr_wg_int Workgroup
2491 %void_fn = OpTypeFunction %void
2492 %func = OpFunction %void None %void_fn
2493 %entry = OpLabel
2494 %cmp_ex = OpAtomicCompareExchange %int %wg_var %workgroup %volatile %volatile %int_0 %int_1
2495 OpReturn
2496 OpFunctionEnd
2497 )";
2498 
2499   CompileSuccessfully(spirv);
2500   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
2501 }
2502 
TEST_F(ValidateAtomics,CompareExchangeVolatileMismatch)2503 TEST_F(ValidateAtomics, CompareExchangeVolatileMismatch) {
2504   const std::string spirv = R"(
2505 OpCapability Shader
2506 OpCapability VulkanMemoryModelKHR
2507 OpCapability Linkage
2508 OpExtension "SPV_KHR_vulkan_memory_model"
2509 OpMemoryModel Logical VulkanKHR
2510 %void = OpTypeVoid
2511 %int = OpTypeInt 32 0
2512 %int_0 = OpConstant %int 0
2513 %int_1 = OpConstant %int 1
2514 %workgroup = OpConstant %int 2
2515 %volatile = OpConstant %int 32768
2516 %non_volatile = OpConstant %int 0
2517 %ptr_wg_int = OpTypePointer Workgroup %int
2518 %wg_var = OpVariable %ptr_wg_int Workgroup
2519 %void_fn = OpTypeFunction %void
2520 %func = OpFunction %void None %void_fn
2521 %entry = OpLabel
2522 %cmp_ex = OpAtomicCompareExchange %int %wg_var %workgroup %non_volatile %volatile %int_0 %int_1
2523 OpReturn
2524 OpFunctionEnd
2525 )";
2526 
2527   CompileSuccessfully(spirv);
2528   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
2529   EXPECT_THAT(getDiagnosticString(),
2530               HasSubstr("Volatile mask setting must match for Equal and "
2531                         "Unequal memory semantics"));
2532 }
2533 
TEST_F(ValidateAtomics,CompareExchangeVolatileMismatchCooperativeMatrix)2534 TEST_F(ValidateAtomics, CompareExchangeVolatileMismatchCooperativeMatrix) {
2535   const std::string spirv = R"(
2536 OpCapability Shader
2537 OpCapability VulkanMemoryModelKHR
2538 OpCapability Linkage
2539 OpCapability CooperativeMatrixNV
2540 OpExtension "SPV_KHR_vulkan_memory_model"
2541 OpExtension "SPV_NV_cooperative_matrix"
2542 OpMemoryModel Logical VulkanKHR
2543 %void = OpTypeVoid
2544 %int = OpTypeInt 32 0
2545 %int_0 = OpConstant %int 0
2546 %int_1 = OpConstant %int 1
2547 %workgroup = OpConstant %int 2
2548 %volatile = OpSpecConstant %int 32768
2549 %non_volatile = OpSpecConstant %int 32768
2550 %ptr_wg_int = OpTypePointer Workgroup %int
2551 %wg_var = OpVariable %ptr_wg_int Workgroup
2552 %void_fn = OpTypeFunction %void
2553 %func = OpFunction %void None %void_fn
2554 %entry = OpLabel
2555 %cmp_ex = OpAtomicCompareExchange %int %wg_var %workgroup %volatile %non_volatile %int_0 %int_1
2556 OpReturn
2557 OpFunctionEnd
2558 )";
2559 
2560   // This is ok because we cannot evaluate the spec constant defaults.
2561   CompileSuccessfully(spirv);
2562   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
2563 }
2564 
TEST_F(ValidateAtomics,VolatileRequiresVulkanMemoryModel)2565 TEST_F(ValidateAtomics, VolatileRequiresVulkanMemoryModel) {
2566   const std::string spirv = R"(
2567 OpCapability Shader
2568 OpCapability Linkage
2569 OpMemoryModel Logical GLSL450
2570 %void = OpTypeVoid
2571 %int = OpTypeInt 32 0
2572 %int_0 = OpConstant %int 0
2573 %int_1 = OpConstant %int 1
2574 %workgroup = OpConstant %int 2
2575 %volatile = OpConstant %int 32768
2576 %ptr_wg_int = OpTypePointer Workgroup %int
2577 %wg_var = OpVariable %ptr_wg_int Workgroup
2578 %void_fn = OpTypeFunction %void
2579 %func = OpFunction %void None %void_fn
2580 %entry = OpLabel
2581 %ld = OpAtomicLoad %int %wg_var %workgroup %volatile
2582 OpReturn
2583 OpFunctionEnd
2584 )";
2585 
2586   CompileSuccessfully(spirv);
2587   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
2588   EXPECT_THAT(getDiagnosticString(),
2589               HasSubstr("Memory Semantics Volatile requires capability "
2590                         "VulkanMemoryModelKHR"));
2591 }
2592 
TEST_F(ValidateAtomics,CooperativeMatrixSemanticsMustBeConstant)2593 TEST_F(ValidateAtomics, CooperativeMatrixSemanticsMustBeConstant) {
2594   const std::string spirv = R"(
2595 OpCapability Shader
2596 OpCapability Linkage
2597 OpCapability CooperativeMatrixNV
2598 OpExtension "SPV_NV_cooperative_matrix"
2599 OpMemoryModel Logical GLSL450
2600 %void = OpTypeVoid
2601 %int = OpTypeInt 32 0
2602 %int_0 = OpConstant %int 0
2603 %int_1 = OpConstant %int 1
2604 %workgroup = OpConstant %int 2
2605 %undef = OpUndef %int
2606 %ptr_wg_int = OpTypePointer Workgroup %int
2607 %wg_var = OpVariable %ptr_wg_int Workgroup
2608 %void_fn = OpTypeFunction %void
2609 %func = OpFunction %void None %void_fn
2610 %entry = OpLabel
2611 %ld = OpAtomicLoad %int %wg_var %workgroup %undef
2612 OpReturn
2613 OpFunctionEnd
2614 )";
2615 
2616   CompileSuccessfully(spirv);
2617   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
2618   EXPECT_THAT(getDiagnosticString(),
2619               HasSubstr("Memory Semantics must be a constant instruction when "
2620                         "CooperativeMatrixNV capability is present"));
2621 }
2622 
2623 }  // namespace
2624 }  // namespace val
2625 }  // namespace spvtools
2626