1 // Copyright (c) 2018 Google LLC.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <string>
16 
17 #include "gmock/gmock.h"
18 #include "test/unit_spirv.h"
19 #include "test/val/val_fixtures.h"
20 
21 namespace spvtools {
22 namespace val {
23 namespace {
24 
25 using ::testing::HasSubstr;
26 
27 using ValidateInterfacesTest = spvtest::ValidateBase<bool>;
28 
TEST_F(ValidateInterfacesTest,EntryPointMissingInput)29 TEST_F(ValidateInterfacesTest, EntryPointMissingInput) {
30   std::string text = R"(
31 OpCapability Shader
32 OpMemoryModel Logical GLSL450
33 OpEntryPoint Fragment %1 "func"
34 OpExecutionMode %1 OriginUpperLeft
35 %2 = OpTypeVoid
36 %3 = OpTypeInt 32 0
37 %4 = OpTypePointer Input %3
38 %5 = OpVariable %4 Input
39 %6 = OpTypeFunction %2
40 %1 = OpFunction %2 None %6
41 %7 = OpLabel
42 %8 = OpLoad %3 %5
43 OpReturn
44 OpFunctionEnd
45 )";
46 
47   CompileSuccessfully(text);
48   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
49   EXPECT_THAT(
50       getDiagnosticString(),
51       HasSubstr(
52           "Interface variable id <5> is used by entry point 'func' id <1>, "
53           "but is not listed as an interface"));
54 }
55 
TEST_F(ValidateInterfacesTest,EntryPointMissingOutput)56 TEST_F(ValidateInterfacesTest, EntryPointMissingOutput) {
57   std::string text = R"(
58 OpCapability Shader
59 OpMemoryModel Logical GLSL450
60 OpEntryPoint Fragment %1 "func"
61 OpExecutionMode %1 OriginUpperLeft
62 %2 = OpTypeVoid
63 %3 = OpTypeInt 32 0
64 %4 = OpTypePointer Output %3
65 %5 = OpVariable %4 Output
66 %6 = OpTypeFunction %2
67 %1 = OpFunction %2 None %6
68 %7 = OpLabel
69 %8 = OpLoad %3 %5
70 OpReturn
71 OpFunctionEnd
72 )";
73 
74   CompileSuccessfully(text);
75   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
76   EXPECT_THAT(
77       getDiagnosticString(),
78       HasSubstr(
79           "Interface variable id <5> is used by entry point 'func' id <1>, "
80           "but is not listed as an interface"));
81 }
82 
TEST_F(ValidateInterfacesTest,InterfaceMissingUseInSubfunction)83 TEST_F(ValidateInterfacesTest, InterfaceMissingUseInSubfunction) {
84   std::string text = R"(
85 OpCapability Shader
86 OpMemoryModel Logical GLSL450
87 OpEntryPoint Fragment %1 "func"
88 OpExecutionMode %1 OriginUpperLeft
89 %2 = OpTypeVoid
90 %3 = OpTypeInt 32 0
91 %4 = OpTypePointer Input %3
92 %5 = OpVariable %4 Input
93 %6 = OpTypeFunction %2
94 %1 = OpFunction %2 None %6
95 %7 = OpLabel
96 %8 = OpFunctionCall %2 %9
97 OpReturn
98 OpFunctionEnd
99 %9 = OpFunction %2 None %6
100 %10 = OpLabel
101 %11 = OpLoad %3 %5
102 OpReturn
103 OpFunctionEnd
104 )";
105 
106   CompileSuccessfully(text);
107   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
108   EXPECT_THAT(
109       getDiagnosticString(),
110       HasSubstr(
111           "Interface variable id <5> is used by entry point 'func' id <1>, "
112           "but is not listed as an interface"));
113 }
114 
TEST_F(ValidateInterfacesTest,TwoEntryPointsOneFunction)115 TEST_F(ValidateInterfacesTest, TwoEntryPointsOneFunction) {
116   std::string text = R"(
117 OpCapability Shader
118 OpMemoryModel Logical GLSL450
119 OpEntryPoint Fragment %1 "func" %2
120 OpEntryPoint Fragment %1 "func2"
121 OpExecutionMode %1 OriginUpperLeft
122 %3 = OpTypeVoid
123 %4 = OpTypeInt 32 0
124 %5 = OpTypePointer Input %4
125 %2 = OpVariable %5 Input
126 %6 = OpTypeFunction %3
127 %1 = OpFunction %3 None %6
128 %7 = OpLabel
129 %8 = OpLoad %4 %2
130 OpReturn
131 OpFunctionEnd
132 )";
133 
134   CompileSuccessfully(text);
135   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
136   EXPECT_THAT(
137       getDiagnosticString(),
138       HasSubstr(
139           "Interface variable id <2> is used by entry point 'func2' id <1>, "
140           "but is not listed as an interface"));
141 }
142 
TEST_F(ValidateInterfacesTest,MissingInterfaceThroughInitializer)143 TEST_F(ValidateInterfacesTest, MissingInterfaceThroughInitializer) {
144   const std::string text = R"(
145 OpCapability Shader
146 OpCapability VariablePointers
147 OpMemoryModel Logical GLSL450
148 OpEntryPoint Fragment %1 "func"
149 OpExecutionMode %1 OriginUpperLeft
150 %2 = OpTypeVoid
151 %3 = OpTypeInt 32 0
152 %4 = OpTypePointer Input %3
153 %5 = OpTypePointer Function %4
154 %6 = OpVariable %4 Input
155 %7 = OpTypeFunction %2
156 %1 = OpFunction %2 None %7
157 %8 = OpLabel
158 %9 = OpVariable %5 Function %6
159 OpReturn
160 OpFunctionEnd
161 )";
162 
163   CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3);
164   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
165   EXPECT_THAT(
166       getDiagnosticString(),
167       HasSubstr(
168           "Interface variable id <6> is used by entry point 'func' id <1>, "
169           "but is not listed as an interface"));
170 }
171 
TEST_F(ValidateInterfacesTest,NonUniqueInterfacesSPV1p3)172 TEST_F(ValidateInterfacesTest, NonUniqueInterfacesSPV1p3) {
173   const std::string text = R"(
174 OpCapability Shader
175 OpMemoryModel Logical GLSL450
176 OpEntryPoint GLCompute %main "main" %var %var
177 OpExecutionMode %main LocalSize 1 1 1
178 %void = OpTypeVoid
179 %uint = OpTypeInt 32 0
180 %uint3 = OpTypeVector %uint 3
181 %struct = OpTypeStruct %uint3
182 %ptr_struct = OpTypePointer Input %struct
183 %var = OpVariable %ptr_struct Input
184 %func_ty = OpTypeFunction %void
185 %main = OpFunction %void None %func_ty
186 %1 = OpLabel
187 OpReturn
188 OpFunctionEnd
189 )";
190 
191   CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3);
192   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
193 }
194 
TEST_F(ValidateInterfacesTest,NonUniqueInterfacesSPV1p4)195 TEST_F(ValidateInterfacesTest, NonUniqueInterfacesSPV1p4) {
196   const std::string text = R"(
197 OpCapability Shader
198 OpMemoryModel Logical GLSL450
199 OpEntryPoint GLCompute %main "main" %var %var
200 OpExecutionMode %main LocalSize 1 1 1
201 OpName %main "main"
202 OpName %var "var"
203 %void = OpTypeVoid
204 %uint = OpTypeInt 32 0
205 %uint3 = OpTypeVector %uint 3
206 %struct = OpTypeStruct %uint3
207 %ptr_struct = OpTypePointer Input %struct
208 %var = OpVariable %ptr_struct Input
209 %func_ty = OpTypeFunction %void
210 %main = OpFunction %void None %func_ty
211 %1 = OpLabel
212 OpReturn
213 OpFunctionEnd
214 )";
215 
216   CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
217   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
218   EXPECT_THAT(
219       getDiagnosticString(),
220       HasSubstr("Non-unique OpEntryPoint interface '2[%var]' is disallowed"));
221 }
222 
TEST_F(ValidateInterfacesTest,MissingGlobalVarSPV1p3)223 TEST_F(ValidateInterfacesTest, MissingGlobalVarSPV1p3) {
224   const std::string text = R"(
225 OpCapability Shader
226 OpMemoryModel Logical GLSL450
227 OpEntryPoint GLCompute %main "main"
228 OpExecutionMode %main LocalSize 1 1 1
229 %void = OpTypeVoid
230 %uint = OpTypeInt 32 0
231 %uint3 = OpTypeVector %uint 3
232 %struct = OpTypeStruct %uint3
233 %ptr_struct = OpTypePointer StorageBuffer %struct
234 %var = OpVariable %ptr_struct StorageBuffer
235 %func_ty = OpTypeFunction %void
236 %main = OpFunction %void None %func_ty
237 %1 = OpLabel
238 %ld = OpLoad %struct %var
239 OpReturn
240 OpFunctionEnd
241 )";
242 
243   CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3);
244   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
245 }
246 
TEST_F(ValidateInterfacesTest,MissingGlobalVarSPV1p4)247 TEST_F(ValidateInterfacesTest, MissingGlobalVarSPV1p4) {
248   const std::string text = R"(
249 OpCapability Shader
250 OpMemoryModel Logical GLSL450
251 OpEntryPoint GLCompute %main "main"
252 OpExecutionMode %main LocalSize 1 1 1
253 OpName %var "var"
254 %void = OpTypeVoid
255 %uint = OpTypeInt 32 0
256 %uint3 = OpTypeVector %uint 3
257 %struct = OpTypeStruct %uint3
258 %ptr_struct = OpTypePointer StorageBuffer %struct
259 %var = OpVariable %ptr_struct StorageBuffer
260 %func_ty = OpTypeFunction %void
261 %main = OpFunction %void None %func_ty
262 %1 = OpLabel
263 %ld = OpLoad %struct %var
264 OpReturn
265 OpFunctionEnd
266 )";
267 
268   CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
269   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
270   EXPECT_THAT(getDiagnosticString(),
271               HasSubstr("Interface variable id <2> is used by entry point "
272                         "'main' id <1>, but is not listed as an interface"));
273 }
274 
TEST_F(ValidateInterfacesTest,FunctionInterfaceVarSPV1p3)275 TEST_F(ValidateInterfacesTest, FunctionInterfaceVarSPV1p3) {
276   const std::string text = R"(
277 OpCapability Shader
278 OpMemoryModel Logical GLSL450
279 OpEntryPoint GLCompute %main "main" %var
280 OpExecutionMode %main LocalSize 1 1 1
281 OpName %var "var"
282 %void = OpTypeVoid
283 %uint = OpTypeInt 32 0
284 %uint3 = OpTypeVector %uint 3
285 %struct = OpTypeStruct %uint3
286 %ptr_struct = OpTypePointer Function %struct
287 %func_ty = OpTypeFunction %void
288 %main = OpFunction %void None %func_ty
289 %1 = OpLabel
290 %var = OpVariable %ptr_struct Function
291 OpReturn
292 OpFunctionEnd
293 )";
294 
295   CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3);
296   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
297   EXPECT_THAT(getDiagnosticString(),
298               HasSubstr("OpEntryPoint interfaces must be OpVariables with "
299                         "Storage Class of Input(1) or Output(3). Found Storage "
300                         "Class 7 for Entry Point id 1."));
301 }
302 
TEST_F(ValidateInterfacesTest,FunctionInterfaceVarSPV1p4)303 TEST_F(ValidateInterfacesTest, FunctionInterfaceVarSPV1p4) {
304   const std::string text = R"(
305 OpCapability Shader
306 OpMemoryModel Logical GLSL450
307 OpEntryPoint GLCompute %main "main" %var
308 OpExecutionMode %main LocalSize 1 1 1
309 OpName %var "var"
310 %void = OpTypeVoid
311 %uint = OpTypeInt 32 0
312 %uint3 = OpTypeVector %uint 3
313 %struct = OpTypeStruct %uint3
314 %ptr_struct = OpTypePointer Function %struct
315 %func_ty = OpTypeFunction %void
316 %main = OpFunction %void None %func_ty
317 %1 = OpLabel
318 %var = OpVariable %ptr_struct Function
319 OpReturn
320 OpFunctionEnd
321 )";
322 
323   CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
324   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
325   EXPECT_THAT(
326       getDiagnosticString(),
327       HasSubstr("OpEntryPoint interfaces should only list global variables"));
328 }
329 
TEST_F(ValidateInterfacesTest,ModuleSPV1p3ValidateSPV1p4_NotAllUsedGlobals)330 TEST_F(ValidateInterfacesTest, ModuleSPV1p3ValidateSPV1p4_NotAllUsedGlobals) {
331   const std::string text = R"(
332 OpCapability Shader
333 OpMemoryModel Logical GLSL450
334 OpEntryPoint GLCompute %main "main"
335 OpExecutionMode %main LocalSize 1 1 1
336 OpName %var "var"
337 %void = OpTypeVoid
338 %uint = OpTypeInt 32 0
339 %uint3 = OpTypeVector %uint 3
340 %struct = OpTypeStruct %uint3
341 %ptr_struct = OpTypePointer StorageBuffer %struct
342 %var = OpVariable %ptr_struct StorageBuffer
343 %func_ty = OpTypeFunction %void
344 %main = OpFunction %void None %func_ty
345 %1 = OpLabel
346 %ld = OpLoad %struct %var
347 OpReturn
348 OpFunctionEnd
349 )";
350 
351   CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3);
352   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
353 }
354 
TEST_F(ValidateInterfacesTest,ModuleSPV1p3ValidateSPV1p4_DuplicateInterface)355 TEST_F(ValidateInterfacesTest, ModuleSPV1p3ValidateSPV1p4_DuplicateInterface) {
356   const std::string text = R"(
357 OpCapability Shader
358 OpMemoryModel Logical GLSL450
359 OpEntryPoint GLCompute %main "main" %gid %gid
360 OpExecutionMode %main LocalSize 1 1 1
361 OpDecorate %gid BuiltIn GlobalInvocationId
362 %void = OpTypeVoid
363 %int = OpTypeInt 32 0
364 %int3 = OpTypeVector %int 3
365 %ptr_input_int3 = OpTypePointer Input %int3
366 %gid = OpVariable %ptr_input_int3 Input
367 %void_fn = OpTypeFunction %void
368 %main = OpFunction %void None %void_fn
369 %entry = OpLabel
370 OpReturn
371 OpFunctionEnd
372 )";
373 
374   CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3);
375   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
376 }
377 
TEST_F(ValidateInterfacesTest,SPV14MultipleEntryPointsSameFunction)378 TEST_F(ValidateInterfacesTest, SPV14MultipleEntryPointsSameFunction) {
379   const std::string text = R"(
380 OpCapability Shader
381 OpMemoryModel Logical GLSL450
382 OpEntryPoint GLCompute %main "main1" %gid
383 OpEntryPoint GLCompute %main "main2" %gid
384 OpExecutionMode %main LocalSize 1 1 1
385 OpDecorate %gid BuiltIn GlobalInvocationId
386 %void = OpTypeVoid
387 %int = OpTypeInt 32 0
388 %int3 = OpTypeVector %int 3
389 %ptr_input_int3 = OpTypePointer Input %int3
390 %gid = OpVariable %ptr_input_int3 Input
391 %void_fn = OpTypeFunction %void
392 %main = OpFunction %void None %void_fn
393 %entry = OpLabel
394 OpReturn
395 OpFunctionEnd
396 )";
397 
398   CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4);
399   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
400 }
401 
TEST_F(ValidateInterfacesTest,VulkanLocationsDoubleAssignmentVariable)402 TEST_F(ValidateInterfacesTest, VulkanLocationsDoubleAssignmentVariable) {
403   const std::string text = R"(
404 OpCapability Shader
405 OpMemoryModel Logical GLSL450
406 OpEntryPoint Fragment %main "main" %var
407 OpExecutionMode %main OriginUpperLeft
408 OpDecorate %var Location 0
409 OpDecorate %var Location 1
410 %void = OpTypeVoid
411 %void_fn = OpTypeFunction %void
412 %float = OpTypeFloat 32
413 %ptr_input_float = OpTypePointer Input %float
414 %var = OpVariable %ptr_input_float Input
415 %main = OpFunction %void None %void_fn
416 %entry = OpLabel
417 OpReturn
418 OpFunctionEnd
419 )";
420 
421   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
422   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
423   EXPECT_THAT(getDiagnosticString(),
424               HasSubstr("Variable has conflicting location decorations"));
425 }
426 
TEST_F(ValidateInterfacesTest,VulkanLocationsVariableAndMemberAssigned)427 TEST_F(ValidateInterfacesTest, VulkanLocationsVariableAndMemberAssigned) {
428   const std::string text = R"(
429 OpCapability Shader
430 OpMemoryModel Logical GLSL450
431 OpEntryPoint Fragment %main "main" %var
432 OpExecutionMode %main OriginUpperLeft
433 OpDecorate %var Location 0
434 OpDecorate %struct Block
435 OpMemberDecorate %struct 0 Location 0
436 %void = OpTypeVoid
437 %void_fn = OpTypeFunction %void
438 %float = OpTypeFloat 32
439 %struct = OpTypeStruct %float
440 %ptr_input_struct = OpTypePointer Input %struct
441 %var = OpVariable %ptr_input_struct Input
442 %main = OpFunction %void None %void_fn
443 %entry = OpLabel
444 OpReturn
445 OpFunctionEnd
446 )";
447 
448   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
449   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
450   EXPECT_THAT(getDiagnosticString(),
451               AnyVUID("VUID-StandaloneSpirv-Location-04918"));
452   EXPECT_THAT(getDiagnosticString(),
453               HasSubstr("Members cannot be assigned a location"));
454 }
455 
TEST_F(ValidateInterfacesTest,VulkanLocationsMemberAndSubMemberAssigned)456 TEST_F(ValidateInterfacesTest, VulkanLocationsMemberAndSubMemberAssigned) {
457   const std::string text = R"(
458 OpCapability Shader
459 OpMemoryModel Logical GLSL450
460 OpEntryPoint Fragment %main "main" %var
461 OpExecutionMode %main OriginUpperLeft
462 OpDecorate %outer Block
463 OpMemberDecorate %outer 0 Location 0
464 OpMemberDecorate %struct 0 Location 0
465 %void = OpTypeVoid
466 %void_fn = OpTypeFunction %void
467 %float = OpTypeFloat 32
468 %struct = OpTypeStruct %float
469 %outer = OpTypeStruct %struct
470 %ptr_input_outer = OpTypePointer Input %outer
471 %var = OpVariable %ptr_input_outer Input
472 %main = OpFunction %void None %void_fn
473 %entry = OpLabel
474 OpReturn
475 OpFunctionEnd
476 )";
477 
478   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
479   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
480   EXPECT_THAT(getDiagnosticString(),
481               AnyVUID("VUID-StandaloneSpirv-Location-04918"));
482   EXPECT_THAT(getDiagnosticString(),
483               HasSubstr("Members cannot be assigned a location"));
484 }
485 
TEST_F(ValidateInterfacesTest,VulkanLocationsDoubleAssignmentStructMember)486 TEST_F(ValidateInterfacesTest, VulkanLocationsDoubleAssignmentStructMember) {
487   const std::string text = R"(
488 OpCapability Shader
489 OpMemoryModel Logical GLSL450
490 OpEntryPoint Fragment %main "main" %var
491 OpExecutionMode %main OriginUpperLeft
492 OpDecorate %struct Block
493 OpMemberDecorate %struct 1 Location 0
494 OpMemberDecorate %struct 1 Location 1
495 %void = OpTypeVoid
496 %void_fn = OpTypeFunction %void
497 %float = OpTypeFloat 32
498 %struct = OpTypeStruct %float %float
499 %ptr_input_struct = OpTypePointer Input %struct
500 %var = OpVariable %ptr_input_struct Input
501 %main = OpFunction %void None %void_fn
502 %entry = OpLabel
503 OpReturn
504 OpFunctionEnd
505 )";
506 
507   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
508   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
509   EXPECT_THAT(getDiagnosticString(),
510               HasSubstr("Member index 1 has conflicting location assignments"));
511 }
512 
TEST_F(ValidateInterfacesTest,VulkanLocationsMissingAssignmentStructMember)513 TEST_F(ValidateInterfacesTest, VulkanLocationsMissingAssignmentStructMember) {
514   const std::string text = R"(
515 OpCapability Shader
516 OpMemoryModel Logical GLSL450
517 OpEntryPoint Fragment %main "main" %var
518 OpExecutionMode %main OriginUpperLeft
519 OpDecorate %struct Block
520 OpMemberDecorate %struct 1 Location 1
521 %void = OpTypeVoid
522 %void_fn = OpTypeFunction %void
523 %float = OpTypeFloat 32
524 %struct = OpTypeStruct %float %float
525 %ptr_input_struct = OpTypePointer Input %struct
526 %var = OpVariable %ptr_input_struct Input
527 %main = OpFunction %void None %void_fn
528 %entry = OpLabel
529 OpReturn
530 OpFunctionEnd
531 )";
532 
533   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
534   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
535   EXPECT_THAT(getDiagnosticString(),
536               HasSubstr("Member index 0 is missing a location assignment"));
537 }
538 
TEST_F(ValidateInterfacesTest,VulkanLocationsMissingAssignmentNonBlockStruct)539 TEST_F(ValidateInterfacesTest, VulkanLocationsMissingAssignmentNonBlockStruct) {
540   const std::string text = R"(
541 OpCapability Shader
542 OpMemoryModel Logical GLSL450
543 OpEntryPoint Fragment %main "main" %var
544 OpExecutionMode %main OriginUpperLeft
545 %void = OpTypeVoid
546 %void_fn = OpTypeFunction %void
547 %float = OpTypeFloat 32
548 %struct = OpTypeStruct %float %float
549 %ptr_input_struct = OpTypePointer Input %struct
550 %var = OpVariable %ptr_input_struct Input
551 %main = OpFunction %void None %void_fn
552 %entry = OpLabel
553 OpReturn
554 OpFunctionEnd
555 )";
556 
557   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
558   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
559   EXPECT_THAT(getDiagnosticString(),
560               HasSubstr("Variable must be decorated with a location"));
561 }
562 
TEST_F(ValidateInterfacesTest,VulkanLocationsVariableConflictInput)563 TEST_F(ValidateInterfacesTest, VulkanLocationsVariableConflictInput) {
564   const std::string text = R"(
565 OpCapability Shader
566 OpMemoryModel Logical GLSL450
567 OpEntryPoint Fragment %main "main" %var1 %var2
568 OpExecutionMode %main OriginUpperLeft
569 OpDecorate %var1 Location 0
570 OpDecorate %var2 Location 0
571 %void = OpTypeVoid
572 %void_fn = OpTypeFunction %void
573 %float = OpTypeFloat 32
574 %struct = OpTypeStruct %float %float
575 %ptr_input_struct = OpTypePointer Input %struct
576 %var1 = OpVariable %ptr_input_struct Input
577 %var2 = OpVariable %ptr_input_struct Input
578 %main = OpFunction %void None %void_fn
579 %entry = OpLabel
580 OpReturn
581 OpFunctionEnd
582 )";
583 
584   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
585   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
586   EXPECT_THAT(getDiagnosticString(),
587               AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08721"));
588   EXPECT_THAT(getDiagnosticString(),
589               HasSubstr("Entry-point has conflicting input location assignment "
590                         "at location 0"));
591 }
592 
TEST_F(ValidateInterfacesTest,VulkanLocationsVariableConflictOutput)593 TEST_F(ValidateInterfacesTest, VulkanLocationsVariableConflictOutput) {
594   const std::string text = R"(
595 OpCapability Shader
596 OpMemoryModel Logical GLSL450
597 OpEntryPoint Fragment %main "main" %var1 %var2
598 OpExecutionMode %main OriginUpperLeft
599 OpDecorate %var1 Location 1
600 OpDecorate %var2 Location 1
601 %void = OpTypeVoid
602 %void_fn = OpTypeFunction %void
603 %float = OpTypeFloat 32
604 %struct = OpTypeStruct %float %float
605 %ptr_output_struct = OpTypePointer Output %struct
606 %var1 = OpVariable %ptr_output_struct Output
607 %var2 = OpVariable %ptr_output_struct Output
608 %main = OpFunction %void None %void_fn
609 %entry = OpLabel
610 OpReturn
611 OpFunctionEnd
612 )";
613 
614   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
615   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
616   EXPECT_THAT(getDiagnosticString(),
617               AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08722"));
618   EXPECT_THAT(
619       getDiagnosticString(),
620       HasSubstr("Entry-point has conflicting output location assignment "
621                 "at location 1"));
622 }
623 
TEST_F(ValidateInterfacesTest,VulkanLocationsSameLocationInputAndOutputNoConflict)624 TEST_F(ValidateInterfacesTest,
625        VulkanLocationsSameLocationInputAndOutputNoConflict) {
626   const std::string text = R"(
627 OpCapability Shader
628 OpMemoryModel Logical GLSL450
629 OpEntryPoint Fragment %main "main" %var1 %var2
630 OpExecutionMode %main OriginUpperLeft
631 OpDecorate %var1 Location 1
632 OpDecorate %var2 Location 1
633 %void = OpTypeVoid
634 %void_fn = OpTypeFunction %void
635 %float = OpTypeFloat 32
636 %struct = OpTypeStruct %float %float
637 %ptr_input_struct = OpTypePointer Input %struct
638 %ptr_output_struct = OpTypePointer Output %struct
639 %var1 = OpVariable %ptr_input_struct Input
640 %var2 = OpVariable %ptr_output_struct Output
641 %main = OpFunction %void None %void_fn
642 %entry = OpLabel
643 OpReturn
644 OpFunctionEnd
645 )";
646 
647   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
648   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
649 }
650 
TEST_F(ValidateInterfacesTest,VulkanLocationsVariableInGap)651 TEST_F(ValidateInterfacesTest, VulkanLocationsVariableInGap) {
652   const std::string text = R"(
653 OpCapability Shader
654 OpMemoryModel Logical GLSL450
655 OpEntryPoint Fragment %main "main" %var1 %var2
656 OpExecutionMode %main OriginUpperLeft
657 OpDecorate %struct Block
658 OpMemberDecorate %struct 0 Location 0
659 OpMemberDecorate %struct 1 Location 2
660 OpDecorate %var2 Location 1
661 %void = OpTypeVoid
662 %void_fn = OpTypeFunction %void
663 %float = OpTypeFloat 32
664 %struct = OpTypeStruct %float %float
665 %ptr_input_struct = OpTypePointer Input %struct
666 %ptr_input_float = OpTypePointer Input %float
667 %var1 = OpVariable %ptr_input_struct Input
668 %var2 = OpVariable %ptr_input_float Input
669 %main = OpFunction %void None %void_fn
670 %entry = OpLabel
671 OpReturn
672 OpFunctionEnd
673 )";
674 
675   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
676   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
677 }
678 
TEST_F(ValidateInterfacesTest,VulkanLocationsLargeFloatVectorConflict)679 TEST_F(ValidateInterfacesTest, VulkanLocationsLargeFloatVectorConflict) {
680   const std::string text = R"(
681 OpCapability Shader
682 OpCapability Float64
683 OpMemoryModel Logical GLSL450
684 OpEntryPoint Fragment %main "main" %var1 %var2
685 OpExecutionMode %main OriginUpperLeft
686 OpDecorate %var1 Location 0
687 OpDecorate %var2 Location 1
688 %void = OpTypeVoid
689 %void_fn = OpTypeFunction %void
690 %float = OpTypeFloat 32
691 %double = OpTypeFloat 64
692 %vector = OpTypeVector %double 3
693 %ptr_input_float = OpTypePointer Input %float
694 %ptr_input_vector = OpTypePointer Input %vector
695 %var1 = OpVariable %ptr_input_vector Input
696 %var2 = OpVariable %ptr_input_float Input
697 %main = OpFunction %void None %void_fn
698 %entry = OpLabel
699 OpReturn
700 OpFunctionEnd
701 )";
702 
703   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
704   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
705   EXPECT_THAT(getDiagnosticString(),
706               AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08721"));
707   EXPECT_THAT(getDiagnosticString(),
708               HasSubstr("Entry-point has conflicting input location assignment "
709                         "at location 1"));
710 }
711 
TEST_F(ValidateInterfacesTest,VulkanLocationsLargeIntVectorConflict)712 TEST_F(ValidateInterfacesTest, VulkanLocationsLargeIntVectorConflict) {
713   const std::string text = R"(
714 OpCapability Shader
715 OpCapability Int64
716 OpMemoryModel Logical GLSL450
717 OpEntryPoint Fragment %main "main" %var1 %var2
718 OpExecutionMode %main OriginUpperLeft
719 OpDecorate %var1 Location 0
720 OpDecorate %var1 Flat
721 OpDecorate %var2 Location 1
722 OpDecorate %var2 Flat
723 %void = OpTypeVoid
724 %void_fn = OpTypeFunction %void
725 %float = OpTypeFloat 32
726 %long = OpTypeInt 64 0
727 %vector = OpTypeVector %long 4
728 %ptr_input_float = OpTypePointer Input %float
729 %ptr_input_vector = OpTypePointer Input %vector
730 %var1 = OpVariable %ptr_input_vector Input
731 %var2 = OpVariable %ptr_input_float Input
732 %main = OpFunction %void None %void_fn
733 %entry = OpLabel
734 OpReturn
735 OpFunctionEnd
736 )";
737 
738   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
739   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
740   EXPECT_THAT(getDiagnosticString(),
741               AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08721"));
742   EXPECT_THAT(getDiagnosticString(),
743               HasSubstr("Entry-point has conflicting input location assignment "
744                         "at location 1"));
745 }
746 
TEST_F(ValidateInterfacesTest,VulkanLocationsMatrix2x2Conflict)747 TEST_F(ValidateInterfacesTest, VulkanLocationsMatrix2x2Conflict) {
748   const std::string text = R"(
749 OpCapability Shader
750 OpMemoryModel Logical GLSL450
751 OpEntryPoint Fragment %main "main" %var1 %var2
752 OpExecutionMode %main OriginUpperLeft
753 OpDecorate %var1 Location 0
754 OpDecorate %var2 Location 1
755 %void = OpTypeVoid
756 %void_fn = OpTypeFunction %void
757 %float = OpTypeFloat 32
758 %vector = OpTypeVector %float 2
759 %matrix = OpTypeMatrix %vector 2
760 %ptr_input_float = OpTypePointer Input %float
761 %ptr_input_matrix = OpTypePointer Input %matrix
762 %var1 = OpVariable %ptr_input_matrix Input
763 %var2 = OpVariable %ptr_input_float Input
764 %main = OpFunction %void None %void_fn
765 %entry = OpLabel
766 OpReturn
767 OpFunctionEnd
768 )";
769 
770   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
771   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
772   EXPECT_THAT(getDiagnosticString(),
773               AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08721"));
774   EXPECT_THAT(getDiagnosticString(),
775               HasSubstr("Entry-point has conflicting input location assignment "
776                         "at location 1"));
777 }
778 
TEST_F(ValidateInterfacesTest,VulkanLocationsMatrix3x3Conflict)779 TEST_F(ValidateInterfacesTest, VulkanLocationsMatrix3x3Conflict) {
780   const std::string text = R"(
781 OpCapability Shader
782 OpMemoryModel Logical GLSL450
783 OpEntryPoint Fragment %main "main" %var1 %var2
784 OpExecutionMode %main OriginUpperLeft
785 OpDecorate %var1 Location 0
786 OpDecorate %var2 Location 2
787 %void = OpTypeVoid
788 %void_fn = OpTypeFunction %void
789 %float = OpTypeFloat 32
790 %vector = OpTypeVector %float 3
791 %matrix = OpTypeMatrix %vector 3
792 %ptr_input_float = OpTypePointer Input %float
793 %ptr_input_matrix = OpTypePointer Input %matrix
794 %var1 = OpVariable %ptr_input_matrix Input
795 %var2 = OpVariable %ptr_input_float Input
796 %main = OpFunction %void None %void_fn
797 %entry = OpLabel
798 OpReturn
799 OpFunctionEnd
800 )";
801 
802   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
803   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
804   EXPECT_THAT(getDiagnosticString(),
805               AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08721"));
806   EXPECT_THAT(getDiagnosticString(),
807               HasSubstr("Entry-point has conflicting input location assignment "
808                         "at location 2"));
809 }
810 
TEST_F(ValidateInterfacesTest,VulkanLocationsMatrix4x4Conflict)811 TEST_F(ValidateInterfacesTest, VulkanLocationsMatrix4x4Conflict) {
812   const std::string text = R"(
813 OpCapability Shader
814 OpMemoryModel Logical GLSL450
815 OpEntryPoint Fragment %main "main" %var1 %var2
816 OpExecutionMode %main OriginUpperLeft
817 OpDecorate %var1 Location 0
818 OpDecorate %var2 Location 3
819 %void = OpTypeVoid
820 %void_fn = OpTypeFunction %void
821 %float = OpTypeFloat 32
822 %vector = OpTypeVector %float 4
823 %matrix = OpTypeMatrix %vector 4
824 %ptr_input_float = OpTypePointer Input %float
825 %ptr_input_matrix = OpTypePointer Input %matrix
826 %var1 = OpVariable %ptr_input_matrix Input
827 %var2 = OpVariable %ptr_input_float Input
828 %main = OpFunction %void None %void_fn
829 %entry = OpLabel
830 OpReturn
831 OpFunctionEnd
832 )";
833 
834   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
835   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
836   EXPECT_THAT(getDiagnosticString(),
837               AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08721"));
838   EXPECT_THAT(getDiagnosticString(),
839               HasSubstr("Entry-point has conflicting input location assignment "
840                         "at location 3"));
841 }
842 
TEST_F(ValidateInterfacesTest,VulkanLocationsLargeMatrix2x2Conflict)843 TEST_F(ValidateInterfacesTest, VulkanLocationsLargeMatrix2x2Conflict) {
844   const std::string text = R"(
845 OpCapability Shader
846 OpCapability Float64
847 OpMemoryModel Logical GLSL450
848 OpEntryPoint Fragment %main "main" %var1 %var2
849 OpExecutionMode %main OriginUpperLeft
850 OpDecorate %var1 Location 0
851 OpDecorate %var2 Location 1
852 %void = OpTypeVoid
853 %void_fn = OpTypeFunction %void
854 %float = OpTypeFloat 32
855 %double = OpTypeFloat 64
856 %vector = OpTypeVector %double 2
857 %matrix = OpTypeMatrix %vector 2
858 %ptr_input_float = OpTypePointer Input %float
859 %ptr_input_matrix = OpTypePointer Input %matrix
860 %var1 = OpVariable %ptr_input_matrix Input
861 %var2 = OpVariable %ptr_input_float Input
862 %main = OpFunction %void None %void_fn
863 %entry = OpLabel
864 OpReturn
865 OpFunctionEnd
866 )";
867 
868   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
869   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
870   EXPECT_THAT(getDiagnosticString(),
871               AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08721"));
872   EXPECT_THAT(getDiagnosticString(),
873               HasSubstr("Entry-point has conflicting input location assignment "
874                         "at location 1"));
875 }
876 
TEST_F(ValidateInterfacesTest,VulkanLocationsLargeMatrix3x3Conflict)877 TEST_F(ValidateInterfacesTest, VulkanLocationsLargeMatrix3x3Conflict) {
878   const std::string text = R"(
879 OpCapability Shader
880 OpCapability Float64
881 OpMemoryModel Logical GLSL450
882 OpEntryPoint Fragment %main "main" %var1 %var2
883 OpExecutionMode %main OriginUpperLeft
884 OpDecorate %var1 Location 0
885 OpDecorate %var2 Location 5
886 %void = OpTypeVoid
887 %void_fn = OpTypeFunction %void
888 %float = OpTypeFloat 32
889 %double = OpTypeFloat 64
890 %vector = OpTypeVector %double 3
891 %matrix = OpTypeMatrix %vector 3
892 %ptr_input_float = OpTypePointer Input %float
893 %ptr_input_matrix = OpTypePointer Input %matrix
894 %var1 = OpVariable %ptr_input_matrix Input
895 %var2 = OpVariable %ptr_input_float Input
896 %main = OpFunction %void None %void_fn
897 %entry = OpLabel
898 OpReturn
899 OpFunctionEnd
900 )";
901 
902   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
903   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
904   EXPECT_THAT(getDiagnosticString(),
905               AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08721"));
906   EXPECT_THAT(getDiagnosticString(),
907               HasSubstr("Entry-point has conflicting input location assignment "
908                         "at location 5"));
909 }
910 
TEST_F(ValidateInterfacesTest,VulkanLocationsLargeMatrix4x4Conflict)911 TEST_F(ValidateInterfacesTest, VulkanLocationsLargeMatrix4x4Conflict) {
912   const std::string text = R"(
913 OpCapability Shader
914 OpCapability Float64
915 OpMemoryModel Logical GLSL450
916 OpEntryPoint Fragment %main "main" %var1 %var2
917 OpExecutionMode %main OriginUpperLeft
918 OpDecorate %var1 Location 0
919 OpDecorate %var2 Location 7
920 %void = OpTypeVoid
921 %void_fn = OpTypeFunction %void
922 %float = OpTypeFloat 32
923 %double = OpTypeFloat 64
924 %vector = OpTypeVector %double 4
925 %matrix = OpTypeMatrix %vector 4
926 %ptr_input_float = OpTypePointer Input %float
927 %ptr_input_matrix = OpTypePointer Input %matrix
928 %var1 = OpVariable %ptr_input_matrix Input
929 %var2 = OpVariable %ptr_input_float Input
930 %main = OpFunction %void None %void_fn
931 %entry = OpLabel
932 OpReturn
933 OpFunctionEnd
934 )";
935 
936   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
937   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
938   EXPECT_THAT(getDiagnosticString(),
939               AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08721"));
940   EXPECT_THAT(getDiagnosticString(),
941               HasSubstr("Entry-point has conflicting input location assignment "
942                         "at location 7"));
943 }
944 
TEST_F(ValidateInterfacesTest,VulkanLocationsArray2Conflict)945 TEST_F(ValidateInterfacesTest, VulkanLocationsArray2Conflict) {
946   const std::string text = R"(
947 OpCapability Shader
948 OpMemoryModel Logical GLSL450
949 OpEntryPoint Fragment %main "main" %var1 %var2
950 OpExecutionMode %main OriginUpperLeft
951 OpDecorate %var1 Location 0
952 OpDecorate %var2 Location 1
953 %void = OpTypeVoid
954 %void_fn = OpTypeFunction %void
955 %float = OpTypeFloat 32
956 %int = OpTypeInt 32 0
957 %int_2 = OpConstant %int 2
958 %array = OpTypeArray %int %int_2
959 %struct = OpTypeStruct %array
960 %ptr_input_float = OpTypePointer Input %float
961 %ptr_input_struct = OpTypePointer Input %struct
962 %var1 = OpVariable %ptr_input_struct Input
963 %var2 = OpVariable %ptr_input_float Input
964 %main = OpFunction %void None %void_fn
965 %entry = OpLabel
966 OpReturn
967 OpFunctionEnd
968 )";
969 
970   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
971   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
972   EXPECT_THAT(getDiagnosticString(),
973               AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08721"));
974   EXPECT_THAT(getDiagnosticString(),
975               HasSubstr("Entry-point has conflicting input location assignment "
976                         "at location 1"));
977 }
978 
TEST_F(ValidateInterfacesTest,VulkanLocationsArray4Conflict)979 TEST_F(ValidateInterfacesTest, VulkanLocationsArray4Conflict) {
980   const std::string text = R"(
981 OpCapability Shader
982 OpMemoryModel Logical GLSL450
983 OpEntryPoint Fragment %main "main" %var1 %var2
984 OpExecutionMode %main OriginUpperLeft
985 OpDecorate %var1 Location 0
986 OpDecorate %var2 Location 3
987 %void = OpTypeVoid
988 %void_fn = OpTypeFunction %void
989 %float = OpTypeFloat 32
990 %int = OpTypeInt 32 0
991 %int_4 = OpConstant %int 4
992 %array = OpTypeArray %int %int_4
993 %struct = OpTypeStruct %array
994 %ptr_input_float = OpTypePointer Input %float
995 %ptr_input_struct = OpTypePointer Input %struct
996 %var1 = OpVariable %ptr_input_struct Input
997 %var2 = OpVariable %ptr_input_float Input
998 %main = OpFunction %void None %void_fn
999 %entry = OpLabel
1000 OpReturn
1001 OpFunctionEnd
1002 )";
1003 
1004   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
1005   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
1006   EXPECT_THAT(getDiagnosticString(),
1007               AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08721"));
1008   EXPECT_THAT(getDiagnosticString(),
1009               HasSubstr("Entry-point has conflicting input location assignment "
1010                         "at location 3"));
1011 }
1012 
TEST_F(ValidateInterfacesTest,VulkanLocationsMatrix4x4Array4Conflict)1013 TEST_F(ValidateInterfacesTest, VulkanLocationsMatrix4x4Array4Conflict) {
1014   const std::string text = R"(
1015 OpCapability Shader
1016 OpMemoryModel Logical GLSL450
1017 OpEntryPoint Fragment %main "main" %var1 %var2
1018 OpExecutionMode %main OriginUpperLeft
1019 OpDecorate %var1 Location 0
1020 OpDecorate %var2 Location 15
1021 %void = OpTypeVoid
1022 %void_fn = OpTypeFunction %void
1023 %float = OpTypeFloat 32
1024 %int = OpTypeInt 32 0
1025 %int_4 = OpConstant %int 4
1026 %vector = OpTypeVector %float 4
1027 %matrix = OpTypeMatrix %vector 4
1028 %array = OpTypeArray %matrix %int_4
1029 %struct = OpTypeStruct %array
1030 %ptr_input_float = OpTypePointer Input %float
1031 %ptr_input_struct = OpTypePointer Input %struct
1032 %var1 = OpVariable %ptr_input_struct Input
1033 %var2 = OpVariable %ptr_input_float Input
1034 %main = OpFunction %void None %void_fn
1035 %entry = OpLabel
1036 OpReturn
1037 OpFunctionEnd
1038 )";
1039 
1040   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
1041   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
1042   EXPECT_THAT(getDiagnosticString(),
1043               AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08721"));
1044   EXPECT_THAT(getDiagnosticString(),
1045               HasSubstr("Entry-point has conflicting input location assignment "
1046                         "at location 15"));
1047 }
1048 
TEST_F(ValidateInterfacesTest,VulkanLocationsComponentDisambiguates)1049 TEST_F(ValidateInterfacesTest, VulkanLocationsComponentDisambiguates) {
1050   const std::string text = R"(
1051 OpCapability Shader
1052 OpMemoryModel Logical GLSL450
1053 OpEntryPoint Fragment %main "main" %var1
1054 OpExecutionMode %main OriginUpperLeft
1055 OpDecorate %struct Block
1056 OpMemberDecorate %struct 0 Location 0
1057 OpMemberDecorate %struct 0 Component 0
1058 OpMemberDecorate %struct 1 Location 0
1059 OpMemberDecorate %struct 1 Component 1
1060 %void = OpTypeVoid
1061 %void_fn = OpTypeFunction %void
1062 %float = OpTypeFloat 32
1063 %struct = OpTypeStruct %float %float
1064 %ptr_input_struct = OpTypePointer Input %struct
1065 %var1 = OpVariable %ptr_input_struct Input
1066 %main = OpFunction %void None %void_fn
1067 %entry = OpLabel
1068 OpReturn
1069 OpFunctionEnd
1070 )";
1071 
1072   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
1073   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
1074 }
1075 
TEST_F(ValidateInterfacesTest,VulkanLocationsComponentIn64BitVec3)1076 TEST_F(ValidateInterfacesTest, VulkanLocationsComponentIn64BitVec3) {
1077   const std::string text = R"(
1078 OpCapability Shader
1079 OpCapability Float64
1080 OpMemoryModel Logical GLSL450
1081 OpEntryPoint Fragment %main "main" %var
1082 OpExecutionMode %main OriginUpperLeft
1083 OpDecorate %struct Block
1084 OpMemberDecorate %struct 0 Location 0
1085 OpMemberDecorate %struct 1 Location 1
1086 OpMemberDecorate %struct 1 Component 1
1087 %void = OpTypeVoid
1088 %void_fn = OpTypeFunction %void
1089 %float = OpTypeFloat 32
1090 %double = OpTypeFloat 64
1091 %double3 = OpTypeVector %double 3
1092 %struct = OpTypeStruct %double3 %float
1093 %ptr_input_struct = OpTypePointer Input %struct
1094 %var = OpVariable %ptr_input_struct Input
1095 %main = OpFunction %void None %void_fn
1096 %entry = OpLabel
1097 OpReturn
1098 OpFunctionEnd
1099 )";
1100 
1101   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
1102   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
1103   EXPECT_THAT(getDiagnosticString(),
1104               AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08721"));
1105   EXPECT_THAT(getDiagnosticString(),
1106               HasSubstr("Entry-point has conflicting input location assignment "
1107                         "at location 1, component 1"));
1108 }
1109 
TEST_F(ValidateInterfacesTest,VulkanLocationsComponentAfter64BitVec3)1110 TEST_F(ValidateInterfacesTest, VulkanLocationsComponentAfter64BitVec3) {
1111   const std::string text = R"(
1112 OpCapability Shader
1113 OpCapability Float64
1114 OpMemoryModel Logical GLSL450
1115 OpEntryPoint Fragment %main "main" %var
1116 OpExecutionMode %main OriginUpperLeft
1117 OpDecorate %struct Block
1118 OpMemberDecorate %struct 0 Location 0
1119 OpMemberDecorate %struct 1 Location 1
1120 OpMemberDecorate %struct 1 Component 2
1121 %void = OpTypeVoid
1122 %void_fn = OpTypeFunction %void
1123 %float = OpTypeFloat 32
1124 %double = OpTypeFloat 64
1125 %double3 = OpTypeVector %double 3
1126 %struct = OpTypeStruct %double3 %float
1127 %ptr_input_struct = OpTypePointer Input %struct
1128 %var = OpVariable %ptr_input_struct Input
1129 %main = OpFunction %void None %void_fn
1130 %entry = OpLabel
1131 OpReturn
1132 OpFunctionEnd
1133 )";
1134 
1135   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
1136   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
1137 }
1138 
TEST_F(ValidateInterfacesTest,VulkanLocationsConflictingComponentVariable)1139 TEST_F(ValidateInterfacesTest, VulkanLocationsConflictingComponentVariable) {
1140   const std::string text = R"(
1141 OpCapability Shader
1142 OpMemoryModel Logical GLSL450
1143 OpEntryPoint Fragment %main "main" %var
1144 OpExecutionMode %main OriginUpperLeft
1145 OpDecorate %var Location 0
1146 OpDecorate %var Component 0
1147 OpDecorate %var Component 1
1148 %void = OpTypeVoid
1149 %void_fn = OpTypeFunction %void
1150 %float = OpTypeFloat 32
1151 %ptr_input_float = OpTypePointer Input %float
1152 %var = OpVariable %ptr_input_float Input
1153 %main = OpFunction %void None %void_fn
1154 %entry = OpLabel
1155 OpReturn
1156 OpFunctionEnd
1157 )";
1158 
1159   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
1160   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
1161   EXPECT_THAT(getDiagnosticString(),
1162               HasSubstr("Variable has conflicting component decorations"));
1163 }
1164 
TEST_F(ValidateInterfacesTest,VulkanLocationsConflictingComponentStructMember)1165 TEST_F(ValidateInterfacesTest,
1166        VulkanLocationsConflictingComponentStructMember) {
1167   const std::string text = R"(
1168 OpCapability Shader
1169 OpMemoryModel Logical GLSL450
1170 OpEntryPoint Fragment %main "main" %var
1171 OpExecutionMode %main OriginUpperLeft
1172 OpDecorate %struct Block
1173 OpMemberDecorate %struct 0 Location 0
1174 OpMemberDecorate %struct 0 Component 0
1175 OpMemberDecorate %struct 0 Component 1
1176 %void = OpTypeVoid
1177 %void_fn = OpTypeFunction %void
1178 %float = OpTypeFloat 32
1179 %struct = OpTypeStruct %float
1180 %ptr_input_struct = OpTypePointer Input %struct
1181 %var = OpVariable %ptr_input_struct Input
1182 %main = OpFunction %void None %void_fn
1183 %entry = OpLabel
1184 OpReturn
1185 OpFunctionEnd
1186 )";
1187 
1188   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
1189   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
1190   EXPECT_THAT(
1191       getDiagnosticString(),
1192       HasSubstr("Member index 0 has conflicting component assignments"));
1193 }
1194 
TEST_F(ValidateInterfacesTest,VulkanLocationsVariableConflictOutputIndex1)1195 TEST_F(ValidateInterfacesTest, VulkanLocationsVariableConflictOutputIndex1) {
1196   const std::string text = R"(
1197 OpCapability Shader
1198 OpMemoryModel Logical GLSL450
1199 OpEntryPoint Fragment %main "main" %var1 %var2
1200 OpExecutionMode %main OriginUpperLeft
1201 OpDecorate %var1 Location 1
1202 OpDecorate %var1 Index 1
1203 OpDecorate %var2 Location 1
1204 OpDecorate %var2 Index 1
1205 %void = OpTypeVoid
1206 %void_fn = OpTypeFunction %void
1207 %float = OpTypeFloat 32
1208 %struct = OpTypeStruct %float %float
1209 %ptr_output_struct = OpTypePointer Output %struct
1210 %var1 = OpVariable %ptr_output_struct Output
1211 %var2 = OpVariable %ptr_output_struct Output
1212 %main = OpFunction %void None %void_fn
1213 %entry = OpLabel
1214 OpReturn
1215 OpFunctionEnd
1216 )";
1217 
1218   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
1219   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
1220   EXPECT_THAT(getDiagnosticString(),
1221               AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08722"));
1222   EXPECT_THAT(
1223       getDiagnosticString(),
1224       HasSubstr("Entry-point has conflicting output location assignment "
1225                 "at location 1"));
1226 }
1227 
TEST_F(ValidateInterfacesTest,VulkanLocationsVariableNoConflictDifferentIndex)1228 TEST_F(ValidateInterfacesTest,
1229        VulkanLocationsVariableNoConflictDifferentIndex) {
1230   const std::string text = R"(
1231 OpCapability Shader
1232 OpMemoryModel Logical GLSL450
1233 OpEntryPoint Fragment %main "main" %var1 %var2
1234 OpExecutionMode %main OriginUpperLeft
1235 OpDecorate %var1 Location 1
1236 OpDecorate %var1 Index 0
1237 OpDecorate %var2 Location 1
1238 OpDecorate %var2 Index 1
1239 %void = OpTypeVoid
1240 %void_fn = OpTypeFunction %void
1241 %float = OpTypeFloat 32
1242 %struct = OpTypeStruct %float %float
1243 %ptr_output_struct = OpTypePointer Output %struct
1244 %var1 = OpVariable %ptr_output_struct Output
1245 %var2 = OpVariable %ptr_output_struct Output
1246 %main = OpFunction %void None %void_fn
1247 %entry = OpLabel
1248 OpReturn
1249 OpFunctionEnd
1250 )";
1251 
1252   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
1253   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
1254 }
1255 
TEST_F(ValidateInterfacesTest,VulkanLocationsIndexGLCompute)1256 TEST_F(ValidateInterfacesTest, VulkanLocationsIndexGLCompute) {
1257   const std::string text = R"(
1258 OpCapability Shader
1259 OpCapability Geometry
1260 OpMemoryModel Logical GLSL450
1261 OpEntryPoint Geometry %main "main" %var1
1262 OpExecutionMode %main Triangles
1263 OpExecutionMode %main OutputPoints
1264 OpDecorate %var1 Location 1
1265 OpDecorate %var1 Index 1
1266 %void = OpTypeVoid
1267 %void_fn = OpTypeFunction %void
1268 %float = OpTypeFloat 32
1269 %struct = OpTypeStruct %float %float
1270 %ptr_output_struct = OpTypePointer Output %struct
1271 %var1 = OpVariable %ptr_output_struct Output
1272 %main = OpFunction %void None %void_fn
1273 %entry = OpLabel
1274 OpReturn
1275 OpFunctionEnd
1276 )";
1277 
1278   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
1279   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
1280   EXPECT_THAT(
1281       getDiagnosticString(),
1282       HasSubstr("Index can only be applied to Fragment output variables"));
1283 }
1284 
TEST_F(ValidateInterfacesTest,VulkanLocationsIndexInput)1285 TEST_F(ValidateInterfacesTest, VulkanLocationsIndexInput) {
1286   const std::string text = R"(
1287 OpCapability Shader
1288 OpMemoryModel Logical GLSL450
1289 OpEntryPoint Fragment %main "main" %var1
1290 OpExecutionMode %main OriginUpperLeft
1291 OpDecorate %var1 Location 1
1292 OpDecorate %var1 Index 1
1293 %void = OpTypeVoid
1294 %void_fn = OpTypeFunction %void
1295 %float = OpTypeFloat 32
1296 %struct = OpTypeStruct %float %float
1297 %ptr_input_struct = OpTypePointer Input %struct
1298 %var1 = OpVariable %ptr_input_struct Input
1299 %main = OpFunction %void None %void_fn
1300 %entry = OpLabel
1301 OpReturn
1302 OpFunctionEnd
1303 )";
1304 
1305   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
1306   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
1307   EXPECT_THAT(getDiagnosticString(),
1308               HasSubstr("must be in the Output storage class"));
1309 }
1310 
TEST_F(ValidateInterfacesTest,VulkanLocationsArrayWithComponent)1311 TEST_F(ValidateInterfacesTest, VulkanLocationsArrayWithComponent) {
1312   const std::string text = R"(
1313 OpCapability Shader
1314 OpMemoryModel Logical GLSL450
1315 OpEntryPoint Fragment %4 "main" %11 %18 %28 %36 %40
1316 OpExecutionMode %4 OriginUpperLeft
1317 OpDecorate %11 Location 0
1318 OpDecorate %18 Component 0
1319 OpDecorate %18 Location 0
1320 OpDecorate %28 Component 1
1321 OpDecorate %28 Location 0
1322 OpDecorate %36 Location 1
1323 OpDecorate %40 Component 0
1324 OpDecorate %40 Location 1
1325 %void = OpTypeVoid
1326 %3 = OpTypeFunction %void
1327 %float = OpTypeFloat 32
1328 %v4float = OpTypeVector %float 4
1329 %_ptr_Input_v4float = OpTypePointer Input %v4float
1330 %11 = OpVariable %_ptr_Input_v4float Input
1331 %_ptr_Output_float = OpTypePointer Output %float
1332 %18 = OpVariable %_ptr_Output_float Output
1333 %uint = OpTypeInt 32 0
1334 %v3float = OpTypeVector %float 3
1335 %uint_2 = OpConstant %uint 2
1336 %_arr_v3float_uint_2 = OpTypeArray %v3float %uint_2
1337 %_ptr_Output__arr_v3float_uint_2 = OpTypePointer Output %_arr_v3float_uint_2
1338 %28 = OpVariable %_ptr_Output__arr_v3float_uint_2 Output
1339 %_ptr_Output_v3float = OpTypePointer Output %v3float
1340 %36 = OpVariable %_ptr_Input_v4float Input
1341 %40 = OpVariable %_ptr_Output_float Output
1342 %4 = OpFunction %void None %3
1343 %5 = OpLabel
1344 OpReturn
1345 OpFunctionEnd
1346 )";
1347 
1348   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
1349   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
1350 }
1351 
TEST_F(ValidateInterfacesTest,VulkanLocationsArrayWithComponentBad)1352 TEST_F(ValidateInterfacesTest, VulkanLocationsArrayWithComponentBad) {
1353   const std::string text = R"(
1354 OpCapability Shader
1355 OpMemoryModel Logical GLSL450
1356 OpEntryPoint Fragment %4 "main" %11 %18 %28 %36 %40
1357 OpExecutionMode %4 OriginUpperLeft
1358 OpDecorate %11 Location 0
1359 OpDecorate %18 Component 0
1360 OpDecorate %18 Location 0
1361 OpDecorate %28 Component 1
1362 OpDecorate %28 Location 0
1363 OpDecorate %36 Location 1
1364 OpDecorate %40 Component 1
1365 OpDecorate %40 Location 1
1366 %void = OpTypeVoid
1367 %3 = OpTypeFunction %void
1368 %float = OpTypeFloat 32
1369 %v4float = OpTypeVector %float 4
1370 %_ptr_Input_v4float = OpTypePointer Input %v4float
1371 %11 = OpVariable %_ptr_Input_v4float Input
1372 %_ptr_Output_float = OpTypePointer Output %float
1373 %18 = OpVariable %_ptr_Output_float Output
1374 %uint = OpTypeInt 32 0
1375 %v3float = OpTypeVector %float 3
1376 %uint_2 = OpConstant %uint 2
1377 %_arr_v3float_uint_2 = OpTypeArray %v3float %uint_2
1378 %_ptr_Output__arr_v3float_uint_2 = OpTypePointer Output %_arr_v3float_uint_2
1379 %28 = OpVariable %_ptr_Output__arr_v3float_uint_2 Output
1380 %_ptr_Output_v3float = OpTypePointer Output %v3float
1381 %36 = OpVariable %_ptr_Input_v4float Input
1382 %40 = OpVariable %_ptr_Output_float Output
1383 %4 = OpFunction %void None %3
1384 %5 = OpLabel
1385 OpReturn
1386 OpFunctionEnd
1387 )";
1388 
1389   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
1390   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
1391   EXPECT_THAT(getDiagnosticString(),
1392               AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08722"));
1393   EXPECT_THAT(getDiagnosticString(),
1394               HasSubstr("Entry-point has conflicting output location "
1395                         "assignment at location 1, component 1"));
1396 }
1397 
TEST_F(ValidateInterfacesTest,VulkanLocationsLargeLocation)1398 TEST_F(ValidateInterfacesTest, VulkanLocationsLargeLocation) {
1399   const std::string text = R"(
1400                OpCapability Shader
1401                OpMemoryModel Logical GLSL450
1402                OpEntryPoint Fragment %4 "????????" %17
1403                OpExecutionMode %4 OriginUpperLeft
1404                OpDecorate %17 Location 4227868160
1405        %void = OpTypeVoid
1406           %3 = OpTypeFunction %void
1407       %float = OpTypeFloat 32
1408     %v3float = OpTypeVector %float 3
1409 %_ptr_Input_v3float = OpTypePointer Input %v3float
1410          %17 = OpVariable %_ptr_Input_v3float Input
1411           %4 = OpFunction %void None %3
1412           %5 = OpLabel
1413                OpUnreachable
1414                OpFunctionEnd
1415 )";
1416 
1417   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
1418   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
1419 }
1420 
TEST_F(ValidateInterfacesTest,VulkanLocationMeshShader)1421 TEST_F(ValidateInterfacesTest, VulkanLocationMeshShader) {
1422   const std::string text = R"(
1423 OpCapability Shader
1424 OpCapability MeshShadingNV
1425 OpExtension "SPV_NV_mesh_shader"
1426 OpMemoryModel Logical GLSL450
1427 OpEntryPoint MeshNV %foo "foo" %in
1428 OpExecutionMode %foo LocalSize 1 1 1
1429 OpDecorate %block Block
1430 OpMemberDecorate %block 0 PerTaskNV
1431 OpMemberDecorate %block 0 Offset 0
1432 %void = OpTypeVoid
1433 %int = OpTypeInt 32 0
1434 %int_32 = OpConstant %int 32
1435 %array = OpTypeArray %int %int_32
1436 %block = OpTypeStruct %array
1437 %ptr_input_block = OpTypePointer Input %block
1438 %in = OpVariable %ptr_input_block Input
1439 %void_fn = OpTypeFunction %void
1440 %foo = OpFunction %void None %void_fn
1441 %entry = OpLabel
1442 OpReturn
1443 OpFunctionEnd
1444 )";
1445 
1446   CompileSuccessfully(text, SPV_ENV_VULKAN_1_2);
1447   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2));
1448 }
1449 
TEST_F(ValidateInterfacesTest,VulkanLocationArrayWithComponent1)1450 TEST_F(ValidateInterfacesTest, VulkanLocationArrayWithComponent1) {
1451   const std::string text = R"(
1452 OpCapability Shader
1453 OpMemoryModel Logical GLSL450
1454 OpEntryPoint Fragment %main "main" %in
1455 OpExecutionMode %main OriginUpperLeft
1456 OpDecorate %struct Block
1457 OpMemberDecorate %struct 0 Location 0
1458 OpMemberDecorate %struct 0 Component 0
1459 OpMemberDecorate %struct 1 Location 0
1460 OpMemberDecorate %struct 1 Component 1
1461 %void = OpTypeVoid
1462 %void_fn = OpTypeFunction %void
1463 %float = OpTypeFloat 32
1464 %int = OpTypeInt 32 0
1465 %int_2 = OpConstant %int 2
1466 %float_arr = OpTypeArray %float %int_2
1467 %struct = OpTypeStruct %float_arr %float_arr
1468 %ptr = OpTypePointer Input %struct
1469 %in = OpVariable %ptr Input
1470 %main = OpFunction %void None %void_fn
1471 %entry = OpLabel
1472 OpReturn
1473 OpFunctionEnd
1474 )";
1475 
1476   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
1477   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
1478 }
1479 
TEST_F(ValidateInterfacesTest,VulkanLocationArrayWithComponent2)1480 TEST_F(ValidateInterfacesTest, VulkanLocationArrayWithComponent2) {
1481   const std::string text = R"(
1482 OpCapability Shader
1483 OpCapability Float64
1484 OpMemoryModel Logical GLSL450
1485 OpEntryPoint Fragment %main "main" %in
1486 OpExecutionMode %main OriginUpperLeft
1487 OpDecorate %struct Block
1488 OpMemberDecorate %struct 0 Location 0
1489 OpMemberDecorate %struct 0 Component 0
1490 OpMemberDecorate %struct 1 Location 0
1491 OpMemberDecorate %struct 1 Component 2
1492 %void = OpTypeVoid
1493 %void_fn = OpTypeFunction %void
1494 %float = OpTypeFloat 32
1495 %double = OpTypeFloat 64
1496 %int = OpTypeInt 32 0
1497 %int_2 = OpConstant %int 2
1498 %double_arr = OpTypeArray %double %int_2
1499 %struct = OpTypeStruct %float %double_arr
1500 %ptr = OpTypePointer Input %struct
1501 %in = OpVariable %ptr Input
1502 %main = OpFunction %void None %void_fn
1503 %entry = OpLabel
1504 OpReturn
1505 OpFunctionEnd
1506 )";
1507 
1508   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
1509   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
1510 }
1511 
TEST_F(ValidateInterfacesTest,DuplicateInterfaceVariableSuccess)1512 TEST_F(ValidateInterfacesTest, DuplicateInterfaceVariableSuccess) {
1513   const std::string text = R"(
1514 OpCapability Shader
1515 OpMemoryModel Logical GLSL450
1516 OpEntryPoint Fragment %main "main" %in %out %in
1517 OpExecutionMode %main OriginUpperLeft
1518 OpDecorate %in Location 0
1519 OpDecorate %out Location 0
1520 %void = OpTypeVoid
1521 %float = OpTypeFloat 32
1522 %in_ptr = OpTypePointer Input %float
1523 %out_ptr = OpTypePointer Output %float
1524 %in = OpVariable %in_ptr Input
1525 %out = OpVariable %out_ptr Output
1526 %void_fn = OpTypeFunction %void
1527 %main = OpFunction %void None %void_fn
1528 %entry = OpLabel
1529 OpReturn
1530 OpFunctionEnd
1531 )";
1532 
1533   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
1534   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
1535 }
1536 
TEST_F(ValidateInterfacesTest,StructWithBuiltinsMissingBlock_Bad)1537 TEST_F(ValidateInterfacesTest, StructWithBuiltinsMissingBlock_Bad) {
1538   // See https://github.com/KhronosGroup/SPIRV-Registry/issues/134
1539   //
1540   // When a shader input or output is a struct that does not have Block,
1541   // then it must have a Location.
1542   // But BuiltIns must not have locations.
1543   const std::string text = R"(
1544 OpCapability Shader
1545 OpMemoryModel Logical GLSL450
1546 OpEntryPoint Fragment %main "main" %in
1547 OpExecutionMode %main OriginUpperLeft
1548 ; %struct needs a Block decoration
1549 OpMemberDecorate %struct 0 BuiltIn Position
1550 %void = OpTypeVoid
1551 %float = OpTypeFloat 32
1552 %v4float = OpTypeVector %float 4
1553 %struct = OpTypeStruct %v4float
1554 %in_ptr = OpTypePointer Input %struct
1555 %in = OpVariable %in_ptr Input
1556 %void_fn = OpTypeFunction %void
1557 %main = OpFunction %void None %void_fn
1558 %entry = OpLabel
1559 OpReturn
1560 OpFunctionEnd
1561 )";
1562 
1563   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
1564   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
1565   EXPECT_THAT(getDiagnosticString(),
1566               AnyVUID("VUID-StandaloneSpirv-Location-04919"));
1567   EXPECT_THAT(
1568       getDiagnosticString(),
1569       HasSubstr(
1570           "Interface struct has no Block decoration but has BuiltIn members."));
1571 }
1572 
TEST_F(ValidateInterfacesTest,InvalidLocationTypePointer)1573 TEST_F(ValidateInterfacesTest, InvalidLocationTypePointer) {
1574   const std::string text = R"(
1575                OpCapability Shader
1576                OpMemoryModel Logical Simple
1577                OpEntryPoint Vertex %1 "Aiqn0" %2 %3
1578                OpDecorate %2 Location 0
1579        %void = OpTypeVoid
1580           %5 = OpTypeFunction %void
1581       %float = OpTypeFloat 32
1582 %_ptr_Private_void = OpTypePointer Private %void
1583        %uint = OpTypeInt 32 0
1584 %uint_4278132784 = OpConstant %uint 4278132784
1585 %_arr__ptr_Private_void_uint_4278132784 = OpTypeArray %_ptr_Private_void %uint_4278132784
1586 %_ptr_Output__arr__ptr_Private_void_uint_4278132784 = OpTypePointer Output %_arr__ptr_Private_void_uint_4278132784
1587           %2 = OpVariable %_ptr_Output__arr__ptr_Private_void_uint_4278132784 Output
1588 %_ptr_Output__ptr_Private_void = OpTypePointer Output %_ptr_Private_void
1589           %3 = OpVariable %_ptr_Output__arr__ptr_Private_void_uint_4278132784 Output
1590           %1 = OpFunction %void None %5
1591          %15 = OpLabel
1592                OpReturn
1593                OpFunctionEnd
1594 )";
1595 
1596   CompileSuccessfully(text, SPV_ENV_VULKAN_1_1);
1597   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_1));
1598   EXPECT_THAT(getDiagnosticString(),
1599               HasSubstr("Invalid type to assign a location"));
1600 }
1601 
TEST_F(ValidateInterfacesTest,ValidLocationTypePhysicalStorageBufferPointer)1602 TEST_F(ValidateInterfacesTest, ValidLocationTypePhysicalStorageBufferPointer) {
1603   const std::string text = R"(
1604 OpCapability Shader
1605 OpCapability PhysicalStorageBufferAddresses
1606 OpMemoryModel PhysicalStorageBuffer64 GLSL450
1607 OpEntryPoint Vertex %main "main" %var
1608 OpDecorate %var Location 0
1609 OpDecorate %var RestrictPointer
1610 %void = OpTypeVoid
1611 %int = OpTypeInt 32 0
1612 %ptr = OpTypePointer PhysicalStorageBuffer %int
1613 %ptr2 = OpTypePointer Input %ptr
1614 %var = OpVariable %ptr2 Input
1615 %void_fn = OpTypeFunction %void
1616 %main = OpFunction %void None %void_fn
1617 %entry = OpLabel
1618 OpReturn
1619 OpFunctionEnd
1620 )";
1621   CompileSuccessfully(text, SPV_ENV_VULKAN_1_3);
1622   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_3));
1623 }
1624 
1625 }  // namespace
1626 }  // namespace val
1627 }  // namespace spvtools
1628