validation_during_reduction_test.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573
  1. // Copyright (c) 2018 Google LLC
  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. #include "reduce_test_util.h"
  15. #include "source/reduce/reducer.h"
  16. #include "source/reduce/reduction_pass.h"
  17. #include "source/reduce/remove_instruction_reduction_opportunity.h"
  18. namespace spvtools {
  19. namespace reduce {
  20. namespace {
  21. // A dumb reduction opportunity finder that finds opportunities to remove global
  22. // values regardless of whether they are referenced. This is very likely to make
  23. // the resulting module invalid. We use this to test the reducer's behavior in
  24. // the scenario where a bad reduction pass leads to an invalid module.
  25. class BlindlyRemoveGlobalValuesReductionOpportunityFinder
  26. : public ReductionOpportunityFinder {
  27. public:
  28. BlindlyRemoveGlobalValuesReductionOpportunityFinder() = default;
  29. ~BlindlyRemoveGlobalValuesReductionOpportunityFinder() override = default;
  30. // The name of this pass.
  31. std::string GetName() const final { return "BlindlyRemoveGlobalValuesPass"; };
  32. // Finds opportunities to remove all global values. Assuming they are all
  33. // referenced (directly or indirectly) from elsewhere in the module, each such
  34. // opportunity will make the module invalid.
  35. std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities(
  36. opt::IRContext* context) const final {
  37. std::vector<std::unique_ptr<ReductionOpportunity>> result;
  38. for (auto& inst : context->module()->types_values()) {
  39. if (inst.HasResultId()) {
  40. result.push_back(
  41. MakeUnique<RemoveInstructionReductionOpportunity>(&inst));
  42. }
  43. }
  44. return result;
  45. }
  46. };
  47. // A dumb reduction opportunity that exists at the start of every function whose
  48. // first instruction is an OpVariable instruction. When applied, the OpVariable
  49. // instruction is duplicated (with a fresh result id). This allows each
  50. // reduction step to increase the number of variables to check if the validator
  51. // limits are enforced.
  52. class OpVariableDuplicatorReductionOpportunity : public ReductionOpportunity {
  53. public:
  54. OpVariableDuplicatorReductionOpportunity(Function* function_)
  55. : function_(function_) {}
  56. bool PreconditionHolds() override {
  57. Instruction* first_instruction = &*function_->begin()[0].begin();
  58. return first_instruction->opcode() == SpvOpVariable;
  59. }
  60. protected:
  61. void Apply() override {
  62. // Duplicate the first OpVariable instruction.
  63. Instruction* first_instruction = &*function_->begin()[0].begin();
  64. assert(first_instruction->opcode() == SpvOpVariable &&
  65. "Expected first instruction to be OpVariable");
  66. IRContext* context = first_instruction->context();
  67. Instruction* cloned_instruction = first_instruction->Clone(context);
  68. cloned_instruction->SetResultId(context->TakeNextId());
  69. cloned_instruction->InsertBefore(first_instruction);
  70. }
  71. private:
  72. Function* function_;
  73. };
  74. // A reduction opportunity finder that finds
  75. // OpVariableDuplicatorReductionOpportunity.
  76. class OpVariableDuplicatorReductionOpportunityFinder
  77. : public ReductionOpportunityFinder {
  78. public:
  79. OpVariableDuplicatorReductionOpportunityFinder() = default;
  80. ~OpVariableDuplicatorReductionOpportunityFinder() override = default;
  81. std::string GetName() const final {
  82. return "LocalVariableAdderReductionOpportunityFinder";
  83. };
  84. std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities(
  85. opt::IRContext* context) const final {
  86. std::vector<std::unique_ptr<ReductionOpportunity>> result;
  87. for (auto& function : *context->module()) {
  88. Instruction* first_instruction = &*function.begin()[0].begin();
  89. if (first_instruction->opcode() == SpvOpVariable) {
  90. result.push_back(
  91. MakeUnique<OpVariableDuplicatorReductionOpportunity>(&function));
  92. }
  93. }
  94. return result;
  95. }
  96. };
  97. TEST(ValidationDuringReductionTest, CheckInvalidPassMakesNoProgress) {
  98. // A module whose global values are all referenced, so that any application of
  99. // MakeModuleInvalidPass will make the module invalid.
  100. std::string original = R"(
  101. OpCapability Shader
  102. %1 = OpExtInstImport "GLSL.std.450"
  103. OpMemoryModel Logical GLSL450
  104. OpEntryPoint Fragment %4 "main" %60
  105. OpExecutionMode %4 OriginUpperLeft
  106. OpSource ESSL 310
  107. OpName %4 "main"
  108. OpName %16 "buf2"
  109. OpMemberName %16 0 "i"
  110. OpName %18 ""
  111. OpName %25 "buf1"
  112. OpMemberName %25 0 "f"
  113. OpName %27 ""
  114. OpName %60 "_GLF_color"
  115. OpMemberDecorate %16 0 Offset 0
  116. OpDecorate %16 Block
  117. OpDecorate %18 DescriptorSet 0
  118. OpDecorate %18 Binding 2
  119. OpMemberDecorate %25 0 Offset 0
  120. OpDecorate %25 Block
  121. OpDecorate %27 DescriptorSet 0
  122. OpDecorate %27 Binding 1
  123. OpDecorate %60 Location 0
  124. %2 = OpTypeVoid
  125. %3 = OpTypeFunction %2
  126. %6 = OpTypeInt 32 1
  127. %9 = OpConstant %6 0
  128. %16 = OpTypeStruct %6
  129. %17 = OpTypePointer Uniform %16
  130. %18 = OpVariable %17 Uniform
  131. %19 = OpTypePointer Uniform %6
  132. %22 = OpTypeBool
  133. %24 = OpTypeFloat 32
  134. %25 = OpTypeStruct %24
  135. %26 = OpTypePointer Uniform %25
  136. %27 = OpVariable %26 Uniform
  137. %28 = OpTypePointer Uniform %24
  138. %31 = OpConstant %24 2
  139. %56 = OpConstant %6 1
  140. %58 = OpTypeVector %24 4
  141. %59 = OpTypePointer Output %58
  142. %60 = OpVariable %59 Output
  143. %72 = OpUndef %24
  144. %74 = OpUndef %6
  145. %4 = OpFunction %2 None %3
  146. %5 = OpLabel
  147. OpBranch %10
  148. %10 = OpLabel
  149. %73 = OpPhi %6 %74 %5 %77 %34
  150. %71 = OpPhi %24 %72 %5 %76 %34
  151. %70 = OpPhi %6 %9 %5 %57 %34
  152. %20 = OpAccessChain %19 %18 %9
  153. %21 = OpLoad %6 %20
  154. %23 = OpSLessThan %22 %70 %21
  155. OpLoopMerge %12 %34 None
  156. OpBranchConditional %23 %11 %12
  157. %11 = OpLabel
  158. %29 = OpAccessChain %28 %27 %9
  159. %30 = OpLoad %24 %29
  160. %32 = OpFOrdGreaterThan %22 %30 %31
  161. OpSelectionMerge %34 None
  162. OpBranchConditional %32 %33 %46
  163. %33 = OpLabel
  164. %40 = OpFAdd %24 %71 %30
  165. %45 = OpISub %6 %73 %21
  166. OpBranch %34
  167. %46 = OpLabel
  168. %50 = OpFMul %24 %71 %30
  169. %54 = OpSDiv %6 %73 %21
  170. OpBranch %34
  171. %34 = OpLabel
  172. %77 = OpPhi %6 %45 %33 %54 %46
  173. %76 = OpPhi %24 %40 %33 %50 %46
  174. %57 = OpIAdd %6 %70 %56
  175. OpBranch %10
  176. %12 = OpLabel
  177. %61 = OpAccessChain %28 %27 %9
  178. %62 = OpLoad %24 %61
  179. %66 = OpConvertSToF %24 %21
  180. %68 = OpConvertSToF %24 %73
  181. %69 = OpCompositeConstruct %58 %62 %71 %66 %68
  182. OpStore %60 %69
  183. OpReturn
  184. OpFunctionEnd
  185. )";
  186. spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
  187. Reducer reducer(env);
  188. reducer.SetMessageConsumer(NopDiagnostic);
  189. // Say that every module is interesting.
  190. reducer.SetInterestingnessFunction(
  191. [](const std::vector<uint32_t>&, uint32_t) -> bool { return true; });
  192. reducer.AddReductionPass(
  193. MakeUnique<BlindlyRemoveGlobalValuesReductionOpportunityFinder>());
  194. std::vector<uint32_t> binary_in;
  195. SpirvTools t(env);
  196. ASSERT_TRUE(t.Assemble(original, &binary_in, kReduceAssembleOption));
  197. std::vector<uint32_t> binary_out;
  198. spvtools::ReducerOptions reducer_options;
  199. reducer_options.set_step_limit(500);
  200. spvtools::ValidatorOptions validator_options;
  201. Reducer::ReductionResultStatus status = reducer.Run(
  202. std::move(binary_in), &binary_out, reducer_options, validator_options);
  203. ASSERT_EQ(status, Reducer::ReductionResultStatus::kComplete);
  204. // The reducer should have no impact.
  205. CheckEqual(env, original, binary_out);
  206. }
  207. TEST(ValidationDuringReductionTest, CheckNotAlwaysInvalidCanMakeProgress) {
  208. // A module with just one unreferenced global value. All but one application
  209. // of MakeModuleInvalidPass will make the module invalid.
  210. std::string original = R"(
  211. OpCapability Shader
  212. %1 = OpExtInstImport "GLSL.std.450"
  213. OpMemoryModel Logical GLSL450
  214. OpEntryPoint Fragment %4 "main" %60
  215. OpExecutionMode %4 OriginUpperLeft
  216. OpSource ESSL 310
  217. OpName %4 "main"
  218. OpName %16 "buf2"
  219. OpMemberName %16 0 "i"
  220. OpName %18 ""
  221. OpName %25 "buf1"
  222. OpMemberName %25 0 "f"
  223. OpName %27 ""
  224. OpName %60 "_GLF_color"
  225. OpMemberDecorate %16 0 Offset 0
  226. OpDecorate %16 Block
  227. OpDecorate %18 DescriptorSet 0
  228. OpDecorate %18 Binding 2
  229. OpMemberDecorate %25 0 Offset 0
  230. OpDecorate %25 Block
  231. OpDecorate %27 DescriptorSet 0
  232. OpDecorate %27 Binding 1
  233. OpDecorate %60 Location 0
  234. %2 = OpTypeVoid
  235. %3 = OpTypeFunction %2
  236. %6 = OpTypeInt 32 1
  237. %9 = OpConstant %6 0
  238. %16 = OpTypeStruct %6
  239. %17 = OpTypePointer Uniform %16
  240. %18 = OpVariable %17 Uniform
  241. %19 = OpTypePointer Uniform %6
  242. %22 = OpTypeBool
  243. %24 = OpTypeFloat 32
  244. %25 = OpTypeStruct %24
  245. %26 = OpTypePointer Uniform %25
  246. %27 = OpVariable %26 Uniform
  247. %28 = OpTypePointer Uniform %24
  248. %31 = OpConstant %24 2
  249. %56 = OpConstant %6 1
  250. %1000 = OpConstant %6 1000 ; It should be possible to remove this instruction without making the module invalid.
  251. %58 = OpTypeVector %24 4
  252. %59 = OpTypePointer Output %58
  253. %60 = OpVariable %59 Output
  254. %72 = OpUndef %24
  255. %74 = OpUndef %6
  256. %4 = OpFunction %2 None %3
  257. %5 = OpLabel
  258. OpBranch %10
  259. %10 = OpLabel
  260. %73 = OpPhi %6 %74 %5 %77 %34
  261. %71 = OpPhi %24 %72 %5 %76 %34
  262. %70 = OpPhi %6 %9 %5 %57 %34
  263. %20 = OpAccessChain %19 %18 %9
  264. %21 = OpLoad %6 %20
  265. %23 = OpSLessThan %22 %70 %21
  266. OpLoopMerge %12 %34 None
  267. OpBranchConditional %23 %11 %12
  268. %11 = OpLabel
  269. %29 = OpAccessChain %28 %27 %9
  270. %30 = OpLoad %24 %29
  271. %32 = OpFOrdGreaterThan %22 %30 %31
  272. OpSelectionMerge %34 None
  273. OpBranchConditional %32 %33 %46
  274. %33 = OpLabel
  275. %40 = OpFAdd %24 %71 %30
  276. %45 = OpISub %6 %73 %21
  277. OpBranch %34
  278. %46 = OpLabel
  279. %50 = OpFMul %24 %71 %30
  280. %54 = OpSDiv %6 %73 %21
  281. OpBranch %34
  282. %34 = OpLabel
  283. %77 = OpPhi %6 %45 %33 %54 %46
  284. %76 = OpPhi %24 %40 %33 %50 %46
  285. %57 = OpIAdd %6 %70 %56
  286. OpBranch %10
  287. %12 = OpLabel
  288. %61 = OpAccessChain %28 %27 %9
  289. %62 = OpLoad %24 %61
  290. %66 = OpConvertSToF %24 %21
  291. %68 = OpConvertSToF %24 %73
  292. %69 = OpCompositeConstruct %58 %62 %71 %66 %68
  293. OpStore %60 %69
  294. OpReturn
  295. OpFunctionEnd
  296. )";
  297. // This is the same as the original, except that the constant declaration of
  298. // 1000 is gone.
  299. std::string expected = R"(
  300. OpCapability Shader
  301. %1 = OpExtInstImport "GLSL.std.450"
  302. OpMemoryModel Logical GLSL450
  303. OpEntryPoint Fragment %4 "main" %60
  304. OpExecutionMode %4 OriginUpperLeft
  305. OpSource ESSL 310
  306. OpName %4 "main"
  307. OpName %16 "buf2"
  308. OpMemberName %16 0 "i"
  309. OpName %18 ""
  310. OpName %25 "buf1"
  311. OpMemberName %25 0 "f"
  312. OpName %27 ""
  313. OpName %60 "_GLF_color"
  314. OpMemberDecorate %16 0 Offset 0
  315. OpDecorate %16 Block
  316. OpDecorate %18 DescriptorSet 0
  317. OpDecorate %18 Binding 2
  318. OpMemberDecorate %25 0 Offset 0
  319. OpDecorate %25 Block
  320. OpDecorate %27 DescriptorSet 0
  321. OpDecorate %27 Binding 1
  322. OpDecorate %60 Location 0
  323. %2 = OpTypeVoid
  324. %3 = OpTypeFunction %2
  325. %6 = OpTypeInt 32 1
  326. %9 = OpConstant %6 0
  327. %16 = OpTypeStruct %6
  328. %17 = OpTypePointer Uniform %16
  329. %18 = OpVariable %17 Uniform
  330. %19 = OpTypePointer Uniform %6
  331. %22 = OpTypeBool
  332. %24 = OpTypeFloat 32
  333. %25 = OpTypeStruct %24
  334. %26 = OpTypePointer Uniform %25
  335. %27 = OpVariable %26 Uniform
  336. %28 = OpTypePointer Uniform %24
  337. %31 = OpConstant %24 2
  338. %56 = OpConstant %6 1
  339. %58 = OpTypeVector %24 4
  340. %59 = OpTypePointer Output %58
  341. %60 = OpVariable %59 Output
  342. %72 = OpUndef %24
  343. %74 = OpUndef %6
  344. %4 = OpFunction %2 None %3
  345. %5 = OpLabel
  346. OpBranch %10
  347. %10 = OpLabel
  348. %73 = OpPhi %6 %74 %5 %77 %34
  349. %71 = OpPhi %24 %72 %5 %76 %34
  350. %70 = OpPhi %6 %9 %5 %57 %34
  351. %20 = OpAccessChain %19 %18 %9
  352. %21 = OpLoad %6 %20
  353. %23 = OpSLessThan %22 %70 %21
  354. OpLoopMerge %12 %34 None
  355. OpBranchConditional %23 %11 %12
  356. %11 = OpLabel
  357. %29 = OpAccessChain %28 %27 %9
  358. %30 = OpLoad %24 %29
  359. %32 = OpFOrdGreaterThan %22 %30 %31
  360. OpSelectionMerge %34 None
  361. OpBranchConditional %32 %33 %46
  362. %33 = OpLabel
  363. %40 = OpFAdd %24 %71 %30
  364. %45 = OpISub %6 %73 %21
  365. OpBranch %34
  366. %46 = OpLabel
  367. %50 = OpFMul %24 %71 %30
  368. %54 = OpSDiv %6 %73 %21
  369. OpBranch %34
  370. %34 = OpLabel
  371. %77 = OpPhi %6 %45 %33 %54 %46
  372. %76 = OpPhi %24 %40 %33 %50 %46
  373. %57 = OpIAdd %6 %70 %56
  374. OpBranch %10
  375. %12 = OpLabel
  376. %61 = OpAccessChain %28 %27 %9
  377. %62 = OpLoad %24 %61
  378. %66 = OpConvertSToF %24 %21
  379. %68 = OpConvertSToF %24 %73
  380. %69 = OpCompositeConstruct %58 %62 %71 %66 %68
  381. OpStore %60 %69
  382. OpReturn
  383. OpFunctionEnd
  384. )";
  385. spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
  386. Reducer reducer(env);
  387. reducer.SetMessageConsumer(NopDiagnostic);
  388. // Say that every module is interesting.
  389. reducer.SetInterestingnessFunction(
  390. [](const std::vector<uint32_t>&, uint32_t) -> bool { return true; });
  391. reducer.AddReductionPass(
  392. MakeUnique<BlindlyRemoveGlobalValuesReductionOpportunityFinder>());
  393. std::vector<uint32_t> binary_in;
  394. SpirvTools t(env);
  395. ASSERT_TRUE(t.Assemble(original, &binary_in, kReduceAssembleOption));
  396. std::vector<uint32_t> binary_out;
  397. spvtools::ReducerOptions reducer_options;
  398. reducer_options.set_step_limit(500);
  399. spvtools::ValidatorOptions validator_options;
  400. Reducer::ReductionResultStatus status = reducer.Run(
  401. std::move(binary_in), &binary_out, reducer_options, validator_options);
  402. ASSERT_EQ(status, Reducer::ReductionResultStatus::kComplete);
  403. CheckEqual(env, expected, binary_out);
  404. }
  405. // Sets up a Reducer for use in the CheckValidationOptions test; avoids
  406. // repetition.
  407. void setupReducerForCheckValidationOptions(Reducer* reducer) {
  408. reducer->SetMessageConsumer(NopDiagnostic);
  409. // Say that every module is interesting.
  410. reducer->SetInterestingnessFunction(
  411. [](const std::vector<uint32_t>&, uint32_t) -> bool { return true; });
  412. // Each "reduction" step will duplicate the first OpVariable instruction in
  413. // the function.
  414. reducer->AddReductionPass(
  415. MakeUnique<OpVariableDuplicatorReductionOpportunityFinder>());
  416. }
  417. TEST(ValidationDuringReductionTest, CheckValidationOptions) {
  418. // A module that only validates when the "skip-block-layout" validator option
  419. // is used. Also, the entry point's first instruction creates a local
  420. // variable; this instruction will be duplicated on each reduction step.
  421. std::string original = R"(
  422. OpCapability Shader
  423. %1 = OpExtInstImport "GLSL.std.450"
  424. OpMemoryModel Logical GLSL450
  425. OpEntryPoint Vertex %2 "Main" %3
  426. OpSource HLSL 600
  427. OpDecorate %3 BuiltIn Position
  428. OpDecorate %4 DescriptorSet 0
  429. OpDecorate %4 Binding 99
  430. OpDecorate %5 ArrayStride 16
  431. OpMemberDecorate %6 0 Offset 0
  432. OpMemberDecorate %6 1 Offset 32
  433. OpMemberDecorate %6 1 MatrixStride 16
  434. OpMemberDecorate %6 1 ColMajor
  435. OpMemberDecorate %6 2 Offset 96
  436. OpMemberDecorate %6 3 Offset 100
  437. OpMemberDecorate %6 4 Offset 112
  438. OpMemberDecorate %6 4 MatrixStride 16
  439. OpMemberDecorate %6 4 ColMajor
  440. OpMemberDecorate %6 5 Offset 176
  441. OpDecorate %6 Block
  442. %7 = OpTypeFloat 32
  443. %8 = OpTypeVector %7 4
  444. %9 = OpTypeMatrix %8 4
  445. %10 = OpTypeVector %7 2
  446. %11 = OpTypeInt 32 1
  447. %12 = OpTypeInt 32 0
  448. %13 = OpConstant %12 2
  449. %14 = OpConstant %11 1
  450. %15 = OpConstant %11 5
  451. %5 = OpTypeArray %8 %13
  452. %6 = OpTypeStruct %5 %9 %12 %10 %9 %7
  453. %16 = OpTypePointer Uniform %6
  454. %17 = OpTypePointer Output %8
  455. %18 = OpTypeVoid
  456. %19 = OpTypeFunction %18
  457. %20 = OpTypePointer Uniform %7
  458. %4 = OpVariable %16 Uniform
  459. %3 = OpVariable %17 Output
  460. %21 = OpTypePointer Function %11
  461. %2 = OpFunction %18 None %19
  462. %22 = OpLabel
  463. %23 = OpVariable %21 Function
  464. %24 = OpAccessChain %20 %4 %15
  465. %25 = OpLoad %7 %24
  466. %26 = OpCompositeConstruct %8 %25 %25 %25 %25
  467. OpStore %3 %26
  468. OpReturn
  469. OpFunctionEnd
  470. )";
  471. spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
  472. std::vector<uint32_t> binary_in;
  473. SpirvTools t(env);
  474. ASSERT_TRUE(t.Assemble(original, &binary_in, kReduceAssembleOption));
  475. std::vector<uint32_t> binary_out;
  476. spvtools::ReducerOptions reducer_options;
  477. spvtools::ValidatorOptions validator_options;
  478. reducer_options.set_step_limit(3);
  479. // Reduction should fail because the initial state is invalid without the
  480. // "skip-block-layout" validator option. Note that the interestingness test
  481. // always returns true.
  482. {
  483. Reducer reducer(env);
  484. setupReducerForCheckValidationOptions(&reducer);
  485. Reducer::ReductionResultStatus status =
  486. reducer.Run(std::vector<uint32_t>(binary_in), &binary_out,
  487. reducer_options, validator_options);
  488. ASSERT_EQ(status, Reducer::ReductionResultStatus::kInitialStateInvalid);
  489. }
  490. // Try again with validator option.
  491. validator_options.SetSkipBlockLayout(true);
  492. // Reduction should hit step limit; module is seen as valid, interestingness
  493. // test always succeeds, and the finder yields infinite opportunities.
  494. {
  495. Reducer reducer(env);
  496. setupReducerForCheckValidationOptions(&reducer);
  497. Reducer::ReductionResultStatus status =
  498. reducer.Run(std::vector<uint32_t>(binary_in), &binary_out,
  499. reducer_options, validator_options);
  500. ASSERT_EQ(status, Reducer::ReductionResultStatus::kReachedStepLimit);
  501. }
  502. // Now set a limit on the number of local variables.
  503. validator_options.SetUniversalLimit(spv_validator_limit_max_local_variables,
  504. 2);
  505. // Reduction should "complete"; after one step, a local variable is added and
  506. // the module becomes "invalid" given the validator limits.
  507. {
  508. Reducer reducer(env);
  509. setupReducerForCheckValidationOptions(&reducer);
  510. Reducer::ReductionResultStatus status =
  511. reducer.Run(std::vector<uint32_t>(binary_in), &binary_out,
  512. reducer_options, validator_options);
  513. ASSERT_EQ(status, Reducer::ReductionResultStatus::kComplete);
  514. }
  515. }
  516. } // namespace
  517. } // namespace reduce
  518. } // namespace spvtools