val_limits_test.cpp 23 KB

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