• 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 == "convert-to-sampled-image") {
529     if (pass_args.size() > 0) {
530       auto descriptor_set_binding_pairs =
531           opt::ConvertToSampledImagePass::ParseDescriptorSetBindingPairsString(
532               pass_args.c_str());
533       if (!descriptor_set_binding_pairs) {
534         Errorf(consumer(), nullptr, {},
535                "Invalid argument for --convert-to-sampled-image: %s",
536                pass_args.c_str());
537         return false;
538       }
539       RegisterPass(CreateConvertToSampledImagePass(
540           std::move(*descriptor_set_binding_pairs)));
541     } else {
542       Errorf(consumer(), nullptr, {},
543              "Invalid pairs of descriptor set and binding '%s'. Expected a "
544              "string of <descriptor set>:<binding> pairs.",
545              pass_args.c_str());
546       return false;
547     }
548   } else {
549     Errorf(consumer(), nullptr, {},
550            "Unknown flag '--%s'. Use --help for a list of valid flags",
551            pass_name.c_str());
552     return false;
553   }
554 
555   return true;
556 }
557 
SetTargetEnv(const spv_target_env env)558 void Optimizer::SetTargetEnv(const spv_target_env env) {
559   impl_->target_env = env;
560 }
561 
Run(const uint32_t * original_binary,const size_t original_binary_size,std::vector<uint32_t> * optimized_binary) const562 bool Optimizer::Run(const uint32_t* original_binary,
563                     const size_t original_binary_size,
564                     std::vector<uint32_t>* optimized_binary) const {
565   return Run(original_binary, original_binary_size, optimized_binary,
566              OptimizerOptions());
567 }
568 
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) const569 bool Optimizer::Run(const uint32_t* original_binary,
570                     const size_t original_binary_size,
571                     std::vector<uint32_t>* optimized_binary,
572                     const ValidatorOptions& validator_options,
573                     bool skip_validation) const {
574   OptimizerOptions opt_options;
575   opt_options.set_run_validator(!skip_validation);
576   opt_options.set_validator_options(validator_options);
577   return Run(original_binary, original_binary_size, optimized_binary,
578              opt_options);
579 }
580 
Run(const uint32_t * original_binary,const size_t original_binary_size,std::vector<uint32_t> * optimized_binary,const spv_optimizer_options opt_options) const581 bool Optimizer::Run(const uint32_t* original_binary,
582                     const size_t original_binary_size,
583                     std::vector<uint32_t>* optimized_binary,
584                     const spv_optimizer_options opt_options) const {
585   spvtools::SpirvTools tools(impl_->target_env);
586   tools.SetMessageConsumer(impl_->pass_manager.consumer());
587   if (opt_options->run_validator_ &&
588       !tools.Validate(original_binary, original_binary_size,
589                       &opt_options->val_options_)) {
590     return false;
591   }
592 
593   std::unique_ptr<opt::IRContext> context = BuildModule(
594       impl_->target_env, consumer(), original_binary, original_binary_size);
595   if (context == nullptr) return false;
596 
597   context->set_max_id_bound(opt_options->max_id_bound_);
598   context->set_preserve_bindings(opt_options->preserve_bindings_);
599   context->set_preserve_spec_constants(opt_options->preserve_spec_constants_);
600 
601   impl_->pass_manager.SetValidatorOptions(&opt_options->val_options_);
602   impl_->pass_manager.SetTargetEnv(impl_->target_env);
603   auto status = impl_->pass_manager.Run(context.get());
604 
605   if (status == opt::Pass::Status::Failure) {
606     return false;
607   }
608 
609 #ifndef NDEBUG
610   // We do not keep the result id of DebugScope in struct DebugScope.
611   // Instead, we assign random ids for them, which results in integrity
612   // check failures. In addition, propagating the OpLine/OpNoLine to preserve
613   // the debug information through transformations results in integrity
614   // check failures. We want to skip the integrity check when the module
615   // contains DebugScope or OpLine/OpNoLine instructions.
616   if (status == opt::Pass::Status::SuccessWithoutChange &&
617       !context->module()->ContainsDebugInfo()) {
618     std::vector<uint32_t> optimized_binary_with_nop;
619     context->module()->ToBinary(&optimized_binary_with_nop,
620                                 /* skip_nop = */ false);
621     assert(optimized_binary_with_nop.size() == original_binary_size &&
622            "Binary size unexpectedly changed despite the optimizer saying "
623            "there was no change");
624     assert(memcmp(optimized_binary_with_nop.data(), original_binary,
625                   original_binary_size) == 0 &&
626            "Binary content unexpectedly changed despite the optimizer saying "
627            "there was no change");
628   }
629 #endif  // !NDEBUG
630 
631   // Note that |original_binary| and |optimized_binary| may share the same
632   // buffer and the below will invalidate |original_binary|.
633   optimized_binary->clear();
634   context->module()->ToBinary(optimized_binary, /* skip_nop = */ true);
635 
636   return true;
637 }
638 
SetPrintAll(std::ostream * out)639 Optimizer& Optimizer::SetPrintAll(std::ostream* out) {
640   impl_->pass_manager.SetPrintAll(out);
641   return *this;
642 }
643 
SetTimeReport(std::ostream * out)644 Optimizer& Optimizer::SetTimeReport(std::ostream* out) {
645   impl_->pass_manager.SetTimeReport(out);
646   return *this;
647 }
648 
SetValidateAfterAll(bool validate)649 Optimizer& Optimizer::SetValidateAfterAll(bool validate) {
650   impl_->pass_manager.SetValidateAfterAll(validate);
651   return *this;
652 }
653 
CreateNullPass()654 Optimizer::PassToken CreateNullPass() {
655   return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::NullPass>());
656 }
657 
CreateStripDebugInfoPass()658 Optimizer::PassToken CreateStripDebugInfoPass() {
659   return MakeUnique<Optimizer::PassToken::Impl>(
660       MakeUnique<opt::StripDebugInfoPass>());
661 }
662 
CreateStripReflectInfoPass()663 Optimizer::PassToken CreateStripReflectInfoPass() {
664   return CreateStripNonSemanticInfoPass();
665 }
666 
CreateStripNonSemanticInfoPass()667 Optimizer::PassToken CreateStripNonSemanticInfoPass() {
668   return MakeUnique<Optimizer::PassToken::Impl>(
669       MakeUnique<opt::StripNonSemanticInfoPass>());
670 }
671 
CreateEliminateDeadFunctionsPass()672 Optimizer::PassToken CreateEliminateDeadFunctionsPass() {
673   return MakeUnique<Optimizer::PassToken::Impl>(
674       MakeUnique<opt::EliminateDeadFunctionsPass>());
675 }
676 
CreateEliminateDeadMembersPass()677 Optimizer::PassToken CreateEliminateDeadMembersPass() {
678   return MakeUnique<Optimizer::PassToken::Impl>(
679       MakeUnique<opt::EliminateDeadMembersPass>());
680 }
681 
CreateSetSpecConstantDefaultValuePass(const std::unordered_map<uint32_t,std::string> & id_value_map)682 Optimizer::PassToken CreateSetSpecConstantDefaultValuePass(
683     const std::unordered_map<uint32_t, std::string>& id_value_map) {
684   return MakeUnique<Optimizer::PassToken::Impl>(
685       MakeUnique<opt::SetSpecConstantDefaultValuePass>(id_value_map));
686 }
687 
CreateSetSpecConstantDefaultValuePass(const std::unordered_map<uint32_t,std::vector<uint32_t>> & id_value_map)688 Optimizer::PassToken CreateSetSpecConstantDefaultValuePass(
689     const std::unordered_map<uint32_t, std::vector<uint32_t>>& id_value_map) {
690   return MakeUnique<Optimizer::PassToken::Impl>(
691       MakeUnique<opt::SetSpecConstantDefaultValuePass>(id_value_map));
692 }
693 
CreateFlattenDecorationPass()694 Optimizer::PassToken CreateFlattenDecorationPass() {
695   return MakeUnique<Optimizer::PassToken::Impl>(
696       MakeUnique<opt::FlattenDecorationPass>());
697 }
698 
CreateFreezeSpecConstantValuePass()699 Optimizer::PassToken CreateFreezeSpecConstantValuePass() {
700   return MakeUnique<Optimizer::PassToken::Impl>(
701       MakeUnique<opt::FreezeSpecConstantValuePass>());
702 }
703 
CreateFoldSpecConstantOpAndCompositePass()704 Optimizer::PassToken CreateFoldSpecConstantOpAndCompositePass() {
705   return MakeUnique<Optimizer::PassToken::Impl>(
706       MakeUnique<opt::FoldSpecConstantOpAndCompositePass>());
707 }
708 
CreateUnifyConstantPass()709 Optimizer::PassToken CreateUnifyConstantPass() {
710   return MakeUnique<Optimizer::PassToken::Impl>(
711       MakeUnique<opt::UnifyConstantPass>());
712 }
713 
CreateEliminateDeadConstantPass()714 Optimizer::PassToken CreateEliminateDeadConstantPass() {
715   return MakeUnique<Optimizer::PassToken::Impl>(
716       MakeUnique<opt::EliminateDeadConstantPass>());
717 }
718 
CreateDeadVariableEliminationPass()719 Optimizer::PassToken CreateDeadVariableEliminationPass() {
720   return MakeUnique<Optimizer::PassToken::Impl>(
721       MakeUnique<opt::DeadVariableElimination>());
722 }
723 
CreateStrengthReductionPass()724 Optimizer::PassToken CreateStrengthReductionPass() {
725   return MakeUnique<Optimizer::PassToken::Impl>(
726       MakeUnique<opt::StrengthReductionPass>());
727 }
728 
CreateBlockMergePass()729 Optimizer::PassToken CreateBlockMergePass() {
730   return MakeUnique<Optimizer::PassToken::Impl>(
731       MakeUnique<opt::BlockMergePass>());
732 }
733 
CreateInlineExhaustivePass()734 Optimizer::PassToken CreateInlineExhaustivePass() {
735   return MakeUnique<Optimizer::PassToken::Impl>(
736       MakeUnique<opt::InlineExhaustivePass>());
737 }
738 
CreateInlineOpaquePass()739 Optimizer::PassToken CreateInlineOpaquePass() {
740   return MakeUnique<Optimizer::PassToken::Impl>(
741       MakeUnique<opt::InlineOpaquePass>());
742 }
743 
CreateLocalAccessChainConvertPass()744 Optimizer::PassToken CreateLocalAccessChainConvertPass() {
745   return MakeUnique<Optimizer::PassToken::Impl>(
746       MakeUnique<opt::LocalAccessChainConvertPass>());
747 }
748 
CreateLocalSingleBlockLoadStoreElimPass()749 Optimizer::PassToken CreateLocalSingleBlockLoadStoreElimPass() {
750   return MakeUnique<Optimizer::PassToken::Impl>(
751       MakeUnique<opt::LocalSingleBlockLoadStoreElimPass>());
752 }
753 
CreateLocalSingleStoreElimPass()754 Optimizer::PassToken CreateLocalSingleStoreElimPass() {
755   return MakeUnique<Optimizer::PassToken::Impl>(
756       MakeUnique<opt::LocalSingleStoreElimPass>());
757 }
758 
CreateInsertExtractElimPass()759 Optimizer::PassToken CreateInsertExtractElimPass() {
760   return MakeUnique<Optimizer::PassToken::Impl>(
761       MakeUnique<opt::SimplificationPass>());
762 }
763 
CreateDeadInsertElimPass()764 Optimizer::PassToken CreateDeadInsertElimPass() {
765   return MakeUnique<Optimizer::PassToken::Impl>(
766       MakeUnique<opt::DeadInsertElimPass>());
767 }
768 
CreateDeadBranchElimPass()769 Optimizer::PassToken CreateDeadBranchElimPass() {
770   return MakeUnique<Optimizer::PassToken::Impl>(
771       MakeUnique<opt::DeadBranchElimPass>());
772 }
773 
CreateLocalMultiStoreElimPass()774 Optimizer::PassToken CreateLocalMultiStoreElimPass() {
775   return MakeUnique<Optimizer::PassToken::Impl>(
776       MakeUnique<opt::SSARewritePass>());
777 }
778 
CreateAggressiveDCEPass()779 Optimizer::PassToken CreateAggressiveDCEPass() {
780   return MakeUnique<Optimizer::PassToken::Impl>(
781       MakeUnique<opt::AggressiveDCEPass>(false));
782 }
783 
CreateAggressiveDCEPass(bool preserve_interface)784 Optimizer::PassToken CreateAggressiveDCEPass(bool preserve_interface) {
785   return MakeUnique<Optimizer::PassToken::Impl>(
786       MakeUnique<opt::AggressiveDCEPass>(preserve_interface));
787 }
788 
CreateRemoveUnusedInterfaceVariablesPass()789 Optimizer::PassToken CreateRemoveUnusedInterfaceVariablesPass() {
790   return MakeUnique<Optimizer::PassToken::Impl>(
791       MakeUnique<opt::RemoveUnusedInterfaceVariablesPass>());
792 }
793 
CreatePropagateLineInfoPass()794 Optimizer::PassToken CreatePropagateLineInfoPass() {
795   return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::EmptyPass>());
796 }
797 
CreateRedundantLineInfoElimPass()798 Optimizer::PassToken CreateRedundantLineInfoElimPass() {
799   return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::EmptyPass>());
800 }
801 
CreateCompactIdsPass()802 Optimizer::PassToken CreateCompactIdsPass() {
803   return MakeUnique<Optimizer::PassToken::Impl>(
804       MakeUnique<opt::CompactIdsPass>());
805 }
806 
CreateMergeReturnPass()807 Optimizer::PassToken CreateMergeReturnPass() {
808   return MakeUnique<Optimizer::PassToken::Impl>(
809       MakeUnique<opt::MergeReturnPass>());
810 }
811 
GetPassNames() const812 std::vector<const char*> Optimizer::GetPassNames() const {
813   std::vector<const char*> v;
814   for (uint32_t i = 0; i < impl_->pass_manager.NumPasses(); i++) {
815     v.push_back(impl_->pass_manager.GetPass(i)->name());
816   }
817   return v;
818 }
819 
CreateCFGCleanupPass()820 Optimizer::PassToken CreateCFGCleanupPass() {
821   return MakeUnique<Optimizer::PassToken::Impl>(
822       MakeUnique<opt::CFGCleanupPass>());
823 }
824 
CreateLocalRedundancyEliminationPass()825 Optimizer::PassToken CreateLocalRedundancyEliminationPass() {
826   return MakeUnique<Optimizer::PassToken::Impl>(
827       MakeUnique<opt::LocalRedundancyEliminationPass>());
828 }
829 
CreateLoopFissionPass(size_t threshold)830 Optimizer::PassToken CreateLoopFissionPass(size_t threshold) {
831   return MakeUnique<Optimizer::PassToken::Impl>(
832       MakeUnique<opt::LoopFissionPass>(threshold));
833 }
834 
CreateLoopFusionPass(size_t max_registers_per_loop)835 Optimizer::PassToken CreateLoopFusionPass(size_t max_registers_per_loop) {
836   return MakeUnique<Optimizer::PassToken::Impl>(
837       MakeUnique<opt::LoopFusionPass>(max_registers_per_loop));
838 }
839 
CreateLoopInvariantCodeMotionPass()840 Optimizer::PassToken CreateLoopInvariantCodeMotionPass() {
841   return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::LICMPass>());
842 }
843 
CreateLoopPeelingPass()844 Optimizer::PassToken CreateLoopPeelingPass() {
845   return MakeUnique<Optimizer::PassToken::Impl>(
846       MakeUnique<opt::LoopPeelingPass>());
847 }
848 
CreateLoopUnswitchPass()849 Optimizer::PassToken CreateLoopUnswitchPass() {
850   return MakeUnique<Optimizer::PassToken::Impl>(
851       MakeUnique<opt::LoopUnswitchPass>());
852 }
853 
CreateRedundancyEliminationPass()854 Optimizer::PassToken CreateRedundancyEliminationPass() {
855   return MakeUnique<Optimizer::PassToken::Impl>(
856       MakeUnique<opt::RedundancyEliminationPass>());
857 }
858 
CreateRemoveDuplicatesPass()859 Optimizer::PassToken CreateRemoveDuplicatesPass() {
860   return MakeUnique<Optimizer::PassToken::Impl>(
861       MakeUnique<opt::RemoveDuplicatesPass>());
862 }
863 
CreateScalarReplacementPass(uint32_t size_limit)864 Optimizer::PassToken CreateScalarReplacementPass(uint32_t size_limit) {
865   return MakeUnique<Optimizer::PassToken::Impl>(
866       MakeUnique<opt::ScalarReplacementPass>(size_limit));
867 }
868 
CreatePrivateToLocalPass()869 Optimizer::PassToken CreatePrivateToLocalPass() {
870   return MakeUnique<Optimizer::PassToken::Impl>(
871       MakeUnique<opt::PrivateToLocalPass>());
872 }
873 
CreateCCPPass()874 Optimizer::PassToken CreateCCPPass() {
875   return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::CCPPass>());
876 }
877 
CreateWorkaround1209Pass()878 Optimizer::PassToken CreateWorkaround1209Pass() {
879   return MakeUnique<Optimizer::PassToken::Impl>(
880       MakeUnique<opt::Workaround1209>());
881 }
882 
CreateIfConversionPass()883 Optimizer::PassToken CreateIfConversionPass() {
884   return MakeUnique<Optimizer::PassToken::Impl>(
885       MakeUnique<opt::IfConversion>());
886 }
887 
CreateReplaceInvalidOpcodePass()888 Optimizer::PassToken CreateReplaceInvalidOpcodePass() {
889   return MakeUnique<Optimizer::PassToken::Impl>(
890       MakeUnique<opt::ReplaceInvalidOpcodePass>());
891 }
892 
CreateSimplificationPass()893 Optimizer::PassToken CreateSimplificationPass() {
894   return MakeUnique<Optimizer::PassToken::Impl>(
895       MakeUnique<opt::SimplificationPass>());
896 }
897 
CreateLoopUnrollPass(bool fully_unroll,int factor)898 Optimizer::PassToken CreateLoopUnrollPass(bool fully_unroll, int factor) {
899   return MakeUnique<Optimizer::PassToken::Impl>(
900       MakeUnique<opt::LoopUnroller>(fully_unroll, factor));
901 }
902 
CreateSSARewritePass()903 Optimizer::PassToken CreateSSARewritePass() {
904   return MakeUnique<Optimizer::PassToken::Impl>(
905       MakeUnique<opt::SSARewritePass>());
906 }
907 
CreateCopyPropagateArraysPass()908 Optimizer::PassToken CreateCopyPropagateArraysPass() {
909   return MakeUnique<Optimizer::PassToken::Impl>(
910       MakeUnique<opt::CopyPropagateArrays>());
911 }
912 
CreateVectorDCEPass()913 Optimizer::PassToken CreateVectorDCEPass() {
914   return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::VectorDCE>());
915 }
916 
CreateReduceLoadSizePass(double load_replacement_threshold)917 Optimizer::PassToken CreateReduceLoadSizePass(
918     double load_replacement_threshold) {
919   return MakeUnique<Optimizer::PassToken::Impl>(
920       MakeUnique<opt::ReduceLoadSize>(load_replacement_threshold));
921 }
922 
CreateCombineAccessChainsPass()923 Optimizer::PassToken CreateCombineAccessChainsPass() {
924   return MakeUnique<Optimizer::PassToken::Impl>(
925       MakeUnique<opt::CombineAccessChains>());
926 }
927 
CreateUpgradeMemoryModelPass()928 Optimizer::PassToken CreateUpgradeMemoryModelPass() {
929   return MakeUnique<Optimizer::PassToken::Impl>(
930       MakeUnique<opt::UpgradeMemoryModel>());
931 }
932 
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)933 Optimizer::PassToken CreateInstBindlessCheckPass(
934     uint32_t desc_set, uint32_t shader_id, bool desc_length_enable,
935     bool desc_init_enable, bool buff_oob_enable, bool texbuff_oob_enable) {
936   return MakeUnique<Optimizer::PassToken::Impl>(
937       MakeUnique<opt::InstBindlessCheckPass>(
938           desc_set, shader_id, desc_length_enable, desc_init_enable,
939           buff_oob_enable, texbuff_oob_enable,
940           desc_length_enable || desc_init_enable || buff_oob_enable));
941 }
942 
CreateInstDebugPrintfPass(uint32_t desc_set,uint32_t shader_id)943 Optimizer::PassToken CreateInstDebugPrintfPass(uint32_t desc_set,
944                                                uint32_t shader_id) {
945   return MakeUnique<Optimizer::PassToken::Impl>(
946       MakeUnique<opt::InstDebugPrintfPass>(desc_set, shader_id));
947 }
948 
CreateInstBuffAddrCheckPass(uint32_t desc_set,uint32_t shader_id)949 Optimizer::PassToken CreateInstBuffAddrCheckPass(uint32_t desc_set,
950                                                  uint32_t shader_id) {
951   return MakeUnique<Optimizer::PassToken::Impl>(
952       MakeUnique<opt::InstBuffAddrCheckPass>(desc_set, shader_id));
953 }
954 
CreateConvertRelaxedToHalfPass()955 Optimizer::PassToken CreateConvertRelaxedToHalfPass() {
956   return MakeUnique<Optimizer::PassToken::Impl>(
957       MakeUnique<opt::ConvertToHalfPass>());
958 }
959 
CreateRelaxFloatOpsPass()960 Optimizer::PassToken CreateRelaxFloatOpsPass() {
961   return MakeUnique<Optimizer::PassToken::Impl>(
962       MakeUnique<opt::RelaxFloatOpsPass>());
963 }
964 
CreateCodeSinkingPass()965 Optimizer::PassToken CreateCodeSinkingPass() {
966   return MakeUnique<Optimizer::PassToken::Impl>(
967       MakeUnique<opt::CodeSinkingPass>());
968 }
969 
CreateFixStorageClassPass()970 Optimizer::PassToken CreateFixStorageClassPass() {
971   return MakeUnique<Optimizer::PassToken::Impl>(
972       MakeUnique<opt::FixStorageClass>());
973 }
974 
CreateGraphicsRobustAccessPass()975 Optimizer::PassToken CreateGraphicsRobustAccessPass() {
976   return MakeUnique<Optimizer::PassToken::Impl>(
977       MakeUnique<opt::GraphicsRobustAccessPass>());
978 }
979 
CreateReplaceDescArrayAccessUsingVarIndexPass()980 Optimizer::PassToken CreateReplaceDescArrayAccessUsingVarIndexPass() {
981   return MakeUnique<Optimizer::PassToken::Impl>(
982       MakeUnique<opt::ReplaceDescArrayAccessUsingVarIndex>());
983 }
984 
CreateSpreadVolatileSemanticsPass()985 Optimizer::PassToken CreateSpreadVolatileSemanticsPass() {
986   return MakeUnique<Optimizer::PassToken::Impl>(
987       MakeUnique<opt::SpreadVolatileSemantics>());
988 }
989 
CreateDescriptorScalarReplacementPass()990 Optimizer::PassToken CreateDescriptorScalarReplacementPass() {
991   return MakeUnique<Optimizer::PassToken::Impl>(
992       MakeUnique<opt::DescriptorScalarReplacement>());
993 }
994 
CreateWrapOpKillPass()995 Optimizer::PassToken CreateWrapOpKillPass() {
996   return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::WrapOpKill>());
997 }
998 
CreateAmdExtToKhrPass()999 Optimizer::PassToken CreateAmdExtToKhrPass() {
1000   return MakeUnique<Optimizer::PassToken::Impl>(
1001       MakeUnique<opt::AmdExtensionToKhrPass>());
1002 }
1003 
CreateInterpolateFixupPass()1004 Optimizer::PassToken CreateInterpolateFixupPass() {
1005   return MakeUnique<Optimizer::PassToken::Impl>(
1006       MakeUnique<opt::InterpFixupPass>());
1007 }
1008 
CreateEliminateDeadInputComponentsPass()1009 Optimizer::PassToken CreateEliminateDeadInputComponentsPass() {
1010   return MakeUnique<Optimizer::PassToken::Impl>(
1011       MakeUnique<opt::EliminateDeadInputComponentsPass>());
1012 }
1013 
CreateConvertToSampledImagePass(const std::vector<opt::DescriptorSetAndBinding> & descriptor_set_binding_pairs)1014 Optimizer::PassToken CreateConvertToSampledImagePass(
1015     const std::vector<opt::DescriptorSetAndBinding>&
1016         descriptor_set_binding_pairs) {
1017   return MakeUnique<Optimizer::PassToken::Impl>(
1018       MakeUnique<opt::ConvertToSampledImagePass>(descriptor_set_binding_pairs));
1019 }
1020 
CreateRemoveDontInlinePass()1021 Optimizer::PassToken CreateRemoveDontInlinePass() {
1022   return MakeUnique<Optimizer::PassToken::Impl>(
1023       MakeUnique<opt::RemoveDontInline>());
1024 }
1025 }  // namespace spvtools
1026