• 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 == "set-spec-const-default-value") {
292     if (pass_args.size() > 0) {
293       auto spec_ids_vals =
294           opt::SetSpecConstantDefaultValuePass::ParseDefaultValuesString(
295               pass_args.c_str());
296       if (!spec_ids_vals) {
297         Errorf(consumer(), nullptr, {},
298                "Invalid argument for --set-spec-const-default-value: %s",
299                pass_args.c_str());
300         return false;
301       }
302       RegisterPass(
303           CreateSetSpecConstantDefaultValuePass(std::move(*spec_ids_vals)));
304     } else {
305       Errorf(consumer(), nullptr, {},
306              "Invalid spec constant value string '%s'. Expected a string of "
307              "<spec id>:<default value> pairs.",
308              pass_args.c_str());
309       return false;
310     }
311   } else if (pass_name == "if-conversion") {
312     RegisterPass(CreateIfConversionPass());
313   } else if (pass_name == "freeze-spec-const") {
314     RegisterPass(CreateFreezeSpecConstantValuePass());
315   } else if (pass_name == "inline-entry-points-exhaustive") {
316     RegisterPass(CreateInlineExhaustivePass());
317   } else if (pass_name == "inline-entry-points-opaque") {
318     RegisterPass(CreateInlineOpaquePass());
319   } else if (pass_name == "combine-access-chains") {
320     RegisterPass(CreateCombineAccessChainsPass());
321   } else if (pass_name == "convert-local-access-chains") {
322     RegisterPass(CreateLocalAccessChainConvertPass());
323   } else if (pass_name == "replace-desc-array-access-using-var-index") {
324     RegisterPass(CreateReplaceDescArrayAccessUsingVarIndexPass());
325   } else if (pass_name == "descriptor-scalar-replacement") {
326     RegisterPass(CreateDescriptorScalarReplacementPass());
327   } else if (pass_name == "eliminate-dead-code-aggressive") {
328     RegisterPass(CreateAggressiveDCEPass());
329   } else if (pass_name == "eliminate-insert-extract") {
330     RegisterPass(CreateInsertExtractElimPass());
331   } else if (pass_name == "eliminate-local-single-block") {
332     RegisterPass(CreateLocalSingleBlockLoadStoreElimPass());
333   } else if (pass_name == "eliminate-local-single-store") {
334     RegisterPass(CreateLocalSingleStoreElimPass());
335   } else if (pass_name == "merge-blocks") {
336     RegisterPass(CreateBlockMergePass());
337   } else if (pass_name == "merge-return") {
338     RegisterPass(CreateMergeReturnPass());
339   } else if (pass_name == "eliminate-dead-branches") {
340     RegisterPass(CreateDeadBranchElimPass());
341   } else if (pass_name == "eliminate-dead-functions") {
342     RegisterPass(CreateEliminateDeadFunctionsPass());
343   } else if (pass_name == "eliminate-local-multi-store") {
344     RegisterPass(CreateLocalMultiStoreElimPass());
345   } else if (pass_name == "eliminate-dead-const") {
346     RegisterPass(CreateEliminateDeadConstantPass());
347   } else if (pass_name == "eliminate-dead-inserts") {
348     RegisterPass(CreateDeadInsertElimPass());
349   } else if (pass_name == "eliminate-dead-variables") {
350     RegisterPass(CreateDeadVariableEliminationPass());
351   } else if (pass_name == "eliminate-dead-members") {
352     RegisterPass(CreateEliminateDeadMembersPass());
353   } else if (pass_name == "fold-spec-const-op-composite") {
354     RegisterPass(CreateFoldSpecConstantOpAndCompositePass());
355   } else if (pass_name == "loop-unswitch") {
356     RegisterPass(CreateLoopUnswitchPass());
357   } else if (pass_name == "scalar-replacement") {
358     if (pass_args.size() == 0) {
359       RegisterPass(CreateScalarReplacementPass());
360     } else {
361       int limit = -1;
362       if (pass_args.find_first_not_of("0123456789") == std::string::npos) {
363         limit = atoi(pass_args.c_str());
364       }
365 
366       if (limit >= 0) {
367         RegisterPass(CreateScalarReplacementPass(limit));
368       } else {
369         Error(consumer(), nullptr, {},
370               "--scalar-replacement must have no arguments or a non-negative "
371               "integer argument");
372         return false;
373       }
374     }
375   } else if (pass_name == "strength-reduction") {
376     RegisterPass(CreateStrengthReductionPass());
377   } else if (pass_name == "unify-const") {
378     RegisterPass(CreateUnifyConstantPass());
379   } else if (pass_name == "flatten-decorations") {
380     RegisterPass(CreateFlattenDecorationPass());
381   } else if (pass_name == "compact-ids") {
382     RegisterPass(CreateCompactIdsPass());
383   } else if (pass_name == "cfg-cleanup") {
384     RegisterPass(CreateCFGCleanupPass());
385   } else if (pass_name == "local-redundancy-elimination") {
386     RegisterPass(CreateLocalRedundancyEliminationPass());
387   } else if (pass_name == "loop-invariant-code-motion") {
388     RegisterPass(CreateLoopInvariantCodeMotionPass());
389   } else if (pass_name == "reduce-load-size") {
390     if (pass_args.size() == 0) {
391       RegisterPass(CreateReduceLoadSizePass());
392     } else {
393       double load_replacement_threshold = 0.9;
394       if (pass_args.find_first_not_of(".0123456789") == std::string::npos) {
395         load_replacement_threshold = atof(pass_args.c_str());
396       }
397 
398       if (load_replacement_threshold >= 0) {
399         RegisterPass(CreateReduceLoadSizePass(load_replacement_threshold));
400       } else {
401         Error(consumer(), nullptr, {},
402               "--reduce-load-size must have no arguments or a non-negative "
403               "double argument");
404         return false;
405       }
406     }
407   } else if (pass_name == "redundancy-elimination") {
408     RegisterPass(CreateRedundancyEliminationPass());
409   } else if (pass_name == "private-to-local") {
410     RegisterPass(CreatePrivateToLocalPass());
411   } else if (pass_name == "remove-duplicates") {
412     RegisterPass(CreateRemoveDuplicatesPass());
413   } else if (pass_name == "workaround-1209") {
414     RegisterPass(CreateWorkaround1209Pass());
415   } else if (pass_name == "replace-invalid-opcode") {
416     RegisterPass(CreateReplaceInvalidOpcodePass());
417   } else if (pass_name == "inst-bindless-check") {
418     RegisterPass(CreateInstBindlessCheckPass(7, 23, false, false));
419     RegisterPass(CreateSimplificationPass());
420     RegisterPass(CreateDeadBranchElimPass());
421     RegisterPass(CreateBlockMergePass());
422     RegisterPass(CreateAggressiveDCEPass(true));
423   } else if (pass_name == "inst-desc-idx-check") {
424     RegisterPass(CreateInstBindlessCheckPass(7, 23, true, true));
425     RegisterPass(CreateSimplificationPass());
426     RegisterPass(CreateDeadBranchElimPass());
427     RegisterPass(CreateBlockMergePass());
428     RegisterPass(CreateAggressiveDCEPass(true));
429   } else if (pass_name == "inst-buff-oob-check") {
430     RegisterPass(CreateInstBindlessCheckPass(7, 23, false, false, true, true));
431     RegisterPass(CreateSimplificationPass());
432     RegisterPass(CreateDeadBranchElimPass());
433     RegisterPass(CreateBlockMergePass());
434     RegisterPass(CreateAggressiveDCEPass(true));
435   } else if (pass_name == "inst-buff-addr-check") {
436     RegisterPass(CreateInstBuffAddrCheckPass(7, 23));
437     RegisterPass(CreateAggressiveDCEPass(true));
438   } else if (pass_name == "convert-relaxed-to-half") {
439     RegisterPass(CreateConvertRelaxedToHalfPass());
440   } else if (pass_name == "relax-float-ops") {
441     RegisterPass(CreateRelaxFloatOpsPass());
442   } else if (pass_name == "inst-debug-printf") {
443     RegisterPass(CreateInstDebugPrintfPass(7, 23));
444   } else if (pass_name == "simplify-instructions") {
445     RegisterPass(CreateSimplificationPass());
446   } else if (pass_name == "ssa-rewrite") {
447     RegisterPass(CreateSSARewritePass());
448   } else if (pass_name == "copy-propagate-arrays") {
449     RegisterPass(CreateCopyPropagateArraysPass());
450   } else if (pass_name == "loop-fission") {
451     int register_threshold_to_split =
452         (pass_args.size() > 0) ? atoi(pass_args.c_str()) : -1;
453     if (register_threshold_to_split > 0) {
454       RegisterPass(CreateLoopFissionPass(
455           static_cast<size_t>(register_threshold_to_split)));
456     } else {
457       Error(consumer(), nullptr, {},
458             "--loop-fission must have a positive integer argument");
459       return false;
460     }
461   } else if (pass_name == "loop-fusion") {
462     int max_registers_per_loop =
463         (pass_args.size() > 0) ? atoi(pass_args.c_str()) : -1;
464     if (max_registers_per_loop > 0) {
465       RegisterPass(
466           CreateLoopFusionPass(static_cast<size_t>(max_registers_per_loop)));
467     } else {
468       Error(consumer(), nullptr, {},
469             "--loop-fusion must have a positive integer argument");
470       return false;
471     }
472   } else if (pass_name == "loop-unroll") {
473     RegisterPass(CreateLoopUnrollPass(true));
474   } else if (pass_name == "upgrade-memory-model") {
475     RegisterPass(CreateUpgradeMemoryModelPass());
476   } else if (pass_name == "vector-dce") {
477     RegisterPass(CreateVectorDCEPass());
478   } else if (pass_name == "loop-unroll-partial") {
479     int factor = (pass_args.size() > 0) ? atoi(pass_args.c_str()) : 0;
480     if (factor > 0) {
481       RegisterPass(CreateLoopUnrollPass(false, factor));
482     } else {
483       Error(consumer(), nullptr, {},
484             "--loop-unroll-partial must have a positive integer argument");
485       return false;
486     }
487   } else if (pass_name == "loop-peeling") {
488     RegisterPass(CreateLoopPeelingPass());
489   } else if (pass_name == "loop-peeling-threshold") {
490     int factor = (pass_args.size() > 0) ? atoi(pass_args.c_str()) : 0;
491     if (factor > 0) {
492       opt::LoopPeelingPass::SetLoopPeelingThreshold(factor);
493     } else {
494       Error(consumer(), nullptr, {},
495             "--loop-peeling-threshold must have a positive integer argument");
496       return false;
497     }
498   } else if (pass_name == "ccp") {
499     RegisterPass(CreateCCPPass());
500   } else if (pass_name == "code-sink") {
501     RegisterPass(CreateCodeSinkingPass());
502   } else if (pass_name == "fix-storage-class") {
503     RegisterPass(CreateFixStorageClassPass());
504   } else if (pass_name == "O") {
505     RegisterPerformancePasses();
506   } else if (pass_name == "Os") {
507     RegisterSizePasses();
508   } else if (pass_name == "legalize-hlsl") {
509     RegisterLegalizationPasses();
510   } else if (pass_name == "remove-unused-interface-variables") {
511     RegisterPass(CreateRemoveUnusedInterfaceVariablesPass());
512   } else if (pass_name == "graphics-robust-access") {
513     RegisterPass(CreateGraphicsRobustAccessPass());
514   } else if (pass_name == "wrap-opkill") {
515     RegisterPass(CreateWrapOpKillPass());
516   } else if (pass_name == "amd-ext-to-khr") {
517     RegisterPass(CreateAmdExtToKhrPass());
518   } else if (pass_name == "interpolate-fixup") {
519     RegisterPass(CreateInterpolateFixupPass());
520   } else if (pass_name == "convert-to-sampled-image") {
521     if (pass_args.size() > 0) {
522       auto descriptor_set_binding_pairs =
523           opt::ConvertToSampledImagePass::ParseDescriptorSetBindingPairsString(
524               pass_args.c_str());
525       if (!descriptor_set_binding_pairs) {
526         Errorf(consumer(), nullptr, {},
527                "Invalid argument for --convert-to-sampled-image: %s",
528                pass_args.c_str());
529         return false;
530       }
531       RegisterPass(CreateConvertToSampledImagePass(
532           std::move(*descriptor_set_binding_pairs)));
533     } else {
534       Errorf(consumer(), nullptr, {},
535              "Invalid pairs of descriptor set and binding '%s'. Expected a "
536              "string of <descriptor set>:<binding> pairs.",
537              pass_args.c_str());
538       return false;
539     }
540   } else {
541     Errorf(consumer(), nullptr, {},
542            "Unknown flag '--%s'. Use --help for a list of valid flags",
543            pass_name.c_str());
544     return false;
545   }
546 
547   return true;
548 }
549 
SetTargetEnv(const spv_target_env env)550 void Optimizer::SetTargetEnv(const spv_target_env env) {
551   impl_->target_env = env;
552 }
553 
Run(const uint32_t * original_binary,const size_t original_binary_size,std::vector<uint32_t> * optimized_binary) const554 bool Optimizer::Run(const uint32_t* original_binary,
555                     const size_t original_binary_size,
556                     std::vector<uint32_t>* optimized_binary) const {
557   return Run(original_binary, original_binary_size, optimized_binary,
558              OptimizerOptions());
559 }
560 
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) const561 bool Optimizer::Run(const uint32_t* original_binary,
562                     const size_t original_binary_size,
563                     std::vector<uint32_t>* optimized_binary,
564                     const ValidatorOptions& validator_options,
565                     bool skip_validation) const {
566   OptimizerOptions opt_options;
567   opt_options.set_run_validator(!skip_validation);
568   opt_options.set_validator_options(validator_options);
569   return Run(original_binary, original_binary_size, optimized_binary,
570              opt_options);
571 }
572 
Run(const uint32_t * original_binary,const size_t original_binary_size,std::vector<uint32_t> * optimized_binary,const spv_optimizer_options opt_options) const573 bool Optimizer::Run(const uint32_t* original_binary,
574                     const size_t original_binary_size,
575                     std::vector<uint32_t>* optimized_binary,
576                     const spv_optimizer_options opt_options) const {
577   spvtools::SpirvTools tools(impl_->target_env);
578   tools.SetMessageConsumer(impl_->pass_manager.consumer());
579   if (opt_options->run_validator_ &&
580       !tools.Validate(original_binary, original_binary_size,
581                       &opt_options->val_options_)) {
582     return false;
583   }
584 
585   std::unique_ptr<opt::IRContext> context = BuildModule(
586       impl_->target_env, consumer(), original_binary, original_binary_size);
587   if (context == nullptr) return false;
588 
589   context->set_max_id_bound(opt_options->max_id_bound_);
590   context->set_preserve_bindings(opt_options->preserve_bindings_);
591   context->set_preserve_spec_constants(opt_options->preserve_spec_constants_);
592 
593   impl_->pass_manager.SetValidatorOptions(&opt_options->val_options_);
594   impl_->pass_manager.SetTargetEnv(impl_->target_env);
595   auto status = impl_->pass_manager.Run(context.get());
596 
597   if (status == opt::Pass::Status::Failure) {
598     return false;
599   }
600 
601 #ifndef NDEBUG
602   // We do not keep the result id of DebugScope in struct DebugScope.
603   // Instead, we assign random ids for them, which results in integrity
604   // check failures. In addition, propagating the OpLine/OpNoLine to preserve
605   // the debug information through transformations results in integrity
606   // check failures. We want to skip the integrity check when the module
607   // contains DebugScope or OpLine/OpNoLine instructions.
608   if (status == opt::Pass::Status::SuccessWithoutChange &&
609       !context->module()->ContainsDebugInfo()) {
610     std::vector<uint32_t> optimized_binary_with_nop;
611     context->module()->ToBinary(&optimized_binary_with_nop,
612                                 /* skip_nop = */ false);
613     assert(optimized_binary_with_nop.size() == original_binary_size &&
614            "Binary size unexpectedly changed despite the optimizer saying "
615            "there was no change");
616     assert(memcmp(optimized_binary_with_nop.data(), original_binary,
617                   original_binary_size) == 0 &&
618            "Binary content unexpectedly changed despite the optimizer saying "
619            "there was no change");
620   }
621 #endif  // !NDEBUG
622 
623   // Note that |original_binary| and |optimized_binary| may share the same
624   // buffer and the below will invalidate |original_binary|.
625   optimized_binary->clear();
626   context->module()->ToBinary(optimized_binary, /* skip_nop = */ true);
627 
628   return true;
629 }
630 
SetPrintAll(std::ostream * out)631 Optimizer& Optimizer::SetPrintAll(std::ostream* out) {
632   impl_->pass_manager.SetPrintAll(out);
633   return *this;
634 }
635 
SetTimeReport(std::ostream * out)636 Optimizer& Optimizer::SetTimeReport(std::ostream* out) {
637   impl_->pass_manager.SetTimeReport(out);
638   return *this;
639 }
640 
SetValidateAfterAll(bool validate)641 Optimizer& Optimizer::SetValidateAfterAll(bool validate) {
642   impl_->pass_manager.SetValidateAfterAll(validate);
643   return *this;
644 }
645 
CreateNullPass()646 Optimizer::PassToken CreateNullPass() {
647   return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::NullPass>());
648 }
649 
CreateStripDebugInfoPass()650 Optimizer::PassToken CreateStripDebugInfoPass() {
651   return MakeUnique<Optimizer::PassToken::Impl>(
652       MakeUnique<opt::StripDebugInfoPass>());
653 }
654 
CreateStripReflectInfoPass()655 Optimizer::PassToken CreateStripReflectInfoPass() {
656   return MakeUnique<Optimizer::PassToken::Impl>(
657       MakeUnique<opt::StripReflectInfoPass>());
658 }
659 
CreateEliminateDeadFunctionsPass()660 Optimizer::PassToken CreateEliminateDeadFunctionsPass() {
661   return MakeUnique<Optimizer::PassToken::Impl>(
662       MakeUnique<opt::EliminateDeadFunctionsPass>());
663 }
664 
CreateEliminateDeadMembersPass()665 Optimizer::PassToken CreateEliminateDeadMembersPass() {
666   return MakeUnique<Optimizer::PassToken::Impl>(
667       MakeUnique<opt::EliminateDeadMembersPass>());
668 }
669 
CreateSetSpecConstantDefaultValuePass(const std::unordered_map<uint32_t,std::string> & id_value_map)670 Optimizer::PassToken CreateSetSpecConstantDefaultValuePass(
671     const std::unordered_map<uint32_t, std::string>& id_value_map) {
672   return MakeUnique<Optimizer::PassToken::Impl>(
673       MakeUnique<opt::SetSpecConstantDefaultValuePass>(id_value_map));
674 }
675 
CreateSetSpecConstantDefaultValuePass(const std::unordered_map<uint32_t,std::vector<uint32_t>> & id_value_map)676 Optimizer::PassToken CreateSetSpecConstantDefaultValuePass(
677     const std::unordered_map<uint32_t, std::vector<uint32_t>>& id_value_map) {
678   return MakeUnique<Optimizer::PassToken::Impl>(
679       MakeUnique<opt::SetSpecConstantDefaultValuePass>(id_value_map));
680 }
681 
CreateFlattenDecorationPass()682 Optimizer::PassToken CreateFlattenDecorationPass() {
683   return MakeUnique<Optimizer::PassToken::Impl>(
684       MakeUnique<opt::FlattenDecorationPass>());
685 }
686 
CreateFreezeSpecConstantValuePass()687 Optimizer::PassToken CreateFreezeSpecConstantValuePass() {
688   return MakeUnique<Optimizer::PassToken::Impl>(
689       MakeUnique<opt::FreezeSpecConstantValuePass>());
690 }
691 
CreateFoldSpecConstantOpAndCompositePass()692 Optimizer::PassToken CreateFoldSpecConstantOpAndCompositePass() {
693   return MakeUnique<Optimizer::PassToken::Impl>(
694       MakeUnique<opt::FoldSpecConstantOpAndCompositePass>());
695 }
696 
CreateUnifyConstantPass()697 Optimizer::PassToken CreateUnifyConstantPass() {
698   return MakeUnique<Optimizer::PassToken::Impl>(
699       MakeUnique<opt::UnifyConstantPass>());
700 }
701 
CreateEliminateDeadConstantPass()702 Optimizer::PassToken CreateEliminateDeadConstantPass() {
703   return MakeUnique<Optimizer::PassToken::Impl>(
704       MakeUnique<opt::EliminateDeadConstantPass>());
705 }
706 
CreateDeadVariableEliminationPass()707 Optimizer::PassToken CreateDeadVariableEliminationPass() {
708   return MakeUnique<Optimizer::PassToken::Impl>(
709       MakeUnique<opt::DeadVariableElimination>());
710 }
711 
CreateStrengthReductionPass()712 Optimizer::PassToken CreateStrengthReductionPass() {
713   return MakeUnique<Optimizer::PassToken::Impl>(
714       MakeUnique<opt::StrengthReductionPass>());
715 }
716 
CreateBlockMergePass()717 Optimizer::PassToken CreateBlockMergePass() {
718   return MakeUnique<Optimizer::PassToken::Impl>(
719       MakeUnique<opt::BlockMergePass>());
720 }
721 
CreateInlineExhaustivePass()722 Optimizer::PassToken CreateInlineExhaustivePass() {
723   return MakeUnique<Optimizer::PassToken::Impl>(
724       MakeUnique<opt::InlineExhaustivePass>());
725 }
726 
CreateInlineOpaquePass()727 Optimizer::PassToken CreateInlineOpaquePass() {
728   return MakeUnique<Optimizer::PassToken::Impl>(
729       MakeUnique<opt::InlineOpaquePass>());
730 }
731 
CreateLocalAccessChainConvertPass()732 Optimizer::PassToken CreateLocalAccessChainConvertPass() {
733   return MakeUnique<Optimizer::PassToken::Impl>(
734       MakeUnique<opt::LocalAccessChainConvertPass>());
735 }
736 
CreateLocalSingleBlockLoadStoreElimPass()737 Optimizer::PassToken CreateLocalSingleBlockLoadStoreElimPass() {
738   return MakeUnique<Optimizer::PassToken::Impl>(
739       MakeUnique<opt::LocalSingleBlockLoadStoreElimPass>());
740 }
741 
CreateLocalSingleStoreElimPass()742 Optimizer::PassToken CreateLocalSingleStoreElimPass() {
743   return MakeUnique<Optimizer::PassToken::Impl>(
744       MakeUnique<opt::LocalSingleStoreElimPass>());
745 }
746 
CreateInsertExtractElimPass()747 Optimizer::PassToken CreateInsertExtractElimPass() {
748   return MakeUnique<Optimizer::PassToken::Impl>(
749       MakeUnique<opt::SimplificationPass>());
750 }
751 
CreateDeadInsertElimPass()752 Optimizer::PassToken CreateDeadInsertElimPass() {
753   return MakeUnique<Optimizer::PassToken::Impl>(
754       MakeUnique<opt::DeadInsertElimPass>());
755 }
756 
CreateDeadBranchElimPass()757 Optimizer::PassToken CreateDeadBranchElimPass() {
758   return MakeUnique<Optimizer::PassToken::Impl>(
759       MakeUnique<opt::DeadBranchElimPass>());
760 }
761 
CreateLocalMultiStoreElimPass()762 Optimizer::PassToken CreateLocalMultiStoreElimPass() {
763   return MakeUnique<Optimizer::PassToken::Impl>(
764       MakeUnique<opt::SSARewritePass>());
765 }
766 
CreateAggressiveDCEPass(bool preserve_interface)767 Optimizer::PassToken CreateAggressiveDCEPass(bool preserve_interface) {
768   return MakeUnique<Optimizer::PassToken::Impl>(
769       MakeUnique<opt::AggressiveDCEPass>(preserve_interface));
770 }
771 
CreateRemoveUnusedInterfaceVariablesPass()772 Optimizer::PassToken CreateRemoveUnusedInterfaceVariablesPass() {
773   return MakeUnique<Optimizer::PassToken::Impl>(
774       MakeUnique<opt::RemoveUnusedInterfaceVariablesPass>());
775 }
776 
CreatePropagateLineInfoPass()777 Optimizer::PassToken CreatePropagateLineInfoPass() {
778   return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::EmptyPass>());
779 }
780 
CreateRedundantLineInfoElimPass()781 Optimizer::PassToken CreateRedundantLineInfoElimPass() {
782   return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::EmptyPass>());
783 }
784 
CreateCompactIdsPass()785 Optimizer::PassToken CreateCompactIdsPass() {
786   return MakeUnique<Optimizer::PassToken::Impl>(
787       MakeUnique<opt::CompactIdsPass>());
788 }
789 
CreateMergeReturnPass()790 Optimizer::PassToken CreateMergeReturnPass() {
791   return MakeUnique<Optimizer::PassToken::Impl>(
792       MakeUnique<opt::MergeReturnPass>());
793 }
794 
GetPassNames() const795 std::vector<const char*> Optimizer::GetPassNames() const {
796   std::vector<const char*> v;
797   for (uint32_t i = 0; i < impl_->pass_manager.NumPasses(); i++) {
798     v.push_back(impl_->pass_manager.GetPass(i)->name());
799   }
800   return v;
801 }
802 
CreateCFGCleanupPass()803 Optimizer::PassToken CreateCFGCleanupPass() {
804   return MakeUnique<Optimizer::PassToken::Impl>(
805       MakeUnique<opt::CFGCleanupPass>());
806 }
807 
CreateLocalRedundancyEliminationPass()808 Optimizer::PassToken CreateLocalRedundancyEliminationPass() {
809   return MakeUnique<Optimizer::PassToken::Impl>(
810       MakeUnique<opt::LocalRedundancyEliminationPass>());
811 }
812 
CreateLoopFissionPass(size_t threshold)813 Optimizer::PassToken CreateLoopFissionPass(size_t threshold) {
814   return MakeUnique<Optimizer::PassToken::Impl>(
815       MakeUnique<opt::LoopFissionPass>(threshold));
816 }
817 
CreateLoopFusionPass(size_t max_registers_per_loop)818 Optimizer::PassToken CreateLoopFusionPass(size_t max_registers_per_loop) {
819   return MakeUnique<Optimizer::PassToken::Impl>(
820       MakeUnique<opt::LoopFusionPass>(max_registers_per_loop));
821 }
822 
CreateLoopInvariantCodeMotionPass()823 Optimizer::PassToken CreateLoopInvariantCodeMotionPass() {
824   return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::LICMPass>());
825 }
826 
CreateLoopPeelingPass()827 Optimizer::PassToken CreateLoopPeelingPass() {
828   return MakeUnique<Optimizer::PassToken::Impl>(
829       MakeUnique<opt::LoopPeelingPass>());
830 }
831 
CreateLoopUnswitchPass()832 Optimizer::PassToken CreateLoopUnswitchPass() {
833   return MakeUnique<Optimizer::PassToken::Impl>(
834       MakeUnique<opt::LoopUnswitchPass>());
835 }
836 
CreateRedundancyEliminationPass()837 Optimizer::PassToken CreateRedundancyEliminationPass() {
838   return MakeUnique<Optimizer::PassToken::Impl>(
839       MakeUnique<opt::RedundancyEliminationPass>());
840 }
841 
CreateRemoveDuplicatesPass()842 Optimizer::PassToken CreateRemoveDuplicatesPass() {
843   return MakeUnique<Optimizer::PassToken::Impl>(
844       MakeUnique<opt::RemoveDuplicatesPass>());
845 }
846 
CreateScalarReplacementPass(uint32_t size_limit)847 Optimizer::PassToken CreateScalarReplacementPass(uint32_t size_limit) {
848   return MakeUnique<Optimizer::PassToken::Impl>(
849       MakeUnique<opt::ScalarReplacementPass>(size_limit));
850 }
851 
CreatePrivateToLocalPass()852 Optimizer::PassToken CreatePrivateToLocalPass() {
853   return MakeUnique<Optimizer::PassToken::Impl>(
854       MakeUnique<opt::PrivateToLocalPass>());
855 }
856 
CreateCCPPass()857 Optimizer::PassToken CreateCCPPass() {
858   return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::CCPPass>());
859 }
860 
CreateWorkaround1209Pass()861 Optimizer::PassToken CreateWorkaround1209Pass() {
862   return MakeUnique<Optimizer::PassToken::Impl>(
863       MakeUnique<opt::Workaround1209>());
864 }
865 
CreateIfConversionPass()866 Optimizer::PassToken CreateIfConversionPass() {
867   return MakeUnique<Optimizer::PassToken::Impl>(
868       MakeUnique<opt::IfConversion>());
869 }
870 
CreateReplaceInvalidOpcodePass()871 Optimizer::PassToken CreateReplaceInvalidOpcodePass() {
872   return MakeUnique<Optimizer::PassToken::Impl>(
873       MakeUnique<opt::ReplaceInvalidOpcodePass>());
874 }
875 
CreateSimplificationPass()876 Optimizer::PassToken CreateSimplificationPass() {
877   return MakeUnique<Optimizer::PassToken::Impl>(
878       MakeUnique<opt::SimplificationPass>());
879 }
880 
CreateLoopUnrollPass(bool fully_unroll,int factor)881 Optimizer::PassToken CreateLoopUnrollPass(bool fully_unroll, int factor) {
882   return MakeUnique<Optimizer::PassToken::Impl>(
883       MakeUnique<opt::LoopUnroller>(fully_unroll, factor));
884 }
885 
CreateSSARewritePass()886 Optimizer::PassToken CreateSSARewritePass() {
887   return MakeUnique<Optimizer::PassToken::Impl>(
888       MakeUnique<opt::SSARewritePass>());
889 }
890 
CreateCopyPropagateArraysPass()891 Optimizer::PassToken CreateCopyPropagateArraysPass() {
892   return MakeUnique<Optimizer::PassToken::Impl>(
893       MakeUnique<opt::CopyPropagateArrays>());
894 }
895 
CreateVectorDCEPass()896 Optimizer::PassToken CreateVectorDCEPass() {
897   return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::VectorDCE>());
898 }
899 
CreateReduceLoadSizePass(double load_replacement_threshold)900 Optimizer::PassToken CreateReduceLoadSizePass(
901     double load_replacement_threshold) {
902   return MakeUnique<Optimizer::PassToken::Impl>(
903       MakeUnique<opt::ReduceLoadSize>(load_replacement_threshold));
904 }
905 
CreateCombineAccessChainsPass()906 Optimizer::PassToken CreateCombineAccessChainsPass() {
907   return MakeUnique<Optimizer::PassToken::Impl>(
908       MakeUnique<opt::CombineAccessChains>());
909 }
910 
CreateUpgradeMemoryModelPass()911 Optimizer::PassToken CreateUpgradeMemoryModelPass() {
912   return MakeUnique<Optimizer::PassToken::Impl>(
913       MakeUnique<opt::UpgradeMemoryModel>());
914 }
915 
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)916 Optimizer::PassToken CreateInstBindlessCheckPass(
917     uint32_t desc_set, uint32_t shader_id, bool desc_length_enable,
918     bool desc_init_enable, bool buff_oob_enable, bool texbuff_oob_enable) {
919   return MakeUnique<Optimizer::PassToken::Impl>(
920       MakeUnique<opt::InstBindlessCheckPass>(
921           desc_set, shader_id, desc_length_enable, desc_init_enable,
922           buff_oob_enable, texbuff_oob_enable,
923           desc_length_enable || desc_init_enable || buff_oob_enable));
924 }
925 
CreateInstDebugPrintfPass(uint32_t desc_set,uint32_t shader_id)926 Optimizer::PassToken CreateInstDebugPrintfPass(uint32_t desc_set,
927                                                uint32_t shader_id) {
928   return MakeUnique<Optimizer::PassToken::Impl>(
929       MakeUnique<opt::InstDebugPrintfPass>(desc_set, shader_id));
930 }
931 
CreateInstBuffAddrCheckPass(uint32_t desc_set,uint32_t shader_id)932 Optimizer::PassToken CreateInstBuffAddrCheckPass(uint32_t desc_set,
933                                                  uint32_t shader_id) {
934   return MakeUnique<Optimizer::PassToken::Impl>(
935       MakeUnique<opt::InstBuffAddrCheckPass>(desc_set, shader_id));
936 }
937 
CreateConvertRelaxedToHalfPass()938 Optimizer::PassToken CreateConvertRelaxedToHalfPass() {
939   return MakeUnique<Optimizer::PassToken::Impl>(
940       MakeUnique<opt::ConvertToHalfPass>());
941 }
942 
CreateRelaxFloatOpsPass()943 Optimizer::PassToken CreateRelaxFloatOpsPass() {
944   return MakeUnique<Optimizer::PassToken::Impl>(
945       MakeUnique<opt::RelaxFloatOpsPass>());
946 }
947 
CreateCodeSinkingPass()948 Optimizer::PassToken CreateCodeSinkingPass() {
949   return MakeUnique<Optimizer::PassToken::Impl>(
950       MakeUnique<opt::CodeSinkingPass>());
951 }
952 
CreateFixStorageClassPass()953 Optimizer::PassToken CreateFixStorageClassPass() {
954   return MakeUnique<Optimizer::PassToken::Impl>(
955       MakeUnique<opt::FixStorageClass>());
956 }
957 
CreateGraphicsRobustAccessPass()958 Optimizer::PassToken CreateGraphicsRobustAccessPass() {
959   return MakeUnique<Optimizer::PassToken::Impl>(
960       MakeUnique<opt::GraphicsRobustAccessPass>());
961 }
962 
CreateReplaceDescArrayAccessUsingVarIndexPass()963 Optimizer::PassToken CreateReplaceDescArrayAccessUsingVarIndexPass() {
964   return MakeUnique<Optimizer::PassToken::Impl>(
965       MakeUnique<opt::ReplaceDescArrayAccessUsingVarIndex>());
966 }
967 
CreateDescriptorScalarReplacementPass()968 Optimizer::PassToken CreateDescriptorScalarReplacementPass() {
969   return MakeUnique<Optimizer::PassToken::Impl>(
970       MakeUnique<opt::DescriptorScalarReplacement>());
971 }
972 
CreateWrapOpKillPass()973 Optimizer::PassToken CreateWrapOpKillPass() {
974   return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::WrapOpKill>());
975 }
976 
CreateAmdExtToKhrPass()977 Optimizer::PassToken CreateAmdExtToKhrPass() {
978   return MakeUnique<Optimizer::PassToken::Impl>(
979       MakeUnique<opt::AmdExtensionToKhrPass>());
980 }
981 
CreateInterpolateFixupPass()982 Optimizer::PassToken CreateInterpolateFixupPass() {
983   return MakeUnique<Optimizer::PassToken::Impl>(
984       MakeUnique<opt::InterpFixupPass>());
985 }
986 
CreateConvertToSampledImagePass(const std::vector<opt::DescriptorSetAndBinding> & descriptor_set_binding_pairs)987 Optimizer::PassToken CreateConvertToSampledImagePass(
988     const std::vector<opt::DescriptorSetAndBinding>&
989         descriptor_set_binding_pairs) {
990   return MakeUnique<Optimizer::PassToken::Impl>(
991       MakeUnique<opt::ConvertToSampledImagePass>(descriptor_set_binding_pairs));
992 }
993 
994 }  // namespace spvtools
995