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/unit_spirv.h"
23 #include "test/val/val_fixtures.h"
24 
25 namespace spvtools {
26 namespace val {
27 namespace {
28 
29 using ::testing::Eq;
30 using ::testing::HasSubstr;
31 
32 using ValidateDecorations = spvtest::ValidateBase<bool>;
33 
TEST_F(ValidateDecorations,ValidateOpDecorateRegistration)34 TEST_F(ValidateDecorations, ValidateOpDecorateRegistration) {
35   std::string spirv = R"(
36     OpCapability Shader
37     OpCapability Linkage
38     OpMemoryModel Logical GLSL450
39     OpDecorate %1 ArrayStride 4
40     OpDecorate %1 RelaxedPrecision
41     %2 = OpTypeFloat 32
42     %1 = OpTypeRuntimeArray %2
43     ; Since %1 is used first in Decoration, it gets id 1.
44 )";
45   const uint32_t id = 1;
46   CompileSuccessfully(spirv);
47   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
48   // Must have 2 decorations.
49   EXPECT_THAT(
50       vstate_->id_decorations(id),
51       Eq(std::vector<Decoration>{Decoration(SpvDecorationArrayStride, {4}),
52                                  Decoration(SpvDecorationRelaxedPrecision)}));
53 }
54 
TEST_F(ValidateDecorations,ValidateOpMemberDecorateRegistration)55 TEST_F(ValidateDecorations, ValidateOpMemberDecorateRegistration) {
56   std::string spirv = R"(
57     OpCapability Shader
58     OpCapability Linkage
59     OpMemoryModel Logical GLSL450
60     OpDecorate %_arr_double_uint_6 ArrayStride 4
61     OpMemberDecorate %_struct_115 2 NonReadable
62     OpMemberDecorate %_struct_115 2 Offset 2
63     OpDecorate %_struct_115 BufferBlock
64     %float = OpTypeFloat 32
65     %uint = OpTypeInt 32 0
66     %uint_6 = OpConstant %uint 6
67     %_arr_double_uint_6 = OpTypeArray %float %uint_6
68     %_struct_115 = OpTypeStruct %float %float %_arr_double_uint_6
69 )";
70   CompileSuccessfully(spirv);
71   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
72 
73   // The array must have 1 decoration.
74   const uint32_t arr_id = 1;
75   EXPECT_THAT(
76       vstate_->id_decorations(arr_id),
77       Eq(std::vector<Decoration>{Decoration(SpvDecorationArrayStride, {4})}));
78 
79   // The struct must have 3 decorations.
80   const uint32_t struct_id = 2;
81   EXPECT_THAT(
82       vstate_->id_decorations(struct_id),
83       Eq(std::vector<Decoration>{Decoration(SpvDecorationNonReadable, {}, 2),
84                                  Decoration(SpvDecorationOffset, {2}, 2),
85                                  Decoration(SpvDecorationBufferBlock)}));
86 }
87 
TEST_F(ValidateDecorations,ValidateOpMemberDecorateOutOfBound)88 TEST_F(ValidateDecorations, ValidateOpMemberDecorateOutOfBound) {
89   std::string spirv = R"(
90                OpCapability Shader
91                OpMemoryModel Logical GLSL450
92                OpEntryPoint Fragment %1 "Main"
93                OpExecutionMode %1 OriginUpperLeft
94                OpMemberDecorate %_struct_2 1 RelaxedPrecision
95        %void = OpTypeVoid
96           %4 = OpTypeFunction %void
97       %float = OpTypeFloat 32
98   %_struct_2 = OpTypeStruct %float
99           %1 = OpFunction %void None %4
100           %6 = OpLabel
101                OpReturn
102                OpFunctionEnd
103 )";
104   CompileSuccessfully(spirv);
105   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
106   EXPECT_THAT(getDiagnosticString(),
107               HasSubstr("Index 1 provided in OpMemberDecorate for struct <id> "
108                         "2[%_struct_2] is out of bounds. The structure has 1 "
109                         "members. Largest valid index is 0."));
110 }
111 
TEST_F(ValidateDecorations,ValidateGroupDecorateRegistration)112 TEST_F(ValidateDecorations, ValidateGroupDecorateRegistration) {
113   std::string spirv = R"(
114                OpCapability Shader
115                OpCapability Linkage
116                OpMemoryModel Logical GLSL450
117                OpDecorate %1 DescriptorSet 0
118                OpDecorate %1 NonWritable
119                OpDecorate %1 Restrict
120           %1 = OpDecorationGroup
121                OpGroupDecorate %1 %2 %3
122                OpGroupDecorate %1 %4
123   %float = OpTypeFloat 32
124 %_runtimearr_float = OpTypeRuntimeArray %float
125   %_struct_9 = OpTypeStruct %_runtimearr_float
126 %_ptr_Uniform__struct_9 = OpTypePointer Uniform %_struct_9
127          %2 = OpVariable %_ptr_Uniform__struct_9 Uniform
128  %_struct_10 = OpTypeStruct %_runtimearr_float
129 %_ptr_Uniform__struct_10 = OpTypePointer Uniform %_struct_10
130          %3 = OpVariable %_ptr_Uniform__struct_10 Uniform
131  %_struct_11 = OpTypeStruct %_runtimearr_float
132 %_ptr_Uniform__struct_11 = OpTypePointer Uniform %_struct_11
133          %4 = OpVariable %_ptr_Uniform__struct_11 Uniform
134   )";
135   CompileSuccessfully(spirv);
136   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
137 
138   // Decoration group has 3 decorations.
139   auto expected_decorations = std::vector<Decoration>{
140       Decoration(SpvDecorationDescriptorSet, {0}),
141       Decoration(SpvDecorationNonWritable), Decoration(SpvDecorationRestrict)};
142 
143   // Decoration group is applied to id 1, 2, 3, and 4. Note that id 1 (which is
144   // the decoration group id) also has all the decorations.
145   EXPECT_THAT(vstate_->id_decorations(1), Eq(expected_decorations));
146   EXPECT_THAT(vstate_->id_decorations(2), Eq(expected_decorations));
147   EXPECT_THAT(vstate_->id_decorations(3), Eq(expected_decorations));
148   EXPECT_THAT(vstate_->id_decorations(4), Eq(expected_decorations));
149 }
150 
TEST_F(ValidateDecorations,WebGPUOpDecorationGroupBad)151 TEST_F(ValidateDecorations, WebGPUOpDecorationGroupBad) {
152   std::string spirv = R"(
153                OpCapability Shader
154                OpCapability VulkanMemoryModelKHR
155                OpExtension "SPV_KHR_vulkan_memory_model"
156                OpMemoryModel Logical VulkanKHR
157                OpDecorate %1 DescriptorSet 0
158                OpDecorate %1 NonWritable
159                OpDecorate %1 Restrict
160           %1 = OpDecorationGroup
161                OpGroupDecorate %1 %2 %3
162                OpGroupDecorate %1 %4
163   %float = OpTypeFloat 32
164 %_runtimearr_float = OpTypeRuntimeArray %float
165   %_struct_9 = OpTypeStruct %_runtimearr_float
166 %_ptr_Uniform__struct_9 = OpTypePointer Uniform %_struct_9
167          %2 = OpVariable %_ptr_Uniform__struct_9 Uniform
168  %_struct_10 = OpTypeStruct %_runtimearr_float
169 %_ptr_Uniform__struct_10 = OpTypePointer Uniform %_struct_10
170          %3 = OpVariable %_ptr_Uniform__struct_10 Uniform
171  %_struct_11 = OpTypeStruct %_runtimearr_float
172 %_ptr_Uniform__struct_11 = OpTypePointer Uniform %_struct_11
173          %4 = OpVariable %_ptr_Uniform__struct_11 Uniform
174   )";
175   CompileSuccessfully(spirv);
176   EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions(SPV_ENV_WEBGPU_0));
177   EXPECT_THAT(getDiagnosticString(),
178               HasSubstr("OpDecorationGroup is not allowed in the WebGPU "
179                         "execution environment.\n  %1 = OpDecorationGroup\n"));
180 }
181 
182 // For WebGPU, OpGroupDecorate does not have a test case, because it requires
183 // being preceded by OpDecorationGroup, which will cause a validation error.
184 
185 // For WebGPU, OpGroupMemberDecorate does not have a test case, because it
186 // requires being preceded by OpDecorationGroup, which will cause a validation
187 // error.
188 
TEST_F(ValidateDecorations,ValidateGroupMemberDecorateRegistration)189 TEST_F(ValidateDecorations, ValidateGroupMemberDecorateRegistration) {
190   std::string spirv = R"(
191                OpCapability Shader
192                OpCapability Linkage
193                OpMemoryModel Logical GLSL450
194                OpDecorate %1 Offset 3
195           %1 = OpDecorationGroup
196                OpGroupMemberDecorate %1 %_struct_1 3 %_struct_2 3 %_struct_3 3
197       %float = OpTypeFloat 32
198 %_runtimearr = OpTypeRuntimeArray %float
199   %_struct_1 = OpTypeStruct %float %float %float %_runtimearr
200   %_struct_2 = OpTypeStruct %float %float %float %_runtimearr
201   %_struct_3 = OpTypeStruct %float %float %float %_runtimearr
202   )";
203   CompileSuccessfully(spirv);
204   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
205   // Decoration group has 1 decoration.
206   auto expected_decorations =
207       std::vector<Decoration>{Decoration(SpvDecorationOffset, {3}, 3)};
208 
209   // Decoration group is applied to id 2, 3, and 4.
210   EXPECT_THAT(vstate_->id_decorations(2), Eq(expected_decorations));
211   EXPECT_THAT(vstate_->id_decorations(3), Eq(expected_decorations));
212   EXPECT_THAT(vstate_->id_decorations(4), Eq(expected_decorations));
213 }
214 
TEST_F(ValidateDecorations,LinkageImportUsedForInitializedVariableBad)215 TEST_F(ValidateDecorations, LinkageImportUsedForInitializedVariableBad) {
216   std::string spirv = R"(
217                OpCapability Shader
218                OpCapability Linkage
219                OpMemoryModel Logical GLSL450
220                OpDecorate %target LinkageAttributes "link_ptr" Import
221       %float = OpTypeFloat 32
222  %_ptr_float = OpTypePointer Uniform %float
223        %zero = OpConstantNull %float
224      %target = OpVariable %_ptr_float Uniform %zero
225   )";
226   CompileSuccessfully(spirv);
227   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
228   EXPECT_THAT(getDiagnosticString(),
229               HasSubstr("A module-scope OpVariable with initialization value "
230                         "cannot be marked with the Import Linkage Type."));
231 }
TEST_F(ValidateDecorations,LinkageExportUsedForInitializedVariableGood)232 TEST_F(ValidateDecorations, LinkageExportUsedForInitializedVariableGood) {
233   std::string spirv = R"(
234                OpCapability Shader
235                OpCapability Linkage
236                OpMemoryModel Logical GLSL450
237                OpDecorate %target LinkageAttributes "link_ptr" Export
238       %float = OpTypeFloat 32
239  %_ptr_float = OpTypePointer Uniform %float
240        %zero = OpConstantNull %float
241      %target = OpVariable %_ptr_float Uniform %zero
242   )";
243   CompileSuccessfully(spirv);
244   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
245 }
246 
TEST_F(ValidateDecorations,StructAllMembersHaveBuiltInDecorationsGood)247 TEST_F(ValidateDecorations, StructAllMembersHaveBuiltInDecorationsGood) {
248   std::string spirv = R"(
249                OpCapability Shader
250                OpCapability Linkage
251                OpMemoryModel Logical GLSL450
252                OpMemberDecorate %_struct_1 0 BuiltIn Position
253                OpMemberDecorate %_struct_1 1 BuiltIn Position
254                OpMemberDecorate %_struct_1 2 BuiltIn Position
255                OpMemberDecorate %_struct_1 3 BuiltIn Position
256       %float = OpTypeFloat 32
257 %_runtimearr = OpTypeRuntimeArray %float
258   %_struct_1 = OpTypeStruct %float %float %float %_runtimearr
259   )";
260   CompileSuccessfully(spirv);
261   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
262 }
263 
TEST_F(ValidateDecorations,MixedBuiltInDecorationsBad)264 TEST_F(ValidateDecorations, MixedBuiltInDecorationsBad) {
265   std::string spirv = R"(
266                OpCapability Shader
267                OpCapability Linkage
268                OpMemoryModel Logical GLSL450
269                OpMemberDecorate %_struct_1 0 BuiltIn Position
270                OpMemberDecorate %_struct_1 1 BuiltIn Position
271       %float = OpTypeFloat 32
272 %_runtimearr = OpTypeRuntimeArray %float
273   %_struct_1 = OpTypeStruct %float %float %float %_runtimearr
274   )";
275   CompileSuccessfully(spirv);
276   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
277   EXPECT_THAT(
278       getDiagnosticString(),
279       HasSubstr("When BuiltIn decoration is applied to a structure-type "
280                 "member, all members of that structure type must also be "
281                 "decorated with BuiltIn (No allowed mixing of built-in "
282                 "variables and non-built-in variables within a single "
283                 "structure). Structure id 1 does not meet this requirement."));
284 }
285 
TEST_F(ValidateDecorations,StructContainsBuiltInStructBad)286 TEST_F(ValidateDecorations, StructContainsBuiltInStructBad) {
287   std::string spirv = R"(
288                OpCapability Shader
289                OpCapability Linkage
290                OpMemoryModel Logical GLSL450
291                OpMemberDecorate %_struct_1 0 BuiltIn Position
292                OpMemberDecorate %_struct_1 1 BuiltIn Position
293                OpMemberDecorate %_struct_1 2 BuiltIn Position
294                OpMemberDecorate %_struct_1 3 BuiltIn Position
295       %float = OpTypeFloat 32
296 %_runtimearr = OpTypeRuntimeArray %float
297   %_struct_1 = OpTypeStruct %float %float %float %_runtimearr
298   %_struct_2 = OpTypeStruct %_struct_1
299   )";
300   CompileSuccessfully(spirv);
301   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
302   EXPECT_THAT(getDiagnosticString(),
303               HasSubstr("Structure <id> 1[%_struct_1] contains members with "
304                         "BuiltIn decoration. Therefore this structure may not "
305                         "be contained as a member of another structure type. "
306                         "Structure <id> 4[%_struct_4] contains structure <id> "
307                         "1[%_struct_1]."));
308 }
309 
TEST_F(ValidateDecorations,StructContainsNonBuiltInStructGood)310 TEST_F(ValidateDecorations, StructContainsNonBuiltInStructGood) {
311   std::string spirv = R"(
312                OpCapability Shader
313                OpCapability Linkage
314                OpMemoryModel Logical GLSL450
315       %float = OpTypeFloat 32
316   %_struct_1 = OpTypeStruct %float
317   %_struct_2 = OpTypeStruct %_struct_1
318   )";
319   CompileSuccessfully(spirv);
320   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
321 }
322 
TEST_F(ValidateDecorations,MultipleBuiltInObjectsConsumedByOpEntryPointBad)323 TEST_F(ValidateDecorations, MultipleBuiltInObjectsConsumedByOpEntryPointBad) {
324   std::string spirv = R"(
325                OpCapability Shader
326                OpCapability Geometry
327                OpMemoryModel Logical GLSL450
328                OpEntryPoint Geometry %main "main" %in_1 %in_2
329                OpExecutionMode %main InputPoints
330                OpExecutionMode %main OutputPoints
331                OpMemberDecorate %struct_1 0 BuiltIn InvocationId
332                OpMemberDecorate %struct_2 0 BuiltIn Position
333       %int = OpTypeInt 32 1
334      %void = OpTypeVoid
335      %func = OpTypeFunction %void
336     %float = OpTypeFloat 32
337  %struct_1 = OpTypeStruct %int
338  %struct_2 = OpTypeStruct %float
339 %ptr_builtin_1 = OpTypePointer Input %struct_1
340 %ptr_builtin_2 = OpTypePointer Input %struct_2
341 %in_1 = OpVariable %ptr_builtin_1 Input
342 %in_2 = OpVariable %ptr_builtin_2 Input
343        %main = OpFunction %void None %func
344           %5 = OpLabel
345                OpReturn
346                OpFunctionEnd
347   )";
348   CompileSuccessfully(spirv);
349   EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateAndRetrieveValidationState());
350   EXPECT_THAT(getDiagnosticString(),
351               HasSubstr("There must be at most one object per Storage Class "
352                         "that can contain a structure type containing members "
353                         "decorated with BuiltIn, consumed per entry-point."));
354 }
355 
TEST_F(ValidateDecorations,OneBuiltInObjectPerStorageClassConsumedByOpEntryPointGood)356 TEST_F(ValidateDecorations,
357        OneBuiltInObjectPerStorageClassConsumedByOpEntryPointGood) {
358   std::string spirv = R"(
359                OpCapability Shader
360                OpCapability Geometry
361                OpMemoryModel Logical GLSL450
362                OpEntryPoint Geometry %main "main" %in_1 %out_1
363                OpExecutionMode %main InputPoints
364                OpExecutionMode %main OutputPoints
365                OpMemberDecorate %struct_1 0 BuiltIn InvocationId
366                OpMemberDecorate %struct_2 0 BuiltIn Position
367       %int = OpTypeInt 32 1
368      %void = OpTypeVoid
369      %func = OpTypeFunction %void
370     %float = OpTypeFloat 32
371  %struct_1 = OpTypeStruct %int
372  %struct_2 = OpTypeStruct %float
373 %ptr_builtin_1 = OpTypePointer Input %struct_1
374 %ptr_builtin_2 = OpTypePointer Output %struct_2
375 %in_1 = OpVariable %ptr_builtin_1 Input
376 %out_1 = OpVariable %ptr_builtin_2 Output
377        %main = OpFunction %void None %func
378           %5 = OpLabel
379                OpReturn
380                OpFunctionEnd
381   )";
382   CompileSuccessfully(spirv);
383   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
384 }
385 
TEST_F(ValidateDecorations,NoBuiltInObjectsConsumedByOpEntryPointGood)386 TEST_F(ValidateDecorations, NoBuiltInObjectsConsumedByOpEntryPointGood) {
387   std::string spirv = R"(
388                OpCapability Shader
389                OpCapability Geometry
390                OpMemoryModel Logical GLSL450
391                OpEntryPoint Geometry %main "main" %in_1 %out_1
392                OpExecutionMode %main InputPoints
393                OpExecutionMode %main OutputPoints
394       %int = OpTypeInt 32 1
395      %void = OpTypeVoid
396      %func = OpTypeFunction %void
397     %float = OpTypeFloat 32
398  %struct_1 = OpTypeStruct %int
399  %struct_2 = OpTypeStruct %float
400 %ptr_builtin_1 = OpTypePointer Input %struct_1
401 %ptr_builtin_2 = OpTypePointer Output %struct_2
402 %in_1 = OpVariable %ptr_builtin_1 Input
403 %out_1 = OpVariable %ptr_builtin_2 Output
404        %main = OpFunction %void None %func
405           %5 = OpLabel
406                OpReturn
407                OpFunctionEnd
408   )";
409   CompileSuccessfully(spirv);
410   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
411 }
412 
TEST_F(ValidateDecorations,EntryPointFunctionHasLinkageAttributeBad)413 TEST_F(ValidateDecorations, EntryPointFunctionHasLinkageAttributeBad) {
414   std::string spirv = R"(
415       OpCapability Shader
416       OpCapability Linkage
417       OpMemoryModel Logical GLSL450
418       OpEntryPoint GLCompute %main "main"
419       OpDecorate %main LinkageAttributes "import_main" Import
420 %1 = OpTypeVoid
421 %2 = OpTypeFunction %1
422 %main = OpFunction %1 None %2
423 %4 = OpLabel
424      OpReturn
425      OpFunctionEnd
426 )";
427   CompileSuccessfully(spirv.c_str());
428   EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
429   EXPECT_THAT(
430       getDiagnosticString(),
431       HasSubstr("The LinkageAttributes Decoration (Linkage name: import_main) "
432                 "cannot be applied to function id 1 because it is targeted by "
433                 "an OpEntryPoint instruction."));
434 }
435 
TEST_F(ValidateDecorations,FunctionDeclarationWithoutImportLinkageBad)436 TEST_F(ValidateDecorations, FunctionDeclarationWithoutImportLinkageBad) {
437   std::string spirv = R"(
438                OpCapability Shader
439                OpCapability Linkage
440                OpMemoryModel Logical GLSL450
441      %void = OpTypeVoid
442      %func = OpTypeFunction %void
443        %main = OpFunction %void None %func
444                OpFunctionEnd
445   )";
446   CompileSuccessfully(spirv);
447   EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateAndRetrieveValidationState());
448   EXPECT_THAT(
449       getDiagnosticString(),
450       HasSubstr("Function declaration (id 3) must have a LinkageAttributes "
451                 "decoration with the Import Linkage type."));
452 }
453 
TEST_F(ValidateDecorations,FunctionDeclarationWithImportLinkageGood)454 TEST_F(ValidateDecorations, FunctionDeclarationWithImportLinkageGood) {
455   std::string spirv = R"(
456                OpCapability Shader
457                OpCapability Linkage
458                OpMemoryModel Logical GLSL450
459                OpDecorate %main LinkageAttributes "link_fn" Import
460      %void = OpTypeVoid
461      %func = OpTypeFunction %void
462        %main = OpFunction %void None %func
463                OpFunctionEnd
464   )";
465   CompileSuccessfully(spirv);
466   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
467 }
468 
TEST_F(ValidateDecorations,FunctionDeclarationWithExportLinkageBad)469 TEST_F(ValidateDecorations, FunctionDeclarationWithExportLinkageBad) {
470   std::string spirv = R"(
471                OpCapability Shader
472                OpCapability Linkage
473                OpMemoryModel Logical GLSL450
474                OpDecorate %main LinkageAttributes "link_fn" Export
475      %void = OpTypeVoid
476      %func = OpTypeFunction %void
477        %main = OpFunction %void None %func
478                OpFunctionEnd
479   )";
480   CompileSuccessfully(spirv);
481   EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateAndRetrieveValidationState());
482   EXPECT_THAT(
483       getDiagnosticString(),
484       HasSubstr("Function declaration (id 1) must have a LinkageAttributes "
485                 "decoration with the Import Linkage type."));
486 }
487 
TEST_F(ValidateDecorations,FunctionDefinitionWithImportLinkageBad)488 TEST_F(ValidateDecorations, FunctionDefinitionWithImportLinkageBad) {
489   std::string spirv = R"(
490                OpCapability Shader
491                OpCapability Linkage
492                OpMemoryModel Logical GLSL450
493                OpDecorate %main LinkageAttributes "link_fn" Import
494      %void = OpTypeVoid
495      %func = OpTypeFunction %void
496        %main = OpFunction %void None %func
497       %label = OpLabel
498                OpReturn
499                OpFunctionEnd
500   )";
501   CompileSuccessfully(spirv);
502   EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateAndRetrieveValidationState());
503   EXPECT_THAT(getDiagnosticString(),
504               HasSubstr("Function definition (id 1) may not be decorated with "
505                         "Import Linkage type."));
506 }
507 
TEST_F(ValidateDecorations,FunctionDefinitionWithoutImportLinkageGood)508 TEST_F(ValidateDecorations, FunctionDefinitionWithoutImportLinkageGood) {
509   std::string spirv = R"(
510                OpCapability Shader
511                OpCapability Linkage
512                OpMemoryModel Logical GLSL450
513      %void = OpTypeVoid
514      %func = OpTypeFunction %void
515        %main = OpFunction %void None %func
516       %label = OpLabel
517                OpReturn
518                OpFunctionEnd
519   )";
520   CompileSuccessfully(spirv);
521   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
522 }
523 
TEST_F(ValidateDecorations,BuiltinVariablesGoodVulkan)524 TEST_F(ValidateDecorations, BuiltinVariablesGoodVulkan) {
525   const spv_target_env env = SPV_ENV_VULKAN_1_0;
526   std::string spirv = R"(
527 OpCapability Shader
528 OpMemoryModel Logical GLSL450
529 OpEntryPoint Fragment %main "main" %gl_FragCoord %_entryPointOutput
530 OpExecutionMode %main OriginUpperLeft
531 OpSource HLSL 500
532 OpDecorate %gl_FragCoord BuiltIn FragCoord
533 OpDecorate %_entryPointOutput Location 0
534 %void = OpTypeVoid
535 %3 = OpTypeFunction %void
536 %float = OpTypeFloat 32
537 %v4float = OpTypeVector %float 4
538 %float_0 = OpConstant %float 0
539 %14 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
540 %_ptr_Input_v4float = OpTypePointer Input %v4float
541 %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
542 %_ptr_Output_v4float = OpTypePointer Output %v4float
543 %_entryPointOutput = OpVariable %_ptr_Output_v4float Output
544 %main = OpFunction %void None %3
545 %5 = OpLabel
546 OpStore %_entryPointOutput %14
547 OpReturn
548 OpFunctionEnd
549 )";
550 
551   CompileSuccessfully(spirv, env);
552   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env));
553 }
554 
TEST_F(ValidateDecorations,BuiltinVariablesWithLocationDecorationVulkan)555 TEST_F(ValidateDecorations, BuiltinVariablesWithLocationDecorationVulkan) {
556   const spv_target_env env = SPV_ENV_VULKAN_1_0;
557   std::string spirv = R"(
558 OpCapability Shader
559 OpMemoryModel Logical GLSL450
560 OpEntryPoint Fragment %main "main" %gl_FragCoord %_entryPointOutput
561 OpExecutionMode %main OriginUpperLeft
562 OpSource HLSL 500
563 OpDecorate %gl_FragCoord BuiltIn FragCoord
564 OpDecorate %gl_FragCoord Location 0
565 OpDecorate %_entryPointOutput Location 0
566 %void = OpTypeVoid
567 %3 = OpTypeFunction %void
568 %float = OpTypeFloat 32
569 %v4float = OpTypeVector %float 4
570 %float_0 = OpConstant %float 0
571 %14 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
572 %_ptr_Input_v4float = OpTypePointer Input %v4float
573 %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
574 %_ptr_Output_v4float = OpTypePointer Output %v4float
575 %_entryPointOutput = OpVariable %_ptr_Output_v4float Output
576 %main = OpFunction %void None %3
577 %5 = OpLabel
578 OpStore %_entryPointOutput %14
579 OpReturn
580 OpFunctionEnd
581 )";
582 
583   CompileSuccessfully(spirv, env);
584   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(env));
585   EXPECT_THAT(getDiagnosticString(),
586               HasSubstr("A BuiltIn variable (id 2) cannot have any Location or "
587                         "Component decorations"));
588 }
TEST_F(ValidateDecorations,BuiltinVariablesWithComponentDecorationVulkan)589 TEST_F(ValidateDecorations, BuiltinVariablesWithComponentDecorationVulkan) {
590   const spv_target_env env = SPV_ENV_VULKAN_1_0;
591   std::string spirv = R"(
592 OpCapability Shader
593 OpMemoryModel Logical GLSL450
594 OpEntryPoint Fragment %main "main" %gl_FragCoord %_entryPointOutput
595 OpExecutionMode %main OriginUpperLeft
596 OpSource HLSL 500
597 OpDecorate %gl_FragCoord BuiltIn FragCoord
598 OpDecorate %gl_FragCoord Component 0
599 OpDecorate %_entryPointOutput Location 0
600 %void = OpTypeVoid
601 %3 = OpTypeFunction %void
602 %float = OpTypeFloat 32
603 %v4float = OpTypeVector %float 4
604 %float_0 = OpConstant %float 0
605 %14 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
606 %_ptr_Input_v4float = OpTypePointer Input %v4float
607 %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
608 %_ptr_Output_v4float = OpTypePointer Output %v4float
609 %_entryPointOutput = OpVariable %_ptr_Output_v4float Output
610 %main = OpFunction %void None %3
611 %5 = OpLabel
612 OpStore %_entryPointOutput %14
613 OpReturn
614 OpFunctionEnd
615 )";
616 
617   CompileSuccessfully(spirv, env);
618   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(env));
619   EXPECT_THAT(getDiagnosticString(),
620               HasSubstr("A BuiltIn variable (id 2) cannot have any Location or "
621                         "Component decorations"));
622 }
623 
624 // #version 440
625 // #extension GL_EXT_nonuniform_qualifier : enable
626 // layout(binding = 1) uniform sampler2D s2d[];
627 // layout(location = 0) in nonuniformEXT int i;
628 // void main()
629 // {
630 //     vec4 v = texture(s2d[i], vec2(0.3));
631 // }
TEST_F(ValidateDecorations,RuntimeArrayOfDescriptorSetsIsAllowed)632 TEST_F(ValidateDecorations, RuntimeArrayOfDescriptorSetsIsAllowed) {
633   const spv_target_env env = SPV_ENV_VULKAN_1_0;
634   std::string spirv = R"(
635                OpCapability Shader
636                OpCapability ShaderNonUniformEXT
637                OpCapability RuntimeDescriptorArrayEXT
638                OpCapability SampledImageArrayNonUniformIndexingEXT
639                OpExtension "SPV_EXT_descriptor_indexing"
640           %1 = OpExtInstImport "GLSL.std.450"
641                OpMemoryModel Logical GLSL450
642                OpEntryPoint Vertex %main "main" %i
643                OpSource GLSL 440
644                OpSourceExtension "GL_EXT_nonuniform_qualifier"
645                OpName %main "main"
646                OpName %v "v"
647                OpName %s2d "s2d"
648                OpName %i "i"
649                OpDecorate %s2d DescriptorSet 0
650                OpDecorate %s2d Binding 1
651                OpDecorate %i Location 0
652                OpDecorate %i NonUniformEXT
653                OpDecorate %18 NonUniformEXT
654                OpDecorate %21 NonUniformEXT
655        %void = OpTypeVoid
656           %3 = OpTypeFunction %void
657       %float = OpTypeFloat 32
658     %v4float = OpTypeVector %float 4
659 %_ptr_Function_v4float = OpTypePointer Function %v4float
660          %10 = OpTypeImage %float 2D 0 0 0 1 Unknown
661          %11 = OpTypeSampledImage %10
662 %_runtimearr_11 = OpTypeRuntimeArray %11
663 %_ptr_Uniform__runtimearr_11 = OpTypePointer Uniform %_runtimearr_11
664         %s2d = OpVariable %_ptr_Uniform__runtimearr_11 Uniform
665         %int = OpTypeInt 32 1
666 %_ptr_Input_int = OpTypePointer Input %int
667           %i = OpVariable %_ptr_Input_int Input
668 %_ptr_Uniform_11 = OpTypePointer Uniform %11
669     %v2float = OpTypeVector %float 2
670 %float_0_300000012 = OpConstant %float 0.300000012
671          %24 = OpConstantComposite %v2float %float_0_300000012 %float_0_300000012
672     %float_0 = OpConstant %float 0
673        %main = OpFunction %void None %3
674           %5 = OpLabel
675           %v = OpVariable %_ptr_Function_v4float Function
676          %18 = OpLoad %int %i
677          %20 = OpAccessChain %_ptr_Uniform_11 %s2d %18
678          %21 = OpLoad %11 %20
679          %26 = OpImageSampleExplicitLod %v4float %21 %24 Lod %float_0
680                OpStore %v %26
681                OpReturn
682                OpFunctionEnd
683 )";
684   CompileSuccessfully(spirv, env);
685   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
686 }
687 
TEST_F(ValidateDecorations,BlockMissingOffsetBad)688 TEST_F(ValidateDecorations, BlockMissingOffsetBad) {
689   std::string spirv = R"(
690                OpCapability Shader
691           %1 = OpExtInstImport "GLSL.std.450"
692                OpMemoryModel Logical GLSL450
693                OpEntryPoint GLCompute %main "main"
694                OpExecutionMode %main LocalSize 1 1 1
695                OpSource GLSL 430
696                OpDecorate %Output Block
697        %void = OpTypeVoid
698           %3 = OpTypeFunction %void
699       %float = OpTypeFloat 32
700      %Output = OpTypeStruct %float
701 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
702  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
703        %main = OpFunction %void None %3
704           %5 = OpLabel
705                OpReturn
706                OpFunctionEnd
707   )";
708 
709   CompileSuccessfully(spirv);
710   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
711   EXPECT_THAT(getDiagnosticString(),
712               HasSubstr("must be explicitly laid out with Offset decorations"));
713 }
714 
TEST_F(ValidateDecorations,BufferBlockMissingOffsetBad)715 TEST_F(ValidateDecorations, BufferBlockMissingOffsetBad) {
716   std::string spirv = R"(
717                OpCapability Shader
718           %1 = OpExtInstImport "GLSL.std.450"
719                OpMemoryModel Logical GLSL450
720                OpEntryPoint GLCompute %main "main"
721                OpExecutionMode %main LocalSize 1 1 1
722                OpSource GLSL 430
723                OpDecorate %Output BufferBlock
724        %void = OpTypeVoid
725           %3 = OpTypeFunction %void
726       %float = OpTypeFloat 32
727      %Output = OpTypeStruct %float
728 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
729  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
730        %main = OpFunction %void None %3
731           %5 = OpLabel
732                OpReturn
733                OpFunctionEnd
734   )";
735 
736   CompileSuccessfully(spirv);
737   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
738   EXPECT_THAT(getDiagnosticString(),
739               HasSubstr("must be explicitly laid out with Offset decorations"));
740 }
741 
TEST_F(ValidateDecorations,BlockNestedStructMissingOffsetBad)742 TEST_F(ValidateDecorations, BlockNestedStructMissingOffsetBad) {
743   std::string spirv = R"(
744                OpCapability Shader
745           %1 = OpExtInstImport "GLSL.std.450"
746                OpMemoryModel Logical GLSL450
747                OpEntryPoint GLCompute %main "main"
748                OpExecutionMode %main LocalSize 1 1 1
749                OpSource GLSL 430
750                OpMemberDecorate %S 0 Offset 0
751                OpMemberDecorate %Output 0 Offset 0
752                OpMemberDecorate %Output 1 Offset 16
753                OpMemberDecorate %Output 2 Offset 32
754                OpDecorate %Output Block
755        %void = OpTypeVoid
756           %3 = OpTypeFunction %void
757       %float = OpTypeFloat 32
758     %v4float = OpTypeVector %float 4
759     %v3float = OpTypeVector %float 3
760         %int = OpTypeInt 32 1
761           %S = OpTypeStruct %v3float %int
762      %Output = OpTypeStruct %float %v4float %S
763 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
764  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
765        %main = OpFunction %void None %3
766           %5 = OpLabel
767                OpReturn
768                OpFunctionEnd
769   )";
770 
771   CompileSuccessfully(spirv);
772   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
773   EXPECT_THAT(getDiagnosticString(),
774               HasSubstr("must be explicitly laid out with Offset decorations"));
775 }
776 
TEST_F(ValidateDecorations,BufferBlockNestedStructMissingOffsetBad)777 TEST_F(ValidateDecorations, BufferBlockNestedStructMissingOffsetBad) {
778   std::string spirv = R"(
779                OpCapability Shader
780           %1 = OpExtInstImport "GLSL.std.450"
781                OpMemoryModel Logical GLSL450
782                OpEntryPoint GLCompute %main "main"
783                OpExecutionMode %main LocalSize 1 1 1
784                OpSource GLSL 430
785                OpMemberDecorate %S 0 Offset 0
786                OpMemberDecorate %Output 0 Offset 0
787                OpMemberDecorate %Output 1 Offset 16
788                OpMemberDecorate %Output 2 Offset 32
789                OpDecorate %Output BufferBlock
790        %void = OpTypeVoid
791           %3 = OpTypeFunction %void
792       %float = OpTypeFloat 32
793     %v4float = OpTypeVector %float 4
794     %v3float = OpTypeVector %float 3
795         %int = OpTypeInt 32 1
796           %S = OpTypeStruct %v3float %int
797      %Output = OpTypeStruct %float %v4float %S
798 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
799  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
800        %main = OpFunction %void None %3
801           %5 = OpLabel
802                OpReturn
803                OpFunctionEnd
804   )";
805 
806   CompileSuccessfully(spirv);
807   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
808   EXPECT_THAT(getDiagnosticString(),
809               HasSubstr("must be explicitly laid out with Offset decorations"));
810 }
811 
TEST_F(ValidateDecorations,BlockGLSLSharedBad)812 TEST_F(ValidateDecorations, BlockGLSLSharedBad) {
813   std::string spirv = R"(
814                OpCapability Shader
815           %1 = OpExtInstImport "GLSL.std.450"
816                OpMemoryModel Logical GLSL450
817                OpEntryPoint GLCompute %main "main"
818                OpExecutionMode %main LocalSize 1 1 1
819                OpSource GLSL 430
820                OpDecorate %Output Block
821                OpDecorate %Output GLSLShared
822                OpMemberDecorate %Output 0 Offset 0
823        %void = OpTypeVoid
824           %3 = OpTypeFunction %void
825       %float = OpTypeFloat 32
826      %Output = OpTypeStruct %float
827 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
828  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
829        %main = OpFunction %void None %3
830           %5 = OpLabel
831                OpReturn
832                OpFunctionEnd
833   )";
834 
835   CompileSuccessfully(spirv);
836   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
837   EXPECT_THAT(getDiagnosticString(),
838               HasSubstr("must not use GLSLShared decoration"));
839 }
840 
TEST_F(ValidateDecorations,BufferBlockGLSLSharedBad)841 TEST_F(ValidateDecorations, BufferBlockGLSLSharedBad) {
842   std::string spirv = R"(
843                OpCapability Shader
844           %1 = OpExtInstImport "GLSL.std.450"
845                OpMemoryModel Logical GLSL450
846                OpEntryPoint GLCompute %main "main"
847                OpExecutionMode %main LocalSize 1 1 1
848                OpSource GLSL 430
849                OpDecorate %Output BufferBlock
850                OpDecorate %Output GLSLShared
851                OpMemberDecorate %Output 0 Offset 0
852        %void = OpTypeVoid
853           %3 = OpTypeFunction %void
854       %float = OpTypeFloat 32
855      %Output = OpTypeStruct %float
856 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
857  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
858        %main = OpFunction %void None %3
859           %5 = OpLabel
860                OpReturn
861                OpFunctionEnd
862   )";
863 
864   CompileSuccessfully(spirv);
865   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
866   EXPECT_THAT(getDiagnosticString(),
867               HasSubstr("must not use GLSLShared decoration"));
868 }
869 
TEST_F(ValidateDecorations,BlockNestedStructGLSLSharedBad)870 TEST_F(ValidateDecorations, BlockNestedStructGLSLSharedBad) {
871   std::string spirv = R"(
872                OpCapability Shader
873           %1 = OpExtInstImport "GLSL.std.450"
874                OpMemoryModel Logical GLSL450
875                OpEntryPoint GLCompute %main "main"
876                OpExecutionMode %main LocalSize 1 1 1
877                OpSource GLSL 430
878                OpMemberDecorate %S 0 Offset 0
879                OpDecorate %S GLSLShared
880                OpMemberDecorate %Output 0 Offset 0
881                OpMemberDecorate %Output 1 Offset 16
882                OpMemberDecorate %Output 2 Offset 32
883                OpDecorate %Output Block
884        %void = OpTypeVoid
885           %3 = OpTypeFunction %void
886       %float = OpTypeFloat 32
887     %v4float = OpTypeVector %float 4
888         %int = OpTypeInt 32 1
889           %S = OpTypeStruct %int
890      %Output = OpTypeStruct %float %v4float %S
891 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
892  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
893        %main = OpFunction %void None %3
894           %5 = OpLabel
895                OpReturn
896                OpFunctionEnd
897   )";
898 
899   CompileSuccessfully(spirv);
900   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
901   EXPECT_THAT(getDiagnosticString(),
902               HasSubstr("must not use GLSLShared decoration"));
903 }
904 
TEST_F(ValidateDecorations,BufferBlockNestedStructGLSLSharedBad)905 TEST_F(ValidateDecorations, BufferBlockNestedStructGLSLSharedBad) {
906   std::string spirv = R"(
907                OpCapability Shader
908           %1 = OpExtInstImport "GLSL.std.450"
909                OpMemoryModel Logical GLSL450
910                OpEntryPoint GLCompute %main "main"
911                OpExecutionMode %main LocalSize 1 1 1
912                OpSource GLSL 430
913                OpMemberDecorate %S 0 Offset 0
914                OpDecorate %S GLSLShared
915                OpMemberDecorate %Output 0 Offset 0
916                OpMemberDecorate %Output 1 Offset 16
917                OpMemberDecorate %Output 2 Offset 32
918                OpDecorate %Output BufferBlock
919        %void = OpTypeVoid
920           %3 = OpTypeFunction %void
921       %float = OpTypeFloat 32
922     %v4float = OpTypeVector %float 4
923         %int = OpTypeInt 32 1
924           %S = OpTypeStruct %int
925      %Output = OpTypeStruct %float %v4float %S
926 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
927  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
928        %main = OpFunction %void None %3
929           %5 = OpLabel
930                OpReturn
931                OpFunctionEnd
932   )";
933 
934   CompileSuccessfully(spirv);
935   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
936   EXPECT_THAT(getDiagnosticString(),
937               HasSubstr("must not use GLSLShared decoration"));
938 }
939 
TEST_F(ValidateDecorations,BlockGLSLPackedBad)940 TEST_F(ValidateDecorations, BlockGLSLPackedBad) {
941   std::string spirv = R"(
942                OpCapability Shader
943           %1 = OpExtInstImport "GLSL.std.450"
944                OpMemoryModel Logical GLSL450
945                OpEntryPoint GLCompute %main "main"
946                OpExecutionMode %main LocalSize 1 1 1
947                OpSource GLSL 430
948                OpDecorate %Output Block
949                OpDecorate %Output GLSLPacked
950                OpMemberDecorate %Output 0 Offset 0
951        %void = OpTypeVoid
952           %3 = OpTypeFunction %void
953       %float = OpTypeFloat 32
954      %Output = OpTypeStruct %float
955 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
956  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
957        %main = OpFunction %void None %3
958           %5 = OpLabel
959                OpReturn
960                OpFunctionEnd
961   )";
962 
963   CompileSuccessfully(spirv);
964   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
965   EXPECT_THAT(getDiagnosticString(),
966               HasSubstr("must not use GLSLPacked decoration"));
967 }
968 
TEST_F(ValidateDecorations,BufferBlockGLSLPackedBad)969 TEST_F(ValidateDecorations, BufferBlockGLSLPackedBad) {
970   std::string spirv = R"(
971                OpCapability Shader
972           %1 = OpExtInstImport "GLSL.std.450"
973                OpMemoryModel Logical GLSL450
974                OpEntryPoint GLCompute %main "main"
975                OpExecutionMode %main LocalSize 1 1 1
976                OpSource GLSL 430
977                OpDecorate %Output BufferBlock
978                OpDecorate %Output GLSLPacked
979                OpMemberDecorate %Output 0 Offset 0
980        %void = OpTypeVoid
981           %3 = OpTypeFunction %void
982       %float = OpTypeFloat 32
983      %Output = OpTypeStruct %float
984 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
985  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
986        %main = OpFunction %void None %3
987           %5 = OpLabel
988                OpReturn
989                OpFunctionEnd
990   )";
991 
992   CompileSuccessfully(spirv);
993   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
994   EXPECT_THAT(getDiagnosticString(),
995               HasSubstr("must not use GLSLPacked decoration"));
996 }
997 
TEST_F(ValidateDecorations,BlockNestedStructGLSLPackedBad)998 TEST_F(ValidateDecorations, BlockNestedStructGLSLPackedBad) {
999   std::string spirv = R"(
1000                OpCapability Shader
1001           %1 = OpExtInstImport "GLSL.std.450"
1002                OpMemoryModel Logical GLSL450
1003                OpEntryPoint GLCompute %main "main"
1004                OpExecutionMode %main LocalSize 1 1 1
1005                OpSource GLSL 430
1006                OpMemberDecorate %S 0 Offset 0
1007                OpDecorate %S GLSLPacked
1008                OpMemberDecorate %Output 0 Offset 0
1009                OpMemberDecorate %Output 1 Offset 16
1010                OpMemberDecorate %Output 2 Offset 32
1011                OpDecorate %Output Block
1012        %void = OpTypeVoid
1013           %3 = OpTypeFunction %void
1014       %float = OpTypeFloat 32
1015     %v4float = OpTypeVector %float 4
1016         %int = OpTypeInt 32 1
1017           %S = OpTypeStruct %int
1018      %Output = OpTypeStruct %float %v4float %S
1019 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
1020  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
1021        %main = OpFunction %void None %3
1022           %5 = OpLabel
1023                OpReturn
1024                OpFunctionEnd
1025   )";
1026 
1027   CompileSuccessfully(spirv);
1028   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
1029   EXPECT_THAT(getDiagnosticString(),
1030               HasSubstr("must not use GLSLPacked decoration"));
1031 }
1032 
TEST_F(ValidateDecorations,BufferBlockNestedStructGLSLPackedBad)1033 TEST_F(ValidateDecorations, BufferBlockNestedStructGLSLPackedBad) {
1034   std::string spirv = R"(
1035                OpCapability Shader
1036           %1 = OpExtInstImport "GLSL.std.450"
1037                OpMemoryModel Logical GLSL450
1038                OpEntryPoint GLCompute %main "main"
1039                OpExecutionMode %main LocalSize 1 1 1
1040                OpSource GLSL 430
1041                OpMemberDecorate %S 0 Offset 0
1042                OpDecorate %S GLSLPacked
1043                OpMemberDecorate %Output 0 Offset 0
1044                OpMemberDecorate %Output 1 Offset 16
1045                OpMemberDecorate %Output 2 Offset 32
1046                OpDecorate %Output BufferBlock
1047        %void = OpTypeVoid
1048           %3 = OpTypeFunction %void
1049       %float = OpTypeFloat 32
1050     %v4float = OpTypeVector %float 4
1051         %int = OpTypeInt 32 1
1052           %S = OpTypeStruct %int
1053      %Output = OpTypeStruct %float %v4float %S
1054 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
1055  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
1056        %main = OpFunction %void None %3
1057           %5 = OpLabel
1058                OpReturn
1059                OpFunctionEnd
1060   )";
1061 
1062   CompileSuccessfully(spirv);
1063   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
1064   EXPECT_THAT(getDiagnosticString(),
1065               HasSubstr("must not use GLSLPacked decoration"));
1066 }
1067 
TEST_F(ValidateDecorations,BlockMissingArrayStrideBad)1068 TEST_F(ValidateDecorations, BlockMissingArrayStrideBad) {
1069   std::string spirv = R"(
1070                OpCapability Shader
1071           %1 = OpExtInstImport "GLSL.std.450"
1072                OpMemoryModel Logical GLSL450
1073                OpEntryPoint GLCompute %main "main"
1074                OpExecutionMode %main LocalSize 1 1 1
1075                OpSource GLSL 430
1076                OpDecorate %Output Block
1077                OpMemberDecorate %Output 0 Offset 0
1078        %void = OpTypeVoid
1079           %3 = OpTypeFunction %void
1080       %float = OpTypeFloat 32
1081         %int = OpTypeInt 32 1
1082       %int_3 = OpConstant %int 3
1083       %array = OpTypeArray %float %int_3
1084      %Output = OpTypeStruct %array
1085 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
1086  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
1087        %main = OpFunction %void None %3
1088           %5 = OpLabel
1089                OpReturn
1090                OpFunctionEnd
1091   )";
1092 
1093   CompileSuccessfully(spirv);
1094   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
1095   EXPECT_THAT(
1096       getDiagnosticString(),
1097       HasSubstr("must be explicitly laid out with ArrayStride decorations"));
1098 }
1099 
TEST_F(ValidateDecorations,BufferBlockMissingArrayStrideBad)1100 TEST_F(ValidateDecorations, BufferBlockMissingArrayStrideBad) {
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 BufferBlock
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,BlockNestedStructMissingArrayStrideBad)1132 TEST_F(ValidateDecorations, BlockNestedStructMissingArrayStrideBad) {
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                OpMemberDecorate %S 0 Offset 0
1141                OpMemberDecorate %Output 0 Offset 0
1142                OpMemberDecorate %Output 1 Offset 16
1143                OpMemberDecorate %Output 2 Offset 32
1144                OpDecorate %Output Block
1145        %void = OpTypeVoid
1146           %3 = OpTypeFunction %void
1147       %float = OpTypeFloat 32
1148     %v4float = OpTypeVector %float 4
1149         %int = OpTypeInt 32 1
1150       %int_3 = OpConstant %int 3
1151       %array = OpTypeArray %float %int_3
1152           %S = OpTypeStruct %array
1153      %Output = OpTypeStruct %float %v4float %S
1154 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
1155  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
1156        %main = OpFunction %void None %3
1157           %5 = OpLabel
1158                OpReturn
1159                OpFunctionEnd
1160   )";
1161 
1162   CompileSuccessfully(spirv);
1163   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
1164   EXPECT_THAT(
1165       getDiagnosticString(),
1166       HasSubstr("must be explicitly laid out with ArrayStride decorations"));
1167 }
1168 
TEST_F(ValidateDecorations,BufferBlockNestedStructMissingArrayStrideBad)1169 TEST_F(ValidateDecorations, BufferBlockNestedStructMissingArrayStrideBad) {
1170   std::string spirv = R"(
1171                OpCapability Shader
1172           %1 = OpExtInstImport "GLSL.std.450"
1173                OpMemoryModel Logical GLSL450
1174                OpEntryPoint GLCompute %main "main"
1175                OpExecutionMode %main LocalSize 1 1 1
1176                OpSource GLSL 430
1177                OpMemberDecorate %S 0 Offset 0
1178                OpMemberDecorate %Output 0 Offset 0
1179                OpMemberDecorate %Output 1 Offset 16
1180                OpMemberDecorate %Output 2 Offset 32
1181                OpDecorate %Output BufferBlock
1182        %void = OpTypeVoid
1183           %3 = OpTypeFunction %void
1184       %float = OpTypeFloat 32
1185     %v4float = OpTypeVector %float 4
1186         %int = OpTypeInt 32 1
1187       %int_3 = OpConstant %int 3
1188       %array = OpTypeArray %float %int_3
1189           %S = OpTypeStruct %array
1190      %Output = OpTypeStruct %float %v4float %S
1191 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
1192  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
1193        %main = OpFunction %void None %3
1194           %5 = OpLabel
1195                OpReturn
1196                OpFunctionEnd
1197   )";
1198 
1199   CompileSuccessfully(spirv);
1200   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
1201   EXPECT_THAT(
1202       getDiagnosticString(),
1203       HasSubstr("must be explicitly laid out with ArrayStride decorations"));
1204 }
1205 
TEST_F(ValidateDecorations,BlockMissingMatrixStrideBad)1206 TEST_F(ValidateDecorations, BlockMissingMatrixStrideBad) {
1207   std::string spirv = R"(
1208                OpCapability Shader
1209           %1 = OpExtInstImport "GLSL.std.450"
1210                OpMemoryModel Logical GLSL450
1211                OpEntryPoint GLCompute %main "main"
1212                OpExecutionMode %main LocalSize 1 1 1
1213                OpSource GLSL 430
1214                OpDecorate %Output Block
1215                OpMemberDecorate %Output 0 Offset 0
1216        %void = OpTypeVoid
1217           %3 = OpTypeFunction %void
1218       %float = OpTypeFloat 32
1219     %v3float = OpTypeVector %float 3
1220      %matrix = OpTypeMatrix %v3float 4
1221      %Output = OpTypeStruct %matrix
1222 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
1223  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
1224        %main = OpFunction %void None %3
1225           %5 = OpLabel
1226                OpReturn
1227                OpFunctionEnd
1228   )";
1229 
1230   CompileSuccessfully(spirv);
1231   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
1232   EXPECT_THAT(
1233       getDiagnosticString(),
1234       HasSubstr("must be explicitly laid out with MatrixStride decorations"));
1235 }
1236 
TEST_F(ValidateDecorations,BufferBlockMissingMatrixStrideBad)1237 TEST_F(ValidateDecorations, BufferBlockMissingMatrixStrideBad) {
1238   std::string spirv = R"(
1239                OpCapability Shader
1240           %1 = OpExtInstImport "GLSL.std.450"
1241                OpMemoryModel Logical GLSL450
1242                OpEntryPoint GLCompute %main "main"
1243                OpExecutionMode %main LocalSize 1 1 1
1244                OpSource GLSL 430
1245                OpDecorate %Output BufferBlock
1246                OpMemberDecorate %Output 0 Offset 0
1247        %void = OpTypeVoid
1248           %3 = OpTypeFunction %void
1249       %float = OpTypeFloat 32
1250     %v3float = OpTypeVector %float 3
1251      %matrix = OpTypeMatrix %v3float 4
1252      %Output = OpTypeStruct %matrix
1253 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
1254  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
1255        %main = OpFunction %void None %3
1256           %5 = OpLabel
1257                OpReturn
1258                OpFunctionEnd
1259   )";
1260 
1261   CompileSuccessfully(spirv);
1262   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
1263   EXPECT_THAT(
1264       getDiagnosticString(),
1265       HasSubstr("must be explicitly laid out with MatrixStride decorations"));
1266 }
1267 
TEST_F(ValidateDecorations,BlockMissingMatrixStrideArrayBad)1268 TEST_F(ValidateDecorations, BlockMissingMatrixStrideArrayBad) {
1269   std::string spirv = R"(
1270                OpCapability Shader
1271           %1 = OpExtInstImport "GLSL.std.450"
1272                OpMemoryModel Logical GLSL450
1273                OpEntryPoint GLCompute %main "main"
1274                OpExecutionMode %main LocalSize 1 1 1
1275                OpSource GLSL 430
1276                OpDecorate %Output Block
1277                OpMemberDecorate %Output 0 Offset 0
1278        %void = OpTypeVoid
1279           %3 = OpTypeFunction %void
1280       %float = OpTypeFloat 32
1281     %v3float = OpTypeVector %float 3
1282      %matrix = OpTypeMatrix %v3float 4
1283         %int = OpTypeInt 32 1
1284       %int_3 = OpConstant %int 3
1285       %array = OpTypeArray %matrix %int_3
1286      %Output = OpTypeStruct %matrix
1287 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
1288  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
1289        %main = OpFunction %void None %3
1290           %5 = OpLabel
1291                OpReturn
1292                OpFunctionEnd
1293   )";
1294 
1295   CompileSuccessfully(spirv);
1296   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
1297   EXPECT_THAT(
1298       getDiagnosticString(),
1299       HasSubstr("must be explicitly laid out with MatrixStride decorations"));
1300 }
1301 
TEST_F(ValidateDecorations,BufferBlockMissingMatrixStrideArrayBad)1302 TEST_F(ValidateDecorations, BufferBlockMissingMatrixStrideArrayBad) {
1303   std::string spirv = R"(
1304                OpCapability Shader
1305           %1 = OpExtInstImport "GLSL.std.450"
1306                OpMemoryModel Logical GLSL450
1307                OpEntryPoint GLCompute %main "main"
1308                OpExecutionMode %main LocalSize 1 1 1
1309                OpSource GLSL 430
1310                OpDecorate %Output BufferBlock
1311                OpMemberDecorate %Output 0 Offset 0
1312        %void = OpTypeVoid
1313           %3 = OpTypeFunction %void
1314       %float = OpTypeFloat 32
1315     %v3float = OpTypeVector %float 3
1316      %matrix = OpTypeMatrix %v3float 4
1317         %int = OpTypeInt 32 1
1318       %int_3 = OpConstant %int 3
1319       %array = OpTypeArray %matrix %int_3
1320      %Output = OpTypeStruct %matrix
1321 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
1322  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
1323        %main = OpFunction %void None %3
1324           %5 = OpLabel
1325                OpReturn
1326                OpFunctionEnd
1327   )";
1328 
1329   CompileSuccessfully(spirv);
1330   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
1331   EXPECT_THAT(
1332       getDiagnosticString(),
1333       HasSubstr("must be explicitly laid out with MatrixStride decorations"));
1334 }
1335 
TEST_F(ValidateDecorations,BlockNestedStructMissingMatrixStrideBad)1336 TEST_F(ValidateDecorations, BlockNestedStructMissingMatrixStrideBad) {
1337   std::string spirv = R"(
1338                OpCapability Shader
1339           %1 = OpExtInstImport "GLSL.std.450"
1340                OpMemoryModel Logical GLSL450
1341                OpEntryPoint GLCompute %main "main"
1342                OpExecutionMode %main LocalSize 1 1 1
1343                OpSource GLSL 430
1344                OpMemberDecorate %S 0 Offset 0
1345                OpMemberDecorate %Output 0 Offset 0
1346                OpMemberDecorate %Output 1 Offset 16
1347                OpMemberDecorate %Output 2 Offset 32
1348                OpDecorate %Output Block
1349        %void = OpTypeVoid
1350           %3 = OpTypeFunction %void
1351       %float = OpTypeFloat 32
1352     %v3float = OpTypeVector %float 3
1353     %v4float = OpTypeVector %float 4
1354      %matrix = OpTypeMatrix %v3float 4
1355           %S = OpTypeStruct %matrix
1356      %Output = OpTypeStruct %float %v4float %S
1357 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
1358  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
1359        %main = OpFunction %void None %3
1360           %5 = OpLabel
1361                OpReturn
1362                OpFunctionEnd
1363   )";
1364 
1365   CompileSuccessfully(spirv);
1366   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
1367   EXPECT_THAT(
1368       getDiagnosticString(),
1369       HasSubstr("must be explicitly laid out with MatrixStride decorations"));
1370 }
1371 
TEST_F(ValidateDecorations,BufferBlockNestedStructMissingMatrixStrideBad)1372 TEST_F(ValidateDecorations, BufferBlockNestedStructMissingMatrixStrideBad) {
1373   std::string spirv = R"(
1374                OpCapability Shader
1375           %1 = OpExtInstImport "GLSL.std.450"
1376                OpMemoryModel Logical GLSL450
1377                OpEntryPoint GLCompute %main "main"
1378                OpExecutionMode %main LocalSize 1 1 1
1379                OpSource GLSL 430
1380                OpMemberDecorate %S 0 Offset 0
1381                OpMemberDecorate %Output 0 Offset 0
1382                OpMemberDecorate %Output 1 Offset 16
1383                OpMemberDecorate %Output 2 Offset 32
1384                OpDecorate %Output BufferBlock
1385        %void = OpTypeVoid
1386           %3 = OpTypeFunction %void
1387       %float = OpTypeFloat 32
1388     %v3float = OpTypeVector %float 3
1389     %v4float = OpTypeVector %float 4
1390      %matrix = OpTypeMatrix %v3float 4
1391           %S = OpTypeStruct %matrix
1392      %Output = OpTypeStruct %float %v4float %S
1393 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
1394  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
1395        %main = OpFunction %void None %3
1396           %5 = OpLabel
1397                OpReturn
1398                OpFunctionEnd
1399   )";
1400 
1401   CompileSuccessfully(spirv);
1402   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
1403   EXPECT_THAT(
1404       getDiagnosticString(),
1405       HasSubstr("must be explicitly laid out with MatrixStride decorations"));
1406 }
1407 
TEST_F(ValidateDecorations,BlockStandardUniformBufferLayout)1408 TEST_F(ValidateDecorations, BlockStandardUniformBufferLayout) {
1409   std::string spirv = R"(
1410                OpCapability Shader
1411           %1 = OpExtInstImport "GLSL.std.450"
1412                OpMemoryModel Logical GLSL450
1413                OpEntryPoint GLCompute %main "main"
1414                OpExecutionMode %main LocalSize 1 1 1
1415                OpSource GLSL 430
1416                OpMemberDecorate %F 0 Offset 0
1417                OpMemberDecorate %F 1 Offset 8
1418                OpDecorate %_arr_float_uint_2 ArrayStride 16
1419                OpDecorate %_arr_mat3v3float_uint_2 ArrayStride 48
1420                OpMemberDecorate %O 0 Offset 0
1421                OpMemberDecorate %O 1 Offset 16
1422                OpMemberDecorate %O 2 Offset 32
1423                OpMemberDecorate %O 3 Offset 64
1424                OpMemberDecorate %O 4 ColMajor
1425                OpMemberDecorate %O 4 Offset 80
1426                OpMemberDecorate %O 4 MatrixStride 16
1427                OpDecorate %_arr_O_uint_2 ArrayStride 176
1428                OpMemberDecorate %Output 0 Offset 0
1429                OpMemberDecorate %Output 1 Offset 8
1430                OpMemberDecorate %Output 2 Offset 16
1431                OpMemberDecorate %Output 3 Offset 32
1432                OpMemberDecorate %Output 4 Offset 48
1433                OpMemberDecorate %Output 5 Offset 64
1434                OpMemberDecorate %Output 6 ColMajor
1435                OpMemberDecorate %Output 6 Offset 96
1436                OpMemberDecorate %Output 6 MatrixStride 16
1437                OpMemberDecorate %Output 7 Offset 128
1438                OpDecorate %Output Block
1439        %void = OpTypeVoid
1440           %3 = OpTypeFunction %void
1441       %float = OpTypeFloat 32
1442     %v2float = OpTypeVector %float 2
1443     %v3float = OpTypeVector %float 3
1444         %int = OpTypeInt 32 1
1445        %uint = OpTypeInt 32 0
1446      %v2uint = OpTypeVector %uint 2
1447           %F = OpTypeStruct %int %v2uint
1448      %uint_2 = OpConstant %uint 2
1449 %_arr_float_uint_2 = OpTypeArray %float %uint_2
1450 %mat2v3float = OpTypeMatrix %v3float 2
1451      %v3uint = OpTypeVector %uint 3
1452 %mat3v3float = OpTypeMatrix %v3float 3
1453 %_arr_mat3v3float_uint_2 = OpTypeArray %mat3v3float %uint_2
1454           %O = OpTypeStruct %v3uint %v2float %_arr_float_uint_2 %v2float %_arr_mat3v3float_uint_2
1455 %_arr_O_uint_2 = OpTypeArray %O %uint_2
1456      %Output = OpTypeStruct %float %v2float %v3float %F %float %_arr_float_uint_2 %mat2v3float %_arr_O_uint_2
1457 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
1458  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
1459        %main = OpFunction %void None %3
1460           %5 = OpLabel
1461                OpReturn
1462                OpFunctionEnd
1463   )";
1464 
1465   CompileSuccessfully(spirv);
1466   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
1467 }
1468 
TEST_F(ValidateDecorations,BlockLayoutPermitsTightVec3ScalarPackingGood)1469 TEST_F(ValidateDecorations, BlockLayoutPermitsTightVec3ScalarPackingGood) {
1470   // See https://github.com/KhronosGroup/SPIRV-Tools/issues/1666
1471   std::string spirv = R"(
1472                OpCapability Shader
1473                OpMemoryModel Logical GLSL450
1474                OpEntryPoint Vertex %main "main"
1475                OpSource GLSL 450
1476                OpMemberDecorate %S 0 Offset 0
1477                OpMemberDecorate %S 1 Offset 12
1478                OpDecorate %S Block
1479                OpDecorate %B DescriptorSet 0
1480                OpDecorate %B Binding 0
1481        %void = OpTypeVoid
1482           %3 = OpTypeFunction %void
1483       %float = OpTypeFloat 32
1484     %v3float = OpTypeVector %float 3
1485           %S = OpTypeStruct %v3float %float
1486 %_ptr_Uniform_S = OpTypePointer Uniform %S
1487           %B = OpVariable %_ptr_Uniform_S Uniform
1488        %main = OpFunction %void None %3
1489           %5 = OpLabel
1490                OpReturn
1491                OpFunctionEnd
1492   )";
1493 
1494   CompileSuccessfully(spirv);
1495   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
1496       << getDiagnosticString();
1497 }
1498 
TEST_F(ValidateDecorations,BlockLayoutForbidsTightScalarVec3PackingBad)1499 TEST_F(ValidateDecorations, BlockLayoutForbidsTightScalarVec3PackingBad) {
1500   // See https://github.com/KhronosGroup/SPIRV-Tools/issues/1666
1501   std::string spirv = R"(
1502                OpCapability Shader
1503                OpMemoryModel Logical GLSL450
1504                OpEntryPoint Vertex %main "main"
1505                OpSource GLSL 450
1506                OpMemberDecorate %S 0 Offset 0
1507                OpMemberDecorate %S 1 Offset 4
1508                OpDecorate %S Block
1509                OpDecorate %B DescriptorSet 0
1510                OpDecorate %B Binding 0
1511        %void = OpTypeVoid
1512           %3 = OpTypeFunction %void
1513       %float = OpTypeFloat 32
1514     %v3float = OpTypeVector %float 3
1515           %S = OpTypeStruct %float %v3float
1516 %_ptr_Uniform_S = OpTypePointer Uniform %S
1517           %B = OpVariable %_ptr_Uniform_S Uniform
1518        %main = OpFunction %void None %3
1519           %5 = OpLabel
1520                OpReturn
1521                OpFunctionEnd
1522   )";
1523 
1524   CompileSuccessfully(spirv);
1525   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
1526   EXPECT_THAT(
1527       getDiagnosticString(),
1528       HasSubstr("Structure id 2 decorated as Block for variable in Uniform "
1529                 "storage class must follow standard uniform buffer layout "
1530                 "rules: member 1 at offset 4 is not aligned to 16"));
1531 }
1532 
TEST_F(ValidateDecorations,BlockLayoutPermitsTightScalarVec3PackingWithRelaxedLayoutGood)1533 TEST_F(ValidateDecorations,
1534        BlockLayoutPermitsTightScalarVec3PackingWithRelaxedLayoutGood) {
1535   // Same as previous test, but with explicit option to relax block layout.
1536   std::string spirv = R"(
1537                OpCapability Shader
1538                OpMemoryModel Logical GLSL450
1539                OpEntryPoint Vertex %main "main"
1540                OpSource GLSL 450
1541                OpMemberDecorate %S 0 Offset 0
1542                OpMemberDecorate %S 1 Offset 4
1543                OpDecorate %S Block
1544                OpDecorate %B DescriptorSet 0
1545                OpDecorate %B Binding 0
1546        %void = OpTypeVoid
1547           %3 = OpTypeFunction %void
1548       %float = OpTypeFloat 32
1549     %v3float = OpTypeVector %float 3
1550           %S = OpTypeStruct %float %v3float
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   spvValidatorOptionsSetRelaxBlockLayout(getValidatorOptions(), true);
1561   EXPECT_EQ(SPV_SUCCESS,
1562             ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
1563   EXPECT_THAT(getDiagnosticString(), Eq(""));
1564 }
1565 
TEST_F(ValidateDecorations,BlockLayoutPermitsTightScalarVec3PackingBadOffsetWithRelaxedLayoutBad)1566 TEST_F(ValidateDecorations,
1567        BlockLayoutPermitsTightScalarVec3PackingBadOffsetWithRelaxedLayoutBad) {
1568   // Same as previous test, but with the vector not aligned to its scalar
1569   // element. Use offset 5 instead of a multiple of 4.
1570   std::string spirv = R"(
1571                OpCapability Shader
1572                OpMemoryModel Logical GLSL450
1573                OpEntryPoint Vertex %main "main"
1574                OpSource GLSL 450
1575                OpMemberDecorate %S 0 Offset 0
1576                OpMemberDecorate %S 1 Offset 5
1577                OpDecorate %S Block
1578                OpDecorate %B DescriptorSet 0
1579                OpDecorate %B Binding 0
1580        %void = OpTypeVoid
1581           %3 = OpTypeFunction %void
1582       %float = OpTypeFloat 32
1583     %v3float = OpTypeVector %float 3
1584           %S = OpTypeStruct %float %v3float
1585 %_ptr_Uniform_S = OpTypePointer Uniform %S
1586           %B = OpVariable %_ptr_Uniform_S Uniform
1587        %main = OpFunction %void None %3
1588           %5 = OpLabel
1589                OpReturn
1590                OpFunctionEnd
1591   )";
1592 
1593   CompileSuccessfully(spirv);
1594   spvValidatorOptionsSetRelaxBlockLayout(getValidatorOptions(), true);
1595   EXPECT_EQ(SPV_ERROR_INVALID_ID,
1596             ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
1597   EXPECT_THAT(
1598       getDiagnosticString(),
1599       HasSubstr(
1600           "Structure id 2 decorated as Block for variable in Uniform storage "
1601           "class must follow relaxed uniform buffer layout rules: member 1 at "
1602           "offset 5 is not aligned to scalar element size 4"));
1603 }
1604 
TEST_F(ValidateDecorations,BlockLayoutPermitsTightScalarVec3PackingWithVulkan1_1Good)1605 TEST_F(ValidateDecorations,
1606        BlockLayoutPermitsTightScalarVec3PackingWithVulkan1_1Good) {
1607   // Same as previous test, but with Vulkan 1.1.  Vulkan 1.1 included
1608   // VK_KHR_relaxed_block_layout in core.
1609   std::string spirv = R"(
1610                OpCapability Shader
1611                OpMemoryModel Logical GLSL450
1612                OpEntryPoint Vertex %main "main"
1613                OpSource GLSL 450
1614                OpMemberDecorate %S 0 Offset 0
1615                OpMemberDecorate %S 1 Offset 4
1616                OpDecorate %S Block
1617                OpDecorate %B DescriptorSet 0
1618                OpDecorate %B Binding 0
1619        %void = OpTypeVoid
1620           %3 = OpTypeFunction %void
1621       %float = OpTypeFloat 32
1622     %v3float = OpTypeVector %float 3
1623           %S = OpTypeStruct %float %v3float
1624 %_ptr_Uniform_S = OpTypePointer Uniform %S
1625           %B = OpVariable %_ptr_Uniform_S Uniform
1626        %main = OpFunction %void None %3
1627           %5 = OpLabel
1628                OpReturn
1629                OpFunctionEnd
1630   )";
1631 
1632   CompileSuccessfully(spirv);
1633   EXPECT_EQ(SPV_SUCCESS,
1634             ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
1635   EXPECT_THAT(getDiagnosticString(), Eq(""));
1636 }
1637 
TEST_F(ValidateDecorations,BlockLayoutPermitsTightScalarVec3PackingWithScalarLayoutGood)1638 TEST_F(ValidateDecorations,
1639        BlockLayoutPermitsTightScalarVec3PackingWithScalarLayoutGood) {
1640   // Same as previous test, but with scalar block layout.
1641   std::string spirv = R"(
1642                OpCapability Shader
1643                OpMemoryModel Logical GLSL450
1644                OpEntryPoint Vertex %main "main"
1645                OpSource GLSL 450
1646                OpMemberDecorate %S 0 Offset 0
1647                OpMemberDecorate %S 1 Offset 4
1648                OpDecorate %S Block
1649                OpDecorate %B DescriptorSet 0
1650                OpDecorate %B Binding 0
1651        %void = OpTypeVoid
1652           %3 = OpTypeFunction %void
1653       %float = OpTypeFloat 32
1654     %v3float = OpTypeVector %float 3
1655           %S = OpTypeStruct %float %v3float
1656 %_ptr_Uniform_S = OpTypePointer Uniform %S
1657           %B = OpVariable %_ptr_Uniform_S Uniform
1658        %main = OpFunction %void None %3
1659           %5 = OpLabel
1660                OpReturn
1661                OpFunctionEnd
1662   )";
1663 
1664   CompileSuccessfully(spirv);
1665   spvValidatorOptionsSetScalarBlockLayout(getValidatorOptions(), true);
1666   EXPECT_EQ(SPV_SUCCESS,
1667             ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
1668   EXPECT_THAT(getDiagnosticString(), Eq(""));
1669 }
1670 
TEST_F(ValidateDecorations,BlockLayoutPermitsScalarAlignedArrayWithScalarLayoutGood)1671 TEST_F(ValidateDecorations,
1672        BlockLayoutPermitsScalarAlignedArrayWithScalarLayoutGood) {
1673   // The array at offset 4 is ok with scalar block layout.
1674   std::string spirv = R"(
1675                OpCapability Shader
1676                OpMemoryModel Logical GLSL450
1677                OpEntryPoint Vertex %main "main"
1678                OpSource GLSL 450
1679                OpMemberDecorate %S 0 Offset 0
1680                OpMemberDecorate %S 1 Offset 4
1681                OpDecorate %S Block
1682                OpDecorate %B DescriptorSet 0
1683                OpDecorate %B Binding 0
1684                OpDecorate %arr_float ArrayStride 4
1685        %void = OpTypeVoid
1686           %3 = OpTypeFunction %void
1687        %uint = OpTypeInt 32 0
1688      %uint_3 = OpConstant %uint 3
1689       %float = OpTypeFloat 32
1690   %arr_float = OpTypeArray %float %uint_3
1691           %S = OpTypeStruct %float %arr_float
1692 %_ptr_Uniform_S = OpTypePointer Uniform %S
1693           %B = OpVariable %_ptr_Uniform_S Uniform
1694        %main = OpFunction %void None %3
1695           %5 = OpLabel
1696                OpReturn
1697                OpFunctionEnd
1698   )";
1699 
1700   CompileSuccessfully(spirv);
1701   spvValidatorOptionsSetScalarBlockLayout(getValidatorOptions(), true);
1702   EXPECT_EQ(SPV_SUCCESS,
1703             ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
1704   EXPECT_THAT(getDiagnosticString(), Eq(""));
1705 }
1706 
TEST_F(ValidateDecorations,BlockLayoutPermitsScalarAlignedArrayOfVec3WithScalarLayoutGood)1707 TEST_F(ValidateDecorations,
1708        BlockLayoutPermitsScalarAlignedArrayOfVec3WithScalarLayoutGood) {
1709   // The array at offset 4 is ok with scalar block layout, even though
1710   // its elements are vec3.
1711   // This is the same as the previous case, but the array elements are vec3
1712   // instead of float.
1713   std::string spirv = R"(
1714                OpCapability Shader
1715                OpMemoryModel Logical GLSL450
1716                OpEntryPoint Vertex %main "main"
1717                OpSource GLSL 450
1718                OpMemberDecorate %S 0 Offset 0
1719                OpMemberDecorate %S 1 Offset 4
1720                OpDecorate %S Block
1721                OpDecorate %B DescriptorSet 0
1722                OpDecorate %B Binding 0
1723                OpDecorate %arr_vec3 ArrayStride 12
1724        %void = OpTypeVoid
1725           %3 = OpTypeFunction %void
1726        %uint = OpTypeInt 32 0
1727      %uint_3 = OpConstant %uint 3
1728       %float = OpTypeFloat 32
1729        %vec3 = OpTypeVector %float 3
1730    %arr_vec3 = OpTypeArray %vec3 %uint_3
1731           %S = OpTypeStruct %float %arr_vec3
1732 %_ptr_Uniform_S = OpTypePointer Uniform %S
1733           %B = OpVariable %_ptr_Uniform_S Uniform
1734        %main = OpFunction %void None %3
1735           %5 = OpLabel
1736                OpReturn
1737                OpFunctionEnd
1738   )";
1739 
1740   CompileSuccessfully(spirv);
1741   spvValidatorOptionsSetScalarBlockLayout(getValidatorOptions(), true);
1742   EXPECT_EQ(SPV_SUCCESS,
1743             ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
1744   EXPECT_THAT(getDiagnosticString(), Eq(""));
1745 }
1746 
TEST_F(ValidateDecorations,BlockLayoutPermitsScalarAlignedStructWithScalarLayoutGood)1747 TEST_F(ValidateDecorations,
1748        BlockLayoutPermitsScalarAlignedStructWithScalarLayoutGood) {
1749   // Scalar block layout permits the struct at offset 4, even though
1750   // it contains a vector with base alignment 8 and scalar alignment 4.
1751   std::string spirv = R"(
1752                OpCapability Shader
1753                OpMemoryModel Logical GLSL450
1754                OpEntryPoint Vertex %main "main"
1755                OpSource GLSL 450
1756                OpMemberDecorate %S 0 Offset 0
1757                OpMemberDecorate %S 1 Offset 4
1758                OpMemberDecorate %st 0 Offset 0
1759                OpMemberDecorate %st 1 Offset 8
1760                OpDecorate %S Block
1761                OpDecorate %B DescriptorSet 0
1762                OpDecorate %B Binding 0
1763        %void = OpTypeVoid
1764           %3 = OpTypeFunction %void
1765       %float = OpTypeFloat 32
1766        %vec2 = OpTypeVector %float 2
1767         %st  = OpTypeStruct %vec2 %float
1768           %S = OpTypeStruct %float %st
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   spvValidatorOptionsSetScalarBlockLayout(getValidatorOptions(), true);
1779   EXPECT_EQ(SPV_SUCCESS,
1780             ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
1781   EXPECT_THAT(getDiagnosticString(), Eq(""));
1782 }
1783 
TEST_F(ValidateDecorations,BlockLayoutPermitsFieldsInBaseAlignmentPaddingAtEndOfStructWithScalarLayoutGood)1784 TEST_F(
1785     ValidateDecorations,
1786     BlockLayoutPermitsFieldsInBaseAlignmentPaddingAtEndOfStructWithScalarLayoutGood) {
1787   // Scalar block layout permits fields in what would normally be the padding at
1788   // the end of a struct.
1789   std::string spirv = R"(
1790                OpCapability Shader
1791                OpCapability Float64
1792                OpMemoryModel Logical GLSL450
1793                OpEntryPoint Vertex %main "main"
1794                OpSource GLSL 450
1795                OpMemberDecorate %st 0 Offset 0
1796                OpMemberDecorate %st 1 Offset 8
1797                OpMemberDecorate %S 0 Offset 0
1798                OpMemberDecorate %S 1 Offset 12
1799                OpDecorate %S Block
1800                OpDecorate %B DescriptorSet 0
1801                OpDecorate %B Binding 0
1802        %void = OpTypeVoid
1803           %3 = OpTypeFunction %void
1804       %float = OpTypeFloat 32
1805      %double = OpTypeFloat 64
1806          %st = OpTypeStruct %double %float
1807           %S = OpTypeStruct %st %float
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   spvValidatorOptionsSetScalarBlockLayout(getValidatorOptions(), true);
1818   EXPECT_EQ(SPV_SUCCESS,
1819             ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
1820   EXPECT_THAT(getDiagnosticString(), Eq(""));
1821 }
1822 
TEST_F(ValidateDecorations,BlockLayoutPermitsStraddlingVectorWithScalarLayoutOverrideRelaxBlockLayoutGood)1823 TEST_F(
1824     ValidateDecorations,
1825     BlockLayoutPermitsStraddlingVectorWithScalarLayoutOverrideRelaxBlockLayoutGood) {
1826   // Same as previous, but set relaxed block layout first.  Scalar layout always
1827   // wins.
1828   std::string spirv = R"(
1829                OpCapability Shader
1830                OpMemoryModel Logical GLSL450
1831                OpEntryPoint Vertex %main "main"
1832                OpSource GLSL 450
1833                OpMemberDecorate %S 0 Offset 0
1834                OpMemberDecorate %S 1 Offset 4
1835                OpDecorate %S Block
1836                OpDecorate %B DescriptorSet 0
1837                OpDecorate %B Binding 0
1838        %void = OpTypeVoid
1839           %3 = OpTypeFunction %void
1840       %float = OpTypeFloat 32
1841        %vec4 = OpTypeVector %float 4
1842           %S = OpTypeStruct %float %vec4
1843 %_ptr_Uniform_S = OpTypePointer Uniform %S
1844           %B = OpVariable %_ptr_Uniform_S Uniform
1845        %main = OpFunction %void None %3
1846           %5 = OpLabel
1847                OpReturn
1848                OpFunctionEnd
1849   )";
1850 
1851   CompileSuccessfully(spirv);
1852   spvValidatorOptionsSetRelaxBlockLayout(getValidatorOptions(), true);
1853   spvValidatorOptionsSetScalarBlockLayout(getValidatorOptions(), true);
1854   EXPECT_EQ(SPV_SUCCESS,
1855             ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
1856   EXPECT_THAT(getDiagnosticString(), Eq(""));
1857 }
1858 
TEST_F(ValidateDecorations,BlockLayoutPermitsStraddlingVectorWithRelaxedLayoutOverridenByScalarBlockLayoutGood)1859 TEST_F(
1860     ValidateDecorations,
1861     BlockLayoutPermitsStraddlingVectorWithRelaxedLayoutOverridenByScalarBlockLayoutGood) {
1862   // Same as previous, but set scalar block layout first.  Scalar layout always
1863   // wins.
1864   std::string spirv = R"(
1865                OpCapability Shader
1866                OpMemoryModel Logical GLSL450
1867                OpEntryPoint Vertex %main "main"
1868                OpSource GLSL 450
1869                OpMemberDecorate %S 0 Offset 0
1870                OpMemberDecorate %S 1 Offset 4
1871                OpDecorate %S Block
1872                OpDecorate %B DescriptorSet 0
1873                OpDecorate %B Binding 0
1874        %void = OpTypeVoid
1875           %3 = OpTypeFunction %void
1876       %float = OpTypeFloat 32
1877        %vec4 = OpTypeVector %float 4
1878           %S = OpTypeStruct %float %vec4
1879 %_ptr_Uniform_S = OpTypePointer Uniform %S
1880           %B = OpVariable %_ptr_Uniform_S Uniform
1881        %main = OpFunction %void None %3
1882           %5 = OpLabel
1883                OpReturn
1884                OpFunctionEnd
1885   )";
1886 
1887   CompileSuccessfully(spirv);
1888   spvValidatorOptionsSetScalarBlockLayout(getValidatorOptions(), true);
1889   spvValidatorOptionsSetRelaxBlockLayout(getValidatorOptions(), true);
1890   EXPECT_EQ(SPV_SUCCESS,
1891             ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
1892   EXPECT_THAT(getDiagnosticString(), Eq(""));
1893 }
1894 
TEST_F(ValidateDecorations,BufferBlock16bitStandardStorageBufferLayout)1895 TEST_F(ValidateDecorations, BufferBlock16bitStandardStorageBufferLayout) {
1896   std::string spirv = R"(
1897              OpCapability Shader
1898              OpCapability StorageUniform16
1899              OpExtension "SPV_KHR_16bit_storage"
1900              OpMemoryModel Logical GLSL450
1901              OpEntryPoint GLCompute %main "main"
1902              OpExecutionMode %main LocalSize 1 1 1
1903              OpDecorate %f32arr ArrayStride 4
1904              OpDecorate %f16arr ArrayStride 2
1905              OpMemberDecorate %SSBO32 0 Offset 0
1906              OpMemberDecorate %SSBO16 0 Offset 0
1907              OpDecorate %SSBO32 BufferBlock
1908              OpDecorate %SSBO16 BufferBlock
1909      %void = OpTypeVoid
1910     %voidf = OpTypeFunction %void
1911       %u32 = OpTypeInt 32 0
1912       %i32 = OpTypeInt 32 1
1913       %f32 = OpTypeFloat 32
1914     %uvec3 = OpTypeVector %u32 3
1915  %c_i32_32 = OpConstant %i32 32
1916 %c_i32_128 = OpConstant %i32 128
1917    %f32arr = OpTypeArray %f32 %c_i32_128
1918       %f16 = OpTypeFloat 16
1919    %f16arr = OpTypeArray %f16 %c_i32_128
1920    %SSBO32 = OpTypeStruct %f32arr
1921    %SSBO16 = OpTypeStruct %f16arr
1922 %_ptr_Uniform_SSBO32 = OpTypePointer Uniform %SSBO32
1923  %varSSBO32 = OpVariable %_ptr_Uniform_SSBO32 Uniform
1924 %_ptr_Uniform_SSBO16 = OpTypePointer Uniform %SSBO16
1925  %varSSBO16 = OpVariable %_ptr_Uniform_SSBO16 Uniform
1926      %main = OpFunction %void None %voidf
1927     %label = OpLabel
1928              OpReturn
1929              OpFunctionEnd
1930   )";
1931 
1932   CompileSuccessfully(spirv);
1933   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
1934 }
1935 
TEST_F(ValidateDecorations,BlockArrayBaseAlignmentGood)1936 TEST_F(ValidateDecorations, BlockArrayBaseAlignmentGood) {
1937   // For uniform buffer, Array base alignment is 16, and ArrayStride
1938   // must be a multiple of 16.
1939   std::string spirv = R"(
1940                OpCapability Shader
1941                OpMemoryModel Logical GLSL450
1942                OpEntryPoint Vertex %main "main"
1943                OpSource GLSL 450
1944                OpDecorate %_arr_float_uint_2 ArrayStride 16
1945                OpMemberDecorate %S 0 Offset 0
1946                OpMemberDecorate %S 1 Offset 16
1947                OpDecorate %S Block
1948        %void = OpTypeVoid
1949           %3 = OpTypeFunction %void
1950       %float = OpTypeFloat 32
1951     %v2float = OpTypeVector %float 2
1952        %uint = OpTypeInt 32 0
1953      %uint_2 = OpConstant %uint 2
1954 %_arr_float_uint_2 = OpTypeArray %float %uint_2
1955           %S = OpTypeStruct %v2float %_arr_float_uint_2
1956 %_ptr_PushConstant_S = OpTypePointer PushConstant %S
1957           %u = OpVariable %_ptr_PushConstant_S PushConstant
1958        %main = OpFunction %void None %3
1959           %5 = OpLabel
1960                OpReturn
1961                OpFunctionEnd
1962   )";
1963 
1964   CompileSuccessfully(spirv);
1965   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
1966       << getDiagnosticString();
1967 }
1968 
TEST_F(ValidateDecorations,BlockArrayBadAlignmentBad)1969 TEST_F(ValidateDecorations, BlockArrayBadAlignmentBad) {
1970   // For uniform buffer, Array base alignment is 16.
1971   std::string spirv = R"(
1972                OpCapability Shader
1973                OpMemoryModel Logical GLSL450
1974                OpEntryPoint Vertex %main "main"
1975                OpSource GLSL 450
1976                OpDecorate %_arr_float_uint_2 ArrayStride 16
1977                OpMemberDecorate %S 0 Offset 0
1978                OpMemberDecorate %S 1 Offset 8
1979                OpDecorate %S Block
1980        %void = OpTypeVoid
1981           %3 = OpTypeFunction %void
1982       %float = OpTypeFloat 32
1983     %v2float = OpTypeVector %float 2
1984        %uint = OpTypeInt 32 0
1985      %uint_2 = OpConstant %uint 2
1986 %_arr_float_uint_2 = OpTypeArray %float %uint_2
1987           %S = OpTypeStruct %v2float %_arr_float_uint_2
1988 %_ptr_Uniform_S = OpTypePointer Uniform %S
1989           %u = OpVariable %_ptr_Uniform_S Uniform
1990        %main = OpFunction %void None %3
1991           %5 = OpLabel
1992                OpReturn
1993                OpFunctionEnd
1994   )";
1995 
1996   CompileSuccessfully(spirv);
1997   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
1998   EXPECT_THAT(
1999       getDiagnosticString(),
2000       HasSubstr(
2001           "Structure id 3 decorated as Block for variable in Uniform "
2002           "storage class must follow standard uniform buffer layout rules: "
2003           "member 1 at offset 8 is not aligned to 16"));
2004 }
2005 
TEST_F(ValidateDecorations,BlockArrayBadAlignmentWithRelaxedLayoutStillBad)2006 TEST_F(ValidateDecorations, BlockArrayBadAlignmentWithRelaxedLayoutStillBad) {
2007   // For uniform buffer, Array base alignment is 16, and ArrayStride
2008   // must be a multiple of 16.  This case uses relaxed block layout.  Relaxed
2009   // layout only relaxes rules for vector alignment, not array alignment.
2010   std::string spirv = R"(
2011                OpCapability Shader
2012                OpMemoryModel Logical GLSL450
2013                OpEntryPoint Vertex %main "main"
2014                OpSource GLSL 450
2015                OpDecorate %_arr_float_uint_2 ArrayStride 16
2016                OpDecorate %u DescriptorSet 0
2017                OpDecorate %u Binding 0
2018                OpMemberDecorate %S 0 Offset 0
2019                OpMemberDecorate %S 1 Offset 8
2020                OpDecorate %S Block
2021        %void = OpTypeVoid
2022           %3 = OpTypeFunction %void
2023       %float = OpTypeFloat 32
2024     %v2float = OpTypeVector %float 2
2025        %uint = OpTypeInt 32 0
2026      %uint_2 = OpConstant %uint 2
2027 %_arr_float_uint_2 = OpTypeArray %float %uint_2
2028           %S = OpTypeStruct %v2float %_arr_float_uint_2
2029 %_ptr_Uniform_S = OpTypePointer Uniform %S
2030           %u = OpVariable %_ptr_Uniform_S Uniform
2031        %main = OpFunction %void None %3
2032           %5 = OpLabel
2033                OpReturn
2034                OpFunctionEnd
2035   )";
2036 
2037   CompileSuccessfully(spirv);
2038   EXPECT_EQ(SPV_ERROR_INVALID_ID,
2039             ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
2040   spvValidatorOptionsSetRelaxBlockLayout(getValidatorOptions(), true);
2041   EXPECT_THAT(
2042       getDiagnosticString(),
2043       HasSubstr(
2044           "Structure id 4 decorated as Block for variable in Uniform "
2045           "storage class must follow standard uniform buffer layout rules: "
2046           "member 1 at offset 8 is not aligned to 16"));
2047 }
2048 
TEST_F(ValidateDecorations,BlockArrayBadAlignmentWithVulkan1_1StillBad)2049 TEST_F(ValidateDecorations, BlockArrayBadAlignmentWithVulkan1_1StillBad) {
2050   // Same as previous test, but with Vulkan 1.1, which includes
2051   // VK_KHR_relaxed_block_layout in core.
2052   std::string spirv = R"(
2053                OpCapability Shader
2054                OpMemoryModel Logical GLSL450
2055                OpEntryPoint Vertex %main "main"
2056                OpSource GLSL 450
2057                OpDecorate %_arr_float_uint_2 ArrayStride 16
2058                OpDecorate %u DescriptorSet 0
2059                OpDecorate %u Binding 0
2060                OpMemberDecorate %S 0 Offset 0
2061                OpMemberDecorate %S 1 Offset 8
2062                OpDecorate %S Block
2063        %void = OpTypeVoid
2064           %3 = OpTypeFunction %void
2065       %float = OpTypeFloat 32
2066     %v2float = OpTypeVector %float 2
2067        %uint = OpTypeInt 32 0
2068      %uint_2 = OpConstant %uint 2
2069 %_arr_float_uint_2 = OpTypeArray %float %uint_2
2070           %S = OpTypeStruct %v2float %_arr_float_uint_2
2071 %_ptr_Uniform_S = OpTypePointer Uniform %S
2072           %u = OpVariable %_ptr_Uniform_S Uniform
2073        %main = OpFunction %void None %3
2074           %5 = OpLabel
2075                OpReturn
2076                OpFunctionEnd
2077   )";
2078 
2079   CompileSuccessfully(spirv);
2080   EXPECT_EQ(SPV_ERROR_INVALID_ID,
2081             ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
2082   EXPECT_THAT(
2083       getDiagnosticString(),
2084       HasSubstr(
2085           "Structure id 4 decorated as Block for variable in Uniform "
2086           "storage class must follow relaxed uniform buffer layout rules: "
2087           "member 1 at offset 8 is not aligned to 16"));
2088 }
2089 
TEST_F(ValidateDecorations,PushConstantArrayBaseAlignmentGood)2090 TEST_F(ValidateDecorations, PushConstantArrayBaseAlignmentGood) {
2091   // Tests https://github.com/KhronosGroup/SPIRV-Tools/issues/1664
2092   // From GLSL vertex shader:
2093   // #version 450
2094   // layout(push_constant) uniform S { vec2 v; float arr[2]; } u;
2095   // void main() { }
2096 
2097   std::string spirv = R"(
2098                OpCapability Shader
2099                OpMemoryModel Logical GLSL450
2100                OpEntryPoint Vertex %main "main"
2101                OpSource GLSL 450
2102                OpDecorate %_arr_float_uint_2 ArrayStride 4
2103                OpMemberDecorate %S 0 Offset 0
2104                OpMemberDecorate %S 1 Offset 8
2105                OpDecorate %S Block
2106        %void = OpTypeVoid
2107           %3 = OpTypeFunction %void
2108       %float = OpTypeFloat 32
2109     %v2float = OpTypeVector %float 2
2110        %uint = OpTypeInt 32 0
2111      %uint_2 = OpConstant %uint 2
2112 %_arr_float_uint_2 = OpTypeArray %float %uint_2
2113           %S = OpTypeStruct %v2float %_arr_float_uint_2
2114 %_ptr_PushConstant_S = OpTypePointer PushConstant %S
2115           %u = OpVariable %_ptr_PushConstant_S PushConstant
2116        %main = OpFunction %void None %3
2117           %5 = OpLabel
2118                OpReturn
2119                OpFunctionEnd
2120   )";
2121 
2122   CompileSuccessfully(spirv);
2123   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
2124       << getDiagnosticString();
2125 }
2126 
TEST_F(ValidateDecorations,PushConstantArrayBadAlignmentBad)2127 TEST_F(ValidateDecorations, PushConstantArrayBadAlignmentBad) {
2128   // Like the previous test, but with offset 7 instead of 8.
2129   std::string spirv = R"(
2130                OpCapability Shader
2131                OpMemoryModel Logical GLSL450
2132                OpEntryPoint Vertex %main "main"
2133                OpSource GLSL 450
2134                OpDecorate %_arr_float_uint_2 ArrayStride 4
2135                OpMemberDecorate %S 0 Offset 0
2136                OpMemberDecorate %S 1 Offset 7
2137                OpDecorate %S Block
2138        %void = OpTypeVoid
2139           %3 = OpTypeFunction %void
2140       %float = OpTypeFloat 32
2141     %v2float = OpTypeVector %float 2
2142        %uint = OpTypeInt 32 0
2143      %uint_2 = OpConstant %uint 2
2144 %_arr_float_uint_2 = OpTypeArray %float %uint_2
2145           %S = OpTypeStruct %v2float %_arr_float_uint_2
2146 %_ptr_PushConstant_S = OpTypePointer PushConstant %S
2147           %u = OpVariable %_ptr_PushConstant_S PushConstant
2148        %main = OpFunction %void None %3
2149           %5 = OpLabel
2150                OpReturn
2151                OpFunctionEnd
2152   )";
2153 
2154   CompileSuccessfully(spirv);
2155   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
2156   EXPECT_THAT(
2157       getDiagnosticString(),
2158       HasSubstr(
2159           "Structure id 3 decorated as Block for variable in PushConstant "
2160           "storage class must follow standard storage buffer layout rules: "
2161           "member 1 at offset 7 is not aligned to 4"));
2162 }
2163 
TEST_F(ValidateDecorations,PushConstantLayoutPermitsTightVec3ScalarPackingGood)2164 TEST_F(ValidateDecorations,
2165        PushConstantLayoutPermitsTightVec3ScalarPackingGood) {
2166   // See https://github.com/KhronosGroup/SPIRV-Tools/issues/1666
2167   std::string spirv = R"(
2168                OpCapability Shader
2169                OpMemoryModel Logical GLSL450
2170                OpEntryPoint Vertex %main "main"
2171                OpSource GLSL 450
2172                OpMemberDecorate %S 0 Offset 0
2173                OpMemberDecorate %S 1 Offset 12
2174                OpDecorate %S Block
2175        %void = OpTypeVoid
2176           %3 = OpTypeFunction %void
2177       %float = OpTypeFloat 32
2178     %v3float = OpTypeVector %float 3
2179           %S = OpTypeStruct %v3float %float
2180 %_ptr_PushConstant_S = OpTypePointer PushConstant %S
2181           %B = OpVariable %_ptr_PushConstant_S PushConstant
2182        %main = OpFunction %void None %3
2183           %5 = OpLabel
2184                OpReturn
2185                OpFunctionEnd
2186   )";
2187 
2188   CompileSuccessfully(spirv);
2189   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
2190       << getDiagnosticString();
2191 }
2192 
TEST_F(ValidateDecorations,PushConstantLayoutForbidsTightScalarVec3PackingBad)2193 TEST_F(ValidateDecorations,
2194        PushConstantLayoutForbidsTightScalarVec3PackingBad) {
2195   // See https://github.com/KhronosGroup/SPIRV-Tools/issues/1666
2196   std::string spirv = R"(
2197                OpCapability Shader
2198                OpMemoryModel Logical GLSL450
2199                OpEntryPoint Vertex %main "main"
2200                OpSource GLSL 450
2201                OpMemberDecorate %S 0 Offset 0
2202                OpMemberDecorate %S 1 Offset 4
2203                OpDecorate %S Block
2204        %void = OpTypeVoid
2205           %3 = OpTypeFunction %void
2206       %float = OpTypeFloat 32
2207     %v3float = OpTypeVector %float 3
2208           %S = OpTypeStruct %float %v3float
2209 %_ptr_Uniform_S = OpTypePointer PushConstant %S
2210           %B = OpVariable %_ptr_Uniform_S PushConstant
2211        %main = OpFunction %void None %3
2212           %5 = OpLabel
2213                OpReturn
2214                OpFunctionEnd
2215   )";
2216 
2217   CompileSuccessfully(spirv);
2218   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
2219   EXPECT_THAT(
2220       getDiagnosticString(),
2221       HasSubstr(
2222           "Structure id 2 decorated as Block for variable in PushConstant "
2223           "storage class must follow standard storage buffer layout "
2224           "rules: member 1 at offset 4 is not aligned to 16"));
2225 }
2226 
TEST_F(ValidateDecorations,PushConstantMissingBlockGood)2227 TEST_F(ValidateDecorations, PushConstantMissingBlockGood) {
2228   std::string spirv = R"(
2229             OpCapability Shader
2230             OpMemoryModel Logical GLSL450
2231             OpEntryPoint Fragment %1 "main"
2232             OpExecutionMode %1 OriginUpperLeft
2233 
2234             OpMemberDecorate %struct 0 Offset 0
2235 
2236     %void = OpTypeVoid
2237   %voidfn = OpTypeFunction %void
2238    %float = OpTypeFloat 32
2239   %struct = OpTypeStruct %float
2240      %ptr = OpTypePointer PushConstant %struct
2241       %pc = OpVariable %ptr PushConstant
2242 
2243        %1 = OpFunction %void None %voidfn
2244    %label = OpLabel
2245             OpReturn
2246             OpFunctionEnd
2247 )";
2248 
2249   CompileSuccessfully(spirv);
2250   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
2251       << getDiagnosticString();
2252 }
2253 
TEST_F(ValidateDecorations,VulkanPushConstantMissingBlockBad)2254 TEST_F(ValidateDecorations, VulkanPushConstantMissingBlockBad) {
2255   std::string spirv = R"(
2256             OpCapability Shader
2257             OpMemoryModel Logical GLSL450
2258             OpEntryPoint Fragment %1 "main"
2259             OpExecutionMode %1 OriginUpperLeft
2260 
2261             OpMemberDecorate %struct 0 Offset 0
2262 
2263     %void = OpTypeVoid
2264   %voidfn = OpTypeFunction %void
2265    %float = OpTypeFloat 32
2266   %struct = OpTypeStruct %float
2267      %ptr = OpTypePointer PushConstant %struct
2268       %pc = OpVariable %ptr PushConstant
2269 
2270        %1 = OpFunction %void None %voidfn
2271    %label = OpLabel
2272             OpReturn
2273             OpFunctionEnd
2274 )";
2275 
2276   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
2277   EXPECT_EQ(SPV_ERROR_INVALID_ID,
2278             ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
2279   EXPECT_THAT(getDiagnosticString(),
2280               HasSubstr("PushConstant id '2' is missing Block decoration.\n"
2281                         "From Vulkan spec, section 14.5.1:\n"
2282                         "Such variables must be identified with a Block "
2283                         "decoration"));
2284 }
2285 
TEST_F(ValidateDecorations,MultiplePushConstantsSingleEntryPointGood)2286 TEST_F(ValidateDecorations, MultiplePushConstantsSingleEntryPointGood) {
2287   std::string spirv = R"(
2288                 OpCapability Shader
2289                 OpMemoryModel Logical GLSL450
2290                 OpEntryPoint Fragment %1 "main"
2291                 OpExecutionMode %1 OriginUpperLeft
2292 
2293                 OpDecorate %struct Block
2294                 OpMemberDecorate %struct 0 Offset 0
2295 
2296         %void = OpTypeVoid
2297       %voidfn = OpTypeFunction %void
2298        %float = OpTypeFloat 32
2299          %int = OpTypeInt 32 0
2300        %int_0 = OpConstant %int 0
2301       %struct = OpTypeStruct %float
2302          %ptr = OpTypePointer PushConstant %struct
2303    %ptr_float = OpTypePointer PushConstant %float
2304          %pc1 = OpVariable %ptr PushConstant
2305          %pc2 = OpVariable %ptr PushConstant
2306 
2307            %1 = OpFunction %void None %voidfn
2308        %label = OpLabel
2309            %2 = OpAccessChain %ptr_float %pc1 %int_0
2310            %3 = OpLoad %float %2
2311            %4 = OpAccessChain %ptr_float %pc2 %int_0
2312            %5 = OpLoad %float %4
2313                 OpReturn
2314                 OpFunctionEnd
2315 )";
2316 
2317   CompileSuccessfully(spirv);
2318   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
2319       << getDiagnosticString();
2320 }
2321 
TEST_F(ValidateDecorations,VulkanMultiplePushConstantsDifferentEntryPointGood)2322 TEST_F(ValidateDecorations,
2323        VulkanMultiplePushConstantsDifferentEntryPointGood) {
2324   std::string spirv = R"(
2325                 OpCapability Shader
2326                 OpMemoryModel Logical GLSL450
2327                 OpEntryPoint Vertex %1 "func1"
2328                 OpEntryPoint Fragment %2 "func2"
2329                 OpExecutionMode %2 OriginUpperLeft
2330 
2331                 OpDecorate %struct Block
2332                 OpMemberDecorate %struct 0 Offset 0
2333 
2334         %void = OpTypeVoid
2335       %voidfn = OpTypeFunction %void
2336        %float = OpTypeFloat 32
2337          %int = OpTypeInt 32 0
2338        %int_0 = OpConstant %int 0
2339       %struct = OpTypeStruct %float
2340          %ptr = OpTypePointer PushConstant %struct
2341    %ptr_float = OpTypePointer PushConstant %float
2342          %pc1 = OpVariable %ptr PushConstant
2343          %pc2 = OpVariable %ptr PushConstant
2344 
2345            %1 = OpFunction %void None %voidfn
2346       %label1 = OpLabel
2347            %3 = OpAccessChain %ptr_float %pc1 %int_0
2348            %4 = OpLoad %float %3
2349                 OpReturn
2350                 OpFunctionEnd
2351 
2352            %2 = OpFunction %void None %voidfn
2353       %label2 = OpLabel
2354            %5 = OpAccessChain %ptr_float %pc2 %int_0
2355            %6 = OpLoad %float %5
2356                 OpReturn
2357                 OpFunctionEnd
2358 )";
2359 
2360   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
2361   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1))
2362       << getDiagnosticString();
2363 }
2364 
TEST_F(ValidateDecorations,VulkanMultiplePushConstantsUnusedSingleEntryPointGood)2365 TEST_F(ValidateDecorations,
2366        VulkanMultiplePushConstantsUnusedSingleEntryPointGood) {
2367   std::string spirv = R"(
2368                 OpCapability Shader
2369                 OpMemoryModel Logical GLSL450
2370                 OpEntryPoint Fragment %1 "main"
2371                 OpExecutionMode %1 OriginUpperLeft
2372 
2373                 OpDecorate %struct Block
2374                 OpMemberDecorate %struct 0 Offset 0
2375 
2376         %void = OpTypeVoid
2377       %voidfn = OpTypeFunction %void
2378        %float = OpTypeFloat 32
2379          %int = OpTypeInt 32 0
2380        %int_0 = OpConstant %int 0
2381       %struct = OpTypeStruct %float
2382          %ptr = OpTypePointer PushConstant %struct
2383    %ptr_float = OpTypePointer PushConstant %float
2384          %pc1 = OpVariable %ptr PushConstant
2385          %pc2 = OpVariable %ptr PushConstant
2386 
2387            %1 = OpFunction %void None %voidfn
2388        %label = OpLabel
2389                 OpReturn
2390                 OpFunctionEnd
2391 )";
2392 
2393   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
2394   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1))
2395       << getDiagnosticString();
2396 }
2397 
TEST_F(ValidateDecorations,VulkanMultiplePushConstantsSingleEntryPointBad)2398 TEST_F(ValidateDecorations, VulkanMultiplePushConstantsSingleEntryPointBad) {
2399   std::string spirv = R"(
2400                 OpCapability Shader
2401                 OpMemoryModel Logical GLSL450
2402                 OpEntryPoint Fragment %1 "main"
2403                 OpExecutionMode %1 OriginUpperLeft
2404 
2405                 OpDecorate %struct Block
2406                 OpMemberDecorate %struct 0 Offset 0
2407 
2408         %void = OpTypeVoid
2409       %voidfn = OpTypeFunction %void
2410        %float = OpTypeFloat 32
2411          %int = OpTypeInt 32 0
2412        %int_0 = OpConstant %int 0
2413       %struct = OpTypeStruct %float
2414          %ptr = OpTypePointer PushConstant %struct
2415    %ptr_float = OpTypePointer PushConstant %float
2416          %pc1 = OpVariable %ptr PushConstant
2417          %pc2 = OpVariable %ptr PushConstant
2418 
2419            %1 = OpFunction %void None %voidfn
2420        %label = OpLabel
2421            %2 = OpAccessChain %ptr_float %pc1 %int_0
2422            %3 = OpLoad %float %2
2423            %4 = OpAccessChain %ptr_float %pc2 %int_0
2424            %5 = OpLoad %float %4
2425                 OpReturn
2426                 OpFunctionEnd
2427 )";
2428 
2429   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
2430   EXPECT_EQ(SPV_ERROR_INVALID_ID,
2431             ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
2432   EXPECT_THAT(
2433       getDiagnosticString(),
2434       HasSubstr(
2435           "Entry point id '1' uses more than one PushConstant interface.\n"
2436           "From Vulkan spec, section 14.5.1:\n"
2437           "There must be no more than one push constant block "
2438           "statically used per shader entry point."));
2439 }
2440 
TEST_F(ValidateDecorations,VulkanMultiplePushConstantsDifferentEntryPointSubFunctionGood)2441 TEST_F(ValidateDecorations,
2442        VulkanMultiplePushConstantsDifferentEntryPointSubFunctionGood) {
2443   std::string spirv = R"(
2444                 OpCapability Shader
2445                 OpMemoryModel Logical GLSL450
2446                 OpEntryPoint Vertex %1 "func1"
2447                 OpEntryPoint Fragment %2 "func2"
2448                 OpExecutionMode %2 OriginUpperLeft
2449 
2450                 OpDecorate %struct Block
2451                 OpMemberDecorate %struct 0 Offset 0
2452 
2453         %void = OpTypeVoid
2454       %voidfn = OpTypeFunction %void
2455        %float = OpTypeFloat 32
2456          %int = OpTypeInt 32 0
2457        %int_0 = OpConstant %int 0
2458       %struct = OpTypeStruct %float
2459          %ptr = OpTypePointer PushConstant %struct
2460    %ptr_float = OpTypePointer PushConstant %float
2461          %pc1 = OpVariable %ptr PushConstant
2462          %pc2 = OpVariable %ptr PushConstant
2463 
2464         %sub1 = OpFunction %void None %voidfn
2465   %label_sub1 = OpLabel
2466            %3 = OpAccessChain %ptr_float %pc1 %int_0
2467            %4 = OpLoad %float %3
2468                 OpReturn
2469                 OpFunctionEnd
2470 
2471         %sub2 = OpFunction %void None %voidfn
2472   %label_sub2 = OpLabel
2473            %5 = OpAccessChain %ptr_float %pc2 %int_0
2474            %6 = OpLoad %float %5
2475                 OpReturn
2476                 OpFunctionEnd
2477 
2478            %1 = OpFunction %void None %voidfn
2479       %label1 = OpLabel
2480        %call1 = OpFunctionCall %void %sub1
2481                 OpReturn
2482                 OpFunctionEnd
2483 
2484            %2 = OpFunction %void None %voidfn
2485       %label2 = OpLabel
2486        %call2 = OpFunctionCall %void %sub2
2487                 OpReturn
2488                 OpFunctionEnd
2489 )";
2490 
2491   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
2492   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1))
2493       << getDiagnosticString();
2494 }
2495 
TEST_F(ValidateDecorations,VulkanMultiplePushConstantsSingleEntryPointSubFunctionBad)2496 TEST_F(ValidateDecorations,
2497        VulkanMultiplePushConstantsSingleEntryPointSubFunctionBad) {
2498   std::string spirv = R"(
2499                 OpCapability Shader
2500                 OpMemoryModel Logical GLSL450
2501                 OpEntryPoint Fragment %1 "main"
2502                 OpExecutionMode %1 OriginUpperLeft
2503 
2504                 OpDecorate %struct Block
2505                 OpMemberDecorate %struct 0 Offset 0
2506 
2507         %void = OpTypeVoid
2508       %voidfn = OpTypeFunction %void
2509        %float = OpTypeFloat 32
2510          %int = OpTypeInt 32 0
2511        %int_0 = OpConstant %int 0
2512       %struct = OpTypeStruct %float
2513          %ptr = OpTypePointer PushConstant %struct
2514    %ptr_float = OpTypePointer PushConstant %float
2515          %pc1 = OpVariable %ptr PushConstant
2516          %pc2 = OpVariable %ptr PushConstant
2517 
2518         %sub1 = OpFunction %void None %voidfn
2519   %label_sub1 = OpLabel
2520            %3 = OpAccessChain %ptr_float %pc1 %int_0
2521            %4 = OpLoad %float %3
2522                 OpReturn
2523                 OpFunctionEnd
2524 
2525         %sub2 = OpFunction %void None %voidfn
2526   %label_sub2 = OpLabel
2527            %5 = OpAccessChain %ptr_float %pc2 %int_0
2528            %6 = OpLoad %float %5
2529                 OpReturn
2530                 OpFunctionEnd
2531 
2532            %1 = OpFunction %void None %voidfn
2533       %label1 = OpLabel
2534        %call1 = OpFunctionCall %void %sub1
2535        %call2 = OpFunctionCall %void %sub2
2536                 OpReturn
2537                 OpFunctionEnd
2538 )";
2539 
2540   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
2541   EXPECT_EQ(SPV_ERROR_INVALID_ID,
2542             ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
2543   EXPECT_THAT(
2544       getDiagnosticString(),
2545       HasSubstr(
2546           "Entry point id '1' uses more than one PushConstant interface.\n"
2547           "From Vulkan spec, section 14.5.1:\n"
2548           "There must be no more than one push constant block "
2549           "statically used per shader entry point."));
2550 }
2551 
TEST_F(ValidateDecorations,VulkanUniformMissingDescriptorSetBad)2552 TEST_F(ValidateDecorations, VulkanUniformMissingDescriptorSetBad) {
2553   std::string spirv = R"(
2554             OpCapability Shader
2555             OpMemoryModel Logical GLSL450
2556             OpEntryPoint Fragment %1 "main"
2557             OpExecutionMode %1 OriginUpperLeft
2558 
2559             OpDecorate %struct Block
2560             OpMemberDecorate %struct 0 Offset 0
2561             OpDecorate %var Binding 0
2562 
2563     %void = OpTypeVoid
2564   %voidfn = OpTypeFunction %void
2565    %float = OpTypeFloat 32
2566   %struct = OpTypeStruct %float
2567      %ptr = OpTypePointer Uniform %struct
2568 %ptr_float = OpTypePointer Uniform %float
2569      %var = OpVariable %ptr Uniform
2570      %int = OpTypeInt 32 0
2571    %int_0 = OpConstant %int 0
2572 
2573        %1 = OpFunction %void None %voidfn
2574    %label = OpLabel
2575        %2 = OpAccessChain %ptr_float %var %int_0
2576        %3 = OpLoad %float %2
2577             OpReturn
2578             OpFunctionEnd
2579 )";
2580 
2581   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
2582   EXPECT_EQ(SPV_ERROR_INVALID_ID,
2583             ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
2584   EXPECT_THAT(getDiagnosticString(),
2585               HasSubstr("Uniform id '3' is missing DescriptorSet decoration.\n"
2586                         "From Vulkan spec, section 14.5.2:\n"
2587                         "These variables must have DescriptorSet and Binding "
2588                         "decorations specified"));
2589 }
2590 
TEST_F(ValidateDecorations,VulkanUniformMissingBindingBad)2591 TEST_F(ValidateDecorations, VulkanUniformMissingBindingBad) {
2592   std::string spirv = R"(
2593             OpCapability Shader
2594             OpMemoryModel Logical GLSL450
2595             OpEntryPoint Fragment %1 "main"
2596             OpExecutionMode %1 OriginUpperLeft
2597 
2598             OpDecorate %struct Block
2599             OpMemberDecorate %struct 0 Offset 0
2600             OpDecorate %var DescriptorSet 0
2601 
2602     %void = OpTypeVoid
2603   %voidfn = OpTypeFunction %void
2604    %float = OpTypeFloat 32
2605   %struct = OpTypeStruct %float
2606      %ptr = OpTypePointer Uniform %struct
2607 %ptr_float = OpTypePointer Uniform %float
2608      %var = OpVariable %ptr Uniform
2609      %int = OpTypeInt 32 0
2610    %int_0 = OpConstant %int 0
2611 
2612        %1 = OpFunction %void None %voidfn
2613    %label = OpLabel
2614        %2 = OpAccessChain %ptr_float %var %int_0
2615        %3 = OpLoad %float %2
2616             OpReturn
2617             OpFunctionEnd
2618 )";
2619 
2620   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
2621   EXPECT_EQ(SPV_ERROR_INVALID_ID,
2622             ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
2623   EXPECT_THAT(getDiagnosticString(),
2624               HasSubstr("Uniform id '3' is missing Binding decoration.\n"
2625                         "From Vulkan spec, section 14.5.2:\n"
2626                         "These variables must have DescriptorSet and Binding "
2627                         "decorations specified"));
2628 }
2629 
TEST_F(ValidateDecorations,VulkanUniformConstantMissingDescriptorSetBad)2630 TEST_F(ValidateDecorations, VulkanUniformConstantMissingDescriptorSetBad) {
2631   std::string spirv = R"(
2632             OpCapability Shader
2633             OpMemoryModel Logical GLSL450
2634             OpEntryPoint Fragment %1 "main"
2635             OpExecutionMode %1 OriginUpperLeft
2636 
2637             OpDecorate %var Binding 0
2638 
2639     %void = OpTypeVoid
2640   %voidfn = OpTypeFunction %void
2641  %sampler = OpTypeSampler
2642      %ptr = OpTypePointer UniformConstant %sampler
2643      %var = OpVariable %ptr UniformConstant
2644 
2645        %1 = OpFunction %void None %voidfn
2646    %label = OpLabel
2647        %2 = OpLoad %sampler %var
2648             OpReturn
2649             OpFunctionEnd
2650 )";
2651 
2652   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
2653   EXPECT_EQ(SPV_ERROR_INVALID_ID,
2654             ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
2655   EXPECT_THAT(
2656       getDiagnosticString(),
2657       HasSubstr("UniformConstant id '2' is missing DescriptorSet decoration.\n"
2658                 "From Vulkan spec, section 14.5.2:\n"
2659                 "These variables must have DescriptorSet and Binding "
2660                 "decorations specified"));
2661 }
2662 
TEST_F(ValidateDecorations,VulkanUniformConstantMissingBindingBad)2663 TEST_F(ValidateDecorations, VulkanUniformConstantMissingBindingBad) {
2664   std::string spirv = R"(
2665             OpCapability Shader
2666             OpMemoryModel Logical GLSL450
2667             OpEntryPoint Fragment %1 "main"
2668             OpExecutionMode %1 OriginUpperLeft
2669 
2670             OpDecorate %var DescriptorSet 0
2671 
2672     %void = OpTypeVoid
2673   %voidfn = OpTypeFunction %void
2674  %sampler = OpTypeSampler
2675      %ptr = OpTypePointer UniformConstant %sampler
2676      %var = OpVariable %ptr UniformConstant
2677 
2678        %1 = OpFunction %void None %voidfn
2679    %label = OpLabel
2680        %2 = OpLoad %sampler %var
2681             OpReturn
2682             OpFunctionEnd
2683 )";
2684 
2685   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
2686   EXPECT_EQ(SPV_ERROR_INVALID_ID,
2687             ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
2688   EXPECT_THAT(
2689       getDiagnosticString(),
2690       HasSubstr("UniformConstant id '2' is missing Binding decoration.\n"
2691                 "From Vulkan spec, section 14.5.2:\n"
2692                 "These variables must have DescriptorSet and Binding "
2693                 "decorations specified"));
2694 }
2695 
TEST_F(ValidateDecorations,VulkanStorageBufferMissingDescriptorSetBad)2696 TEST_F(ValidateDecorations, VulkanStorageBufferMissingDescriptorSetBad) {
2697   std::string spirv = R"(
2698             OpCapability Shader
2699             OpExtension "SPV_KHR_storage_buffer_storage_class"
2700             OpMemoryModel Logical GLSL450
2701             OpEntryPoint Fragment %1 "main"
2702             OpExecutionMode %1 OriginUpperLeft
2703 
2704             OpDecorate %struct Block
2705             OpDecorate %var Binding 0
2706 
2707     %void = OpTypeVoid
2708   %voidfn = OpTypeFunction %void
2709    %float = OpTypeFloat 32
2710   %struct = OpTypeStruct %float
2711      %ptr = OpTypePointer StorageBuffer %struct
2712      %var = OpVariable %ptr StorageBuffer
2713 %ptr_float = OpTypePointer StorageBuffer %float
2714      %int = OpTypeInt 32 0
2715    %int_0 = OpConstant %int 0
2716 
2717        %1 = OpFunction %void None %voidfn
2718    %label = OpLabel
2719        %2 = OpAccessChain %ptr_float %var %int_0
2720        %3 = OpLoad %float %2
2721             OpReturn
2722             OpFunctionEnd
2723 )";
2724 
2725   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
2726   EXPECT_EQ(SPV_ERROR_INVALID_ID,
2727             ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
2728   EXPECT_THAT(
2729       getDiagnosticString(),
2730       HasSubstr("StorageBuffer id '3' is missing DescriptorSet decoration.\n"
2731                 "From Vulkan spec, section 14.5.2:\n"
2732                 "These variables must have DescriptorSet and Binding "
2733                 "decorations specified"));
2734 }
2735 
TEST_F(ValidateDecorations,VulkanStorageBufferMissingBindingBad)2736 TEST_F(ValidateDecorations, VulkanStorageBufferMissingBindingBad) {
2737   std::string spirv = R"(
2738             OpCapability Shader
2739             OpExtension "SPV_KHR_storage_buffer_storage_class"
2740             OpMemoryModel Logical GLSL450
2741             OpEntryPoint Fragment %1 "main"
2742             OpExecutionMode %1 OriginUpperLeft
2743 
2744             OpDecorate %struct Block
2745             OpDecorate %var DescriptorSet 0
2746 
2747     %void = OpTypeVoid
2748   %voidfn = OpTypeFunction %void
2749    %float = OpTypeFloat 32
2750   %struct = OpTypeStruct %float
2751      %ptr = OpTypePointer StorageBuffer %struct
2752      %var = OpVariable %ptr StorageBuffer
2753 %ptr_float = OpTypePointer StorageBuffer %float
2754      %int = OpTypeInt 32 0
2755    %int_0 = OpConstant %int 0
2756 
2757        %1 = OpFunction %void None %voidfn
2758    %label = OpLabel
2759        %2 = OpAccessChain %ptr_float %var %int_0
2760        %3 = OpLoad %float %2
2761             OpReturn
2762             OpFunctionEnd
2763 )";
2764 
2765   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
2766   EXPECT_EQ(SPV_ERROR_INVALID_ID,
2767             ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
2768   EXPECT_THAT(getDiagnosticString(),
2769               HasSubstr("StorageBuffer id '3' is missing Binding decoration.\n"
2770                         "From Vulkan spec, section 14.5.2:\n"
2771                         "These variables must have DescriptorSet and Binding "
2772                         "decorations specified"));
2773 }
2774 
TEST_F(ValidateDecorations,VulkanStorageBufferMissingDescriptorSetSubFunctionBad)2775 TEST_F(ValidateDecorations,
2776        VulkanStorageBufferMissingDescriptorSetSubFunctionBad) {
2777   std::string spirv = R"(
2778             OpCapability Shader
2779             OpExtension "SPV_KHR_storage_buffer_storage_class"
2780             OpMemoryModel Logical GLSL450
2781             OpEntryPoint Fragment %1 "main"
2782             OpExecutionMode %1 OriginUpperLeft
2783 
2784             OpDecorate %struct Block
2785             OpDecorate %var Binding 0
2786 
2787     %void = OpTypeVoid
2788   %voidfn = OpTypeFunction %void
2789    %float = OpTypeFloat 32
2790   %struct = OpTypeStruct %float
2791      %ptr = OpTypePointer StorageBuffer %struct
2792      %var = OpVariable %ptr StorageBuffer
2793 %ptr_float = OpTypePointer StorageBuffer %float
2794      %int = OpTypeInt 32 0
2795    %int_0 = OpConstant %int 0
2796 
2797        %1 = OpFunction %void None %voidfn
2798    %label = OpLabel
2799     %call = OpFunctionCall %void %2
2800             OpReturn
2801             OpFunctionEnd
2802        %2 = OpFunction %void None %voidfn
2803   %label2 = OpLabel
2804        %3 = OpAccessChain %ptr_float %var %int_0
2805        %4 = OpLoad %float %3
2806             OpReturn
2807             OpFunctionEnd
2808 )";
2809 
2810   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
2811   EXPECT_EQ(SPV_ERROR_INVALID_ID,
2812             ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
2813   EXPECT_THAT(
2814       getDiagnosticString(),
2815       HasSubstr("StorageBuffer id '3' is missing DescriptorSet decoration.\n"
2816                 "From Vulkan spec, section 14.5.2:\n"
2817                 "These variables must have DescriptorSet and Binding "
2818                 "decorations specified"));
2819 }
2820 
TEST_F(ValidateDecorations,VulkanStorageBufferMissingDescriptorAndBindingUnusedGood)2821 TEST_F(ValidateDecorations,
2822        VulkanStorageBufferMissingDescriptorAndBindingUnusedGood) {
2823   std::string spirv = R"(
2824             OpCapability Shader
2825             OpExtension "SPV_KHR_storage_buffer_storage_class"
2826             OpMemoryModel Logical GLSL450
2827             OpEntryPoint Fragment %1 "main"
2828             OpExecutionMode %1 OriginUpperLeft
2829 
2830             OpDecorate %struct BufferBlock
2831 
2832     %void = OpTypeVoid
2833   %voidfn = OpTypeFunction %void
2834    %float = OpTypeFloat 32
2835   %struct = OpTypeStruct %float
2836      %ptr = OpTypePointer StorageBuffer %struct
2837      %var = OpVariable %ptr StorageBuffer
2838 
2839        %1 = OpFunction %void None %voidfn
2840    %label = OpLabel
2841             OpReturn
2842             OpFunctionEnd
2843 )";
2844 
2845   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
2846   EXPECT_EQ(SPV_SUCCESS,
2847             ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
2848 }
2849 
TEST_F(ValidateDecorations,UniformMissingDescriptorSetGood)2850 TEST_F(ValidateDecorations, UniformMissingDescriptorSetGood) {
2851   std::string spirv = R"(
2852             OpCapability Shader
2853             OpMemoryModel Logical GLSL450
2854             OpEntryPoint Fragment %1 "main"
2855             OpExecutionMode %1 OriginUpperLeft
2856 
2857             OpDecorate %struct Block
2858             OpMemberDecorate %struct 0 Offset 0
2859             OpDecorate %var Binding 0
2860 
2861     %void = OpTypeVoid
2862   %voidfn = OpTypeFunction %void
2863    %float = OpTypeFloat 32
2864   %struct = OpTypeStruct %float
2865      %ptr = OpTypePointer Uniform %struct
2866      %var = OpVariable %ptr Uniform
2867 
2868        %1 = OpFunction %void None %voidfn
2869    %label = OpLabel
2870             OpReturn
2871             OpFunctionEnd
2872 )";
2873 
2874   CompileSuccessfully(spirv);
2875   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
2876       << getDiagnosticString();
2877 }
2878 
TEST_F(ValidateDecorations,UniformMissingBindingGood)2879 TEST_F(ValidateDecorations, UniformMissingBindingGood) {
2880   std::string spirv = R"(
2881             OpCapability Shader
2882             OpMemoryModel Logical GLSL450
2883             OpEntryPoint Fragment %1 "main"
2884             OpExecutionMode %1 OriginUpperLeft
2885 
2886             OpDecorate %struct Block
2887             OpMemberDecorate %struct 0 Offset 0
2888             OpDecorate %var DescriptorSet 0
2889 
2890     %void = OpTypeVoid
2891   %voidfn = OpTypeFunction %void
2892    %float = OpTypeFloat 32
2893   %struct = OpTypeStruct %float
2894      %ptr = OpTypePointer Uniform %struct
2895      %var = OpVariable %ptr Uniform
2896 
2897        %1 = OpFunction %void None %voidfn
2898    %label = OpLabel
2899             OpReturn
2900             OpFunctionEnd
2901 )";
2902 
2903   CompileSuccessfully(spirv);
2904   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
2905       << getDiagnosticString();
2906 }
2907 
TEST_F(ValidateDecorations,UniformConstantMissingDescriptorSetGood)2908 TEST_F(ValidateDecorations, UniformConstantMissingDescriptorSetGood) {
2909   std::string spirv = R"(
2910             OpCapability Shader
2911             OpMemoryModel Logical GLSL450
2912             OpEntryPoint Fragment %1 "main"
2913             OpExecutionMode %1 OriginUpperLeft
2914 
2915             OpDecorate %var Binding 0
2916 
2917     %void = OpTypeVoid
2918   %voidfn = OpTypeFunction %void
2919  %sampler = OpTypeSampler
2920      %ptr = OpTypePointer UniformConstant %sampler
2921      %var = OpVariable %ptr UniformConstant
2922 
2923        %1 = OpFunction %void None %voidfn
2924    %label = OpLabel
2925             OpReturn
2926             OpFunctionEnd
2927 )";
2928 
2929   CompileSuccessfully(spirv);
2930   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
2931       << getDiagnosticString();
2932 }
2933 
TEST_F(ValidateDecorations,UniformConstantMissingBindingGood)2934 TEST_F(ValidateDecorations, UniformConstantMissingBindingGood) {
2935   std::string spirv = R"(
2936             OpCapability Shader
2937             OpMemoryModel Logical GLSL450
2938             OpEntryPoint Fragment %1 "main"
2939             OpExecutionMode %1 OriginUpperLeft
2940 
2941             OpDecorate %var DescriptorSet 0
2942 
2943     %void = OpTypeVoid
2944   %voidfn = OpTypeFunction %void
2945  %sampler = OpTypeSampler
2946      %ptr = OpTypePointer UniformConstant %sampler
2947      %var = OpVariable %ptr UniformConstant
2948 
2949        %1 = OpFunction %void None %voidfn
2950    %label = OpLabel
2951             OpReturn
2952             OpFunctionEnd
2953 )";
2954 
2955   CompileSuccessfully(spirv);
2956   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
2957       << getDiagnosticString();
2958 }
2959 
TEST_F(ValidateDecorations,StorageBufferMissingDescriptorSetGood)2960 TEST_F(ValidateDecorations, StorageBufferMissingDescriptorSetGood) {
2961   std::string spirv = R"(
2962             OpCapability Shader
2963             OpExtension "SPV_KHR_storage_buffer_storage_class"
2964             OpMemoryModel Logical GLSL450
2965             OpEntryPoint Fragment %1 "main"
2966             OpExecutionMode %1 OriginUpperLeft
2967 
2968             OpDecorate %struct BufferBlock
2969             OpDecorate %var Binding 0
2970 
2971     %void = OpTypeVoid
2972   %voidfn = OpTypeFunction %void
2973    %float = OpTypeFloat 32
2974   %struct = OpTypeStruct %float
2975      %ptr = OpTypePointer StorageBuffer %struct
2976      %var = OpVariable %ptr StorageBuffer
2977 
2978        %1 = OpFunction %void None %voidfn
2979    %label = OpLabel
2980             OpReturn
2981             OpFunctionEnd
2982 )";
2983 
2984   CompileSuccessfully(spirv);
2985   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
2986       << getDiagnosticString();
2987 }
2988 
TEST_F(ValidateDecorations,StorageBufferMissingBindingGood)2989 TEST_F(ValidateDecorations, StorageBufferMissingBindingGood) {
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 BufferBlock
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 
3007        %1 = OpFunction %void None %voidfn
3008    %label = OpLabel
3009             OpReturn
3010             OpFunctionEnd
3011 )";
3012 
3013   CompileSuccessfully(spirv);
3014   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
3015       << getDiagnosticString();
3016 }
3017 
TEST_F(ValidateDecorations,StorageBufferStorageClassArrayBaseAlignmentGood)3018 TEST_F(ValidateDecorations, StorageBufferStorageClassArrayBaseAlignmentGood) {
3019   // Spot check buffer rules when using StorageBuffer storage class with Block
3020   // decoration.
3021   std::string spirv = R"(
3022                OpCapability Shader
3023                OpExtension "SPV_KHR_storage_buffer_storage_class"
3024                OpMemoryModel Logical GLSL450
3025                OpEntryPoint Vertex %main "main"
3026                OpSource GLSL 450
3027                OpDecorate %_arr_float_uint_2 ArrayStride 4
3028                OpMemberDecorate %S 0 Offset 0
3029                OpMemberDecorate %S 1 Offset 8
3030                OpDecorate %S Block
3031                OpDecorate %u DescriptorSet 0
3032                OpDecorate %u Binding 0
3033        %void = OpTypeVoid
3034           %3 = OpTypeFunction %void
3035       %float = OpTypeFloat 32
3036     %v2float = OpTypeVector %float 2
3037        %uint = OpTypeInt 32 0
3038      %uint_2 = OpConstant %uint 2
3039 %_arr_float_uint_2 = OpTypeArray %float %uint_2
3040           %S = OpTypeStruct %v2float %_arr_float_uint_2
3041 %_ptr_Uniform_S = OpTypePointer StorageBuffer %S
3042           %u = OpVariable %_ptr_Uniform_S StorageBuffer
3043        %main = OpFunction %void None %3
3044           %5 = OpLabel
3045                OpReturn
3046                OpFunctionEnd
3047   )";
3048 
3049   CompileSuccessfully(spirv);
3050   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
3051       << getDiagnosticString();
3052 }
3053 
TEST_F(ValidateDecorations,StorageBufferStorageClassArrayBadAlignmentBad)3054 TEST_F(ValidateDecorations, StorageBufferStorageClassArrayBadAlignmentBad) {
3055   // Like the previous test, but with offset 7.
3056   std::string spirv = R"(
3057                OpCapability Shader
3058                OpExtension "SPV_KHR_storage_buffer_storage_class"
3059                OpMemoryModel Logical GLSL450
3060                OpEntryPoint Vertex %main "main"
3061                OpSource GLSL 450
3062                OpDecorate %_arr_float_uint_2 ArrayStride 4
3063                OpMemberDecorate %S 0 Offset 0
3064                OpMemberDecorate %S 1 Offset 7
3065                OpDecorate %S Block
3066                OpDecorate %u DescriptorSet 0
3067                OpDecorate %u Binding 0
3068        %void = OpTypeVoid
3069           %3 = OpTypeFunction %void
3070       %float = OpTypeFloat 32
3071     %v2float = OpTypeVector %float 2
3072        %uint = OpTypeInt 32 0
3073      %uint_2 = OpConstant %uint 2
3074 %_arr_float_uint_2 = OpTypeArray %float %uint_2
3075           %S = OpTypeStruct %v2float %_arr_float_uint_2
3076 %_ptr_Uniform_S = OpTypePointer StorageBuffer %S
3077           %u = OpVariable %_ptr_Uniform_S StorageBuffer
3078        %main = OpFunction %void None %3
3079           %5 = OpLabel
3080                OpReturn
3081                OpFunctionEnd
3082   )";
3083 
3084   CompileSuccessfully(spirv);
3085   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
3086   EXPECT_THAT(
3087       getDiagnosticString(),
3088       HasSubstr(
3089           "Structure id 3 decorated as Block for variable in StorageBuffer "
3090           "storage class must follow standard storage buffer layout rules: "
3091           "member 1 at offset 7 is not aligned to 4"));
3092 }
3093 
TEST_F(ValidateDecorations,BufferBlockStandardStorageBufferLayout)3094 TEST_F(ValidateDecorations, BufferBlockStandardStorageBufferLayout) {
3095   std::string spirv = R"(
3096                OpCapability Shader
3097           %1 = OpExtInstImport "GLSL.std.450"
3098                OpMemoryModel Logical GLSL450
3099                OpEntryPoint GLCompute %main "main"
3100                OpExecutionMode %main LocalSize 1 1 1
3101                OpSource GLSL 430
3102                OpMemberDecorate %F 0 Offset 0
3103                OpMemberDecorate %F 1 Offset 8
3104                OpDecorate %_arr_float_uint_2 ArrayStride 4
3105                OpDecorate %_arr_mat3v3float_uint_2 ArrayStride 48
3106                OpMemberDecorate %O 0 Offset 0
3107                OpMemberDecorate %O 1 Offset 16
3108                OpMemberDecorate %O 2 Offset 24
3109                OpMemberDecorate %O 3 Offset 32
3110                OpMemberDecorate %O 4 ColMajor
3111                OpMemberDecorate %O 4 Offset 48
3112                OpMemberDecorate %O 4 MatrixStride 16
3113                OpDecorate %_arr_O_uint_2 ArrayStride 144
3114                OpMemberDecorate %Output 0 Offset 0
3115                OpMemberDecorate %Output 1 Offset 8
3116                OpMemberDecorate %Output 2 Offset 16
3117                OpMemberDecorate %Output 3 Offset 32
3118                OpMemberDecorate %Output 4 Offset 48
3119                OpMemberDecorate %Output 5 Offset 52
3120                OpMemberDecorate %Output 6 ColMajor
3121                OpMemberDecorate %Output 6 Offset 64
3122                OpMemberDecorate %Output 6 MatrixStride 16
3123                OpMemberDecorate %Output 7 Offset 96
3124                OpDecorate %Output BufferBlock
3125        %void = OpTypeVoid
3126           %3 = OpTypeFunction %void
3127       %float = OpTypeFloat 32
3128     %v2float = OpTypeVector %float 2
3129     %v3float = OpTypeVector %float 3
3130         %int = OpTypeInt 32 1
3131        %uint = OpTypeInt 32 0
3132      %v2uint = OpTypeVector %uint 2
3133           %F = OpTypeStruct %int %v2uint
3134      %uint_2 = OpConstant %uint 2
3135 %_arr_float_uint_2 = OpTypeArray %float %uint_2
3136 %mat2v3float = OpTypeMatrix %v3float 2
3137      %v3uint = OpTypeVector %uint 3
3138 %mat3v3float = OpTypeMatrix %v3float 3
3139 %_arr_mat3v3float_uint_2 = OpTypeArray %mat3v3float %uint_2
3140           %O = OpTypeStruct %v3uint %v2float %_arr_float_uint_2 %v2float %_arr_mat3v3float_uint_2
3141 %_arr_O_uint_2 = OpTypeArray %O %uint_2
3142      %Output = OpTypeStruct %float %v2float %v3float %F %float %_arr_float_uint_2 %mat2v3float %_arr_O_uint_2
3143 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
3144  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
3145        %main = OpFunction %void None %3
3146           %5 = OpLabel
3147                OpReturn
3148                OpFunctionEnd
3149   )";
3150 
3151   CompileSuccessfully(spirv);
3152   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
3153 }
3154 
TEST_F(ValidateDecorations,StorageBufferLayoutPermitsTightVec3ScalarPackingGood)3155 TEST_F(ValidateDecorations,
3156        StorageBufferLayoutPermitsTightVec3ScalarPackingGood) {
3157   // See https://github.com/KhronosGroup/SPIRV-Tools/issues/1666
3158   std::string spirv = R"(
3159                OpCapability Shader
3160                OpExtension "SPV_KHR_storage_buffer_storage_class"
3161                OpMemoryModel Logical GLSL450
3162                OpEntryPoint Vertex %main "main"
3163                OpSource GLSL 450
3164                OpMemberDecorate %S 0 Offset 0
3165                OpMemberDecorate %S 1 Offset 12
3166                OpDecorate %S Block
3167                OpDecorate %B DescriptorSet 0
3168                OpDecorate %B Binding 0
3169        %void = OpTypeVoid
3170           %3 = OpTypeFunction %void
3171       %float = OpTypeFloat 32
3172     %v3float = OpTypeVector %float 3
3173           %S = OpTypeStruct %v3float %float
3174 %_ptr_StorageBuffer_S = OpTypePointer StorageBuffer %S
3175           %B = OpVariable %_ptr_StorageBuffer_S StorageBuffer
3176        %main = OpFunction %void None %3
3177           %5 = OpLabel
3178                OpReturn
3179                OpFunctionEnd
3180   )";
3181 
3182   CompileSuccessfully(spirv);
3183   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
3184       << getDiagnosticString();
3185 }
3186 
TEST_F(ValidateDecorations,StorageBufferLayoutForbidsTightScalarVec3PackingBad)3187 TEST_F(ValidateDecorations,
3188        StorageBufferLayoutForbidsTightScalarVec3PackingBad) {
3189   // See https://github.com/KhronosGroup/SPIRV-Tools/issues/1666
3190   std::string spirv = R"(
3191                OpCapability Shader
3192                OpExtension "SPV_KHR_storage_buffer_storage_class"
3193                OpMemoryModel Logical GLSL450
3194                OpEntryPoint Vertex %main "main"
3195                OpSource GLSL 450
3196                OpMemberDecorate %S 0 Offset 0
3197                OpMemberDecorate %S 1 Offset 4
3198                OpDecorate %S Block
3199                OpDecorate %B DescriptorSet 0
3200                OpDecorate %B Binding 0
3201        %void = OpTypeVoid
3202           %3 = OpTypeFunction %void
3203       %float = OpTypeFloat 32
3204     %v3float = OpTypeVector %float 3
3205           %S = OpTypeStruct %float %v3float
3206 %_ptr_StorageBuffer_S = OpTypePointer StorageBuffer %S
3207           %B = OpVariable %_ptr_StorageBuffer_S StorageBuffer
3208        %main = OpFunction %void None %3
3209           %5 = OpLabel
3210                OpReturn
3211                OpFunctionEnd
3212   )";
3213 
3214   CompileSuccessfully(spirv);
3215   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
3216   EXPECT_THAT(
3217       getDiagnosticString(),
3218       HasSubstr(
3219           "Structure id 2 decorated as Block for variable in StorageBuffer "
3220           "storage class must follow standard storage buffer layout "
3221           "rules: member 1 at offset 4 is not aligned to 16"));
3222 }
3223 
TEST_F(ValidateDecorations,BlockStandardUniformBufferLayoutIncorrectOffset0Bad)3224 TEST_F(ValidateDecorations,
3225        BlockStandardUniformBufferLayoutIncorrectOffset0Bad) {
3226   std::string spirv = R"(
3227                OpCapability Shader
3228           %1 = OpExtInstImport "GLSL.std.450"
3229                OpMemoryModel Logical GLSL450
3230                OpEntryPoint GLCompute %main "main"
3231                OpExecutionMode %main LocalSize 1 1 1
3232                OpSource GLSL 430
3233                OpMemberDecorate %F 0 Offset 0
3234                OpMemberDecorate %F 1 Offset 8
3235                OpDecorate %_arr_float_uint_2 ArrayStride 16
3236                OpDecorate %_arr_mat3v3float_uint_2 ArrayStride 48
3237                OpMemberDecorate %O 0 Offset 0
3238                OpMemberDecorate %O 1 Offset 16
3239                OpMemberDecorate %O 2 Offset 24
3240                OpMemberDecorate %O 3 Offset 33
3241                OpMemberDecorate %O 4 ColMajor
3242                OpMemberDecorate %O 4 Offset 80
3243                OpMemberDecorate %O 4 MatrixStride 16
3244                OpDecorate %_arr_O_uint_2 ArrayStride 176
3245                OpMemberDecorate %Output 0 Offset 0
3246                OpMemberDecorate %Output 1 Offset 8
3247                OpMemberDecorate %Output 2 Offset 16
3248                OpMemberDecorate %Output 3 Offset 32
3249                OpMemberDecorate %Output 4 Offset 48
3250                OpMemberDecorate %Output 5 Offset 64
3251                OpMemberDecorate %Output 6 ColMajor
3252                OpMemberDecorate %Output 6 Offset 96
3253                OpMemberDecorate %Output 6 MatrixStride 16
3254                OpMemberDecorate %Output 7 Offset 128
3255                OpDecorate %Output Block
3256        %void = OpTypeVoid
3257           %3 = OpTypeFunction %void
3258       %float = OpTypeFloat 32
3259     %v2float = OpTypeVector %float 2
3260     %v3float = OpTypeVector %float 3
3261         %int = OpTypeInt 32 1
3262        %uint = OpTypeInt 32 0
3263      %v2uint = OpTypeVector %uint 2
3264           %F = OpTypeStruct %int %v2uint
3265      %uint_2 = OpConstant %uint 2
3266 %_arr_float_uint_2 = OpTypeArray %float %uint_2
3267 %mat2v3float = OpTypeMatrix %v3float 2
3268      %v3uint = OpTypeVector %uint 3
3269 %mat3v3float = OpTypeMatrix %v3float 3
3270 %_arr_mat3v3float_uint_2 = OpTypeArray %mat3v3float %uint_2
3271           %O = OpTypeStruct %v3uint %v2float %_arr_float_uint_2 %v2float %_arr_mat3v3float_uint_2
3272 %_arr_O_uint_2 = OpTypeArray %O %uint_2
3273      %Output = OpTypeStruct %float %v2float %v3float %F %float %_arr_float_uint_2 %mat2v3float %_arr_O_uint_2
3274 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
3275  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
3276        %main = OpFunction %void None %3
3277           %5 = OpLabel
3278                OpReturn
3279                OpFunctionEnd
3280   )";
3281 
3282   CompileSuccessfully(spirv);
3283   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
3284   EXPECT_THAT(
3285       getDiagnosticString(),
3286       HasSubstr("Structure id 6 decorated as Block for variable in Uniform "
3287                 "storage class must follow standard uniform buffer layout "
3288                 "rules: member 2 at offset 24 is not aligned to 16"));
3289 }
3290 
TEST_F(ValidateDecorations,BlockStandardUniformBufferLayoutIncorrectOffset1Bad)3291 TEST_F(ValidateDecorations,
3292        BlockStandardUniformBufferLayoutIncorrectOffset1Bad) {
3293   std::string spirv = R"(
3294                OpCapability Shader
3295           %1 = OpExtInstImport "GLSL.std.450"
3296                OpMemoryModel Logical GLSL450
3297                OpEntryPoint GLCompute %main "main"
3298                OpExecutionMode %main LocalSize 1 1 1
3299                OpSource GLSL 430
3300                OpMemberDecorate %F 0 Offset 0
3301                OpMemberDecorate %F 1 Offset 8
3302                OpDecorate %_arr_float_uint_2 ArrayStride 16
3303                OpDecorate %_arr_mat3v3float_uint_2 ArrayStride 48
3304                OpMemberDecorate %O 0 Offset 0
3305                OpMemberDecorate %O 1 Offset 16
3306                OpMemberDecorate %O 2 Offset 32
3307                OpMemberDecorate %O 3 Offset 64
3308                OpMemberDecorate %O 4 ColMajor
3309                OpMemberDecorate %O 4 Offset 80
3310                OpMemberDecorate %O 4 MatrixStride 16
3311                OpDecorate %_arr_O_uint_2 ArrayStride 176
3312                OpMemberDecorate %Output 0 Offset 0
3313                OpMemberDecorate %Output 1 Offset 8
3314                OpMemberDecorate %Output 2 Offset 16
3315                OpMemberDecorate %Output 3 Offset 32
3316                OpMemberDecorate %Output 4 Offset 48
3317                OpMemberDecorate %Output 5 Offset 71
3318                OpMemberDecorate %Output 6 ColMajor
3319                OpMemberDecorate %Output 6 Offset 96
3320                OpMemberDecorate %Output 6 MatrixStride 16
3321                OpMemberDecorate %Output 7 Offset 128
3322                OpDecorate %Output Block
3323        %void = OpTypeVoid
3324           %3 = OpTypeFunction %void
3325       %float = OpTypeFloat 32
3326     %v2float = OpTypeVector %float 2
3327     %v3float = OpTypeVector %float 3
3328         %int = OpTypeInt 32 1
3329        %uint = OpTypeInt 32 0
3330      %v2uint = OpTypeVector %uint 2
3331           %F = OpTypeStruct %int %v2uint
3332      %uint_2 = OpConstant %uint 2
3333 %_arr_float_uint_2 = OpTypeArray %float %uint_2
3334 %mat2v3float = OpTypeMatrix %v3float 2
3335      %v3uint = OpTypeVector %uint 3
3336 %mat3v3float = OpTypeMatrix %v3float 3
3337 %_arr_mat3v3float_uint_2 = OpTypeArray %mat3v3float %uint_2
3338           %O = OpTypeStruct %v3uint %v2float %_arr_float_uint_2 %v2float %_arr_mat3v3float_uint_2
3339 %_arr_O_uint_2 = OpTypeArray %O %uint_2
3340      %Output = OpTypeStruct %float %v2float %v3float %F %float %_arr_float_uint_2 %mat2v3float %_arr_O_uint_2
3341 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
3342  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
3343        %main = OpFunction %void None %3
3344           %5 = OpLabel
3345                OpReturn
3346                OpFunctionEnd
3347   )";
3348 
3349   CompileSuccessfully(spirv);
3350   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
3351   EXPECT_THAT(
3352       getDiagnosticString(),
3353       HasSubstr("Structure id 8 decorated as Block for variable in Uniform "
3354                 "storage class must follow standard uniform buffer layout "
3355                 "rules: member 5 at offset 71 is not aligned to 16"));
3356 }
3357 
TEST_F(ValidateDecorations,BlockUniformBufferLayoutIncorrectArrayStrideBad)3358 TEST_F(ValidateDecorations, BlockUniformBufferLayoutIncorrectArrayStrideBad) {
3359   std::string spirv = R"(
3360                OpCapability Shader
3361           %1 = OpExtInstImport "GLSL.std.450"
3362                OpMemoryModel Logical GLSL450
3363                OpEntryPoint GLCompute %main "main"
3364                OpExecutionMode %main LocalSize 1 1 1
3365                OpSource GLSL 430
3366                OpMemberDecorate %F 0 Offset 0
3367                OpMemberDecorate %F 1 Offset 8
3368                OpDecorate %_arr_float_uint_2 ArrayStride 16
3369                OpDecorate %_arr_mat3v3float_uint_2 ArrayStride 49
3370                OpMemberDecorate %O 0 Offset 0
3371                OpMemberDecorate %O 1 Offset 16
3372                OpMemberDecorate %O 2 Offset 32
3373                OpMemberDecorate %O 3 Offset 64
3374                OpMemberDecorate %O 4 ColMajor
3375                OpMemberDecorate %O 4 Offset 80
3376                OpMemberDecorate %O 4 MatrixStride 16
3377                OpDecorate %_arr_O_uint_2 ArrayStride 176
3378                OpMemberDecorate %Output 0 Offset 0
3379                OpMemberDecorate %Output 1 Offset 8
3380                OpMemberDecorate %Output 2 Offset 16
3381                OpMemberDecorate %Output 3 Offset 32
3382                OpMemberDecorate %Output 4 Offset 48
3383                OpMemberDecorate %Output 5 Offset 64
3384                OpMemberDecorate %Output 6 ColMajor
3385                OpMemberDecorate %Output 6 Offset 96
3386                OpMemberDecorate %Output 6 MatrixStride 16
3387                OpMemberDecorate %Output 7 Offset 128
3388                OpDecorate %Output Block
3389        %void = OpTypeVoid
3390           %3 = OpTypeFunction %void
3391       %float = OpTypeFloat 32
3392     %v2float = OpTypeVector %float 2
3393     %v3float = OpTypeVector %float 3
3394         %int = OpTypeInt 32 1
3395        %uint = OpTypeInt 32 0
3396      %v2uint = OpTypeVector %uint 2
3397           %F = OpTypeStruct %int %v2uint
3398      %uint_2 = OpConstant %uint 2
3399 %_arr_float_uint_2 = OpTypeArray %float %uint_2
3400 %mat2v3float = OpTypeMatrix %v3float 2
3401      %v3uint = OpTypeVector %uint 3
3402 %mat3v3float = OpTypeMatrix %v3float 3
3403 %_arr_mat3v3float_uint_2 = OpTypeArray %mat3v3float %uint_2
3404           %O = OpTypeStruct %v3uint %v2float %_arr_float_uint_2 %v2float %_arr_mat3v3float_uint_2
3405 %_arr_O_uint_2 = OpTypeArray %O %uint_2
3406      %Output = OpTypeStruct %float %v2float %v3float %F %float %_arr_float_uint_2 %mat2v3float %_arr_O_uint_2
3407 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
3408  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
3409        %main = OpFunction %void None %3
3410           %5 = OpLabel
3411                OpReturn
3412                OpFunctionEnd
3413   )";
3414 
3415   CompileSuccessfully(spirv);
3416   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
3417   EXPECT_THAT(
3418       getDiagnosticString(),
3419       HasSubstr(
3420           "Structure id 6 decorated as Block for variable in Uniform storage "
3421           "class must follow standard uniform buffer layout rules: member 4 is "
3422           "an array with stride 49 not satisfying alignment to 16"));
3423 }
3424 
TEST_F(ValidateDecorations,BufferBlockStandardStorageBufferLayoutImproperStraddleBad)3425 TEST_F(ValidateDecorations,
3426        BufferBlockStandardStorageBufferLayoutImproperStraddleBad) {
3427   std::string spirv = R"(
3428                OpCapability Shader
3429           %1 = OpExtInstImport "GLSL.std.450"
3430                OpMemoryModel Logical GLSL450
3431                OpEntryPoint GLCompute %main "main"
3432                OpExecutionMode %main LocalSize 1 1 1
3433                OpSource GLSL 430
3434                OpMemberDecorate %Output 0 Offset 0
3435                OpMemberDecorate %Output 1 Offset 8
3436                OpDecorate %Output BufferBlock
3437        %void = OpTypeVoid
3438           %3 = OpTypeFunction %void
3439       %float = OpTypeFloat 32
3440     %v3float = OpTypeVector %float 3
3441      %Output = OpTypeStruct %float %v3float
3442 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
3443  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
3444        %main = OpFunction %void None %3
3445           %5 = OpLabel
3446                OpReturn
3447                OpFunctionEnd
3448   )";
3449 
3450   CompileSuccessfully(spirv);
3451   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
3452   EXPECT_THAT(
3453       getDiagnosticString(),
3454       HasSubstr("Structure id 3 decorated as BufferBlock for variable in "
3455                 "Uniform storage class must follow standard storage buffer "
3456                 "layout rules: member 1 at offset 8 is not aligned to 16"));
3457 }
3458 
TEST_F(ValidateDecorations,BlockUniformBufferLayoutOffsetInsideArrayPaddingBad)3459 TEST_F(ValidateDecorations,
3460        BlockUniformBufferLayoutOffsetInsideArrayPaddingBad) {
3461   // In this case the 2nd member fits entirely within the padding.
3462   std::string spirv = R"(
3463                OpCapability Shader
3464           %1 = OpExtInstImport "GLSL.std.450"
3465                OpMemoryModel Logical GLSL450
3466                OpEntryPoint GLCompute %main "main"
3467                OpExecutionMode %main LocalSize 1 1 1
3468                OpSource GLSL 430
3469                OpDecorate %_arr_float_uint_2 ArrayStride 16
3470                OpMemberDecorate %Output 0 Offset 0
3471                OpMemberDecorate %Output 1 Offset 20
3472                OpDecorate %Output Block
3473        %void = OpTypeVoid
3474           %3 = OpTypeFunction %void
3475       %float = OpTypeFloat 32
3476        %uint = OpTypeInt 32 0
3477      %v2uint = OpTypeVector %uint 2
3478      %uint_2 = OpConstant %uint 2
3479 %_arr_float_uint_2 = OpTypeArray %float %uint_2
3480      %Output = OpTypeStruct %_arr_float_uint_2 %float
3481 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
3482  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
3483        %main = OpFunction %void None %3
3484           %5 = OpLabel
3485                OpReturn
3486                OpFunctionEnd
3487   )";
3488 
3489   CompileSuccessfully(spirv);
3490   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
3491   EXPECT_THAT(
3492       getDiagnosticString(),
3493       HasSubstr(
3494           "Structure id 4 decorated as Block for variable in Uniform storage "
3495           "class must follow standard uniform buffer layout rules: member 1 at "
3496           "offset 20 overlaps previous member ending at offset 31"));
3497 }
3498 
TEST_F(ValidateDecorations,BlockUniformBufferLayoutOffsetInsideStructPaddingBad)3499 TEST_F(ValidateDecorations,
3500        BlockUniformBufferLayoutOffsetInsideStructPaddingBad) {
3501   // In this case the 2nd member fits entirely within the padding.
3502   std::string spirv = R"(
3503                OpCapability Shader
3504                OpMemoryModel Logical GLSL450
3505                OpEntryPoint GLCompute %1 "main"
3506                OpMemberDecorate %_struct_6 0 Offset 0
3507                OpMemberDecorate %_struct_2 0 Offset 0
3508                OpMemberDecorate %_struct_2 1 Offset 4
3509                OpDecorate %_struct_2 Block
3510        %void = OpTypeVoid
3511           %4 = OpTypeFunction %void
3512       %float = OpTypeFloat 32
3513   %_struct_6 = OpTypeStruct %float
3514   %_struct_2 = OpTypeStruct %_struct_6 %float
3515 %_ptr_Uniform__struct_2 = OpTypePointer Uniform %_struct_2
3516           %8 = OpVariable %_ptr_Uniform__struct_2 Uniform
3517           %1 = OpFunction %void None %4
3518           %9 = OpLabel
3519                OpReturn
3520                OpFunctionEnd
3521   )";
3522 
3523   CompileSuccessfully(spirv);
3524   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
3525   EXPECT_THAT(
3526       getDiagnosticString(),
3527       HasSubstr(
3528           "Structure id 3 decorated as Block for variable in Uniform storage "
3529           "class must follow standard uniform buffer layout rules: member 1 at "
3530           "offset 4 overlaps previous member ending at offset 15"));
3531 }
3532 
TEST_F(ValidateDecorations,BlockLayoutOffsetOutOfOrderGoodUniversal1_0)3533 TEST_F(ValidateDecorations, BlockLayoutOffsetOutOfOrderGoodUniversal1_0) {
3534   std::string spirv = R"(
3535                OpCapability Shader
3536           %1 = OpExtInstImport "GLSL.std.450"
3537                OpMemoryModel Logical GLSL450
3538                OpEntryPoint GLCompute %main "main"
3539                OpExecutionMode %main LocalSize 1 1 1
3540                OpMemberDecorate %Outer 0 Offset 4
3541                OpMemberDecorate %Outer 1 Offset 0
3542                OpDecorate %Outer Block
3543                OpDecorate %O DescriptorSet 0
3544                OpDecorate %O Binding 0
3545        %void = OpTypeVoid
3546           %3 = OpTypeFunction %void
3547        %uint = OpTypeInt 32 0
3548       %Outer = OpTypeStruct %uint %uint
3549 %_ptr_Uniform_Outer = OpTypePointer Uniform %Outer
3550           %O = OpVariable %_ptr_Uniform_Outer Uniform
3551        %main = OpFunction %void None %3
3552           %5 = OpLabel
3553                OpReturn
3554                OpFunctionEnd
3555   )";
3556 
3557   CompileSuccessfully(spirv);
3558   EXPECT_EQ(SPV_SUCCESS,
3559             ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_0));
3560 }
3561 
TEST_F(ValidateDecorations,BlockLayoutOffsetOutOfOrderGoodOpenGL4_5)3562 TEST_F(ValidateDecorations, BlockLayoutOffsetOutOfOrderGoodOpenGL4_5) {
3563   std::string spirv = R"(
3564                OpCapability Shader
3565           %1 = OpExtInstImport "GLSL.std.450"
3566                OpMemoryModel Logical GLSL450
3567                OpEntryPoint GLCompute %main "main"
3568                OpExecutionMode %main LocalSize 1 1 1
3569                OpMemberDecorate %Outer 0 Offset 4
3570                OpMemberDecorate %Outer 1 Offset 0
3571                OpDecorate %Outer Block
3572                OpDecorate %O DescriptorSet 0
3573                OpDecorate %O Binding 0
3574        %void = OpTypeVoid
3575           %3 = OpTypeFunction %void
3576        %uint = OpTypeInt 32 0
3577       %Outer = OpTypeStruct %uint %uint
3578 %_ptr_Uniform_Outer = OpTypePointer Uniform %Outer
3579           %O = OpVariable %_ptr_Uniform_Outer Uniform
3580        %main = OpFunction %void None %3
3581           %5 = OpLabel
3582                OpReturn
3583                OpFunctionEnd
3584   )";
3585 
3586   CompileSuccessfully(spirv);
3587   EXPECT_EQ(SPV_SUCCESS,
3588             ValidateAndRetrieveValidationState(SPV_ENV_OPENGL_4_5));
3589 }
3590 
TEST_F(ValidateDecorations,BlockLayoutOffsetOutOfOrderGoodVulkan1_1)3591 TEST_F(ValidateDecorations, BlockLayoutOffsetOutOfOrderGoodVulkan1_1) {
3592   std::string spirv = R"(
3593                OpCapability Shader
3594           %1 = OpExtInstImport "GLSL.std.450"
3595                OpMemoryModel Logical GLSL450
3596                OpEntryPoint GLCompute %main "main"
3597                OpExecutionMode %main LocalSize 1 1 1
3598                OpMemberDecorate %Outer 0 Offset 4
3599                OpMemberDecorate %Outer 1 Offset 0
3600                OpDecorate %Outer Block
3601                OpDecorate %O DescriptorSet 0
3602                OpDecorate %O Binding 0
3603        %void = OpTypeVoid
3604           %3 = OpTypeFunction %void
3605        %uint = OpTypeInt 32 0
3606       %Outer = OpTypeStruct %uint %uint
3607 %_ptr_Uniform_Outer = OpTypePointer Uniform %Outer
3608           %O = OpVariable %_ptr_Uniform_Outer Uniform
3609        %main = OpFunction %void None %3
3610           %5 = OpLabel
3611                OpReturn
3612                OpFunctionEnd
3613   )";
3614 
3615   CompileSuccessfully(spirv);
3616   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1))
3617       << getDiagnosticString();
3618   EXPECT_THAT(getDiagnosticString(), Eq(""));
3619 }
3620 
TEST_F(ValidateDecorations,BlockLayoutOffsetOverlapBad)3621 TEST_F(ValidateDecorations, BlockLayoutOffsetOverlapBad) {
3622   std::string spirv = R"(
3623                OpCapability Shader
3624           %1 = OpExtInstImport "GLSL.std.450"
3625                OpMemoryModel Logical GLSL450
3626                OpEntryPoint GLCompute %main "main"
3627                OpExecutionMode %main LocalSize 1 1 1
3628                OpMemberDecorate %Outer 0 Offset 0
3629                OpMemberDecorate %Outer 1 Offset 16
3630                OpMemberDecorate %Inner 0 Offset 0
3631                OpMemberDecorate %Inner 1 Offset 16
3632                OpDecorate %Outer Block
3633                OpDecorate %O DescriptorSet 0
3634                OpDecorate %O Binding 0
3635        %void = OpTypeVoid
3636           %3 = OpTypeFunction %void
3637        %uint = OpTypeInt 32 0
3638       %Inner = OpTypeStruct %uint %uint
3639       %Outer = OpTypeStruct %Inner %uint
3640 %_ptr_Uniform_Outer = OpTypePointer Uniform %Outer
3641           %O = OpVariable %_ptr_Uniform_Outer Uniform
3642        %main = OpFunction %void None %3
3643           %5 = OpLabel
3644                OpReturn
3645                OpFunctionEnd
3646   )";
3647 
3648   CompileSuccessfully(spirv);
3649   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
3650   EXPECT_THAT(
3651       getDiagnosticString(),
3652       HasSubstr(
3653           "Structure id 3 decorated as Block for variable in Uniform storage "
3654           "class must follow standard uniform buffer layout rules: member 1 at "
3655           "offset 16 overlaps previous member ending at offset 31"));
3656 }
3657 
TEST_F(ValidateDecorations,BufferBlockEmptyStruct)3658 TEST_F(ValidateDecorations, BufferBlockEmptyStruct) {
3659   std::string spirv = R"(
3660                OpCapability Shader
3661           %1 = OpExtInstImport "GLSL.std.450"
3662                OpMemoryModel Logical GLSL450
3663                OpEntryPoint GLCompute %main "main"
3664                OpExecutionMode %main LocalSize 1 1 1
3665                OpSource GLSL 430
3666                OpMemberDecorate %Output 0 Offset 0
3667                OpDecorate %Output BufferBlock
3668        %void = OpTypeVoid
3669           %3 = OpTypeFunction %void
3670           %S = OpTypeStruct
3671      %Output = OpTypeStruct %S
3672 %_ptr_Uniform_Output = OpTypePointer Uniform %Output
3673  %dataOutput = OpVariable %_ptr_Uniform_Output Uniform
3674        %main = OpFunction %void None %3
3675           %5 = OpLabel
3676                OpReturn
3677                OpFunctionEnd
3678   )";
3679 
3680   CompileSuccessfully(spirv);
3681   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
3682 }
3683 
TEST_F(ValidateDecorations,RowMajorMatrixTightPackingGood)3684 TEST_F(ValidateDecorations, RowMajorMatrixTightPackingGood) {
3685   // Row major matrix rule:
3686   //     A row-major matrix of C columns has a base alignment equal to
3687   //     the base alignment of a vector of C matrix components.
3688   // Note: The "matrix component" is the scalar element type.
3689 
3690   // The matrix has 3 columns and 2 rows (C=3, R=2).
3691   // So the base alignment of b is the same as a vector of 3 floats, which is 16
3692   // bytes. The matrix consists of two of these, and therefore occupies 2 x 16
3693   // bytes, or 32 bytes.
3694   //
3695   // So the offsets can be:
3696   // a -> 0
3697   // b -> 16
3698   // c -> 48
3699   // d -> 60 ; d fits at bytes 12-15 after offset of c. Tight (vec3;float)
3700   // packing
3701 
3702   std::string spirv = R"(
3703                OpCapability Shader
3704                OpMemoryModel Logical GLSL450
3705                OpEntryPoint Vertex %1 "main"
3706                OpSource GLSL 450
3707                OpMemberDecorate %_struct_2 0 Offset 0
3708                OpMemberDecorate %_struct_2 1 RowMajor
3709                OpMemberDecorate %_struct_2 1 Offset 16
3710                OpMemberDecorate %_struct_2 1 MatrixStride 16
3711                OpMemberDecorate %_struct_2 2 Offset 48
3712                OpMemberDecorate %_struct_2 3 Offset 60
3713                OpDecorate %_struct_2 Block
3714                OpDecorate %3 DescriptorSet 0
3715                OpDecorate %3 Binding 0
3716        %void = OpTypeVoid
3717           %5 = OpTypeFunction %void
3718       %float = OpTypeFloat 32
3719     %v4float = OpTypeVector %float 4
3720     %v2float = OpTypeVector %float 2
3721 %mat3v2float = OpTypeMatrix %v2float 3
3722     %v3float = OpTypeVector %float 3
3723   %_struct_2 = OpTypeStruct %v4float %mat3v2float %v3float %float
3724 %_ptr_Uniform__struct_2 = OpTypePointer Uniform %_struct_2
3725           %3 = OpVariable %_ptr_Uniform__struct_2 Uniform
3726           %1 = OpFunction %void None %5
3727          %12 = OpLabel
3728                OpReturn
3729                OpFunctionEnd
3730   )";
3731 
3732   CompileSuccessfully(spirv);
3733   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
3734       << getDiagnosticString();
3735 }
3736 
TEST_F(ValidateDecorations,ArrayArrayRowMajorMatrixTightPackingGood)3737 TEST_F(ValidateDecorations, ArrayArrayRowMajorMatrixTightPackingGood) {
3738   // Like the previous case, but we have an array of arrays of matrices.
3739   // The RowMajor decoration goes on the struct member (surprisingly).
3740 
3741   std::string spirv = R"(
3742                OpCapability Shader
3743                OpMemoryModel Logical GLSL450
3744                OpEntryPoint Vertex %1 "main"
3745                OpSource GLSL 450
3746                OpMemberDecorate %_struct_2 0 Offset 0
3747                OpMemberDecorate %_struct_2 1 RowMajor
3748                OpMemberDecorate %_struct_2 1 Offset 16
3749                OpMemberDecorate %_struct_2 1 MatrixStride 16
3750                OpMemberDecorate %_struct_2 2 Offset 80
3751                OpMemberDecorate %_struct_2 3 Offset 92
3752                OpDecorate %arr_mat ArrayStride 32
3753                OpDecorate %arr_arr_mat ArrayStride 32
3754                OpDecorate %_struct_2 Block
3755                OpDecorate %3 DescriptorSet 0
3756                OpDecorate %3 Binding 0
3757        %void = OpTypeVoid
3758           %5 = OpTypeFunction %void
3759       %float = OpTypeFloat 32
3760     %v4float = OpTypeVector %float 4
3761     %v2float = OpTypeVector %float 2
3762 %mat3v2float = OpTypeMatrix %v2float 3
3763 %uint        = OpTypeInt 32 0
3764 %uint_1      = OpConstant %uint 1
3765 %uint_2      = OpConstant %uint 2
3766     %arr_mat = OpTypeArray %mat3v2float %uint_1
3767 %arr_arr_mat = OpTypeArray %arr_mat %uint_2
3768     %v3float = OpTypeVector %float 3
3769   %_struct_2 = OpTypeStruct %v4float %arr_arr_mat %v3float %float
3770 %_ptr_Uniform__struct_2 = OpTypePointer Uniform %_struct_2
3771           %3 = OpVariable %_ptr_Uniform__struct_2 Uniform
3772           %1 = OpFunction %void None %5
3773          %12 = OpLabel
3774                OpReturn
3775                OpFunctionEnd
3776   )";
3777 
3778   CompileSuccessfully(spirv);
3779   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState())
3780       << getDiagnosticString();
3781 }
3782 
TEST_F(ValidateDecorations,ArrayArrayRowMajorMatrixNextMemberOverlapsBad)3783 TEST_F(ValidateDecorations, ArrayArrayRowMajorMatrixNextMemberOverlapsBad) {
3784   // Like the previous case, but the offset of member 2 overlaps the matrix.
3785   std::string spirv = R"(
3786                OpCapability Shader
3787                OpMemoryModel Logical GLSL450
3788                OpEntryPoint Vertex %1 "main"
3789                OpSource GLSL 450
3790                OpMemberDecorate %_struct_2 0 Offset 0
3791                OpMemberDecorate %_struct_2 1 RowMajor
3792                OpMemberDecorate %_struct_2 1 Offset 16
3793                OpMemberDecorate %_struct_2 1 MatrixStride 16
3794                OpMemberDecorate %_struct_2 2 Offset 64
3795                OpMemberDecorate %_struct_2 3 Offset 92
3796                OpDecorate %arr_mat ArrayStride 32
3797                OpDecorate %arr_arr_mat ArrayStride 32
3798                OpDecorate %_struct_2 Block
3799                OpDecorate %3 DescriptorSet 0
3800                OpDecorate %3 Binding 0
3801        %void = OpTypeVoid
3802           %5 = OpTypeFunction %void
3803       %float = OpTypeFloat 32
3804     %v4float = OpTypeVector %float 4
3805     %v2float = OpTypeVector %float 2
3806 %mat3v2float = OpTypeMatrix %v2float 3
3807 %uint        = OpTypeInt 32 0
3808 %uint_1      = OpConstant %uint 1
3809 %uint_2      = OpConstant %uint 2
3810     %arr_mat = OpTypeArray %mat3v2float %uint_1
3811 %arr_arr_mat = OpTypeArray %arr_mat %uint_2
3812     %v3float = OpTypeVector %float 3
3813   %_struct_2 = OpTypeStruct %v4float %arr_arr_mat %v3float %float
3814 %_ptr_Uniform__struct_2 = OpTypePointer Uniform %_struct_2
3815           %3 = OpVariable %_ptr_Uniform__struct_2 Uniform
3816           %1 = OpFunction %void None %5
3817          %12 = OpLabel
3818                OpReturn
3819                OpFunctionEnd
3820   )";
3821 
3822   CompileSuccessfully(spirv);
3823   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
3824   EXPECT_THAT(
3825       getDiagnosticString(),
3826       HasSubstr(
3827           "Structure id 2 decorated as Block for variable in Uniform storage "
3828           "class must follow standard uniform buffer layout rules: member 2 at "
3829           "offset 64 overlaps previous member ending at offset 79"));
3830 }
3831 
TEST_F(ValidateDecorations,StorageBufferArraySizeCalculationPackGood)3832 TEST_F(ValidateDecorations, StorageBufferArraySizeCalculationPackGood) {
3833   // Original GLSL
3834 
3835   // #version 450
3836   // layout (set=0,binding=0) buffer S {
3837   //   uvec3 arr[2][2]; // first 3 elements are 16 bytes, last is 12
3838   //   uint i;  // Can have offset 60 = 3x16 + 12
3839   // } B;
3840   // void main() {}
3841 
3842   std::string spirv = R"(
3843                OpCapability Shader
3844                OpMemoryModel Logical GLSL450
3845                OpEntryPoint Vertex %1 "main"
3846                OpDecorate %_arr_v3uint_uint_2 ArrayStride 16
3847                OpDecorate %_arr__arr_v3uint_uint_2_uint_2 ArrayStride 32
3848                OpMemberDecorate %_struct_4 0 Offset 0
3849                OpMemberDecorate %_struct_4 1 Offset 60
3850                OpDecorate %_struct_4 BufferBlock
3851                OpDecorate %5 DescriptorSet 0
3852                OpDecorate %5 Binding 0
3853        %void = OpTypeVoid
3854           %7 = OpTypeFunction %void
3855        %uint = OpTypeInt 32 0
3856      %v3uint = OpTypeVector %uint 3
3857      %uint_2 = OpConstant %uint 2
3858 %_arr_v3uint_uint_2 = OpTypeArray %v3uint %uint_2
3859 %_arr__arr_v3uint_uint_2_uint_2 = OpTypeArray %_arr_v3uint_uint_2 %uint_2
3860   %_struct_4 = OpTypeStruct %_arr__arr_v3uint_uint_2_uint_2 %uint
3861 %_ptr_Uniform__struct_4 = OpTypePointer Uniform %_struct_4
3862           %5 = OpVariable %_ptr_Uniform__struct_4 Uniform
3863           %1 = OpFunction %void None %7
3864          %12 = OpLabel
3865                OpReturn
3866                OpFunctionEnd
3867   )";
3868 
3869   CompileSuccessfully(spirv);
3870   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
3871 }
3872 
TEST_F(ValidateDecorations,StorageBufferArraySizeCalculationPackBad)3873 TEST_F(ValidateDecorations, StorageBufferArraySizeCalculationPackBad) {
3874   // Like previous but, the offset of the second member is too small.
3875 
3876   std::string spirv = R"(
3877                OpCapability Shader
3878                OpMemoryModel Logical GLSL450
3879                OpEntryPoint Vertex %1 "main"
3880                OpDecorate %_arr_v3uint_uint_2 ArrayStride 16
3881                OpDecorate %_arr__arr_v3uint_uint_2_uint_2 ArrayStride 32
3882                OpMemberDecorate %_struct_4 0 Offset 0
3883                OpMemberDecorate %_struct_4 1 Offset 56
3884                OpDecorate %_struct_4 BufferBlock
3885                OpDecorate %5 DescriptorSet 0
3886                OpDecorate %5 Binding 0
3887        %void = OpTypeVoid
3888           %7 = OpTypeFunction %void
3889        %uint = OpTypeInt 32 0
3890      %v3uint = OpTypeVector %uint 3
3891      %uint_2 = OpConstant %uint 2
3892 %_arr_v3uint_uint_2 = OpTypeArray %v3uint %uint_2
3893 %_arr__arr_v3uint_uint_2_uint_2 = OpTypeArray %_arr_v3uint_uint_2 %uint_2
3894   %_struct_4 = OpTypeStruct %_arr__arr_v3uint_uint_2_uint_2 %uint
3895 %_ptr_Uniform__struct_4 = OpTypePointer Uniform %_struct_4
3896           %5 = OpVariable %_ptr_Uniform__struct_4 Uniform
3897           %1 = OpFunction %void None %7
3898          %12 = OpLabel
3899                OpReturn
3900                OpFunctionEnd
3901   )";
3902 
3903   CompileSuccessfully(spirv);
3904   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
3905   EXPECT_THAT(getDiagnosticString(),
3906               HasSubstr("Structure id 4 decorated as BufferBlock for variable "
3907                         "in Uniform storage class must follow standard storage "
3908                         "buffer layout rules: member 1 at offset 56 overlaps "
3909                         "previous member ending at offset 59"));
3910 }
3911 
TEST_F(ValidateDecorations,UniformBufferArraySizeCalculationPackGood)3912 TEST_F(ValidateDecorations, UniformBufferArraySizeCalculationPackGood) {
3913   // Like the corresponding buffer block case, but the array padding must
3914   // count for the last element as well, and so the offset of the second
3915   // member must be at least 64.
3916   std::string spirv = R"(
3917                OpCapability Shader
3918                OpMemoryModel Logical GLSL450
3919                OpEntryPoint Vertex %1 "main"
3920                OpDecorate %_arr_v3uint_uint_2 ArrayStride 16
3921                OpDecorate %_arr__arr_v3uint_uint_2_uint_2 ArrayStride 32
3922                OpMemberDecorate %_struct_4 0 Offset 0
3923                OpMemberDecorate %_struct_4 1 Offset 64
3924                OpDecorate %_struct_4 Block
3925                OpDecorate %5 DescriptorSet 0
3926                OpDecorate %5 Binding 0
3927        %void = OpTypeVoid
3928           %7 = OpTypeFunction %void
3929        %uint = OpTypeInt 32 0
3930      %v3uint = OpTypeVector %uint 3
3931      %uint_2 = OpConstant %uint 2
3932 %_arr_v3uint_uint_2 = OpTypeArray %v3uint %uint_2
3933 %_arr__arr_v3uint_uint_2_uint_2 = OpTypeArray %_arr_v3uint_uint_2 %uint_2
3934   %_struct_4 = OpTypeStruct %_arr__arr_v3uint_uint_2_uint_2 %uint
3935 %_ptr_Uniform__struct_4 = OpTypePointer Uniform %_struct_4
3936           %5 = OpVariable %_ptr_Uniform__struct_4 Uniform
3937           %1 = OpFunction %void None %7
3938          %12 = OpLabel
3939                OpReturn
3940                OpFunctionEnd
3941   )";
3942 
3943   CompileSuccessfully(spirv);
3944   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
3945 }
3946 
TEST_F(ValidateDecorations,UniformBufferArraySizeCalculationPackBad)3947 TEST_F(ValidateDecorations, UniformBufferArraySizeCalculationPackBad) {
3948   // Like previous but, the offset of the second member is too small.
3949 
3950   std::string spirv = R"(
3951                OpCapability Shader
3952                OpMemoryModel Logical GLSL450
3953                OpEntryPoint Vertex %1 "main"
3954                OpDecorate %_arr_v3uint_uint_2 ArrayStride 16
3955                OpDecorate %_arr__arr_v3uint_uint_2_uint_2 ArrayStride 32
3956                OpMemberDecorate %_struct_4 0 Offset 0
3957                OpMemberDecorate %_struct_4 1 Offset 60
3958                OpDecorate %_struct_4 Block
3959                OpDecorate %5 DescriptorSet 0
3960                OpDecorate %5 Binding 0
3961        %void = OpTypeVoid
3962           %7 = OpTypeFunction %void
3963        %uint = OpTypeInt 32 0
3964      %v3uint = OpTypeVector %uint 3
3965      %uint_2 = OpConstant %uint 2
3966 %_arr_v3uint_uint_2 = OpTypeArray %v3uint %uint_2
3967 %_arr__arr_v3uint_uint_2_uint_2 = OpTypeArray %_arr_v3uint_uint_2 %uint_2
3968   %_struct_4 = OpTypeStruct %_arr__arr_v3uint_uint_2_uint_2 %uint
3969 %_ptr_Uniform__struct_4 = OpTypePointer Uniform %_struct_4
3970           %5 = OpVariable %_ptr_Uniform__struct_4 Uniform
3971           %1 = OpFunction %void None %7
3972          %12 = OpLabel
3973                OpReturn
3974                OpFunctionEnd
3975   )";
3976 
3977   CompileSuccessfully(spirv);
3978   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
3979   EXPECT_THAT(
3980       getDiagnosticString(),
3981       HasSubstr(
3982           "Structure id 4 decorated as Block for variable in Uniform storage "
3983           "class must follow standard uniform buffer layout rules: member 1 at "
3984           "offset 60 overlaps previous member ending at offset 63"));
3985 }
3986 
TEST_F(ValidateDecorations,LayoutNotCheckedWhenSkipBlockLayout)3987 TEST_F(ValidateDecorations, LayoutNotCheckedWhenSkipBlockLayout) {
3988   // Checks that block layout is not verified in skipping block layout mode.
3989   // Even for obviously wrong layout.
3990   std::string spirv = R"(
3991                OpCapability Shader
3992                OpMemoryModel Logical GLSL450
3993                OpEntryPoint Vertex %main "main"
3994                OpSource GLSL 450
3995                OpMemberDecorate %S 0 Offset 3 ; wrong alignment
3996                OpMemberDecorate %S 1 Offset 3 ; same offset as before!
3997                OpDecorate %S Block
3998                OpDecorate %B DescriptorSet 0
3999                OpDecorate %B Binding 0
4000        %void = OpTypeVoid
4001           %3 = OpTypeFunction %void
4002       %float = OpTypeFloat 32
4003     %v3float = OpTypeVector %float 3
4004           %S = OpTypeStruct %float %v3float
4005 %_ptr_Uniform_S = OpTypePointer Uniform %S
4006           %B = OpVariable %_ptr_Uniform_S Uniform
4007        %main = OpFunction %void None %3
4008           %5 = OpLabel
4009                OpReturn
4010                OpFunctionEnd
4011   )";
4012 
4013   CompileSuccessfully(spirv);
4014   spvValidatorOptionsSetSkipBlockLayout(getValidatorOptions(), true);
4015   EXPECT_EQ(SPV_SUCCESS,
4016             ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
4017   EXPECT_THAT(getDiagnosticString(), Eq(""));
4018 }
4019 
TEST_F(ValidateDecorations,EntryPointVariableWrongStorageClass)4020 TEST_F(ValidateDecorations, EntryPointVariableWrongStorageClass) {
4021   const std::string spirv = R"(
4022 OpCapability Shader
4023 OpMemoryModel Logical GLSL450
4024 OpEntryPoint Fragment %1 "func" %var
4025 OpExecutionMode %1 OriginUpperLeft
4026 %void = OpTypeVoid
4027 %int = OpTypeInt 32 0
4028 %ptr_int_Workgroup = OpTypePointer Workgroup %int
4029 %var = OpVariable %ptr_int_Workgroup Workgroup
4030 %func_ty = OpTypeFunction %void
4031 %1 = OpFunction %void None %func_ty
4032 %2 = OpLabel
4033 OpReturn
4034 OpFunctionEnd
4035 )";
4036 
4037   CompileSuccessfully(spirv);
4038   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
4039   EXPECT_THAT(getDiagnosticString(),
4040               HasSubstr("OpEntryPoint interfaces must be OpVariables with "
4041                         "Storage Class of Input(1) or Output(3). Found Storage "
4042                         "Class 4 for Entry Point id 1."));
4043 }
4044 
TEST_F(ValidateDecorations,VulkanMemoryModelNonCoherent)4045 TEST_F(ValidateDecorations, VulkanMemoryModelNonCoherent) {
4046   const std::string spirv = R"(
4047 OpCapability Shader
4048 OpCapability VulkanMemoryModelKHR
4049 OpCapability Linkage
4050 OpExtension "SPV_KHR_vulkan_memory_model"
4051 OpExtension "SPV_KHR_storage_buffer_storage_class"
4052 OpMemoryModel Logical VulkanKHR
4053 OpDecorate %1 Coherent
4054 %2 = OpTypeInt 32 0
4055 %3 = OpTypePointer StorageBuffer %2
4056 %1 = OpVariable %3 StorageBuffer
4057 )";
4058 
4059   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
4060   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
4061   EXPECT_THAT(getDiagnosticString(),
4062               HasSubstr("Coherent decoration targeting 1[%1] is "
4063                         "banned when using the Vulkan memory model."));
4064 }
4065 
TEST_F(ValidateDecorations,VulkanMemoryModelNoCoherentMember)4066 TEST_F(ValidateDecorations, VulkanMemoryModelNoCoherentMember) {
4067   const std::string spirv = R"(
4068 OpCapability Shader
4069 OpCapability VulkanMemoryModelKHR
4070 OpCapability Linkage
4071 OpExtension "SPV_KHR_vulkan_memory_model"
4072 OpMemoryModel Logical VulkanKHR
4073 OpMemberDecorate %1 0 Coherent
4074 %2 = OpTypeInt 32 0
4075 %1 = OpTypeStruct %2 %2
4076 )";
4077 
4078   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
4079   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
4080   EXPECT_THAT(
4081       getDiagnosticString(),
4082       HasSubstr("Coherent decoration targeting 1[%_struct_1] (member index 0) "
4083                 "is banned when using the Vulkan memory model."));
4084 }
4085 
TEST_F(ValidateDecorations,VulkanMemoryModelNoVolatile)4086 TEST_F(ValidateDecorations, VulkanMemoryModelNoVolatile) {
4087   const std::string spirv = R"(
4088 OpCapability Shader
4089 OpCapability VulkanMemoryModelKHR
4090 OpCapability Linkage
4091 OpExtension "SPV_KHR_vulkan_memory_model"
4092 OpExtension "SPV_KHR_storage_buffer_storage_class"
4093 OpMemoryModel Logical VulkanKHR
4094 OpDecorate %1 Volatile
4095 %2 = OpTypeInt 32 0
4096 %3 = OpTypePointer StorageBuffer %2
4097 %1 = OpVariable %3 StorageBuffer
4098 )";
4099 
4100   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
4101   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
4102   EXPECT_THAT(getDiagnosticString(),
4103               HasSubstr("Volatile decoration targeting 1[%1] is banned when "
4104                         "using the Vulkan memory model."));
4105 }
4106 
TEST_F(ValidateDecorations,VulkanMemoryModelNoVolatileMember)4107 TEST_F(ValidateDecorations, VulkanMemoryModelNoVolatileMember) {
4108   const std::string spirv = R"(
4109 OpCapability Shader
4110 OpCapability VulkanMemoryModelKHR
4111 OpCapability Linkage
4112 OpExtension "SPV_KHR_vulkan_memory_model"
4113 OpMemoryModel Logical VulkanKHR
4114 OpMemberDecorate %1 1 Volatile
4115 %2 = OpTypeInt 32 0
4116 %1 = OpTypeStruct %2 %2
4117 )";
4118 
4119   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
4120   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
4121   EXPECT_THAT(getDiagnosticString(),
4122               HasSubstr("Volatile decoration targeting 1[%_struct_1] (member "
4123                         "index 1) is banned when using the Vulkan memory "
4124                         "model."));
4125 }
4126 
TEST_F(ValidateDecorations,FPRoundingModeGood)4127 TEST_F(ValidateDecorations, FPRoundingModeGood) {
4128   std::string spirv = R"(
4129 OpCapability Shader
4130 OpCapability Linkage
4131 OpCapability StorageBuffer16BitAccess
4132 OpExtension "SPV_KHR_storage_buffer_storage_class"
4133 OpExtension "SPV_KHR_variable_pointers"
4134 OpExtension "SPV_KHR_16bit_storage"
4135 OpMemoryModel Logical GLSL450
4136 OpEntryPoint GLCompute %main "main"
4137 OpDecorate %_ FPRoundingMode RTE
4138 %half = OpTypeFloat 16
4139 %float = OpTypeFloat 32
4140 %float_1_25 = OpConstant %float 1.25
4141 %half_ptr = OpTypePointer StorageBuffer %half
4142 %half_ptr_var = OpVariable %half_ptr StorageBuffer
4143 %void = OpTypeVoid
4144 %func = OpTypeFunction %void
4145 %main = OpFunction %void None %func
4146 %main_entry = OpLabel
4147 %_ = OpFConvert %half %float_1_25
4148 OpStore %half_ptr_var %_
4149 OpReturn
4150 OpFunctionEnd
4151   )";
4152 
4153   CompileSuccessfully(spirv);
4154   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
4155 }
4156 
TEST_F(ValidateDecorations,FPRoundingModeVectorGood)4157 TEST_F(ValidateDecorations, FPRoundingModeVectorGood) {
4158   std::string spirv = R"(
4159 OpCapability Shader
4160 OpCapability Linkage
4161 OpCapability StorageBuffer16BitAccess
4162 OpExtension "SPV_KHR_storage_buffer_storage_class"
4163 OpExtension "SPV_KHR_variable_pointers"
4164 OpExtension "SPV_KHR_16bit_storage"
4165 OpMemoryModel Logical GLSL450
4166 OpEntryPoint GLCompute %main "main"
4167 OpDecorate %_ FPRoundingMode RTE
4168 %half = OpTypeFloat 16
4169 %float = OpTypeFloat 32
4170 %v2half = OpTypeVector %half 2
4171 %v2float = OpTypeVector %float 2
4172 %float_1_25 = OpConstant %float 1.25
4173 %floats = OpConstantComposite %v2float %float_1_25 %float_1_25
4174 %halfs_ptr = OpTypePointer StorageBuffer %v2half
4175 %halfs_ptr_var = OpVariable %halfs_ptr StorageBuffer
4176 %void = OpTypeVoid
4177 %func = OpTypeFunction %void
4178 %main = OpFunction %void None %func
4179 %main_entry = OpLabel
4180 %_ = OpFConvert %v2half %floats
4181 OpStore %halfs_ptr_var %_
4182 OpReturn
4183 OpFunctionEnd
4184   )";
4185 
4186   CompileSuccessfully(spirv);
4187   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
4188 }
4189 
TEST_F(ValidateDecorations,FPRoundingModeNotOpFConvert)4190 TEST_F(ValidateDecorations, FPRoundingModeNotOpFConvert) {
4191   std::string spirv = R"(
4192 OpCapability Shader
4193 OpCapability Linkage
4194 OpCapability StorageBuffer16BitAccess
4195 OpExtension "SPV_KHR_storage_buffer_storage_class"
4196 OpExtension "SPV_KHR_variable_pointers"
4197 OpExtension "SPV_KHR_16bit_storage"
4198 OpMemoryModel Logical GLSL450
4199 OpEntryPoint GLCompute %main "main"
4200 OpDecorate %_ FPRoundingMode RTE
4201 %short = OpTypeInt 16 1
4202 %int = OpTypeInt 32 1
4203 %int_17 = OpConstant %int 17
4204 %short_ptr = OpTypePointer StorageBuffer %short
4205 %short_ptr_var = OpVariable %short_ptr StorageBuffer
4206 %void = OpTypeVoid
4207 %func = OpTypeFunction %void
4208 %main = OpFunction %void None %func
4209 %main_entry = OpLabel
4210 %_ = OpSConvert %short %int_17
4211 OpStore %short_ptr_var %_
4212 OpReturn
4213 OpFunctionEnd
4214   )";
4215 
4216   CompileSuccessfully(spirv);
4217   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
4218   EXPECT_THAT(getDiagnosticString(),
4219               HasSubstr("FPRoundingMode decoration can be applied only to a "
4220                         "width-only conversion instruction for floating-point "
4221                         "object."));
4222 }
4223 
TEST_F(ValidateDecorations,FPRoundingModeNoOpStoreGood)4224 TEST_F(ValidateDecorations, FPRoundingModeNoOpStoreGood) {
4225   std::string spirv = R"(
4226 OpCapability Shader
4227 OpCapability Linkage
4228 OpCapability StorageBuffer16BitAccess
4229 OpExtension "SPV_KHR_storage_buffer_storage_class"
4230 OpExtension "SPV_KHR_variable_pointers"
4231 OpExtension "SPV_KHR_16bit_storage"
4232 OpMemoryModel Logical GLSL450
4233 OpEntryPoint GLCompute %main "main"
4234 OpDecorate %_ FPRoundingMode RTE
4235 %half = OpTypeFloat 16
4236 %float = OpTypeFloat 32
4237 %float_1_25 = OpConstant %float 1.25
4238 %half_ptr = OpTypePointer StorageBuffer %half
4239 %half_ptr_var = OpVariable %half_ptr StorageBuffer
4240 %void = OpTypeVoid
4241 %func = OpTypeFunction %void
4242 %main = OpFunction %void None %func
4243 %main_entry = OpLabel
4244 %_ = OpFConvert %half %float_1_25
4245 OpReturn
4246 OpFunctionEnd
4247   )";
4248 
4249   CompileSuccessfully(spirv);
4250   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
4251 }
4252 
TEST_F(ValidateDecorations,FPRoundingModeFConvert64to16Good)4253 TEST_F(ValidateDecorations, FPRoundingModeFConvert64to16Good) {
4254   std::string spirv = R"(
4255 OpCapability Shader
4256 OpCapability Linkage
4257 OpCapability StorageBuffer16BitAccess
4258 OpCapability Float64
4259 OpExtension "SPV_KHR_storage_buffer_storage_class"
4260 OpExtension "SPV_KHR_variable_pointers"
4261 OpExtension "SPV_KHR_16bit_storage"
4262 OpMemoryModel Logical GLSL450
4263 OpEntryPoint GLCompute %main "main"
4264 OpDecorate %_ FPRoundingMode RTE
4265 %half = OpTypeFloat 16
4266 %double = OpTypeFloat 64
4267 %double_1_25 = OpConstant %double 1.25
4268 %half_ptr = OpTypePointer StorageBuffer %half
4269 %half_ptr_var = OpVariable %half_ptr StorageBuffer
4270 %void = OpTypeVoid
4271 %func = OpTypeFunction %void
4272 %main = OpFunction %void None %func
4273 %main_entry = OpLabel
4274 %_ = OpFConvert %half %double_1_25
4275 OpStore %half_ptr_var %_
4276 OpReturn
4277 OpFunctionEnd
4278   )";
4279 
4280   CompileSuccessfully(spirv);
4281   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
4282 }
4283 
TEST_F(ValidateDecorations,FPRoundingModeNotStoreInFloat16)4284 TEST_F(ValidateDecorations, FPRoundingModeNotStoreInFloat16) {
4285   std::string spirv = R"(
4286 OpCapability Shader
4287 OpCapability Linkage
4288 OpCapability StorageBuffer16BitAccess
4289 OpCapability Float64
4290 OpExtension "SPV_KHR_storage_buffer_storage_class"
4291 OpExtension "SPV_KHR_variable_pointers"
4292 OpExtension "SPV_KHR_16bit_storage"
4293 OpMemoryModel Logical GLSL450
4294 OpEntryPoint GLCompute %main "main"
4295 OpDecorate %_ FPRoundingMode RTE
4296 %float = OpTypeFloat 32
4297 %double = OpTypeFloat 64
4298 %double_1_25 = OpConstant %double 1.25
4299 %float_ptr = OpTypePointer StorageBuffer %float
4300 %float_ptr_var = OpVariable %float_ptr StorageBuffer
4301 %void = OpTypeVoid
4302 %func = OpTypeFunction %void
4303 %main = OpFunction %void None %func
4304 %main_entry = OpLabel
4305 %_ = OpFConvert %float %double_1_25
4306 OpStore %float_ptr_var %_
4307 OpReturn
4308 OpFunctionEnd
4309   )";
4310 
4311   CompileSuccessfully(spirv);
4312   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
4313   EXPECT_THAT(
4314       getDiagnosticString(),
4315       HasSubstr("FPRoundingMode decoration can be applied only to the "
4316                 "Object operand of an OpStore storing through a "
4317                 "pointer to a 16-bit floating-point scalar or vector object."));
4318 }
4319 
TEST_F(ValidateDecorations,FPRoundingModeBadStorageClass)4320 TEST_F(ValidateDecorations, FPRoundingModeBadStorageClass) {
4321   std::string spirv = R"(
4322 OpCapability Shader
4323 OpCapability Linkage
4324 OpCapability StorageBuffer16BitAccess
4325 OpExtension "SPV_KHR_storage_buffer_storage_class"
4326 OpExtension "SPV_KHR_variable_pointers"
4327 OpExtension "SPV_KHR_16bit_storage"
4328 OpMemoryModel Logical GLSL450
4329 OpEntryPoint GLCompute %main "main"
4330 OpDecorate %_ FPRoundingMode RTE
4331 %half = OpTypeFloat 16
4332 %float = OpTypeFloat 32
4333 %float_1_25 = OpConstant %float 1.25
4334 %half_ptr = OpTypePointer Private %half
4335 %half_ptr_var = OpVariable %half_ptr Private
4336 %void = OpTypeVoid
4337 %func = OpTypeFunction %void
4338 %main = OpFunction %void None %func
4339 %main_entry = OpLabel
4340 %_ = OpFConvert %half %float_1_25
4341 OpStore %half_ptr_var %_
4342 OpReturn
4343 OpFunctionEnd
4344   )";
4345 
4346   CompileSuccessfully(spirv);
4347   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
4348   EXPECT_THAT(
4349       getDiagnosticString(),
4350       HasSubstr("FPRoundingMode decoration can be applied only to the "
4351                 "Object operand of an OpStore in the StorageBuffer, Uniform, "
4352                 "PushConstant, Input, or Output Storage Classes."));
4353 }
4354 
TEST_F(ValidateDecorations,FPRoundingModeMultipleOpStoreGood)4355 TEST_F(ValidateDecorations, FPRoundingModeMultipleOpStoreGood) {
4356   std::string spirv = R"(
4357 OpCapability Shader
4358 OpCapability Linkage
4359 OpCapability StorageBuffer16BitAccess
4360 OpExtension "SPV_KHR_storage_buffer_storage_class"
4361 OpExtension "SPV_KHR_variable_pointers"
4362 OpExtension "SPV_KHR_16bit_storage"
4363 OpMemoryModel Logical GLSL450
4364 OpEntryPoint GLCompute %main "main"
4365 OpDecorate %_ FPRoundingMode RTE
4366 %half = OpTypeFloat 16
4367 %float = OpTypeFloat 32
4368 %float_1_25 = OpConstant %float 1.25
4369 %half_ptr = OpTypePointer StorageBuffer %half
4370 %half_ptr_var_0 = OpVariable %half_ptr StorageBuffer
4371 %half_ptr_var_1 = OpVariable %half_ptr StorageBuffer
4372 %half_ptr_var_2 = OpVariable %half_ptr StorageBuffer
4373 %void = OpTypeVoid
4374 %func = OpTypeFunction %void
4375 %main = OpFunction %void None %func
4376 %main_entry = OpLabel
4377 %_ = OpFConvert %half %float_1_25
4378 OpStore %half_ptr_var_0 %_
4379 OpStore %half_ptr_var_1 %_
4380 OpStore %half_ptr_var_2 %_
4381 OpReturn
4382 OpFunctionEnd
4383   )";
4384 
4385   CompileSuccessfully(spirv);
4386   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
4387 }
4388 
TEST_F(ValidateDecorations,FPRoundingModeMultipleUsesBad)4389 TEST_F(ValidateDecorations, FPRoundingModeMultipleUsesBad) {
4390   std::string spirv = R"(
4391 OpCapability Shader
4392 OpCapability Linkage
4393 OpCapability StorageBuffer16BitAccess
4394 OpExtension "SPV_KHR_storage_buffer_storage_class"
4395 OpExtension "SPV_KHR_variable_pointers"
4396 OpExtension "SPV_KHR_16bit_storage"
4397 OpMemoryModel Logical GLSL450
4398 OpEntryPoint GLCompute %main "main"
4399 OpDecorate %_ FPRoundingMode RTE
4400 %half = OpTypeFloat 16
4401 %float = OpTypeFloat 32
4402 %float_1_25 = OpConstant %float 1.25
4403 %half_ptr = OpTypePointer StorageBuffer %half
4404 %half_ptr_var_0 = OpVariable %half_ptr StorageBuffer
4405 %half_ptr_var_1 = OpVariable %half_ptr StorageBuffer
4406 %void = OpTypeVoid
4407 %func = OpTypeFunction %void
4408 %main = OpFunction %void None %func
4409 %main_entry = OpLabel
4410 %_ = OpFConvert %half %float_1_25
4411 OpStore %half_ptr_var_0 %_
4412 %result = OpFAdd %half %_ %_
4413 OpStore %half_ptr_var_1 %_
4414 OpReturn
4415 OpFunctionEnd
4416   )";
4417 
4418   CompileSuccessfully(spirv);
4419   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
4420   EXPECT_THAT(getDiagnosticString(),
4421               HasSubstr("FPRoundingMode decoration can be applied only to the "
4422                         "Object operand of an OpStore."));
4423 }
4424 
TEST_F(ValidateDecorations,GroupDecorateTargetsDecorationGroup)4425 TEST_F(ValidateDecorations, GroupDecorateTargetsDecorationGroup) {
4426   std::string spirv = R"(
4427 OpCapability Shader
4428 OpCapability Linkage
4429 OpMemoryModel Logical GLSL450
4430 %1 = OpDecorationGroup
4431 OpGroupDecorate %1 %1
4432 )";
4433 
4434   CompileSuccessfully(spirv);
4435   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
4436   EXPECT_THAT(getDiagnosticString(),
4437               HasSubstr("OpGroupDecorate may not target OpDecorationGroup <id> "
4438                         "'1[%1]'"));
4439 }
4440 
TEST_F(ValidateDecorations,GroupDecorateTargetsDecorationGroup2)4441 TEST_F(ValidateDecorations, GroupDecorateTargetsDecorationGroup2) {
4442   std::string spirv = R"(
4443 OpCapability Shader
4444 OpCapability Linkage
4445 OpMemoryModel Logical GLSL450
4446 %1 = OpDecorationGroup
4447 OpGroupDecorate %1 %2 %1
4448 %2 = OpTypeVoid
4449 )";
4450 
4451   CompileSuccessfully(spirv);
4452   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
4453   EXPECT_THAT(getDiagnosticString(),
4454               HasSubstr("OpGroupDecorate may not target OpDecorationGroup <id> "
4455                         "'1[%1]'"));
4456 }
4457 
TEST_F(ValidateDecorations,RecurseThroughRuntimeArray)4458 TEST_F(ValidateDecorations, RecurseThroughRuntimeArray) {
4459   const std::string spirv = R"(
4460 OpCapability Shader
4461 OpCapability Linkage
4462 OpMemoryModel Logical GLSL450
4463 OpDecorate %outer Block
4464 OpMemberDecorate %inner 0 Offset 0
4465 OpMemberDecorate %inner 1 Offset 1
4466 OpDecorate %runtime ArrayStride 16
4467 OpMemberDecorate %outer 0 Offset 0
4468 %int = OpTypeInt 32 0
4469 %inner = OpTypeStruct %int %int
4470 %runtime = OpTypeRuntimeArray %inner
4471 %outer = OpTypeStruct %runtime
4472 %outer_ptr = OpTypePointer Uniform %outer
4473 %var = OpVariable %outer_ptr Uniform
4474 )";
4475 
4476   CompileSuccessfully(spirv);
4477   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
4478   EXPECT_THAT(
4479       getDiagnosticString(),
4480       HasSubstr("Structure id 2 decorated as Block for variable in Uniform "
4481                 "storage class must follow standard uniform buffer layout "
4482                 "rules: member 1 at offset 1 is not aligned to 4"));
4483 }
4484 
TEST_F(ValidateDecorations,EmptyStructAtNonZeroOffsetGood)4485 TEST_F(ValidateDecorations, EmptyStructAtNonZeroOffsetGood) {
4486   const std::string spirv = R"(
4487 OpCapability Shader
4488 OpMemoryModel Logical GLSL450
4489 OpEntryPoint GLCompute %main "main"
4490 OpExecutionMode %main LocalSize 1 1 1
4491 OpDecorate %struct Block
4492 OpMemberDecorate %struct 0 Offset 0
4493 OpMemberDecorate %struct 1 Offset 16
4494 OpDecorate %var DescriptorSet 0
4495 OpDecorate %var Binding 0
4496 %void = OpTypeVoid
4497 %float = OpTypeFloat 32
4498 %empty = OpTypeStruct
4499 %struct = OpTypeStruct %float %empty
4500 %ptr_struct_ubo = OpTypePointer Uniform %struct
4501 %var = OpVariable %ptr_struct_ubo Uniform
4502 %voidfn = OpTypeFunction %void
4503 %main = OpFunction %void None %voidfn
4504 %entry = OpLabel
4505 OpReturn
4506 OpFunctionEnd
4507 )";
4508 
4509   CompileSuccessfully(spirv);
4510   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
4511 }
4512 
4513 // Uniform decoration
4514 
TEST_F(ValidateDecorations,UniformDecorationGood)4515 TEST_F(ValidateDecorations, UniformDecorationGood) {
4516   const std::string spirv = R"(
4517 OpCapability Shader
4518 OpMemoryModel Logical Simple
4519 OpEntryPoint GLCompute %main "main"
4520 OpExecutionMode %main LocalSize 1 1 1
4521 OpDecorate %int0 Uniform
4522 OpDecorate %var Uniform
4523 OpDecorate %val Uniform
4524 %void = OpTypeVoid
4525 %int = OpTypeInt 32 1
4526 %int0 = OpConstantNull %int
4527 %intptr = OpTypePointer Private %int
4528 %var = OpVariable %intptr Private
4529 %fn = OpTypeFunction %void
4530 %main = OpFunction %void None %fn
4531 %entry = OpLabel
4532 %val = OpLoad %int %var
4533 OpReturn
4534 OpFunctionEnd
4535 )";
4536 
4537   CompileSuccessfully(spirv);
4538   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
4539   EXPECT_THAT(getDiagnosticString(), Eq(""));
4540 }
4541 
TEST_F(ValidateDecorations,UniformDecorationTargetsTypeBad)4542 TEST_F(ValidateDecorations, UniformDecorationTargetsTypeBad) {
4543   const std::string spirv = R"(
4544 OpCapability Shader
4545 OpMemoryModel Logical Simple
4546 OpEntryPoint GLCompute %main "main"
4547 OpExecutionMode %main LocalSize 1 1 1
4548 OpDecorate %fn Uniform
4549 %void = OpTypeVoid
4550 %fn = OpTypeFunction %void
4551 %main = OpFunction %void None %fn
4552 %entry = OpLabel
4553 OpReturn
4554 OpFunctionEnd
4555 )";
4556 
4557   CompileSuccessfully(spirv);
4558   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
4559   EXPECT_THAT(getDiagnosticString(),
4560               HasSubstr("Uniform decoration applied to a non-object"));
4561   EXPECT_THAT(getDiagnosticString(), HasSubstr("%2 = OpTypeFunction %void"));
4562 }
4563 
TEST_F(ValidateDecorations,UniformDecorationTargetsVoidValueBad)4564 TEST_F(ValidateDecorations, UniformDecorationTargetsVoidValueBad) {
4565   const std::string spirv = R"(
4566 OpCapability Shader
4567 OpMemoryModel Logical Simple
4568 OpEntryPoint GLCompute %main "main"
4569 OpExecutionMode %main LocalSize 1 1 1
4570 OpName %call "call"
4571 OpName %myfunc "myfunc"
4572 OpDecorate %call Uniform
4573 %void = OpTypeVoid
4574 %fnty = OpTypeFunction %void
4575 %myfunc = OpFunction %void None %fnty
4576 %myfuncentry = OpLabel
4577 OpReturn
4578 OpFunctionEnd
4579 %main = OpFunction %void None %fnty
4580 %entry = OpLabel
4581 %call = OpFunctionCall %void %myfunc
4582 OpReturn
4583 OpFunctionEnd
4584 )";
4585 
4586   CompileSuccessfully(spirv);
4587   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
4588   EXPECT_THAT(getDiagnosticString(),
4589               HasSubstr("Uniform decoration applied to a value with void type\n"
4590                         "  %call = OpFunctionCall %void %myfunc"));
4591 }
4592 
TEST_F(ValidateDecorations,MultipleOffsetDecorationsOnSameID)4593 TEST_F(ValidateDecorations, MultipleOffsetDecorationsOnSameID) {
4594   std::string spirv = R"(
4595             OpCapability Shader
4596             OpMemoryModel Logical GLSL450
4597             OpEntryPoint Fragment %1 "main"
4598             OpExecutionMode %1 OriginUpperLeft
4599 
4600             OpMemberDecorate %struct 0 Offset 0
4601             OpMemberDecorate %struct 0 Offset 0
4602 
4603     %void = OpTypeVoid
4604   %voidfn = OpTypeFunction %void
4605    %float = OpTypeFloat 32
4606   %struct = OpTypeStruct %float
4607 
4608        %1 = OpFunction %void None %voidfn
4609    %label = OpLabel
4610             OpReturn
4611             OpFunctionEnd
4612 )";
4613 
4614   CompileSuccessfully(spirv);
4615   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
4616   EXPECT_THAT(getDiagnosticString(),
4617               HasSubstr("ID '2', member '0' decorated with Offset multiple "
4618                         "times is not allowed."));
4619 }
4620 
TEST_F(ValidateDecorations,MultipleArrayStrideDecorationsOnSameID)4621 TEST_F(ValidateDecorations, MultipleArrayStrideDecorationsOnSameID) {
4622   std::string spirv = R"(
4623             OpCapability Shader
4624             OpMemoryModel Logical GLSL450
4625             OpEntryPoint Fragment %1 "main"
4626             OpExecutionMode %1 OriginUpperLeft
4627 
4628             OpDecorate %array ArrayStride 4
4629             OpDecorate %array ArrayStride 4
4630 
4631     %void = OpTypeVoid
4632   %voidfn = OpTypeFunction %void
4633    %float = OpTypeFloat 32
4634     %uint = OpTypeInt 32 0
4635   %uint_4 = OpConstant %uint 4
4636    %array = OpTypeArray %float %uint_4
4637 
4638        %1 = OpFunction %void None %voidfn
4639    %label = OpLabel
4640             OpReturn
4641             OpFunctionEnd
4642 )";
4643 
4644   CompileSuccessfully(spirv);
4645   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
4646   EXPECT_THAT(getDiagnosticString(),
4647               HasSubstr("ID '2' decorated with ArrayStride multiple "
4648                         "times is not allowed."));
4649 }
4650 
TEST_F(ValidateDecorations,MultipleMatrixStrideDecorationsOnSameID)4651 TEST_F(ValidateDecorations, MultipleMatrixStrideDecorationsOnSameID) {
4652   std::string spirv = R"(
4653             OpCapability Shader
4654             OpMemoryModel Logical GLSL450
4655             OpEntryPoint Fragment %1 "main"
4656             OpExecutionMode %1 OriginUpperLeft
4657 
4658             OpMemberDecorate %struct 0 Offset 0
4659             OpMemberDecorate %struct 0 ColMajor
4660             OpMemberDecorate %struct 0 MatrixStride 16
4661             OpMemberDecorate %struct 0 MatrixStride 16
4662 
4663     %void = OpTypeVoid
4664   %voidfn = OpTypeFunction %void
4665    %float = OpTypeFloat 32
4666    %fvec4 = OpTypeVector %float 4
4667    %fmat4 = OpTypeMatrix %fvec4 4
4668   %struct = OpTypeStruct %fmat4
4669 
4670        %1 = OpFunction %void None %voidfn
4671    %label = OpLabel
4672             OpReturn
4673             OpFunctionEnd
4674 )";
4675 
4676   CompileSuccessfully(spirv);
4677   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
4678   EXPECT_THAT(getDiagnosticString(),
4679               HasSubstr("ID '2', member '0' decorated with MatrixStride "
4680                         "multiple times is not allowed."));
4681 }
4682 
TEST_F(ValidateDecorations,MultipleRowMajorDecorationsOnSameID)4683 TEST_F(ValidateDecorations, MultipleRowMajorDecorationsOnSameID) {
4684   std::string spirv = R"(
4685             OpCapability Shader
4686             OpMemoryModel Logical GLSL450
4687             OpEntryPoint Fragment %1 "main"
4688             OpExecutionMode %1 OriginUpperLeft
4689 
4690             OpMemberDecorate %struct 0 Offset 0
4691             OpMemberDecorate %struct 0 MatrixStride 16
4692             OpMemberDecorate %struct 0 RowMajor
4693             OpMemberDecorate %struct 0 RowMajor
4694 
4695     %void = OpTypeVoid
4696   %voidfn = OpTypeFunction %void
4697    %float = OpTypeFloat 32
4698    %fvec4 = OpTypeVector %float 4
4699    %fmat4 = OpTypeMatrix %fvec4 4
4700   %struct = OpTypeStruct %fmat4
4701 
4702        %1 = OpFunction %void None %voidfn
4703    %label = OpLabel
4704             OpReturn
4705             OpFunctionEnd
4706 )";
4707 
4708   CompileSuccessfully(spirv);
4709   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
4710   EXPECT_THAT(getDiagnosticString(),
4711               HasSubstr("ID '2', member '0' decorated with RowMajor multiple "
4712                         "times is not allowed."));
4713 }
4714 
TEST_F(ValidateDecorations,MultipleColMajorDecorationsOnSameID)4715 TEST_F(ValidateDecorations, MultipleColMajorDecorationsOnSameID) {
4716   std::string spirv = R"(
4717             OpCapability Shader
4718             OpMemoryModel Logical GLSL450
4719             OpEntryPoint Fragment %1 "main"
4720             OpExecutionMode %1 OriginUpperLeft
4721 
4722             OpMemberDecorate %struct 0 Offset 0
4723             OpMemberDecorate %struct 0 MatrixStride 16
4724             OpMemberDecorate %struct 0 ColMajor
4725             OpMemberDecorate %struct 0 ColMajor
4726 
4727     %void = OpTypeVoid
4728   %voidfn = OpTypeFunction %void
4729    %float = OpTypeFloat 32
4730    %fvec4 = OpTypeVector %float 4
4731    %fmat4 = OpTypeMatrix %fvec4 4
4732   %struct = OpTypeStruct %fmat4
4733 
4734        %1 = OpFunction %void None %voidfn
4735    %label = OpLabel
4736             OpReturn
4737             OpFunctionEnd
4738 )";
4739 
4740   CompileSuccessfully(spirv);
4741   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
4742   EXPECT_THAT(getDiagnosticString(),
4743               HasSubstr("ID '2', member '0' decorated with ColMajor multiple "
4744                         "times is not allowed."));
4745 }
4746 
TEST_F(ValidateDecorations,RowMajorAndColMajorDecorationsOnSameID)4747 TEST_F(ValidateDecorations, RowMajorAndColMajorDecorationsOnSameID) {
4748   std::string spirv = R"(
4749             OpCapability Shader
4750             OpMemoryModel Logical GLSL450
4751             OpEntryPoint Fragment %1 "main"
4752             OpExecutionMode %1 OriginUpperLeft
4753 
4754             OpMemberDecorate %struct 0 Offset 0
4755             OpMemberDecorate %struct 0 MatrixStride 16
4756             OpMemberDecorate %struct 0 ColMajor
4757             OpMemberDecorate %struct 0 RowMajor
4758 
4759     %void = OpTypeVoid
4760   %voidfn = OpTypeFunction %void
4761    %float = OpTypeFloat 32
4762    %fvec4 = OpTypeVector %float 4
4763    %fmat4 = OpTypeMatrix %fvec4 4
4764   %struct = OpTypeStruct %fmat4
4765 
4766        %1 = OpFunction %void None %voidfn
4767    %label = OpLabel
4768             OpReturn
4769             OpFunctionEnd
4770 )";
4771 
4772   CompileSuccessfully(spirv);
4773   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
4774   EXPECT_THAT(getDiagnosticString(),
4775               HasSubstr("ID '2', member '0' decorated with both RowMajor and "
4776                         "ColMajor is not allowed."));
4777 }
4778 
TEST_F(ValidateDecorations,BlockAndBufferBlockDecorationsOnSameID)4779 TEST_F(ValidateDecorations, BlockAndBufferBlockDecorationsOnSameID) {
4780   std::string spirv = R"(
4781             OpCapability Shader
4782             OpMemoryModel Logical GLSL450
4783             OpEntryPoint Fragment %1 "main"
4784             OpExecutionMode %1 OriginUpperLeft
4785 
4786             OpDecorate %struct Block
4787             OpDecorate %struct BufferBlock
4788             OpMemberDecorate %struct 0 Offset 0
4789             OpMemberDecorate %struct 0 MatrixStride 16
4790             OpMemberDecorate %struct 0 RowMajor
4791 
4792     %void = OpTypeVoid
4793   %voidfn = OpTypeFunction %void
4794    %float = OpTypeFloat 32
4795    %fvec4 = OpTypeVector %float 4
4796    %fmat4 = OpTypeMatrix %fvec4 4
4797   %struct = OpTypeStruct %fmat4
4798 
4799        %1 = OpFunction %void None %voidfn
4800    %label = OpLabel
4801             OpReturn
4802             OpFunctionEnd
4803 )";
4804 
4805   CompileSuccessfully(spirv);
4806   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
4807   EXPECT_THAT(
4808       getDiagnosticString(),
4809       HasSubstr(
4810           "ID '2' decorated with both BufferBlock and Block is not allowed."));
4811 }
4812 
4813 }  // namespace
4814 }  // namespace val
4815 }  // namespace spvtools
4816