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