1 // Copyright (c) 2016 Google Inc.
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 // Validation tests for Universal Limits. (Section 2.17 of the SPIR-V Spec)
16
17 #include <sstream>
18 #include <string>
19 #include <utility>
20
21 #include "gmock/gmock.h"
22 #include "test/unit_spirv.h"
23 #include "test/val/val_fixtures.h"
24
25 namespace spvtools {
26 namespace val {
27 namespace {
28
29 using ::testing::HasSubstr;
30 using ::testing::MatchesRegex;
31
32 using ValidateLimits = spvtest::ValidateBase<bool>;
33
34 std::string header = R"(
35 OpCapability Shader
36 OpCapability Linkage
37 OpMemoryModel Logical GLSL450
38 )";
39
TEST_F(ValidateLimits,IdLargerThanBoundBad)40 TEST_F(ValidateLimits, IdLargerThanBoundBad) {
41 std::string str = header + R"(
42 ; %i32 has ID 1
43 %i32 = OpTypeInt 32 1
44 %c = OpConstant %i32 100
45
46 ; Fake an instruction with 64 as the result id.
47 ; !64 = OpConstantNull %i32
48 !0x3002e !1 !64
49 )";
50
51 CompileSuccessfully(str);
52 ASSERT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
53 EXPECT_THAT(
54 getDiagnosticString(),
55 HasSubstr("Result <id> '64' must be less than the ID bound '3'."));
56 }
57
TEST_F(ValidateLimits,IdEqualToBoundBad)58 TEST_F(ValidateLimits, IdEqualToBoundBad) {
59 std::string str = header + R"(
60 ; %i32 has ID 1
61 %i32 = OpTypeInt 32 1
62 %c = OpConstant %i32 100
63
64 ; Fake an instruction with 64 as the result id.
65 ; !64 = OpConstantNull %i32
66 !0x3002e !1 !64
67 )";
68
69 CompileSuccessfully(str);
70
71 // The largest ID used in this program is 64. Let's overwrite the ID bound in
72 // the header to be 64. This should result in an error because all IDs must
73 // satisfy: 0 < id < bound.
74 OverwriteAssembledBinary(3, 64);
75
76 ASSERT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
77 EXPECT_THAT(
78 getDiagnosticString(),
79 HasSubstr("Result <id> '64' must be less than the ID bound '64'."));
80 }
81
TEST_F(ValidateLimits,IdBoundTooBigDeaultLimit)82 TEST_F(ValidateLimits, IdBoundTooBigDeaultLimit) {
83 std::string str = header;
84
85 CompileSuccessfully(str);
86
87 // The largest ID used in this program is 64. Let's overwrite the ID bound in
88 // the header to be 64. This should result in an error because all IDs must
89 // satisfy: 0 < id < bound.
90 OverwriteAssembledBinary(3, 0x4FFFFF);
91
92 ASSERT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
93 EXPECT_THAT(getDiagnosticString(),
94 HasSubstr("Invalid SPIR-V. The id bound is larger than the max "
95 "id bound 4194303."));
96 }
97
TEST_F(ValidateLimits,IdBoundAtSetLimit)98 TEST_F(ValidateLimits, IdBoundAtSetLimit) {
99 std::string str = header;
100
101 CompileSuccessfully(str);
102
103 // The largest ID used in this program is 64. Let's overwrite the ID bound in
104 // the header to be 64. This should result in an error because all IDs must
105 // satisfy: 0 < id < bound.
106 uint32_t id_bound = 0x4FFFFF;
107
108 OverwriteAssembledBinary(3, id_bound);
109 getValidatorOptions()->universal_limits_.max_id_bound = id_bound;
110
111 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
112 }
113
TEST_F(ValidateLimits,IdBoundJustAboveSetLimit)114 TEST_F(ValidateLimits, IdBoundJustAboveSetLimit) {
115 std::string str = header;
116
117 CompileSuccessfully(str);
118
119 // The largest ID used in this program is 64. Let's overwrite the ID bound in
120 // the header to be 64. This should result in an error because all IDs must
121 // satisfy: 0 < id < bound.
122 uint32_t id_bound = 5242878;
123
124 OverwriteAssembledBinary(3, id_bound);
125 getValidatorOptions()->universal_limits_.max_id_bound = id_bound - 1;
126
127 ASSERT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
128 EXPECT_THAT(getDiagnosticString(),
129 HasSubstr("Invalid SPIR-V. The id bound is larger than the max "
130 "id bound 5242877."));
131 }
132
TEST_F(ValidateLimits,IdBoundAtInMaxLimit)133 TEST_F(ValidateLimits, IdBoundAtInMaxLimit) {
134 std::string str = header;
135
136 CompileSuccessfully(str);
137
138 uint32_t id_bound = std::numeric_limits<uint32_t>::max();
139
140 OverwriteAssembledBinary(3, id_bound);
141 getValidatorOptions()->universal_limits_.max_id_bound = id_bound;
142
143 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
144 }
145
TEST_F(ValidateLimits,StructNumMembersGood)146 TEST_F(ValidateLimits, StructNumMembersGood) {
147 std::ostringstream spirv;
148 spirv << header << R"(
149 %1 = OpTypeInt 32 0
150 %2 = OpTypeStruct)";
151 for (int i = 0; i < 16383; ++i) {
152 spirv << " %1";
153 }
154 CompileSuccessfully(spirv.str());
155 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
156 }
157
TEST_F(ValidateLimits,StructNumMembersExceededBad)158 TEST_F(ValidateLimits, StructNumMembersExceededBad) {
159 std::ostringstream spirv;
160 spirv << header << R"(
161 %1 = OpTypeInt 32 0
162 %2 = OpTypeStruct)";
163 for (int i = 0; i < 16384; ++i) {
164 spirv << " %1";
165 }
166 CompileSuccessfully(spirv.str());
167 ASSERT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
168 EXPECT_THAT(getDiagnosticString(),
169 HasSubstr("Number of OpTypeStruct members (16384) has exceeded "
170 "the limit (16383)."));
171 }
172
TEST_F(ValidateLimits,CustomizedStructNumMembersGood)173 TEST_F(ValidateLimits, CustomizedStructNumMembersGood) {
174 std::ostringstream spirv;
175 spirv << header << R"(
176 %1 = OpTypeInt 32 0
177 %2 = OpTypeStruct)";
178 for (int i = 0; i < 32000; ++i) {
179 spirv << " %1";
180 }
181 spvValidatorOptionsSetUniversalLimit(
182 options_, spv_validator_limit_max_struct_members, 32000u);
183 CompileSuccessfully(spirv.str());
184 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
185 }
186
TEST_F(ValidateLimits,CustomizedStructNumMembersBad)187 TEST_F(ValidateLimits, CustomizedStructNumMembersBad) {
188 std::ostringstream spirv;
189 spirv << header << R"(
190 %1 = OpTypeInt 32 0
191 %2 = OpTypeStruct)";
192 for (int i = 0; i < 32001; ++i) {
193 spirv << " %1";
194 }
195 spvValidatorOptionsSetUniversalLimit(
196 options_, spv_validator_limit_max_struct_members, 32000u);
197 CompileSuccessfully(spirv.str());
198 ASSERT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
199 EXPECT_THAT(getDiagnosticString(),
200 HasSubstr("Number of OpTypeStruct members (32001) has exceeded "
201 "the limit (32000)."));
202 }
203
204 // Valid: Switch statement has 16,383 branches.
TEST_F(ValidateLimits,SwitchNumBranchesGood)205 TEST_F(ValidateLimits, SwitchNumBranchesGood) {
206 std::ostringstream spirv;
207 spirv << header << R"(
208 %1 = OpTypeVoid
209 %2 = OpTypeFunction %1
210 %3 = OpTypeInt 32 0
211 %4 = OpConstant %3 1234
212 %5 = OpFunction %1 None %2
213 %7 = OpLabel
214 %8 = OpIAdd %3 %4 %4
215 OpSwitch %4 %10)";
216
217 // Now add the (literal, label) pairs
218 for (int i = 0; i < 16383; ++i) {
219 spirv << " 1 %10";
220 }
221
222 spirv << R"(
223 %10 = OpLabel
224 OpReturn
225 OpFunctionEnd
226 )";
227
228 CompileSuccessfully(spirv.str());
229 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
230 }
231
232 // Invalid: Switch statement has 16,384 branches.
TEST_F(ValidateLimits,SwitchNumBranchesBad)233 TEST_F(ValidateLimits, SwitchNumBranchesBad) {
234 std::ostringstream spirv;
235 spirv << header << R"(
236 %1 = OpTypeVoid
237 %2 = OpTypeFunction %1
238 %3 = OpTypeInt 32 0
239 %4 = OpConstant %3 1234
240 %5 = OpFunction %1 None %2
241 %7 = OpLabel
242 %8 = OpIAdd %3 %4 %4
243 OpSwitch %4 %10)";
244
245 // Now add the (literal, label) pairs
246 for (int i = 0; i < 16384; ++i) {
247 spirv << " 1 %10";
248 }
249
250 spirv << R"(
251 %10 = OpLabel
252 OpReturn
253 OpFunctionEnd
254 )";
255
256 CompileSuccessfully(spirv.str());
257 ASSERT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
258 EXPECT_THAT(getDiagnosticString(),
259 HasSubstr("Number of (literal, label) pairs in OpSwitch (16384) "
260 "exceeds the limit (16383)."));
261 }
262
263 // Valid: Switch statement has 10 branches (limit is 10)
TEST_F(ValidateLimits,CustomizedSwitchNumBranchesGood)264 TEST_F(ValidateLimits, CustomizedSwitchNumBranchesGood) {
265 std::ostringstream spirv;
266 spirv << header << R"(
267 %1 = OpTypeVoid
268 %2 = OpTypeFunction %1
269 %3 = OpTypeInt 32 0
270 %4 = OpConstant %3 1234
271 %5 = OpFunction %1 None %2
272 %7 = OpLabel
273 %8 = OpIAdd %3 %4 %4
274 OpSwitch %4 %10)";
275
276 // Now add the (literal, label) pairs
277 for (int i = 0; i < 10; ++i) {
278 spirv << " 1 %10";
279 }
280
281 spirv << R"(
282 %10 = OpLabel
283 OpReturn
284 OpFunctionEnd
285 )";
286
287 spvValidatorOptionsSetUniversalLimit(
288 options_, spv_validator_limit_max_switch_branches, 10u);
289 CompileSuccessfully(spirv.str());
290 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
291 }
292
293 // Invalid: Switch statement has 11 branches (limit is 10)
TEST_F(ValidateLimits,CustomizedSwitchNumBranchesBad)294 TEST_F(ValidateLimits, CustomizedSwitchNumBranchesBad) {
295 std::ostringstream spirv;
296 spirv << header << R"(
297 %1 = OpTypeVoid
298 %2 = OpTypeFunction %1
299 %3 = OpTypeInt 32 0
300 %4 = OpConstant %3 1234
301 %5 = OpFunction %1 None %2
302 %7 = OpLabel
303 %8 = OpIAdd %3 %4 %4
304 OpSwitch %4 %10)";
305
306 // Now add the (literal, label) pairs
307 for (int i = 0; i < 11; ++i) {
308 spirv << " 1 %10";
309 }
310
311 spirv << R"(
312 %10 = OpLabel
313 OpReturn
314 OpFunctionEnd
315 )";
316
317 spvValidatorOptionsSetUniversalLimit(
318 options_, spv_validator_limit_max_switch_branches, 10u);
319 CompileSuccessfully(spirv.str());
320 ASSERT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
321 EXPECT_THAT(getDiagnosticString(),
322 HasSubstr("Number of (literal, label) pairs in OpSwitch (11) "
323 "exceeds the limit (10)."));
324 }
325
326 // Valid: OpTypeFunction with 255 arguments.
TEST_F(ValidateLimits,OpTypeFunctionGood)327 TEST_F(ValidateLimits, OpTypeFunctionGood) {
328 int num_args = 255;
329 std::ostringstream spirv;
330 spirv << header << R"(
331 %1 = OpTypeInt 32 0
332 %2 = OpTypeFunction %1)";
333 // add parameters
334 for (int i = 0; i < num_args; ++i) {
335 spirv << " %1";
336 }
337 CompileSuccessfully(spirv.str());
338 EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
339 }
340
341 // Invalid: OpTypeFunction with 256 arguments. (limit is 255 according to the
342 // spec Universal Limits (2.17).
TEST_F(ValidateLimits,OpTypeFunctionBad)343 TEST_F(ValidateLimits, OpTypeFunctionBad) {
344 int num_args = 256;
345 std::ostringstream spirv;
346 spirv << header << R"(
347 %1 = OpTypeInt 32 0
348 %2 = OpTypeFunction %1)";
349 for (int i = 0; i < num_args; ++i) {
350 spirv << " %1";
351 }
352 CompileSuccessfully(spirv.str());
353 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
354 EXPECT_THAT(getDiagnosticString(),
355 HasSubstr("OpTypeFunction may not take more than 255 arguments. "
356 "OpTypeFunction <id> '2[%2]' has 256 arguments."));
357 }
358
359 // Valid: OpTypeFunction with 100 arguments (Custom limit: 100)
TEST_F(ValidateLimits,CustomizedOpTypeFunctionGood)360 TEST_F(ValidateLimits, CustomizedOpTypeFunctionGood) {
361 int num_args = 100;
362 std::ostringstream spirv;
363 spirv << header << R"(
364 %1 = OpTypeInt 32 0
365 %2 = OpTypeFunction %1)";
366 // add parameters
367 for (int i = 0; i < num_args; ++i) {
368 spirv << " %1";
369 }
370 spvValidatorOptionsSetUniversalLimit(
371 options_, spv_validator_limit_max_function_args, 100u);
372 CompileSuccessfully(spirv.str());
373 EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
374 }
375
376 // Invalid: OpTypeFunction with 101 arguments. (Custom limit: 100)
TEST_F(ValidateLimits,CustomizedOpTypeFunctionBad)377 TEST_F(ValidateLimits, CustomizedOpTypeFunctionBad) {
378 int num_args = 101;
379 std::ostringstream spirv;
380 spirv << header << R"(
381 %1 = OpTypeInt 32 0
382 %2 = OpTypeFunction %1)";
383 for (int i = 0; i < num_args; ++i) {
384 spirv << " %1";
385 }
386 spvValidatorOptionsSetUniversalLimit(
387 options_, spv_validator_limit_max_function_args, 100u);
388 CompileSuccessfully(spirv.str());
389 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
390 EXPECT_THAT(getDiagnosticString(),
391 HasSubstr("OpTypeFunction may not take more than 100 arguments. "
392 "OpTypeFunction <id> '2[%2]' has 101 arguments."));
393 }
394
395 // Valid: module has 65,535 global variables.
TEST_F(ValidateLimits,NumGlobalVarsGood)396 TEST_F(ValidateLimits, NumGlobalVarsGood) {
397 int num_globals = 65535;
398 std::ostringstream spirv;
399 spirv << header << R"(
400 %int = OpTypeInt 32 0
401 %_ptr_int = OpTypePointer Input %int
402 )";
403
404 for (int i = 0; i < num_globals; ++i) {
405 spirv << "%var_" << i << " = OpVariable %_ptr_int Input\n";
406 }
407
408 CompileSuccessfully(spirv.str());
409 EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
410 }
411
412 // Invalid: module has 65,536 global variables (limit is 65,535).
TEST_F(ValidateLimits,NumGlobalVarsBad)413 TEST_F(ValidateLimits, NumGlobalVarsBad) {
414 int num_globals = 65536;
415 std::ostringstream spirv;
416 spirv << header << R"(
417 %int = OpTypeInt 32 0
418 %_ptr_int = OpTypePointer Input %int
419 )";
420
421 for (int i = 0; i < num_globals; ++i) {
422 spirv << "%var_" << i << " = OpVariable %_ptr_int Input\n";
423 }
424
425 CompileSuccessfully(spirv.str());
426 EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
427 EXPECT_THAT(getDiagnosticString(),
428 HasSubstr("Number of Global Variables (Storage Class other than "
429 "'Function') exceeded the valid limit (65535)."));
430 }
431
432 // Valid: module has 50 global variables (limit is 50)
TEST_F(ValidateLimits,CustomizedNumGlobalVarsGood)433 TEST_F(ValidateLimits, CustomizedNumGlobalVarsGood) {
434 int num_globals = 50;
435 std::ostringstream spirv;
436 spirv << header << R"(
437 %int = OpTypeInt 32 0
438 %_ptr_int = OpTypePointer Input %int
439 )";
440
441 for (int i = 0; i < num_globals; ++i) {
442 spirv << "%var_" << i << " = OpVariable %_ptr_int Input\n";
443 }
444
445 spvValidatorOptionsSetUniversalLimit(
446 options_, spv_validator_limit_max_global_variables, 50u);
447 CompileSuccessfully(spirv.str());
448 EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
449 }
450
451 // Invalid: module has 51 global variables (limit is 50).
TEST_F(ValidateLimits,CustomizedNumGlobalVarsBad)452 TEST_F(ValidateLimits, CustomizedNumGlobalVarsBad) {
453 int num_globals = 51;
454 std::ostringstream spirv;
455 spirv << header << R"(
456 %int = OpTypeInt 32 0
457 %_ptr_int = OpTypePointer Input %int
458 )";
459
460 for (int i = 0; i < num_globals; ++i) {
461 spirv << "%var_" << i << " = OpVariable %_ptr_int Input\n";
462 }
463
464 spvValidatorOptionsSetUniversalLimit(
465 options_, spv_validator_limit_max_global_variables, 50u);
466 CompileSuccessfully(spirv.str());
467 EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
468 EXPECT_THAT(getDiagnosticString(),
469 HasSubstr("Number of Global Variables (Storage Class other than "
470 "'Function') exceeded the valid limit (50)."));
471 }
472
473 // Valid: module has 524,287 local variables.
474 // Note: AppVeyor limits process time to 300s. For a VisualStudio Debug
475 // build, going up to 524287 local variables gets too close to that
476 // limit. So test with an artificially lowered limit.
TEST_F(ValidateLimits,NumLocalVarsGoodArtificiallyLowLimit5K)477 TEST_F(ValidateLimits, NumLocalVarsGoodArtificiallyLowLimit5K) {
478 int num_locals = 5000;
479 std::ostringstream spirv;
480 spirv << header << R"(
481 %int = OpTypeInt 32 0
482 %_ptr_int = OpTypePointer Function %int
483 %voidt = OpTypeVoid
484 %funct = OpTypeFunction %voidt
485 %main = OpFunction %voidt None %funct
486 %entry = OpLabel
487 )";
488
489 for (int i = 0; i < num_locals; ++i) {
490 spirv << "%var_" << i << " = OpVariable %_ptr_int Function\n";
491 }
492
493 spirv << R"(
494 OpReturn
495 OpFunctionEnd
496 )";
497
498 CompileSuccessfully(spirv.str());
499 // Artificially limit it.
500 spvValidatorOptionsSetUniversalLimit(
501 options_, spv_validator_limit_max_local_variables, num_locals);
502 EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
503 }
504
505 // Invalid: module has 524,288 local variables (limit is 524,287).
506 // Artificially limit the check to 5001.
TEST_F(ValidateLimits,NumLocalVarsBadArtificiallyLowLimit5K)507 TEST_F(ValidateLimits, NumLocalVarsBadArtificiallyLowLimit5K) {
508 int num_locals = 5001;
509 std::ostringstream spirv;
510 spirv << header << R"(
511 %int = OpTypeInt 32 0
512 %_ptr_int = OpTypePointer Function %int
513 %voidt = OpTypeVoid
514 %funct = OpTypeFunction %voidt
515 %main = OpFunction %voidt None %funct
516 %entry = OpLabel
517 )";
518
519 for (int i = 0; i < num_locals; ++i) {
520 spirv << "%var_" << i << " = OpVariable %_ptr_int Function\n";
521 }
522
523 spirv << R"(
524 OpReturn
525 OpFunctionEnd
526 )";
527
528 CompileSuccessfully(spirv.str());
529 spvValidatorOptionsSetUniversalLimit(
530 options_, spv_validator_limit_max_local_variables, 5000u);
531 EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
532 EXPECT_THAT(getDiagnosticString(),
533 HasSubstr("Number of local variables ('Function' Storage Class) "
534 "exceeded the valid limit (5000)."));
535 }
536
537 // Valid: module has 100 local variables (limit is 100).
TEST_F(ValidateLimits,CustomizedNumLocalVarsGood)538 TEST_F(ValidateLimits, CustomizedNumLocalVarsGood) {
539 int num_locals = 100;
540 std::ostringstream spirv;
541 spirv << header << R"(
542 %int = OpTypeInt 32 0
543 %_ptr_int = OpTypePointer Function %int
544 %voidt = OpTypeVoid
545 %funct = OpTypeFunction %voidt
546 %main = OpFunction %voidt None %funct
547 %entry = OpLabel
548 )";
549
550 for (int i = 0; i < num_locals; ++i) {
551 spirv << "%var_" << i << " = OpVariable %_ptr_int Function\n";
552 }
553
554 spirv << R"(
555 OpReturn
556 OpFunctionEnd
557 )";
558
559 spvValidatorOptionsSetUniversalLimit(
560 options_, spv_validator_limit_max_local_variables, 100u);
561 CompileSuccessfully(spirv.str());
562 EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
563 }
564
565 // Invalid: module has 101 local variables (limit is 100).
TEST_F(ValidateLimits,CustomizedNumLocalVarsBad)566 TEST_F(ValidateLimits, CustomizedNumLocalVarsBad) {
567 int num_locals = 101;
568 std::ostringstream spirv;
569 spirv << header << R"(
570 %int = OpTypeInt 32 0
571 %_ptr_int = OpTypePointer Function %int
572 %voidt = OpTypeVoid
573 %funct = OpTypeFunction %voidt
574 %main = OpFunction %voidt None %funct
575 %entry = OpLabel
576 )";
577
578 for (int i = 0; i < num_locals; ++i) {
579 spirv << "%var_" << i << " = OpVariable %_ptr_int Function\n";
580 }
581
582 spirv << R"(
583 OpReturn
584 OpFunctionEnd
585 )";
586
587 spvValidatorOptionsSetUniversalLimit(
588 options_, spv_validator_limit_max_local_variables, 100u);
589 CompileSuccessfully(spirv.str());
590 EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
591 EXPECT_THAT(getDiagnosticString(),
592 HasSubstr("Number of local variables ('Function' Storage Class) "
593 "exceeded the valid limit (100)."));
594 }
595
596 // Valid: Structure nesting depth of 255.
TEST_F(ValidateLimits,StructNestingDepthGood)597 TEST_F(ValidateLimits, StructNestingDepthGood) {
598 std::ostringstream spirv;
599 spirv << header << R"(
600 %int = OpTypeInt 32 0
601 %s_depth_1 = OpTypeStruct %int
602 )";
603 for (auto i = 2; i <= 255; ++i) {
604 spirv << "%s_depth_" << i << " = OpTypeStruct %int %s_depth_" << i - 1;
605 spirv << "\n";
606 }
607 CompileSuccessfully(spirv.str());
608 EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
609 }
610
611 // Invalid: Structure nesting depth of 256.
TEST_F(ValidateLimits,StructNestingDepthBad)612 TEST_F(ValidateLimits, StructNestingDepthBad) {
613 std::ostringstream spirv;
614 spirv << header << R"(
615 %int = OpTypeInt 32 0
616 %s_depth_1 = OpTypeStruct %int
617 )";
618 for (auto i = 2; i <= 256; ++i) {
619 spirv << "%s_depth_" << i << " = OpTypeStruct %int %s_depth_" << i - 1;
620 spirv << "\n";
621 }
622 CompileSuccessfully(spirv.str());
623 EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
624 EXPECT_THAT(
625 getDiagnosticString(),
626 HasSubstr(
627 "Structure Nesting Depth may not be larger than 255. Found 256."));
628 }
629
630 // Valid: Structure nesting depth of 100 (limit is 100).
TEST_F(ValidateLimits,CustomizedStructNestingDepthGood)631 TEST_F(ValidateLimits, CustomizedStructNestingDepthGood) {
632 std::ostringstream spirv;
633 spirv << header << R"(
634 %int = OpTypeInt 32 0
635 %s_depth_1 = OpTypeStruct %int
636 )";
637 for (auto i = 2; i <= 100; ++i) {
638 spirv << "%s_depth_" << i << " = OpTypeStruct %int %s_depth_" << i - 1;
639 spirv << "\n";
640 }
641 spvValidatorOptionsSetUniversalLimit(
642 options_, spv_validator_limit_max_struct_depth, 100u);
643 CompileSuccessfully(spirv.str());
644 EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
645 }
646
647 // Invalid: Structure nesting depth of 101 (limit is 100).
TEST_F(ValidateLimits,CustomizedStructNestingDepthBad)648 TEST_F(ValidateLimits, CustomizedStructNestingDepthBad) {
649 std::ostringstream spirv;
650 spirv << header << R"(
651 %int = OpTypeInt 32 0
652 %s_depth_1 = OpTypeStruct %int
653 )";
654 for (auto i = 2; i <= 101; ++i) {
655 spirv << "%s_depth_" << i << " = OpTypeStruct %int %s_depth_" << i - 1;
656 spirv << "\n";
657 }
658 spvValidatorOptionsSetUniversalLimit(
659 options_, spv_validator_limit_max_struct_depth, 100u);
660 CompileSuccessfully(spirv.str());
661 EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
662 EXPECT_THAT(
663 getDiagnosticString(),
664 HasSubstr(
665 "Structure Nesting Depth may not be larger than 100. Found 101."));
666 }
667
668 // clang-format off
669 // Generates an SPIRV program with the given control flow nesting depth
GenerateSpirvProgramWithCfgNestingDepth(std::string & str,int depth)670 void GenerateSpirvProgramWithCfgNestingDepth(std::string& str, int depth) {
671 std::ostringstream spirv;
672 spirv << header << R"(
673 %void = OpTypeVoid
674 %3 = OpTypeFunction %void
675 %bool = OpTypeBool
676 %12 = OpConstantTrue %bool
677 %main = OpFunction %void None %3
678 %5 = OpLabel
679 OpBranch %6
680 %6 = OpLabel
681 OpLoopMerge %8 %9 None
682 OpBranch %10
683 %10 = OpLabel
684 OpBranchConditional %12 %7 %8
685 %7 = OpLabel
686 )";
687 int first_id = 13;
688 int last_id = 14;
689 // We already have 1 level of nesting due to the Loop.
690 int num_if_conditions = depth-1;
691 int largest_index = first_id + 2*num_if_conditions - 2;
692 for (int i = first_id; i <= largest_index; i = i + 2) {
693 spirv << "OpSelectionMerge %" << i+1 << " None" << "\n";
694 spirv << "OpBranchConditional %12 " << "%" << i << " %" << i+1 << "\n";
695 spirv << "%" << i << " = OpLabel" << "\n";
696 }
697 spirv << "OpBranch %9" << "\n";
698
699 for (int i = largest_index+1; i > last_id; i = i - 2) {
700 spirv << "%" << i << " = OpLabel" << "\n";
701 spirv << "OpBranch %" << i-2 << "\n";
702 }
703 spirv << "%" << last_id << " = OpLabel" << "\n";
704 spirv << "OpBranch %9" << "\n";
705 spirv << R"(
706 %9 = OpLabel
707 OpBranch %6
708 %8 = OpLabel
709 OpReturn
710 OpFunctionEnd
711 )";
712 str = spirv.str();
713 }
714 // clang-format on
715
716 // Invalid: Control Flow Nesting depth is 1024. (limit is 1023).
TEST_F(ValidateLimits,ControlFlowDepthBad)717 TEST_F(ValidateLimits, ControlFlowDepthBad) {
718 std::string spirv;
719 GenerateSpirvProgramWithCfgNestingDepth(spirv, 1024);
720 CompileSuccessfully(spirv);
721 EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
722 EXPECT_THAT(getDiagnosticString(),
723 HasSubstr("Maximum Control Flow nesting depth exceeded."));
724 }
725
726 // Valid: Control Flow Nesting depth is 10 (custom limit: 10).
TEST_F(ValidateLimits,CustomizedControlFlowDepthGood)727 TEST_F(ValidateLimits, CustomizedControlFlowDepthGood) {
728 std::string spirv;
729 GenerateSpirvProgramWithCfgNestingDepth(spirv, 10);
730 spvValidatorOptionsSetUniversalLimit(
731 options_, spv_validator_limit_max_control_flow_nesting_depth, 10u);
732 CompileSuccessfully(spirv);
733 EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
734 }
735
736 // Invalid: Control Flow Nesting depth is 11. (custom limit: 10).
TEST_F(ValidateLimits,CustomizedControlFlowDepthBad)737 TEST_F(ValidateLimits, CustomizedControlFlowDepthBad) {
738 std::string spirv;
739 GenerateSpirvProgramWithCfgNestingDepth(spirv, 11);
740 spvValidatorOptionsSetUniversalLimit(
741 options_, spv_validator_limit_max_control_flow_nesting_depth, 10u);
742 CompileSuccessfully(spirv);
743 EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
744 EXPECT_THAT(getDiagnosticString(),
745 HasSubstr("Maximum Control Flow nesting depth exceeded."));
746 }
747
748 // Valid. The purpose here is to test the CFG depth calculation code when a loop
749 // continue target is the loop iteself. It also exercises the case where a loop
750 // is unreachable.
TEST_F(ValidateLimits,ControlFlowNoEntryToLoopGood)751 TEST_F(ValidateLimits, ControlFlowNoEntryToLoopGood) {
752 std::string str = header + R"(
753 OpName %entry "entry"
754 OpName %loop "loop"
755 OpName %exit "exit"
756 %voidt = OpTypeVoid
757 %boolt = OpTypeBool
758 %undef = OpUndef %boolt
759 %funct = OpTypeFunction %voidt
760 %main = OpFunction %voidt None %funct
761 %entry = OpLabel
762 OpBranch %exit
763 %loop = OpLabel
764 OpLoopMerge %dead %loop None
765 OpBranchConditional %undef %loop %loop
766 %dead = OpLabel
767 OpUnreachable
768 %exit = OpLabel
769 OpReturn
770 OpFunctionEnd
771 )";
772 CompileSuccessfully(str);
773 EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
774 }
775
776 } // namespace
777 } // namespace val
778 } // namespace spvtools
779