• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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               HasSubstr("Entry-point has conflicting input location assignment "
588                         "at location 0"));
589 }
590 
TEST_F(ValidateInterfacesTest,VulkanLocationsVariableConflictOutput)591 TEST_F(ValidateInterfacesTest, VulkanLocationsVariableConflictOutput) {
592   const std::string text = R"(
593 OpCapability Shader
594 OpMemoryModel Logical GLSL450
595 OpEntryPoint Fragment %main "main" %var1 %var2
596 OpExecutionMode %main OriginUpperLeft
597 OpDecorate %var1 Location 1
598 OpDecorate %var2 Location 1
599 %void = OpTypeVoid
600 %void_fn = OpTypeFunction %void
601 %float = OpTypeFloat 32
602 %struct = OpTypeStruct %float %float
603 %ptr_output_struct = OpTypePointer Output %struct
604 %var1 = OpVariable %ptr_output_struct Output
605 %var2 = OpVariable %ptr_output_struct Output
606 %main = OpFunction %void None %void_fn
607 %entry = OpLabel
608 OpReturn
609 OpFunctionEnd
610 )";
611 
612   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
613   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
614   EXPECT_THAT(
615       getDiagnosticString(),
616       HasSubstr("Entry-point has conflicting output location assignment "
617                 "at location 1"));
618 }
619 
TEST_F(ValidateInterfacesTest,VulkanLocationsSameLocationInputAndOutputNoConflict)620 TEST_F(ValidateInterfacesTest,
621        VulkanLocationsSameLocationInputAndOutputNoConflict) {
622   const std::string text = R"(
623 OpCapability Shader
624 OpMemoryModel Logical GLSL450
625 OpEntryPoint Fragment %main "main" %var1 %var2
626 OpExecutionMode %main OriginUpperLeft
627 OpDecorate %var1 Location 1
628 OpDecorate %var2 Location 1
629 %void = OpTypeVoid
630 %void_fn = OpTypeFunction %void
631 %float = OpTypeFloat 32
632 %struct = OpTypeStruct %float %float
633 %ptr_input_struct = OpTypePointer Input %struct
634 %ptr_output_struct = OpTypePointer Output %struct
635 %var1 = OpVariable %ptr_input_struct Input
636 %var2 = OpVariable %ptr_output_struct Output
637 %main = OpFunction %void None %void_fn
638 %entry = OpLabel
639 OpReturn
640 OpFunctionEnd
641 )";
642 
643   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
644   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
645 }
646 
TEST_F(ValidateInterfacesTest,VulkanLocationsVariableInGap)647 TEST_F(ValidateInterfacesTest, VulkanLocationsVariableInGap) {
648   const std::string text = R"(
649 OpCapability Shader
650 OpMemoryModel Logical GLSL450
651 OpEntryPoint Fragment %main "main" %var1 %var2
652 OpExecutionMode %main OriginUpperLeft
653 OpDecorate %struct Block
654 OpMemberDecorate %struct 0 Location 0
655 OpMemberDecorate %struct 1 Location 2
656 OpDecorate %var2 Location 1
657 %void = OpTypeVoid
658 %void_fn = OpTypeFunction %void
659 %float = OpTypeFloat 32
660 %struct = OpTypeStruct %float %float
661 %ptr_input_struct = OpTypePointer Input %struct
662 %ptr_input_float = OpTypePointer Input %float
663 %var1 = OpVariable %ptr_input_struct Input
664 %var2 = OpVariable %ptr_input_float Input
665 %main = OpFunction %void None %void_fn
666 %entry = OpLabel
667 OpReturn
668 OpFunctionEnd
669 )";
670 
671   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
672   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
673 }
674 
TEST_F(ValidateInterfacesTest,VulkanLocationsLargeFloatVectorConflict)675 TEST_F(ValidateInterfacesTest, VulkanLocationsLargeFloatVectorConflict) {
676   const std::string text = R"(
677 OpCapability Shader
678 OpCapability Float64
679 OpMemoryModel Logical GLSL450
680 OpEntryPoint Fragment %main "main" %var1 %var2
681 OpExecutionMode %main OriginUpperLeft
682 OpDecorate %var1 Location 0
683 OpDecorate %var2 Location 1
684 %void = OpTypeVoid
685 %void_fn = OpTypeFunction %void
686 %float = OpTypeFloat 32
687 %double = OpTypeFloat 64
688 %vector = OpTypeVector %double 3
689 %ptr_input_float = OpTypePointer Input %float
690 %ptr_input_vector = OpTypePointer Input %vector
691 %var1 = OpVariable %ptr_input_vector Input
692 %var2 = OpVariable %ptr_input_float Input
693 %main = OpFunction %void None %void_fn
694 %entry = OpLabel
695 OpReturn
696 OpFunctionEnd
697 )";
698 
699   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
700   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
701   EXPECT_THAT(getDiagnosticString(),
702               HasSubstr("Entry-point has conflicting input location assignment "
703                         "at location 1"));
704 }
705 
TEST_F(ValidateInterfacesTest,VulkanLocationsLargeIntVectorConflict)706 TEST_F(ValidateInterfacesTest, VulkanLocationsLargeIntVectorConflict) {
707   const std::string text = R"(
708 OpCapability Shader
709 OpCapability Int64
710 OpMemoryModel Logical GLSL450
711 OpEntryPoint Fragment %main "main" %var1 %var2
712 OpExecutionMode %main OriginUpperLeft
713 OpDecorate %var1 Location 0
714 OpDecorate %var2 Location 1
715 %void = OpTypeVoid
716 %void_fn = OpTypeFunction %void
717 %float = OpTypeFloat 32
718 %long = OpTypeInt 64 0
719 %vector = OpTypeVector %long 4
720 %ptr_input_float = OpTypePointer Input %float
721 %ptr_input_vector = OpTypePointer Input %vector
722 %var1 = OpVariable %ptr_input_vector Input
723 %var2 = OpVariable %ptr_input_float Input
724 %main = OpFunction %void None %void_fn
725 %entry = OpLabel
726 OpReturn
727 OpFunctionEnd
728 )";
729 
730   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
731   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
732   EXPECT_THAT(getDiagnosticString(),
733               HasSubstr("Entry-point has conflicting input location assignment "
734                         "at location 1"));
735 }
736 
TEST_F(ValidateInterfacesTest,VulkanLocationsMatrix2x2Conflict)737 TEST_F(ValidateInterfacesTest, VulkanLocationsMatrix2x2Conflict) {
738   const std::string text = R"(
739 OpCapability Shader
740 OpMemoryModel Logical GLSL450
741 OpEntryPoint Fragment %main "main" %var1 %var2
742 OpExecutionMode %main OriginUpperLeft
743 OpDecorate %var1 Location 0
744 OpDecorate %var2 Location 1
745 %void = OpTypeVoid
746 %void_fn = OpTypeFunction %void
747 %float = OpTypeFloat 32
748 %vector = OpTypeVector %float 2
749 %matrix = OpTypeMatrix %vector 2
750 %ptr_input_float = OpTypePointer Input %float
751 %ptr_input_matrix = OpTypePointer Input %matrix
752 %var1 = OpVariable %ptr_input_matrix Input
753 %var2 = OpVariable %ptr_input_float Input
754 %main = OpFunction %void None %void_fn
755 %entry = OpLabel
756 OpReturn
757 OpFunctionEnd
758 )";
759 
760   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
761   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
762   EXPECT_THAT(getDiagnosticString(),
763               HasSubstr("Entry-point has conflicting input location assignment "
764                         "at location 1"));
765 }
766 
TEST_F(ValidateInterfacesTest,VulkanLocationsMatrix3x3Conflict)767 TEST_F(ValidateInterfacesTest, VulkanLocationsMatrix3x3Conflict) {
768   const std::string text = R"(
769 OpCapability Shader
770 OpMemoryModel Logical GLSL450
771 OpEntryPoint Fragment %main "main" %var1 %var2
772 OpExecutionMode %main OriginUpperLeft
773 OpDecorate %var1 Location 0
774 OpDecorate %var2 Location 2
775 %void = OpTypeVoid
776 %void_fn = OpTypeFunction %void
777 %float = OpTypeFloat 32
778 %vector = OpTypeVector %float 3
779 %matrix = OpTypeMatrix %vector 3
780 %ptr_input_float = OpTypePointer Input %float
781 %ptr_input_matrix = OpTypePointer Input %matrix
782 %var1 = OpVariable %ptr_input_matrix Input
783 %var2 = OpVariable %ptr_input_float Input
784 %main = OpFunction %void None %void_fn
785 %entry = OpLabel
786 OpReturn
787 OpFunctionEnd
788 )";
789 
790   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
791   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
792   EXPECT_THAT(getDiagnosticString(),
793               HasSubstr("Entry-point has conflicting input location assignment "
794                         "at location 2"));
795 }
796 
TEST_F(ValidateInterfacesTest,VulkanLocationsMatrix4x4Conflict)797 TEST_F(ValidateInterfacesTest, VulkanLocationsMatrix4x4Conflict) {
798   const std::string text = R"(
799 OpCapability Shader
800 OpMemoryModel Logical GLSL450
801 OpEntryPoint Fragment %main "main" %var1 %var2
802 OpExecutionMode %main OriginUpperLeft
803 OpDecorate %var1 Location 0
804 OpDecorate %var2 Location 3
805 %void = OpTypeVoid
806 %void_fn = OpTypeFunction %void
807 %float = OpTypeFloat 32
808 %vector = OpTypeVector %float 4
809 %matrix = OpTypeMatrix %vector 4
810 %ptr_input_float = OpTypePointer Input %float
811 %ptr_input_matrix = OpTypePointer Input %matrix
812 %var1 = OpVariable %ptr_input_matrix Input
813 %var2 = OpVariable %ptr_input_float Input
814 %main = OpFunction %void None %void_fn
815 %entry = OpLabel
816 OpReturn
817 OpFunctionEnd
818 )";
819 
820   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
821   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
822   EXPECT_THAT(getDiagnosticString(),
823               HasSubstr("Entry-point has conflicting input location assignment "
824                         "at location 3"));
825 }
826 
TEST_F(ValidateInterfacesTest,VulkanLocationsLargeMatrix2x2Conflict)827 TEST_F(ValidateInterfacesTest, VulkanLocationsLargeMatrix2x2Conflict) {
828   const std::string text = R"(
829 OpCapability Shader
830 OpCapability Float64
831 OpMemoryModel Logical GLSL450
832 OpEntryPoint Fragment %main "main" %var1 %var2
833 OpExecutionMode %main OriginUpperLeft
834 OpDecorate %var1 Location 0
835 OpDecorate %var2 Location 1
836 %void = OpTypeVoid
837 %void_fn = OpTypeFunction %void
838 %float = OpTypeFloat 32
839 %double = OpTypeFloat 64
840 %vector = OpTypeVector %double 2
841 %matrix = OpTypeMatrix %vector 2
842 %ptr_input_float = OpTypePointer Input %float
843 %ptr_input_matrix = OpTypePointer Input %matrix
844 %var1 = OpVariable %ptr_input_matrix Input
845 %var2 = OpVariable %ptr_input_float Input
846 %main = OpFunction %void None %void_fn
847 %entry = OpLabel
848 OpReturn
849 OpFunctionEnd
850 )";
851 
852   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
853   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
854   EXPECT_THAT(getDiagnosticString(),
855               HasSubstr("Entry-point has conflicting input location assignment "
856                         "at location 1"));
857 }
858 
TEST_F(ValidateInterfacesTest,VulkanLocationsLargeMatrix3x3Conflict)859 TEST_F(ValidateInterfacesTest, VulkanLocationsLargeMatrix3x3Conflict) {
860   const std::string text = R"(
861 OpCapability Shader
862 OpCapability Float64
863 OpMemoryModel Logical GLSL450
864 OpEntryPoint Fragment %main "main" %var1 %var2
865 OpExecutionMode %main OriginUpperLeft
866 OpDecorate %var1 Location 0
867 OpDecorate %var2 Location 5
868 %void = OpTypeVoid
869 %void_fn = OpTypeFunction %void
870 %float = OpTypeFloat 32
871 %double = OpTypeFloat 64
872 %vector = OpTypeVector %double 3
873 %matrix = OpTypeMatrix %vector 3
874 %ptr_input_float = OpTypePointer Input %float
875 %ptr_input_matrix = OpTypePointer Input %matrix
876 %var1 = OpVariable %ptr_input_matrix Input
877 %var2 = OpVariable %ptr_input_float Input
878 %main = OpFunction %void None %void_fn
879 %entry = OpLabel
880 OpReturn
881 OpFunctionEnd
882 )";
883 
884   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
885   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
886   EXPECT_THAT(getDiagnosticString(),
887               HasSubstr("Entry-point has conflicting input location assignment "
888                         "at location 5"));
889 }
890 
TEST_F(ValidateInterfacesTest,VulkanLocationsLargeMatrix4x4Conflict)891 TEST_F(ValidateInterfacesTest, VulkanLocationsLargeMatrix4x4Conflict) {
892   const std::string text = R"(
893 OpCapability Shader
894 OpCapability Float64
895 OpMemoryModel Logical GLSL450
896 OpEntryPoint Fragment %main "main" %var1 %var2
897 OpExecutionMode %main OriginUpperLeft
898 OpDecorate %var1 Location 0
899 OpDecorate %var2 Location 7
900 %void = OpTypeVoid
901 %void_fn = OpTypeFunction %void
902 %float = OpTypeFloat 32
903 %double = OpTypeFloat 64
904 %vector = OpTypeVector %double 4
905 %matrix = OpTypeMatrix %vector 4
906 %ptr_input_float = OpTypePointer Input %float
907 %ptr_input_matrix = OpTypePointer Input %matrix
908 %var1 = OpVariable %ptr_input_matrix Input
909 %var2 = OpVariable %ptr_input_float Input
910 %main = OpFunction %void None %void_fn
911 %entry = OpLabel
912 OpReturn
913 OpFunctionEnd
914 )";
915 
916   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
917   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
918   EXPECT_THAT(getDiagnosticString(),
919               HasSubstr("Entry-point has conflicting input location assignment "
920                         "at location 7"));
921 }
922 
TEST_F(ValidateInterfacesTest,VulkanLocationsArray2Conflict)923 TEST_F(ValidateInterfacesTest, VulkanLocationsArray2Conflict) {
924   const std::string text = R"(
925 OpCapability Shader
926 OpMemoryModel Logical GLSL450
927 OpEntryPoint Fragment %main "main" %var1 %var2
928 OpExecutionMode %main OriginUpperLeft
929 OpDecorate %var1 Location 0
930 OpDecorate %var2 Location 1
931 %void = OpTypeVoid
932 %void_fn = OpTypeFunction %void
933 %float = OpTypeFloat 32
934 %int = OpTypeInt 32 0
935 %int_2 = OpConstant %int 2
936 %array = OpTypeArray %int %int_2
937 %struct = OpTypeStruct %array
938 %ptr_input_float = OpTypePointer Input %float
939 %ptr_input_struct = OpTypePointer Input %struct
940 %var1 = OpVariable %ptr_input_struct Input
941 %var2 = OpVariable %ptr_input_float Input
942 %main = OpFunction %void None %void_fn
943 %entry = OpLabel
944 OpReturn
945 OpFunctionEnd
946 )";
947 
948   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
949   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
950   EXPECT_THAT(getDiagnosticString(),
951               HasSubstr("Entry-point has conflicting input location assignment "
952                         "at location 1"));
953 }
954 
TEST_F(ValidateInterfacesTest,VulkanLocationsArray4Conflict)955 TEST_F(ValidateInterfacesTest, VulkanLocationsArray4Conflict) {
956   const std::string text = R"(
957 OpCapability Shader
958 OpMemoryModel Logical GLSL450
959 OpEntryPoint Fragment %main "main" %var1 %var2
960 OpExecutionMode %main OriginUpperLeft
961 OpDecorate %var1 Location 0
962 OpDecorate %var2 Location 3
963 %void = OpTypeVoid
964 %void_fn = OpTypeFunction %void
965 %float = OpTypeFloat 32
966 %int = OpTypeInt 32 0
967 %int_4 = OpConstant %int 4
968 %array = OpTypeArray %int %int_4
969 %struct = OpTypeStruct %array
970 %ptr_input_float = OpTypePointer Input %float
971 %ptr_input_struct = OpTypePointer Input %struct
972 %var1 = OpVariable %ptr_input_struct Input
973 %var2 = OpVariable %ptr_input_float Input
974 %main = OpFunction %void None %void_fn
975 %entry = OpLabel
976 OpReturn
977 OpFunctionEnd
978 )";
979 
980   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
981   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
982   EXPECT_THAT(getDiagnosticString(),
983               HasSubstr("Entry-point has conflicting input location assignment "
984                         "at location 3"));
985 }
986 
TEST_F(ValidateInterfacesTest,VulkanLocationsMatrix4x4Array4Conflict)987 TEST_F(ValidateInterfacesTest, VulkanLocationsMatrix4x4Array4Conflict) {
988   const std::string text = R"(
989 OpCapability Shader
990 OpMemoryModel Logical GLSL450
991 OpEntryPoint Fragment %main "main" %var1 %var2
992 OpExecutionMode %main OriginUpperLeft
993 OpDecorate %var1 Location 0
994 OpDecorate %var2 Location 15
995 %void = OpTypeVoid
996 %void_fn = OpTypeFunction %void
997 %float = OpTypeFloat 32
998 %int = OpTypeInt 32 0
999 %int_4 = OpConstant %int 4
1000 %vector = OpTypeVector %float 4
1001 %matrix = OpTypeMatrix %vector 4
1002 %array = OpTypeArray %matrix %int_4
1003 %struct = OpTypeStruct %array
1004 %ptr_input_float = OpTypePointer Input %float
1005 %ptr_input_struct = OpTypePointer Input %struct
1006 %var1 = OpVariable %ptr_input_struct Input
1007 %var2 = OpVariable %ptr_input_float Input
1008 %main = OpFunction %void None %void_fn
1009 %entry = OpLabel
1010 OpReturn
1011 OpFunctionEnd
1012 )";
1013 
1014   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
1015   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
1016   EXPECT_THAT(getDiagnosticString(),
1017               HasSubstr("Entry-point has conflicting input location assignment "
1018                         "at location 15"));
1019 }
1020 
TEST_F(ValidateInterfacesTest,VulkanLocationsComponentDisambiguates)1021 TEST_F(ValidateInterfacesTest, VulkanLocationsComponentDisambiguates) {
1022   const std::string text = R"(
1023 OpCapability Shader
1024 OpMemoryModel Logical GLSL450
1025 OpEntryPoint Fragment %main "main" %var1
1026 OpExecutionMode %main OriginUpperLeft
1027 OpDecorate %struct Block
1028 OpMemberDecorate %struct 0 Location 0
1029 OpMemberDecorate %struct 0 Component 0
1030 OpMemberDecorate %struct 1 Location 0
1031 OpMemberDecorate %struct 1 Component 1
1032 %void = OpTypeVoid
1033 %void_fn = OpTypeFunction %void
1034 %float = OpTypeFloat 32
1035 %struct = OpTypeStruct %float %float
1036 %ptr_input_struct = OpTypePointer Input %struct
1037 %var1 = OpVariable %ptr_input_struct Input
1038 %main = OpFunction %void None %void_fn
1039 %entry = OpLabel
1040 OpReturn
1041 OpFunctionEnd
1042 )";
1043 
1044   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
1045   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
1046 }
1047 
TEST_F(ValidateInterfacesTest,VulkanLocationsComponentIn64BitVec3)1048 TEST_F(ValidateInterfacesTest, VulkanLocationsComponentIn64BitVec3) {
1049   const std::string text = R"(
1050 OpCapability Shader
1051 OpCapability Float64
1052 OpMemoryModel Logical GLSL450
1053 OpEntryPoint Fragment %main "main" %var
1054 OpExecutionMode %main OriginUpperLeft
1055 OpDecorate %struct Block
1056 OpMemberDecorate %struct 0 Location 0
1057 OpMemberDecorate %struct 1 Location 1
1058 OpMemberDecorate %struct 1 Component 1
1059 %void = OpTypeVoid
1060 %void_fn = OpTypeFunction %void
1061 %float = OpTypeFloat 32
1062 %double = OpTypeFloat 64
1063 %double3 = OpTypeVector %double 3
1064 %struct = OpTypeStruct %double3 %float
1065 %ptr_input_struct = OpTypePointer Input %struct
1066 %var = OpVariable %ptr_input_struct Input
1067 %main = OpFunction %void None %void_fn
1068 %entry = OpLabel
1069 OpReturn
1070 OpFunctionEnd
1071 )";
1072 
1073   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
1074   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
1075   EXPECT_THAT(getDiagnosticString(),
1076               HasSubstr("Entry-point has conflicting input location assignment "
1077                         "at location 1, component 1"));
1078 }
1079 
TEST_F(ValidateInterfacesTest,VulkanLocationsComponentAfter64BitVec3)1080 TEST_F(ValidateInterfacesTest, VulkanLocationsComponentAfter64BitVec3) {
1081   const std::string text = R"(
1082 OpCapability Shader
1083 OpCapability Float64
1084 OpMemoryModel Logical GLSL450
1085 OpEntryPoint Fragment %main "main" %var
1086 OpExecutionMode %main OriginUpperLeft
1087 OpDecorate %struct Block
1088 OpMemberDecorate %struct 0 Location 0
1089 OpMemberDecorate %struct 1 Location 1
1090 OpMemberDecorate %struct 1 Component 2
1091 %void = OpTypeVoid
1092 %void_fn = OpTypeFunction %void
1093 %float = OpTypeFloat 32
1094 %double = OpTypeFloat 64
1095 %double3 = OpTypeVector %double 3
1096 %struct = OpTypeStruct %double3 %float
1097 %ptr_input_struct = OpTypePointer Input %struct
1098 %var = OpVariable %ptr_input_struct Input
1099 %main = OpFunction %void None %void_fn
1100 %entry = OpLabel
1101 OpReturn
1102 OpFunctionEnd
1103 )";
1104 
1105   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
1106   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
1107 }
1108 
TEST_F(ValidateInterfacesTest,VulkanLocationsConflictingComponentVariable)1109 TEST_F(ValidateInterfacesTest, VulkanLocationsConflictingComponentVariable) {
1110   const std::string text = R"(
1111 OpCapability Shader
1112 OpMemoryModel Logical GLSL450
1113 OpEntryPoint Fragment %main "main" %var
1114 OpExecutionMode %main OriginUpperLeft
1115 OpDecorate %var Location 0
1116 OpDecorate %var Component 0
1117 OpDecorate %var Component 1
1118 %void = OpTypeVoid
1119 %void_fn = OpTypeFunction %void
1120 %float = OpTypeFloat 32
1121 %ptr_input_float = OpTypePointer Input %float
1122 %var = OpVariable %ptr_input_float Input
1123 %main = OpFunction %void None %void_fn
1124 %entry = OpLabel
1125 OpReturn
1126 OpFunctionEnd
1127 )";
1128 
1129   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
1130   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
1131   EXPECT_THAT(getDiagnosticString(),
1132               HasSubstr("Variable has conflicting component decorations"));
1133 }
1134 
TEST_F(ValidateInterfacesTest,VulkanLocationsConflictingComponentStructMember)1135 TEST_F(ValidateInterfacesTest,
1136        VulkanLocationsConflictingComponentStructMember) {
1137   const std::string text = R"(
1138 OpCapability Shader
1139 OpMemoryModel Logical GLSL450
1140 OpEntryPoint Fragment %main "main" %var
1141 OpExecutionMode %main OriginUpperLeft
1142 OpDecorate %struct Block
1143 OpMemberDecorate %struct 0 Location 0
1144 OpMemberDecorate %struct 0 Component 0
1145 OpMemberDecorate %struct 0 Component 1
1146 %void = OpTypeVoid
1147 %void_fn = OpTypeFunction %void
1148 %float = OpTypeFloat 32
1149 %struct = OpTypeStruct %float
1150 %ptr_input_struct = OpTypePointer Input %struct
1151 %var = OpVariable %ptr_input_struct Input
1152 %main = OpFunction %void None %void_fn
1153 %entry = OpLabel
1154 OpReturn
1155 OpFunctionEnd
1156 )";
1157 
1158   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
1159   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
1160   EXPECT_THAT(
1161       getDiagnosticString(),
1162       HasSubstr("Member index 0 has conflicting component assignments"));
1163 }
1164 
TEST_F(ValidateInterfacesTest,VulkanLocationsVariableConflictOutputIndex1)1165 TEST_F(ValidateInterfacesTest, VulkanLocationsVariableConflictOutputIndex1) {
1166   const std::string text = R"(
1167 OpCapability Shader
1168 OpMemoryModel Logical GLSL450
1169 OpEntryPoint Fragment %main "main" %var1 %var2
1170 OpExecutionMode %main OriginUpperLeft
1171 OpDecorate %var1 Location 1
1172 OpDecorate %var1 Index 1
1173 OpDecorate %var2 Location 1
1174 OpDecorate %var2 Index 1
1175 %void = OpTypeVoid
1176 %void_fn = OpTypeFunction %void
1177 %float = OpTypeFloat 32
1178 %struct = OpTypeStruct %float %float
1179 %ptr_output_struct = OpTypePointer Output %struct
1180 %var1 = OpVariable %ptr_output_struct Output
1181 %var2 = OpVariable %ptr_output_struct Output
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("Entry-point has conflicting output location assignment "
1193                 "at location 1"));
1194 }
1195 
TEST_F(ValidateInterfacesTest,VulkanLocationsVariableNoConflictDifferentIndex)1196 TEST_F(ValidateInterfacesTest,
1197        VulkanLocationsVariableNoConflictDifferentIndex) {
1198   const std::string text = R"(
1199 OpCapability Shader
1200 OpMemoryModel Logical GLSL450
1201 OpEntryPoint Fragment %main "main" %var1 %var2
1202 OpExecutionMode %main OriginUpperLeft
1203 OpDecorate %var1 Location 1
1204 OpDecorate %var1 Index 0
1205 OpDecorate %var2 Location 1
1206 OpDecorate %var2 Index 1
1207 %void = OpTypeVoid
1208 %void_fn = OpTypeFunction %void
1209 %float = OpTypeFloat 32
1210 %struct = OpTypeStruct %float %float
1211 %ptr_output_struct = OpTypePointer Output %struct
1212 %var1 = OpVariable %ptr_output_struct Output
1213 %var2 = OpVariable %ptr_output_struct Output
1214 %main = OpFunction %void None %void_fn
1215 %entry = OpLabel
1216 OpReturn
1217 OpFunctionEnd
1218 )";
1219 
1220   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
1221   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
1222 }
1223 
TEST_F(ValidateInterfacesTest,VulkanLocationsIndexGLCompute)1224 TEST_F(ValidateInterfacesTest, VulkanLocationsIndexGLCompute) {
1225   const std::string text = R"(
1226 OpCapability Shader
1227 OpCapability Geometry
1228 OpMemoryModel Logical GLSL450
1229 OpEntryPoint Geometry %main "main" %var1
1230 OpExecutionMode %main Triangles
1231 OpExecutionMode %main OutputPoints
1232 OpDecorate %var1 Location 1
1233 OpDecorate %var1 Index 1
1234 %void = OpTypeVoid
1235 %void_fn = OpTypeFunction %void
1236 %float = OpTypeFloat 32
1237 %struct = OpTypeStruct %float %float
1238 %ptr_output_struct = OpTypePointer Output %struct
1239 %var1 = OpVariable %ptr_output_struct Output
1240 %main = OpFunction %void None %void_fn
1241 %entry = OpLabel
1242 OpReturn
1243 OpFunctionEnd
1244 )";
1245 
1246   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
1247   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
1248   EXPECT_THAT(
1249       getDiagnosticString(),
1250       HasSubstr("Index can only be applied to Fragment output variables"));
1251 }
1252 
TEST_F(ValidateInterfacesTest,VulkanLocationsIndexInput)1253 TEST_F(ValidateInterfacesTest, VulkanLocationsIndexInput) {
1254   const std::string text = R"(
1255 OpCapability Shader
1256 OpMemoryModel Logical GLSL450
1257 OpEntryPoint Fragment %main "main" %var1
1258 OpExecutionMode %main OriginUpperLeft
1259 OpDecorate %var1 Location 1
1260 OpDecorate %var1 Index 1
1261 %void = OpTypeVoid
1262 %void_fn = OpTypeFunction %void
1263 %float = OpTypeFloat 32
1264 %struct = OpTypeStruct %float %float
1265 %ptr_input_struct = OpTypePointer Input %struct
1266 %var1 = OpVariable %ptr_input_struct Input
1267 %main = OpFunction %void None %void_fn
1268 %entry = OpLabel
1269 OpReturn
1270 OpFunctionEnd
1271 )";
1272 
1273   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
1274   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
1275   EXPECT_THAT(getDiagnosticString(),
1276               HasSubstr("must be in the Output storage class"));
1277 }
1278 
TEST_F(ValidateInterfacesTest,VulkanLocationsArrayWithComponent)1279 TEST_F(ValidateInterfacesTest, VulkanLocationsArrayWithComponent) {
1280   const std::string text = R"(
1281 OpCapability Shader
1282 OpMemoryModel Logical GLSL450
1283 OpEntryPoint Fragment %4 "main" %11 %18 %28 %36 %40
1284 OpExecutionMode %4 OriginUpperLeft
1285 OpDecorate %11 Location 0
1286 OpDecorate %18 Component 0
1287 OpDecorate %18 Location 0
1288 OpDecorate %28 Component 1
1289 OpDecorate %28 Location 0
1290 OpDecorate %36 Location 1
1291 OpDecorate %40 Component 0
1292 OpDecorate %40 Location 1
1293 %void = OpTypeVoid
1294 %3 = OpTypeFunction %void
1295 %float = OpTypeFloat 32
1296 %v4float = OpTypeVector %float 4
1297 %_ptr_Input_v4float = OpTypePointer Input %v4float
1298 %11 = OpVariable %_ptr_Input_v4float Input
1299 %_ptr_Output_float = OpTypePointer Output %float
1300 %18 = OpVariable %_ptr_Output_float Output
1301 %uint = OpTypeInt 32 0
1302 %v3float = OpTypeVector %float 3
1303 %uint_2 = OpConstant %uint 2
1304 %_arr_v3float_uint_2 = OpTypeArray %v3float %uint_2
1305 %_ptr_Output__arr_v3float_uint_2 = OpTypePointer Output %_arr_v3float_uint_2
1306 %28 = OpVariable %_ptr_Output__arr_v3float_uint_2 Output
1307 %_ptr_Output_v3float = OpTypePointer Output %v3float
1308 %36 = OpVariable %_ptr_Input_v4float Input
1309 %40 = OpVariable %_ptr_Output_float Output
1310 %4 = OpFunction %void None %3
1311 %5 = OpLabel
1312 OpReturn
1313 OpFunctionEnd
1314 )";
1315 
1316   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
1317   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
1318 }
1319 
TEST_F(ValidateInterfacesTest,VulkanLocationsArrayWithComponentBad)1320 TEST_F(ValidateInterfacesTest, VulkanLocationsArrayWithComponentBad) {
1321   const std::string text = R"(
1322 OpCapability Shader
1323 OpMemoryModel Logical GLSL450
1324 OpEntryPoint Fragment %4 "main" %11 %18 %28 %36 %40
1325 OpExecutionMode %4 OriginUpperLeft
1326 OpDecorate %11 Location 0
1327 OpDecorate %18 Component 0
1328 OpDecorate %18 Location 0
1329 OpDecorate %28 Component 1
1330 OpDecorate %28 Location 0
1331 OpDecorate %36 Location 1
1332 OpDecorate %40 Component 1
1333 OpDecorate %40 Location 1
1334 %void = OpTypeVoid
1335 %3 = OpTypeFunction %void
1336 %float = OpTypeFloat 32
1337 %v4float = OpTypeVector %float 4
1338 %_ptr_Input_v4float = OpTypePointer Input %v4float
1339 %11 = OpVariable %_ptr_Input_v4float Input
1340 %_ptr_Output_float = OpTypePointer Output %float
1341 %18 = OpVariable %_ptr_Output_float Output
1342 %uint = OpTypeInt 32 0
1343 %v3float = OpTypeVector %float 3
1344 %uint_2 = OpConstant %uint 2
1345 %_arr_v3float_uint_2 = OpTypeArray %v3float %uint_2
1346 %_ptr_Output__arr_v3float_uint_2 = OpTypePointer Output %_arr_v3float_uint_2
1347 %28 = OpVariable %_ptr_Output__arr_v3float_uint_2 Output
1348 %_ptr_Output_v3float = OpTypePointer Output %v3float
1349 %36 = OpVariable %_ptr_Input_v4float Input
1350 %40 = OpVariable %_ptr_Output_float Output
1351 %4 = OpFunction %void None %3
1352 %5 = OpLabel
1353 OpReturn
1354 OpFunctionEnd
1355 )";
1356 
1357   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
1358   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
1359   EXPECT_THAT(getDiagnosticString(),
1360               HasSubstr("Entry-point has conflicting output location "
1361                         "assignment at location 1, component 1"));
1362 }
1363 
TEST_F(ValidateInterfacesTest,VulkanLocationsLargeLocation)1364 TEST_F(ValidateInterfacesTest, VulkanLocationsLargeLocation) {
1365   const std::string text = R"(
1366                OpCapability Shader
1367                OpMemoryModel Logical GLSL450
1368                OpEntryPoint Fragment %4 "????????" %17
1369                OpExecutionMode %4 OriginUpperLeft
1370                OpDecorate %17 Location 4227868160
1371        %void = OpTypeVoid
1372           %3 = OpTypeFunction %void
1373       %float = OpTypeFloat 32
1374     %v3float = OpTypeVector %float 3
1375 %_ptr_Input_v3float = OpTypePointer Input %v3float
1376          %17 = OpVariable %_ptr_Input_v3float Input
1377           %4 = OpFunction %void None %3
1378           %5 = OpLabel
1379                OpUnreachable
1380                OpFunctionEnd
1381 )";
1382 
1383   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
1384   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
1385 }
1386 
TEST_F(ValidateInterfacesTest,VulkanLocationMeshShader)1387 TEST_F(ValidateInterfacesTest, VulkanLocationMeshShader) {
1388   const std::string text = R"(
1389 OpCapability Shader
1390 OpCapability MeshShadingNV
1391 OpExtension "SPV_NV_mesh_shader"
1392 OpMemoryModel Logical GLSL450
1393 OpEntryPoint MeshNV %foo "foo" %in
1394 OpExecutionMode %foo LocalSize 1 1 1
1395 OpDecorate %block Block
1396 OpMemberDecorate %block 0 PerTaskNV
1397 OpMemberDecorate %block 0 Offset 0
1398 %void = OpTypeVoid
1399 %int = OpTypeInt 32 0
1400 %int_32 = OpConstant %int 32
1401 %array = OpTypeArray %int %int_32
1402 %block = OpTypeStruct %array
1403 %ptr_input_block = OpTypePointer Input %block
1404 %in = OpVariable %ptr_input_block Input
1405 %void_fn = OpTypeFunction %void
1406 %foo = OpFunction %void None %void_fn
1407 %entry = OpLabel
1408 OpReturn
1409 OpFunctionEnd
1410 )";
1411 
1412   CompileSuccessfully(text, SPV_ENV_VULKAN_1_2);
1413   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2));
1414 }
1415 
TEST_F(ValidateInterfacesTest,VulkanLocationArrayWithComponent1)1416 TEST_F(ValidateInterfacesTest, VulkanLocationArrayWithComponent1) {
1417   const std::string text = R"(
1418 OpCapability Shader
1419 OpMemoryModel Logical GLSL450
1420 OpEntryPoint Fragment %main "main" %in
1421 OpExecutionMode %main OriginUpperLeft
1422 OpDecorate %struct Block
1423 OpMemberDecorate %struct 0 Location 0
1424 OpMemberDecorate %struct 0 Component 0
1425 OpMemberDecorate %struct 1 Location 0
1426 OpMemberDecorate %struct 1 Component 1
1427 %void = OpTypeVoid
1428 %void_fn = OpTypeFunction %void
1429 %float = OpTypeFloat 32
1430 %int = OpTypeInt 32 0
1431 %int_2 = OpConstant %int 2
1432 %float_arr = OpTypeArray %float %int_2
1433 %struct = OpTypeStruct %float_arr %float_arr
1434 %ptr = OpTypePointer Input %struct
1435 %in = OpVariable %ptr Input
1436 %main = OpFunction %void None %void_fn
1437 %entry = OpLabel
1438 OpReturn
1439 OpFunctionEnd
1440 )";
1441 
1442   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
1443   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
1444 }
1445 
TEST_F(ValidateInterfacesTest,VulkanLocationArrayWithComponent2)1446 TEST_F(ValidateInterfacesTest, VulkanLocationArrayWithComponent2) {
1447   const std::string text = R"(
1448 OpCapability Shader
1449 OpCapability Float64
1450 OpMemoryModel Logical GLSL450
1451 OpEntryPoint Fragment %main "main" %in
1452 OpExecutionMode %main OriginUpperLeft
1453 OpDecorate %struct Block
1454 OpMemberDecorate %struct 0 Location 0
1455 OpMemberDecorate %struct 0 Component 0
1456 OpMemberDecorate %struct 1 Location 0
1457 OpMemberDecorate %struct 1 Component 1
1458 %void = OpTypeVoid
1459 %void_fn = OpTypeFunction %void
1460 %float = OpTypeFloat 32
1461 %double = OpTypeFloat 64
1462 %int = OpTypeInt 32 0
1463 %int_2 = OpConstant %int 2
1464 %double_arr = OpTypeArray %double %int_2
1465 %struct = OpTypeStruct %float %double_arr
1466 %ptr = OpTypePointer Input %struct
1467 %in = OpVariable %ptr Input
1468 %main = OpFunction %void None %void_fn
1469 %entry = OpLabel
1470 OpReturn
1471 OpFunctionEnd
1472 )";
1473 
1474   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
1475   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
1476 }
1477 
TEST_F(ValidateInterfacesTest,DuplicateInterfaceVariableSuccess)1478 TEST_F(ValidateInterfacesTest, DuplicateInterfaceVariableSuccess) {
1479   const std::string text = R"(
1480 OpCapability Shader
1481 OpMemoryModel Logical GLSL450
1482 OpEntryPoint Fragment %main "main" %in %out %in
1483 OpExecutionMode %main OriginUpperLeft
1484 OpDecorate %in Location 0
1485 OpDecorate %out Location 0
1486 %void = OpTypeVoid
1487 %float = OpTypeFloat 32
1488 %in_ptr = OpTypePointer Input %float
1489 %out_ptr = OpTypePointer Output %float
1490 %in = OpVariable %in_ptr Input
1491 %out = OpVariable %out_ptr Output
1492 %void_fn = OpTypeFunction %void
1493 %main = OpFunction %void None %void_fn
1494 %entry = OpLabel
1495 OpReturn
1496 OpFunctionEnd
1497 )";
1498 
1499   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
1500   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
1501 }
1502 
TEST_F(ValidateInterfacesTest,StructWithBuiltinsMissingBlock_Bad)1503 TEST_F(ValidateInterfacesTest, StructWithBuiltinsMissingBlock_Bad) {
1504   // See https://github.com/KhronosGroup/SPIRV-Registry/issues/134
1505   //
1506   // When a shader input or output is a struct that does not have Block,
1507   // then it must have a Location.
1508   // But BuiltIns must not have locations.
1509   const std::string text = R"(
1510 OpCapability Shader
1511 OpMemoryModel Logical GLSL450
1512 OpEntryPoint Fragment %main "main" %in
1513 OpExecutionMode %main OriginUpperLeft
1514 ; %struct needs a Block decoration
1515 OpMemberDecorate %struct 0 BuiltIn Position
1516 %void = OpTypeVoid
1517 %float = OpTypeFloat 32
1518 %v4float = OpTypeVector %float 4
1519 %struct = OpTypeStruct %v4float
1520 %in_ptr = OpTypePointer Input %struct
1521 %in = OpVariable %in_ptr Input
1522 %void_fn = OpTypeFunction %void
1523 %main = OpFunction %void None %void_fn
1524 %entry = OpLabel
1525 OpReturn
1526 OpFunctionEnd
1527 )";
1528 
1529   CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
1530   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
1531   EXPECT_THAT(getDiagnosticString(),
1532               AnyVUID("VUID-StandaloneSpirv-Location-04919"));
1533   EXPECT_THAT(
1534       getDiagnosticString(),
1535       HasSubstr(
1536           "Interface struct has no Block decoration but has BuiltIn members."));
1537 }
1538 
1539 }  // namespace
1540 }  // namespace val
1541 }  // namespace spvtools
1542