Home | History | Annotate | Download | only in val
      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