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