• 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 %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