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