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