val_limits_test.cpp 23 KB

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