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 == "fix-func-call-param") {
529 RegisterPass(CreateFixFuncCallArgumentsPass());
530 } else if (pass_name == "convert-to-sampled-image") {
531 if (pass_args.size() > 0) {
532 auto descriptor_set_binding_pairs =
533 opt::ConvertToSampledImagePass::ParseDescriptorSetBindingPairsString(
534 pass_args.c_str());
535 if (!descriptor_set_binding_pairs) {
536 Errorf(consumer(), nullptr, {},
537 "Invalid argument for --convert-to-sampled-image: %s",
538 pass_args.c_str());
539 return false;
540 }
541 RegisterPass(CreateConvertToSampledImagePass(
542 std::move(*descriptor_set_binding_pairs)));
543 } else {
544 Errorf(consumer(), nullptr, {},
545 "Invalid pairs of descriptor set and binding '%s'. Expected a "
546 "string of <descriptor set>:<binding> pairs.",
547 pass_args.c_str());
548 return false;
549 }
550 } else {
551 Errorf(consumer(), nullptr, {},
552 "Unknown flag '--%s'. Use --help for a list of valid flags",
553 pass_name.c_str());
554 return false;
555 }
556
557 return true;
558 }
559
SetTargetEnv(const spv_target_env env)560 void Optimizer::SetTargetEnv(const spv_target_env env) {
561 impl_->target_env = env;
562 }
563
Run(const uint32_t * original_binary,const size_t original_binary_size,std::vector<uint32_t> * optimized_binary) const564 bool Optimizer::Run(const uint32_t* original_binary,
565 const size_t original_binary_size,
566 std::vector<uint32_t>* optimized_binary) const {
567 return Run(original_binary, original_binary_size, optimized_binary,
568 OptimizerOptions());
569 }
570
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) const571 bool Optimizer::Run(const uint32_t* original_binary,
572 const size_t original_binary_size,
573 std::vector<uint32_t>* optimized_binary,
574 const ValidatorOptions& validator_options,
575 bool skip_validation) const {
576 OptimizerOptions opt_options;
577 opt_options.set_run_validator(!skip_validation);
578 opt_options.set_validator_options(validator_options);
579 return Run(original_binary, original_binary_size, optimized_binary,
580 opt_options);
581 }
582
Run(const uint32_t * original_binary,const size_t original_binary_size,std::vector<uint32_t> * optimized_binary,const spv_optimizer_options opt_options) const583 bool Optimizer::Run(const uint32_t* original_binary,
584 const size_t original_binary_size,
585 std::vector<uint32_t>* optimized_binary,
586 const spv_optimizer_options opt_options) const {
587 spvtools::SpirvTools tools(impl_->target_env);
588 tools.SetMessageConsumer(impl_->pass_manager.consumer());
589 if (opt_options->run_validator_ &&
590 !tools.Validate(original_binary, original_binary_size,
591 &opt_options->val_options_)) {
592 return false;
593 }
594
595 std::unique_ptr<opt::IRContext> context = BuildModule(
596 impl_->target_env, consumer(), original_binary, original_binary_size);
597 if (context == nullptr) return false;
598
599 context->set_max_id_bound(opt_options->max_id_bound_);
600 context->set_preserve_bindings(opt_options->preserve_bindings_);
601 context->set_preserve_spec_constants(opt_options->preserve_spec_constants_);
602
603 impl_->pass_manager.SetValidatorOptions(&opt_options->val_options_);
604 impl_->pass_manager.SetTargetEnv(impl_->target_env);
605 auto status = impl_->pass_manager.Run(context.get());
606
607 if (status == opt::Pass::Status::Failure) {
608 return false;
609 }
610
611 #ifndef NDEBUG
612 // We do not keep the result id of DebugScope in struct DebugScope.
613 // Instead, we assign random ids for them, which results in integrity
614 // check failures. In addition, propagating the OpLine/OpNoLine to preserve
615 // the debug information through transformations results in integrity
616 // check failures. We want to skip the integrity check when the module
617 // contains DebugScope or OpLine/OpNoLine instructions.
618 if (status == opt::Pass::Status::SuccessWithoutChange &&
619 !context->module()->ContainsDebugInfo()) {
620 std::vector<uint32_t> optimized_binary_with_nop;
621 context->module()->ToBinary(&optimized_binary_with_nop,
622 /* skip_nop = */ false);
623 assert(optimized_binary_with_nop.size() == original_binary_size &&
624 "Binary size unexpectedly changed despite the optimizer saying "
625 "there was no change");
626
627 // Compare the magic number to make sure the binaries were encoded in the
628 // endianness. If not, the contents of the binaries will be different, so
629 // do not check the contents.
630 if (optimized_binary_with_nop[0] == original_binary[0]) {
631 assert(memcmp(optimized_binary_with_nop.data(), original_binary,
632 original_binary_size) == 0 &&
633 "Binary content unexpectedly changed despite the optimizer saying "
634 "there was no change");
635 }
636 }
637 #endif // !NDEBUG
638
639 // Note that |original_binary| and |optimized_binary| may share the same
640 // buffer and the below will invalidate |original_binary|.
641 optimized_binary->clear();
642 context->module()->ToBinary(optimized_binary, /* skip_nop = */ true);
643
644 return true;
645 }
646
SetPrintAll(std::ostream * out)647 Optimizer& Optimizer::SetPrintAll(std::ostream* out) {
648 impl_->pass_manager.SetPrintAll(out);
649 return *this;
650 }
651
SetTimeReport(std::ostream * out)652 Optimizer& Optimizer::SetTimeReport(std::ostream* out) {
653 impl_->pass_manager.SetTimeReport(out);
654 return *this;
655 }
656
SetValidateAfterAll(bool validate)657 Optimizer& Optimizer::SetValidateAfterAll(bool validate) {
658 impl_->pass_manager.SetValidateAfterAll(validate);
659 return *this;
660 }
661
CreateNullPass()662 Optimizer::PassToken CreateNullPass() {
663 return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::NullPass>());
664 }
665
CreateStripDebugInfoPass()666 Optimizer::PassToken CreateStripDebugInfoPass() {
667 return MakeUnique<Optimizer::PassToken::Impl>(
668 MakeUnique<opt::StripDebugInfoPass>());
669 }
670
CreateStripReflectInfoPass()671 Optimizer::PassToken CreateStripReflectInfoPass() {
672 return CreateStripNonSemanticInfoPass();
673 }
674
CreateStripNonSemanticInfoPass()675 Optimizer::PassToken CreateStripNonSemanticInfoPass() {
676 return MakeUnique<Optimizer::PassToken::Impl>(
677 MakeUnique<opt::StripNonSemanticInfoPass>());
678 }
679
CreateEliminateDeadFunctionsPass()680 Optimizer::PassToken CreateEliminateDeadFunctionsPass() {
681 return MakeUnique<Optimizer::PassToken::Impl>(
682 MakeUnique<opt::EliminateDeadFunctionsPass>());
683 }
684
CreateEliminateDeadMembersPass()685 Optimizer::PassToken CreateEliminateDeadMembersPass() {
686 return MakeUnique<Optimizer::PassToken::Impl>(
687 MakeUnique<opt::EliminateDeadMembersPass>());
688 }
689
CreateSetSpecConstantDefaultValuePass(const std::unordered_map<uint32_t,std::string> & id_value_map)690 Optimizer::PassToken CreateSetSpecConstantDefaultValuePass(
691 const std::unordered_map<uint32_t, std::string>& id_value_map) {
692 return MakeUnique<Optimizer::PassToken::Impl>(
693 MakeUnique<opt::SetSpecConstantDefaultValuePass>(id_value_map));
694 }
695
CreateSetSpecConstantDefaultValuePass(const std::unordered_map<uint32_t,std::vector<uint32_t>> & id_value_map)696 Optimizer::PassToken CreateSetSpecConstantDefaultValuePass(
697 const std::unordered_map<uint32_t, std::vector<uint32_t>>& id_value_map) {
698 return MakeUnique<Optimizer::PassToken::Impl>(
699 MakeUnique<opt::SetSpecConstantDefaultValuePass>(id_value_map));
700 }
701
CreateFlattenDecorationPass()702 Optimizer::PassToken CreateFlattenDecorationPass() {
703 return MakeUnique<Optimizer::PassToken::Impl>(
704 MakeUnique<opt::FlattenDecorationPass>());
705 }
706
CreateFreezeSpecConstantValuePass()707 Optimizer::PassToken CreateFreezeSpecConstantValuePass() {
708 return MakeUnique<Optimizer::PassToken::Impl>(
709 MakeUnique<opt::FreezeSpecConstantValuePass>());
710 }
711
CreateFoldSpecConstantOpAndCompositePass()712 Optimizer::PassToken CreateFoldSpecConstantOpAndCompositePass() {
713 return MakeUnique<Optimizer::PassToken::Impl>(
714 MakeUnique<opt::FoldSpecConstantOpAndCompositePass>());
715 }
716
CreateUnifyConstantPass()717 Optimizer::PassToken CreateUnifyConstantPass() {
718 return MakeUnique<Optimizer::PassToken::Impl>(
719 MakeUnique<opt::UnifyConstantPass>());
720 }
721
CreateEliminateDeadConstantPass()722 Optimizer::PassToken CreateEliminateDeadConstantPass() {
723 return MakeUnique<Optimizer::PassToken::Impl>(
724 MakeUnique<opt::EliminateDeadConstantPass>());
725 }
726
CreateDeadVariableEliminationPass()727 Optimizer::PassToken CreateDeadVariableEliminationPass() {
728 return MakeUnique<Optimizer::PassToken::Impl>(
729 MakeUnique<opt::DeadVariableElimination>());
730 }
731
CreateStrengthReductionPass()732 Optimizer::PassToken CreateStrengthReductionPass() {
733 return MakeUnique<Optimizer::PassToken::Impl>(
734 MakeUnique<opt::StrengthReductionPass>());
735 }
736
CreateBlockMergePass()737 Optimizer::PassToken CreateBlockMergePass() {
738 return MakeUnique<Optimizer::PassToken::Impl>(
739 MakeUnique<opt::BlockMergePass>());
740 }
741
CreateInlineExhaustivePass()742 Optimizer::PassToken CreateInlineExhaustivePass() {
743 return MakeUnique<Optimizer::PassToken::Impl>(
744 MakeUnique<opt::InlineExhaustivePass>());
745 }
746
CreateInlineOpaquePass()747 Optimizer::PassToken CreateInlineOpaquePass() {
748 return MakeUnique<Optimizer::PassToken::Impl>(
749 MakeUnique<opt::InlineOpaquePass>());
750 }
751
CreateLocalAccessChainConvertPass()752 Optimizer::PassToken CreateLocalAccessChainConvertPass() {
753 return MakeUnique<Optimizer::PassToken::Impl>(
754 MakeUnique<opt::LocalAccessChainConvertPass>());
755 }
756
CreateLocalSingleBlockLoadStoreElimPass()757 Optimizer::PassToken CreateLocalSingleBlockLoadStoreElimPass() {
758 return MakeUnique<Optimizer::PassToken::Impl>(
759 MakeUnique<opt::LocalSingleBlockLoadStoreElimPass>());
760 }
761
CreateLocalSingleStoreElimPass()762 Optimizer::PassToken CreateLocalSingleStoreElimPass() {
763 return MakeUnique<Optimizer::PassToken::Impl>(
764 MakeUnique<opt::LocalSingleStoreElimPass>());
765 }
766
CreateInsertExtractElimPass()767 Optimizer::PassToken CreateInsertExtractElimPass() {
768 return MakeUnique<Optimizer::PassToken::Impl>(
769 MakeUnique<opt::SimplificationPass>());
770 }
771
CreateDeadInsertElimPass()772 Optimizer::PassToken CreateDeadInsertElimPass() {
773 return MakeUnique<Optimizer::PassToken::Impl>(
774 MakeUnique<opt::DeadInsertElimPass>());
775 }
776
CreateDeadBranchElimPass()777 Optimizer::PassToken CreateDeadBranchElimPass() {
778 return MakeUnique<Optimizer::PassToken::Impl>(
779 MakeUnique<opt::DeadBranchElimPass>());
780 }
781
CreateLocalMultiStoreElimPass()782 Optimizer::PassToken CreateLocalMultiStoreElimPass() {
783 return MakeUnique<Optimizer::PassToken::Impl>(
784 MakeUnique<opt::SSARewritePass>());
785 }
786
CreateAggressiveDCEPass()787 Optimizer::PassToken CreateAggressiveDCEPass() {
788 return MakeUnique<Optimizer::PassToken::Impl>(
789 MakeUnique<opt::AggressiveDCEPass>(false));
790 }
791
CreateAggressiveDCEPass(bool preserve_interface)792 Optimizer::PassToken CreateAggressiveDCEPass(bool preserve_interface) {
793 return MakeUnique<Optimizer::PassToken::Impl>(
794 MakeUnique<opt::AggressiveDCEPass>(preserve_interface));
795 }
796
CreateRemoveUnusedInterfaceVariablesPass()797 Optimizer::PassToken CreateRemoveUnusedInterfaceVariablesPass() {
798 return MakeUnique<Optimizer::PassToken::Impl>(
799 MakeUnique<opt::RemoveUnusedInterfaceVariablesPass>());
800 }
801
CreatePropagateLineInfoPass()802 Optimizer::PassToken CreatePropagateLineInfoPass() {
803 return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::EmptyPass>());
804 }
805
CreateRedundantLineInfoElimPass()806 Optimizer::PassToken CreateRedundantLineInfoElimPass() {
807 return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::EmptyPass>());
808 }
809
CreateCompactIdsPass()810 Optimizer::PassToken CreateCompactIdsPass() {
811 return MakeUnique<Optimizer::PassToken::Impl>(
812 MakeUnique<opt::CompactIdsPass>());
813 }
814
CreateMergeReturnPass()815 Optimizer::PassToken CreateMergeReturnPass() {
816 return MakeUnique<Optimizer::PassToken::Impl>(
817 MakeUnique<opt::MergeReturnPass>());
818 }
819
GetPassNames() const820 std::vector<const char*> Optimizer::GetPassNames() const {
821 std::vector<const char*> v;
822 for (uint32_t i = 0; i < impl_->pass_manager.NumPasses(); i++) {
823 v.push_back(impl_->pass_manager.GetPass(i)->name());
824 }
825 return v;
826 }
827
CreateCFGCleanupPass()828 Optimizer::PassToken CreateCFGCleanupPass() {
829 return MakeUnique<Optimizer::PassToken::Impl>(
830 MakeUnique<opt::CFGCleanupPass>());
831 }
832
CreateLocalRedundancyEliminationPass()833 Optimizer::PassToken CreateLocalRedundancyEliminationPass() {
834 return MakeUnique<Optimizer::PassToken::Impl>(
835 MakeUnique<opt::LocalRedundancyEliminationPass>());
836 }
837
CreateLoopFissionPass(size_t threshold)838 Optimizer::PassToken CreateLoopFissionPass(size_t threshold) {
839 return MakeUnique<Optimizer::PassToken::Impl>(
840 MakeUnique<opt::LoopFissionPass>(threshold));
841 }
842
CreateLoopFusionPass(size_t max_registers_per_loop)843 Optimizer::PassToken CreateLoopFusionPass(size_t max_registers_per_loop) {
844 return MakeUnique<Optimizer::PassToken::Impl>(
845 MakeUnique<opt::LoopFusionPass>(max_registers_per_loop));
846 }
847
CreateLoopInvariantCodeMotionPass()848 Optimizer::PassToken CreateLoopInvariantCodeMotionPass() {
849 return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::LICMPass>());
850 }
851
CreateLoopPeelingPass()852 Optimizer::PassToken CreateLoopPeelingPass() {
853 return MakeUnique<Optimizer::PassToken::Impl>(
854 MakeUnique<opt::LoopPeelingPass>());
855 }
856
CreateLoopUnswitchPass()857 Optimizer::PassToken CreateLoopUnswitchPass() {
858 return MakeUnique<Optimizer::PassToken::Impl>(
859 MakeUnique<opt::LoopUnswitchPass>());
860 }
861
CreateRedundancyEliminationPass()862 Optimizer::PassToken CreateRedundancyEliminationPass() {
863 return MakeUnique<Optimizer::PassToken::Impl>(
864 MakeUnique<opt::RedundancyEliminationPass>());
865 }
866
CreateRemoveDuplicatesPass()867 Optimizer::PassToken CreateRemoveDuplicatesPass() {
868 return MakeUnique<Optimizer::PassToken::Impl>(
869 MakeUnique<opt::RemoveDuplicatesPass>());
870 }
871
CreateScalarReplacementPass(uint32_t size_limit)872 Optimizer::PassToken CreateScalarReplacementPass(uint32_t size_limit) {
873 return MakeUnique<Optimizer::PassToken::Impl>(
874 MakeUnique<opt::ScalarReplacementPass>(size_limit));
875 }
876
CreatePrivateToLocalPass()877 Optimizer::PassToken CreatePrivateToLocalPass() {
878 return MakeUnique<Optimizer::PassToken::Impl>(
879 MakeUnique<opt::PrivateToLocalPass>());
880 }
881
CreateCCPPass()882 Optimizer::PassToken CreateCCPPass() {
883 return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::CCPPass>());
884 }
885
CreateWorkaround1209Pass()886 Optimizer::PassToken CreateWorkaround1209Pass() {
887 return MakeUnique<Optimizer::PassToken::Impl>(
888 MakeUnique<opt::Workaround1209>());
889 }
890
CreateIfConversionPass()891 Optimizer::PassToken CreateIfConversionPass() {
892 return MakeUnique<Optimizer::PassToken::Impl>(
893 MakeUnique<opt::IfConversion>());
894 }
895
CreateReplaceInvalidOpcodePass()896 Optimizer::PassToken CreateReplaceInvalidOpcodePass() {
897 return MakeUnique<Optimizer::PassToken::Impl>(
898 MakeUnique<opt::ReplaceInvalidOpcodePass>());
899 }
900
CreateSimplificationPass()901 Optimizer::PassToken CreateSimplificationPass() {
902 return MakeUnique<Optimizer::PassToken::Impl>(
903 MakeUnique<opt::SimplificationPass>());
904 }
905
CreateLoopUnrollPass(bool fully_unroll,int factor)906 Optimizer::PassToken CreateLoopUnrollPass(bool fully_unroll, int factor) {
907 return MakeUnique<Optimizer::PassToken::Impl>(
908 MakeUnique<opt::LoopUnroller>(fully_unroll, factor));
909 }
910
CreateSSARewritePass()911 Optimizer::PassToken CreateSSARewritePass() {
912 return MakeUnique<Optimizer::PassToken::Impl>(
913 MakeUnique<opt::SSARewritePass>());
914 }
915
CreateCopyPropagateArraysPass()916 Optimizer::PassToken CreateCopyPropagateArraysPass() {
917 return MakeUnique<Optimizer::PassToken::Impl>(
918 MakeUnique<opt::CopyPropagateArrays>());
919 }
920
CreateVectorDCEPass()921 Optimizer::PassToken CreateVectorDCEPass() {
922 return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::VectorDCE>());
923 }
924
CreateReduceLoadSizePass(double load_replacement_threshold)925 Optimizer::PassToken CreateReduceLoadSizePass(
926 double load_replacement_threshold) {
927 return MakeUnique<Optimizer::PassToken::Impl>(
928 MakeUnique<opt::ReduceLoadSize>(load_replacement_threshold));
929 }
930
CreateCombineAccessChainsPass()931 Optimizer::PassToken CreateCombineAccessChainsPass() {
932 return MakeUnique<Optimizer::PassToken::Impl>(
933 MakeUnique<opt::CombineAccessChains>());
934 }
935
CreateUpgradeMemoryModelPass()936 Optimizer::PassToken CreateUpgradeMemoryModelPass() {
937 return MakeUnique<Optimizer::PassToken::Impl>(
938 MakeUnique<opt::UpgradeMemoryModel>());
939 }
940
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)941 Optimizer::PassToken CreateInstBindlessCheckPass(
942 uint32_t desc_set, uint32_t shader_id, bool desc_length_enable,
943 bool desc_init_enable, bool buff_oob_enable, bool texbuff_oob_enable) {
944 return MakeUnique<Optimizer::PassToken::Impl>(
945 MakeUnique<opt::InstBindlessCheckPass>(
946 desc_set, shader_id, desc_length_enable, desc_init_enable,
947 buff_oob_enable, texbuff_oob_enable,
948 desc_length_enable || desc_init_enable || buff_oob_enable));
949 }
950
CreateInstDebugPrintfPass(uint32_t desc_set,uint32_t shader_id)951 Optimizer::PassToken CreateInstDebugPrintfPass(uint32_t desc_set,
952 uint32_t shader_id) {
953 return MakeUnique<Optimizer::PassToken::Impl>(
954 MakeUnique<opt::InstDebugPrintfPass>(desc_set, shader_id));
955 }
956
CreateInstBuffAddrCheckPass(uint32_t desc_set,uint32_t shader_id)957 Optimizer::PassToken CreateInstBuffAddrCheckPass(uint32_t desc_set,
958 uint32_t shader_id) {
959 return MakeUnique<Optimizer::PassToken::Impl>(
960 MakeUnique<opt::InstBuffAddrCheckPass>(desc_set, shader_id));
961 }
962
CreateConvertRelaxedToHalfPass()963 Optimizer::PassToken CreateConvertRelaxedToHalfPass() {
964 return MakeUnique<Optimizer::PassToken::Impl>(
965 MakeUnique<opt::ConvertToHalfPass>());
966 }
967
CreateRelaxFloatOpsPass()968 Optimizer::PassToken CreateRelaxFloatOpsPass() {
969 return MakeUnique<Optimizer::PassToken::Impl>(
970 MakeUnique<opt::RelaxFloatOpsPass>());
971 }
972
CreateCodeSinkingPass()973 Optimizer::PassToken CreateCodeSinkingPass() {
974 return MakeUnique<Optimizer::PassToken::Impl>(
975 MakeUnique<opt::CodeSinkingPass>());
976 }
977
CreateFixStorageClassPass()978 Optimizer::PassToken CreateFixStorageClassPass() {
979 return MakeUnique<Optimizer::PassToken::Impl>(
980 MakeUnique<opt::FixStorageClass>());
981 }
982
CreateGraphicsRobustAccessPass()983 Optimizer::PassToken CreateGraphicsRobustAccessPass() {
984 return MakeUnique<Optimizer::PassToken::Impl>(
985 MakeUnique<opt::GraphicsRobustAccessPass>());
986 }
987
CreateReplaceDescArrayAccessUsingVarIndexPass()988 Optimizer::PassToken CreateReplaceDescArrayAccessUsingVarIndexPass() {
989 return MakeUnique<Optimizer::PassToken::Impl>(
990 MakeUnique<opt::ReplaceDescArrayAccessUsingVarIndex>());
991 }
992
CreateSpreadVolatileSemanticsPass()993 Optimizer::PassToken CreateSpreadVolatileSemanticsPass() {
994 return MakeUnique<Optimizer::PassToken::Impl>(
995 MakeUnique<opt::SpreadVolatileSemantics>());
996 }
997
CreateDescriptorScalarReplacementPass()998 Optimizer::PassToken CreateDescriptorScalarReplacementPass() {
999 return MakeUnique<Optimizer::PassToken::Impl>(
1000 MakeUnique<opt::DescriptorScalarReplacement>());
1001 }
1002
CreateWrapOpKillPass()1003 Optimizer::PassToken CreateWrapOpKillPass() {
1004 return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::WrapOpKill>());
1005 }
1006
CreateAmdExtToKhrPass()1007 Optimizer::PassToken CreateAmdExtToKhrPass() {
1008 return MakeUnique<Optimizer::PassToken::Impl>(
1009 MakeUnique<opt::AmdExtensionToKhrPass>());
1010 }
1011
CreateInterpolateFixupPass()1012 Optimizer::PassToken CreateInterpolateFixupPass() {
1013 return MakeUnique<Optimizer::PassToken::Impl>(
1014 MakeUnique<opt::InterpFixupPass>());
1015 }
1016
CreateEliminateDeadInputComponentsPass()1017 Optimizer::PassToken CreateEliminateDeadInputComponentsPass() {
1018 return MakeUnique<Optimizer::PassToken::Impl>(
1019 MakeUnique<opt::EliminateDeadInputComponentsPass>());
1020 }
1021
CreateConvertToSampledImagePass(const std::vector<opt::DescriptorSetAndBinding> & descriptor_set_binding_pairs)1022 Optimizer::PassToken CreateConvertToSampledImagePass(
1023 const std::vector<opt::DescriptorSetAndBinding>&
1024 descriptor_set_binding_pairs) {
1025 return MakeUnique<Optimizer::PassToken::Impl>(
1026 MakeUnique<opt::ConvertToSampledImagePass>(descriptor_set_binding_pairs));
1027 }
1028
CreateInterfaceVariableScalarReplacementPass()1029 Optimizer::PassToken CreateInterfaceVariableScalarReplacementPass() {
1030 return MakeUnique<Optimizer::PassToken::Impl>(
1031 MakeUnique<opt::InterfaceVariableScalarReplacement>());
1032 }
1033
CreateRemoveDontInlinePass()1034 Optimizer::PassToken CreateRemoveDontInlinePass() {
1035 return MakeUnique<Optimizer::PassToken::Impl>(
1036 MakeUnique<opt::RemoveDontInline>());
1037 }
1038
CreateFixFuncCallArgumentsPass()1039 Optimizer::PassToken CreateFixFuncCallArgumentsPass() {
1040 return MakeUnique<Optimizer::PassToken::Impl>(
1041 MakeUnique<opt::FixFuncCallArgumentsPass>());
1042 }
1043 } // namespace spvtools
1044