• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2018 Google Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 // Validation tests for memory/storage
16 
17 #include <string>
18 #include <vector>
19 
20 #include "gmock/gmock.h"
21 #include "test/unit_spirv.h"
22 #include "test/val/val_code_generator.h"
23 #include "test/val/val_fixtures.h"
24 
25 // For pretty-printing tuples with spv_target_env.
operator <<(std::ostream & stream,spv_target_env target)26 std::ostream& operator<<(std::ostream& stream, spv_target_env target)
27 {
28   switch (target) {
29     case SPV_ENV_UNIVERSAL_1_3: return stream << "SPV_ENV_UNIVERSAL_1_3";
30     case SPV_ENV_UNIVERSAL_1_4: return stream << "SPV_ENV_UNIVERSAL_1_4";
31     default:                    return stream << (unsigned)target;
32   }
33 }
34 
35 namespace spvtools {
36 namespace val {
37 namespace {
38 
39 using ::testing::Combine;
40 using ::testing::Eq;
41 using ::testing::HasSubstr;
42 using ::testing::Values;
43 
44 using ValidateMemory = spvtest::ValidateBase<bool>;
45 
TEST_F(ValidateMemory,VulkanUniformConstantOnNonOpaqueResourceBad)46 TEST_F(ValidateMemory, VulkanUniformConstantOnNonOpaqueResourceBad) {
47   std::string spirv = R"(
48 OpCapability Shader
49 OpMemoryModel Logical GLSL450
50 OpEntryPoint Fragment %func "func"
51 OpExecutionMode %func OriginUpperLeft
52 %float = OpTypeFloat 32
53 %float_ptr = OpTypePointer UniformConstant %float
54 %2 = OpVariable %float_ptr UniformConstant
55 %void = OpTypeVoid
56 %functy = OpTypeFunction %void
57 %func = OpFunction %void None %functy
58 %1 = OpLabel
59 OpReturn
60 OpFunctionEnd
61 )";
62   CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
63   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
64   EXPECT_THAT(getDiagnosticString(),
65               AnyVUID("VUID-StandaloneSpirv-UniformConstant-04655"));
66   EXPECT_THAT(
67       getDiagnosticString(),
68       HasSubstr("Variables identified with the UniformConstant storage class "
69                 "are used only as handles to refer to opaque resources. Such "
70                 "variables must be typed as OpTypeImage, OpTypeSampler, "
71                 "OpTypeSampledImage, OpTypeAccelerationStructureKHR, "
72                 "or an array of one of these types."));
73 }
74 
TEST_F(ValidateMemory,VulkanUniformConstantOnOpaqueResourceGood)75 TEST_F(ValidateMemory, VulkanUniformConstantOnOpaqueResourceGood) {
76   std::string spirv = R"(
77 OpCapability Shader
78 OpMemoryModel Logical GLSL450
79 OpEntryPoint Fragment %func "func"
80 OpExecutionMode %func OriginUpperLeft
81 OpDecorate %2 DescriptorSet 0
82 OpDecorate %2 Binding 0
83 %sampler = OpTypeSampler
84 %sampler_ptr = OpTypePointer UniformConstant %sampler
85 %2 = OpVariable %sampler_ptr UniformConstant
86 %void = OpTypeVoid
87 %functy = OpTypeFunction %void
88 %func = OpFunction %void None %functy
89 %1 = OpLabel
90 OpReturn
91 OpFunctionEnd
92 )";
93   CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
94   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
95 }
96 
TEST_F(ValidateMemory,VulkanUniformConstantOnNonOpaqueResourceArrayBad)97 TEST_F(ValidateMemory, VulkanUniformConstantOnNonOpaqueResourceArrayBad) {
98   std::string spirv = R"(
99 OpCapability Shader
100 OpMemoryModel Logical GLSL450
101 OpEntryPoint Fragment %func "func"
102 OpExecutionMode %func OriginUpperLeft
103 %float = OpTypeFloat 32
104 %uint = OpTypeInt 32 0
105 %array_size = OpConstant %uint 5
106 %array = OpTypeArray %float %array_size
107 %array_ptr = OpTypePointer UniformConstant %array
108 %2 = OpVariable %array_ptr UniformConstant
109 %void = OpTypeVoid
110 %functy = OpTypeFunction %void
111 %func = OpFunction %void None %functy
112 %1 = OpLabel
113 OpReturn
114 OpFunctionEnd
115 )";
116   CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
117   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
118   EXPECT_THAT(getDiagnosticString(),
119               AnyVUID("VUID-StandaloneSpirv-UniformConstant-04655"));
120   EXPECT_THAT(
121       getDiagnosticString(),
122       HasSubstr("Variables identified with the UniformConstant storage class "
123                 "are used only as handles to refer to opaque resources. Such "
124                 "variables must be typed as OpTypeImage, OpTypeSampler, "
125                 "OpTypeSampledImage, OpTypeAccelerationStructureKHR, "
126                 "or an array of one of these types."));
127 }
128 
TEST_F(ValidateMemory,VulkanUniformConstantOnOpaqueResourceArrayGood)129 TEST_F(ValidateMemory, VulkanUniformConstantOnOpaqueResourceArrayGood) {
130   std::string spirv = R"(
131 OpCapability Shader
132 OpMemoryModel Logical GLSL450
133 OpEntryPoint Fragment %func "func"
134 OpExecutionMode %func OriginUpperLeft
135 OpDecorate %2 DescriptorSet 0
136 OpDecorate %2 Binding 0
137 %sampler = OpTypeSampler
138 %uint = OpTypeInt 32 0
139 %array_size = OpConstant %uint 5
140 %array = OpTypeArray %sampler %array_size
141 %array_ptr = OpTypePointer UniformConstant %array
142 %2 = OpVariable %array_ptr UniformConstant
143 %void = OpTypeVoid
144 %functy = OpTypeFunction %void
145 %func = OpFunction %void None %functy
146 %1 = OpLabel
147 OpReturn
148 OpFunctionEnd
149 )";
150   CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
151   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
152 }
153 
TEST_F(ValidateMemory,VulkanUniformConstantOnOpaqueResourceRuntimeArrayGood)154 TEST_F(ValidateMemory, VulkanUniformConstantOnOpaqueResourceRuntimeArrayGood) {
155   std::string spirv = R"(
156 OpCapability RuntimeDescriptorArrayEXT
157 OpCapability Shader
158 OpExtension "SPV_EXT_descriptor_indexing"
159 OpMemoryModel Logical GLSL450
160 OpEntryPoint Fragment %func "func"
161 OpExecutionMode %func OriginUpperLeft
162 OpDecorate %2 DescriptorSet 0
163 OpDecorate %2 Binding 0
164 %sampler = OpTypeSampler
165 %uint = OpTypeInt 32 0
166 %array = OpTypeRuntimeArray %sampler
167 %array_ptr = OpTypePointer UniformConstant %array
168 %2 = OpVariable %array_ptr UniformConstant
169 %void = OpTypeVoid
170 %functy = OpTypeFunction %void
171 %func = OpFunction %void None %functy
172 %1 = OpLabel
173 OpReturn
174 OpFunctionEnd
175 )";
176   CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
177   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
178 }
179 
TEST_F(ValidateMemory,VulkanUniformOnIntBad)180 TEST_F(ValidateMemory, VulkanUniformOnIntBad) {
181   char src[] = R"(
182             OpCapability Shader
183             OpMemoryModel Logical GLSL450
184             OpEntryPoint GLCompute %kernel "main"
185             OpExecutionMode %kernel LocalSize 1 1 1
186 
187             OpDecorate %var DescriptorSet 0
188             OpDecorate %var Binding 0
189 
190   %voidty = OpTypeVoid
191 %kernelty = OpTypeFunction %voidty
192    %intty = OpTypeInt 32 0
193    %varty = OpTypePointer Uniform %intty
194    %value = OpConstant %intty 42
195 
196      %var = OpVariable %varty Uniform
197 
198   %kernel = OpFunction %voidty None %kernelty
199    %label = OpLabel
200             OpStore %var %value
201             OpReturn
202             OpFunctionEnd
203 )";
204   CompileSuccessfully(src, SPV_ENV_VULKAN_1_1);
205   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
206   EXPECT_THAT(
207       getDiagnosticString(),
208       HasSubstr("From Vulkan spec, section 14.5.2:\n"
209                 "Variables identified with the Uniform storage class are used "
210                 "to access transparent buffer backed resources. Such variables "
211                 "must be typed as OpTypeStruct, or an array of this type"));
212 }
213 
214 // #version 440
215 // #extension GL_EXT_nonuniform_qualifier : enable
216 // layout(binding = 1) uniform sampler2D s2d[][2];
217 // layout(location = 0) in nonuniformEXT int i;
218 // void main()
219 // {
220 //     vec4 v = texture(s2d[i][i], vec2(0.3));
221 // }
TEST_F(ValidateMemory,VulkanUniformOnRuntimeArrayOfArrayBad)222 TEST_F(ValidateMemory, VulkanUniformOnRuntimeArrayOfArrayBad) {
223   char src[] = R"(
224                OpCapability Shader
225                OpCapability ShaderNonUniformEXT
226                OpCapability RuntimeDescriptorArrayEXT
227                OpCapability SampledImageArrayNonUniformIndexingEXT
228                OpExtension "SPV_EXT_descriptor_indexing"
229           %1 = OpExtInstImport "GLSL.std.450"
230                OpMemoryModel Logical GLSL450
231                OpEntryPoint Vertex %main "main" %i
232                OpSource GLSL 440
233                OpSourceExtension "GL_EXT_nonuniform_qualifier"
234                OpName %main "main"
235                OpName %v "v"
236                OpName %s2d "s2d"
237                OpName %i "i"
238                OpDecorate %s2d DescriptorSet 0
239                OpDecorate %s2d Binding 1
240                OpDecorate %i Location 0
241                OpDecorate %i NonUniformEXT
242                OpDecorate %21 NonUniformEXT
243                OpDecorate %22 NonUniformEXT
244                OpDecorate %25 NonUniformEXT
245        %void = OpTypeVoid
246           %3 = OpTypeFunction %void
247       %float = OpTypeFloat 32
248     %v4float = OpTypeVector %float 4
249 %_ptr_Function_v4float = OpTypePointer Function %v4float
250          %10 = OpTypeImage %float 2D 0 0 0 1 Unknown
251          %11 = OpTypeSampledImage %10
252        %uint = OpTypeInt 32 0
253      %uint_2 = OpConstant %uint 2
254 %_arr_11_uint_2 = OpTypeArray %11 %uint_2
255 %_runtimearr__arr_11_uint_2 = OpTypeRuntimeArray %_arr_11_uint_2
256 %_ptr_Uniform__runtimearr__arr_11_uint_2 = OpTypePointer Uniform %_runtimearr__arr_11_uint_2
257         %s2d = OpVariable %_ptr_Uniform__runtimearr__arr_11_uint_2 Uniform
258         %int = OpTypeInt 32 1
259 %_ptr_Input_int = OpTypePointer Input %int
260           %i = OpVariable %_ptr_Input_int Input
261 %_ptr_Uniform_11 = OpTypePointer Uniform %11
262     %v2float = OpTypeVector %float 2
263 %float_0_300000012 = OpConstant %float 0.300000012
264          %28 = OpConstantComposite %v2float %float_0_300000012 %float_0_300000012
265     %float_0 = OpConstant %float 0
266        %main = OpFunction %void None %3
267           %5 = OpLabel
268           %v = OpVariable %_ptr_Function_v4float Function
269          %21 = OpLoad %int %i
270          %22 = OpLoad %int %i
271          %24 = OpAccessChain %_ptr_Uniform_11 %s2d %21 %22
272          %25 = OpLoad %11 %24
273          %30 = OpImageSampleExplicitLod %v4float %25 %28 Lod %float_0
274                OpStore %v %30
275                OpReturn
276                OpFunctionEnd
277 )";
278   CompileSuccessfully(src, SPV_ENV_VULKAN_1_1);
279   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
280   EXPECT_THAT(
281       getDiagnosticString(),
282       HasSubstr("From Vulkan spec, section 14.5.2:\n"
283                 "Variables identified with the Uniform storage class are used "
284                 "to access transparent buffer backed resources. Such variables "
285                 "must be typed as OpTypeStruct, or an array of this type"));
286 }
287 
288 // #version 440
289 // layout (set=1, binding=1) uniform sampler2D variableName[2][2];
290 // void main() {
291 // }
TEST_F(ValidateMemory,VulkanUniformOnArrayOfArrayBad)292 TEST_F(ValidateMemory, VulkanUniformOnArrayOfArrayBad) {
293   char src[] = R"(
294                OpCapability Shader
295           %1 = OpExtInstImport "GLSL.std.450"
296                OpMemoryModel Logical GLSL450
297                OpEntryPoint Vertex %main "main"
298                OpSource GLSL 440
299                OpName %main "main"
300                OpName %variableName "variableName"
301                OpDecorate %variableName DescriptorSet 1
302                OpDecorate %variableName Binding 1
303        %void = OpTypeVoid
304           %3 = OpTypeFunction %void
305       %float = OpTypeFloat 32
306           %7 = OpTypeImage %float 2D 0 0 0 1 Unknown
307           %8 = OpTypeSampledImage %7
308        %uint = OpTypeInt 32 0
309      %uint_2 = OpConstant %uint 2
310 %_arr_8_uint_2 = OpTypeArray %8 %uint_2
311 %_arr__arr_8_uint_2_uint_2 = OpTypeArray %_arr_8_uint_2 %uint_2
312 %_ptr_Uniform__arr__arr_8_uint_2_uint_2 = OpTypePointer Uniform %_arr__arr_8_uint_2_uint_2
313 %variableName = OpVariable %_ptr_Uniform__arr__arr_8_uint_2_uint_2 Uniform
314        %main = OpFunction %void None %3
315           %5 = OpLabel
316                OpReturn
317                OpFunctionEnd
318 )";
319   CompileSuccessfully(src, SPV_ENV_VULKAN_1_1);
320   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
321   EXPECT_THAT(
322       getDiagnosticString(),
323       HasSubstr("From Vulkan spec, section 14.5.2:\n"
324                 "Variables identified with the Uniform storage class are used "
325                 "to access transparent buffer backed resources. Such variables "
326                 "must be typed as OpTypeStruct, or an array of this type"));
327 }
328 
TEST_F(ValidateMemory,MismatchingStorageClassesBad)329 TEST_F(ValidateMemory, MismatchingStorageClassesBad) {
330   std::string spirv = R"(
331 OpCapability Shader
332 OpMemoryModel Logical GLSL450
333 OpEntryPoint Fragment %func "func"
334 OpExecutionMode %func OriginUpperLeft
335 %float = OpTypeFloat 32
336 %float_ptr = OpTypePointer Uniform %float
337 %void = OpTypeVoid
338 %functy = OpTypeFunction %void
339 %func = OpFunction %void None %functy
340 %1 = OpLabel
341 %2 = OpVariable %float_ptr Function
342 OpReturn
343 OpFunctionEnd
344 )";
345   CompileSuccessfully(spirv.c_str());
346   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
347   EXPECT_THAT(
348       getDiagnosticString(),
349       HasSubstr(
350           "From SPIR-V spec, section 3.32.8 on OpVariable:\n"
351           "Its Storage Class operand must be the same as the Storage Class "
352           "operand of the result type."));
353 }
354 
TEST_F(ValidateMemory,MatchingStorageClassesGood)355 TEST_F(ValidateMemory, MatchingStorageClassesGood) {
356   std::string spirv = R"(
357 OpCapability Shader
358 OpMemoryModel Logical GLSL450
359 OpEntryPoint Fragment %func "func"
360 OpExecutionMode %func OriginUpperLeft
361 %float = OpTypeFloat 32
362 %float_ptr = OpTypePointer Function %float
363 %void = OpTypeVoid
364 %functy = OpTypeFunction %void
365 %func = OpFunction %void None %functy
366 %1 = OpLabel
367 %2 = OpVariable %float_ptr Function
368 OpReturn
369 OpFunctionEnd
370 )";
371   CompileSuccessfully(spirv.c_str());
372   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
373 }
374 
TEST_F(ValidateMemory,VulkanInitializerWithOutputStorageClassesGood)375 TEST_F(ValidateMemory, VulkanInitializerWithOutputStorageClassesGood) {
376   std::string spirv = R"(
377 OpCapability Shader
378 OpMemoryModel Logical GLSL450
379 OpEntryPoint Fragment %func "func"
380 OpExecutionMode %func OriginUpperLeft
381 %float = OpTypeFloat 32
382 %float_ptr = OpTypePointer Output %float
383 %init_val = OpConstant %float 1.0
384 %1 = OpVariable %float_ptr Output %init_val
385 %void = OpTypeVoid
386 %functy = OpTypeFunction %void
387 %func = OpFunction %void None %functy
388 %2 = OpLabel
389 OpReturn
390 OpFunctionEnd
391 )";
392   CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
393   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
394 }
395 
TEST_F(ValidateMemory,VulkanInitializerWithFunctionStorageClassesGood)396 TEST_F(ValidateMemory, VulkanInitializerWithFunctionStorageClassesGood) {
397   std::string spirv = R"(
398 OpCapability Shader
399 OpMemoryModel Logical GLSL450
400 OpEntryPoint Fragment %func "func"
401 OpExecutionMode %func OriginUpperLeft
402 %float = OpTypeFloat 32
403 %float_ptr = OpTypePointer Function %float
404 %init_val = OpConstant %float 1.0
405 %void = OpTypeVoid
406 %functy = OpTypeFunction %void
407 %func = OpFunction %void None %functy
408 %1 = OpLabel
409 %2 = OpVariable %float_ptr Function %init_val
410 OpReturn
411 OpFunctionEnd
412 )";
413   CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
414   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
415 }
416 
TEST_F(ValidateMemory,VulkanInitializerWithPrivateStorageClassesGood)417 TEST_F(ValidateMemory, VulkanInitializerWithPrivateStorageClassesGood) {
418   std::string spirv = R"(
419 OpCapability Shader
420 OpMemoryModel Logical GLSL450
421 OpEntryPoint Fragment %func "func"
422 OpExecutionMode %func OriginUpperLeft
423 %float = OpTypeFloat 32
424 %float_ptr = OpTypePointer Private %float
425 %init_val = OpConstant %float 1.0
426 %1 = OpVariable %float_ptr Private %init_val
427 %void = OpTypeVoid
428 %functy = OpTypeFunction %void
429 %func = OpFunction %void None %functy
430 %2 = OpLabel
431 OpReturn
432 OpFunctionEnd
433 )";
434   CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
435   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
436 }
437 
TEST_F(ValidateMemory,VulkanInitializerWithDisallowedStorageClassesBad)438 TEST_F(ValidateMemory, VulkanInitializerWithDisallowedStorageClassesBad) {
439   std::string spirv = R"(
440 OpCapability Shader
441 OpMemoryModel Logical GLSL450
442 OpEntryPoint Fragment %func "func"
443 OpExecutionMode %func OriginUpperLeft
444 %float = OpTypeFloat 32
445 %float_ptr = OpTypePointer Input %float
446 %init_val = OpConstant %float 1.0
447 %1 = OpVariable %float_ptr Input %init_val
448 %void = OpTypeVoid
449 %functy = OpTypeFunction %void
450 %func = OpFunction %void None %functy
451 %2 = OpLabel
452 OpReturn
453 OpFunctionEnd
454 )";
455   CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
456   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
457   EXPECT_THAT(getDiagnosticString(),
458               AnyVUID("VUID-StandaloneSpirv-OpVariable-04651"));
459   EXPECT_THAT(
460       getDiagnosticString(),
461       HasSubstr("OpVariable, <id> '5[%5]', has a disallowed initializer & "
462                 "storage class combination.\nFrom Vulkan spec:\nVariable "
463                 "declarations that include initializers must have one of the "
464                 "following storage classes: Output, Private, Function or "
465                 "Workgroup\n  %5 "
466                 "= OpVariable %_ptr_Input_float Input %float_1\n"));
467 }
468 
TEST_F(ValidateMemory,ArrayLenCorrectResultType)469 TEST_F(ValidateMemory, ArrayLenCorrectResultType) {
470   std::string spirv = R"(
471                OpCapability Shader
472                OpMemoryModel Logical GLSL450
473                OpEntryPoint Fragment %1 "main"
474                OpExecutionMode %1 OriginUpperLeft
475        %void = OpTypeVoid
476           %3 = OpTypeFunction %void
477       %float = OpTypeFloat 32
478      %uint = OpTypeInt 32 0
479 %_runtimearr_float = OpTypeRuntimeArray %float
480   %_struct_7 = OpTypeStruct %_runtimearr_float
481 %_ptr_Function__struct_7 = OpTypePointer Function %_struct_7
482           %1 = OpFunction %void None %3
483           %9 = OpLabel
484          %10 = OpVariable %_ptr_Function__struct_7 Function
485          %11 = OpArrayLength %uint %10 0
486                OpReturn
487                OpFunctionEnd
488 
489 )";
490 
491   CompileSuccessfully(spirv.c_str());
492   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
493 }
494 
TEST_F(ValidateMemory,ArrayLenIndexCorrectWith2Members)495 TEST_F(ValidateMemory, ArrayLenIndexCorrectWith2Members) {
496   std::string spirv = R"(
497                OpCapability Shader
498                OpMemoryModel Logical GLSL450
499                OpEntryPoint Fragment %1 "main"
500                OpExecutionMode %1 OriginUpperLeft
501        %void = OpTypeVoid
502           %3 = OpTypeFunction %void
503       %float = OpTypeFloat 32
504      %uint = OpTypeInt 32 0
505 %_runtimearr_float = OpTypeRuntimeArray %float
506   %_struct_7 = OpTypeStruct %float %_runtimearr_float
507 %_ptr_Function__struct_7  = OpTypePointer Function %_struct_7
508           %1 = OpFunction %void None %3
509           %9 = OpLabel
510          %10 = OpVariable %_ptr_Function__struct_7  Function
511          %11 = OpArrayLength %uint %10 1
512                OpReturn
513                OpFunctionEnd
514 
515 )";
516 
517   CompileSuccessfully(spirv.c_str());
518   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
519 }
520 
TEST_F(ValidateMemory,ArrayLenResultNotIntType)521 TEST_F(ValidateMemory, ArrayLenResultNotIntType) {
522   std::string spirv = R"(
523                OpCapability Shader
524                OpMemoryModel Logical GLSL450
525                OpEntryPoint Fragment %1 "main"
526                OpExecutionMode %1 OriginUpperLeft
527        %void = OpTypeVoid
528           %3 = OpTypeFunction %void
529       %float = OpTypeFloat 32
530 %_runtimearr_float = OpTypeRuntimeArray %float
531   %_struct_6 = OpTypeStruct %_runtimearr_float
532 %_ptr_Function__struct_6 = OpTypePointer Function %_struct_6
533           %1 = OpFunction %void None %3
534           %8 = OpLabel
535           %9 = OpVariable %_ptr_Function__struct_6 Function
536          %10 = OpArrayLength %float %9 0
537                OpReturn
538                OpFunctionEnd
539 )";
540 
541   CompileSuccessfully(spirv.c_str());
542   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
543   EXPECT_THAT(
544       getDiagnosticString(),
545       HasSubstr(
546           "The Result Type of OpArrayLength <id> '10[%10]' must be OpTypeInt "
547           "with width 32 and signedness 0.\n  %10 = OpArrayLength %float %9 "
548           "0\n"));
549 }
550 
TEST_F(ValidateMemory,ArrayLenResultNot32bits)551 TEST_F(ValidateMemory, ArrayLenResultNot32bits) {
552   std::string spirv = R"(
553                OpCapability Shader
554                OpCapability Int16
555                OpMemoryModel Logical GLSL450
556                OpEntryPoint Fragment %1 "main"
557                OpExecutionMode %1 OriginUpperLeft
558        %void = OpTypeVoid
559           %3 = OpTypeFunction %void
560       %float = OpTypeFloat 32
561      %ushort = OpTypeInt 16 0
562 %_runtimearr_float = OpTypeRuntimeArray %float
563   %_struct_7 = OpTypeStruct %_runtimearr_float
564 %_ptr_Function__struct_7 = OpTypePointer Function %_struct_7
565           %1 = OpFunction %void None %3
566           %9 = OpLabel
567          %10 = OpVariable %_ptr_Function__struct_7 Function
568          %11 = OpArrayLength %ushort %10 0
569                OpReturn
570                OpFunctionEnd
571 
572 )";
573 
574   CompileSuccessfully(spirv.c_str());
575   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
576   EXPECT_THAT(
577       getDiagnosticString(),
578       HasSubstr(
579           "The Result Type of OpArrayLength <id> '11[%11]' must be OpTypeInt "
580           "with width 32 and signedness 0.\n  %11 = OpArrayLength %ushort %10 "
581           "0\n"));
582 }
583 
TEST_F(ValidateMemory,ArrayLenResultSigned)584 TEST_F(ValidateMemory, ArrayLenResultSigned) {
585   std::string spirv = R"(
586                OpCapability Shader
587                OpMemoryModel Logical GLSL450
588                OpEntryPoint Fragment %1 "main"
589                OpExecutionMode %1 OriginUpperLeft
590        %void = OpTypeVoid
591           %3 = OpTypeFunction %void
592       %float = OpTypeFloat 32
593      %int = OpTypeInt 32 1
594 %_runtimearr_float = OpTypeRuntimeArray %float
595   %_struct_7 = OpTypeStruct %_runtimearr_float
596 %_ptr_Function__struct_7 = OpTypePointer Function %_struct_7
597           %1 = OpFunction %void None %3
598           %9 = OpLabel
599          %10 = OpVariable %_ptr_Function__struct_7 Function
600          %11 = OpArrayLength %int %10 0
601                OpReturn
602                OpFunctionEnd
603 
604 )";
605 
606   CompileSuccessfully(spirv.c_str());
607   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
608   EXPECT_THAT(
609       getDiagnosticString(),
610       HasSubstr(
611           "The Result Type of OpArrayLength <id> '11[%11]' must be OpTypeInt "
612           "with width 32 and signedness 0.\n  %11 = OpArrayLength %int %10 "
613           "0\n"));
614 }
615 
TEST_F(ValidateMemory,ArrayLenInputNotStruct)616 TEST_F(ValidateMemory, ArrayLenInputNotStruct) {
617   std::string spirv = R"(
618                OpCapability Shader
619                OpMemoryModel Logical GLSL450
620                OpEntryPoint Fragment %1 "main"
621                OpExecutionMode %1 OriginUpperLeft
622        %void = OpTypeVoid
623           %3 = OpTypeFunction %void
624       %float = OpTypeFloat 32
625      %uint = OpTypeInt 32 0
626 %_runtimearr_float = OpTypeRuntimeArray %float
627   %_struct_7 = OpTypeStruct %_runtimearr_float
628 %_ptr_Function_float = OpTypePointer Function %float
629           %1 = OpFunction %void None %3
630           %9 = OpLabel
631          %10 = OpVariable %_ptr_Function_float Function
632          %11 = OpArrayLength %uint %10 0
633                OpReturn
634                OpFunctionEnd
635 
636 )";
637 
638   CompileSuccessfully(spirv.c_str());
639   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
640   EXPECT_THAT(getDiagnosticString(),
641               HasSubstr("The Struture's type in OpArrayLength <id> '11[%11]' "
642                         "must be a pointer to an OpTypeStruct."));
643 }
644 
TEST_F(ValidateMemory,ArrayLenInputLastMemberNoRTA)645 TEST_F(ValidateMemory, ArrayLenInputLastMemberNoRTA) {
646   std::string spirv = R"(
647                OpCapability Shader
648                OpMemoryModel Logical GLSL450
649                OpEntryPoint Fragment %1 "main"
650                OpExecutionMode %1 OriginUpperLeft
651        %void = OpTypeVoid
652           %3 = OpTypeFunction %void
653       %float = OpTypeFloat 32
654      %uint = OpTypeInt 32 0
655 %_runtimearr_float = OpTypeRuntimeArray %float
656   %_struct_7 = OpTypeStruct %float
657 %_ptr_Function__struct_7  = OpTypePointer Function %_struct_7
658           %1 = OpFunction %void None %3
659           %9 = OpLabel
660          %10 = OpVariable %_ptr_Function__struct_7  Function
661          %11 = OpArrayLength %uint %10 0
662                OpReturn
663                OpFunctionEnd
664 
665 )";
666 
667   CompileSuccessfully(spirv.c_str());
668   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
669   EXPECT_THAT(
670       getDiagnosticString(),
671       HasSubstr("The Struture's last member in OpArrayLength <id> '11[%11]' "
672                 "must be an OpTypeRuntimeArray.\n  %11 = OpArrayLength %uint "
673                 "%10 0\n"));
674 }
675 
TEST_F(ValidateMemory,ArrayLenInputLastMemberNoRTA2)676 TEST_F(ValidateMemory, ArrayLenInputLastMemberNoRTA2) {
677   std::string spirv = R"(
678                OpCapability Shader
679                OpMemoryModel Logical GLSL450
680                OpEntryPoint Fragment %1 "main"
681                OpExecutionMode %1 OriginUpperLeft
682        %void = OpTypeVoid
683           %3 = OpTypeFunction %void
684       %float = OpTypeFloat 32
685      %uint = OpTypeInt 32 0
686 %_runtimearr_float = OpTypeRuntimeArray %float
687   %_struct_7 = OpTypeStruct %_runtimearr_float %float
688 %_ptr_Function__struct_7  = OpTypePointer Function %_struct_7
689           %1 = OpFunction %void None %3
690           %9 = OpLabel
691          %10 = OpVariable %_ptr_Function__struct_7  Function
692          %11 = OpArrayLength %uint %10 1
693                OpReturn
694                OpFunctionEnd
695 
696 )";
697 
698   CompileSuccessfully(spirv.c_str());
699   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
700   EXPECT_THAT(
701       getDiagnosticString(),
702       HasSubstr("The Struture's last member in OpArrayLength <id> '11[%11]' "
703                 "must be an OpTypeRuntimeArray.\n  %11 = OpArrayLength %uint "
704                 "%10 1\n"));
705 }
706 
TEST_F(ValidateMemory,ArrayLenIndexNotLastMember)707 TEST_F(ValidateMemory, ArrayLenIndexNotLastMember) {
708   std::string spirv = R"(
709                OpCapability Shader
710                OpMemoryModel Logical GLSL450
711                OpEntryPoint Fragment %1 "main"
712                OpExecutionMode %1 OriginUpperLeft
713        %void = OpTypeVoid
714           %3 = OpTypeFunction %void
715       %float = OpTypeFloat 32
716      %uint = OpTypeInt 32 0
717 %_runtimearr_float = OpTypeRuntimeArray %float
718   %_struct_7 = OpTypeStruct %float %_runtimearr_float
719 %_ptr_Function__struct_7  = OpTypePointer Function %_struct_7
720           %1 = OpFunction %void None %3
721           %9 = OpLabel
722          %10 = OpVariable %_ptr_Function__struct_7  Function
723          %11 = OpArrayLength %uint %10 0
724                OpReturn
725                OpFunctionEnd
726 
727 )";
728 
729   CompileSuccessfully(spirv.c_str());
730   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
731   EXPECT_THAT(
732       getDiagnosticString(),
733       HasSubstr(
734           "The array member in OpArrayLength <id> '11[%11]' must be an the "
735           "last member of the struct.\n  %11 = OpArrayLength %uint %10 0\n"));
736 }
737 
TEST_F(ValidateMemory,ArrayLenIndexNotPointerToStruct)738 TEST_F(ValidateMemory, ArrayLenIndexNotPointerToStruct) {
739   std::string spirv = R"(
740                OpCapability Shader
741                OpMemoryModel Logical GLSL450
742                OpEntryPoint Fragment %1 "main"
743                OpExecutionMode %1 OriginUpperLeft
744        %void = OpTypeVoid
745           %3 = OpTypeFunction %void
746       %float = OpTypeFloat 32
747      %uint = OpTypeInt 32 0
748 %_runtimearr_float = OpTypeRuntimeArray %float
749   %_struct_7 = OpTypeStruct %float %_runtimearr_float
750 %_ptr_Function__struct_7  = OpTypePointer Function %_struct_7
751           %1 = OpFunction %void None %3
752           %9 = OpLabel
753          %10 = OpVariable %_ptr_Function__struct_7  Function
754          %11 = OpLoad %_struct_7 %10
755          %12 = OpArrayLength %uint %11 0
756                OpReturn
757                OpFunctionEnd
758 
759 )";
760 
761   CompileSuccessfully(spirv.c_str());
762   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
763   EXPECT_THAT(
764       getDiagnosticString(),
765       HasSubstr(
766           "The Struture's type in OpArrayLength <id> '12[%12]' must be a "
767           "pointer to an OpTypeStruct.\n  %12 = OpArrayLength %uint %11 0\n"));
768 }
769 
TEST_F(ValidateMemory,ArrayLenPointerIsAType)770 TEST_F(ValidateMemory, ArrayLenPointerIsAType) {
771   std::string spirv = R"(
772                OpCapability Shader
773                OpMemoryModel Logical GLSL450
774                OpEntryPoint Fragment %1 "main"
775                OpExecutionMode %1 OriginUpperLeft
776        %void = OpTypeVoid
777           %3 = OpTypeFunction %void
778       %float = OpTypeFloat 32
779        %uint = OpTypeInt 32 0
780           %1 = OpFunction %void None %3
781           %9 = OpLabel
782          %12 = OpArrayLength %uint %float 0
783                OpReturn
784                OpFunctionEnd
785 
786 )";
787 
788   CompileSuccessfully(spirv.c_str());
789   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
790   EXPECT_THAT(getDiagnosticString(), HasSubstr("Operand 4[%float] cannot be a "
791                                                "type"));
792 }
793 
TEST_F(ValidateMemory,PushConstantNotStructGood)794 TEST_F(ValidateMemory, PushConstantNotStructGood) {
795   std::string spirv = R"(
796             OpCapability Shader
797             OpMemoryModel Logical GLSL450
798             OpEntryPoint Fragment %1 "main"
799             OpExecutionMode %1 OriginUpperLeft
800 
801     %void = OpTypeVoid
802   %voidfn = OpTypeFunction %void
803    %float = OpTypeFloat 32
804      %ptr = OpTypePointer PushConstant %float
805       %pc = OpVariable %ptr PushConstant
806 
807        %1 = OpFunction %void None %voidfn
808    %label = OpLabel
809             OpReturn
810             OpFunctionEnd
811 )";
812   CompileSuccessfully(spirv);
813   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
814 }
815 
TEST_F(ValidateMemory,VulkanPushConstantNotStructBad)816 TEST_F(ValidateMemory, VulkanPushConstantNotStructBad) {
817   std::string spirv = R"(
818             OpCapability Shader
819             OpMemoryModel Logical GLSL450
820             OpEntryPoint Fragment %1 "main"
821             OpExecutionMode %1 OriginUpperLeft
822 
823     %void = OpTypeVoid
824   %voidfn = OpTypeFunction %void
825    %float = OpTypeFloat 32
826      %ptr = OpTypePointer PushConstant %float
827       %pc = OpVariable %ptr PushConstant
828 
829        %1 = OpFunction %void None %voidfn
830    %label = OpLabel
831             OpReturn
832             OpFunctionEnd
833 )";
834   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
835   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
836   EXPECT_THAT(getDiagnosticString(),
837               HasSubstr("PushConstant OpVariable <id> '6[%6]' has illegal "
838                         "type.\nFrom Vulkan spec, section 14.5.1:\n"
839                         "Such variables must be typed as OpTypeStruct, "
840                         "or an array of this type"));
841 }
842 
TEST_F(ValidateMemory,VulkanPushConstant)843 TEST_F(ValidateMemory, VulkanPushConstant) {
844   std::string spirv = R"(
845             OpCapability Shader
846             OpMemoryModel Logical GLSL450
847             OpEntryPoint Fragment %1 "main"
848             OpExecutionMode %1 OriginUpperLeft
849 
850             OpDecorate %struct Block
851             OpMemberDecorate %struct 0 Offset 0
852 
853     %void = OpTypeVoid
854   %voidfn = OpTypeFunction %void
855    %float = OpTypeFloat 32
856   %struct = OpTypeStruct %float
857      %ptr = OpTypePointer PushConstant %struct
858       %pc = OpVariable %ptr PushConstant
859 
860        %1 = OpFunction %void None %voidfn
861    %label = OpLabel
862             OpReturn
863             OpFunctionEnd
864 )";
865   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
866   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
867 }
868 
TEST_F(ValidateMemory,VulkanMemoryModelDeviceScopeLoadBad1)869 TEST_F(ValidateMemory, VulkanMemoryModelDeviceScopeLoadBad1) {
870   const std::string spirv = R"(
871 OpCapability Shader
872 OpCapability VulkanMemoryModelKHR
873 OpCapability Linkage
874 OpExtension "SPV_KHR_vulkan_memory_model"
875 OpMemoryModel Logical VulkanKHR
876 %void = OpTypeVoid
877 %int = OpTypeInt 32 0
878 %device = OpConstant %int 1
879 %int_ptr_ssbo = OpTypePointer StorageBuffer %int
880 %var = OpVariable %int_ptr_ssbo StorageBuffer
881 %voidfn = OpTypeFunction %void
882 %func = OpFunction %void None %voidfn
883 %entry = OpLabel
884 %load = OpLoad %int %var MakePointerVisibleKHR|NonPrivatePointerKHR %device
885 OpReturn
886 OpFunctionEnd
887 )";
888 
889   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
890   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
891             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
892   EXPECT_THAT(
893       getDiagnosticString(),
894       HasSubstr("Use of device scope with VulkanKHR memory model requires the "
895                 "VulkanMemoryModelDeviceScopeKHR capability"));
896 }
897 
TEST_F(ValidateMemory,VulkanMemoryModelDeviceScopeLoadBad2)898 TEST_F(ValidateMemory, VulkanMemoryModelDeviceScopeLoadBad2) {
899   const std::string spirv = R"(
900 OpCapability Shader
901 OpCapability VulkanMemoryModelKHR
902 OpCapability Linkage
903 OpExtension "SPV_KHR_vulkan_memory_model"
904 OpMemoryModel Logical VulkanKHR
905 %void = OpTypeVoid
906 %int = OpTypeInt 32 0
907 %device = OpConstant %int 1
908 %int_ptr_ssbo = OpTypePointer StorageBuffer %int
909 %var = OpVariable %int_ptr_ssbo StorageBuffer
910 %voidfn = OpTypeFunction %void
911 %func = OpFunction %void None %voidfn
912 %entry = OpLabel
913 %load = OpLoad %int %var Aligned|MakePointerVisibleKHR|NonPrivatePointerKHR 4 %device
914 OpReturn
915 OpFunctionEnd
916 )";
917 
918   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
919   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
920             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
921   EXPECT_THAT(
922       getDiagnosticString(),
923       HasSubstr("Use of device scope with VulkanKHR memory model requires the "
924                 "VulkanMemoryModelDeviceScopeKHR capability"));
925 }
926 
TEST_F(ValidateMemory,VulkanMemoryModelDeviceScopeLoadGood1)927 TEST_F(ValidateMemory, VulkanMemoryModelDeviceScopeLoadGood1) {
928   const std::string spirv = R"(
929 OpCapability Shader
930 OpCapability VulkanMemoryModelKHR
931 OpCapability VulkanMemoryModelDeviceScopeKHR
932 OpCapability Linkage
933 OpExtension "SPV_KHR_vulkan_memory_model"
934 OpMemoryModel Logical VulkanKHR
935 %void = OpTypeVoid
936 %int = OpTypeInt 32 0
937 %device = OpConstant %int 1
938 %int_ptr_ssbo = OpTypePointer StorageBuffer %int
939 %var = OpVariable %int_ptr_ssbo StorageBuffer
940 %voidfn = OpTypeFunction %void
941 %func = OpFunction %void None %voidfn
942 %entry = OpLabel
943 %load = OpLoad %int %var MakePointerVisibleKHR|NonPrivatePointerKHR %device
944 OpReturn
945 OpFunctionEnd
946 )";
947 
948   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
949   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
950 }
951 
TEST_F(ValidateMemory,VulkanMemoryModelDeviceScopeLoadGood2)952 TEST_F(ValidateMemory, VulkanMemoryModelDeviceScopeLoadGood2) {
953   const std::string spirv = R"(
954 OpCapability Shader
955 OpCapability VulkanMemoryModelKHR
956 OpCapability VulkanMemoryModelDeviceScopeKHR
957 OpCapability Linkage
958 OpExtension "SPV_KHR_vulkan_memory_model"
959 OpMemoryModel Logical VulkanKHR
960 %void = OpTypeVoid
961 %int = OpTypeInt 32 0
962 %device = OpConstant %int 1
963 %int_ptr_ssbo = OpTypePointer StorageBuffer %int
964 %var = OpVariable %int_ptr_ssbo StorageBuffer
965 %voidfn = OpTypeFunction %void
966 %func = OpFunction %void None %voidfn
967 %entry = OpLabel
968 %load = OpLoad %int %var Aligned|MakePointerVisibleKHR|NonPrivatePointerKHR 4 %device
969 OpReturn
970 OpFunctionEnd
971 )";
972 
973   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
974   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
975 }
976 
TEST_F(ValidateMemory,VulkanMemoryModelDeviceScopeStoreBad1)977 TEST_F(ValidateMemory, VulkanMemoryModelDeviceScopeStoreBad1) {
978   const std::string spirv = R"(
979 OpCapability Shader
980 OpCapability VulkanMemoryModelKHR
981 OpCapability Linkage
982 OpExtension "SPV_KHR_vulkan_memory_model"
983 OpMemoryModel Logical VulkanKHR
984 %void = OpTypeVoid
985 %int = OpTypeInt 32 0
986 %device = OpConstant %int 1
987 %int_ptr_ssbo = OpTypePointer StorageBuffer %int
988 %var = OpVariable %int_ptr_ssbo StorageBuffer
989 %voidfn = OpTypeFunction %void
990 %func = OpFunction %void None %voidfn
991 %entry = OpLabel
992 OpStore %var %device MakePointerAvailableKHR|NonPrivatePointerKHR %device
993 OpReturn
994 OpFunctionEnd
995 )";
996 
997   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
998   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
999             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1000   EXPECT_THAT(
1001       getDiagnosticString(),
1002       HasSubstr("Use of device scope with VulkanKHR memory model requires the "
1003                 "VulkanMemoryModelDeviceScopeKHR capability"));
1004 }
1005 
TEST_F(ValidateMemory,VulkanMemoryModelDeviceScopeStoreBad2)1006 TEST_F(ValidateMemory, VulkanMemoryModelDeviceScopeStoreBad2) {
1007   const std::string spirv = R"(
1008 OpCapability Shader
1009 OpCapability VulkanMemoryModelKHR
1010 OpCapability Linkage
1011 OpExtension "SPV_KHR_vulkan_memory_model"
1012 OpMemoryModel Logical VulkanKHR
1013 %void = OpTypeVoid
1014 %int = OpTypeInt 32 0
1015 %device = OpConstant %int 1
1016 %int_ptr_ssbo = OpTypePointer StorageBuffer %int
1017 %var = OpVariable %int_ptr_ssbo StorageBuffer
1018 %voidfn = OpTypeFunction %void
1019 %func = OpFunction %void None %voidfn
1020 %entry = OpLabel
1021 OpStore %var %device Aligned|MakePointerAvailableKHR|NonPrivatePointerKHR 4 %device
1022 OpReturn
1023 OpFunctionEnd
1024 )";
1025 
1026   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
1027   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
1028             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1029   EXPECT_THAT(
1030       getDiagnosticString(),
1031       HasSubstr("Use of device scope with VulkanKHR memory model requires the "
1032                 "VulkanMemoryModelDeviceScopeKHR capability"));
1033 }
1034 
TEST_F(ValidateMemory,VulkanMemoryModelDeviceScopeStoreGood1)1035 TEST_F(ValidateMemory, VulkanMemoryModelDeviceScopeStoreGood1) {
1036   const std::string spirv = R"(
1037 OpCapability Shader
1038 OpCapability VulkanMemoryModelKHR
1039 OpCapability VulkanMemoryModelDeviceScopeKHR
1040 OpCapability Linkage
1041 OpExtension "SPV_KHR_vulkan_memory_model"
1042 OpMemoryModel Logical VulkanKHR
1043 %void = OpTypeVoid
1044 %int = OpTypeInt 32 0
1045 %device = OpConstant %int 1
1046 %int_ptr_ssbo = OpTypePointer StorageBuffer %int
1047 %var = OpVariable %int_ptr_ssbo StorageBuffer
1048 %voidfn = OpTypeFunction %void
1049 %func = OpFunction %void None %voidfn
1050 %entry = OpLabel
1051 OpStore %var %device MakePointerAvailableKHR|NonPrivatePointerKHR %device
1052 OpReturn
1053 OpFunctionEnd
1054 )";
1055 
1056   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
1057   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1058 }
1059 
TEST_F(ValidateMemory,VulkanMemoryModelDeviceScopeStoreGood2)1060 TEST_F(ValidateMemory, VulkanMemoryModelDeviceScopeStoreGood2) {
1061   const std::string spirv = R"(
1062 OpCapability Shader
1063 OpCapability VulkanMemoryModelKHR
1064 OpCapability VulkanMemoryModelDeviceScopeKHR
1065 OpCapability Linkage
1066 OpExtension "SPV_KHR_vulkan_memory_model"
1067 OpMemoryModel Logical VulkanKHR
1068 %void = OpTypeVoid
1069 %int = OpTypeInt 32 0
1070 %device = OpConstant %int 1
1071 %int_ptr_ssbo = OpTypePointer StorageBuffer %int
1072 %var = OpVariable %int_ptr_ssbo StorageBuffer
1073 %voidfn = OpTypeFunction %void
1074 %func = OpFunction %void None %voidfn
1075 %entry = OpLabel
1076 OpStore %var %device Aligned|MakePointerAvailableKHR|NonPrivatePointerKHR 4 %device
1077 OpReturn
1078 OpFunctionEnd
1079 )";
1080 
1081   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
1082   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1083 }
1084 
TEST_F(ValidateMemory,VulkanMemoryModelDeviceScopeCopyMemoryBad1)1085 TEST_F(ValidateMemory, VulkanMemoryModelDeviceScopeCopyMemoryBad1) {
1086   const std::string spirv = R"(
1087 OpCapability Shader
1088 OpCapability VulkanMemoryModelKHR
1089 OpCapability Linkage
1090 OpExtension "SPV_KHR_vulkan_memory_model"
1091 OpMemoryModel Logical VulkanKHR
1092 %void = OpTypeVoid
1093 %int = OpTypeInt 32 0
1094 %device = OpConstant %int 1
1095 %int_ptr_ssbo = OpTypePointer StorageBuffer %int
1096 %var1 = OpVariable %int_ptr_ssbo StorageBuffer
1097 %var2 = OpVariable %int_ptr_ssbo StorageBuffer
1098 %voidfn = OpTypeFunction %void
1099 %func = OpFunction %void None %voidfn
1100 %entry = OpLabel
1101 OpCopyMemory %var1 %var2 MakePointerAvailableKHR|NonPrivatePointerKHR %device
1102 OpReturn
1103 OpFunctionEnd
1104 )";
1105 
1106   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
1107   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
1108             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1109   EXPECT_THAT(
1110       getDiagnosticString(),
1111       HasSubstr("Use of device scope with VulkanKHR memory model requires the "
1112                 "VulkanMemoryModelDeviceScopeKHR capability"));
1113 }
1114 
TEST_F(ValidateMemory,VulkanMemoryModelDeviceScopeCopyMemoryBad2)1115 TEST_F(ValidateMemory, VulkanMemoryModelDeviceScopeCopyMemoryBad2) {
1116   const std::string spirv = R"(
1117 OpCapability Shader
1118 OpCapability VulkanMemoryModelKHR
1119 OpCapability Linkage
1120 OpExtension "SPV_KHR_vulkan_memory_model"
1121 OpMemoryModel Logical VulkanKHR
1122 %void = OpTypeVoid
1123 %int = OpTypeInt 32 0
1124 %device = OpConstant %int 1
1125 %workgroup = OpConstant %int 1
1126 %int_ptr_ssbo = OpTypePointer StorageBuffer %int
1127 %var1 = OpVariable %int_ptr_ssbo StorageBuffer
1128 %var2 = OpVariable %int_ptr_ssbo StorageBuffer
1129 %voidfn = OpTypeFunction %void
1130 %func = OpFunction %void None %voidfn
1131 %entry = OpLabel
1132 OpCopyMemory %var1 %var2 Aligned|MakePointerVisibleKHR|MakePointerAvailableKHR|NonPrivatePointerKHR 4 %device %workgroup
1133 OpReturn
1134 OpFunctionEnd
1135 )";
1136 
1137   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
1138   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
1139             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1140   EXPECT_THAT(
1141       getDiagnosticString(),
1142       HasSubstr("Use of device scope with VulkanKHR memory model requires the "
1143                 "VulkanMemoryModelDeviceScopeKHR capability"));
1144 }
1145 
TEST_F(ValidateMemory,VulkanMemoryModelDeviceScopeCopyMemoryBad3)1146 TEST_F(ValidateMemory, VulkanMemoryModelDeviceScopeCopyMemoryBad3) {
1147   const std::string spirv = R"(
1148 OpCapability Shader
1149 OpCapability VulkanMemoryModelKHR
1150 OpCapability Linkage
1151 OpExtension "SPV_KHR_vulkan_memory_model"
1152 OpMemoryModel Logical VulkanKHR
1153 %void = OpTypeVoid
1154 %int = OpTypeInt 32 0
1155 %device = OpConstant %int 1
1156 %workgroup = OpConstant %int 1
1157 %int_ptr_ssbo = OpTypePointer StorageBuffer %int
1158 %var1 = OpVariable %int_ptr_ssbo StorageBuffer
1159 %var2 = OpVariable %int_ptr_ssbo StorageBuffer
1160 %voidfn = OpTypeFunction %void
1161 %func = OpFunction %void None %voidfn
1162 %entry = OpLabel
1163 OpCopyMemory %var1 %var2 Aligned|MakePointerVisibleKHR|MakePointerAvailableKHR|NonPrivatePointerKHR 4 %workgroup %device
1164 OpReturn
1165 OpFunctionEnd
1166 )";
1167 
1168   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
1169   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
1170             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1171   EXPECT_THAT(
1172       getDiagnosticString(),
1173       HasSubstr("Use of device scope with VulkanKHR memory model requires the "
1174                 "VulkanMemoryModelDeviceScopeKHR capability"));
1175 }
1176 
TEST_F(ValidateMemory,VulkanMemoryModelDeviceScopeCopyMemoryGood2)1177 TEST_F(ValidateMemory, VulkanMemoryModelDeviceScopeCopyMemoryGood2) {
1178   const std::string spirv = R"(
1179 OpCapability Shader
1180 OpCapability VulkanMemoryModelKHR
1181 OpCapability VulkanMemoryModelDeviceScopeKHR
1182 OpCapability Linkage
1183 OpExtension "SPV_KHR_vulkan_memory_model"
1184 OpMemoryModel Logical VulkanKHR
1185 %void = OpTypeVoid
1186 %int = OpTypeInt 32 0
1187 %device = OpConstant %int 1
1188 %workgroup = OpConstant %int 2
1189 %int_ptr_ssbo = OpTypePointer StorageBuffer %int
1190 %var1 = OpVariable %int_ptr_ssbo StorageBuffer
1191 %var2 = OpVariable %int_ptr_ssbo StorageBuffer
1192 %voidfn = OpTypeFunction %void
1193 %func = OpFunction %void None %voidfn
1194 %entry = OpLabel
1195 OpCopyMemory %var1 %var2 Aligned|MakePointerVisibleKHR|MakePointerAvailableKHR|NonPrivatePointerKHR 4 %device %workgroup
1196 OpReturn
1197 OpFunctionEnd
1198 )";
1199 
1200   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
1201   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1202 }
1203 
TEST_F(ValidateMemory,VulkanMemoryModelDeviceScopeCopyMemoryGood3)1204 TEST_F(ValidateMemory, VulkanMemoryModelDeviceScopeCopyMemoryGood3) {
1205   const std::string spirv = R"(
1206 OpCapability Shader
1207 OpCapability VulkanMemoryModelKHR
1208 OpCapability VulkanMemoryModelDeviceScopeKHR
1209 OpCapability Linkage
1210 OpExtension "SPV_KHR_vulkan_memory_model"
1211 OpMemoryModel Logical VulkanKHR
1212 %void = OpTypeVoid
1213 %int = OpTypeInt 32 0
1214 %device = OpConstant %int 1
1215 %workgroup = OpConstant %int 2
1216 %int_ptr_ssbo = OpTypePointer StorageBuffer %int
1217 %var1 = OpVariable %int_ptr_ssbo StorageBuffer
1218 %var2 = OpVariable %int_ptr_ssbo StorageBuffer
1219 %voidfn = OpTypeFunction %void
1220 %func = OpFunction %void None %voidfn
1221 %entry = OpLabel
1222 OpCopyMemory %var1 %var2 Aligned|MakePointerVisibleKHR|MakePointerAvailableKHR|NonPrivatePointerKHR 4 %workgroup %device
1223 OpReturn
1224 OpFunctionEnd
1225 )";
1226 
1227   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
1228   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1229 }
1230 
TEST_F(ValidateMemory,VulkanMemoryModelCopyMemoryTwoAccessAvVisBadBinaryV13)1231 TEST_F(ValidateMemory, VulkanMemoryModelCopyMemoryTwoAccessAvVisBadBinaryV13) {
1232   const std::string spirv = R"(
1233 OpCapability Shader
1234 OpCapability VulkanMemoryModelKHR
1235 OpCapability VulkanMemoryModelDeviceScopeKHR
1236 OpCapability Linkage
1237 OpExtension "SPV_KHR_vulkan_memory_model"
1238 OpMemoryModel Logical VulkanKHR
1239 %void = OpTypeVoid
1240 %int = OpTypeInt 32 0
1241 %device = OpConstant %int 1
1242 %int_ptr_ssbo = OpTypePointer StorageBuffer %int
1243 %var1 = OpVariable %int_ptr_ssbo StorageBuffer
1244 %var2 = OpVariable %int_ptr_ssbo StorageBuffer
1245 %voidfn = OpTypeFunction %void
1246 %func = OpFunction %void None %voidfn
1247 %entry = OpLabel
1248 OpCopyMemory %var1 %var2
1249   MakePointerAvailableKHR|NonPrivatePointerKHR %device
1250   MakePointerVisibleKHR|NonPrivatePointerKHR %device
1251 OpReturn
1252 OpFunctionEnd
1253 )";
1254 
1255   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
1256   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
1257             ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
1258   EXPECT_THAT(
1259       getDiagnosticString(),
1260       HasSubstr(
1261           "with two memory access operands requires SPIR-V 1.4 or later"));
1262 }
1263 
TEST_F(ValidateMemory,VulkanMemoryModelCopyMemoryTwoAccessAvVisGood)1264 TEST_F(ValidateMemory, VulkanMemoryModelCopyMemoryTwoAccessAvVisGood) {
1265   const std::string spirv = R"(
1266 OpCapability Shader
1267 OpCapability VulkanMemoryModelKHR
1268 OpCapability VulkanMemoryModelDeviceScopeKHR
1269 OpCapability Linkage
1270 OpExtension "SPV_KHR_vulkan_memory_model"
1271 OpMemoryModel Logical VulkanKHR
1272 %void = OpTypeVoid
1273 %int = OpTypeInt 32 0
1274 %device = OpConstant %int 1
1275 %int_ptr_ssbo = OpTypePointer StorageBuffer %int
1276 %var1 = OpVariable %int_ptr_ssbo StorageBuffer
1277 %var2 = OpVariable %int_ptr_ssbo StorageBuffer
1278 %voidfn = OpTypeFunction %void
1279 %func = OpFunction %void None %voidfn
1280 %entry = OpLabel
1281 OpCopyMemory %var1 %var2
1282   MakePointerAvailableKHR|NonPrivatePointerKHR %device
1283   MakePointerVisibleKHR|NonPrivatePointerKHR %device
1284 OpReturn
1285 OpFunctionEnd
1286 )";
1287 
1288   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
1289   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
1290   EXPECT_THAT(getDiagnosticString(), Eq(""));
1291 }
1292 
TEST_F(ValidateMemory,VulkanMemoryModelCopyMemoryTwoAccessFirstWithAvBad)1293 TEST_F(ValidateMemory, VulkanMemoryModelCopyMemoryTwoAccessFirstWithAvBad) {
1294   const std::string spirv = R"(
1295 OpCapability Shader
1296 OpCapability VulkanMemoryModelKHR
1297 OpCapability VulkanMemoryModelDeviceScopeKHR
1298 OpCapability Linkage
1299 OpExtension "SPV_KHR_vulkan_memory_model"
1300 OpMemoryModel Logical VulkanKHR
1301 %void = OpTypeVoid
1302 %int = OpTypeInt 32 0
1303 %device = OpConstant %int 1
1304 %int_ptr_ssbo = OpTypePointer StorageBuffer %int
1305 %var1 = OpVariable %int_ptr_ssbo StorageBuffer
1306 %var2 = OpVariable %int_ptr_ssbo StorageBuffer
1307 %voidfn = OpTypeFunction %void
1308 %func = OpFunction %void None %voidfn
1309 %entry = OpLabel
1310 OpCopyMemory %var1 %var2
1311   MakePointerAvailableKHR|NonPrivatePointerKHR %device
1312   MakePointerAvailableKHR|NonPrivatePointerKHR %device
1313 OpReturn
1314 OpFunctionEnd
1315 )";
1316 
1317   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
1318   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
1319             ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
1320   EXPECT_THAT(
1321       getDiagnosticString(),
1322       HasSubstr(
1323           "Source memory access must not include MakePointerAvailableKHR\n"
1324           "  OpCopyMemory %5 %6 MakePointerAvailable|NonPrivatePointer"
1325           " %uint_1 MakePointerAvailable|NonPrivatePointer %uint_1"));
1326 }
1327 
TEST_F(ValidateMemory,VulkanMemoryModelCopyMemoryTwoAccessSecondWithVisBad)1328 TEST_F(ValidateMemory, VulkanMemoryModelCopyMemoryTwoAccessSecondWithVisBad) {
1329   const std::string spirv = R"(
1330 OpCapability Shader
1331 OpCapability VulkanMemoryModelKHR
1332 OpCapability VulkanMemoryModelDeviceScopeKHR
1333 OpCapability Linkage
1334 OpExtension "SPV_KHR_vulkan_memory_model"
1335 OpMemoryModel Logical VulkanKHR
1336 %void = OpTypeVoid
1337 %int = OpTypeInt 32 0
1338 %device = OpConstant %int 1
1339 %int_ptr_ssbo = OpTypePointer StorageBuffer %int
1340 %var1 = OpVariable %int_ptr_ssbo StorageBuffer
1341 %var2 = OpVariable %int_ptr_ssbo StorageBuffer
1342 %voidfn = OpTypeFunction %void
1343 %func = OpFunction %void None %voidfn
1344 %entry = OpLabel
1345 OpCopyMemory %var1 %var2
1346   MakePointerVisibleKHR|NonPrivatePointerKHR %device
1347   MakePointerVisibleKHR|NonPrivatePointerKHR %device
1348 OpReturn
1349 OpFunctionEnd
1350 )";
1351 
1352   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
1353   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
1354             ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
1355   EXPECT_THAT(
1356       getDiagnosticString(),
1357       HasSubstr("Target memory access must not include MakePointerVisibleKHR\n"
1358                 "  OpCopyMemory %5 %6 MakePointerVisible|NonPrivatePointer"
1359                 " %uint_1 MakePointerVisible|NonPrivatePointer %uint_1"));
1360 }
1361 
TEST_F(ValidateMemory,VulkanMemoryModelDeviceScopeCopyMemorySizedBad1)1362 TEST_F(ValidateMemory, VulkanMemoryModelDeviceScopeCopyMemorySizedBad1) {
1363   const std::string spirv = R"(
1364 OpCapability Shader
1365 OpCapability VulkanMemoryModelKHR
1366 OpCapability Linkage
1367 OpCapability Addresses
1368 OpExtension "SPV_KHR_vulkan_memory_model"
1369 OpMemoryModel Logical VulkanKHR
1370 %void = OpTypeVoid
1371 %int = OpTypeInt 32 0
1372 %device = OpConstant %int 1
1373 %int_ptr_ssbo = OpTypePointer StorageBuffer %int
1374 %var1 = OpVariable %int_ptr_ssbo StorageBuffer
1375 %var2 = OpVariable %int_ptr_ssbo StorageBuffer
1376 %voidfn = OpTypeFunction %void
1377 %func = OpFunction %void None %voidfn
1378 %entry = OpLabel
1379 OpCopyMemorySized %var1 %var2 %device MakePointerAvailableKHR|NonPrivatePointerKHR %device
1380 OpReturn
1381 OpFunctionEnd
1382 )";
1383 
1384   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
1385   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
1386             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1387   EXPECT_THAT(
1388       getDiagnosticString(),
1389       HasSubstr("Use of device scope with VulkanKHR memory model requires the "
1390                 "VulkanMemoryModelDeviceScopeKHR capability"));
1391 }
1392 
TEST_F(ValidateMemory,VulkanMemoryModelDeviceScopeCopyMemorySizedBad2)1393 TEST_F(ValidateMemory, VulkanMemoryModelDeviceScopeCopyMemorySizedBad2) {
1394   const std::string spirv = R"(
1395 OpCapability Shader
1396 OpCapability VulkanMemoryModelKHR
1397 OpCapability Linkage
1398 OpCapability Addresses
1399 OpExtension "SPV_KHR_vulkan_memory_model"
1400 OpMemoryModel Logical VulkanKHR
1401 %void = OpTypeVoid
1402 %int = OpTypeInt 32 0
1403 %device = OpConstant %int 1
1404 %workgroup = OpConstant %int 1
1405 %int_ptr_ssbo = OpTypePointer StorageBuffer %int
1406 %var1 = OpVariable %int_ptr_ssbo StorageBuffer
1407 %var2 = OpVariable %int_ptr_ssbo StorageBuffer
1408 %voidfn = OpTypeFunction %void
1409 %func = OpFunction %void None %voidfn
1410 %entry = OpLabel
1411 OpCopyMemorySized %var1 %var2 %device Aligned|MakePointerVisibleKHR|MakePointerAvailableKHR|NonPrivatePointerKHR 4 %device %workgroup
1412 OpReturn
1413 OpFunctionEnd
1414 )";
1415 
1416   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
1417   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
1418             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1419   EXPECT_THAT(
1420       getDiagnosticString(),
1421       HasSubstr("Use of device scope with VulkanKHR memory model requires the "
1422                 "VulkanMemoryModelDeviceScopeKHR capability"));
1423 }
1424 
TEST_F(ValidateMemory,VulkanMemoryModelDeviceScopeCopyMemorySizedBad3)1425 TEST_F(ValidateMemory, VulkanMemoryModelDeviceScopeCopyMemorySizedBad3) {
1426   const std::string spirv = R"(
1427 OpCapability Shader
1428 OpCapability VulkanMemoryModelKHR
1429 OpCapability Linkage
1430 OpCapability Addresses
1431 OpExtension "SPV_KHR_vulkan_memory_model"
1432 OpMemoryModel Logical VulkanKHR
1433 %void = OpTypeVoid
1434 %int = OpTypeInt 32 0
1435 %device = OpConstant %int 1
1436 %workgroup = OpConstant %int 1
1437 %int_ptr_ssbo = OpTypePointer StorageBuffer %int
1438 %var1 = OpVariable %int_ptr_ssbo StorageBuffer
1439 %var2 = OpVariable %int_ptr_ssbo StorageBuffer
1440 %voidfn = OpTypeFunction %void
1441 %func = OpFunction %void None %voidfn
1442 %entry = OpLabel
1443 OpCopyMemorySized %var1 %var2 %device Aligned|MakePointerVisibleKHR|MakePointerAvailableKHR|NonPrivatePointerKHR 4 %workgroup %device
1444 OpReturn
1445 OpFunctionEnd
1446 )";
1447 
1448   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
1449   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
1450             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1451   EXPECT_THAT(
1452       getDiagnosticString(),
1453       HasSubstr("Use of device scope with VulkanKHR memory model requires the "
1454                 "VulkanMemoryModelDeviceScopeKHR capability"));
1455 }
1456 
TEST_F(ValidateMemory,VulkanMemoryModelDeviceScopeCopyMemorySizedGood1)1457 TEST_F(ValidateMemory, VulkanMemoryModelDeviceScopeCopyMemorySizedGood1) {
1458   const std::string spirv = R"(
1459 OpCapability Shader
1460 OpCapability VulkanMemoryModelKHR
1461 OpCapability VulkanMemoryModelDeviceScopeKHR
1462 OpCapability Linkage
1463 OpCapability Addresses
1464 OpExtension "SPV_KHR_vulkan_memory_model"
1465 OpMemoryModel Logical VulkanKHR
1466 %void = OpTypeVoid
1467 %int = OpTypeInt 32 0
1468 %device = OpConstant %int 1
1469 %int_ptr_ssbo = OpTypePointer StorageBuffer %int
1470 %var1 = OpVariable %int_ptr_ssbo StorageBuffer
1471 %var2 = OpVariable %int_ptr_ssbo StorageBuffer
1472 %voidfn = OpTypeFunction %void
1473 %func = OpFunction %void None %voidfn
1474 %entry = OpLabel
1475 OpCopyMemorySized %var1 %var2 %device MakePointerAvailableKHR|NonPrivatePointerKHR %device
1476 OpReturn
1477 OpFunctionEnd
1478 )";
1479 
1480   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
1481   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1482 }
1483 
TEST_F(ValidateMemory,VulkanMemoryModelDeviceScopeCopyMemorySizedGood2)1484 TEST_F(ValidateMemory, VulkanMemoryModelDeviceScopeCopyMemorySizedGood2) {
1485   const std::string spirv = R"(
1486 OpCapability Shader
1487 OpCapability VulkanMemoryModelKHR
1488 OpCapability VulkanMemoryModelDeviceScopeKHR
1489 OpCapability Linkage
1490 OpCapability Addresses
1491 OpExtension "SPV_KHR_vulkan_memory_model"
1492 OpMemoryModel Logical VulkanKHR
1493 %void = OpTypeVoid
1494 %int = OpTypeInt 32 0
1495 %device = OpConstant %int 1
1496 %workgroup = OpConstant %int 2
1497 %int_ptr_ssbo = OpTypePointer StorageBuffer %int
1498 %var1 = OpVariable %int_ptr_ssbo StorageBuffer
1499 %var2 = OpVariable %int_ptr_ssbo StorageBuffer
1500 %voidfn = OpTypeFunction %void
1501 %func = OpFunction %void None %voidfn
1502 %entry = OpLabel
1503 OpCopyMemorySized %var1 %var2 %device Aligned|MakePointerVisibleKHR|MakePointerAvailableKHR|NonPrivatePointerKHR 4 %device %workgroup
1504 OpReturn
1505 OpFunctionEnd
1506 )";
1507 
1508   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
1509   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1510 }
1511 
TEST_F(ValidateMemory,VulkanMemoryModelDeviceScopeCopyMemorySizedGood3)1512 TEST_F(ValidateMemory, VulkanMemoryModelDeviceScopeCopyMemorySizedGood3) {
1513   const std::string spirv = R"(
1514 OpCapability Shader
1515 OpCapability VulkanMemoryModelKHR
1516 OpCapability VulkanMemoryModelDeviceScopeKHR
1517 OpCapability Linkage
1518 OpCapability Addresses
1519 OpExtension "SPV_KHR_vulkan_memory_model"
1520 OpMemoryModel Logical VulkanKHR
1521 %void = OpTypeVoid
1522 %int = OpTypeInt 32 0
1523 %device = OpConstant %int 1
1524 %workgroup = OpConstant %int 2
1525 %int_ptr_ssbo = OpTypePointer StorageBuffer %int
1526 %var1 = OpVariable %int_ptr_ssbo StorageBuffer
1527 %var2 = OpVariable %int_ptr_ssbo StorageBuffer
1528 %voidfn = OpTypeFunction %void
1529 %func = OpFunction %void None %voidfn
1530 %entry = OpLabel
1531 OpCopyMemorySized %var1 %var2 %device Aligned|MakePointerVisibleKHR|MakePointerAvailableKHR|NonPrivatePointerKHR 4 %workgroup %device
1532 OpReturn
1533 OpFunctionEnd
1534 )";
1535 
1536   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
1537   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1538 }
1539 
TEST_F(ValidateMemory,ArrayLengthStructIsLabel)1540 TEST_F(ValidateMemory, ArrayLengthStructIsLabel) {
1541   const std::string spirv = R"(
1542 OpCapability Tessellation
1543 OpMemoryModel Logical GLSL450
1544 OpName %20 "incorrect"
1545 %void = OpTypeVoid
1546 %3 = OpTypeFunction %void
1547 %float = OpTypeFloat 32
1548 %v4float = OpTypeVector %float 4
1549 %uint = OpTypeInt 32 0
1550 %4 = OpFunction %void None %3
1551 %20 = OpLabel
1552 %24 = OpArrayLength %uint %20 0
1553 %25 = OpLoad %v4float %24
1554 OpReturnValue %25
1555 OpFunctionEnd
1556 )";
1557 
1558   CompileSuccessfully(spirv);
1559   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1560   EXPECT_THAT(getDiagnosticString(),
1561               HasSubstr("Operand 1[%incorrect] requires a type"));
1562 }
1563 
TEST_F(ValidateMemory,PSBLoadAlignedSuccess)1564 TEST_F(ValidateMemory, PSBLoadAlignedSuccess) {
1565   const std::string body = R"(
1566 OpCapability PhysicalStorageBufferAddressesEXT
1567 OpCapability Int64
1568 OpCapability Shader
1569 OpExtension "SPV_EXT_physical_storage_buffer"
1570 OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
1571 OpEntryPoint Fragment %main "main"
1572 OpExecutionMode %main OriginUpperLeft
1573 OpDecorate %val1 AliasedPointerEXT
1574 %uint64 = OpTypeInt 64 0
1575 %ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
1576 %pptr_f = OpTypePointer Function %ptr
1577 %void = OpTypeVoid
1578 %voidfn = OpTypeFunction %void
1579 %main = OpFunction %void None %voidfn
1580 %entry = OpLabel
1581 %val1 = OpVariable %pptr_f Function
1582 %val2 = OpLoad %ptr %val1
1583 %val3 = OpLoad %uint64 %val2 Aligned 8
1584 OpReturn
1585 OpFunctionEnd
1586 )";
1587 
1588   CompileSuccessfully(body.c_str());
1589   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
1590 }
1591 
TEST_F(ValidateMemory,PSBLoadAlignedMissing)1592 TEST_F(ValidateMemory, PSBLoadAlignedMissing) {
1593   const std::string body = R"(
1594 OpCapability PhysicalStorageBufferAddressesEXT
1595 OpCapability Int64
1596 OpCapability Shader
1597 OpExtension "SPV_EXT_physical_storage_buffer"
1598 OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
1599 OpEntryPoint Fragment %main "main"
1600 OpExecutionMode %main OriginUpperLeft
1601 OpDecorate %val1 AliasedPointerEXT
1602 %uint64 = OpTypeInt 64 0
1603 %ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
1604 %pptr_f = OpTypePointer Function %ptr
1605 %void = OpTypeVoid
1606 %voidfn = OpTypeFunction %void
1607 %main = OpFunction %void None %voidfn
1608 %entry = OpLabel
1609 %val1 = OpVariable %pptr_f Function
1610 %val2 = OpLoad %ptr %val1
1611 %val3 = OpLoad %uint64 %val2
1612 OpReturn
1613 OpFunctionEnd
1614 )";
1615 
1616   CompileSuccessfully(body.c_str());
1617   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1618   EXPECT_THAT(
1619       getDiagnosticString(),
1620       HasSubstr(
1621           "Memory accesses with PhysicalStorageBufferEXT must use Aligned"));
1622 }
1623 
TEST_F(ValidateMemory,PSBStoreAlignedSuccess)1624 TEST_F(ValidateMemory, PSBStoreAlignedSuccess) {
1625   const std::string body = R"(
1626 OpCapability PhysicalStorageBufferAddressesEXT
1627 OpCapability Int64
1628 OpCapability Shader
1629 OpExtension "SPV_EXT_physical_storage_buffer"
1630 OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
1631 OpEntryPoint Fragment %main "main"
1632 OpExecutionMode %main OriginUpperLeft
1633 OpDecorate %val1 AliasedPointerEXT
1634 %uint64 = OpTypeInt 64 0
1635 %u64_1 = OpConstant %uint64 1
1636 %ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
1637 %pptr_f = OpTypePointer Function %ptr
1638 %void = OpTypeVoid
1639 %voidfn = OpTypeFunction %void
1640 %main = OpFunction %void None %voidfn
1641 %entry = OpLabel
1642 %val1 = OpVariable %pptr_f Function
1643 %val2 = OpLoad %ptr %val1
1644 OpStore %val2 %u64_1 Aligned 8
1645 OpReturn
1646 OpFunctionEnd
1647 )";
1648 
1649   CompileSuccessfully(body.c_str());
1650   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
1651 }
1652 
TEST_F(ValidateMemory,PSBStoreAlignedMissing)1653 TEST_F(ValidateMemory, PSBStoreAlignedMissing) {
1654   const std::string body = R"(
1655 OpCapability PhysicalStorageBufferAddressesEXT
1656 OpCapability Int64
1657 OpCapability Shader
1658 OpExtension "SPV_EXT_physical_storage_buffer"
1659 OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
1660 OpEntryPoint Fragment %main "main"
1661 OpExecutionMode %main OriginUpperLeft
1662 OpDecorate %val1 AliasedPointerEXT
1663 %uint64 = OpTypeInt 64 0
1664 %u64_1 = OpConstant %uint64 1
1665 %ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
1666 %pptr_f = OpTypePointer Function %ptr
1667 %void = OpTypeVoid
1668 %voidfn = OpTypeFunction %void
1669 %main = OpFunction %void None %voidfn
1670 %entry = OpLabel
1671 %val1 = OpVariable %pptr_f Function
1672 %val2 = OpLoad %ptr %val1
1673 OpStore %val2 %u64_1 None
1674 OpReturn
1675 OpFunctionEnd
1676 )";
1677 
1678   CompileSuccessfully(body.c_str());
1679   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1680   EXPECT_THAT(
1681       getDiagnosticString(),
1682       HasSubstr(
1683           "Memory accesses with PhysicalStorageBufferEXT must use Aligned"));
1684 }
1685 
TEST_F(ValidateMemory,PSBVariable)1686 TEST_F(ValidateMemory, PSBVariable) {
1687   const std::string body = R"(
1688 OpCapability PhysicalStorageBufferAddressesEXT
1689 OpCapability Int64
1690 OpCapability Shader
1691 OpExtension "SPV_EXT_physical_storage_buffer"
1692 OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
1693 OpEntryPoint Fragment %main "main"
1694 OpExecutionMode %main OriginUpperLeft
1695 OpDecorate %val1 AliasedPointerEXT
1696 %uint64 = OpTypeInt 64 0
1697 %ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
1698 %val1 = OpVariable %ptr PhysicalStorageBufferEXT
1699 %void = OpTypeVoid
1700 %voidfn = OpTypeFunction %void
1701 %main = OpFunction %void None %voidfn
1702 %entry = OpLabel
1703 OpReturn
1704 OpFunctionEnd
1705 )";
1706 
1707   CompileSuccessfully(body);
1708   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1709   EXPECT_THAT(
1710       getDiagnosticString(),
1711       HasSubstr("PhysicalStorageBufferEXT must not be used with OpVariable"));
1712 }
1713 
GenCoopMatLoadStoreShader(const std::string & storeMemoryAccess,const std::string & loadMemoryAccess)1714 std::string GenCoopMatLoadStoreShader(const std::string& storeMemoryAccess,
1715                                       const std::string& loadMemoryAccess) {
1716   std::string s = R"(
1717 OpCapability Shader
1718 OpCapability GroupNonUniform
1719 OpCapability VulkanMemoryModelKHR
1720 OpCapability CooperativeMatrixNV
1721 OpExtension "SPV_KHR_vulkan_memory_model"
1722 OpExtension "SPV_NV_cooperative_matrix"
1723 %1 = OpExtInstImport "GLSL.std.450"
1724 OpMemoryModel Logical VulkanKHR
1725 OpEntryPoint GLCompute %4 "main" %11 %21
1726 OpExecutionMode %4 LocalSize 1 1 1
1727 OpDecorate %11 BuiltIn SubgroupId
1728 OpDecorate %21 BuiltIn WorkgroupId
1729 OpDecorate %74 ArrayStride 4
1730 OpMemberDecorate %75 0 Offset 0
1731 OpDecorate %75 Block
1732 OpDecorate %77 DescriptorSet 0
1733 OpDecorate %77 Binding 0
1734 OpDecorate %92 ArrayStride 4
1735 OpMemberDecorate %93 0 Offset 0
1736 OpDecorate %93 Block
1737 OpDecorate %95 DescriptorSet 0
1738 OpDecorate %95 Binding 1
1739 OpDecorate %102 ArrayStride 4
1740 OpMemberDecorate %103 0 Offset 0
1741 OpDecorate %103 Block
1742 OpDecorate %105 DescriptorSet 0
1743 OpDecorate %105 Binding 2
1744 OpDecorate %117 ArrayStride 4
1745 OpMemberDecorate %118 0 Offset 0
1746 OpDecorate %118 Block
1747 OpDecorate %120 DescriptorSet 0
1748 OpDecorate %120 Binding 3
1749 OpDecorate %123 SpecId 2
1750 OpDecorate %124 SpecId 3
1751 OpDecorate %125 SpecId 4
1752 OpDecorate %126 SpecId 5
1753 OpDecorate %127 SpecId 0
1754 OpDecorate %128 SpecId 1
1755 OpDecorate %129 BuiltIn WorkgroupSize
1756 %2 = OpTypeVoid
1757 %3 = OpTypeFunction %2
1758 %6 = OpTypeInt 32 0
1759 %7 = OpTypeVector %6 2
1760 %8 = OpTypePointer Function %7
1761 %10 = OpTypePointer Input %6
1762 %11 = OpVariable %10 Input
1763 %13 = OpConstant %6 2
1764 %19 = OpTypeVector %6 3
1765 %20 = OpTypePointer Input %19
1766 %21 = OpVariable %20 Input
1767 %27 = OpConstantComposite %7 %13 %13
1768 %31 = OpTypePointer Function %6
1769 %33 = OpConstant %6 1024
1770 %34 = OpConstant %6 1
1771 %38 = OpConstant %6 8
1772 %39 = OpConstant %6 0
1773 %68 = OpTypeFloat 32
1774 %69 = OpConstant %6 16
1775 %70 = OpConstant %6 3
1776 %71 = OpTypeCooperativeMatrixNV %68 %70 %69 %38
1777 %72 = OpTypePointer Function %71
1778 %74 = OpTypeRuntimeArray %68
1779 %75 = OpTypeStruct %74
1780 %76 = OpTypePointer StorageBuffer %75
1781 %77 = OpVariable %76 StorageBuffer
1782 %78 = OpTypeInt 32 1
1783 %79 = OpConstant %78 0
1784 %81 = OpConstant %6 5
1785 %82 = OpTypePointer StorageBuffer %68
1786 %84 = OpConstant %6 64
1787 %85 = OpTypeBool
1788 %86 = OpConstantFalse %85
1789 %88 = OpTypePointer Private %71
1790 %89 = OpVariable %88 Private
1791 %92 = OpTypeRuntimeArray %68
1792 %93 = OpTypeStruct %92
1793 %94 = OpTypePointer StorageBuffer %93
1794 %95 = OpVariable %94 StorageBuffer
1795 %99 = OpVariable %88 Private
1796 %102 = OpTypeRuntimeArray %68
1797 %103 = OpTypeStruct %102
1798 %104 = OpTypePointer StorageBuffer %103
1799 %105 = OpVariable %104 StorageBuffer
1800 %109 = OpVariable %88 Private
1801 %111 = OpVariable %88 Private
1802 %112 = OpSpecConstantOp %6 CooperativeMatrixLengthNV %71
1803 %113 = OpSpecConstantOp %78 IAdd %112 %79
1804 %117 = OpTypeRuntimeArray %68
1805 %118 = OpTypeStruct %117
1806 %119 = OpTypePointer StorageBuffer %118
1807 %120 = OpVariable %119 StorageBuffer
1808 %123 = OpSpecConstant %78 1
1809 %124 = OpSpecConstant %78 1
1810 %125 = OpSpecConstant %78 1
1811 %126 = OpSpecConstant %78 1
1812 %127 = OpSpecConstant %6 1
1813 %128 = OpSpecConstant %6 1
1814 %129 = OpSpecConstantComposite %19 %127 %128 %34
1815 %4 = OpFunction %2 None %3
1816 %5 = OpLabel
1817 %9 = OpVariable %8 Function
1818 %18 = OpVariable %8 Function
1819 %32 = OpVariable %31 Function
1820 %44 = OpVariable %31 Function
1821 %52 = OpVariable %31 Function
1822 %60 = OpVariable %31 Function
1823 %73 = OpVariable %72 Function
1824 %91 = OpVariable %72 Function
1825 %101 = OpVariable %72 Function
1826 %12 = OpLoad %6 %11
1827 %14 = OpUMod %6 %12 %13
1828 %15 = OpLoad %6 %11
1829 %16 = OpUDiv %6 %15 %13
1830 %17 = OpCompositeConstruct %7 %14 %16
1831 OpStore %9 %17
1832 %22 = OpLoad %19 %21
1833 %23 = OpVectorShuffle %7 %22 %22 0 1
1834 %24 = OpCompositeExtract %6 %23 0
1835 %25 = OpCompositeExtract %6 %23 1
1836 %26 = OpCompositeConstruct %7 %24 %25
1837 %28 = OpIMul %7 %26 %27
1838 %29 = OpLoad %7 %9
1839 %30 = OpIAdd %7 %28 %29
1840 OpStore %18 %30
1841 %35 = OpAccessChain %31 %18 %34
1842 %36 = OpLoad %6 %35
1843 %37 = OpIMul %6 %33 %36
1844 %40 = OpAccessChain %31 %18 %39
1845 %41 = OpLoad %6 %40
1846 %42 = OpIMul %6 %38 %41
1847 %43 = OpIAdd %6 %37 %42
1848 OpStore %32 %43
1849 %45 = OpAccessChain %31 %18 %34
1850 %46 = OpLoad %6 %45
1851 %47 = OpIMul %6 %33 %46
1852 %48 = OpAccessChain %31 %18 %39
1853 %49 = OpLoad %6 %48
1854 %50 = OpIMul %6 %38 %49
1855 %51 = OpIAdd %6 %47 %50
1856 OpStore %44 %51
1857 %53 = OpAccessChain %31 %18 %34
1858 %54 = OpLoad %6 %53
1859 %55 = OpIMul %6 %33 %54
1860 %56 = OpAccessChain %31 %18 %39
1861 %57 = OpLoad %6 %56
1862 %58 = OpIMul %6 %38 %57
1863 %59 = OpIAdd %6 %55 %58
1864 OpStore %52 %59
1865 %61 = OpAccessChain %31 %18 %34
1866 %62 = OpLoad %6 %61
1867 %63 = OpIMul %6 %33 %62
1868 %64 = OpAccessChain %31 %18 %39
1869 %65 = OpLoad %6 %64
1870 %66 = OpIMul %6 %38 %65
1871 %67 = OpIAdd %6 %63 %66
1872 OpStore %60 %67
1873 %80 = OpLoad %6 %32
1874 %83 = OpAccessChain %82 %77 %79 %80
1875 %87 = OpCooperativeMatrixLoadNV %71 %83 %84 %86 )" +
1876                   loadMemoryAccess + R"( %81
1877 OpStore %73 %87
1878 %90 = OpLoad %71 %73
1879 OpStore %89 %90
1880 %96 = OpLoad %6 %44
1881 %97 = OpAccessChain %82 %95 %79 %96
1882 %98 = OpCooperativeMatrixLoadNV %71 %97 %84 %86 MakePointerVisibleKHR|NonPrivatePointerKHR %81
1883 OpStore %91 %98
1884 %100 = OpLoad %71 %91
1885 OpStore %99 %100
1886 %106 = OpLoad %6 %52
1887 %107 = OpAccessChain %82 %105 %79 %106
1888 %108 = OpCooperativeMatrixLoadNV %71 %107 %84 %86 MakePointerVisibleKHR|NonPrivatePointerKHR %81
1889 OpStore %101 %108
1890 %110 = OpLoad %71 %101
1891 OpStore %109 %110
1892 %114 = OpConvertSToF %68 %113
1893 %115 = OpCompositeConstruct %71 %114
1894 OpStore %111 %115
1895 %116 = OpLoad %71 %111
1896 %121 = OpLoad %6 %60
1897 %122 = OpAccessChain %82 %120 %79 %121
1898 OpCooperativeMatrixStoreNV %122 %116 %84 %86 )" + storeMemoryAccess + R"( %81
1899 OpReturn
1900 OpFunctionEnd
1901 )";
1902 
1903   return s;
1904 }
1905 
TEST_F(ValidateMemory,CoopMatLoadStoreSuccess)1906 TEST_F(ValidateMemory, CoopMatLoadStoreSuccess) {
1907   std::string spirv =
1908       GenCoopMatLoadStoreShader("MakePointerAvailableKHR|NonPrivatePointerKHR",
1909                                 "MakePointerVisibleKHR|NonPrivatePointerKHR");
1910 
1911   CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
1912   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
1913 }
1914 
TEST_F(ValidateMemory,CoopMatStoreMemoryAccessFail)1915 TEST_F(ValidateMemory, CoopMatStoreMemoryAccessFail) {
1916   std::string spirv =
1917       GenCoopMatLoadStoreShader("MakePointerVisibleKHR|NonPrivatePointerKHR",
1918                                 "MakePointerVisibleKHR|NonPrivatePointerKHR");
1919 
1920   CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
1921   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
1922   EXPECT_THAT(getDiagnosticString(),
1923               HasSubstr("MakePointerVisibleKHR cannot be used with OpStore"));
1924 }
1925 
TEST_F(ValidateMemory,CoopMatLoadMemoryAccessFail)1926 TEST_F(ValidateMemory, CoopMatLoadMemoryAccessFail) {
1927   std::string spirv =
1928       GenCoopMatLoadStoreShader("MakePointerAvailableKHR|NonPrivatePointerKHR",
1929                                 "MakePointerAvailableKHR|NonPrivatePointerKHR");
1930 
1931   CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
1932   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
1933   EXPECT_THAT(getDiagnosticString(),
1934               HasSubstr("MakePointerAvailableKHR cannot be used with OpLoad"));
1935 }
1936 
TEST_F(ValidateMemory,CoopMatInvalidStorageClassFail)1937 TEST_F(ValidateMemory, CoopMatInvalidStorageClassFail) {
1938   const std::string body =
1939       R"(
1940 OpCapability Shader
1941 OpCapability Float16
1942 OpCapability CooperativeMatrixNV
1943 OpExtension "SPV_NV_cooperative_matrix"
1944 OpMemoryModel Logical GLSL450
1945 OpEntryPoint GLCompute %main "main"
1946 %void = OpTypeVoid
1947 %func = OpTypeFunction %void
1948 %f16 = OpTypeFloat 16
1949 %u32 = OpTypeInt 32 0
1950 
1951 %u32_8 = OpConstant %u32 8
1952 %subgroup = OpConstant %u32 3
1953 
1954 %f16mat = OpTypeCooperativeMatrixNV %f16 %subgroup %u32_8 %u32_8
1955 
1956 %str = OpTypeStruct %f16mat
1957 %str_ptr = OpTypePointer Workgroup %str
1958 %sh = OpVariable %str_ptr Workgroup
1959 
1960 %main = OpFunction %void None %func
1961 %main_entry = OpLabel
1962 
1963 OpReturn
1964 OpFunctionEnd)";
1965 
1966   CompileSuccessfully(body.c_str());
1967   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1968   EXPECT_THAT(
1969       getDiagnosticString(),
1970       HasSubstr(
1971           "Cooperative matrix types (or types containing them) can only be "
1972           "allocated in Function or Private storage classes or as function "
1973           "parameters"));
1974 }
1975 
TEST_F(ValidateMemory,CoopMatMatrixLengthResultTypeBad)1976 TEST_F(ValidateMemory, CoopMatMatrixLengthResultTypeBad) {
1977   const std::string body =
1978       R"(
1979 OpCapability Shader
1980 OpCapability Float16
1981 OpCapability CooperativeMatrixNV
1982 OpExtension "SPV_NV_cooperative_matrix"
1983 OpMemoryModel Logical GLSL450
1984 OpEntryPoint GLCompute %main "main"
1985 %void = OpTypeVoid
1986 %func = OpTypeFunction %void
1987 %f16 = OpTypeFloat 16
1988 %u32 = OpTypeInt 32 0
1989 %i32 = OpTypeInt 32 1
1990 
1991 %u32_8 = OpConstant %u32 8
1992 %subgroup = OpConstant %u32 3
1993 
1994 %f16mat = OpTypeCooperativeMatrixNV %f16 %subgroup %u32_8 %u32_8
1995 
1996 %main = OpFunction %void None %func
1997 %main_entry = OpLabel
1998 
1999 %1 = OpCooperativeMatrixLengthNV %i32 %f16mat
2000 
2001 OpReturn
2002 OpFunctionEnd)";
2003 
2004   CompileSuccessfully(body.c_str());
2005   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
2006   EXPECT_THAT(
2007       getDiagnosticString(),
2008       HasSubstr("The Result Type of OpCooperativeMatrixLengthNV <id> "
2009                 "'11[%11]' must be OpTypeInt with width 32 and signedness 0"));
2010 }
2011 
TEST_F(ValidateMemory,CoopMatMatrixLengthOperandTypeBad)2012 TEST_F(ValidateMemory, CoopMatMatrixLengthOperandTypeBad) {
2013   const std::string body =
2014       R"(
2015 OpCapability Shader
2016 OpCapability Float16
2017 OpCapability CooperativeMatrixNV
2018 OpExtension "SPV_NV_cooperative_matrix"
2019 OpMemoryModel Logical GLSL450
2020 OpEntryPoint GLCompute %main "main"
2021 %void = OpTypeVoid
2022 %func = OpTypeFunction %void
2023 %f16 = OpTypeFloat 16
2024 %u32 = OpTypeInt 32 0
2025 %i32 = OpTypeInt 32 1
2026 
2027 %u32_8 = OpConstant %u32 8
2028 %subgroup = OpConstant %u32 3
2029 
2030 %f16mat = OpTypeCooperativeMatrixNV %f16 %subgroup %u32_8 %u32_8
2031 
2032 %main = OpFunction %void None %func
2033 %main_entry = OpLabel
2034 
2035 %1 = OpCooperativeMatrixLengthNV %u32 %u32
2036 
2037 OpReturn
2038 OpFunctionEnd)";
2039 
2040   CompileSuccessfully(body.c_str());
2041   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
2042   EXPECT_THAT(
2043       getDiagnosticString(),
2044       HasSubstr("The type in OpCooperativeMatrixLengthNV <id> '5[%uint]' "
2045                 "must be OpTypeCooperativeMatrixNV"));
2046 }
2047 
TEST_F(ValidateMemory,CoopMatMatrixLengthGood)2048 TEST_F(ValidateMemory, CoopMatMatrixLengthGood) {
2049   const std::string body =
2050       R"(
2051 OpCapability Shader
2052 OpCapability Float16
2053 OpCapability CooperativeMatrixNV
2054 OpExtension "SPV_NV_cooperative_matrix"
2055 OpMemoryModel Logical GLSL450
2056 OpEntryPoint GLCompute %main "main"
2057 %void = OpTypeVoid
2058 %func = OpTypeFunction %void
2059 %f16 = OpTypeFloat 16
2060 %u32 = OpTypeInt 32 0
2061 %i32 = OpTypeInt 32 1
2062 
2063 %u32_8 = OpConstant %u32 8
2064 %subgroup = OpConstant %u32 3
2065 
2066 %f16mat = OpTypeCooperativeMatrixNV %f16 %subgroup %u32_8 %u32_8
2067 
2068 %main = OpFunction %void None %func
2069 %main_entry = OpLabel
2070 
2071 %1 = OpCooperativeMatrixLengthNV %u32 %f16mat
2072 
2073 OpReturn
2074 OpFunctionEnd)";
2075 
2076   CompileSuccessfully(body.c_str());
2077   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
2078 }
2079 
TEST_F(ValidateMemory,VulkanRTAOutsideOfStructBad)2080 TEST_F(ValidateMemory, VulkanRTAOutsideOfStructBad) {
2081   std::string spirv = R"(
2082 OpCapability Shader
2083 OpMemoryModel Logical GLSL450
2084 OpEntryPoint Fragment %func "func"
2085 OpExecutionMode %func OriginUpperLeft
2086 %sampler_t = OpTypeSampler
2087 %array_t = OpTypeRuntimeArray %sampler_t
2088 %array_ptr = OpTypePointer UniformConstant %array_t
2089 %2 = OpVariable %array_ptr UniformConstant
2090 %void = OpTypeVoid
2091 %func_t = OpTypeFunction %void
2092 %func = OpFunction %void None %func_t
2093 %1 = OpLabel
2094 OpReturn
2095 OpFunctionEnd
2096 )";
2097 
2098   CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
2099   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
2100   EXPECT_THAT(
2101       getDiagnosticString(),
2102       HasSubstr(
2103           "OpVariable, <id> '5[%5]', is attempting to create memory for an "
2104           "illegal type, OpTypeRuntimeArray.\nFor Vulkan OpTypeRuntimeArray "
2105           "can only appear as the final member of an OpTypeStruct, thus cannot "
2106           "be instantiated via OpVariable\n  %5 = OpVariable "
2107           "%_ptr_UniformConstant__runtimearr_2 UniformConstant\n"));
2108 }
2109 
TEST_F(ValidateMemory,VulkanRTAOutsideOfStructWithRuntimeDescriptorArrayGood)2110 TEST_F(ValidateMemory, VulkanRTAOutsideOfStructWithRuntimeDescriptorArrayGood) {
2111   std::string spirv = R"(
2112 OpCapability Shader
2113 OpCapability RuntimeDescriptorArrayEXT
2114 OpExtension "SPV_EXT_descriptor_indexing"
2115 OpMemoryModel Logical GLSL450
2116 OpEntryPoint Fragment %func "func"
2117 OpExecutionMode %func OriginUpperLeft
2118 OpDecorate %struct Block
2119 OpMemberDecorate %struct 0 Offset 0
2120 %sampler_t = OpTypeSampler
2121 %uint = OpTypeInt 32 0
2122 %array_t = OpTypeRuntimeArray %sampler_t
2123 %struct = OpTypeStruct %uint
2124 %sb_array_t = OpTypeRuntimeArray %struct
2125 %array_sb_ptr = OpTypePointer StorageBuffer %sb_array_t
2126 %2 = OpVariable %array_sb_ptr StorageBuffer
2127 %array_uc_ptr = OpTypePointer UniformConstant %array_t
2128 %3 = OpVariable %array_uc_ptr UniformConstant
2129 %void = OpTypeVoid
2130 %func_t = OpTypeFunction %void
2131 %func = OpFunction %void None %func_t
2132 %1 = OpLabel
2133 OpReturn
2134 OpFunctionEnd
2135 )";
2136 
2137   CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
2138   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
2139 }
2140 
TEST_F(ValidateMemory,VulkanRTAOutsideOfStructWithRuntimeDescriptorArrayAndWrongStorageClassBad)2141 TEST_F(
2142     ValidateMemory,
2143     VulkanRTAOutsideOfStructWithRuntimeDescriptorArrayAndWrongStorageClassBad) {
2144   std::string spirv = R"(
2145 OpCapability Shader
2146 OpCapability RuntimeDescriptorArrayEXT
2147 OpExtension "SPV_EXT_descriptor_indexing"
2148 OpMemoryModel Logical GLSL450
2149 OpEntryPoint Fragment %func "func"
2150 OpExecutionMode %func OriginUpperLeft
2151 %uint_t = OpTypeInt 32 0
2152 %array_t = OpTypeRuntimeArray %uint_t
2153 %array_ptr = OpTypePointer Workgroup %array_t
2154 %2 = OpVariable %array_ptr Workgroup
2155 %void = OpTypeVoid
2156 %func_t = OpTypeFunction %void
2157 %func = OpFunction %void None %func_t
2158 %1 = OpLabel
2159 OpReturn
2160 OpFunctionEnd
2161 )";
2162 
2163   CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
2164   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
2165   EXPECT_THAT(
2166       getDiagnosticString(),
2167       HasSubstr("For Vulkan with RuntimeDescriptorArrayEXT, a variable "
2168                 "containing OpTypeRuntimeArray must have storage class of "
2169                 "StorageBuffer, Uniform, or UniformConstant.\n  %5 = "
2170                 "OpVariable %_ptr_Workgroup__runtimearr_uint Workgroup\n"));
2171 }
2172 
TEST_F(ValidateMemory,VulkanRTAInsideStorageBufferStructGood)2173 TEST_F(ValidateMemory, VulkanRTAInsideStorageBufferStructGood) {
2174   std::string spirv = R"(
2175 OpCapability Shader
2176 OpMemoryModel Logical GLSL450
2177 OpEntryPoint Fragment %func "func"
2178 OpExecutionMode %func OriginUpperLeft
2179 OpDecorate %array_t ArrayStride 4
2180 OpMemberDecorate %struct_t 0 Offset 0
2181 OpDecorate %struct_t Block
2182 %uint_t = OpTypeInt 32 0
2183 %array_t = OpTypeRuntimeArray %uint_t
2184 %struct_t = OpTypeStruct %array_t
2185 %struct_ptr = OpTypePointer StorageBuffer %struct_t
2186 %2 = OpVariable %struct_ptr StorageBuffer
2187 %void = OpTypeVoid
2188 %func_t = OpTypeFunction %void
2189 %func = OpFunction %void None %func_t
2190 %1 = OpLabel
2191 OpReturn
2192 OpFunctionEnd
2193 )";
2194 
2195   CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
2196   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
2197 }
2198 
TEST_F(ValidateMemory,VulkanRTAInsideWrongStorageClassStructBad)2199 TEST_F(ValidateMemory, VulkanRTAInsideWrongStorageClassStructBad) {
2200   std::string spirv = R"(
2201 OpCapability Shader
2202 OpMemoryModel Logical GLSL450
2203 OpEntryPoint Fragment %func "func"
2204 OpExecutionMode %func OriginUpperLeft
2205 %uint_t = OpTypeInt 32 0
2206 %array_t = OpTypeRuntimeArray %uint_t
2207 %struct_t = OpTypeStruct %array_t
2208 %struct_ptr = OpTypePointer Workgroup %struct_t
2209 %2 = OpVariable %struct_ptr Workgroup
2210 %void = OpTypeVoid
2211 %func_t = OpTypeFunction %void
2212 %func = OpFunction %void None %func_t
2213 %1 = OpLabel
2214 OpReturn
2215 OpFunctionEnd
2216 )";
2217 
2218   CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
2219   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
2220   EXPECT_THAT(
2221       getDiagnosticString(),
2222       HasSubstr(
2223           "For Vulkan, OpTypeStruct variables containing OpTypeRuntimeArray "
2224           "must have storage class of StorageBuffer or Uniform.\n  %6 = "
2225           "OpVariable %_ptr_Workgroup__struct_4 Workgroup\n"));
2226 }
2227 
TEST_F(ValidateMemory,VulkanRTAInsideStorageBufferStructWithoutBlockBad)2228 TEST_F(ValidateMemory, VulkanRTAInsideStorageBufferStructWithoutBlockBad) {
2229   std::string spirv = R"(
2230 OpCapability Shader
2231 OpMemoryModel Logical GLSL450
2232 OpEntryPoint Fragment %func "func"
2233 OpExecutionMode %func OriginUpperLeft
2234 %uint_t = OpTypeInt 32 0
2235 %array_t = OpTypeRuntimeArray %uint_t
2236 %struct_t = OpTypeStruct %array_t
2237 %struct_ptr = OpTypePointer StorageBuffer %struct_t
2238 %2 = OpVariable %struct_ptr StorageBuffer
2239 %void = OpTypeVoid
2240 %func_t = OpTypeFunction %void
2241 %func = OpFunction %void None %func_t
2242 %1 = OpLabel
2243 OpReturn
2244 OpFunctionEnd
2245 )";
2246 
2247   CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
2248   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
2249   EXPECT_THAT(getDiagnosticString(),
2250               HasSubstr("For Vulkan, an OpTypeStruct variable containing an "
2251                         "OpTypeRuntimeArray must be decorated with Block if it "
2252                         "has storage class StorageBuffer.\n  %6 = OpVariable "
2253                         "%_ptr_StorageBuffer__struct_4 StorageBuffer\n"));
2254 }
2255 
TEST_F(ValidateMemory,VulkanRTAInsideUniformStructGood)2256 TEST_F(ValidateMemory, VulkanRTAInsideUniformStructGood) {
2257   std::string spirv = R"(
2258 OpCapability Shader
2259 OpMemoryModel Logical GLSL450
2260 OpEntryPoint Fragment %func "func"
2261 OpExecutionMode %func OriginUpperLeft
2262 OpDecorate %array_t ArrayStride 4
2263 OpMemberDecorate %struct_t 0 Offset 0
2264 OpDecorate %struct_t BufferBlock
2265 %uint_t = OpTypeInt 32 0
2266 %array_t = OpTypeRuntimeArray %uint_t
2267 %struct_t = OpTypeStruct %array_t
2268 %struct_ptr = OpTypePointer Uniform %struct_t
2269 %2 = OpVariable %struct_ptr Uniform
2270 %void = OpTypeVoid
2271 %func_t = OpTypeFunction %void
2272 %func = OpFunction %void None %func_t
2273 %1 = OpLabel
2274 OpReturn
2275 OpFunctionEnd
2276 )";
2277 
2278   CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
2279   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
2280 }
2281 
TEST_F(ValidateMemory,VulkanRTAInsideUniformStructWithoutBufferBlockBad)2282 TEST_F(ValidateMemory, VulkanRTAInsideUniformStructWithoutBufferBlockBad) {
2283   std::string spirv = R"(
2284 OpCapability Shader
2285 OpMemoryModel Logical GLSL450
2286 OpEntryPoint Fragment %func "func"
2287 OpExecutionMode %func OriginUpperLeft
2288 %uint_t = OpTypeInt 32 0
2289 %array_t = OpTypeRuntimeArray %uint_t
2290 %struct_t = OpTypeStruct %array_t
2291 %struct_ptr = OpTypePointer Uniform %struct_t
2292 %2 = OpVariable %struct_ptr Uniform
2293 %void = OpTypeVoid
2294 %func_t = OpTypeFunction %void
2295 %func = OpFunction %void None %func_t
2296 %1 = OpLabel
2297 OpReturn
2298 OpFunctionEnd
2299 )";
2300 
2301   CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
2302   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
2303   EXPECT_THAT(getDiagnosticString(),
2304               HasSubstr("For Vulkan, an OpTypeStruct variable containing an "
2305                         "OpTypeRuntimeArray must be decorated with BufferBlock "
2306                         "if it has storage class Uniform.\n  %6 = OpVariable "
2307                         "%_ptr_Uniform__struct_4 Uniform\n"));
2308 }
2309 
TEST_F(ValidateMemory,VulkanRTAInsideRTABad)2310 TEST_F(ValidateMemory, VulkanRTAInsideRTABad) {
2311   std::string spirv = R"(
2312 OpCapability Shader
2313 OpMemoryModel Logical GLSL450
2314 OpEntryPoint Fragment %func "func"
2315 OpExecutionMode %func OriginUpperLeft
2316 %sampler_t = OpTypeSampler
2317 %inner_array_t = OpTypeRuntimeArray %sampler_t
2318 %array_t = OpTypeRuntimeArray %inner_array_t
2319 %array_ptr = OpTypePointer UniformConstant %array_t
2320 %2 = OpVariable %array_ptr UniformConstant
2321 %void = OpTypeVoid
2322 %func_t = OpTypeFunction %void
2323 %func = OpFunction %void None %func_t
2324 %1 = OpLabel
2325 OpReturn
2326 OpFunctionEnd
2327 )";
2328 
2329   CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
2330   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
2331   EXPECT_THAT(
2332       getDiagnosticString(),
2333       HasSubstr(
2334           "OpTypeRuntimeArray Element Type <id> '3[%_runtimearr_2]' is not "
2335           "valid in Vulkan environments.\n  %_runtimearr__runtimearr_2 = "
2336           "OpTypeRuntimeArray %_runtimearr_2\n"));
2337 }
2338 
TEST_F(ValidateMemory,VulkanRTAInsideRTAWithRuntimeDescriptorArrayBad)2339 TEST_F(ValidateMemory, VulkanRTAInsideRTAWithRuntimeDescriptorArrayBad) {
2340   std::string spirv = R"(
2341 OpCapability RuntimeDescriptorArrayEXT
2342 OpCapability Shader
2343 OpExtension "SPV_EXT_descriptor_indexing"
2344 OpMemoryModel Logical GLSL450
2345 OpEntryPoint Fragment %func "func"
2346 OpExecutionMode %func OriginUpperLeft
2347 OpDecorate %array_t Block
2348 %uint_t = OpTypeInt 32 0
2349 %inner_array_t = OpTypeRuntimeArray %uint_t
2350 %array_t = OpTypeRuntimeArray %inner_array_t
2351 %array_ptr = OpTypePointer StorageBuffer %array_t
2352 %2 = OpVariable %array_ptr StorageBuffer
2353 %void = OpTypeVoid
2354 %func_t = OpTypeFunction %void
2355 %func = OpFunction %void None %func_t
2356 %1 = OpLabel
2357 OpReturn
2358 OpFunctionEnd
2359 )";
2360 
2361   CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
2362   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
2363   EXPECT_THAT(
2364       getDiagnosticString(),
2365       HasSubstr(
2366           "OpTypeRuntimeArray Element Type <id> '4[%_runtimearr_uint]' is not "
2367           "valid in Vulkan environments.\n  %_runtimearr__runtimearr_uint = "
2368           "OpTypeRuntimeArray %_runtimearr_uint\n"));
2369 }
2370 
TEST_F(ValidateMemory,VulkanUniformStructInsideRTAWithRuntimeDescriptorArrayGood)2371 TEST_F(ValidateMemory,
2372        VulkanUniformStructInsideRTAWithRuntimeDescriptorArrayGood) {
2373   std::string spirv = R"(
2374 OpCapability RuntimeDescriptorArrayEXT
2375 OpCapability Shader
2376 OpExtension "SPV_EXT_descriptor_indexing"
2377 OpMemoryModel Logical GLSL450
2378 OpEntryPoint Fragment %func "func"
2379 OpExecutionMode %func OriginUpperLeft
2380 OpDecorate %array_t ArrayStride 4
2381 OpMemberDecorate %struct_t 0 Offset 0
2382 OpDecorate %struct_t Block
2383 %uint_t = OpTypeInt 32 0
2384 %struct_t = OpTypeStruct %uint_t
2385 %array_t = OpTypeRuntimeArray %struct_t
2386 %array_ptr = OpTypePointer Uniform %array_t
2387 %2 = OpVariable %array_ptr Uniform
2388 %void = OpTypeVoid
2389 %func_t = OpTypeFunction %void
2390 %func = OpFunction %void None %func_t
2391 %1 = OpLabel
2392 OpReturn
2393 OpFunctionEnd
2394 )";
2395 
2396   CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
2397   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
2398 }
2399 
TEST_F(ValidateMemory,VulkanRTAInsideRTAInsideStructBad)2400 TEST_F(ValidateMemory, VulkanRTAInsideRTAInsideStructBad) {
2401   std::string spirv = R"(
2402 OpCapability Shader
2403 OpMemoryModel Logical GLSL450
2404 OpEntryPoint Fragment %func "func"
2405 OpExecutionMode %func OriginUpperLeft
2406 OpDecorate %array_t ArrayStride 4
2407 OpMemberDecorate %struct_t 0 Offset 0
2408 OpDecorate %struct_t Block
2409 %uint_t = OpTypeInt 32 0
2410 %inner_array_t = OpTypeRuntimeArray %uint_t
2411 %array_t = OpTypeRuntimeArray %inner_array_t
2412 %struct_t = OpTypeStruct %array_t
2413 %struct_ptr = OpTypePointer StorageBuffer %struct_t
2414 %2 = OpVariable %struct_ptr StorageBuffer
2415 %void = OpTypeVoid
2416 %func_t = OpTypeFunction %void
2417 %func = OpFunction %void None %func_t
2418 %1 = OpLabel
2419 OpReturn
2420 OpFunctionEnd
2421 )";
2422 
2423   CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
2424   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
2425   EXPECT_THAT(
2426       getDiagnosticString(),
2427       HasSubstr(
2428           "OpTypeRuntimeArray Element Type <id> '5[%_runtimearr_uint]' is not "
2429           "valid in Vulkan environments.\n  %_runtimearr__runtimearr_uint = "
2430           "OpTypeRuntimeArray %_runtimearr_uint\n"));
2431 }
2432 
TEST_F(ValidateMemory,VulkanRTAInsideRTAInsideStructWithRuntimeDescriptorArrayBad)2433 TEST_F(ValidateMemory,
2434        VulkanRTAInsideRTAInsideStructWithRuntimeDescriptorArrayBad) {
2435   std::string spirv = R"(
2436 OpCapability RuntimeDescriptorArrayEXT
2437 OpCapability Shader
2438 OpExtension "SPV_EXT_descriptor_indexing"
2439 OpMemoryModel Logical GLSL450
2440 OpEntryPoint Fragment %func "func"
2441 OpExecutionMode %func OriginUpperLeft
2442 OpDecorate %array_t ArrayStride 4
2443 OpMemberDecorate %struct_t 0 Offset 0
2444 OpDecorate %struct_t Block
2445 %uint_t = OpTypeInt 32 0
2446 %inner_array_t = OpTypeRuntimeArray %uint_t
2447 %array_t = OpTypeRuntimeArray %inner_array_t
2448 %struct_t = OpTypeStruct %array_t
2449 %struct_ptr = OpTypePointer StorageBuffer %struct_t
2450 %2 = OpVariable %struct_ptr StorageBuffer
2451 %void = OpTypeVoid
2452 %func_t = OpTypeFunction %void
2453 %func = OpFunction %void None %func_t
2454 %1 = OpLabel
2455 OpReturn
2456 OpFunctionEnd
2457 )";
2458 
2459   CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
2460   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
2461   EXPECT_THAT(
2462       getDiagnosticString(),
2463       HasSubstr(
2464           "OpTypeRuntimeArray Element Type <id> '5[%_runtimearr_uint]' is not "
2465           "valid in Vulkan environments.\n  %_runtimearr__runtimearr_uint = "
2466           "OpTypeRuntimeArray %_runtimearr_uint\n"));
2467 }
2468 
TEST_F(ValidateMemory,VulkanRTAInsideArrayBad)2469 TEST_F(ValidateMemory, VulkanRTAInsideArrayBad) {
2470   std::string spirv = R"(
2471 OpCapability Shader
2472 OpMemoryModel Logical GLSL450
2473 OpEntryPoint Fragment %func "func"
2474 OpExecutionMode %func OriginUpperLeft
2475 %uint_t = OpTypeInt 32 0
2476 %dim = OpConstant %uint_t 1
2477 %sampler_t = OpTypeSampler
2478 %inner_array_t = OpTypeRuntimeArray %sampler_t
2479 %array_t = OpTypeArray %inner_array_t %dim
2480 %array_ptr = OpTypePointer UniformConstant %array_t
2481 %2 = OpVariable %array_ptr UniformConstant
2482 %void = OpTypeVoid
2483 %func_t = OpTypeFunction %void
2484 %func = OpFunction %void None %func_t
2485 %1 = OpLabel
2486 OpReturn
2487 OpFunctionEnd
2488 )";
2489 
2490   CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
2491   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
2492   EXPECT_THAT(
2493       getDiagnosticString(),
2494       HasSubstr("OpTypeArray Element Type <id> '5[%_runtimearr_4]' is not "
2495                 "valid in Vulkan environments.\n  %_arr__runtimearr_4_uint_1 = "
2496                 "OpTypeArray %_runtimearr_4 %uint_1\n"));
2497 }
2498 
TEST_F(ValidateMemory,VulkanRTAInsideArrayWithRuntimeDescriptorArrayBad)2499 TEST_F(ValidateMemory, VulkanRTAInsideArrayWithRuntimeDescriptorArrayBad) {
2500   std::string spirv = R"(
2501 OpCapability RuntimeDescriptorArrayEXT
2502 OpCapability Shader
2503 OpExtension "SPV_EXT_descriptor_indexing"
2504 OpMemoryModel Logical GLSL450
2505 OpEntryPoint Fragment %func "func"
2506 OpExecutionMode %func OriginUpperLeft
2507 OpDecorate %array_t Block
2508 %uint_t = OpTypeInt 32 0
2509 %dim = OpConstant %uint_t 1
2510 %sampler_t = OpTypeSampler
2511 %inner_array_t = OpTypeRuntimeArray %uint_t
2512 %array_t = OpTypeRuntimeArray %inner_array_t
2513 %array_ptr = OpTypePointer StorageBuffer %array_t
2514 %2 = OpVariable %array_ptr StorageBuffer
2515 %void = OpTypeVoid
2516 %func_t = OpTypeFunction %void
2517 %func = OpFunction %void None %func_t
2518 %1 = OpLabel
2519 OpReturn
2520 OpFunctionEnd
2521 )";
2522 
2523   CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
2524   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
2525   EXPECT_THAT(
2526       getDiagnosticString(),
2527       HasSubstr(
2528           "OpTypeRuntimeArray Element Type <id> '6[%_runtimearr_uint]' is not "
2529           "valid in Vulkan environments.\n  %_runtimearr__runtimearr_uint = "
2530           "OpTypeRuntimeArray %_runtimearr_uint\n"));
2531 }
2532 
TEST_F(ValidateMemory,VulkanRTAInsideArrayInsideStructBad)2533 TEST_F(ValidateMemory, VulkanRTAInsideArrayInsideStructBad) {
2534   std::string spirv = R"(
2535 OpCapability Shader
2536 OpMemoryModel Logical GLSL450
2537 OpEntryPoint Fragment %func "func"
2538 OpExecutionMode %func OriginUpperLeft
2539 OpDecorate %array_t ArrayStride 4
2540 OpMemberDecorate %struct_t 0 Offset 0
2541 OpDecorate %struct_t Block
2542 %uint_t = OpTypeInt 32 0
2543 %dim = OpConstant %uint_t 1
2544 %inner_array_t = OpTypeRuntimeArray %uint_t
2545 %array_t = OpTypeArray %inner_array_t %dim
2546 %struct_t = OpTypeStruct %array_t
2547 %struct_ptr = OpTypePointer StorageBuffer %struct_t
2548 %2 = OpVariable %struct_ptr StorageBuffer
2549 %void = OpTypeVoid
2550 %func_t = OpTypeFunction %void
2551 %func = OpFunction %void None %func_t
2552 %1 = OpLabel
2553 OpReturn
2554 OpFunctionEnd
2555 )";
2556 
2557   CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
2558   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
2559   EXPECT_THAT(
2560       getDiagnosticString(),
2561       HasSubstr(
2562           "OpTypeArray Element Type <id> '6[%_runtimearr_uint]' is not "
2563           "valid in Vulkan environments.\n  %_arr__runtimearr_uint_uint_1 "
2564           "= OpTypeArray %_runtimearr_uint %uint_1\n"));
2565 }
2566 
TEST_F(ValidateMemory,VulkanRTAInsideArrayInsideStructWithRuntimeDescriptorArrayBad)2567 TEST_F(ValidateMemory,
2568        VulkanRTAInsideArrayInsideStructWithRuntimeDescriptorArrayBad) {
2569   std::string spirv = R"(
2570 OpCapability RuntimeDescriptorArrayEXT
2571 OpCapability Shader
2572 OpExtension "SPV_EXT_descriptor_indexing"
2573 OpMemoryModel Logical GLSL450
2574 OpEntryPoint Fragment %func "func"
2575 OpExecutionMode %func OriginUpperLeft
2576 OpDecorate %array_t ArrayStride 4
2577 OpMemberDecorate %struct_t 0 Offset 0
2578 OpDecorate %struct_t Block
2579 %uint_t = OpTypeInt 32 0
2580 %dim = OpConstant %uint_t 1
2581 %inner_array_t = OpTypeRuntimeArray %uint_t
2582 %array_t = OpTypeArray %inner_array_t %dim
2583 %struct_t = OpTypeStruct %array_t
2584 %struct_ptr = OpTypePointer StorageBuffer %struct_t
2585 %2 = OpVariable %struct_ptr StorageBuffer
2586 %void = OpTypeVoid
2587 %func_t = OpTypeFunction %void
2588 %func = OpFunction %void None %func_t
2589 %1 = OpLabel
2590 OpReturn
2591 OpFunctionEnd
2592 )";
2593 
2594   CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
2595   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
2596   EXPECT_THAT(
2597       getDiagnosticString(),
2598       HasSubstr(
2599           "OpTypeArray Element Type <id> '6[%_runtimearr_uint]' is not "
2600           "valid in Vulkan environments.\n  %_arr__runtimearr_uint_uint_1 "
2601           "= OpTypeArray %_runtimearr_uint %uint_1\n"));
2602 }
2603 
TEST_F(ValidateMemory,VulkanRTAStructInsideRTAWithRuntimeDescriptorArrayGood)2604 TEST_F(ValidateMemory, VulkanRTAStructInsideRTAWithRuntimeDescriptorArrayGood) {
2605   std::string spirv = R"(
2606 OpCapability RuntimeDescriptorArrayEXT
2607 OpCapability Shader
2608 OpExtension "SPV_EXT_descriptor_indexing"
2609 OpMemoryModel Logical GLSL450
2610 OpEntryPoint Fragment %func "func"
2611 OpExecutionMode %func OriginUpperLeft
2612 OpDecorate %inner_array_t ArrayStride 4
2613 OpDecorate %array_t ArrayStride 4
2614 OpMemberDecorate %struct_t 0 Offset 0
2615 OpDecorate %struct_t Block
2616 %uint_t = OpTypeInt 32 0
2617 %inner_array_t = OpTypeRuntimeArray %uint_t
2618 %struct_t = OpTypeStruct %inner_array_t
2619 %array_t = OpTypeRuntimeArray %struct_t
2620 %array_ptr = OpTypePointer StorageBuffer %array_t
2621 %2 = OpVariable %array_ptr StorageBuffer
2622 %void = OpTypeVoid
2623 %func_t = OpTypeFunction %void
2624 %func = OpFunction %void None %func_t
2625 %1 = OpLabel
2626 OpReturn
2627 OpFunctionEnd
2628 )";
2629 
2630   CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
2631   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
2632 }
2633 
TEST_F(ValidateMemory,VulkanRTAStructInsideArrayGood)2634 TEST_F(ValidateMemory, VulkanRTAStructInsideArrayGood) {
2635   std::string spirv = R"(
2636 OpCapability RuntimeDescriptorArrayEXT
2637 OpCapability Shader
2638 OpExtension "SPV_EXT_descriptor_indexing"
2639 OpMemoryModel Logical GLSL450
2640 OpEntryPoint Fragment %func "func"
2641 OpExecutionMode %func OriginUpperLeft
2642 OpDecorate %inner_array_t ArrayStride 4
2643 OpDecorate %array_t ArrayStride 4
2644 OpMemberDecorate %struct_t 0 Offset 0
2645 OpDecorate %struct_t Block
2646 %uint_t = OpTypeInt 32 0
2647 %inner_array_t = OpTypeRuntimeArray %uint_t
2648 %struct_t = OpTypeStruct %inner_array_t
2649 %array_size = OpConstant %uint_t 5
2650 %array_t = OpTypeArray %struct_t %array_size
2651 %array_ptr = OpTypePointer StorageBuffer %array_t
2652 %2 = OpVariable %array_ptr StorageBuffer
2653 %void = OpTypeVoid
2654 %func_t = OpTypeFunction %void
2655 %func = OpFunction %void None %func_t
2656 %1 = OpLabel
2657 OpReturn
2658 OpFunctionEnd
2659 )";
2660 
2661   CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
2662   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
2663 }
2664 
TEST_F(ValidateMemory,CopyMemoryNoAccessGood)2665 TEST_F(ValidateMemory, CopyMemoryNoAccessGood) {
2666   const std::string spirv = R"(
2667 OpCapability Shader
2668 OpCapability Linkage
2669 OpMemoryModel Logical GLSL450
2670 %void = OpTypeVoid
2671 %int = OpTypeInt 32 0
2672 %int_ptr_priv = OpTypePointer Private %int
2673 %var1 = OpVariable %int_ptr_priv Private
2674 %var2 = OpVariable %int_ptr_priv Private
2675 %voidfn = OpTypeFunction %void
2676 %func = OpFunction %void None %voidfn
2677 %entry = OpLabel
2678 OpCopyMemory %var1 %var2
2679 OpReturn
2680 OpFunctionEnd
2681 )";
2682 
2683   CompileSuccessfully(spirv);
2684   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
2685   EXPECT_THAT(getDiagnosticString(), Eq(""));
2686 }
2687 
TEST_F(ValidateMemory,CopyMemorySimpleMixedAccessGood)2688 TEST_F(ValidateMemory, CopyMemorySimpleMixedAccessGood) {
2689   // Test one memory access operand using features that don't require the
2690   // Vulkan memory model.
2691   const std::string spirv = R"(
2692 OpCapability Shader
2693 OpCapability Linkage
2694 OpMemoryModel Logical GLSL450
2695 %void = OpTypeVoid
2696 %int = OpTypeInt 32 0
2697 %int_ptr_priv = OpTypePointer Private %int
2698 %var1 = OpVariable %int_ptr_priv Private
2699 %var2 = OpVariable %int_ptr_priv Private
2700 %voidfn = OpTypeFunction %void
2701 %func = OpFunction %void None %voidfn
2702 %entry = OpLabel
2703 OpCopyMemory %var1 %var2 Volatile|Aligned|Nontemporal 4
2704 OpReturn
2705 OpFunctionEnd
2706 )";
2707 
2708   CompileSuccessfully(spirv);
2709   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
2710   EXPECT_THAT(getDiagnosticString(), Eq(""));
2711 }
2712 
TEST_F(ValidateMemory,CopyMemorySimpleTwoMixedAccessV13Bad)2713 TEST_F(ValidateMemory, CopyMemorySimpleTwoMixedAccessV13Bad) {
2714   // Two memory access operands is invalid up to SPIR-V 1.3
2715   const std::string spirv = R"(
2716 OpCapability Shader
2717 OpCapability Linkage
2718 OpMemoryModel Logical GLSL450
2719 %void = OpTypeVoid
2720 %int = OpTypeInt 32 0
2721 %int_ptr_priv = OpTypePointer Private %int
2722 %var1 = OpVariable %int_ptr_priv Private
2723 %var2 = OpVariable %int_ptr_priv Private
2724 %voidfn = OpTypeFunction %void
2725 %func = OpFunction %void None %voidfn
2726 %entry = OpLabel
2727 OpCopyMemory %var1 %var2 Volatile Volatile
2728 OpReturn
2729 OpFunctionEnd
2730 )";
2731 
2732   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
2733   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
2734             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
2735   EXPECT_THAT(getDiagnosticString(),
2736               HasSubstr("CopyMemory with two memory access operands requires "
2737                         "SPIR-V 1.4 or later"));
2738 }
2739 
TEST_F(ValidateMemory,CopyMemorySimpleTwoMixedAccessV14Good)2740 TEST_F(ValidateMemory, CopyMemorySimpleTwoMixedAccessV14Good) {
2741   // Two memory access operands is valid in SPIR-V 1.4
2742   const std::string spirv = R"(
2743 OpCapability Shader
2744 OpCapability Linkage
2745 OpMemoryModel Logical GLSL450
2746 %void = OpTypeVoid
2747 %int = OpTypeInt 32 0
2748 %int_ptr_priv = OpTypePointer Private %int
2749 %var1 = OpVariable %int_ptr_priv Private
2750 %var2 = OpVariable %int_ptr_priv Private
2751 %voidfn = OpTypeFunction %void
2752 %func = OpFunction %void None %voidfn
2753 %entry = OpLabel
2754 OpCopyMemory %var1 %var2 Volatile Volatile
2755 OpReturn
2756 OpFunctionEnd
2757 )";
2758 
2759   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
2760   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
2761   EXPECT_THAT(getDiagnosticString(), Eq(""));
2762 }
2763 
TEST_F(ValidateMemory,CopyMemorySizedNoAccessGood)2764 TEST_F(ValidateMemory, CopyMemorySizedNoAccessGood) {
2765   const std::string spirv = R"(
2766 OpCapability Shader
2767 OpCapability Linkage
2768 OpCapability Addresses
2769 OpMemoryModel Logical GLSL450
2770 %void = OpTypeVoid
2771 %int = OpTypeInt 32 0
2772 %int_16 = OpConstant %int 16
2773 %int_ptr_priv = OpTypePointer Private %int
2774 %var1 = OpVariable %int_ptr_priv Private
2775 %var2 = OpVariable %int_ptr_priv Private
2776 %voidfn = OpTypeFunction %void
2777 %func = OpFunction %void None %voidfn
2778 %entry = OpLabel
2779 OpCopyMemorySized %var1 %var2 %int_16
2780 OpReturn
2781 OpFunctionEnd
2782 )";
2783 
2784   CompileSuccessfully(spirv);
2785   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
2786   EXPECT_THAT(getDiagnosticString(), Eq(""));
2787 }
2788 
TEST_F(ValidateMemory,CopyMemorySizedSimpleMixedAccessGood)2789 TEST_F(ValidateMemory, CopyMemorySizedSimpleMixedAccessGood) {
2790   // Test one memory access operand using features that don't require the
2791   // Vulkan memory model.
2792   const std::string spirv = R"(
2793 OpCapability Shader
2794 OpCapability Linkage
2795 OpCapability Addresses
2796 OpMemoryModel Logical GLSL450
2797 %void = OpTypeVoid
2798 %int = OpTypeInt 32 0
2799 %int_16 = OpConstant %int 16
2800 %int_ptr_priv = OpTypePointer Private %int
2801 %var1 = OpVariable %int_ptr_priv Private
2802 %var2 = OpVariable %int_ptr_priv Private
2803 %voidfn = OpTypeFunction %void
2804 %func = OpFunction %void None %voidfn
2805 %entry = OpLabel
2806 OpCopyMemorySized %var1 %var2 %int_16 Volatile|Aligned|Nontemporal 4
2807 OpReturn
2808 OpFunctionEnd
2809 )";
2810 
2811   CompileSuccessfully(spirv);
2812   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
2813 }
2814 
TEST_F(ValidateMemory,CopyMemorySizedSimpleTwoMixedAccessV13Bad)2815 TEST_F(ValidateMemory, CopyMemorySizedSimpleTwoMixedAccessV13Bad) {
2816   // Two memory access operands is invalid up to SPIR-V 1.3
2817   const std::string spirv = R"(
2818 OpCapability Shader
2819 OpCapability Linkage
2820 OpCapability Addresses
2821 OpMemoryModel Logical GLSL450
2822 %void = OpTypeVoid
2823 %int = OpTypeInt 32 0
2824 %int_16 = OpConstant %int 16
2825 %int_ptr_priv = OpTypePointer Private %int
2826 %var1 = OpVariable %int_ptr_priv Private
2827 %var2 = OpVariable %int_ptr_priv Private
2828 %voidfn = OpTypeFunction %void
2829 %func = OpFunction %void None %voidfn
2830 %entry = OpLabel
2831 OpCopyMemorySized %var1 %var2 %int_16 Volatile Volatile
2832 OpReturn
2833 OpFunctionEnd
2834 )";
2835 
2836   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
2837   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
2838             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
2839   EXPECT_THAT(
2840       getDiagnosticString(),
2841       HasSubstr("CopyMemorySized with two memory access operands requires "
2842                 "SPIR-V 1.4 or later"));
2843 }
2844 
TEST_F(ValidateMemory,CopyMemorySizedSimpleTwoMixedAccessV14Good)2845 TEST_F(ValidateMemory, CopyMemorySizedSimpleTwoMixedAccessV14Good) {
2846   // Two memory access operands is valid in SPIR-V 1.4
2847   const std::string spirv = R"(
2848 OpCapability Shader
2849 OpCapability Linkage
2850 OpCapability Addresses
2851 OpMemoryModel Logical GLSL450
2852 %void = OpTypeVoid
2853 %int = OpTypeInt 32 0
2854 %int_16 = OpConstant %int 16
2855 %int_ptr_priv = OpTypePointer Private %int
2856 %var1 = OpVariable %int_ptr_priv Private
2857 %var2 = OpVariable %int_ptr_priv Private
2858 %voidfn = OpTypeFunction %void
2859 %func = OpFunction %void None %voidfn
2860 %entry = OpLabel
2861 OpCopyMemorySized %var1 %var2 %int_16 Volatile Volatile
2862 OpReturn
2863 OpFunctionEnd
2864 )";
2865 
2866   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
2867   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
2868   EXPECT_THAT(getDiagnosticString(), Eq(""));
2869 }
2870 
2871 using ValidatePointerComparisons = spvtest::ValidateBase<std::string>;
2872 
TEST_P(ValidatePointerComparisons,Good)2873 TEST_P(ValidatePointerComparisons, Good) {
2874   const std::string operation = GetParam();
2875 
2876   std::string spirv = R"(
2877 OpCapability Shader
2878 OpCapability Linkage
2879 OpCapability VariablePointersStorageBuffer
2880 OpMemoryModel Logical GLSL450
2881 %void = OpTypeVoid
2882 %bool = OpTypeBool
2883 %int = OpTypeInt 32 0
2884 %ptr_int = OpTypePointer StorageBuffer %int
2885 %var = OpVariable %ptr_int StorageBuffer
2886 %func_ty = OpTypeFunction %void
2887 %func = OpFunction %void None %func_ty
2888 %1 = OpLabel
2889 %equal = )" + operation;
2890 
2891   if (operation == "OpPtrDiff") {
2892     spirv += " %int ";
2893   } else {
2894     spirv += " %bool ";
2895   }
2896 
2897   spirv += R"(%var %var
2898 OpReturn
2899 OpFunctionEnd
2900 )";
2901 
2902   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
2903   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
2904 }
2905 
TEST_P(ValidatePointerComparisons,GoodWorkgroup)2906 TEST_P(ValidatePointerComparisons, GoodWorkgroup) {
2907   const std::string operation = GetParam();
2908 
2909   std::string spirv = R"(
2910 OpCapability Shader
2911 OpCapability Linkage
2912 OpCapability VariablePointers
2913 OpMemoryModel Logical GLSL450
2914 %void = OpTypeVoid
2915 %bool = OpTypeBool
2916 %int = OpTypeInt 32 0
2917 %ptr_int = OpTypePointer Workgroup %int
2918 %var = OpVariable %ptr_int Workgroup
2919 %func_ty = OpTypeFunction %void
2920 %func = OpFunction %void None %func_ty
2921 %1 = OpLabel
2922 %equal = )" + operation;
2923 
2924   if (operation == "OpPtrDiff") {
2925     spirv += " %int ";
2926   } else {
2927     spirv += " %bool ";
2928   }
2929 
2930   spirv += R"(%var %var
2931 OpReturn
2932 OpFunctionEnd
2933 )";
2934 
2935   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
2936   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
2937 }
2938 
TEST_P(ValidatePointerComparisons,BadResultType)2939 TEST_P(ValidatePointerComparisons, BadResultType) {
2940   const std::string operation = GetParam();
2941 
2942   std::string spirv = R"(
2943 OpCapability Shader
2944 OpCapability Linkage
2945 OpCapability VariablePointersStorageBuffer
2946 OpMemoryModel Logical GLSL450
2947 %void = OpTypeVoid
2948 %bool = OpTypeBool
2949 %int = OpTypeInt 32 0
2950 %ptr_int = OpTypePointer StorageBuffer %int
2951 %var = OpVariable %ptr_int StorageBuffer
2952 %func_ty = OpTypeFunction %void
2953 %func = OpFunction %void None %func_ty
2954 %1 = OpLabel
2955 %equal = )" + operation;
2956 
2957   if (operation == "OpPtrDiff") {
2958     spirv += " %bool ";
2959   } else {
2960     spirv += " %int ";
2961   }
2962 
2963   spirv += R"(%var %var
2964 OpReturn
2965 OpFunctionEnd
2966 )";
2967 
2968   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
2969   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
2970   if (operation == "OpPtrDiff") {
2971     EXPECT_THAT(getDiagnosticString(),
2972                 HasSubstr("Result Type must be an integer scalar"));
2973   } else {
2974     EXPECT_THAT(getDiagnosticString(),
2975                 HasSubstr("Result Type must be OpTypeBool"));
2976   }
2977 }
2978 
TEST_P(ValidatePointerComparisons,BadCapabilities)2979 TEST_P(ValidatePointerComparisons, BadCapabilities) {
2980   const std::string operation = GetParam();
2981 
2982   std::string spirv = R"(
2983 OpCapability Shader
2984 OpCapability Linkage
2985 OpMemoryModel Logical GLSL450
2986 %void = OpTypeVoid
2987 %bool = OpTypeBool
2988 %int = OpTypeInt 32 0
2989 %ptr_int = OpTypePointer StorageBuffer %int
2990 %var = OpVariable %ptr_int StorageBuffer
2991 %func_ty = OpTypeFunction %void
2992 %func = OpFunction %void None %func_ty
2993 %1 = OpLabel
2994 %equal = )" + operation;
2995 
2996   if (operation == "OpPtrDiff") {
2997     spirv += " %int ";
2998   } else {
2999     spirv += " %bool ";
3000   }
3001 
3002   spirv += R"(%var %var
3003 OpReturn
3004 OpFunctionEnd
3005 )";
3006 
3007   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
3008   if (operation == "OpPtrDiff") {
3009     // Gets caught by the grammar.
3010     EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY,
3011               ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
3012   } else {
3013     EXPECT_EQ(SPV_ERROR_INVALID_ID,
3014               ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
3015     EXPECT_THAT(getDiagnosticString(),
3016                 HasSubstr("Instruction cannot be used without a variable "
3017                           "pointers capability"));
3018   }
3019 }
3020 
TEST_P(ValidatePointerComparisons,BadOperandType)3021 TEST_P(ValidatePointerComparisons, BadOperandType) {
3022   const std::string operation = GetParam();
3023 
3024   std::string spirv = R"(
3025 OpCapability Shader
3026 OpCapability Linkage
3027 OpCapability VariablePointersStorageBuffer
3028 OpMemoryModel Logical GLSL450
3029 %void = OpTypeVoid
3030 %bool = OpTypeBool
3031 %int = OpTypeInt 32 0
3032 %ptr_int = OpTypePointer StorageBuffer %int
3033 %var = OpVariable %ptr_int StorageBuffer
3034 %func_ty = OpTypeFunction %void
3035 %func = OpFunction %void None %func_ty
3036 %1 = OpLabel
3037 %ld = OpLoad %int %var
3038 %equal = )" + operation;
3039 
3040   if (operation == "OpPtrDiff") {
3041     spirv += " %int ";
3042   } else {
3043     spirv += " %bool ";
3044   }
3045 
3046   spirv += R"(%ld %ld
3047 OpReturn
3048 OpFunctionEnd
3049 )";
3050 
3051   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
3052   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
3053   EXPECT_THAT(getDiagnosticString(),
3054               HasSubstr("Operand type must be a pointer"));
3055 }
3056 
TEST_P(ValidatePointerComparisons,BadStorageClassWorkgroup)3057 TEST_P(ValidatePointerComparisons, BadStorageClassWorkgroup) {
3058   const std::string operation = GetParam();
3059 
3060   std::string spirv = R"(
3061 OpCapability Shader
3062 OpCapability Linkage
3063 OpCapability VariablePointersStorageBuffer
3064 OpMemoryModel Logical GLSL450
3065 %void = OpTypeVoid
3066 %bool = OpTypeBool
3067 %int = OpTypeInt 32 0
3068 %ptr_int = OpTypePointer Workgroup %int
3069 %var = OpVariable %ptr_int Workgroup
3070 %func_ty = OpTypeFunction %void
3071 %func = OpFunction %void None %func_ty
3072 %1 = OpLabel
3073 %equal = )" + operation;
3074 
3075   if (operation == "OpPtrDiff") {
3076     spirv += " %int ";
3077   } else {
3078     spirv += " %bool ";
3079   }
3080 
3081   spirv += R"(%var %var
3082 OpReturn
3083 OpFunctionEnd
3084 )";
3085 
3086   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
3087   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
3088   EXPECT_THAT(getDiagnosticString(),
3089               HasSubstr("Workgroup storage class pointer requires "
3090                         "VariablePointers capability to be specified"));
3091 }
3092 
TEST_P(ValidatePointerComparisons,BadStorageClass)3093 TEST_P(ValidatePointerComparisons, BadStorageClass) {
3094   const std::string operation = GetParam();
3095 
3096   std::string spirv = R"(
3097 OpCapability Shader
3098 OpCapability Linkage
3099 OpCapability VariablePointersStorageBuffer
3100 OpMemoryModel Logical GLSL450
3101 %void = OpTypeVoid
3102 %bool = OpTypeBool
3103 %int = OpTypeInt 32 0
3104 %ptr_int = OpTypePointer Private %int
3105 %var = OpVariable %ptr_int Private
3106 %func_ty = OpTypeFunction %void
3107 %func = OpFunction %void None %func_ty
3108 %1 = OpLabel
3109 %equal = )" + operation;
3110 
3111   if (operation == "OpPtrDiff") {
3112     spirv += " %int ";
3113   } else {
3114     spirv += " %bool ";
3115   }
3116 
3117   spirv += R"(%var %var
3118 OpReturn
3119 OpFunctionEnd
3120 )";
3121 
3122   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
3123   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
3124   EXPECT_THAT(getDiagnosticString(),
3125               HasSubstr("Invalid pointer storage class"));
3126 }
3127 
TEST_P(ValidatePointerComparisons,BadDiffOperandTypes)3128 TEST_P(ValidatePointerComparisons, BadDiffOperandTypes) {
3129   const std::string operation = GetParam();
3130 
3131   std::string spirv = R"(
3132 OpCapability Shader
3133 OpCapability Linkage
3134 OpCapability VariablePointersStorageBuffer
3135 OpMemoryModel Logical GLSL450
3136 %void = OpTypeVoid
3137 %bool = OpTypeBool
3138 %int = OpTypeInt 32 0
3139 %ptr_int = OpTypePointer Private %int
3140 %var = OpVariable %ptr_int Private
3141 %func_ty = OpTypeFunction %void
3142 %func = OpFunction %void None %func_ty
3143 %1 = OpLabel
3144 %ld = OpLoad %int %var
3145 %equal = )" + operation;
3146 
3147   if (operation == "OpPtrDiff") {
3148     spirv += " %int ";
3149   } else {
3150     spirv += " %bool ";
3151   }
3152 
3153   spirv += R"(%var %ld
3154 OpReturn
3155 OpFunctionEnd
3156 )";
3157 
3158   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
3159   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
3160   EXPECT_THAT(getDiagnosticString(),
3161               HasSubstr("The types of Operand 1 and Operand 2 must match"));
3162 }
3163 
3164 INSTANTIATE_TEST_SUITE_P(PointerComparisons, ValidatePointerComparisons,
3165                          Values("OpPtrEqual", "OpPtrNotEqual", "OpPtrDiff"));
3166 
TEST_F(ValidateMemory,VariableInitializerWrongType)3167 TEST_F(ValidateMemory, VariableInitializerWrongType) {
3168   const std::string spirv = R"(
3169 OpCapability Shader
3170 OpCapability Linkage
3171 OpCapability VariablePointersStorageBuffer
3172 OpMemoryModel Logical GLSL450
3173 %void = OpTypeVoid
3174 %int = OpTypeInt 32 0
3175 %float = OpTypeFloat 32
3176 %ptr_wg_int = OpTypePointer Workgroup %int
3177 %ptr_wg_float = OpTypePointer Workgroup %int
3178 %wg_var = OpVariable %ptr_wg_int Workgroup
3179 %ptr_private_wg_float = OpTypePointer Private %ptr_wg_float
3180 %priv_var = OpVariable %ptr_private_wg_float Private %wg_var
3181 )";
3182 
3183   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
3184   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
3185   EXPECT_THAT(getDiagnosticString(),
3186               HasSubstr("Initializer type must match the type pointed to by "
3187                         "the Result Type"));
3188 }
3189 
TEST_F(ValidateMemory,StoreToUniformBlock)3190 TEST_F(ValidateMemory, StoreToUniformBlock) {
3191   const std::string spirv = R"(
3192 OpCapability Shader
3193 OpMemoryModel Logical GLSL450
3194 OpEntryPoint GLCompute %main "main"
3195 OpExecutionMode %main LocalSize 1 1 1
3196 OpDecorate %struct Block
3197 OpMemberDecorate %struct 0 Offset 0
3198 OpDecorate %var DescriptorSet 0
3199 OpDecorate %var Binding 0
3200 %void = OpTypeVoid
3201 %int = OpTypeInt 32 0
3202 %int_0 = OpConstant %int 0
3203 %int4 = OpTypeVector %int 4
3204 %struct = OpTypeStruct %int4
3205 %ptr_uniform_struct = OpTypePointer Uniform %struct
3206 %ptr_uniform_int4 = OpTypePointer Uniform %int4
3207 %ptr_uniform_int = OpTypePointer Uniform %int
3208 %var = OpVariable %ptr_uniform_struct Uniform
3209 %void_fn = OpTypeFunction %void
3210 %main = OpFunction %void None %void_fn
3211 %entry = OpLabel
3212 %gep1 = OpAccessChain %ptr_uniform_int4 %var %int_0
3213 %gep2 = OpAccessChain %ptr_uniform_int %gep1 %int_0
3214 OpStore %gep2 %int_0
3215 OpReturn
3216 OpFunctionEnd
3217 )";
3218 
3219   CompileSuccessfully(spirv);
3220   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
3221 }
3222 
TEST_F(ValidateMemory,StoreToUniformBlockVulkan)3223 TEST_F(ValidateMemory, StoreToUniformBlockVulkan) {
3224   const std::string spirv = R"(
3225 OpCapability Shader
3226 OpMemoryModel Logical GLSL450
3227 OpEntryPoint GLCompute %main "main"
3228 OpExecutionMode %main LocalSize 1 1 1
3229 OpDecorate %struct Block
3230 OpMemberDecorate %struct 0 Offset 0
3231 OpDecorate %var DescriptorSet 0
3232 OpDecorate %var Binding 0
3233 %void = OpTypeVoid
3234 %int = OpTypeInt 32 0
3235 %int_0 = OpConstant %int 0
3236 %int4 = OpTypeVector %int 4
3237 %struct = OpTypeStruct %int4
3238 %ptr_uniform_struct = OpTypePointer Uniform %struct
3239 %ptr_uniform_int4 = OpTypePointer Uniform %int4
3240 %ptr_uniform_int = OpTypePointer Uniform %int
3241 %var = OpVariable %ptr_uniform_struct Uniform
3242 %void_fn = OpTypeFunction %void
3243 %main = OpFunction %void None %void_fn
3244 %entry = OpLabel
3245 %gep1 = OpAccessChain %ptr_uniform_int4 %var %int_0
3246 %gep2 = OpAccessChain %ptr_uniform_int %gep1 %int_0
3247 OpStore %gep2 %int_0
3248 OpReturn
3249 OpFunctionEnd
3250 )";
3251 
3252   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
3253   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
3254   EXPECT_THAT(
3255       getDiagnosticString(),
3256       HasSubstr("In the Vulkan environment, cannot store to Uniform Blocks"));
3257 }
3258 
3259 // This test requires that the struct is not id 2.
TEST_F(ValidateMemory,StoreToUniformBlockVulkan2)3260 TEST_F(ValidateMemory, StoreToUniformBlockVulkan2) {
3261   const std::string spirv = R"(
3262 OpCapability Shader
3263 OpMemoryModel Logical GLSL450
3264 OpEntryPoint GLCompute %main "main" %gid_var
3265 OpExecutionMode %main LocalSize 1 1 1
3266 OpDecorate %3 Block
3267 OpMemberDecorate %3 0 Offset 0
3268 OpDecorate %var DescriptorSet 0
3269 OpDecorate %var Binding 0
3270 OpDecorate %gid_var BuiltIn GlobalInvocationId
3271 %void = OpTypeVoid
3272 %int = OpTypeInt 32 0
3273 %int_0 = OpConstant %int 0
3274 %int3 = OpTypeVector %int 3
3275 %int4 = OpTypeVector %int 4
3276 %3 = OpTypeStruct %int4
3277 %ptr_uniform_struct = OpTypePointer Uniform %3
3278 %ptr_uniform_int4 = OpTypePointer Uniform %int4
3279 %ptr_uniform_int = OpTypePointer Uniform %int
3280 %var = OpVariable %ptr_uniform_struct Uniform
3281 %ptr_input_int3 = OpTypePointer Input %int3
3282 %gid_var = OpVariable %ptr_input_int3 Input
3283 %void_fn = OpTypeFunction %void
3284 %main = OpFunction %void None %void_fn
3285 %entry = OpLabel
3286 %gep1 = OpAccessChain %ptr_uniform_int4 %var %int_0
3287 %gep2 = OpAccessChain %ptr_uniform_int %gep1 %int_0
3288 OpStore %gep2 %int_0
3289 OpReturn
3290 OpFunctionEnd
3291 )";
3292 
3293   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
3294   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
3295   EXPECT_THAT(
3296       getDiagnosticString(),
3297       HasSubstr("In the Vulkan environment, cannot store to Uniform Blocks"));
3298 }
3299 
TEST_F(ValidateMemory,StoreToUniformBufferBlockVulkan)3300 TEST_F(ValidateMemory, StoreToUniformBufferBlockVulkan) {
3301   const std::string spirv = R"(
3302 OpCapability Shader
3303 OpMemoryModel Logical GLSL450
3304 OpEntryPoint GLCompute %main "main"
3305 OpExecutionMode %main LocalSize 1 1 1
3306 OpDecorate %struct BufferBlock
3307 OpMemberDecorate %struct 0 Offset 0
3308 OpDecorate %var DescriptorSet 0
3309 OpDecorate %var Binding 0
3310 %void = OpTypeVoid
3311 %int = OpTypeInt 32 0
3312 %int_0 = OpConstant %int 0
3313 %int4 = OpTypeVector %int 4
3314 %struct = OpTypeStruct %int4
3315 %ptr_uniform_struct = OpTypePointer Uniform %struct
3316 %ptr_uniform_int4 = OpTypePointer Uniform %int4
3317 %ptr_uniform_int = OpTypePointer Uniform %int
3318 %var = OpVariable %ptr_uniform_struct Uniform
3319 %void_fn = OpTypeFunction %void
3320 %main = OpFunction %void None %void_fn
3321 %entry = OpLabel
3322 %gep1 = OpAccessChain %ptr_uniform_int4 %var %int_0
3323 %gep2 = OpAccessChain %ptr_uniform_int %gep1 %int_0
3324 OpStore %gep2 %int_0
3325 OpReturn
3326 OpFunctionEnd
3327 )";
3328 
3329   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
3330   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
3331 }
3332 
TEST_F(ValidateMemory,StoreToUniformBlockVulkanArray)3333 TEST_F(ValidateMemory, StoreToUniformBlockVulkanArray) {
3334   const std::string spirv = R"(
3335 OpCapability Shader
3336 OpMemoryModel Logical GLSL450
3337 OpEntryPoint GLCompute %main "main"
3338 OpExecutionMode %main LocalSize 1 1 1
3339 OpDecorate %struct Block
3340 OpMemberDecorate %struct 0 Offset 0
3341 OpDecorate %var DescriptorSet 0
3342 OpDecorate %var Binding 0
3343 %void = OpTypeVoid
3344 %int = OpTypeInt 32 0
3345 %int_0 = OpConstant %int 0
3346 %int_1 = OpConstant %int 1
3347 %int4 = OpTypeVector %int 4
3348 %struct = OpTypeStruct %int4
3349 %array_struct = OpTypeArray %struct %int_1
3350 %ptr_uniform_array = OpTypePointer Uniform %array_struct
3351 %ptr_uniform_struct = OpTypePointer Uniform %struct
3352 %ptr_uniform_int4 = OpTypePointer Uniform %int4
3353 %ptr_uniform_int = OpTypePointer Uniform %int
3354 %var = OpVariable %ptr_uniform_array Uniform
3355 %void_fn = OpTypeFunction %void
3356 %main = OpFunction %void None %void_fn
3357 %entry = OpLabel
3358 %gep1 = OpAccessChain %ptr_uniform_int %var %int_0 %int_0 %int_0
3359 %gep2 = OpCopyObject %ptr_uniform_int %gep1
3360 OpStore %gep2 %int_0
3361 OpReturn
3362 OpFunctionEnd
3363 )";
3364 
3365   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
3366   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
3367   EXPECT_THAT(
3368       getDiagnosticString(),
3369       HasSubstr("In the Vulkan environment, cannot store to Uniform Blocks"));
3370 }
3371 
3372 // This test requires that the struct is not id 2.
TEST_F(ValidateMemory,StoreToUniformBlockVulkanArray2)3373 TEST_F(ValidateMemory, StoreToUniformBlockVulkanArray2) {
3374   const std::string spirv = R"(
3375 OpCapability Shader
3376 OpMemoryModel Logical GLSL450
3377 OpEntryPoint GLCompute %main "main" %gid_var
3378 OpExecutionMode %main LocalSize 1 1 1
3379 OpDecorate %struct Block
3380 OpMemberDecorate %struct 0 Offset 0
3381 OpDecorate %var DescriptorSet 0
3382 OpDecorate %var Binding 0
3383 OpDecorate %gid_var BuiltIn GlobalInvocationId
3384 %void = OpTypeVoid
3385 %int = OpTypeInt 32 0
3386 %int_0 = OpConstant %int 0
3387 %int_1 = OpConstant %int 1
3388 %int3 = OpTypeVector %int 3
3389 %int4 = OpTypeVector %int 4
3390 %struct = OpTypeStruct %int4
3391 %array_struct = OpTypeArray %struct %int_1
3392 %ptr_uniform_array = OpTypePointer Uniform %array_struct
3393 %ptr_uniform_struct = OpTypePointer Uniform %struct
3394 %ptr_uniform_int4 = OpTypePointer Uniform %int4
3395 %ptr_uniform_int = OpTypePointer Uniform %int
3396 %var = OpVariable %ptr_uniform_array Uniform
3397 %ptr_input_int3 = OpTypePointer Input %int3
3398 %gid_var = OpVariable %ptr_input_int3 Input
3399 %void_fn = OpTypeFunction %void
3400 %main = OpFunction %void None %void_fn
3401 %entry = OpLabel
3402 %gep1 = OpAccessChain %ptr_uniform_int %var %int_0 %int_0 %int_0
3403 %gep2 = OpCopyObject %ptr_uniform_int %gep1
3404 OpStore %gep2 %int_0
3405 OpReturn
3406 OpFunctionEnd
3407 )";
3408 
3409   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
3410   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
3411   EXPECT_THAT(
3412       getDiagnosticString(),
3413       HasSubstr("In the Vulkan environment, cannot store to Uniform Blocks"));
3414 }
3415 
TEST_F(ValidateMemory,StoreToUniformBlockVulkanRuntimeArray)3416 TEST_F(ValidateMemory, StoreToUniformBlockVulkanRuntimeArray) {
3417   const std::string spirv = R"(
3418 OpCapability Shader
3419 OpCapability RuntimeDescriptorArrayEXT
3420 OpExtension "SPV_EXT_descriptor_indexing"
3421 OpMemoryModel Logical GLSL450
3422 OpEntryPoint GLCompute %main "main"
3423 OpExecutionMode %main LocalSize 1 1 1
3424 OpDecorate %struct Block
3425 OpMemberDecorate %struct 0 Offset 0
3426 OpDecorate %var DescriptorSet 0
3427 OpDecorate %var Binding 0
3428 %void = OpTypeVoid
3429 %int = OpTypeInt 32 0
3430 %int_0 = OpConstant %int 0
3431 %int4 = OpTypeVector %int 4
3432 %struct = OpTypeStruct %int4
3433 %array_struct = OpTypeRuntimeArray %struct
3434 %ptr_uniform_array = OpTypePointer Uniform %array_struct
3435 %ptr_uniform_struct = OpTypePointer Uniform %struct
3436 %ptr_uniform_int4 = OpTypePointer Uniform %int4
3437 %ptr_uniform_int = OpTypePointer Uniform %int
3438 %var = OpVariable %ptr_uniform_array Uniform
3439 %void_fn = OpTypeFunction %void
3440 %main = OpFunction %void None %void_fn
3441 %entry = OpLabel
3442 %gep1 = OpAccessChain %ptr_uniform_int4 %var %int_0 %int_0
3443 %gep2 = OpInBoundsAccessChain %ptr_uniform_int %gep1 %int_0
3444 OpStore %gep2 %int_0
3445 OpReturn
3446 OpFunctionEnd
3447 )";
3448 
3449   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
3450   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
3451   EXPECT_THAT(
3452       getDiagnosticString(),
3453       HasSubstr("In the Vulkan environment, cannot store to Uniform Blocks"));
3454 }
3455 
3456 using ValidateSizedVariable =
3457     spvtest::ValidateBase<std::tuple<std::string, std::string,
3458                                      std::string, spv_target_env>>;
3459 
GetSizedVariableCodeGenerator(bool is_8bit,bool buffer_block)3460 CodeGenerator GetSizedVariableCodeGenerator(bool is_8bit, bool buffer_block) {
3461   CodeGenerator generator;
3462   generator.capabilities_ = "OpCapability Shader\nOpCapability Linkage\n";
3463   generator.extensions_ =
3464       "OpExtension \"SPV_KHR_16bit_storage\"\nOpExtension "
3465       "\"SPV_KHR_8bit_storage\"\n";
3466   generator.memory_model_ = "OpMemoryModel Logical GLSL450\n";
3467   if (is_8bit) {
3468     generator.before_types_ = "OpMemberDecorate %char_buffer_block 0 Offset 0\n";
3469     if (buffer_block)
3470       generator.before_types_ += "OpDecorate %char_buffer_block BufferBlock\n";
3471 
3472     generator.types_ = R"(%void = OpTypeVoid
3473 %char = OpTypeInt 8 0
3474 %char4 = OpTypeVector %char 4
3475 %char_buffer_block = OpTypeStruct %char
3476 )";
3477   } else {
3478     generator.before_types_ =
3479         "OpMemberDecorate %half_buffer_block 0 Offset 0\n"
3480         "OpMemberDecorate %short_buffer_block 0 Offset 0\n";
3481     if (buffer_block) {
3482       generator.before_types_ +=
3483           "OpDecorate %half_buffer_block BufferBlock\n"
3484           "OpDecorate %short_buffer_block BufferBlock\n";
3485     }
3486 
3487     generator.types_ = R"(%void = OpTypeVoid
3488 %short = OpTypeInt 16 0
3489 %half = OpTypeFloat 16
3490 %short4 = OpTypeVector %short 4
3491 %half4 = OpTypeVector %half 4
3492 %mat4x4 = OpTypeMatrix %half4 4
3493 %short_buffer_block = OpTypeStruct %short
3494 %half_buffer_block = OpTypeStruct %half
3495 )";
3496   }
3497   generator.after_types_ = R"(%void_fn = OpTypeFunction %void
3498 %func = OpFunction %void None %void_fn
3499 %entry = OpLabel
3500 )";
3501   generator.add_at_the_end_ = "OpReturn\nOpFunctionEnd\n";
3502   return generator;
3503 }
3504 
TEST_P(ValidateSizedVariable,Capability)3505 TEST_P(ValidateSizedVariable, Capability) {
3506   const std::string storage_class = std::get<0>(GetParam());
3507   const std::string capability = std::get<1>(GetParam());
3508   const std::string var_type = std::get<2>(GetParam());
3509   const spv_target_env target = std::get<3>(GetParam());
3510 
3511   ASSERT_TRUE(target == SPV_ENV_UNIVERSAL_1_3 ||
3512               target == SPV_ENV_UNIVERSAL_1_4);
3513 
3514   bool type_8bit = false;
3515   if (var_type == "%char" || var_type == "%char4" ||
3516       var_type == "%char_buffer_block") {
3517     type_8bit = true;
3518   }
3519 
3520   const bool buffer_block = var_type.find("buffer_block") != std::string::npos;
3521 
3522   auto generator = GetSizedVariableCodeGenerator(type_8bit, buffer_block);
3523 
3524   if (capability == "WorkgroupMemoryExplicitLayout8BitAccessKHR" ||
3525       capability == "WorkgroupMemoryExplicitLayout16BitAccessKHR") {
3526     generator.extensions_ +=
3527         "OpExtension \"SPV_KHR_workgroup_memory_explicit_layout\"\n";
3528   }
3529 
3530   generator.types_ += "%ptr_type = OpTypePointer " + storage_class + " " +
3531                       var_type + "\n%var = OpVariable %ptr_type " +
3532                       storage_class + "\n";
3533   generator.capabilities_ += "OpCapability " + capability + "\n";
3534 
3535   bool capability_ok = false;
3536   bool storage_class_ok = false;
3537   if (storage_class == "Input" || storage_class == "Output") {
3538     if (!type_8bit) {
3539       capability_ok = capability == "StorageInputOutput16";
3540       storage_class_ok = true;
3541     }
3542   } else if (storage_class == "StorageBuffer") {
3543     if (type_8bit) {
3544       capability_ok = capability == "StorageBuffer8BitAccess" ||
3545                       capability == "UniformAndStorageBuffer8BitAccess";
3546     } else {
3547       capability_ok = capability == "StorageBuffer16BitAccess" ||
3548                       capability == "UniformAndStorageBuffer16BitAccess";
3549     }
3550     storage_class_ok = true;
3551   } else if (storage_class == "PushConstant") {
3552     if (type_8bit) {
3553       capability_ok = capability == "StoragePushConstant8";
3554     } else {
3555       capability_ok = capability == "StoragePushConstant16";
3556     }
3557     storage_class_ok = true;
3558   } else if (storage_class == "Uniform") {
3559     if (type_8bit) {
3560       capability_ok = capability == "UniformAndStorageBuffer8BitAccess" ||
3561                       (capability == "StorageBuffer8BitAccess" && buffer_block);
3562     } else {
3563       capability_ok =
3564           capability == "UniformAndStorageBuffer16BitAccess" ||
3565           (capability == "StorageBuffer16BitAccess" && buffer_block);
3566     }
3567     storage_class_ok = true;
3568   } else if (storage_class == "Workgroup") {
3569     if (type_8bit) {
3570       capability_ok =
3571           capability == "WorkgroupMemoryExplicitLayout8BitAccessKHR";
3572     } else {
3573       capability_ok =
3574           capability == "WorkgroupMemoryExplicitLayout16BitAccessKHR";
3575     }
3576     storage_class_ok = true;
3577   }
3578 
3579   CompileSuccessfully(generator.Build(), target);
3580   spv_result_t result = ValidateInstructions(target);
3581   if (target < SPV_ENV_UNIVERSAL_1_4 &&
3582       (capability == "WorkgroupMemoryExplicitLayout8BitAccessKHR" ||
3583        capability == "WorkgroupMemoryExplicitLayout16BitAccessKHR")) {
3584     EXPECT_EQ(SPV_ERROR_WRONG_VERSION, result);
3585     EXPECT_THAT(getDiagnosticString(),
3586                 HasSubstr("requires SPIR-V version 1.4 or later"));
3587   } else if (buffer_block && target > SPV_ENV_UNIVERSAL_1_3) {
3588     EXPECT_EQ(SPV_ERROR_WRONG_VERSION, result);
3589     EXPECT_THAT(getDiagnosticString(),
3590                 HasSubstr("requires SPIR-V version 1.3 or earlier"));
3591   } else if (capability_ok) {
3592     EXPECT_EQ(SPV_SUCCESS, result);
3593   } else {
3594     EXPECT_EQ(SPV_ERROR_INVALID_ID, result);
3595     if (storage_class_ok) {
3596       std::string message = std::string("Allocating a variable containing a ") +
3597                             (type_8bit ? "8" : "16") + "-bit element in " +
3598                             storage_class +
3599                             " storage class requires an additional capability";
3600       EXPECT_THAT(getDiagnosticString(), HasSubstr(message));
3601     } else {
3602       std::string message =
3603           std::string("Cannot allocate a variable containing a ") +
3604           (type_8bit ? "8" : "16") + "-bit type in " + storage_class +
3605           " storage class";
3606       EXPECT_THAT(getDiagnosticString(), HasSubstr(message));
3607     }
3608   }
3609 }
3610 
3611 INSTANTIATE_TEST_SUITE_P(
3612     Storage8, ValidateSizedVariable,
3613     Combine(Values("UniformConstant", "Input", "Output", "Workgroup",
3614                    "CrossWorkgroup", "Private", "StorageBuffer", "Uniform"),
3615             Values("StorageBuffer8BitAccess",
3616                    "UniformAndStorageBuffer8BitAccess", "StoragePushConstant8",
3617                    "WorkgroupMemoryExplicitLayout8BitAccessKHR"),
3618             Values("%char", "%char4", "%char_buffer_block"),
3619             Values(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_UNIVERSAL_1_4)));
3620 
3621 INSTANTIATE_TEST_SUITE_P(
3622     Storage16, ValidateSizedVariable,
3623     Combine(Values("UniformConstant", "Input", "Output", "Workgroup",
3624                    "CrossWorkgroup", "Private", "StorageBuffer", "Uniform"),
3625             Values("StorageBuffer16BitAccess",
3626                    "UniformAndStorageBuffer16BitAccess",
3627                    "StoragePushConstant16", "StorageInputOutput16",
3628                    "WorkgroupMemoryExplicitLayout16BitAccessKHR"),
3629             Values("%short", "%half", "%short4", "%half4", "%mat4x4",
3630                    "%short_buffer_block", "%half_buffer_block"),
3631             Values(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_UNIVERSAL_1_4)));
3632 
3633 using ValidateSizedLoadStore =
3634     spvtest::ValidateBase<std::tuple<std::string, uint32_t, std::string>>;
3635 
GetSizedLoadStoreCodeGenerator(const std::string & base_type,uint32_t width)3636 CodeGenerator GetSizedLoadStoreCodeGenerator(const std::string& base_type,
3637                                              uint32_t width) {
3638   CodeGenerator generator;
3639   generator.capabilities_ = "OpCapability Shader\nOpCapability Linkage\n";
3640   if (width == 8) {
3641     generator.capabilities_ +=
3642         "OpCapability UniformAndStorageBuffer8BitAccess\n";
3643     generator.extensions_ = "OpExtension \"SPV_KHR_8bit_storage\"\n";
3644   } else {
3645     generator.capabilities_ +=
3646         "OpCapability UniformAndStorageBuffer16BitAccess\n";
3647     generator.extensions_ = "OpExtension \"SPV_KHR_16bit_storage\"\n";
3648   }
3649   generator.memory_model_ = "OpMemoryModel Logical GLSL450\n";
3650   generator.before_types_ = R"(OpDecorate %block Block
3651 OpMemberDecorate %block 0 Offset 0
3652 OpMemberDecorate %struct 0 Offset 0
3653 )";
3654   generator.types_ = R"(%void = OpTypeVoid
3655 %int = OpTypeInt 32 0
3656 %int_0 = OpConstant %int 0
3657 %int_1 = OpConstant %int 1
3658 %int_2 = OpConstant %int 2
3659 %int_3 = OpConstant %int 3
3660 )";
3661 
3662   if (width == 8) {
3663     generator.types_ += R"(%scalar = OpTypeInt 8 0
3664 %vector = OpTypeVector %scalar 4
3665 %struct = OpTypeStruct %vector
3666 )";
3667   } else if (base_type == "int") {
3668     generator.types_ += R"(%scalar = OpTypeInt 16 0
3669 %vector = OpTypeVector %scalar 4
3670 %struct = OpTypeStruct %vector
3671 )";
3672   } else {
3673     generator.types_ += R"(%scalar = OpTypeFloat 16
3674 %vector = OpTypeVector %scalar 4
3675 %matrix = OpTypeMatrix %vector 4
3676 %struct = OpTypeStruct %matrix
3677 %ptr_ssbo_matrix = OpTypePointer StorageBuffer %matrix
3678 )";
3679     generator.before_types_ += R"(OpMemberDecorate %struct 0 RowMajor
3680 OpMemberDecorate %struct 0 MatrixStride 16
3681 )";
3682   }
3683   generator.types_ += R"(%block = OpTypeStruct %struct
3684 %ptr_ssbo_block = OpTypePointer StorageBuffer %block
3685 %ptr_ssbo_struct = OpTypePointer StorageBuffer %struct
3686 %ptr_ssbo_vector = OpTypePointer StorageBuffer %vector
3687 %ptr_ssbo_scalar = OpTypePointer StorageBuffer %scalar
3688 %ld_var = OpVariable %ptr_ssbo_block StorageBuffer
3689 %st_var = OpVariable %ptr_ssbo_block StorageBuffer
3690 )";
3691 
3692   generator.after_types_ = R"(%void_fn = OpTypeFunction %void
3693 %func = OpFunction %void None %void_fn
3694 %entry = OpLabel
3695 )";
3696   generator.add_at_the_end_ = "OpReturn\nOpFunctionEnd\n";
3697   return generator;
3698 }
3699 
TEST_P(ValidateSizedLoadStore,Load)3700 TEST_P(ValidateSizedLoadStore, Load) {
3701   std::string base_type = std::get<0>(GetParam());
3702   uint32_t width = std::get<1>(GetParam());
3703   std::string mem_type = std::get<2>(GetParam());
3704 
3705   CodeGenerator generator = GetSizedLoadStoreCodeGenerator(base_type, width);
3706   generator.after_types_ +=
3707       "%ld_gep = OpAccessChain %ptr_ssbo_" + mem_type + " %ld_var %int_0";
3708   if (mem_type != "struct") {
3709     generator.after_types_ += " %int_0";
3710     if (mem_type != "matrix" && base_type == "float") {
3711       generator.after_types_ += " %int_0";
3712     }
3713     if (mem_type == "scalar") {
3714       generator.after_types_ += " %int_0";
3715     }
3716   }
3717   generator.after_types_ += "\n";
3718   generator.after_types_ += "%ld = OpLoad %" + mem_type + " %ld_gep\n";
3719 
3720   CompileSuccessfully(generator.Build(), SPV_ENV_UNIVERSAL_1_3);
3721   if (mem_type == "struct") {
3722     EXPECT_EQ(SPV_ERROR_INVALID_ID,
3723               ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
3724     EXPECT_THAT(
3725         getDiagnosticString(),
3726         HasSubstr(
3727             "8- or 16-bit loads must be a scalar, vector or matrix type"));
3728   } else {
3729     EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
3730   }
3731 }
3732 
TEST_P(ValidateSizedLoadStore,Store)3733 TEST_P(ValidateSizedLoadStore, Store) {
3734   std::string base_type = std::get<0>(GetParam());
3735   uint32_t width = std::get<1>(GetParam());
3736   std::string mem_type = std::get<2>(GetParam());
3737 
3738   CodeGenerator generator = GetSizedLoadStoreCodeGenerator(base_type, width);
3739   generator.after_types_ +=
3740       "%ld_gep = OpAccessChain %ptr_ssbo_" + mem_type + " %ld_var %int_0";
3741   if (mem_type != "struct") {
3742     generator.after_types_ += " %int_0";
3743     if (mem_type != "matrix" && base_type == "float") {
3744       generator.after_types_ += " %int_0";
3745     }
3746     if (mem_type == "scalar") {
3747       generator.after_types_ += " %int_0";
3748     }
3749   }
3750   generator.after_types_ += "\n";
3751   generator.after_types_ += "%ld = OpLoad %" + mem_type + " %ld_gep\n";
3752   generator.after_types_ +=
3753       "%st_gep = OpAccessChain %ptr_ssbo_" + mem_type + " %st_var %int_0";
3754   if (mem_type != "struct") {
3755     generator.after_types_ += " %int_0";
3756     if (mem_type != "matrix" && base_type == "float") {
3757       generator.after_types_ += " %int_0";
3758     }
3759     if (mem_type == "scalar") {
3760       generator.after_types_ += " %int_0";
3761     }
3762   }
3763   generator.after_types_ += "\n";
3764   generator.after_types_ += "OpStore %st_gep %ld\n";
3765 
3766   CompileSuccessfully(generator.Build(), SPV_ENV_UNIVERSAL_1_3);
3767   if (mem_type == "struct") {
3768     EXPECT_EQ(SPV_ERROR_INVALID_ID,
3769               ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
3770     // Can only catch the load.
3771     EXPECT_THAT(
3772         getDiagnosticString(),
3773         HasSubstr(
3774             "8- or 16-bit loads must be a scalar, vector or matrix type"));
3775   } else {
3776     EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
3777   }
3778 }
3779 
3780 INSTANTIATE_TEST_SUITE_P(LoadStoreInt8, ValidateSizedLoadStore,
3781                          Combine(Values("int"), Values(8u),
3782                                  Values("scalar", "vector", "struct")));
3783 INSTANTIATE_TEST_SUITE_P(LoadStoreInt16, ValidateSizedLoadStore,
3784                          Combine(Values("int"), Values(16u),
3785                                  Values("scalar", "vector", "struct")));
3786 INSTANTIATE_TEST_SUITE_P(LoadStoreFloat16, ValidateSizedLoadStore,
3787                          Combine(Values("float"), Values(16u),
3788                                  Values("scalar", "vector", "matrix",
3789                                         "struct")));
3790 
TEST_F(ValidateMemory,SmallStorageCopyMemoryChar)3791 TEST_F(ValidateMemory, SmallStorageCopyMemoryChar) {
3792   const std::string spirv = R"(
3793 OpCapability Shader
3794 OpCapability Linkage
3795 OpCapability UniformAndStorageBuffer8BitAccess
3796 OpExtension "SPV_KHR_8bit_storage"
3797 OpMemoryModel Logical GLSL450
3798 OpDecorate %block Block
3799 OpMemberDecorate %block 0 Offset 0
3800 %void = OpTypeVoid
3801 %int = OpTypeInt 32 0
3802 %int_0 = OpConstant %int 0
3803 %char = OpTypeInt 8 0
3804 %block = OpTypeStruct %char
3805 %ptr_ssbo_block = OpTypePointer StorageBuffer %block
3806 %in = OpVariable %ptr_ssbo_block StorageBuffer
3807 %out = OpVariable %ptr_ssbo_block StorageBuffer
3808 %void_fn = OpTypeFunction %void
3809 %func = OpFunction %void None %void_fn
3810 %entry = OpLabel
3811 OpCopyMemory %out %in
3812 OpReturn
3813 OpFunctionEnd
3814 )";
3815 
3816   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
3817   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
3818   EXPECT_THAT(
3819       getDiagnosticString(),
3820       HasSubstr("Cannot copy memory of objects containing 8- or 16-bit types"));
3821 }
3822 
TEST_F(ValidateMemory,SmallStorageCopyMemoryShort)3823 TEST_F(ValidateMemory, SmallStorageCopyMemoryShort) {
3824   const std::string spirv = R"(
3825 OpCapability Shader
3826 OpCapability Linkage
3827 OpCapability UniformAndStorageBuffer16BitAccess
3828 OpExtension "SPV_KHR_16bit_storage"
3829 OpMemoryModel Logical GLSL450
3830 OpDecorate %block Block
3831 OpMemberDecorate %block 0 Offset 0
3832 %void = OpTypeVoid
3833 %int = OpTypeInt 32 0
3834 %int_0 = OpConstant %int 0
3835 %short = OpTypeInt 16 0
3836 %block = OpTypeStruct %short
3837 %ptr_ssbo_block = OpTypePointer StorageBuffer %block
3838 %in = OpVariable %ptr_ssbo_block StorageBuffer
3839 %out = OpVariable %ptr_ssbo_block StorageBuffer
3840 %void_fn = OpTypeFunction %void
3841 %func = OpFunction %void None %void_fn
3842 %entry = OpLabel
3843 OpCopyMemory %out %in
3844 OpReturn
3845 OpFunctionEnd
3846 )";
3847 
3848   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
3849   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
3850   EXPECT_THAT(
3851       getDiagnosticString(),
3852       HasSubstr("Cannot copy memory of objects containing 8- or 16-bit types"));
3853 }
3854 
TEST_F(ValidateMemory,SmallStorageCopyMemoryHalf)3855 TEST_F(ValidateMemory, SmallStorageCopyMemoryHalf) {
3856   const std::string spirv = R"(
3857 OpCapability Shader
3858 OpCapability Linkage
3859 OpCapability UniformAndStorageBuffer16BitAccess
3860 OpExtension "SPV_KHR_16bit_storage"
3861 OpMemoryModel Logical GLSL450
3862 OpDecorate %block Block
3863 OpMemberDecorate %block 0 Offset 0
3864 %void = OpTypeVoid
3865 %int = OpTypeInt 32 0
3866 %int_0 = OpConstant %int 0
3867 %half = OpTypeFloat 16
3868 %block = OpTypeStruct %half
3869 %ptr_ssbo_block = OpTypePointer StorageBuffer %block
3870 %in = OpVariable %ptr_ssbo_block StorageBuffer
3871 %out = OpVariable %ptr_ssbo_block StorageBuffer
3872 %void_fn = OpTypeFunction %void
3873 %func = OpFunction %void None %void_fn
3874 %entry = OpLabel
3875 OpCopyMemory %out %in
3876 OpReturn
3877 OpFunctionEnd
3878 )";
3879 
3880   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
3881   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
3882   EXPECT_THAT(
3883       getDiagnosticString(),
3884       HasSubstr("Cannot copy memory of objects containing 8- or 16-bit types"));
3885 }
3886 
TEST_F(ValidateMemory,SmallStorageVariableArrayBufferBlockShort)3887 TEST_F(ValidateMemory, SmallStorageVariableArrayBufferBlockShort) {
3888   const std::string spirv = R"(
3889 OpCapability Shader
3890 OpCapability Linkage
3891 OpCapability StorageBuffer16BitAccess
3892 OpExtension "SPV_KHR_16bit_storage"
3893 OpMemoryModel Logical GLSL450
3894 OpDecorate %block BufferBlock
3895 OpMemberDecorate %block 0 Offset 0
3896 %void = OpTypeVoid
3897 %short = OpTypeInt 16 0
3898 %int = OpTypeInt 32 0
3899 %int_4 = OpConstant %int 4
3900 %block = OpTypeStruct %short
3901 %block_array = OpTypeArray %block %int_4
3902 %ptr_block_array = OpTypePointer Uniform %block_array
3903 %var = OpVariable %ptr_block_array Uniform
3904 )";
3905 
3906   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
3907   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
3908 }
3909 
TEST_F(ValidateMemory,SmallStorageVariableArrayBufferBlockChar)3910 TEST_F(ValidateMemory, SmallStorageVariableArrayBufferBlockChar) {
3911   const std::string spirv = R"(
3912 OpCapability Shader
3913 OpCapability Linkage
3914 OpCapability StorageBuffer8BitAccess
3915 OpExtension "SPV_KHR_8bit_storage"
3916 OpMemoryModel Logical GLSL450
3917 OpDecorate %block BufferBlock
3918 OpMemberDecorate %block 0 Offset 0
3919 %void = OpTypeVoid
3920 %char = OpTypeInt 8 0
3921 %int = OpTypeInt 32 0
3922 %int_4 = OpConstant %int 4
3923 %block = OpTypeStruct %char
3924 %block_array = OpTypeArray %block %int_4
3925 %ptr_block_array = OpTypePointer Uniform %block_array
3926 %var = OpVariable %ptr_block_array Uniform
3927 )";
3928 
3929   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
3930   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
3931 }
3932 
TEST_F(ValidateMemory,SmallStorageVariableArrayBufferBlockHalf)3933 TEST_F(ValidateMemory, SmallStorageVariableArrayBufferBlockHalf) {
3934   const std::string spirv = R"(
3935 OpCapability Shader
3936 OpCapability Linkage
3937 OpCapability StorageBuffer16BitAccess
3938 OpExtension "SPV_KHR_16bit_storage"
3939 OpMemoryModel Logical GLSL450
3940 OpDecorate %block BufferBlock
3941 OpMemberDecorate %block 0 Offset 0
3942 %void = OpTypeVoid
3943 %half = OpTypeFloat 16
3944 %int = OpTypeInt 32 0
3945 %int_4 = OpConstant %int 4
3946 %block = OpTypeStruct %half
3947 %block_array = OpTypeArray %block %int_4
3948 %ptr_block_array = OpTypePointer Uniform %block_array
3949 %var = OpVariable %ptr_block_array Uniform
3950 )";
3951 
3952   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
3953   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
3954 }
3955 
TEST_F(ValidateMemory,VulkanStorageBufferNotAStruct)3956 TEST_F(ValidateMemory, VulkanStorageBufferNotAStruct) {
3957   const std::string spirv = R"(
3958 OpCapability Shader
3959 OpExtension "SPV_KHR_storage_buffer_storage_class"
3960 OpMemoryModel Logical GLSL450
3961 OpEntryPoint GLCompute %main "main"
3962 OpExecutionMode %main LocalSize 1 1 1
3963 %void = OpTypeVoid
3964 %uint = OpTypeInt 32 0
3965 %ptr_ssbo = OpTypePointer StorageBuffer %uint
3966 %var = OpVariable %ptr_ssbo StorageBuffer
3967 %void_fn = OpTypeFunction %void
3968 %main = OpFunction %void None %void_fn
3969 %entry = OpLabel
3970 OpReturn
3971 OpFunctionEnd
3972 )";
3973 
3974   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0);
3975   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
3976   EXPECT_THAT(
3977       getDiagnosticString(),
3978       HasSubstr("From Vulkan spec, section 14.5.2:\nVariables identified with "
3979                 "the StorageBuffer storage class are used to access "
3980                 "transparent buffer backed resources. Such variables must be "
3981                 "typed as OpTypeStruct, or an array of this type"));
3982 }
3983 
TEST_F(ValidateMemory,VulkanStorageBufferRuntimeArrayNotAStruct)3984 TEST_F(ValidateMemory, VulkanStorageBufferRuntimeArrayNotAStruct) {
3985   const std::string spirv = R"(
3986 OpCapability Shader
3987 OpCapability RuntimeDescriptorArrayEXT
3988 OpExtension "SPV_KHR_storage_buffer_storage_class"
3989 OpExtension "SPV_EXT_descriptor_indexing"
3990 OpMemoryModel Logical GLSL450
3991 OpEntryPoint GLCompute %main "main"
3992 OpExecutionMode %main LocalSize 1 1 1
3993 %void = OpTypeVoid
3994 %uint = OpTypeInt 32 0
3995 %array = OpTypeRuntimeArray %uint
3996 %ptr_ssbo = OpTypePointer StorageBuffer %array
3997 %var = OpVariable %ptr_ssbo StorageBuffer
3998 %void_fn = OpTypeFunction %void
3999 %main = OpFunction %void None %void_fn
4000 %entry = OpLabel
4001 OpReturn
4002 OpFunctionEnd
4003 )";
4004 
4005   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0);
4006   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
4007   EXPECT_THAT(
4008       getDiagnosticString(),
4009       HasSubstr("From Vulkan spec, section 14.5.2:\nVariables identified with "
4010                 "the StorageBuffer storage class are used to access "
4011                 "transparent buffer backed resources. Such variables must be "
4012                 "typed as OpTypeStruct, or an array of this type"));
4013 }
4014 
TEST_F(ValidateMemory,VulkanStorageBufferArrayNotAStruct)4015 TEST_F(ValidateMemory, VulkanStorageBufferArrayNotAStruct) {
4016   const std::string spirv = R"(
4017 OpCapability Shader
4018 OpExtension "SPV_KHR_storage_buffer_storage_class"
4019 OpMemoryModel Logical GLSL450
4020 OpEntryPoint GLCompute %main "main"
4021 OpExecutionMode %main LocalSize 1 1 1
4022 %void = OpTypeVoid
4023 %uint = OpTypeInt 32 0
4024 %uint_4 = OpConstant %uint 4
4025 %array = OpTypeArray %uint %uint_4
4026 %ptr_ssbo = OpTypePointer StorageBuffer %array
4027 %var = OpVariable %ptr_ssbo StorageBuffer
4028 %void_fn = OpTypeFunction %void
4029 %main = OpFunction %void None %void_fn
4030 %entry = OpLabel
4031 OpReturn
4032 OpFunctionEnd
4033 )";
4034 
4035   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0);
4036   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
4037   EXPECT_THAT(
4038       getDiagnosticString(),
4039       HasSubstr("From Vulkan spec, section 14.5.2:\nVariables identified with "
4040                 "the StorageBuffer storage class are used to access "
4041                 "transparent buffer backed resources. Such variables must be "
4042                 "typed as OpTypeStruct, or an array of this type"));
4043 }
4044 
TEST_F(ValidateMemory,VulkanInvariantOutputSuccess)4045 TEST_F(ValidateMemory, VulkanInvariantOutputSuccess) {
4046   const std::string spirv = R"(
4047 OpCapability Shader
4048 OpMemoryModel Logical GLSL450
4049 OpEntryPoint Vertex %main "main"
4050 OpDecorate %var Location 0
4051 OpDecorate %var Invariant
4052 %void = OpTypeVoid
4053 %f32 = OpTypeFloat 32
4054 %ptr_output = OpTypePointer Output %f32
4055 %var = OpVariable %ptr_output Output
4056 %void_fn = OpTypeFunction %void
4057 %main = OpFunction %void None %void_fn
4058 %entry = OpLabel
4059 OpReturn
4060 OpFunctionEnd
4061 )";
4062 
4063   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0);
4064   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
4065 }
4066 
TEST_F(ValidateMemory,VulkanInvariantInputStructSuccess)4067 TEST_F(ValidateMemory, VulkanInvariantInputStructSuccess) {
4068   const std::string spirv = R"(
4069 OpCapability Shader
4070 OpMemoryModel Logical GLSL450
4071 OpEntryPoint Fragment %main "main"
4072 OpExecutionMode %main OriginUpperLeft
4073 OpDecorate %var Location 0
4074 OpMemberDecorate %struct 1 Invariant
4075 %void = OpTypeVoid
4076 %f32 = OpTypeFloat 32
4077 %struct = OpTypeStruct %f32 %f32
4078 %ptr_input = OpTypePointer Input %struct
4079 %var = OpVariable %ptr_input Input
4080 %void_fn = OpTypeFunction %void
4081 %main = OpFunction %void None %void_fn
4082 %entry = OpLabel
4083 OpReturn
4084 OpFunctionEnd
4085 )";
4086 
4087   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0);
4088   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
4089 }
4090 
TEST_F(ValidateMemory,VulkanInvariantWrongStorageClass)4091 TEST_F(ValidateMemory, VulkanInvariantWrongStorageClass) {
4092   const std::string spirv = R"(
4093 OpCapability Shader
4094 OpMemoryModel Logical GLSL450
4095 OpEntryPoint Vertex %main "main"
4096 OpDecorate %var Invariant
4097 %void = OpTypeVoid
4098 %f32 = OpTypeFloat 32
4099 %ptr_private = OpTypePointer Private %f32
4100 %var = OpVariable %ptr_private Private
4101 %void_fn = OpTypeFunction %void
4102 %main = OpFunction %void None %void_fn
4103 %entry = OpLabel
4104 OpReturn
4105 OpFunctionEnd
4106 )";
4107 
4108   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0);
4109   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
4110   EXPECT_THAT(getDiagnosticString(),
4111               AnyVUID("VUID-StandaloneSpirv-Invariant-04677"));
4112   EXPECT_THAT(
4113       getDiagnosticString(),
4114       HasSubstr(
4115           "Variable decorated with Invariant must only be identified with the "
4116           "Input or Output storage class in Vulkan environment."));
4117 }
4118 
TEST_F(ValidateMemory,VulkanInvariantMemberWrongStorageClass)4119 TEST_F(ValidateMemory, VulkanInvariantMemberWrongStorageClass) {
4120   const std::string spirv = R"(
4121 OpCapability Shader
4122 OpMemoryModel Logical GLSL450
4123 OpEntryPoint Fragment %main "main"
4124 OpExecutionMode %main OriginUpperLeft
4125 OpMemberDecorate %struct 1 Invariant
4126 %void = OpTypeVoid
4127 %f32 = OpTypeFloat 32
4128 %struct = OpTypeStruct %f32 %f32
4129 %ptr_private = OpTypePointer Private %struct
4130 %var = OpVariable %ptr_private Private
4131 %void_fn = OpTypeFunction %void
4132 %main = OpFunction %void None %void_fn
4133 %entry = OpLabel
4134 OpReturn
4135 OpFunctionEnd
4136 )";
4137 
4138   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0);
4139   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
4140   EXPECT_THAT(getDiagnosticString(),
4141               AnyVUID("VUID-StandaloneSpirv-Invariant-04677"));
4142   EXPECT_THAT(getDiagnosticString(),
4143               HasSubstr("Variable struct member decorated with Invariant must "
4144                         "only be identified with the Input or Output storage "
4145                         "class in Vulkan environment."));
4146 }
4147 
TEST_F(ValidateMemory,PhysicalStorageBufferPtrEqual)4148 TEST_F(ValidateMemory, PhysicalStorageBufferPtrEqual) {
4149   const std::string spirv = R"(
4150 OpCapability Shader
4151 OpCapability Int64
4152 OpCapability PhysicalStorageBufferAddresses
4153 OpMemoryModel PhysicalStorageBuffer64 GLSL450
4154 OpEntryPoint GLCompute %main "main"
4155 OpExecutionMode %main LocalSize 1 1 1
4156 %void = OpTypeVoid
4157 %bool = OpTypeBool
4158 %long = OpTypeInt 64 0
4159 %long_0 = OpConstant %long 0
4160 %ptr_pssbo_long = OpTypePointer PhysicalStorageBuffer %long
4161 %void_fn = OpTypeFunction %void
4162 %main = OpFunction %void None %void_fn
4163 %entry = OpLabel
4164 %conv = OpConvertUToPtr %ptr_pssbo_long %long_0
4165 %eq = OpPtrEqual %bool %conv %conv
4166 OpReturn
4167 OpFunctionEnd
4168 )";
4169 
4170   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_5);
4171   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_5));
4172   EXPECT_THAT(
4173       getDiagnosticString(),
4174       HasSubstr(
4175           "Cannot use a pointer in the PhysicalStorageBuffer storage class"));
4176 }
4177 
TEST_F(ValidateMemory,PhysicalStorageBufferPtrNotEqual)4178 TEST_F(ValidateMemory, PhysicalStorageBufferPtrNotEqual) {
4179   const std::string spirv = R"(
4180 OpCapability Shader
4181 OpCapability Int64
4182 OpCapability PhysicalStorageBufferAddresses
4183 OpMemoryModel PhysicalStorageBuffer64 GLSL450
4184 OpEntryPoint GLCompute %main "main"
4185 OpExecutionMode %main LocalSize 1 1 1
4186 %void = OpTypeVoid
4187 %bool = OpTypeBool
4188 %long = OpTypeInt 64 0
4189 %long_0 = OpConstant %long 0
4190 %ptr_pssbo_long = OpTypePointer PhysicalStorageBuffer %long
4191 %void_fn = OpTypeFunction %void
4192 %main = OpFunction %void None %void_fn
4193 %entry = OpLabel
4194 %conv = OpConvertUToPtr %ptr_pssbo_long %long_0
4195 %neq = OpPtrNotEqual %bool %conv %conv
4196 OpReturn
4197 OpFunctionEnd
4198 )";
4199 
4200   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_5);
4201   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_5));
4202   EXPECT_THAT(
4203       getDiagnosticString(),
4204       HasSubstr(
4205           "Cannot use a pointer in the PhysicalStorageBuffer storage class"));
4206 }
4207 
TEST_F(ValidateMemory,PhysicalStorageBufferPtrDiff)4208 TEST_F(ValidateMemory, PhysicalStorageBufferPtrDiff) {
4209   const std::string spirv = R"(
4210 OpCapability Shader
4211 OpCapability Int64
4212 OpCapability PhysicalStorageBufferAddresses
4213 OpCapability VariablePointers
4214 OpMemoryModel PhysicalStorageBuffer64 GLSL450
4215 OpEntryPoint GLCompute %main "main"
4216 OpExecutionMode %main LocalSize 1 1 1
4217 %void = OpTypeVoid
4218 %long = OpTypeInt 64 0
4219 %long_0 = OpConstant %long 0
4220 %ptr_pssbo_long = OpTypePointer PhysicalStorageBuffer %long
4221 %void_fn = OpTypeFunction %void
4222 %main = OpFunction %void None %void_fn
4223 %entry = OpLabel
4224 %conv = OpConvertUToPtr %ptr_pssbo_long %long_0
4225 %diff = OpPtrDiff %long %conv %conv
4226 OpReturn
4227 OpFunctionEnd
4228 )";
4229 
4230   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_5);
4231   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_5));
4232   EXPECT_THAT(
4233       getDiagnosticString(),
4234       HasSubstr(
4235           "Cannot use a pointer in the PhysicalStorageBuffer storage class"));
4236 }
4237 
TEST_F(ValidateMemory,VulkanInitializerWithWorkgroupStorageClassBad)4238 TEST_F(ValidateMemory, VulkanInitializerWithWorkgroupStorageClassBad) {
4239   std::string spirv = R"(
4240 OpCapability Shader
4241 OpCapability VulkanMemoryModelKHR
4242 OpExtension "SPV_KHR_vulkan_memory_model"
4243 OpMemoryModel Logical VulkanKHR
4244 OpEntryPoint Fragment %func "func"
4245 OpExecutionMode %func OriginUpperLeft
4246 %float = OpTypeFloat 32
4247 %float_ptr = OpTypePointer Workgroup %float
4248 %init_val = OpConstant %float 1.0
4249 %1 = OpVariable %float_ptr Workgroup %init_val
4250 %void = OpTypeVoid
4251 %functy = OpTypeFunction %void
4252 %func = OpFunction %void None %functy
4253 %2 = OpLabel
4254 OpReturn
4255 OpFunctionEnd
4256 )";
4257   CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_0);
4258   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
4259   EXPECT_THAT(getDiagnosticString(),
4260               HasSubstr("Variable initializers in Workgroup storage class are "
4261                         "limited to OpConstantNull"));
4262 }
4263 
TEST_F(ValidateMemory,VulkanInitializerWithWorkgroupStorageClassGood)4264 TEST_F(ValidateMemory, VulkanInitializerWithWorkgroupStorageClassGood) {
4265   std::string spirv = R"(
4266 OpCapability Shader
4267 OpCapability VulkanMemoryModelKHR
4268 OpExtension "SPV_KHR_vulkan_memory_model"
4269 OpMemoryModel Logical VulkanKHR
4270 OpEntryPoint Fragment %func "func"
4271 OpExecutionMode %func OriginUpperLeft
4272 %float = OpTypeFloat 32
4273 %float_ptr = OpTypePointer Workgroup %float
4274 %init_val = OpConstantNull %float
4275 %1 = OpVariable %float_ptr Workgroup %init_val
4276 %void = OpTypeVoid
4277 %functy = OpTypeFunction %void
4278 %func = OpFunction %void None %functy
4279 %2 = OpLabel
4280 OpReturn
4281 OpFunctionEnd
4282 )";
4283   CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_0);
4284   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
4285 }
4286 
4287 }  // namespace
4288 }  // namespace val
4289 }  // namespace spvtools
4290