• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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