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