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