optimizer.cpp 49 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303
  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 <cassert>
  16. #include <charconv>
  17. #include <memory>
  18. #include <string>
  19. #include <system_error>
  20. #include <unordered_map>
  21. #include <utility>
  22. #include <vector>
  23. #include "source/opt/build_module.h"
  24. #include "source/opt/graphics_robust_access_pass.h"
  25. #include "source/opt/log.h"
  26. #include "source/opt/pass_manager.h"
  27. #include "source/opt/passes.h"
  28. #include "source/spirv_optimizer_options.h"
  29. #include "source/util/make_unique.h"
  30. #include "source/util/string_utils.h"
  31. namespace spvtools {
  32. std::vector<std::string> GetVectorOfStrings(const char** strings,
  33. const size_t string_count) {
  34. std::vector<std::string> result;
  35. for (uint32_t i = 0; i < string_count; i++) {
  36. result.emplace_back(strings[i]);
  37. }
  38. return result;
  39. }
  40. struct Optimizer::PassToken::Impl {
  41. Impl(std::unique_ptr<opt::Pass> p) : pass(std::move(p)) {}
  42. std::unique_ptr<opt::Pass> pass; // Internal implementation pass.
  43. };
  44. Optimizer::PassToken::PassToken(
  45. std::unique_ptr<Optimizer::PassToken::Impl> impl)
  46. : impl_(std::move(impl)) {}
  47. Optimizer::PassToken::PassToken(std::unique_ptr<opt::Pass>&& pass)
  48. : impl_(MakeUnique<Optimizer::PassToken::Impl>(std::move(pass))) {}
  49. Optimizer::PassToken::PassToken(PassToken&& that)
  50. : impl_(std::move(that.impl_)) {}
  51. Optimizer::PassToken& Optimizer::PassToken::operator=(PassToken&& that) {
  52. impl_ = std::move(that.impl_);
  53. return *this;
  54. }
  55. Optimizer::PassToken::~PassToken() {}
  56. struct Optimizer::Impl {
  57. explicit Impl(spv_target_env env) : target_env(env), pass_manager() {}
  58. spv_target_env target_env; // Target environment.
  59. opt::PassManager pass_manager; // Internal implementation pass manager.
  60. std::unordered_set<uint32_t> live_locs; // Arg to debug dead output passes
  61. };
  62. Optimizer::Optimizer(spv_target_env env) : impl_(new Impl(env)) {
  63. assert(env != SPV_ENV_WEBGPU_0);
  64. }
  65. Optimizer::~Optimizer() {}
  66. void Optimizer::SetMessageConsumer(MessageConsumer c) {
  67. // All passes' message consumer needs to be updated.
  68. for (uint32_t i = 0; i < impl_->pass_manager.NumPasses(); ++i) {
  69. impl_->pass_manager.GetPass(i)->SetMessageConsumer(c);
  70. }
  71. impl_->pass_manager.SetMessageConsumer(std::move(c));
  72. }
  73. const MessageConsumer& Optimizer::consumer() const {
  74. return impl_->pass_manager.consumer();
  75. }
  76. Optimizer& Optimizer::RegisterPass(PassToken&& p) {
  77. // Change to use the pass manager's consumer.
  78. p.impl_->pass->SetMessageConsumer(consumer());
  79. impl_->pass_manager.AddPass(std::move(p.impl_->pass));
  80. return *this;
  81. }
  82. // The legalization passes take a spir-v shader generated by an HLSL front-end
  83. // and turn it into a valid vulkan spir-v shader. There are two ways in which
  84. // the code will be invalid at the start:
  85. //
  86. // 1) There will be opaque objects, like images, which will be passed around
  87. // in intermediate objects. Valid spir-v will have to replace the use of
  88. // the opaque object with an intermediate object that is the result of the
  89. // load of the global opaque object.
  90. //
  91. // 2) There will be variables that contain pointers to structured or uniform
  92. // buffers. It be legal, the variables must be eliminated, and the
  93. // references to the structured buffers must use the result of OpVariable
  94. // in the Uniform storage class.
  95. //
  96. // Optimization in this list must accept shaders with these relaxation of the
  97. // rules. There is not guarantee that this list of optimizations is able to
  98. // legalize all inputs, but it is on a best effort basis.
  99. //
  100. // The legalization problem is essentially a very general copy propagation
  101. // problem. The optimization we use are all used to either do copy propagation
  102. // or enable more copy propagation.
  103. Optimizer& Optimizer::RegisterLegalizationPasses(bool preserve_interface) {
  104. return
  105. // Wrap OpKill instructions so all other code can be inlined.
  106. RegisterPass(CreateWrapOpKillPass())
  107. // Remove unreachable block so that merge return works.
  108. .RegisterPass(CreateDeadBranchElimPass())
  109. // Merge the returns so we can inline.
  110. .RegisterPass(CreateMergeReturnPass())
  111. // Make sure uses and definitions are in the same function.
  112. .RegisterPass(CreateInlineExhaustivePass())
  113. // Make private variable function scope
  114. .RegisterPass(CreateEliminateDeadFunctionsPass())
  115. .RegisterPass(CreatePrivateToLocalPass())
  116. // Fix up the storage classes that DXC may have purposely generated
  117. // incorrectly. All functions are inlined, and a lot of dead code has
  118. // been removed.
  119. .RegisterPass(CreateFixStorageClassPass())
  120. // Propagate the value stored to the loads in very simple cases.
  121. .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass())
  122. .RegisterPass(CreateLocalSingleStoreElimPass())
  123. .RegisterPass(CreateAggressiveDCEPass(preserve_interface))
  124. // Split up aggregates so they are easier to deal with.
  125. .RegisterPass(CreateScalarReplacementPass(0))
  126. // Remove loads and stores so everything is in intermediate values.
  127. // Takes care of copy propagation of non-members.
  128. .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass())
  129. .RegisterPass(CreateLocalSingleStoreElimPass())
  130. .RegisterPass(CreateAggressiveDCEPass(preserve_interface))
  131. .RegisterPass(CreateLocalMultiStoreElimPass())
  132. .RegisterPass(CreateAggressiveDCEPass(preserve_interface))
  133. // Propagate constants to get as many constant conditions on branches
  134. // as possible.
  135. .RegisterPass(CreateCCPPass())
  136. .RegisterPass(CreateLoopUnrollPass(true))
  137. .RegisterPass(CreateDeadBranchElimPass())
  138. // Copy propagate members. Cleans up code sequences generated by
  139. // scalar replacement. Also important for removing OpPhi nodes.
  140. .RegisterPass(CreateSimplificationPass())
  141. .RegisterPass(CreateAggressiveDCEPass(preserve_interface))
  142. .RegisterPass(CreateCopyPropagateArraysPass())
  143. // May need loop unrolling here see
  144. // https://github.com/Microsoft/DirectXShaderCompiler/pull/930
  145. // Get rid of unused code that contain traces of illegal code
  146. // or unused references to unbound external objects
  147. .RegisterPass(CreateVectorDCEPass())
  148. .RegisterPass(CreateDeadInsertElimPass())
  149. .RegisterPass(CreateReduceLoadSizePass())
  150. .RegisterPass(CreateAggressiveDCEPass(preserve_interface))
  151. .RegisterPass(CreateRemoveUnusedInterfaceVariablesPass())
  152. .RegisterPass(CreateInterpolateFixupPass())
  153. .RegisterPass(CreateInvocationInterlockPlacementPass())
  154. .RegisterPass(CreateOpExtInstWithForwardReferenceFixupPass());
  155. }
  156. Optimizer& Optimizer::RegisterLegalizationPasses() {
  157. return RegisterLegalizationPasses(false);
  158. }
  159. Optimizer& Optimizer::RegisterPerformancePasses(bool preserve_interface) {
  160. return RegisterPass(CreateWrapOpKillPass())
  161. .RegisterPass(CreateDeadBranchElimPass())
  162. .RegisterPass(CreateMergeReturnPass())
  163. .RegisterPass(CreateInlineExhaustivePass())
  164. .RegisterPass(CreateEliminateDeadFunctionsPass())
  165. .RegisterPass(CreateAggressiveDCEPass(preserve_interface))
  166. .RegisterPass(CreatePrivateToLocalPass())
  167. .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass())
  168. .RegisterPass(CreateLocalSingleStoreElimPass())
  169. .RegisterPass(CreateAggressiveDCEPass(preserve_interface))
  170. .RegisterPass(CreateScalarReplacementPass(0))
  171. .RegisterPass(CreateLocalAccessChainConvertPass())
  172. .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass())
  173. .RegisterPass(CreateLocalSingleStoreElimPass())
  174. .RegisterPass(CreateAggressiveDCEPass(preserve_interface))
  175. .RegisterPass(CreateLocalMultiStoreElimPass())
  176. .RegisterPass(CreateAggressiveDCEPass(preserve_interface))
  177. .RegisterPass(CreateCCPPass())
  178. .RegisterPass(CreateAggressiveDCEPass(preserve_interface))
  179. .RegisterPass(CreateLoopUnrollPass(true))
  180. .RegisterPass(CreateDeadBranchElimPass())
  181. .RegisterPass(CreateRedundancyEliminationPass())
  182. .RegisterPass(CreateCombineAccessChainsPass())
  183. .RegisterPass(CreateSimplificationPass())
  184. .RegisterPass(CreateScalarReplacementPass(0))
  185. .RegisterPass(CreateLocalAccessChainConvertPass())
  186. .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass())
  187. .RegisterPass(CreateLocalSingleStoreElimPass())
  188. .RegisterPass(CreateAggressiveDCEPass(preserve_interface))
  189. .RegisterPass(CreateSSARewritePass())
  190. .RegisterPass(CreateAggressiveDCEPass(preserve_interface))
  191. .RegisterPass(CreateVectorDCEPass())
  192. .RegisterPass(CreateDeadInsertElimPass())
  193. .RegisterPass(CreateDeadBranchElimPass())
  194. .RegisterPass(CreateSimplificationPass())
  195. .RegisterPass(CreateIfConversionPass())
  196. .RegisterPass(CreateCopyPropagateArraysPass())
  197. .RegisterPass(CreateReduceLoadSizePass())
  198. .RegisterPass(CreateAggressiveDCEPass(preserve_interface))
  199. .RegisterPass(CreateBlockMergePass())
  200. .RegisterPass(CreateRedundancyEliminationPass())
  201. .RegisterPass(CreateDeadBranchElimPass())
  202. .RegisterPass(CreateBlockMergePass())
  203. .RegisterPass(CreateSimplificationPass());
  204. }
  205. Optimizer& Optimizer::RegisterPerformancePasses() {
  206. return RegisterPerformancePasses(false);
  207. }
  208. Optimizer& Optimizer::RegisterSizePasses(bool preserve_interface) {
  209. return RegisterPass(CreateWrapOpKillPass())
  210. .RegisterPass(CreateDeadBranchElimPass())
  211. .RegisterPass(CreateMergeReturnPass())
  212. .RegisterPass(CreateInlineExhaustivePass())
  213. .RegisterPass(CreateEliminateDeadFunctionsPass())
  214. .RegisterPass(CreatePrivateToLocalPass())
  215. .RegisterPass(CreateScalarReplacementPass(0))
  216. .RegisterPass(CreateLocalMultiStoreElimPass())
  217. .RegisterPass(CreateCCPPass())
  218. .RegisterPass(CreateLoopUnrollPass(true))
  219. .RegisterPass(CreateDeadBranchElimPass())
  220. .RegisterPass(CreateSimplificationPass())
  221. .RegisterPass(CreateScalarReplacementPass(0))
  222. .RegisterPass(CreateLocalSingleStoreElimPass())
  223. .RegisterPass(CreateIfConversionPass())
  224. .RegisterPass(CreateSimplificationPass())
  225. .RegisterPass(CreateAggressiveDCEPass(preserve_interface))
  226. .RegisterPass(CreateDeadBranchElimPass())
  227. .RegisterPass(CreateBlockMergePass())
  228. .RegisterPass(CreateLocalAccessChainConvertPass())
  229. .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass())
  230. .RegisterPass(CreateAggressiveDCEPass(preserve_interface))
  231. .RegisterPass(CreateCopyPropagateArraysPass())
  232. .RegisterPass(CreateVectorDCEPass())
  233. .RegisterPass(CreateDeadInsertElimPass())
  234. .RegisterPass(CreateEliminateDeadMembersPass())
  235. .RegisterPass(CreateLocalSingleStoreElimPass())
  236. .RegisterPass(CreateBlockMergePass())
  237. .RegisterPass(CreateLocalMultiStoreElimPass())
  238. .RegisterPass(CreateRedundancyEliminationPass())
  239. .RegisterPass(CreateSimplificationPass())
  240. .RegisterPass(CreateAggressiveDCEPass(preserve_interface))
  241. .RegisterPass(CreateCFGCleanupPass());
  242. }
  243. Optimizer& Optimizer::RegisterSizePasses() { return RegisterSizePasses(false); }
  244. bool Optimizer::RegisterPassesFromFlags(const std::vector<std::string>& flags) {
  245. return RegisterPassesFromFlags(flags, false);
  246. }
  247. bool Optimizer::RegisterPassesFromFlags(const std::vector<std::string>& flags,
  248. bool preserve_interface) {
  249. for (const auto& flag : flags) {
  250. if (!RegisterPassFromFlag(flag, preserve_interface)) {
  251. return false;
  252. }
  253. }
  254. return true;
  255. }
  256. bool Optimizer::FlagHasValidForm(const std::string& flag) const {
  257. if (flag == "-O" || flag == "-Os") {
  258. return true;
  259. } else if (flag.size() > 2 && flag.substr(0, 2) == "--") {
  260. return true;
  261. }
  262. Errorf(consumer(), nullptr, {},
  263. "%s is not a valid flag. Flag passes should have the form "
  264. "'--pass_name[=pass_args]'. Special flag names also accepted: -O "
  265. "and -Os.",
  266. flag.c_str());
  267. return false;
  268. }
  269. bool Optimizer::RegisterPassFromFlag(const std::string& flag) {
  270. return RegisterPassFromFlag(flag, false);
  271. }
  272. bool Optimizer::RegisterPassFromFlag(const std::string& flag,
  273. bool preserve_interface) {
  274. if (!FlagHasValidForm(flag)) {
  275. return false;
  276. }
  277. // Split flags of the form --pass_name=pass_args.
  278. auto p = utils::SplitFlagArgs(flag);
  279. std::string pass_name = p.first;
  280. std::string pass_args = p.second;
  281. // FIXME(dnovillo): This should be re-factored so that pass names can be
  282. // automatically checked against Pass::name() and PassToken instances created
  283. // via a template function. Additionally, class Pass should have a desc()
  284. // method that describes the pass (so it can be used in --help).
  285. //
  286. // Both Pass::name() and Pass::desc() should be static class members so they
  287. // can be invoked without creating a pass instance.
  288. if (pass_name == "strip-debug") {
  289. RegisterPass(CreateStripDebugInfoPass());
  290. } else if (pass_name == "strip-reflect") {
  291. RegisterPass(CreateStripReflectInfoPass());
  292. } else if (pass_name == "strip-nonsemantic") {
  293. RegisterPass(CreateStripNonSemanticInfoPass());
  294. } else if (pass_name == "fix-opextinst-opcodes") {
  295. RegisterPass(CreateOpExtInstWithForwardReferenceFixupPass());
  296. } else if (pass_name == "set-spec-const-default-value") {
  297. if (pass_args.size() > 0) {
  298. auto spec_ids_vals =
  299. opt::SetSpecConstantDefaultValuePass::ParseDefaultValuesString(
  300. pass_args.c_str());
  301. if (!spec_ids_vals) {
  302. Errorf(consumer(), nullptr, {},
  303. "Invalid argument for --set-spec-const-default-value: %s",
  304. pass_args.c_str());
  305. return false;
  306. }
  307. RegisterPass(
  308. CreateSetSpecConstantDefaultValuePass(std::move(*spec_ids_vals)));
  309. } else {
  310. Errorf(consumer(), nullptr, {},
  311. "Invalid spec constant value string '%s'. Expected a string of "
  312. "<spec id>:<default value> pairs.",
  313. pass_args.c_str());
  314. return false;
  315. }
  316. } else if (pass_name == "if-conversion") {
  317. RegisterPass(CreateIfConversionPass());
  318. } else if (pass_name == "freeze-spec-const") {
  319. RegisterPass(CreateFreezeSpecConstantValuePass());
  320. } else if (pass_name == "inline-entry-points-exhaustive") {
  321. RegisterPass(CreateInlineExhaustivePass());
  322. } else if (pass_name == "inline-entry-points-opaque") {
  323. RegisterPass(CreateInlineOpaquePass());
  324. } else if (pass_name == "combine-access-chains") {
  325. RegisterPass(CreateCombineAccessChainsPass());
  326. } else if (pass_name == "convert-local-access-chains") {
  327. RegisterPass(CreateLocalAccessChainConvertPass());
  328. } else if (pass_name == "replace-desc-array-access-using-var-index") {
  329. RegisterPass(CreateReplaceDescArrayAccessUsingVarIndexPass());
  330. } else if (pass_name == "spread-volatile-semantics") {
  331. RegisterPass(CreateSpreadVolatileSemanticsPass());
  332. } else if (pass_name == "descriptor-scalar-replacement") {
  333. RegisterPass(CreateDescriptorScalarReplacementPass());
  334. } else if (pass_name == "descriptor-composite-scalar-replacement") {
  335. RegisterPass(CreateDescriptorCompositeScalarReplacementPass());
  336. } else if (pass_name == "descriptor-array-scalar-replacement") {
  337. RegisterPass(CreateDescriptorArrayScalarReplacementPass());
  338. } else if (pass_name == "eliminate-dead-code-aggressive") {
  339. RegisterPass(CreateAggressiveDCEPass(preserve_interface));
  340. } else if (pass_name == "eliminate-insert-extract") {
  341. RegisterPass(CreateInsertExtractElimPass());
  342. } else if (pass_name == "eliminate-local-single-block") {
  343. RegisterPass(CreateLocalSingleBlockLoadStoreElimPass());
  344. } else if (pass_name == "eliminate-local-single-store") {
  345. RegisterPass(CreateLocalSingleStoreElimPass());
  346. } else if (pass_name == "merge-blocks") {
  347. RegisterPass(CreateBlockMergePass());
  348. } else if (pass_name == "merge-return") {
  349. RegisterPass(CreateMergeReturnPass());
  350. } else if (pass_name == "eliminate-dead-branches") {
  351. RegisterPass(CreateDeadBranchElimPass());
  352. } else if (pass_name == "eliminate-dead-functions") {
  353. RegisterPass(CreateEliminateDeadFunctionsPass());
  354. } else if (pass_name == "eliminate-local-multi-store") {
  355. RegisterPass(CreateLocalMultiStoreElimPass());
  356. } else if (pass_name == "eliminate-dead-const") {
  357. RegisterPass(CreateEliminateDeadConstantPass());
  358. } else if (pass_name == "eliminate-dead-inserts") {
  359. RegisterPass(CreateDeadInsertElimPass());
  360. } else if (pass_name == "eliminate-dead-variables") {
  361. RegisterPass(CreateDeadVariableEliminationPass());
  362. } else if (pass_name == "eliminate-dead-members") {
  363. RegisterPass(CreateEliminateDeadMembersPass());
  364. } else if (pass_name == "fold-spec-const-op-composite") {
  365. RegisterPass(CreateFoldSpecConstantOpAndCompositePass());
  366. } else if (pass_name == "loop-unswitch") {
  367. RegisterPass(CreateLoopUnswitchPass());
  368. } else if (pass_name == "scalar-replacement") {
  369. if (pass_args.size() == 0) {
  370. RegisterPass(CreateScalarReplacementPass(0));
  371. } else {
  372. int limit = -1;
  373. if (pass_args.find_first_not_of("0123456789") == std::string::npos) {
  374. limit = atoi(pass_args.c_str());
  375. }
  376. if (limit >= 0) {
  377. RegisterPass(CreateScalarReplacementPass(limit));
  378. } else {
  379. Error(consumer(), nullptr, {},
  380. "--scalar-replacement must have no arguments or a non-negative "
  381. "integer argument");
  382. return false;
  383. }
  384. }
  385. } else if (pass_name == "strength-reduction") {
  386. RegisterPass(CreateStrengthReductionPass());
  387. } else if (pass_name == "unify-const") {
  388. RegisterPass(CreateUnifyConstantPass());
  389. } else if (pass_name == "flatten-decorations") {
  390. RegisterPass(CreateFlattenDecorationPass());
  391. } else if (pass_name == "compact-ids") {
  392. RegisterPass(CreateCompactIdsPass());
  393. } else if (pass_name == "cfg-cleanup") {
  394. RegisterPass(CreateCFGCleanupPass());
  395. } else if (pass_name == "local-redundancy-elimination") {
  396. RegisterPass(CreateLocalRedundancyEliminationPass());
  397. } else if (pass_name == "loop-invariant-code-motion") {
  398. RegisterPass(CreateLoopInvariantCodeMotionPass());
  399. } else if (pass_name == "reduce-load-size") {
  400. if (pass_args.size() == 0) {
  401. RegisterPass(CreateReduceLoadSizePass());
  402. } else {
  403. double load_replacement_threshold = 0.9;
  404. if (pass_args.find_first_not_of(".0123456789") == std::string::npos) {
  405. load_replacement_threshold = atof(pass_args.c_str());
  406. }
  407. if (load_replacement_threshold >= 0) {
  408. RegisterPass(CreateReduceLoadSizePass(load_replacement_threshold));
  409. } else {
  410. Error(consumer(), nullptr, {},
  411. "--reduce-load-size must have no arguments or a non-negative "
  412. "double argument");
  413. return false;
  414. }
  415. }
  416. } else if (pass_name == "redundancy-elimination") {
  417. RegisterPass(CreateRedundancyEliminationPass());
  418. } else if (pass_name == "private-to-local") {
  419. RegisterPass(CreatePrivateToLocalPass());
  420. } else if (pass_name == "remove-duplicates") {
  421. RegisterPass(CreateRemoveDuplicatesPass());
  422. } else if (pass_name == "workaround-1209") {
  423. RegisterPass(CreateWorkaround1209Pass());
  424. } else if (pass_name == "replace-invalid-opcode") {
  425. RegisterPass(CreateReplaceInvalidOpcodePass());
  426. } else if (pass_name == "convert-relaxed-to-half") {
  427. RegisterPass(CreateConvertRelaxedToHalfPass());
  428. } else if (pass_name == "relax-float-ops") {
  429. RegisterPass(CreateRelaxFloatOpsPass());
  430. } else if (pass_name == "simplify-instructions") {
  431. RegisterPass(CreateSimplificationPass());
  432. } else if (pass_name == "ssa-rewrite") {
  433. RegisterPass(CreateSSARewritePass());
  434. } else if (pass_name == "copy-propagate-arrays") {
  435. RegisterPass(CreateCopyPropagateArraysPass());
  436. } else if (pass_name == "loop-fission") {
  437. int register_threshold_to_split =
  438. (pass_args.size() > 0) ? atoi(pass_args.c_str()) : -1;
  439. if (register_threshold_to_split > 0) {
  440. RegisterPass(CreateLoopFissionPass(
  441. static_cast<size_t>(register_threshold_to_split)));
  442. } else {
  443. Error(consumer(), nullptr, {},
  444. "--loop-fission must have a positive integer argument");
  445. return false;
  446. }
  447. } else if (pass_name == "loop-fusion") {
  448. int max_registers_per_loop =
  449. (pass_args.size() > 0) ? atoi(pass_args.c_str()) : -1;
  450. if (max_registers_per_loop > 0) {
  451. RegisterPass(
  452. CreateLoopFusionPass(static_cast<size_t>(max_registers_per_loop)));
  453. } else {
  454. Error(consumer(), nullptr, {},
  455. "--loop-fusion must have a positive integer argument");
  456. return false;
  457. }
  458. } else if (pass_name == "loop-unroll") {
  459. RegisterPass(CreateLoopUnrollPass(true));
  460. } else if (pass_name == "upgrade-memory-model") {
  461. RegisterPass(CreateUpgradeMemoryModelPass());
  462. } else if (pass_name == "vector-dce") {
  463. RegisterPass(CreateVectorDCEPass());
  464. } else if (pass_name == "loop-unroll-partial") {
  465. int factor = (pass_args.size() > 0) ? atoi(pass_args.c_str()) : 0;
  466. if (factor > 0) {
  467. RegisterPass(CreateLoopUnrollPass(false, factor));
  468. } else {
  469. Error(consumer(), nullptr, {},
  470. "--loop-unroll-partial must have a positive integer argument");
  471. return false;
  472. }
  473. } else if (pass_name == "loop-peeling") {
  474. RegisterPass(CreateLoopPeelingPass());
  475. } else if (pass_name == "loop-peeling-threshold") {
  476. int factor = (pass_args.size() > 0) ? atoi(pass_args.c_str()) : 0;
  477. if (factor > 0) {
  478. opt::LoopPeelingPass::SetLoopPeelingThreshold(factor);
  479. } else {
  480. Error(consumer(), nullptr, {},
  481. "--loop-peeling-threshold must have a positive integer argument");
  482. return false;
  483. }
  484. } else if (pass_name == "ccp") {
  485. RegisterPass(CreateCCPPass());
  486. } else if (pass_name == "code-sink") {
  487. RegisterPass(CreateCodeSinkingPass());
  488. } else if (pass_name == "fix-storage-class") {
  489. RegisterPass(CreateFixStorageClassPass());
  490. } else if (pass_name == "O") {
  491. RegisterPerformancePasses(preserve_interface);
  492. } else if (pass_name == "Os") {
  493. RegisterSizePasses(preserve_interface);
  494. } else if (pass_name == "legalize-hlsl") {
  495. RegisterLegalizationPasses(preserve_interface);
  496. } else if (pass_name == "remove-unused-interface-variables") {
  497. RegisterPass(CreateRemoveUnusedInterfaceVariablesPass());
  498. } else if (pass_name == "graphics-robust-access") {
  499. RegisterPass(CreateGraphicsRobustAccessPass());
  500. } else if (pass_name == "wrap-opkill") {
  501. RegisterPass(CreateWrapOpKillPass());
  502. } else if (pass_name == "amd-ext-to-khr") {
  503. RegisterPass(CreateAmdExtToKhrPass());
  504. } else if (pass_name == "interpolate-fixup") {
  505. RegisterPass(CreateInterpolateFixupPass());
  506. } else if (pass_name == "remove-dont-inline") {
  507. RegisterPass(CreateRemoveDontInlinePass());
  508. } else if (pass_name == "eliminate-dead-input-components") {
  509. RegisterPass(CreateEliminateDeadInputComponentsSafePass());
  510. } else if (pass_name == "fix-func-call-param") {
  511. RegisterPass(CreateFixFuncCallArgumentsPass());
  512. } else if (pass_name == "convert-to-sampled-image") {
  513. if (pass_args.size() > 0) {
  514. auto descriptor_set_binding_pairs =
  515. opt::ConvertToSampledImagePass::ParseDescriptorSetBindingPairsString(
  516. pass_args.c_str());
  517. if (!descriptor_set_binding_pairs) {
  518. Errorf(consumer(), nullptr, {},
  519. "Invalid argument for --convert-to-sampled-image: %s",
  520. pass_args.c_str());
  521. return false;
  522. }
  523. RegisterPass(CreateConvertToSampledImagePass(
  524. std::move(*descriptor_set_binding_pairs)));
  525. } else {
  526. Errorf(consumer(), nullptr, {},
  527. "Invalid pairs of descriptor set and binding '%s'. Expected a "
  528. "string of <descriptor set>:<binding> pairs.",
  529. pass_args.c_str());
  530. return false;
  531. }
  532. } else if (pass_name == "struct-packing") {
  533. if (pass_args.size() == 0) {
  534. Error(consumer(), nullptr, {},
  535. "--struct-packing requires a name:rule argument.");
  536. return false;
  537. }
  538. auto separator_pos = pass_args.find(':');
  539. if (separator_pos == std::string::npos || separator_pos == 0 ||
  540. separator_pos + 1 == pass_args.size()) {
  541. Errorf(consumer(), nullptr, {},
  542. "Invalid argument for --struct-packing: %s", pass_args.c_str());
  543. return false;
  544. }
  545. const std::string struct_name = pass_args.substr(0, separator_pos);
  546. const std::string rule_name = pass_args.substr(separator_pos + 1);
  547. RegisterPass(
  548. CreateStructPackingPass(struct_name.c_str(), rule_name.c_str()));
  549. } else if (pass_name == "switch-descriptorset") {
  550. if (pass_args.size() == 0) {
  551. Error(consumer(), nullptr, {},
  552. "--switch-descriptorset requires a from:to argument.");
  553. return false;
  554. }
  555. uint32_t from_set = 0, to_set = 0;
  556. const char* start = pass_args.data();
  557. const char* end = pass_args.data() + pass_args.size();
  558. auto result = std::from_chars(start, end, from_set);
  559. if (result.ec != std::errc()) {
  560. Errorf(consumer(), nullptr, {},
  561. "Invalid argument for --switch-descriptorset: %s",
  562. pass_args.c_str());
  563. return false;
  564. }
  565. start = result.ptr;
  566. if (start[0] != ':') {
  567. Errorf(consumer(), nullptr, {},
  568. "Invalid argument for --switch-descriptorset: %s",
  569. pass_args.c_str());
  570. return false;
  571. }
  572. start++;
  573. result = std::from_chars(start, end, to_set);
  574. if (result.ec != std::errc() || result.ptr != end) {
  575. Errorf(consumer(), nullptr, {},
  576. "Invalid argument for --switch-descriptorset: %s",
  577. pass_args.c_str());
  578. return false;
  579. }
  580. RegisterPass(CreateSwitchDescriptorSetPass(from_set, to_set));
  581. } else if (pass_name == "modify-maximal-reconvergence") {
  582. if (pass_args.size() == 0) {
  583. Error(consumer(), nullptr, {},
  584. "--modify-maximal-reconvergence requires an argument");
  585. return false;
  586. }
  587. if (pass_args == "add") {
  588. RegisterPass(CreateModifyMaximalReconvergencePass(true));
  589. } else if (pass_args == "remove") {
  590. RegisterPass(CreateModifyMaximalReconvergencePass(false));
  591. } else {
  592. Errorf(consumer(), nullptr, {},
  593. "Invalid argument for --modify-maximal-reconvergence: %s (must be "
  594. "'add' or 'remove')",
  595. pass_args.c_str());
  596. return false;
  597. }
  598. } else if (pass_name == "trim-capabilities") {
  599. RegisterPass(CreateTrimCapabilitiesPass());
  600. } else if (pass_name == "split-combined-image-sampler") {
  601. RegisterPass(CreateSplitCombinedImageSamplerPass());
  602. } else if (pass_name == "resolve-binding-conflicts") {
  603. RegisterPass(CreateResolveBindingConflictsPass());
  604. } else {
  605. Errorf(consumer(), nullptr, {},
  606. "Unknown flag '--%s'. Use --help for a list of valid flags",
  607. pass_name.c_str());
  608. return false;
  609. }
  610. return true;
  611. }
  612. void Optimizer::SetTargetEnv(const spv_target_env env) {
  613. impl_->target_env = env;
  614. }
  615. bool Optimizer::Run(const uint32_t* original_binary,
  616. const size_t original_binary_size,
  617. std::vector<uint32_t>* optimized_binary) const {
  618. return Run(original_binary, original_binary_size, optimized_binary,
  619. OptimizerOptions());
  620. }
  621. bool Optimizer::Run(const uint32_t* original_binary,
  622. const size_t original_binary_size,
  623. std::vector<uint32_t>* optimized_binary,
  624. const ValidatorOptions& validator_options,
  625. bool skip_validation) const {
  626. OptimizerOptions opt_options;
  627. opt_options.set_run_validator(!skip_validation);
  628. opt_options.set_validator_options(validator_options);
  629. return Run(original_binary, original_binary_size, optimized_binary,
  630. opt_options);
  631. }
  632. bool Optimizer::Run(const uint32_t* original_binary,
  633. const size_t original_binary_size,
  634. std::vector<uint32_t>* optimized_binary,
  635. const spv_optimizer_options opt_options) const {
  636. spvtools::SpirvTools tools(impl_->target_env);
  637. tools.SetMessageConsumer(impl_->pass_manager.consumer());
  638. if (opt_options->run_validator_ &&
  639. !tools.Validate(original_binary, original_binary_size,
  640. &opt_options->val_options_)) {
  641. return false;
  642. }
  643. std::unique_ptr<opt::IRContext> context = BuildModule(
  644. impl_->target_env, consumer(), original_binary, original_binary_size);
  645. if (context == nullptr) return false;
  646. context->set_max_id_bound(opt_options->max_id_bound_);
  647. context->set_preserve_bindings(opt_options->preserve_bindings_);
  648. context->set_preserve_spec_constants(opt_options->preserve_spec_constants_);
  649. impl_->pass_manager.SetValidatorOptions(&opt_options->val_options_);
  650. impl_->pass_manager.SetTargetEnv(impl_->target_env);
  651. auto status = impl_->pass_manager.Run(context.get());
  652. if (status == opt::Pass::Status::Failure) {
  653. return false;
  654. }
  655. #ifndef NDEBUG
  656. // We do not keep the result id of DebugScope in struct DebugScope.
  657. // Instead, we assign random ids for them, which results in integrity
  658. // check failures. In addition, propagating the OpLine/OpNoLine to preserve
  659. // the debug information through transformations results in integrity
  660. // check failures. We want to skip the integrity check when the module
  661. // contains DebugScope or OpLine/OpNoLine instructions.
  662. if (status == opt::Pass::Status::SuccessWithoutChange &&
  663. !context->module()->ContainsDebugInfo()) {
  664. std::vector<uint32_t> optimized_binary_with_nop;
  665. context->module()->ToBinary(&optimized_binary_with_nop,
  666. /* skip_nop = */ false);
  667. assert(optimized_binary_with_nop.size() == original_binary_size &&
  668. "Binary size unexpectedly changed despite the optimizer saying "
  669. "there was no change");
  670. // Compare the magic number to make sure the binaries were encoded in the
  671. // endianness. If not, the contents of the binaries will be different, so
  672. // do not check the contents.
  673. if (optimized_binary_with_nop[0] == original_binary[0]) {
  674. assert(memcmp(optimized_binary_with_nop.data(), original_binary,
  675. original_binary_size) == 0 &&
  676. "Binary content unexpectedly changed despite the optimizer saying "
  677. "there was no change");
  678. }
  679. }
  680. #endif // !NDEBUG
  681. // Note that |original_binary| and |optimized_binary| may share the same
  682. // buffer and the below will invalidate |original_binary|.
  683. optimized_binary->clear();
  684. context->module()->ToBinary(optimized_binary, /* skip_nop = */ true);
  685. return true;
  686. }
  687. Optimizer& Optimizer::SetPrintAll(std::ostream* out) {
  688. impl_->pass_manager.SetPrintAll(out);
  689. return *this;
  690. }
  691. Optimizer& Optimizer::SetTimeReport(std::ostream* out) {
  692. impl_->pass_manager.SetTimeReport(out);
  693. return *this;
  694. }
  695. Optimizer& Optimizer::SetValidateAfterAll(bool validate) {
  696. impl_->pass_manager.SetValidateAfterAll(validate);
  697. return *this;
  698. }
  699. Optimizer::PassToken CreateNullPass() {
  700. return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::NullPass>());
  701. }
  702. Optimizer::PassToken CreateStripDebugInfoPass() {
  703. return MakeUnique<Optimizer::PassToken::Impl>(
  704. MakeUnique<opt::StripDebugInfoPass>());
  705. }
  706. Optimizer::PassToken CreateStripReflectInfoPass() {
  707. return CreateStripNonSemanticInfoPass();
  708. }
  709. Optimizer::PassToken CreateStripNonSemanticInfoPass() {
  710. return MakeUnique<Optimizer::PassToken::Impl>(
  711. MakeUnique<opt::StripNonSemanticInfoPass>());
  712. }
  713. Optimizer::PassToken CreateEliminateDeadFunctionsPass() {
  714. return MakeUnique<Optimizer::PassToken::Impl>(
  715. MakeUnique<opt::EliminateDeadFunctionsPass>());
  716. }
  717. Optimizer::PassToken CreateEliminateDeadMembersPass() {
  718. return MakeUnique<Optimizer::PassToken::Impl>(
  719. MakeUnique<opt::EliminateDeadMembersPass>());
  720. }
  721. Optimizer::PassToken CreateSetSpecConstantDefaultValuePass(
  722. const std::unordered_map<uint32_t, std::string>& id_value_map) {
  723. return MakeUnique<Optimizer::PassToken::Impl>(
  724. MakeUnique<opt::SetSpecConstantDefaultValuePass>(id_value_map));
  725. }
  726. Optimizer::PassToken CreateSetSpecConstantDefaultValuePass(
  727. const std::unordered_map<uint32_t, std::vector<uint32_t>>& id_value_map) {
  728. return MakeUnique<Optimizer::PassToken::Impl>(
  729. MakeUnique<opt::SetSpecConstantDefaultValuePass>(id_value_map));
  730. }
  731. Optimizer::PassToken CreateFlattenDecorationPass() {
  732. return MakeUnique<Optimizer::PassToken::Impl>(
  733. MakeUnique<opt::FlattenDecorationPass>());
  734. }
  735. Optimizer::PassToken CreateFreezeSpecConstantValuePass() {
  736. return MakeUnique<Optimizer::PassToken::Impl>(
  737. MakeUnique<opt::FreezeSpecConstantValuePass>());
  738. }
  739. Optimizer::PassToken CreateFoldSpecConstantOpAndCompositePass() {
  740. return MakeUnique<Optimizer::PassToken::Impl>(
  741. MakeUnique<opt::FoldSpecConstantOpAndCompositePass>());
  742. }
  743. Optimizer::PassToken CreateUnifyConstantPass() {
  744. return MakeUnique<Optimizer::PassToken::Impl>(
  745. MakeUnique<opt::UnifyConstantPass>());
  746. }
  747. Optimizer::PassToken CreateEliminateDeadConstantPass() {
  748. return MakeUnique<Optimizer::PassToken::Impl>(
  749. MakeUnique<opt::EliminateDeadConstantPass>());
  750. }
  751. Optimizer::PassToken CreateDeadVariableEliminationPass() {
  752. return MakeUnique<Optimizer::PassToken::Impl>(
  753. MakeUnique<opt::DeadVariableElimination>());
  754. }
  755. Optimizer::PassToken CreateStrengthReductionPass() {
  756. return MakeUnique<Optimizer::PassToken::Impl>(
  757. MakeUnique<opt::StrengthReductionPass>());
  758. }
  759. Optimizer::PassToken CreateBlockMergePass() {
  760. return MakeUnique<Optimizer::PassToken::Impl>(
  761. MakeUnique<opt::BlockMergePass>());
  762. }
  763. Optimizer::PassToken CreateInlineExhaustivePass() {
  764. return MakeUnique<Optimizer::PassToken::Impl>(
  765. MakeUnique<opt::InlineExhaustivePass>());
  766. }
  767. Optimizer::PassToken CreateInlineOpaquePass() {
  768. return MakeUnique<Optimizer::PassToken::Impl>(
  769. MakeUnique<opt::InlineOpaquePass>());
  770. }
  771. Optimizer::PassToken CreateLocalAccessChainConvertPass() {
  772. return MakeUnique<Optimizer::PassToken::Impl>(
  773. MakeUnique<opt::LocalAccessChainConvertPass>());
  774. }
  775. Optimizer::PassToken CreateLocalSingleBlockLoadStoreElimPass() {
  776. return MakeUnique<Optimizer::PassToken::Impl>(
  777. MakeUnique<opt::LocalSingleBlockLoadStoreElimPass>());
  778. }
  779. Optimizer::PassToken CreateLocalSingleStoreElimPass() {
  780. return MakeUnique<Optimizer::PassToken::Impl>(
  781. MakeUnique<opt::LocalSingleStoreElimPass>());
  782. }
  783. Optimizer::PassToken CreateInsertExtractElimPass() {
  784. return MakeUnique<Optimizer::PassToken::Impl>(
  785. MakeUnique<opt::SimplificationPass>());
  786. }
  787. Optimizer::PassToken CreateDeadInsertElimPass() {
  788. return MakeUnique<Optimizer::PassToken::Impl>(
  789. MakeUnique<opt::DeadInsertElimPass>());
  790. }
  791. Optimizer::PassToken CreateDeadBranchElimPass() {
  792. return MakeUnique<Optimizer::PassToken::Impl>(
  793. MakeUnique<opt::DeadBranchElimPass>());
  794. }
  795. Optimizer::PassToken CreateLocalMultiStoreElimPass() {
  796. return MakeUnique<Optimizer::PassToken::Impl>(
  797. MakeUnique<opt::SSARewritePass>());
  798. }
  799. Optimizer::PassToken CreateAggressiveDCEPass() {
  800. return MakeUnique<Optimizer::PassToken::Impl>(
  801. MakeUnique<opt::AggressiveDCEPass>(false, false));
  802. }
  803. Optimizer::PassToken CreateAggressiveDCEPass(bool preserve_interface) {
  804. return MakeUnique<Optimizer::PassToken::Impl>(
  805. MakeUnique<opt::AggressiveDCEPass>(preserve_interface, false));
  806. }
  807. Optimizer::PassToken CreateAggressiveDCEPass(bool preserve_interface,
  808. bool remove_outputs) {
  809. return MakeUnique<Optimizer::PassToken::Impl>(
  810. MakeUnique<opt::AggressiveDCEPass>(preserve_interface, remove_outputs));
  811. }
  812. Optimizer::PassToken CreateRemoveUnusedInterfaceVariablesPass() {
  813. return MakeUnique<Optimizer::PassToken::Impl>(
  814. MakeUnique<opt::RemoveUnusedInterfaceVariablesPass>());
  815. }
  816. Optimizer::PassToken CreatePropagateLineInfoPass() {
  817. return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::EmptyPass>());
  818. }
  819. Optimizer::PassToken CreateRedundantLineInfoElimPass() {
  820. return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::EmptyPass>());
  821. }
  822. Optimizer::PassToken CreateCompactIdsPass() {
  823. return MakeUnique<Optimizer::PassToken::Impl>(
  824. MakeUnique<opt::CompactIdsPass>());
  825. }
  826. Optimizer::PassToken CreateMergeReturnPass() {
  827. return MakeUnique<Optimizer::PassToken::Impl>(
  828. MakeUnique<opt::MergeReturnPass>());
  829. }
  830. std::vector<const char*> Optimizer::GetPassNames() const {
  831. std::vector<const char*> v;
  832. for (uint32_t i = 0; i < impl_->pass_manager.NumPasses(); i++) {
  833. v.push_back(impl_->pass_manager.GetPass(i)->name());
  834. }
  835. return v;
  836. }
  837. Optimizer::PassToken CreateCFGCleanupPass() {
  838. return MakeUnique<Optimizer::PassToken::Impl>(
  839. MakeUnique<opt::CFGCleanupPass>());
  840. }
  841. Optimizer::PassToken CreateLocalRedundancyEliminationPass() {
  842. return MakeUnique<Optimizer::PassToken::Impl>(
  843. MakeUnique<opt::LocalRedundancyEliminationPass>());
  844. }
  845. Optimizer::PassToken CreateLoopFissionPass(size_t threshold) {
  846. return MakeUnique<Optimizer::PassToken::Impl>(
  847. MakeUnique<opt::LoopFissionPass>(threshold));
  848. }
  849. Optimizer::PassToken CreateLoopFusionPass(size_t max_registers_per_loop) {
  850. return MakeUnique<Optimizer::PassToken::Impl>(
  851. MakeUnique<opt::LoopFusionPass>(max_registers_per_loop));
  852. }
  853. Optimizer::PassToken CreateLoopInvariantCodeMotionPass() {
  854. return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::LICMPass>());
  855. }
  856. Optimizer::PassToken CreateLoopPeelingPass() {
  857. return MakeUnique<Optimizer::PassToken::Impl>(
  858. MakeUnique<opt::LoopPeelingPass>());
  859. }
  860. Optimizer::PassToken CreateLoopUnswitchPass() {
  861. return MakeUnique<Optimizer::PassToken::Impl>(
  862. MakeUnique<opt::LoopUnswitchPass>());
  863. }
  864. Optimizer::PassToken CreateRedundancyEliminationPass() {
  865. return MakeUnique<Optimizer::PassToken::Impl>(
  866. MakeUnique<opt::RedundancyEliminationPass>());
  867. }
  868. Optimizer::PassToken CreateRemoveDuplicatesPass() {
  869. return MakeUnique<Optimizer::PassToken::Impl>(
  870. MakeUnique<opt::RemoveDuplicatesPass>());
  871. }
  872. Optimizer::PassToken CreateScalarReplacementPass(uint32_t size_limit) {
  873. return MakeUnique<Optimizer::PassToken::Impl>(
  874. MakeUnique<opt::ScalarReplacementPass>(size_limit));
  875. }
  876. Optimizer::PassToken CreatePrivateToLocalPass() {
  877. return MakeUnique<Optimizer::PassToken::Impl>(
  878. MakeUnique<opt::PrivateToLocalPass>());
  879. }
  880. Optimizer::PassToken CreateCCPPass() {
  881. return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::CCPPass>());
  882. }
  883. Optimizer::PassToken CreateWorkaround1209Pass() {
  884. return MakeUnique<Optimizer::PassToken::Impl>(
  885. MakeUnique<opt::Workaround1209>());
  886. }
  887. Optimizer::PassToken CreateIfConversionPass() {
  888. return MakeUnique<Optimizer::PassToken::Impl>(
  889. MakeUnique<opt::IfConversion>());
  890. }
  891. Optimizer::PassToken CreateReplaceInvalidOpcodePass() {
  892. return MakeUnique<Optimizer::PassToken::Impl>(
  893. MakeUnique<opt::ReplaceInvalidOpcodePass>());
  894. }
  895. Optimizer::PassToken CreateSimplificationPass() {
  896. return MakeUnique<Optimizer::PassToken::Impl>(
  897. MakeUnique<opt::SimplificationPass>());
  898. }
  899. Optimizer::PassToken CreateLoopUnrollPass(bool fully_unroll, int factor) {
  900. return MakeUnique<Optimizer::PassToken::Impl>(
  901. MakeUnique<opt::LoopUnroller>(fully_unroll, factor));
  902. }
  903. Optimizer::PassToken CreateSSARewritePass() {
  904. return MakeUnique<Optimizer::PassToken::Impl>(
  905. MakeUnique<opt::SSARewritePass>());
  906. }
  907. Optimizer::PassToken CreateCopyPropagateArraysPass() {
  908. return MakeUnique<Optimizer::PassToken::Impl>(
  909. MakeUnique<opt::CopyPropagateArrays>());
  910. }
  911. Optimizer::PassToken CreateVectorDCEPass() {
  912. return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::VectorDCE>());
  913. }
  914. Optimizer::PassToken CreateReduceLoadSizePass(
  915. double load_replacement_threshold) {
  916. return MakeUnique<Optimizer::PassToken::Impl>(
  917. MakeUnique<opt::ReduceLoadSize>(load_replacement_threshold));
  918. }
  919. Optimizer::PassToken CreateCombineAccessChainsPass() {
  920. return MakeUnique<Optimizer::PassToken::Impl>(
  921. MakeUnique<opt::CombineAccessChains>());
  922. }
  923. Optimizer::PassToken CreateUpgradeMemoryModelPass() {
  924. return MakeUnique<Optimizer::PassToken::Impl>(
  925. MakeUnique<opt::UpgradeMemoryModel>());
  926. }
  927. Optimizer::PassToken CreateConvertRelaxedToHalfPass() {
  928. return MakeUnique<Optimizer::PassToken::Impl>(
  929. MakeUnique<opt::ConvertToHalfPass>());
  930. }
  931. Optimizer::PassToken CreateRelaxFloatOpsPass() {
  932. return MakeUnique<Optimizer::PassToken::Impl>(
  933. MakeUnique<opt::RelaxFloatOpsPass>());
  934. }
  935. Optimizer::PassToken CreateCodeSinkingPass() {
  936. return MakeUnique<Optimizer::PassToken::Impl>(
  937. MakeUnique<opt::CodeSinkingPass>());
  938. }
  939. Optimizer::PassToken CreateFixStorageClassPass() {
  940. return MakeUnique<Optimizer::PassToken::Impl>(
  941. MakeUnique<opt::FixStorageClass>());
  942. }
  943. Optimizer::PassToken CreateGraphicsRobustAccessPass() {
  944. return MakeUnique<Optimizer::PassToken::Impl>(
  945. MakeUnique<opt::GraphicsRobustAccessPass>());
  946. }
  947. Optimizer::PassToken CreateReplaceDescArrayAccessUsingVarIndexPass() {
  948. return MakeUnique<Optimizer::PassToken::Impl>(
  949. MakeUnique<opt::ReplaceDescArrayAccessUsingVarIndex>());
  950. }
  951. Optimizer::PassToken CreateSpreadVolatileSemanticsPass() {
  952. return MakeUnique<Optimizer::PassToken::Impl>(
  953. MakeUnique<opt::SpreadVolatileSemantics>());
  954. }
  955. Optimizer::PassToken CreateDescriptorScalarReplacementPass() {
  956. return MakeUnique<Optimizer::PassToken::Impl>(
  957. MakeUnique<opt::DescriptorScalarReplacement>(
  958. /* flatten_composites= */ true, /* flatten_arrays= */ true));
  959. }
  960. Optimizer::PassToken CreateDescriptorCompositeScalarReplacementPass() {
  961. return MakeUnique<Optimizer::PassToken::Impl>(
  962. MakeUnique<opt::DescriptorScalarReplacement>(
  963. /* flatten_composites= */ true, /* flatten_arrays= */ false));
  964. }
  965. Optimizer::PassToken CreateDescriptorArrayScalarReplacementPass() {
  966. return MakeUnique<Optimizer::PassToken::Impl>(
  967. MakeUnique<opt::DescriptorScalarReplacement>(
  968. /* flatten_composites= */ false, /* flatten_arrays= */ true));
  969. }
  970. Optimizer::PassToken CreateWrapOpKillPass() {
  971. return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::WrapOpKill>());
  972. }
  973. Optimizer::PassToken CreateAmdExtToKhrPass() {
  974. return MakeUnique<Optimizer::PassToken::Impl>(
  975. MakeUnique<opt::AmdExtensionToKhrPass>());
  976. }
  977. Optimizer::PassToken CreateInterpolateFixupPass() {
  978. return MakeUnique<Optimizer::PassToken::Impl>(
  979. MakeUnique<opt::InterpFixupPass>());
  980. }
  981. Optimizer::PassToken CreateEliminateDeadInputComponentsPass() {
  982. return MakeUnique<Optimizer::PassToken::Impl>(
  983. MakeUnique<opt::EliminateDeadIOComponentsPass>(spv::StorageClass::Input,
  984. /* safe_mode */ false));
  985. }
  986. Optimizer::PassToken CreateEliminateDeadOutputComponentsPass() {
  987. return MakeUnique<Optimizer::PassToken::Impl>(
  988. MakeUnique<opt::EliminateDeadIOComponentsPass>(spv::StorageClass::Output,
  989. /* safe_mode */ false));
  990. }
  991. Optimizer::PassToken CreateEliminateDeadInputComponentsSafePass() {
  992. return MakeUnique<Optimizer::PassToken::Impl>(
  993. MakeUnique<opt::EliminateDeadIOComponentsPass>(spv::StorageClass::Input,
  994. /* safe_mode */ true));
  995. }
  996. Optimizer::PassToken CreateAnalyzeLiveInputPass(
  997. std::unordered_set<uint32_t>* live_locs,
  998. std::unordered_set<uint32_t>* live_builtins) {
  999. return MakeUnique<Optimizer::PassToken::Impl>(
  1000. MakeUnique<opt::AnalyzeLiveInputPass>(live_locs, live_builtins));
  1001. }
  1002. Optimizer::PassToken CreateEliminateDeadOutputStoresPass(
  1003. std::unordered_set<uint32_t>* live_locs,
  1004. std::unordered_set<uint32_t>* live_builtins) {
  1005. return MakeUnique<Optimizer::PassToken::Impl>(
  1006. MakeUnique<opt::EliminateDeadOutputStoresPass>(live_locs, live_builtins));
  1007. }
  1008. Optimizer::PassToken CreateConvertToSampledImagePass(
  1009. const std::vector<opt::DescriptorSetAndBinding>&
  1010. descriptor_set_binding_pairs) {
  1011. return MakeUnique<Optimizer::PassToken::Impl>(
  1012. MakeUnique<opt::ConvertToSampledImagePass>(descriptor_set_binding_pairs));
  1013. }
  1014. Optimizer::PassToken CreateInterfaceVariableScalarReplacementPass() {
  1015. return MakeUnique<Optimizer::PassToken::Impl>(
  1016. MakeUnique<opt::InterfaceVariableScalarReplacement>());
  1017. }
  1018. Optimizer::PassToken CreateRemoveDontInlinePass() {
  1019. return MakeUnique<Optimizer::PassToken::Impl>(
  1020. MakeUnique<opt::RemoveDontInline>());
  1021. }
  1022. Optimizer::PassToken CreateFixFuncCallArgumentsPass() {
  1023. return MakeUnique<Optimizer::PassToken::Impl>(
  1024. MakeUnique<opt::FixFuncCallArgumentsPass>());
  1025. }
  1026. Optimizer::PassToken CreateTrimCapabilitiesPass() {
  1027. return MakeUnique<Optimizer::PassToken::Impl>(
  1028. MakeUnique<opt::TrimCapabilitiesPass>());
  1029. }
  1030. Optimizer::PassToken CreateStructPackingPass(const char* structToPack,
  1031. const char* packingRule) {
  1032. return MakeUnique<Optimizer::PassToken::Impl>(
  1033. MakeUnique<opt::StructPackingPass>(
  1034. structToPack,
  1035. opt::StructPackingPass::ParsePackingRuleFromString(packingRule)));
  1036. }
  1037. Optimizer::PassToken CreateSwitchDescriptorSetPass(uint32_t from, uint32_t to) {
  1038. return MakeUnique<Optimizer::PassToken::Impl>(
  1039. MakeUnique<opt::SwitchDescriptorSetPass>(from, to));
  1040. }
  1041. Optimizer::PassToken CreateInvocationInterlockPlacementPass() {
  1042. return MakeUnique<Optimizer::PassToken::Impl>(
  1043. MakeUnique<opt::InvocationInterlockPlacementPass>());
  1044. }
  1045. Optimizer::PassToken CreateModifyMaximalReconvergencePass(bool add) {
  1046. return MakeUnique<Optimizer::PassToken::Impl>(
  1047. MakeUnique<opt::ModifyMaximalReconvergence>(add));
  1048. }
  1049. Optimizer::PassToken CreateOpExtInstWithForwardReferenceFixupPass() {
  1050. return MakeUnique<Optimizer::PassToken::Impl>(
  1051. MakeUnique<opt::OpExtInstWithForwardReferenceFixupPass>());
  1052. }
  1053. Optimizer::PassToken CreateSplitCombinedImageSamplerPass() {
  1054. return MakeUnique<Optimizer::PassToken::Impl>(
  1055. MakeUnique<opt::SplitCombinedImageSamplerPass>());
  1056. }
  1057. Optimizer::PassToken CreateResolveBindingConflictsPass() {
  1058. return MakeUnique<Optimizer::PassToken::Impl>(
  1059. MakeUnique<opt::ResolveBindingConflictsPass>());
  1060. }
  1061. } // namespace spvtools
  1062. extern "C" {
  1063. SPIRV_TOOLS_EXPORT spv_optimizer_t* spvOptimizerCreate(spv_target_env env) {
  1064. return reinterpret_cast<spv_optimizer_t*>(new spvtools::Optimizer(env));
  1065. }
  1066. SPIRV_TOOLS_EXPORT void spvOptimizerDestroy(spv_optimizer_t* optimizer) {
  1067. delete reinterpret_cast<spvtools::Optimizer*>(optimizer);
  1068. }
  1069. SPIRV_TOOLS_EXPORT void spvOptimizerSetMessageConsumer(
  1070. spv_optimizer_t* optimizer, spv_message_consumer consumer) {
  1071. reinterpret_cast<spvtools::Optimizer*>(optimizer)->
  1072. SetMessageConsumer(
  1073. [consumer](spv_message_level_t level, const char* source,
  1074. const spv_position_t& position, const char* message) {
  1075. return consumer(level, source, &position, message);
  1076. });
  1077. }
  1078. SPIRV_TOOLS_EXPORT void spvOptimizerRegisterLegalizationPasses(
  1079. spv_optimizer_t* optimizer) {
  1080. reinterpret_cast<spvtools::Optimizer*>(optimizer)->
  1081. RegisterLegalizationPasses();
  1082. }
  1083. SPIRV_TOOLS_EXPORT void spvOptimizerRegisterPerformancePasses(
  1084. spv_optimizer_t* optimizer) {
  1085. reinterpret_cast<spvtools::Optimizer*>(optimizer)->
  1086. RegisterPerformancePasses();
  1087. }
  1088. SPIRV_TOOLS_EXPORT void spvOptimizerRegisterSizePasses(
  1089. spv_optimizer_t* optimizer) {
  1090. reinterpret_cast<spvtools::Optimizer*>(optimizer)->RegisterSizePasses();
  1091. }
  1092. SPIRV_TOOLS_EXPORT bool spvOptimizerRegisterPassFromFlag(
  1093. spv_optimizer_t* optimizer, const char* flag)
  1094. {
  1095. return reinterpret_cast<spvtools::Optimizer*>(optimizer)->
  1096. RegisterPassFromFlag(flag);
  1097. }
  1098. SPIRV_TOOLS_EXPORT bool spvOptimizerRegisterPassesFromFlags(
  1099. spv_optimizer_t* optimizer, const char** flags, const size_t flag_count) {
  1100. std::vector<std::string> opt_flags =
  1101. spvtools::GetVectorOfStrings(flags, flag_count);
  1102. return reinterpret_cast<spvtools::Optimizer*>(optimizer)
  1103. ->RegisterPassesFromFlags(opt_flags, false);
  1104. }
  1105. SPIRV_TOOLS_EXPORT bool
  1106. spvOptimizerRegisterPassesFromFlagsWhilePreservingTheInterface(
  1107. spv_optimizer_t* optimizer, const char** flags, const size_t flag_count) {
  1108. std::vector<std::string> opt_flags =
  1109. spvtools::GetVectorOfStrings(flags, flag_count);
  1110. return reinterpret_cast<spvtools::Optimizer*>(optimizer)
  1111. ->RegisterPassesFromFlags(opt_flags, true);
  1112. }
  1113. SPIRV_TOOLS_EXPORT
  1114. spv_result_t spvOptimizerRun(spv_optimizer_t* optimizer,
  1115. const uint32_t* binary,
  1116. const size_t word_count,
  1117. spv_binary* optimized_binary,
  1118. const spv_optimizer_options options) {
  1119. std::vector<uint32_t> optimized;
  1120. if (!reinterpret_cast<spvtools::Optimizer*>(optimizer)->
  1121. Run(binary, word_count, &optimized, options)) {
  1122. return SPV_ERROR_INTERNAL;
  1123. }
  1124. auto result_binary = new spv_binary_t();
  1125. if (!result_binary) {
  1126. *optimized_binary = nullptr;
  1127. return SPV_ERROR_OUT_OF_MEMORY;
  1128. }
  1129. result_binary->code = new uint32_t[optimized.size()];
  1130. if (!result_binary->code) {
  1131. delete result_binary;
  1132. *optimized_binary = nullptr;
  1133. return SPV_ERROR_OUT_OF_MEMORY;
  1134. }
  1135. result_binary->wordCount = optimized.size();
  1136. memcpy(result_binary->code, optimized.data(),
  1137. optimized.size() * sizeof(uint32_t));
  1138. *optimized_binary = result_binary;
  1139. return SPV_SUCCESS;
  1140. }
  1141. } // extern "C"