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 
TEST_F(DecorationTest,FPFastMathModeInvalidMask)68 TEST_F(DecorationTest, FPFastMathModeInvalidMask) {
69   const std::string text = R"(
70 OpCapability Shader
71 OpCapability FloatControls2
72 OpExtension "SPV_KHR_float_controls2"
73 OpMemoryModel Logical GLSL450
74 OpEntryPoint GLCompute %main "main"
75 OpExecutionMode %main LocalSize 1 1 1
76 OpDecorate %add FPFastMathMode !524288
77 %void = OpTypeVoid
78 %float = OpTypeFloat 32
79 %undef = OpUndef %float
80 %void_fn = OpTypeFunction %void
81 %main = OpFunction %void None %void_fn
82 %entry = OpLabel
83 %add = OpFAdd %float %undef %undef
84 OpReturn
85 OpFunctionEnd
86 )";
87 
88   CompileSuccessfully(text);
89   EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
90   EXPECT_THAT(getDiagnosticString(),
91               HasSubstr("Invalid floating-point fast math mode operand"));
92 }
93 
TEST_F(DecorationTest,FPFastMathModeAllowTransformMissingAllowContract)94 TEST_F(DecorationTest, FPFastMathModeAllowTransformMissingAllowContract) {
95   const std::string text = R"(
96 OpCapability Shader
97 OpCapability FloatControls2
98 OpExtension "SPV_KHR_float_controls2"
99 OpMemoryModel Logical GLSL450
100 OpEntryPoint GLCompute %main "main"
101 OpExecutionMode %main LocalSize 1 1 1
102 OpDecorate %add FPFastMathMode AllowTransform|AllowReassoc
103 %void = OpTypeVoid
104 %float = OpTypeFloat 32
105 %undef = OpUndef %float
106 %void_fn = OpTypeFunction %void
107 %main = OpFunction %void None %void_fn
108 %entry = OpLabel
109 %add = OpFAdd %float %undef %undef
110 OpReturn
111 OpFunctionEnd
112 )";
113 
114   CompileSuccessfully(text);
115   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
116   EXPECT_THAT(getDiagnosticString(),
117               HasSubstr("AllowReassoc and AllowContract must be specified when "
118                         "AllowTransform is specified"));
119 }
120 
TEST_F(DecorationTest,FPFastMathModeAllowTransformMissingAllowReassoc)121 TEST_F(DecorationTest, FPFastMathModeAllowTransformMissingAllowReassoc) {
122   const std::string text = R"(
123 OpCapability Shader
124 OpCapability FloatControls2
125 OpExtension "SPV_KHR_float_controls2"
126 OpMemoryModel Logical GLSL450
127 OpEntryPoint GLCompute %main "main"
128 OpExecutionMode %main LocalSize 1 1 1
129 OpDecorate %add FPFastMathMode AllowTransform|AllowContract
130 %void = OpTypeVoid
131 %float = OpTypeFloat 32
132 %undef = OpUndef %float
133 %void_fn = OpTypeFunction %void
134 %main = OpFunction %void None %void_fn
135 %entry = OpLabel
136 %add = OpFAdd %float %undef %undef
137 OpReturn
138 OpFunctionEnd
139 )";
140 
141   CompileSuccessfully(text);
142   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
143   EXPECT_THAT(getDiagnosticString(),
144               HasSubstr("AllowReassoc and AllowContract must be specified when "
145                         "AllowTransform is specified"));
146 }
147 
TEST_F(DecorationTest,FPFastMathModeAllowTransformMissingContractAndReassoc)148 TEST_F(DecorationTest, FPFastMathModeAllowTransformMissingContractAndReassoc) {
149   const std::string text = R"(
150 OpCapability Shader
151 OpCapability FloatControls2
152 OpExtension "SPV_KHR_float_controls2"
153 OpMemoryModel Logical GLSL450
154 OpEntryPoint GLCompute %main "main"
155 OpExecutionMode %main LocalSize 1 1 1
156 OpDecorate %add FPFastMathMode AllowTransform
157 %void = OpTypeVoid
158 %float = OpTypeFloat 32
159 %undef = OpUndef %float
160 %void_fn = OpTypeFunction %void
161 %main = OpFunction %void None %void_fn
162 %entry = OpLabel
163 %add = OpFAdd %float %undef %undef
164 OpReturn
165 OpFunctionEnd
166 )";
167 
168   CompileSuccessfully(text);
169   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
170   EXPECT_THAT(getDiagnosticString(),
171               HasSubstr("AllowReassoc and AllowContract must be specified when "
172                         "AllowTransform is specified"));
173 }
174 
TEST_F(DecorationTest,FPFastMathModeAndNoContraction)175 TEST_F(DecorationTest, FPFastMathModeAndNoContraction) {
176   const std::string text = R"(
177 OpCapability Shader
178 OpCapability FloatControls2
179 OpExtension "SPV_KHR_float_controls2"
180 OpMemoryModel Logical GLSL450
181 OpEntryPoint GLCompute %main "main"
182 OpExecutionMode %main LocalSize 1 1 1
183 OpDecorate %add FPFastMathMode None
184 OpDecorate %add NoContraction
185 %void = OpTypeVoid
186 %float = OpTypeFloat 32
187 %undef = OpUndef %float
188 %void_fn = OpTypeFunction %void
189 %main = OpFunction %void None %void_fn
190 %entry = OpLabel
191 %add = OpFAdd %float %undef %undef
192 OpReturn
193 OpFunctionEnd
194 )";
195 
196   CompileSuccessfully(text);
197   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
198   EXPECT_THAT(
199       getDiagnosticString(),
200       HasSubstr(
201           "FPFastMathMode and NoContraction cannot decorate the same target"));
202 }
203 
TEST_F(DecorationTest,FPFastMathModeAndNoContraction2)204 TEST_F(DecorationTest, FPFastMathModeAndNoContraction2) {
205   const std::string text = R"(
206 OpCapability Shader
207 OpCapability FloatControls2
208 OpExtension "SPV_KHR_float_controls2"
209 OpMemoryModel Logical GLSL450
210 OpEntryPoint GLCompute %main "main"
211 OpExecutionMode %main LocalSize 1 1 1
212 OpDecorate %add NoContraction
213 OpDecorate %add FPFastMathMode None
214 %void = OpTypeVoid
215 %float = OpTypeFloat 32
216 %undef = OpUndef %float
217 %void_fn = OpTypeFunction %void
218 %main = OpFunction %void None %void_fn
219 %entry = OpLabel
220 %add = OpFAdd %float %undef %undef
221 OpReturn
222 OpFunctionEnd
223 )";
224 
225   CompileSuccessfully(text);
226   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
227   EXPECT_THAT(
228       getDiagnosticString(),
229       HasSubstr(
230           "FPFastMathMode and NoContraction cannot decorate the same target"));
231 }
232 
233 using MemberOnlyDecorations = spvtest::ValidateBase<std::string>;
234 
TEST_P(MemberOnlyDecorations,MemberDecoration)235 TEST_P(MemberOnlyDecorations, MemberDecoration) {
236   const auto deco = GetParam();
237   const std::string text = R"(
238 OpCapability Shader
239 OpCapability Linkage
240 OpMemoryModel Logical GLSL450
241 OpMemberDecorate %struct 0 )" +
242                            deco + R"(
243 %float = OpTypeFloat 32
244 %float2 = OpTypeVector %float 2
245 %float2x2 = OpTypeMatrix %float2 2
246 %struct = OpTypeStruct %float2x2
247 )";
248 
249   CompileSuccessfully(text);
250   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
251 }
252 
TEST_P(MemberOnlyDecorations,Decoration)253 TEST_P(MemberOnlyDecorations, Decoration) {
254   const auto deco = GetParam();
255   const std::string text = R"(
256 OpCapability Shader
257 OpCapability Linkage
258 OpMemoryModel Logical GLSL450
259 OpDecorate %struct )" + deco +
260                            R"(
261 %float = OpTypeFloat 32
262 %float2 = OpTypeVector %float 2
263 %float2x2 = OpTypeMatrix %float2 2
264 %struct = OpTypeStruct %float2x2
265 )";
266 
267   CompileSuccessfully(text);
268   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
269   EXPECT_THAT(getDiagnosticString(),
270               HasSubstr("can only be applied to structure members"));
271 }
272 
273 INSTANTIATE_TEST_SUITE_P(ValidateMemberOnlyDecorations, MemberOnlyDecorations,
274                          Values("RowMajor", "ColMajor", "MatrixStride 16"
275                                 // SPIR-V spec bug?
276                                 /*,"Offset 0"*/));
277 
278 using NonMemberOnlyDecorations = spvtest::ValidateBase<std::string>;
279 
TEST_P(NonMemberOnlyDecorations,MemberDecoration)280 TEST_P(NonMemberOnlyDecorations, MemberDecoration) {
281   const auto deco = GetParam();
282   const auto text = R"(
283 OpCapability Shader
284 OpCapability Kernel
285 OpCapability Linkage
286 OpCapability InputAttachment
287 OpCapability Addresses
288 OpCapability PhysicalStorageBufferAddresses
289 OpCapability ShaderNonUniform
290 OpExtension "SPV_KHR_no_integer_wrap_decoration"
291 OpExtension "SPV_KHR_physical_storage_buffer"
292 OpExtension "SPV_GOOGLE_hlsl_functionality1"
293 OpExtension "SPV_EXT_descriptor_indexing"
294 OpMemoryModel Logical GLSL450
295 OpMemberDecorate %struct 0 )" +
296                     deco + R"(
297 %float = OpTypeFloat 32
298 %float2 = OpTypeVector %float 2
299 %float2x2 = OpTypeMatrix %float2 2
300 %struct = OpTypeStruct %float2x2
301 )";
302 
303   CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3);
304   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
305   EXPECT_THAT(getDiagnosticString(),
306               HasSubstr("cannot be applied to structure members"));
307 }
308 
309 INSTANTIATE_TEST_SUITE_P(
310     ValidateNonMemberOnlyDecorations, NonMemberOnlyDecorations,
311     Values("SpecId 1", "Block", "BufferBlock", "ArrayStride 4", "GLSLShared",
312            "GLSLPacked", "CPacked",
313            // TODO: https://github.com/KhronosGroup/glslang/issues/703:
314            // glslang applies Restrict to structure members.
315            //"Restrict",
316            "Aliased", "Constant", "Uniform", "SaturatedConversion", "Index 0",
317            "Binding 0", "DescriptorSet 0", "FuncParamAttr Zext",
318            "FPRoundingMode RTE", "FPFastMathMode None",
319            "LinkageAttributes \"ext\" Import", "NoContraction",
320            "InputAttachmentIndex 0", "Alignment 4", "MaxByteOffset 4",
321            "AlignmentId %float", "MaxByteOffsetId %float", "NoSignedWrap",
322            "NoUnsignedWrap", "NonUniform", "RestrictPointer", "AliasedPointer",
323            "CounterBuffer %float"));
324 
325 using StructDecorations = spvtest::ValidateBase<std::string>;
326 
TEST_P(StructDecorations,Struct)327 TEST_P(StructDecorations, Struct) {
328   const std::string deco = GetParam();
329   const std::string text = R"(
330 OpCapability Shader
331 OpCapability Kernel
332 OpCapability Linkage
333 OpMemoryModel Logical GLSL450
334 OpDecorate %struct )" + deco +
335                            R"(
336 %struct = OpTypeStruct
337 )";
338 
339   CompileSuccessfully(text);
340   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
341 }
342 
TEST_P(StructDecorations,OtherType)343 TEST_P(StructDecorations, OtherType) {
344   const std::string deco = GetParam();
345   const std::string text = R"(
346 OpCapability Shader
347 OpCapability Kernel
348 OpCapability Linkage
349 OpMemoryModel Logical GLSL450
350 OpDecorate %int )" + deco + R"(
351 %int = OpTypeInt 32 0
352 )";
353 
354   CompileSuccessfully(text);
355   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
356   EXPECT_THAT(getDiagnosticString(), HasSubstr("must be a structure type"));
357 }
358 
TEST_P(StructDecorations,Variable)359 TEST_P(StructDecorations, Variable) {
360   const std::string deco = GetParam();
361   const std::string text = R"(
362 OpCapability Shader
363 OpCapability Kernel
364 OpCapability Linkage
365 OpMemoryModel Logical GLSL450
366 OpDecorate %var )" + deco + R"(
367 %int = OpTypeInt 32 0
368 %ptr = OpTypePointer Private %int
369 %var = OpVariable %ptr Private
370 )";
371 
372   CompileSuccessfully(text);
373   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
374   EXPECT_THAT(getDiagnosticString(), HasSubstr("must be a structure type"));
375 }
376 
TEST_P(StructDecorations,FunctionParameter)377 TEST_P(StructDecorations, FunctionParameter) {
378   const auto deco = GetParam();
379   const std::string text = R"(
380 OpCapability Shader
381 OpCapability Kernel
382 OpCapability Linkage
383 OpMemoryModel Logical GLSL450
384 OpDecorate %func LinkageAttributes "import" Import
385 OpDecorate %param )" + deco +
386                            R"(
387 %int = OpTypeInt 32 0
388 %void = OpTypeVoid
389 %fn = OpTypeFunction %void %int
390 %func = OpFunction %void None %fn
391 %param = OpFunctionParameter %int
392 OpFunctionEnd
393 )";
394 
395   CompileSuccessfully(text);
396   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
397   EXPECT_THAT(getDiagnosticString(), HasSubstr("must be a structure type"));
398 }
399 
TEST_P(StructDecorations,Constant)400 TEST_P(StructDecorations, Constant) {
401   const std::string deco = GetParam();
402   const std::string text = R"(
403 OpCapability Shader
404 OpCapability Kernel
405 OpCapability Linkage
406 OpMemoryModel Logical GLSL450
407 OpDecorate %int_0 )" + deco +
408                            R"(
409 %int = OpTypeInt 32 0
410 %int_0 = OpConstant %int 0
411 )";
412 
413   CompileSuccessfully(text);
414   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
415   EXPECT_THAT(getDiagnosticString(), HasSubstr("must be a structure type"));
416 }
417 
418 INSTANTIATE_TEST_SUITE_P(ValidateStructDecorations, StructDecorations,
419                          Values("Block", "BufferBlock", "GLSLShared",
420                                 "GLSLPacked", "CPacked"));
421 
422 using ArrayDecorations = spvtest::ValidateBase<std::string>;
423 
TEST_P(ArrayDecorations,Array)424 TEST_P(ArrayDecorations, Array) {
425   const auto deco = GetParam();
426   const std::string text = R"(
427 OpCapability Shader
428 OpCapability Linkage
429 OpMemoryModel Logical GLSL450
430 OpDecorate %array )" + deco +
431                            R"(
432 %int = OpTypeInt 32 0
433 %int_4 = OpConstant %int 4
434 %array = OpTypeArray %int %int_4
435 )";
436 
437   CompileSuccessfully(text);
438   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
439 }
440 
TEST_P(ArrayDecorations,RuntimeArray)441 TEST_P(ArrayDecorations, RuntimeArray) {
442   const auto deco = GetParam();
443   const std::string text = R"(
444 OpCapability Shader
445 OpCapability Linkage
446 OpMemoryModel Logical GLSL450
447 OpDecorate %array )" + deco +
448                            R"(
449 %int = OpTypeInt 32 0
450 %array = OpTypeRuntimeArray %int
451 )";
452 
453   CompileSuccessfully(text);
454   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
455 }
456 
TEST_P(ArrayDecorations,Pointer)457 TEST_P(ArrayDecorations, Pointer) {
458   const auto deco = GetParam();
459   const std::string text = R"(
460 OpCapability Shader
461 OpCapability Linkage
462 OpMemoryModel Logical GLSL450
463 OpDecorate %ptr )" + deco + R"(
464 %int = OpTypeInt 32 0
465 %ptr = OpTypePointer Workgroup %int
466 )";
467 
468   CompileSuccessfully(text);
469   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
470 }
471 
TEST_P(ArrayDecorations,Struct)472 TEST_P(ArrayDecorations, Struct) {
473   const auto deco = GetParam();
474   const std::string text = R"(
475 OpCapability Shader
476 OpCapability Linkage
477 OpMemoryModel Logical GLSL450
478 OpDecorate %struct )" + deco +
479                            R"(
480 %int = OpTypeInt 32 0
481 %struct = OpTypeStruct %int
482 )";
483 
484   CompileSuccessfully(text);
485   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
486   EXPECT_THAT(getDiagnosticString(),
487               HasSubstr("must be an array or pointer type"));
488 }
489 
TEST_P(ArrayDecorations,Variable)490 TEST_P(ArrayDecorations, Variable) {
491   const auto deco = GetParam();
492   const std::string text = R"(
493 OpCapability Shader
494 OpCapability Linkage
495 OpMemoryModel Logical GLSL450
496 OpDecorate %var )" + deco + R"(
497 %int = OpTypeInt 32 0
498 %ptr = OpTypePointer Private %int
499 %var = OpVariable %ptr Private
500 )";
501 
502   CompileSuccessfully(text);
503   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
504   EXPECT_THAT(getDiagnosticString(),
505               HasSubstr("must be an array or pointer type"));
506 }
507 
TEST_P(ArrayDecorations,FunctionParameter)508 TEST_P(ArrayDecorations, FunctionParameter) {
509   const auto deco = GetParam();
510   const std::string text = R"(
511 OpCapability Shader
512 OpCapability Linkage
513 OpMemoryModel Logical GLSL450
514 OpDecorate %func LinkageAttributes "import" Import
515 OpDecorate %param )" + deco +
516                            R"(
517 %int = OpTypeInt 32 0
518 %void = OpTypeVoid
519 %fn = OpTypeFunction %void %int
520 %func = OpFunction %void None %fn
521 %param = OpFunctionParameter %int
522 OpFunctionEnd
523 )";
524 
525   CompileSuccessfully(text);
526   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
527   EXPECT_THAT(getDiagnosticString(),
528               HasSubstr("must be an array or pointer type"));
529 }
530 
TEST_P(ArrayDecorations,Constant)531 TEST_P(ArrayDecorations, Constant) {
532   const auto deco = GetParam();
533   const std::string text = R"(
534 OpCapability Shader
535 OpCapability Linkage
536 OpMemoryModel Logical GLSL450
537 OpDecorate %null )" + deco +
538                            R"(
539 %int = OpTypeInt 32 0
540 %int_4 = OpConstant %int 4
541 %array = OpTypeArray %int %int_4
542 %null = OpConstantNull %array
543 )";
544 
545   CompileSuccessfully(text);
546   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
547   EXPECT_THAT(getDiagnosticString(),
548               HasSubstr("must be an array or pointer type"));
549 }
550 
551 INSTANTIATE_TEST_SUITE_P(ValidateArrayDecorations, ArrayDecorations,
552                          Values("ArrayStride 4"));
553 
554 using BuiltInDecorations = spvtest::ValidateBase<std::string>;
555 
TEST_P(BuiltInDecorations,Variable)556 TEST_P(BuiltInDecorations, Variable) {
557   const auto deco = GetParam();
558   const std::string text = R"(
559 OpCapability Shader
560 OpCapability Linkage
561 OpMemoryModel Logical GLSL450
562 OpDecorate %var BuiltIn )" +
563                            deco + R"(
564 %int = OpTypeInt 32 0
565 %ptr = OpTypePointer Input %int
566 %var = OpVariable %ptr Input
567 )";
568 
569   CompileSuccessfully(text);
570   if (deco != "WorkgroupSize") {
571     EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
572   } else {
573     EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
574     EXPECT_THAT(getDiagnosticString(),
575                 HasSubstr("must be a constant for WorkgroupSize"));
576   }
577 }
578 
TEST_P(BuiltInDecorations,IntegerType)579 TEST_P(BuiltInDecorations, IntegerType) {
580   const auto deco = GetParam();
581   const std::string text = R"(
582 OpCapability Shader
583 OpCapability Linkage
584 OpMemoryModel Logical GLSL450
585 OpDecorate %int BuiltIn )" +
586                            deco + R"(
587 %int = OpTypeInt 32 0
588 )";
589 
590   CompileSuccessfully(text);
591   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
592   EXPECT_THAT(getDiagnosticString(),
593               HasSubstr("BuiltIns can only target variables, structure members "
594                         "or constants"));
595 }
596 
TEST_P(BuiltInDecorations,FunctionParameter)597 TEST_P(BuiltInDecorations, FunctionParameter) {
598   const auto deco = GetParam();
599   const std::string text = R"(
600 OpCapability Shader
601 OpCapability Linkage
602 OpMemoryModel Logical GLSL450
603 OpDecorate %func LinkageAttributes "import" Import
604 OpDecorate %param BuiltIn )" +
605                            deco + R"(
606 %int = OpTypeInt 32 0
607 %void = OpTypeVoid
608 %fn = OpTypeFunction %void %int
609 %func = OpFunction %void None %fn
610 %param = OpFunctionParameter %int
611 OpFunctionEnd
612 )";
613 
614   CompileSuccessfully(text);
615   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
616   EXPECT_THAT(getDiagnosticString(),
617               HasSubstr("BuiltIns can only target variables, structure members "
618                         "or constants"));
619 }
620 
TEST_P(BuiltInDecorations,Constant)621 TEST_P(BuiltInDecorations, Constant) {
622   const auto deco = GetParam();
623   const std::string text = R"(
624 OpCapability Shader
625 OpCapability Linkage
626 OpMemoryModel Logical GLSL450
627 OpDecorate %const BuiltIn )" +
628                            deco + R"(
629 %int = OpTypeInt 32 0
630 %int3 = OpTypeVector %int 3
631 %int_1 = OpConstant %int 1
632 %const = OpConstantComposite %int3 %int_1 %int_1 %int_1
633 )";
634 
635   CompileSuccessfully(text);
636   if (deco == "WorkgroupSize") {
637     EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
638   } else {
639     EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
640     EXPECT_THAT(getDiagnosticString(), HasSubstr("must be a variable"));
641   }
642 }
643 
TEST_P(BuiltInDecorations,SpecConstant)644 TEST_P(BuiltInDecorations, SpecConstant) {
645   const auto deco = GetParam();
646   const std::string text = R"(
647 OpCapability Shader
648 OpCapability Linkage
649 OpMemoryModel Logical GLSL450
650 OpDecorate %const BuiltIn )" +
651                            deco + R"(
652 %int = OpTypeInt 32 0
653 %int3 = OpTypeVector %int 3
654 %int_1 = OpConstant %int 1
655 %const = OpSpecConstantComposite %int3 %int_1 %int_1 %int_1
656 )";
657 
658   CompileSuccessfully(text);
659   if (deco == "WorkgroupSize") {
660     EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
661   } else {
662     EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
663     EXPECT_THAT(getDiagnosticString(), HasSubstr("must be a variable"));
664   }
665 }
666 
667 INSTANTIATE_TEST_SUITE_P(ValidateBuiltInDecorations, BuiltInDecorations,
668                          Values("Position", "PointSize", "VertexId",
669                                 "InstanceId", "FragCoord", "FrontFacing",
670                                 "NumWorkgroups", "WorkgroupSize",
671                                 "LocalInvocationId", "GlobalInvocationId"));
672 
673 using MemoryObjectDecorations = spvtest::ValidateBase<std::string>;
674 
TEST_P(MemoryObjectDecorations,Variable)675 TEST_P(MemoryObjectDecorations, Variable) {
676   const auto deco = GetParam();
677   const std::string text = R"(
678 OpCapability Shader
679 OpCapability Linkage
680 OpCapability SampleRateShading
681 OpCapability TransformFeedback
682 OpCapability GeometryStreams
683 OpCapability Tessellation
684 OpCapability PhysicalStorageBufferAddresses
685 OpExtension "SPV_KHR_physical_storage_buffer"
686 OpMemoryModel Logical GLSL450
687 OpDecorate %var )" + deco + R"(
688 %float = OpTypeFloat 32
689 %ptr = OpTypePointer Input %float
690 %var = OpVariable %ptr Input
691 )";
692 
693   CompileSuccessfully(text);
694   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
695 }
696 
TEST_P(MemoryObjectDecorations,FunctionParameterGood)697 TEST_P(MemoryObjectDecorations, FunctionParameterGood) {
698   const auto deco = GetParam();
699   const std::string text = R"(
700 OpCapability Shader
701 OpCapability Linkage
702 OpCapability SampleRateShading
703 OpCapability TransformFeedback
704 OpCapability GeometryStreams
705 OpCapability Tessellation
706 OpCapability PhysicalStorageBufferAddresses
707 OpExtension "SPV_KHR_physical_storage_buffer"
708 OpMemoryModel Logical GLSL450
709 OpDecorate %func LinkageAttributes "import" Import
710 OpDecorate %param )" + deco +
711                            R"(
712 %float = OpTypeFloat 32
713 %ptr = OpTypePointer Input %float
714 %void = OpTypeVoid
715 %fn = OpTypeFunction %void %ptr
716 %func = OpFunction %void None %fn
717 %param = OpFunctionParameter %ptr
718 OpFunctionEnd
719 )";
720 
721   CompileSuccessfully(text);
722   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
723 }
724 
TEST_P(MemoryObjectDecorations,FunctionParameterNotAPointer)725 TEST_P(MemoryObjectDecorations, FunctionParameterNotAPointer) {
726   const auto deco = GetParam();
727   const std::string text = R"(
728 OpCapability Shader
729 OpCapability Linkage
730 OpCapability SampleRateShading
731 OpCapability TransformFeedback
732 OpCapability GeometryStreams
733 OpCapability Tessellation
734 OpCapability PhysicalStorageBufferAddresses
735 OpExtension "SPV_KHR_physical_storage_buffer"
736 OpMemoryModel Logical GLSL450
737 OpDecorate %func LinkageAttributes "import" Import
738 OpDecorate %param )" + deco +
739                            R"(
740 %float = OpTypeFloat 32
741 %void = OpTypeVoid
742 %fn = OpTypeFunction %void %float
743 %func = OpFunction %void None %fn
744 %param = OpFunctionParameter %float
745 OpFunctionEnd
746 )";
747 
748   CompileSuccessfully(text);
749   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
750   EXPECT_THAT(getDiagnosticString(), HasSubstr("must be a pointer type"));
751 }
752 
TEST_P(MemoryObjectDecorations,FloatType)753 TEST_P(MemoryObjectDecorations, FloatType) {
754   const auto deco = GetParam();
755   const std::string text = R"(
756 OpCapability Shader
757 OpCapability Linkage
758 OpCapability SampleRateShading
759 OpCapability TransformFeedback
760 OpCapability GeometryStreams
761 OpCapability Tessellation
762 OpCapability PhysicalStorageBufferAddresses
763 OpExtension "SPV_KHR_physical_storage_buffer"
764 OpMemoryModel Logical GLSL450
765 OpDecorate %float )" + deco +
766                            R"(
767 %float = OpTypeFloat 32
768 )";
769 
770   CompileSuccessfully(text);
771   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
772   EXPECT_THAT(getDiagnosticString(),
773               HasSubstr("must be a memory object declaration"));
774 }
775 
TEST_P(MemoryObjectDecorations,Constant)776 TEST_P(MemoryObjectDecorations, Constant) {
777   const auto deco = GetParam();
778   const std::string text = R"(
779 OpCapability Shader
780 OpCapability Linkage
781 OpCapability SampleRateShading
782 OpCapability TransformFeedback
783 OpCapability GeometryStreams
784 OpCapability Tessellation
785 OpCapability PhysicalStorageBufferAddresses
786 OpExtension "SPV_KHR_physical_storage_buffer"
787 OpMemoryModel Logical GLSL450
788 OpDecorate %const )" + deco +
789                            R"(
790 %float = OpTypeFloat 32
791 %const = OpConstant %float 0
792 )";
793 
794   CompileSuccessfully(text);
795   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
796   EXPECT_THAT(getDiagnosticString(),
797               HasSubstr("must be a memory object declaration"));
798 }
799 
800 // NonWritable and NonReadable are covered by other tests.
801 INSTANTIATE_TEST_SUITE_P(
802     ValidateMemoryObjectDecorations, MemoryObjectDecorations,
803     Values("NoPerspective", "Flat", "Patch", "Centroid", "Component 0",
804            "Sample", "Restrict", "Aliased", "Volatile", "Coherent", "Stream 0",
805            "XfbBuffer 1", "XfbStride 1", "AliasedPointer", "RestrictPointer"));
806 
807 using VariableDecorations = spvtest::ValidateBase<std::string>;
808 
TEST_P(VariableDecorations,Variable)809 TEST_P(VariableDecorations, Variable) {
810   const auto deco = GetParam();
811   const std::string text = R"(
812 OpCapability Shader
813 OpCapability Kernel
814 OpCapability Linkage
815 OpCapability InputAttachment
816 OpMemoryModel Logical GLSL450
817 OpDecorate %var )" + deco + R"(
818 %float = OpTypeFloat 32
819 %ptr = OpTypePointer Input %float
820 %var = OpVariable %ptr Input
821 )";
822 
823   CompileSuccessfully(text);
824   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
825 }
826 
TEST_P(VariableDecorations,FunctionParameter)827 TEST_P(VariableDecorations, FunctionParameter) {
828   const auto deco = GetParam();
829   const std::string text = R"(
830 OpCapability Shader
831 OpCapability Kernel
832 OpCapability Linkage
833 OpCapability InputAttachment
834 OpMemoryModel Logical GLSL450
835 OpDecorate %func LinkageAttributes "import" Import
836 OpDecorate %param )" + deco +
837                            R"(
838 %float = OpTypeFloat 32
839 %void = OpTypeVoid
840 %fn = OpTypeFunction %void %float
841 %func = OpFunction %void None %fn
842 %param = OpFunctionParameter %float
843 OpFunctionEnd
844 )";
845 
846   CompileSuccessfully(text);
847   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
848   EXPECT_THAT(getDiagnosticString(), HasSubstr("must be a variable"));
849 }
850 
TEST_P(VariableDecorations,FloatType)851 TEST_P(VariableDecorations, FloatType) {
852   const auto deco = GetParam();
853   const std::string text = R"(
854 OpCapability Shader
855 OpCapability Kernel
856 OpCapability Linkage
857 OpCapability InputAttachment
858 OpMemoryModel Logical GLSL450
859 OpDecorate %float )" + deco +
860                            R"(
861 %float = OpTypeFloat 32
862 )";
863 
864   CompileSuccessfully(text);
865   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
866   EXPECT_THAT(getDiagnosticString(), HasSubstr("must be a variable"));
867 }
868 
TEST_P(VariableDecorations,Constant)869 TEST_P(VariableDecorations, Constant) {
870   const auto deco = GetParam();
871   const std::string text = R"(
872 OpCapability Shader
873 OpCapability Kernel
874 OpCapability Linkage
875 OpCapability InputAttachment
876 OpMemoryModel Logical GLSL450
877 OpDecorate %const )" + deco +
878                            R"(
879 %float = OpTypeFloat 32
880 %const = OpConstant %float 0
881 )";
882 
883   CompileSuccessfully(text);
884   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
885   EXPECT_THAT(getDiagnosticString(), HasSubstr("must be a variable"));
886 }
887 
888 INSTANTIATE_TEST_SUITE_P(ValidateVariableDecorations, VariableDecorations,
889                          Values("Invariant", "Constant", "Location 0",
890                                 "Index 0", "Binding 0", "DescriptorSet 0"));
891 
892 using VulkanIOStorageClass =
893     spvtest::ValidateBase<std::tuple<std::string, std::string>>;
894 
TEST_P(VulkanIOStorageClass,Invalid)895 TEST_P(VulkanIOStorageClass, Invalid) {
896   const auto deco = std::get<0>(GetParam());
897   const auto sc = std::get<1>(GetParam());
898   const std::string text = R"(
899 OpCapability Shader
900 OpExtension "SPV_KHR_storage_buffer_storage_class"
901 OpMemoryModel Logical GLSL450
902 OpEntryPoint Fragment %main "main"
903 OpExecutionMode %main OriginUpperLeft
904 OpDecorate %var )" + deco + R"( 0
905 %void = OpTypeVoid
906 %float = OpTypeFloat 32
907 %ptr = OpTypePointer )" +
908                            sc +
909                            R"( %float
910 %var = OpVariable %ptr )" + sc +
911                            R"(
912 %void_fn = OpTypeFunction %void
913 %main = OpFunction %void None %void_fn
914 %entry = OpLabel
915 OpReturn
916 OpFunctionEnd
917 )";
918 
919   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
920   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
921   EXPECT_THAT(getDiagnosticString(),
922               AnyVUID("VUID-StandaloneSpirv-Location-06672"));
923   EXPECT_THAT(
924       getDiagnosticString(),
925       HasSubstr("decoration must not be applied to this storage class"));
926 }
927 
928 INSTANTIATE_TEST_SUITE_P(ValidateVulkanIOStorageClass, VulkanIOStorageClass,
929                          Combine(Values("Location", "Component"),
930                                  Values("StorageBuffer", "Uniform",
931                                         "UniformConstant", "Workgroup",
932                                         "Private")));
933 
934 using VulkanResourceStorageClass =
935     spvtest::ValidateBase<std::tuple<std::string, std::string>>;
936 
TEST_P(VulkanResourceStorageClass,Invalid)937 TEST_P(VulkanResourceStorageClass, Invalid) {
938   const auto deco = std::get<0>(GetParam());
939   const auto sc = std::get<1>(GetParam());
940   const std::string text = R"(
941 OpCapability Shader
942 OpMemoryModel Logical GLSL450
943 OpEntryPoint Fragment %main "main"
944 OpExecutionMode %main OriginUpperLeft
945 OpDecorate %var )" + deco + R"( 0
946 %void = OpTypeVoid
947 %float = OpTypeFloat 32
948 %ptr = OpTypePointer )" +
949                            sc +
950                            R"( %float
951 %var = OpVariable %ptr )" + sc +
952                            R"(
953 %void_fn = OpTypeFunction %void
954 %main = OpFunction %void None %void_fn
955 %entry = OpLabel
956 OpReturn
957 OpFunctionEnd
958 )";
959 
960   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
961   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
962   EXPECT_THAT(getDiagnosticString(),
963               HasSubstr("VUID-StandaloneSpirv-DescriptorSet-06491"));
964   EXPECT_THAT(getDiagnosticString(),
965               HasSubstr("must be in the StorageBuffer, Uniform, or "
966                         "UniformConstant storage class"));
967 }
968 
969 INSTANTIATE_TEST_SUITE_P(ValidateVulkanResourceStorageClass,
970                          VulkanResourceStorageClass,
971                          Combine(Values("DescriptorSet", "Binding"),
972                                  Values("Private", "Input", "Output",
973                                         "Workgroup")));
974 
975 using VulkanInterpolationStorageClass = spvtest::ValidateBase<std::string>;
976 
TEST_P(VulkanInterpolationStorageClass,Input)977 TEST_P(VulkanInterpolationStorageClass, Input) {
978   const auto deco = GetParam();
979   const std::string text = R"(
980 OpCapability Shader
981 OpCapability SampleRateShading
982 OpMemoryModel Logical GLSL450
983 OpEntryPoint Fragment %main "main"
984 OpExecutionMode %main OriginUpperLeft
985 OpDecorate %var )" + deco + R"(
986 %void = OpTypeVoid
987 %float = OpTypeFloat 32
988 %void_fn = OpTypeFunction %void
989 %ptr = OpTypePointer Input %float
990 %var = OpVariable %ptr Input
991 %main = OpFunction %void None %void_fn
992 %entry = OpLabel
993 OpReturn
994 OpFunctionEnd
995 )";
996 
997   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
998   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
999 }
1000 
TEST_P(VulkanInterpolationStorageClass,Output)1001 TEST_P(VulkanInterpolationStorageClass, Output) {
1002   const auto deco = GetParam();
1003   const std::string text = R"(
1004 OpCapability Shader
1005 OpCapability SampleRateShading
1006 OpMemoryModel Logical GLSL450
1007 OpEntryPoint Vertex %main "main"
1008 OpDecorate %var )" + deco + R"(
1009 %void = OpTypeVoid
1010 %float = OpTypeFloat 32
1011 %void_fn = OpTypeFunction %void
1012 %ptr = OpTypePointer Output %float
1013 %var = OpVariable %ptr Output
1014 %main = OpFunction %void None %void_fn
1015 %entry = OpLabel
1016 OpReturn
1017 OpFunctionEnd
1018 )";
1019 
1020   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
1021   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
1022 }
1023 
TEST_P(VulkanInterpolationStorageClass,Private)1024 TEST_P(VulkanInterpolationStorageClass, Private) {
1025   const auto deco = GetParam();
1026   const std::string text = R"(
1027 OpCapability Shader
1028 OpCapability SampleRateShading
1029 OpMemoryModel Logical GLSL450
1030 OpEntryPoint Fragment %main "main"
1031 OpExecutionMode %main OriginUpperLeft
1032 OpDecorate %var )" + deco + R"(
1033 %void = OpTypeVoid
1034 %float = OpTypeFloat 32
1035 %void_fn = OpTypeFunction %void
1036 %ptr = OpTypePointer Private %float
1037 %var = OpVariable %ptr Private
1038 %main = OpFunction %void None %void_fn
1039 %entry = OpLabel
1040 OpReturn
1041 OpFunctionEnd
1042 )";
1043 
1044   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
1045   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
1046   EXPECT_THAT(getDiagnosticString(),
1047               HasSubstr("storage class must be Input or Output"));
1048   EXPECT_THAT(getDiagnosticString(),
1049               HasSubstr("[VUID-StandaloneSpirv-Flat-04670"));
1050 }
1051 
TEST_P(VulkanInterpolationStorageClass,Uniform)1052 TEST_P(VulkanInterpolationStorageClass, Uniform) {
1053   const auto deco = GetParam();
1054   const std::string text = R"(
1055 OpCapability Shader
1056 OpCapability SampleRateShading
1057 OpMemoryModel Logical GLSL450
1058 OpEntryPoint Fragment %main "main"
1059 OpExecutionMode %main OriginUpperLeft
1060 OpDecorate %var )" + deco + R"(
1061 OpDecorate %var Binding 0
1062 OpDecorate %var DescriptorSet 0
1063 %void = OpTypeVoid
1064 %float = OpTypeFloat 32
1065 %void_fn = OpTypeFunction %void
1066 %ptr = OpTypePointer Uniform %float
1067 %var = OpVariable %ptr Uniform
1068 %main = OpFunction %void None %void_fn
1069 %entry = OpLabel
1070 OpReturn
1071 OpFunctionEnd
1072 )";
1073 
1074   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
1075   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
1076   EXPECT_THAT(getDiagnosticString(),
1077               HasSubstr("storage class must be Input or Output"));
1078   EXPECT_THAT(getDiagnosticString(),
1079               HasSubstr("[VUID-StandaloneSpirv-Flat-04670"));
1080 }
1081 
TEST_P(VulkanInterpolationStorageClass,StorageBuffer)1082 TEST_P(VulkanInterpolationStorageClass, StorageBuffer) {
1083   const auto deco = GetParam();
1084   const std::string text = R"(
1085 OpCapability Shader
1086 OpCapability SampleRateShading
1087 OpExtension "SPV_KHR_storage_buffer_storage_class"
1088 OpMemoryModel Logical GLSL450
1089 OpEntryPoint Fragment %main "main"
1090 OpExecutionMode %main OriginUpperLeft
1091 OpDecorate %var )" + deco + R"(
1092 OpDecorate %var Binding 0
1093 OpDecorate %var DescriptorSet 0
1094 %void = OpTypeVoid
1095 %float = OpTypeFloat 32
1096 %void_fn = OpTypeFunction %void
1097 %ptr = OpTypePointer StorageBuffer %float
1098 %var = OpVariable %ptr StorageBuffer
1099 %main = OpFunction %void None %void_fn
1100 %entry = OpLabel
1101 OpReturn
1102 OpFunctionEnd
1103 )";
1104 
1105   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
1106   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
1107   EXPECT_THAT(getDiagnosticString(),
1108               HasSubstr("storage class must be Input or Output"));
1109   EXPECT_THAT(getDiagnosticString(),
1110               HasSubstr("[VUID-StandaloneSpirv-Flat-04670"));
1111 }
1112 
1113 INSTANTIATE_TEST_SUITE_P(ValidateVulkanInterpolationStorageClass,
1114                          VulkanInterpolationStorageClass,
1115                          Values("Flat", "NoPerspective", "Centroid", "Sample"));
1116 
1117 }  // namespace
1118 }  // namespace val
1119 }  // namespace spvtools
1120