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