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 24namespace spvtools { 25namespace val { 26namespace { 27 28using ::testing::HasSubstr; 29using ::testing::MatchesRegex; 30 31using ValidateLimits = spvtest::ValidateBase<bool>; 32 33std::string header = R"( 34 OpCapability Shader 35 OpCapability Linkage 36 OpMemoryModel Logical GLSL450 37)"; 38 39TEST_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 57TEST_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 81TEST_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 97TEST_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 113TEST_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 132TEST_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 145TEST_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 157TEST_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 172TEST_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 186TEST_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. 204TEST_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 224OpReturn 225OpFunctionEnd 226 )"; 227 228 CompileSuccessfully(spirv.str()); 229 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); 230} 231 232// Invalid: Switch statement has 16,384 branches. 233TEST_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 253OpReturn 254OpFunctionEnd 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) 265TEST_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 285OpReturn 286OpFunctionEnd 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) 296TEST_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 316OpReturn 317OpFunctionEnd 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. 330TEST_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). 346TEST_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) 363TEST_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) 380TEST_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. 399TEST_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). 416TEST_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) 436TEST_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). 455TEST_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. 480TEST_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. 510TEST_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). 541TEST_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). 569TEST_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. 600TEST_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. 615TEST_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). 634TEST_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). 651TEST_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 673void 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). 720TEST_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). 730TEST_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). 740TEST_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. 754TEST_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