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 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 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 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 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 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 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 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 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 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 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. 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 %9 = 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. 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 %9 = 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) 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 %9 = 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) 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 %9 = 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. 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). 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) 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) 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. 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). 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) 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). 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. 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. 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). 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). 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. 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. 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). 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). 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 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). 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). 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). 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. 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 %funct = OpTypeFunction %voidt 758 %main = OpFunction %voidt None %funct 759 %entry = OpLabel 760 OpBranch %exit 761 %loop = OpLabel 762 OpLoopMerge %loop %loop None 763 OpBranch %loop 764 %exit = OpLabel 765 OpReturn 766 OpFunctionEnd 767 )"; 768 CompileSuccessfully(str); 769 EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); 770 } 771 772 } // namespace 773 } // namespace val 774 } // namespace spvtools 775