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