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 %shadercall = OpConstant %u32 6
74
75 %none = OpConstant %u32 0
76 %acquire = OpConstant %u32 2
77 %release = OpConstant %u32 4
78 %acquire_release = OpConstant %u32 8
79 %acquire_and_release = OpConstant %u32 6
80 %sequentially_consistent = OpConstant %u32 16
81 %acquire_release_uniform_workgroup = OpConstant %u32 328
82 %acquire_uniform_workgroup = OpConstant %u32 322
83 %release_uniform_workgroup = OpConstant %u32 324
84 %acquire_and_release_uniform = OpConstant %u32 70
85 %acquire_release_subgroup = OpConstant %u32 136
86 %acquire_release_workgroup = OpConstant %u32 264
87 %uniform = OpConstant %u32 64
88 %uniform_workgroup = OpConstant %u32 320
89 %workgroup_memory = OpConstant %u32 256
90 %image_memory = OpConstant %u32 2048
91 %uniform_image_memory = OpConstant %u32 2112
92
93 %main = OpFunction %void None %func
94 %main_entry = OpLabel
95 )";
96
97 ss << body;
98
99 ss << R"(
100 OpReturn
101 OpFunctionEnd)";
102
103 return ss.str();
104 }
105
GenerateShaderCode(const std::string & body,const std::string & capabilities_and_extensions="",const std::string & execution_model="GLCompute")106 std::string GenerateShaderCode(
107 const std::string& body,
108 const std::string& capabilities_and_extensions = "",
109 const std::string& execution_model = "GLCompute") {
110 const std::string int64_capability = R"(
111 OpCapability Int64
112 )";
113 const std::string int64_declarations = R"(
114 %u64 = OpTypeInt 64 0
115 %u64_0 = OpConstant %u64 0
116 %u64_1 = OpConstant %u64 1
117 )";
118 const std::string memory_model = "OpMemoryModel Logical GLSL450";
119 return GenerateShaderCodeImpl(
120 body, int64_capability + capabilities_and_extensions, int64_declarations,
121 execution_model, memory_model);
122 }
123
GenerateVulkanVertexShaderCode(const std::string & body,const std::string & capabilities_and_extensions="",const std::string & execution_model="Vertex")124 std::string GenerateVulkanVertexShaderCode(
125 const std::string& body,
126 const std::string& capabilities_and_extensions = "",
127 const std::string& execution_model = "Vertex") {
128 const std::string memory_model = "OpMemoryModel Logical GLSL450";
129 return GenerateShaderCodeImpl(body, capabilities_and_extensions, "",
130 execution_model, memory_model);
131 }
132
GenerateKernelCode(const std::string & body,const std::string & capabilities_and_extensions="")133 std::string GenerateKernelCode(
134 const std::string& body,
135 const std::string& capabilities_and_extensions = "") {
136 std::ostringstream ss;
137 ss << R"(
138 OpCapability Addresses
139 OpCapability Kernel
140 OpCapability Linkage
141 OpCapability Int64
142 OpCapability NamedBarrier
143 )";
144
145 ss << capabilities_and_extensions;
146 ss << R"(
147 OpMemoryModel Physical32 OpenCL
148 %void = OpTypeVoid
149 %func = OpTypeFunction %void
150 %bool = OpTypeBool
151 %f32 = OpTypeFloat 32
152 %u32 = OpTypeInt 32 0
153 %u64 = OpTypeInt 64 0
154
155 %f32_0 = OpConstant %f32 0
156 %f32_1 = OpConstant %f32 1
157 %f32_4 = OpConstant %f32 4
158 %u32_0 = OpConstant %u32 0
159 %u32_1 = OpConstant %u32 1
160 %u32_4 = OpConstant %u32 4
161 %u64_0 = OpConstant %u64 0
162 %u64_1 = OpConstant %u64 1
163 %u64_4 = OpConstant %u64 4
164
165 %cross_device = OpConstant %u32 0
166 %device = OpConstant %u32 1
167 %workgroup = OpConstant %u32 2
168 %subgroup = OpConstant %u32 3
169 %invocation = OpConstant %u32 4
170
171 %none = OpConstant %u32 0
172 %acquire = OpConstant %u32 2
173 %release = OpConstant %u32 4
174 %acquire_release = OpConstant %u32 8
175 %acquire_and_release = OpConstant %u32 6
176 %sequentially_consistent = OpConstant %u32 16
177 %acquire_release_workgroup = OpConstant %u32 264
178
179 %named_barrier = OpTypeNamedBarrier
180
181 %main = OpFunction %void None %func
182 %main_entry = OpLabel
183 )";
184
185 ss << body;
186
187 ss << R"(
188 OpReturn
189 OpFunctionEnd)";
190
191 return ss.str();
192 }
193
TEST_F(ValidateBarriers,OpControlBarrierGLComputeSuccess)194 TEST_F(ValidateBarriers, OpControlBarrierGLComputeSuccess) {
195 const std::string body = R"(
196 OpControlBarrier %device %device %none
197 OpControlBarrier %workgroup %workgroup %acquire
198 OpControlBarrier %workgroup %device %release
199 OpControlBarrier %cross_device %cross_device %acquire_release
200 OpControlBarrier %cross_device %cross_device %sequentially_consistent
201 OpControlBarrier %cross_device %cross_device %acquire_release_uniform_workgroup
202 )";
203
204 CompileSuccessfully(GenerateShaderCode(body));
205 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
206 }
207
TEST_F(ValidateBarriers,OpControlBarrierKernelSuccess)208 TEST_F(ValidateBarriers, OpControlBarrierKernelSuccess) {
209 const std::string body = R"(
210 OpControlBarrier %device %device %none
211 OpControlBarrier %workgroup %workgroup %acquire
212 OpControlBarrier %workgroup %device %release
213 OpControlBarrier %cross_device %cross_device %acquire_release
214 OpControlBarrier %cross_device %cross_device %sequentially_consistent
215 OpControlBarrier %cross_device %cross_device %acquire_release_workgroup
216 )";
217
218 CompileSuccessfully(GenerateKernelCode(body), SPV_ENV_UNIVERSAL_1_1);
219 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
220 }
221
TEST_F(ValidateBarriers,OpControlBarrierTesselationControlSuccess)222 TEST_F(ValidateBarriers, OpControlBarrierTesselationControlSuccess) {
223 const std::string body = R"(
224 OpControlBarrier %device %device %none
225 OpControlBarrier %workgroup %workgroup %acquire
226 OpControlBarrier %workgroup %device %release
227 OpControlBarrier %cross_device %cross_device %acquire_release
228 OpControlBarrier %cross_device %cross_device %sequentially_consistent
229 OpControlBarrier %cross_device %cross_device %acquire_release_uniform_workgroup
230 )";
231
232 CompileSuccessfully(GenerateShaderCode(body, "OpCapability Tessellation\n",
233 "TessellationControl"));
234 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
235 }
236
TEST_F(ValidateBarriers,OpControlBarrierVulkanSuccess)237 TEST_F(ValidateBarriers, OpControlBarrierVulkanSuccess) {
238 const std::string body = R"(
239 OpControlBarrier %workgroup %device %none
240 OpControlBarrier %workgroup %workgroup %acquire_release_uniform_workgroup
241 )";
242
243 CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0);
244 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
245 }
246
TEST_F(ValidateBarriers,OpControlBarrierExecutionModelFragmentSpirv12)247 TEST_F(ValidateBarriers, OpControlBarrierExecutionModelFragmentSpirv12) {
248 const std::string body = R"(
249 OpControlBarrier %device %device %none
250 )";
251
252 CompileSuccessfully(GenerateShaderCode(body, "", "Fragment"),
253 SPV_ENV_UNIVERSAL_1_2);
254 ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_2));
255 EXPECT_THAT(
256 getDiagnosticString(),
257 HasSubstr("OpControlBarrier requires one of the following Execution "
258 "Models: TessellationControl, GLCompute or Kernel"));
259 }
260
TEST_F(ValidateBarriers,OpControlBarrierExecutionModelFragmentSpirv13)261 TEST_F(ValidateBarriers, OpControlBarrierExecutionModelFragmentSpirv13) {
262 const std::string body = R"(
263 OpControlBarrier %device %device %none
264 )";
265
266 CompileSuccessfully(GenerateShaderCode(body, "", "Fragment"),
267 SPV_ENV_UNIVERSAL_1_3);
268 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
269 }
270
TEST_F(ValidateBarriers,OpControlBarrierFloatExecutionScope)271 TEST_F(ValidateBarriers, OpControlBarrierFloatExecutionScope) {
272 const std::string body = R"(
273 OpControlBarrier %f32_1 %device %none
274 )";
275
276 CompileSuccessfully(GenerateShaderCode(body));
277 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
278 EXPECT_THAT(getDiagnosticString(),
279 HasSubstr("ControlBarrier: expected scope to be a 32-bit int"));
280 }
281
TEST_F(ValidateBarriers,OpControlBarrierU64ExecutionScope)282 TEST_F(ValidateBarriers, OpControlBarrierU64ExecutionScope) {
283 const std::string body = R"(
284 OpControlBarrier %u64_1 %device %none
285 )";
286
287 CompileSuccessfully(GenerateShaderCode(body));
288 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
289 EXPECT_THAT(getDiagnosticString(),
290 HasSubstr("ControlBarrier: expected scope to be a 32-bit int"));
291 }
292
TEST_F(ValidateBarriers,OpControlBarrierFloatMemoryScope)293 TEST_F(ValidateBarriers, OpControlBarrierFloatMemoryScope) {
294 const std::string body = R"(
295 OpControlBarrier %device %f32_1 %none
296 )";
297
298 CompileSuccessfully(GenerateShaderCode(body));
299 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
300 EXPECT_THAT(getDiagnosticString(),
301 HasSubstr("ControlBarrier: expected scope to be a 32-bit int"));
302 }
303
TEST_F(ValidateBarriers,OpControlBarrierU64MemoryScope)304 TEST_F(ValidateBarriers, OpControlBarrierU64MemoryScope) {
305 const std::string body = R"(
306 OpControlBarrier %device %u64_1 %none
307 )";
308
309 CompileSuccessfully(GenerateShaderCode(body));
310 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
311 EXPECT_THAT(getDiagnosticString(),
312 HasSubstr("ControlBarrier: expected scope to be a 32-bit int"));
313 }
314
TEST_F(ValidateBarriers,OpControlBarrierFloatMemorySemantics)315 TEST_F(ValidateBarriers, OpControlBarrierFloatMemorySemantics) {
316 const std::string body = R"(
317 OpControlBarrier %device %device %f32_0
318 )";
319
320 CompileSuccessfully(GenerateShaderCode(body));
321 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
322 EXPECT_THAT(
323 getDiagnosticString(),
324 HasSubstr(
325 "ControlBarrier: expected Memory Semantics to be a 32-bit int"));
326 }
327
TEST_F(ValidateBarriers,OpControlBarrierU64MemorySemantics)328 TEST_F(ValidateBarriers, OpControlBarrierU64MemorySemantics) {
329 const std::string body = R"(
330 OpControlBarrier %device %device %u64_0
331 )";
332
333 CompileSuccessfully(GenerateShaderCode(body));
334 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
335 EXPECT_THAT(
336 getDiagnosticString(),
337 HasSubstr(
338 "ControlBarrier: expected Memory Semantics to be a 32-bit int"));
339 }
340
TEST_F(ValidateBarriers,OpControlBarrierVulkanExecutionScopeDevice)341 TEST_F(ValidateBarriers, OpControlBarrierVulkanExecutionScopeDevice) {
342 const std::string body = R"(
343 OpControlBarrier %device %workgroup %none
344 )";
345
346 CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0);
347 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
348 EXPECT_THAT(getDiagnosticString(),
349 HasSubstr("ControlBarrier: in Vulkan environment Execution Scope "
350 "is limited to Workgroup and Subgroup"));
351 }
352
TEST_F(ValidateBarriers,OpControlBarrierVulkanMemoryScopeSubgroup)353 TEST_F(ValidateBarriers, OpControlBarrierVulkanMemoryScopeSubgroup) {
354 const std::string body = R"(
355 OpControlBarrier %subgroup %subgroup %none
356 )";
357
358 CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0);
359 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
360 EXPECT_THAT(getDiagnosticString(),
361 AnyVUID("VUID-StandaloneSpirv-None-04638"));
362 EXPECT_THAT(
363 getDiagnosticString(),
364 HasSubstr("ControlBarrier: in Vulkan 1.0 environment Memory Scope is "
365 "limited to Device, Workgroup and Invocation"));
366 }
367
TEST_F(ValidateBarriers,OpControlBarrierVulkan1p1MemoryScopeSubgroup)368 TEST_F(ValidateBarriers, OpControlBarrierVulkan1p1MemoryScopeSubgroup) {
369 const std::string body = R"(
370 OpControlBarrier %subgroup %subgroup %none
371 )";
372
373 CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_1);
374 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
375 }
376
TEST_F(ValidateBarriers,OpControlBarrierVulkan1p1MemoryScopeCrossDevice)377 TEST_F(ValidateBarriers, OpControlBarrierVulkan1p1MemoryScopeCrossDevice) {
378 const std::string body = R"(
379 OpControlBarrier %subgroup %cross_device %none
380 )";
381
382 CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_1);
383 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_1));
384 EXPECT_THAT(getDiagnosticString(),
385 AnyVUID("VUID-StandaloneSpirv-None-04638"));
386 EXPECT_THAT(getDiagnosticString(),
387 HasSubstr("ControlBarrier: in Vulkan environment, Memory Scope "
388 "cannot be CrossDevice"));
389 }
390
TEST_F(ValidateBarriers,OpControlBarrierVulkan1p1WorkgroupNonComputeFailure)391 TEST_F(ValidateBarriers, OpControlBarrierVulkan1p1WorkgroupNonComputeFailure) {
392 const std::string body = R"(
393 OpControlBarrier %workgroup %workgroup %acquire
394 )";
395
396 CompileSuccessfully(GenerateVulkanVertexShaderCode(body), SPV_ENV_VULKAN_1_1);
397 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
398 EXPECT_THAT(getDiagnosticString(),
399 AnyVUID("VUID-StandaloneSpirv-None-04639"));
400 EXPECT_THAT(getDiagnosticString(),
401 HasSubstr("Workgroup Memory Scope is limited to MeshNV, TaskNV, "
402 "and GLCompute execution model"));
403 }
404
TEST_F(ValidateBarriers,OpControlBarrierVulkan1p1WorkgroupNonComputeSuccess)405 TEST_F(ValidateBarriers, OpControlBarrierVulkan1p1WorkgroupNonComputeSuccess) {
406 const std::string body = R"(
407 OpControlBarrier %workgroup %workgroup %acquire
408 )";
409
410 CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_1);
411 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
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(getDiagnosticString(),
641 HasSubstr("MemoryBarrier: expected scope to be a 32-bit int"));
642 }
643
TEST_F(ValidateBarriers,OpMemoryBarrierU64MemoryScope)644 TEST_F(ValidateBarriers, OpMemoryBarrierU64MemoryScope) {
645 const std::string body = R"(
646 OpMemoryBarrier %u64_1 %acquire_release_uniform_workgroup
647 )";
648
649 CompileSuccessfully(GenerateShaderCode(body));
650 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
651 EXPECT_THAT(getDiagnosticString(),
652 HasSubstr("MemoryBarrier: expected scope to be a 32-bit int"));
653 }
654
TEST_F(ValidateBarriers,OpMemoryBarrierFloatMemorySemantics)655 TEST_F(ValidateBarriers, OpMemoryBarrierFloatMemorySemantics) {
656 const std::string body = R"(
657 OpMemoryBarrier %device %f32_0
658 )";
659
660 CompileSuccessfully(GenerateShaderCode(body));
661 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
662 EXPECT_THAT(
663 getDiagnosticString(),
664 HasSubstr("MemoryBarrier: expected Memory Semantics to be a 32-bit int"));
665 }
666
TEST_F(ValidateBarriers,OpMemoryBarrierU64MemorySemantics)667 TEST_F(ValidateBarriers, OpMemoryBarrierU64MemorySemantics) {
668 const std::string body = R"(
669 OpMemoryBarrier %device %u64_0
670 )";
671
672 CompileSuccessfully(GenerateShaderCode(body));
673 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
674 EXPECT_THAT(
675 getDiagnosticString(),
676 HasSubstr("MemoryBarrier: expected Memory Semantics to be a 32-bit int"));
677 }
678
TEST_F(ValidateBarriers,OpMemoryBarrierVulkanMemoryScopeSubgroup)679 TEST_F(ValidateBarriers, OpMemoryBarrierVulkanMemoryScopeSubgroup) {
680 const std::string body = R"(
681 OpMemoryBarrier %subgroup %acquire_release_uniform_workgroup
682 )";
683
684 CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0);
685 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
686 EXPECT_THAT(getDiagnosticString(),
687 AnyVUID("VUID-StandaloneSpirv-None-04638"));
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(getDiagnosticString(),
724 AnyVUID("VUID-StandaloneSpirv-OpMemoryBarrier-04732"));
725 EXPECT_THAT(
726 getDiagnosticString(),
727 HasSubstr("MemoryBarrier: Vulkan specification requires Memory Semantics "
728 "to have one of the following bits set: Acquire, Release, "
729 "AcquireRelease or SequentiallyConsistent"));
730 }
731
TEST_F(ValidateBarriers,OpMemoryBarrierVulkanMemorySemanticsAcquire)732 TEST_F(ValidateBarriers, OpMemoryBarrierVulkanMemorySemanticsAcquire) {
733 const std::string body = R"(
734 OpMemoryBarrier %device %acquire
735 )";
736
737 CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0);
738 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
739 EXPECT_THAT(getDiagnosticString(),
740 AnyVUID("VUID-StandaloneSpirv-OpMemoryBarrier-04733"));
741 EXPECT_THAT(getDiagnosticString(),
742 HasSubstr("MemoryBarrier: expected Memory Semantics to include a "
743 "Vulkan-supported storage class"));
744 }
745
TEST_F(ValidateBarriers,OpMemoryBarrierVulkanSubgroupStorageClass)746 TEST_F(ValidateBarriers, OpMemoryBarrierVulkanSubgroupStorageClass) {
747 const std::string body = R"(
748 OpMemoryBarrier %device %acquire_release_subgroup
749 )";
750
751 CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0);
752 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
753 EXPECT_THAT(getDiagnosticString(),
754 AnyVUID("VUID-StandaloneSpirv-OpMemoryBarrier-04733"));
755 EXPECT_THAT(getDiagnosticString(),
756 HasSubstr("MemoryBarrier: expected Memory Semantics to include a "
757 "Vulkan-supported storage class"));
758 }
759
TEST_F(ValidateBarriers,OpNamedBarrierInitializeSuccess)760 TEST_F(ValidateBarriers, OpNamedBarrierInitializeSuccess) {
761 const std::string body = R"(
762 %barrier = OpNamedBarrierInitialize %named_barrier %u32_4
763 )";
764
765 CompileSuccessfully(GenerateKernelCode(body), SPV_ENV_UNIVERSAL_1_1);
766 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
767 }
768
TEST_F(ValidateBarriers,OpNamedBarrierInitializeWrongResultType)769 TEST_F(ValidateBarriers, OpNamedBarrierInitializeWrongResultType) {
770 const std::string body = R"(
771 %barrier = OpNamedBarrierInitialize %u32 %u32_4
772 )";
773
774 CompileSuccessfully(GenerateKernelCode(body), SPV_ENV_UNIVERSAL_1_1);
775 ASSERT_EQ(SPV_ERROR_INVALID_DATA,
776 ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
777 EXPECT_THAT(getDiagnosticString(),
778 HasSubstr("NamedBarrierInitialize: expected Result Type to be "
779 "OpTypeNamedBarrier"));
780 }
781
TEST_F(ValidateBarriers,OpNamedBarrierInitializeFloatSubgroupCount)782 TEST_F(ValidateBarriers, OpNamedBarrierInitializeFloatSubgroupCount) {
783 const std::string body = R"(
784 %barrier = OpNamedBarrierInitialize %named_barrier %f32_4
785 )";
786
787 CompileSuccessfully(GenerateKernelCode(body), SPV_ENV_UNIVERSAL_1_1);
788 ASSERT_EQ(SPV_ERROR_INVALID_DATA,
789 ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
790 EXPECT_THAT(getDiagnosticString(),
791 HasSubstr("NamedBarrierInitialize: expected Subgroup Count to be "
792 "a 32-bit int"));
793 }
794
TEST_F(ValidateBarriers,OpNamedBarrierInitializeU64SubgroupCount)795 TEST_F(ValidateBarriers, OpNamedBarrierInitializeU64SubgroupCount) {
796 const std::string body = R"(
797 %barrier = OpNamedBarrierInitialize %named_barrier %u64_4
798 )";
799
800 CompileSuccessfully(GenerateKernelCode(body), SPV_ENV_UNIVERSAL_1_1);
801 ASSERT_EQ(SPV_ERROR_INVALID_DATA,
802 ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
803 EXPECT_THAT(getDiagnosticString(),
804 HasSubstr("NamedBarrierInitialize: expected Subgroup Count to be "
805 "a 32-bit int"));
806 }
807
TEST_F(ValidateBarriers,OpMemoryNamedBarrierSuccess)808 TEST_F(ValidateBarriers, OpMemoryNamedBarrierSuccess) {
809 const std::string body = R"(
810 %barrier = OpNamedBarrierInitialize %named_barrier %u32_4
811 OpMemoryNamedBarrier %barrier %workgroup %acquire_release_workgroup
812 )";
813
814 CompileSuccessfully(GenerateKernelCode(body), SPV_ENV_UNIVERSAL_1_1);
815 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
816 }
817
TEST_F(ValidateBarriers,OpMemoryNamedBarrierNotNamedBarrier)818 TEST_F(ValidateBarriers, OpMemoryNamedBarrierNotNamedBarrier) {
819 const std::string body = R"(
820 OpMemoryNamedBarrier %u32_1 %workgroup %acquire_release_workgroup
821 )";
822
823 CompileSuccessfully(GenerateKernelCode(body), SPV_ENV_UNIVERSAL_1_1);
824 ASSERT_EQ(SPV_ERROR_INVALID_DATA,
825 ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
826 EXPECT_THAT(getDiagnosticString(),
827 HasSubstr("MemoryNamedBarrier: expected Named Barrier to be of "
828 "type OpTypeNamedBarrier"));
829 }
830
TEST_F(ValidateBarriers,OpMemoryNamedBarrierFloatMemoryScope)831 TEST_F(ValidateBarriers, OpMemoryNamedBarrierFloatMemoryScope) {
832 const std::string body = R"(
833 %barrier = OpNamedBarrierInitialize %named_barrier %u32_4
834 OpMemoryNamedBarrier %barrier %f32_1 %acquire_release_workgroup
835 )";
836
837 CompileSuccessfully(GenerateKernelCode(body), SPV_ENV_UNIVERSAL_1_1);
838 ASSERT_EQ(SPV_ERROR_INVALID_DATA,
839 ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
840 EXPECT_THAT(
841 getDiagnosticString(),
842 HasSubstr("MemoryNamedBarrier: expected scope to be a 32-bit int"));
843 }
844
TEST_F(ValidateBarriers,OpMemoryNamedBarrierFloatMemorySemantics)845 TEST_F(ValidateBarriers, OpMemoryNamedBarrierFloatMemorySemantics) {
846 const std::string body = R"(
847 %barrier = OpNamedBarrierInitialize %named_barrier %u32_4
848 OpMemoryNamedBarrier %barrier %workgroup %f32_0
849 )";
850
851 CompileSuccessfully(GenerateKernelCode(body), SPV_ENV_UNIVERSAL_1_1);
852 ASSERT_EQ(SPV_ERROR_INVALID_DATA,
853 ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
854 EXPECT_THAT(
855 getDiagnosticString(),
856 HasSubstr(
857 "MemoryNamedBarrier: expected Memory Semantics to be a 32-bit int"));
858 }
859
TEST_F(ValidateBarriers,OpMemoryNamedBarrierAcquireAndRelease)860 TEST_F(ValidateBarriers, OpMemoryNamedBarrierAcquireAndRelease) {
861 const std::string body = R"(
862 %barrier = OpNamedBarrierInitialize %named_barrier %u32_4
863 OpMemoryNamedBarrier %barrier %workgroup %acquire_and_release
864 )";
865
866 CompileSuccessfully(GenerateKernelCode(body), SPV_ENV_UNIVERSAL_1_1);
867 ASSERT_EQ(SPV_ERROR_INVALID_DATA,
868 ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
869 EXPECT_THAT(getDiagnosticString(),
870 HasSubstr("MemoryNamedBarrier: Memory Semantics can have at most "
871 "one of the following bits set: Acquire, Release, "
872 "AcquireRelease or SequentiallyConsistent"));
873 }
874
TEST_F(ValidateBarriers,TypeAsMemoryScope)875 TEST_F(ValidateBarriers, TypeAsMemoryScope) {
876 const std::string body = R"(
877 OpMemoryBarrier %u32 %u32_0
878 )";
879
880 CompileSuccessfully(GenerateKernelCode(body), SPV_ENV_UNIVERSAL_1_1);
881 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
882 EXPECT_THAT(getDiagnosticString(), HasSubstr("Operand 5[%uint] cannot be a "
883 "type"));
884 }
885
TEST_F(ValidateBarriers,OpControlBarrierVulkanMemoryModelBanSequentiallyConsistent)886 TEST_F(ValidateBarriers,
887 OpControlBarrierVulkanMemoryModelBanSequentiallyConsistent) {
888 const std::string text = R"(
889 OpCapability Shader
890 OpCapability VulkanMemoryModelKHR
891 OpExtension "SPV_KHR_vulkan_memory_model"
892 OpMemoryModel Logical VulkanKHR
893 OpEntryPoint Fragment %1 "func"
894 OpExecutionMode %1 OriginUpperLeft
895 %2 = OpTypeVoid
896 %3 = OpTypeInt 32 0
897 %4 = OpConstant %3 16
898 %5 = OpTypeFunction %2
899 %6 = OpConstant %3 5
900 %1 = OpFunction %2 None %5
901 %7 = OpLabel
902 OpControlBarrier %6 %6 %4
903 OpReturn
904 OpFunctionEnd
905 )";
906
907 CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3);
908 EXPECT_EQ(SPV_ERROR_INVALID_DATA,
909 ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
910 EXPECT_THAT(getDiagnosticString(),
911 HasSubstr("SequentiallyConsistent memory semantics cannot be "
912 "used with the VulkanKHR memory model."));
913 }
914
TEST_F(ValidateBarriers,OpMemoryBarrierVulkanMemoryModelBanSequentiallyConsistent)915 TEST_F(ValidateBarriers,
916 OpMemoryBarrierVulkanMemoryModelBanSequentiallyConsistent) {
917 const std::string text = R"(
918 OpCapability Shader
919 OpCapability VulkanMemoryModelKHR
920 OpExtension "SPV_KHR_vulkan_memory_model"
921 OpMemoryModel Logical VulkanKHR
922 OpEntryPoint Fragment %1 "func"
923 OpExecutionMode %1 OriginUpperLeft
924 %2 = OpTypeVoid
925 %3 = OpTypeInt 32 0
926 %4 = OpConstant %3 16
927 %5 = OpTypeFunction %2
928 %6 = OpConstant %3 5
929 %1 = OpFunction %2 None %5
930 %7 = OpLabel
931 OpMemoryBarrier %6 %4
932 OpReturn
933 OpFunctionEnd
934 )";
935
936 CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3);
937 EXPECT_EQ(SPV_ERROR_INVALID_DATA,
938 ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
939 EXPECT_THAT(getDiagnosticString(),
940 HasSubstr("SequentiallyConsistent memory semantics cannot be "
941 "used with the VulkanKHR memory model."));
942 }
943
TEST_F(ValidateBarriers,OutputMemoryKHRRequireVulkanMemoryModelKHR)944 TEST_F(ValidateBarriers, OutputMemoryKHRRequireVulkanMemoryModelKHR) {
945 const std::string text = R"(
946 OpCapability Shader
947 OpMemoryModel Logical GLSL450
948 OpEntryPoint Fragment %1 "func"
949 OpExecutionMode %1 OriginUpperLeft
950 %2 = OpTypeVoid
951 %3 = OpTypeInt 32 0
952 %semantics = OpConstant %3 4104
953 %5 = OpTypeFunction %2
954 %device = OpConstant %3 1
955 %1 = OpFunction %2 None %5
956 %7 = OpLabel
957 OpControlBarrier %device %device %semantics
958 OpReturn
959 OpFunctionEnd
960 )";
961
962 CompileSuccessfully(text);
963 EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
964 EXPECT_THAT(getDiagnosticString(),
965 HasSubstr("ControlBarrier: Memory Semantics OutputMemoryKHR "
966 "requires capability VulkanMemoryModelKHR"));
967 }
968
TEST_F(ValidateBarriers,MakeAvailableKHRRequireVulkanMemoryModelKHR)969 TEST_F(ValidateBarriers, MakeAvailableKHRRequireVulkanMemoryModelKHR) {
970 const std::string text = R"(
971 OpCapability Shader
972 OpMemoryModel Logical GLSL450
973 OpEntryPoint Fragment %1 "func"
974 OpExecutionMode %1 OriginUpperLeft
975 %2 = OpTypeVoid
976 %3 = OpTypeInt 32 0
977 %semantics = OpConstant %3 8264
978 %5 = OpTypeFunction %2
979 %device = OpConstant %3 1
980 %1 = OpFunction %2 None %5
981 %7 = OpLabel
982 OpControlBarrier %device %device %semantics
983 OpReturn
984 OpFunctionEnd
985 )";
986
987 CompileSuccessfully(text);
988 EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
989 EXPECT_THAT(getDiagnosticString(),
990 HasSubstr("ControlBarrier: Memory Semantics MakeAvailableKHR "
991 "requires capability VulkanMemoryModelKHR"));
992 }
993
TEST_F(ValidateBarriers,MakeVisibleKHRRequireVulkanMemoryModelKHR)994 TEST_F(ValidateBarriers, MakeVisibleKHRRequireVulkanMemoryModelKHR) {
995 const std::string text = R"(
996 OpCapability Shader
997 OpMemoryModel Logical GLSL450
998 OpEntryPoint Fragment %1 "func"
999 OpExecutionMode %1 OriginUpperLeft
1000 %2 = OpTypeVoid
1001 %3 = OpTypeInt 32 0
1002 %semantics = OpConstant %3 16456
1003 %5 = OpTypeFunction %2
1004 %device = OpConstant %3 1
1005 %1 = OpFunction %2 None %5
1006 %7 = OpLabel
1007 OpControlBarrier %device %device %semantics
1008 OpReturn
1009 OpFunctionEnd
1010 )";
1011
1012 CompileSuccessfully(text);
1013 EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1014 EXPECT_THAT(getDiagnosticString(),
1015 HasSubstr("ControlBarrier: Memory Semantics MakeVisibleKHR "
1016 "requires capability VulkanMemoryModelKHR"));
1017 }
1018
TEST_F(ValidateBarriers,MakeAvailableKHRRequiresReleaseSemantics)1019 TEST_F(ValidateBarriers, MakeAvailableKHRRequiresReleaseSemantics) {
1020 const std::string text = R"(
1021 OpCapability Shader
1022 OpCapability VulkanMemoryModelKHR
1023 OpExtension "SPV_KHR_vulkan_memory_model"
1024 OpMemoryModel Logical VulkanKHR
1025 OpEntryPoint Fragment %func "func"
1026 OpExecutionMode %func OriginUpperLeft
1027 %void = OpTypeVoid
1028 %int = OpTypeInt 32 0
1029 %workgroup = OpConstant %int 2
1030 %semantics = OpConstant %int 8448
1031 %functy = OpTypeFunction %void
1032 %func = OpFunction %void None %functy
1033 %1 = OpLabel
1034 OpControlBarrier %workgroup %workgroup %semantics
1035 OpReturn
1036 OpFunctionEnd
1037 )";
1038
1039 CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3);
1040 EXPECT_EQ(SPV_ERROR_INVALID_DATA,
1041 ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1042 EXPECT_THAT(
1043 getDiagnosticString(),
1044 HasSubstr("ControlBarrier: MakeAvailableKHR Memory Semantics also "
1045 "requires either Release or AcquireRelease Memory Semantics"));
1046 }
1047
TEST_F(ValidateBarriers,MakeVisibleKHRRequiresAcquireSemantics)1048 TEST_F(ValidateBarriers, MakeVisibleKHRRequiresAcquireSemantics) {
1049 const std::string text = R"(
1050 OpCapability Shader
1051 OpCapability VulkanMemoryModelKHR
1052 OpExtension "SPV_KHR_vulkan_memory_model"
1053 OpMemoryModel Logical VulkanKHR
1054 OpEntryPoint Fragment %func "func"
1055 OpExecutionMode %func OriginUpperLeft
1056 %void = OpTypeVoid
1057 %int = OpTypeInt 32 0
1058 %workgroup = OpConstant %int 2
1059 %semantics = OpConstant %int 16640
1060 %functy = OpTypeFunction %void
1061 %func = OpFunction %void None %functy
1062 %1 = OpLabel
1063 OpControlBarrier %workgroup %workgroup %semantics
1064 OpReturn
1065 OpFunctionEnd
1066 )";
1067
1068 CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3);
1069 EXPECT_EQ(SPV_ERROR_INVALID_DATA,
1070 ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1071 EXPECT_THAT(
1072 getDiagnosticString(),
1073 HasSubstr("ControlBarrier: MakeVisibleKHR Memory Semantics also requires "
1074 "either Acquire or AcquireRelease Memory Semantics"));
1075 }
1076
TEST_F(ValidateBarriers,MakeAvailableKHRRequiresStorageSemantics)1077 TEST_F(ValidateBarriers, MakeAvailableKHRRequiresStorageSemantics) {
1078 const std::string text = R"(
1079 OpCapability Shader
1080 OpCapability VulkanMemoryModelKHR
1081 OpExtension "SPV_KHR_vulkan_memory_model"
1082 OpMemoryModel Logical VulkanKHR
1083 OpEntryPoint Fragment %func "func"
1084 OpExecutionMode %func OriginUpperLeft
1085 %void = OpTypeVoid
1086 %int = OpTypeInt 32 0
1087 %workgroup = OpConstant %int 2
1088 %semantics = OpConstant %int 8196
1089 %functy = OpTypeFunction %void
1090 %func = OpFunction %void None %functy
1091 %1 = OpLabel
1092 OpMemoryBarrier %workgroup %semantics
1093 OpReturn
1094 OpFunctionEnd
1095 )";
1096
1097 CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3);
1098 EXPECT_EQ(SPV_ERROR_INVALID_DATA,
1099 ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1100 EXPECT_THAT(getDiagnosticString(),
1101 HasSubstr("MemoryBarrier: expected Memory Semantics to include a "
1102 "storage class"));
1103 }
1104
TEST_F(ValidateBarriers,MakeVisibleKHRRequiresStorageSemantics)1105 TEST_F(ValidateBarriers, MakeVisibleKHRRequiresStorageSemantics) {
1106 const std::string text = R"(
1107 OpCapability Shader
1108 OpCapability VulkanMemoryModelKHR
1109 OpExtension "SPV_KHR_vulkan_memory_model"
1110 OpMemoryModel Logical VulkanKHR
1111 OpEntryPoint Fragment %func "func"
1112 OpExecutionMode %func OriginUpperLeft
1113 %void = OpTypeVoid
1114 %int = OpTypeInt 32 0
1115 %workgroup = OpConstant %int 2
1116 %semantics = OpConstant %int 16386
1117 %functy = OpTypeFunction %void
1118 %func = OpFunction %void None %functy
1119 %1 = OpLabel
1120 OpMemoryBarrier %workgroup %semantics
1121 OpReturn
1122 OpFunctionEnd
1123 )";
1124
1125 CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3);
1126 EXPECT_EQ(SPV_ERROR_INVALID_DATA,
1127 ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1128 EXPECT_THAT(getDiagnosticString(),
1129 HasSubstr("MemoryBarrier: expected Memory Semantics to include a "
1130 "storage class"));
1131 }
1132
TEST_F(ValidateBarriers,SemanticsSpecConstantShader)1133 TEST_F(ValidateBarriers, SemanticsSpecConstantShader) {
1134 const std::string spirv = R"(
1135 OpCapability Shader
1136 OpMemoryModel Logical GLSL450
1137 OpEntryPoint Fragment %func "func"
1138 OpExecutionMode %func OriginUpperLeft
1139 %void = OpTypeVoid
1140 %int = OpTypeInt 32 0
1141 %ptr_int_workgroup = OpTypePointer Workgroup %int
1142 %var = OpVariable %ptr_int_workgroup Workgroup
1143 %voidfn = OpTypeFunction %void
1144 %spec_const = OpSpecConstant %int 0
1145 %workgroup = OpConstant %int 2
1146 %func = OpFunction %void None %voidfn
1147 %entry = OpLabel
1148 OpMemoryBarrier %workgroup %spec_const
1149 OpReturn
1150 OpFunctionEnd
1151 )";
1152
1153 CompileSuccessfully(spirv);
1154 EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1155 EXPECT_THAT(getDiagnosticString(),
1156 HasSubstr("Memory Semantics ids must be OpConstant when Shader "
1157 "capability is present"));
1158 }
1159
TEST_F(ValidateBarriers,SemanticsSpecConstantKernel)1160 TEST_F(ValidateBarriers, SemanticsSpecConstantKernel) {
1161 const std::string spirv = R"(
1162 OpCapability Kernel
1163 OpCapability Linkage
1164 OpMemoryModel Logical OpenCL
1165 %void = OpTypeVoid
1166 %int = OpTypeInt 32 0
1167 %ptr_int_workgroup = OpTypePointer Workgroup %int
1168 %var = OpVariable %ptr_int_workgroup Workgroup
1169 %voidfn = OpTypeFunction %void
1170 %spec_const = OpSpecConstant %int 0
1171 %workgroup = OpConstant %int 2
1172 %func = OpFunction %void None %voidfn
1173 %entry = OpLabel
1174 OpMemoryBarrier %workgroup %spec_const
1175 OpReturn
1176 OpFunctionEnd
1177 )";
1178
1179 CompileSuccessfully(spirv);
1180 EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
1181 }
1182
TEST_F(ValidateBarriers,ScopeSpecConstantShader)1183 TEST_F(ValidateBarriers, ScopeSpecConstantShader) {
1184 const std::string spirv = R"(
1185 OpCapability Shader
1186 OpMemoryModel Logical GLSL450
1187 OpEntryPoint Fragment %func "func"
1188 OpExecutionMode %func OriginUpperLeft
1189 %void = OpTypeVoid
1190 %int = OpTypeInt 32 0
1191 %ptr_int_workgroup = OpTypePointer Workgroup %int
1192 %var = OpVariable %ptr_int_workgroup Workgroup
1193 %voidfn = OpTypeFunction %void
1194 %spec_const = OpSpecConstant %int 0
1195 %relaxed = OpConstant %int 0
1196 %func = OpFunction %void None %voidfn
1197 %entry = OpLabel
1198 OpMemoryBarrier %spec_const %relaxed
1199 OpReturn
1200 OpFunctionEnd
1201 )";
1202
1203 CompileSuccessfully(spirv);
1204 EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1205 EXPECT_THAT(getDiagnosticString(),
1206 HasSubstr("Scope ids must be OpConstant when Shader "
1207 "capability is present"));
1208 }
1209
TEST_F(ValidateBarriers,ScopeSpecConstantKernel)1210 TEST_F(ValidateBarriers, ScopeSpecConstantKernel) {
1211 const std::string spirv = R"(
1212 OpCapability Kernel
1213 OpCapability Linkage
1214 OpMemoryModel Logical OpenCL
1215 %void = OpTypeVoid
1216 %int = OpTypeInt 32 0
1217 %ptr_int_workgroup = OpTypePointer Workgroup %int
1218 %var = OpVariable %ptr_int_workgroup Workgroup
1219 %voidfn = OpTypeFunction %void
1220 %spec_const = OpSpecConstant %int 0
1221 %relaxed = OpConstant %int 0
1222 %func = OpFunction %void None %voidfn
1223 %entry = OpLabel
1224 OpMemoryBarrier %spec_const %relaxed
1225 OpReturn
1226 OpFunctionEnd
1227 )";
1228
1229 CompileSuccessfully(spirv);
1230 EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
1231 }
1232
TEST_F(ValidateBarriers,VulkanMemoryModelDeviceScopeBad)1233 TEST_F(ValidateBarriers, VulkanMemoryModelDeviceScopeBad) {
1234 const std::string text = R"(
1235 OpCapability Shader
1236 OpCapability VulkanMemoryModelKHR
1237 OpExtension "SPV_KHR_vulkan_memory_model"
1238 OpMemoryModel Logical VulkanKHR
1239 OpEntryPoint Fragment %func "func"
1240 OpExecutionMode %func OriginUpperLeft
1241 %void = OpTypeVoid
1242 %int = OpTypeInt 32 0
1243 %device = OpConstant %int 1
1244 %semantics = OpConstant %int 0
1245 %functy = OpTypeFunction %void
1246 %func = OpFunction %void None %functy
1247 %1 = OpLabel
1248 OpMemoryBarrier %device %semantics
1249 OpReturn
1250 OpFunctionEnd
1251 )";
1252
1253 CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3);
1254 EXPECT_EQ(SPV_ERROR_INVALID_DATA,
1255 ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1256 EXPECT_THAT(
1257 getDiagnosticString(),
1258 HasSubstr("Use of device scope with VulkanKHR memory model requires the "
1259 "VulkanMemoryModelDeviceScopeKHR capability"));
1260 }
1261
TEST_F(ValidateBarriers,VulkanMemoryModelDeviceScopeGood)1262 TEST_F(ValidateBarriers, VulkanMemoryModelDeviceScopeGood) {
1263 const std::string text = R"(
1264 OpCapability Shader
1265 OpCapability VulkanMemoryModelKHR
1266 OpCapability VulkanMemoryModelDeviceScopeKHR
1267 OpExtension "SPV_KHR_vulkan_memory_model"
1268 OpMemoryModel Logical VulkanKHR
1269 OpEntryPoint Fragment %func "func"
1270 OpExecutionMode %func OriginUpperLeft
1271 %void = OpTypeVoid
1272 %int = OpTypeInt 32 0
1273 %device = OpConstant %int 1
1274 %semantics = OpConstant %int 0
1275 %functy = OpTypeFunction %void
1276 %func = OpFunction %void None %functy
1277 %1 = OpLabel
1278 OpMemoryBarrier %device %semantics
1279 OpReturn
1280 OpFunctionEnd
1281 )";
1282
1283 CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3);
1284 EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1285 }
1286
TEST_F(ValidateBarriers,VolatileMemoryBarrier)1287 TEST_F(ValidateBarriers, VolatileMemoryBarrier) {
1288 const std::string text = R"(
1289 OpCapability Shader
1290 OpCapability VulkanMemoryModelKHR
1291 OpCapability VulkanMemoryModelDeviceScopeKHR
1292 OpCapability Linkage
1293 OpExtension "SPV_KHR_vulkan_memory_model"
1294 OpMemoryModel Logical VulkanKHR
1295 %void = OpTypeVoid
1296 %int = OpTypeInt 32 0
1297 %device = OpConstant %int 1
1298 %semantics = OpConstant %int 32768
1299 %functy = OpTypeFunction %void
1300 %func = OpFunction %void None %functy
1301 %1 = OpLabel
1302 OpMemoryBarrier %device %semantics
1303 OpReturn
1304 OpFunctionEnd
1305 )";
1306
1307 CompileSuccessfully(text);
1308 EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1309 EXPECT_THAT(getDiagnosticString(),
1310 HasSubstr("Memory Semantics Volatile can only be used with "
1311 "atomic instructions"));
1312 }
1313
TEST_F(ValidateBarriers,VolatileControlBarrier)1314 TEST_F(ValidateBarriers, VolatileControlBarrier) {
1315 const std::string text = R"(
1316 OpCapability Shader
1317 OpCapability VulkanMemoryModelKHR
1318 OpCapability VulkanMemoryModelDeviceScopeKHR
1319 OpCapability Linkage
1320 OpExtension "SPV_KHR_vulkan_memory_model"
1321 OpMemoryModel Logical VulkanKHR
1322 %void = OpTypeVoid
1323 %int = OpTypeInt 32 0
1324 %device = OpConstant %int 1
1325 %semantics = OpConstant %int 32768
1326 %functy = OpTypeFunction %void
1327 %func = OpFunction %void None %functy
1328 %1 = OpLabel
1329 OpControlBarrier %device %device %semantics
1330 OpReturn
1331 OpFunctionEnd
1332 )";
1333
1334 CompileSuccessfully(text);
1335 EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1336 EXPECT_THAT(getDiagnosticString(),
1337 HasSubstr("Memory Semantics Volatile can only be used with "
1338 "atomic instructions"));
1339 }
1340
TEST_F(ValidateBarriers,CooperativeMatrixSpecConstantVolatile)1341 TEST_F(ValidateBarriers, CooperativeMatrixSpecConstantVolatile) {
1342 const std::string text = R"(
1343 OpCapability Shader
1344 OpCapability VulkanMemoryModelKHR
1345 OpCapability VulkanMemoryModelDeviceScopeKHR
1346 OpCapability CooperativeMatrixNV
1347 OpCapability Linkage
1348 OpExtension "SPV_KHR_vulkan_memory_model"
1349 OpExtension "SPV_NV_cooperative_matrix"
1350 OpMemoryModel Logical VulkanKHR
1351 %void = OpTypeVoid
1352 %int = OpTypeInt 32 0
1353 %device = OpConstant %int 1
1354 %semantics = OpSpecConstant %int 32768
1355 %functy = OpTypeFunction %void
1356 %func = OpFunction %void None %functy
1357 %1 = OpLabel
1358 OpControlBarrier %device %device %semantics
1359 OpReturn
1360 OpFunctionEnd
1361 )";
1362
1363 CompileSuccessfully(text);
1364 EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
1365 }
1366
TEST_F(ValidateBarriers,CooperativeMatrixNonConstantSemantics)1367 TEST_F(ValidateBarriers, CooperativeMatrixNonConstantSemantics) {
1368 const std::string text = R"(
1369 OpCapability Shader
1370 OpCapability VulkanMemoryModelKHR
1371 OpCapability VulkanMemoryModelDeviceScopeKHR
1372 OpCapability CooperativeMatrixNV
1373 OpCapability Linkage
1374 OpExtension "SPV_KHR_vulkan_memory_model"
1375 OpExtension "SPV_NV_cooperative_matrix"
1376 OpMemoryModel Logical VulkanKHR
1377 %void = OpTypeVoid
1378 %int = OpTypeInt 32 0
1379 %device = OpConstant %int 1
1380 %semantics = OpUndef %int
1381 %functy = OpTypeFunction %void
1382 %func = OpFunction %void None %functy
1383 %1 = OpLabel
1384 OpControlBarrier %device %device %semantics
1385 OpReturn
1386 OpFunctionEnd
1387 )";
1388
1389 CompileSuccessfully(text);
1390 EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1391 EXPECT_THAT(getDiagnosticString(),
1392 HasSubstr("Memory Semantics must be a constant instruction when "
1393 "CooperativeMatrixNV capability is present"));
1394 }
1395
TEST_F(ValidateBarriers,OpMemoryBarrierShaderCallRayGenSuccess)1396 TEST_F(ValidateBarriers, OpMemoryBarrierShaderCallRayGenSuccess) {
1397 const std::string body =
1398 "OpMemoryBarrier %shadercall %release_uniform_workgroup";
1399
1400 CompileSuccessfully(GenerateShaderCodeImpl(body,
1401 // capabilities_and_extensions
1402 R"(
1403 OpCapability VulkanMemoryModelKHR
1404 OpCapability RayTracingKHR
1405 OpExtension "SPV_KHR_vulkan_memory_model"
1406 OpExtension "SPV_KHR_ray_tracing"
1407 )",
1408 // definitions
1409 "",
1410 // execution_model
1411 "RayGenerationKHR",
1412 // memory_model
1413 "OpMemoryModel Logical VulkanKHR"),
1414 SPV_ENV_VULKAN_1_1);
1415
1416 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
1417 }
1418
TEST_F(ValidateBarriers,OpMemoryBarrierShaderCallComputeFailure)1419 TEST_F(ValidateBarriers, OpMemoryBarrierShaderCallComputeFailure) {
1420 const std::string body =
1421 "OpMemoryBarrier %shadercall %release_uniform_workgroup";
1422
1423 CompileSuccessfully(GenerateShaderCodeImpl(body,
1424 // capabilities_and_extensions
1425 R"(
1426 OpCapability VulkanMemoryModelKHR
1427 OpExtension "SPV_KHR_vulkan_memory_model"
1428 )",
1429 // definitions
1430 "",
1431 // execution_model
1432 "GLCompute",
1433 // memory_model
1434 "OpMemoryModel Logical VulkanKHR"),
1435 SPV_ENV_VULKAN_1_1);
1436
1437 ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
1438 EXPECT_THAT(getDiagnosticString(),
1439 AnyVUID("VUID-StandaloneSpirv-None-04640"));
1440 EXPECT_THAT(
1441 getDiagnosticString(),
1442 HasSubstr(
1443 "ShaderCallKHR Memory Scope requires a ray tracing execution model"));
1444 }
1445
TEST_F(ValidateBarriers,OpControlBarrierShaderCallRayGenFailure)1446 TEST_F(ValidateBarriers, OpControlBarrierShaderCallRayGenFailure) {
1447 const std::string body = "OpControlBarrier %shadercall %shadercall %none";
1448
1449 CompileSuccessfully(GenerateShaderCodeImpl(body,
1450 // capabilities_and_extensions
1451 R"(
1452 OpCapability VulkanMemoryModelKHR
1453 OpCapability RayTracingKHR
1454 OpExtension "SPV_KHR_vulkan_memory_model"
1455 OpExtension "SPV_KHR_ray_tracing"
1456 )",
1457 // definitions
1458 "",
1459 // execution_model
1460 "RayGenerationKHR",
1461 // memory_model
1462 "OpMemoryModel Logical VulkanKHR"),
1463 SPV_ENV_VULKAN_1_1);
1464
1465 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_1));
1466 EXPECT_THAT(getDiagnosticString(),
1467 HasSubstr("in Vulkan environment Execution Scope is limited to "
1468 "Workgroup and Subgroup"));
1469 }
1470
1471 } // namespace
1472 } // namespace val
1473 } // namespace spvtools
1474