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