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