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