• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2017 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 decorations
16 
17 #include <string>
18 #include <vector>
19 
20 #include "gmock/gmock.h"
21 #include "source/val/decoration.h"
22 #include "test/test_fixture.h"
23 #include "test/unit_spirv.h"
24 #include "test/val/val_code_generator.h"
25 #include "test/val/val_fixtures.h"
26 
27 namespace spvtools {
28 namespace val {
29 namespace {
30 
31 using ::testing::Combine;
32 using ::testing::Eq;
33 using ::testing::HasSubstr;
34 using ::testing::Values;
35 
36 struct TestResult {
TestResultspvtools::val::__anon081788260111::TestResult37   TestResult(spv_result_t in_validation_result = SPV_SUCCESS,
38              const std::string& in_error_str = "")
39       : validation_result(in_validation_result), error_str(in_error_str) {}
40   spv_result_t validation_result;
41   const std::string error_str;
42 };
43 
44 using ValidateDecorations = spvtest::ValidateBase<bool>;
45 using ValidateVulkanCombineDecorationResult =
46     spvtest::ValidateBase<std::tuple<const char*, const char*, TestResult>>;
47 
TEST_F(ValidateDecorations,ValidateOpDecorateRegistration)48 TEST_F(ValidateDecorations, ValidateOpDecorateRegistration) {
49   std::string spirv = R"(
50     OpCapability Shader
51     OpCapability Linkage
52     OpMemoryModel Logical GLSL450
53     OpDecorate %1 ArrayStride 4
54     OpDecorate %1 RelaxedPrecision
55     %2 = OpTypeFloat 32
56     %1 = OpTypeRuntimeArray %2
57     ; Since %1 is used first in Decoration, it gets id 1.
58 )";
59   const uint32_t id = 1;
60   CompileSuccessfully(spirv);
61   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
62   // Must have 2 decorations.
63   EXPECT_THAT(
64       vstate_->id_decorations(id),
65       Eq(std::vector<Decoration>{Decoration(SpvDecorationArrayStride, {4}),
66                                  Decoration(SpvDecorationRelaxedPrecision)}));
67 }
68 
TEST_F(ValidateDecorations,ValidateOpMemberDecorateRegistration)69 TEST_F(ValidateDecorations, ValidateOpMemberDecorateRegistration) {
70   std::string spirv = R"(
71     OpCapability Shader
72     OpCapability Linkage
73     OpMemoryModel Logical GLSL450
74     OpDecorate %_arr_double_uint_6 ArrayStride 4
75     OpMemberDecorate %_struct_115 2 NonReadable
76     OpMemberDecorate %_struct_115 2 Offset 2
77     OpDecorate %_struct_115 BufferBlock
78     %float = OpTypeFloat 32
79     %uint = OpTypeInt 32 0
80     %uint_6 = OpConstant %uint 6
81     %_arr_double_uint_6 = OpTypeArray %float %uint_6
82     %_struct_115 = OpTypeStruct %float %float %_arr_double_uint_6
83 )";
84   CompileSuccessfully(spirv);
85   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
86 
87   // The array must have 1 decoration.
88   const uint32_t arr_id = 1;
89   EXPECT_THAT(
90       vstate_->id_decorations(arr_id),
91       Eq(std::vector<Decoration>{Decoration(SpvDecorationArrayStride, {4})}));
92 
93   // The struct must have 3 decorations.
94   const uint32_t struct_id = 2;
95   EXPECT_THAT(
96       vstate_->id_decorations(struct_id),
97       Eq(std::vector<Decoration>{Decoration(SpvDecorationNonReadable, {}, 2),
98                                  Decoration(SpvDecorationOffset, {2}, 2),
99                                  Decoration(SpvDecorationBufferBlock)}));
100 }
101 
TEST_F(ValidateDecorations,ValidateOpMemberDecorateOutOfBound)102 TEST_F(ValidateDecorations, ValidateOpMemberDecorateOutOfBound) {
103   std::string spirv = R"(
104                OpCapability Shader
105                OpMemoryModel Logical GLSL450
106                OpEntryPoint Fragment %1 "Main"
107                OpExecutionMode %1 OriginUpperLeft
108                OpMemberDecorate %_struct_2 1 RelaxedPrecision
109        %void = OpTypeVoid
110           %4 = OpTypeFunction %void
111       %float = OpTypeFloat 32
112   %_struct_2 = OpTypeStruct %float
113           %1 = OpFunction %void None %4
114           %6 = OpLabel
115                OpReturn
116                OpFunctionEnd
117 )";
118   CompileSuccessfully(spirv);
119   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
120   EXPECT_THAT(getDiagnosticString(),
121               HasSubstr("Index 1 provided in OpMemberDecorate for struct <id> "
122                         "2[%_struct_2] is out of bounds. The structure has 1 "
123                         "members. Largest valid index is 0."));
124 }
125 
TEST_F(ValidateDecorations,ValidateGroupDecorateRegistration)126 TEST_F(ValidateDecorations, ValidateGroupDecorateRegistration) {
127   std::string spirv = R"(
128                OpCapability Shader
129                OpCapability Linkage
130                OpMemoryModel Logical GLSL450
131                OpDecorate %1 DescriptorSet 0
132                OpDecorate %1 RelaxedPrecision
133                OpDecorate %1 Restrict
134           %1 = OpDecorationGroup
135                OpGroupDecorate %1 %2 %3
136                OpGroupDecorate %1 %4
137   %float = OpTypeFloat 32
138 %_runtimearr_float = OpTypeRuntimeArray %float
139   %_struct_9 = OpTypeStruct %_runtimearr_float
140 %_ptr_Uniform__struct_9 = OpTypePointer Uniform %_struct_9
141          %2 = OpVariable %_ptr_Uniform__struct_9 Uniform
142  %_struct_10 = OpTypeStruct %_runtimearr_float
143 %_ptr_Uniform__struct_10 = OpTypePointer Uniform %_struct_10
144          %3 = OpVariable %_ptr_Uniform__struct_10 Uniform
145  %_struct_11 = OpTypeStruct %_runtimearr_float
146 %_ptr_Uniform__struct_11 = OpTypePointer Uniform %_struct_11
147          %4 = OpVariable %_ptr_Uniform__struct_11 Uniform
148   )";
149   CompileSuccessfully(spirv);
150   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
151 
152   // Decoration group has 3 decorations.
153   auto expected_decorations =
154       std::vector<Decoration>{Decoration(SpvDecorationDescriptorSet, {0}),
155                               Decoration(SpvDecorationRelaxedPrecision),
156                               Decoration(SpvDecorationRestrict)};
157 
158   // Decoration group is applied to id 1, 2, 3, and 4. Note that id 1 (which is
159   // the decoration group id) also has all the decorations.
160   EXPECT_THAT(vstate_->id_decorations(1), Eq(expected_decorations));
161   EXPECT_THAT(vstate_->id_decorations(2), Eq(expected_decorations));
162   EXPECT_THAT(vstate_->id_decorations(3), Eq(expected_decorations));
163   EXPECT_THAT(vstate_->id_decorations(4), Eq(expected_decorations));
164 }
165 
TEST_F(ValidateDecorations,ValidateGroupMemberDecorateRegistration)166 TEST_F(ValidateDecorations, ValidateGroupMemberDecorateRegistration) {
167   std::string spirv = R"(
168                OpCapability Shader
169                OpCapability Linkage
170                OpMemoryModel Logical GLSL450
171                OpDecorate %1 Offset 3
172           %1 = OpDecorationGroup
173                OpGroupMemberDecorate %1 %_struct_1 3 %_struct_2 3 %_struct_3 3
174       %float = OpTypeFloat 32
175 %_runtimearr = OpTypeRuntimeArray %float
176   %_struct_1 = OpTypeStruct %float %float %float %_runtimearr
177   %_struct_2 = OpTypeStruct %float %float %float %_runtimearr
178   %_struct_3 = OpTypeStruct %float %float %float %_runtimearr
179   )";
180   CompileSuccessfully(spirv);
181   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
182   // Decoration group has 1 decoration.
183   auto expected_decorations =
184       std::vector<Decoration>{Decoration(SpvDecorationOffset, {3}, 3)};
185 
186   // Decoration group is applied to id 2, 3, and 4.
187   EXPECT_THAT(vstate_->id_decorations(2), Eq(expected_decorations));
188   EXPECT_THAT(vstate_->id_decorations(3), Eq(expected_decorations));
189   EXPECT_THAT(vstate_->id_decorations(4), Eq(expected_decorations));
190 }
191 
TEST_F(ValidateDecorations,LinkageImportUsedForInitializedVariableBad)192 TEST_F(ValidateDecorations, LinkageImportUsedForInitializedVariableBad) {
193   std::string spirv = R"(
194                OpCapability Shader
195                OpCapability Linkage
196                OpMemoryModel Logical GLSL450
197                OpDecorate %target LinkageAttributes "link_ptr" Import
198       %float = OpTypeFloat 32
199  %_ptr_float = OpTypePointer Uniform %float
200        %zero = OpConstantNull %float
201      %target = OpVariable %_ptr_float Uniform %zero
202   )";
203   CompileSuccessfully(spirv);
204   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
205   EXPECT_THAT(getDiagnosticString(),
206               HasSubstr("A module-scope OpVariable with initialization value "
207                         "cannot be marked with the Import Linkage Type."));
208 }
TEST_F(ValidateDecorations,LinkageExportUsedForInitializedVariableGood)209 TEST_F(ValidateDecorations, LinkageExportUsedForInitializedVariableGood) {
210   std::string spirv = R"(
211                OpCapability Shader
212                OpCapability Linkage
213                OpMemoryModel Logical GLSL450
214                OpDecorate %target LinkageAttributes "link_ptr" Export
215       %float = OpTypeFloat 32
216  %_ptr_float = OpTypePointer Uniform %float
217        %zero = OpConstantNull %float
218      %target = OpVariable %_ptr_float Uniform %zero
219   )";
220   CompileSuccessfully(spirv);
221   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
222 }
223 
TEST_F(ValidateDecorations,StructAllMembersHaveBuiltInDecorationsGood)224 TEST_F(ValidateDecorations, StructAllMembersHaveBuiltInDecorationsGood) {
225   std::string spirv = R"(
226                OpCapability Shader
227                OpCapability Linkage
228                OpMemoryModel Logical GLSL450
229                OpMemberDecorate %_struct_1 0 BuiltIn Position
230                OpMemberDecorate %_struct_1 1 BuiltIn Position
231                OpMemberDecorate %_struct_1 2 BuiltIn Position
232                OpMemberDecorate %_struct_1 3 BuiltIn Position
233       %float = OpTypeFloat 32
234 %_runtimearr = OpTypeRuntimeArray %float
235   %_struct_1 = OpTypeStruct %float %float %float %_runtimearr
236   )";
237   CompileSuccessfully(spirv);
238   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
239 }
240 
TEST_F(ValidateDecorations,MixedBuiltInDecorationsBad)241 TEST_F(ValidateDecorations, MixedBuiltInDecorationsBad) {
242   std::string spirv = R"(
243                OpCapability Shader
244                OpCapability Linkage
245                OpMemoryModel Logical GLSL450
246                OpMemberDecorate %_struct_1 0 BuiltIn Position
247                OpMemberDecorate %_struct_1 1 BuiltIn Position
248       %float = OpTypeFloat 32
249 %_runtimearr = OpTypeRuntimeArray %float
250   %_struct_1 = OpTypeStruct %float %float %float %_runtimearr
251   )";
252   CompileSuccessfully(spirv);
253   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
254   EXPECT_THAT(
255       getDiagnosticString(),
256       HasSubstr("When BuiltIn decoration is applied to a structure-type "
257                 "member, all members of that structure type must also be "
258                 "decorated with BuiltIn (No allowed mixing of built-in "
259                 "variables and non-built-in variables within a single "
260                 "structure). Structure id 1 does not meet this requirement."));
261 }
262 
TEST_F(ValidateDecorations,StructContainsBuiltInStructBad)263 TEST_F(ValidateDecorations, StructContainsBuiltInStructBad) {
264   std::string spirv = R"(
265                OpCapability Shader
266                OpCapability Linkage
267                OpMemoryModel Logical GLSL450
268                OpMemberDecorate %_struct_1 0 BuiltIn Position
269                OpMemberDecorate %_struct_1 1 BuiltIn Position
270                OpMemberDecorate %_struct_1 2 BuiltIn Position
271                OpMemberDecorate %_struct_1 3 BuiltIn Position
272       %float = OpTypeFloat 32
273 %_runtimearr = OpTypeRuntimeArray %float
274   %_struct_1 = OpTypeStruct %float %float %float %_runtimearr
275   %_struct_2 = OpTypeStruct %_struct_1
276   )";
277   CompileSuccessfully(spirv);
278   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
279   EXPECT_THAT(getDiagnosticString(),
280               HasSubstr("Structure <id> 1[%_struct_1] contains members with "
281                         "BuiltIn decoration. Therefore this structure may not "
282                         "be contained as a member of another structure type. "
283                         "Structure <id> 4[%_struct_4] contains structure <id> "
284                         "1[%_struct_1]."));
285 }
286 
TEST_F(ValidateDecorations,StructContainsNonBuiltInStructGood)287 TEST_F(ValidateDecorations, StructContainsNonBuiltInStructGood) {
288   std::string spirv = R"(
289                OpCapability Shader
290                OpCapability Linkage
291                OpMemoryModel Logical GLSL450
292       %float = OpTypeFloat 32
293   %_struct_1 = OpTypeStruct %float
294   %_struct_2 = OpTypeStruct %_struct_1
295   )";
296   CompileSuccessfully(spirv);
297   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
298 }
299 
TEST_F(ValidateDecorations,MultipleBuiltInObjectsConsumedByOpEntryPointBad)300 TEST_F(ValidateDecorations, MultipleBuiltInObjectsConsumedByOpEntryPointBad) {
301   std::string spirv = R"(
302                OpCapability Shader
303                OpCapability Geometry
304                OpMemoryModel Logical GLSL450
305                OpEntryPoint Geometry %main "main" %in_1 %in_2
306                OpExecutionMode %main InputPoints
307                OpExecutionMode %main OutputPoints
308                OpMemberDecorate %struct_1 0 BuiltIn InvocationId
309                OpMemberDecorate %struct_2 0 BuiltIn Position
310       %int = OpTypeInt 32 1
311      %void = OpTypeVoid
312      %func = OpTypeFunction %void
313     %float = OpTypeFloat 32
314  %struct_1 = OpTypeStruct %int
315  %struct_2 = OpTypeStruct %float
316 %ptr_builtin_1 = OpTypePointer Input %struct_1
317 %ptr_builtin_2 = OpTypePointer Input %struct_2
318 %in_1 = OpVariable %ptr_builtin_1 Input
319 %in_2 = OpVariable %ptr_builtin_2 Input
320        %main = OpFunction %void None %func
321           %5 = OpLabel
322                OpReturn
323                OpFunctionEnd
324   )";
325   CompileSuccessfully(spirv);
326   EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateAndRetrieveValidationState());
327   EXPECT_THAT(getDiagnosticString(),
328               HasSubstr("There must be at most one object per Storage Class "
329                         "that can contain a structure type containing members "
330                         "decorated with BuiltIn, consumed per entry-point."));
331 }
332 
TEST_F(ValidateDecorations,OneBuiltInObjectPerStorageClassConsumedByOpEntryPointGood)333 TEST_F(ValidateDecorations,
334        OneBuiltInObjectPerStorageClassConsumedByOpEntryPointGood) {
335   std::string spirv = R"(
336                OpCapability Shader
337                OpCapability Geometry
338                OpMemoryModel Logical GLSL450
339                OpEntryPoint Geometry %main "main" %in_1 %out_1
340                OpExecutionMode %main InputPoints
341                OpExecutionMode %main OutputPoints
342                OpMemberDecorate %struct_1 0 BuiltIn InvocationId
343                OpMemberDecorate %struct_2 0 BuiltIn Position
344       %int = OpTypeInt 32 1
345      %void = OpTypeVoid
346      %func = OpTypeFunction %void
347     %float = OpTypeFloat 32
348  %struct_1 = OpTypeStruct %int
349  %struct_2 = OpTypeStruct %float
350 %ptr_builtin_1 = OpTypePointer Input %struct_1
351 %ptr_builtin_2 = OpTypePointer Output %struct_2
352 %in_1 = OpVariable %ptr_builtin_1 Input
353 %out_1 = OpVariable %ptr_builtin_2 Output
354        %main = OpFunction %void None %func
355           %5 = OpLabel
356                OpReturn
357                OpFunctionEnd
358   )";
359   CompileSuccessfully(spirv);
360   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
361 }
362 
TEST_F(ValidateDecorations,NoBuiltInObjectsConsumedByOpEntryPointGood)363 TEST_F(ValidateDecorations, NoBuiltInObjectsConsumedByOpEntryPointGood) {
364   std::string spirv = R"(
365                OpCapability Shader
366                OpCapability Geometry
367                OpMemoryModel Logical GLSL450
368                OpEntryPoint Geometry %main "main" %in_1 %out_1
369                OpExecutionMode %main InputPoints
370                OpExecutionMode %main OutputPoints
371       %int = OpTypeInt 32 1
372      %void = OpTypeVoid
373      %func = OpTypeFunction %void
374     %float = OpTypeFloat 32
375  %struct_1 = OpTypeStruct %int
376  %struct_2 = OpTypeStruct %float
377 %ptr_builtin_1 = OpTypePointer Input %struct_1
378 %ptr_builtin_2 = OpTypePointer Output %struct_2
379 %in_1 = OpVariable %ptr_builtin_1 Input
380 %out_1 = OpVariable %ptr_builtin_2 Output
381        %main = OpFunction %void None %func
382           %5 = OpLabel
383                OpReturn
384                OpFunctionEnd
385   )";
386   CompileSuccessfully(spirv);
387   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
388 }
389 
TEST_F(ValidateDecorations,EntryPointFunctionHasLinkageAttributeBad)390 TEST_F(ValidateDecorations, EntryPointFunctionHasLinkageAttributeBad) {
391   std::string spirv = R"(
392       OpCapability Shader
393       OpCapability Linkage
394       OpMemoryModel Logical GLSL450
395       OpEntryPoint GLCompute %main "main"
396       OpDecorate %main LinkageAttributes "import_main" Import
397 %1 = OpTypeVoid
398 %2 = OpTypeFunction %1
399 %main = OpFunction %1 None %2
400 %4 = OpLabel
401      OpReturn
402      OpFunctionEnd
403 )";
404   CompileSuccessfully(spirv.c_str());
405   EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
406   EXPECT_THAT(
407       getDiagnosticString(),
408       HasSubstr("The LinkageAttributes Decoration (Linkage name: import_main) "
409                 "cannot be applied to function id 1 because it is targeted by "
410                 "an OpEntryPoint instruction."));
411 }
412 
TEST_F(ValidateDecorations,FunctionDeclarationWithoutImportLinkageBad)413 TEST_F(ValidateDecorations, FunctionDeclarationWithoutImportLinkageBad) {
414   std::string spirv = R"(
415                OpCapability Shader
416                OpCapability Linkage
417                OpMemoryModel Logical GLSL450
418      %void = OpTypeVoid
419      %func = OpTypeFunction %void
420        %main = OpFunction %void None %func
421                OpFunctionEnd
422   )";
423   CompileSuccessfully(spirv);
424   EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateAndRetrieveValidationState());
425   EXPECT_THAT(
426       getDiagnosticString(),
427       HasSubstr("Function declaration (id 3) must have a LinkageAttributes "
428                 "decoration with the Import Linkage type."));
429 }
430 
TEST_F(ValidateDecorations,FunctionDeclarationWithImportLinkageGood)431 TEST_F(ValidateDecorations, FunctionDeclarationWithImportLinkageGood) {
432   std::string spirv = R"(
433                OpCapability Shader
434                OpCapability Linkage
435                OpMemoryModel Logical GLSL450
436                OpDecorate %main LinkageAttributes "link_fn" Import
437      %void = OpTypeVoid
438      %func = OpTypeFunction %void
439        %main = OpFunction %void None %func
440                OpFunctionEnd
441   )";
442   CompileSuccessfully(spirv);
443   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
444 }
445 
TEST_F(ValidateDecorations,FunctionDeclarationWithExportLinkageBad)446 TEST_F(ValidateDecorations, FunctionDeclarationWithExportLinkageBad) {
447   std::string spirv = R"(
448                OpCapability Shader
449                OpCapability Linkage
450                OpMemoryModel Logical GLSL450
451                OpDecorate %main LinkageAttributes "link_fn" Export
452      %void = OpTypeVoid
453      %func = OpTypeFunction %void
454        %main = OpFunction %void None %func
455                OpFunctionEnd
456   )";
457   CompileSuccessfully(spirv);
458   EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateAndRetrieveValidationState());
459   EXPECT_THAT(
460       getDiagnosticString(),
461       HasSubstr("Function declaration (id 1) must have a LinkageAttributes "
462                 "decoration with the Import Linkage type."));
463 }
464 
TEST_F(ValidateDecorations,FunctionDefinitionWithImportLinkageBad)465 TEST_F(ValidateDecorations, FunctionDefinitionWithImportLinkageBad) {
466   std::string spirv = R"(
467                OpCapability Shader
468                OpCapability Linkage
469                OpMemoryModel Logical GLSL450
470                OpDecorate %main LinkageAttributes "link_fn" Import
471      %void = OpTypeVoid
472      %func = OpTypeFunction %void
473        %main = OpFunction %void None %func
474       %label = OpLabel
475                OpReturn
476                OpFunctionEnd
477   )";
478   CompileSuccessfully(spirv);
479   EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateAndRetrieveValidationState());
480   EXPECT_THAT(getDiagnosticString(),
481               HasSubstr("Function definition (id 1) may not be decorated with "
482                         "Import Linkage type."));
483 }
484 
TEST_F(ValidateDecorations,FunctionDefinitionWithoutImportLinkageGood)485 TEST_F(ValidateDecorations, FunctionDefinitionWithoutImportLinkageGood) {
486   std::string spirv = R"(
487                OpCapability Shader
488                OpCapability Linkage
489                OpMemoryModel Logical GLSL450
490      %void = OpTypeVoid
491      %func = OpTypeFunction %void
492        %main = OpFunction %void None %func
493       %label = OpLabel
494                OpReturn
495                OpFunctionEnd
496   )";
497   CompileSuccessfully(spirv);
498   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
499 }
500 
TEST_F(ValidateDecorations,BuiltinVariablesGoodVulkan)501 TEST_F(ValidateDecorations, BuiltinVariablesGoodVulkan) {
502   const spv_target_env env = SPV_ENV_VULKAN_1_0;
503   std::string spirv = R"(
504 OpCapability Shader
505 OpMemoryModel Logical GLSL450
506 OpEntryPoint Fragment %main "main" %gl_FragCoord %_entryPointOutput
507 OpExecutionMode %main OriginUpperLeft
508 OpSource HLSL 500
509 OpDecorate %gl_FragCoord BuiltIn FragCoord
510 OpDecorate %_entryPointOutput Location 0
511 %void = OpTypeVoid
512 %3 = OpTypeFunction %void
513 %float = OpTypeFloat 32
514 %v4float = OpTypeVector %float 4
515 %float_0 = OpConstant %float 0
516 %14 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
517 %_ptr_Input_v4float = OpTypePointer Input %v4float
518 %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
519 %_ptr_Output_v4float = OpTypePointer Output %v4float
520 %_entryPointOutput = OpVariable %_ptr_Output_v4float Output
521 %main = OpFunction %void None %3
522 %5 = OpLabel
523 OpStore %_entryPointOutput %14
524 OpReturn
525 OpFunctionEnd
526 )";
527 
528   CompileSuccessfully(spirv, env);
529   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env));
530 }
531 
TEST_F(ValidateDecorations,BuiltinVariablesWithLocationDecorationVulkan)532 TEST_F(ValidateDecorations, BuiltinVariablesWithLocationDecorationVulkan) {
533   const spv_target_env env = SPV_ENV_VULKAN_1_0;
534   std::string spirv = R"(
535 OpCapability Shader
536 OpMemoryModel Logical GLSL450
537 OpEntryPoint Fragment %main "main" %gl_FragCoord %_entryPointOutput
538 OpExecutionMode %main OriginUpperLeft
539 OpSource HLSL 500
540 OpDecorate %gl_FragCoord BuiltIn FragCoord
541 OpDecorate %gl_FragCoord Location 0
542 OpDecorate %_entryPointOutput Location 0
543 %void = OpTypeVoid
544 %3 = OpTypeFunction %void
545 %float = OpTypeFloat 32
546 %v4float = OpTypeVector %float 4
547 %float_0 = OpConstant %float 0
548 %14 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
549 %_ptr_Input_v4float = OpTypePointer Input %v4float
550 %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
551 %_ptr_Output_v4float = OpTypePointer Output %v4float
552 %_entryPointOutput = OpVariable %_ptr_Output_v4float Output
553 %main = OpFunction %void None %3
554 %5 = OpLabel
555 OpStore %_entryPointOutput %14
556 OpReturn
557 OpFunctionEnd
558 )";
559 
560   CompileSuccessfully(spirv, env);
561   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(env));
562   EXPECT_THAT(getDiagnosticString(),
563               HasSubstr("A BuiltIn variable (id 2) cannot have any Location or "
564                         "Component decorations"));
565 }
TEST_F(ValidateDecorations,BuiltinVariablesWithComponentDecorationVulkan)566 TEST_F(ValidateDecorations, BuiltinVariablesWithComponentDecorationVulkan) {
567   const spv_target_env env = SPV_ENV_VULKAN_1_0;
568   std::string spirv = R"(
569 OpCapability Shader
570 OpMemoryModel Logical GLSL450
571 OpEntryPoint Fragment %main "main" %gl_FragCoord %_entryPointOutput
572 OpExecutionMode %main OriginUpperLeft
573 OpSource HLSL 500
574 OpDecorate %gl_FragCoord BuiltIn FragCoord
575 OpDecorate %gl_FragCoord Component 0
576 OpDecorate %_entryPointOutput Location 0
577 %void = OpTypeVoid
578 %3 = OpTypeFunction %void
579 %float = OpTypeFloat 32
580 %v4float = OpTypeVector %float 4
581 %float_0 = OpConstant %float 0
582 %14 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
583 %_ptr_Input_v4float = OpTypePointer Input %v4float
584 %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
585 %_ptr_Output_v4float = OpTypePointer Output %v4float
586 %_entryPointOutput = OpVariable %_ptr_Output_v4float Output
587 %main = OpFunction %void None %3
588 %5 = OpLabel
589 OpStore %_entryPointOutput %14
590 OpReturn
591 OpFunctionEnd
592 )";
593 
594   CompileSuccessfully(spirv, env);
595   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(env));
596   EXPECT_THAT(getDiagnosticString(),
597               HasSubstr("A BuiltIn variable (id 2) cannot have any Location or "
598                         "Component decorations"));
599 }
600 
601 // #version 440
602 // #extension GL_EXT_nonuniform_qualifier : enable
603 // layout(binding = 1) uniform sampler2D s2d[];
604 // layout(location = 0) in nonuniformEXT int i;
605 // void main()
606 // {
607 //     vec4 v = texture(s2d[i], vec2(0.3));
608 // }
TEST_F(ValidateDecorations,RuntimeArrayOfDescriptorSetsIsAllowed)609 TEST_F(ValidateDecorations, RuntimeArrayOfDescriptorSetsIsAllowed) {
610   const spv_target_env env = SPV_ENV_VULKAN_1_0;
611   std::string spirv = R"(
612                OpCapability Shader
613                OpCapability ShaderNonUniformEXT
614                OpCapability RuntimeDescriptorArrayEXT
615                OpCapability SampledImageArrayNonUniformIndexingEXT
616                OpExtension "SPV_EXT_descriptor_indexing"
617           %1 = OpExtInstImport "GLSL.std.450"
618                OpMemoryModel Logical GLSL450
619                OpEntryPoint Vertex %main "main" %i
620                OpSource GLSL 440
621                OpSourceExtension "GL_EXT_nonuniform_qualifier"
622                OpName %main "main"
623                OpName %v "v"
624                OpName %s2d "s2d"
625                OpName %i "i"
626                OpDecorate %s2d DescriptorSet 0
627                OpDecorate %s2d Binding 1
628                OpDecorate %i Location 0
629                OpDecorate %i NonUniformEXT
630                OpDecorate %18 NonUniformEXT
631                OpDecorate %21 NonUniformEXT
632        %void = OpTypeVoid
633           %3 = OpTypeFunction %void
634       %float = OpTypeFloat 32
635     %v4float = OpTypeVector %float 4
636 %_ptr_Function_v4float = OpTypePointer Function %v4float
637          %10 = OpTypeImage %float 2D 0 0 0 1 Unknown
638          %11 = OpTypeSampledImage %10
639 %_runtimearr_11 = OpTypeRuntimeArray %11
640 %_ptr_Uniform__runtimearr_11 = OpTypePointer Uniform %_runtimearr_11
641         %s2d = OpVariable %_ptr_Uniform__runtimearr_11 Uniform
642         %int = OpTypeInt 32 1
643 %_ptr_Input_int = OpTypePointer Input %int
644           %i = OpVariable %_ptr_Input_int Input
645 %_ptr_Uniform_11 = OpTypePointer Uniform %11
646     %v2float = OpTypeVector %float 2
647 %float_0_300000012 = OpConstant %float 0.300000012
648          %24 = OpConstantComposite %v2float %float_0_300000012 %float_0_300000012
649     %float_0 = OpConstant %float 0
650        %main = OpFunction %void None %3
651           %5 = OpLabel
652           %v = OpVariable %_ptr_Function_v4float Function
653          %18 = OpLoad %int %i
654          %20 = OpAccessChain %_ptr_Uniform_11 %s2d %18
655          %21 = OpLoad %11 %20
656          %26 = OpImageSampleExplicitLod %v4float %21 %24 Lod %float_0
657                OpStore %v %26
658                OpReturn
659                OpFunctionEnd
660 )";
661   CompileSuccessfully(spirv, env);
662   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
663 }
664 
TEST_F(ValidateDecorations,BlockDecoratingArrayBad)665 TEST_F(ValidateDecorations, BlockDecoratingArrayBad) {
666   std::string spirv = R"(
667                OpCapability Shader
668           %1 = OpExtInstImport "GLSL.std.450"
669                OpMemoryModel Logical GLSL450
670                OpEntryPoint GLCompute %main "main"
671                OpExecutionMode %main LocalSize 1 1 1
672                OpSource GLSL 430
673                OpDecorate %Output Block
674        %void = OpTypeVoid
675           %3 = OpTypeFunction %void
676       %float = OpTypeFloat 32
677         %int = OpTypeInt 32 1
678       %int_3 = OpConstant %int 3
679      %Output = OpTypeArray %float %int_3
680 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
681  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
682        %main = OpFunction %void None %3
683           %5 = OpLabel
684                OpReturn
685                OpFunctionEnd
686   )";
687 
688   CompileSuccessfully(spirv);
689   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
690   EXPECT_THAT(getDiagnosticString(),
691               HasSubstr("Block decoration on a non-struct type"));
692 }
693 
TEST_F(ValidateDecorations,BlockDecoratingIntBad)694 TEST_F(ValidateDecorations, BlockDecoratingIntBad) {
695   std::string spirv = R"(
696                OpCapability Shader
697           %1 = OpExtInstImport "GLSL.std.450"
698                OpMemoryModel Logical GLSL450
699                OpEntryPoint GLCompute %main "main"
700                OpExecutionMode %main LocalSize 1 1 1
701                OpSource GLSL 430
702                OpDecorate %Output Block
703        %void = OpTypeVoid
704           %3 = OpTypeFunction %void
705      %Output = OpTypeInt 32 1
706 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
707  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
708        %main = OpFunction %void None %3
709           %5 = OpLabel
710                OpReturn
711                OpFunctionEnd
712   )";
713 
714   CompileSuccessfully(spirv);
715   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
716   EXPECT_THAT(getDiagnosticString(),
717               HasSubstr("Block decoration on a non-struct type"));
718 }
719 
TEST_F(ValidateDecorations,BlockMissingOffsetBad)720 TEST_F(ValidateDecorations, BlockMissingOffsetBad) {
721   std::string spirv = R"(
722                OpCapability Shader
723           %1 = OpExtInstImport "GLSL.std.450"
724                OpMemoryModel Logical GLSL450
725                OpEntryPoint GLCompute %main "main"
726                OpExecutionMode %main LocalSize 1 1 1
727                OpSource GLSL 430
728                OpDecorate %Output Block
729        %void = OpTypeVoid
730           %3 = OpTypeFunction %void
731       %float = OpTypeFloat 32
732      %Output = OpTypeStruct %float
733 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
734  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
735        %main = OpFunction %void None %3
736           %5 = OpLabel
737                OpReturn
738                OpFunctionEnd
739   )";
740 
741   CompileSuccessfully(spirv);
742   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
743   EXPECT_THAT(getDiagnosticString(),
744               HasSubstr("must be explicitly laid out with Offset decorations"));
745 }
746 
TEST_F(ValidateDecorations,BufferBlockMissingOffsetBad)747 TEST_F(ValidateDecorations, BufferBlockMissingOffsetBad) {
748   std::string spirv = R"(
749                OpCapability Shader
750           %1 = OpExtInstImport "GLSL.std.450"
751                OpMemoryModel Logical GLSL450
752                OpEntryPoint GLCompute %main "main"
753                OpExecutionMode %main LocalSize 1 1 1
754                OpSource GLSL 430
755                OpDecorate %Output BufferBlock
756        %void = OpTypeVoid
757           %3 = OpTypeFunction %void
758       %float = OpTypeFloat 32
759      %Output = OpTypeStruct %float
760 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
761  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
762        %main = OpFunction %void None %3
763           %5 = OpLabel
764                OpReturn
765                OpFunctionEnd
766   )";
767 
768   CompileSuccessfully(spirv);
769   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
770   EXPECT_THAT(getDiagnosticString(),
771               HasSubstr("must be explicitly laid out with Offset decorations"));
772 }
773 
TEST_F(ValidateDecorations,BlockNestedStructMissingOffsetBad)774 TEST_F(ValidateDecorations, BlockNestedStructMissingOffsetBad) {
775   std::string spirv = R"(
776                OpCapability Shader
777           %1 = OpExtInstImport "GLSL.std.450"
778                OpMemoryModel Logical GLSL450
779                OpEntryPoint GLCompute %main "main"
780                OpExecutionMode %main LocalSize 1 1 1
781                OpSource GLSL 430
782                OpMemberDecorate %S 0 Offset 0
783                OpMemberDecorate %Output 0 Offset 0
784                OpMemberDecorate %Output 1 Offset 16
785                OpMemberDecorate %Output 2 Offset 32
786                OpDecorate %Output Block
787        %void = OpTypeVoid
788           %3 = OpTypeFunction %void
789       %float = OpTypeFloat 32
790     %v4float = OpTypeVector %float 4
791     %v3float = OpTypeVector %float 3
792         %int = OpTypeInt 32 1
793           %S = OpTypeStruct %v3float %int
794      %Output = OpTypeStruct %float %v4float %S
795 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
796  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
797        %main = OpFunction %void None %3
798           %5 = OpLabel
799                OpReturn
800                OpFunctionEnd
801   )";
802 
803   CompileSuccessfully(spirv);
804   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
805   EXPECT_THAT(getDiagnosticString(),
806               HasSubstr("must be explicitly laid out with Offset decorations"));
807 }
808 
TEST_F(ValidateDecorations,BufferBlockNestedStructMissingOffsetBad)809 TEST_F(ValidateDecorations, BufferBlockNestedStructMissingOffsetBad) {
810   std::string spirv = R"(
811                OpCapability Shader
812           %1 = OpExtInstImport "GLSL.std.450"
813                OpMemoryModel Logical GLSL450
814                OpEntryPoint GLCompute %main "main"
815                OpExecutionMode %main LocalSize 1 1 1
816                OpSource GLSL 430
817                OpMemberDecorate %S 0 Offset 0
818                OpMemberDecorate %Output 0 Offset 0
819                OpMemberDecorate %Output 1 Offset 16
820                OpMemberDecorate %Output 2 Offset 32
821                OpDecorate %Output BufferBlock
822        %void = OpTypeVoid
823           %3 = OpTypeFunction %void
824       %float = OpTypeFloat 32
825     %v4float = OpTypeVector %float 4
826     %v3float = OpTypeVector %float 3
827         %int = OpTypeInt 32 1
828           %S = OpTypeStruct %v3float %int
829      %Output = OpTypeStruct %float %v4float %S
830 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
831  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
832        %main = OpFunction %void None %3
833           %5 = OpLabel
834                OpReturn
835                OpFunctionEnd
836   )";
837 
838   CompileSuccessfully(spirv);
839   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
840   EXPECT_THAT(getDiagnosticString(),
841               HasSubstr("must be explicitly laid out with Offset decorations"));
842 }
843 
TEST_F(ValidateDecorations,BlockGLSLSharedBad)844 TEST_F(ValidateDecorations, BlockGLSLSharedBad) {
845   std::string spirv = R"(
846                OpCapability Shader
847           %1 = OpExtInstImport "GLSL.std.450"
848                OpMemoryModel Logical GLSL450
849                OpEntryPoint GLCompute %main "main"
850                OpExecutionMode %main LocalSize 1 1 1
851                OpSource GLSL 430
852                OpDecorate %Output Block
853                OpDecorate %Output GLSLShared
854                OpMemberDecorate %Output 0 Offset 0
855        %void = OpTypeVoid
856           %3 = OpTypeFunction %void
857       %float = OpTypeFloat 32
858      %Output = OpTypeStruct %float
859 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
860  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
861        %main = OpFunction %void None %3
862           %5 = OpLabel
863                OpReturn
864                OpFunctionEnd
865   )";
866 
867   CompileSuccessfully(spirv);
868   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
869   EXPECT_THAT(getDiagnosticString(),
870               HasSubstr("must not use GLSLShared decoration"));
871 }
872 
TEST_F(ValidateDecorations,BufferBlockGLSLSharedBad)873 TEST_F(ValidateDecorations, BufferBlockGLSLSharedBad) {
874   std::string spirv = R"(
875                OpCapability Shader
876           %1 = OpExtInstImport "GLSL.std.450"
877                OpMemoryModel Logical GLSL450
878                OpEntryPoint GLCompute %main "main"
879                OpExecutionMode %main LocalSize 1 1 1
880                OpSource GLSL 430
881                OpDecorate %Output BufferBlock
882                OpDecorate %Output GLSLShared
883                OpMemberDecorate %Output 0 Offset 0
884        %void = OpTypeVoid
885           %3 = OpTypeFunction %void
886       %float = OpTypeFloat 32
887      %Output = OpTypeStruct %float
888 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
889  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
890        %main = OpFunction %void None %3
891           %5 = OpLabel
892                OpReturn
893                OpFunctionEnd
894   )";
895 
896   CompileSuccessfully(spirv);
897   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
898   EXPECT_THAT(getDiagnosticString(),
899               HasSubstr("must not use GLSLShared decoration"));
900 }
901 
TEST_F(ValidateDecorations,BlockNestedStructGLSLSharedBad)902 TEST_F(ValidateDecorations, BlockNestedStructGLSLSharedBad) {
903   std::string spirv = R"(
904                OpCapability Shader
905           %1 = OpExtInstImport "GLSL.std.450"
906                OpMemoryModel Logical GLSL450
907                OpEntryPoint GLCompute %main "main"
908                OpExecutionMode %main LocalSize 1 1 1
909                OpSource GLSL 430
910                OpMemberDecorate %S 0 Offset 0
911                OpDecorate %S GLSLShared
912                OpMemberDecorate %Output 0 Offset 0
913                OpMemberDecorate %Output 1 Offset 16
914                OpMemberDecorate %Output 2 Offset 32
915                OpDecorate %Output Block
916        %void = OpTypeVoid
917           %3 = OpTypeFunction %void
918       %float = OpTypeFloat 32
919     %v4float = OpTypeVector %float 4
920         %int = OpTypeInt 32 1
921           %S = OpTypeStruct %int
922      %Output = OpTypeStruct %float %v4float %S
923 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
924  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
925        %main = OpFunction %void None %3
926           %5 = OpLabel
927                OpReturn
928                OpFunctionEnd
929   )";
930 
931   CompileSuccessfully(spirv);
932   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
933   EXPECT_THAT(getDiagnosticString(),
934               HasSubstr("must not use GLSLShared decoration"));
935 }
936 
TEST_F(ValidateDecorations,BufferBlockNestedStructGLSLSharedBad)937 TEST_F(ValidateDecorations, BufferBlockNestedStructGLSLSharedBad) {
938   std::string spirv = R"(
939                OpCapability Shader
940           %1 = OpExtInstImport "GLSL.std.450"
941                OpMemoryModel Logical GLSL450
942                OpEntryPoint GLCompute %main "main"
943                OpExecutionMode %main LocalSize 1 1 1
944                OpSource GLSL 430
945                OpMemberDecorate %S 0 Offset 0
946                OpDecorate %S GLSLShared
947                OpMemberDecorate %Output 0 Offset 0
948                OpMemberDecorate %Output 1 Offset 16
949                OpMemberDecorate %Output 2 Offset 32
950                OpDecorate %Output BufferBlock
951        %void = OpTypeVoid
952           %3 = OpTypeFunction %void
953       %float = OpTypeFloat 32
954     %v4float = OpTypeVector %float 4
955         %int = OpTypeInt 32 1
956           %S = OpTypeStruct %int
957      %Output = OpTypeStruct %float %v4float %S
958 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
959  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
960        %main = OpFunction %void None %3
961           %5 = OpLabel
962                OpReturn
963                OpFunctionEnd
964   )";
965 
966   CompileSuccessfully(spirv);
967   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
968   EXPECT_THAT(getDiagnosticString(),
969               HasSubstr("must not use GLSLShared decoration"));
970 }
971 
TEST_F(ValidateDecorations,BlockGLSLPackedBad)972 TEST_F(ValidateDecorations, BlockGLSLPackedBad) {
973   std::string spirv = R"(
974                OpCapability Shader
975           %1 = OpExtInstImport "GLSL.std.450"
976                OpMemoryModel Logical GLSL450
977                OpEntryPoint GLCompute %main "main"
978                OpExecutionMode %main LocalSize 1 1 1
979                OpSource GLSL 430
980                OpDecorate %Output Block
981                OpDecorate %Output GLSLPacked
982                OpMemberDecorate %Output 0 Offset 0
983        %void = OpTypeVoid
984           %3 = OpTypeFunction %void
985       %float = OpTypeFloat 32
986      %Output = OpTypeStruct %float
987 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
988  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
989        %main = OpFunction %void None %3
990           %5 = OpLabel
991                OpReturn
992                OpFunctionEnd
993   )";
994 
995   CompileSuccessfully(spirv);
996   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
997   EXPECT_THAT(getDiagnosticString(),
998               HasSubstr("must not use GLSLPacked decoration"));
999 }
1000 
TEST_F(ValidateDecorations,BufferBlockGLSLPackedBad)1001 TEST_F(ValidateDecorations, BufferBlockGLSLPackedBad) {
1002   std::string spirv = R"(
1003                OpCapability Shader
1004           %1 = OpExtInstImport "GLSL.std.450"
1005                OpMemoryModel Logical GLSL450
1006                OpEntryPoint GLCompute %main "main"
1007                OpExecutionMode %main LocalSize 1 1 1
1008                OpSource GLSL 430
1009                OpDecorate %Output BufferBlock
1010                OpDecorate %Output GLSLPacked
1011                OpMemberDecorate %Output 0 Offset 0
1012        %void = OpTypeVoid
1013           %3 = OpTypeFunction %void
1014       %float = OpTypeFloat 32
1015      %Output = OpTypeStruct %float
1016 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
1017  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
1018        %main = OpFunction %void None %3
1019           %5 = OpLabel
1020                OpReturn
1021                OpFunctionEnd
1022   )";
1023 
1024   CompileSuccessfully(spirv);
1025   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
1026   EXPECT_THAT(getDiagnosticString(),
1027               HasSubstr("must not use GLSLPacked decoration"));
1028 }
1029 
TEST_F(ValidateDecorations,BlockNestedStructGLSLPackedBad)1030 TEST_F(ValidateDecorations, BlockNestedStructGLSLPackedBad) {
1031   std::string spirv = R"(
1032                OpCapability Shader
1033           %1 = OpExtInstImport "GLSL.std.450"
1034                OpMemoryModel Logical GLSL450
1035                OpEntryPoint GLCompute %main "main"
1036                OpExecutionMode %main LocalSize 1 1 1
1037                OpSource GLSL 430
1038                OpMemberDecorate %S 0 Offset 0
1039                OpDecorate %S GLSLPacked
1040                OpMemberDecorate %Output 0 Offset 0
1041                OpMemberDecorate %Output 1 Offset 16
1042                OpMemberDecorate %Output 2 Offset 32
1043                OpDecorate %Output Block
1044        %void = OpTypeVoid
1045           %3 = OpTypeFunction %void
1046       %float = OpTypeFloat 32
1047     %v4float = OpTypeVector %float 4
1048         %int = OpTypeInt 32 1
1049           %S = OpTypeStruct %int
1050      %Output = OpTypeStruct %float %v4float %S
1051 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
1052  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
1053        %main = OpFunction %void None %3
1054           %5 = OpLabel
1055                OpReturn
1056                OpFunctionEnd
1057   )";
1058 
1059   CompileSuccessfully(spirv);
1060   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
1061   EXPECT_THAT(getDiagnosticString(),
1062               HasSubstr("must not use GLSLPacked decoration"));
1063 }
1064 
TEST_F(ValidateDecorations,BufferBlockNestedStructGLSLPackedBad)1065 TEST_F(ValidateDecorations, BufferBlockNestedStructGLSLPackedBad) {
1066   std::string spirv = R"(
1067                OpCapability Shader
1068           %1 = OpExtInstImport "GLSL.std.450"
1069                OpMemoryModel Logical GLSL450
1070                OpEntryPoint GLCompute %main "main"
1071                OpExecutionMode %main LocalSize 1 1 1
1072                OpSource GLSL 430
1073                OpMemberDecorate %S 0 Offset 0
1074                OpDecorate %S GLSLPacked
1075                OpMemberDecorate %Output 0 Offset 0
1076                OpMemberDecorate %Output 1 Offset 16
1077                OpMemberDecorate %Output 2 Offset 32
1078                OpDecorate %Output BufferBlock
1079        %void = OpTypeVoid
1080           %3 = OpTypeFunction %void
1081       %float = OpTypeFloat 32
1082     %v4float = OpTypeVector %float 4
1083         %int = OpTypeInt 32 1
1084           %S = OpTypeStruct %int
1085      %Output = OpTypeStruct %float %v4float %S
1086 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
1087  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
1088        %main = OpFunction %void None %3
1089           %5 = OpLabel
1090                OpReturn
1091                OpFunctionEnd
1092   )";
1093 
1094   CompileSuccessfully(spirv);
1095   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
1096   EXPECT_THAT(getDiagnosticString(),
1097               HasSubstr("must not use GLSLPacked decoration"));
1098 }
1099 
TEST_F(ValidateDecorations,BlockMissingArrayStrideBad)1100 TEST_F(ValidateDecorations, BlockMissingArrayStrideBad) {
1101   std::string spirv = R"(
1102                OpCapability Shader
1103           %1 = OpExtInstImport "GLSL.std.450"
1104                OpMemoryModel Logical GLSL450
1105                OpEntryPoint GLCompute %main "main"
1106                OpExecutionMode %main LocalSize 1 1 1
1107                OpSource GLSL 430
1108                OpDecorate %Output Block
1109                OpMemberDecorate %Output 0 Offset 0
1110        %void = OpTypeVoid
1111           %3 = OpTypeFunction %void
1112       %float = OpTypeFloat 32
1113         %int = OpTypeInt 32 1
1114       %int_3 = OpConstant %int 3
1115       %array = OpTypeArray %float %int_3
1116      %Output = OpTypeStruct %array
1117 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
1118  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
1119        %main = OpFunction %void None %3
1120           %5 = OpLabel
1121                OpReturn
1122                OpFunctionEnd
1123   )";
1124 
1125   CompileSuccessfully(spirv);
1126   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
1127   EXPECT_THAT(
1128       getDiagnosticString(),
1129       HasSubstr("must be explicitly laid out with ArrayStride decorations"));
1130 }
1131 
TEST_F(ValidateDecorations,BufferBlockMissingArrayStrideBad)1132 TEST_F(ValidateDecorations, BufferBlockMissingArrayStrideBad) {
1133   std::string spirv = R"(
1134                OpCapability Shader
1135           %1 = OpExtInstImport "GLSL.std.450"
1136                OpMemoryModel Logical GLSL450
1137                OpEntryPoint GLCompute %main "main"
1138                OpExecutionMode %main LocalSize 1 1 1
1139                OpSource GLSL 430
1140                OpDecorate %Output BufferBlock
1141                OpMemberDecorate %Output 0 Offset 0
1142        %void = OpTypeVoid
1143           %3 = OpTypeFunction %void
1144       %float = OpTypeFloat 32
1145         %int = OpTypeInt 32 1
1146       %int_3 = OpConstant %int 3
1147       %array = OpTypeArray %float %int_3
1148      %Output = OpTypeStruct %array
1149 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
1150  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
1151        %main = OpFunction %void None %3
1152           %5 = OpLabel
1153                OpReturn
1154                OpFunctionEnd
1155   )";
1156 
1157   CompileSuccessfully(spirv);
1158   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
1159   EXPECT_THAT(
1160       getDiagnosticString(),
1161       HasSubstr("must be explicitly laid out with ArrayStride decorations"));
1162 }
1163 
TEST_F(ValidateDecorations,BlockNestedStructMissingArrayStrideBad)1164 TEST_F(ValidateDecorations, BlockNestedStructMissingArrayStrideBad) {
1165   std::string spirv = R"(
1166                OpCapability Shader
1167           %1 = OpExtInstImport "GLSL.std.450"
1168                OpMemoryModel Logical GLSL450
1169                OpEntryPoint GLCompute %main "main"
1170                OpExecutionMode %main LocalSize 1 1 1
1171                OpSource GLSL 430
1172                OpMemberDecorate %S 0 Offset 0
1173                OpMemberDecorate %Output 0 Offset 0
1174                OpMemberDecorate %Output 1 Offset 16
1175                OpMemberDecorate %Output 2 Offset 32
1176                OpDecorate %Output Block
1177        %void = OpTypeVoid
1178           %3 = OpTypeFunction %void
1179       %float = OpTypeFloat 32
1180     %v4float = OpTypeVector %float 4
1181         %int = OpTypeInt 32 1
1182       %int_3 = OpConstant %int 3
1183       %array = OpTypeArray %float %int_3
1184           %S = OpTypeStruct %array
1185      %Output = OpTypeStruct %float %v4float %S
1186 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
1187  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
1188        %main = OpFunction %void None %3
1189           %5 = OpLabel
1190                OpReturn
1191                OpFunctionEnd
1192   )";
1193 
1194   CompileSuccessfully(spirv);
1195   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
1196   EXPECT_THAT(
1197       getDiagnosticString(),
1198       HasSubstr("must be explicitly laid out with ArrayStride decorations"));
1199 }
1200 
TEST_F(ValidateDecorations,BufferBlockNestedStructMissingArrayStrideBad)1201 TEST_F(ValidateDecorations, BufferBlockNestedStructMissingArrayStrideBad) {
1202   std::string spirv = R"(
1203                OpCapability Shader
1204           %1 = OpExtInstImport "GLSL.std.450"
1205                OpMemoryModel Logical GLSL450
1206                OpEntryPoint GLCompute %main "main"
1207                OpExecutionMode %main LocalSize 1 1 1
1208                OpSource GLSL 430
1209                OpMemberDecorate %S 0 Offset 0
1210                OpMemberDecorate %Output 0 Offset 0
1211                OpMemberDecorate %Output 1 Offset 16
1212                OpMemberDecorate %Output 2 Offset 32
1213                OpDecorate %Output BufferBlock
1214        %void = OpTypeVoid
1215           %3 = OpTypeFunction %void
1216       %float = OpTypeFloat 32
1217     %v4float = OpTypeVector %float 4
1218         %int = OpTypeInt 32 1
1219       %int_3 = OpConstant %int 3
1220       %array = OpTypeArray %float %int_3
1221           %S = OpTypeStruct %array
1222      %Output = OpTypeStruct %float %v4float %S
1223 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
1224  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
1225        %main = OpFunction %void None %3
1226           %5 = OpLabel
1227                OpReturn
1228                OpFunctionEnd
1229   )";
1230 
1231   CompileSuccessfully(spirv);
1232   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
1233   EXPECT_THAT(
1234       getDiagnosticString(),
1235       HasSubstr("must be explicitly laid out with ArrayStride decorations"));
1236 }
1237 
TEST_F(ValidateDecorations,BlockMissingMatrixStrideBad)1238 TEST_F(ValidateDecorations, BlockMissingMatrixStrideBad) {
1239   std::string spirv = R"(
1240                OpCapability Shader
1241           %1 = OpExtInstImport "GLSL.std.450"
1242                OpMemoryModel Logical GLSL450
1243                OpEntryPoint GLCompute %main "main"
1244                OpExecutionMode %main LocalSize 1 1 1
1245                OpSource GLSL 430
1246                OpDecorate %Output Block
1247                OpMemberDecorate %Output 0 Offset 0
1248        %void = OpTypeVoid
1249           %3 = OpTypeFunction %void
1250       %float = OpTypeFloat 32
1251     %v3float = OpTypeVector %float 3
1252      %matrix = OpTypeMatrix %v3float 4
1253      %Output = OpTypeStruct %matrix
1254 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
1255  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
1256        %main = OpFunction %void None %3
1257           %5 = OpLabel
1258                OpReturn
1259                OpFunctionEnd
1260   )";
1261 
1262   CompileSuccessfully(spirv);
1263   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
1264   EXPECT_THAT(
1265       getDiagnosticString(),
1266       HasSubstr("must be explicitly laid out with MatrixStride decorations"));
1267 }
1268 
TEST_F(ValidateDecorations,BufferBlockMissingMatrixStrideBad)1269 TEST_F(ValidateDecorations, BufferBlockMissingMatrixStrideBad) {
1270   std::string spirv = R"(
1271                OpCapability Shader
1272           %1 = OpExtInstImport "GLSL.std.450"
1273                OpMemoryModel Logical GLSL450
1274                OpEntryPoint GLCompute %main "main"
1275                OpExecutionMode %main LocalSize 1 1 1
1276                OpSource GLSL 430
1277                OpDecorate %Output BufferBlock
1278                OpMemberDecorate %Output 0 Offset 0
1279        %void = OpTypeVoid
1280           %3 = OpTypeFunction %void
1281       %float = OpTypeFloat 32
1282     %v3float = OpTypeVector %float 3
1283      %matrix = OpTypeMatrix %v3float 4
1284      %Output = OpTypeStruct %matrix
1285 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
1286  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
1287        %main = OpFunction %void None %3
1288           %5 = OpLabel
1289                OpReturn
1290                OpFunctionEnd
1291   )";
1292 
1293   CompileSuccessfully(spirv);
1294   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
1295   EXPECT_THAT(
1296       getDiagnosticString(),
1297       HasSubstr("must be explicitly laid out with MatrixStride decorations"));
1298 }
1299 
TEST_F(ValidateDecorations,BlockMissingMatrixStrideArrayBad)1300 TEST_F(ValidateDecorations, BlockMissingMatrixStrideArrayBad) {
1301   std::string spirv = R"(
1302                OpCapability Shader
1303           %1 = OpExtInstImport "GLSL.std.450"
1304                OpMemoryModel Logical GLSL450
1305                OpEntryPoint GLCompute %main "main"
1306                OpExecutionMode %main LocalSize 1 1 1
1307                OpSource GLSL 430
1308                OpDecorate %Output Block
1309                OpMemberDecorate %Output 0 Offset 0
1310        %void = OpTypeVoid
1311           %3 = OpTypeFunction %void
1312       %float = OpTypeFloat 32
1313     %v3float = OpTypeVector %float 3
1314      %matrix = OpTypeMatrix %v3float 4
1315         %int = OpTypeInt 32 1
1316       %int_3 = OpConstant %int 3
1317       %array = OpTypeArray %matrix %int_3
1318      %Output = OpTypeStruct %matrix
1319 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
1320  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
1321        %main = OpFunction %void None %3
1322           %5 = OpLabel
1323                OpReturn
1324                OpFunctionEnd
1325   )";
1326 
1327   CompileSuccessfully(spirv);
1328   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
1329   EXPECT_THAT(
1330       getDiagnosticString(),
1331       HasSubstr("must be explicitly laid out with MatrixStride decorations"));
1332 }
1333 
TEST_F(ValidateDecorations,BufferBlockMissingMatrixStrideArrayBad)1334 TEST_F(ValidateDecorations, BufferBlockMissingMatrixStrideArrayBad) {
1335   std::string spirv = R"(
1336                OpCapability Shader
1337           %1 = OpExtInstImport "GLSL.std.450"
1338                OpMemoryModel Logical GLSL450
1339                OpEntryPoint GLCompute %main "main"
1340                OpExecutionMode %main LocalSize 1 1 1
1341                OpSource GLSL 430
1342                OpDecorate %Output BufferBlock
1343                OpMemberDecorate %Output 0 Offset 0
1344        %void = OpTypeVoid
1345           %3 = OpTypeFunction %void
1346       %float = OpTypeFloat 32
1347     %v3float = OpTypeVector %float 3
1348      %matrix = OpTypeMatrix %v3float 4
1349         %int = OpTypeInt 32 1
1350       %int_3 = OpConstant %int 3
1351       %array = OpTypeArray %matrix %int_3
1352      %Output = OpTypeStruct %matrix
1353 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
1354  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
1355        %main = OpFunction %void None %3
1356           %5 = OpLabel
1357                OpReturn
1358                OpFunctionEnd
1359   )";
1360 
1361   CompileSuccessfully(spirv);
1362   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
1363   EXPECT_THAT(
1364       getDiagnosticString(),
1365       HasSubstr("must be explicitly laid out with MatrixStride decorations"));
1366 }
1367 
TEST_F(ValidateDecorations,BlockNestedStructMissingMatrixStrideBad)1368 TEST_F(ValidateDecorations, BlockNestedStructMissingMatrixStrideBad) {
1369   std::string spirv = R"(
1370                OpCapability Shader
1371           %1 = OpExtInstImport "GLSL.std.450"
1372                OpMemoryModel Logical GLSL450
1373                OpEntryPoint GLCompute %main "main"
1374                OpExecutionMode %main LocalSize 1 1 1
1375                OpSource GLSL 430
1376                OpMemberDecorate %S 0 Offset 0
1377                OpMemberDecorate %Output 0 Offset 0
1378                OpMemberDecorate %Output 1 Offset 16
1379                OpMemberDecorate %Output 2 Offset 32
1380                OpDecorate %Output Block
1381        %void = OpTypeVoid
1382           %3 = OpTypeFunction %void
1383       %float = OpTypeFloat 32
1384     %v3float = OpTypeVector %float 3
1385     %v4float = OpTypeVector %float 4
1386      %matrix = OpTypeMatrix %v3float 4
1387           %S = OpTypeStruct %matrix
1388      %Output = OpTypeStruct %float %v4float %S
1389 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
1390  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
1391        %main = OpFunction %void None %3
1392           %5 = OpLabel
1393                OpReturn
1394                OpFunctionEnd
1395   )";
1396 
1397   CompileSuccessfully(spirv);
1398   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
1399   EXPECT_THAT(
1400       getDiagnosticString(),
1401       HasSubstr("must be explicitly laid out with MatrixStride decorations"));
1402 }
1403 
TEST_F(ValidateDecorations,BufferBlockNestedStructMissingMatrixStrideBad)1404 TEST_F(ValidateDecorations, BufferBlockNestedStructMissingMatrixStrideBad) {
1405   std::string spirv = R"(
1406                OpCapability Shader
1407           %1 = OpExtInstImport "GLSL.std.450"
1408                OpMemoryModel Logical GLSL450
1409                OpEntryPoint GLCompute %main "main"
1410                OpExecutionMode %main LocalSize 1 1 1
1411                OpSource GLSL 430
1412                OpMemberDecorate %S 0 Offset 0
1413                OpMemberDecorate %Output 0 Offset 0
1414                OpMemberDecorate %Output 1 Offset 16
1415                OpMemberDecorate %Output 2 Offset 32
1416                OpDecorate %Output BufferBlock
1417        %void = OpTypeVoid
1418           %3 = OpTypeFunction %void
1419       %float = OpTypeFloat 32
1420     %v3float = OpTypeVector %float 3
1421     %v4float = OpTypeVector %float 4
1422      %matrix = OpTypeMatrix %v3float 4
1423           %S = OpTypeStruct %matrix
1424      %Output = OpTypeStruct %float %v4float %S
1425 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
1426  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
1427        %main = OpFunction %void None %3
1428           %5 = OpLabel
1429                OpReturn
1430                OpFunctionEnd
1431   )";
1432 
1433   CompileSuccessfully(spirv);
1434   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
1435   EXPECT_THAT(
1436       getDiagnosticString(),
1437       HasSubstr("must be explicitly laid out with MatrixStride decorations"));
1438 }
1439 
TEST_F(ValidateDecorations,BlockStandardUniformBufferLayout)1440 TEST_F(ValidateDecorations, BlockStandardUniformBufferLayout) {
1441   std::string spirv = R"(
1442                OpCapability Shader
1443           %1 = OpExtInstImport "GLSL.std.450"
1444                OpMemoryModel Logical GLSL450
1445                OpEntryPoint GLCompute %main "main"
1446                OpExecutionMode %main LocalSize 1 1 1
1447                OpSource GLSL 430
1448                OpMemberDecorate %F 0 Offset 0
1449                OpMemberDecorate %F 1 Offset 8
1450                OpDecorate %_arr_float_uint_2 ArrayStride 16
1451                OpDecorate %_arr_mat3v3float_uint_2 ArrayStride 48
1452                OpMemberDecorate %O 0 Offset 0
1453                OpMemberDecorate %O 1 Offset 16
1454                OpMemberDecorate %O 2 Offset 32
1455                OpMemberDecorate %O 3 Offset 64
1456                OpMemberDecorate %O 4 ColMajor
1457                OpMemberDecorate %O 4 Offset 80
1458                OpMemberDecorate %O 4 MatrixStride 16
1459                OpDecorate %_arr_O_uint_2 ArrayStride 176
1460                OpMemberDecorate %Output 0 Offset 0
1461                OpMemberDecorate %Output 1 Offset 8
1462                OpMemberDecorate %Output 2 Offset 16
1463                OpMemberDecorate %Output 3 Offset 32
1464                OpMemberDecorate %Output 4 Offset 48
1465                OpMemberDecorate %Output 5 Offset 64
1466                OpMemberDecorate %Output 6 ColMajor
1467                OpMemberDecorate %Output 6 Offset 96
1468                OpMemberDecorate %Output 6 MatrixStride 16
1469                OpMemberDecorate %Output 7 Offset 128
1470                OpDecorate %Output Block
1471        %void = OpTypeVoid
1472           %3 = OpTypeFunction %void
1473       %float = OpTypeFloat 32
1474     %v2float = OpTypeVector %float 2
1475     %v3float = OpTypeVector %float 3
1476         %int = OpTypeInt 32 1
1477        %uint = OpTypeInt 32 0
1478      %v2uint = OpTypeVector %uint 2
1479           %F = OpTypeStruct %int %v2uint
1480      %uint_2 = OpConstant %uint 2
1481 %_arr_float_uint_2 = OpTypeArray %float %uint_2
1482 %mat2v3float = OpTypeMatrix %v3float 2
1483      %v3uint = OpTypeVector %uint 3
1484 %mat3v3float = OpTypeMatrix %v3float 3
1485 %_arr_mat3v3float_uint_2 = OpTypeArray %mat3v3float %uint_2
1486           %O = OpTypeStruct %v3uint %v2float %_arr_float_uint_2 %v2float %_arr_mat3v3float_uint_2
1487 %_arr_O_uint_2 = OpTypeArray %O %uint_2
1488      %Output = OpTypeStruct %float %v2float %v3float %F %float %_arr_float_uint_2 %mat2v3float %_arr_O_uint_2
1489 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
1490  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
1491        %main = OpFunction %void None %3
1492           %5 = OpLabel
1493                OpReturn
1494                OpFunctionEnd
1495   )";
1496 
1497   CompileSuccessfully(spirv);
1498   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
1499 }
1500 
TEST_F(ValidateDecorations,BlockLayoutPermitsTightVec3ScalarPackingGood)1501 TEST_F(ValidateDecorations, BlockLayoutPermitsTightVec3ScalarPackingGood) {
1502   // See https://github.com/KhronosGroup/SPIRV-Tools/issues/1666
1503   std::string spirv = R"(
1504                OpCapability Shader
1505                OpMemoryModel Logical GLSL450
1506                OpEntryPoint Vertex %main "main"
1507                OpSource GLSL 450
1508                OpMemberDecorate %S 0 Offset 0
1509                OpMemberDecorate %S 1 Offset 12
1510                OpDecorate %S Block
1511                OpDecorate %B DescriptorSet 0
1512                OpDecorate %B Binding 0
1513        %void = OpTypeVoid
1514           %3 = OpTypeFunction %void
1515       %float = OpTypeFloat 32
1516     %v3float = OpTypeVector %float 3
1517           %S = OpTypeStruct %v3float %float
1518 %_ptr_Uniform_S = OpTypePointer Uniform %S
1519           %B = OpVariable %_ptr_Uniform_S Uniform
1520        %main = OpFunction %void None %3
1521           %5 = OpLabel
1522                OpReturn
1523                OpFunctionEnd
1524   )";
1525 
1526   CompileSuccessfully(spirv);
1527   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
1528       << getDiagnosticString();
1529 }
1530 
TEST_F(ValidateDecorations,BlockCantAppearWithinABlockBad)1531 TEST_F(ValidateDecorations, BlockCantAppearWithinABlockBad) {
1532   // See https://github.com/KhronosGroup/SPIRV-Tools/issues/1587
1533   std::string spirv = R"(
1534                OpCapability Shader
1535                OpMemoryModel Logical GLSL450
1536                OpEntryPoint Vertex %main "main"
1537                OpSource GLSL 450
1538                OpMemberDecorate %S 0 Offset 0
1539                OpMemberDecorate %S 1 Offset 16
1540                OpMemberDecorate %S2 0 Offset 0
1541                OpMemberDecorate %S2 1 Offset 12
1542                OpDecorate %S Block
1543                OpDecorate %S2 Block
1544                OpDecorate %B DescriptorSet 0
1545                OpDecorate %B Binding 0
1546        %void = OpTypeVoid
1547           %3 = OpTypeFunction %void
1548       %float = OpTypeFloat 32
1549          %S2 = OpTypeStruct %float %float
1550           %S = OpTypeStruct %float %S2
1551 %_ptr_Uniform_S = OpTypePointer Uniform %S
1552           %B = OpVariable %_ptr_Uniform_S Uniform
1553        %main = OpFunction %void None %3
1554           %5 = OpLabel
1555                OpReturn
1556                OpFunctionEnd
1557   )";
1558 
1559   CompileSuccessfully(spirv);
1560   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
1561   EXPECT_THAT(getDiagnosticString(),
1562               HasSubstr("rules: A Block or BufferBlock cannot be nested within "
1563                         "another Block or BufferBlock."));
1564 }
1565 
TEST_F(ValidateDecorations,BufferblockCantAppearWithinABufferblockBad)1566 TEST_F(ValidateDecorations, BufferblockCantAppearWithinABufferblockBad) {
1567   // See https://github.com/KhronosGroup/SPIRV-Tools/issues/1587
1568   std::string spirv = R"(
1569                OpCapability Shader
1570                OpMemoryModel Logical GLSL450
1571                OpEntryPoint Vertex %main "main"
1572                OpSource GLSL 450
1573                OpMemberDecorate %S 0 Offset 0
1574                OpMemberDecorate %S 1 Offset 16
1575               OpMemberDecorate %S2 0 Offset 0
1576                OpMemberDecorate %S2 1 Offset 16
1577                OpMemberDecorate %S3 0 Offset 0
1578                OpMemberDecorate %S3 1 Offset 12
1579                OpDecorate %S BufferBlock
1580                OpDecorate %S3 BufferBlock
1581                OpDecorate %B DescriptorSet 0
1582                OpDecorate %B Binding 0
1583        %void = OpTypeVoid
1584           %3 = OpTypeFunction %void
1585       %float = OpTypeFloat 32
1586          %S3 = OpTypeStruct %float %float
1587          %S2 = OpTypeStruct %float %S3
1588           %S = OpTypeStruct %float %S2
1589 %_ptr_Uniform_S = OpTypePointer Uniform %S
1590           %B = OpVariable %_ptr_Uniform_S Uniform
1591        %main = OpFunction %void None %3
1592           %5 = OpLabel
1593                OpReturn
1594                OpFunctionEnd
1595   )";
1596 
1597   CompileSuccessfully(spirv);
1598   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
1599   EXPECT_THAT(getDiagnosticString(),
1600               HasSubstr("rules: A Block or BufferBlock cannot be nested within "
1601                         "another Block or BufferBlock."));
1602 }
1603 
TEST_F(ValidateDecorations,BufferblockCantAppearWithinABlockBad)1604 TEST_F(ValidateDecorations, BufferblockCantAppearWithinABlockBad) {
1605   // See https://github.com/KhronosGroup/SPIRV-Tools/issues/1587
1606   std::string spirv = R"(
1607                OpCapability Shader
1608                OpMemoryModel Logical GLSL450
1609                OpEntryPoint Vertex %main "main"
1610                OpSource GLSL 450
1611                OpMemberDecorate %S 0 Offset 0
1612                OpMemberDecorate %S 1 Offset 16
1613               OpMemberDecorate %S2 0 Offset 0
1614                OpMemberDecorate %S2 1 Offset 16
1615                OpMemberDecorate %S3 0 Offset 0
1616                OpMemberDecorate %S3 1 Offset 12
1617                OpDecorate %S Block
1618                OpDecorate %S3 BufferBlock
1619                OpDecorate %B DescriptorSet 0
1620                OpDecorate %B Binding 0
1621        %void = OpTypeVoid
1622           %3 = OpTypeFunction %void
1623       %float = OpTypeFloat 32
1624          %S3 = OpTypeStruct %float %float
1625          %S2 = OpTypeStruct %float %S3
1626           %S = OpTypeStruct %float %S2
1627 %_ptr_Uniform_S = OpTypePointer Uniform %S
1628           %B = OpVariable %_ptr_Uniform_S Uniform
1629        %main = OpFunction %void None %3
1630           %5 = OpLabel
1631                OpReturn
1632                OpFunctionEnd
1633   )";
1634 
1635   CompileSuccessfully(spirv);
1636   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
1637   EXPECT_THAT(getDiagnosticString(),
1638               HasSubstr("rules: A Block or BufferBlock cannot be nested within "
1639                         "another Block or BufferBlock."));
1640 }
1641 
TEST_F(ValidateDecorations,BlockCantAppearWithinABufferblockBad)1642 TEST_F(ValidateDecorations, BlockCantAppearWithinABufferblockBad) {
1643   // See https://github.com/KhronosGroup/SPIRV-Tools/issues/1587
1644   std::string spirv = R"(
1645                OpCapability Shader
1646                OpMemoryModel Logical GLSL450
1647                OpEntryPoint Vertex %main "main"
1648                OpSource GLSL 450
1649                OpMemberDecorate %S 0 Offset 0
1650                OpMemberDecorate %S 1 Offset 16
1651               OpMemberDecorate %S2 0 Offset 0
1652                OpMemberDecorate %S2 1 Offset 16
1653               OpMemberDecorate %S3 0 Offset 0
1654                OpMemberDecorate %S3 1 Offset 16
1655                OpMemberDecorate %S4 0 Offset 0
1656                OpMemberDecorate %S4 1 Offset 12
1657                OpDecorate %S BufferBlock
1658                OpDecorate %S4 Block
1659                OpDecorate %B DescriptorSet 0
1660                OpDecorate %B Binding 0
1661        %void = OpTypeVoid
1662           %3 = OpTypeFunction %void
1663       %float = OpTypeFloat 32
1664          %S4 = OpTypeStruct %float %float
1665          %S3 = OpTypeStruct %float %S4
1666          %S2 = OpTypeStruct %float %S3
1667           %S = OpTypeStruct %float %S2
1668 %_ptr_Uniform_S = OpTypePointer Uniform %S
1669           %B = OpVariable %_ptr_Uniform_S Uniform
1670        %main = OpFunction %void None %3
1671           %5 = OpLabel
1672                OpReturn
1673                OpFunctionEnd
1674   )";
1675 
1676   CompileSuccessfully(spirv);
1677   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
1678   EXPECT_THAT(getDiagnosticString(),
1679               HasSubstr("rules: A Block or BufferBlock cannot be nested within "
1680                         "another Block or BufferBlock."));
1681 }
1682 
TEST_F(ValidateDecorations,BlockLayoutForbidsTightScalarVec3PackingBad)1683 TEST_F(ValidateDecorations, BlockLayoutForbidsTightScalarVec3PackingBad) {
1684   // See https://github.com/KhronosGroup/SPIRV-Tools/issues/1666
1685   std::string spirv = R"(
1686                OpCapability Shader
1687                OpMemoryModel Logical GLSL450
1688                OpEntryPoint Vertex %main "main"
1689                OpSource GLSL 450
1690                OpMemberDecorate %S 0 Offset 0
1691                OpMemberDecorate %S 1 Offset 4
1692                OpDecorate %S Block
1693                OpDecorate %B DescriptorSet 0
1694                OpDecorate %B Binding 0
1695        %void = OpTypeVoid
1696           %3 = OpTypeFunction %void
1697       %float = OpTypeFloat 32
1698     %v3float = OpTypeVector %float 3
1699           %S = OpTypeStruct %float %v3float
1700 %_ptr_Uniform_S = OpTypePointer Uniform %S
1701           %B = OpVariable %_ptr_Uniform_S Uniform
1702        %main = OpFunction %void None %3
1703           %5 = OpLabel
1704                OpReturn
1705                OpFunctionEnd
1706   )";
1707 
1708   CompileSuccessfully(spirv);
1709   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
1710   EXPECT_THAT(
1711       getDiagnosticString(),
1712       HasSubstr("Structure id 2 decorated as Block for variable in Uniform "
1713                 "storage class must follow standard uniform buffer layout "
1714                 "rules: member 1 at offset 4 is not aligned to 16"));
1715 }
1716 
TEST_F(ValidateDecorations,BlockLayoutPermitsTightScalarVec3PackingWithRelaxedLayoutGood)1717 TEST_F(ValidateDecorations,
1718        BlockLayoutPermitsTightScalarVec3PackingWithRelaxedLayoutGood) {
1719   // Same as previous test, but with explicit option to relax block layout.
1720   std::string spirv = R"(
1721                OpCapability Shader
1722                OpMemoryModel Logical GLSL450
1723                OpEntryPoint Vertex %main "main"
1724                OpSource GLSL 450
1725                OpMemberDecorate %S 0 Offset 0
1726                OpMemberDecorate %S 1 Offset 4
1727                OpDecorate %S Block
1728                OpDecorate %B DescriptorSet 0
1729                OpDecorate %B Binding 0
1730        %void = OpTypeVoid
1731           %3 = OpTypeFunction %void
1732       %float = OpTypeFloat 32
1733     %v3float = OpTypeVector %float 3
1734           %S = OpTypeStruct %float %v3float
1735 %_ptr_Uniform_S = OpTypePointer Uniform %S
1736           %B = OpVariable %_ptr_Uniform_S Uniform
1737        %main = OpFunction %void None %3
1738           %5 = OpLabel
1739                OpReturn
1740                OpFunctionEnd
1741   )";
1742 
1743   CompileSuccessfully(spirv);
1744   spvValidatorOptionsSetRelaxBlockLayout(getValidatorOptions(), true);
1745   EXPECT_EQ(SPV_SUCCESS,
1746             ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
1747   EXPECT_THAT(getDiagnosticString(), Eq(""));
1748 }
1749 
TEST_F(ValidateDecorations,BlockLayoutPermitsTightScalarVec3PackingBadOffsetWithRelaxedLayoutBad)1750 TEST_F(ValidateDecorations,
1751        BlockLayoutPermitsTightScalarVec3PackingBadOffsetWithRelaxedLayoutBad) {
1752   // Same as previous test, but with the vector not aligned to its scalar
1753   // element. Use offset 5 instead of a multiple of 4.
1754   std::string spirv = R"(
1755                OpCapability Shader
1756                OpMemoryModel Logical GLSL450
1757                OpEntryPoint Vertex %main "main"
1758                OpSource GLSL 450
1759                OpMemberDecorate %S 0 Offset 0
1760                OpMemberDecorate %S 1 Offset 5
1761                OpDecorate %S Block
1762                OpDecorate %B DescriptorSet 0
1763                OpDecorate %B Binding 0
1764        %void = OpTypeVoid
1765           %3 = OpTypeFunction %void
1766       %float = OpTypeFloat 32
1767     %v3float = OpTypeVector %float 3
1768           %S = OpTypeStruct %float %v3float
1769 %_ptr_Uniform_S = OpTypePointer Uniform %S
1770           %B = OpVariable %_ptr_Uniform_S Uniform
1771        %main = OpFunction %void None %3
1772           %5 = OpLabel
1773                OpReturn
1774                OpFunctionEnd
1775   )";
1776 
1777   CompileSuccessfully(spirv);
1778   spvValidatorOptionsSetRelaxBlockLayout(getValidatorOptions(), true);
1779   EXPECT_EQ(SPV_ERROR_INVALID_ID,
1780             ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
1781   EXPECT_THAT(
1782       getDiagnosticString(),
1783       HasSubstr(
1784           "Structure id 2 decorated as Block for variable in Uniform storage "
1785           "class must follow relaxed uniform buffer layout rules: member 1 at "
1786           "offset 5 is not aligned to scalar element size 4"));
1787 }
1788 
TEST_F(ValidateDecorations,BlockLayoutPermitsTightScalarVec3PackingWithVulkan1_1Good)1789 TEST_F(ValidateDecorations,
1790        BlockLayoutPermitsTightScalarVec3PackingWithVulkan1_1Good) {
1791   // Same as previous test, but with Vulkan 1.1.  Vulkan 1.1 included
1792   // VK_KHR_relaxed_block_layout in core.
1793   std::string spirv = R"(
1794                OpCapability Shader
1795                OpMemoryModel Logical GLSL450
1796                OpEntryPoint Vertex %main "main"
1797                OpSource GLSL 450
1798                OpMemberDecorate %S 0 Offset 0
1799                OpMemberDecorate %S 1 Offset 4
1800                OpDecorate %S Block
1801                OpDecorate %B DescriptorSet 0
1802                OpDecorate %B Binding 0
1803        %void = OpTypeVoid
1804           %3 = OpTypeFunction %void
1805       %float = OpTypeFloat 32
1806     %v3float = OpTypeVector %float 3
1807           %S = OpTypeStruct %float %v3float
1808 %_ptr_Uniform_S = OpTypePointer Uniform %S
1809           %B = OpVariable %_ptr_Uniform_S Uniform
1810        %main = OpFunction %void None %3
1811           %5 = OpLabel
1812                OpReturn
1813                OpFunctionEnd
1814   )";
1815 
1816   CompileSuccessfully(spirv);
1817   EXPECT_EQ(SPV_SUCCESS,
1818             ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
1819   EXPECT_THAT(getDiagnosticString(), Eq(""));
1820 }
1821 
TEST_F(ValidateDecorations,BlockLayoutPermitsTightScalarVec3PackingWithScalarLayoutGood)1822 TEST_F(ValidateDecorations,
1823        BlockLayoutPermitsTightScalarVec3PackingWithScalarLayoutGood) {
1824   // Same as previous test, but with scalar block layout.
1825   std::string spirv = R"(
1826                OpCapability Shader
1827                OpMemoryModel Logical GLSL450
1828                OpEntryPoint Vertex %main "main"
1829                OpSource GLSL 450
1830                OpMemberDecorate %S 0 Offset 0
1831                OpMemberDecorate %S 1 Offset 4
1832                OpDecorate %S Block
1833                OpDecorate %B DescriptorSet 0
1834                OpDecorate %B Binding 0
1835        %void = OpTypeVoid
1836           %3 = OpTypeFunction %void
1837       %float = OpTypeFloat 32
1838     %v3float = OpTypeVector %float 3
1839           %S = OpTypeStruct %float %v3float
1840 %_ptr_Uniform_S = OpTypePointer Uniform %S
1841           %B = OpVariable %_ptr_Uniform_S Uniform
1842        %main = OpFunction %void None %3
1843           %5 = OpLabel
1844                OpReturn
1845                OpFunctionEnd
1846   )";
1847 
1848   CompileSuccessfully(spirv);
1849   spvValidatorOptionsSetScalarBlockLayout(getValidatorOptions(), true);
1850   EXPECT_EQ(SPV_SUCCESS,
1851             ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
1852   EXPECT_THAT(getDiagnosticString(), Eq(""));
1853 }
1854 
TEST_F(ValidateDecorations,BlockLayoutPermitsScalarAlignedArrayWithScalarLayoutGood)1855 TEST_F(ValidateDecorations,
1856        BlockLayoutPermitsScalarAlignedArrayWithScalarLayoutGood) {
1857   // The array at offset 4 is ok with scalar block layout.
1858   std::string spirv = R"(
1859                OpCapability Shader
1860                OpMemoryModel Logical GLSL450
1861                OpEntryPoint Vertex %main "main"
1862                OpSource GLSL 450
1863                OpMemberDecorate %S 0 Offset 0
1864                OpMemberDecorate %S 1 Offset 4
1865                OpDecorate %S Block
1866                OpDecorate %B DescriptorSet 0
1867                OpDecorate %B Binding 0
1868                OpDecorate %arr_float ArrayStride 4
1869        %void = OpTypeVoid
1870           %3 = OpTypeFunction %void
1871        %uint = OpTypeInt 32 0
1872      %uint_3 = OpConstant %uint 3
1873       %float = OpTypeFloat 32
1874   %arr_float = OpTypeArray %float %uint_3
1875           %S = OpTypeStruct %float %arr_float
1876 %_ptr_Uniform_S = OpTypePointer Uniform %S
1877           %B = OpVariable %_ptr_Uniform_S Uniform
1878        %main = OpFunction %void None %3
1879           %5 = OpLabel
1880                OpReturn
1881                OpFunctionEnd
1882   )";
1883 
1884   CompileSuccessfully(spirv);
1885   spvValidatorOptionsSetScalarBlockLayout(getValidatorOptions(), true);
1886   EXPECT_EQ(SPV_SUCCESS,
1887             ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
1888   EXPECT_THAT(getDiagnosticString(), Eq(""));
1889 }
1890 
TEST_F(ValidateDecorations,BlockLayoutPermitsScalarAlignedArrayOfVec3WithScalarLayoutGood)1891 TEST_F(ValidateDecorations,
1892        BlockLayoutPermitsScalarAlignedArrayOfVec3WithScalarLayoutGood) {
1893   // The array at offset 4 is ok with scalar block layout, even though
1894   // its elements are vec3.
1895   // This is the same as the previous case, but the array elements are vec3
1896   // instead of float.
1897   std::string spirv = R"(
1898                OpCapability Shader
1899                OpMemoryModel Logical GLSL450
1900                OpEntryPoint Vertex %main "main"
1901                OpSource GLSL 450
1902                OpMemberDecorate %S 0 Offset 0
1903                OpMemberDecorate %S 1 Offset 4
1904                OpDecorate %S Block
1905                OpDecorate %B DescriptorSet 0
1906                OpDecorate %B Binding 0
1907                OpDecorate %arr_vec3 ArrayStride 12
1908        %void = OpTypeVoid
1909           %3 = OpTypeFunction %void
1910        %uint = OpTypeInt 32 0
1911      %uint_3 = OpConstant %uint 3
1912       %float = OpTypeFloat 32
1913        %vec3 = OpTypeVector %float 3
1914    %arr_vec3 = OpTypeArray %vec3 %uint_3
1915           %S = OpTypeStruct %float %arr_vec3
1916 %_ptr_Uniform_S = OpTypePointer Uniform %S
1917           %B = OpVariable %_ptr_Uniform_S Uniform
1918        %main = OpFunction %void None %3
1919           %5 = OpLabel
1920                OpReturn
1921                OpFunctionEnd
1922   )";
1923 
1924   CompileSuccessfully(spirv);
1925   spvValidatorOptionsSetScalarBlockLayout(getValidatorOptions(), true);
1926   EXPECT_EQ(SPV_SUCCESS,
1927             ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
1928   EXPECT_THAT(getDiagnosticString(), Eq(""));
1929 }
1930 
TEST_F(ValidateDecorations,BlockLayoutPermitsScalarAlignedStructWithScalarLayoutGood)1931 TEST_F(ValidateDecorations,
1932        BlockLayoutPermitsScalarAlignedStructWithScalarLayoutGood) {
1933   // Scalar block layout permits the struct at offset 4, even though
1934   // it contains a vector with base alignment 8 and scalar alignment 4.
1935   std::string spirv = R"(
1936                OpCapability Shader
1937                OpMemoryModel Logical GLSL450
1938                OpEntryPoint Vertex %main "main"
1939                OpSource GLSL 450
1940                OpMemberDecorate %S 0 Offset 0
1941                OpMemberDecorate %S 1 Offset 4
1942                OpMemberDecorate %st 0 Offset 0
1943                OpMemberDecorate %st 1 Offset 8
1944                OpDecorate %S Block
1945                OpDecorate %B DescriptorSet 0
1946                OpDecorate %B Binding 0
1947        %void = OpTypeVoid
1948           %3 = OpTypeFunction %void
1949       %float = OpTypeFloat 32
1950        %vec2 = OpTypeVector %float 2
1951         %st  = OpTypeStruct %vec2 %float
1952           %S = OpTypeStruct %float %st
1953 %_ptr_Uniform_S = OpTypePointer Uniform %S
1954           %B = OpVariable %_ptr_Uniform_S Uniform
1955        %main = OpFunction %void None %3
1956           %5 = OpLabel
1957                OpReturn
1958                OpFunctionEnd
1959   )";
1960 
1961   CompileSuccessfully(spirv);
1962   spvValidatorOptionsSetScalarBlockLayout(getValidatorOptions(), true);
1963   EXPECT_EQ(SPV_SUCCESS,
1964             ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
1965   EXPECT_THAT(getDiagnosticString(), Eq(""));
1966 }
1967 
TEST_F(ValidateDecorations,BlockLayoutPermitsFieldsInBaseAlignmentPaddingAtEndOfStructWithScalarLayoutGood)1968 TEST_F(
1969     ValidateDecorations,
1970     BlockLayoutPermitsFieldsInBaseAlignmentPaddingAtEndOfStructWithScalarLayoutGood) {
1971   // Scalar block layout permits fields in what would normally be the padding at
1972   // the end of a struct.
1973   std::string spirv = R"(
1974                OpCapability Shader
1975                OpCapability Float64
1976                OpMemoryModel Logical GLSL450
1977                OpEntryPoint Vertex %main "main"
1978                OpSource GLSL 450
1979                OpMemberDecorate %st 0 Offset 0
1980                OpMemberDecorate %st 1 Offset 8
1981                OpMemberDecorate %S 0 Offset 0
1982                OpMemberDecorate %S 1 Offset 12
1983                OpDecorate %S Block
1984                OpDecorate %B DescriptorSet 0
1985                OpDecorate %B Binding 0
1986        %void = OpTypeVoid
1987           %3 = OpTypeFunction %void
1988       %float = OpTypeFloat 32
1989      %double = OpTypeFloat 64
1990          %st = OpTypeStruct %double %float
1991           %S = OpTypeStruct %st %float
1992 %_ptr_Uniform_S = OpTypePointer Uniform %S
1993           %B = OpVariable %_ptr_Uniform_S Uniform
1994        %main = OpFunction %void None %3
1995           %5 = OpLabel
1996                OpReturn
1997                OpFunctionEnd
1998   )";
1999 
2000   CompileSuccessfully(spirv);
2001   spvValidatorOptionsSetScalarBlockLayout(getValidatorOptions(), true);
2002   EXPECT_EQ(SPV_SUCCESS,
2003             ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
2004   EXPECT_THAT(getDiagnosticString(), Eq(""));
2005 }
2006 
TEST_F(ValidateDecorations,BlockLayoutPermitsStraddlingVectorWithScalarLayoutOverrideRelaxBlockLayoutGood)2007 TEST_F(
2008     ValidateDecorations,
2009     BlockLayoutPermitsStraddlingVectorWithScalarLayoutOverrideRelaxBlockLayoutGood) {
2010   // Same as previous, but set relaxed block layout first.  Scalar layout always
2011   // wins.
2012   std::string spirv = R"(
2013                OpCapability Shader
2014                OpMemoryModel Logical GLSL450
2015                OpEntryPoint Vertex %main "main"
2016                OpSource GLSL 450
2017                OpMemberDecorate %S 0 Offset 0
2018                OpMemberDecorate %S 1 Offset 4
2019                OpDecorate %S Block
2020                OpDecorate %B DescriptorSet 0
2021                OpDecorate %B Binding 0
2022        %void = OpTypeVoid
2023           %3 = OpTypeFunction %void
2024       %float = OpTypeFloat 32
2025        %vec4 = OpTypeVector %float 4
2026           %S = OpTypeStruct %float %vec4
2027 %_ptr_Uniform_S = OpTypePointer Uniform %S
2028           %B = OpVariable %_ptr_Uniform_S Uniform
2029        %main = OpFunction %void None %3
2030           %5 = OpLabel
2031                OpReturn
2032                OpFunctionEnd
2033   )";
2034 
2035   CompileSuccessfully(spirv);
2036   spvValidatorOptionsSetRelaxBlockLayout(getValidatorOptions(), true);
2037   spvValidatorOptionsSetScalarBlockLayout(getValidatorOptions(), true);
2038   EXPECT_EQ(SPV_SUCCESS,
2039             ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
2040   EXPECT_THAT(getDiagnosticString(), Eq(""));
2041 }
2042 
TEST_F(ValidateDecorations,BlockLayoutPermitsStraddlingVectorWithRelaxedLayoutOverridenByScalarBlockLayoutGood)2043 TEST_F(
2044     ValidateDecorations,
2045     BlockLayoutPermitsStraddlingVectorWithRelaxedLayoutOverridenByScalarBlockLayoutGood) {
2046   // Same as previous, but set scalar block layout first.  Scalar layout always
2047   // wins.
2048   std::string spirv = R"(
2049                OpCapability Shader
2050                OpMemoryModel Logical GLSL450
2051                OpEntryPoint Vertex %main "main"
2052                OpSource GLSL 450
2053                OpMemberDecorate %S 0 Offset 0
2054                OpMemberDecorate %S 1 Offset 4
2055                OpDecorate %S Block
2056                OpDecorate %B DescriptorSet 0
2057                OpDecorate %B Binding 0
2058        %void = OpTypeVoid
2059           %3 = OpTypeFunction %void
2060       %float = OpTypeFloat 32
2061        %vec4 = OpTypeVector %float 4
2062           %S = OpTypeStruct %float %vec4
2063 %_ptr_Uniform_S = OpTypePointer Uniform %S
2064           %B = OpVariable %_ptr_Uniform_S Uniform
2065        %main = OpFunction %void None %3
2066           %5 = OpLabel
2067                OpReturn
2068                OpFunctionEnd
2069   )";
2070 
2071   CompileSuccessfully(spirv);
2072   spvValidatorOptionsSetScalarBlockLayout(getValidatorOptions(), true);
2073   spvValidatorOptionsSetRelaxBlockLayout(getValidatorOptions(), true);
2074   EXPECT_EQ(SPV_SUCCESS,
2075             ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
2076   EXPECT_THAT(getDiagnosticString(), Eq(""));
2077 }
2078 
TEST_F(ValidateDecorations,BufferBlock16bitStandardStorageBufferLayout)2079 TEST_F(ValidateDecorations, BufferBlock16bitStandardStorageBufferLayout) {
2080   std::string spirv = R"(
2081              OpCapability Shader
2082              OpCapability StorageUniform16
2083              OpExtension "SPV_KHR_16bit_storage"
2084              OpMemoryModel Logical GLSL450
2085              OpEntryPoint GLCompute %main "main"
2086              OpExecutionMode %main LocalSize 1 1 1
2087              OpDecorate %f32arr ArrayStride 4
2088              OpDecorate %f16arr ArrayStride 2
2089              OpMemberDecorate %SSBO32 0 Offset 0
2090              OpMemberDecorate %SSBO16 0 Offset 0
2091              OpDecorate %SSBO32 BufferBlock
2092              OpDecorate %SSBO16 BufferBlock
2093      %void = OpTypeVoid
2094     %voidf = OpTypeFunction %void
2095       %u32 = OpTypeInt 32 0
2096       %i32 = OpTypeInt 32 1
2097       %f32 = OpTypeFloat 32
2098     %uvec3 = OpTypeVector %u32 3
2099  %c_i32_32 = OpConstant %i32 32
2100 %c_i32_128 = OpConstant %i32 128
2101    %f32arr = OpTypeArray %f32 %c_i32_128
2102       %f16 = OpTypeFloat 16
2103    %f16arr = OpTypeArray %f16 %c_i32_128
2104    %SSBO32 = OpTypeStruct %f32arr
2105    %SSBO16 = OpTypeStruct %f16arr
2106 %_ptr_Uniform_SSBO32 = OpTypePointer Uniform %SSBO32
2107  %varSSBO32 = OpVariable %_ptr_Uniform_SSBO32 Uniform
2108 %_ptr_Uniform_SSBO16 = OpTypePointer Uniform %SSBO16
2109  %varSSBO16 = OpVariable %_ptr_Uniform_SSBO16 Uniform
2110      %main = OpFunction %void None %voidf
2111     %label = OpLabel
2112              OpReturn
2113              OpFunctionEnd
2114   )";
2115 
2116   CompileSuccessfully(spirv);
2117   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
2118 }
2119 
TEST_F(ValidateDecorations,BlockArrayExtendedAlignmentGood)2120 TEST_F(ValidateDecorations, BlockArrayExtendedAlignmentGood) {
2121   // For uniform buffer, Array base alignment is 16, and ArrayStride
2122   // must be a multiple of 16.
2123   std::string spirv = R"(
2124                OpCapability Shader
2125                OpMemoryModel Logical GLSL450
2126                OpEntryPoint Vertex %main "main"
2127                OpSource GLSL 450
2128                OpDecorate %_arr_float_uint_2 ArrayStride 16
2129                OpMemberDecorate %S 0 Offset 0
2130                OpMemberDecorate %S 1 Offset 16
2131                OpDecorate %S Block
2132        %void = OpTypeVoid
2133           %3 = OpTypeFunction %void
2134       %float = OpTypeFloat 32
2135     %v2float = OpTypeVector %float 2
2136        %uint = OpTypeInt 32 0
2137      %uint_2 = OpConstant %uint 2
2138 %_arr_float_uint_2 = OpTypeArray %float %uint_2
2139           %S = OpTypeStruct %v2float %_arr_float_uint_2
2140 %_ptr_PushConstant_S = OpTypePointer PushConstant %S
2141           %u = OpVariable %_ptr_PushConstant_S PushConstant
2142        %main = OpFunction %void None %3
2143           %5 = OpLabel
2144                OpReturn
2145                OpFunctionEnd
2146   )";
2147 
2148   CompileSuccessfully(spirv);
2149   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
2150       << getDiagnosticString();
2151 }
2152 
TEST_F(ValidateDecorations,BlockArrayBaseAlignmentBad)2153 TEST_F(ValidateDecorations, BlockArrayBaseAlignmentBad) {
2154   // For uniform buffer, Array base alignment is 16.
2155   std::string spirv = R"(
2156                OpCapability Shader
2157                OpMemoryModel Logical GLSL450
2158                OpEntryPoint Vertex %main "main"
2159                OpSource GLSL 450
2160                OpDecorate %_arr_float_uint_2 ArrayStride 16
2161                OpMemberDecorate %S 0 Offset 0
2162                OpMemberDecorate %S 1 Offset 8
2163                OpDecorate %S Block
2164        %void = OpTypeVoid
2165           %3 = OpTypeFunction %void
2166       %float = OpTypeFloat 32
2167     %v2float = OpTypeVector %float 2
2168        %uint = OpTypeInt 32 0
2169      %uint_2 = OpConstant %uint 2
2170 %_arr_float_uint_2 = OpTypeArray %float %uint_2
2171           %S = OpTypeStruct %v2float %_arr_float_uint_2
2172 %_ptr_Uniform_S = OpTypePointer Uniform %S
2173           %u = OpVariable %_ptr_Uniform_S Uniform
2174        %main = OpFunction %void None %3
2175           %5 = OpLabel
2176                OpReturn
2177                OpFunctionEnd
2178   )";
2179 
2180   CompileSuccessfully(spirv);
2181   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
2182   EXPECT_THAT(
2183       getDiagnosticString(),
2184       HasSubstr(
2185           "Structure id 3 decorated as Block for variable in Uniform "
2186           "storage class must follow standard uniform buffer layout rules: "
2187           "member 1 at offset 8 is not aligned to 16"));
2188 }
2189 
TEST_F(ValidateDecorations,BlockArrayBaseAlignmentWithRelaxedLayoutStillBad)2190 TEST_F(ValidateDecorations, BlockArrayBaseAlignmentWithRelaxedLayoutStillBad) {
2191   // For uniform buffer, Array base alignment is 16, and ArrayStride
2192   // must be a multiple of 16.  This case uses relaxed block layout.  Relaxed
2193   // layout only relaxes rules for vector alignment, not array alignment.
2194   std::string spirv = R"(
2195                OpCapability Shader
2196                OpMemoryModel Logical GLSL450
2197                OpEntryPoint Vertex %main "main"
2198                OpSource GLSL 450
2199                OpDecorate %_arr_float_uint_2 ArrayStride 16
2200                OpDecorate %u DescriptorSet 0
2201                OpDecorate %u Binding 0
2202                OpMemberDecorate %S 0 Offset 0
2203                OpMemberDecorate %S 1 Offset 8
2204                OpDecorate %S Block
2205        %void = OpTypeVoid
2206           %3 = OpTypeFunction %void
2207       %float = OpTypeFloat 32
2208     %v2float = OpTypeVector %float 2
2209        %uint = OpTypeInt 32 0
2210      %uint_2 = OpConstant %uint 2
2211 %_arr_float_uint_2 = OpTypeArray %float %uint_2
2212           %S = OpTypeStruct %v2float %_arr_float_uint_2
2213 %_ptr_Uniform_S = OpTypePointer Uniform %S
2214           %u = OpVariable %_ptr_Uniform_S Uniform
2215        %main = OpFunction %void None %3
2216           %5 = OpLabel
2217                OpReturn
2218                OpFunctionEnd
2219   )";
2220 
2221   CompileSuccessfully(spirv);
2222   EXPECT_EQ(SPV_ERROR_INVALID_ID,
2223             ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
2224   spvValidatorOptionsSetRelaxBlockLayout(getValidatorOptions(), true);
2225   EXPECT_THAT(
2226       getDiagnosticString(),
2227       HasSubstr(
2228           "Structure id 4 decorated as Block for variable in Uniform "
2229           "storage class must follow standard uniform buffer layout rules: "
2230           "member 1 at offset 8 is not aligned to 16"));
2231 }
2232 
TEST_F(ValidateDecorations,BlockArrayBaseAlignmentWithVulkan1_1StillBad)2233 TEST_F(ValidateDecorations, BlockArrayBaseAlignmentWithVulkan1_1StillBad) {
2234   // Same as previous test, but with Vulkan 1.1, which includes
2235   // VK_KHR_relaxed_block_layout in core.
2236   std::string spirv = R"(
2237                OpCapability Shader
2238                OpMemoryModel Logical GLSL450
2239                OpEntryPoint Vertex %main "main"
2240                OpSource GLSL 450
2241                OpDecorate %_arr_float_uint_2 ArrayStride 16
2242                OpDecorate %u DescriptorSet 0
2243                OpDecorate %u Binding 0
2244                OpMemberDecorate %S 0 Offset 0
2245                OpMemberDecorate %S 1 Offset 8
2246                OpDecorate %S Block
2247        %void = OpTypeVoid
2248           %3 = OpTypeFunction %void
2249       %float = OpTypeFloat 32
2250     %v2float = OpTypeVector %float 2
2251        %uint = OpTypeInt 32 0
2252      %uint_2 = OpConstant %uint 2
2253 %_arr_float_uint_2 = OpTypeArray %float %uint_2
2254           %S = OpTypeStruct %v2float %_arr_float_uint_2
2255 %_ptr_Uniform_S = OpTypePointer Uniform %S
2256           %u = OpVariable %_ptr_Uniform_S Uniform
2257        %main = OpFunction %void None %3
2258           %5 = OpLabel
2259                OpReturn
2260                OpFunctionEnd
2261   )";
2262 
2263   CompileSuccessfully(spirv);
2264   EXPECT_EQ(SPV_ERROR_INVALID_ID,
2265             ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
2266   EXPECT_THAT(
2267       getDiagnosticString(),
2268       HasSubstr(
2269           "Structure id 4 decorated as Block for variable in Uniform "
2270           "storage class must follow relaxed uniform buffer layout rules: "
2271           "member 1 at offset 8 is not aligned to 16"));
2272 }
2273 
TEST_F(ValidateDecorations,BlockArrayBaseAlignmentWithBlockStandardLayoutGood)2274 TEST_F(ValidateDecorations,
2275        BlockArrayBaseAlignmentWithBlockStandardLayoutGood) {
2276   // Same as previous test, but with VK_KHR_uniform_buffer_standard_layout
2277   std::string spirv = R"(
2278                OpCapability Shader
2279                OpMemoryModel Logical GLSL450
2280                OpEntryPoint Vertex %main "main"
2281                OpSource GLSL 450
2282                OpDecorate %_arr_float_uint_2 ArrayStride 16
2283                OpDecorate %u DescriptorSet 0
2284                OpDecorate %u Binding 0
2285                OpMemberDecorate %S 0 Offset 0
2286                OpMemberDecorate %S 1 Offset 8
2287                OpDecorate %S Block
2288        %void = OpTypeVoid
2289           %3 = OpTypeFunction %void
2290       %float = OpTypeFloat 32
2291     %v2float = OpTypeVector %float 2
2292        %uint = OpTypeInt 32 0
2293      %uint_2 = OpConstant %uint 2
2294 %_arr_float_uint_2 = OpTypeArray %float %uint_2
2295           %S = OpTypeStruct %v2float %_arr_float_uint_2
2296 %_ptr_Uniform_S = OpTypePointer Uniform %S
2297           %u = OpVariable %_ptr_Uniform_S Uniform
2298        %main = OpFunction %void None %3
2299           %5 = OpLabel
2300                OpReturn
2301                OpFunctionEnd
2302   )";
2303 
2304   CompileSuccessfully(spirv);
2305   spvValidatorOptionsSetUniformBufferStandardLayout(getValidatorOptions(),
2306                                                     true);
2307   EXPECT_EQ(SPV_SUCCESS,
2308             ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
2309   EXPECT_THAT(getDiagnosticString(), Eq(""));
2310 }
2311 
TEST_F(ValidateDecorations,VulkanBufferBlockOnStorageBufferBad)2312 TEST_F(ValidateDecorations, VulkanBufferBlockOnStorageBufferBad) {
2313   std::string spirv = R"(
2314             OpCapability Shader
2315             OpExtension "SPV_KHR_storage_buffer_storage_class"
2316             OpMemoryModel Logical GLSL450
2317             OpEntryPoint Fragment %1 "main"
2318             OpExecutionMode %1 OriginUpperLeft
2319 
2320             OpDecorate %struct BufferBlock
2321 
2322     %void = OpTypeVoid
2323   %voidfn = OpTypeFunction %void
2324    %float = OpTypeFloat 32
2325   %struct = OpTypeStruct %float
2326      %ptr = OpTypePointer StorageBuffer %struct
2327      %var = OpVariable %ptr StorageBuffer
2328 
2329        %1 = OpFunction %void None %voidfn
2330    %label = OpLabel
2331             OpReturn
2332             OpFunctionEnd
2333 )";
2334 
2335   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
2336   EXPECT_EQ(SPV_ERROR_INVALID_ID,
2337             ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
2338   EXPECT_THAT(getDiagnosticString(),
2339               HasSubstr("In Vulkan, BufferBlock is disallowed on variables in "
2340                         "the StorageBuffer storage class"));
2341 }
2342 
TEST_F(ValidateDecorations,PushConstantArrayBaseAlignmentGood)2343 TEST_F(ValidateDecorations, PushConstantArrayBaseAlignmentGood) {
2344   // Tests https://github.com/KhronosGroup/SPIRV-Tools/issues/1664
2345   // From GLSL vertex shader:
2346   // #version 450
2347   // layout(push_constant) uniform S { vec2 v; float arr[2]; } u;
2348   // void main() { }
2349 
2350   std::string spirv = R"(
2351                OpCapability Shader
2352                OpMemoryModel Logical GLSL450
2353                OpEntryPoint Vertex %main "main"
2354                OpSource GLSL 450
2355                OpDecorate %_arr_float_uint_2 ArrayStride 4
2356                OpMemberDecorate %S 0 Offset 0
2357                OpMemberDecorate %S 1 Offset 8
2358                OpDecorate %S Block
2359        %void = OpTypeVoid
2360           %3 = OpTypeFunction %void
2361       %float = OpTypeFloat 32
2362     %v2float = OpTypeVector %float 2
2363        %uint = OpTypeInt 32 0
2364      %uint_2 = OpConstant %uint 2
2365 %_arr_float_uint_2 = OpTypeArray %float %uint_2
2366           %S = OpTypeStruct %v2float %_arr_float_uint_2
2367 %_ptr_PushConstant_S = OpTypePointer PushConstant %S
2368           %u = OpVariable %_ptr_PushConstant_S PushConstant
2369        %main = OpFunction %void None %3
2370           %5 = OpLabel
2371                OpReturn
2372                OpFunctionEnd
2373   )";
2374 
2375   CompileSuccessfully(spirv);
2376   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
2377       << getDiagnosticString();
2378 }
2379 
TEST_F(ValidateDecorations,PushConstantArrayBadAlignmentBad)2380 TEST_F(ValidateDecorations, PushConstantArrayBadAlignmentBad) {
2381   // Like the previous test, but with offset 7 instead of 8.
2382   std::string spirv = R"(
2383                OpCapability Shader
2384                OpMemoryModel Logical GLSL450
2385                OpEntryPoint Vertex %main "main"
2386                OpSource GLSL 450
2387                OpDecorate %_arr_float_uint_2 ArrayStride 4
2388                OpMemberDecorate %S 0 Offset 0
2389                OpMemberDecorate %S 1 Offset 7
2390                OpDecorate %S Block
2391        %void = OpTypeVoid
2392           %3 = OpTypeFunction %void
2393       %float = OpTypeFloat 32
2394     %v2float = OpTypeVector %float 2
2395        %uint = OpTypeInt 32 0
2396      %uint_2 = OpConstant %uint 2
2397 %_arr_float_uint_2 = OpTypeArray %float %uint_2
2398           %S = OpTypeStruct %v2float %_arr_float_uint_2
2399 %_ptr_PushConstant_S = OpTypePointer PushConstant %S
2400           %u = OpVariable %_ptr_PushConstant_S PushConstant
2401        %main = OpFunction %void None %3
2402           %5 = OpLabel
2403                OpReturn
2404                OpFunctionEnd
2405   )";
2406 
2407   CompileSuccessfully(spirv);
2408   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
2409   EXPECT_THAT(
2410       getDiagnosticString(),
2411       HasSubstr(
2412           "Structure id 3 decorated as Block for variable in PushConstant "
2413           "storage class must follow standard storage buffer layout rules: "
2414           "member 1 at offset 7 is not aligned to 4"));
2415 }
2416 
TEST_F(ValidateDecorations,PushConstantLayoutPermitsTightVec3ScalarPackingGood)2417 TEST_F(ValidateDecorations,
2418        PushConstantLayoutPermitsTightVec3ScalarPackingGood) {
2419   // See https://github.com/KhronosGroup/SPIRV-Tools/issues/1666
2420   std::string spirv = R"(
2421                OpCapability Shader
2422                OpMemoryModel Logical GLSL450
2423                OpEntryPoint Vertex %main "main"
2424                OpSource GLSL 450
2425                OpMemberDecorate %S 0 Offset 0
2426                OpMemberDecorate %S 1 Offset 12
2427                OpDecorate %S Block
2428        %void = OpTypeVoid
2429           %3 = OpTypeFunction %void
2430       %float = OpTypeFloat 32
2431     %v3float = OpTypeVector %float 3
2432           %S = OpTypeStruct %v3float %float
2433 %_ptr_PushConstant_S = OpTypePointer PushConstant %S
2434           %B = OpVariable %_ptr_PushConstant_S PushConstant
2435        %main = OpFunction %void None %3
2436           %5 = OpLabel
2437                OpReturn
2438                OpFunctionEnd
2439   )";
2440 
2441   CompileSuccessfully(spirv);
2442   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
2443       << getDiagnosticString();
2444 }
2445 
TEST_F(ValidateDecorations,PushConstantLayoutForbidsTightScalarVec3PackingBad)2446 TEST_F(ValidateDecorations,
2447        PushConstantLayoutForbidsTightScalarVec3PackingBad) {
2448   // See https://github.com/KhronosGroup/SPIRV-Tools/issues/1666
2449   std::string spirv = R"(
2450                OpCapability Shader
2451                OpMemoryModel Logical GLSL450
2452                OpEntryPoint Vertex %main "main"
2453                OpSource GLSL 450
2454                OpMemberDecorate %S 0 Offset 0
2455                OpMemberDecorate %S 1 Offset 4
2456                OpDecorate %S Block
2457        %void = OpTypeVoid
2458           %3 = OpTypeFunction %void
2459       %float = OpTypeFloat 32
2460     %v3float = OpTypeVector %float 3
2461           %S = OpTypeStruct %float %v3float
2462 %_ptr_Uniform_S = OpTypePointer PushConstant %S
2463           %B = OpVariable %_ptr_Uniform_S PushConstant
2464        %main = OpFunction %void None %3
2465           %5 = OpLabel
2466                OpReturn
2467                OpFunctionEnd
2468   )";
2469 
2470   CompileSuccessfully(spirv);
2471   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
2472   EXPECT_THAT(
2473       getDiagnosticString(),
2474       HasSubstr(
2475           "Structure id 2 decorated as Block for variable in PushConstant "
2476           "storage class must follow standard storage buffer layout "
2477           "rules: member 1 at offset 4 is not aligned to 16"));
2478 }
2479 
TEST_F(ValidateDecorations,PushConstantMissingBlockGood)2480 TEST_F(ValidateDecorations, PushConstantMissingBlockGood) {
2481   std::string spirv = R"(
2482             OpCapability Shader
2483             OpMemoryModel Logical GLSL450
2484             OpEntryPoint Fragment %1 "main"
2485             OpExecutionMode %1 OriginUpperLeft
2486 
2487             OpMemberDecorate %struct 0 Offset 0
2488 
2489     %void = OpTypeVoid
2490   %voidfn = OpTypeFunction %void
2491    %float = OpTypeFloat 32
2492   %struct = OpTypeStruct %float
2493      %ptr = OpTypePointer PushConstant %struct
2494       %pc = OpVariable %ptr PushConstant
2495 
2496        %1 = OpFunction %void None %voidfn
2497    %label = OpLabel
2498             OpReturn
2499             OpFunctionEnd
2500 )";
2501 
2502   CompileSuccessfully(spirv);
2503   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
2504       << getDiagnosticString();
2505 }
2506 
TEST_F(ValidateDecorations,VulkanPushConstantMissingBlockBad)2507 TEST_F(ValidateDecorations, VulkanPushConstantMissingBlockBad) {
2508   std::string spirv = R"(
2509             OpCapability Shader
2510             OpMemoryModel Logical GLSL450
2511             OpEntryPoint Fragment %1 "main"
2512             OpExecutionMode %1 OriginUpperLeft
2513 
2514             OpMemberDecorate %struct 0 Offset 0
2515 
2516     %void = OpTypeVoid
2517   %voidfn = OpTypeFunction %void
2518    %float = OpTypeFloat 32
2519   %struct = OpTypeStruct %float
2520      %ptr = OpTypePointer PushConstant %struct
2521       %pc = OpVariable %ptr PushConstant
2522 
2523        %1 = OpFunction %void None %voidfn
2524    %label = OpLabel
2525             OpReturn
2526             OpFunctionEnd
2527 )";
2528 
2529   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
2530   EXPECT_EQ(SPV_ERROR_INVALID_ID,
2531             ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
2532   EXPECT_THAT(getDiagnosticString(),
2533               HasSubstr("PushConstant id '2' is missing Block decoration.\n"
2534                         "From Vulkan spec, section 14.5.1:\n"
2535                         "Such variables must be identified with a Block "
2536                         "decoration"));
2537 }
2538 
TEST_F(ValidateDecorations,MultiplePushConstantsSingleEntryPointGood)2539 TEST_F(ValidateDecorations, MultiplePushConstantsSingleEntryPointGood) {
2540   std::string spirv = R"(
2541                 OpCapability Shader
2542                 OpMemoryModel Logical GLSL450
2543                 OpEntryPoint Fragment %1 "main"
2544                 OpExecutionMode %1 OriginUpperLeft
2545 
2546                 OpDecorate %struct Block
2547                 OpMemberDecorate %struct 0 Offset 0
2548 
2549         %void = OpTypeVoid
2550       %voidfn = OpTypeFunction %void
2551        %float = OpTypeFloat 32
2552          %int = OpTypeInt 32 0
2553        %int_0 = OpConstant %int 0
2554       %struct = OpTypeStruct %float
2555          %ptr = OpTypePointer PushConstant %struct
2556    %ptr_float = OpTypePointer PushConstant %float
2557          %pc1 = OpVariable %ptr PushConstant
2558          %pc2 = OpVariable %ptr PushConstant
2559 
2560            %1 = OpFunction %void None %voidfn
2561        %label = OpLabel
2562            %2 = OpAccessChain %ptr_float %pc1 %int_0
2563            %3 = OpLoad %float %2
2564            %4 = OpAccessChain %ptr_float %pc2 %int_0
2565            %5 = OpLoad %float %4
2566                 OpReturn
2567                 OpFunctionEnd
2568 )";
2569 
2570   CompileSuccessfully(spirv);
2571   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
2572       << getDiagnosticString();
2573 }
2574 
TEST_F(ValidateDecorations,VulkanMultiplePushConstantsDifferentEntryPointGood)2575 TEST_F(ValidateDecorations,
2576        VulkanMultiplePushConstantsDifferentEntryPointGood) {
2577   std::string spirv = R"(
2578                 OpCapability Shader
2579                 OpMemoryModel Logical GLSL450
2580                 OpEntryPoint Vertex %1 "func1"
2581                 OpEntryPoint Fragment %2 "func2"
2582                 OpExecutionMode %2 OriginUpperLeft
2583 
2584                 OpDecorate %struct Block
2585                 OpMemberDecorate %struct 0 Offset 0
2586 
2587         %void = OpTypeVoid
2588       %voidfn = OpTypeFunction %void
2589        %float = OpTypeFloat 32
2590          %int = OpTypeInt 32 0
2591        %int_0 = OpConstant %int 0
2592       %struct = OpTypeStruct %float
2593          %ptr = OpTypePointer PushConstant %struct
2594    %ptr_float = OpTypePointer PushConstant %float
2595          %pc1 = OpVariable %ptr PushConstant
2596          %pc2 = OpVariable %ptr PushConstant
2597 
2598            %1 = OpFunction %void None %voidfn
2599       %label1 = OpLabel
2600            %3 = OpAccessChain %ptr_float %pc1 %int_0
2601            %4 = OpLoad %float %3
2602                 OpReturn
2603                 OpFunctionEnd
2604 
2605            %2 = OpFunction %void None %voidfn
2606       %label2 = OpLabel
2607            %5 = OpAccessChain %ptr_float %pc2 %int_0
2608            %6 = OpLoad %float %5
2609                 OpReturn
2610                 OpFunctionEnd
2611 )";
2612 
2613   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
2614   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1))
2615       << getDiagnosticString();
2616 }
2617 
TEST_F(ValidateDecorations,VulkanMultiplePushConstantsUnusedSingleEntryPointGood)2618 TEST_F(ValidateDecorations,
2619        VulkanMultiplePushConstantsUnusedSingleEntryPointGood) {
2620   std::string spirv = R"(
2621                 OpCapability Shader
2622                 OpMemoryModel Logical GLSL450
2623                 OpEntryPoint Fragment %1 "main"
2624                 OpExecutionMode %1 OriginUpperLeft
2625 
2626                 OpDecorate %struct Block
2627                 OpMemberDecorate %struct 0 Offset 0
2628 
2629         %void = OpTypeVoid
2630       %voidfn = OpTypeFunction %void
2631        %float = OpTypeFloat 32
2632          %int = OpTypeInt 32 0
2633        %int_0 = OpConstant %int 0
2634       %struct = OpTypeStruct %float
2635          %ptr = OpTypePointer PushConstant %struct
2636    %ptr_float = OpTypePointer PushConstant %float
2637          %pc1 = OpVariable %ptr PushConstant
2638          %pc2 = OpVariable %ptr PushConstant
2639 
2640            %1 = OpFunction %void None %voidfn
2641        %label = OpLabel
2642                 OpReturn
2643                 OpFunctionEnd
2644 )";
2645 
2646   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
2647   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1))
2648       << getDiagnosticString();
2649 }
2650 
TEST_F(ValidateDecorations,VulkanMultiplePushConstantsSingleEntryPointBad)2651 TEST_F(ValidateDecorations, VulkanMultiplePushConstantsSingleEntryPointBad) {
2652   std::string spirv = R"(
2653                 OpCapability Shader
2654                 OpMemoryModel Logical GLSL450
2655                 OpEntryPoint Fragment %1 "main"
2656                 OpExecutionMode %1 OriginUpperLeft
2657 
2658                 OpDecorate %struct Block
2659                 OpMemberDecorate %struct 0 Offset 0
2660 
2661         %void = OpTypeVoid
2662       %voidfn = OpTypeFunction %void
2663        %float = OpTypeFloat 32
2664          %int = OpTypeInt 32 0
2665        %int_0 = OpConstant %int 0
2666       %struct = OpTypeStruct %float
2667          %ptr = OpTypePointer PushConstant %struct
2668    %ptr_float = OpTypePointer PushConstant %float
2669          %pc1 = OpVariable %ptr PushConstant
2670          %pc2 = OpVariable %ptr PushConstant
2671 
2672            %1 = OpFunction %void None %voidfn
2673        %label = OpLabel
2674            %2 = OpAccessChain %ptr_float %pc1 %int_0
2675            %3 = OpLoad %float %2
2676            %4 = OpAccessChain %ptr_float %pc2 %int_0
2677            %5 = OpLoad %float %4
2678                 OpReturn
2679                 OpFunctionEnd
2680 )";
2681 
2682   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
2683   EXPECT_EQ(SPV_ERROR_INVALID_ID,
2684             ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
2685   EXPECT_THAT(
2686       getDiagnosticString(),
2687       HasSubstr(
2688           "Entry point id '1' uses more than one PushConstant interface.\n"
2689           "From Vulkan spec, section 14.5.1:\n"
2690           "There must be no more than one push constant block "
2691           "statically used per shader entry point."));
2692 }
2693 
TEST_F(ValidateDecorations,VulkanMultiplePushConstantsDifferentEntryPointSubFunctionGood)2694 TEST_F(ValidateDecorations,
2695        VulkanMultiplePushConstantsDifferentEntryPointSubFunctionGood) {
2696   std::string spirv = R"(
2697                 OpCapability Shader
2698                 OpMemoryModel Logical GLSL450
2699                 OpEntryPoint Vertex %1 "func1"
2700                 OpEntryPoint Fragment %2 "func2"
2701                 OpExecutionMode %2 OriginUpperLeft
2702 
2703                 OpDecorate %struct Block
2704                 OpMemberDecorate %struct 0 Offset 0
2705 
2706         %void = OpTypeVoid
2707       %voidfn = OpTypeFunction %void
2708        %float = OpTypeFloat 32
2709          %int = OpTypeInt 32 0
2710        %int_0 = OpConstant %int 0
2711       %struct = OpTypeStruct %float
2712          %ptr = OpTypePointer PushConstant %struct
2713    %ptr_float = OpTypePointer PushConstant %float
2714          %pc1 = OpVariable %ptr PushConstant
2715          %pc2 = OpVariable %ptr PushConstant
2716 
2717         %sub1 = OpFunction %void None %voidfn
2718   %label_sub1 = OpLabel
2719            %3 = OpAccessChain %ptr_float %pc1 %int_0
2720            %4 = OpLoad %float %3
2721                 OpReturn
2722                 OpFunctionEnd
2723 
2724         %sub2 = OpFunction %void None %voidfn
2725   %label_sub2 = OpLabel
2726            %5 = OpAccessChain %ptr_float %pc2 %int_0
2727            %6 = OpLoad %float %5
2728                 OpReturn
2729                 OpFunctionEnd
2730 
2731            %1 = OpFunction %void None %voidfn
2732       %label1 = OpLabel
2733        %call1 = OpFunctionCall %void %sub1
2734                 OpReturn
2735                 OpFunctionEnd
2736 
2737            %2 = OpFunction %void None %voidfn
2738       %label2 = OpLabel
2739        %call2 = OpFunctionCall %void %sub2
2740                 OpReturn
2741                 OpFunctionEnd
2742 )";
2743 
2744   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
2745   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1))
2746       << getDiagnosticString();
2747 }
2748 
TEST_F(ValidateDecorations,VulkanMultiplePushConstantsSingleEntryPointSubFunctionBad)2749 TEST_F(ValidateDecorations,
2750        VulkanMultiplePushConstantsSingleEntryPointSubFunctionBad) {
2751   std::string spirv = R"(
2752                 OpCapability Shader
2753                 OpMemoryModel Logical GLSL450
2754                 OpEntryPoint Fragment %1 "main"
2755                 OpExecutionMode %1 OriginUpperLeft
2756 
2757                 OpDecorate %struct Block
2758                 OpMemberDecorate %struct 0 Offset 0
2759 
2760         %void = OpTypeVoid
2761       %voidfn = OpTypeFunction %void
2762        %float = OpTypeFloat 32
2763          %int = OpTypeInt 32 0
2764        %int_0 = OpConstant %int 0
2765       %struct = OpTypeStruct %float
2766          %ptr = OpTypePointer PushConstant %struct
2767    %ptr_float = OpTypePointer PushConstant %float
2768          %pc1 = OpVariable %ptr PushConstant
2769          %pc2 = OpVariable %ptr PushConstant
2770 
2771         %sub1 = OpFunction %void None %voidfn
2772   %label_sub1 = OpLabel
2773            %3 = OpAccessChain %ptr_float %pc1 %int_0
2774            %4 = OpLoad %float %3
2775                 OpReturn
2776                 OpFunctionEnd
2777 
2778         %sub2 = OpFunction %void None %voidfn
2779   %label_sub2 = OpLabel
2780            %5 = OpAccessChain %ptr_float %pc2 %int_0
2781            %6 = OpLoad %float %5
2782                 OpReturn
2783                 OpFunctionEnd
2784 
2785            %1 = OpFunction %void None %voidfn
2786       %label1 = OpLabel
2787        %call1 = OpFunctionCall %void %sub1
2788        %call2 = OpFunctionCall %void %sub2
2789                 OpReturn
2790                 OpFunctionEnd
2791 )";
2792 
2793   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
2794   EXPECT_EQ(SPV_ERROR_INVALID_ID,
2795             ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
2796   EXPECT_THAT(
2797       getDiagnosticString(),
2798       HasSubstr(
2799           "Entry point id '1' uses more than one PushConstant interface.\n"
2800           "From Vulkan spec, section 14.5.1:\n"
2801           "There must be no more than one push constant block "
2802           "statically used per shader entry point."));
2803 }
2804 
TEST_F(ValidateDecorations,VulkanUniformMissingDescriptorSetBad)2805 TEST_F(ValidateDecorations, VulkanUniformMissingDescriptorSetBad) {
2806   std::string spirv = R"(
2807             OpCapability Shader
2808             OpMemoryModel Logical GLSL450
2809             OpEntryPoint Fragment %1 "main"
2810             OpExecutionMode %1 OriginUpperLeft
2811 
2812             OpDecorate %struct Block
2813             OpMemberDecorate %struct 0 Offset 0
2814             OpDecorate %var Binding 0
2815 
2816     %void = OpTypeVoid
2817   %voidfn = OpTypeFunction %void
2818    %float = OpTypeFloat 32
2819   %struct = OpTypeStruct %float
2820      %ptr = OpTypePointer Uniform %struct
2821 %ptr_float = OpTypePointer Uniform %float
2822      %var = OpVariable %ptr Uniform
2823      %int = OpTypeInt 32 0
2824    %int_0 = OpConstant %int 0
2825 
2826        %1 = OpFunction %void None %voidfn
2827    %label = OpLabel
2828        %2 = OpAccessChain %ptr_float %var %int_0
2829        %3 = OpLoad %float %2
2830             OpReturn
2831             OpFunctionEnd
2832 )";
2833 
2834   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
2835   EXPECT_EQ(SPV_ERROR_INVALID_ID,
2836             ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
2837   EXPECT_THAT(getDiagnosticString(),
2838               HasSubstr("Uniform id '3' is missing DescriptorSet decoration.\n"
2839                         "From Vulkan spec, section 14.5.2:\n"
2840                         "These variables must have DescriptorSet and Binding "
2841                         "decorations specified"));
2842 }
2843 
TEST_F(ValidateDecorations,VulkanUniformMissingBindingBad)2844 TEST_F(ValidateDecorations, VulkanUniformMissingBindingBad) {
2845   std::string spirv = R"(
2846             OpCapability Shader
2847             OpMemoryModel Logical GLSL450
2848             OpEntryPoint Fragment %1 "main"
2849             OpExecutionMode %1 OriginUpperLeft
2850 
2851             OpDecorate %struct Block
2852             OpMemberDecorate %struct 0 Offset 0
2853             OpDecorate %var DescriptorSet 0
2854 
2855     %void = OpTypeVoid
2856   %voidfn = OpTypeFunction %void
2857    %float = OpTypeFloat 32
2858   %struct = OpTypeStruct %float
2859      %ptr = OpTypePointer Uniform %struct
2860 %ptr_float = OpTypePointer Uniform %float
2861      %var = OpVariable %ptr Uniform
2862      %int = OpTypeInt 32 0
2863    %int_0 = OpConstant %int 0
2864 
2865        %1 = OpFunction %void None %voidfn
2866    %label = OpLabel
2867        %2 = OpAccessChain %ptr_float %var %int_0
2868        %3 = OpLoad %float %2
2869             OpReturn
2870             OpFunctionEnd
2871 )";
2872 
2873   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
2874   EXPECT_EQ(SPV_ERROR_INVALID_ID,
2875             ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
2876   EXPECT_THAT(getDiagnosticString(),
2877               HasSubstr("Uniform id '3' is missing Binding decoration.\n"
2878                         "From Vulkan spec, section 14.5.2:\n"
2879                         "These variables must have DescriptorSet and Binding "
2880                         "decorations specified"));
2881 }
2882 
TEST_F(ValidateDecorations,VulkanUniformConstantMissingDescriptorSetBad)2883 TEST_F(ValidateDecorations, VulkanUniformConstantMissingDescriptorSetBad) {
2884   std::string spirv = R"(
2885             OpCapability Shader
2886             OpMemoryModel Logical GLSL450
2887             OpEntryPoint Fragment %1 "main"
2888             OpExecutionMode %1 OriginUpperLeft
2889 
2890             OpDecorate %var Binding 0
2891 
2892     %void = OpTypeVoid
2893   %voidfn = OpTypeFunction %void
2894  %sampler = OpTypeSampler
2895      %ptr = OpTypePointer UniformConstant %sampler
2896      %var = OpVariable %ptr UniformConstant
2897 
2898        %1 = OpFunction %void None %voidfn
2899    %label = OpLabel
2900        %2 = OpLoad %sampler %var
2901             OpReturn
2902             OpFunctionEnd
2903 )";
2904 
2905   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
2906   EXPECT_EQ(SPV_ERROR_INVALID_ID,
2907             ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
2908   EXPECT_THAT(
2909       getDiagnosticString(),
2910       HasSubstr("UniformConstant id '2' is missing DescriptorSet decoration.\n"
2911                 "From Vulkan spec, section 14.5.2:\n"
2912                 "These variables must have DescriptorSet and Binding "
2913                 "decorations specified"));
2914 }
2915 
TEST_F(ValidateDecorations,VulkanUniformConstantMissingBindingBad)2916 TEST_F(ValidateDecorations, VulkanUniformConstantMissingBindingBad) {
2917   std::string spirv = R"(
2918             OpCapability Shader
2919             OpMemoryModel Logical GLSL450
2920             OpEntryPoint Fragment %1 "main"
2921             OpExecutionMode %1 OriginUpperLeft
2922 
2923             OpDecorate %var DescriptorSet 0
2924 
2925     %void = OpTypeVoid
2926   %voidfn = OpTypeFunction %void
2927  %sampler = OpTypeSampler
2928      %ptr = OpTypePointer UniformConstant %sampler
2929      %var = OpVariable %ptr UniformConstant
2930 
2931        %1 = OpFunction %void None %voidfn
2932    %label = OpLabel
2933        %2 = OpLoad %sampler %var
2934             OpReturn
2935             OpFunctionEnd
2936 )";
2937 
2938   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
2939   EXPECT_EQ(SPV_ERROR_INVALID_ID,
2940             ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
2941   EXPECT_THAT(
2942       getDiagnosticString(),
2943       HasSubstr("UniformConstant id '2' is missing Binding decoration.\n"
2944                 "From Vulkan spec, section 14.5.2:\n"
2945                 "These variables must have DescriptorSet and Binding "
2946                 "decorations specified"));
2947 }
2948 
TEST_F(ValidateDecorations,VulkanStorageBufferMissingDescriptorSetBad)2949 TEST_F(ValidateDecorations, VulkanStorageBufferMissingDescriptorSetBad) {
2950   std::string spirv = R"(
2951             OpCapability Shader
2952             OpExtension "SPV_KHR_storage_buffer_storage_class"
2953             OpMemoryModel Logical GLSL450
2954             OpEntryPoint Fragment %1 "main"
2955             OpExecutionMode %1 OriginUpperLeft
2956 
2957             OpDecorate %struct Block
2958             OpDecorate %var Binding 0
2959 
2960     %void = OpTypeVoid
2961   %voidfn = OpTypeFunction %void
2962    %float = OpTypeFloat 32
2963   %struct = OpTypeStruct %float
2964      %ptr = OpTypePointer StorageBuffer %struct
2965      %var = OpVariable %ptr StorageBuffer
2966 %ptr_float = OpTypePointer StorageBuffer %float
2967      %int = OpTypeInt 32 0
2968    %int_0 = OpConstant %int 0
2969 
2970        %1 = OpFunction %void None %voidfn
2971    %label = OpLabel
2972        %2 = OpAccessChain %ptr_float %var %int_0
2973        %3 = OpLoad %float %2
2974             OpReturn
2975             OpFunctionEnd
2976 )";
2977 
2978   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
2979   EXPECT_EQ(SPV_ERROR_INVALID_ID,
2980             ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
2981   EXPECT_THAT(
2982       getDiagnosticString(),
2983       HasSubstr("StorageBuffer id '3' is missing DescriptorSet decoration.\n"
2984                 "From Vulkan spec, section 14.5.2:\n"
2985                 "These variables must have DescriptorSet and Binding "
2986                 "decorations specified"));
2987 }
2988 
TEST_F(ValidateDecorations,VulkanStorageBufferMissingBindingBad)2989 TEST_F(ValidateDecorations, VulkanStorageBufferMissingBindingBad) {
2990   std::string spirv = R"(
2991             OpCapability Shader
2992             OpExtension "SPV_KHR_storage_buffer_storage_class"
2993             OpMemoryModel Logical GLSL450
2994             OpEntryPoint Fragment %1 "main"
2995             OpExecutionMode %1 OriginUpperLeft
2996 
2997             OpDecorate %struct Block
2998             OpDecorate %var DescriptorSet 0
2999 
3000     %void = OpTypeVoid
3001   %voidfn = OpTypeFunction %void
3002    %float = OpTypeFloat 32
3003   %struct = OpTypeStruct %float
3004      %ptr = OpTypePointer StorageBuffer %struct
3005      %var = OpVariable %ptr StorageBuffer
3006 %ptr_float = OpTypePointer StorageBuffer %float
3007      %int = OpTypeInt 32 0
3008    %int_0 = OpConstant %int 0
3009 
3010        %1 = OpFunction %void None %voidfn
3011    %label = OpLabel
3012        %2 = OpAccessChain %ptr_float %var %int_0
3013        %3 = OpLoad %float %2
3014             OpReturn
3015             OpFunctionEnd
3016 )";
3017 
3018   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
3019   EXPECT_EQ(SPV_ERROR_INVALID_ID,
3020             ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
3021   EXPECT_THAT(getDiagnosticString(),
3022               HasSubstr("StorageBuffer id '3' is missing Binding decoration.\n"
3023                         "From Vulkan spec, section 14.5.2:\n"
3024                         "These variables must have DescriptorSet and Binding "
3025                         "decorations specified"));
3026 }
3027 
TEST_F(ValidateDecorations,VulkanStorageBufferMissingDescriptorSetSubFunctionBad)3028 TEST_F(ValidateDecorations,
3029        VulkanStorageBufferMissingDescriptorSetSubFunctionBad) {
3030   std::string spirv = R"(
3031             OpCapability Shader
3032             OpExtension "SPV_KHR_storage_buffer_storage_class"
3033             OpMemoryModel Logical GLSL450
3034             OpEntryPoint Fragment %1 "main"
3035             OpExecutionMode %1 OriginUpperLeft
3036 
3037             OpDecorate %struct Block
3038             OpDecorate %var Binding 0
3039 
3040     %void = OpTypeVoid
3041   %voidfn = OpTypeFunction %void
3042    %float = OpTypeFloat 32
3043   %struct = OpTypeStruct %float
3044      %ptr = OpTypePointer StorageBuffer %struct
3045      %var = OpVariable %ptr StorageBuffer
3046 %ptr_float = OpTypePointer StorageBuffer %float
3047      %int = OpTypeInt 32 0
3048    %int_0 = OpConstant %int 0
3049 
3050        %1 = OpFunction %void None %voidfn
3051    %label = OpLabel
3052     %call = OpFunctionCall %void %2
3053             OpReturn
3054             OpFunctionEnd
3055        %2 = OpFunction %void None %voidfn
3056   %label2 = OpLabel
3057        %3 = OpAccessChain %ptr_float %var %int_0
3058        %4 = OpLoad %float %3
3059             OpReturn
3060             OpFunctionEnd
3061 )";
3062 
3063   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
3064   EXPECT_EQ(SPV_ERROR_INVALID_ID,
3065             ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
3066   EXPECT_THAT(
3067       getDiagnosticString(),
3068       HasSubstr("StorageBuffer id '3' is missing DescriptorSet decoration.\n"
3069                 "From Vulkan spec, section 14.5.2:\n"
3070                 "These variables must have DescriptorSet and Binding "
3071                 "decorations specified"));
3072 }
3073 
TEST_F(ValidateDecorations,VulkanStorageBufferMissingDescriptorAndBindingUnusedGood)3074 TEST_F(ValidateDecorations,
3075        VulkanStorageBufferMissingDescriptorAndBindingUnusedGood) {
3076   std::string spirv = R"(
3077             OpCapability Shader
3078             OpExtension "SPV_KHR_storage_buffer_storage_class"
3079             OpMemoryModel Logical GLSL450
3080             OpEntryPoint Fragment %1 "main"
3081             OpExecutionMode %1 OriginUpperLeft
3082             OpDecorate %struct Block
3083             OpMemberDecorate %struct 0 Offset 0
3084 
3085     %void = OpTypeVoid
3086   %voidfn = OpTypeFunction %void
3087    %float = OpTypeFloat 32
3088   %struct = OpTypeStruct %float
3089      %ptr = OpTypePointer StorageBuffer %struct
3090      %var = OpVariable %ptr StorageBuffer
3091 
3092        %1 = OpFunction %void None %voidfn
3093    %label = OpLabel
3094             OpReturn
3095             OpFunctionEnd
3096 )";
3097 
3098   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
3099   EXPECT_EQ(SPV_SUCCESS,
3100             ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
3101 }
3102 
TEST_F(ValidateDecorations,UniformMissingDescriptorSetGood)3103 TEST_F(ValidateDecorations, UniformMissingDescriptorSetGood) {
3104   std::string spirv = R"(
3105             OpCapability Shader
3106             OpMemoryModel Logical GLSL450
3107             OpEntryPoint Fragment %1 "main"
3108             OpExecutionMode %1 OriginUpperLeft
3109 
3110             OpDecorate %struct Block
3111             OpMemberDecorate %struct 0 Offset 0
3112             OpDecorate %var Binding 0
3113 
3114     %void = OpTypeVoid
3115   %voidfn = OpTypeFunction %void
3116    %float = OpTypeFloat 32
3117   %struct = OpTypeStruct %float
3118      %ptr = OpTypePointer Uniform %struct
3119      %var = OpVariable %ptr Uniform
3120 
3121        %1 = OpFunction %void None %voidfn
3122    %label = OpLabel
3123             OpReturn
3124             OpFunctionEnd
3125 )";
3126 
3127   CompileSuccessfully(spirv);
3128   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
3129       << getDiagnosticString();
3130 }
3131 
TEST_F(ValidateDecorations,UniformMissingBindingGood)3132 TEST_F(ValidateDecorations, UniformMissingBindingGood) {
3133   std::string spirv = R"(
3134             OpCapability Shader
3135             OpMemoryModel Logical GLSL450
3136             OpEntryPoint Fragment %1 "main"
3137             OpExecutionMode %1 OriginUpperLeft
3138 
3139             OpDecorate %struct Block
3140             OpMemberDecorate %struct 0 Offset 0
3141             OpDecorate %var DescriptorSet 0
3142 
3143     %void = OpTypeVoid
3144   %voidfn = OpTypeFunction %void
3145    %float = OpTypeFloat 32
3146   %struct = OpTypeStruct %float
3147      %ptr = OpTypePointer Uniform %struct
3148      %var = OpVariable %ptr Uniform
3149 
3150        %1 = OpFunction %void None %voidfn
3151    %label = OpLabel
3152             OpReturn
3153             OpFunctionEnd
3154 )";
3155 
3156   CompileSuccessfully(spirv);
3157   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
3158       << getDiagnosticString();
3159 }
3160 
TEST_F(ValidateDecorations,UniformConstantMissingDescriptorSetGood)3161 TEST_F(ValidateDecorations, UniformConstantMissingDescriptorSetGood) {
3162   std::string spirv = R"(
3163             OpCapability Shader
3164             OpMemoryModel Logical GLSL450
3165             OpEntryPoint Fragment %1 "main"
3166             OpExecutionMode %1 OriginUpperLeft
3167 
3168             OpDecorate %var Binding 0
3169 
3170     %void = OpTypeVoid
3171   %voidfn = OpTypeFunction %void
3172  %sampler = OpTypeSampler
3173      %ptr = OpTypePointer UniformConstant %sampler
3174      %var = OpVariable %ptr UniformConstant
3175 
3176        %1 = OpFunction %void None %voidfn
3177    %label = OpLabel
3178             OpReturn
3179             OpFunctionEnd
3180 )";
3181 
3182   CompileSuccessfully(spirv);
3183   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
3184       << getDiagnosticString();
3185 }
3186 
TEST_F(ValidateDecorations,UniformConstantMissingBindingGood)3187 TEST_F(ValidateDecorations, UniformConstantMissingBindingGood) {
3188   std::string spirv = R"(
3189             OpCapability Shader
3190             OpMemoryModel Logical GLSL450
3191             OpEntryPoint Fragment %1 "main"
3192             OpExecutionMode %1 OriginUpperLeft
3193 
3194             OpDecorate %var DescriptorSet 0
3195 
3196     %void = OpTypeVoid
3197   %voidfn = OpTypeFunction %void
3198  %sampler = OpTypeSampler
3199      %ptr = OpTypePointer UniformConstant %sampler
3200      %var = OpVariable %ptr UniformConstant
3201 
3202        %1 = OpFunction %void None %voidfn
3203    %label = OpLabel
3204             OpReturn
3205             OpFunctionEnd
3206 )";
3207 
3208   CompileSuccessfully(spirv);
3209   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
3210       << getDiagnosticString();
3211 }
3212 
TEST_F(ValidateDecorations,StorageBufferMissingDescriptorSetGood)3213 TEST_F(ValidateDecorations, StorageBufferMissingDescriptorSetGood) {
3214   std::string spirv = R"(
3215             OpCapability Shader
3216             OpExtension "SPV_KHR_storage_buffer_storage_class"
3217             OpMemoryModel Logical GLSL450
3218             OpEntryPoint Fragment %1 "main"
3219             OpExecutionMode %1 OriginUpperLeft
3220 
3221             OpDecorate %struct BufferBlock
3222             OpDecorate %var Binding 0
3223 
3224     %void = OpTypeVoid
3225   %voidfn = OpTypeFunction %void
3226    %float = OpTypeFloat 32
3227   %struct = OpTypeStruct %float
3228      %ptr = OpTypePointer StorageBuffer %struct
3229      %var = OpVariable %ptr StorageBuffer
3230 
3231        %1 = OpFunction %void None %voidfn
3232    %label = OpLabel
3233             OpReturn
3234             OpFunctionEnd
3235 )";
3236 
3237   CompileSuccessfully(spirv);
3238   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
3239       << getDiagnosticString();
3240 }
3241 
TEST_F(ValidateDecorations,StorageBufferMissingBindingGood)3242 TEST_F(ValidateDecorations, StorageBufferMissingBindingGood) {
3243   std::string spirv = R"(
3244             OpCapability Shader
3245             OpExtension "SPV_KHR_storage_buffer_storage_class"
3246             OpMemoryModel Logical GLSL450
3247             OpEntryPoint Fragment %1 "main"
3248             OpExecutionMode %1 OriginUpperLeft
3249 
3250             OpDecorate %struct BufferBlock
3251             OpDecorate %var DescriptorSet 0
3252 
3253     %void = OpTypeVoid
3254   %voidfn = OpTypeFunction %void
3255    %float = OpTypeFloat 32
3256   %struct = OpTypeStruct %float
3257      %ptr = OpTypePointer StorageBuffer %struct
3258      %var = OpVariable %ptr StorageBuffer
3259 
3260        %1 = OpFunction %void None %voidfn
3261    %label = OpLabel
3262             OpReturn
3263             OpFunctionEnd
3264 )";
3265 
3266   CompileSuccessfully(spirv);
3267   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
3268       << getDiagnosticString();
3269 }
3270 
TEST_F(ValidateDecorations,StorageBufferStorageClassArrayBaseAlignmentGood)3271 TEST_F(ValidateDecorations, StorageBufferStorageClassArrayBaseAlignmentGood) {
3272   // Spot check buffer rules when using StorageBuffer storage class with Block
3273   // decoration.
3274   std::string spirv = R"(
3275                OpCapability Shader
3276                OpExtension "SPV_KHR_storage_buffer_storage_class"
3277                OpMemoryModel Logical GLSL450
3278                OpEntryPoint Vertex %main "main"
3279                OpSource GLSL 450
3280                OpDecorate %_arr_float_uint_2 ArrayStride 4
3281                OpMemberDecorate %S 0 Offset 0
3282                OpMemberDecorate %S 1 Offset 8
3283                OpDecorate %S Block
3284                OpDecorate %u DescriptorSet 0
3285                OpDecorate %u Binding 0
3286        %void = OpTypeVoid
3287           %3 = OpTypeFunction %void
3288       %float = OpTypeFloat 32
3289     %v2float = OpTypeVector %float 2
3290        %uint = OpTypeInt 32 0
3291      %uint_2 = OpConstant %uint 2
3292 %_arr_float_uint_2 = OpTypeArray %float %uint_2
3293           %S = OpTypeStruct %v2float %_arr_float_uint_2
3294 %_ptr_Uniform_S = OpTypePointer StorageBuffer %S
3295           %u = OpVariable %_ptr_Uniform_S StorageBuffer
3296        %main = OpFunction %void None %3
3297           %5 = OpLabel
3298                OpReturn
3299                OpFunctionEnd
3300   )";
3301 
3302   CompileSuccessfully(spirv);
3303   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
3304       << getDiagnosticString();
3305 }
3306 
TEST_F(ValidateDecorations,StorageBufferStorageClassArrayBadAlignmentBad)3307 TEST_F(ValidateDecorations, StorageBufferStorageClassArrayBadAlignmentBad) {
3308   // Like the previous test, but with offset 7.
3309   std::string spirv = R"(
3310                OpCapability Shader
3311                OpExtension "SPV_KHR_storage_buffer_storage_class"
3312                OpMemoryModel Logical GLSL450
3313                OpEntryPoint Vertex %main "main"
3314                OpSource GLSL 450
3315                OpDecorate %_arr_float_uint_2 ArrayStride 4
3316                OpMemberDecorate %S 0 Offset 0
3317                OpMemberDecorate %S 1 Offset 7
3318                OpDecorate %S Block
3319                OpDecorate %u DescriptorSet 0
3320                OpDecorate %u Binding 0
3321        %void = OpTypeVoid
3322           %3 = OpTypeFunction %void
3323       %float = OpTypeFloat 32
3324     %v2float = OpTypeVector %float 2
3325        %uint = OpTypeInt 32 0
3326      %uint_2 = OpConstant %uint 2
3327 %_arr_float_uint_2 = OpTypeArray %float %uint_2
3328           %S = OpTypeStruct %v2float %_arr_float_uint_2
3329 %_ptr_Uniform_S = OpTypePointer StorageBuffer %S
3330           %u = OpVariable %_ptr_Uniform_S StorageBuffer
3331        %main = OpFunction %void None %3
3332           %5 = OpLabel
3333                OpReturn
3334                OpFunctionEnd
3335   )";
3336 
3337   CompileSuccessfully(spirv);
3338   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
3339   EXPECT_THAT(
3340       getDiagnosticString(),
3341       HasSubstr(
3342           "Structure id 3 decorated as Block for variable in StorageBuffer "
3343           "storage class must follow standard storage buffer layout rules: "
3344           "member 1 at offset 7 is not aligned to 4"));
3345 }
3346 
TEST_F(ValidateDecorations,BufferBlockStandardStorageBufferLayout)3347 TEST_F(ValidateDecorations, BufferBlockStandardStorageBufferLayout) {
3348   std::string spirv = R"(
3349                OpCapability Shader
3350           %1 = OpExtInstImport "GLSL.std.450"
3351                OpMemoryModel Logical GLSL450
3352                OpEntryPoint GLCompute %main "main"
3353                OpExecutionMode %main LocalSize 1 1 1
3354                OpSource GLSL 430
3355                OpMemberDecorate %F 0 Offset 0
3356                OpMemberDecorate %F 1 Offset 8
3357                OpDecorate %_arr_float_uint_2 ArrayStride 4
3358                OpDecorate %_arr_mat3v3float_uint_2 ArrayStride 48
3359                OpMemberDecorate %O 0 Offset 0
3360                OpMemberDecorate %O 1 Offset 16
3361                OpMemberDecorate %O 2 Offset 24
3362                OpMemberDecorate %O 3 Offset 32
3363                OpMemberDecorate %O 4 ColMajor
3364                OpMemberDecorate %O 4 Offset 48
3365                OpMemberDecorate %O 4 MatrixStride 16
3366                OpDecorate %_arr_O_uint_2 ArrayStride 144
3367                OpMemberDecorate %Output 0 Offset 0
3368                OpMemberDecorate %Output 1 Offset 8
3369                OpMemberDecorate %Output 2 Offset 16
3370                OpMemberDecorate %Output 3 Offset 32
3371                OpMemberDecorate %Output 4 Offset 48
3372                OpMemberDecorate %Output 5 Offset 52
3373                OpMemberDecorate %Output 6 ColMajor
3374                OpMemberDecorate %Output 6 Offset 64
3375                OpMemberDecorate %Output 6 MatrixStride 16
3376                OpMemberDecorate %Output 7 Offset 96
3377                OpDecorate %Output BufferBlock
3378        %void = OpTypeVoid
3379           %3 = OpTypeFunction %void
3380       %float = OpTypeFloat 32
3381     %v2float = OpTypeVector %float 2
3382     %v3float = OpTypeVector %float 3
3383         %int = OpTypeInt 32 1
3384        %uint = OpTypeInt 32 0
3385      %v2uint = OpTypeVector %uint 2
3386           %F = OpTypeStruct %int %v2uint
3387      %uint_2 = OpConstant %uint 2
3388 %_arr_float_uint_2 = OpTypeArray %float %uint_2
3389 %mat2v3float = OpTypeMatrix %v3float 2
3390      %v3uint = OpTypeVector %uint 3
3391 %mat3v3float = OpTypeMatrix %v3float 3
3392 %_arr_mat3v3float_uint_2 = OpTypeArray %mat3v3float %uint_2
3393           %O = OpTypeStruct %v3uint %v2float %_arr_float_uint_2 %v2float %_arr_mat3v3float_uint_2
3394 %_arr_O_uint_2 = OpTypeArray %O %uint_2
3395      %Output = OpTypeStruct %float %v2float %v3float %F %float %_arr_float_uint_2 %mat2v3float %_arr_O_uint_2
3396 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
3397  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
3398        %main = OpFunction %void None %3
3399           %5 = OpLabel
3400                OpReturn
3401                OpFunctionEnd
3402   )";
3403 
3404   CompileSuccessfully(spirv);
3405   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
3406 }
3407 
TEST_F(ValidateDecorations,StorageBufferLayoutPermitsTightVec3ScalarPackingGood)3408 TEST_F(ValidateDecorations,
3409        StorageBufferLayoutPermitsTightVec3ScalarPackingGood) {
3410   // See https://github.com/KhronosGroup/SPIRV-Tools/issues/1666
3411   std::string spirv = R"(
3412                OpCapability Shader
3413                OpExtension "SPV_KHR_storage_buffer_storage_class"
3414                OpMemoryModel Logical GLSL450
3415                OpEntryPoint Vertex %main "main"
3416                OpSource GLSL 450
3417                OpMemberDecorate %S 0 Offset 0
3418                OpMemberDecorate %S 1 Offset 12
3419                OpDecorate %S Block
3420                OpDecorate %B DescriptorSet 0
3421                OpDecorate %B Binding 0
3422        %void = OpTypeVoid
3423           %3 = OpTypeFunction %void
3424       %float = OpTypeFloat 32
3425     %v3float = OpTypeVector %float 3
3426           %S = OpTypeStruct %v3float %float
3427 %_ptr_StorageBuffer_S = OpTypePointer StorageBuffer %S
3428           %B = OpVariable %_ptr_StorageBuffer_S StorageBuffer
3429        %main = OpFunction %void None %3
3430           %5 = OpLabel
3431                OpReturn
3432                OpFunctionEnd
3433   )";
3434 
3435   CompileSuccessfully(spirv);
3436   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
3437       << getDiagnosticString();
3438 }
3439 
TEST_F(ValidateDecorations,StorageBufferLayoutForbidsTightScalarVec3PackingBad)3440 TEST_F(ValidateDecorations,
3441        StorageBufferLayoutForbidsTightScalarVec3PackingBad) {
3442   // See https://github.com/KhronosGroup/SPIRV-Tools/issues/1666
3443   std::string spirv = R"(
3444                OpCapability Shader
3445                OpExtension "SPV_KHR_storage_buffer_storage_class"
3446                OpMemoryModel Logical GLSL450
3447                OpEntryPoint Vertex %main "main"
3448                OpSource GLSL 450
3449                OpMemberDecorate %S 0 Offset 0
3450                OpMemberDecorate %S 1 Offset 4
3451                OpDecorate %S Block
3452                OpDecorate %B DescriptorSet 0
3453                OpDecorate %B Binding 0
3454        %void = OpTypeVoid
3455           %3 = OpTypeFunction %void
3456       %float = OpTypeFloat 32
3457     %v3float = OpTypeVector %float 3
3458           %S = OpTypeStruct %float %v3float
3459 %_ptr_StorageBuffer_S = OpTypePointer StorageBuffer %S
3460           %B = OpVariable %_ptr_StorageBuffer_S StorageBuffer
3461        %main = OpFunction %void None %3
3462           %5 = OpLabel
3463                OpReturn
3464                OpFunctionEnd
3465   )";
3466 
3467   CompileSuccessfully(spirv);
3468   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
3469   EXPECT_THAT(
3470       getDiagnosticString(),
3471       HasSubstr(
3472           "Structure id 2 decorated as Block for variable in StorageBuffer "
3473           "storage class must follow standard storage buffer layout "
3474           "rules: member 1 at offset 4 is not aligned to 16"));
3475 }
3476 
TEST_F(ValidateDecorations,BlockStandardUniformBufferLayoutIncorrectOffset0Bad)3477 TEST_F(ValidateDecorations,
3478        BlockStandardUniformBufferLayoutIncorrectOffset0Bad) {
3479   std::string spirv = R"(
3480                OpCapability Shader
3481           %1 = OpExtInstImport "GLSL.std.450"
3482                OpMemoryModel Logical GLSL450
3483                OpEntryPoint GLCompute %main "main"
3484                OpExecutionMode %main LocalSize 1 1 1
3485                OpSource GLSL 430
3486                OpMemberDecorate %F 0 Offset 0
3487                OpMemberDecorate %F 1 Offset 8
3488                OpDecorate %_arr_float_uint_2 ArrayStride 16
3489                OpDecorate %_arr_mat3v3float_uint_2 ArrayStride 48
3490                OpMemberDecorate %O 0 Offset 0
3491                OpMemberDecorate %O 1 Offset 16
3492                OpMemberDecorate %O 2 Offset 24
3493                OpMemberDecorate %O 3 Offset 33
3494                OpMemberDecorate %O 4 ColMajor
3495                OpMemberDecorate %O 4 Offset 80
3496                OpMemberDecorate %O 4 MatrixStride 16
3497                OpDecorate %_arr_O_uint_2 ArrayStride 176
3498                OpMemberDecorate %Output 0 Offset 0
3499                OpMemberDecorate %Output 1 Offset 8
3500                OpMemberDecorate %Output 2 Offset 16
3501                OpMemberDecorate %Output 3 Offset 32
3502                OpMemberDecorate %Output 4 Offset 48
3503                OpMemberDecorate %Output 5 Offset 64
3504                OpMemberDecorate %Output 6 ColMajor
3505                OpMemberDecorate %Output 6 Offset 96
3506                OpMemberDecorate %Output 6 MatrixStride 16
3507                OpMemberDecorate %Output 7 Offset 128
3508                OpDecorate %Output Block
3509        %void = OpTypeVoid
3510           %3 = OpTypeFunction %void
3511       %float = OpTypeFloat 32
3512     %v2float = OpTypeVector %float 2
3513     %v3float = OpTypeVector %float 3
3514         %int = OpTypeInt 32 1
3515        %uint = OpTypeInt 32 0
3516      %v2uint = OpTypeVector %uint 2
3517           %F = OpTypeStruct %int %v2uint
3518      %uint_2 = OpConstant %uint 2
3519 %_arr_float_uint_2 = OpTypeArray %float %uint_2
3520 %mat2v3float = OpTypeMatrix %v3float 2
3521      %v3uint = OpTypeVector %uint 3
3522 %mat3v3float = OpTypeMatrix %v3float 3
3523 %_arr_mat3v3float_uint_2 = OpTypeArray %mat3v3float %uint_2
3524           %O = OpTypeStruct %v3uint %v2float %_arr_float_uint_2 %v2float %_arr_mat3v3float_uint_2
3525 %_arr_O_uint_2 = OpTypeArray %O %uint_2
3526      %Output = OpTypeStruct %float %v2float %v3float %F %float %_arr_float_uint_2 %mat2v3float %_arr_O_uint_2
3527 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
3528  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
3529        %main = OpFunction %void None %3
3530           %5 = OpLabel
3531                OpReturn
3532                OpFunctionEnd
3533   )";
3534 
3535   CompileSuccessfully(spirv);
3536   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
3537   EXPECT_THAT(
3538       getDiagnosticString(),
3539       HasSubstr("Structure id 6 decorated as Block for variable in Uniform "
3540                 "storage class must follow standard uniform buffer layout "
3541                 "rules: member 2 at offset 152 is not aligned to 16"));
3542 }
3543 
TEST_F(ValidateDecorations,BlockStandardUniformBufferLayoutIncorrectOffset1Bad)3544 TEST_F(ValidateDecorations,
3545        BlockStandardUniformBufferLayoutIncorrectOffset1Bad) {
3546   std::string spirv = R"(
3547                OpCapability Shader
3548           %1 = OpExtInstImport "GLSL.std.450"
3549                OpMemoryModel Logical GLSL450
3550                OpEntryPoint GLCompute %main "main"
3551                OpExecutionMode %main LocalSize 1 1 1
3552                OpSource GLSL 430
3553                OpMemberDecorate %F 0 Offset 0
3554                OpMemberDecorate %F 1 Offset 8
3555                OpDecorate %_arr_float_uint_2 ArrayStride 16
3556                OpDecorate %_arr_mat3v3float_uint_2 ArrayStride 48
3557                OpMemberDecorate %O 0 Offset 0
3558                OpMemberDecorate %O 1 Offset 16
3559                OpMemberDecorate %O 2 Offset 32
3560                OpMemberDecorate %O 3 Offset 64
3561                OpMemberDecorate %O 4 ColMajor
3562                OpMemberDecorate %O 4 Offset 80
3563                OpMemberDecorate %O 4 MatrixStride 16
3564                OpDecorate %_arr_O_uint_2 ArrayStride 176
3565                OpMemberDecorate %Output 0 Offset 0
3566                OpMemberDecorate %Output 1 Offset 8
3567                OpMemberDecorate %Output 2 Offset 16
3568                OpMemberDecorate %Output 3 Offset 32
3569                OpMemberDecorate %Output 4 Offset 48
3570                OpMemberDecorate %Output 5 Offset 71
3571                OpMemberDecorate %Output 6 ColMajor
3572                OpMemberDecorate %Output 6 Offset 96
3573                OpMemberDecorate %Output 6 MatrixStride 16
3574                OpMemberDecorate %Output 7 Offset 128
3575                OpDecorate %Output Block
3576        %void = OpTypeVoid
3577           %3 = OpTypeFunction %void
3578       %float = OpTypeFloat 32
3579     %v2float = OpTypeVector %float 2
3580     %v3float = OpTypeVector %float 3
3581         %int = OpTypeInt 32 1
3582        %uint = OpTypeInt 32 0
3583      %v2uint = OpTypeVector %uint 2
3584           %F = OpTypeStruct %int %v2uint
3585      %uint_2 = OpConstant %uint 2
3586 %_arr_float_uint_2 = OpTypeArray %float %uint_2
3587 %mat2v3float = OpTypeMatrix %v3float 2
3588      %v3uint = OpTypeVector %uint 3
3589 %mat3v3float = OpTypeMatrix %v3float 3
3590 %_arr_mat3v3float_uint_2 = OpTypeArray %mat3v3float %uint_2
3591           %O = OpTypeStruct %v3uint %v2float %_arr_float_uint_2 %v2float %_arr_mat3v3float_uint_2
3592 %_arr_O_uint_2 = OpTypeArray %O %uint_2
3593      %Output = OpTypeStruct %float %v2float %v3float %F %float %_arr_float_uint_2 %mat2v3float %_arr_O_uint_2
3594 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
3595  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
3596        %main = OpFunction %void None %3
3597           %5 = OpLabel
3598                OpReturn
3599                OpFunctionEnd
3600   )";
3601 
3602   CompileSuccessfully(spirv);
3603   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
3604   EXPECT_THAT(
3605       getDiagnosticString(),
3606       HasSubstr("Structure id 8 decorated as Block for variable in Uniform "
3607                 "storage class must follow standard uniform buffer layout "
3608                 "rules: member 5 at offset 71 is not aligned to 16"));
3609 }
3610 
TEST_F(ValidateDecorations,BlockUniformBufferLayoutIncorrectArrayStrideBad)3611 TEST_F(ValidateDecorations, BlockUniformBufferLayoutIncorrectArrayStrideBad) {
3612   std::string spirv = R"(
3613                OpCapability Shader
3614           %1 = OpExtInstImport "GLSL.std.450"
3615                OpMemoryModel Logical GLSL450
3616                OpEntryPoint GLCompute %main "main"
3617                OpExecutionMode %main LocalSize 1 1 1
3618                OpSource GLSL 430
3619                OpMemberDecorate %F 0 Offset 0
3620                OpMemberDecorate %F 1 Offset 8
3621                OpDecorate %_arr_float_uint_2 ArrayStride 16
3622                OpDecorate %_arr_mat3v3float_uint_2 ArrayStride 49
3623                OpMemberDecorate %O 0 Offset 0
3624                OpMemberDecorate %O 1 Offset 16
3625                OpMemberDecorate %O 2 Offset 32
3626                OpMemberDecorate %O 3 Offset 64
3627                OpMemberDecorate %O 4 ColMajor
3628                OpMemberDecorate %O 4 Offset 80
3629                OpMemberDecorate %O 4 MatrixStride 16
3630                OpDecorate %_arr_O_uint_2 ArrayStride 176
3631                OpMemberDecorate %Output 0 Offset 0
3632                OpMemberDecorate %Output 1 Offset 8
3633                OpMemberDecorate %Output 2 Offset 16
3634                OpMemberDecorate %Output 3 Offset 32
3635                OpMemberDecorate %Output 4 Offset 48
3636                OpMemberDecorate %Output 5 Offset 64
3637                OpMemberDecorate %Output 6 ColMajor
3638                OpMemberDecorate %Output 6 Offset 96
3639                OpMemberDecorate %Output 6 MatrixStride 16
3640                OpMemberDecorate %Output 7 Offset 128
3641                OpDecorate %Output Block
3642        %void = OpTypeVoid
3643           %3 = OpTypeFunction %void
3644       %float = OpTypeFloat 32
3645     %v2float = OpTypeVector %float 2
3646     %v3float = OpTypeVector %float 3
3647         %int = OpTypeInt 32 1
3648        %uint = OpTypeInt 32 0
3649      %v2uint = OpTypeVector %uint 2
3650           %F = OpTypeStruct %int %v2uint
3651      %uint_2 = OpConstant %uint 2
3652 %_arr_float_uint_2 = OpTypeArray %float %uint_2
3653 %mat2v3float = OpTypeMatrix %v3float 2
3654      %v3uint = OpTypeVector %uint 3
3655 %mat3v3float = OpTypeMatrix %v3float 3
3656 %_arr_mat3v3float_uint_2 = OpTypeArray %mat3v3float %uint_2
3657           %O = OpTypeStruct %v3uint %v2float %_arr_float_uint_2 %v2float %_arr_mat3v3float_uint_2
3658 %_arr_O_uint_2 = OpTypeArray %O %uint_2
3659      %Output = OpTypeStruct %float %v2float %v3float %F %float %_arr_float_uint_2 %mat2v3float %_arr_O_uint_2
3660 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
3661  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
3662        %main = OpFunction %void None %3
3663           %5 = OpLabel
3664                OpReturn
3665                OpFunctionEnd
3666   )";
3667 
3668   CompileSuccessfully(spirv);
3669   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
3670   EXPECT_THAT(
3671       getDiagnosticString(),
3672       HasSubstr(
3673           "Structure id 6 decorated as Block for variable in Uniform storage "
3674           "class must follow standard uniform buffer layout rules: member 4 "
3675           "contains "
3676           "an array with stride 49 not satisfying alignment to 16"));
3677 }
3678 
TEST_F(ValidateDecorations,BufferBlockStandardStorageBufferLayoutImproperStraddleBad)3679 TEST_F(ValidateDecorations,
3680        BufferBlockStandardStorageBufferLayoutImproperStraddleBad) {
3681   std::string spirv = R"(
3682                OpCapability Shader
3683           %1 = OpExtInstImport "GLSL.std.450"
3684                OpMemoryModel Logical GLSL450
3685                OpEntryPoint GLCompute %main "main"
3686                OpExecutionMode %main LocalSize 1 1 1
3687                OpSource GLSL 430
3688                OpMemberDecorate %Output 0 Offset 0
3689                OpMemberDecorate %Output 1 Offset 8
3690                OpDecorate %Output BufferBlock
3691        %void = OpTypeVoid
3692           %3 = OpTypeFunction %void
3693       %float = OpTypeFloat 32
3694     %v3float = OpTypeVector %float 3
3695      %Output = OpTypeStruct %float %v3float
3696 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
3697  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
3698        %main = OpFunction %void None %3
3699           %5 = OpLabel
3700                OpReturn
3701                OpFunctionEnd
3702   )";
3703 
3704   CompileSuccessfully(spirv);
3705   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
3706   EXPECT_THAT(
3707       getDiagnosticString(),
3708       HasSubstr("Structure id 3 decorated as BufferBlock for variable in "
3709                 "Uniform storage class must follow standard storage buffer "
3710                 "layout rules: member 1 at offset 8 is not aligned to 16"));
3711 }
3712 
TEST_F(ValidateDecorations,BlockUniformBufferLayoutOffsetInsideArrayPaddingBad)3713 TEST_F(ValidateDecorations,
3714        BlockUniformBufferLayoutOffsetInsideArrayPaddingBad) {
3715   // In this case the 2nd member fits entirely within the padding.
3716   std::string spirv = R"(
3717                OpCapability Shader
3718           %1 = OpExtInstImport "GLSL.std.450"
3719                OpMemoryModel Logical GLSL450
3720                OpEntryPoint GLCompute %main "main"
3721                OpExecutionMode %main LocalSize 1 1 1
3722                OpSource GLSL 430
3723                OpDecorate %_arr_float_uint_2 ArrayStride 16
3724                OpMemberDecorate %Output 0 Offset 0
3725                OpMemberDecorate %Output 1 Offset 20
3726                OpDecorate %Output Block
3727        %void = OpTypeVoid
3728           %3 = OpTypeFunction %void
3729       %float = OpTypeFloat 32
3730        %uint = OpTypeInt 32 0
3731      %v2uint = OpTypeVector %uint 2
3732      %uint_2 = OpConstant %uint 2
3733 %_arr_float_uint_2 = OpTypeArray %float %uint_2
3734      %Output = OpTypeStruct %_arr_float_uint_2 %float
3735 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
3736  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
3737        %main = OpFunction %void None %3
3738           %5 = OpLabel
3739                OpReturn
3740                OpFunctionEnd
3741   )";
3742 
3743   CompileSuccessfully(spirv);
3744   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
3745   EXPECT_THAT(
3746       getDiagnosticString(),
3747       HasSubstr(
3748           "Structure id 4 decorated as Block for variable in Uniform storage "
3749           "class must follow standard uniform buffer layout rules: member 1 at "
3750           "offset 20 overlaps previous member ending at offset 31"));
3751 }
3752 
TEST_F(ValidateDecorations,BlockUniformBufferLayoutOffsetInsideStructPaddingBad)3753 TEST_F(ValidateDecorations,
3754        BlockUniformBufferLayoutOffsetInsideStructPaddingBad) {
3755   // In this case the 2nd member fits entirely within the padding.
3756   std::string spirv = R"(
3757                OpCapability Shader
3758                OpMemoryModel Logical GLSL450
3759                OpEntryPoint GLCompute %1 "main"
3760                OpMemberDecorate %_struct_6 0 Offset 0
3761                OpMemberDecorate %_struct_2 0 Offset 0
3762                OpMemberDecorate %_struct_2 1 Offset 4
3763                OpDecorate %_struct_2 Block
3764        %void = OpTypeVoid
3765           %4 = OpTypeFunction %void
3766       %float = OpTypeFloat 32
3767   %_struct_6 = OpTypeStruct %float
3768   %_struct_2 = OpTypeStruct %_struct_6 %float
3769 %_ptr_Uniform__struct_2 = OpTypePointer Uniform %_struct_2
3770           %8 = OpVariable %_ptr_Uniform__struct_2 Uniform
3771           %1 = OpFunction %void None %4
3772           %9 = OpLabel
3773                OpReturn
3774                OpFunctionEnd
3775   )";
3776 
3777   CompileSuccessfully(spirv);
3778   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
3779   EXPECT_THAT(
3780       getDiagnosticString(),
3781       HasSubstr(
3782           "Structure id 3 decorated as Block for variable in Uniform storage "
3783           "class must follow standard uniform buffer layout rules: member 1 at "
3784           "offset 4 overlaps previous member ending at offset 15"));
3785 }
3786 
TEST_F(ValidateDecorations,BlockLayoutOffsetOutOfOrderGoodUniversal1_0)3787 TEST_F(ValidateDecorations, BlockLayoutOffsetOutOfOrderGoodUniversal1_0) {
3788   std::string spirv = R"(
3789                OpCapability Shader
3790           %1 = OpExtInstImport "GLSL.std.450"
3791                OpMemoryModel Logical GLSL450
3792                OpEntryPoint GLCompute %main "main"
3793                OpExecutionMode %main LocalSize 1 1 1
3794                OpMemberDecorate %Outer 0 Offset 4
3795                OpMemberDecorate %Outer 1 Offset 0
3796                OpDecorate %Outer Block
3797                OpDecorate %O DescriptorSet 0
3798                OpDecorate %O Binding 0
3799        %void = OpTypeVoid
3800           %3 = OpTypeFunction %void
3801        %uint = OpTypeInt 32 0
3802       %Outer = OpTypeStruct %uint %uint
3803 %_ptr_Uniform_Outer = OpTypePointer Uniform %Outer
3804           %O = OpVariable %_ptr_Uniform_Outer Uniform
3805        %main = OpFunction %void None %3
3806           %5 = OpLabel
3807                OpReturn
3808                OpFunctionEnd
3809   )";
3810 
3811   CompileSuccessfully(spirv);
3812   EXPECT_EQ(SPV_SUCCESS,
3813             ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_0));
3814 }
3815 
TEST_F(ValidateDecorations,BlockLayoutOffsetOutOfOrderGoodOpenGL4_5)3816 TEST_F(ValidateDecorations, BlockLayoutOffsetOutOfOrderGoodOpenGL4_5) {
3817   std::string spirv = R"(
3818                OpCapability Shader
3819           %1 = OpExtInstImport "GLSL.std.450"
3820                OpMemoryModel Logical GLSL450
3821                OpEntryPoint GLCompute %main "main"
3822                OpExecutionMode %main LocalSize 1 1 1
3823                OpMemberDecorate %Outer 0 Offset 4
3824                OpMemberDecorate %Outer 1 Offset 0
3825                OpDecorate %Outer Block
3826                OpDecorate %O DescriptorSet 0
3827                OpDecorate %O Binding 0
3828        %void = OpTypeVoid
3829           %3 = OpTypeFunction %void
3830        %uint = OpTypeInt 32 0
3831       %Outer = OpTypeStruct %uint %uint
3832 %_ptr_Uniform_Outer = OpTypePointer Uniform %Outer
3833           %O = OpVariable %_ptr_Uniform_Outer Uniform
3834        %main = OpFunction %void None %3
3835           %5 = OpLabel
3836                OpReturn
3837                OpFunctionEnd
3838   )";
3839 
3840   CompileSuccessfully(spirv);
3841   EXPECT_EQ(SPV_SUCCESS,
3842             ValidateAndRetrieveValidationState(SPV_ENV_OPENGL_4_5));
3843 }
3844 
TEST_F(ValidateDecorations,BlockLayoutOffsetOutOfOrderGoodVulkan1_1)3845 TEST_F(ValidateDecorations, BlockLayoutOffsetOutOfOrderGoodVulkan1_1) {
3846   std::string spirv = R"(
3847                OpCapability Shader
3848           %1 = OpExtInstImport "GLSL.std.450"
3849                OpMemoryModel Logical GLSL450
3850                OpEntryPoint GLCompute %main "main"
3851                OpExecutionMode %main LocalSize 1 1 1
3852                OpMemberDecorate %Outer 0 Offset 4
3853                OpMemberDecorate %Outer 1 Offset 0
3854                OpDecorate %Outer Block
3855                OpDecorate %O DescriptorSet 0
3856                OpDecorate %O Binding 0
3857        %void = OpTypeVoid
3858           %3 = OpTypeFunction %void
3859        %uint = OpTypeInt 32 0
3860       %Outer = OpTypeStruct %uint %uint
3861 %_ptr_Uniform_Outer = OpTypePointer Uniform %Outer
3862           %O = OpVariable %_ptr_Uniform_Outer Uniform
3863        %main = OpFunction %void None %3
3864           %5 = OpLabel
3865                OpReturn
3866                OpFunctionEnd
3867   )";
3868 
3869   CompileSuccessfully(spirv);
3870   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1))
3871       << getDiagnosticString();
3872   EXPECT_THAT(getDiagnosticString(), Eq(""));
3873 }
3874 
TEST_F(ValidateDecorations,BlockLayoutOffsetOverlapBad)3875 TEST_F(ValidateDecorations, BlockLayoutOffsetOverlapBad) {
3876   std::string spirv = R"(
3877                OpCapability Shader
3878           %1 = OpExtInstImport "GLSL.std.450"
3879                OpMemoryModel Logical GLSL450
3880                OpEntryPoint GLCompute %main "main"
3881                OpExecutionMode %main LocalSize 1 1 1
3882                OpMemberDecorate %Outer 0 Offset 0
3883                OpMemberDecorate %Outer 1 Offset 16
3884                OpMemberDecorate %Inner 0 Offset 0
3885                OpMemberDecorate %Inner 1 Offset 16
3886                OpDecorate %Outer Block
3887                OpDecorate %O DescriptorSet 0
3888                OpDecorate %O Binding 0
3889        %void = OpTypeVoid
3890           %3 = OpTypeFunction %void
3891        %uint = OpTypeInt 32 0
3892       %Inner = OpTypeStruct %uint %uint
3893       %Outer = OpTypeStruct %Inner %uint
3894 %_ptr_Uniform_Outer = OpTypePointer Uniform %Outer
3895           %O = OpVariable %_ptr_Uniform_Outer Uniform
3896        %main = OpFunction %void None %3
3897           %5 = OpLabel
3898                OpReturn
3899                OpFunctionEnd
3900   )";
3901 
3902   CompileSuccessfully(spirv);
3903   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
3904   EXPECT_THAT(
3905       getDiagnosticString(),
3906       HasSubstr(
3907           "Structure id 3 decorated as Block for variable in Uniform storage "
3908           "class must follow standard uniform buffer layout rules: member 1 at "
3909           "offset 16 overlaps previous member ending at offset 31"));
3910 }
3911 
TEST_F(ValidateDecorations,BufferBlockEmptyStruct)3912 TEST_F(ValidateDecorations, BufferBlockEmptyStruct) {
3913   std::string spirv = R"(
3914                OpCapability Shader
3915           %1 = OpExtInstImport "GLSL.std.450"
3916                OpMemoryModel Logical GLSL450
3917                OpEntryPoint GLCompute %main "main"
3918                OpExecutionMode %main LocalSize 1 1 1
3919                OpSource GLSL 430
3920                OpMemberDecorate %Output 0 Offset 0
3921                OpDecorate %Output BufferBlock
3922        %void = OpTypeVoid
3923           %3 = OpTypeFunction %void
3924           %S = OpTypeStruct
3925      %Output = OpTypeStruct %S
3926 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
3927  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
3928        %main = OpFunction %void None %3
3929           %5 = OpLabel
3930                OpReturn
3931                OpFunctionEnd
3932   )";
3933 
3934   CompileSuccessfully(spirv);
3935   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
3936 }
3937 
TEST_F(ValidateDecorations,RowMajorMatrixTightPackingGood)3938 TEST_F(ValidateDecorations, RowMajorMatrixTightPackingGood) {
3939   // Row major matrix rule:
3940   //     A row-major matrix of C columns has a base alignment equal to
3941   //     the base alignment of a vector of C matrix components.
3942   // Note: The "matrix component" is the scalar element type.
3943 
3944   // The matrix has 3 columns and 2 rows (C=3, R=2).
3945   // So the base alignment of b is the same as a vector of 3 floats, which is 16
3946   // bytes. The matrix consists of two of these, and therefore occupies 2 x 16
3947   // bytes, or 32 bytes.
3948   //
3949   // So the offsets can be:
3950   // a -> 0
3951   // b -> 16
3952   // c -> 48
3953   // d -> 60 ; d fits at bytes 12-15 after offset of c. Tight (vec3;float)
3954   // packing
3955 
3956   std::string spirv = R"(
3957                OpCapability Shader
3958                OpMemoryModel Logical GLSL450
3959                OpEntryPoint Vertex %1 "main"
3960                OpSource GLSL 450
3961                OpMemberDecorate %_struct_2 0 Offset 0
3962                OpMemberDecorate %_struct_2 1 RowMajor
3963                OpMemberDecorate %_struct_2 1 Offset 16
3964                OpMemberDecorate %_struct_2 1 MatrixStride 16
3965                OpMemberDecorate %_struct_2 2 Offset 48
3966                OpMemberDecorate %_struct_2 3 Offset 60
3967                OpDecorate %_struct_2 Block
3968                OpDecorate %3 DescriptorSet 0
3969                OpDecorate %3 Binding 0
3970        %void = OpTypeVoid
3971           %5 = OpTypeFunction %void
3972       %float = OpTypeFloat 32
3973     %v4float = OpTypeVector %float 4
3974     %v2float = OpTypeVector %float 2
3975 %mat3v2float = OpTypeMatrix %v2float 3
3976     %v3float = OpTypeVector %float 3
3977   %_struct_2 = OpTypeStruct %v4float %mat3v2float %v3float %float
3978 %_ptr_Uniform__struct_2 = OpTypePointer Uniform %_struct_2
3979           %3 = OpVariable %_ptr_Uniform__struct_2 Uniform
3980           %1 = OpFunction %void None %5
3981          %12 = OpLabel
3982                OpReturn
3983                OpFunctionEnd
3984   )";
3985 
3986   CompileSuccessfully(spirv);
3987   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
3988       << getDiagnosticString();
3989 }
3990 
TEST_F(ValidateDecorations,ArrayArrayRowMajorMatrixTightPackingGood)3991 TEST_F(ValidateDecorations, ArrayArrayRowMajorMatrixTightPackingGood) {
3992   // Like the previous case, but we have an array of arrays of matrices.
3993   // The RowMajor decoration goes on the struct member (surprisingly).
3994 
3995   std::string spirv = R"(
3996                OpCapability Shader
3997                OpMemoryModel Logical GLSL450
3998                OpEntryPoint Vertex %1 "main"
3999                OpSource GLSL 450
4000                OpMemberDecorate %_struct_2 0 Offset 0
4001                OpMemberDecorate %_struct_2 1 RowMajor
4002                OpMemberDecorate %_struct_2 1 Offset 16
4003                OpMemberDecorate %_struct_2 1 MatrixStride 16
4004                OpMemberDecorate %_struct_2 2 Offset 80
4005                OpMemberDecorate %_struct_2 3 Offset 92
4006                OpDecorate %arr_mat ArrayStride 32
4007                OpDecorate %arr_arr_mat ArrayStride 32
4008                OpDecorate %_struct_2 Block
4009                OpDecorate %3 DescriptorSet 0
4010                OpDecorate %3 Binding 0
4011        %void = OpTypeVoid
4012           %5 = OpTypeFunction %void
4013       %float = OpTypeFloat 32
4014     %v4float = OpTypeVector %float 4
4015     %v2float = OpTypeVector %float 2
4016 %mat3v2float = OpTypeMatrix %v2float 3
4017 %uint        = OpTypeInt 32 0
4018 %uint_1      = OpConstant %uint 1
4019 %uint_2      = OpConstant %uint 2
4020     %arr_mat = OpTypeArray %mat3v2float %uint_1
4021 %arr_arr_mat = OpTypeArray %arr_mat %uint_2
4022     %v3float = OpTypeVector %float 3
4023   %_struct_2 = OpTypeStruct %v4float %arr_arr_mat %v3float %float
4024 %_ptr_Uniform__struct_2 = OpTypePointer Uniform %_struct_2
4025           %3 = OpVariable %_ptr_Uniform__struct_2 Uniform
4026           %1 = OpFunction %void None %5
4027          %12 = OpLabel
4028                OpReturn
4029                OpFunctionEnd
4030   )";
4031 
4032   CompileSuccessfully(spirv);
4033   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
4034       << getDiagnosticString();
4035 }
4036 
TEST_F(ValidateDecorations,ArrayArrayRowMajorMatrixNextMemberOverlapsBad)4037 TEST_F(ValidateDecorations, ArrayArrayRowMajorMatrixNextMemberOverlapsBad) {
4038   // Like the previous case, but the offset of member 2 overlaps the matrix.
4039   std::string spirv = R"(
4040                OpCapability Shader
4041                OpMemoryModel Logical GLSL450
4042                OpEntryPoint Vertex %1 "main"
4043                OpSource GLSL 450
4044                OpMemberDecorate %_struct_2 0 Offset 0
4045                OpMemberDecorate %_struct_2 1 RowMajor
4046                OpMemberDecorate %_struct_2 1 Offset 16
4047                OpMemberDecorate %_struct_2 1 MatrixStride 16
4048                OpMemberDecorate %_struct_2 2 Offset 64
4049                OpMemberDecorate %_struct_2 3 Offset 92
4050                OpDecorate %arr_mat ArrayStride 32
4051                OpDecorate %arr_arr_mat ArrayStride 32
4052                OpDecorate %_struct_2 Block
4053                OpDecorate %3 DescriptorSet 0
4054                OpDecorate %3 Binding 0
4055        %void = OpTypeVoid
4056           %5 = OpTypeFunction %void
4057       %float = OpTypeFloat 32
4058     %v4float = OpTypeVector %float 4
4059     %v2float = OpTypeVector %float 2
4060 %mat3v2float = OpTypeMatrix %v2float 3
4061 %uint        = OpTypeInt 32 0
4062 %uint_1      = OpConstant %uint 1
4063 %uint_2      = OpConstant %uint 2
4064     %arr_mat = OpTypeArray %mat3v2float %uint_1
4065 %arr_arr_mat = OpTypeArray %arr_mat %uint_2
4066     %v3float = OpTypeVector %float 3
4067   %_struct_2 = OpTypeStruct %v4float %arr_arr_mat %v3float %float
4068 %_ptr_Uniform__struct_2 = OpTypePointer Uniform %_struct_2
4069           %3 = OpVariable %_ptr_Uniform__struct_2 Uniform
4070           %1 = OpFunction %void None %5
4071          %12 = OpLabel
4072                OpReturn
4073                OpFunctionEnd
4074   )";
4075 
4076   CompileSuccessfully(spirv);
4077   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
4078   EXPECT_THAT(
4079       getDiagnosticString(),
4080       HasSubstr(
4081           "Structure id 2 decorated as Block for variable in Uniform storage "
4082           "class must follow standard uniform buffer layout rules: member 2 at "
4083           "offset 64 overlaps previous member ending at offset 79"));
4084 }
4085 
TEST_F(ValidateDecorations,StorageBufferArraySizeCalculationPackGood)4086 TEST_F(ValidateDecorations, StorageBufferArraySizeCalculationPackGood) {
4087   // Original GLSL
4088 
4089   // #version 450
4090   // layout (set=0,binding=0) buffer S {
4091   //   uvec3 arr[2][2]; // first 3 elements are 16 bytes, last is 12
4092   //   uint i;  // Can have offset 60 = 3x16 + 12
4093   // } B;
4094   // void main() {}
4095 
4096   std::string spirv = R"(
4097                OpCapability Shader
4098                OpMemoryModel Logical GLSL450
4099                OpEntryPoint Vertex %1 "main"
4100                OpDecorate %_arr_v3uint_uint_2 ArrayStride 16
4101                OpDecorate %_arr__arr_v3uint_uint_2_uint_2 ArrayStride 32
4102                OpMemberDecorate %_struct_4 0 Offset 0
4103                OpMemberDecorate %_struct_4 1 Offset 60
4104                OpDecorate %_struct_4 BufferBlock
4105                OpDecorate %5 DescriptorSet 0
4106                OpDecorate %5 Binding 0
4107        %void = OpTypeVoid
4108           %7 = OpTypeFunction %void
4109        %uint = OpTypeInt 32 0
4110      %v3uint = OpTypeVector %uint 3
4111      %uint_2 = OpConstant %uint 2
4112 %_arr_v3uint_uint_2 = OpTypeArray %v3uint %uint_2
4113 %_arr__arr_v3uint_uint_2_uint_2 = OpTypeArray %_arr_v3uint_uint_2 %uint_2
4114   %_struct_4 = OpTypeStruct %_arr__arr_v3uint_uint_2_uint_2 %uint
4115 %_ptr_Uniform__struct_4 = OpTypePointer Uniform %_struct_4
4116           %5 = OpVariable %_ptr_Uniform__struct_4 Uniform
4117           %1 = OpFunction %void None %7
4118          %12 = OpLabel
4119                OpReturn
4120                OpFunctionEnd
4121   )";
4122 
4123   CompileSuccessfully(spirv);
4124   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
4125 }
4126 
TEST_F(ValidateDecorations,StorageBufferArraySizeCalculationPackBad)4127 TEST_F(ValidateDecorations, StorageBufferArraySizeCalculationPackBad) {
4128   // Like previous but, the offset of the second member is too small.
4129 
4130   std::string spirv = R"(
4131                OpCapability Shader
4132                OpMemoryModel Logical GLSL450
4133                OpEntryPoint Vertex %1 "main"
4134                OpDecorate %_arr_v3uint_uint_2 ArrayStride 16
4135                OpDecorate %_arr__arr_v3uint_uint_2_uint_2 ArrayStride 32
4136                OpMemberDecorate %_struct_4 0 Offset 0
4137                OpMemberDecorate %_struct_4 1 Offset 56
4138                OpDecorate %_struct_4 BufferBlock
4139                OpDecorate %5 DescriptorSet 0
4140                OpDecorate %5 Binding 0
4141        %void = OpTypeVoid
4142           %7 = OpTypeFunction %void
4143        %uint = OpTypeInt 32 0
4144      %v3uint = OpTypeVector %uint 3
4145      %uint_2 = OpConstant %uint 2
4146 %_arr_v3uint_uint_2 = OpTypeArray %v3uint %uint_2
4147 %_arr__arr_v3uint_uint_2_uint_2 = OpTypeArray %_arr_v3uint_uint_2 %uint_2
4148   %_struct_4 = OpTypeStruct %_arr__arr_v3uint_uint_2_uint_2 %uint
4149 %_ptr_Uniform__struct_4 = OpTypePointer Uniform %_struct_4
4150           %5 = OpVariable %_ptr_Uniform__struct_4 Uniform
4151           %1 = OpFunction %void None %7
4152          %12 = OpLabel
4153                OpReturn
4154                OpFunctionEnd
4155   )";
4156 
4157   CompileSuccessfully(spirv);
4158   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
4159   EXPECT_THAT(getDiagnosticString(),
4160               HasSubstr("Structure id 4 decorated as BufferBlock for variable "
4161                         "in Uniform storage class must follow standard storage "
4162                         "buffer layout rules: member 1 at offset 56 overlaps "
4163                         "previous member ending at offset 59"));
4164 }
4165 
TEST_F(ValidateDecorations,UniformBufferArraySizeCalculationPackGood)4166 TEST_F(ValidateDecorations, UniformBufferArraySizeCalculationPackGood) {
4167   // Like the corresponding buffer block case, but the array padding must
4168   // count for the last element as well, and so the offset of the second
4169   // member must be at least 64.
4170   std::string spirv = R"(
4171                OpCapability Shader
4172                OpMemoryModel Logical GLSL450
4173                OpEntryPoint Vertex %1 "main"
4174                OpDecorate %_arr_v3uint_uint_2 ArrayStride 16
4175                OpDecorate %_arr__arr_v3uint_uint_2_uint_2 ArrayStride 32
4176                OpMemberDecorate %_struct_4 0 Offset 0
4177                OpMemberDecorate %_struct_4 1 Offset 64
4178                OpDecorate %_struct_4 Block
4179                OpDecorate %5 DescriptorSet 0
4180                OpDecorate %5 Binding 0
4181        %void = OpTypeVoid
4182           %7 = OpTypeFunction %void
4183        %uint = OpTypeInt 32 0
4184      %v3uint = OpTypeVector %uint 3
4185      %uint_2 = OpConstant %uint 2
4186 %_arr_v3uint_uint_2 = OpTypeArray %v3uint %uint_2
4187 %_arr__arr_v3uint_uint_2_uint_2 = OpTypeArray %_arr_v3uint_uint_2 %uint_2
4188   %_struct_4 = OpTypeStruct %_arr__arr_v3uint_uint_2_uint_2 %uint
4189 %_ptr_Uniform__struct_4 = OpTypePointer Uniform %_struct_4
4190           %5 = OpVariable %_ptr_Uniform__struct_4 Uniform
4191           %1 = OpFunction %void None %7
4192          %12 = OpLabel
4193                OpReturn
4194                OpFunctionEnd
4195   )";
4196 
4197   CompileSuccessfully(spirv);
4198   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
4199 }
4200 
TEST_F(ValidateDecorations,UniformBufferArraySizeCalculationPackBad)4201 TEST_F(ValidateDecorations, UniformBufferArraySizeCalculationPackBad) {
4202   // Like previous but, the offset of the second member is too small.
4203 
4204   std::string spirv = R"(
4205                OpCapability Shader
4206                OpMemoryModel Logical GLSL450
4207                OpEntryPoint Vertex %1 "main"
4208                OpDecorate %_arr_v3uint_uint_2 ArrayStride 16
4209                OpDecorate %_arr__arr_v3uint_uint_2_uint_2 ArrayStride 32
4210                OpMemberDecorate %_struct_4 0 Offset 0
4211                OpMemberDecorate %_struct_4 1 Offset 60
4212                OpDecorate %_struct_4 Block
4213                OpDecorate %5 DescriptorSet 0
4214                OpDecorate %5 Binding 0
4215        %void = OpTypeVoid
4216           %7 = OpTypeFunction %void
4217        %uint = OpTypeInt 32 0
4218      %v3uint = OpTypeVector %uint 3
4219      %uint_2 = OpConstant %uint 2
4220 %_arr_v3uint_uint_2 = OpTypeArray %v3uint %uint_2
4221 %_arr__arr_v3uint_uint_2_uint_2 = OpTypeArray %_arr_v3uint_uint_2 %uint_2
4222   %_struct_4 = OpTypeStruct %_arr__arr_v3uint_uint_2_uint_2 %uint
4223 %_ptr_Uniform__struct_4 = OpTypePointer Uniform %_struct_4
4224           %5 = OpVariable %_ptr_Uniform__struct_4 Uniform
4225           %1 = OpFunction %void None %7
4226          %12 = OpLabel
4227                OpReturn
4228                OpFunctionEnd
4229   )";
4230 
4231   CompileSuccessfully(spirv);
4232   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
4233   EXPECT_THAT(
4234       getDiagnosticString(),
4235       HasSubstr(
4236           "Structure id 4 decorated as Block for variable in Uniform storage "
4237           "class must follow standard uniform buffer layout rules: member 1 at "
4238           "offset 60 overlaps previous member ending at offset 63"));
4239 }
4240 
TEST_F(ValidateDecorations,LayoutNotCheckedWhenSkipBlockLayout)4241 TEST_F(ValidateDecorations, LayoutNotCheckedWhenSkipBlockLayout) {
4242   // Checks that block layout is not verified in skipping block layout mode.
4243   // Even for obviously wrong layout.
4244   std::string spirv = R"(
4245                OpCapability Shader
4246                OpMemoryModel Logical GLSL450
4247                OpEntryPoint Vertex %main "main"
4248                OpSource GLSL 450
4249                OpMemberDecorate %S 0 Offset 3 ; wrong alignment
4250                OpMemberDecorate %S 1 Offset 3 ; same offset as before!
4251                OpDecorate %S Block
4252                OpDecorate %B DescriptorSet 0
4253                OpDecorate %B Binding 0
4254        %void = OpTypeVoid
4255           %3 = OpTypeFunction %void
4256       %float = OpTypeFloat 32
4257     %v3float = OpTypeVector %float 3
4258           %S = OpTypeStruct %float %v3float
4259 %_ptr_Uniform_S = OpTypePointer Uniform %S
4260           %B = OpVariable %_ptr_Uniform_S Uniform
4261        %main = OpFunction %void None %3
4262           %5 = OpLabel
4263                OpReturn
4264                OpFunctionEnd
4265   )";
4266 
4267   CompileSuccessfully(spirv);
4268   spvValidatorOptionsSetSkipBlockLayout(getValidatorOptions(), true);
4269   EXPECT_EQ(SPV_SUCCESS,
4270             ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
4271   EXPECT_THAT(getDiagnosticString(), Eq(""));
4272 }
4273 
TEST_F(ValidateDecorations,EntryPointVariableWrongStorageClass)4274 TEST_F(ValidateDecorations, EntryPointVariableWrongStorageClass) {
4275   const std::string spirv = R"(
4276 OpCapability Shader
4277 OpMemoryModel Logical GLSL450
4278 OpEntryPoint Fragment %1 "func" %var
4279 OpExecutionMode %1 OriginUpperLeft
4280 %void = OpTypeVoid
4281 %int = OpTypeInt 32 0
4282 %ptr_int_Workgroup = OpTypePointer Workgroup %int
4283 %var = OpVariable %ptr_int_Workgroup Workgroup
4284 %func_ty = OpTypeFunction %void
4285 %1 = OpFunction %void None %func_ty
4286 %2 = OpLabel
4287 OpReturn
4288 OpFunctionEnd
4289 )";
4290 
4291   CompileSuccessfully(spirv);
4292   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
4293   EXPECT_THAT(getDiagnosticString(),
4294               HasSubstr("OpEntryPoint interfaces must be OpVariables with "
4295                         "Storage Class of Input(1) or Output(3). Found Storage "
4296                         "Class 4 for Entry Point id 1."));
4297 }
4298 
TEST_F(ValidateDecorations,VulkanMemoryModelNonCoherent)4299 TEST_F(ValidateDecorations, VulkanMemoryModelNonCoherent) {
4300   const std::string spirv = R"(
4301 OpCapability Shader
4302 OpCapability VulkanMemoryModelKHR
4303 OpCapability Linkage
4304 OpExtension "SPV_KHR_vulkan_memory_model"
4305 OpExtension "SPV_KHR_storage_buffer_storage_class"
4306 OpMemoryModel Logical VulkanKHR
4307 OpDecorate %1 Coherent
4308 %2 = OpTypeInt 32 0
4309 %3 = OpTypePointer StorageBuffer %2
4310 %1 = OpVariable %3 StorageBuffer
4311 )";
4312 
4313   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
4314   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
4315   EXPECT_THAT(getDiagnosticString(),
4316               HasSubstr("Coherent decoration targeting 1[%1] is "
4317                         "banned when using the Vulkan memory model."));
4318 }
4319 
TEST_F(ValidateDecorations,VulkanMemoryModelNoCoherentMember)4320 TEST_F(ValidateDecorations, VulkanMemoryModelNoCoherentMember) {
4321   const std::string spirv = R"(
4322 OpCapability Shader
4323 OpCapability VulkanMemoryModelKHR
4324 OpCapability Linkage
4325 OpExtension "SPV_KHR_vulkan_memory_model"
4326 OpMemoryModel Logical VulkanKHR
4327 OpMemberDecorate %1 0 Coherent
4328 %2 = OpTypeInt 32 0
4329 %1 = OpTypeStruct %2 %2
4330 )";
4331 
4332   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
4333   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
4334   EXPECT_THAT(
4335       getDiagnosticString(),
4336       HasSubstr("Coherent decoration targeting 1[%_struct_1] (member index 0) "
4337                 "is banned when using the Vulkan memory model."));
4338 }
4339 
TEST_F(ValidateDecorations,VulkanMemoryModelNoVolatile)4340 TEST_F(ValidateDecorations, VulkanMemoryModelNoVolatile) {
4341   const std::string spirv = R"(
4342 OpCapability Shader
4343 OpCapability VulkanMemoryModelKHR
4344 OpCapability Linkage
4345 OpExtension "SPV_KHR_vulkan_memory_model"
4346 OpExtension "SPV_KHR_storage_buffer_storage_class"
4347 OpMemoryModel Logical VulkanKHR
4348 OpDecorate %1 Volatile
4349 %2 = OpTypeInt 32 0
4350 %3 = OpTypePointer StorageBuffer %2
4351 %1 = OpVariable %3 StorageBuffer
4352 )";
4353 
4354   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
4355   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
4356   EXPECT_THAT(getDiagnosticString(),
4357               HasSubstr("Volatile decoration targeting 1[%1] is banned when "
4358                         "using the Vulkan memory model."));
4359 }
4360 
TEST_F(ValidateDecorations,VulkanMemoryModelNoVolatileMember)4361 TEST_F(ValidateDecorations, VulkanMemoryModelNoVolatileMember) {
4362   const std::string spirv = R"(
4363 OpCapability Shader
4364 OpCapability VulkanMemoryModelKHR
4365 OpCapability Linkage
4366 OpExtension "SPV_KHR_vulkan_memory_model"
4367 OpMemoryModel Logical VulkanKHR
4368 OpMemberDecorate %1 1 Volatile
4369 %2 = OpTypeInt 32 0
4370 %1 = OpTypeStruct %2 %2
4371 )";
4372 
4373   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
4374   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
4375   EXPECT_THAT(getDiagnosticString(),
4376               HasSubstr("Volatile decoration targeting 1[%_struct_1] (member "
4377                         "index 1) is banned when using the Vulkan memory "
4378                         "model."));
4379 }
4380 
TEST_F(ValidateDecorations,FPRoundingModeGood)4381 TEST_F(ValidateDecorations, FPRoundingModeGood) {
4382   std::string spirv = R"(
4383 OpCapability Shader
4384 OpCapability Linkage
4385 OpCapability StorageBuffer16BitAccess
4386 OpExtension "SPV_KHR_storage_buffer_storage_class"
4387 OpExtension "SPV_KHR_variable_pointers"
4388 OpExtension "SPV_KHR_16bit_storage"
4389 OpMemoryModel Logical GLSL450
4390 OpEntryPoint GLCompute %main "main"
4391 OpDecorate %_ FPRoundingMode RTE
4392 %half = OpTypeFloat 16
4393 %float = OpTypeFloat 32
4394 %float_1_25 = OpConstant %float 1.25
4395 %half_ptr = OpTypePointer StorageBuffer %half
4396 %half_ptr_var = OpVariable %half_ptr StorageBuffer
4397 %void = OpTypeVoid
4398 %func = OpTypeFunction %void
4399 %main = OpFunction %void None %func
4400 %main_entry = OpLabel
4401 %_ = OpFConvert %half %float_1_25
4402 OpStore %half_ptr_var %_
4403 OpReturn
4404 OpFunctionEnd
4405   )";
4406 
4407   CompileSuccessfully(spirv);
4408   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
4409 }
4410 
TEST_F(ValidateDecorations,FPRoundingModeVectorGood)4411 TEST_F(ValidateDecorations, FPRoundingModeVectorGood) {
4412   std::string spirv = R"(
4413 OpCapability Shader
4414 OpCapability Linkage
4415 OpCapability StorageBuffer16BitAccess
4416 OpExtension "SPV_KHR_storage_buffer_storage_class"
4417 OpExtension "SPV_KHR_variable_pointers"
4418 OpExtension "SPV_KHR_16bit_storage"
4419 OpMemoryModel Logical GLSL450
4420 OpEntryPoint GLCompute %main "main"
4421 OpDecorate %_ FPRoundingMode RTE
4422 %half = OpTypeFloat 16
4423 %float = OpTypeFloat 32
4424 %v2half = OpTypeVector %half 2
4425 %v2float = OpTypeVector %float 2
4426 %float_1_25 = OpConstant %float 1.25
4427 %floats = OpConstantComposite %v2float %float_1_25 %float_1_25
4428 %halfs_ptr = OpTypePointer StorageBuffer %v2half
4429 %halfs_ptr_var = OpVariable %halfs_ptr StorageBuffer
4430 %void = OpTypeVoid
4431 %func = OpTypeFunction %void
4432 %main = OpFunction %void None %func
4433 %main_entry = OpLabel
4434 %_ = OpFConvert %v2half %floats
4435 OpStore %halfs_ptr_var %_
4436 OpReturn
4437 OpFunctionEnd
4438   )";
4439 
4440   CompileSuccessfully(spirv);
4441   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
4442 }
4443 
TEST_F(ValidateDecorations,FPRoundingModeNotOpFConvert)4444 TEST_F(ValidateDecorations, FPRoundingModeNotOpFConvert) {
4445   std::string spirv = R"(
4446 OpCapability Shader
4447 OpCapability Linkage
4448 OpCapability StorageBuffer16BitAccess
4449 OpExtension "SPV_KHR_storage_buffer_storage_class"
4450 OpExtension "SPV_KHR_variable_pointers"
4451 OpExtension "SPV_KHR_16bit_storage"
4452 OpMemoryModel Logical GLSL450
4453 OpEntryPoint GLCompute %main "main"
4454 OpDecorate %_ FPRoundingMode RTE
4455 %short = OpTypeInt 16 1
4456 %int = OpTypeInt 32 1
4457 %int_17 = OpConstant %int 17
4458 %short_ptr = OpTypePointer StorageBuffer %short
4459 %short_ptr_var = OpVariable %short_ptr StorageBuffer
4460 %void = OpTypeVoid
4461 %func = OpTypeFunction %void
4462 %main = OpFunction %void None %func
4463 %main_entry = OpLabel
4464 %_ = OpSConvert %short %int_17
4465 OpStore %short_ptr_var %_
4466 OpReturn
4467 OpFunctionEnd
4468   )";
4469 
4470   CompileSuccessfully(spirv);
4471   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
4472   EXPECT_THAT(getDiagnosticString(),
4473               HasSubstr("FPRoundingMode decoration can be applied only to a "
4474                         "width-only conversion instruction for floating-point "
4475                         "object."));
4476 }
4477 
TEST_F(ValidateDecorations,FPRoundingModeNoOpStoreGood)4478 TEST_F(ValidateDecorations, FPRoundingModeNoOpStoreGood) {
4479   std::string spirv = R"(
4480 OpCapability Shader
4481 OpCapability Linkage
4482 OpCapability StorageBuffer16BitAccess
4483 OpExtension "SPV_KHR_storage_buffer_storage_class"
4484 OpExtension "SPV_KHR_variable_pointers"
4485 OpExtension "SPV_KHR_16bit_storage"
4486 OpMemoryModel Logical GLSL450
4487 OpEntryPoint GLCompute %main "main"
4488 OpDecorate %_ FPRoundingMode RTE
4489 %half = OpTypeFloat 16
4490 %float = OpTypeFloat 32
4491 %float_1_25 = OpConstant %float 1.25
4492 %half_ptr = OpTypePointer StorageBuffer %half
4493 %half_ptr_var = OpVariable %half_ptr StorageBuffer
4494 %void = OpTypeVoid
4495 %func = OpTypeFunction %void
4496 %main = OpFunction %void None %func
4497 %main_entry = OpLabel
4498 %_ = OpFConvert %half %float_1_25
4499 OpReturn
4500 OpFunctionEnd
4501   )";
4502 
4503   CompileSuccessfully(spirv);
4504   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
4505 }
4506 
TEST_F(ValidateDecorations,FPRoundingModeFConvert64to16Good)4507 TEST_F(ValidateDecorations, FPRoundingModeFConvert64to16Good) {
4508   std::string spirv = R"(
4509 OpCapability Shader
4510 OpCapability Linkage
4511 OpCapability StorageBuffer16BitAccess
4512 OpCapability Float64
4513 OpExtension "SPV_KHR_storage_buffer_storage_class"
4514 OpExtension "SPV_KHR_variable_pointers"
4515 OpExtension "SPV_KHR_16bit_storage"
4516 OpMemoryModel Logical GLSL450
4517 OpEntryPoint GLCompute %main "main"
4518 OpDecorate %_ FPRoundingMode RTE
4519 %half = OpTypeFloat 16
4520 %double = OpTypeFloat 64
4521 %double_1_25 = OpConstant %double 1.25
4522 %half_ptr = OpTypePointer StorageBuffer %half
4523 %half_ptr_var = OpVariable %half_ptr StorageBuffer
4524 %void = OpTypeVoid
4525 %func = OpTypeFunction %void
4526 %main = OpFunction %void None %func
4527 %main_entry = OpLabel
4528 %_ = OpFConvert %half %double_1_25
4529 OpStore %half_ptr_var %_
4530 OpReturn
4531 OpFunctionEnd
4532   )";
4533 
4534   CompileSuccessfully(spirv);
4535   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
4536 }
4537 
TEST_F(ValidateDecorations,FPRoundingModeNotStoreInFloat16)4538 TEST_F(ValidateDecorations, FPRoundingModeNotStoreInFloat16) {
4539   std::string spirv = R"(
4540 OpCapability Shader
4541 OpCapability Linkage
4542 OpCapability StorageBuffer16BitAccess
4543 OpCapability Float64
4544 OpExtension "SPV_KHR_storage_buffer_storage_class"
4545 OpExtension "SPV_KHR_variable_pointers"
4546 OpExtension "SPV_KHR_16bit_storage"
4547 OpMemoryModel Logical GLSL450
4548 OpEntryPoint GLCompute %main "main"
4549 OpDecorate %_ FPRoundingMode RTE
4550 %float = OpTypeFloat 32
4551 %double = OpTypeFloat 64
4552 %double_1_25 = OpConstant %double 1.25
4553 %float_ptr = OpTypePointer StorageBuffer %float
4554 %float_ptr_var = OpVariable %float_ptr StorageBuffer
4555 %void = OpTypeVoid
4556 %func = OpTypeFunction %void
4557 %main = OpFunction %void None %func
4558 %main_entry = OpLabel
4559 %_ = OpFConvert %float %double_1_25
4560 OpStore %float_ptr_var %_
4561 OpReturn
4562 OpFunctionEnd
4563   )";
4564 
4565   CompileSuccessfully(spirv);
4566   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
4567   EXPECT_THAT(
4568       getDiagnosticString(),
4569       HasSubstr("FPRoundingMode decoration can be applied only to the "
4570                 "Object operand of an OpStore storing through a "
4571                 "pointer to a 16-bit floating-point scalar or vector object."));
4572 }
4573 
TEST_F(ValidateDecorations,FPRoundingModeMultipleOpStoreGood)4574 TEST_F(ValidateDecorations, FPRoundingModeMultipleOpStoreGood) {
4575   std::string spirv = R"(
4576 OpCapability Shader
4577 OpCapability Linkage
4578 OpCapability StorageBuffer16BitAccess
4579 OpExtension "SPV_KHR_storage_buffer_storage_class"
4580 OpExtension "SPV_KHR_variable_pointers"
4581 OpExtension "SPV_KHR_16bit_storage"
4582 OpMemoryModel Logical GLSL450
4583 OpEntryPoint GLCompute %main "main"
4584 OpDecorate %_ FPRoundingMode RTE
4585 %half = OpTypeFloat 16
4586 %float = OpTypeFloat 32
4587 %float_1_25 = OpConstant %float 1.25
4588 %half_ptr = OpTypePointer StorageBuffer %half
4589 %half_ptr_var_0 = OpVariable %half_ptr StorageBuffer
4590 %half_ptr_var_1 = OpVariable %half_ptr StorageBuffer
4591 %half_ptr_var_2 = OpVariable %half_ptr StorageBuffer
4592 %void = OpTypeVoid
4593 %func = OpTypeFunction %void
4594 %main = OpFunction %void None %func
4595 %main_entry = OpLabel
4596 %_ = OpFConvert %half %float_1_25
4597 OpStore %half_ptr_var_0 %_
4598 OpStore %half_ptr_var_1 %_
4599 OpStore %half_ptr_var_2 %_
4600 OpReturn
4601 OpFunctionEnd
4602   )";
4603 
4604   CompileSuccessfully(spirv);
4605   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
4606 }
4607 
TEST_F(ValidateDecorations,FPRoundingModeMultipleUsesBad)4608 TEST_F(ValidateDecorations, FPRoundingModeMultipleUsesBad) {
4609   std::string spirv = R"(
4610 OpCapability Shader
4611 OpCapability Linkage
4612 OpCapability StorageBuffer16BitAccess
4613 OpExtension "SPV_KHR_storage_buffer_storage_class"
4614 OpExtension "SPV_KHR_variable_pointers"
4615 OpExtension "SPV_KHR_16bit_storage"
4616 OpMemoryModel Logical GLSL450
4617 OpEntryPoint GLCompute %main "main"
4618 OpDecorate %_ FPRoundingMode RTE
4619 %half = OpTypeFloat 16
4620 %float = OpTypeFloat 32
4621 %float_1_25 = OpConstant %float 1.25
4622 %half_ptr = OpTypePointer StorageBuffer %half
4623 %half_ptr_var_0 = OpVariable %half_ptr StorageBuffer
4624 %half_ptr_var_1 = OpVariable %half_ptr StorageBuffer
4625 %void = OpTypeVoid
4626 %func = OpTypeFunction %void
4627 %main = OpFunction %void None %func
4628 %main_entry = OpLabel
4629 %_ = OpFConvert %half %float_1_25
4630 OpStore %half_ptr_var_0 %_
4631 %result = OpFAdd %half %_ %_
4632 OpStore %half_ptr_var_1 %_
4633 OpReturn
4634 OpFunctionEnd
4635   )";
4636 
4637   CompileSuccessfully(spirv);
4638   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
4639   EXPECT_THAT(getDiagnosticString(),
4640               HasSubstr("FPRoundingMode decoration can be applied only to the "
4641                         "Object operand of an OpStore."));
4642 }
4643 
TEST_F(ValidateDecorations,VulkanFPRoundingModeGood)4644 TEST_F(ValidateDecorations, VulkanFPRoundingModeGood) {
4645   std::string spirv = R"(
4646                OpCapability Shader
4647                OpCapability StorageBuffer16BitAccess
4648           %1 = OpExtInstImport "GLSL.std.450"
4649                OpMemoryModel Logical GLSL450
4650                OpEntryPoint GLCompute %main "main" %_
4651                OpExecutionMode %main LocalSize 1 1 1
4652                OpMemberDecorate %ssbo 0 Offset 0
4653                OpDecorate %ssbo Block
4654                OpDecorate %_ DescriptorSet 0
4655                OpDecorate %_ Binding 0
4656                OpDecorate %17 FPRoundingMode RTE
4657        %void = OpTypeVoid
4658           %3 = OpTypeFunction %void
4659       %float = OpTypeFloat 32
4660 %_ptr_Function_float = OpTypePointer Function %float
4661     %float_1 = OpConstant %float 1
4662        %half = OpTypeFloat 16
4663        %ssbo = OpTypeStruct %half
4664 %_ptr_StorageBuffer_ssbo = OpTypePointer StorageBuffer %ssbo
4665           %_ = OpVariable %_ptr_StorageBuffer_ssbo StorageBuffer
4666         %int = OpTypeInt 32 1
4667       %int_0 = OpConstant %int 0
4668 %_ptr_StorageBuffer_half = OpTypePointer StorageBuffer %half
4669        %main = OpFunction %void None %3
4670           %5 = OpLabel
4671           %b = OpVariable %_ptr_Function_float Function
4672                OpStore %b %float_1
4673          %16 = OpLoad %float %b
4674          %17 = OpFConvert %half %16
4675          %19 = OpAccessChain %_ptr_StorageBuffer_half %_ %int_0
4676                OpStore %19 %17
4677                OpReturn
4678                OpFunctionEnd
4679   )";
4680 
4681   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_2);
4682   EXPECT_EQ(SPV_SUCCESS,
4683             ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_2));
4684 }
4685 
TEST_F(ValidateDecorations,VulkanFPRoundingModeBadMode)4686 TEST_F(ValidateDecorations, VulkanFPRoundingModeBadMode) {
4687   std::string spirv = R"(
4688                OpCapability Shader
4689                OpCapability StorageBuffer16BitAccess
4690           %1 = OpExtInstImport "GLSL.std.450"
4691                OpMemoryModel Logical GLSL450
4692                OpEntryPoint GLCompute %main "main" %_
4693                OpExecutionMode %main LocalSize 1 1 1
4694                OpMemberDecorate %ssbo 0 Offset 0
4695                OpDecorate %ssbo Block
4696                OpDecorate %_ DescriptorSet 0
4697                OpDecorate %_ Binding 0
4698                OpDecorate %17 FPRoundingMode RTP
4699        %void = OpTypeVoid
4700           %3 = OpTypeFunction %void
4701       %float = OpTypeFloat 32
4702 %_ptr_Function_float = OpTypePointer Function %float
4703     %float_1 = OpConstant %float 1
4704        %half = OpTypeFloat 16
4705        %ssbo = OpTypeStruct %half
4706 %_ptr_StorageBuffer_ssbo = OpTypePointer StorageBuffer %ssbo
4707           %_ = OpVariable %_ptr_StorageBuffer_ssbo StorageBuffer
4708         %int = OpTypeInt 32 1
4709       %int_0 = OpConstant %int 0
4710 %_ptr_StorageBuffer_half = OpTypePointer StorageBuffer %half
4711        %main = OpFunction %void None %3
4712           %5 = OpLabel
4713           %b = OpVariable %_ptr_Function_float Function
4714                OpStore %b %float_1
4715          %16 = OpLoad %float %b
4716          %17 = OpFConvert %half %16
4717          %19 = OpAccessChain %_ptr_StorageBuffer_half %_ %int_0
4718                OpStore %19 %17
4719                OpReturn
4720                OpFunctionEnd
4721   )";
4722 
4723   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_2);
4724   EXPECT_EQ(SPV_ERROR_INVALID_ID,
4725             ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_2));
4726   EXPECT_THAT(getDiagnosticString(),
4727               AnyVUID("VUID-StandaloneSpirv-FPRoundingMode-04675"));
4728   EXPECT_THAT(
4729       getDiagnosticString(),
4730       HasSubstr("In Vulkan, the FPRoundingMode mode must only by RTE or RTZ."));
4731 }
4732 
TEST_F(ValidateDecorations,GroupDecorateTargetsDecorationGroup)4733 TEST_F(ValidateDecorations, GroupDecorateTargetsDecorationGroup) {
4734   std::string spirv = R"(
4735 OpCapability Shader
4736 OpCapability Linkage
4737 OpMemoryModel Logical GLSL450
4738 %1 = OpDecorationGroup
4739 OpGroupDecorate %1 %1
4740 )";
4741 
4742   CompileSuccessfully(spirv);
4743   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
4744   EXPECT_THAT(getDiagnosticString(),
4745               HasSubstr("OpGroupDecorate may not target OpDecorationGroup <id> "
4746                         "'1[%1]'"));
4747 }
4748 
TEST_F(ValidateDecorations,GroupDecorateTargetsDecorationGroup2)4749 TEST_F(ValidateDecorations, GroupDecorateTargetsDecorationGroup2) {
4750   std::string spirv = R"(
4751 OpCapability Shader
4752 OpCapability Linkage
4753 OpMemoryModel Logical GLSL450
4754 %1 = OpDecorationGroup
4755 OpGroupDecorate %1 %2 %1
4756 %2 = OpTypeVoid
4757 )";
4758 
4759   CompileSuccessfully(spirv);
4760   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
4761   EXPECT_THAT(getDiagnosticString(),
4762               HasSubstr("OpGroupDecorate may not target OpDecorationGroup <id> "
4763                         "'1[%1]'"));
4764 }
4765 
TEST_F(ValidateDecorations,RecurseThroughRuntimeArray)4766 TEST_F(ValidateDecorations, RecurseThroughRuntimeArray) {
4767   const std::string spirv = R"(
4768 OpCapability Shader
4769 OpCapability Linkage
4770 OpMemoryModel Logical GLSL450
4771 OpDecorate %outer Block
4772 OpMemberDecorate %inner 0 Offset 0
4773 OpMemberDecorate %inner 1 Offset 1
4774 OpDecorate %runtime ArrayStride 16
4775 OpMemberDecorate %outer 0 Offset 0
4776 %int = OpTypeInt 32 0
4777 %inner = OpTypeStruct %int %int
4778 %runtime = OpTypeRuntimeArray %inner
4779 %outer = OpTypeStruct %runtime
4780 %outer_ptr = OpTypePointer Uniform %outer
4781 %var = OpVariable %outer_ptr Uniform
4782 )";
4783 
4784   CompileSuccessfully(spirv);
4785   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
4786   EXPECT_THAT(
4787       getDiagnosticString(),
4788       HasSubstr("Structure id 2 decorated as Block for variable in Uniform "
4789                 "storage class must follow standard uniform buffer layout "
4790                 "rules: member 1 at offset 1 is not aligned to 4"));
4791 }
4792 
TEST_F(ValidateDecorations,EmptyStructAtNonZeroOffsetGood)4793 TEST_F(ValidateDecorations, EmptyStructAtNonZeroOffsetGood) {
4794   const std::string spirv = R"(
4795 OpCapability Shader
4796 OpMemoryModel Logical GLSL450
4797 OpEntryPoint GLCompute %main "main"
4798 OpExecutionMode %main LocalSize 1 1 1
4799 OpDecorate %struct Block
4800 OpMemberDecorate %struct 0 Offset 0
4801 OpMemberDecorate %struct 1 Offset 16
4802 OpDecorate %var DescriptorSet 0
4803 OpDecorate %var Binding 0
4804 %void = OpTypeVoid
4805 %float = OpTypeFloat 32
4806 %empty = OpTypeStruct
4807 %struct = OpTypeStruct %float %empty
4808 %ptr_struct_ubo = OpTypePointer Uniform %struct
4809 %var = OpVariable %ptr_struct_ubo Uniform
4810 %voidfn = OpTypeFunction %void
4811 %main = OpFunction %void None %voidfn
4812 %entry = OpLabel
4813 OpReturn
4814 OpFunctionEnd
4815 )";
4816 
4817   CompileSuccessfully(spirv);
4818   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
4819 }
4820 
4821 // Uniform and UniformId decorations
4822 
TEST_F(ValidateDecorations,UniformDecorationGood)4823 TEST_F(ValidateDecorations, UniformDecorationGood) {
4824   const std::string spirv = R"(
4825 OpCapability Shader
4826 OpMemoryModel Logical Simple
4827 OpEntryPoint GLCompute %main "main"
4828 OpExecutionMode %main LocalSize 1 1 1
4829 OpDecorate %int0 Uniform
4830 OpDecorate %var Uniform
4831 OpDecorate %val Uniform
4832 %void = OpTypeVoid
4833 %int = OpTypeInt 32 1
4834 %int0 = OpConstantNull %int
4835 %intptr = OpTypePointer Private %int
4836 %var = OpVariable %intptr Private
4837 %fn = OpTypeFunction %void
4838 %main = OpFunction %void None %fn
4839 %entry = OpLabel
4840 %val = OpLoad %int %var
4841 OpReturn
4842 OpFunctionEnd
4843 )";
4844 
4845   CompileSuccessfully(spirv);
4846   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
4847   EXPECT_THAT(getDiagnosticString(), Eq(""));
4848 }
4849 
4850 // Returns SPIR-V assembly for a shader that uses a given decoration
4851 // instruction.
ShaderWithUniformLikeDecoration(const std::string & inst)4852 std::string ShaderWithUniformLikeDecoration(const std::string& inst) {
4853   return std::string(R"(
4854 OpCapability Shader
4855 OpMemoryModel Logical Simple
4856 OpEntryPoint GLCompute %main "main"
4857 OpExecutionMode %main LocalSize 1 1 1
4858 OpName %subgroupscope "subgroupscope"
4859 OpName %call "call"
4860 OpName %myfunc "myfunc"
4861 OpName %int0 "int0"
4862 OpName %float0 "float0"
4863 OpName %fn "fn"
4864 )") + inst +
4865          R"(
4866 %void = OpTypeVoid
4867 %float = OpTypeFloat 32
4868 %int = OpTypeInt 32 1
4869 %int0 = OpConstantNull %int
4870 %int_99 = OpConstant %int 99
4871 %subgroupscope = OpConstant %int 3
4872 %float0 = OpConstantNull %float
4873 %fn = OpTypeFunction %void
4874 %myfunc = OpFunction %void None %fn
4875 %myfuncentry = OpLabel
4876 OpReturn
4877 OpFunctionEnd
4878 %main = OpFunction %void None %fn
4879 %entry = OpLabel
4880 %call = OpFunctionCall %void %myfunc
4881 OpReturn
4882 OpFunctionEnd
4883 )";
4884 }
4885 
TEST_F(ValidateDecorations,UniformIdDecorationWithScopeIdV13Bad)4886 TEST_F(ValidateDecorations, UniformIdDecorationWithScopeIdV13Bad) {
4887   const std::string spirv = ShaderWithUniformLikeDecoration(
4888       "OpDecorateId %int0 UniformId %subgroupscope");
4889   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
4890   EXPECT_EQ(SPV_ERROR_WRONG_VERSION,
4891             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
4892   EXPECT_THAT(getDiagnosticString(),
4893               HasSubstr("requires SPIR-V version 1.4 or later\n"
4894                         "  OpDecorateId %int0 UniformId %subgroupscope"))
4895       << spirv;
4896 }
4897 
TEST_F(ValidateDecorations,UniformIdDecorationWithScopeIdV13BadTargetV14)4898 TEST_F(ValidateDecorations, UniformIdDecorationWithScopeIdV13BadTargetV14) {
4899   const std::string spirv = ShaderWithUniformLikeDecoration(
4900       "OpDecorateId %int0 UniformId %subgroupscope");
4901   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
4902   EXPECT_EQ(SPV_ERROR_WRONG_VERSION,
4903             ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
4904   EXPECT_THAT(getDiagnosticString(),
4905               HasSubstr("requires SPIR-V version 1.4 or later"));
4906 }
4907 
TEST_F(ValidateDecorations,UniformIdDecorationWithScopeIdV14Good)4908 TEST_F(ValidateDecorations, UniformIdDecorationWithScopeIdV14Good) {
4909   const std::string spirv = ShaderWithUniformLikeDecoration(
4910       "OpDecorateId %int0 UniformId %subgroupscope");
4911   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
4912   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
4913   EXPECT_THAT(getDiagnosticString(), Eq(""));
4914 }
4915 
TEST_F(ValidateDecorations,UniformDecorationTargetsTypeBad)4916 TEST_F(ValidateDecorations, UniformDecorationTargetsTypeBad) {
4917   const std::string spirv =
4918       ShaderWithUniformLikeDecoration("OpDecorate %fn Uniform");
4919 
4920   CompileSuccessfully(spirv);
4921   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
4922   EXPECT_THAT(getDiagnosticString(),
4923               HasSubstr("Uniform decoration applied to a non-object"));
4924   EXPECT_THAT(getDiagnosticString(), HasSubstr("%fn = OpTypeFunction %void"));
4925 }
4926 
TEST_F(ValidateDecorations,UniformIdDecorationTargetsTypeBad)4927 TEST_F(ValidateDecorations, UniformIdDecorationTargetsTypeBad) {
4928   const std::string spirv = ShaderWithUniformLikeDecoration(
4929       "OpDecorateId %fn UniformId %subgroupscope");
4930 
4931   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
4932   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
4933   EXPECT_THAT(getDiagnosticString(),
4934               HasSubstr("UniformId decoration applied to a non-object"));
4935   EXPECT_THAT(getDiagnosticString(), HasSubstr("%fn = OpTypeFunction %void"));
4936 }
4937 
TEST_F(ValidateDecorations,UniformDecorationTargetsVoidValueBad)4938 TEST_F(ValidateDecorations, UniformDecorationTargetsVoidValueBad) {
4939   const std::string spirv =
4940       ShaderWithUniformLikeDecoration("OpDecorate %call Uniform");
4941 
4942   CompileSuccessfully(spirv);
4943   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
4944   EXPECT_THAT(getDiagnosticString(),
4945               HasSubstr("Uniform decoration applied to a value with void type\n"
4946                         "  %call = OpFunctionCall %void %myfunc"));
4947 }
4948 
TEST_F(ValidateDecorations,UniformIdDecorationTargetsVoidValueBad)4949 TEST_F(ValidateDecorations, UniformIdDecorationTargetsVoidValueBad) {
4950   const std::string spirv = ShaderWithUniformLikeDecoration(
4951       "OpDecorateId %call UniformId %subgroupscope");
4952 
4953   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
4954   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4))
4955       << spirv;
4956   EXPECT_THAT(
4957       getDiagnosticString(),
4958       HasSubstr("UniformId decoration applied to a value with void type\n"
4959                 "  %call = OpFunctionCall %void %myfunc"));
4960 }
4961 
TEST_F(ValidateDecorations,UniformDecorationWithScopeIdV14IdIsFloatValueIsBad)4962 TEST_F(ValidateDecorations,
4963        UniformDecorationWithScopeIdV14IdIsFloatValueIsBad) {
4964   const std::string spirv =
4965       ShaderWithUniformLikeDecoration("OpDecorateId %int0 UniformId %float0");
4966 
4967   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
4968   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
4969             ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
4970   EXPECT_THAT(getDiagnosticString(),
4971               HasSubstr("ConstantNull: expected scope to be a 32-bit int"));
4972 }
4973 
TEST_F(ValidateDecorations,UniformDecorationWithScopeIdV14IdIsInvalidIntValueBad)4974 TEST_F(ValidateDecorations,
4975        UniformDecorationWithScopeIdV14IdIsInvalidIntValueBad) {
4976   const std::string spirv =
4977       ShaderWithUniformLikeDecoration("OpDecorateId %int0 UniformId %int_99");
4978 
4979   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
4980   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
4981             ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
4982   EXPECT_THAT(
4983       getDiagnosticString(),
4984       HasSubstr("Invalid scope value:\n %int_99 = OpConstant %int 99\n"));
4985 }
4986 
TEST_F(ValidateDecorations,UniformDecorationWithScopeIdV14VulkanEnv)4987 TEST_F(ValidateDecorations, UniformDecorationWithScopeIdV14VulkanEnv) {
4988   const std::string spirv =
4989       ShaderWithUniformLikeDecoration("OpDecorateId %int0 UniformId %int0");
4990 
4991   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1_SPIRV_1_4);
4992   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
4993             ValidateInstructions(SPV_ENV_VULKAN_1_1_SPIRV_1_4));
4994   EXPECT_THAT(getDiagnosticString(),
4995               HasSubstr(": in Vulkan environment Execution Scope is limited to "
4996                         "Workgroup and Subgroup"));
4997 }
4998 
TEST_F(ValidateDecorations,UniformDecorationWithWrongInstructionBad)4999 TEST_F(ValidateDecorations, UniformDecorationWithWrongInstructionBad) {
5000   const std::string spirv =
5001       ShaderWithUniformLikeDecoration("OpDecorateId %int0 Uniform");
5002 
5003   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_2);
5004   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_2));
5005   EXPECT_THAT(getDiagnosticString(),
5006               HasSubstr("Decorations that don't take ID parameters may not be "
5007                         "used with OpDecorateId\n"
5008                         "  OpDecorateId %int0 Uniform"));
5009 }
5010 
TEST_F(ValidateDecorations,UniformIdDecorationWithWrongInstructionBad)5011 TEST_F(ValidateDecorations, UniformIdDecorationWithWrongInstructionBad) {
5012   const std::string spirv = ShaderWithUniformLikeDecoration(
5013       "OpDecorate %int0 UniformId %subgroupscope");
5014 
5015   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
5016   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
5017   EXPECT_THAT(
5018       getDiagnosticString(),
5019       HasSubstr(
5020           "Decorations taking ID parameters may not be used with OpDecorateId\n"
5021           "  OpDecorate %int0 UniformId %subgroupscope"));
5022 }
5023 
TEST_F(ValidateDecorations,MultipleOffsetDecorationsOnSameID)5024 TEST_F(ValidateDecorations, MultipleOffsetDecorationsOnSameID) {
5025   std::string spirv = R"(
5026             OpCapability Shader
5027             OpMemoryModel Logical GLSL450
5028             OpEntryPoint Fragment %1 "main"
5029             OpExecutionMode %1 OriginUpperLeft
5030 
5031             OpMemberDecorate %struct 0 Offset 0
5032             OpMemberDecorate %struct 0 Offset 0
5033 
5034     %void = OpTypeVoid
5035   %voidfn = OpTypeFunction %void
5036    %float = OpTypeFloat 32
5037   %struct = OpTypeStruct %float
5038 
5039        %1 = OpFunction %void None %voidfn
5040    %label = OpLabel
5041             OpReturn
5042             OpFunctionEnd
5043 )";
5044 
5045   CompileSuccessfully(spirv);
5046   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
5047   EXPECT_THAT(getDiagnosticString(),
5048               HasSubstr("ID '2', member '0' decorated with Offset multiple "
5049                         "times is not allowed."));
5050 }
5051 
TEST_F(ValidateDecorations,MultipleArrayStrideDecorationsOnSameID)5052 TEST_F(ValidateDecorations, MultipleArrayStrideDecorationsOnSameID) {
5053   std::string spirv = R"(
5054             OpCapability Shader
5055             OpMemoryModel Logical GLSL450
5056             OpEntryPoint Fragment %1 "main"
5057             OpExecutionMode %1 OriginUpperLeft
5058 
5059             OpDecorate %array ArrayStride 4
5060             OpDecorate %array ArrayStride 4
5061 
5062     %void = OpTypeVoid
5063   %voidfn = OpTypeFunction %void
5064    %float = OpTypeFloat 32
5065     %uint = OpTypeInt 32 0
5066   %uint_4 = OpConstant %uint 4
5067    %array = OpTypeArray %float %uint_4
5068 
5069        %1 = OpFunction %void None %voidfn
5070    %label = OpLabel
5071             OpReturn
5072             OpFunctionEnd
5073 )";
5074 
5075   CompileSuccessfully(spirv);
5076   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
5077   EXPECT_THAT(getDiagnosticString(),
5078               HasSubstr("ID '2' decorated with ArrayStride multiple "
5079                         "times is not allowed."));
5080 }
5081 
TEST_F(ValidateDecorations,MultipleMatrixStrideDecorationsOnSameID)5082 TEST_F(ValidateDecorations, MultipleMatrixStrideDecorationsOnSameID) {
5083   std::string spirv = R"(
5084             OpCapability Shader
5085             OpMemoryModel Logical GLSL450
5086             OpEntryPoint Fragment %1 "main"
5087             OpExecutionMode %1 OriginUpperLeft
5088 
5089             OpMemberDecorate %struct 0 Offset 0
5090             OpMemberDecorate %struct 0 ColMajor
5091             OpMemberDecorate %struct 0 MatrixStride 16
5092             OpMemberDecorate %struct 0 MatrixStride 16
5093 
5094     %void = OpTypeVoid
5095   %voidfn = OpTypeFunction %void
5096    %float = OpTypeFloat 32
5097    %fvec4 = OpTypeVector %float 4
5098    %fmat4 = OpTypeMatrix %fvec4 4
5099   %struct = OpTypeStruct %fmat4
5100 
5101        %1 = OpFunction %void None %voidfn
5102    %label = OpLabel
5103             OpReturn
5104             OpFunctionEnd
5105 )";
5106 
5107   CompileSuccessfully(spirv);
5108   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
5109   EXPECT_THAT(getDiagnosticString(),
5110               HasSubstr("ID '2', member '0' decorated with MatrixStride "
5111                         "multiple times is not allowed."));
5112 }
5113 
TEST_F(ValidateDecorations,MultipleRowMajorDecorationsOnSameID)5114 TEST_F(ValidateDecorations, MultipleRowMajorDecorationsOnSameID) {
5115   std::string spirv = R"(
5116             OpCapability Shader
5117             OpMemoryModel Logical GLSL450
5118             OpEntryPoint Fragment %1 "main"
5119             OpExecutionMode %1 OriginUpperLeft
5120 
5121             OpMemberDecorate %struct 0 Offset 0
5122             OpMemberDecorate %struct 0 MatrixStride 16
5123             OpMemberDecorate %struct 0 RowMajor
5124             OpMemberDecorate %struct 0 RowMajor
5125 
5126     %void = OpTypeVoid
5127   %voidfn = OpTypeFunction %void
5128    %float = OpTypeFloat 32
5129    %fvec4 = OpTypeVector %float 4
5130    %fmat4 = OpTypeMatrix %fvec4 4
5131   %struct = OpTypeStruct %fmat4
5132 
5133        %1 = OpFunction %void None %voidfn
5134    %label = OpLabel
5135             OpReturn
5136             OpFunctionEnd
5137 )";
5138 
5139   CompileSuccessfully(spirv);
5140   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
5141   EXPECT_THAT(getDiagnosticString(),
5142               HasSubstr("ID '2', member '0' decorated with RowMajor multiple "
5143                         "times is not allowed."));
5144 }
5145 
TEST_F(ValidateDecorations,MultipleColMajorDecorationsOnSameID)5146 TEST_F(ValidateDecorations, MultipleColMajorDecorationsOnSameID) {
5147   std::string spirv = R"(
5148             OpCapability Shader
5149             OpMemoryModel Logical GLSL450
5150             OpEntryPoint Fragment %1 "main"
5151             OpExecutionMode %1 OriginUpperLeft
5152 
5153             OpMemberDecorate %struct 0 Offset 0
5154             OpMemberDecorate %struct 0 MatrixStride 16
5155             OpMemberDecorate %struct 0 ColMajor
5156             OpMemberDecorate %struct 0 ColMajor
5157 
5158     %void = OpTypeVoid
5159   %voidfn = OpTypeFunction %void
5160    %float = OpTypeFloat 32
5161    %fvec4 = OpTypeVector %float 4
5162    %fmat4 = OpTypeMatrix %fvec4 4
5163   %struct = OpTypeStruct %fmat4
5164 
5165        %1 = OpFunction %void None %voidfn
5166    %label = OpLabel
5167             OpReturn
5168             OpFunctionEnd
5169 )";
5170 
5171   CompileSuccessfully(spirv);
5172   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
5173   EXPECT_THAT(getDiagnosticString(),
5174               HasSubstr("ID '2', member '0' decorated with ColMajor multiple "
5175                         "times is not allowed."));
5176 }
5177 
TEST_F(ValidateDecorations,RowMajorAndColMajorDecorationsOnSameID)5178 TEST_F(ValidateDecorations, RowMajorAndColMajorDecorationsOnSameID) {
5179   std::string spirv = R"(
5180             OpCapability Shader
5181             OpMemoryModel Logical GLSL450
5182             OpEntryPoint Fragment %1 "main"
5183             OpExecutionMode %1 OriginUpperLeft
5184 
5185             OpMemberDecorate %struct 0 Offset 0
5186             OpMemberDecorate %struct 0 MatrixStride 16
5187             OpMemberDecorate %struct 0 ColMajor
5188             OpMemberDecorate %struct 0 RowMajor
5189 
5190     %void = OpTypeVoid
5191   %voidfn = OpTypeFunction %void
5192    %float = OpTypeFloat 32
5193    %fvec4 = OpTypeVector %float 4
5194    %fmat4 = OpTypeMatrix %fvec4 4
5195   %struct = OpTypeStruct %fmat4
5196 
5197        %1 = OpFunction %void None %voidfn
5198    %label = OpLabel
5199             OpReturn
5200             OpFunctionEnd
5201 )";
5202 
5203   CompileSuccessfully(spirv);
5204   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
5205   EXPECT_THAT(getDiagnosticString(),
5206               HasSubstr("ID '2', member '0' decorated with both RowMajor and "
5207                         "ColMajor is not allowed."));
5208 }
5209 
TEST_F(ValidateDecorations,BlockAndBufferBlockDecorationsOnSameID)5210 TEST_F(ValidateDecorations, BlockAndBufferBlockDecorationsOnSameID) {
5211   std::string spirv = R"(
5212             OpCapability Shader
5213             OpMemoryModel Logical GLSL450
5214             OpEntryPoint Fragment %1 "main"
5215             OpExecutionMode %1 OriginUpperLeft
5216 
5217             OpDecorate %struct Block
5218             OpDecorate %struct BufferBlock
5219             OpMemberDecorate %struct 0 Offset 0
5220             OpMemberDecorate %struct 0 MatrixStride 16
5221             OpMemberDecorate %struct 0 RowMajor
5222 
5223     %void = OpTypeVoid
5224   %voidfn = OpTypeFunction %void
5225    %float = OpTypeFloat 32
5226    %fvec4 = OpTypeVector %float 4
5227    %fmat4 = OpTypeMatrix %fvec4 4
5228   %struct = OpTypeStruct %fmat4
5229 
5230        %1 = OpFunction %void None %voidfn
5231    %label = OpLabel
5232             OpReturn
5233             OpFunctionEnd
5234 )";
5235 
5236   CompileSuccessfully(spirv);
5237   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
5238   EXPECT_THAT(
5239       getDiagnosticString(),
5240       HasSubstr(
5241           "ID '2' decorated with both BufferBlock and Block is not allowed."));
5242 }
5243 
MakeIntegerShader(const std::string & decoration,const std::string & inst,const std::string & extension="OpExtension \\"SPV_KHR_no_integer_wrap_decoration\\"")5244 std::string MakeIntegerShader(
5245     const std::string& decoration, const std::string& inst,
5246     const std::string& extension =
5247         "OpExtension \"SPV_KHR_no_integer_wrap_decoration\"") {
5248   return R"(
5249 OpCapability Shader
5250 OpCapability Linkage
5251 )" + extension +
5252          R"(
5253 %glsl = OpExtInstImport "GLSL.std.450"
5254 %opencl = OpExtInstImport "OpenCL.std"
5255 OpMemoryModel Logical GLSL450
5256 OpEntryPoint GLCompute %main "main"
5257 OpName %entry "entry"
5258 )" + decoration +
5259          R"(
5260     %void = OpTypeVoid
5261   %voidfn = OpTypeFunction %void
5262      %int = OpTypeInt 32 1
5263     %zero = OpConstantNull %int
5264    %float = OpTypeFloat 32
5265   %float0 = OpConstantNull %float
5266     %main = OpFunction %void None %voidfn
5267    %entry = OpLabel
5268 )" + inst +
5269          R"(
5270 OpReturn
5271 OpFunctionEnd)";
5272 }
5273 
5274 // NoSignedWrap
5275 
TEST_F(ValidateDecorations,NoSignedWrapOnTypeBad)5276 TEST_F(ValidateDecorations, NoSignedWrapOnTypeBad) {
5277   std::string spirv = MakeIntegerShader("OpDecorate %void NoSignedWrap", "");
5278 
5279   CompileSuccessfully(spirv);
5280   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
5281   EXPECT_THAT(
5282       getDiagnosticString(),
5283       HasSubstr("NoSignedWrap decoration may not be applied to TypeVoid"));
5284 }
5285 
TEST_F(ValidateDecorations,NoSignedWrapOnLabelBad)5286 TEST_F(ValidateDecorations, NoSignedWrapOnLabelBad) {
5287   std::string spirv = MakeIntegerShader("OpDecorate %entry NoSignedWrap", "");
5288 
5289   CompileSuccessfully(spirv);
5290   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
5291   EXPECT_THAT(getDiagnosticString(),
5292               HasSubstr("NoSignedWrap decoration may not be applied to Label"));
5293 }
5294 
TEST_F(ValidateDecorations,NoSignedWrapRequiresExtensionBad)5295 TEST_F(ValidateDecorations, NoSignedWrapRequiresExtensionBad) {
5296   std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap",
5297                                         "%val = OpIAdd %int %zero %zero", "");
5298 
5299   CompileSuccessfully(spirv);
5300   EXPECT_NE(SPV_SUCCESS, ValidateInstructions());
5301   EXPECT_THAT(getDiagnosticString(),
5302               HasSubstr("requires one of these extensions: "
5303                         "SPV_KHR_no_integer_wrap_decoration"));
5304 }
5305 
TEST_F(ValidateDecorations,NoSignedWrapRequiresExtensionV13Bad)5306 TEST_F(ValidateDecorations, NoSignedWrapRequiresExtensionV13Bad) {
5307   std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap",
5308                                         "%val = OpIAdd %int %zero %zero", "");
5309 
5310   CompileSuccessfully(spirv);
5311   EXPECT_NE(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
5312   EXPECT_THAT(getDiagnosticString(),
5313               HasSubstr("requires one of these extensions: "
5314                         "SPV_KHR_no_integer_wrap_decoration"));
5315 }
5316 
TEST_F(ValidateDecorations,NoSignedWrapOkInSPV14Good)5317 TEST_F(ValidateDecorations, NoSignedWrapOkInSPV14Good) {
5318   std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap",
5319                                         "%val = OpIAdd %int %zero %zero", "");
5320 
5321   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
5322   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
5323   EXPECT_THAT(getDiagnosticString(), Eq(""));
5324 }
5325 
TEST_F(ValidateDecorations,NoSignedWrapIAddGood)5326 TEST_F(ValidateDecorations, NoSignedWrapIAddGood) {
5327   std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap",
5328                                         "%val = OpIAdd %int %zero %zero");
5329 
5330   CompileSuccessfully(spirv);
5331   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
5332   EXPECT_THAT(getDiagnosticString(), Eq(""));
5333 }
5334 
TEST_F(ValidateDecorations,NoSignedWrapISubGood)5335 TEST_F(ValidateDecorations, NoSignedWrapISubGood) {
5336   std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap",
5337                                         "%val = OpISub %int %zero %zero");
5338 
5339   CompileSuccessfully(spirv);
5340   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
5341   EXPECT_THAT(getDiagnosticString(), Eq(""));
5342 }
5343 
TEST_F(ValidateDecorations,NoSignedWrapIMulGood)5344 TEST_F(ValidateDecorations, NoSignedWrapIMulGood) {
5345   std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap",
5346                                         "%val = OpIMul %int %zero %zero");
5347 
5348   CompileSuccessfully(spirv);
5349   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
5350   EXPECT_THAT(getDiagnosticString(), Eq(""));
5351 }
5352 
TEST_F(ValidateDecorations,NoSignedWrapShiftLeftLogicalGood)5353 TEST_F(ValidateDecorations, NoSignedWrapShiftLeftLogicalGood) {
5354   std::string spirv =
5355       MakeIntegerShader("OpDecorate %val NoSignedWrap",
5356                         "%val = OpShiftLeftLogical %int %zero %zero");
5357 
5358   CompileSuccessfully(spirv);
5359   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
5360   EXPECT_THAT(getDiagnosticString(), Eq(""));
5361 }
5362 
TEST_F(ValidateDecorations,NoSignedWrapSNegateGood)5363 TEST_F(ValidateDecorations, NoSignedWrapSNegateGood) {
5364   std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap",
5365                                         "%val = OpSNegate %int %zero");
5366 
5367   CompileSuccessfully(spirv);
5368   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
5369   EXPECT_THAT(getDiagnosticString(), Eq(""));
5370 }
5371 
TEST_F(ValidateDecorations,NoSignedWrapSRemBad)5372 TEST_F(ValidateDecorations, NoSignedWrapSRemBad) {
5373   std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap",
5374                                         "%val = OpSRem %int %zero %zero");
5375 
5376   CompileSuccessfully(spirv);
5377   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
5378   EXPECT_THAT(getDiagnosticString(),
5379               HasSubstr("NoSignedWrap decoration may not be applied to SRem"));
5380 }
5381 
TEST_F(ValidateDecorations,NoSignedWrapFAddBad)5382 TEST_F(ValidateDecorations, NoSignedWrapFAddBad) {
5383   std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap",
5384                                         "%val = OpFAdd %float %float0 %float0");
5385 
5386   CompileSuccessfully(spirv);
5387   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
5388   EXPECT_THAT(getDiagnosticString(),
5389               HasSubstr("NoSignedWrap decoration may not be applied to FAdd"));
5390 }
5391 
TEST_F(ValidateDecorations,NoSignedWrapExtInstOpenCLGood)5392 TEST_F(ValidateDecorations, NoSignedWrapExtInstOpenCLGood) {
5393   std::string spirv =
5394       MakeIntegerShader("OpDecorate %val NoSignedWrap",
5395                         "%val = OpExtInst %int %opencl s_abs %zero");
5396 
5397   CompileSuccessfully(spirv);
5398   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
5399   EXPECT_THAT(getDiagnosticString(), Eq(""));
5400 }
5401 
TEST_F(ValidateDecorations,NoSignedWrapExtInstGLSLGood)5402 TEST_F(ValidateDecorations, NoSignedWrapExtInstGLSLGood) {
5403   std::string spirv = MakeIntegerShader(
5404       "OpDecorate %val NoSignedWrap", "%val = OpExtInst %int %glsl SAbs %zero");
5405 
5406   CompileSuccessfully(spirv);
5407   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
5408   EXPECT_THAT(getDiagnosticString(), Eq(""));
5409 }
5410 
5411 // TODO(dneto): For NoSignedWrap and NoUnsignedWrap, permit
5412 // "OpExtInst for instruction numbers specified in the extended
5413 // instruction-set specifications as accepting this decoration."
5414 
5415 // NoUnignedWrap
5416 
TEST_F(ValidateDecorations,NoUnsignedWrapOnTypeBad)5417 TEST_F(ValidateDecorations, NoUnsignedWrapOnTypeBad) {
5418   std::string spirv = MakeIntegerShader("OpDecorate %void NoUnsignedWrap", "");
5419 
5420   CompileSuccessfully(spirv);
5421   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
5422   EXPECT_THAT(
5423       getDiagnosticString(),
5424       HasSubstr("NoUnsignedWrap decoration may not be applied to TypeVoid"));
5425 }
5426 
TEST_F(ValidateDecorations,NoUnsignedWrapOnLabelBad)5427 TEST_F(ValidateDecorations, NoUnsignedWrapOnLabelBad) {
5428   std::string spirv = MakeIntegerShader("OpDecorate %entry NoUnsignedWrap", "");
5429 
5430   CompileSuccessfully(spirv);
5431   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
5432   EXPECT_THAT(
5433       getDiagnosticString(),
5434       HasSubstr("NoUnsignedWrap decoration may not be applied to Label"));
5435 }
5436 
TEST_F(ValidateDecorations,NoUnsignedWrapRequiresExtensionBad)5437 TEST_F(ValidateDecorations, NoUnsignedWrapRequiresExtensionBad) {
5438   std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
5439                                         "%val = OpIAdd %int %zero %zero", "");
5440 
5441   CompileSuccessfully(spirv);
5442   EXPECT_NE(SPV_SUCCESS, ValidateInstructions());
5443   EXPECT_THAT(getDiagnosticString(),
5444               HasSubstr("requires one of these extensions: "
5445                         "SPV_KHR_no_integer_wrap_decoration"));
5446 }
5447 
TEST_F(ValidateDecorations,NoUnsignedWrapRequiresExtensionV13Bad)5448 TEST_F(ValidateDecorations, NoUnsignedWrapRequiresExtensionV13Bad) {
5449   std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
5450                                         "%val = OpIAdd %int %zero %zero", "");
5451 
5452   CompileSuccessfully(spirv);
5453   EXPECT_NE(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
5454   EXPECT_THAT(getDiagnosticString(),
5455               HasSubstr("requires one of these extensions: "
5456                         "SPV_KHR_no_integer_wrap_decoration"));
5457 }
5458 
TEST_F(ValidateDecorations,NoUnsignedWrapOkInSPV14Good)5459 TEST_F(ValidateDecorations, NoUnsignedWrapOkInSPV14Good) {
5460   std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
5461                                         "%val = OpIAdd %int %zero %zero", "");
5462 
5463   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
5464   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
5465   EXPECT_THAT(getDiagnosticString(), Eq(""));
5466 }
5467 
TEST_F(ValidateDecorations,NoUnsignedWrapIAddGood)5468 TEST_F(ValidateDecorations, NoUnsignedWrapIAddGood) {
5469   std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
5470                                         "%val = OpIAdd %int %zero %zero");
5471 
5472   CompileSuccessfully(spirv);
5473   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
5474   EXPECT_THAT(getDiagnosticString(), Eq(""));
5475 }
5476 
TEST_F(ValidateDecorations,NoUnsignedWrapISubGood)5477 TEST_F(ValidateDecorations, NoUnsignedWrapISubGood) {
5478   std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
5479                                         "%val = OpISub %int %zero %zero");
5480 
5481   CompileSuccessfully(spirv);
5482   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
5483   EXPECT_THAT(getDiagnosticString(), Eq(""));
5484 }
5485 
TEST_F(ValidateDecorations,NoUnsignedWrapIMulGood)5486 TEST_F(ValidateDecorations, NoUnsignedWrapIMulGood) {
5487   std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
5488                                         "%val = OpIMul %int %zero %zero");
5489 
5490   CompileSuccessfully(spirv);
5491   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
5492   EXPECT_THAT(getDiagnosticString(), Eq(""));
5493 }
5494 
TEST_F(ValidateDecorations,NoUnsignedWrapShiftLeftLogicalGood)5495 TEST_F(ValidateDecorations, NoUnsignedWrapShiftLeftLogicalGood) {
5496   std::string spirv =
5497       MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
5498                         "%val = OpShiftLeftLogical %int %zero %zero");
5499 
5500   CompileSuccessfully(spirv);
5501   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
5502   EXPECT_THAT(getDiagnosticString(), Eq(""));
5503 }
5504 
TEST_F(ValidateDecorations,NoUnsignedWrapSNegateGood)5505 TEST_F(ValidateDecorations, NoUnsignedWrapSNegateGood) {
5506   std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
5507                                         "%val = OpSNegate %int %zero");
5508 
5509   CompileSuccessfully(spirv);
5510   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
5511   EXPECT_THAT(getDiagnosticString(), Eq(""));
5512 }
5513 
TEST_F(ValidateDecorations,NoUnsignedWrapSRemBad)5514 TEST_F(ValidateDecorations, NoUnsignedWrapSRemBad) {
5515   std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
5516                                         "%val = OpSRem %int %zero %zero");
5517 
5518   CompileSuccessfully(spirv);
5519   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
5520   EXPECT_THAT(
5521       getDiagnosticString(),
5522       HasSubstr("NoUnsignedWrap decoration may not be applied to SRem"));
5523 }
5524 
TEST_F(ValidateDecorations,NoUnsignedWrapFAddBad)5525 TEST_F(ValidateDecorations, NoUnsignedWrapFAddBad) {
5526   std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
5527                                         "%val = OpFAdd %float %float0 %float0");
5528 
5529   CompileSuccessfully(spirv);
5530   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
5531   EXPECT_THAT(
5532       getDiagnosticString(),
5533       HasSubstr("NoUnsignedWrap decoration may not be applied to FAdd"));
5534 }
5535 
TEST_F(ValidateDecorations,NoUnsignedWrapExtInstOpenCLGood)5536 TEST_F(ValidateDecorations, NoUnsignedWrapExtInstOpenCLGood) {
5537   std::string spirv =
5538       MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
5539                         "%val = OpExtInst %int %opencl s_abs %zero");
5540 
5541   CompileSuccessfully(spirv);
5542   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
5543   EXPECT_THAT(getDiagnosticString(), Eq(""));
5544 }
5545 
TEST_F(ValidateDecorations,NoUnsignedWrapExtInstGLSLGood)5546 TEST_F(ValidateDecorations, NoUnsignedWrapExtInstGLSLGood) {
5547   std::string spirv =
5548       MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
5549                         "%val = OpExtInst %int %glsl SAbs %zero");
5550 
5551   CompileSuccessfully(spirv);
5552   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
5553   EXPECT_THAT(getDiagnosticString(), Eq(""));
5554 }
5555 
TEST_F(ValidateDecorations,AliasedandRestrictBad)5556 TEST_F(ValidateDecorations, AliasedandRestrictBad) {
5557   const std::string body = R"(
5558 OpCapability Shader
5559 %1 = OpExtInstImport "GLSL.std.450"
5560 OpMemoryModel Logical GLSL450
5561 OpEntryPoint GLCompute %main "main"
5562 OpExecutionMode %main LocalSize 1 1 1
5563 OpSource GLSL 430
5564 OpMemberDecorate %Output 0 Offset 0
5565 OpDecorate %Output BufferBlock
5566 OpDecorate %dataOutput Restrict
5567 OpDecorate %dataOutput Aliased
5568 %void = OpTypeVoid
5569 %3 = OpTypeFunction %void
5570 %float = OpTypeFloat 32
5571 %Output = OpTypeStruct %float
5572 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
5573 %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
5574 %main = OpFunction %void None %3
5575 %5 = OpLabel
5576 OpReturn
5577 OpFunctionEnd
5578 )";
5579 
5580   CompileSuccessfully(body.c_str());
5581   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
5582   EXPECT_THAT(
5583       getDiagnosticString(),
5584       HasSubstr("decorated with both Aliased and Restrict is not allowed"));
5585 }
5586 
5587 // TODO(dneto): For NoUnsignedWrap and NoUnsignedWrap, permit
5588 // "OpExtInst for instruction numbers specified in the extended
5589 // instruction-set specifications as accepting this decoration."
5590 
TEST_F(ValidateDecorations,PSBAliasedRestrictPointerSuccess)5591 TEST_F(ValidateDecorations, PSBAliasedRestrictPointerSuccess) {
5592   const std::string body = R"(
5593 OpCapability PhysicalStorageBufferAddressesEXT
5594 OpCapability Int64
5595 OpCapability Shader
5596 OpExtension "SPV_EXT_physical_storage_buffer"
5597 OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
5598 OpEntryPoint Fragment %main "main"
5599 OpExecutionMode %main OriginUpperLeft
5600 OpDecorate %val1 RestrictPointerEXT
5601 %uint64 = OpTypeInt 64 0
5602 %ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
5603 %pptr_f = OpTypePointer Function %ptr
5604 %void = OpTypeVoid
5605 %voidfn = OpTypeFunction %void
5606 %main = OpFunction %void None %voidfn
5607 %entry = OpLabel
5608 %val1 = OpVariable %pptr_f Function
5609 OpReturn
5610 OpFunctionEnd
5611 )";
5612 
5613   CompileSuccessfully(body.c_str());
5614   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
5615 }
5616 
TEST_F(ValidateDecorations,PSBAliasedRestrictPointerMissing)5617 TEST_F(ValidateDecorations, PSBAliasedRestrictPointerMissing) {
5618   const std::string body = R"(
5619 OpCapability PhysicalStorageBufferAddressesEXT
5620 OpCapability Int64
5621 OpCapability Shader
5622 OpExtension "SPV_EXT_physical_storage_buffer"
5623 OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
5624 OpEntryPoint Fragment %main "main"
5625 OpExecutionMode %main OriginUpperLeft
5626 %uint64 = OpTypeInt 64 0
5627 %ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
5628 %pptr_f = OpTypePointer Function %ptr
5629 %void = OpTypeVoid
5630 %voidfn = OpTypeFunction %void
5631 %main = OpFunction %void None %voidfn
5632 %entry = OpLabel
5633 %val1 = OpVariable %pptr_f Function
5634 OpReturn
5635 OpFunctionEnd
5636 )";
5637 
5638   CompileSuccessfully(body.c_str());
5639   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
5640   EXPECT_THAT(getDiagnosticString(),
5641               HasSubstr("expected AliasedPointerEXT or RestrictPointerEXT for "
5642                         "PhysicalStorageBufferEXT pointer"));
5643 }
5644 
TEST_F(ValidateDecorations,PSBAliasedRestrictPointerBoth)5645 TEST_F(ValidateDecorations, PSBAliasedRestrictPointerBoth) {
5646   const std::string body = R"(
5647 OpCapability PhysicalStorageBufferAddressesEXT
5648 OpCapability Int64
5649 OpCapability Shader
5650 OpExtension "SPV_EXT_physical_storage_buffer"
5651 OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
5652 OpEntryPoint Fragment %main "main"
5653 OpExecutionMode %main OriginUpperLeft
5654 OpDecorate %val1 RestrictPointerEXT
5655 OpDecorate %val1 AliasedPointerEXT
5656 %uint64 = OpTypeInt 64 0
5657 %ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
5658 %pptr_f = OpTypePointer Function %ptr
5659 %void = OpTypeVoid
5660 %voidfn = OpTypeFunction %void
5661 %main = OpFunction %void None %voidfn
5662 %entry = OpLabel
5663 %val1 = OpVariable %pptr_f Function
5664 OpReturn
5665 OpFunctionEnd
5666 )";
5667 
5668   CompileSuccessfully(body.c_str());
5669   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
5670   EXPECT_THAT(
5671       getDiagnosticString(),
5672       HasSubstr("can't specify both AliasedPointerEXT and RestrictPointerEXT "
5673                 "for PhysicalStorageBufferEXT pointer"));
5674 }
5675 
TEST_F(ValidateDecorations,PSBAliasedRestrictFunctionParamSuccess)5676 TEST_F(ValidateDecorations, PSBAliasedRestrictFunctionParamSuccess) {
5677   const std::string body = R"(
5678 OpCapability PhysicalStorageBufferAddressesEXT
5679 OpCapability Int64
5680 OpCapability Shader
5681 OpExtension "SPV_EXT_physical_storage_buffer"
5682 OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
5683 OpEntryPoint Fragment %main "main"
5684 OpExecutionMode %main OriginUpperLeft
5685 OpDecorate %fparam Restrict
5686 %uint64 = OpTypeInt 64 0
5687 %ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
5688 %void = OpTypeVoid
5689 %voidfn = OpTypeFunction %void
5690 %fnptr = OpTypeFunction %void %ptr
5691 %main = OpFunction %void None %voidfn
5692 %entry = OpLabel
5693 OpReturn
5694 OpFunctionEnd
5695 %fn = OpFunction %void None %fnptr
5696 %fparam = OpFunctionParameter %ptr
5697 %lab = OpLabel
5698 OpReturn
5699 OpFunctionEnd
5700 )";
5701 
5702   CompileSuccessfully(body.c_str());
5703   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
5704 }
5705 
TEST_F(ValidateDecorations,PSBAliasedRestrictFunctionParamMissing)5706 TEST_F(ValidateDecorations, PSBAliasedRestrictFunctionParamMissing) {
5707   const std::string body = R"(
5708 OpCapability PhysicalStorageBufferAddressesEXT
5709 OpCapability Int64
5710 OpCapability Shader
5711 OpExtension "SPV_EXT_physical_storage_buffer"
5712 OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
5713 OpEntryPoint Fragment %main "main"
5714 OpExecutionMode %main OriginUpperLeft
5715 %uint64 = OpTypeInt 64 0
5716 %ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
5717 %void = OpTypeVoid
5718 %voidfn = OpTypeFunction %void
5719 %fnptr = OpTypeFunction %void %ptr
5720 %main = OpFunction %void None %voidfn
5721 %entry = OpLabel
5722 OpReturn
5723 OpFunctionEnd
5724 %fn = OpFunction %void None %fnptr
5725 %fparam = OpFunctionParameter %ptr
5726 %lab = OpLabel
5727 OpReturn
5728 OpFunctionEnd
5729 )";
5730 
5731   CompileSuccessfully(body.c_str());
5732   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
5733   EXPECT_THAT(getDiagnosticString(),
5734               HasSubstr("expected Aliased or Restrict for "
5735                         "PhysicalStorageBufferEXT pointer"));
5736 }
5737 
TEST_F(ValidateDecorations,PSBAliasedRestrictFunctionParamBoth)5738 TEST_F(ValidateDecorations, PSBAliasedRestrictFunctionParamBoth) {
5739   const std::string body = R"(
5740 OpCapability PhysicalStorageBufferAddressesEXT
5741 OpCapability Int64
5742 OpCapability Shader
5743 OpExtension "SPV_EXT_physical_storage_buffer"
5744 OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
5745 OpEntryPoint Fragment %main "main"
5746 OpExecutionMode %main OriginUpperLeft
5747 OpDecorate %fparam Restrict
5748 OpDecorate %fparam Aliased
5749 %uint64 = OpTypeInt 64 0
5750 %ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
5751 %void = OpTypeVoid
5752 %voidfn = OpTypeFunction %void
5753 %fnptr = OpTypeFunction %void %ptr
5754 %main = OpFunction %void None %voidfn
5755 %entry = OpLabel
5756 OpReturn
5757 OpFunctionEnd
5758 %fn = OpFunction %void None %fnptr
5759 %fparam = OpFunctionParameter %ptr
5760 %lab = OpLabel
5761 OpReturn
5762 OpFunctionEnd
5763 )";
5764 
5765   CompileSuccessfully(body.c_str());
5766   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
5767   EXPECT_THAT(getDiagnosticString(),
5768               HasSubstr("can't specify both Aliased and Restrict for "
5769                         "PhysicalStorageBufferEXT pointer"));
5770 }
5771 
TEST_F(ValidateDecorations,PSBFPRoundingModeSuccess)5772 TEST_F(ValidateDecorations, PSBFPRoundingModeSuccess) {
5773   std::string spirv = R"(
5774 OpCapability PhysicalStorageBufferAddressesEXT
5775 OpCapability Shader
5776 OpCapability Linkage
5777 OpCapability StorageBuffer16BitAccess
5778 OpExtension "SPV_EXT_physical_storage_buffer"
5779 OpExtension "SPV_KHR_storage_buffer_storage_class"
5780 OpExtension "SPV_KHR_variable_pointers"
5781 OpExtension "SPV_KHR_16bit_storage"
5782 OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
5783 OpEntryPoint GLCompute %main "main"
5784 OpDecorate %_ FPRoundingMode RTE
5785 OpDecorate %half_ptr_var AliasedPointerEXT
5786 %half = OpTypeFloat 16
5787 %float = OpTypeFloat 32
5788 %float_1_25 = OpConstant %float 1.25
5789 %half_ptr = OpTypePointer PhysicalStorageBufferEXT %half
5790 %half_pptr_f = OpTypePointer Function %half_ptr
5791 %void = OpTypeVoid
5792 %func = OpTypeFunction %void
5793 %main = OpFunction %void None %func
5794 %main_entry = OpLabel
5795 %half_ptr_var = OpVariable %half_pptr_f Function
5796 %val1 = OpLoad %half_ptr %half_ptr_var
5797 %_ = OpFConvert %half %float_1_25
5798 OpStore %val1 %_ Aligned 2
5799 OpReturn
5800 OpFunctionEnd
5801   )";
5802 
5803   CompileSuccessfully(spirv);
5804   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
5805 }
5806 
TEST_F(ValidateDecorations,InvalidStraddle)5807 TEST_F(ValidateDecorations, InvalidStraddle) {
5808   const std::string spirv = R"(
5809 OpCapability Shader
5810 OpMemoryModel Logical GLSL450
5811 OpEntryPoint GLCompute %main "main"
5812 OpExecutionMode %main LocalSize 1 1 1
5813 OpMemberDecorate %inner_struct 0 Offset 0
5814 OpMemberDecorate %inner_struct 1 Offset 4
5815 OpDecorate %outer_struct Block
5816 OpMemberDecorate %outer_struct 0 Offset 0
5817 OpMemberDecorate %outer_struct 1 Offset 8
5818 OpDecorate %var DescriptorSet 0
5819 OpDecorate %var Binding 0
5820 %void = OpTypeVoid
5821 %float = OpTypeFloat 32
5822 %float2 = OpTypeVector %float 2
5823 %inner_struct = OpTypeStruct %float %float2
5824 %outer_struct = OpTypeStruct %float2 %inner_struct
5825 %ptr_ssbo_outer = OpTypePointer StorageBuffer %outer_struct
5826 %var = OpVariable %ptr_ssbo_outer StorageBuffer
5827 %void_fn = OpTypeFunction %void
5828 %main = OpFunction %void None %void_fn
5829 %entry = OpLabel
5830 OpReturn
5831 OpFunctionEnd
5832 )";
5833 
5834   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
5835   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
5836   EXPECT_THAT(getDiagnosticString(),
5837               HasSubstr("Structure id 2 decorated as Block for variable in "
5838                         "StorageBuffer storage class must follow relaxed "
5839                         "storage buffer layout rules: member 1 is an "
5840                         "improperly straddling vector at offset 12"));
5841 }
5842 
TEST_F(ValidateDecorations,DescriptorArray)5843 TEST_F(ValidateDecorations, DescriptorArray) {
5844   const std::string spirv = R"(
5845 OpCapability Shader
5846 OpExtension "SPV_KHR_storage_buffer_storage_class"
5847 OpMemoryModel Logical GLSL450
5848 OpEntryPoint GLCompute %main "main"
5849 OpExecutionMode %main LocalSize 1 1 1
5850 OpDecorate %struct Block
5851 OpMemberDecorate %struct 0 Offset 0
5852 OpMemberDecorate %struct 1 Offset 1
5853 OpDecorate %var DescriptorSet 0
5854 OpDecorate %var Binding 0
5855 %void = OpTypeVoid
5856 %float = OpTypeFloat 32
5857 %int = OpTypeInt 32 0
5858 %int_2 = OpConstant %int 2
5859 %float2 = OpTypeVector %float 2
5860 %struct = OpTypeStruct %float %float2
5861 %struct_array = OpTypeArray %struct %int_2
5862 %ptr_ssbo_array = OpTypePointer StorageBuffer %struct_array
5863 %var = OpVariable %ptr_ssbo_array StorageBuffer
5864 %void_fn = OpTypeFunction %void
5865 %main = OpFunction %void None %void_fn
5866 %entry = OpLabel
5867 OpReturn
5868 OpFunctionEnd
5869 )";
5870 
5871   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0);
5872   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
5873   EXPECT_THAT(getDiagnosticString(),
5874               HasSubstr("Structure id 2 decorated as Block for variable in "
5875                         "StorageBuffer storage class must follow standard "
5876                         "storage buffer layout rules: member 1 at offset 1 is "
5877                         "not aligned to 8"));
5878 }
5879 
TEST_F(ValidateDecorations,DescriptorRuntimeArray)5880 TEST_F(ValidateDecorations, DescriptorRuntimeArray) {
5881   const std::string spirv = R"(
5882 OpCapability Shader
5883 OpCapability RuntimeDescriptorArrayEXT
5884 OpExtension "SPV_KHR_storage_buffer_storage_class"
5885 OpExtension "SPV_EXT_descriptor_indexing"
5886 OpMemoryModel Logical GLSL450
5887 OpEntryPoint GLCompute %main "main"
5888 OpExecutionMode %main LocalSize 1 1 1
5889 OpDecorate %struct Block
5890 OpMemberDecorate %struct 0 Offset 0
5891 OpMemberDecorate %struct 1 Offset 1
5892 OpDecorate %var DescriptorSet 0
5893 OpDecorate %var Binding 0
5894 %void = OpTypeVoid
5895 %float = OpTypeFloat 32
5896 %int = OpTypeInt 32 0
5897 %float2 = OpTypeVector %float 2
5898 %struct = OpTypeStruct %float %float2
5899 %struct_array = OpTypeRuntimeArray %struct
5900 %ptr_ssbo_array = OpTypePointer StorageBuffer %struct_array
5901 %var = OpVariable %ptr_ssbo_array StorageBuffer
5902 %void_fn = OpTypeFunction %void
5903 %main = OpFunction %void None %void_fn
5904 %entry = OpLabel
5905 OpReturn
5906 OpFunctionEnd
5907 )";
5908 
5909   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0);
5910   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
5911   EXPECT_THAT(getDiagnosticString(),
5912               HasSubstr("Structure id 2 decorated as Block for variable in "
5913                         "StorageBuffer storage class must follow standard "
5914                         "storage buffer layout rules: member 1 at offset 1 is "
5915                         "not aligned to 8"));
5916 }
5917 
TEST_F(ValidateDecorations,MultiDimensionalArray)5918 TEST_F(ValidateDecorations, MultiDimensionalArray) {
5919   const std::string spirv = R"(
5920 OpCapability Shader
5921 OpMemoryModel Logical GLSL450
5922 OpEntryPoint GLCompute %main "main"
5923 OpExecutionMode %main LocalSize 1 1 1
5924 OpDecorate %struct Block
5925 OpMemberDecorate %struct 0 Offset 0
5926 OpDecorate %array_4 ArrayStride 4
5927 OpDecorate %array_3 ArrayStride 48
5928 OpDecorate %var DescriptorSet 0
5929 OpDecorate %var Binding 0
5930 %void = OpTypeVoid
5931 %int = OpTypeInt 32 0
5932 %int_3 = OpConstant %int 3
5933 %int_4 = OpConstant %int 4
5934 %array_4 = OpTypeArray %int %int_4
5935 %array_3 = OpTypeArray %array_4 %int_3
5936 %struct = OpTypeStruct %array_3
5937 %ptr_struct = OpTypePointer Uniform %struct
5938 %var = OpVariable %ptr_struct Uniform
5939 %void_fn = OpTypeFunction %void
5940 %main = OpFunction %void None %void_fn
5941 %entry = OpLabel
5942 OpReturn
5943 OpFunctionEnd
5944 )";
5945 
5946   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0);
5947   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
5948   EXPECT_THAT(getDiagnosticString(),
5949               HasSubstr("Structure id 2 decorated as Block for variable in "
5950                         "Uniform storage class must follow standard uniform "
5951                         "buffer layout rules: member 0 contains an array with "
5952                         "stride 4 not satisfying alignment to 16"));
5953 }
5954 
TEST_F(ValidateDecorations,ImproperStraddleInArray)5955 TEST_F(ValidateDecorations, ImproperStraddleInArray) {
5956   const std::string spirv = R"(
5957 OpCapability Shader
5958 OpMemoryModel Logical GLSL450
5959 OpEntryPoint GLCompute %main "main"
5960 OpExecutionMode %main LocalSize 1 1 1
5961 OpDecorate %struct Block
5962 OpMemberDecorate %struct 0 Offset 0
5963 OpDecorate %array ArrayStride 24
5964 OpMemberDecorate %inner 0 Offset 0
5965 OpMemberDecorate %inner 1 Offset 4
5966 OpMemberDecorate %inner 2 Offset 12
5967 OpMemberDecorate %inner 3 Offset 16
5968 OpDecorate %var DescriptorSet 0
5969 OpDecorate %var Binding 0
5970 %void = OpTypeVoid
5971 %int = OpTypeInt 32 0
5972 %int_2 = OpConstant %int 2
5973 %int2 = OpTypeVector %int 2
5974 %inner = OpTypeStruct %int %int2 %int %int
5975 %array = OpTypeArray %inner %int_2
5976 %struct = OpTypeStruct %array
5977 %ptr_struct = OpTypePointer StorageBuffer %struct
5978 %var = OpVariable %ptr_struct StorageBuffer
5979 %void_fn = OpTypeFunction %void
5980 %main = OpFunction %void None %void_fn
5981 %entry = OpLabel
5982 OpReturn
5983 OpFunctionEnd
5984 )";
5985 
5986   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
5987   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
5988   EXPECT_THAT(getDiagnosticString(),
5989               HasSubstr("Structure id 4 decorated as Block for variable in "
5990                         "StorageBuffer storage class must follow relaxed "
5991                         "storage buffer layout rules: member 1 is an "
5992                         "improperly straddling vector at offset 28"));
5993 }
5994 
TEST_F(ValidateDecorations,LargeArray)5995 TEST_F(ValidateDecorations, LargeArray) {
5996   const std::string spirv = R"(
5997 OpCapability Shader
5998 OpMemoryModel Logical GLSL450
5999 OpEntryPoint GLCompute %main "main"
6000 OpExecutionMode %main LocalSize 1 1 1
6001 OpDecorate %struct Block
6002 OpMemberDecorate %struct 0 Offset 0
6003 OpDecorate %array ArrayStride 24
6004 OpMemberDecorate %inner 0 Offset 0
6005 OpMemberDecorate %inner 1 Offset 8
6006 OpMemberDecorate %inner 2 Offset 16
6007 OpMemberDecorate %inner 3 Offset 20
6008 OpDecorate %var DescriptorSet 0
6009 OpDecorate %var Binding 0
6010 %void = OpTypeVoid
6011 %int = OpTypeInt 32 0
6012 %int_2000000 = OpConstant %int 2000000
6013 %int2 = OpTypeVector %int 2
6014 %inner = OpTypeStruct %int %int2 %int %int
6015 %array = OpTypeArray %inner %int_2000000
6016 %struct = OpTypeStruct %array
6017 %ptr_struct = OpTypePointer StorageBuffer %struct
6018 %var = OpVariable %ptr_struct StorageBuffer
6019 %void_fn = OpTypeFunction %void
6020 %main = OpFunction %void None %void_fn
6021 %entry = OpLabel
6022 OpReturn
6023 OpFunctionEnd
6024 )";
6025 
6026   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
6027   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
6028 }
6029 
6030 // NonWritable
6031 
6032 // Returns a SPIR-V shader module with variables in various storage classes,
6033 // parameterizable by which ID should be decorated as NonWritable.
ShaderWithNonWritableTarget(const std::string & target,bool member_decorate=false)6034 std::string ShaderWithNonWritableTarget(const std::string& target,
6035                                         bool member_decorate = false) {
6036   const std::string decoration_inst =
6037       std::string(member_decorate ? "OpMemberDecorate " : "OpDecorate ") +
6038       target + (member_decorate ? " 0" : "");
6039 
6040   return std::string(R"(
6041             OpCapability Shader
6042             OpCapability RuntimeDescriptorArrayEXT
6043             OpExtension "SPV_EXT_descriptor_indexing"
6044             OpExtension "SPV_KHR_storage_buffer_storage_class"
6045             OpMemoryModel Logical GLSL450
6046             OpEntryPoint Vertex %main "main"
6047             OpName %label "label"
6048             OpName %param_f "param_f"
6049             OpName %param_p "param_p"
6050             OpName %_ptr_imstor "_ptr_imstor"
6051             OpName %_ptr_imsam "_ptr_imsam"
6052             OpName %var_wg "var_wg"
6053             OpName %var_imsam "var_imsam"
6054             OpName %var_priv "var_priv"
6055             OpName %var_func "var_func"
6056             OpName %simple_struct "simple_struct"
6057 
6058             OpDecorate %struct_b Block
6059             OpDecorate %struct_b_rtarr Block
6060             OpMemberDecorate %struct_b 0 Offset 0
6061             OpMemberDecorate %struct_b_rtarr 0 Offset 0
6062             OpDecorate %rtarr ArrayStride 4
6063 )") + decoration_inst +
6064 
6065          R"( NonWritable
6066 
6067       %void = OpTypeVoid
6068    %void_fn = OpTypeFunction %void
6069      %float = OpTypeFloat 32
6070    %float_0 = OpConstant %float 0
6071    %int     = OpTypeInt 32 0
6072    %int_2   = OpConstant %int 2
6073   %struct_b = OpTypeStruct %float
6074  %rtarr = OpTypeRuntimeArray %float
6075 %struct_b_rtarr = OpTypeStruct %rtarr
6076 %simple_struct = OpTypeStruct %float
6077  ; storage image
6078  %imstor = OpTypeImage %float 2D 0 0 0 2 R32f
6079  ; sampled image
6080  %imsam = OpTypeImage %float 2D 0 0 0 1 R32f
6081 %array_imstor = OpTypeArray %imstor %int_2
6082 %rta_imstor = OpTypeRuntimeArray %imstor
6083 
6084 %_ptr_Uniform_stb        = OpTypePointer Uniform %struct_b
6085 %_ptr_StorageBuffer_stb  = OpTypePointer StorageBuffer %struct_b
6086 %_ptr_StorageBuffer_stb_rtarr  = OpTypePointer StorageBuffer %struct_b_rtarr
6087 %_ptr_Workgroup          = OpTypePointer Workgroup %float
6088 %_ptr_Private            = OpTypePointer Private %float
6089 %_ptr_Function           = OpTypePointer Function %float
6090 %_ptr_imstor             = OpTypePointer UniformConstant %imstor
6091 %_ptr_imsam              = OpTypePointer UniformConstant %imsam
6092 %_ptr_array_imstor       = OpTypePointer UniformConstant %array_imstor
6093 %_ptr_rta_imstor         = OpTypePointer UniformConstant %rta_imstor
6094 
6095 %extra_fn = OpTypeFunction %void %float %_ptr_Private %_ptr_imstor
6096 
6097 %var_ubo = OpVariable %_ptr_Uniform_stb Uniform
6098 %var_ssbo_sb = OpVariable %_ptr_StorageBuffer_stb StorageBuffer
6099 %var_ssbo_sb_rtarr = OpVariable %_ptr_StorageBuffer_stb_rtarr StorageBuffer
6100 %var_wg = OpVariable %_ptr_Workgroup Workgroup
6101 %var_priv = OpVariable %_ptr_Private Private
6102 %var_imstor = OpVariable %_ptr_imstor UniformConstant
6103 %var_imsam = OpVariable %_ptr_imsam UniformConstant
6104 %var_array_imstor = OpVariable %_ptr_array_imstor UniformConstant
6105 %var_rta_imstor = OpVariable %_ptr_rta_imstor UniformConstant
6106 
6107   %helper = OpFunction %void None %extra_fn
6108  %param_f = OpFunctionParameter %float
6109  %param_p = OpFunctionParameter %_ptr_Private
6110  %param_pimstor = OpFunctionParameter %_ptr_imstor
6111 %helper_label = OpLabel
6112 %helper_func_var = OpVariable %_ptr_Function Function
6113             OpReturn
6114             OpFunctionEnd
6115 
6116     %main = OpFunction %void None %void_fn
6117    %label = OpLabel
6118 %var_func = OpVariable %_ptr_Function Function
6119             OpReturn
6120             OpFunctionEnd
6121 )";
6122 }
6123 
TEST_F(ValidateDecorations,NonWritableLabelTargetBad)6124 TEST_F(ValidateDecorations, NonWritableLabelTargetBad) {
6125   std::string spirv = ShaderWithNonWritableTarget("%label");
6126 
6127   CompileSuccessfully(spirv);
6128   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
6129   EXPECT_THAT(getDiagnosticString(),
6130               HasSubstr("Target of NonWritable decoration must be a "
6131                         "memory object declaration (a variable or a function "
6132                         "parameter)\n  %label = OpLabel"));
6133 }
6134 
TEST_F(ValidateDecorations,NonWritableTypeTargetBad)6135 TEST_F(ValidateDecorations, NonWritableTypeTargetBad) {
6136   std::string spirv = ShaderWithNonWritableTarget("%void");
6137 
6138   CompileSuccessfully(spirv);
6139   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
6140   EXPECT_THAT(getDiagnosticString(),
6141               HasSubstr("Target of NonWritable decoration must be a "
6142                         "memory object declaration (a variable or a function "
6143                         "parameter)\n  %void = OpTypeVoid"));
6144 }
6145 
TEST_F(ValidateDecorations,NonWritableValueTargetBad)6146 TEST_F(ValidateDecorations, NonWritableValueTargetBad) {
6147   std::string spirv = ShaderWithNonWritableTarget("%float_0");
6148 
6149   CompileSuccessfully(spirv);
6150   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
6151   EXPECT_THAT(getDiagnosticString(),
6152               HasSubstr("Target of NonWritable decoration must be a "
6153                         "memory object declaration (a variable or a function "
6154                         "parameter)\n  %float_0 = OpConstant %float 0"));
6155 }
6156 
TEST_F(ValidateDecorations,NonWritableValueParamBad)6157 TEST_F(ValidateDecorations, NonWritableValueParamBad) {
6158   std::string spirv = ShaderWithNonWritableTarget("%param_f");
6159 
6160   CompileSuccessfully(spirv);
6161   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
6162   EXPECT_THAT(getDiagnosticString(),
6163               HasSubstr("Target of NonWritable decoration is invalid: must "
6164                         "point to a storage image, uniform block, or storage "
6165                         "buffer\n  %param_f = OpFunctionParameter %float"));
6166 }
6167 
TEST_F(ValidateDecorations,NonWritablePointerParamButWrongTypeBad)6168 TEST_F(ValidateDecorations, NonWritablePointerParamButWrongTypeBad) {
6169   std::string spirv = ShaderWithNonWritableTarget("%param_p");
6170 
6171   CompileSuccessfully(spirv);
6172   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
6173   EXPECT_THAT(
6174       getDiagnosticString(),
6175       HasSubstr(
6176           "Target of NonWritable decoration is invalid: must "
6177           "point to a storage image, uniform block, or storage "
6178           "buffer\n  %param_p = OpFunctionParameter %_ptr_Private_float"));
6179 }
6180 
TEST_F(ValidateDecorations,NonWritablePointerParamStorageImageGood)6181 TEST_F(ValidateDecorations, NonWritablePointerParamStorageImageGood) {
6182   std::string spirv = ShaderWithNonWritableTarget("%param_pimstor");
6183 
6184   CompileSuccessfully(spirv);
6185   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
6186   EXPECT_THAT(getDiagnosticString(), Eq(""));
6187 }
6188 
TEST_F(ValidateDecorations,NonWritableVarStorageImageGood)6189 TEST_F(ValidateDecorations, NonWritableVarStorageImageGood) {
6190   std::string spirv = ShaderWithNonWritableTarget("%var_imstor");
6191 
6192   CompileSuccessfully(spirv);
6193   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
6194   EXPECT_THAT(getDiagnosticString(), Eq(""));
6195 }
6196 
TEST_F(ValidateDecorations,NonWritableVarSampledImageBad)6197 TEST_F(ValidateDecorations, NonWritableVarSampledImageBad) {
6198   std::string spirv = ShaderWithNonWritableTarget("%var_imsam");
6199 
6200   CompileSuccessfully(spirv);
6201   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
6202   EXPECT_THAT(getDiagnosticString(),
6203               HasSubstr("Target of NonWritable decoration is invalid: must "
6204                         "point to a storage image, uniform block, or storage "
6205                         "buffer\n  %var_imsam"));
6206 }
6207 
TEST_F(ValidateDecorations,NonWritableVarUboGood)6208 TEST_F(ValidateDecorations, NonWritableVarUboGood) {
6209   std::string spirv = ShaderWithNonWritableTarget("%var_ubo");
6210 
6211   CompileSuccessfully(spirv);
6212   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
6213   EXPECT_THAT(getDiagnosticString(), Eq(""));
6214 }
6215 
TEST_F(ValidateDecorations,NonWritableVarSsboInUniformGood)6216 TEST_F(ValidateDecorations, NonWritableVarSsboInUniformGood) {
6217   const std::string spirv = R"(
6218 OpCapability Shader
6219 OpMemoryModel Logical GLSL450
6220 OpEntryPoint Vertex %main "main"
6221 OpDecorate %struct_bb BufferBlock
6222 OpMemberDecorate %struct_bb 0 Offset 0
6223 OpDecorate %var_ssbo_u NonWritable
6224 %void = OpTypeVoid
6225 %void_fn = OpTypeFunction %void
6226 %float = OpTypeFloat 32
6227 %struct_bb = OpTypeStruct %float
6228 %_ptr_Uniform_stbb       = OpTypePointer Uniform %struct_bb
6229 %var_ssbo_u = OpVariable %_ptr_Uniform_stbb Uniform
6230 %main = OpFunction %void None %void_fn
6231 %label = OpLabel
6232 OpReturn
6233 OpFunctionEnd
6234 )";
6235 
6236   CompileSuccessfully(spirv);
6237   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
6238   EXPECT_THAT(getDiagnosticString(), Eq(""));
6239 }
6240 
TEST_F(ValidateDecorations,NonWritableVarSsboInStorageBufferGood)6241 TEST_F(ValidateDecorations, NonWritableVarSsboInStorageBufferGood) {
6242   std::string spirv = ShaderWithNonWritableTarget("%var_ssbo_sb");
6243 
6244   CompileSuccessfully(spirv);
6245   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
6246   EXPECT_THAT(getDiagnosticString(), Eq(""));
6247 }
6248 
TEST_F(ValidateDecorations,NonWritableMemberOfSsboInStorageBufferGood)6249 TEST_F(ValidateDecorations, NonWritableMemberOfSsboInStorageBufferGood) {
6250   std::string spirv = ShaderWithNonWritableTarget("%struct_b_rtarr", true);
6251 
6252   CompileSuccessfully(spirv);
6253   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
6254   EXPECT_THAT(getDiagnosticString(), Eq(""));
6255 }
6256 
TEST_F(ValidateDecorations,NonWritableMemberOfStructGood)6257 TEST_F(ValidateDecorations, NonWritableMemberOfStructGood) {
6258   std::string spirv = ShaderWithNonWritableTarget("%simple_struct", true);
6259 
6260   CompileSuccessfully(spirv);
6261   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
6262 }
6263 
TEST_F(ValidateDecorations,NonWritableVarWorkgroupBad)6264 TEST_F(ValidateDecorations, NonWritableVarWorkgroupBad) {
6265   std::string spirv = ShaderWithNonWritableTarget("%var_wg");
6266 
6267   CompileSuccessfully(spirv);
6268   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
6269   EXPECT_THAT(getDiagnosticString(),
6270               HasSubstr("Target of NonWritable decoration is invalid: must "
6271                         "point to a storage image, uniform block, or storage "
6272                         "buffer\n  %var_wg"));
6273 }
6274 
TEST_F(ValidateDecorations,NonWritableVarWorkgroupV14Bad)6275 TEST_F(ValidateDecorations, NonWritableVarWorkgroupV14Bad) {
6276   std::string spirv = ShaderWithNonWritableTarget("%var_wg");
6277 
6278   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
6279   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
6280   EXPECT_THAT(getDiagnosticString(),
6281               HasSubstr("Target of NonWritable decoration is invalid: must "
6282                         "point to a storage image, uniform block, storage "
6283                         "buffer, or variable in Private or Function storage "
6284                         "class\n  %var_wg"));
6285 }
6286 
TEST_F(ValidateDecorations,NonWritableVarPrivateBad)6287 TEST_F(ValidateDecorations, NonWritableVarPrivateBad) {
6288   std::string spirv = ShaderWithNonWritableTarget("%var_priv");
6289 
6290   CompileSuccessfully(spirv);
6291   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
6292   EXPECT_THAT(getDiagnosticString(),
6293               HasSubstr("Target of NonWritable decoration is invalid: must "
6294                         "point to a storage image, uniform block, or storage "
6295                         "buffer\n  %var_priv"));
6296 }
6297 
TEST_F(ValidateDecorations,NonWritableVarPrivateV13Bad)6298 TEST_F(ValidateDecorations, NonWritableVarPrivateV13Bad) {
6299   std::string spirv = ShaderWithNonWritableTarget("%var_priv");
6300 
6301   CompileSuccessfully(spirv);
6302   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
6303   EXPECT_THAT(getDiagnosticString(),
6304               HasSubstr("Target of NonWritable decoration is invalid: must "
6305                         "point to a storage image, uniform block, or storage "
6306                         "buffer\n  %var_priv"));
6307 }
6308 
TEST_F(ValidateDecorations,NonWritableVarPrivateV14Good)6309 TEST_F(ValidateDecorations, NonWritableVarPrivateV14Good) {
6310   std::string spirv = ShaderWithNonWritableTarget("%var_priv");
6311 
6312   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
6313   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
6314   EXPECT_THAT(getDiagnosticString(), Eq(""));
6315 }
6316 
TEST_F(ValidateDecorations,NonWritableVarPrivateV13TargetV14Bad)6317 TEST_F(ValidateDecorations, NonWritableVarPrivateV13TargetV14Bad) {
6318   std::string spirv = ShaderWithNonWritableTarget("%var_priv");
6319 
6320   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
6321   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
6322   EXPECT_THAT(getDiagnosticString(),
6323               HasSubstr("Target of NonWritable decoration is invalid: must "
6324                         "point to a storage image, uniform block, or storage "
6325                         "buffer\n  %var_priv"));
6326 }
6327 
TEST_F(ValidateDecorations,NonWritableVarFunctionBad)6328 TEST_F(ValidateDecorations, NonWritableVarFunctionBad) {
6329   std::string spirv = ShaderWithNonWritableTarget("%var_func");
6330 
6331   CompileSuccessfully(spirv);
6332   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
6333   EXPECT_THAT(getDiagnosticString(),
6334               HasSubstr("Target of NonWritable decoration is invalid: must "
6335                         "point to a storage image, uniform block, or storage "
6336                         "buffer\n  %var_func"));
6337 }
6338 
TEST_F(ValidateDecorations,NonWritableArrayGood)6339 TEST_F(ValidateDecorations, NonWritableArrayGood) {
6340   std::string spirv = ShaderWithNonWritableTarget("%var_array_imstor");
6341 
6342   CompileSuccessfully(spirv);
6343   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
6344 }
6345 
TEST_F(ValidateDecorations,NonWritableRuntimeArrayGood)6346 TEST_F(ValidateDecorations, NonWritableRuntimeArrayGood) {
6347   std::string spirv = ShaderWithNonWritableTarget("%var_rta_imstor");
6348 
6349   CompileSuccessfully(spirv);
6350   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
6351 }
6352 
TEST_P(ValidateVulkanCombineDecorationResult,Decorate)6353 TEST_P(ValidateVulkanCombineDecorationResult, Decorate) {
6354   const char* const decoration = std::get<0>(GetParam());
6355   const char* const vuid = std::get<1>(GetParam());
6356   const TestResult& test_result = std::get<2>(GetParam());
6357 
6358   CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator();
6359   generator.before_types_ = "OpDecorate %u32 ";
6360   generator.before_types_ += decoration;
6361   generator.before_types_ += "\n";
6362 
6363   EntryPoint entry_point;
6364   entry_point.name = "main";
6365   entry_point.execution_model = "Vertex";
6366   generator.entry_points_.push_back(std::move(entry_point));
6367 
6368   CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0);
6369   ASSERT_EQ(test_result.validation_result,
6370             ValidateInstructions(SPV_ENV_VULKAN_1_0));
6371   if (!test_result.error_str.empty()) {
6372     EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str));
6373   }
6374   if (vuid) {
6375     EXPECT_THAT(getDiagnosticString(), AnyVUID(vuid));
6376   }
6377 }
6378 
6379 INSTANTIATE_TEST_SUITE_P(
6380     DecorationAllowListFailure, ValidateVulkanCombineDecorationResult,
6381     Combine(Values("GLSLShared", "GLSLPacked"),
6382             Values("VUID-StandaloneSpirv-GLSLShared-04669"),
6383             Values(TestResult(
6384                 SPV_ERROR_INVALID_ID,
6385                 "is not valid for the Vulkan execution environment."))));
6386 
TEST_F(ValidateDecorations,NonWritableVarFunctionV13Bad)6387 TEST_F(ValidateDecorations, NonWritableVarFunctionV13Bad) {
6388   std::string spirv = ShaderWithNonWritableTarget("%var_func");
6389 
6390   CompileSuccessfully(spirv);
6391   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
6392   EXPECT_THAT(getDiagnosticString(),
6393               HasSubstr("Target of NonWritable decoration is invalid: must "
6394                         "point to a storage image, uniform block, or storage "
6395                         "buffer\n  %var_func"));
6396 }
6397 
TEST_F(ValidateDecorations,NonWritableVarFunctionV14Good)6398 TEST_F(ValidateDecorations, NonWritableVarFunctionV14Good) {
6399   std::string spirv = ShaderWithNonWritableTarget("%var_func");
6400 
6401   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
6402   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
6403   EXPECT_THAT(getDiagnosticString(), Eq(""));
6404 }
6405 
TEST_F(ValidateDecorations,NonWritableVarFunctionV13TargetV14Bad)6406 TEST_F(ValidateDecorations, NonWritableVarFunctionV13TargetV14Bad) {
6407   std::string spirv = ShaderWithNonWritableTarget("%var_func");
6408 
6409   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
6410   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
6411   EXPECT_THAT(getDiagnosticString(),
6412               HasSubstr("Target of NonWritable decoration is invalid: must "
6413                         "point to a storage image, uniform block, or storage "
6414                         "buffer\n  %var_func"));
6415 }
6416 
TEST_F(ValidateDecorations,BufferBlockV13ValV14Good)6417 TEST_F(ValidateDecorations, BufferBlockV13ValV14Good) {
6418   std::string spirv = R"(
6419 OpCapability Shader
6420 OpCapability Linkage
6421 OpMemoryModel Logical GLSL450
6422 OpDecorate %1 BufferBlock
6423 %1 = OpTypeStruct
6424 )";
6425 
6426   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
6427   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
6428 }
6429 
TEST_F(ValidateDecorations,BufferBlockV14Bad)6430 TEST_F(ValidateDecorations, BufferBlockV14Bad) {
6431   std::string spirv = R"(
6432 OpCapability Shader
6433 OpCapability Linkage
6434 OpMemoryModel Logical GLSL450
6435 OpDecorate %1 BufferBlock
6436 %1 = OpTypeStruct
6437 )";
6438 
6439   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
6440   EXPECT_EQ(SPV_ERROR_WRONG_VERSION,
6441             ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
6442   EXPECT_THAT(getDiagnosticString(),
6443               HasSubstr("2nd operand of Decorate: operand BufferBlock(3) "
6444                         "requires SPIR-V version 1.3 or earlier"));
6445 }
6446 
6447 // Component
6448 
TEST_F(ValidateDecorations,ComponentDecorationBadTarget)6449 TEST_F(ValidateDecorations, ComponentDecorationBadTarget) {
6450   std::string spirv = R"(
6451 OpCapability Shader
6452 OpMemoryModel Logical GLSL450
6453 OpEntryPoint Vertex %main "main"
6454 OpDecorate %t Component 0
6455 %void = OpTypeVoid
6456 %3 = OpTypeFunction %void
6457 %float = OpTypeFloat 32
6458 %t = OpTypeVector %float 2
6459 %main = OpFunction %void None %3
6460 %5 = OpLabel
6461 OpReturn
6462 OpFunctionEnd
6463 )";
6464 
6465   CompileSuccessfully(spirv);
6466   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
6467   EXPECT_THAT(getDiagnosticString(),
6468               HasSubstr("Target of Component decoration must be "
6469                         "a memory object declaration"));
6470 }
6471 
TEST_F(ValidateDecorations,ComponentDecorationBadStorageClass)6472 TEST_F(ValidateDecorations, ComponentDecorationBadStorageClass) {
6473   std::string spirv = R"(
6474 OpCapability Shader
6475 OpMemoryModel Logical GLSL450
6476 OpEntryPoint Vertex %main "main"
6477 OpDecorate %v Component 0
6478 %void = OpTypeVoid
6479 %3 = OpTypeFunction %void
6480 %float = OpTypeFloat 32
6481 %t = OpTypeVector %float 2
6482 %ptr_private = OpTypePointer Private %t
6483 %v = OpVariable %ptr_private Private
6484 %main = OpFunction %void None %3
6485 %5 = OpLabel
6486 OpReturn
6487 OpFunctionEnd
6488 )";
6489 
6490   CompileSuccessfully(spirv);
6491   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
6492   EXPECT_THAT(getDiagnosticString(),
6493               HasSubstr("Target of Component decoration is invalid: must "
6494                         "point to a Storage Class of Input(1) or Output(3)"));
6495 }
6496 
TEST_F(ValidateDecorations,ComponentDecorationBadTypeVulkan)6497 TEST_F(ValidateDecorations, ComponentDecorationBadTypeVulkan) {
6498   const spv_target_env env = SPV_ENV_VULKAN_1_0;
6499   std::string spirv = R"(
6500 OpCapability Shader
6501 OpCapability Matrix
6502 OpMemoryModel Logical GLSL450
6503 OpEntryPoint Vertex %main "main"
6504 OpDecorate %v Component 0
6505 %void = OpTypeVoid
6506 %3 = OpTypeFunction %void
6507 %float = OpTypeFloat 32
6508 %vtype = OpTypeVector %float 4
6509 %t = OpTypeMatrix %vtype 4
6510 %ptr_input = OpTypePointer Input %t
6511 %v = OpVariable %ptr_input Input
6512 %main = OpFunction %void None %3
6513 %5 = OpLabel
6514 OpReturn
6515 OpFunctionEnd
6516 )";
6517 
6518   CompileSuccessfully(spirv, env);
6519   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(env));
6520   EXPECT_THAT(getDiagnosticString(),
6521               HasSubstr("Component decoration specified for type"));
6522   EXPECT_THAT(getDiagnosticString(), HasSubstr("is not a scalar or vector"));
6523 }
6524 
ShaderWithComponentDecoration(const std::string & type,const std::string & decoration)6525 std::string ShaderWithComponentDecoration(const std::string& type,
6526                                           const std::string& decoration) {
6527   return R"(
6528 OpCapability Shader
6529 OpMemoryModel Logical GLSL450
6530 OpEntryPoint Fragment %main "main" %entryPointOutput
6531 OpExecutionMode %main OriginUpperLeft
6532 OpDecorate %entryPointOutput Location 0
6533 OpDecorate %entryPointOutput )" +
6534          decoration + R"(
6535 %void = OpTypeVoid
6536 %3 = OpTypeFunction %void
6537 %float = OpTypeFloat 32
6538 %v3float = OpTypeVector %float 3
6539 %v4float = OpTypeVector %float 4
6540 %uint = OpTypeInt 32 0
6541 %uint_2 = OpConstant %uint 2
6542 %arr_v3float_uint_2 = OpTypeArray %v3float %uint_2
6543 %float_0 = OpConstant %float 0
6544 %_ptr_Output_type = OpTypePointer Output %)" + type + R"(
6545 %entryPointOutput = OpVariable %_ptr_Output_type Output
6546 %main = OpFunction %void None %3
6547 %5 = OpLabel
6548 OpReturn
6549 OpFunctionEnd
6550 )";
6551 }
6552 
TEST_F(ValidateDecorations,ComponentDecorationIntGood0Vulkan)6553 TEST_F(ValidateDecorations, ComponentDecorationIntGood0Vulkan) {
6554   const spv_target_env env = SPV_ENV_VULKAN_1_0;
6555   std::string spirv = ShaderWithComponentDecoration("uint", "Component 0");
6556 
6557   CompileSuccessfully(spirv, env);
6558   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env));
6559   EXPECT_THAT(getDiagnosticString(), Eq(""));
6560 }
6561 
TEST_F(ValidateDecorations,ComponentDecorationIntGood1Vulkan)6562 TEST_F(ValidateDecorations, ComponentDecorationIntGood1Vulkan) {
6563   const spv_target_env env = SPV_ENV_VULKAN_1_0;
6564   std::string spirv = ShaderWithComponentDecoration("uint", "Component 1");
6565 
6566   CompileSuccessfully(spirv, env);
6567   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env));
6568   EXPECT_THAT(getDiagnosticString(), Eq(""));
6569 }
6570 
TEST_F(ValidateDecorations,ComponentDecorationIntGood2Vulkan)6571 TEST_F(ValidateDecorations, ComponentDecorationIntGood2Vulkan) {
6572   const spv_target_env env = SPV_ENV_VULKAN_1_0;
6573   std::string spirv = ShaderWithComponentDecoration("uint", "Component 2");
6574 
6575   CompileSuccessfully(spirv, env);
6576   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env));
6577   EXPECT_THAT(getDiagnosticString(), Eq(""));
6578 }
6579 
TEST_F(ValidateDecorations,ComponentDecorationIntGood3Vulkan)6580 TEST_F(ValidateDecorations, ComponentDecorationIntGood3Vulkan) {
6581   const spv_target_env env = SPV_ENV_VULKAN_1_0;
6582   std::string spirv = ShaderWithComponentDecoration("uint", "Component 3");
6583 
6584   CompileSuccessfully(spirv, env);
6585   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env));
6586   EXPECT_THAT(getDiagnosticString(), Eq(""));
6587 }
6588 
TEST_F(ValidateDecorations,ComponentDecorationIntBad4Vulkan)6589 TEST_F(ValidateDecorations, ComponentDecorationIntBad4Vulkan) {
6590   const spv_target_env env = SPV_ENV_VULKAN_1_0;
6591   std::string spirv = ShaderWithComponentDecoration("uint", "Component 4");
6592 
6593   CompileSuccessfully(spirv, env);
6594   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(env));
6595   EXPECT_THAT(getDiagnosticString(),
6596               HasSubstr("Sequence of components starting with 4 "
6597                         "and ending with 4 gets larger than 3"));
6598 }
6599 
TEST_F(ValidateDecorations,ComponentDecorationVector3GoodVulkan)6600 TEST_F(ValidateDecorations, ComponentDecorationVector3GoodVulkan) {
6601   const spv_target_env env = SPV_ENV_VULKAN_1_0;
6602   std::string spirv = ShaderWithComponentDecoration("v3float", "Component 1");
6603 
6604   CompileSuccessfully(spirv, env);
6605   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env));
6606   EXPECT_THAT(getDiagnosticString(), Eq(""));
6607 }
6608 
TEST_F(ValidateDecorations,ComponentDecorationVector4GoodVulkan)6609 TEST_F(ValidateDecorations, ComponentDecorationVector4GoodVulkan) {
6610   const spv_target_env env = SPV_ENV_VULKAN_1_0;
6611   std::string spirv = ShaderWithComponentDecoration("v4float", "Component 0");
6612 
6613   CompileSuccessfully(spirv, env);
6614   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env));
6615   EXPECT_THAT(getDiagnosticString(), Eq(""));
6616 }
6617 
TEST_F(ValidateDecorations,ComponentDecorationVector4Bad1Vulkan)6618 TEST_F(ValidateDecorations, ComponentDecorationVector4Bad1Vulkan) {
6619   const spv_target_env env = SPV_ENV_VULKAN_1_0;
6620   std::string spirv = ShaderWithComponentDecoration("v4float", "Component 1");
6621 
6622   CompileSuccessfully(spirv, env);
6623   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(env));
6624   EXPECT_THAT(getDiagnosticString(),
6625               HasSubstr("Sequence of components starting with 1 "
6626                         "and ending with 4 gets larger than 3"));
6627 }
6628 
TEST_F(ValidateDecorations,ComponentDecorationVector4Bad3Vulkan)6629 TEST_F(ValidateDecorations, ComponentDecorationVector4Bad3Vulkan) {
6630   const spv_target_env env = SPV_ENV_VULKAN_1_0;
6631   std::string spirv = ShaderWithComponentDecoration("v4float", "Component 3");
6632 
6633   CompileSuccessfully(spirv, env);
6634   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(env));
6635   EXPECT_THAT(getDiagnosticString(),
6636               HasSubstr("Sequence of components starting with 3 "
6637                         "and ending with 6 gets larger than 3"));
6638 }
6639 
TEST_F(ValidateDecorations,ComponentDecorationArrayGoodVulkan)6640 TEST_F(ValidateDecorations, ComponentDecorationArrayGoodVulkan) {
6641   const spv_target_env env = SPV_ENV_VULKAN_1_0;
6642   std::string spirv =
6643       ShaderWithComponentDecoration("arr_v3float_uint_2", "Component 1");
6644 
6645   CompileSuccessfully(spirv, env);
6646   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env));
6647   EXPECT_THAT(getDiagnosticString(), Eq(""));
6648 }
6649 
TEST_F(ValidateDecorations,ComponentDecorationArrayBadVulkan)6650 TEST_F(ValidateDecorations, ComponentDecorationArrayBadVulkan) {
6651   const spv_target_env env = SPV_ENV_VULKAN_1_0;
6652   std::string spirv =
6653       ShaderWithComponentDecoration("arr_v3float_uint_2", "Component 2");
6654 
6655   CompileSuccessfully(spirv, env);
6656   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(env));
6657   EXPECT_THAT(getDiagnosticString(),
6658               HasSubstr("Sequence of components starting with 2 "
6659                         "and ending with 4 gets larger than 3"));
6660 }
6661 
TEST_F(ValidateDecorations,ComponentDecorationBlockGood)6662 TEST_F(ValidateDecorations, ComponentDecorationBlockGood) {
6663   std::string spirv = R"(
6664 OpCapability Shader
6665 OpMemoryModel Logical GLSL450
6666 OpEntryPoint Fragment %4 "main" %9 %12
6667 OpExecutionMode %4 OriginUpperLeft
6668 OpDecorate %9 Location 0
6669 OpMemberDecorate %block 0 Location 2
6670 OpMemberDecorate %block 0 Component 1
6671 OpDecorate %block Block
6672 %2 = OpTypeVoid
6673 %3 = OpTypeFunction %2
6674 %float = OpTypeFloat 32
6675 %vec3 = OpTypeVector %float 3
6676 %8 = OpTypePointer Output %vec3
6677 %9 = OpVariable %8 Output
6678 %block = OpTypeStruct %vec3
6679 %11 = OpTypePointer Input %block
6680 %12 = OpVariable %11 Input
6681 %int = OpTypeInt 32 1
6682 %14 = OpConstant %int 0
6683 %15 = OpTypePointer Input %vec3
6684 %4 = OpFunction %2 None %3
6685 %5 = OpLabel
6686 %16 = OpAccessChain %15 %12 %14
6687 %17 = OpLoad %vec3 %16
6688 OpStore %9 %17
6689 OpReturn
6690 OpFunctionEnd
6691 )";
6692 
6693   CompileSuccessfully(spirv);
6694   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
6695   EXPECT_THAT(getDiagnosticString(), Eq(""));
6696 }
6697 
TEST_F(ValidateDecorations,ComponentDecorationBlockBadVulkan)6698 TEST_F(ValidateDecorations, ComponentDecorationBlockBadVulkan) {
6699   const spv_target_env env = SPV_ENV_VULKAN_1_0;
6700   std::string spirv = R"(
6701 OpCapability Shader
6702 OpMemoryModel Logical GLSL450
6703 OpEntryPoint Fragment %4 "main" %9 %12
6704 OpExecutionMode %4 OriginUpperLeft
6705 OpDecorate %9 Location 0
6706 OpMemberDecorate %block 0 Location 2
6707 OpMemberDecorate %block 0 Component 2
6708 OpDecorate %block Block
6709 %2 = OpTypeVoid
6710 %3 = OpTypeFunction %2
6711 %float = OpTypeFloat 32
6712 %vec3 = OpTypeVector %float 3
6713 %8 = OpTypePointer Output %vec3
6714 %9 = OpVariable %8 Output
6715 %block = OpTypeStruct %vec3
6716 %11 = OpTypePointer Input %block
6717 %12 = OpVariable %11 Input
6718 %int = OpTypeInt 32 1
6719 %14 = OpConstant %int 0
6720 %15 = OpTypePointer Input %vec3
6721 %4 = OpFunction %2 None %3
6722 %5 = OpLabel
6723 %16 = OpAccessChain %15 %12 %14
6724 %17 = OpLoad %vec3 %16
6725 OpStore %9 %17
6726 OpReturn
6727 OpFunctionEnd
6728 )";
6729 
6730   CompileSuccessfully(spirv, env);
6731   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(env));
6732   EXPECT_THAT(getDiagnosticString(),
6733               HasSubstr("Sequence of components starting with 2 "
6734                         "and ending with 4 gets larger than 3"));
6735 }
6736 
TEST_F(ValidateDecorations,ComponentDecorationFunctionParameter)6737 TEST_F(ValidateDecorations, ComponentDecorationFunctionParameter) {
6738   std::string spirv = R"(
6739               OpCapability Shader
6740               OpMemoryModel Logical GLSL450
6741               OpEntryPoint Vertex %main "main"
6742 
6743               OpDecorate %param_f Component 0
6744 
6745       %void = OpTypeVoid
6746    %void_fn = OpTypeFunction %void
6747      %float = OpTypeFloat 32
6748    %float_0 = OpConstant %float 0
6749    %int     = OpTypeInt 32 0
6750    %int_2   = OpConstant %int 2
6751   %struct_b = OpTypeStruct %float
6752 
6753 %extra_fn = OpTypeFunction %void %float
6754 
6755   %helper = OpFunction %void None %extra_fn
6756  %param_f = OpFunctionParameter %float
6757 %helper_label = OpLabel
6758             OpReturn
6759             OpFunctionEnd
6760 
6761     %main = OpFunction %void None %void_fn
6762    %label = OpLabel
6763             OpReturn
6764             OpFunctionEnd
6765 )";
6766 
6767   CompileSuccessfully(spirv);
6768   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
6769   EXPECT_THAT(getDiagnosticString(), Eq(""));
6770 }
6771 
TEST_F(ValidateDecorations,VulkanStorageBufferBlock)6772 TEST_F(ValidateDecorations, VulkanStorageBufferBlock) {
6773   const std::string spirv = R"(
6774 OpCapability Shader
6775 OpExtension "SPV_KHR_storage_buffer_storage_class"
6776 OpMemoryModel Logical GLSL450
6777 OpEntryPoint GLCompute %main "main"
6778 OpExecutionMode %main LocalSize 1 1 1
6779 OpDecorate %struct Block
6780 OpMemberDecorate %struct 0 Offset 0
6781 %void = OpTypeVoid
6782 %uint = OpTypeInt 32 0
6783 %struct = OpTypeStruct %uint
6784 %ptr_ssbo = OpTypePointer StorageBuffer %struct
6785 %var = OpVariable %ptr_ssbo StorageBuffer
6786 %void_fn = OpTypeFunction %void
6787 %main = OpFunction %void None %void_fn
6788 %entry = OpLabel
6789 OpReturn
6790 OpFunctionEnd
6791 )";
6792 
6793   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0);
6794   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
6795 }
6796 
TEST_F(ValidateDecorations,VulkanStorageBufferMissingBlock)6797 TEST_F(ValidateDecorations, VulkanStorageBufferMissingBlock) {
6798   const std::string spirv = R"(
6799 OpCapability Shader
6800 OpExtension "SPV_KHR_storage_buffer_storage_class"
6801 OpMemoryModel Logical GLSL450
6802 OpEntryPoint GLCompute %main "main"
6803 OpExecutionMode %main LocalSize 1 1 1
6804 %void = OpTypeVoid
6805 %uint = OpTypeInt 32 0
6806 %struct = OpTypeStruct %uint
6807 %ptr_ssbo = OpTypePointer StorageBuffer %struct
6808 %var = OpVariable %ptr_ssbo StorageBuffer
6809 %void_fn = OpTypeFunction %void
6810 %main = OpFunction %void None %void_fn
6811 %entry = OpLabel
6812 OpReturn
6813 OpFunctionEnd
6814 )";
6815 
6816   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0);
6817   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
6818   EXPECT_THAT(getDiagnosticString(),
6819               HasSubstr("From Vulkan spec, section 14.5.2:\nSuch variables "
6820                         "must be identified with a Block decoration"));
6821 }
6822 
TEST_F(ValidateDecorations,VulkanStorageBufferArrayMissingBlock)6823 TEST_F(ValidateDecorations, VulkanStorageBufferArrayMissingBlock) {
6824   const std::string spirv = R"(
6825 OpCapability Shader
6826 OpExtension "SPV_KHR_storage_buffer_storage_class"
6827 OpMemoryModel Logical GLSL450
6828 OpEntryPoint GLCompute %main "main"
6829 OpExecutionMode %main LocalSize 1 1 1
6830 %void = OpTypeVoid
6831 %uint = OpTypeInt 32 0
6832 %uint_4 = OpConstant %uint 4
6833 %struct = OpTypeStruct %uint
6834 %array = OpTypeArray %struct %uint_4
6835 %ptr_ssbo = OpTypePointer StorageBuffer %array
6836 %var = OpVariable %ptr_ssbo StorageBuffer
6837 %void_fn = OpTypeFunction %void
6838 %main = OpFunction %void None %void_fn
6839 %entry = OpLabel
6840 OpReturn
6841 OpFunctionEnd
6842 )";
6843 
6844   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0);
6845   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
6846   EXPECT_THAT(getDiagnosticString(),
6847               HasSubstr("From Vulkan spec, section 14.5.2:\nSuch variables "
6848                         "must be identified with a Block decoration"));
6849 }
6850 
TEST_F(ValidateDecorations,VulkanStorageBufferRuntimeArrayMissingBlock)6851 TEST_F(ValidateDecorations, VulkanStorageBufferRuntimeArrayMissingBlock) {
6852   const std::string spirv = R"(
6853 OpCapability Shader
6854 OpCapability RuntimeDescriptorArrayEXT
6855 OpExtension "SPV_EXT_descriptor_indexing"
6856 OpExtension "SPV_KHR_storage_buffer_storage_class"
6857 OpMemoryModel Logical GLSL450
6858 OpEntryPoint GLCompute %main "main"
6859 OpExecutionMode %main LocalSize 1 1 1
6860 %void = OpTypeVoid
6861 %uint = OpTypeInt 32 0
6862 %struct = OpTypeStruct %uint
6863 %array = OpTypeRuntimeArray %struct
6864 %ptr_ssbo = OpTypePointer StorageBuffer %array
6865 %var = OpVariable %ptr_ssbo StorageBuffer
6866 %void_fn = OpTypeFunction %void
6867 %main = OpFunction %void None %void_fn
6868 %entry = OpLabel
6869 OpReturn
6870 OpFunctionEnd
6871 )";
6872 
6873   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0);
6874   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
6875   EXPECT_THAT(getDiagnosticString(),
6876               HasSubstr("From Vulkan spec, section 14.5.2:\nSuch variables "
6877                         "must be identified with a Block decoration"));
6878 }
6879 
TEST_F(ValidateDecorations,VulkanUniformBlock)6880 TEST_F(ValidateDecorations, VulkanUniformBlock) {
6881   const std::string spirv = R"(
6882 OpCapability Shader
6883 OpMemoryModel Logical GLSL450
6884 OpEntryPoint GLCompute %main "main"
6885 OpExecutionMode %main LocalSize 1 1 1
6886 OpDecorate %struct Block
6887 OpMemberDecorate %struct 0 Offset 0
6888 %void = OpTypeVoid
6889 %uint = OpTypeInt 32 0
6890 %struct = OpTypeStruct %uint
6891 %ptr_ubo = OpTypePointer Uniform %struct
6892 %var = OpVariable %ptr_ubo Uniform
6893 %void_fn = OpTypeFunction %void
6894 %main = OpFunction %void None %void_fn
6895 %entry = OpLabel
6896 OpReturn
6897 OpFunctionEnd
6898 )";
6899 
6900   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0);
6901   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
6902 }
6903 
TEST_F(ValidateDecorations,VulkanUniformBufferBlock)6904 TEST_F(ValidateDecorations, VulkanUniformBufferBlock) {
6905   const std::string spirv = R"(
6906 OpCapability Shader
6907 OpMemoryModel Logical GLSL450
6908 OpEntryPoint GLCompute %main "main"
6909 OpExecutionMode %main LocalSize 1 1 1
6910 OpDecorate %struct BufferBlock
6911 OpMemberDecorate %struct 0 Offset 0
6912 %void = OpTypeVoid
6913 %uint = OpTypeInt 32 0
6914 %struct = OpTypeStruct %uint
6915 %ptr_ubo = OpTypePointer Uniform %struct
6916 %var = OpVariable %ptr_ubo Uniform
6917 %void_fn = OpTypeFunction %void
6918 %main = OpFunction %void None %void_fn
6919 %entry = OpLabel
6920 OpReturn
6921 OpFunctionEnd
6922 )";
6923 
6924   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0);
6925   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
6926 }
6927 
TEST_F(ValidateDecorations,VulkanUniformMissingBlock)6928 TEST_F(ValidateDecorations, VulkanUniformMissingBlock) {
6929   const std::string spirv = R"(
6930 OpCapability Shader
6931 OpMemoryModel Logical GLSL450
6932 OpEntryPoint GLCompute %main "main"
6933 OpExecutionMode %main LocalSize 1 1 1
6934 %void = OpTypeVoid
6935 %uint = OpTypeInt 32 0
6936 %struct = OpTypeStruct %uint
6937 %ptr_ubo = OpTypePointer Uniform %struct
6938 %var = OpVariable %ptr_ubo Uniform
6939 %void_fn = OpTypeFunction %void
6940 %main = OpFunction %void None %void_fn
6941 %entry = OpLabel
6942 OpReturn
6943 OpFunctionEnd
6944 )";
6945 
6946   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0);
6947   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
6948   EXPECT_THAT(
6949       getDiagnosticString(),
6950       HasSubstr("From Vulkan spec, section 14.5.2:\nSuch variables must be "
6951                 "identified with a Block or BufferBlock decoration"));
6952 }
6953 
TEST_F(ValidateDecorations,VulkanUniformArrayMissingBlock)6954 TEST_F(ValidateDecorations, VulkanUniformArrayMissingBlock) {
6955   const std::string spirv = R"(
6956 OpCapability Shader
6957 OpMemoryModel Logical GLSL450
6958 OpEntryPoint GLCompute %main "main"
6959 OpExecutionMode %main LocalSize 1 1 1
6960 %void = OpTypeVoid
6961 %uint = OpTypeInt 32 0
6962 %uint_4 = OpConstant %uint 4
6963 %struct = OpTypeStruct %uint
6964 %array = OpTypeArray %struct %uint_4
6965 %ptr_ubo = OpTypePointer Uniform %array
6966 %var = OpVariable %ptr_ubo Uniform
6967 %void_fn = OpTypeFunction %void
6968 %main = OpFunction %void None %void_fn
6969 %entry = OpLabel
6970 OpReturn
6971 OpFunctionEnd
6972 )";
6973 
6974   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0);
6975   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
6976   EXPECT_THAT(
6977       getDiagnosticString(),
6978       HasSubstr("From Vulkan spec, section 14.5.2:\nSuch variables must be "
6979                 "identified with a Block or BufferBlock decoration"));
6980 }
6981 
TEST_F(ValidateDecorations,VulkanUniformRuntimeArrayMissingBlock)6982 TEST_F(ValidateDecorations, VulkanUniformRuntimeArrayMissingBlock) {
6983   const std::string spirv = R"(
6984 OpCapability Shader
6985 OpCapability RuntimeDescriptorArrayEXT
6986 OpExtension "SPV_EXT_descriptor_indexing"
6987 OpMemoryModel Logical GLSL450
6988 OpEntryPoint GLCompute %main "main"
6989 OpExecutionMode %main LocalSize 1 1 1
6990 %void = OpTypeVoid
6991 %uint = OpTypeInt 32 0
6992 %struct = OpTypeStruct %uint
6993 %array = OpTypeRuntimeArray %struct
6994 %ptr_ubo = OpTypePointer Uniform %array
6995 %var = OpVariable %ptr_ubo Uniform
6996 %void_fn = OpTypeFunction %void
6997 %main = OpFunction %void None %void_fn
6998 %entry = OpLabel
6999 OpReturn
7000 OpFunctionEnd
7001 )";
7002 
7003   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0);
7004   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
7005   EXPECT_THAT(
7006       getDiagnosticString(),
7007       HasSubstr("From Vulkan spec, section 14.5.2:\nSuch variables must be "
7008                 "identified with a Block or BufferBlock decoration"));
7009 }
7010 
TEST_F(ValidateDecorations,VulkanArrayStrideZero)7011 TEST_F(ValidateDecorations, VulkanArrayStrideZero) {
7012   const std::string spirv = R"(
7013 OpCapability Shader
7014 OpMemoryModel Logical GLSL450
7015 OpEntryPoint GLCompute %main "main"
7016 OpExecutionMode %main LocalSize 1 1 1
7017 OpDecorate %var DescriptorSet 0
7018 OpDecorate %var Binding 0
7019 OpDecorate %struct Block
7020 OpMemberDecorate %struct 0 Offset 0
7021 OpDecorate %array ArrayStride 0
7022 %void = OpTypeVoid
7023 %int = OpTypeInt 32 0
7024 %int_4 = OpConstant %int 4
7025 %array = OpTypeArray %int %int_4
7026 %struct = OpTypeStruct %array
7027 %ptr_ssbo_struct = OpTypePointer StorageBuffer %struct
7028 %var = OpVariable %ptr_ssbo_struct StorageBuffer
7029 %void_fn = OpTypeFunction %void
7030 %main = OpFunction %void None %void_fn
7031 %entry = OpLabel
7032 OpReturn
7033 OpFunctionEnd
7034 )";
7035 
7036   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
7037   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
7038   EXPECT_THAT(getDiagnosticString(),
7039               HasSubstr("contains an array with stride 0"));
7040 }
7041 
TEST_F(ValidateDecorations,VulkanArrayStrideTooSmall)7042 TEST_F(ValidateDecorations, VulkanArrayStrideTooSmall) {
7043   const std::string spirv = R"(
7044 OpCapability Shader
7045 OpMemoryModel Logical GLSL450
7046 OpEntryPoint GLCompute %main "main"
7047 OpExecutionMode %main LocalSize 1 1 1
7048 OpDecorate %var DescriptorSet 0
7049 OpDecorate %var Binding 0
7050 OpDecorate %struct Block
7051 OpMemberDecorate %struct 0 Offset 0
7052 OpDecorate %inner ArrayStride 4
7053 OpDecorate %outer ArrayStride 4
7054 %void = OpTypeVoid
7055 %int = OpTypeInt 32 0
7056 %int_4 = OpConstant %int 4
7057 %inner = OpTypeArray %int %int_4
7058 %outer = OpTypeArray %inner %int_4
7059 %struct = OpTypeStruct %outer
7060 %ptr_ssbo_struct = OpTypePointer StorageBuffer %struct
7061 %var = OpVariable %ptr_ssbo_struct StorageBuffer
7062 %void_fn = OpTypeFunction %void
7063 %main = OpFunction %void None %void_fn
7064 %entry = OpLabel
7065 OpReturn
7066 OpFunctionEnd
7067 )";
7068 
7069   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
7070   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
7071   EXPECT_THAT(
7072       getDiagnosticString(),
7073       HasSubstr(
7074           "contains an array with stride 4, but with an element size of 16"));
7075 }
7076 
TEST_F(ValidateDecorations,FunctionsWithOpGroupDecorate)7077 TEST_F(ValidateDecorations, FunctionsWithOpGroupDecorate) {
7078   std::string spirv = R"(
7079                 OpCapability Addresses
7080                 OpCapability Linkage
7081                 OpCapability Kernel
7082                 OpCapability Int8
7083            %1 = OpExtInstImport "OpenCL.std"
7084                 OpMemoryModel Physical32 OpenCL
7085                 OpName %foo "foo"
7086                 OpName %entry "entry"
7087                 OpName %bar "bar"
7088                 OpName %entry_0 "entry"
7089                 OpName %k "k"
7090                 OpName %entry_1 "entry"
7091                 OpName %b "b"
7092                 OpDecorate %28 FuncParamAttr Zext
7093           %28 = OpDecorationGroup
7094                 OpDecorate %k LinkageAttributes "k" Export
7095                 OpDecorate %foo LinkageAttributes "foo" Export
7096                 OpDecorate %bar LinkageAttributes "bar" Export
7097                 OpDecorate %b Alignment 1
7098                 OpGroupDecorate %28 %foo %bar
7099        %uchar = OpTypeInt 8 0
7100         %bool = OpTypeBool
7101            %3 = OpTypeFunction %bool
7102         %void = OpTypeVoid
7103           %10 = OpTypeFunction %void
7104  %_ptr_Function_uchar = OpTypePointer Function %uchar
7105         %true = OpConstantTrue %bool
7106          %foo = OpFunction %bool DontInline %3
7107        %entry = OpLabel
7108                 OpReturnValue %true
7109                 OpFunctionEnd
7110          %bar = OpFunction %bool DontInline %3
7111      %entry_0 = OpLabel
7112                 OpReturnValue %true
7113                 OpFunctionEnd
7114            %k = OpFunction %void DontInline %10
7115      %entry_1 = OpLabel
7116            %b = OpVariable %_ptr_Function_uchar Function
7117                 OpReturn
7118                 OpFunctionEnd
7119   )";
7120   CompileSuccessfully(spirv);
7121   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
7122 }
7123 
TEST_F(ValidateDecorations,LocationVariableGood)7124 TEST_F(ValidateDecorations, LocationVariableGood) {
7125   const std::string spirv = R"(
7126 OpCapability Shader
7127 OpCapability Linkage
7128 OpMemoryModel Logical GLSL450
7129 OpDecorate %in_var Location 0
7130 %float = OpTypeFloat 32
7131 %ptr_input_float = OpTypePointer Input %float
7132 %in_var = OpVariable %ptr_input_float Input
7133 )";
7134 
7135   CompileSuccessfully(spirv);
7136   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
7137 }
7138 
TEST_F(ValidateDecorations,LocationStructMemberGood)7139 TEST_F(ValidateDecorations, LocationStructMemberGood) {
7140   const std::string spirv = R"(
7141 OpCapability Shader
7142 OpCapability Linkage
7143 OpMemoryModel Logical GLSL450
7144 OpMemberDecorate %struct 0 Location 0
7145 %float = OpTypeFloat 32
7146 %struct = OpTypeStruct %float
7147 )";
7148 
7149   CompileSuccessfully(spirv);
7150   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
7151 }
7152 
TEST_F(ValidateDecorations,LocationStructBad)7153 TEST_F(ValidateDecorations, LocationStructBad) {
7154   const std::string spirv = R"(
7155 OpCapability Shader
7156 OpCapability Linkage
7157 OpMemoryModel Logical GLSL450
7158 OpDecorate %struct Location 0
7159 %float = OpTypeFloat 32
7160 %struct = OpTypeStruct %float
7161 )";
7162 
7163   CompileSuccessfully(spirv);
7164   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
7165   EXPECT_THAT(getDiagnosticString(),
7166               HasSubstr("Location decoration can only be applied to a variable "
7167                         "or member of a structure type"));
7168 }
7169 
TEST_F(ValidateDecorations,LocationFloatBad)7170 TEST_F(ValidateDecorations, LocationFloatBad) {
7171   const std::string spirv = R"(
7172 OpCapability Shader
7173 OpCapability Linkage
7174 OpMemoryModel Logical GLSL450
7175 OpDecorate %float Location 0
7176 %float = OpTypeFloat 32
7177 )";
7178 
7179   CompileSuccessfully(spirv);
7180   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
7181   EXPECT_THAT(getDiagnosticString(),
7182               HasSubstr("Location decoration can only be applied to a variable "
7183                         "or member of a structure type"));
7184 }
7185 
TEST_F(ValidateDecorations,WorkgroupSingleBlockVariable)7186 TEST_F(ValidateDecorations, WorkgroupSingleBlockVariable) {
7187   std::string spirv = R"(
7188                OpCapability Shader
7189                OpCapability WorkgroupMemoryExplicitLayoutKHR
7190                OpExtension "SPV_KHR_workgroup_memory_explicit_layout"
7191                OpMemoryModel Logical GLSL450
7192                OpEntryPoint GLCompute %main "main" %_
7193                OpExecutionMode %main LocalSize 8 1 1
7194                OpMemberDecorate %first 0 Offset 0
7195                OpDecorate %first Block
7196        %void = OpTypeVoid
7197           %3 = OpTypeFunction %void
7198         %int = OpTypeInt 32 1
7199       %first = OpTypeStruct %int
7200 %_ptr_Workgroup_first = OpTypePointer Workgroup %first
7201           %_ = OpVariable %_ptr_Workgroup_first Workgroup
7202       %int_0 = OpConstant %int 0
7203       %int_2 = OpConstant %int 2
7204 %_ptr_Workgroup_int = OpTypePointer Workgroup %int
7205        %main = OpFunction %void None %3
7206           %5 = OpLabel
7207          %13 = OpAccessChain %_ptr_Workgroup_int %_ %int_0
7208                OpStore %13 %int_2
7209                OpReturn
7210                OpFunctionEnd
7211   )";
7212 
7213   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
7214   EXPECT_EQ(SPV_SUCCESS,
7215 	    ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_4));
7216 }
7217 
TEST_F(ValidateDecorations,WorkgroupBlockVariableRequiresV14)7218 TEST_F(ValidateDecorations, WorkgroupBlockVariableRequiresV14) {
7219   std::string spirv = R"(
7220                OpCapability Shader
7221                OpCapability WorkgroupMemoryExplicitLayoutKHR
7222                OpExtension "SPV_KHR_workgroup_memory_explicit_layout"
7223                OpMemoryModel Logical GLSL450
7224                OpEntryPoint GLCompute %main "main" %_
7225                OpExecutionMode %main LocalSize 8 1 1
7226                OpMemberDecorate %first 0 Offset 0
7227                OpDecorate %first Block
7228        %void = OpTypeVoid
7229           %3 = OpTypeFunction %void
7230         %int = OpTypeInt 32 1
7231       %first = OpTypeStruct %int
7232 %_ptr_Workgroup_first = OpTypePointer Workgroup %first
7233           %_ = OpVariable %_ptr_Workgroup_first Workgroup
7234       %int_0 = OpConstant %int 0
7235       %int_2 = OpConstant %int 2
7236 %_ptr_Workgroup_int = OpTypePointer Workgroup %int
7237        %main = OpFunction %void None %3
7238           %5 = OpLabel
7239          %13 = OpAccessChain %_ptr_Workgroup_int %_ %int_0
7240                OpStore %13 %int_2
7241                OpReturn
7242                OpFunctionEnd
7243   )";
7244 
7245   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
7246   EXPECT_EQ(SPV_ERROR_WRONG_VERSION,
7247             ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_4));
7248   EXPECT_THAT(getDiagnosticString(),
7249               HasSubstr("requires SPIR-V version 1.4 or later"));
7250 }
7251 
TEST_F(ValidateDecorations,WorkgroupSingleNonBlockVariable)7252 TEST_F(ValidateDecorations, WorkgroupSingleNonBlockVariable) {
7253   std::string spirv = R"(
7254                OpCapability Shader
7255                OpMemoryModel Logical GLSL450
7256                OpEntryPoint GLCompute %main "main" %a
7257                OpExecutionMode %main LocalSize 8 1 1
7258        %void = OpTypeVoid
7259           %3 = OpTypeFunction %void
7260         %int = OpTypeInt 32 1
7261 %_ptr_Workgroup_int = OpTypePointer Workgroup %int
7262           %a = OpVariable %_ptr_Workgroup_int Workgroup
7263       %int_2 = OpConstant %int 2
7264        %main = OpFunction %void None %3
7265           %5 = OpLabel
7266                OpStore %a %int_2
7267                OpReturn
7268                OpFunctionEnd
7269   )";
7270 
7271   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
7272   EXPECT_EQ(SPV_SUCCESS,
7273 	    ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_4));
7274 }
7275 
TEST_F(ValidateDecorations,WorkgroupMultiBlockVariable)7276 TEST_F(ValidateDecorations, WorkgroupMultiBlockVariable) {
7277   std::string spirv = R"(
7278                OpCapability Shader
7279                OpCapability WorkgroupMemoryExplicitLayoutKHR
7280                OpExtension "SPV_KHR_workgroup_memory_explicit_layout"
7281                OpMemoryModel Logical GLSL450
7282                OpEntryPoint GLCompute %main "main" %_ %__0
7283                OpExecutionMode %main LocalSize 8 1 1
7284                OpMemberDecorate %first 0 Offset 0
7285                OpDecorate %first Block
7286                OpMemberDecorate %second 0 Offset 0
7287                OpDecorate %second Block
7288                OpDecorate %_ Aliased
7289                OpDecorate %__0 Aliased
7290        %void = OpTypeVoid
7291           %3 = OpTypeFunction %void
7292         %int = OpTypeInt 32 1
7293       %first = OpTypeStruct %int
7294 %_ptr_Workgroup_first = OpTypePointer Workgroup %first
7295           %_ = OpVariable %_ptr_Workgroup_first Workgroup
7296       %int_0 = OpConstant %int 0
7297       %int_2 = OpConstant %int 2
7298 %_ptr_Workgroup_int = OpTypePointer Workgroup %int
7299      %second = OpTypeStruct %int
7300 %_ptr_Workgroup_second = OpTypePointer Workgroup %second
7301         %__0 = OpVariable %_ptr_Workgroup_second Workgroup
7302       %int_3 = OpConstant %int 3
7303        %main = OpFunction %void None %3
7304           %5 = OpLabel
7305          %13 = OpAccessChain %_ptr_Workgroup_int %_ %int_0
7306                OpStore %13 %int_2
7307          %18 = OpAccessChain %_ptr_Workgroup_int %__0 %int_0
7308                OpStore %18 %int_3
7309                OpReturn
7310                OpFunctionEnd
7311   )";
7312 
7313   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
7314   EXPECT_EQ(SPV_SUCCESS,
7315 	    ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_4));
7316 }
7317 
TEST_F(ValidateDecorations,WorkgroupBlockVariableWith8BitType)7318 TEST_F(ValidateDecorations, WorkgroupBlockVariableWith8BitType) {
7319   std::string spirv = R"(
7320                OpCapability Shader
7321                OpCapability Int8
7322                OpCapability WorkgroupMemoryExplicitLayout8BitAccessKHR
7323                OpExtension "SPV_KHR_workgroup_memory_explicit_layout"
7324                OpMemoryModel Logical GLSL450
7325                OpEntryPoint GLCompute %main "main" %_
7326                OpExecutionMode %main LocalSize 2 1 1
7327                OpMemberDecorate %first 0 Offset 0
7328                OpDecorate %first Block
7329        %void = OpTypeVoid
7330           %3 = OpTypeFunction %void
7331        %char = OpTypeInt 8 1
7332       %first = OpTypeStruct %char
7333 %_ptr_Workgroup_first = OpTypePointer Workgroup %first
7334           %_ = OpVariable %_ptr_Workgroup_first Workgroup
7335         %int = OpTypeInt 32 1
7336       %int_0 = OpConstant %int 0
7337      %char_2 = OpConstant %char 2
7338 %_ptr_Workgroup_char = OpTypePointer Workgroup %char
7339        %main = OpFunction %void None %3
7340           %5 = OpLabel
7341          %14 = OpAccessChain %_ptr_Workgroup_char %_ %int_0
7342                OpStore %14 %char_2
7343                OpReturn
7344                OpFunctionEnd
7345   )";
7346 
7347   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
7348   EXPECT_EQ(SPV_SUCCESS,
7349 	    ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_4));
7350 }
7351 
TEST_F(ValidateDecorations,WorkgroupMultiNonBlockVariable)7352 TEST_F(ValidateDecorations, WorkgroupMultiNonBlockVariable) {
7353   std::string spirv = R"(
7354                OpCapability Shader
7355                OpMemoryModel Logical GLSL450
7356                OpEntryPoint GLCompute %main "main" %a %b
7357                OpExecutionMode %main LocalSize 8 1 1
7358        %void = OpTypeVoid
7359           %3 = OpTypeFunction %void
7360         %int = OpTypeInt 32 1
7361 %_ptr_Workgroup_int = OpTypePointer Workgroup %int
7362           %a = OpVariable %_ptr_Workgroup_int Workgroup
7363       %int_2 = OpConstant %int 2
7364           %b = OpVariable %_ptr_Workgroup_int Workgroup
7365       %int_3 = OpConstant %int 3
7366        %main = OpFunction %void None %3
7367           %5 = OpLabel
7368                OpStore %a %int_2
7369                OpStore %b %int_3
7370                OpReturn
7371                OpFunctionEnd
7372   )";
7373 
7374   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
7375   EXPECT_EQ(SPV_SUCCESS,
7376 	    ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_4));
7377 }
7378 
TEST_F(ValidateDecorations,WorkgroupBlockVariableWith16BitType)7379 TEST_F(ValidateDecorations, WorkgroupBlockVariableWith16BitType) {
7380   std::string spirv = R"(
7381                OpCapability Shader
7382                OpCapability Float16
7383                OpCapability Int16
7384                OpCapability WorkgroupMemoryExplicitLayout16BitAccessKHR
7385                OpExtension "SPV_KHR_workgroup_memory_explicit_layout"
7386                OpMemoryModel Logical GLSL450
7387                OpEntryPoint GLCompute %main "main" %_
7388                OpExecutionMode %main LocalSize 2 1 1
7389                OpMemberDecorate %first 0 Offset 0
7390                OpMemberDecorate %first 1 Offset 2
7391                OpDecorate %first Block
7392        %void = OpTypeVoid
7393           %3 = OpTypeFunction %void
7394       %short = OpTypeInt 16 1
7395        %half = OpTypeFloat 16
7396       %first = OpTypeStruct %short %half
7397 %_ptr_Workgroup_first = OpTypePointer Workgroup %first
7398           %_ = OpVariable %_ptr_Workgroup_first Workgroup
7399         %int = OpTypeInt 32 1
7400       %int_0 = OpConstant %int 0
7401     %short_3 = OpConstant %short 3
7402 %_ptr_Workgroup_short = OpTypePointer Workgroup %short
7403       %int_1 = OpConstant %int 1
7404 %half_0x1_898p_3 = OpConstant %half 0x1.898p+3
7405 %_ptr_Workgroup_half = OpTypePointer Workgroup %half
7406        %main = OpFunction %void None %3
7407           %5 = OpLabel
7408          %15 = OpAccessChain %_ptr_Workgroup_short %_ %int_0
7409                OpStore %15 %short_3
7410          %19 = OpAccessChain %_ptr_Workgroup_half %_ %int_1
7411                OpStore %19 %half_0x1_898p_3
7412                OpReturn
7413                OpFunctionEnd
7414   )";
7415 
7416   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
7417   EXPECT_EQ(SPV_SUCCESS,
7418 	    ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_4));
7419 }
7420 
TEST_F(ValidateDecorations,WorkgroupBlockVariableScalarLayout)7421 TEST_F(ValidateDecorations, WorkgroupBlockVariableScalarLayout) {
7422   std::string spirv = R"(
7423                OpCapability Shader
7424                OpCapability WorkgroupMemoryExplicitLayoutKHR
7425                OpExtension "SPV_KHR_workgroup_memory_explicit_layout"
7426                OpMemoryModel Logical GLSL450
7427                OpEntryPoint Vertex %main "main" %B
7428                OpSource GLSL 450
7429                OpMemberDecorate %S 0 Offset 0
7430                OpMemberDecorate %S 1 Offset 4
7431                OpMemberDecorate %S 2 Offset 16
7432                OpMemberDecorate %S 3 Offset 28
7433                OpDecorate %S Block
7434                OpDecorate %B Aliased
7435        %void = OpTypeVoid
7436           %3 = OpTypeFunction %void
7437       %float = OpTypeFloat 32
7438     %v3float = OpTypeVector %float 3
7439           %S = OpTypeStruct %float %v3float %v3float %v3float
7440 %_ptr_Workgroup_S = OpTypePointer Workgroup %S
7441           %B = OpVariable %_ptr_Workgroup_S Workgroup
7442        %main = OpFunction %void None %3
7443           %5 = OpLabel
7444                OpReturn
7445                OpFunctionEnd
7446   )";
7447 
7448   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
7449   spvValidatorOptionsSetWorkgroupScalarBlockLayout(getValidatorOptions(), true);
7450   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_4))
7451       << getDiagnosticString();
7452 }
7453 
TEST_F(ValidateDecorations,WorkgroupMixBlockAndNonBlockBad)7454 TEST_F(ValidateDecorations, WorkgroupMixBlockAndNonBlockBad) {
7455   std::string spirv = R"(
7456                OpCapability Shader
7457                OpCapability WorkgroupMemoryExplicitLayoutKHR
7458                OpExtension "SPV_KHR_workgroup_memory_explicit_layout"
7459                OpMemoryModel Logical GLSL450
7460                OpEntryPoint GLCompute %main "main" %_ %b
7461                OpExecutionMode %main LocalSize 8 1 1
7462                OpMemberDecorate %first 0 Offset 0
7463                OpDecorate %first Block
7464                OpDecorate %_ Aliased
7465                OpDecorate %b Aliased
7466        %void = OpTypeVoid
7467           %3 = OpTypeFunction %void
7468         %int = OpTypeInt 32 1
7469       %first = OpTypeStruct %int
7470 %_ptr_Workgroup_first = OpTypePointer Workgroup %first
7471           %_ = OpVariable %_ptr_Workgroup_first Workgroup
7472       %int_0 = OpConstant %int 0
7473       %int_2 = OpConstant %int 2
7474 %_ptr_Workgroup_int = OpTypePointer Workgroup %int
7475           %b = OpVariable %_ptr_Workgroup_int Workgroup
7476       %int_3 = OpConstant %int 3
7477        %main = OpFunction %void None %3
7478           %5 = OpLabel
7479          %13 = OpAccessChain %_ptr_Workgroup_int %_ %int_0
7480                OpStore %13 %int_2
7481                OpStore %b %int_3
7482                OpReturn
7483                OpFunctionEnd
7484   )";
7485 
7486   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
7487   EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
7488             ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_4));
7489   EXPECT_THAT(
7490       getDiagnosticString(),
7491       HasSubstr("either all or none of the Workgroup Storage Class variables "
7492                 "in the entry point interface must point to struct types "
7493                 "decorated with Block"));
7494 }
7495 
TEST_F(ValidateDecorations,WorkgroupMultiBlockVariableMissingAliased)7496 TEST_F(ValidateDecorations, WorkgroupMultiBlockVariableMissingAliased) {
7497   std::string spirv = R"(
7498                OpCapability Shader
7499                OpCapability WorkgroupMemoryExplicitLayoutKHR
7500                OpExtension "SPV_KHR_workgroup_memory_explicit_layout"
7501                OpMemoryModel Logical GLSL450
7502                OpEntryPoint GLCompute %main "main" %_ %__0
7503                OpExecutionMode %main LocalSize 8 1 1
7504                OpMemberDecorate %first 0 Offset 0
7505                OpDecorate %first Block
7506                OpMemberDecorate %second 0 Offset 0
7507                OpDecorate %second Block
7508                OpDecorate %_ Aliased
7509        %void = OpTypeVoid
7510           %3 = OpTypeFunction %void
7511         %int = OpTypeInt 32 1
7512       %first = OpTypeStruct %int
7513 %_ptr_Workgroup_first = OpTypePointer Workgroup %first
7514           %_ = OpVariable %_ptr_Workgroup_first Workgroup
7515       %int_0 = OpConstant %int 0
7516       %int_2 = OpConstant %int 2
7517 %_ptr_Workgroup_int = OpTypePointer Workgroup %int
7518      %second = OpTypeStruct %int
7519 %_ptr_Workgroup_second = OpTypePointer Workgroup %second
7520         %__0 = OpVariable %_ptr_Workgroup_second Workgroup
7521       %int_3 = OpConstant %int 3
7522        %main = OpFunction %void None %3
7523           %5 = OpLabel
7524          %13 = OpAccessChain %_ptr_Workgroup_int %_ %int_0
7525                OpStore %13 %int_2
7526          %18 = OpAccessChain %_ptr_Workgroup_int %__0 %int_0
7527                OpStore %18 %int_3
7528                OpReturn
7529                OpFunctionEnd
7530   )";
7531 
7532   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
7533   EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
7534             ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_4));
7535   EXPECT_THAT(
7536       getDiagnosticString(),
7537       HasSubstr("more than one Workgroup Storage Class variable in the "
7538                 "entry point interface point to a type decorated with Block, "
7539                 "all of them must be decorated with Aliased"));
7540 }
7541 
TEST_F(ValidateDecorations,WorkgroupSingleBlockVariableNotAStruct)7542 TEST_F(ValidateDecorations, WorkgroupSingleBlockVariableNotAStruct) {
7543   std::string spirv = R"(
7544                OpCapability Shader
7545                OpCapability WorkgroupMemoryExplicitLayoutKHR
7546                OpExtension "SPV_KHR_workgroup_memory_explicit_layout"
7547                OpMemoryModel Logical GLSL450
7548                OpEntryPoint GLCompute %main "main" %_
7549                OpExecutionMode %main LocalSize 8 1 1
7550                OpDecorate %first Block
7551        %void = OpTypeVoid
7552           %3 = OpTypeFunction %void
7553         %int = OpTypeInt 32 1
7554       %int_3 = OpConstant %int 3
7555       %first = OpTypeArray %int %int_3
7556 %_ptr_Workgroup_first = OpTypePointer Workgroup %first
7557           %_ = OpVariable %_ptr_Workgroup_first Workgroup
7558       %int_0 = OpConstant %int 0
7559       %int_2 = OpConstant %int 2
7560 %_ptr_Workgroup_int = OpTypePointer Workgroup %int
7561        %main = OpFunction %void None %3
7562           %5 = OpLabel
7563          %13 = OpAccessChain %_ptr_Workgroup_int %_ %int_0
7564                OpStore %13 %int_2
7565                OpReturn
7566                OpFunctionEnd
7567   )";
7568 
7569   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
7570   EXPECT_EQ(SPV_ERROR_INVALID_ID,
7571             ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_4));
7572   EXPECT_THAT(
7573       getDiagnosticString(),
7574       HasSubstr("Block decoration on a non-struct type"));
7575 }
7576 
TEST_F(ValidateDecorations,WorkgroupSingleBlockVariableMissingLayout)7577 TEST_F(ValidateDecorations, WorkgroupSingleBlockVariableMissingLayout) {
7578   std::string spirv = R"(
7579                OpCapability Shader
7580                OpCapability WorkgroupMemoryExplicitLayoutKHR
7581                OpExtension "SPV_KHR_workgroup_memory_explicit_layout"
7582                OpMemoryModel Logical GLSL450
7583                OpEntryPoint GLCompute %main "main" %_
7584                OpExecutionMode %main LocalSize 8 1 1
7585                OpDecorate %first Block
7586        %void = OpTypeVoid
7587           %3 = OpTypeFunction %void
7588         %int = OpTypeInt 32 1
7589       %first = OpTypeStruct %int
7590 %_ptr_Workgroup_first = OpTypePointer Workgroup %first
7591           %_ = OpVariable %_ptr_Workgroup_first Workgroup
7592       %int_0 = OpConstant %int 0
7593       %int_2 = OpConstant %int 2
7594 %_ptr_Workgroup_int = OpTypePointer Workgroup %int
7595        %main = OpFunction %void None %3
7596           %5 = OpLabel
7597          %13 = OpAccessChain %_ptr_Workgroup_int %_ %int_0
7598                OpStore %13 %int_2
7599                OpReturn
7600                OpFunctionEnd
7601   )";
7602 
7603   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
7604   EXPECT_EQ(SPV_ERROR_INVALID_ID,
7605             ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_4));
7606   EXPECT_THAT(
7607       getDiagnosticString(),
7608       HasSubstr("Block must be explicitly laid out with Offset decorations"));
7609 }
7610 
TEST_F(ValidateDecorations,WorkgroupSingleBlockVariableBadLayout)7611 TEST_F(ValidateDecorations, WorkgroupSingleBlockVariableBadLayout) {
7612   std::string spirv = R"(
7613                OpCapability Shader
7614                OpCapability WorkgroupMemoryExplicitLayoutKHR
7615                OpExtension "SPV_KHR_workgroup_memory_explicit_layout"
7616                OpMemoryModel Logical GLSL450
7617                OpEntryPoint GLCompute %main "main" %_
7618                OpExecutionMode %main LocalSize 8 1 1
7619                OpMemberDecorate %first 0 Offset 1
7620                OpDecorate %first Block
7621        %void = OpTypeVoid
7622           %3 = OpTypeFunction %void
7623         %int = OpTypeInt 32 1
7624       %first = OpTypeStruct %int
7625 %_ptr_Workgroup_first = OpTypePointer Workgroup %first
7626           %_ = OpVariable %_ptr_Workgroup_first Workgroup
7627       %int_0 = OpConstant %int 0
7628       %int_2 = OpConstant %int 2
7629 %_ptr_Workgroup_int = OpTypePointer Workgroup %int
7630        %main = OpFunction %void None %3
7631           %5 = OpLabel
7632          %13 = OpAccessChain %_ptr_Workgroup_int %_ %int_0
7633                OpStore %13 %int_2
7634                OpReturn
7635                OpFunctionEnd
7636   )";
7637 
7638   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
7639   EXPECT_EQ(SPV_ERROR_INVALID_ID,
7640             ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_4));
7641   EXPECT_THAT(
7642       getDiagnosticString(),
7643       HasSubstr(
7644           "Block for variable in Workgroup storage class must follow "
7645           "standard storage buffer layout rules: "
7646           "member 0 at offset 1 is not aligned to 4"));
7647 }
7648 
7649 }  // namespace
7650 }  // namespace val
7651 }  // namespace spvtools
7652