optimizer.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752
  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. #include "spirv-tools/optimizer.hpp"
  15. #include <memory>
  16. #include <string>
  17. #include <unordered_map>
  18. #include <utility>
  19. #include <vector>
  20. #include "source/opt/build_module.h"
  21. #include "source/opt/log.h"
  22. #include "source/opt/pass_manager.h"
  23. #include "source/opt/passes.h"
  24. #include "source/opt/reduce_load_size.h"
  25. #include "source/opt/simplification_pass.h"
  26. #include "source/util/make_unique.h"
  27. namespace spvtools {
  28. struct Optimizer::PassToken::Impl {
  29. Impl(std::unique_ptr<opt::Pass> p) : pass(std::move(p)) {}
  30. std::unique_ptr<opt::Pass> pass; // Internal implementation pass.
  31. };
  32. Optimizer::PassToken::PassToken(
  33. std::unique_ptr<Optimizer::PassToken::Impl> impl)
  34. : impl_(std::move(impl)) {}
  35. Optimizer::PassToken::PassToken(std::unique_ptr<opt::Pass>&& pass)
  36. : impl_(MakeUnique<Optimizer::PassToken::Impl>(std::move(pass))) {}
  37. Optimizer::PassToken::PassToken(PassToken&& that)
  38. : impl_(std::move(that.impl_)) {}
  39. Optimizer::PassToken& Optimizer::PassToken::operator=(PassToken&& that) {
  40. impl_ = std::move(that.impl_);
  41. return *this;
  42. }
  43. Optimizer::PassToken::~PassToken() {}
  44. struct Optimizer::Impl {
  45. explicit Impl(spv_target_env env) : target_env(env), pass_manager() {}
  46. const spv_target_env target_env; // Target environment.
  47. opt::PassManager pass_manager; // Internal implementation pass manager.
  48. };
  49. Optimizer::Optimizer(spv_target_env env) : impl_(new Impl(env)) {}
  50. Optimizer::~Optimizer() {}
  51. void Optimizer::SetMessageConsumer(MessageConsumer c) {
  52. // All passes' message consumer needs to be updated.
  53. for (uint32_t i = 0; i < impl_->pass_manager.NumPasses(); ++i) {
  54. impl_->pass_manager.GetPass(i)->SetMessageConsumer(c);
  55. }
  56. impl_->pass_manager.SetMessageConsumer(std::move(c));
  57. }
  58. const MessageConsumer& Optimizer::consumer() const {
  59. return impl_->pass_manager.consumer();
  60. }
  61. Optimizer& Optimizer::RegisterPass(PassToken&& p) {
  62. // Change to use the pass manager's consumer.
  63. p.impl_->pass->SetMessageConsumer(consumer());
  64. impl_->pass_manager.AddPass(std::move(p.impl_->pass));
  65. return *this;
  66. }
  67. // The legalization passes take a spir-v shader generated by an HLSL front-end
  68. // and turn it into a valid vulkan spir-v shader. There are two ways in which
  69. // the code will be invalid at the start:
  70. //
  71. // 1) There will be opaque objects, like images, which will be passed around
  72. // in intermediate objects. Valid spir-v will have to replace the use of
  73. // the opaque object with an intermediate object that is the result of the
  74. // load of the global opaque object.
  75. //
  76. // 2) There will be variables that contain pointers to structured or uniform
  77. // buffers. It be legal, the variables must be eliminated, and the
  78. // references to the structured buffers must use the result of OpVariable
  79. // in the Uniform storage class.
  80. //
  81. // Optimization in this list must accept shaders with these relaxation of the
  82. // rules. There is not guarantee that this list of optimizations is able to
  83. // legalize all inputs, but it is on a best effort basis.
  84. //
  85. // The legalization problem is essentially a very general copy propagation
  86. // problem. The optimization we use are all used to either do copy propagation
  87. // or enable more copy propagation.
  88. Optimizer& Optimizer::RegisterLegalizationPasses() {
  89. return
  90. // Remove unreachable block so that merge return works.
  91. RegisterPass(CreateDeadBranchElimPass())
  92. // Merge the returns so we can inline.
  93. .RegisterPass(CreateMergeReturnPass())
  94. // Make sure uses and definitions are in the same function.
  95. .RegisterPass(CreateInlineExhaustivePass())
  96. // Make private variable function scope
  97. .RegisterPass(CreateEliminateDeadFunctionsPass())
  98. .RegisterPass(CreatePrivateToLocalPass())
  99. // Propagate the value stored to the loads in very simple cases.
  100. .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass())
  101. .RegisterPass(CreateLocalSingleStoreElimPass())
  102. .RegisterPass(CreateAggressiveDCEPass())
  103. // Split up aggregates so they are easier to deal with.
  104. .RegisterPass(CreateScalarReplacementPass(0))
  105. // Remove loads and stores so everything is in intermediate values.
  106. // Takes care of copy propagation of non-members.
  107. .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass())
  108. .RegisterPass(CreateLocalSingleStoreElimPass())
  109. .RegisterPass(CreateAggressiveDCEPass())
  110. .RegisterPass(CreateLocalMultiStoreElimPass())
  111. .RegisterPass(CreateAggressiveDCEPass())
  112. // Propagate constants to get as many constant conditions on branches
  113. // as possible.
  114. .RegisterPass(CreateCCPPass())
  115. .RegisterPass(CreateDeadBranchElimPass())
  116. // Copy propagate members. Cleans up code sequences generated by
  117. // scalar replacement. Also important for removing OpPhi nodes.
  118. .RegisterPass(CreateSimplificationPass())
  119. .RegisterPass(CreateAggressiveDCEPass())
  120. .RegisterPass(CreateCopyPropagateArraysPass())
  121. // May need loop unrolling here see
  122. // https://github.com/Microsoft/DirectXShaderCompiler/pull/930
  123. // Get rid of unused code that contain traces of illegal code
  124. // or unused references to unbound external objects
  125. .RegisterPass(CreateVectorDCEPass())
  126. .RegisterPass(CreateDeadInsertElimPass())
  127. .RegisterPass(CreateReduceLoadSizePass())
  128. .RegisterPass(CreateAggressiveDCEPass());
  129. }
  130. Optimizer& Optimizer::RegisterPerformancePasses() {
  131. return RegisterPass(CreateMergeReturnPass())
  132. .RegisterPass(CreateInlineExhaustivePass())
  133. .RegisterPass(CreateAggressiveDCEPass())
  134. .RegisterPass(CreatePrivateToLocalPass())
  135. .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass())
  136. .RegisterPass(CreateLocalSingleStoreElimPass())
  137. .RegisterPass(CreateAggressiveDCEPass())
  138. .RegisterPass(CreateScalarReplacementPass())
  139. .RegisterPass(CreateLocalAccessChainConvertPass())
  140. .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass())
  141. .RegisterPass(CreateLocalSingleStoreElimPass())
  142. .RegisterPass(CreateAggressiveDCEPass())
  143. .RegisterPass(CreateLocalMultiStoreElimPass())
  144. .RegisterPass(CreateAggressiveDCEPass())
  145. .RegisterPass(CreateCCPPass())
  146. .RegisterPass(CreateAggressiveDCEPass())
  147. .RegisterPass(CreateRedundancyEliminationPass())
  148. .RegisterPass(CreateCombineAccessChainsPass())
  149. .RegisterPass(CreateSimplificationPass())
  150. .RegisterPass(CreateVectorDCEPass())
  151. .RegisterPass(CreateDeadInsertElimPass())
  152. .RegisterPass(CreateDeadBranchElimPass())
  153. .RegisterPass(CreateSimplificationPass())
  154. .RegisterPass(CreateIfConversionPass())
  155. .RegisterPass(CreateCopyPropagateArraysPass())
  156. .RegisterPass(CreateReduceLoadSizePass())
  157. .RegisterPass(CreateAggressiveDCEPass())
  158. .RegisterPass(CreateBlockMergePass())
  159. .RegisterPass(CreateRedundancyEliminationPass())
  160. .RegisterPass(CreateDeadBranchElimPass())
  161. .RegisterPass(CreateBlockMergePass())
  162. .RegisterPass(CreateSimplificationPass());
  163. // Currently exposing driver bugs resulting in crashes (#946)
  164. // .RegisterPass(CreateCommonUniformElimPass())
  165. }
  166. Optimizer& Optimizer::RegisterSizePasses() {
  167. return RegisterPass(CreateMergeReturnPass())
  168. .RegisterPass(CreateInlineExhaustivePass())
  169. .RegisterPass(CreateAggressiveDCEPass())
  170. .RegisterPass(CreatePrivateToLocalPass())
  171. .RegisterPass(CreateScalarReplacementPass())
  172. .RegisterPass(CreateLocalAccessChainConvertPass())
  173. .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass())
  174. .RegisterPass(CreateLocalSingleStoreElimPass())
  175. .RegisterPass(CreateAggressiveDCEPass())
  176. .RegisterPass(CreateSimplificationPass())
  177. .RegisterPass(CreateDeadInsertElimPass())
  178. .RegisterPass(CreateLocalMultiStoreElimPass())
  179. .RegisterPass(CreateAggressiveDCEPass())
  180. .RegisterPass(CreateCCPPass())
  181. .RegisterPass(CreateAggressiveDCEPass())
  182. .RegisterPass(CreateDeadBranchElimPass())
  183. .RegisterPass(CreateIfConversionPass())
  184. .RegisterPass(CreateAggressiveDCEPass())
  185. .RegisterPass(CreateBlockMergePass())
  186. .RegisterPass(CreateSimplificationPass())
  187. .RegisterPass(CreateDeadInsertElimPass())
  188. .RegisterPass(CreateRedundancyEliminationPass())
  189. .RegisterPass(CreateCFGCleanupPass())
  190. // Currently exposing driver bugs resulting in crashes (#946)
  191. // .RegisterPass(CreateCommonUniformElimPass())
  192. .RegisterPass(CreateAggressiveDCEPass());
  193. }
  194. bool Optimizer::RegisterPassesFromFlags(const std::vector<std::string>& flags) {
  195. for (const auto& flag : flags) {
  196. if (!RegisterPassFromFlag(flag)) {
  197. return false;
  198. }
  199. }
  200. return true;
  201. }
  202. namespace {
  203. // Splits the string |flag|, of the form '--pass_name[=pass_args]' into two
  204. // strings "pass_name" and "pass_args". If |flag| has no arguments, the second
  205. // string will be empty.
  206. std::pair<std::string, std::string> SplitFlagArgs(const std::string& flag) {
  207. if (flag.size() < 2) return make_pair(flag, std::string());
  208. // Detect the last dash before the pass name. Since we have to
  209. // handle single dash options (-O and -Os), count up to two dashes.
  210. size_t dash_ix = 0;
  211. if (flag[0] == '-' && flag[1] == '-')
  212. dash_ix = 2;
  213. else if (flag[0] == '-')
  214. dash_ix = 1;
  215. size_t ix = flag.find('=');
  216. return (ix != std::string::npos)
  217. ? make_pair(flag.substr(dash_ix, ix - 2), flag.substr(ix + 1))
  218. : make_pair(flag.substr(dash_ix), std::string());
  219. }
  220. } // namespace
  221. bool Optimizer::FlagHasValidForm(const std::string& flag) const {
  222. if (flag == "-O" || flag == "-Os") {
  223. return true;
  224. } else if (flag.size() > 2 && flag.substr(0, 2) == "--") {
  225. return true;
  226. }
  227. Errorf(consumer(), nullptr, {},
  228. "%s is not a valid flag. Flag passes should have the form "
  229. "'--pass_name[=pass_args]'. Special flag names also accepted: -O "
  230. "and -Os.",
  231. flag.c_str());
  232. return false;
  233. }
  234. bool Optimizer::RegisterPassFromFlag(const std::string& flag) {
  235. if (!FlagHasValidForm(flag)) {
  236. return false;
  237. }
  238. // Split flags of the form --pass_name=pass_args.
  239. auto p = SplitFlagArgs(flag);
  240. std::string pass_name = p.first;
  241. std::string pass_args = p.second;
  242. // FIXME(dnovillo): This should be re-factored so that pass names can be
  243. // automatically checked against Pass::name() and PassToken instances created
  244. // via a template function. Additionally, class Pass should have a desc()
  245. // method that describes the pass (so it can be used in --help).
  246. //
  247. // Both Pass::name() and Pass::desc() should be static class members so they
  248. // can be invoked without creating a pass instance.
  249. if (pass_name == "strip-debug") {
  250. RegisterPass(CreateStripDebugInfoPass());
  251. } else if (pass_name == "strip-reflect") {
  252. RegisterPass(CreateStripReflectInfoPass());
  253. } else if (pass_name == "set-spec-const-default-value") {
  254. if (pass_args.size() > 0) {
  255. auto spec_ids_vals =
  256. opt::SetSpecConstantDefaultValuePass::ParseDefaultValuesString(
  257. pass_args.c_str());
  258. if (!spec_ids_vals) {
  259. Errorf(consumer(), nullptr, {},
  260. "Invalid argument for --set-spec-const-default-value: %s",
  261. pass_args.c_str());
  262. return false;
  263. }
  264. RegisterPass(
  265. CreateSetSpecConstantDefaultValuePass(std::move(*spec_ids_vals)));
  266. } else {
  267. Errorf(consumer(), nullptr, {},
  268. "Invalid spec constant value string '%s'. Expected a string of "
  269. "<spec id>:<default value> pairs.",
  270. pass_args.c_str());
  271. return false;
  272. }
  273. } else if (pass_name == "if-conversion") {
  274. RegisterPass(CreateIfConversionPass());
  275. } else if (pass_name == "freeze-spec-const") {
  276. RegisterPass(CreateFreezeSpecConstantValuePass());
  277. } else if (pass_name == "inline-entry-points-exhaustive") {
  278. RegisterPass(CreateInlineExhaustivePass());
  279. } else if (pass_name == "inline-entry-points-opaque") {
  280. RegisterPass(CreateInlineOpaquePass());
  281. } else if (pass_name == "combine-access-chains") {
  282. RegisterPass(CreateCombineAccessChainsPass());
  283. } else if (pass_name == "convert-local-access-chains") {
  284. RegisterPass(CreateLocalAccessChainConvertPass());
  285. } else if (pass_name == "eliminate-dead-code-aggressive") {
  286. RegisterPass(CreateAggressiveDCEPass());
  287. } else if (pass_name == "eliminate-insert-extract") {
  288. RegisterPass(CreateInsertExtractElimPass());
  289. } else if (pass_name == "eliminate-local-single-block") {
  290. RegisterPass(CreateLocalSingleBlockLoadStoreElimPass());
  291. } else if (pass_name == "eliminate-local-single-store") {
  292. RegisterPass(CreateLocalSingleStoreElimPass());
  293. } else if (pass_name == "merge-blocks") {
  294. RegisterPass(CreateBlockMergePass());
  295. } else if (pass_name == "merge-return") {
  296. RegisterPass(CreateMergeReturnPass());
  297. } else if (pass_name == "eliminate-dead-branches") {
  298. RegisterPass(CreateDeadBranchElimPass());
  299. } else if (pass_name == "eliminate-dead-functions") {
  300. RegisterPass(CreateEliminateDeadFunctionsPass());
  301. } else if (pass_name == "eliminate-local-multi-store") {
  302. RegisterPass(CreateLocalMultiStoreElimPass());
  303. } else if (pass_name == "eliminate-common-uniform") {
  304. RegisterPass(CreateCommonUniformElimPass());
  305. } else if (pass_name == "eliminate-dead-const") {
  306. RegisterPass(CreateEliminateDeadConstantPass());
  307. } else if (pass_name == "eliminate-dead-inserts") {
  308. RegisterPass(CreateDeadInsertElimPass());
  309. } else if (pass_name == "eliminate-dead-variables") {
  310. RegisterPass(CreateDeadVariableEliminationPass());
  311. } else if (pass_name == "fold-spec-const-op-composite") {
  312. RegisterPass(CreateFoldSpecConstantOpAndCompositePass());
  313. } else if (pass_name == "loop-unswitch") {
  314. RegisterPass(CreateLoopUnswitchPass());
  315. } else if (pass_name == "scalar-replacement") {
  316. if (pass_args.size() == 0) {
  317. RegisterPass(CreateScalarReplacementPass());
  318. } else {
  319. int limit = atoi(pass_args.c_str());
  320. if (limit > 0) {
  321. RegisterPass(CreateScalarReplacementPass(limit));
  322. } else {
  323. Error(consumer(), nullptr, {},
  324. "--scalar-replacement must have no arguments or a positive "
  325. "integer argument");
  326. return false;
  327. }
  328. }
  329. } else if (pass_name == "strength-reduction") {
  330. RegisterPass(CreateStrengthReductionPass());
  331. } else if (pass_name == "unify-const") {
  332. RegisterPass(CreateUnifyConstantPass());
  333. } else if (pass_name == "flatten-decorations") {
  334. RegisterPass(CreateFlattenDecorationPass());
  335. } else if (pass_name == "compact-ids") {
  336. RegisterPass(CreateCompactIdsPass());
  337. } else if (pass_name == "cfg-cleanup") {
  338. RegisterPass(CreateCFGCleanupPass());
  339. } else if (pass_name == "local-redundancy-elimination") {
  340. RegisterPass(CreateLocalRedundancyEliminationPass());
  341. } else if (pass_name == "loop-invariant-code-motion") {
  342. RegisterPass(CreateLoopInvariantCodeMotionPass());
  343. } else if (pass_name == "reduce-load-size") {
  344. RegisterPass(CreateReduceLoadSizePass());
  345. } else if (pass_name == "redundancy-elimination") {
  346. RegisterPass(CreateRedundancyEliminationPass());
  347. } else if (pass_name == "private-to-local") {
  348. RegisterPass(CreatePrivateToLocalPass());
  349. } else if (pass_name == "remove-duplicates") {
  350. RegisterPass(CreateRemoveDuplicatesPass());
  351. } else if (pass_name == "workaround-1209") {
  352. RegisterPass(CreateWorkaround1209Pass());
  353. } else if (pass_name == "replace-invalid-opcode") {
  354. RegisterPass(CreateReplaceInvalidOpcodePass());
  355. } else if (pass_name == "simplify-instructions") {
  356. RegisterPass(CreateSimplificationPass());
  357. } else if (pass_name == "ssa-rewrite") {
  358. RegisterPass(CreateSSARewritePass());
  359. } else if (pass_name == "copy-propagate-arrays") {
  360. RegisterPass(CreateCopyPropagateArraysPass());
  361. } else if (pass_name == "loop-fission") {
  362. int register_threshold_to_split =
  363. (pass_args.size() > 0) ? atoi(pass_args.c_str()) : -1;
  364. if (register_threshold_to_split > 0) {
  365. RegisterPass(CreateLoopFissionPass(
  366. static_cast<size_t>(register_threshold_to_split)));
  367. } else {
  368. Error(consumer(), nullptr, {},
  369. "--loop-fission must have a positive integer argument");
  370. return false;
  371. }
  372. } else if (pass_name == "loop-fusion") {
  373. int max_registers_per_loop =
  374. (pass_args.size() > 0) ? atoi(pass_args.c_str()) : -1;
  375. if (max_registers_per_loop > 0) {
  376. RegisterPass(
  377. CreateLoopFusionPass(static_cast<size_t>(max_registers_per_loop)));
  378. } else {
  379. Error(consumer(), nullptr, {},
  380. "--loop-fusion must have a positive integer argument");
  381. return false;
  382. }
  383. } else if (pass_name == "loop-unroll") {
  384. RegisterPass(CreateLoopUnrollPass(true));
  385. } else if (pass_name == "vector-dce") {
  386. RegisterPass(CreateVectorDCEPass());
  387. } else if (pass_name == "loop-unroll-partial") {
  388. int factor = (pass_args.size() > 0) ? atoi(pass_args.c_str()) : 0;
  389. if (factor > 0) {
  390. RegisterPass(CreateLoopUnrollPass(false, factor));
  391. } else {
  392. Error(consumer(), nullptr, {},
  393. "--loop-unroll-partial must have a positive integer argument");
  394. return false;
  395. }
  396. } else if (pass_name == "loop-peeling") {
  397. RegisterPass(CreateLoopPeelingPass());
  398. } else if (pass_name == "loop-peeling-threshold") {
  399. int factor = (pass_args.size() > 0) ? atoi(pass_args.c_str()) : 0;
  400. if (factor > 0) {
  401. opt::LoopPeelingPass::SetLoopPeelingThreshold(factor);
  402. } else {
  403. Error(consumer(), nullptr, {},
  404. "--loop-peeling-threshold must have a positive integer argument");
  405. return false;
  406. }
  407. } else if (pass_name == "ccp") {
  408. RegisterPass(CreateCCPPass());
  409. } else if (pass_name == "O") {
  410. RegisterPerformancePasses();
  411. } else if (pass_name == "Os") {
  412. RegisterSizePasses();
  413. } else if (pass_name == "legalize-hlsl") {
  414. RegisterLegalizationPasses();
  415. } else {
  416. Errorf(consumer(), nullptr, {},
  417. "Unknown flag '--%s'. Use --help for a list of valid flags",
  418. pass_name.c_str());
  419. return false;
  420. }
  421. return true;
  422. }
  423. bool Optimizer::Run(const uint32_t* original_binary,
  424. const size_t original_binary_size,
  425. std::vector<uint32_t>* optimized_binary) const {
  426. return Run(original_binary, original_binary_size, optimized_binary,
  427. ValidatorOptions());
  428. }
  429. bool Optimizer::Run(const uint32_t* original_binary,
  430. const size_t original_binary_size,
  431. std::vector<uint32_t>* optimized_binary,
  432. const ValidatorOptions& options,
  433. bool skip_validation) const {
  434. spvtools::SpirvTools tools(impl_->target_env);
  435. tools.SetMessageConsumer(impl_->pass_manager.consumer());
  436. if (!skip_validation &&
  437. !tools.Validate(original_binary, original_binary_size, options)) {
  438. return false;
  439. }
  440. std::unique_ptr<opt::IRContext> context = BuildModule(
  441. impl_->target_env, consumer(), original_binary, original_binary_size);
  442. if (context == nullptr) return false;
  443. auto status = impl_->pass_manager.Run(context.get());
  444. if (status == opt::Pass::Status::SuccessWithChange ||
  445. (status == opt::Pass::Status::SuccessWithoutChange &&
  446. (optimized_binary->data() != original_binary ||
  447. optimized_binary->size() != original_binary_size))) {
  448. optimized_binary->clear();
  449. context->module()->ToBinary(optimized_binary, /* skip_nop = */ true);
  450. }
  451. return status != opt::Pass::Status::Failure;
  452. }
  453. Optimizer& Optimizer::SetPrintAll(std::ostream* out) {
  454. impl_->pass_manager.SetPrintAll(out);
  455. return *this;
  456. }
  457. Optimizer& Optimizer::SetTimeReport(std::ostream* out) {
  458. impl_->pass_manager.SetTimeReport(out);
  459. return *this;
  460. }
  461. Optimizer::PassToken CreateNullPass() {
  462. return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::NullPass>());
  463. }
  464. Optimizer::PassToken CreateStripDebugInfoPass() {
  465. return MakeUnique<Optimizer::PassToken::Impl>(
  466. MakeUnique<opt::StripDebugInfoPass>());
  467. }
  468. Optimizer::PassToken CreateStripReflectInfoPass() {
  469. return MakeUnique<Optimizer::PassToken::Impl>(
  470. MakeUnique<opt::StripReflectInfoPass>());
  471. }
  472. Optimizer::PassToken CreateEliminateDeadFunctionsPass() {
  473. return MakeUnique<Optimizer::PassToken::Impl>(
  474. MakeUnique<opt::EliminateDeadFunctionsPass>());
  475. }
  476. Optimizer::PassToken CreateSetSpecConstantDefaultValuePass(
  477. const std::unordered_map<uint32_t, std::string>& id_value_map) {
  478. return MakeUnique<Optimizer::PassToken::Impl>(
  479. MakeUnique<opt::SetSpecConstantDefaultValuePass>(id_value_map));
  480. }
  481. Optimizer::PassToken CreateSetSpecConstantDefaultValuePass(
  482. const std::unordered_map<uint32_t, std::vector<uint32_t>>& id_value_map) {
  483. return MakeUnique<Optimizer::PassToken::Impl>(
  484. MakeUnique<opt::SetSpecConstantDefaultValuePass>(id_value_map));
  485. }
  486. Optimizer::PassToken CreateFlattenDecorationPass() {
  487. return MakeUnique<Optimizer::PassToken::Impl>(
  488. MakeUnique<opt::FlattenDecorationPass>());
  489. }
  490. Optimizer::PassToken CreateFreezeSpecConstantValuePass() {
  491. return MakeUnique<Optimizer::PassToken::Impl>(
  492. MakeUnique<opt::FreezeSpecConstantValuePass>());
  493. }
  494. Optimizer::PassToken CreateFoldSpecConstantOpAndCompositePass() {
  495. return MakeUnique<Optimizer::PassToken::Impl>(
  496. MakeUnique<opt::FoldSpecConstantOpAndCompositePass>());
  497. }
  498. Optimizer::PassToken CreateUnifyConstantPass() {
  499. return MakeUnique<Optimizer::PassToken::Impl>(
  500. MakeUnique<opt::UnifyConstantPass>());
  501. }
  502. Optimizer::PassToken CreateEliminateDeadConstantPass() {
  503. return MakeUnique<Optimizer::PassToken::Impl>(
  504. MakeUnique<opt::EliminateDeadConstantPass>());
  505. }
  506. Optimizer::PassToken CreateDeadVariableEliminationPass() {
  507. return MakeUnique<Optimizer::PassToken::Impl>(
  508. MakeUnique<opt::DeadVariableElimination>());
  509. }
  510. Optimizer::PassToken CreateStrengthReductionPass() {
  511. return MakeUnique<Optimizer::PassToken::Impl>(
  512. MakeUnique<opt::StrengthReductionPass>());
  513. }
  514. Optimizer::PassToken CreateBlockMergePass() {
  515. return MakeUnique<Optimizer::PassToken::Impl>(
  516. MakeUnique<opt::BlockMergePass>());
  517. }
  518. Optimizer::PassToken CreateInlineExhaustivePass() {
  519. return MakeUnique<Optimizer::PassToken::Impl>(
  520. MakeUnique<opt::InlineExhaustivePass>());
  521. }
  522. Optimizer::PassToken CreateInlineOpaquePass() {
  523. return MakeUnique<Optimizer::PassToken::Impl>(
  524. MakeUnique<opt::InlineOpaquePass>());
  525. }
  526. Optimizer::PassToken CreateLocalAccessChainConvertPass() {
  527. return MakeUnique<Optimizer::PassToken::Impl>(
  528. MakeUnique<opt::LocalAccessChainConvertPass>());
  529. }
  530. Optimizer::PassToken CreateLocalSingleBlockLoadStoreElimPass() {
  531. return MakeUnique<Optimizer::PassToken::Impl>(
  532. MakeUnique<opt::LocalSingleBlockLoadStoreElimPass>());
  533. }
  534. Optimizer::PassToken CreateLocalSingleStoreElimPass() {
  535. return MakeUnique<Optimizer::PassToken::Impl>(
  536. MakeUnique<opt::LocalSingleStoreElimPass>());
  537. }
  538. Optimizer::PassToken CreateInsertExtractElimPass() {
  539. return MakeUnique<Optimizer::PassToken::Impl>(
  540. MakeUnique<opt::SimplificationPass>());
  541. }
  542. Optimizer::PassToken CreateDeadInsertElimPass() {
  543. return MakeUnique<Optimizer::PassToken::Impl>(
  544. MakeUnique<opt::DeadInsertElimPass>());
  545. }
  546. Optimizer::PassToken CreateDeadBranchElimPass() {
  547. return MakeUnique<Optimizer::PassToken::Impl>(
  548. MakeUnique<opt::DeadBranchElimPass>());
  549. }
  550. Optimizer::PassToken CreateLocalMultiStoreElimPass() {
  551. return MakeUnique<Optimizer::PassToken::Impl>(
  552. MakeUnique<opt::LocalMultiStoreElimPass>());
  553. }
  554. Optimizer::PassToken CreateAggressiveDCEPass() {
  555. return MakeUnique<Optimizer::PassToken::Impl>(
  556. MakeUnique<opt::AggressiveDCEPass>());
  557. }
  558. Optimizer::PassToken CreateCommonUniformElimPass() {
  559. return MakeUnique<Optimizer::PassToken::Impl>(
  560. MakeUnique<opt::CommonUniformElimPass>());
  561. }
  562. Optimizer::PassToken CreateCompactIdsPass() {
  563. return MakeUnique<Optimizer::PassToken::Impl>(
  564. MakeUnique<opt::CompactIdsPass>());
  565. }
  566. Optimizer::PassToken CreateMergeReturnPass() {
  567. return MakeUnique<Optimizer::PassToken::Impl>(
  568. MakeUnique<opt::MergeReturnPass>());
  569. }
  570. std::vector<const char*> Optimizer::GetPassNames() const {
  571. std::vector<const char*> v;
  572. for (uint32_t i = 0; i < impl_->pass_manager.NumPasses(); i++) {
  573. v.push_back(impl_->pass_manager.GetPass(i)->name());
  574. }
  575. return v;
  576. }
  577. Optimizer::PassToken CreateCFGCleanupPass() {
  578. return MakeUnique<Optimizer::PassToken::Impl>(
  579. MakeUnique<opt::CFGCleanupPass>());
  580. }
  581. Optimizer::PassToken CreateLocalRedundancyEliminationPass() {
  582. return MakeUnique<Optimizer::PassToken::Impl>(
  583. MakeUnique<opt::LocalRedundancyEliminationPass>());
  584. }
  585. Optimizer::PassToken CreateLoopFissionPass(size_t threshold) {
  586. return MakeUnique<Optimizer::PassToken::Impl>(
  587. MakeUnique<opt::LoopFissionPass>(threshold));
  588. }
  589. Optimizer::PassToken CreateLoopFusionPass(size_t max_registers_per_loop) {
  590. return MakeUnique<Optimizer::PassToken::Impl>(
  591. MakeUnique<opt::LoopFusionPass>(max_registers_per_loop));
  592. }
  593. Optimizer::PassToken CreateLoopInvariantCodeMotionPass() {
  594. return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::LICMPass>());
  595. }
  596. Optimizer::PassToken CreateLoopPeelingPass() {
  597. return MakeUnique<Optimizer::PassToken::Impl>(
  598. MakeUnique<opt::LoopPeelingPass>());
  599. }
  600. Optimizer::PassToken CreateLoopUnswitchPass() {
  601. return MakeUnique<Optimizer::PassToken::Impl>(
  602. MakeUnique<opt::LoopUnswitchPass>());
  603. }
  604. Optimizer::PassToken CreateRedundancyEliminationPass() {
  605. return MakeUnique<Optimizer::PassToken::Impl>(
  606. MakeUnique<opt::RedundancyEliminationPass>());
  607. }
  608. Optimizer::PassToken CreateRemoveDuplicatesPass() {
  609. return MakeUnique<Optimizer::PassToken::Impl>(
  610. MakeUnique<opt::RemoveDuplicatesPass>());
  611. }
  612. Optimizer::PassToken CreateScalarReplacementPass(uint32_t size_limit) {
  613. return MakeUnique<Optimizer::PassToken::Impl>(
  614. MakeUnique<opt::ScalarReplacementPass>(size_limit));
  615. }
  616. Optimizer::PassToken CreatePrivateToLocalPass() {
  617. return MakeUnique<Optimizer::PassToken::Impl>(
  618. MakeUnique<opt::PrivateToLocalPass>());
  619. }
  620. Optimizer::PassToken CreateCCPPass() {
  621. return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::CCPPass>());
  622. }
  623. Optimizer::PassToken CreateWorkaround1209Pass() {
  624. return MakeUnique<Optimizer::PassToken::Impl>(
  625. MakeUnique<opt::Workaround1209>());
  626. }
  627. Optimizer::PassToken CreateIfConversionPass() {
  628. return MakeUnique<Optimizer::PassToken::Impl>(
  629. MakeUnique<opt::IfConversion>());
  630. }
  631. Optimizer::PassToken CreateReplaceInvalidOpcodePass() {
  632. return MakeUnique<Optimizer::PassToken::Impl>(
  633. MakeUnique<opt::ReplaceInvalidOpcodePass>());
  634. }
  635. Optimizer::PassToken CreateSimplificationPass() {
  636. return MakeUnique<Optimizer::PassToken::Impl>(
  637. MakeUnique<opt::SimplificationPass>());
  638. }
  639. Optimizer::PassToken CreateLoopUnrollPass(bool fully_unroll, int factor) {
  640. return MakeUnique<Optimizer::PassToken::Impl>(
  641. MakeUnique<opt::LoopUnroller>(fully_unroll, factor));
  642. }
  643. Optimizer::PassToken CreateSSARewritePass() {
  644. return MakeUnique<Optimizer::PassToken::Impl>(
  645. MakeUnique<opt::SSARewritePass>());
  646. }
  647. Optimizer::PassToken CreateCopyPropagateArraysPass() {
  648. return MakeUnique<Optimizer::PassToken::Impl>(
  649. MakeUnique<opt::CopyPropagateArrays>());
  650. }
  651. Optimizer::PassToken CreateVectorDCEPass() {
  652. return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::VectorDCE>());
  653. }
  654. Optimizer::PassToken CreateReduceLoadSizePass() {
  655. return MakeUnique<Optimizer::PassToken::Impl>(
  656. MakeUnique<opt::ReduceLoadSize>());
  657. }
  658. Optimizer::PassToken CreateCombineAccessChainsPass() {
  659. return MakeUnique<Optimizer::PassToken::Impl>(
  660. MakeUnique<opt::CombineAccessChains>());
  661. }
  662. } // namespace spvtools