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