val_limits_test.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782
  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. OpSelectionMerge %10 None
  177. OpSwitch %4 %10)";
  178. // Now add the (literal, label) pairs
  179. for (int i = 0; i < 16383; ++i) {
  180. spirv << " 1 %10";
  181. }
  182. spirv << R"(
  183. %10 = OpLabel
  184. OpReturn
  185. OpFunctionEnd
  186. )";
  187. CompileSuccessfully(spirv.str());
  188. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  189. }
  190. // Invalid: Switch statement has 16,384 branches.
  191. TEST_F(ValidateLimits, SwitchNumBranchesBad) {
  192. std::ostringstream spirv;
  193. spirv << header << R"(
  194. %1 = OpTypeVoid
  195. %2 = OpTypeFunction %1
  196. %3 = OpTypeInt 32 0
  197. %4 = OpConstant %3 1234
  198. %5 = OpFunction %1 None %2
  199. %7 = OpLabel
  200. %8 = OpIAdd %3 %4 %4
  201. OpSelectionMerge %10 None
  202. OpSwitch %4 %10)";
  203. // Now add the (literal, label) pairs
  204. for (int i = 0; i < 16384; ++i) {
  205. spirv << " 1 %10";
  206. }
  207. spirv << R"(
  208. %10 = OpLabel
  209. OpReturn
  210. OpFunctionEnd
  211. )";
  212. CompileSuccessfully(spirv.str());
  213. ASSERT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
  214. EXPECT_THAT(getDiagnosticString(),
  215. HasSubstr("Number of (literal, label) pairs in OpSwitch (16384) "
  216. "exceeds the limit (16383)."));
  217. }
  218. // Valid: Switch statement has 10 branches (limit is 10)
  219. TEST_F(ValidateLimits, CustomizedSwitchNumBranchesGood) {
  220. std::ostringstream spirv;
  221. spirv << header << R"(
  222. %1 = OpTypeVoid
  223. %2 = OpTypeFunction %1
  224. %3 = OpTypeInt 32 0
  225. %4 = OpConstant %3 1234
  226. %5 = OpFunction %1 None %2
  227. %7 = OpLabel
  228. %8 = OpIAdd %3 %4 %4
  229. OpSelectionMerge %10 None
  230. OpSwitch %4 %10)";
  231. // Now add the (literal, label) pairs
  232. for (int i = 0; i < 10; ++i) {
  233. spirv << " 1 %10";
  234. }
  235. spirv << R"(
  236. %10 = OpLabel
  237. OpReturn
  238. OpFunctionEnd
  239. )";
  240. spvValidatorOptionsSetUniversalLimit(
  241. options_, spv_validator_limit_max_switch_branches, 10u);
  242. CompileSuccessfully(spirv.str());
  243. ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
  244. }
  245. // Invalid: Switch statement has 11 branches (limit is 10)
  246. TEST_F(ValidateLimits, CustomizedSwitchNumBranchesBad) {
  247. std::ostringstream spirv;
  248. spirv << header << R"(
  249. %1 = OpTypeVoid
  250. %2 = OpTypeFunction %1
  251. %3 = OpTypeInt 32 0
  252. %4 = OpConstant %3 1234
  253. %5 = OpFunction %1 None %2
  254. %7 = OpLabel
  255. %8 = OpIAdd %3 %4 %4
  256. OpSelectionMerge %10 None
  257. OpSwitch %4 %10)";
  258. // Now add the (literal, label) pairs
  259. for (int i = 0; i < 11; ++i) {
  260. spirv << " 1 %10";
  261. }
  262. spirv << R"(
  263. %10 = OpLabel
  264. OpReturn
  265. OpFunctionEnd
  266. )";
  267. spvValidatorOptionsSetUniversalLimit(
  268. options_, spv_validator_limit_max_switch_branches, 10u);
  269. CompileSuccessfully(spirv.str());
  270. ASSERT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
  271. EXPECT_THAT(getDiagnosticString(),
  272. HasSubstr("Number of (literal, label) pairs in OpSwitch (11) "
  273. "exceeds the limit (10)."));
  274. }
  275. // Valid: OpTypeFunction with 255 arguments.
  276. TEST_F(ValidateLimits, OpTypeFunctionGood) {
  277. int num_args = 255;
  278. std::ostringstream spirv;
  279. spirv << header << R"(
  280. %1 = OpTypeInt 32 0
  281. %2 = OpTypeFunction %1)";
  282. // add parameters
  283. for (int i = 0; i < num_args; ++i) {
  284. spirv << " %1";
  285. }
  286. CompileSuccessfully(spirv.str());
  287. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  288. }
  289. // Invalid: OpTypeFunction with 256 arguments. (limit is 255 according to the
  290. // spec Universal Limits (2.17).
  291. TEST_F(ValidateLimits, OpTypeFunctionBad) {
  292. int num_args = 256;
  293. std::ostringstream spirv;
  294. spirv << header << R"(
  295. %1 = OpTypeInt 32 0
  296. %2 = OpTypeFunction %1)";
  297. for (int i = 0; i < num_args; ++i) {
  298. spirv << " %1";
  299. }
  300. CompileSuccessfully(spirv.str());
  301. EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
  302. EXPECT_THAT(getDiagnosticString(),
  303. HasSubstr("OpTypeFunction may not take more than 255 arguments. "
  304. "OpTypeFunction <id> '2[%2]' has 256 arguments."));
  305. }
  306. // Valid: OpTypeFunction with 100 arguments (Custom limit: 100)
  307. TEST_F(ValidateLimits, CustomizedOpTypeFunctionGood) {
  308. int num_args = 100;
  309. std::ostringstream spirv;
  310. spirv << header << R"(
  311. %1 = OpTypeInt 32 0
  312. %2 = OpTypeFunction %1)";
  313. // add parameters
  314. for (int i = 0; i < num_args; ++i) {
  315. spirv << " %1";
  316. }
  317. spvValidatorOptionsSetUniversalLimit(
  318. options_, spv_validator_limit_max_function_args, 100u);
  319. CompileSuccessfully(spirv.str());
  320. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  321. }
  322. // Invalid: OpTypeFunction with 101 arguments. (Custom limit: 100)
  323. TEST_F(ValidateLimits, CustomizedOpTypeFunctionBad) {
  324. int num_args = 101;
  325. std::ostringstream spirv;
  326. spirv << header << R"(
  327. %1 = OpTypeInt 32 0
  328. %2 = OpTypeFunction %1)";
  329. for (int i = 0; i < num_args; ++i) {
  330. spirv << " %1";
  331. }
  332. spvValidatorOptionsSetUniversalLimit(
  333. options_, spv_validator_limit_max_function_args, 100u);
  334. CompileSuccessfully(spirv.str());
  335. EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
  336. EXPECT_THAT(getDiagnosticString(),
  337. HasSubstr("OpTypeFunction may not take more than 100 arguments. "
  338. "OpTypeFunction <id> '2[%2]' has 101 arguments."));
  339. }
  340. // Valid: module has 65,535 global variables.
  341. TEST_F(ValidateLimits, NumGlobalVarsGood) {
  342. int num_globals = 65535;
  343. std::ostringstream spirv;
  344. spirv << header << R"(
  345. %int = OpTypeInt 32 0
  346. %_ptr_int = OpTypePointer Input %int
  347. )";
  348. for (int i = 0; i < num_globals; ++i) {
  349. spirv << "%var_" << i << " = OpVariable %_ptr_int Input\n";
  350. }
  351. CompileSuccessfully(spirv.str());
  352. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  353. }
  354. // Invalid: module has 65,536 global variables (limit is 65,535).
  355. TEST_F(ValidateLimits, NumGlobalVarsBad) {
  356. int num_globals = 65536;
  357. std::ostringstream spirv;
  358. spirv << header << R"(
  359. %int = OpTypeInt 32 0
  360. %_ptr_int = OpTypePointer Input %int
  361. )";
  362. for (int i = 0; i < num_globals; ++i) {
  363. spirv << "%var_" << i << " = OpVariable %_ptr_int Input\n";
  364. }
  365. CompileSuccessfully(spirv.str());
  366. EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
  367. EXPECT_THAT(getDiagnosticString(),
  368. HasSubstr("Number of Global Variables (Storage Class other than "
  369. "'Function') exceeded the valid limit (65535)."));
  370. }
  371. // Valid: module has 50 global variables (limit is 50)
  372. TEST_F(ValidateLimits, CustomizedNumGlobalVarsGood) {
  373. int num_globals = 50;
  374. std::ostringstream spirv;
  375. spirv << header << R"(
  376. %int = OpTypeInt 32 0
  377. %_ptr_int = OpTypePointer Input %int
  378. )";
  379. for (int i = 0; i < num_globals; ++i) {
  380. spirv << "%var_" << i << " = OpVariable %_ptr_int Input\n";
  381. }
  382. spvValidatorOptionsSetUniversalLimit(
  383. options_, spv_validator_limit_max_global_variables, 50u);
  384. CompileSuccessfully(spirv.str());
  385. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  386. }
  387. // Invalid: module has 51 global variables (limit is 50).
  388. TEST_F(ValidateLimits, CustomizedNumGlobalVarsBad) {
  389. int num_globals = 51;
  390. std::ostringstream spirv;
  391. spirv << header << R"(
  392. %int = OpTypeInt 32 0
  393. %_ptr_int = OpTypePointer Input %int
  394. )";
  395. for (int i = 0; i < num_globals; ++i) {
  396. spirv << "%var_" << i << " = OpVariable %_ptr_int Input\n";
  397. }
  398. spvValidatorOptionsSetUniversalLimit(
  399. options_, spv_validator_limit_max_global_variables, 50u);
  400. CompileSuccessfully(spirv.str());
  401. EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
  402. EXPECT_THAT(getDiagnosticString(),
  403. HasSubstr("Number of Global Variables (Storage Class other than "
  404. "'Function') exceeded the valid limit (50)."));
  405. }
  406. // Valid: module has 524,287 local variables.
  407. // Note: AppVeyor limits process time to 300s. For a VisualStudio Debug
  408. // build, going up to 524287 local variables gets too close to that
  409. // limit. So test with an artificially lowered limit.
  410. TEST_F(ValidateLimits, NumLocalVarsGoodArtificiallyLowLimit5K) {
  411. int num_locals = 5000;
  412. std::ostringstream spirv;
  413. spirv << header << R"(
  414. %int = OpTypeInt 32 0
  415. %_ptr_int = OpTypePointer Function %int
  416. %voidt = OpTypeVoid
  417. %funct = OpTypeFunction %voidt
  418. %main = OpFunction %voidt None %funct
  419. %entry = OpLabel
  420. )";
  421. for (int i = 0; i < num_locals; ++i) {
  422. spirv << "%var_" << i << " = OpVariable %_ptr_int Function\n";
  423. }
  424. spirv << R"(
  425. OpReturn
  426. OpFunctionEnd
  427. )";
  428. CompileSuccessfully(spirv.str());
  429. // Artificially limit it.
  430. spvValidatorOptionsSetUniversalLimit(
  431. options_, spv_validator_limit_max_local_variables, num_locals);
  432. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  433. }
  434. // Invalid: module has 524,288 local variables (limit is 524,287).
  435. // Artificially limit the check to 5001.
  436. TEST_F(ValidateLimits, NumLocalVarsBadArtificiallyLowLimit5K) {
  437. int num_locals = 5001;
  438. std::ostringstream spirv;
  439. spirv << header << R"(
  440. %int = OpTypeInt 32 0
  441. %_ptr_int = OpTypePointer Function %int
  442. %voidt = OpTypeVoid
  443. %funct = OpTypeFunction %voidt
  444. %main = OpFunction %voidt None %funct
  445. %entry = OpLabel
  446. )";
  447. for (int i = 0; i < num_locals; ++i) {
  448. spirv << "%var_" << i << " = OpVariable %_ptr_int Function\n";
  449. }
  450. spirv << R"(
  451. OpReturn
  452. OpFunctionEnd
  453. )";
  454. CompileSuccessfully(spirv.str());
  455. spvValidatorOptionsSetUniversalLimit(
  456. options_, spv_validator_limit_max_local_variables, 5000u);
  457. EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
  458. EXPECT_THAT(getDiagnosticString(),
  459. HasSubstr("Number of local variables ('Function' Storage Class) "
  460. "exceeded the valid limit (5000)."));
  461. }
  462. // Valid: module has 100 local variables (limit is 100).
  463. TEST_F(ValidateLimits, CustomizedNumLocalVarsGood) {
  464. int num_locals = 100;
  465. std::ostringstream spirv;
  466. spirv << header << R"(
  467. %int = OpTypeInt 32 0
  468. %_ptr_int = OpTypePointer Function %int
  469. %voidt = OpTypeVoid
  470. %funct = OpTypeFunction %voidt
  471. %main = OpFunction %voidt None %funct
  472. %entry = OpLabel
  473. )";
  474. for (int i = 0; i < num_locals; ++i) {
  475. spirv << "%var_" << i << " = OpVariable %_ptr_int Function\n";
  476. }
  477. spirv << R"(
  478. OpReturn
  479. OpFunctionEnd
  480. )";
  481. spvValidatorOptionsSetUniversalLimit(
  482. options_, spv_validator_limit_max_local_variables, 100u);
  483. CompileSuccessfully(spirv.str());
  484. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  485. }
  486. // Invalid: module has 101 local variables (limit is 100).
  487. TEST_F(ValidateLimits, CustomizedNumLocalVarsBad) {
  488. int num_locals = 101;
  489. std::ostringstream spirv;
  490. spirv << header << R"(
  491. %int = OpTypeInt 32 0
  492. %_ptr_int = OpTypePointer Function %int
  493. %voidt = OpTypeVoid
  494. %funct = OpTypeFunction %voidt
  495. %main = OpFunction %voidt None %funct
  496. %entry = OpLabel
  497. )";
  498. for (int i = 0; i < num_locals; ++i) {
  499. spirv << "%var_" << i << " = OpVariable %_ptr_int Function\n";
  500. }
  501. spirv << R"(
  502. OpReturn
  503. OpFunctionEnd
  504. )";
  505. spvValidatorOptionsSetUniversalLimit(
  506. options_, spv_validator_limit_max_local_variables, 100u);
  507. CompileSuccessfully(spirv.str());
  508. EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
  509. EXPECT_THAT(getDiagnosticString(),
  510. HasSubstr("Number of local variables ('Function' Storage Class) "
  511. "exceeded the valid limit (100)."));
  512. }
  513. // Valid: Structure nesting depth of 255.
  514. TEST_F(ValidateLimits, StructNestingDepthGood) {
  515. std::ostringstream spirv;
  516. spirv << header << R"(
  517. %int = OpTypeInt 32 0
  518. %s_depth_1 = OpTypeStruct %int
  519. )";
  520. for (auto i = 2; i <= 255; ++i) {
  521. spirv << "%s_depth_" << i << " = OpTypeStruct %int %s_depth_" << i - 1;
  522. spirv << "\n";
  523. }
  524. CompileSuccessfully(spirv.str());
  525. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  526. }
  527. // Invalid: Structure nesting depth of 256.
  528. TEST_F(ValidateLimits, StructNestingDepthBad) {
  529. std::ostringstream spirv;
  530. spirv << header << R"(
  531. %int = OpTypeInt 32 0
  532. %s_depth_1 = OpTypeStruct %int
  533. )";
  534. for (auto i = 2; i <= 256; ++i) {
  535. spirv << "%s_depth_" << i << " = OpTypeStruct %int %s_depth_" << i - 1;
  536. spirv << "\n";
  537. }
  538. CompileSuccessfully(spirv.str());
  539. EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
  540. EXPECT_THAT(
  541. getDiagnosticString(),
  542. HasSubstr(
  543. "Structure Nesting Depth may not be larger than 255. Found 256."));
  544. }
  545. // Valid: Structure nesting depth of 100 (limit is 100).
  546. TEST_F(ValidateLimits, CustomizedStructNestingDepthGood) {
  547. std::ostringstream spirv;
  548. spirv << header << R"(
  549. %int = OpTypeInt 32 0
  550. %s_depth_1 = OpTypeStruct %int
  551. )";
  552. for (auto i = 2; i <= 100; ++i) {
  553. spirv << "%s_depth_" << i << " = OpTypeStruct %int %s_depth_" << i - 1;
  554. spirv << "\n";
  555. }
  556. spvValidatorOptionsSetUniversalLimit(
  557. options_, spv_validator_limit_max_struct_depth, 100u);
  558. CompileSuccessfully(spirv.str());
  559. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  560. }
  561. // Invalid: Structure nesting depth of 101 (limit is 100).
  562. TEST_F(ValidateLimits, CustomizedStructNestingDepthBad) {
  563. std::ostringstream spirv;
  564. spirv << header << R"(
  565. %int = OpTypeInt 32 0
  566. %s_depth_1 = OpTypeStruct %int
  567. )";
  568. for (auto i = 2; i <= 101; ++i) {
  569. spirv << "%s_depth_" << i << " = OpTypeStruct %int %s_depth_" << i - 1;
  570. spirv << "\n";
  571. }
  572. spvValidatorOptionsSetUniversalLimit(
  573. options_, spv_validator_limit_max_struct_depth, 100u);
  574. CompileSuccessfully(spirv.str());
  575. EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
  576. EXPECT_THAT(
  577. getDiagnosticString(),
  578. HasSubstr(
  579. "Structure Nesting Depth may not be larger than 100. Found 101."));
  580. }
  581. // clang-format off
  582. // Generates an SPIRV program with the given control flow nesting depth
  583. void GenerateSpirvProgramWithCfgNestingDepth(std::string& str, int depth) {
  584. std::ostringstream spirv;
  585. spirv << header << R"(
  586. %void = OpTypeVoid
  587. %3 = OpTypeFunction %void
  588. %bool = OpTypeBool
  589. %12 = OpConstantTrue %bool
  590. %main = OpFunction %void None %3
  591. %5 = OpLabel
  592. OpBranch %6
  593. %6 = OpLabel
  594. OpLoopMerge %8 %9 None
  595. OpBranch %10
  596. %10 = OpLabel
  597. OpBranchConditional %12 %7 %8
  598. %7 = OpLabel
  599. )";
  600. int first_id = 13;
  601. int last_id = 14;
  602. // We already have 1 level of nesting due to the Loop.
  603. int num_if_conditions = depth-1;
  604. int largest_index = first_id + 2*num_if_conditions - 2;
  605. for (int i = first_id; i <= largest_index; i = i + 2) {
  606. spirv << "OpSelectionMerge %" << i+1 << " None" << "\n";
  607. spirv << "OpBranchConditional %12 " << "%" << i << " %" << i+1 << "\n";
  608. spirv << "%" << i << " = OpLabel" << "\n";
  609. }
  610. spirv << "OpBranch %9" << "\n";
  611. for (int i = largest_index+1; i > last_id; i = i - 2) {
  612. spirv << "%" << i << " = OpLabel" << "\n";
  613. spirv << "OpBranch %" << i-2 << "\n";
  614. }
  615. spirv << "%" << last_id << " = OpLabel" << "\n";
  616. spirv << "OpBranch %9" << "\n";
  617. spirv << R"(
  618. %9 = OpLabel
  619. OpBranch %6
  620. %8 = OpLabel
  621. OpReturn
  622. OpFunctionEnd
  623. )";
  624. str = spirv.str();
  625. }
  626. // clang-format on
  627. // Invalid: Control Flow Nesting depth is 1024. (limit is 1023).
  628. TEST_F(ValidateLimits, ControlFlowDepthBad) {
  629. std::string spirv;
  630. GenerateSpirvProgramWithCfgNestingDepth(spirv, 1024);
  631. CompileSuccessfully(spirv);
  632. EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  633. EXPECT_THAT(getDiagnosticString(),
  634. HasSubstr("Maximum Control Flow nesting depth exceeded."));
  635. }
  636. // Valid: Control Flow Nesting depth is 10 (custom limit: 10).
  637. TEST_F(ValidateLimits, CustomizedControlFlowDepthGood) {
  638. std::string spirv;
  639. GenerateSpirvProgramWithCfgNestingDepth(spirv, 10);
  640. spvValidatorOptionsSetUniversalLimit(
  641. options_, spv_validator_limit_max_control_flow_nesting_depth, 10u);
  642. CompileSuccessfully(spirv);
  643. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  644. }
  645. // Invalid: Control Flow Nesting depth is 11. (custom limit: 10).
  646. TEST_F(ValidateLimits, CustomizedControlFlowDepthBad) {
  647. std::string spirv;
  648. GenerateSpirvProgramWithCfgNestingDepth(spirv, 11);
  649. spvValidatorOptionsSetUniversalLimit(
  650. options_, spv_validator_limit_max_control_flow_nesting_depth, 10u);
  651. CompileSuccessfully(spirv);
  652. EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
  653. EXPECT_THAT(getDiagnosticString(),
  654. HasSubstr("Maximum Control Flow nesting depth exceeded."));
  655. }
  656. // Valid. The purpose here is to test the CFG depth calculation code when a loop
  657. // continue target is the loop itself. It also exercises the case where a loop
  658. // is unreachable.
  659. TEST_F(ValidateLimits, ControlFlowNoEntryToLoopGood) {
  660. std::string str = header + R"(
  661. OpName %entry "entry"
  662. OpName %loop "loop"
  663. OpName %exit "exit"
  664. %voidt = OpTypeVoid
  665. %boolt = OpTypeBool
  666. %undef = OpUndef %boolt
  667. %funct = OpTypeFunction %voidt
  668. %main = OpFunction %voidt None %funct
  669. %entry = OpLabel
  670. OpBranch %exit
  671. %loop = OpLabel
  672. OpLoopMerge %dead %loop None
  673. OpBranchConditional %undef %loop %loop
  674. %dead = OpLabel
  675. OpUnreachable
  676. %exit = OpLabel
  677. OpReturn
  678. OpFunctionEnd
  679. )";
  680. CompileSuccessfully(str);
  681. EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
  682. }
  683. } // namespace
  684. } // namespace val
  685. } // namespace spvtools