Home | History | Annotate | Download | only in opt
      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 {
     35   Impl(std::unique_ptr<opt::Pass> p) : pass(std::move(p)) {}
     36 
     37   std::unique_ptr<opt::Pass> pass;  // Internal implementation pass.
     38 };
     39 
     40 Optimizer::PassToken::PassToken(
     41     std::unique_ptr<Optimizer::PassToken::Impl> impl)
     42     : impl_(std::move(impl)) {}
     43 
     44 Optimizer::PassToken::PassToken(std::unique_ptr<opt::Pass>&& pass)
     45     : impl_(MakeUnique<Optimizer::PassToken::Impl>(std::move(pass))) {}
     46 
     47 Optimizer::PassToken::PassToken(PassToken&& that)
     48     : impl_(std::move(that.impl_)) {}
     49 
     50 Optimizer::PassToken& Optimizer::PassToken::operator=(PassToken&& that) {
     51   impl_ = std::move(that.impl_);
     52   return *this;
     53 }
     54 
     55 Optimizer::PassToken::~PassToken() {}
     56 
     57 struct Optimizer::Impl {
     58   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 
     64 Optimizer::Optimizer(spv_target_env env) : impl_(new Impl(env)) {}
     65 
     66 Optimizer::~Optimizer() {}
     67 
     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 
     76 const MessageConsumer& Optimizer::consumer() const {
     77   return impl_->pass_manager.consumer();
     78 }
     79 
     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.
    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 
    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 
    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 
    221 Optimizer& Optimizer::RegisterWebGPUPasses() {
    222   return RegisterPass(CreateAggressiveDCEPass())
    223       .RegisterPass(CreateDeadBranchElimPass());
    224 }
    225 
    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 
    236 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 
    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 
    462 void Optimizer::SetTargetEnv(const spv_target_env env) {
    463   impl_->target_env = env;
    464 }
    465 
    466 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 
    473 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 
    485 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 
    515 Optimizer& Optimizer::SetPrintAll(std::ostream* out) {
    516   impl_->pass_manager.SetPrintAll(out);
    517   return *this;
    518 }
    519 
    520 Optimizer& Optimizer::SetTimeReport(std::ostream* out) {
    521   impl_->pass_manager.SetTimeReport(out);
    522   return *this;
    523 }
    524 
    525 Optimizer::PassToken CreateNullPass() {
    526   return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::NullPass>());
    527 }
    528 
    529 Optimizer::PassToken CreateStripDebugInfoPass() {
    530   return MakeUnique<Optimizer::PassToken::Impl>(
    531       MakeUnique<opt::StripDebugInfoPass>());
    532 }
    533 
    534 Optimizer::PassToken CreateStripReflectInfoPass() {
    535   return MakeUnique<Optimizer::PassToken::Impl>(
    536       MakeUnique<opt::StripReflectInfoPass>());
    537 }
    538 
    539 Optimizer::PassToken CreateEliminateDeadFunctionsPass() {
    540   return MakeUnique<Optimizer::PassToken::Impl>(
    541       MakeUnique<opt::EliminateDeadFunctionsPass>());
    542 }
    543 
    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 
    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 
    556 Optimizer::PassToken CreateFlattenDecorationPass() {
    557   return MakeUnique<Optimizer::PassToken::Impl>(
    558       MakeUnique<opt::FlattenDecorationPass>());
    559 }
    560 
    561 Optimizer::PassToken CreateFreezeSpecConstantValuePass() {
    562   return MakeUnique<Optimizer::PassToken::Impl>(
    563       MakeUnique<opt::FreezeSpecConstantValuePass>());
    564 }
    565 
    566 Optimizer::PassToken CreateFoldSpecConstantOpAndCompositePass() {
    567   return MakeUnique<Optimizer::PassToken::Impl>(
    568       MakeUnique<opt::FoldSpecConstantOpAndCompositePass>());
    569 }
    570 
    571 Optimizer::PassToken CreateUnifyConstantPass() {
    572   return MakeUnique<Optimizer::PassToken::Impl>(
    573       MakeUnique<opt::UnifyConstantPass>());
    574 }
    575 
    576 Optimizer::PassToken CreateEliminateDeadConstantPass() {
    577   return MakeUnique<Optimizer::PassToken::Impl>(
    578       MakeUnique<opt::EliminateDeadConstantPass>());
    579 }
    580 
    581 Optimizer::PassToken CreateDeadVariableEliminationPass() {
    582   return MakeUnique<Optimizer::PassToken::Impl>(
    583       MakeUnique<opt::DeadVariableElimination>());
    584 }
    585 
    586 Optimizer::PassToken CreateStrengthReductionPass() {
    587   return MakeUnique<Optimizer::PassToken::Impl>(
    588       MakeUnique<opt::StrengthReductionPass>());
    589 }
    590 
    591 Optimizer::PassToken CreateBlockMergePass() {
    592   return MakeUnique<Optimizer::PassToken::Impl>(
    593       MakeUnique<opt::BlockMergePass>());
    594 }
    595 
    596 Optimizer::PassToken CreateInlineExhaustivePass() {
    597   return MakeUnique<Optimizer::PassToken::Impl>(
    598       MakeUnique<opt::InlineExhaustivePass>());
    599 }
    600 
    601 Optimizer::PassToken CreateInlineOpaquePass() {
    602   return MakeUnique<Optimizer::PassToken::Impl>(
    603       MakeUnique<opt::InlineOpaquePass>());
    604 }
    605 
    606 Optimizer::PassToken CreateLocalAccessChainConvertPass() {
    607   return MakeUnique<Optimizer::PassToken::Impl>(
    608       MakeUnique<opt::LocalAccessChainConvertPass>());
    609 }
    610 
    611 Optimizer::PassToken CreateLocalSingleBlockLoadStoreElimPass() {
    612   return MakeUnique<Optimizer::PassToken::Impl>(
    613       MakeUnique<opt::LocalSingleBlockLoadStoreElimPass>());
    614 }
    615 
    616 Optimizer::PassToken CreateLocalSingleStoreElimPass() {
    617   return MakeUnique<Optimizer::PassToken::Impl>(
    618       MakeUnique<opt::LocalSingleStoreElimPass>());
    619 }
    620 
    621 Optimizer::PassToken CreateInsertExtractElimPass() {
    622   return MakeUnique<Optimizer::PassToken::Impl>(
    623       MakeUnique<opt::SimplificationPass>());
    624 }
    625 
    626 Optimizer::PassToken CreateDeadInsertElimPass() {
    627   return MakeUnique<Optimizer::PassToken::Impl>(
    628       MakeUnique<opt::DeadInsertElimPass>());
    629 }
    630 
    631 Optimizer::PassToken CreateDeadBranchElimPass() {
    632   return MakeUnique<Optimizer::PassToken::Impl>(
    633       MakeUnique<opt::DeadBranchElimPass>());
    634 }
    635 
    636 Optimizer::PassToken CreateLocalMultiStoreElimPass() {
    637   return MakeUnique<Optimizer::PassToken::Impl>(
    638       MakeUnique<opt::LocalMultiStoreElimPass>());
    639 }
    640 
    641 Optimizer::PassToken CreateAggressiveDCEPass() {
    642   return MakeUnique<Optimizer::PassToken::Impl>(
    643       MakeUnique<opt::AggressiveDCEPass>());
    644 }
    645 
    646 Optimizer::PassToken CreatePropagateLineInfoPass() {
    647   return MakeUnique<Optimizer::PassToken::Impl>(
    648       MakeUnique<opt::ProcessLinesPass>(opt::kLinesPropagateLines));
    649 }
    650 
    651 Optimizer::PassToken CreateRedundantLineInfoElimPass() {
    652   return MakeUnique<Optimizer::PassToken::Impl>(
    653       MakeUnique<opt::ProcessLinesPass>(opt::kLinesEliminateDeadLines));
    654 }
    655 
    656 Optimizer::PassToken CreateCommonUniformElimPass() {
    657   return MakeUnique<Optimizer::PassToken::Impl>(
    658       MakeUnique<opt::CommonUniformElimPass>());
    659 }
    660 
    661 Optimizer::PassToken CreateCompactIdsPass() {
    662   return MakeUnique<Optimizer::PassToken::Impl>(
    663       MakeUnique<opt::CompactIdsPass>());
    664 }
    665 
    666 Optimizer::PassToken CreateMergeReturnPass() {
    667   return MakeUnique<Optimizer::PassToken::Impl>(
    668       MakeUnique<opt::MergeReturnPass>());
    669 }
    670 
    671 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 
    679 Optimizer::PassToken CreateCFGCleanupPass() {
    680   return MakeUnique<Optimizer::PassToken::Impl>(
    681       MakeUnique<opt::CFGCleanupPass>());
    682 }
    683 
    684 Optimizer::PassToken CreateLocalRedundancyEliminationPass() {
    685   return MakeUnique<Optimizer::PassToken::Impl>(
    686       MakeUnique<opt::LocalRedundancyEliminationPass>());
    687 }
    688 
    689 Optimizer::PassToken CreateLoopFissionPass(size_t threshold) {
    690   return MakeUnique<Optimizer::PassToken::Impl>(
    691       MakeUnique<opt::LoopFissionPass>(threshold));
    692 }
    693 
    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 
    699 Optimizer::PassToken CreateLoopInvariantCodeMotionPass() {
    700   return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::LICMPass>());
    701 }
    702 
    703 Optimizer::PassToken CreateLoopPeelingPass() {
    704   return MakeUnique<Optimizer::PassToken::Impl>(
    705       MakeUnique<opt::LoopPeelingPass>());
    706 }
    707 
    708 Optimizer::PassToken CreateLoopUnswitchPass() {
    709   return MakeUnique<Optimizer::PassToken::Impl>(
    710       MakeUnique<opt::LoopUnswitchPass>());
    711 }
    712 
    713 Optimizer::PassToken CreateRedundancyEliminationPass() {
    714   return MakeUnique<Optimizer::PassToken::Impl>(
    715       MakeUnique<opt::RedundancyEliminationPass>());
    716 }
    717 
    718 Optimizer::PassToken CreateRemoveDuplicatesPass() {
    719   return MakeUnique<Optimizer::PassToken::Impl>(
    720       MakeUnique<opt::RemoveDuplicatesPass>());
    721 }
    722 
    723 Optimizer::PassToken CreateScalarReplacementPass(uint32_t size_limit) {
    724   return MakeUnique<Optimizer::PassToken::Impl>(
    725       MakeUnique<opt::ScalarReplacementPass>(size_limit));
    726 }
    727 
    728 Optimizer::PassToken CreatePrivateToLocalPass() {
    729   return MakeUnique<Optimizer::PassToken::Impl>(
    730       MakeUnique<opt::PrivateToLocalPass>());
    731 }
    732 
    733 Optimizer::PassToken CreateCCPPass() {
    734   return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::CCPPass>());
    735 }
    736 
    737 Optimizer::PassToken CreateWorkaround1209Pass() {
    738   return MakeUnique<Optimizer::PassToken::Impl>(
    739       MakeUnique<opt::Workaround1209>());
    740 }
    741 
    742 Optimizer::PassToken CreateIfConversionPass() {
    743   return MakeUnique<Optimizer::PassToken::Impl>(
    744       MakeUnique<opt::IfConversion>());
    745 }
    746 
    747 Optimizer::PassToken CreateReplaceInvalidOpcodePass() {
    748   return MakeUnique<Optimizer::PassToken::Impl>(
    749       MakeUnique<opt::ReplaceInvalidOpcodePass>());
    750 }
    751 
    752 Optimizer::PassToken CreateSimplificationPass() {
    753   return MakeUnique<Optimizer::PassToken::Impl>(
    754       MakeUnique<opt::SimplificationPass>());
    755 }
    756 
    757 Optimizer::PassToken CreateLoopUnrollPass(bool fully_unroll, int factor) {
    758   return MakeUnique<Optimizer::PassToken::Impl>(
    759       MakeUnique<opt::LoopUnroller>(fully_unroll, factor));
    760 }
    761 
    762 Optimizer::PassToken CreateSSARewritePass() {
    763   return MakeUnique<Optimizer::PassToken::Impl>(
    764       MakeUnique<opt::SSARewritePass>());
    765 }
    766 
    767 Optimizer::PassToken CreateCopyPropagateArraysPass() {
    768   return MakeUnique<Optimizer::PassToken::Impl>(
    769       MakeUnique<opt::CopyPropagateArrays>());
    770 }
    771 
    772 Optimizer::PassToken CreateVectorDCEPass() {
    773   return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::VectorDCE>());
    774 }
    775 
    776 Optimizer::PassToken CreateReduceLoadSizePass() {
    777   return MakeUnique<Optimizer::PassToken::Impl>(
    778       MakeUnique<opt::ReduceLoadSize>());
    779 }
    780 
    781 Optimizer::PassToken CreateCombineAccessChainsPass() {
    782   return MakeUnique<Optimizer::PassToken::Impl>(
    783       MakeUnique<opt::CombineAccessChains>());
    784 }
    785 
    786 Optimizer::PassToken CreateUpgradeMemoryModelPass() {
    787   return MakeUnique<Optimizer::PassToken::Impl>(
    788       MakeUnique<opt::UpgradeMemoryModel>());
    789 }
    790 
    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 
    797 Optimizer::PassToken CreateCodeSinkingPass() {
    798   return MakeUnique<Optimizer::PassToken::Impl>(
    799       MakeUnique<opt::CodeSinkingPass>());
    800 }
    801 
    802 }  // namespace spvtools
    803