1 // Copyright (c) 2018 Google LLC.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <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 ValidateBarriers = spvtest::ValidateBase<bool>;
30
GenerateShaderCodeImpl(const std::string & body,const std::string & capabilities_and_extensions,const std::string & definitions,const std::string & execution_model,const std::string & memory_model)31 std::string GenerateShaderCodeImpl(
32 const std::string& body, const std::string& capabilities_and_extensions,
33 const std::string& definitions, const std::string& execution_model,
34 const std::string& memory_model) {
35 std::ostringstream ss;
36 ss << R"(
37 OpCapability Shader
38 )";
39
40 ss << capabilities_and_extensions;
41 ss << memory_model << std::endl;
42 ss << "OpEntryPoint " << execution_model << " %main \"main\"\n";
43 if (execution_model == "Fragment") {
44 ss << "OpExecutionMode %main OriginUpperLeft\n";
45 } else if (execution_model == "Geometry") {
46 ss << "OpExecutionMode %main InputPoints\n";
47 ss << "OpExecutionMode %main OutputPoints\n";
48 } else if (execution_model == "GLCompute") {
49 ss << "OpExecutionMode %main LocalSize 1 1 1\n";
50 }
51
52 ss << R"(
53 %void = OpTypeVoid
54 %func = OpTypeFunction %void
55 %bool = OpTypeBool
56 %f32 = OpTypeFloat 32
57 %u32 = OpTypeInt 32 0
58
59 %f32_0 = OpConstant %f32 0
60 %f32_1 = OpConstant %f32 1
61 %u32_0 = OpConstant %u32 0
62 %u32_1 = OpConstant %u32 1
63 %u32_4 = OpConstant %u32 4
64 )";
65 ss << definitions;
66 ss << R"(
67 %cross_device = OpConstant %u32 0
68 %device = OpConstant %u32 1
69 %workgroup = OpConstant %u32 2
70 %subgroup = OpConstant %u32 3
71 %invocation = OpConstant %u32 4
72 %queuefamily = OpConstant %u32 5
73
74 %none = OpConstant %u32 0
75 %acquire = OpConstant %u32 2
76 %release = OpConstant %u32 4
77 %acquire_release = OpConstant %u32 8
78 %acquire_and_release = OpConstant %u32 6
79 %sequentially_consistent = OpConstant %u32 16
80 %acquire_release_uniform_workgroup = OpConstant %u32 328
81 %acquire_and_release_uniform = OpConstant %u32 70
82 %acquire_release_subgroup = OpConstant %u32 136
83 %uniform = OpConstant %u32 64
84
85 %main = OpFunction %void None %func
86 %main_entry = OpLabel
87 )";
88
89 ss << body;
90
91 ss << R"(
92 OpReturn
93 OpFunctionEnd)";
94
95 return ss.str();
96 }
97
GenerateShaderCode(const std::string & body,const std::string & capabilities_and_extensions="",const std::string & execution_model="GLCompute")98 std::string GenerateShaderCode(
99 const std::string& body,
100 const std::string& capabilities_and_extensions = "",
101 const std::string& execution_model = "GLCompute") {
102 const std::string int64_capability = R"(
103 OpCapability Int64
104 )";
105 const std::string int64_declarations = R"(
106 %u64 = OpTypeInt 64 0
107 %u64_0 = OpConstant %u64 0
108 %u64_1 = OpConstant %u64 1
109 )";
110 const std::string memory_model = "OpMemoryModel Logical GLSL450";
111 return GenerateShaderCodeImpl(
112 body, int64_capability + capabilities_and_extensions, int64_declarations,
113 execution_model, memory_model);
114 }
115
GenerateWebGPUShaderCode(const std::string & body,const std::string & capabilities_and_extensions="",const std::string & execution_model="GLCompute")116 std::string GenerateWebGPUShaderCode(
117 const std::string& body,
118 const std::string& capabilities_and_extensions = "",
119 const std::string& execution_model = "GLCompute") {
120 const std::string vulkan_memory_capability = R"(
121 OpCapability VulkanMemoryModelKHR
122 )";
123 const std::string vulkan_memory_extension = R"(
124 OpExtension "SPV_KHR_vulkan_memory_model"
125 )";
126 const std::string memory_model = "OpMemoryModel Logical VulkanKHR";
127 return GenerateShaderCodeImpl(body,
128 vulkan_memory_capability +
129 capabilities_and_extensions +
130 vulkan_memory_extension,
131 "", execution_model, memory_model);
132 }
133
GenerateKernelCode(const std::string & body,const std::string & capabilities_and_extensions="")134 std::string GenerateKernelCode(
135 const std::string& body,
136 const std::string& capabilities_and_extensions = "") {
137 std::ostringstream ss;
138 ss << R"(
139 OpCapability Addresses
140 OpCapability Kernel
141 OpCapability Linkage
142 OpCapability Int64
143 OpCapability NamedBarrier
144 )";
145
146 ss << capabilities_and_extensions;
147 ss << R"(
148 OpMemoryModel Physical32 OpenCL
149 %void = OpTypeVoid
150 %func = OpTypeFunction %void
151 %bool = OpTypeBool
152 %f32 = OpTypeFloat 32
153 %u32 = OpTypeInt 32 0
154 %u64 = OpTypeInt 64 0
155
156 %f32_0 = OpConstant %f32 0
157 %f32_1 = OpConstant %f32 1
158 %f32_4 = OpConstant %f32 4
159 %u32_0 = OpConstant %u32 0
160 %u32_1 = OpConstant %u32 1
161 %u32_4 = OpConstant %u32 4
162 %u64_0 = OpConstant %u64 0
163 %u64_1 = OpConstant %u64 1
164 %u64_4 = OpConstant %u64 4
165
166 %cross_device = OpConstant %u32 0
167 %device = OpConstant %u32 1
168 %workgroup = OpConstant %u32 2
169 %subgroup = OpConstant %u32 3
170 %invocation = OpConstant %u32 4
171
172 %none = OpConstant %u32 0
173 %acquire = OpConstant %u32 2
174 %release = OpConstant %u32 4
175 %acquire_release = OpConstant %u32 8
176 %acquire_and_release = OpConstant %u32 6
177 %sequentially_consistent = OpConstant %u32 16
178 %acquire_release_workgroup = OpConstant %u32 264
179
180 %named_barrier = OpTypeNamedBarrier
181
182 %main = OpFunction %void None %func
183 %main_entry = OpLabel
184 )";
185
186 ss << body;
187
188 ss << R"(
189 OpReturn
190 OpFunctionEnd)";
191
192 return ss.str();
193 }
194
TEST_F(ValidateBarriers,OpControlBarrierGLComputeSuccess)195 TEST_F(ValidateBarriers, OpControlBarrierGLComputeSuccess) {
196 const std::string body = R"(
197 OpControlBarrier %device %device %none
198 OpControlBarrier %workgroup %workgroup %acquire
199 OpControlBarrier %workgroup %device %release
200 OpControlBarrier %cross_device %cross_device %acquire_release
201 OpControlBarrier %cross_device %cross_device %sequentially_consistent
202 OpControlBarrier %cross_device %cross_device %acquire_release_uniform_workgroup
203 )";
204
205 CompileSuccessfully(GenerateShaderCode(body));
206 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
207 }
208
TEST_F(ValidateBarriers,OpControlBarrierKernelSuccess)209 TEST_F(ValidateBarriers, OpControlBarrierKernelSuccess) {
210 const std::string body = R"(
211 OpControlBarrier %device %device %none
212 OpControlBarrier %workgroup %workgroup %acquire
213 OpControlBarrier %workgroup %device %release
214 OpControlBarrier %cross_device %cross_device %acquire_release
215 OpControlBarrier %cross_device %cross_device %sequentially_consistent
216 OpControlBarrier %cross_device %cross_device %acquire_release_workgroup
217 )";
218
219 CompileSuccessfully(GenerateKernelCode(body), SPV_ENV_UNIVERSAL_1_1);
220 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
221 }
222
TEST_F(ValidateBarriers,OpControlBarrierTesselationControlSuccess)223 TEST_F(ValidateBarriers, OpControlBarrierTesselationControlSuccess) {
224 const std::string body = R"(
225 OpControlBarrier %device %device %none
226 OpControlBarrier %workgroup %workgroup %acquire
227 OpControlBarrier %workgroup %device %release
228 OpControlBarrier %cross_device %cross_device %acquire_release
229 OpControlBarrier %cross_device %cross_device %sequentially_consistent
230 OpControlBarrier %cross_device %cross_device %acquire_release_uniform_workgroup
231 )";
232
233 CompileSuccessfully(GenerateShaderCode(body, "OpCapability Tessellation\n",
234 "TessellationControl"));
235 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
236 }
237
TEST_F(ValidateBarriers,OpControlBarrierVulkanSuccess)238 TEST_F(ValidateBarriers, OpControlBarrierVulkanSuccess) {
239 const std::string body = R"(
240 OpControlBarrier %workgroup %device %none
241 OpControlBarrier %workgroup %workgroup %acquire_release_uniform_workgroup
242 )";
243
244 CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0);
245 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
246 }
247
TEST_F(ValidateBarriers,OpControlBarrierWebGPUSuccess)248 TEST_F(ValidateBarriers, OpControlBarrierWebGPUSuccess) {
249 const std::string body = R"(
250 OpControlBarrier %workgroup %queuefamily %none
251 OpControlBarrier %workgroup %workgroup %acquire_release_uniform_workgroup
252 )";
253
254 CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0);
255 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0));
256 }
257
TEST_F(ValidateBarriers,OpControlBarrierExecutionModelFragmentSpirv12)258 TEST_F(ValidateBarriers, OpControlBarrierExecutionModelFragmentSpirv12) {
259 const std::string body = R"(
260 OpControlBarrier %device %device %none
261 )";
262
263 CompileSuccessfully(GenerateShaderCode(body, "", "Fragment"),
264 SPV_ENV_UNIVERSAL_1_2);
265 ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_2));
266 EXPECT_THAT(
267 getDiagnosticString(),
268 HasSubstr("OpControlBarrier requires one of the following Execution "
269 "Models: TessellationControl, GLCompute or Kernel"));
270 }
271
TEST_F(ValidateBarriers,OpControlBarrierExecutionModelFragmentSpirv13)272 TEST_F(ValidateBarriers, OpControlBarrierExecutionModelFragmentSpirv13) {
273 const std::string body = R"(
274 OpControlBarrier %device %device %none
275 )";
276
277 CompileSuccessfully(GenerateShaderCode(body, "", "Fragment"),
278 SPV_ENV_UNIVERSAL_1_3);
279 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
280 }
281
TEST_F(ValidateBarriers,OpControlBarrierFloatExecutionScope)282 TEST_F(ValidateBarriers, OpControlBarrierFloatExecutionScope) {
283 const std::string body = R"(
284 OpControlBarrier %f32_1 %device %none
285 )";
286
287 CompileSuccessfully(GenerateShaderCode(body));
288 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
289 EXPECT_THAT(
290 getDiagnosticString(),
291 HasSubstr("ControlBarrier: expected Execution Scope to be a 32-bit int"));
292 }
293
TEST_F(ValidateBarriers,OpControlBarrierU64ExecutionScope)294 TEST_F(ValidateBarriers, OpControlBarrierU64ExecutionScope) {
295 const std::string body = R"(
296 OpControlBarrier %u64_1 %device %none
297 )";
298
299 CompileSuccessfully(GenerateShaderCode(body));
300 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
301 EXPECT_THAT(
302 getDiagnosticString(),
303 HasSubstr("ControlBarrier: expected Execution Scope to be a 32-bit int"));
304 }
305
TEST_F(ValidateBarriers,OpControlBarrierFloatMemoryScope)306 TEST_F(ValidateBarriers, OpControlBarrierFloatMemoryScope) {
307 const std::string body = R"(
308 OpControlBarrier %device %f32_1 %none
309 )";
310
311 CompileSuccessfully(GenerateShaderCode(body));
312 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
313 EXPECT_THAT(
314 getDiagnosticString(),
315 HasSubstr("ControlBarrier: expected Memory Scope to be a 32-bit int"));
316 }
317
TEST_F(ValidateBarriers,OpControlBarrierU64MemoryScope)318 TEST_F(ValidateBarriers, OpControlBarrierU64MemoryScope) {
319 const std::string body = R"(
320 OpControlBarrier %device %u64_1 %none
321 )";
322
323 CompileSuccessfully(GenerateShaderCode(body));
324 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
325 EXPECT_THAT(
326 getDiagnosticString(),
327 HasSubstr("ControlBarrier: expected Memory Scope to be a 32-bit int"));
328 }
329
TEST_F(ValidateBarriers,OpControlBarrierFloatMemorySemantics)330 TEST_F(ValidateBarriers, OpControlBarrierFloatMemorySemantics) {
331 const std::string body = R"(
332 OpControlBarrier %device %device %f32_0
333 )";
334
335 CompileSuccessfully(GenerateShaderCode(body));
336 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
337 EXPECT_THAT(
338 getDiagnosticString(),
339 HasSubstr(
340 "ControlBarrier: expected Memory Semantics to be a 32-bit int"));
341 }
342
TEST_F(ValidateBarriers,OpControlBarrierU64MemorySemantics)343 TEST_F(ValidateBarriers, OpControlBarrierU64MemorySemantics) {
344 const std::string body = R"(
345 OpControlBarrier %device %device %u64_0
346 )";
347
348 CompileSuccessfully(GenerateShaderCode(body));
349 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
350 EXPECT_THAT(
351 getDiagnosticString(),
352 HasSubstr(
353 "ControlBarrier: expected Memory Semantics to be a 32-bit int"));
354 }
355
TEST_F(ValidateBarriers,OpControlBarrierVulkanExecutionScopeDevice)356 TEST_F(ValidateBarriers, OpControlBarrierVulkanExecutionScopeDevice) {
357 const std::string body = R"(
358 OpControlBarrier %device %workgroup %none
359 )";
360
361 CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0);
362 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
363 EXPECT_THAT(getDiagnosticString(),
364 HasSubstr("ControlBarrier: in Vulkan environment Execution Scope "
365 "is limited to Workgroup and Subgroup"));
366 }
367
TEST_F(ValidateBarriers,OpControlBarrierWebGPUExecutionScopeDevice)368 TEST_F(ValidateBarriers, OpControlBarrierWebGPUExecutionScopeDevice) {
369 const std::string body = R"(
370 OpControlBarrier %device %workgroup %none
371 )";
372
373 CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0);
374 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0));
375 EXPECT_THAT(getDiagnosticString(),
376 HasSubstr("ControlBarrier: in WebGPU environment Execution Scope "
377 "is limited to Workgroup and Subgroup"));
378 }
379
TEST_F(ValidateBarriers,OpControlBarrierVulkanMemoryScopeSubgroup)380 TEST_F(ValidateBarriers, OpControlBarrierVulkanMemoryScopeSubgroup) {
381 const std::string body = R"(
382 OpControlBarrier %subgroup %subgroup %none
383 )";
384
385 CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0);
386 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
387 EXPECT_THAT(
388 getDiagnosticString(),
389 HasSubstr("ControlBarrier: in Vulkan 1.0 environment Memory Scope is "
390 "limited to Device, Workgroup and Invocation"));
391 }
392
TEST_F(ValidateBarriers,OpControlBarrierVulkan1p1MemoryScopeSubgroup)393 TEST_F(ValidateBarriers, OpControlBarrierVulkan1p1MemoryScopeSubgroup) {
394 const std::string body = R"(
395 OpControlBarrier %subgroup %subgroup %none
396 )";
397
398 CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_1);
399 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
400 }
401
TEST_F(ValidateBarriers,OpControlBarrierVulkan1p1MemoryScopeCrossDevice)402 TEST_F(ValidateBarriers, OpControlBarrierVulkan1p1MemoryScopeCrossDevice) {
403 const std::string body = R"(
404 OpControlBarrier %subgroup %cross_device %none
405 )";
406
407 CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_1);
408 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_1));
409 EXPECT_THAT(getDiagnosticString(),
410 HasSubstr("ControlBarrier: in Vulkan environment, Memory Scope "
411 "cannot be CrossDevice"));
412 }
413
TEST_F(ValidateBarriers,OpControlBarrierAcquireAndRelease)414 TEST_F(ValidateBarriers, OpControlBarrierAcquireAndRelease) {
415 const std::string body = R"(
416 OpControlBarrier %device %device %acquire_and_release_uniform
417 )";
418
419 CompileSuccessfully(GenerateShaderCode(body));
420 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
421 EXPECT_THAT(getDiagnosticString(),
422 HasSubstr("ControlBarrier: Memory Semantics can have at most one "
423 "of the following bits set: Acquire, Release, "
424 "AcquireRelease or SequentiallyConsistent"));
425 }
426
427 // TODO(atgoo@github.com): the corresponding check fails Vulkan CTS,
428 // reenable once fixed.
TEST_F(ValidateBarriers,DISABLED_OpControlBarrierVulkanSubgroupStorageClass)429 TEST_F(ValidateBarriers, DISABLED_OpControlBarrierVulkanSubgroupStorageClass) {
430 const std::string body = R"(
431 OpControlBarrier %workgroup %device %acquire_release_subgroup
432 )";
433
434 CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0);
435 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
436 EXPECT_THAT(
437 getDiagnosticString(),
438 HasSubstr(
439 "ControlBarrier: expected Memory Semantics to include a "
440 "Vulkan-supported storage class if Memory Semantics is not None"));
441 }
442
TEST_F(ValidateBarriers,OpControlBarrierSubgroupExecutionFragment1p1)443 TEST_F(ValidateBarriers, OpControlBarrierSubgroupExecutionFragment1p1) {
444 const std::string body = R"(
445 OpControlBarrier %subgroup %subgroup %acquire_release_subgroup
446 )";
447
448 CompileSuccessfully(GenerateShaderCode(body, "", "Fragment"),
449 SPV_ENV_VULKAN_1_1);
450 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
451 }
452
TEST_F(ValidateBarriers,OpControlBarrierWorkgroupExecutionFragment1p1)453 TEST_F(ValidateBarriers, OpControlBarrierWorkgroupExecutionFragment1p1) {
454 const std::string body = R"(
455 OpControlBarrier %workgroup %workgroup %acquire_release
456 )";
457
458 CompileSuccessfully(GenerateShaderCode(body, "", "Fragment"),
459 SPV_ENV_VULKAN_1_1);
460 ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
461 EXPECT_THAT(getDiagnosticString(),
462 HasSubstr("OpControlBarrier execution scope must be Subgroup for "
463 "Fragment, Vertex, Geometry and TessellationEvaluation "
464 "execution models"));
465 }
466
TEST_F(ValidateBarriers,OpControlBarrierSubgroupExecutionFragment1p0)467 TEST_F(ValidateBarriers, OpControlBarrierSubgroupExecutionFragment1p0) {
468 const std::string body = R"(
469 OpControlBarrier %subgroup %workgroup %acquire_release
470 )";
471
472 CompileSuccessfully(GenerateShaderCode(body, "", "Fragment"),
473 SPV_ENV_VULKAN_1_0);
474 ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
475 EXPECT_THAT(
476 getDiagnosticString(),
477 HasSubstr("OpControlBarrier requires one of the following Execution "
478 "Models: TessellationControl, GLCompute or Kernel"));
479 }
480
TEST_F(ValidateBarriers,OpControlBarrierSubgroupExecutionVertex1p1)481 TEST_F(ValidateBarriers, OpControlBarrierSubgroupExecutionVertex1p1) {
482 const std::string body = R"(
483 OpControlBarrier %subgroup %subgroup %acquire_release_subgroup
484 )";
485
486 CompileSuccessfully(GenerateShaderCode(body, "", "Vertex"),
487 SPV_ENV_VULKAN_1_1);
488 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
489 }
490
TEST_F(ValidateBarriers,OpControlBarrierWorkgroupExecutionVertex1p1)491 TEST_F(ValidateBarriers, OpControlBarrierWorkgroupExecutionVertex1p1) {
492 const std::string body = R"(
493 OpControlBarrier %workgroup %workgroup %acquire_release
494 )";
495
496 CompileSuccessfully(GenerateShaderCode(body, "", "Vertex"),
497 SPV_ENV_VULKAN_1_1);
498 ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
499 EXPECT_THAT(getDiagnosticString(),
500 HasSubstr("OpControlBarrier execution scope must be Subgroup for "
501 "Fragment, Vertex, Geometry and TessellationEvaluation "
502 "execution models"));
503 }
504
TEST_F(ValidateBarriers,OpControlBarrierSubgroupExecutionVertex1p0)505 TEST_F(ValidateBarriers, OpControlBarrierSubgroupExecutionVertex1p0) {
506 const std::string body = R"(
507 OpControlBarrier %subgroup %workgroup %acquire_release
508 )";
509
510 CompileSuccessfully(GenerateShaderCode(body, "", "Vertex"),
511 SPV_ENV_VULKAN_1_0);
512 ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
513 EXPECT_THAT(
514 getDiagnosticString(),
515 HasSubstr("OpControlBarrier requires one of the following Execution "
516 "Models: TessellationControl, GLCompute or Kernel"));
517 }
518
TEST_F(ValidateBarriers,OpControlBarrierSubgroupExecutionGeometry1p1)519 TEST_F(ValidateBarriers, OpControlBarrierSubgroupExecutionGeometry1p1) {
520 const std::string body = R"(
521 OpControlBarrier %subgroup %subgroup %acquire_release_subgroup
522 )";
523
524 CompileSuccessfully(
525 GenerateShaderCode(body, "OpCapability Geometry\n", "Geometry"),
526 SPV_ENV_VULKAN_1_1);
527 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
528 }
529
TEST_F(ValidateBarriers,OpControlBarrierWorkgroupExecutionGeometry1p1)530 TEST_F(ValidateBarriers, OpControlBarrierWorkgroupExecutionGeometry1p1) {
531 const std::string body = R"(
532 OpControlBarrier %workgroup %workgroup %acquire_release
533 )";
534
535 CompileSuccessfully(
536 GenerateShaderCode(body, "OpCapability Geometry\n", "Geometry"),
537 SPV_ENV_VULKAN_1_1);
538 ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
539 EXPECT_THAT(getDiagnosticString(),
540 HasSubstr("OpControlBarrier execution scope must be Subgroup for "
541 "Fragment, Vertex, Geometry and TessellationEvaluation "
542 "execution models"));
543 }
544
TEST_F(ValidateBarriers,OpControlBarrierSubgroupExecutionGeometry1p0)545 TEST_F(ValidateBarriers, OpControlBarrierSubgroupExecutionGeometry1p0) {
546 const std::string body = R"(
547 OpControlBarrier %subgroup %workgroup %acquire_release
548 )";
549
550 CompileSuccessfully(
551 GenerateShaderCode(body, "OpCapability Geometry\n", "Geometry"),
552 SPV_ENV_VULKAN_1_0);
553 ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
554 EXPECT_THAT(
555 getDiagnosticString(),
556 HasSubstr("OpControlBarrier requires one of the following Execution "
557 "Models: TessellationControl, GLCompute or Kernel"));
558 }
559
TEST_F(ValidateBarriers,OpControlBarrierSubgroupExecutionTessellationEvaluation1p1)560 TEST_F(ValidateBarriers,
561 OpControlBarrierSubgroupExecutionTessellationEvaluation1p1) {
562 const std::string body = R"(
563 OpControlBarrier %subgroup %subgroup %acquire_release_subgroup
564 )";
565
566 CompileSuccessfully(GenerateShaderCode(body, "OpCapability Tessellation\n",
567 "TessellationEvaluation"),
568 SPV_ENV_VULKAN_1_1);
569 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
570 }
571
TEST_F(ValidateBarriers,OpControlBarrierWorkgroupExecutionTessellationEvaluation1p1)572 TEST_F(ValidateBarriers,
573 OpControlBarrierWorkgroupExecutionTessellationEvaluation1p1) {
574 const std::string body = R"(
575 OpControlBarrier %workgroup %workgroup %acquire_release
576 )";
577
578 CompileSuccessfully(GenerateShaderCode(body, "OpCapability Tessellation\n",
579 "TessellationEvaluation"),
580 SPV_ENV_VULKAN_1_1);
581 ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
582 EXPECT_THAT(getDiagnosticString(),
583 HasSubstr("OpControlBarrier execution scope must be Subgroup for "
584 "Fragment, Vertex, Geometry and TessellationEvaluation "
585 "execution models"));
586 }
587
TEST_F(ValidateBarriers,OpControlBarrierSubgroupExecutionTessellationEvaluation1p0)588 TEST_F(ValidateBarriers,
589 OpControlBarrierSubgroupExecutionTessellationEvaluation1p0) {
590 const std::string body = R"(
591 OpControlBarrier %subgroup %workgroup %acquire_release
592 )";
593
594 CompileSuccessfully(GenerateShaderCode(body, "OpCapability Tessellation\n",
595 "TessellationEvaluation"),
596 SPV_ENV_VULKAN_1_0);
597 ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
598 EXPECT_THAT(
599 getDiagnosticString(),
600 HasSubstr("OpControlBarrier requires one of the following Execution "
601 "Models: TessellationControl, GLCompute or Kernel"));
602 }
603
TEST_F(ValidateBarriers,OpMemoryBarrierSuccess)604 TEST_F(ValidateBarriers, OpMemoryBarrierSuccess) {
605 const std::string body = R"(
606 OpMemoryBarrier %cross_device %acquire_release_uniform_workgroup
607 OpMemoryBarrier %device %uniform
608 )";
609
610 CompileSuccessfully(GenerateShaderCode(body));
611 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
612 }
613
TEST_F(ValidateBarriers,OpMemoryBarrierKernelSuccess)614 TEST_F(ValidateBarriers, OpMemoryBarrierKernelSuccess) {
615 const std::string body = R"(
616 OpMemoryBarrier %cross_device %acquire_release_workgroup
617 OpMemoryBarrier %device %none
618 )";
619
620 CompileSuccessfully(GenerateKernelCode(body), SPV_ENV_UNIVERSAL_1_1);
621 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
622 }
623
TEST_F(ValidateBarriers,OpMemoryBarrierVulkanSuccess)624 TEST_F(ValidateBarriers, OpMemoryBarrierVulkanSuccess) {
625 const std::string body = R"(
626 OpMemoryBarrier %workgroup %acquire_release_uniform_workgroup
627 )";
628
629 CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0);
630 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
631 }
632
TEST_F(ValidateBarriers,OpMemoryBarrierFloatMemoryScope)633 TEST_F(ValidateBarriers, OpMemoryBarrierFloatMemoryScope) {
634 const std::string body = R"(
635 OpMemoryBarrier %f32_1 %acquire_release_uniform_workgroup
636 )";
637
638 CompileSuccessfully(GenerateShaderCode(body));
639 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
640 EXPECT_THAT(
641 getDiagnosticString(),
642 HasSubstr("MemoryBarrier: expected Memory Scope to be a 32-bit int"));
643 }
644
TEST_F(ValidateBarriers,OpMemoryBarrierU64MemoryScope)645 TEST_F(ValidateBarriers, OpMemoryBarrierU64MemoryScope) {
646 const std::string body = R"(
647 OpMemoryBarrier %u64_1 %acquire_release_uniform_workgroup
648 )";
649
650 CompileSuccessfully(GenerateShaderCode(body));
651 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
652 EXPECT_THAT(
653 getDiagnosticString(),
654 HasSubstr("MemoryBarrier: expected Memory Scope to be a 32-bit int"));
655 }
656
TEST_F(ValidateBarriers,OpMemoryBarrierFloatMemorySemantics)657 TEST_F(ValidateBarriers, OpMemoryBarrierFloatMemorySemantics) {
658 const std::string body = R"(
659 OpMemoryBarrier %device %f32_0
660 )";
661
662 CompileSuccessfully(GenerateShaderCode(body));
663 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
664 EXPECT_THAT(
665 getDiagnosticString(),
666 HasSubstr("MemoryBarrier: expected Memory Semantics to be a 32-bit int"));
667 }
668
TEST_F(ValidateBarriers,OpMemoryBarrierU64MemorySemantics)669 TEST_F(ValidateBarriers, OpMemoryBarrierU64MemorySemantics) {
670 const std::string body = R"(
671 OpMemoryBarrier %device %u64_0
672 )";
673
674 CompileSuccessfully(GenerateShaderCode(body));
675 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
676 EXPECT_THAT(
677 getDiagnosticString(),
678 HasSubstr("MemoryBarrier: expected Memory Semantics to be a 32-bit int"));
679 }
680
TEST_F(ValidateBarriers,OpMemoryBarrierVulkanMemoryScopeSubgroup)681 TEST_F(ValidateBarriers, OpMemoryBarrierVulkanMemoryScopeSubgroup) {
682 const std::string body = R"(
683 OpMemoryBarrier %subgroup %acquire_release_uniform_workgroup
684 )";
685
686 CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0);
687 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
688 EXPECT_THAT(
689 getDiagnosticString(),
690 HasSubstr("MemoryBarrier: in Vulkan 1.0 environment Memory Scope is "
691 "limited to Device, Workgroup and Invocation"));
692 }
693
TEST_F(ValidateBarriers,OpMemoryBarrierVulkan1p1MemoryScopeSubgroup)694 TEST_F(ValidateBarriers, OpMemoryBarrierVulkan1p1MemoryScopeSubgroup) {
695 const std::string body = R"(
696 OpMemoryBarrier %subgroup %acquire_release_uniform_workgroup
697 )";
698
699 CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_1);
700 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
701 }
702
TEST_F(ValidateBarriers,OpMemoryBarrierAcquireAndRelease)703 TEST_F(ValidateBarriers, OpMemoryBarrierAcquireAndRelease) {
704 const std::string body = R"(
705 OpMemoryBarrier %device %acquire_and_release_uniform
706 )";
707
708 CompileSuccessfully(GenerateShaderCode(body));
709 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
710 EXPECT_THAT(getDiagnosticString(),
711 HasSubstr("MemoryBarrier: Memory Semantics can have at most one "
712 "of the following bits set: Acquire, Release, "
713 "AcquireRelease or SequentiallyConsistent"));
714 }
715
TEST_F(ValidateBarriers,OpMemoryBarrierVulkanMemorySemanticsNone)716 TEST_F(ValidateBarriers, OpMemoryBarrierVulkanMemorySemanticsNone) {
717 const std::string body = R"(
718 OpMemoryBarrier %device %none
719 )";
720
721 CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0);
722 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
723 EXPECT_THAT(
724 getDiagnosticString(),
725 HasSubstr("MemoryBarrier: Vulkan specification requires Memory Semantics "
726 "to have one of the following bits set: Acquire, Release, "
727 "AcquireRelease or SequentiallyConsistent"));
728 }
729
TEST_F(ValidateBarriers,OpMemoryBarrierVulkanMemorySemanticsAcquire)730 TEST_F(ValidateBarriers, OpMemoryBarrierVulkanMemorySemanticsAcquire) {
731 const std::string body = R"(
732 OpMemoryBarrier %device %acquire
733 )";
734
735 CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0);
736 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
737 EXPECT_THAT(getDiagnosticString(),
738 HasSubstr("MemoryBarrier: expected Memory Semantics to include a "
739 "Vulkan-supported storage class"));
740 }
741
TEST_F(ValidateBarriers,OpMemoryBarrierVulkanSubgroupStorageClass)742 TEST_F(ValidateBarriers, OpMemoryBarrierVulkanSubgroupStorageClass) {
743 const std::string body = R"(
744 OpMemoryBarrier %device %acquire_release_subgroup
745 )";
746
747 CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0);
748 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
749 EXPECT_THAT(getDiagnosticString(),
750 HasSubstr("MemoryBarrier: expected Memory Semantics to include a "
751 "Vulkan-supported storage class"));
752 }
753
TEST_F(ValidateBarriers,OpNamedBarrierInitializeSuccess)754 TEST_F(ValidateBarriers, OpNamedBarrierInitializeSuccess) {
755 const std::string body = R"(
756 %barrier = OpNamedBarrierInitialize %named_barrier %u32_4
757 )";
758
759 CompileSuccessfully(GenerateKernelCode(body), SPV_ENV_UNIVERSAL_1_1);
760 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
761 }
762
TEST_F(ValidateBarriers,OpNamedBarrierInitializeWrongResultType)763 TEST_F(ValidateBarriers, OpNamedBarrierInitializeWrongResultType) {
764 const std::string body = R"(
765 %barrier = OpNamedBarrierInitialize %u32 %u32_4
766 )";
767
768 CompileSuccessfully(GenerateKernelCode(body), SPV_ENV_UNIVERSAL_1_1);
769 ASSERT_EQ(SPV_ERROR_INVALID_DATA,
770 ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
771 EXPECT_THAT(getDiagnosticString(),
772 HasSubstr("NamedBarrierInitialize: expected Result Type to be "
773 "OpTypeNamedBarrier"));
774 }
775
TEST_F(ValidateBarriers,OpNamedBarrierInitializeFloatSubgroupCount)776 TEST_F(ValidateBarriers, OpNamedBarrierInitializeFloatSubgroupCount) {
777 const std::string body = R"(
778 %barrier = OpNamedBarrierInitialize %named_barrier %f32_4
779 )";
780
781 CompileSuccessfully(GenerateKernelCode(body), SPV_ENV_UNIVERSAL_1_1);
782 ASSERT_EQ(SPV_ERROR_INVALID_DATA,
783 ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
784 EXPECT_THAT(getDiagnosticString(),
785 HasSubstr("NamedBarrierInitialize: expected Subgroup Count to be "
786 "a 32-bit int"));
787 }
788
TEST_F(ValidateBarriers,OpNamedBarrierInitializeU64SubgroupCount)789 TEST_F(ValidateBarriers, OpNamedBarrierInitializeU64SubgroupCount) {
790 const std::string body = R"(
791 %barrier = OpNamedBarrierInitialize %named_barrier %u64_4
792 )";
793
794 CompileSuccessfully(GenerateKernelCode(body), SPV_ENV_UNIVERSAL_1_1);
795 ASSERT_EQ(SPV_ERROR_INVALID_DATA,
796 ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
797 EXPECT_THAT(getDiagnosticString(),
798 HasSubstr("NamedBarrierInitialize: expected Subgroup Count to be "
799 "a 32-bit int"));
800 }
801
TEST_F(ValidateBarriers,OpMemoryNamedBarrierSuccess)802 TEST_F(ValidateBarriers, OpMemoryNamedBarrierSuccess) {
803 const std::string body = R"(
804 %barrier = OpNamedBarrierInitialize %named_barrier %u32_4
805 OpMemoryNamedBarrier %barrier %workgroup %acquire_release_workgroup
806 )";
807
808 CompileSuccessfully(GenerateKernelCode(body), SPV_ENV_UNIVERSAL_1_1);
809 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
810 }
811
TEST_F(ValidateBarriers,OpMemoryNamedBarrierNotNamedBarrier)812 TEST_F(ValidateBarriers, OpMemoryNamedBarrierNotNamedBarrier) {
813 const std::string body = R"(
814 OpMemoryNamedBarrier %u32_1 %workgroup %acquire_release_workgroup
815 )";
816
817 CompileSuccessfully(GenerateKernelCode(body), SPV_ENV_UNIVERSAL_1_1);
818 ASSERT_EQ(SPV_ERROR_INVALID_DATA,
819 ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
820 EXPECT_THAT(getDiagnosticString(),
821 HasSubstr("MemoryNamedBarrier: expected Named Barrier to be of "
822 "type OpTypeNamedBarrier"));
823 }
824
TEST_F(ValidateBarriers,OpMemoryNamedBarrierFloatMemoryScope)825 TEST_F(ValidateBarriers, OpMemoryNamedBarrierFloatMemoryScope) {
826 const std::string body = R"(
827 %barrier = OpNamedBarrierInitialize %named_barrier %u32_4
828 OpMemoryNamedBarrier %barrier %f32_1 %acquire_release_workgroup
829 )";
830
831 CompileSuccessfully(GenerateKernelCode(body), SPV_ENV_UNIVERSAL_1_1);
832 ASSERT_EQ(SPV_ERROR_INVALID_DATA,
833 ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
834 EXPECT_THAT(
835 getDiagnosticString(),
836 HasSubstr(
837 "MemoryNamedBarrier: expected Memory Scope to be a 32-bit int"));
838 }
839
TEST_F(ValidateBarriers,OpMemoryNamedBarrierFloatMemorySemantics)840 TEST_F(ValidateBarriers, OpMemoryNamedBarrierFloatMemorySemantics) {
841 const std::string body = R"(
842 %barrier = OpNamedBarrierInitialize %named_barrier %u32_4
843 OpMemoryNamedBarrier %barrier %workgroup %f32_0
844 )";
845
846 CompileSuccessfully(GenerateKernelCode(body), SPV_ENV_UNIVERSAL_1_1);
847 ASSERT_EQ(SPV_ERROR_INVALID_DATA,
848 ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
849 EXPECT_THAT(
850 getDiagnosticString(),
851 HasSubstr(
852 "MemoryNamedBarrier: expected Memory Semantics to be a 32-bit int"));
853 }
854
TEST_F(ValidateBarriers,OpMemoryNamedBarrierAcquireAndRelease)855 TEST_F(ValidateBarriers, OpMemoryNamedBarrierAcquireAndRelease) {
856 const std::string body = R"(
857 %barrier = OpNamedBarrierInitialize %named_barrier %u32_4
858 OpMemoryNamedBarrier %barrier %workgroup %acquire_and_release
859 )";
860
861 CompileSuccessfully(GenerateKernelCode(body), SPV_ENV_UNIVERSAL_1_1);
862 ASSERT_EQ(SPV_ERROR_INVALID_DATA,
863 ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
864 EXPECT_THAT(getDiagnosticString(),
865 HasSubstr("MemoryNamedBarrier: Memory Semantics can have at most "
866 "one of the following bits set: Acquire, Release, "
867 "AcquireRelease or SequentiallyConsistent"));
868 }
869
TEST_F(ValidateBarriers,TypeAsMemoryScope)870 TEST_F(ValidateBarriers, TypeAsMemoryScope) {
871 const std::string body = R"(
872 OpMemoryBarrier %u32 %u32_0
873 )";
874
875 CompileSuccessfully(GenerateKernelCode(body));
876 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
877 EXPECT_THAT(getDiagnosticString(), HasSubstr("Operand 5[%uint] cannot be a "
878 "type"));
879 }
880
TEST_F(ValidateBarriers,OpControlBarrierVulkanMemoryModelBanSequentiallyConsistent)881 TEST_F(ValidateBarriers,
882 OpControlBarrierVulkanMemoryModelBanSequentiallyConsistent) {
883 const std::string text = R"(
884 OpCapability Shader
885 OpCapability VulkanMemoryModelKHR
886 OpExtension "SPV_KHR_vulkan_memory_model"
887 OpMemoryModel Logical VulkanKHR
888 OpEntryPoint Fragment %1 "func"
889 OpExecutionMode %1 OriginUpperLeft
890 %2 = OpTypeVoid
891 %3 = OpTypeInt 32 0
892 %4 = OpConstant %3 16
893 %5 = OpTypeFunction %2
894 %6 = OpConstant %3 5
895 %1 = OpFunction %2 None %5
896 %7 = OpLabel
897 OpControlBarrier %6 %6 %4
898 OpReturn
899 OpFunctionEnd
900 )";
901
902 CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3);
903 EXPECT_EQ(SPV_ERROR_INVALID_DATA,
904 ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
905 EXPECT_THAT(getDiagnosticString(),
906 HasSubstr("SequentiallyConsistent memory semantics cannot be "
907 "used with the VulkanKHR memory model."));
908 }
909
TEST_F(ValidateBarriers,OpMemoryBarrierVulkanMemoryModelBanSequentiallyConsistent)910 TEST_F(ValidateBarriers,
911 OpMemoryBarrierVulkanMemoryModelBanSequentiallyConsistent) {
912 const std::string text = R"(
913 OpCapability Shader
914 OpCapability VulkanMemoryModelKHR
915 OpExtension "SPV_KHR_vulkan_memory_model"
916 OpMemoryModel Logical VulkanKHR
917 OpEntryPoint Fragment %1 "func"
918 OpExecutionMode %1 OriginUpperLeft
919 %2 = OpTypeVoid
920 %3 = OpTypeInt 32 0
921 %4 = OpConstant %3 16
922 %5 = OpTypeFunction %2
923 %6 = OpConstant %3 5
924 %1 = OpFunction %2 None %5
925 %7 = OpLabel
926 OpMemoryBarrier %6 %4
927 OpReturn
928 OpFunctionEnd
929 )";
930
931 CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3);
932 EXPECT_EQ(SPV_ERROR_INVALID_DATA,
933 ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
934 EXPECT_THAT(getDiagnosticString(),
935 HasSubstr("SequentiallyConsistent memory semantics cannot be "
936 "used with the VulkanKHR memory model."));
937 }
938
TEST_F(ValidateBarriers,OutputMemoryKHRRequireVulkanMemoryModelKHR)939 TEST_F(ValidateBarriers, OutputMemoryKHRRequireVulkanMemoryModelKHR) {
940 const std::string text = R"(
941 OpCapability Shader
942 OpMemoryModel Logical GLSL450
943 OpEntryPoint Fragment %1 "func"
944 OpExecutionMode %1 OriginUpperLeft
945 %2 = OpTypeVoid
946 %3 = OpTypeInt 32 0
947 %semantics = OpConstant %3 4104
948 %5 = OpTypeFunction %2
949 %device = OpConstant %3 1
950 %1 = OpFunction %2 None %5
951 %7 = OpLabel
952 OpControlBarrier %device %device %semantics
953 OpReturn
954 OpFunctionEnd
955 )";
956
957 CompileSuccessfully(text);
958 EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
959 EXPECT_THAT(getDiagnosticString(),
960 HasSubstr("ControlBarrier: Memory Semantics OutputMemoryKHR "
961 "requires capability VulkanMemoryModelKHR"));
962 }
963
TEST_F(ValidateBarriers,MakeAvailableKHRRequireVulkanMemoryModelKHR)964 TEST_F(ValidateBarriers, MakeAvailableKHRRequireVulkanMemoryModelKHR) {
965 const std::string text = R"(
966 OpCapability Shader
967 OpMemoryModel Logical GLSL450
968 OpEntryPoint Fragment %1 "func"
969 OpExecutionMode %1 OriginUpperLeft
970 %2 = OpTypeVoid
971 %3 = OpTypeInt 32 0
972 %semantics = OpConstant %3 8264
973 %5 = OpTypeFunction %2
974 %device = OpConstant %3 1
975 %1 = OpFunction %2 None %5
976 %7 = OpLabel
977 OpControlBarrier %device %device %semantics
978 OpReturn
979 OpFunctionEnd
980 )";
981
982 CompileSuccessfully(text);
983 EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
984 EXPECT_THAT(getDiagnosticString(),
985 HasSubstr("ControlBarrier: Memory Semantics MakeAvailableKHR "
986 "requires capability VulkanMemoryModelKHR"));
987 }
988
TEST_F(ValidateBarriers,MakeVisibleKHRRequireVulkanMemoryModelKHR)989 TEST_F(ValidateBarriers, MakeVisibleKHRRequireVulkanMemoryModelKHR) {
990 const std::string text = R"(
991 OpCapability Shader
992 OpMemoryModel Logical GLSL450
993 OpEntryPoint Fragment %1 "func"
994 OpExecutionMode %1 OriginUpperLeft
995 %2 = OpTypeVoid
996 %3 = OpTypeInt 32 0
997 %semantics = OpConstant %3 16456
998 %5 = OpTypeFunction %2
999 %device = OpConstant %3 1
1000 %1 = OpFunction %2 None %5
1001 %7 = OpLabel
1002 OpControlBarrier %device %device %semantics
1003 OpReturn
1004 OpFunctionEnd
1005 )";
1006
1007 CompileSuccessfully(text);
1008 EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1009 EXPECT_THAT(getDiagnosticString(),
1010 HasSubstr("ControlBarrier: Memory Semantics MakeVisibleKHR "
1011 "requires capability VulkanMemoryModelKHR"));
1012 }
1013
TEST_F(ValidateBarriers,MakeAvailableKHRRequiresReleaseSemantics)1014 TEST_F(ValidateBarriers, MakeAvailableKHRRequiresReleaseSemantics) {
1015 const std::string text = R"(
1016 OpCapability Shader
1017 OpCapability VulkanMemoryModelKHR
1018 OpExtension "SPV_KHR_vulkan_memory_model"
1019 OpMemoryModel Logical VulkanKHR
1020 OpEntryPoint Fragment %func "func"
1021 OpExecutionMode %func OriginUpperLeft
1022 %void = OpTypeVoid
1023 %int = OpTypeInt 32 0
1024 %workgroup = OpConstant %int 2
1025 %semantics = OpConstant %int 8448
1026 %functy = OpTypeFunction %void
1027 %func = OpFunction %void None %functy
1028 %1 = OpLabel
1029 OpControlBarrier %workgroup %workgroup %semantics
1030 OpReturn
1031 OpFunctionEnd
1032 )";
1033
1034 CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3);
1035 EXPECT_EQ(SPV_ERROR_INVALID_DATA,
1036 ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1037 EXPECT_THAT(
1038 getDiagnosticString(),
1039 HasSubstr("ControlBarrier: MakeAvailableKHR Memory Semantics also "
1040 "requires either Release or AcquireRelease Memory Semantics"));
1041 }
1042
TEST_F(ValidateBarriers,MakeVisibleKHRRequiresAcquireSemantics)1043 TEST_F(ValidateBarriers, MakeVisibleKHRRequiresAcquireSemantics) {
1044 const std::string text = R"(
1045 OpCapability Shader
1046 OpCapability VulkanMemoryModelKHR
1047 OpExtension "SPV_KHR_vulkan_memory_model"
1048 OpMemoryModel Logical VulkanKHR
1049 OpEntryPoint Fragment %func "func"
1050 OpExecutionMode %func OriginUpperLeft
1051 %void = OpTypeVoid
1052 %int = OpTypeInt 32 0
1053 %workgroup = OpConstant %int 2
1054 %semantics = OpConstant %int 16640
1055 %functy = OpTypeFunction %void
1056 %func = OpFunction %void None %functy
1057 %1 = OpLabel
1058 OpControlBarrier %workgroup %workgroup %semantics
1059 OpReturn
1060 OpFunctionEnd
1061 )";
1062
1063 CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3);
1064 EXPECT_EQ(SPV_ERROR_INVALID_DATA,
1065 ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1066 EXPECT_THAT(
1067 getDiagnosticString(),
1068 HasSubstr("ControlBarrier: MakeVisibleKHR Memory Semantics also requires "
1069 "either Acquire or AcquireRelease Memory Semantics"));
1070 }
1071
TEST_F(ValidateBarriers,MakeAvailableKHRRequiresStorageSemantics)1072 TEST_F(ValidateBarriers, MakeAvailableKHRRequiresStorageSemantics) {
1073 const std::string text = R"(
1074 OpCapability Shader
1075 OpCapability VulkanMemoryModelKHR
1076 OpExtension "SPV_KHR_vulkan_memory_model"
1077 OpMemoryModel Logical VulkanKHR
1078 OpEntryPoint Fragment %func "func"
1079 OpExecutionMode %func OriginUpperLeft
1080 %void = OpTypeVoid
1081 %int = OpTypeInt 32 0
1082 %workgroup = OpConstant %int 2
1083 %semantics = OpConstant %int 8196
1084 %functy = OpTypeFunction %void
1085 %func = OpFunction %void None %functy
1086 %1 = OpLabel
1087 OpMemoryBarrier %workgroup %semantics
1088 OpReturn
1089 OpFunctionEnd
1090 )";
1091
1092 CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3);
1093 EXPECT_EQ(SPV_ERROR_INVALID_DATA,
1094 ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1095 EXPECT_THAT(getDiagnosticString(),
1096 HasSubstr("MemoryBarrier: expected Memory Semantics to include a "
1097 "storage class"));
1098 }
1099
TEST_F(ValidateBarriers,MakeVisibleKHRRequiresStorageSemantics)1100 TEST_F(ValidateBarriers, MakeVisibleKHRRequiresStorageSemantics) {
1101 const std::string text = R"(
1102 OpCapability Shader
1103 OpCapability VulkanMemoryModelKHR
1104 OpExtension "SPV_KHR_vulkan_memory_model"
1105 OpMemoryModel Logical VulkanKHR
1106 OpEntryPoint Fragment %func "func"
1107 OpExecutionMode %func OriginUpperLeft
1108 %void = OpTypeVoid
1109 %int = OpTypeInt 32 0
1110 %workgroup = OpConstant %int 2
1111 %semantics = OpConstant %int 16386
1112 %functy = OpTypeFunction %void
1113 %func = OpFunction %void None %functy
1114 %1 = OpLabel
1115 OpMemoryBarrier %workgroup %semantics
1116 OpReturn
1117 OpFunctionEnd
1118 )";
1119
1120 CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3);
1121 EXPECT_EQ(SPV_ERROR_INVALID_DATA,
1122 ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1123 EXPECT_THAT(getDiagnosticString(),
1124 HasSubstr("MemoryBarrier: expected Memory Semantics to include a "
1125 "storage class"));
1126 }
1127
TEST_F(ValidateBarriers,SemanticsSpecConstantShader)1128 TEST_F(ValidateBarriers, SemanticsSpecConstantShader) {
1129 const std::string spirv = R"(
1130 OpCapability Shader
1131 OpMemoryModel Logical GLSL450
1132 OpEntryPoint Fragment %func "func"
1133 OpExecutionMode %func OriginUpperLeft
1134 %void = OpTypeVoid
1135 %int = OpTypeInt 32 0
1136 %ptr_int_workgroup = OpTypePointer Workgroup %int
1137 %var = OpVariable %ptr_int_workgroup Workgroup
1138 %voidfn = OpTypeFunction %void
1139 %spec_const = OpSpecConstant %int 0
1140 %workgroup = OpConstant %int 2
1141 %func = OpFunction %void None %voidfn
1142 %entry = OpLabel
1143 OpMemoryBarrier %workgroup %spec_const
1144 OpReturn
1145 OpFunctionEnd
1146 )";
1147
1148 CompileSuccessfully(spirv);
1149 EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1150 EXPECT_THAT(getDiagnosticString(),
1151 HasSubstr("Memory Semantics ids must be OpConstant when Shader "
1152 "capability is present"));
1153 }
1154
TEST_F(ValidateBarriers,SemanticsSpecConstantKernel)1155 TEST_F(ValidateBarriers, SemanticsSpecConstantKernel) {
1156 const std::string spirv = R"(
1157 OpCapability Kernel
1158 OpCapability Linkage
1159 OpMemoryModel Logical OpenCL
1160 %void = OpTypeVoid
1161 %int = OpTypeInt 32 0
1162 %ptr_int_workgroup = OpTypePointer Workgroup %int
1163 %var = OpVariable %ptr_int_workgroup Workgroup
1164 %voidfn = OpTypeFunction %void
1165 %spec_const = OpSpecConstant %int 0
1166 %workgroup = OpConstant %int 2
1167 %func = OpFunction %void None %voidfn
1168 %entry = OpLabel
1169 OpMemoryBarrier %workgroup %spec_const
1170 OpReturn
1171 OpFunctionEnd
1172 )";
1173
1174 CompileSuccessfully(spirv);
1175 EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
1176 }
1177
TEST_F(ValidateBarriers,ScopeSpecConstantShader)1178 TEST_F(ValidateBarriers, ScopeSpecConstantShader) {
1179 const std::string spirv = R"(
1180 OpCapability Shader
1181 OpMemoryModel Logical GLSL450
1182 OpEntryPoint Fragment %func "func"
1183 OpExecutionMode %func OriginUpperLeft
1184 %void = OpTypeVoid
1185 %int = OpTypeInt 32 0
1186 %ptr_int_workgroup = OpTypePointer Workgroup %int
1187 %var = OpVariable %ptr_int_workgroup Workgroup
1188 %voidfn = OpTypeFunction %void
1189 %spec_const = OpSpecConstant %int 0
1190 %relaxed = OpConstant %int 0
1191 %func = OpFunction %void None %voidfn
1192 %entry = OpLabel
1193 OpMemoryBarrier %spec_const %relaxed
1194 OpReturn
1195 OpFunctionEnd
1196 )";
1197
1198 CompileSuccessfully(spirv);
1199 EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1200 EXPECT_THAT(getDiagnosticString(),
1201 HasSubstr("Scope ids must be OpConstant when Shader "
1202 "capability is present"));
1203 }
1204
TEST_F(ValidateBarriers,ScopeSpecConstantKernel)1205 TEST_F(ValidateBarriers, ScopeSpecConstantKernel) {
1206 const std::string spirv = R"(
1207 OpCapability Kernel
1208 OpCapability Linkage
1209 OpMemoryModel Logical OpenCL
1210 %void = OpTypeVoid
1211 %int = OpTypeInt 32 0
1212 %ptr_int_workgroup = OpTypePointer Workgroup %int
1213 %var = OpVariable %ptr_int_workgroup Workgroup
1214 %voidfn = OpTypeFunction %void
1215 %spec_const = OpSpecConstant %int 0
1216 %relaxed = OpConstant %int 0
1217 %func = OpFunction %void None %voidfn
1218 %entry = OpLabel
1219 OpMemoryBarrier %spec_const %relaxed
1220 OpReturn
1221 OpFunctionEnd
1222 )";
1223
1224 CompileSuccessfully(spirv);
1225 EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
1226 }
1227
TEST_F(ValidateBarriers,VulkanMemoryModelDeviceScopeBad)1228 TEST_F(ValidateBarriers, VulkanMemoryModelDeviceScopeBad) {
1229 const std::string text = R"(
1230 OpCapability Shader
1231 OpCapability VulkanMemoryModelKHR
1232 OpExtension "SPV_KHR_vulkan_memory_model"
1233 OpMemoryModel Logical VulkanKHR
1234 OpEntryPoint Fragment %func "func"
1235 OpExecutionMode %func OriginUpperLeft
1236 %void = OpTypeVoid
1237 %int = OpTypeInt 32 0
1238 %device = OpConstant %int 1
1239 %semantics = OpConstant %int 0
1240 %functy = OpTypeFunction %void
1241 %func = OpFunction %void None %functy
1242 %1 = OpLabel
1243 OpMemoryBarrier %device %semantics
1244 OpReturn
1245 OpFunctionEnd
1246 )";
1247
1248 CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3);
1249 EXPECT_EQ(SPV_ERROR_INVALID_DATA,
1250 ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1251 EXPECT_THAT(
1252 getDiagnosticString(),
1253 HasSubstr("Use of device scope with VulkanKHR memory model requires the "
1254 "VulkanMemoryModelDeviceScopeKHR capability"));
1255 }
1256
TEST_F(ValidateBarriers,VulkanMemoryModelDeviceScopeGood)1257 TEST_F(ValidateBarriers, VulkanMemoryModelDeviceScopeGood) {
1258 const std::string text = R"(
1259 OpCapability Shader
1260 OpCapability VulkanMemoryModelKHR
1261 OpCapability VulkanMemoryModelDeviceScopeKHR
1262 OpExtension "SPV_KHR_vulkan_memory_model"
1263 OpMemoryModel Logical VulkanKHR
1264 OpEntryPoint Fragment %func "func"
1265 OpExecutionMode %func OriginUpperLeft
1266 %void = OpTypeVoid
1267 %int = OpTypeInt 32 0
1268 %device = OpConstant %int 1
1269 %semantics = OpConstant %int 0
1270 %functy = OpTypeFunction %void
1271 %func = OpFunction %void None %functy
1272 %1 = OpLabel
1273 OpMemoryBarrier %device %semantics
1274 OpReturn
1275 OpFunctionEnd
1276 )";
1277
1278 CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3);
1279 EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1280 }
1281
1282 } // namespace
1283 } // namespace val
1284 } // namespace spvtools
1285