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 OpSelectionMerge %10 None
216 OpSwitch %4 %10)";
217
218 // Now add the (literal, label) pairs
219 for (int i = 0; i < 16383; ++i) {
220 spirv << " 1 %10";
221 }
222
223 spirv << R"(
224 %10 = OpLabel
225 OpReturn
226 OpFunctionEnd
227 )";
228
229 CompileSuccessfully(spirv.str());
230 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
231 }
232
233 // Invalid: Switch statement has 16,384 branches.
TEST_F(ValidateLimits,SwitchNumBranchesBad)234 TEST_F(ValidateLimits, SwitchNumBranchesBad) {
235 std::ostringstream spirv;
236 spirv << header << R"(
237 %1 = OpTypeVoid
238 %2 = OpTypeFunction %1
239 %3 = OpTypeInt 32 0
240 %4 = OpConstant %3 1234
241 %5 = OpFunction %1 None %2
242 %7 = OpLabel
243 %8 = OpIAdd %3 %4 %4
244 OpSelectionMerge %10 None
245 OpSwitch %4 %10)";
246
247 // Now add the (literal, label) pairs
248 for (int i = 0; i < 16384; ++i) {
249 spirv << " 1 %10";
250 }
251
252 spirv << R"(
253 %10 = OpLabel
254 OpReturn
255 OpFunctionEnd
256 )";
257
258 CompileSuccessfully(spirv.str());
259 ASSERT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
260 EXPECT_THAT(getDiagnosticString(),
261 HasSubstr("Number of (literal, label) pairs in OpSwitch (16384) "
262 "exceeds the limit (16383)."));
263 }
264
265 // Valid: Switch statement has 10 branches (limit is 10)
TEST_F(ValidateLimits,CustomizedSwitchNumBranchesGood)266 TEST_F(ValidateLimits, CustomizedSwitchNumBranchesGood) {
267 std::ostringstream spirv;
268 spirv << header << R"(
269 %1 = OpTypeVoid
270 %2 = OpTypeFunction %1
271 %3 = OpTypeInt 32 0
272 %4 = OpConstant %3 1234
273 %5 = OpFunction %1 None %2
274 %7 = OpLabel
275 %8 = OpIAdd %3 %4 %4
276 OpSelectionMerge %10 None
277 OpSwitch %4 %10)";
278
279 // Now add the (literal, label) pairs
280 for (int i = 0; i < 10; ++i) {
281 spirv << " 1 %10";
282 }
283
284 spirv << R"(
285 %10 = OpLabel
286 OpReturn
287 OpFunctionEnd
288 )";
289
290 spvValidatorOptionsSetUniversalLimit(
291 options_, spv_validator_limit_max_switch_branches, 10u);
292 CompileSuccessfully(spirv.str());
293 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
294 }
295
296 // Invalid: Switch statement has 11 branches (limit is 10)
TEST_F(ValidateLimits,CustomizedSwitchNumBranchesBad)297 TEST_F(ValidateLimits, CustomizedSwitchNumBranchesBad) {
298 std::ostringstream spirv;
299 spirv << header << R"(
300 %1 = OpTypeVoid
301 %2 = OpTypeFunction %1
302 %3 = OpTypeInt 32 0
303 %4 = OpConstant %3 1234
304 %5 = OpFunction %1 None %2
305 %7 = OpLabel
306 %8 = OpIAdd %3 %4 %4
307 OpSelectionMerge %10 None
308 OpSwitch %4 %10)";
309
310 // Now add the (literal, label) pairs
311 for (int i = 0; i < 11; ++i) {
312 spirv << " 1 %10";
313 }
314
315 spirv << R"(
316 %10 = OpLabel
317 OpReturn
318 OpFunctionEnd
319 )";
320
321 spvValidatorOptionsSetUniversalLimit(
322 options_, spv_validator_limit_max_switch_branches, 10u);
323 CompileSuccessfully(spirv.str());
324 ASSERT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
325 EXPECT_THAT(getDiagnosticString(),
326 HasSubstr("Number of (literal, label) pairs in OpSwitch (11) "
327 "exceeds the limit (10)."));
328 }
329
330 // Valid: OpTypeFunction with 255 arguments.
TEST_F(ValidateLimits,OpTypeFunctionGood)331 TEST_F(ValidateLimits, OpTypeFunctionGood) {
332 int num_args = 255;
333 std::ostringstream spirv;
334 spirv << header << R"(
335 %1 = OpTypeInt 32 0
336 %2 = OpTypeFunction %1)";
337 // add parameters
338 for (int i = 0; i < num_args; ++i) {
339 spirv << " %1";
340 }
341 CompileSuccessfully(spirv.str());
342 EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
343 }
344
345 // Invalid: OpTypeFunction with 256 arguments. (limit is 255 according to the
346 // spec Universal Limits (2.17).
TEST_F(ValidateLimits,OpTypeFunctionBad)347 TEST_F(ValidateLimits, OpTypeFunctionBad) {
348 int num_args = 256;
349 std::ostringstream spirv;
350 spirv << header << R"(
351 %1 = OpTypeInt 32 0
352 %2 = OpTypeFunction %1)";
353 for (int i = 0; i < num_args; ++i) {
354 spirv << " %1";
355 }
356 CompileSuccessfully(spirv.str());
357 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
358 EXPECT_THAT(getDiagnosticString(),
359 HasSubstr("OpTypeFunction may not take more than 255 arguments. "
360 "OpTypeFunction <id> '2[%2]' has 256 arguments."));
361 }
362
363 // Valid: OpTypeFunction with 100 arguments (Custom limit: 100)
TEST_F(ValidateLimits,CustomizedOpTypeFunctionGood)364 TEST_F(ValidateLimits, CustomizedOpTypeFunctionGood) {
365 int num_args = 100;
366 std::ostringstream spirv;
367 spirv << header << R"(
368 %1 = OpTypeInt 32 0
369 %2 = OpTypeFunction %1)";
370 // add parameters
371 for (int i = 0; i < num_args; ++i) {
372 spirv << " %1";
373 }
374 spvValidatorOptionsSetUniversalLimit(
375 options_, spv_validator_limit_max_function_args, 100u);
376 CompileSuccessfully(spirv.str());
377 EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
378 }
379
380 // Invalid: OpTypeFunction with 101 arguments. (Custom limit: 100)
TEST_F(ValidateLimits,CustomizedOpTypeFunctionBad)381 TEST_F(ValidateLimits, CustomizedOpTypeFunctionBad) {
382 int num_args = 101;
383 std::ostringstream spirv;
384 spirv << header << R"(
385 %1 = OpTypeInt 32 0
386 %2 = OpTypeFunction %1)";
387 for (int i = 0; i < num_args; ++i) {
388 spirv << " %1";
389 }
390 spvValidatorOptionsSetUniversalLimit(
391 options_, spv_validator_limit_max_function_args, 100u);
392 CompileSuccessfully(spirv.str());
393 EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
394 EXPECT_THAT(getDiagnosticString(),
395 HasSubstr("OpTypeFunction may not take more than 100 arguments. "
396 "OpTypeFunction <id> '2[%2]' has 101 arguments."));
397 }
398
399 // Valid: module has 65,535 global variables.
TEST_F(ValidateLimits,NumGlobalVarsGood)400 TEST_F(ValidateLimits, NumGlobalVarsGood) {
401 int num_globals = 65535;
402 std::ostringstream spirv;
403 spirv << header << R"(
404 %int = OpTypeInt 32 0
405 %_ptr_int = OpTypePointer Input %int
406 )";
407
408 for (int i = 0; i < num_globals; ++i) {
409 spirv << "%var_" << i << " = OpVariable %_ptr_int Input\n";
410 }
411
412 CompileSuccessfully(spirv.str());
413 EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
414 }
415
416 // Invalid: module has 65,536 global variables (limit is 65,535).
TEST_F(ValidateLimits,NumGlobalVarsBad)417 TEST_F(ValidateLimits, NumGlobalVarsBad) {
418 int num_globals = 65536;
419 std::ostringstream spirv;
420 spirv << header << R"(
421 %int = OpTypeInt 32 0
422 %_ptr_int = OpTypePointer Input %int
423 )";
424
425 for (int i = 0; i < num_globals; ++i) {
426 spirv << "%var_" << i << " = OpVariable %_ptr_int Input\n";
427 }
428
429 CompileSuccessfully(spirv.str());
430 EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
431 EXPECT_THAT(getDiagnosticString(),
432 HasSubstr("Number of Global Variables (Storage Class other than "
433 "'Function') exceeded the valid limit (65535)."));
434 }
435
436 // Valid: module has 50 global variables (limit is 50)
TEST_F(ValidateLimits,CustomizedNumGlobalVarsGood)437 TEST_F(ValidateLimits, CustomizedNumGlobalVarsGood) {
438 int num_globals = 50;
439 std::ostringstream spirv;
440 spirv << header << R"(
441 %int = OpTypeInt 32 0
442 %_ptr_int = OpTypePointer Input %int
443 )";
444
445 for (int i = 0; i < num_globals; ++i) {
446 spirv << "%var_" << i << " = OpVariable %_ptr_int Input\n";
447 }
448
449 spvValidatorOptionsSetUniversalLimit(
450 options_, spv_validator_limit_max_global_variables, 50u);
451 CompileSuccessfully(spirv.str());
452 EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
453 }
454
455 // Invalid: module has 51 global variables (limit is 50).
TEST_F(ValidateLimits,CustomizedNumGlobalVarsBad)456 TEST_F(ValidateLimits, CustomizedNumGlobalVarsBad) {
457 int num_globals = 51;
458 std::ostringstream spirv;
459 spirv << header << R"(
460 %int = OpTypeInt 32 0
461 %_ptr_int = OpTypePointer Input %int
462 )";
463
464 for (int i = 0; i < num_globals; ++i) {
465 spirv << "%var_" << i << " = OpVariable %_ptr_int Input\n";
466 }
467
468 spvValidatorOptionsSetUniversalLimit(
469 options_, spv_validator_limit_max_global_variables, 50u);
470 CompileSuccessfully(spirv.str());
471 EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
472 EXPECT_THAT(getDiagnosticString(),
473 HasSubstr("Number of Global Variables (Storage Class other than "
474 "'Function') exceeded the valid limit (50)."));
475 }
476
477 // Valid: module has 524,287 local variables.
478 // Note: AppVeyor limits process time to 300s. For a VisualStudio Debug
479 // build, going up to 524287 local variables gets too close to that
480 // limit. So test with an artificially lowered limit.
TEST_F(ValidateLimits,NumLocalVarsGoodArtificiallyLowLimit5K)481 TEST_F(ValidateLimits, NumLocalVarsGoodArtificiallyLowLimit5K) {
482 int num_locals = 5000;
483 std::ostringstream spirv;
484 spirv << header << R"(
485 %int = OpTypeInt 32 0
486 %_ptr_int = OpTypePointer Function %int
487 %voidt = OpTypeVoid
488 %funct = OpTypeFunction %voidt
489 %main = OpFunction %voidt None %funct
490 %entry = OpLabel
491 )";
492
493 for (int i = 0; i < num_locals; ++i) {
494 spirv << "%var_" << i << " = OpVariable %_ptr_int Function\n";
495 }
496
497 spirv << R"(
498 OpReturn
499 OpFunctionEnd
500 )";
501
502 CompileSuccessfully(spirv.str());
503 // Artificially limit it.
504 spvValidatorOptionsSetUniversalLimit(
505 options_, spv_validator_limit_max_local_variables, num_locals);
506 EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
507 }
508
509 // Invalid: module has 524,288 local variables (limit is 524,287).
510 // Artificially limit the check to 5001.
TEST_F(ValidateLimits,NumLocalVarsBadArtificiallyLowLimit5K)511 TEST_F(ValidateLimits, NumLocalVarsBadArtificiallyLowLimit5K) {
512 int num_locals = 5001;
513 std::ostringstream spirv;
514 spirv << header << R"(
515 %int = OpTypeInt 32 0
516 %_ptr_int = OpTypePointer Function %int
517 %voidt = OpTypeVoid
518 %funct = OpTypeFunction %voidt
519 %main = OpFunction %voidt None %funct
520 %entry = OpLabel
521 )";
522
523 for (int i = 0; i < num_locals; ++i) {
524 spirv << "%var_" << i << " = OpVariable %_ptr_int Function\n";
525 }
526
527 spirv << R"(
528 OpReturn
529 OpFunctionEnd
530 )";
531
532 CompileSuccessfully(spirv.str());
533 spvValidatorOptionsSetUniversalLimit(
534 options_, spv_validator_limit_max_local_variables, 5000u);
535 EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
536 EXPECT_THAT(getDiagnosticString(),
537 HasSubstr("Number of local variables ('Function' Storage Class) "
538 "exceeded the valid limit (5000)."));
539 }
540
541 // Valid: module has 100 local variables (limit is 100).
TEST_F(ValidateLimits,CustomizedNumLocalVarsGood)542 TEST_F(ValidateLimits, CustomizedNumLocalVarsGood) {
543 int num_locals = 100;
544 std::ostringstream spirv;
545 spirv << header << R"(
546 %int = OpTypeInt 32 0
547 %_ptr_int = OpTypePointer Function %int
548 %voidt = OpTypeVoid
549 %funct = OpTypeFunction %voidt
550 %main = OpFunction %voidt None %funct
551 %entry = OpLabel
552 )";
553
554 for (int i = 0; i < num_locals; ++i) {
555 spirv << "%var_" << i << " = OpVariable %_ptr_int Function\n";
556 }
557
558 spirv << R"(
559 OpReturn
560 OpFunctionEnd
561 )";
562
563 spvValidatorOptionsSetUniversalLimit(
564 options_, spv_validator_limit_max_local_variables, 100u);
565 CompileSuccessfully(spirv.str());
566 EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
567 }
568
569 // Invalid: module has 101 local variables (limit is 100).
TEST_F(ValidateLimits,CustomizedNumLocalVarsBad)570 TEST_F(ValidateLimits, CustomizedNumLocalVarsBad) {
571 int num_locals = 101;
572 std::ostringstream spirv;
573 spirv << header << R"(
574 %int = OpTypeInt 32 0
575 %_ptr_int = OpTypePointer Function %int
576 %voidt = OpTypeVoid
577 %funct = OpTypeFunction %voidt
578 %main = OpFunction %voidt None %funct
579 %entry = OpLabel
580 )";
581
582 for (int i = 0; i < num_locals; ++i) {
583 spirv << "%var_" << i << " = OpVariable %_ptr_int Function\n";
584 }
585
586 spirv << R"(
587 OpReturn
588 OpFunctionEnd
589 )";
590
591 spvValidatorOptionsSetUniversalLimit(
592 options_, spv_validator_limit_max_local_variables, 100u);
593 CompileSuccessfully(spirv.str());
594 EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
595 EXPECT_THAT(getDiagnosticString(),
596 HasSubstr("Number of local variables ('Function' Storage Class) "
597 "exceeded the valid limit (100)."));
598 }
599
600 // Valid: Structure nesting depth of 255.
TEST_F(ValidateLimits,StructNestingDepthGood)601 TEST_F(ValidateLimits, StructNestingDepthGood) {
602 std::ostringstream spirv;
603 spirv << header << R"(
604 %int = OpTypeInt 32 0
605 %s_depth_1 = OpTypeStruct %int
606 )";
607 for (auto i = 2; i <= 255; ++i) {
608 spirv << "%s_depth_" << i << " = OpTypeStruct %int %s_depth_" << i - 1;
609 spirv << "\n";
610 }
611 CompileSuccessfully(spirv.str());
612 EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
613 }
614
615 // Invalid: Structure nesting depth of 256.
TEST_F(ValidateLimits,StructNestingDepthBad)616 TEST_F(ValidateLimits, StructNestingDepthBad) {
617 std::ostringstream spirv;
618 spirv << header << R"(
619 %int = OpTypeInt 32 0
620 %s_depth_1 = OpTypeStruct %int
621 )";
622 for (auto i = 2; i <= 256; ++i) {
623 spirv << "%s_depth_" << i << " = OpTypeStruct %int %s_depth_" << i - 1;
624 spirv << "\n";
625 }
626 CompileSuccessfully(spirv.str());
627 EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
628 EXPECT_THAT(
629 getDiagnosticString(),
630 HasSubstr(
631 "Structure Nesting Depth may not be larger than 255. Found 256."));
632 }
633
634 // Valid: Structure nesting depth of 100 (limit is 100).
TEST_F(ValidateLimits,CustomizedStructNestingDepthGood)635 TEST_F(ValidateLimits, CustomizedStructNestingDepthGood) {
636 std::ostringstream spirv;
637 spirv << header << R"(
638 %int = OpTypeInt 32 0
639 %s_depth_1 = OpTypeStruct %int
640 )";
641 for (auto i = 2; i <= 100; ++i) {
642 spirv << "%s_depth_" << i << " = OpTypeStruct %int %s_depth_" << i - 1;
643 spirv << "\n";
644 }
645 spvValidatorOptionsSetUniversalLimit(
646 options_, spv_validator_limit_max_struct_depth, 100u);
647 CompileSuccessfully(spirv.str());
648 EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
649 }
650
651 // Invalid: Structure nesting depth of 101 (limit is 100).
TEST_F(ValidateLimits,CustomizedStructNestingDepthBad)652 TEST_F(ValidateLimits, CustomizedStructNestingDepthBad) {
653 std::ostringstream spirv;
654 spirv << header << R"(
655 %int = OpTypeInt 32 0
656 %s_depth_1 = OpTypeStruct %int
657 )";
658 for (auto i = 2; i <= 101; ++i) {
659 spirv << "%s_depth_" << i << " = OpTypeStruct %int %s_depth_" << i - 1;
660 spirv << "\n";
661 }
662 spvValidatorOptionsSetUniversalLimit(
663 options_, spv_validator_limit_max_struct_depth, 100u);
664 CompileSuccessfully(spirv.str());
665 EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
666 EXPECT_THAT(
667 getDiagnosticString(),
668 HasSubstr(
669 "Structure Nesting Depth may not be larger than 100. Found 101."));
670 }
671
672 // clang-format off
673 // Generates an SPIRV program with the given control flow nesting depth
GenerateSpirvProgramWithCfgNestingDepth(std::string & str,int depth)674 void GenerateSpirvProgramWithCfgNestingDepth(std::string& str, int depth) {
675 std::ostringstream spirv;
676 spirv << header << R"(
677 %void = OpTypeVoid
678 %3 = OpTypeFunction %void
679 %bool = OpTypeBool
680 %12 = OpConstantTrue %bool
681 %main = OpFunction %void None %3
682 %5 = OpLabel
683 OpBranch %6
684 %6 = OpLabel
685 OpLoopMerge %8 %9 None
686 OpBranch %10
687 %10 = OpLabel
688 OpBranchConditional %12 %7 %8
689 %7 = OpLabel
690 )";
691 int first_id = 13;
692 int last_id = 14;
693 // We already have 1 level of nesting due to the Loop.
694 int num_if_conditions = depth-1;
695 int largest_index = first_id + 2*num_if_conditions - 2;
696 for (int i = first_id; i <= largest_index; i = i + 2) {
697 spirv << "OpSelectionMerge %" << i+1 << " None" << "\n";
698 spirv << "OpBranchConditional %12 " << "%" << i << " %" << i+1 << "\n";
699 spirv << "%" << i << " = OpLabel" << "\n";
700 }
701 spirv << "OpBranch %9" << "\n";
702
703 for (int i = largest_index+1; i > last_id; i = i - 2) {
704 spirv << "%" << i << " = OpLabel" << "\n";
705 spirv << "OpBranch %" << i-2 << "\n";
706 }
707 spirv << "%" << last_id << " = OpLabel" << "\n";
708 spirv << "OpBranch %9" << "\n";
709 spirv << R"(
710 %9 = OpLabel
711 OpBranch %6
712 %8 = OpLabel
713 OpReturn
714 OpFunctionEnd
715 )";
716 str = spirv.str();
717 }
718 // clang-format on
719
720 // Invalid: Control Flow Nesting depth is 1024. (limit is 1023).
TEST_F(ValidateLimits,ControlFlowDepthBad)721 TEST_F(ValidateLimits, ControlFlowDepthBad) {
722 std::string spirv;
723 GenerateSpirvProgramWithCfgNestingDepth(spirv, 1024);
724 CompileSuccessfully(spirv);
725 EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
726 EXPECT_THAT(getDiagnosticString(),
727 HasSubstr("Maximum Control Flow nesting depth exceeded."));
728 }
729
730 // Valid: Control Flow Nesting depth is 10 (custom limit: 10).
TEST_F(ValidateLimits,CustomizedControlFlowDepthGood)731 TEST_F(ValidateLimits, CustomizedControlFlowDepthGood) {
732 std::string spirv;
733 GenerateSpirvProgramWithCfgNestingDepth(spirv, 10);
734 spvValidatorOptionsSetUniversalLimit(
735 options_, spv_validator_limit_max_control_flow_nesting_depth, 10u);
736 CompileSuccessfully(spirv);
737 EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
738 }
739
740 // Invalid: Control Flow Nesting depth is 11. (custom limit: 10).
TEST_F(ValidateLimits,CustomizedControlFlowDepthBad)741 TEST_F(ValidateLimits, CustomizedControlFlowDepthBad) {
742 std::string spirv;
743 GenerateSpirvProgramWithCfgNestingDepth(spirv, 11);
744 spvValidatorOptionsSetUniversalLimit(
745 options_, spv_validator_limit_max_control_flow_nesting_depth, 10u);
746 CompileSuccessfully(spirv);
747 EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
748 EXPECT_THAT(getDiagnosticString(),
749 HasSubstr("Maximum Control Flow nesting depth exceeded."));
750 }
751
752 // Valid. The purpose here is to test the CFG depth calculation code when a loop
753 // continue target is the loop itself. It also exercises the case where a loop
754 // is unreachable.
TEST_F(ValidateLimits,ControlFlowNoEntryToLoopGood)755 TEST_F(ValidateLimits, ControlFlowNoEntryToLoopGood) {
756 std::string str = header + R"(
757 OpName %entry "entry"
758 OpName %loop "loop"
759 OpName %exit "exit"
760 %voidt = OpTypeVoid
761 %boolt = OpTypeBool
762 %undef = OpUndef %boolt
763 %funct = OpTypeFunction %voidt
764 %main = OpFunction %voidt None %funct
765 %entry = OpLabel
766 OpBranch %exit
767 %loop = OpLabel
768 OpLoopMerge %dead %loop None
769 OpBranchConditional %undef %loop %loop
770 %dead = OpLabel
771 OpUnreachable
772 %exit = OpLabel
773 OpReturn
774 OpFunctionEnd
775 )";
776 CompileSuccessfully(str);
777 EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
778 }
779
780 } // namespace
781 } // namespace val
782 } // namespace spvtools
783