• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2019 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 <sstream>
16 #include <string>
17 #include <tuple>
18 
19 #include "gmock/gmock.h"
20 #include "test/test_fixture.h"
21 #include "test/unit_spirv.h"
22 #include "test/val/val_fixtures.h"
23 
24 namespace spvtools {
25 namespace val {
26 namespace {
27 
28 using ::testing::Combine;
29 using ::testing::HasSubstr;
30 using ::testing::Values;
31 
32 using ValidateFunctionCall = spvtest::ValidateBase<std::string>;
33 
GenerateShader(const std::string & storage_class,const std::string & capabilities,const std::string & extensions)34 std::string GenerateShader(const std::string& storage_class,
35                            const std::string& capabilities,
36                            const std::string& extensions) {
37   std::string spirv = R"(
38 OpCapability Shader
39 OpCapability Linkage
40 OpCapability AtomicStorage
41 )" + capabilities + R"(
42 OpExtension "SPV_KHR_storage_buffer_storage_class"
43 )" +
44                       extensions + R"(
45 OpMemoryModel Logical GLSL450
46 OpName %var "var"
47 %void = OpTypeVoid
48 %int = OpTypeInt 32 0
49 %ptr = OpTypePointer )" + storage_class + R"( %int
50 %caller_ty = OpTypeFunction %void
51 %callee_ty = OpTypeFunction %void %ptr
52 )";
53 
54   if (storage_class != "Function") {
55     spirv += "%var = OpVariable %ptr " + storage_class;
56   }
57 
58   spirv += R"(
59 %caller = OpFunction %void None %caller_ty
60 %1 = OpLabel
61 )";
62 
63   if (storage_class == "Function") {
64     spirv += "%var = OpVariable %ptr Function";
65   }
66 
67   spirv += R"(
68 %call = OpFunctionCall %void %callee %var
69 OpReturn
70 OpFunctionEnd
71 %callee = OpFunction %void None %callee_ty
72 %param = OpFunctionParameter %ptr
73 %2 = OpLabel
74 OpReturn
75 OpFunctionEnd
76 )";
77 
78   return spirv;
79 }
80 
GenerateShaderParameter(const std::string & storage_class,const std::string & capabilities,const std::string & extensions)81 std::string GenerateShaderParameter(const std::string& storage_class,
82                                     const std::string& capabilities,
83                                     const std::string& extensions) {
84   std::string spirv = R"(
85 OpCapability Shader
86 OpCapability Linkage
87 OpCapability AtomicStorage
88 )" + capabilities + R"(
89 OpExtension "SPV_KHR_storage_buffer_storage_class"
90 )" +
91                       extensions + R"(
92 OpMemoryModel Logical GLSL450
93 OpName %p "p"
94 %void = OpTypeVoid
95 %int = OpTypeInt 32 0
96 %ptr = OpTypePointer )" + storage_class + R"( %int
97 %func_ty = OpTypeFunction %void %ptr
98 %caller = OpFunction %void None %func_ty
99 %p = OpFunctionParameter %ptr
100 %1 = OpLabel
101 %call = OpFunctionCall %void %callee %p
102 OpReturn
103 OpFunctionEnd
104 %callee = OpFunction %void None %func_ty
105 %param = OpFunctionParameter %ptr
106 %2 = OpLabel
107 OpReturn
108 OpFunctionEnd
109 )";
110 
111   return spirv;
112 }
113 
GenerateShaderAccessChain(const std::string & storage_class,const std::string & capabilities,const std::string & extensions)114 std::string GenerateShaderAccessChain(const std::string& storage_class,
115                                       const std::string& capabilities,
116                                       const std::string& extensions) {
117   std::string spirv = R"(
118 OpCapability Shader
119 OpCapability Linkage
120 OpCapability AtomicStorage
121 )" + capabilities + R"(
122 OpExtension "SPV_KHR_storage_buffer_storage_class"
123 )" +
124                       extensions + R"(
125 OpMemoryModel Logical GLSL450
126 OpName %var "var"
127 OpName %gep "gep"
128 %void = OpTypeVoid
129 %int = OpTypeInt 32 0
130 %int2 = OpTypeVector %int 2
131 %int_0 = OpConstant %int 0
132 %ptr = OpTypePointer )" + storage_class + R"( %int2
133 %ptr2 = OpTypePointer )" +
134                       storage_class + R"( %int
135 %caller_ty = OpTypeFunction %void
136 %callee_ty = OpTypeFunction %void %ptr2
137 )";
138 
139   if (storage_class != "Function") {
140     spirv += "%var = OpVariable %ptr " + storage_class;
141   }
142 
143   spirv += R"(
144 %caller = OpFunction %void None %caller_ty
145 %1 = OpLabel
146 )";
147 
148   if (storage_class == "Function") {
149     spirv += "%var = OpVariable %ptr Function";
150   }
151 
152   spirv += R"(
153 %gep = OpAccessChain %ptr2 %var %int_0
154 %call = OpFunctionCall %void %callee %gep
155 OpReturn
156 OpFunctionEnd
157 %callee = OpFunction %void None %callee_ty
158 %param = OpFunctionParameter %ptr2
159 %2 = OpLabel
160 OpReturn
161 OpFunctionEnd
162 )";
163 
164   return spirv;
165 }
166 
TEST_P(ValidateFunctionCall,VariableNoVariablePointers)167 TEST_P(ValidateFunctionCall, VariableNoVariablePointers) {
168   const std::string storage_class = GetParam();
169 
170   std::string spirv = GenerateShader(storage_class, "", "");
171 
172   const std::vector<std::string> valid_storage_classes = {
173       "UniformConstant", "Function", "Private", "Workgroup", "AtomicCounter"};
174   bool valid =
175       std::find(valid_storage_classes.begin(), valid_storage_classes.end(),
176                 storage_class) != valid_storage_classes.end();
177 
178   CompileSuccessfully(spirv);
179   if (valid) {
180     EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
181   } else {
182     EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
183     if (storage_class == "StorageBuffer") {
184       EXPECT_THAT(
185           getDiagnosticString(),
186           HasSubstr("StorageBuffer pointer operand '1[%var]' requires a "
187                     "variable pointers capability"));
188     } else {
189       EXPECT_THAT(
190           getDiagnosticString(),
191           HasSubstr("Invalid storage class for pointer operand '1[%var]'"));
192     }
193   }
194 }
195 
TEST_P(ValidateFunctionCall,VariableVariablePointersStorageClass)196 TEST_P(ValidateFunctionCall, VariableVariablePointersStorageClass) {
197   const std::string storage_class = GetParam();
198 
199   std::string spirv = GenerateShader(
200       storage_class, "OpCapability VariablePointersStorageBuffer",
201       "OpExtension \"SPV_KHR_variable_pointers\"");
202 
203   const std::vector<std::string> valid_storage_classes = {
204       "UniformConstant", "Function",      "Private",
205       "Workgroup",       "StorageBuffer", "AtomicCounter"};
206   bool valid =
207       std::find(valid_storage_classes.begin(), valid_storage_classes.end(),
208                 storage_class) != valid_storage_classes.end();
209 
210   CompileSuccessfully(spirv);
211   if (valid) {
212     EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
213   } else {
214     EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
215     EXPECT_THAT(
216         getDiagnosticString(),
217         HasSubstr("Invalid storage class for pointer operand '1[%var]'"));
218   }
219 }
220 
TEST_P(ValidateFunctionCall,VariableVariablePointers)221 TEST_P(ValidateFunctionCall, VariableVariablePointers) {
222   const std::string storage_class = GetParam();
223 
224   std::string spirv =
225       GenerateShader(storage_class, "OpCapability VariablePointers",
226                      "OpExtension \"SPV_KHR_variable_pointers\"");
227 
228   const std::vector<std::string> valid_storage_classes = {
229       "UniformConstant", "Function",      "Private",
230       "Workgroup",       "StorageBuffer", "AtomicCounter"};
231   bool valid =
232       std::find(valid_storage_classes.begin(), valid_storage_classes.end(),
233                 storage_class) != valid_storage_classes.end();
234 
235   CompileSuccessfully(spirv);
236   if (valid) {
237     EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
238   } else {
239     EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
240     EXPECT_THAT(
241         getDiagnosticString(),
242         HasSubstr("Invalid storage class for pointer operand '1[%var]'"));
243   }
244 }
245 
TEST_P(ValidateFunctionCall,ParameterNoVariablePointers)246 TEST_P(ValidateFunctionCall, ParameterNoVariablePointers) {
247   const std::string storage_class = GetParam();
248 
249   std::string spirv = GenerateShaderParameter(storage_class, "", "");
250 
251   const std::vector<std::string> valid_storage_classes = {
252       "UniformConstant", "Function", "Private", "Workgroup", "AtomicCounter"};
253   bool valid =
254       std::find(valid_storage_classes.begin(), valid_storage_classes.end(),
255                 storage_class) != valid_storage_classes.end();
256 
257   CompileSuccessfully(spirv);
258   if (valid) {
259     EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
260   } else {
261     EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
262     if (storage_class == "StorageBuffer") {
263       EXPECT_THAT(getDiagnosticString(),
264                   HasSubstr("StorageBuffer pointer operand '1[%p]' requires a "
265                             "variable pointers capability"));
266     } else {
267       EXPECT_THAT(
268           getDiagnosticString(),
269           HasSubstr("Invalid storage class for pointer operand '1[%p]'"));
270     }
271   }
272 }
273 
TEST_P(ValidateFunctionCall,ParameterVariablePointersStorageBuffer)274 TEST_P(ValidateFunctionCall, ParameterVariablePointersStorageBuffer) {
275   const std::string storage_class = GetParam();
276 
277   std::string spirv = GenerateShaderParameter(
278       storage_class, "OpCapability VariablePointersStorageBuffer",
279       "OpExtension \"SPV_KHR_variable_pointers\"");
280 
281   const std::vector<std::string> valid_storage_classes = {
282       "UniformConstant", "Function",      "Private",
283       "Workgroup",       "StorageBuffer", "AtomicCounter"};
284   bool valid =
285       std::find(valid_storage_classes.begin(), valid_storage_classes.end(),
286                 storage_class) != valid_storage_classes.end();
287 
288   CompileSuccessfully(spirv);
289   if (valid) {
290     EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
291   } else {
292     EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
293     EXPECT_THAT(getDiagnosticString(),
294                 HasSubstr("Invalid storage class for pointer operand '1[%p]'"));
295   }
296 }
297 
TEST_P(ValidateFunctionCall,ParameterVariablePointers)298 TEST_P(ValidateFunctionCall, ParameterVariablePointers) {
299   const std::string storage_class = GetParam();
300 
301   std::string spirv =
302       GenerateShaderParameter(storage_class, "OpCapability VariablePointers",
303                               "OpExtension \"SPV_KHR_variable_pointers\"");
304 
305   const std::vector<std::string> valid_storage_classes = {
306       "UniformConstant", "Function",      "Private",
307       "Workgroup",       "StorageBuffer", "AtomicCounter"};
308   bool valid =
309       std::find(valid_storage_classes.begin(), valid_storage_classes.end(),
310                 storage_class) != valid_storage_classes.end();
311 
312   CompileSuccessfully(spirv);
313   if (valid) {
314     EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
315   } else {
316     EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
317     EXPECT_THAT(getDiagnosticString(),
318                 HasSubstr("Invalid storage class for pointer operand '1[%p]'"));
319   }
320 }
321 
TEST_P(ValidateFunctionCall,NonMemoryObjectDeclarationNoVariablePointers)322 TEST_P(ValidateFunctionCall, NonMemoryObjectDeclarationNoVariablePointers) {
323   const std::string storage_class = GetParam();
324 
325   std::string spirv = GenerateShaderAccessChain(storage_class, "", "");
326 
327   const std::vector<std::string> valid_storage_classes = {
328       "Function", "Private", "Workgroup", "AtomicCounter"};
329   bool valid_sc =
330       std::find(valid_storage_classes.begin(), valid_storage_classes.end(),
331                 storage_class) != valid_storage_classes.end();
332 
333   CompileSuccessfully(spirv);
334   spv_result_t expected_result =
335       storage_class == "UniformConstant" ? SPV_SUCCESS : SPV_ERROR_INVALID_ID;
336   EXPECT_EQ(expected_result, ValidateInstructions());
337   if (valid_sc) {
338     EXPECT_THAT(
339         getDiagnosticString(),
340         HasSubstr(
341             "Pointer operand '2[%gep]' must be a memory object declaration"));
342   } else {
343     if (storage_class == "StorageBuffer") {
344       EXPECT_THAT(
345           getDiagnosticString(),
346           HasSubstr("StorageBuffer pointer operand '2[%gep]' requires a "
347                     "variable pointers capability"));
348     } else if (storage_class != "UniformConstant") {
349       EXPECT_THAT(
350           getDiagnosticString(),
351           HasSubstr("Invalid storage class for pointer operand '2[%gep]'"));
352     }
353   }
354 }
355 
TEST_P(ValidateFunctionCall,NonMemoryObjectDeclarationVariablePointersStorageBuffer)356 TEST_P(ValidateFunctionCall,
357        NonMemoryObjectDeclarationVariablePointersStorageBuffer) {
358   const std::string storage_class = GetParam();
359 
360   std::string spirv = GenerateShaderAccessChain(
361       storage_class, "OpCapability VariablePointersStorageBuffer",
362       "OpExtension \"SPV_KHR_variable_pointers\"");
363 
364   const std::vector<std::string> valid_storage_classes = {
365       "Function", "Private", "Workgroup", "StorageBuffer", "AtomicCounter"};
366   bool valid_sc =
367       std::find(valid_storage_classes.begin(), valid_storage_classes.end(),
368                 storage_class) != valid_storage_classes.end();
369   bool validate =
370       storage_class == "StorageBuffer" || storage_class == "UniformConstant";
371 
372   CompileSuccessfully(spirv);
373   if (validate) {
374     EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
375   } else {
376     EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
377     if (valid_sc) {
378       EXPECT_THAT(
379           getDiagnosticString(),
380           HasSubstr(
381               "Pointer operand '2[%gep]' must be a memory object declaration"));
382     } else {
383       EXPECT_THAT(
384           getDiagnosticString(),
385           HasSubstr("Invalid storage class for pointer operand '2[%gep]'"));
386     }
387   }
388 }
389 
TEST_P(ValidateFunctionCall,NonMemoryObjectDeclarationVariablePointers)390 TEST_P(ValidateFunctionCall, NonMemoryObjectDeclarationVariablePointers) {
391   const std::string storage_class = GetParam();
392 
393   std::string spirv =
394       GenerateShaderAccessChain(storage_class, "OpCapability VariablePointers",
395                                 "OpExtension \"SPV_KHR_variable_pointers\"");
396 
397   const std::vector<std::string> valid_storage_classes = {
398       "Function", "Private", "Workgroup", "StorageBuffer", "AtomicCounter"};
399   bool valid_sc =
400       std::find(valid_storage_classes.begin(), valid_storage_classes.end(),
401                 storage_class) != valid_storage_classes.end();
402   bool validate = storage_class == "StorageBuffer" ||
403                   storage_class == "Workgroup" ||
404                   storage_class == "UniformConstant";
405 
406   CompileSuccessfully(spirv);
407   if (validate) {
408     EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
409   } else {
410     EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
411     if (valid_sc) {
412       EXPECT_THAT(
413           getDiagnosticString(),
414           HasSubstr(
415               "Pointer operand '2[%gep]' must be a memory object declaration"));
416     } else {
417       EXPECT_THAT(
418           getDiagnosticString(),
419           HasSubstr("Invalid storage class for pointer operand '2[%gep]'"));
420     }
421   }
422 }
423 
TEST_F(ValidateFunctionCall,LogicallyMatchingPointers)424 TEST_F(ValidateFunctionCall, LogicallyMatchingPointers) {
425   std::string spirv =
426       R"(
427                OpCapability Shader
428                OpMemoryModel Logical GLSL450
429                OpEntryPoint GLCompute %1 "main"
430                OpExecutionMode %1 LocalSize 1 1 1
431                OpSource HLSL 600
432                OpDecorate %2 DescriptorSet 0
433                OpDecorate %2 Binding 0
434                OpMemberDecorate %_struct_3 0 Offset 0
435                OpDecorate %_runtimearr__struct_3 ArrayStride 4
436                OpMemberDecorate %_struct_5 0 Offset 0
437                OpDecorate %_struct_5 BufferBlock
438         %int = OpTypeInt 32 1
439       %int_0 = OpConstant %int 0
440        %uint = OpTypeInt 32 0
441      %uint_0 = OpConstant %uint 0
442   %_struct_3 = OpTypeStruct %int
443 %_runtimearr__struct_3 = OpTypeRuntimeArray %_struct_3
444   %_struct_5 = OpTypeStruct %_runtimearr__struct_3
445 %_ptr_Uniform__struct_5 = OpTypePointer Uniform %_struct_5
446        %void = OpTypeVoid
447          %14 = OpTypeFunction %void
448  %_struct_15 = OpTypeStruct %int
449 %_ptr_Function__struct_15 = OpTypePointer Function %_struct_15
450 %_ptr_Uniform__struct_3 = OpTypePointer Uniform %_struct_3
451          %18 = OpTypeFunction %void %_ptr_Function__struct_15
452           %2 = OpVariable %_ptr_Uniform__struct_5 Uniform
453           %1 = OpFunction %void None %14
454          %19 = OpLabel
455          %20 = OpAccessChain %_ptr_Uniform__struct_3 %2 %int_0 %uint_0
456          %21 = OpFunctionCall %void %22 %20
457                OpReturn
458                OpFunctionEnd
459          %22 = OpFunction %void None %18
460          %23 = OpFunctionParameter %_ptr_Function__struct_15
461          %24 = OpLabel
462                OpReturn
463                OpFunctionEnd
464 )";
465   CompileSuccessfully(spirv);
466   spvValidatorOptionsSetBeforeHlslLegalization(getValidatorOptions(), true);
467   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
468 }
469 
TEST_F(ValidateFunctionCall,LogicallyMatchingPointersNestedStruct)470 TEST_F(ValidateFunctionCall, LogicallyMatchingPointersNestedStruct) {
471   std::string spirv =
472       R"(
473                OpCapability Shader
474                OpMemoryModel Logical GLSL450
475                OpEntryPoint GLCompute %1 "main"
476                OpExecutionMode %1 LocalSize 1 1 1
477                OpSource HLSL 600
478                OpDecorate %2 DescriptorSet 0
479                OpDecorate %2 Binding 0
480                OpMemberDecorate %_struct_3 0 Offset 0
481                OpMemberDecorate %_struct_4 0 Offset 0
482                OpDecorate %_runtimearr__struct_4 ArrayStride 4
483                OpMemberDecorate %_struct_6 0 Offset 0
484                OpDecorate %_struct_6 BufferBlock
485         %int = OpTypeInt 32 1
486       %int_0 = OpConstant %int 0
487        %uint = OpTypeInt 32 0
488      %uint_0 = OpConstant %uint 0
489   %_struct_3 = OpTypeStruct %int
490   %_struct_4 = OpTypeStruct %_struct_3
491 %_runtimearr__struct_4 = OpTypeRuntimeArray %_struct_4
492   %_struct_6 = OpTypeStruct %_runtimearr__struct_4
493 %_ptr_Uniform__struct_6 = OpTypePointer Uniform %_struct_6
494        %void = OpTypeVoid
495          %13 = OpTypeFunction %void
496  %_struct_14 = OpTypeStruct %int
497  %_struct_15 = OpTypeStruct %_struct_14
498 %_ptr_Function__struct_15 = OpTypePointer Function %_struct_15
499 %_ptr_Uniform__struct_4 = OpTypePointer Uniform %_struct_4
500          %18 = OpTypeFunction %void %_ptr_Function__struct_15
501           %2 = OpVariable %_ptr_Uniform__struct_6 Uniform
502           %1 = OpFunction %void None %13
503          %19 = OpLabel
504          %20 = OpVariable %_ptr_Function__struct_15 Function
505          %21 = OpAccessChain %_ptr_Uniform__struct_4 %2 %int_0 %uint_0
506          %22 = OpFunctionCall %void %23 %21
507                OpReturn
508                OpFunctionEnd
509          %23 = OpFunction %void None %18
510          %24 = OpFunctionParameter %_ptr_Function__struct_15
511          %25 = OpLabel
512                OpReturn
513                OpFunctionEnd
514 )";
515 
516   CompileSuccessfully(spirv);
517   spvValidatorOptionsSetBeforeHlslLegalization(getValidatorOptions(), true);
518   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
519 }
520 
TEST_F(ValidateFunctionCall,LogicallyMatchingPointersNestedArray)521 TEST_F(ValidateFunctionCall, LogicallyMatchingPointersNestedArray) {
522   std::string spirv =
523       R"(
524               OpCapability Shader
525                OpMemoryModel Logical GLSL450
526                OpEntryPoint GLCompute %1 "main"
527                OpExecutionMode %1 LocalSize 1 1 1
528                OpSource HLSL 600
529                OpDecorate %2 DescriptorSet 0
530                OpDecorate %2 Binding 0
531                OpDecorate %_arr_int_uint_10 ArrayStride 4
532                OpMemberDecorate %_struct_4 0 Offset 0
533                OpDecorate %_runtimearr__struct_4 ArrayStride 40
534                OpMemberDecorate %_struct_6 0 Offset 0
535                OpDecorate %_struct_6 BufferBlock
536         %int = OpTypeInt 32 1
537       %int_0 = OpConstant %int 0
538        %uint = OpTypeInt 32 0
539      %uint_0 = OpConstant %uint 0
540     %uint_10 = OpConstant %uint 10
541 %_arr_int_uint_10 = OpTypeArray %int %uint_10
542   %_struct_4 = OpTypeStruct %_arr_int_uint_10
543 %_runtimearr__struct_4 = OpTypeRuntimeArray %_struct_4
544   %_struct_6 = OpTypeStruct %_runtimearr__struct_4
545 %_ptr_Uniform__struct_6 = OpTypePointer Uniform %_struct_6
546        %void = OpTypeVoid
547          %14 = OpTypeFunction %void
548 %_ptr_Uniform__struct_4 = OpTypePointer Uniform %_struct_4
549 %_arr_int_uint_10_0 = OpTypeArray %int %uint_10
550  %_struct_17 = OpTypeStruct %_arr_int_uint_10_0
551 %_ptr_Function__struct_17 = OpTypePointer Function %_struct_17
552          %19 = OpTypeFunction %void %_ptr_Function__struct_17
553           %2 = OpVariable %_ptr_Uniform__struct_6 Uniform
554           %1 = OpFunction %void None %14
555          %20 = OpLabel
556          %21 = OpAccessChain %_ptr_Uniform__struct_4 %2 %int_0 %uint_0
557          %22 = OpFunctionCall %void %23 %21
558                OpReturn
559                OpFunctionEnd
560          %23 = OpFunction %void None %19
561          %24 = OpFunctionParameter %_ptr_Function__struct_17
562          %25 = OpLabel
563                OpReturn
564                OpFunctionEnd
565 )";
566 
567   CompileSuccessfully(spirv);
568   spvValidatorOptionsSetBeforeHlslLegalization(getValidatorOptions(), true);
569   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
570 }
571 
TEST_F(ValidateFunctionCall,LogicallyMismatchedPointersMissingMember)572 TEST_F(ValidateFunctionCall, LogicallyMismatchedPointersMissingMember) {
573   //  Validation should fail because the formal parameter type has two members,
574   //  while the actual parameter only has 1.
575   std::string spirv =
576       R"(
577                OpCapability Shader
578                OpMemoryModel Logical GLSL450
579                OpEntryPoint GLCompute %1 "main"
580                OpExecutionMode %1 LocalSize 1 1 1
581                OpSource HLSL 600
582                OpDecorate %2 DescriptorSet 0
583                OpDecorate %2 Binding 0
584                OpMemberDecorate %_struct_3 0 Offset 0
585                OpDecorate %_runtimearr__struct_3 ArrayStride 4
586                OpMemberDecorate %_struct_5 0 Offset 0
587                OpDecorate %_struct_5 BufferBlock
588         %int = OpTypeInt 32 1
589       %int_0 = OpConstant %int 0
590        %uint = OpTypeInt 32 0
591      %uint_0 = OpConstant %uint 0
592   %_struct_3 = OpTypeStruct %int
593 %_runtimearr__struct_3 = OpTypeRuntimeArray %_struct_3
594   %_struct_5 = OpTypeStruct %_runtimearr__struct_3
595 %_ptr_Uniform__struct_5 = OpTypePointer Uniform %_struct_5
596        %void = OpTypeVoid
597          %14 = OpTypeFunction %void
598  %_struct_15 = OpTypeStruct %int %int
599 %_ptr_Function__struct_15 = OpTypePointer Function %_struct_15
600 %_ptr_Uniform__struct_3 = OpTypePointer Uniform %_struct_3
601          %18 = OpTypeFunction %void %_ptr_Function__struct_15
602           %2 = OpVariable %_ptr_Uniform__struct_5 Uniform
603           %1 = OpFunction %void None %14
604          %19 = OpLabel
605          %20 = OpAccessChain %_ptr_Uniform__struct_3 %2 %int_0 %uint_0
606          %21 = OpFunctionCall %void %22 %20
607                OpReturn
608                OpFunctionEnd
609          %22 = OpFunction %void None %18
610          %23 = OpFunctionParameter %_ptr_Function__struct_15
611          %24 = OpLabel
612                OpReturn
613                OpFunctionEnd
614 )";
615 
616   CompileSuccessfully(spirv);
617   spvValidatorOptionsSetBeforeHlslLegalization(getValidatorOptions(), true);
618   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
619   EXPECT_THAT(getDiagnosticString(), HasSubstr("OpFunctionCall Argument <id>"));
620   EXPECT_THAT(getDiagnosticString(),
621               HasSubstr("type does not match Function <id>"));
622 }
623 
TEST_F(ValidateFunctionCall,LogicallyMismatchedPointersDifferentMemberType)624 TEST_F(ValidateFunctionCall, LogicallyMismatchedPointersDifferentMemberType) {
625   //  Validation should fail because the formal parameter has a member that is
626   // a different type than the actual parameter.
627   std::string spirv =
628       R"(
629                OpCapability Shader
630                OpMemoryModel Logical GLSL450
631                OpEntryPoint GLCompute %1 "main"
632                OpExecutionMode %1 LocalSize 1 1 1
633                OpSource HLSL 600
634                OpDecorate %2 DescriptorSet 0
635                OpDecorate %2 Binding 0
636                OpMemberDecorate %_struct_3 0 Offset 0
637                OpDecorate %_runtimearr__struct_3 ArrayStride 4
638                OpMemberDecorate %_struct_5 0 Offset 0
639                OpDecorate %_struct_5 BufferBlock
640         %int = OpTypeInt 32 1
641       %int_0 = OpConstant %int 0
642        %uint = OpTypeInt 32 0
643      %uint_0 = OpConstant %uint 0
644   %_struct_3 = OpTypeStruct %uint
645 %_runtimearr__struct_3 = OpTypeRuntimeArray %_struct_3
646   %_struct_5 = OpTypeStruct %_runtimearr__struct_3
647 %_ptr_Uniform__struct_5 = OpTypePointer Uniform %_struct_5
648        %void = OpTypeVoid
649          %14 = OpTypeFunction %void
650  %_struct_15 = OpTypeStruct %int
651 %_ptr_Function__struct_15 = OpTypePointer Function %_struct_15
652 %_ptr_Uniform__struct_3 = OpTypePointer Uniform %_struct_3
653          %18 = OpTypeFunction %void %_ptr_Function__struct_15
654           %2 = OpVariable %_ptr_Uniform__struct_5 Uniform
655           %1 = OpFunction %void None %14
656          %19 = OpLabel
657          %20 = OpAccessChain %_ptr_Uniform__struct_3 %2 %int_0 %uint_0
658          %21 = OpFunctionCall %void %22 %20
659                OpReturn
660                OpFunctionEnd
661          %22 = OpFunction %void None %18
662          %23 = OpFunctionParameter %_ptr_Function__struct_15
663          %24 = OpLabel
664                OpReturn
665                OpFunctionEnd
666 )";
667 
668   CompileSuccessfully(spirv);
669   spvValidatorOptionsSetBeforeHlslLegalization(getValidatorOptions(), true);
670   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
671   EXPECT_THAT(getDiagnosticString(), HasSubstr("OpFunctionCall Argument <id>"));
672   EXPECT_THAT(getDiagnosticString(),
673               HasSubstr("type does not match Function <id>"));
674 }
675 
TEST_F(ValidateFunctionCall,LogicallyMismatchedPointersIncompatableDecorations)676 TEST_F(ValidateFunctionCall,
677        LogicallyMismatchedPointersIncompatableDecorations) {
678   //  Validation should fail because the formal parameter has an incompatible
679   //  decoration.
680   std::string spirv =
681       R"(
682                OpCapability Shader
683                OpMemoryModel Logical GLSL450
684                OpEntryPoint GLCompute %1 "main"
685                OpExecutionMode %1 LocalSize 1 1 1
686                OpSource HLSL 600
687                OpDecorate %2 DescriptorSet 0
688                OpDecorate %2 Binding 0
689                OpMemberDecorate %_struct_3 0 Offset 0
690                OpDecorate %_runtimearr__struct_3 ArrayStride 4
691                OpMemberDecorate %_struct_5 0 Offset 0
692                OpDecorate %_struct_5 Block
693                OpMemberDecorate %_struct_15 0 NonWritable
694         %int = OpTypeInt 32 1
695       %int_0 = OpConstant %int 0
696        %uint = OpTypeInt 32 0
697      %uint_0 = OpConstant %uint 0
698   %_struct_3 = OpTypeStruct %int
699 %_runtimearr__struct_3 = OpTypeRuntimeArray %_struct_3
700   %_struct_5 = OpTypeStruct %_runtimearr__struct_3
701 %_ptr_StorageBuffer__struct_5 = OpTypePointer StorageBuffer %_struct_5
702        %void = OpTypeVoid
703          %14 = OpTypeFunction %void
704  %_struct_15 = OpTypeStruct %int
705 %_ptr_Function__struct_15 = OpTypePointer Function %_struct_15
706 %_ptr_StorageBuffer__struct_3 = OpTypePointer StorageBuffer %_struct_3
707          %18 = OpTypeFunction %void %_ptr_Function__struct_15
708           %2 = OpVariable %_ptr_StorageBuffer__struct_5 StorageBuffer
709           %1 = OpFunction %void None %14
710          %19 = OpLabel
711          %20 = OpAccessChain %_ptr_StorageBuffer__struct_3 %2 %int_0 %uint_0
712          %21 = OpFunctionCall %void %22 %20
713                OpReturn
714                OpFunctionEnd
715          %22 = OpFunction %void None %18
716          %23 = OpFunctionParameter %_ptr_Function__struct_15
717          %24 = OpLabel
718                OpReturn
719                OpFunctionEnd
720 )";
721 
722   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
723   spvValidatorOptionsSetBeforeHlslLegalization(getValidatorOptions(), true);
724   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
725   EXPECT_THAT(getDiagnosticString(), HasSubstr("OpFunctionCall Argument <id>"));
726   EXPECT_THAT(getDiagnosticString(),
727               HasSubstr("type does not match Function <id>"));
728 }
729 
TEST_F(ValidateFunctionCall,LogicallyMismatchedPointersIncompatableDecorations2)730 TEST_F(ValidateFunctionCall,
731        LogicallyMismatchedPointersIncompatableDecorations2) {
732   //  Validation should fail because the formal parameter has an incompatible
733   //  decoration.
734   std::string spirv =
735       R"(
736                OpCapability Shader
737                OpMemoryModel Logical GLSL450
738                OpEntryPoint GLCompute %1 "main"
739                OpExecutionMode %1 LocalSize 1 1 1
740                OpSource HLSL 600
741                OpDecorate %2 DescriptorSet 0
742                OpDecorate %2 Binding 0
743                OpMemberDecorate %_struct_3 0 Offset 0
744                OpDecorate %_runtimearr__struct_3 ArrayStride 4
745                OpMemberDecorate %_struct_5 0 Offset 0
746                OpDecorate %_struct_5 BufferBlock
747                OpDecorate %_ptr_Uniform__struct_3 ArrayStride 4
748                OpDecorate %_ptr_Uniform__struct_3_0 ArrayStride 8
749         %int = OpTypeInt 32 1
750       %int_0 = OpConstant %int 0
751        %uint = OpTypeInt 32 0
752      %uint_0 = OpConstant %uint 0
753   %_struct_3 = OpTypeStruct %int
754 %_runtimearr__struct_3 = OpTypeRuntimeArray %_struct_3
755   %_struct_5 = OpTypeStruct %_runtimearr__struct_3
756 %_ptr_Uniform__struct_5 = OpTypePointer Uniform %_struct_5
757        %void = OpTypeVoid
758          %14 = OpTypeFunction %void
759 %_ptr_Uniform__struct_3 = OpTypePointer Uniform %_struct_3
760 %_ptr_Uniform__struct_3_0 = OpTypePointer Uniform %_struct_3
761          %18 = OpTypeFunction %void %_ptr_Uniform__struct_3_0
762           %2 = OpVariable %_ptr_Uniform__struct_5 Uniform
763           %1 = OpFunction %void None %14
764          %19 = OpLabel
765          %20 = OpAccessChain %_ptr_Uniform__struct_3 %2 %int_0 %uint_0
766          %21 = OpFunctionCall %void %22 %20
767                OpReturn
768                OpFunctionEnd
769          %22 = OpFunction %void None %18
770          %23 = OpFunctionParameter %_ptr_Uniform__struct_3_0
771          %24 = OpLabel
772                OpReturn
773                OpFunctionEnd
774 )";
775 
776   CompileSuccessfully(spirv);
777   spvValidatorOptionsSetBeforeHlslLegalization(getValidatorOptions(), true);
778   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
779   EXPECT_THAT(getDiagnosticString(), HasSubstr("OpFunctionCall Argument <id>"));
780   EXPECT_THAT(getDiagnosticString(),
781               HasSubstr("type does not match Function <id>"));
782 }
783 
TEST_F(ValidateFunctionCall,LogicallyMismatchedPointersArraySize)784 TEST_F(ValidateFunctionCall, LogicallyMismatchedPointersArraySize) {
785   //  Validation should fail because the formal parameter array has a different
786   // number of element than the actual parameter.
787   std::string spirv =
788       R"(
789                OpCapability Shader
790                OpMemoryModel Logical GLSL450
791                OpEntryPoint GLCompute %1 "main"
792                OpExecutionMode %1 LocalSize 1 1 1
793                OpSource HLSL 600
794                OpDecorate %2 DescriptorSet 0
795                OpDecorate %2 Binding 0
796                OpDecorate %_arr_int_uint_10 ArrayStride 4
797                OpMemberDecorate %_struct_4 0 Offset 0
798                OpDecorate %_runtimearr__struct_4 ArrayStride 40
799                OpMemberDecorate %_struct_6 0 Offset 0
800                OpDecorate %_struct_6 BufferBlock
801         %int = OpTypeInt 32 1
802       %int_0 = OpConstant %int 0
803        %uint = OpTypeInt 32 0
804      %uint_0 = OpConstant %uint 0
805     %uint_5 = OpConstant %uint 5
806     %uint_10 = OpConstant %uint 10
807 %_arr_int_uint_10 = OpTypeArray %int %uint_10
808   %_struct_4 = OpTypeStruct %_arr_int_uint_10
809 %_runtimearr__struct_4 = OpTypeRuntimeArray %_struct_4
810   %_struct_6 = OpTypeStruct %_runtimearr__struct_4
811 %_ptr_Uniform__struct_6 = OpTypePointer Uniform %_struct_6
812        %void = OpTypeVoid
813          %14 = OpTypeFunction %void
814 %_ptr_Uniform__struct_4 = OpTypePointer Uniform %_struct_4
815 %_arr_int_uint_5 = OpTypeArray %int %uint_5
816  %_struct_17 = OpTypeStruct %_arr_int_uint_5
817 %_ptr_Function__struct_17 = OpTypePointer Function %_struct_17
818          %19 = OpTypeFunction %void %_ptr_Function__struct_17
819           %2 = OpVariable %_ptr_Uniform__struct_6 Uniform
820           %1 = OpFunction %void None %14
821          %20 = OpLabel
822          %21 = OpAccessChain %_ptr_Uniform__struct_4 %2 %int_0 %uint_0
823          %22 = OpFunctionCall %void %23 %21
824                OpReturn
825                OpFunctionEnd
826          %23 = OpFunction %void None %19
827          %24 = OpFunctionParameter %_ptr_Function__struct_17
828          %25 = OpLabel
829                OpReturn
830                OpFunctionEnd
831 )";
832 
833   CompileSuccessfully(spirv);
834   spvValidatorOptionsSetBeforeHlslLegalization(getValidatorOptions(), true);
835   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
836   EXPECT_THAT(getDiagnosticString(), HasSubstr("OpFunctionCall Argument <id>"));
837   EXPECT_THAT(getDiagnosticString(),
838               HasSubstr("type does not match Function <id>"));
839 }
840 
841 INSTANTIATE_TEST_SUITE_P(StorageClass, ValidateFunctionCall,
842                          Values("UniformConstant", "Input", "Uniform", "Output",
843                                 "Workgroup", "Private", "Function",
844                                 "PushConstant", "Image", "StorageBuffer",
845                                 "AtomicCounter"));
846 }  // namespace
847 }  // namespace val
848 }  // namespace spvtools
849