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