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 <cassert>
18 #include <memory>
19 #include <string>
20 #include <unordered_map>
21 #include <utility>
22 #include <vector>
23
24 #include "source/opt/build_module.h"
25 #include "source/opt/graphics_robust_access_pass.h"
26 #include "source/opt/log.h"
27 #include "source/opt/pass_manager.h"
28 #include "source/opt/passes.h"
29 #include "source/spirv_optimizer_options.h"
30 #include "source/util/make_unique.h"
31 #include "source/util/string_utils.h"
32
33 namespace spvtools {
34
35 struct Optimizer::PassToken::Impl {
Implspvtools::Optimizer::PassToken::Impl36 Impl(std::unique_ptr<opt::Pass> p) : pass(std::move(p)) {}
37
38 std::unique_ptr<opt::Pass> pass; // Internal implementation pass.
39 };
40
PassToken(std::unique_ptr<Optimizer::PassToken::Impl> impl)41 Optimizer::PassToken::PassToken(
42 std::unique_ptr<Optimizer::PassToken::Impl> impl)
43 : impl_(std::move(impl)) {}
44
PassToken(std::unique_ptr<opt::Pass> && pass)45 Optimizer::PassToken::PassToken(std::unique_ptr<opt::Pass>&& pass)
46 : impl_(MakeUnique<Optimizer::PassToken::Impl>(std::move(pass))) {}
47
PassToken(PassToken && that)48 Optimizer::PassToken::PassToken(PassToken&& that)
49 : impl_(std::move(that.impl_)) {}
50
operator =(PassToken && that)51 Optimizer::PassToken& Optimizer::PassToken::operator=(PassToken&& that) {
52 impl_ = std::move(that.impl_);
53 return *this;
54 }
55
~PassToken()56 Optimizer::PassToken::~PassToken() {}
57
58 struct Optimizer::Impl {
Implspvtools::Optimizer::Impl59 explicit Impl(spv_target_env env) : target_env(env), pass_manager() {}
60
61 spv_target_env target_env; // Target environment.
62 opt::PassManager pass_manager; // Internal implementation pass manager.
63 };
64
Optimizer(spv_target_env env)65 Optimizer::Optimizer(spv_target_env env) : impl_(new Impl(env)) {
66 assert(env != SPV_ENV_WEBGPU_0);
67 }
68
~Optimizer()69 Optimizer::~Optimizer() {}
70
SetMessageConsumer(MessageConsumer c)71 void Optimizer::SetMessageConsumer(MessageConsumer c) {
72 // All passes' message consumer needs to be updated.
73 for (uint32_t i = 0; i < impl_->pass_manager.NumPasses(); ++i) {
74 impl_->pass_manager.GetPass(i)->SetMessageConsumer(c);
75 }
76 impl_->pass_manager.SetMessageConsumer(std::move(c));
77 }
78
consumer() const79 const MessageConsumer& Optimizer::consumer() const {
80 return impl_->pass_manager.consumer();
81 }
82
RegisterPass(PassToken && p)83 Optimizer& Optimizer::RegisterPass(PassToken&& p) {
84 // Change to use the pass manager's consumer.
85 p.impl_->pass->SetMessageConsumer(consumer());
86 impl_->pass_manager.AddPass(std::move(p.impl_->pass));
87 return *this;
88 }
89
90 // The legalization passes take a spir-v shader generated by an HLSL front-end
91 // and turn it into a valid vulkan spir-v shader. There are two ways in which
92 // the code will be invalid at the start:
93 //
94 // 1) There will be opaque objects, like images, which will be passed around
95 // in intermediate objects. Valid spir-v will have to replace the use of
96 // the opaque object with an intermediate object that is the result of the
97 // load of the global opaque object.
98 //
99 // 2) There will be variables that contain pointers to structured or uniform
100 // buffers. It be legal, the variables must be eliminated, and the
101 // references to the structured buffers must use the result of OpVariable
102 // in the Uniform storage class.
103 //
104 // Optimization in this list must accept shaders with these relaxation of the
105 // rules. There is not guarantee that this list of optimizations is able to
106 // legalize all inputs, but it is on a best effort basis.
107 //
108 // The legalization problem is essentially a very general copy propagation
109 // problem. The optimization we use are all used to either do copy propagation
110 // or enable more copy propagation.
RegisterLegalizationPasses()111 Optimizer& Optimizer::RegisterLegalizationPasses() {
112 return
113 // Wrap OpKill instructions so all other code can be inlined.
114 RegisterPass(CreateWrapOpKillPass())
115 // Remove unreachable block so that merge return works.
116 .RegisterPass(CreateDeadBranchElimPass())
117 // Merge the returns so we can inline.
118 .RegisterPass(CreateMergeReturnPass())
119 // Make sure uses and definitions are in the same function.
120 .RegisterPass(CreateInlineExhaustivePass())
121 // Make private variable function scope
122 .RegisterPass(CreateEliminateDeadFunctionsPass())
123 .RegisterPass(CreatePrivateToLocalPass())
124 // Fix up the storage classes that DXC may have purposely generated
125 // incorrectly. All functions are inlined, and a lot of dead code has
126 // been removed.
127 .RegisterPass(CreateFixStorageClassPass())
128 // Propagate the value stored to the loads in very simple cases.
129 .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass())
130 .RegisterPass(CreateLocalSingleStoreElimPass())
131 .RegisterPass(CreateAggressiveDCEPass())
132 // Split up aggregates so they are easier to deal with.
133 .RegisterPass(CreateScalarReplacementPass(0))
134 // Remove loads and stores so everything is in intermediate values.
135 // Takes care of copy propagation of non-members.
136 .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass())
137 .RegisterPass(CreateLocalSingleStoreElimPass())
138 .RegisterPass(CreateAggressiveDCEPass())
139 .RegisterPass(CreateLocalMultiStoreElimPass())
140 .RegisterPass(CreateAggressiveDCEPass())
141 // Propagate constants to get as many constant conditions on branches
142 // as possible.
143 .RegisterPass(CreateCCPPass())
144 .RegisterPass(CreateLoopUnrollPass(true))
145 .RegisterPass(CreateDeadBranchElimPass())
146 // Copy propagate members. Cleans up code sequences generated by
147 // scalar replacement. Also important for removing OpPhi nodes.
148 .RegisterPass(CreateSimplificationPass())
149 .RegisterPass(CreateAggressiveDCEPass())
150 .RegisterPass(CreateCopyPropagateArraysPass())
151 // May need loop unrolling here see
152 // https://github.com/Microsoft/DirectXShaderCompiler/pull/930
153 // Get rid of unused code that contain traces of illegal code
154 // or unused references to unbound external objects
155 .RegisterPass(CreateVectorDCEPass())
156 .RegisterPass(CreateDeadInsertElimPass())
157 .RegisterPass(CreateReduceLoadSizePass())
158 .RegisterPass(CreateAggressiveDCEPass())
159 .RegisterPass(CreateInterpolateFixupPass());
160 }
161
RegisterPerformancePasses()162 Optimizer& Optimizer::RegisterPerformancePasses() {
163 return RegisterPass(CreateWrapOpKillPass())
164 .RegisterPass(CreateDeadBranchElimPass())
165 .RegisterPass(CreateMergeReturnPass())
166 .RegisterPass(CreateInlineExhaustivePass())
167 .RegisterPass(CreateEliminateDeadFunctionsPass())
168 .RegisterPass(CreateAggressiveDCEPass())
169 .RegisterPass(CreatePrivateToLocalPass())
170 .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass())
171 .RegisterPass(CreateLocalSingleStoreElimPass())
172 .RegisterPass(CreateAggressiveDCEPass())
173 .RegisterPass(CreateScalarReplacementPass())
174 .RegisterPass(CreateLocalAccessChainConvertPass())
175 .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass())
176 .RegisterPass(CreateLocalSingleStoreElimPass())
177 .RegisterPass(CreateAggressiveDCEPass())
178 .RegisterPass(CreateLocalMultiStoreElimPass())
179 .RegisterPass(CreateAggressiveDCEPass())
180 .RegisterPass(CreateCCPPass())
181 .RegisterPass(CreateAggressiveDCEPass())
182 .RegisterPass(CreateLoopUnrollPass(true))
183 .RegisterPass(CreateDeadBranchElimPass())
184 .RegisterPass(CreateRedundancyEliminationPass())
185 .RegisterPass(CreateCombineAccessChainsPass())
186 .RegisterPass(CreateSimplificationPass())
187 .RegisterPass(CreateScalarReplacementPass())
188 .RegisterPass(CreateLocalAccessChainConvertPass())
189 .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass())
190 .RegisterPass(CreateLocalSingleStoreElimPass())
191 .RegisterPass(CreateAggressiveDCEPass())
192 .RegisterPass(CreateSSARewritePass())
193 .RegisterPass(CreateAggressiveDCEPass())
194 .RegisterPass(CreateVectorDCEPass())
195 .RegisterPass(CreateDeadInsertElimPass())
196 .RegisterPass(CreateDeadBranchElimPass())
197 .RegisterPass(CreateSimplificationPass())
198 .RegisterPass(CreateIfConversionPass())
199 .RegisterPass(CreateCopyPropagateArraysPass())
200 .RegisterPass(CreateReduceLoadSizePass())
201 .RegisterPass(CreateAggressiveDCEPass())
202 .RegisterPass(CreateBlockMergePass())
203 .RegisterPass(CreateRedundancyEliminationPass())
204 .RegisterPass(CreateDeadBranchElimPass())
205 .RegisterPass(CreateBlockMergePass())
206 .RegisterPass(CreateSimplificationPass());
207 }
208
RegisterSizePasses()209 Optimizer& Optimizer::RegisterSizePasses() {
210 return RegisterPass(CreateWrapOpKillPass())
211 .RegisterPass(CreateDeadBranchElimPass())
212 .RegisterPass(CreateMergeReturnPass())
213 .RegisterPass(CreateInlineExhaustivePass())
214 .RegisterPass(CreateEliminateDeadFunctionsPass())
215 .RegisterPass(CreatePrivateToLocalPass())
216 .RegisterPass(CreateScalarReplacementPass(0))
217 .RegisterPass(CreateLocalMultiStoreElimPass())
218 .RegisterPass(CreateCCPPass())
219 .RegisterPass(CreateLoopUnrollPass(true))
220 .RegisterPass(CreateDeadBranchElimPass())
221 .RegisterPass(CreateSimplificationPass())
222 .RegisterPass(CreateScalarReplacementPass(0))
223 .RegisterPass(CreateLocalSingleStoreElimPass())
224 .RegisterPass(CreateIfConversionPass())
225 .RegisterPass(CreateSimplificationPass())
226 .RegisterPass(CreateAggressiveDCEPass())
227 .RegisterPass(CreateDeadBranchElimPass())
228 .RegisterPass(CreateBlockMergePass())
229 .RegisterPass(CreateLocalAccessChainConvertPass())
230 .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass())
231 .RegisterPass(CreateAggressiveDCEPass())
232 .RegisterPass(CreateCopyPropagateArraysPass())
233 .RegisterPass(CreateVectorDCEPass())
234 .RegisterPass(CreateDeadInsertElimPass())
235 .RegisterPass(CreateEliminateDeadMembersPass())
236 .RegisterPass(CreateLocalSingleStoreElimPass())
237 .RegisterPass(CreateBlockMergePass())
238 .RegisterPass(CreateLocalMultiStoreElimPass())
239 .RegisterPass(CreateRedundancyEliminationPass())
240 .RegisterPass(CreateSimplificationPass())
241 .RegisterPass(CreateAggressiveDCEPass())
242 .RegisterPass(CreateCFGCleanupPass());
243 }
244
RegisterPassesFromFlags(const std::vector<std::string> & flags)245 bool Optimizer::RegisterPassesFromFlags(const std::vector<std::string>& flags) {
246 for (const auto& flag : flags) {
247 if (!RegisterPassFromFlag(flag)) {
248 return false;
249 }
250 }
251
252 return true;
253 }
254
FlagHasValidForm(const std::string & flag) const255 bool Optimizer::FlagHasValidForm(const std::string& flag) const {
256 if (flag == "-O" || flag == "-Os") {
257 return true;
258 } else if (flag.size() > 2 && flag.substr(0, 2) == "--") {
259 return true;
260 }
261
262 Errorf(consumer(), nullptr, {},
263 "%s is not a valid flag. Flag passes should have the form "
264 "'--pass_name[=pass_args]'. Special flag names also accepted: -O "
265 "and -Os.",
266 flag.c_str());
267 return false;
268 }
269
RegisterPassFromFlag(const std::string & flag)270 bool Optimizer::RegisterPassFromFlag(const std::string& flag) {
271 if (!FlagHasValidForm(flag)) {
272 return false;
273 }
274
275 // Split flags of the form --pass_name=pass_args.
276 auto p = utils::SplitFlagArgs(flag);
277 std::string pass_name = p.first;
278 std::string pass_args = p.second;
279
280 // FIXME(dnovillo): This should be re-factored so that pass names can be
281 // automatically checked against Pass::name() and PassToken instances created
282 // via a template function. Additionally, class Pass should have a desc()
283 // method that describes the pass (so it can be used in --help).
284 //
285 // Both Pass::name() and Pass::desc() should be static class members so they
286 // can be invoked without creating a pass instance.
287 if (pass_name == "strip-debug") {
288 RegisterPass(CreateStripDebugInfoPass());
289 } else if (pass_name == "strip-reflect") {
290 RegisterPass(CreateStripReflectInfoPass());
291 } else if (pass_name == "strip-nonsemantic") {
292 RegisterPass(CreateStripNonSemanticInfoPass());
293 } else if (pass_name == "set-spec-const-default-value") {
294 if (pass_args.size() > 0) {
295 auto spec_ids_vals =
296 opt::SetSpecConstantDefaultValuePass::ParseDefaultValuesString(
297 pass_args.c_str());
298 if (!spec_ids_vals) {
299 Errorf(consumer(), nullptr, {},
300 "Invalid argument for --set-spec-const-default-value: %s",
301 pass_args.c_str());
302 return false;
303 }
304 RegisterPass(
305 CreateSetSpecConstantDefaultValuePass(std::move(*spec_ids_vals)));
306 } else {
307 Errorf(consumer(), nullptr, {},
308 "Invalid spec constant value string '%s'. Expected a string of "
309 "<spec id>:<default value> pairs.",
310 pass_args.c_str());
311 return false;
312 }
313 } else if (pass_name == "if-conversion") {
314 RegisterPass(CreateIfConversionPass());
315 } else if (pass_name == "freeze-spec-const") {
316 RegisterPass(CreateFreezeSpecConstantValuePass());
317 } else if (pass_name == "inline-entry-points-exhaustive") {
318 RegisterPass(CreateInlineExhaustivePass());
319 } else if (pass_name == "inline-entry-points-opaque") {
320 RegisterPass(CreateInlineOpaquePass());
321 } else if (pass_name == "combine-access-chains") {
322 RegisterPass(CreateCombineAccessChainsPass());
323 } else if (pass_name == "convert-local-access-chains") {
324 RegisterPass(CreateLocalAccessChainConvertPass());
325 } else if (pass_name == "replace-desc-array-access-using-var-index") {
326 RegisterPass(CreateReplaceDescArrayAccessUsingVarIndexPass());
327 } else if (pass_name == "spread-volatile-semantics") {
328 RegisterPass(CreateSpreadVolatileSemanticsPass());
329 } else if (pass_name == "descriptor-scalar-replacement") {
330 RegisterPass(CreateDescriptorScalarReplacementPass());
331 } else if (pass_name == "eliminate-dead-code-aggressive") {
332 RegisterPass(CreateAggressiveDCEPass());
333 } else if (pass_name == "eliminate-insert-extract") {
334 RegisterPass(CreateInsertExtractElimPass());
335 } else if (pass_name == "eliminate-local-single-block") {
336 RegisterPass(CreateLocalSingleBlockLoadStoreElimPass());
337 } else if (pass_name == "eliminate-local-single-store") {
338 RegisterPass(CreateLocalSingleStoreElimPass());
339 } else if (pass_name == "merge-blocks") {
340 RegisterPass(CreateBlockMergePass());
341 } else if (pass_name == "merge-return") {
342 RegisterPass(CreateMergeReturnPass());
343 } else if (pass_name == "eliminate-dead-branches") {
344 RegisterPass(CreateDeadBranchElimPass());
345 } else if (pass_name == "eliminate-dead-functions") {
346 RegisterPass(CreateEliminateDeadFunctionsPass());
347 } else if (pass_name == "eliminate-local-multi-store") {
348 RegisterPass(CreateLocalMultiStoreElimPass());
349 } else if (pass_name == "eliminate-dead-const") {
350 RegisterPass(CreateEliminateDeadConstantPass());
351 } else if (pass_name == "eliminate-dead-inserts") {
352 RegisterPass(CreateDeadInsertElimPass());
353 } else if (pass_name == "eliminate-dead-variables") {
354 RegisterPass(CreateDeadVariableEliminationPass());
355 } else if (pass_name == "eliminate-dead-members") {
356 RegisterPass(CreateEliminateDeadMembersPass());
357 } else if (pass_name == "fold-spec-const-op-composite") {
358 RegisterPass(CreateFoldSpecConstantOpAndCompositePass());
359 } else if (pass_name == "loop-unswitch") {
360 RegisterPass(CreateLoopUnswitchPass());
361 } else if (pass_name == "scalar-replacement") {
362 if (pass_args.size() == 0) {
363 RegisterPass(CreateScalarReplacementPass());
364 } else {
365 int limit = -1;
366 if (pass_args.find_first_not_of("0123456789") == std::string::npos) {
367 limit = atoi(pass_args.c_str());
368 }
369
370 if (limit >= 0) {
371 RegisterPass(CreateScalarReplacementPass(limit));
372 } else {
373 Error(consumer(), nullptr, {},
374 "--scalar-replacement must have no arguments or a non-negative "
375 "integer argument");
376 return false;
377 }
378 }
379 } else if (pass_name == "strength-reduction") {
380 RegisterPass(CreateStrengthReductionPass());
381 } else if (pass_name == "unify-const") {
382 RegisterPass(CreateUnifyConstantPass());
383 } else if (pass_name == "flatten-decorations") {
384 RegisterPass(CreateFlattenDecorationPass());
385 } else if (pass_name == "compact-ids") {
386 RegisterPass(CreateCompactIdsPass());
387 } else if (pass_name == "cfg-cleanup") {
388 RegisterPass(CreateCFGCleanupPass());
389 } else if (pass_name == "local-redundancy-elimination") {
390 RegisterPass(CreateLocalRedundancyEliminationPass());
391 } else if (pass_name == "loop-invariant-code-motion") {
392 RegisterPass(CreateLoopInvariantCodeMotionPass());
393 } else if (pass_name == "reduce-load-size") {
394 if (pass_args.size() == 0) {
395 RegisterPass(CreateReduceLoadSizePass());
396 } else {
397 double load_replacement_threshold = 0.9;
398 if (pass_args.find_first_not_of(".0123456789") == std::string::npos) {
399 load_replacement_threshold = atof(pass_args.c_str());
400 }
401
402 if (load_replacement_threshold >= 0) {
403 RegisterPass(CreateReduceLoadSizePass(load_replacement_threshold));
404 } else {
405 Error(consumer(), nullptr, {},
406 "--reduce-load-size must have no arguments or a non-negative "
407 "double argument");
408 return false;
409 }
410 }
411 } else if (pass_name == "redundancy-elimination") {
412 RegisterPass(CreateRedundancyEliminationPass());
413 } else if (pass_name == "private-to-local") {
414 RegisterPass(CreatePrivateToLocalPass());
415 } else if (pass_name == "remove-duplicates") {
416 RegisterPass(CreateRemoveDuplicatesPass());
417 } else if (pass_name == "workaround-1209") {
418 RegisterPass(CreateWorkaround1209Pass());
419 } else if (pass_name == "replace-invalid-opcode") {
420 RegisterPass(CreateReplaceInvalidOpcodePass());
421 } else if (pass_name == "inst-bindless-check") {
422 RegisterPass(CreateInstBindlessCheckPass(7, 23, false, false));
423 RegisterPass(CreateSimplificationPass());
424 RegisterPass(CreateDeadBranchElimPass());
425 RegisterPass(CreateBlockMergePass());
426 RegisterPass(CreateAggressiveDCEPass(true));
427 } else if (pass_name == "inst-desc-idx-check") {
428 RegisterPass(CreateInstBindlessCheckPass(7, 23, true, true));
429 RegisterPass(CreateSimplificationPass());
430 RegisterPass(CreateDeadBranchElimPass());
431 RegisterPass(CreateBlockMergePass());
432 RegisterPass(CreateAggressiveDCEPass(true));
433 } else if (pass_name == "inst-buff-oob-check") {
434 RegisterPass(CreateInstBindlessCheckPass(7, 23, false, false, true, true));
435 RegisterPass(CreateSimplificationPass());
436 RegisterPass(CreateDeadBranchElimPass());
437 RegisterPass(CreateBlockMergePass());
438 RegisterPass(CreateAggressiveDCEPass(true));
439 } else if (pass_name == "inst-buff-addr-check") {
440 RegisterPass(CreateInstBuffAddrCheckPass(7, 23));
441 RegisterPass(CreateAggressiveDCEPass(true));
442 } else if (pass_name == "convert-relaxed-to-half") {
443 RegisterPass(CreateConvertRelaxedToHalfPass());
444 } else if (pass_name == "relax-float-ops") {
445 RegisterPass(CreateRelaxFloatOpsPass());
446 } else if (pass_name == "inst-debug-printf") {
447 RegisterPass(CreateInstDebugPrintfPass(7, 23));
448 } else if (pass_name == "simplify-instructions") {
449 RegisterPass(CreateSimplificationPass());
450 } else if (pass_name == "ssa-rewrite") {
451 RegisterPass(CreateSSARewritePass());
452 } else if (pass_name == "copy-propagate-arrays") {
453 RegisterPass(CreateCopyPropagateArraysPass());
454 } else if (pass_name == "loop-fission") {
455 int register_threshold_to_split =
456 (pass_args.size() > 0) ? atoi(pass_args.c_str()) : -1;
457 if (register_threshold_to_split > 0) {
458 RegisterPass(CreateLoopFissionPass(
459 static_cast<size_t>(register_threshold_to_split)));
460 } else {
461 Error(consumer(), nullptr, {},
462 "--loop-fission must have a positive integer argument");
463 return false;
464 }
465 } else if (pass_name == "loop-fusion") {
466 int max_registers_per_loop =
467 (pass_args.size() > 0) ? atoi(pass_args.c_str()) : -1;
468 if (max_registers_per_loop > 0) {
469 RegisterPass(
470 CreateLoopFusionPass(static_cast<size_t>(max_registers_per_loop)));
471 } else {
472 Error(consumer(), nullptr, {},
473 "--loop-fusion must have a positive integer argument");
474 return false;
475 }
476 } else if (pass_name == "loop-unroll") {
477 RegisterPass(CreateLoopUnrollPass(true));
478 } else if (pass_name == "upgrade-memory-model") {
479 RegisterPass(CreateUpgradeMemoryModelPass());
480 } else if (pass_name == "vector-dce") {
481 RegisterPass(CreateVectorDCEPass());
482 } else if (pass_name == "loop-unroll-partial") {
483 int factor = (pass_args.size() > 0) ? atoi(pass_args.c_str()) : 0;
484 if (factor > 0) {
485 RegisterPass(CreateLoopUnrollPass(false, factor));
486 } else {
487 Error(consumer(), nullptr, {},
488 "--loop-unroll-partial must have a positive integer argument");
489 return false;
490 }
491 } else if (pass_name == "loop-peeling") {
492 RegisterPass(CreateLoopPeelingPass());
493 } else if (pass_name == "loop-peeling-threshold") {
494 int factor = (pass_args.size() > 0) ? atoi(pass_args.c_str()) : 0;
495 if (factor > 0) {
496 opt::LoopPeelingPass::SetLoopPeelingThreshold(factor);
497 } else {
498 Error(consumer(), nullptr, {},
499 "--loop-peeling-threshold must have a positive integer argument");
500 return false;
501 }
502 } else if (pass_name == "ccp") {
503 RegisterPass(CreateCCPPass());
504 } else if (pass_name == "code-sink") {
505 RegisterPass(CreateCodeSinkingPass());
506 } else if (pass_name == "fix-storage-class") {
507 RegisterPass(CreateFixStorageClassPass());
508 } else if (pass_name == "O") {
509 RegisterPerformancePasses();
510 } else if (pass_name == "Os") {
511 RegisterSizePasses();
512 } else if (pass_name == "legalize-hlsl") {
513 RegisterLegalizationPasses();
514 } else if (pass_name == "remove-unused-interface-variables") {
515 RegisterPass(CreateRemoveUnusedInterfaceVariablesPass());
516 } else if (pass_name == "graphics-robust-access") {
517 RegisterPass(CreateGraphicsRobustAccessPass());
518 } else if (pass_name == "wrap-opkill") {
519 RegisterPass(CreateWrapOpKillPass());
520 } else if (pass_name == "amd-ext-to-khr") {
521 RegisterPass(CreateAmdExtToKhrPass());
522 } else if (pass_name == "interpolate-fixup") {
523 RegisterPass(CreateInterpolateFixupPass());
524 } else if (pass_name == "remove-dont-inline") {
525 RegisterPass(CreateRemoveDontInlinePass());
526 } else if (pass_name == "eliminate-dead-input-components") {
527 RegisterPass(CreateEliminateDeadInputComponentsPass());
528 } else if (pass_name == "convert-to-sampled-image") {
529 if (pass_args.size() > 0) {
530 auto descriptor_set_binding_pairs =
531 opt::ConvertToSampledImagePass::ParseDescriptorSetBindingPairsString(
532 pass_args.c_str());
533 if (!descriptor_set_binding_pairs) {
534 Errorf(consumer(), nullptr, {},
535 "Invalid argument for --convert-to-sampled-image: %s",
536 pass_args.c_str());
537 return false;
538 }
539 RegisterPass(CreateConvertToSampledImagePass(
540 std::move(*descriptor_set_binding_pairs)));
541 } else {
542 Errorf(consumer(), nullptr, {},
543 "Invalid pairs of descriptor set and binding '%s'. Expected a "
544 "string of <descriptor set>:<binding> pairs.",
545 pass_args.c_str());
546 return false;
547 }
548 } else {
549 Errorf(consumer(), nullptr, {},
550 "Unknown flag '--%s'. Use --help for a list of valid flags",
551 pass_name.c_str());
552 return false;
553 }
554
555 return true;
556 }
557
SetTargetEnv(const spv_target_env env)558 void Optimizer::SetTargetEnv(const spv_target_env env) {
559 impl_->target_env = env;
560 }
561
Run(const uint32_t * original_binary,const size_t original_binary_size,std::vector<uint32_t> * optimized_binary) const562 bool Optimizer::Run(const uint32_t* original_binary,
563 const size_t original_binary_size,
564 std::vector<uint32_t>* optimized_binary) const {
565 return Run(original_binary, original_binary_size, optimized_binary,
566 OptimizerOptions());
567 }
568
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) const569 bool Optimizer::Run(const uint32_t* original_binary,
570 const size_t original_binary_size,
571 std::vector<uint32_t>* optimized_binary,
572 const ValidatorOptions& validator_options,
573 bool skip_validation) const {
574 OptimizerOptions opt_options;
575 opt_options.set_run_validator(!skip_validation);
576 opt_options.set_validator_options(validator_options);
577 return Run(original_binary, original_binary_size, optimized_binary,
578 opt_options);
579 }
580
Run(const uint32_t * original_binary,const size_t original_binary_size,std::vector<uint32_t> * optimized_binary,const spv_optimizer_options opt_options) const581 bool Optimizer::Run(const uint32_t* original_binary,
582 const size_t original_binary_size,
583 std::vector<uint32_t>* optimized_binary,
584 const spv_optimizer_options opt_options) const {
585 spvtools::SpirvTools tools(impl_->target_env);
586 tools.SetMessageConsumer(impl_->pass_manager.consumer());
587 if (opt_options->run_validator_ &&
588 !tools.Validate(original_binary, original_binary_size,
589 &opt_options->val_options_)) {
590 return false;
591 }
592
593 std::unique_ptr<opt::IRContext> context = BuildModule(
594 impl_->target_env, consumer(), original_binary, original_binary_size);
595 if (context == nullptr) return false;
596
597 context->set_max_id_bound(opt_options->max_id_bound_);
598 context->set_preserve_bindings(opt_options->preserve_bindings_);
599 context->set_preserve_spec_constants(opt_options->preserve_spec_constants_);
600
601 impl_->pass_manager.SetValidatorOptions(&opt_options->val_options_);
602 impl_->pass_manager.SetTargetEnv(impl_->target_env);
603 auto status = impl_->pass_manager.Run(context.get());
604
605 if (status == opt::Pass::Status::Failure) {
606 return false;
607 }
608
609 #ifndef NDEBUG
610 // We do not keep the result id of DebugScope in struct DebugScope.
611 // Instead, we assign random ids for them, which results in integrity
612 // check failures. In addition, propagating the OpLine/OpNoLine to preserve
613 // the debug information through transformations results in integrity
614 // check failures. We want to skip the integrity check when the module
615 // contains DebugScope or OpLine/OpNoLine instructions.
616 if (status == opt::Pass::Status::SuccessWithoutChange &&
617 !context->module()->ContainsDebugInfo()) {
618 std::vector<uint32_t> optimized_binary_with_nop;
619 context->module()->ToBinary(&optimized_binary_with_nop,
620 /* skip_nop = */ false);
621 assert(optimized_binary_with_nop.size() == original_binary_size &&
622 "Binary size unexpectedly changed despite the optimizer saying "
623 "there was no change");
624 assert(memcmp(optimized_binary_with_nop.data(), original_binary,
625 original_binary_size) == 0 &&
626 "Binary content unexpectedly changed despite the optimizer saying "
627 "there was no change");
628 }
629 #endif // !NDEBUG
630
631 // Note that |original_binary| and |optimized_binary| may share the same
632 // buffer and the below will invalidate |original_binary|.
633 optimized_binary->clear();
634 context->module()->ToBinary(optimized_binary, /* skip_nop = */ true);
635
636 return true;
637 }
638
SetPrintAll(std::ostream * out)639 Optimizer& Optimizer::SetPrintAll(std::ostream* out) {
640 impl_->pass_manager.SetPrintAll(out);
641 return *this;
642 }
643
SetTimeReport(std::ostream * out)644 Optimizer& Optimizer::SetTimeReport(std::ostream* out) {
645 impl_->pass_manager.SetTimeReport(out);
646 return *this;
647 }
648
SetValidateAfterAll(bool validate)649 Optimizer& Optimizer::SetValidateAfterAll(bool validate) {
650 impl_->pass_manager.SetValidateAfterAll(validate);
651 return *this;
652 }
653
CreateNullPass()654 Optimizer::PassToken CreateNullPass() {
655 return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::NullPass>());
656 }
657
CreateStripDebugInfoPass()658 Optimizer::PassToken CreateStripDebugInfoPass() {
659 return MakeUnique<Optimizer::PassToken::Impl>(
660 MakeUnique<opt::StripDebugInfoPass>());
661 }
662
CreateStripReflectInfoPass()663 Optimizer::PassToken CreateStripReflectInfoPass() {
664 return CreateStripNonSemanticInfoPass();
665 }
666
CreateStripNonSemanticInfoPass()667 Optimizer::PassToken CreateStripNonSemanticInfoPass() {
668 return MakeUnique<Optimizer::PassToken::Impl>(
669 MakeUnique<opt::StripNonSemanticInfoPass>());
670 }
671
CreateEliminateDeadFunctionsPass()672 Optimizer::PassToken CreateEliminateDeadFunctionsPass() {
673 return MakeUnique<Optimizer::PassToken::Impl>(
674 MakeUnique<opt::EliminateDeadFunctionsPass>());
675 }
676
CreateEliminateDeadMembersPass()677 Optimizer::PassToken CreateEliminateDeadMembersPass() {
678 return MakeUnique<Optimizer::PassToken::Impl>(
679 MakeUnique<opt::EliminateDeadMembersPass>());
680 }
681
CreateSetSpecConstantDefaultValuePass(const std::unordered_map<uint32_t,std::string> & id_value_map)682 Optimizer::PassToken CreateSetSpecConstantDefaultValuePass(
683 const std::unordered_map<uint32_t, std::string>& id_value_map) {
684 return MakeUnique<Optimizer::PassToken::Impl>(
685 MakeUnique<opt::SetSpecConstantDefaultValuePass>(id_value_map));
686 }
687
CreateSetSpecConstantDefaultValuePass(const std::unordered_map<uint32_t,std::vector<uint32_t>> & id_value_map)688 Optimizer::PassToken CreateSetSpecConstantDefaultValuePass(
689 const std::unordered_map<uint32_t, std::vector<uint32_t>>& id_value_map) {
690 return MakeUnique<Optimizer::PassToken::Impl>(
691 MakeUnique<opt::SetSpecConstantDefaultValuePass>(id_value_map));
692 }
693
CreateFlattenDecorationPass()694 Optimizer::PassToken CreateFlattenDecorationPass() {
695 return MakeUnique<Optimizer::PassToken::Impl>(
696 MakeUnique<opt::FlattenDecorationPass>());
697 }
698
CreateFreezeSpecConstantValuePass()699 Optimizer::PassToken CreateFreezeSpecConstantValuePass() {
700 return MakeUnique<Optimizer::PassToken::Impl>(
701 MakeUnique<opt::FreezeSpecConstantValuePass>());
702 }
703
CreateFoldSpecConstantOpAndCompositePass()704 Optimizer::PassToken CreateFoldSpecConstantOpAndCompositePass() {
705 return MakeUnique<Optimizer::PassToken::Impl>(
706 MakeUnique<opt::FoldSpecConstantOpAndCompositePass>());
707 }
708
CreateUnifyConstantPass()709 Optimizer::PassToken CreateUnifyConstantPass() {
710 return MakeUnique<Optimizer::PassToken::Impl>(
711 MakeUnique<opt::UnifyConstantPass>());
712 }
713
CreateEliminateDeadConstantPass()714 Optimizer::PassToken CreateEliminateDeadConstantPass() {
715 return MakeUnique<Optimizer::PassToken::Impl>(
716 MakeUnique<opt::EliminateDeadConstantPass>());
717 }
718
CreateDeadVariableEliminationPass()719 Optimizer::PassToken CreateDeadVariableEliminationPass() {
720 return MakeUnique<Optimizer::PassToken::Impl>(
721 MakeUnique<opt::DeadVariableElimination>());
722 }
723
CreateStrengthReductionPass()724 Optimizer::PassToken CreateStrengthReductionPass() {
725 return MakeUnique<Optimizer::PassToken::Impl>(
726 MakeUnique<opt::StrengthReductionPass>());
727 }
728
CreateBlockMergePass()729 Optimizer::PassToken CreateBlockMergePass() {
730 return MakeUnique<Optimizer::PassToken::Impl>(
731 MakeUnique<opt::BlockMergePass>());
732 }
733
CreateInlineExhaustivePass()734 Optimizer::PassToken CreateInlineExhaustivePass() {
735 return MakeUnique<Optimizer::PassToken::Impl>(
736 MakeUnique<opt::InlineExhaustivePass>());
737 }
738
CreateInlineOpaquePass()739 Optimizer::PassToken CreateInlineOpaquePass() {
740 return MakeUnique<Optimizer::PassToken::Impl>(
741 MakeUnique<opt::InlineOpaquePass>());
742 }
743
CreateLocalAccessChainConvertPass()744 Optimizer::PassToken CreateLocalAccessChainConvertPass() {
745 return MakeUnique<Optimizer::PassToken::Impl>(
746 MakeUnique<opt::LocalAccessChainConvertPass>());
747 }
748
CreateLocalSingleBlockLoadStoreElimPass()749 Optimizer::PassToken CreateLocalSingleBlockLoadStoreElimPass() {
750 return MakeUnique<Optimizer::PassToken::Impl>(
751 MakeUnique<opt::LocalSingleBlockLoadStoreElimPass>());
752 }
753
CreateLocalSingleStoreElimPass()754 Optimizer::PassToken CreateLocalSingleStoreElimPass() {
755 return MakeUnique<Optimizer::PassToken::Impl>(
756 MakeUnique<opt::LocalSingleStoreElimPass>());
757 }
758
CreateInsertExtractElimPass()759 Optimizer::PassToken CreateInsertExtractElimPass() {
760 return MakeUnique<Optimizer::PassToken::Impl>(
761 MakeUnique<opt::SimplificationPass>());
762 }
763
CreateDeadInsertElimPass()764 Optimizer::PassToken CreateDeadInsertElimPass() {
765 return MakeUnique<Optimizer::PassToken::Impl>(
766 MakeUnique<opt::DeadInsertElimPass>());
767 }
768
CreateDeadBranchElimPass()769 Optimizer::PassToken CreateDeadBranchElimPass() {
770 return MakeUnique<Optimizer::PassToken::Impl>(
771 MakeUnique<opt::DeadBranchElimPass>());
772 }
773
CreateLocalMultiStoreElimPass()774 Optimizer::PassToken CreateLocalMultiStoreElimPass() {
775 return MakeUnique<Optimizer::PassToken::Impl>(
776 MakeUnique<opt::SSARewritePass>());
777 }
778
CreateAggressiveDCEPass()779 Optimizer::PassToken CreateAggressiveDCEPass() {
780 return MakeUnique<Optimizer::PassToken::Impl>(
781 MakeUnique<opt::AggressiveDCEPass>(false));
782 }
783
CreateAggressiveDCEPass(bool preserve_interface)784 Optimizer::PassToken CreateAggressiveDCEPass(bool preserve_interface) {
785 return MakeUnique<Optimizer::PassToken::Impl>(
786 MakeUnique<opt::AggressiveDCEPass>(preserve_interface));
787 }
788
CreateRemoveUnusedInterfaceVariablesPass()789 Optimizer::PassToken CreateRemoveUnusedInterfaceVariablesPass() {
790 return MakeUnique<Optimizer::PassToken::Impl>(
791 MakeUnique<opt::RemoveUnusedInterfaceVariablesPass>());
792 }
793
CreatePropagateLineInfoPass()794 Optimizer::PassToken CreatePropagateLineInfoPass() {
795 return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::EmptyPass>());
796 }
797
CreateRedundantLineInfoElimPass()798 Optimizer::PassToken CreateRedundantLineInfoElimPass() {
799 return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::EmptyPass>());
800 }
801
CreateCompactIdsPass()802 Optimizer::PassToken CreateCompactIdsPass() {
803 return MakeUnique<Optimizer::PassToken::Impl>(
804 MakeUnique<opt::CompactIdsPass>());
805 }
806
CreateMergeReturnPass()807 Optimizer::PassToken CreateMergeReturnPass() {
808 return MakeUnique<Optimizer::PassToken::Impl>(
809 MakeUnique<opt::MergeReturnPass>());
810 }
811
GetPassNames() const812 std::vector<const char*> Optimizer::GetPassNames() const {
813 std::vector<const char*> v;
814 for (uint32_t i = 0; i < impl_->pass_manager.NumPasses(); i++) {
815 v.push_back(impl_->pass_manager.GetPass(i)->name());
816 }
817 return v;
818 }
819
CreateCFGCleanupPass()820 Optimizer::PassToken CreateCFGCleanupPass() {
821 return MakeUnique<Optimizer::PassToken::Impl>(
822 MakeUnique<opt::CFGCleanupPass>());
823 }
824
CreateLocalRedundancyEliminationPass()825 Optimizer::PassToken CreateLocalRedundancyEliminationPass() {
826 return MakeUnique<Optimizer::PassToken::Impl>(
827 MakeUnique<opt::LocalRedundancyEliminationPass>());
828 }
829
CreateLoopFissionPass(size_t threshold)830 Optimizer::PassToken CreateLoopFissionPass(size_t threshold) {
831 return MakeUnique<Optimizer::PassToken::Impl>(
832 MakeUnique<opt::LoopFissionPass>(threshold));
833 }
834
CreateLoopFusionPass(size_t max_registers_per_loop)835 Optimizer::PassToken CreateLoopFusionPass(size_t max_registers_per_loop) {
836 return MakeUnique<Optimizer::PassToken::Impl>(
837 MakeUnique<opt::LoopFusionPass>(max_registers_per_loop));
838 }
839
CreateLoopInvariantCodeMotionPass()840 Optimizer::PassToken CreateLoopInvariantCodeMotionPass() {
841 return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::LICMPass>());
842 }
843
CreateLoopPeelingPass()844 Optimizer::PassToken CreateLoopPeelingPass() {
845 return MakeUnique<Optimizer::PassToken::Impl>(
846 MakeUnique<opt::LoopPeelingPass>());
847 }
848
CreateLoopUnswitchPass()849 Optimizer::PassToken CreateLoopUnswitchPass() {
850 return MakeUnique<Optimizer::PassToken::Impl>(
851 MakeUnique<opt::LoopUnswitchPass>());
852 }
853
CreateRedundancyEliminationPass()854 Optimizer::PassToken CreateRedundancyEliminationPass() {
855 return MakeUnique<Optimizer::PassToken::Impl>(
856 MakeUnique<opt::RedundancyEliminationPass>());
857 }
858
CreateRemoveDuplicatesPass()859 Optimizer::PassToken CreateRemoveDuplicatesPass() {
860 return MakeUnique<Optimizer::PassToken::Impl>(
861 MakeUnique<opt::RemoveDuplicatesPass>());
862 }
863
CreateScalarReplacementPass(uint32_t size_limit)864 Optimizer::PassToken CreateScalarReplacementPass(uint32_t size_limit) {
865 return MakeUnique<Optimizer::PassToken::Impl>(
866 MakeUnique<opt::ScalarReplacementPass>(size_limit));
867 }
868
CreatePrivateToLocalPass()869 Optimizer::PassToken CreatePrivateToLocalPass() {
870 return MakeUnique<Optimizer::PassToken::Impl>(
871 MakeUnique<opt::PrivateToLocalPass>());
872 }
873
CreateCCPPass()874 Optimizer::PassToken CreateCCPPass() {
875 return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::CCPPass>());
876 }
877
CreateWorkaround1209Pass()878 Optimizer::PassToken CreateWorkaround1209Pass() {
879 return MakeUnique<Optimizer::PassToken::Impl>(
880 MakeUnique<opt::Workaround1209>());
881 }
882
CreateIfConversionPass()883 Optimizer::PassToken CreateIfConversionPass() {
884 return MakeUnique<Optimizer::PassToken::Impl>(
885 MakeUnique<opt::IfConversion>());
886 }
887
CreateReplaceInvalidOpcodePass()888 Optimizer::PassToken CreateReplaceInvalidOpcodePass() {
889 return MakeUnique<Optimizer::PassToken::Impl>(
890 MakeUnique<opt::ReplaceInvalidOpcodePass>());
891 }
892
CreateSimplificationPass()893 Optimizer::PassToken CreateSimplificationPass() {
894 return MakeUnique<Optimizer::PassToken::Impl>(
895 MakeUnique<opt::SimplificationPass>());
896 }
897
CreateLoopUnrollPass(bool fully_unroll,int factor)898 Optimizer::PassToken CreateLoopUnrollPass(bool fully_unroll, int factor) {
899 return MakeUnique<Optimizer::PassToken::Impl>(
900 MakeUnique<opt::LoopUnroller>(fully_unroll, factor));
901 }
902
CreateSSARewritePass()903 Optimizer::PassToken CreateSSARewritePass() {
904 return MakeUnique<Optimizer::PassToken::Impl>(
905 MakeUnique<opt::SSARewritePass>());
906 }
907
CreateCopyPropagateArraysPass()908 Optimizer::PassToken CreateCopyPropagateArraysPass() {
909 return MakeUnique<Optimizer::PassToken::Impl>(
910 MakeUnique<opt::CopyPropagateArrays>());
911 }
912
CreateVectorDCEPass()913 Optimizer::PassToken CreateVectorDCEPass() {
914 return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::VectorDCE>());
915 }
916
CreateReduceLoadSizePass(double load_replacement_threshold)917 Optimizer::PassToken CreateReduceLoadSizePass(
918 double load_replacement_threshold) {
919 return MakeUnique<Optimizer::PassToken::Impl>(
920 MakeUnique<opt::ReduceLoadSize>(load_replacement_threshold));
921 }
922
CreateCombineAccessChainsPass()923 Optimizer::PassToken CreateCombineAccessChainsPass() {
924 return MakeUnique<Optimizer::PassToken::Impl>(
925 MakeUnique<opt::CombineAccessChains>());
926 }
927
CreateUpgradeMemoryModelPass()928 Optimizer::PassToken CreateUpgradeMemoryModelPass() {
929 return MakeUnique<Optimizer::PassToken::Impl>(
930 MakeUnique<opt::UpgradeMemoryModel>());
931 }
932
CreateInstBindlessCheckPass(uint32_t desc_set,uint32_t shader_id,bool desc_length_enable,bool desc_init_enable,bool buff_oob_enable,bool texbuff_oob_enable)933 Optimizer::PassToken CreateInstBindlessCheckPass(
934 uint32_t desc_set, uint32_t shader_id, bool desc_length_enable,
935 bool desc_init_enable, bool buff_oob_enable, bool texbuff_oob_enable) {
936 return MakeUnique<Optimizer::PassToken::Impl>(
937 MakeUnique<opt::InstBindlessCheckPass>(
938 desc_set, shader_id, desc_length_enable, desc_init_enable,
939 buff_oob_enable, texbuff_oob_enable,
940 desc_length_enable || desc_init_enable || buff_oob_enable));
941 }
942
CreateInstDebugPrintfPass(uint32_t desc_set,uint32_t shader_id)943 Optimizer::PassToken CreateInstDebugPrintfPass(uint32_t desc_set,
944 uint32_t shader_id) {
945 return MakeUnique<Optimizer::PassToken::Impl>(
946 MakeUnique<opt::InstDebugPrintfPass>(desc_set, shader_id));
947 }
948
CreateInstBuffAddrCheckPass(uint32_t desc_set,uint32_t shader_id)949 Optimizer::PassToken CreateInstBuffAddrCheckPass(uint32_t desc_set,
950 uint32_t shader_id) {
951 return MakeUnique<Optimizer::PassToken::Impl>(
952 MakeUnique<opt::InstBuffAddrCheckPass>(desc_set, shader_id));
953 }
954
CreateConvertRelaxedToHalfPass()955 Optimizer::PassToken CreateConvertRelaxedToHalfPass() {
956 return MakeUnique<Optimizer::PassToken::Impl>(
957 MakeUnique<opt::ConvertToHalfPass>());
958 }
959
CreateRelaxFloatOpsPass()960 Optimizer::PassToken CreateRelaxFloatOpsPass() {
961 return MakeUnique<Optimizer::PassToken::Impl>(
962 MakeUnique<opt::RelaxFloatOpsPass>());
963 }
964
CreateCodeSinkingPass()965 Optimizer::PassToken CreateCodeSinkingPass() {
966 return MakeUnique<Optimizer::PassToken::Impl>(
967 MakeUnique<opt::CodeSinkingPass>());
968 }
969
CreateFixStorageClassPass()970 Optimizer::PassToken CreateFixStorageClassPass() {
971 return MakeUnique<Optimizer::PassToken::Impl>(
972 MakeUnique<opt::FixStorageClass>());
973 }
974
CreateGraphicsRobustAccessPass()975 Optimizer::PassToken CreateGraphicsRobustAccessPass() {
976 return MakeUnique<Optimizer::PassToken::Impl>(
977 MakeUnique<opt::GraphicsRobustAccessPass>());
978 }
979
CreateReplaceDescArrayAccessUsingVarIndexPass()980 Optimizer::PassToken CreateReplaceDescArrayAccessUsingVarIndexPass() {
981 return MakeUnique<Optimizer::PassToken::Impl>(
982 MakeUnique<opt::ReplaceDescArrayAccessUsingVarIndex>());
983 }
984
CreateSpreadVolatileSemanticsPass()985 Optimizer::PassToken CreateSpreadVolatileSemanticsPass() {
986 return MakeUnique<Optimizer::PassToken::Impl>(
987 MakeUnique<opt::SpreadVolatileSemantics>());
988 }
989
CreateDescriptorScalarReplacementPass()990 Optimizer::PassToken CreateDescriptorScalarReplacementPass() {
991 return MakeUnique<Optimizer::PassToken::Impl>(
992 MakeUnique<opt::DescriptorScalarReplacement>());
993 }
994
CreateWrapOpKillPass()995 Optimizer::PassToken CreateWrapOpKillPass() {
996 return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::WrapOpKill>());
997 }
998
CreateAmdExtToKhrPass()999 Optimizer::PassToken CreateAmdExtToKhrPass() {
1000 return MakeUnique<Optimizer::PassToken::Impl>(
1001 MakeUnique<opt::AmdExtensionToKhrPass>());
1002 }
1003
CreateInterpolateFixupPass()1004 Optimizer::PassToken CreateInterpolateFixupPass() {
1005 return MakeUnique<Optimizer::PassToken::Impl>(
1006 MakeUnique<opt::InterpFixupPass>());
1007 }
1008
CreateEliminateDeadInputComponentsPass()1009 Optimizer::PassToken CreateEliminateDeadInputComponentsPass() {
1010 return MakeUnique<Optimizer::PassToken::Impl>(
1011 MakeUnique<opt::EliminateDeadInputComponentsPass>());
1012 }
1013
CreateConvertToSampledImagePass(const std::vector<opt::DescriptorSetAndBinding> & descriptor_set_binding_pairs)1014 Optimizer::PassToken CreateConvertToSampledImagePass(
1015 const std::vector<opt::DescriptorSetAndBinding>&
1016 descriptor_set_binding_pairs) {
1017 return MakeUnique<Optimizer::PassToken::Impl>(
1018 MakeUnique<opt::ConvertToSampledImagePass>(descriptor_set_binding_pairs));
1019 }
1020
CreateRemoveDontInlinePass()1021 Optimizer::PassToken CreateRemoveDontInlinePass() {
1022 return MakeUnique<Optimizer::PassToken::Impl>(
1023 MakeUnique<opt::RemoveDontInline>());
1024 }
1025 } // namespace spvtools
1026