1 // Copyright (c) 2021 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 // Validation tests for decorations
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 namespace spvtools {
26 namespace val {
27 namespace {
28 
29 using ::testing::Combine;
30 using ::testing::Eq;
31 using ::testing::HasSubstr;
32 using ::testing::Values;
33 
34 using DecorationTest = spvtest::ValidateBase<bool>;
35 
TEST_F(DecorationTest, WorkgroupSizeShader)36 TEST_F(DecorationTest, WorkgroupSizeShader) {
37   const std::string text = R"(
38 OpCapability Shader
39 OpCapability Linkage
40 OpMemoryModel Logical GLSL450
41 OpDecorate %ones BuiltIn WorkgroupSize
42 %int = OpTypeInt 32 0
43 %int3 = OpTypeVector %int 3
44 %int_1 = OpConstant %int 1
45 %ones = OpConstantComposite %int3 %int_1 %int_1 %int_1
46 )";
47 
48   CompileSuccessfully(text);
49   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
50 }
51 
TEST_F(DecorationTest, WorkgroupSizeKernel)52 TEST_F(DecorationTest, WorkgroupSizeKernel) {
53   const std::string text = R"(
54 OpCapability Kernel
55 OpCapability Linkage
56 OpMemoryModel Logical OpenCL
57 OpDecorate %var BuiltIn WorkgroupSize
58 %int = OpTypeInt 32 0
59 %int3 = OpTypeVector %int 3
60 %ptr = OpTypePointer Input %int3
61 %var = OpVariable %ptr Input
62 )";
63 
64   CompileSuccessfully(text);
65   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
66 }
67 
68 using MemberOnlyDecorations = spvtest::ValidateBase<std::string>;
69 
TEST_P(MemberOnlyDecorations, MemberDecoration)70 TEST_P(MemberOnlyDecorations, MemberDecoration) {
71   const auto deco = GetParam();
72   const std::string text = R"(
73 OpCapability Shader
74 OpCapability Linkage
75 OpMemoryModel Logical GLSL450
76 OpMemberDecorate %struct 0 )" +
77                            deco + R"(
78 %float = OpTypeFloat 32
79 %float2 = OpTypeVector %float 2
80 %float2x2 = OpTypeMatrix %float2 2
81 %struct = OpTypeStruct %float2x2
82 )";
83 
84   CompileSuccessfully(text);
85   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
86 }
87 
TEST_P(MemberOnlyDecorations, Decoration)88 TEST_P(MemberOnlyDecorations, Decoration) {
89   const auto deco = GetParam();
90   const std::string text = R"(
91 OpCapability Shader
92 OpCapability Linkage
93 OpMemoryModel Logical GLSL450
94 OpDecorate %struct )" + deco +
95                            R"(
96 %float = OpTypeFloat 32
97 %float2 = OpTypeVector %float 2
98 %float2x2 = OpTypeMatrix %float2 2
99 %struct = OpTypeStruct %float2x2
100 )";
101 
102   CompileSuccessfully(text);
103   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
104   EXPECT_THAT(getDiagnosticString(),
105               HasSubstr("can only be applied to structure members"));
106 }
107 
108 INSTANTIATE_TEST_SUITE_P(ValidateMemberOnlyDecorations, MemberOnlyDecorations,
109                          Values("RowMajor", "ColMajor", "MatrixStride 16"
110                                 // SPIR-V spec bug?
111                                 /*,"Offset 0"*/));
112 
113 using NonMemberOnlyDecorations = spvtest::ValidateBase<std::string>;
114 
TEST_P(NonMemberOnlyDecorations, MemberDecoration)115 TEST_P(NonMemberOnlyDecorations, MemberDecoration) {
116   const auto deco = GetParam();
117   const auto text = R"(
118 OpCapability Shader
119 OpCapability Kernel
120 OpCapability Linkage
121 OpCapability InputAttachment
122 OpCapability Addresses
123 OpCapability PhysicalStorageBufferAddresses
124 OpCapability ShaderNonUniform
125 OpExtension "SPV_KHR_no_integer_wrap_decoration"
126 OpExtension "SPV_KHR_physical_storage_buffer"
127 OpExtension "SPV_GOOGLE_hlsl_functionality1"
128 OpExtension "SPV_EXT_descriptor_indexing"
129 OpMemoryModel Logical GLSL450
130 OpMemberDecorate %struct 0 )" +
131                     deco + R"(
132 %float = OpTypeFloat 32
133 %float2 = OpTypeVector %float 2
134 %float2x2 = OpTypeMatrix %float2 2
135 %struct = OpTypeStruct %float2x2
136 )";
137 
138   CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3);
139   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
140   EXPECT_THAT(getDiagnosticString(),
141               HasSubstr("cannot be applied to structure members"));
142 }
143 
144 INSTANTIATE_TEST_SUITE_P(
145     ValidateNonMemberOnlyDecorations, NonMemberOnlyDecorations,
146     Values("SpecId 1", "Block", "BufferBlock", "ArrayStride 4", "GLSLShared",
147            "GLSLPacked", "CPacked",
148            // TODO: https://github.com/KhronosGroup/glslang/issues/703:
149            // glslang applies Restrict to structure members.
150            //"Restrict",
151            "Aliased", "Constant", "Uniform", "SaturatedConversion", "Index 0",
152            "Binding 0", "DescriptorSet 0", "FuncParamAttr Zext",
153            "FPRoundingMode RTE", "FPFastMathMode None",
154            "LinkageAttributes \"ext\" Import", "NoContraction",
155            "InputAttachmentIndex 0", "Alignment 4", "MaxByteOffset 4",
156            "AlignmentId %float", "MaxByteOffsetId %float", "NoSignedWrap",
157            "NoUnsignedWrap", "NonUniform", "RestrictPointer", "AliasedPointer",
158            "CounterBuffer %float"));
159 
160 using StructDecorations = spvtest::ValidateBase<std::string>;
161 
TEST_P(StructDecorations, Struct)162 TEST_P(StructDecorations, Struct) {
163   const std::string deco = GetParam();
164   const std::string text = R"(
165 OpCapability Shader
166 OpCapability Kernel
167 OpCapability Linkage
168 OpMemoryModel Logical GLSL450
169 OpDecorate %struct )" + deco +
170                            R"(
171 %struct = OpTypeStruct
172 )";
173 
174   CompileSuccessfully(text);
175   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
176 }
177 
TEST_P(StructDecorations, OtherType)178 TEST_P(StructDecorations, OtherType) {
179   const std::string deco = GetParam();
180   const std::string text = R"(
181 OpCapability Shader
182 OpCapability Kernel
183 OpCapability Linkage
184 OpMemoryModel Logical GLSL450
185 OpDecorate %int )" + deco + R"(
186 %int = OpTypeInt 32 0
187 )";
188 
189   CompileSuccessfully(text);
190   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
191   EXPECT_THAT(getDiagnosticString(), HasSubstr("must be a structure type"));
192 }
193 
TEST_P(StructDecorations, Variable)194 TEST_P(StructDecorations, Variable) {
195   const std::string deco = GetParam();
196   const std::string text = R"(
197 OpCapability Shader
198 OpCapability Kernel
199 OpCapability Linkage
200 OpMemoryModel Logical GLSL450
201 OpDecorate %var )" + deco + R"(
202 %int = OpTypeInt 32 0
203 %ptr = OpTypePointer Private %int
204 %var = OpVariable %ptr Private
205 )";
206 
207   CompileSuccessfully(text);
208   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
209   EXPECT_THAT(getDiagnosticString(), HasSubstr("must be a structure type"));
210 }
211 
TEST_P(StructDecorations, FunctionParameter)212 TEST_P(StructDecorations, FunctionParameter) {
213   const auto deco = GetParam();
214   const std::string text = R"(
215 OpCapability Shader
216 OpCapability Kernel
217 OpCapability Linkage
218 OpMemoryModel Logical GLSL450
219 OpDecorate %func LinkageAttributes "import" Import
220 OpDecorate %param )" + deco +
221                            R"(
222 %int = OpTypeInt 32 0
223 %void = OpTypeVoid
224 %fn = OpTypeFunction %void %int
225 %func = OpFunction %void None %fn
226 %param = OpFunctionParameter %int
227 OpFunctionEnd
228 )";
229 
230   CompileSuccessfully(text);
231   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
232   EXPECT_THAT(getDiagnosticString(), HasSubstr("must be a structure type"));
233 }
234 
TEST_P(StructDecorations, Constant)235 TEST_P(StructDecorations, Constant) {
236   const std::string deco = GetParam();
237   const std::string text = R"(
238 OpCapability Shader
239 OpCapability Kernel
240 OpCapability Linkage
241 OpMemoryModel Logical GLSL450
242 OpDecorate %int_0 )" + deco +
243                            R"(
244 %int = OpTypeInt 32 0
245 %int_0 = OpConstant %int 0
246 )";
247 
248   CompileSuccessfully(text);
249   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
250   EXPECT_THAT(getDiagnosticString(), HasSubstr("must be a structure type"));
251 }
252 
253 INSTANTIATE_TEST_SUITE_P(ValidateStructDecorations, StructDecorations,
254                          Values("Block", "BufferBlock", "GLSLShared",
255                                 "GLSLPacked", "CPacked"));
256 
257 using ArrayDecorations = spvtest::ValidateBase<std::string>;
258 
TEST_P(ArrayDecorations, Array)259 TEST_P(ArrayDecorations, Array) {
260   const auto deco = GetParam();
261   const std::string text = R"(
262 OpCapability Shader
263 OpCapability Linkage
264 OpMemoryModel Logical GLSL450
265 OpDecorate %array )" + deco +
266                            R"(
267 %int = OpTypeInt 32 0
268 %int_4 = OpConstant %int 4
269 %array = OpTypeArray %int %int_4
270 )";
271 
272   CompileSuccessfully(text);
273   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
274 }
275 
TEST_P(ArrayDecorations, RuntimeArray)276 TEST_P(ArrayDecorations, RuntimeArray) {
277   const auto deco = GetParam();
278   const std::string text = R"(
279 OpCapability Shader
280 OpCapability Linkage
281 OpMemoryModel Logical GLSL450
282 OpDecorate %array )" + deco +
283                            R"(
284 %int = OpTypeInt 32 0
285 %array = OpTypeRuntimeArray %int
286 )";
287 
288   CompileSuccessfully(text);
289   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
290 }
291 
TEST_P(ArrayDecorations, Pointer)292 TEST_P(ArrayDecorations, Pointer) {
293   const auto deco = GetParam();
294   const std::string text = R"(
295 OpCapability Shader
296 OpCapability Linkage
297 OpMemoryModel Logical GLSL450
298 OpDecorate %ptr )" + deco + R"(
299 %int = OpTypeInt 32 0
300 %ptr = OpTypePointer Workgroup %int
301 )";
302 
303   CompileSuccessfully(text);
304   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
305 }
306 
TEST_P(ArrayDecorations, Struct)307 TEST_P(ArrayDecorations, Struct) {
308   const auto deco = GetParam();
309   const std::string text = R"(
310 OpCapability Shader
311 OpCapability Linkage
312 OpMemoryModel Logical GLSL450
313 OpDecorate %struct )" + deco +
314                            R"(
315 %int = OpTypeInt 32 0
316 %struct = OpTypeStruct %int
317 )";
318 
319   CompileSuccessfully(text);
320   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
321   EXPECT_THAT(getDiagnosticString(),
322               HasSubstr("must be an array or pointer type"));
323 }
324 
TEST_P(ArrayDecorations, Variable)325 TEST_P(ArrayDecorations, Variable) {
326   const auto deco = GetParam();
327   const std::string text = R"(
328 OpCapability Shader
329 OpCapability Linkage
330 OpMemoryModel Logical GLSL450
331 OpDecorate %var )" + deco + R"(
332 %int = OpTypeInt 32 0
333 %ptr = OpTypePointer Private %int
334 %var = OpVariable %ptr Private
335 )";
336 
337   CompileSuccessfully(text);
338   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
339   EXPECT_THAT(getDiagnosticString(),
340               HasSubstr("must be an array or pointer type"));
341 }
342 
TEST_P(ArrayDecorations, FunctionParameter)343 TEST_P(ArrayDecorations, FunctionParameter) {
344   const auto deco = GetParam();
345   const std::string text = R"(
346 OpCapability Shader
347 OpCapability Linkage
348 OpMemoryModel Logical GLSL450
349 OpDecorate %func LinkageAttributes "import" Import
350 OpDecorate %param )" + deco +
351                            R"(
352 %int = OpTypeInt 32 0
353 %void = OpTypeVoid
354 %fn = OpTypeFunction %void %int
355 %func = OpFunction %void None %fn
356 %param = OpFunctionParameter %int
357 OpFunctionEnd
358 )";
359 
360   CompileSuccessfully(text);
361   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
362   EXPECT_THAT(getDiagnosticString(),
363               HasSubstr("must be an array or pointer type"));
364 }
365 
TEST_P(ArrayDecorations, Constant)366 TEST_P(ArrayDecorations, Constant) {
367   const auto deco = GetParam();
368   const std::string text = R"(
369 OpCapability Shader
370 OpCapability Linkage
371 OpMemoryModel Logical GLSL450
372 OpDecorate %null )" + deco +
373                            R"(
374 %int = OpTypeInt 32 0
375 %int_4 = OpConstant %int 4
376 %array = OpTypeArray %int %int_4
377 %null = OpConstantNull %array
378 )";
379 
380   CompileSuccessfully(text);
381   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
382   EXPECT_THAT(getDiagnosticString(),
383               HasSubstr("must be an array or pointer type"));
384 }
385 
386 INSTANTIATE_TEST_SUITE_P(ValidateArrayDecorations, ArrayDecorations,
387                          Values("ArrayStride 4"));
388 
389 using BuiltInDecorations = spvtest::ValidateBase<std::string>;
390 
TEST_P(BuiltInDecorations, Variable)391 TEST_P(BuiltInDecorations, Variable) {
392   const auto deco = GetParam();
393   const std::string text = R"(
394 OpCapability Shader
395 OpCapability Linkage
396 OpMemoryModel Logical GLSL450
397 OpDecorate %var BuiltIn )" +
398                            deco + R"(
399 %int = OpTypeInt 32 0
400 %ptr = OpTypePointer Input %int
401 %var = OpVariable %ptr Input
402 )";
403 
404   CompileSuccessfully(text);
405   if (deco != "WorkgroupSize") {
406     EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
407   } else {
408     EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
409     EXPECT_THAT(getDiagnosticString(),
410                 HasSubstr("must be a constant for WorkgroupSize"));
411   }
412 }
413 
TEST_P(BuiltInDecorations, IntegerType)414 TEST_P(BuiltInDecorations, IntegerType) {
415   const auto deco = GetParam();
416   const std::string text = R"(
417 OpCapability Shader
418 OpCapability Linkage
419 OpMemoryModel Logical GLSL450
420 OpDecorate %int BuiltIn )" +
421                            deco + R"(
422 %int = OpTypeInt 32 0
423 )";
424 
425   CompileSuccessfully(text);
426   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
427   EXPECT_THAT(getDiagnosticString(),
428               HasSubstr("BuiltIns can only target variables, structure members "
429                         "or constants"));
430 }
431 
TEST_P(BuiltInDecorations, FunctionParameter)432 TEST_P(BuiltInDecorations, FunctionParameter) {
433   const auto deco = GetParam();
434   const std::string text = R"(
435 OpCapability Shader
436 OpCapability Linkage
437 OpMemoryModel Logical GLSL450
438 OpDecorate %func LinkageAttributes "import" Import
439 OpDecorate %param BuiltIn )" +
440                            deco + R"(
441 %int = OpTypeInt 32 0
442 %void = OpTypeVoid
443 %fn = OpTypeFunction %void %int
444 %func = OpFunction %void None %fn
445 %param = OpFunctionParameter %int
446 OpFunctionEnd
447 )";
448 
449   CompileSuccessfully(text);
450   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
451   EXPECT_THAT(getDiagnosticString(),
452               HasSubstr("BuiltIns can only target variables, structure members "
453                         "or constants"));
454 }
455 
TEST_P(BuiltInDecorations, Constant)456 TEST_P(BuiltInDecorations, Constant) {
457   const auto deco = GetParam();
458   const std::string text = R"(
459 OpCapability Shader
460 OpCapability Linkage
461 OpMemoryModel Logical GLSL450
462 OpDecorate %const BuiltIn )" +
463                            deco + R"(
464 %int = OpTypeInt 32 0
465 %int3 = OpTypeVector %int 3
466 %int_1 = OpConstant %int 1
467 %const = OpConstantComposite %int3 %int_1 %int_1 %int_1
468 )";
469 
470   CompileSuccessfully(text);
471   if (deco == "WorkgroupSize") {
472     EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
473   } else {
474     EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
475     EXPECT_THAT(getDiagnosticString(), HasSubstr("must be a variable"));
476   }
477 }
478 
TEST_P(BuiltInDecorations, SpecConstant)479 TEST_P(BuiltInDecorations, SpecConstant) {
480   const auto deco = GetParam();
481   const std::string text = R"(
482 OpCapability Shader
483 OpCapability Linkage
484 OpMemoryModel Logical GLSL450
485 OpDecorate %const BuiltIn )" +
486                            deco + R"(
487 %int = OpTypeInt 32 0
488 %int3 = OpTypeVector %int 3
489 %int_1 = OpConstant %int 1
490 %const = OpSpecConstantComposite %int3 %int_1 %int_1 %int_1
491 )";
492 
493   CompileSuccessfully(text);
494   if (deco == "WorkgroupSize") {
495     EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
496   } else {
497     EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
498     EXPECT_THAT(getDiagnosticString(), HasSubstr("must be a variable"));
499   }
500 }
501 
502 INSTANTIATE_TEST_SUITE_P(ValidateBuiltInDecorations, BuiltInDecorations,
503                          Values("Position", "PointSize", "VertexId",
504                                 "InstanceId", "FragCoord", "FrontFacing",
505                                 "NumWorkgroups", "WorkgroupSize",
506                                 "LocalInvocationId", "GlobalInvocationId"));
507 
508 using MemoryObjectDecorations = spvtest::ValidateBase<std::string>;
509 
TEST_P(MemoryObjectDecorations, Variable)510 TEST_P(MemoryObjectDecorations, Variable) {
511   const auto deco = GetParam();
512   const std::string text = R"(
513 OpCapability Shader
514 OpCapability Linkage
515 OpCapability SampleRateShading
516 OpCapability TransformFeedback
517 OpCapability GeometryStreams
518 OpCapability Tessellation
519 OpCapability PhysicalStorageBufferAddresses
520 OpExtension "SPV_KHR_physical_storage_buffer"
521 OpMemoryModel Logical GLSL450
522 OpDecorate %var )" + deco + R"(
523 %float = OpTypeFloat 32
524 %ptr = OpTypePointer Input %float
525 %var = OpVariable %ptr Input
526 )";
527 
528   CompileSuccessfully(text);
529   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
530 }
531 
TEST_P(MemoryObjectDecorations, FunctionParameterGood)532 TEST_P(MemoryObjectDecorations, FunctionParameterGood) {
533   const auto deco = GetParam();
534   const std::string text = R"(
535 OpCapability Shader
536 OpCapability Linkage
537 OpCapability SampleRateShading
538 OpCapability TransformFeedback
539 OpCapability GeometryStreams
540 OpCapability Tessellation
541 OpCapability PhysicalStorageBufferAddresses
542 OpExtension "SPV_KHR_physical_storage_buffer"
543 OpMemoryModel Logical GLSL450
544 OpDecorate %func LinkageAttributes "import" Import
545 OpDecorate %param )" + deco +
546                            R"(
547 %float = OpTypeFloat 32
548 %ptr = OpTypePointer Input %float
549 %void = OpTypeVoid
550 %fn = OpTypeFunction %void %ptr
551 %func = OpFunction %void None %fn
552 %param = OpFunctionParameter %ptr
553 OpFunctionEnd
554 )";
555 
556   CompileSuccessfully(text);
557   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
558 }
559 
TEST_P(MemoryObjectDecorations, FunctionParameterNotAPointer)560 TEST_P(MemoryObjectDecorations, FunctionParameterNotAPointer) {
561   const auto deco = GetParam();
562   const std::string text = R"(
563 OpCapability Shader
564 OpCapability Linkage
565 OpCapability SampleRateShading
566 OpCapability TransformFeedback
567 OpCapability GeometryStreams
568 OpCapability Tessellation
569 OpCapability PhysicalStorageBufferAddresses
570 OpExtension "SPV_KHR_physical_storage_buffer"
571 OpMemoryModel Logical GLSL450
572 OpDecorate %func LinkageAttributes "import" Import
573 OpDecorate %param )" + deco +
574                            R"(
575 %float = OpTypeFloat 32
576 %void = OpTypeVoid
577 %fn = OpTypeFunction %void %float
578 %func = OpFunction %void None %fn
579 %param = OpFunctionParameter %float
580 OpFunctionEnd
581 )";
582 
583   CompileSuccessfully(text);
584   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
585   EXPECT_THAT(getDiagnosticString(), HasSubstr("must be a pointer type"));
586 }
587 
TEST_P(MemoryObjectDecorations, FloatType)588 TEST_P(MemoryObjectDecorations, FloatType) {
589   const auto deco = GetParam();
590   const std::string text = R"(
591 OpCapability Shader
592 OpCapability Linkage
593 OpCapability SampleRateShading
594 OpCapability TransformFeedback
595 OpCapability GeometryStreams
596 OpCapability Tessellation
597 OpCapability PhysicalStorageBufferAddresses
598 OpExtension "SPV_KHR_physical_storage_buffer"
599 OpMemoryModel Logical GLSL450
600 OpDecorate %float )" + deco +
601                            R"(
602 %float = OpTypeFloat 32
603 )";
604 
605   CompileSuccessfully(text);
606   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
607   EXPECT_THAT(getDiagnosticString(),
608               HasSubstr("must be a memory object declaration"));
609 }
610 
TEST_P(MemoryObjectDecorations, Constant)611 TEST_P(MemoryObjectDecorations, Constant) {
612   const auto deco = GetParam();
613   const std::string text = R"(
614 OpCapability Shader
615 OpCapability Linkage
616 OpCapability SampleRateShading
617 OpCapability TransformFeedback
618 OpCapability GeometryStreams
619 OpCapability Tessellation
620 OpCapability PhysicalStorageBufferAddresses
621 OpExtension "SPV_KHR_physical_storage_buffer"
622 OpMemoryModel Logical GLSL450
623 OpDecorate %const )" + deco +
624                            R"(
625 %float = OpTypeFloat 32
626 %const = OpConstant %float 0
627 )";
628 
629   CompileSuccessfully(text);
630   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
631   EXPECT_THAT(getDiagnosticString(),
632               HasSubstr("must be a memory object declaration"));
633 }
634 
635 // NonWritable and NonReadable are covered by other tests.
636 INSTANTIATE_TEST_SUITE_P(
637     ValidateMemoryObjectDecorations, MemoryObjectDecorations,
638     Values("NoPerspective", "Flat", "Patch", "Centroid", "Component 0",
639            "Sample", "Restrict", "Aliased", "Volatile", "Coherent", "Stream 0",
640            "XfbBuffer 1", "XfbStride 1", "AliasedPointer", "RestrictPointer"));
641 
642 using VariableDecorations = spvtest::ValidateBase<std::string>;
643 
TEST_P(VariableDecorations, Variable)644 TEST_P(VariableDecorations, Variable) {
645   const auto deco = GetParam();
646   const std::string text = R"(
647 OpCapability Shader
648 OpCapability Kernel
649 OpCapability Linkage
650 OpCapability InputAttachment
651 OpMemoryModel Logical GLSL450
652 OpDecorate %var )" + deco + R"(
653 %float = OpTypeFloat 32
654 %ptr = OpTypePointer Input %float
655 %var = OpVariable %ptr Input
656 )";
657 
658   CompileSuccessfully(text);
659   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
660 }
661 
TEST_P(VariableDecorations, FunctionParameter)662 TEST_P(VariableDecorations, FunctionParameter) {
663   const auto deco = GetParam();
664   const std::string text = R"(
665 OpCapability Shader
666 OpCapability Kernel
667 OpCapability Linkage
668 OpCapability InputAttachment
669 OpMemoryModel Logical GLSL450
670 OpDecorate %func LinkageAttributes "import" Import
671 OpDecorate %param )" + deco +
672                            R"(
673 %float = OpTypeFloat 32
674 %void = OpTypeVoid
675 %fn = OpTypeFunction %void %float
676 %func = OpFunction %void None %fn
677 %param = OpFunctionParameter %float
678 OpFunctionEnd
679 )";
680 
681   CompileSuccessfully(text);
682   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
683   EXPECT_THAT(getDiagnosticString(), HasSubstr("must be a variable"));
684 }
685 
TEST_P(VariableDecorations, FloatType)686 TEST_P(VariableDecorations, FloatType) {
687   const auto deco = GetParam();
688   const std::string text = R"(
689 OpCapability Shader
690 OpCapability Kernel
691 OpCapability Linkage
692 OpCapability InputAttachment
693 OpMemoryModel Logical GLSL450
694 OpDecorate %float )" + deco +
695                            R"(
696 %float = OpTypeFloat 32
697 )";
698 
699   CompileSuccessfully(text);
700   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
701   EXPECT_THAT(getDiagnosticString(), HasSubstr("must be a variable"));
702 }
703 
TEST_P(VariableDecorations, Constant)704 TEST_P(VariableDecorations, Constant) {
705   const auto deco = GetParam();
706   const std::string text = R"(
707 OpCapability Shader
708 OpCapability Kernel
709 OpCapability Linkage
710 OpCapability InputAttachment
711 OpMemoryModel Logical GLSL450
712 OpDecorate %const )" + deco +
713                            R"(
714 %float = OpTypeFloat 32
715 %const = OpConstant %float 0
716 )";
717 
718   CompileSuccessfully(text);
719   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
720   EXPECT_THAT(getDiagnosticString(), HasSubstr("must be a variable"));
721 }
722 
723 INSTANTIATE_TEST_SUITE_P(ValidateVariableDecorations, VariableDecorations,
724                          Values("Invariant", "Constant", "Location 0",
725                                 "Index 0", "Binding 0", "DescriptorSet 0"));
726 
727 using VulkanIOStorageClass =
728     spvtest::ValidateBase<std::tuple<std::string, std::string>>;
729 
TEST_P(VulkanIOStorageClass, Invalid)730 TEST_P(VulkanIOStorageClass, Invalid) {
731   const auto deco = std::get<0>(GetParam());
732   const auto sc = std::get<1>(GetParam());
733   const std::string text = R"(
734 OpCapability Shader
735 OpExtension "SPV_KHR_storage_buffer_storage_class"
736 OpMemoryModel Logical GLSL450
737 OpEntryPoint Fragment %main "main"
738 OpExecutionMode %main OriginUpperLeft
739 OpDecorate %var )" + deco + R"( 0
740 %void = OpTypeVoid
741 %float = OpTypeFloat 32
742 %ptr = OpTypePointer )" +
743                            sc +
744                            R"( %float
745 %var = OpVariable %ptr )" + sc +
746                            R"(
747 %void_fn = OpTypeFunction %void
748 %main = OpFunction %void None %void_fn
749 %entry = OpLabel
750 OpReturn
751 OpFunctionEnd
752 )";
753 
754   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
755   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
756   EXPECT_THAT(getDiagnosticString(),
757               AnyVUID("VUID-StandaloneSpirv-Location-06672"));
758   EXPECT_THAT(
759       getDiagnosticString(),
760       HasSubstr("decoration must not be applied to this storage class"));
761 }
762 
763 INSTANTIATE_TEST_SUITE_P(ValidateVulkanIOStorageClass, VulkanIOStorageClass,
764                          Combine(Values("Location", "Component"),
765                                  Values("StorageBuffer", "Uniform",
766                                         "UniformConstant", "Workgroup",
767                                         "Private")));
768 
769 using VulkanResourceStorageClass =
770     spvtest::ValidateBase<std::tuple<std::string, std::string>>;
771 
TEST_P(VulkanResourceStorageClass, Invalid)772 TEST_P(VulkanResourceStorageClass, Invalid) {
773   const auto deco = std::get<0>(GetParam());
774   const auto sc = std::get<1>(GetParam());
775   const std::string text = R"(
776 OpCapability Shader
777 OpMemoryModel Logical GLSL450
778 OpEntryPoint Fragment %main "main"
779 OpExecutionMode %main OriginUpperLeft
780 OpDecorate %var )" + deco + R"( 0
781 %void = OpTypeVoid
782 %float = OpTypeFloat 32
783 %ptr = OpTypePointer )" +
784                            sc +
785                            R"( %float
786 %var = OpVariable %ptr )" + sc +
787                            R"(
788 %void_fn = OpTypeFunction %void
789 %main = OpFunction %void None %void_fn
790 %entry = OpLabel
791 OpReturn
792 OpFunctionEnd
793 )";
794 
795   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
796   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
797   EXPECT_THAT(getDiagnosticString(),
798               HasSubstr("VUID-StandaloneSpirv-DescriptorSet-06491"));
799   EXPECT_THAT(getDiagnosticString(),
800               HasSubstr("must be in the StorageBuffer, Uniform, or "
801                         "UniformConstant storage class"));
802 }
803 
804 INSTANTIATE_TEST_SUITE_P(ValidateVulkanResourceStorageClass,
805                          VulkanResourceStorageClass,
806                          Combine(Values("DescriptorSet", "Binding"),
807                                  Values("Private", "Input", "Output",
808                                         "Workgroup")));
809 
810 using VulkanInterpolationStorageClass = spvtest::ValidateBase<std::string>;
811 
TEST_P(VulkanInterpolationStorageClass, Input)812 TEST_P(VulkanInterpolationStorageClass, Input) {
813   const auto deco = GetParam();
814   const std::string text = R"(
815 OpCapability Shader
816 OpCapability SampleRateShading
817 OpMemoryModel Logical GLSL450
818 OpEntryPoint Fragment %main "main"
819 OpExecutionMode %main OriginUpperLeft
820 OpDecorate %var )" + deco + R"(
821 %void = OpTypeVoid
822 %float = OpTypeFloat 32
823 %void_fn = OpTypeFunction %void
824 %ptr = OpTypePointer Input %float
825 %var = OpVariable %ptr Input
826 %main = OpFunction %void None %void_fn
827 %entry = OpLabel
828 OpReturn
829 OpFunctionEnd
830 )";
831 
832   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
833   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
834 }
835 
TEST_P(VulkanInterpolationStorageClass, Output)836 TEST_P(VulkanInterpolationStorageClass, Output) {
837   const auto deco = GetParam();
838   const std::string text = R"(
839 OpCapability Shader
840 OpCapability SampleRateShading
841 OpMemoryModel Logical GLSL450
842 OpEntryPoint Vertex %main "main"
843 OpDecorate %var )" + deco + R"(
844 %void = OpTypeVoid
845 %float = OpTypeFloat 32
846 %void_fn = OpTypeFunction %void
847 %ptr = OpTypePointer Output %float
848 %var = OpVariable %ptr Output
849 %main = OpFunction %void None %void_fn
850 %entry = OpLabel
851 OpReturn
852 OpFunctionEnd
853 )";
854 
855   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
856   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
857 }
858 
TEST_P(VulkanInterpolationStorageClass, Private)859 TEST_P(VulkanInterpolationStorageClass, Private) {
860   const auto deco = GetParam();
861   const std::string text = R"(
862 OpCapability Shader
863 OpCapability SampleRateShading
864 OpMemoryModel Logical GLSL450
865 OpEntryPoint Fragment %main "main"
866 OpExecutionMode %main OriginUpperLeft
867 OpDecorate %var )" + deco + R"(
868 %void = OpTypeVoid
869 %float = OpTypeFloat 32
870 %void_fn = OpTypeFunction %void
871 %ptr = OpTypePointer Private %float
872 %var = OpVariable %ptr Private
873 %main = OpFunction %void None %void_fn
874 %entry = OpLabel
875 OpReturn
876 OpFunctionEnd
877 )";
878 
879   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
880   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
881   EXPECT_THAT(getDiagnosticString(),
882               HasSubstr("storage class must be Input or Output"));
883   EXPECT_THAT(getDiagnosticString(),
884               HasSubstr("[VUID-StandaloneSpirv-Flat-04670"));
885 }
886 
TEST_P(VulkanInterpolationStorageClass, Uniform)887 TEST_P(VulkanInterpolationStorageClass, Uniform) {
888   const auto deco = GetParam();
889   const std::string text = R"(
890 OpCapability Shader
891 OpCapability SampleRateShading
892 OpMemoryModel Logical GLSL450
893 OpEntryPoint Fragment %main "main"
894 OpExecutionMode %main OriginUpperLeft
895 OpDecorate %var )" + deco + R"(
896 OpDecorate %var Binding 0
897 OpDecorate %var DescriptorSet 0
898 %void = OpTypeVoid
899 %float = OpTypeFloat 32
900 %void_fn = OpTypeFunction %void
901 %ptr = OpTypePointer Uniform %float
902 %var = OpVariable %ptr Uniform
903 %main = OpFunction %void None %void_fn
904 %entry = OpLabel
905 OpReturn
906 OpFunctionEnd
907 )";
908 
909   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
910   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
911   EXPECT_THAT(getDiagnosticString(),
912               HasSubstr("storage class must be Input or Output"));
913   EXPECT_THAT(getDiagnosticString(),
914               HasSubstr("[VUID-StandaloneSpirv-Flat-04670"));
915 }
916 
TEST_P(VulkanInterpolationStorageClass, StorageBuffer)917 TEST_P(VulkanInterpolationStorageClass, StorageBuffer) {
918   const auto deco = GetParam();
919   const std::string text = R"(
920 OpCapability Shader
921 OpCapability SampleRateShading
922 OpExtension "SPV_KHR_storage_buffer_storage_class"
923 OpMemoryModel Logical GLSL450
924 OpEntryPoint Fragment %main "main"
925 OpExecutionMode %main OriginUpperLeft
926 OpDecorate %var )" + deco + R"(
927 OpDecorate %var Binding 0
928 OpDecorate %var DescriptorSet 0
929 %void = OpTypeVoid
930 %float = OpTypeFloat 32
931 %void_fn = OpTypeFunction %void
932 %ptr = OpTypePointer StorageBuffer %float
933 %var = OpVariable %ptr StorageBuffer
934 %main = OpFunction %void None %void_fn
935 %entry = OpLabel
936 OpReturn
937 OpFunctionEnd
938 )";
939 
940   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
941   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
942   EXPECT_THAT(getDiagnosticString(),
943               HasSubstr("storage class must be Input or Output"));
944   EXPECT_THAT(getDiagnosticString(),
945               HasSubstr("[VUID-StandaloneSpirv-Flat-04670"));
946 }
947 
948 INSTANTIATE_TEST_SUITE_P(ValidateVulkanInterpolationStorageClass,
949                          VulkanInterpolationStorageClass,
950                          Values("Flat", "NoPerspective", "Centroid", "Sample"));
951 
952 }  // namespace
953 }  // namespace val
954 }  // namespace spvtools
955