blob: 8828c707875e45ae2474f44ff18fc4ec5f667b69 [file] [log] [blame]
Chris Forbescc5697f2019-01-30 11:54:08 -08001// Copyright (c) 2016 Google Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include "spirv-tools/optimizer.hpp"
16
Ben Claytond0f684e2019-08-30 22:36:08 +010017#include <cassert>
Chris Forbescc5697f2019-01-30 11:54:08 -080018#include <memory>
19#include <string>
20#include <unordered_map>
21#include <utility>
22#include <vector>
23
Chris Forbescc5697f2019-01-30 11:54:08 -080024#include "source/opt/build_module.h"
Ben Claytond0f684e2019-08-30 22:36:08 +010025#include "source/opt/graphics_robust_access_pass.h"
Chris Forbescc5697f2019-01-30 11:54:08 -080026#include "source/opt/log.h"
27#include "source/opt/pass_manager.h"
28#include "source/opt/passes.h"
Ben Claytond552f632019-11-18 11:18:41 +000029#include "source/spirv_optimizer_options.h"
Chris Forbescc5697f2019-01-30 11:54:08 -080030#include "source/util/make_unique.h"
31#include "source/util/string_utils.h"
32
33namespace spvtools {
34
35struct Optimizer::PassToken::Impl {
36 Impl(std::unique_ptr<opt::Pass> p) : pass(std::move(p)) {}
37
38 std::unique_ptr<opt::Pass> pass; // Internal implementation pass.
39};
40
41Optimizer::PassToken::PassToken(
42 std::unique_ptr<Optimizer::PassToken::Impl> impl)
43 : impl_(std::move(impl)) {}
44
45Optimizer::PassToken::PassToken(std::unique_ptr<opt::Pass>&& pass)
46 : impl_(MakeUnique<Optimizer::PassToken::Impl>(std::move(pass))) {}
47
48Optimizer::PassToken::PassToken(PassToken&& that)
49 : impl_(std::move(that.impl_)) {}
50
51Optimizer::PassToken& Optimizer::PassToken::operator=(PassToken&& that) {
52 impl_ = std::move(that.impl_);
53 return *this;
54}
55
56Optimizer::PassToken::~PassToken() {}
57
58struct Optimizer::Impl {
59 explicit Impl(spv_target_env env) : target_env(env), pass_manager() {}
60
Ben Claytonb73b7602019-07-29 13:56:13 +010061 spv_target_env target_env; // Target environment.
62 opt::PassManager pass_manager; // Internal implementation pass manager.
Nicolas Capens84c9c452022-11-18 14:11:05 +000063 std::unordered_set<uint32_t> live_locs; // Arg to debug dead output passes
Chris Forbescc5697f2019-01-30 11:54:08 -080064};
65
Ben Clayton745997b2021-01-21 22:51:51 +000066Optimizer::Optimizer(spv_target_env env) : impl_(new Impl(env)) {
67 assert(env != SPV_ENV_WEBGPU_0);
68}
Chris Forbescc5697f2019-01-30 11:54:08 -080069
70Optimizer::~Optimizer() {}
71
72void Optimizer::SetMessageConsumer(MessageConsumer c) {
73 // All passes' message consumer needs to be updated.
74 for (uint32_t i = 0; i < impl_->pass_manager.NumPasses(); ++i) {
75 impl_->pass_manager.GetPass(i)->SetMessageConsumer(c);
76 }
77 impl_->pass_manager.SetMessageConsumer(std::move(c));
78}
79
80const MessageConsumer& Optimizer::consumer() const {
81 return impl_->pass_manager.consumer();
82}
83
84Optimizer& Optimizer::RegisterPass(PassToken&& p) {
85 // Change to use the pass manager's consumer.
86 p.impl_->pass->SetMessageConsumer(consumer());
87 impl_->pass_manager.AddPass(std::move(p.impl_->pass));
88 return *this;
89}
90
91// The legalization passes take a spir-v shader generated by an HLSL front-end
92// and turn it into a valid vulkan spir-v shader. There are two ways in which
93// the code will be invalid at the start:
94//
95// 1) There will be opaque objects, like images, which will be passed around
96// in intermediate objects. Valid spir-v will have to replace the use of
97// the opaque object with an intermediate object that is the result of the
98// load of the global opaque object.
99//
100// 2) There will be variables that contain pointers to structured or uniform
101// buffers. It be legal, the variables must be eliminated, and the
102// references to the structured buffers must use the result of OpVariable
103// in the Uniform storage class.
104//
105// Optimization in this list must accept shaders with these relaxation of the
106// rules. There is not guarantee that this list of optimizations is able to
107// legalize all inputs, but it is on a best effort basis.
108//
109// The legalization problem is essentially a very general copy propagation
110// problem. The optimization we use are all used to either do copy propagation
111// or enable more copy propagation.
112Optimizer& Optimizer::RegisterLegalizationPasses() {
113 return
Ben Claytond0f684e2019-08-30 22:36:08 +0100114 // Wrap OpKill instructions so all other code can be inlined.
115 RegisterPass(CreateWrapOpKillPass())
116 // Remove unreachable block so that merge return works.
117 .RegisterPass(CreateDeadBranchElimPass())
Chris Forbescc5697f2019-01-30 11:54:08 -0800118 // Merge the returns so we can inline.
119 .RegisterPass(CreateMergeReturnPass())
120 // Make sure uses and definitions are in the same function.
121 .RegisterPass(CreateInlineExhaustivePass())
122 // Make private variable function scope
123 .RegisterPass(CreateEliminateDeadFunctionsPass())
124 .RegisterPass(CreatePrivateToLocalPass())
Ben Claytonb73b7602019-07-29 13:56:13 +0100125 // Fix up the storage classes that DXC may have purposely generated
126 // incorrectly. All functions are inlined, and a lot of dead code has
127 // been removed.
128 .RegisterPass(CreateFixStorageClassPass())
Chris Forbescc5697f2019-01-30 11:54:08 -0800129 // Propagate the value stored to the loads in very simple cases.
130 .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass())
131 .RegisterPass(CreateLocalSingleStoreElimPass())
132 .RegisterPass(CreateAggressiveDCEPass())
133 // Split up aggregates so they are easier to deal with.
134 .RegisterPass(CreateScalarReplacementPass(0))
135 // Remove loads and stores so everything is in intermediate values.
136 // Takes care of copy propagation of non-members.
137 .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass())
138 .RegisterPass(CreateLocalSingleStoreElimPass())
139 .RegisterPass(CreateAggressiveDCEPass())
140 .RegisterPass(CreateLocalMultiStoreElimPass())
141 .RegisterPass(CreateAggressiveDCEPass())
142 // Propagate constants to get as many constant conditions on branches
143 // as possible.
144 .RegisterPass(CreateCCPPass())
145 .RegisterPass(CreateLoopUnrollPass(true))
146 .RegisterPass(CreateDeadBranchElimPass())
147 // Copy propagate members. Cleans up code sequences generated by
148 // scalar replacement. Also important for removing OpPhi nodes.
149 .RegisterPass(CreateSimplificationPass())
150 .RegisterPass(CreateAggressiveDCEPass())
151 .RegisterPass(CreateCopyPropagateArraysPass())
152 // May need loop unrolling here see
153 // https://github.com/Microsoft/DirectXShaderCompiler/pull/930
154 // Get rid of unused code that contain traces of illegal code
155 // or unused references to unbound external objects
156 .RegisterPass(CreateVectorDCEPass())
157 .RegisterPass(CreateDeadInsertElimPass())
158 .RegisterPass(CreateReduceLoadSizePass())
Alexis Hetu00e0af12021-11-08 08:57:46 -0500159 .RegisterPass(CreateAggressiveDCEPass())
160 .RegisterPass(CreateInterpolateFixupPass());
Chris Forbescc5697f2019-01-30 11:54:08 -0800161}
162
163Optimizer& Optimizer::RegisterPerformancePasses() {
Ben Claytond0f684e2019-08-30 22:36:08 +0100164 return RegisterPass(CreateWrapOpKillPass())
165 .RegisterPass(CreateDeadBranchElimPass())
Chris Forbescc5697f2019-01-30 11:54:08 -0800166 .RegisterPass(CreateMergeReturnPass())
167 .RegisterPass(CreateInlineExhaustivePass())
Sean Risserd2283f82020-11-05 14:17:31 -0500168 .RegisterPass(CreateEliminateDeadFunctionsPass())
Chris Forbescc5697f2019-01-30 11:54:08 -0800169 .RegisterPass(CreateAggressiveDCEPass())
170 .RegisterPass(CreatePrivateToLocalPass())
171 .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass())
172 .RegisterPass(CreateLocalSingleStoreElimPass())
173 .RegisterPass(CreateAggressiveDCEPass())
174 .RegisterPass(CreateScalarReplacementPass())
175 .RegisterPass(CreateLocalAccessChainConvertPass())
176 .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass())
177 .RegisterPass(CreateLocalSingleStoreElimPass())
178 .RegisterPass(CreateAggressiveDCEPass())
179 .RegisterPass(CreateLocalMultiStoreElimPass())
180 .RegisterPass(CreateAggressiveDCEPass())
181 .RegisterPass(CreateCCPPass())
182 .RegisterPass(CreateAggressiveDCEPass())
Ben Clayton38e46912020-05-26 15:56:15 +0100183 .RegisterPass(CreateLoopUnrollPass(true))
184 .RegisterPass(CreateDeadBranchElimPass())
Chris Forbescc5697f2019-01-30 11:54:08 -0800185 .RegisterPass(CreateRedundancyEliminationPass())
186 .RegisterPass(CreateCombineAccessChainsPass())
187 .RegisterPass(CreateSimplificationPass())
Ben Clayton38e46912020-05-26 15:56:15 +0100188 .RegisterPass(CreateScalarReplacementPass())
189 .RegisterPass(CreateLocalAccessChainConvertPass())
190 .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass())
191 .RegisterPass(CreateLocalSingleStoreElimPass())
192 .RegisterPass(CreateAggressiveDCEPass())
193 .RegisterPass(CreateSSARewritePass())
194 .RegisterPass(CreateAggressiveDCEPass())
Chris Forbescc5697f2019-01-30 11:54:08 -0800195 .RegisterPass(CreateVectorDCEPass())
196 .RegisterPass(CreateDeadInsertElimPass())
197 .RegisterPass(CreateDeadBranchElimPass())
198 .RegisterPass(CreateSimplificationPass())
199 .RegisterPass(CreateIfConversionPass())
200 .RegisterPass(CreateCopyPropagateArraysPass())
201 .RegisterPass(CreateReduceLoadSizePass())
202 .RegisterPass(CreateAggressiveDCEPass())
203 .RegisterPass(CreateBlockMergePass())
204 .RegisterPass(CreateRedundancyEliminationPass())
205 .RegisterPass(CreateDeadBranchElimPass())
206 .RegisterPass(CreateBlockMergePass())
Ben Claytonb73b7602019-07-29 13:56:13 +0100207 .RegisterPass(CreateSimplificationPass());
Chris Forbescc5697f2019-01-30 11:54:08 -0800208}
209
210Optimizer& Optimizer::RegisterSizePasses() {
Ben Claytond0f684e2019-08-30 22:36:08 +0100211 return RegisterPass(CreateWrapOpKillPass())
212 .RegisterPass(CreateDeadBranchElimPass())
Chris Forbescc5697f2019-01-30 11:54:08 -0800213 .RegisterPass(CreateMergeReturnPass())
214 .RegisterPass(CreateInlineExhaustivePass())
Ben Clayton0b54f132020-01-06 13:38:54 +0000215 .RegisterPass(CreateEliminateDeadFunctionsPass())
Chris Forbescc5697f2019-01-30 11:54:08 -0800216 .RegisterPass(CreatePrivateToLocalPass())
Ben Clayton0b54f132020-01-06 13:38:54 +0000217 .RegisterPass(CreateScalarReplacementPass(0))
Chris Forbescc5697f2019-01-30 11:54:08 -0800218 .RegisterPass(CreateLocalMultiStoreElimPass())
Chris Forbescc5697f2019-01-30 11:54:08 -0800219 .RegisterPass(CreateCCPPass())
Ben Clayton0b54f132020-01-06 13:38:54 +0000220 .RegisterPass(CreateLoopUnrollPass(true))
221 .RegisterPass(CreateDeadBranchElimPass())
222 .RegisterPass(CreateSimplificationPass())
223 .RegisterPass(CreateScalarReplacementPass(0))
224 .RegisterPass(CreateLocalSingleStoreElimPass())
225 .RegisterPass(CreateIfConversionPass())
226 .RegisterPass(CreateSimplificationPass())
Chris Forbescc5697f2019-01-30 11:54:08 -0800227 .RegisterPass(CreateAggressiveDCEPass())
228 .RegisterPass(CreateDeadBranchElimPass())
Chris Forbescc5697f2019-01-30 11:54:08 -0800229 .RegisterPass(CreateBlockMergePass())
Ben Clayton0b54f132020-01-06 13:38:54 +0000230 .RegisterPass(CreateLocalAccessChainConvertPass())
231 .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass())
232 .RegisterPass(CreateAggressiveDCEPass())
233 .RegisterPass(CreateCopyPropagateArraysPass())
234 .RegisterPass(CreateVectorDCEPass())
Chris Forbescc5697f2019-01-30 11:54:08 -0800235 .RegisterPass(CreateDeadInsertElimPass())
Ben Clayton0b54f132020-01-06 13:38:54 +0000236 .RegisterPass(CreateEliminateDeadMembersPass())
237 .RegisterPass(CreateLocalSingleStoreElimPass())
238 .RegisterPass(CreateBlockMergePass())
239 .RegisterPass(CreateLocalMultiStoreElimPass())
Chris Forbescc5697f2019-01-30 11:54:08 -0800240 .RegisterPass(CreateRedundancyEliminationPass())
Ben Clayton0b54f132020-01-06 13:38:54 +0000241 .RegisterPass(CreateSimplificationPass())
242 .RegisterPass(CreateAggressiveDCEPass())
243 .RegisterPass(CreateCFGCleanupPass());
Chris Forbescc5697f2019-01-30 11:54:08 -0800244}
245
Chris Forbescc5697f2019-01-30 11:54:08 -0800246bool Optimizer::RegisterPassesFromFlags(const std::vector<std::string>& flags) {
247 for (const auto& flag : flags) {
248 if (!RegisterPassFromFlag(flag)) {
249 return false;
250 }
251 }
252
253 return true;
254}
255
256bool Optimizer::FlagHasValidForm(const std::string& flag) const {
257 if (flag == "-O" || flag == "-Os") {
258 return true;
259 } else if (flag.size() > 2 && flag.substr(0, 2) == "--") {
260 return true;
261 }
262
263 Errorf(consumer(), nullptr, {},
264 "%s is not a valid flag. Flag passes should have the form "
265 "'--pass_name[=pass_args]'. Special flag names also accepted: -O "
266 "and -Os.",
267 flag.c_str());
268 return false;
269}
270
271bool Optimizer::RegisterPassFromFlag(const std::string& flag) {
272 if (!FlagHasValidForm(flag)) {
273 return false;
274 }
275
276 // Split flags of the form --pass_name=pass_args.
277 auto p = utils::SplitFlagArgs(flag);
278 std::string pass_name = p.first;
279 std::string pass_args = p.second;
280
281 // FIXME(dnovillo): This should be re-factored so that pass names can be
282 // automatically checked against Pass::name() and PassToken instances created
283 // via a template function. Additionally, class Pass should have a desc()
284 // method that describes the pass (so it can be used in --help).
285 //
286 // Both Pass::name() and Pass::desc() should be static class members so they
287 // can be invoked without creating a pass instance.
Ben Clayton745997b2021-01-21 22:51:51 +0000288 if (pass_name == "strip-debug") {
Chris Forbescc5697f2019-01-30 11:54:08 -0800289 RegisterPass(CreateStripDebugInfoPass());
290 } else if (pass_name == "strip-reflect") {
291 RegisterPass(CreateStripReflectInfoPass());
sugoi1b398bf32022-02-18 10:27:28 -0500292 } else if (pass_name == "strip-nonsemantic") {
293 RegisterPass(CreateStripNonSemanticInfoPass());
Chris Forbescc5697f2019-01-30 11:54:08 -0800294 } else if (pass_name == "set-spec-const-default-value") {
295 if (pass_args.size() > 0) {
296 auto spec_ids_vals =
297 opt::SetSpecConstantDefaultValuePass::ParseDefaultValuesString(
298 pass_args.c_str());
299 if (!spec_ids_vals) {
300 Errorf(consumer(), nullptr, {},
301 "Invalid argument for --set-spec-const-default-value: %s",
302 pass_args.c_str());
303 return false;
304 }
305 RegisterPass(
306 CreateSetSpecConstantDefaultValuePass(std::move(*spec_ids_vals)));
307 } else {
308 Errorf(consumer(), nullptr, {},
309 "Invalid spec constant value string '%s'. Expected a string of "
310 "<spec id>:<default value> pairs.",
311 pass_args.c_str());
312 return false;
313 }
314 } else if (pass_name == "if-conversion") {
315 RegisterPass(CreateIfConversionPass());
316 } else if (pass_name == "freeze-spec-const") {
317 RegisterPass(CreateFreezeSpecConstantValuePass());
318 } else if (pass_name == "inline-entry-points-exhaustive") {
319 RegisterPass(CreateInlineExhaustivePass());
320 } else if (pass_name == "inline-entry-points-opaque") {
321 RegisterPass(CreateInlineOpaquePass());
322 } else if (pass_name == "combine-access-chains") {
323 RegisterPass(CreateCombineAccessChainsPass());
324 } else if (pass_name == "convert-local-access-chains") {
325 RegisterPass(CreateLocalAccessChainConvertPass());
Alexis Hetu00e0af12021-11-08 08:57:46 -0500326 } else if (pass_name == "replace-desc-array-access-using-var-index") {
327 RegisterPass(CreateReplaceDescArrayAccessUsingVarIndexPass());
sugoi1b398bf32022-02-18 10:27:28 -0500328 } else if (pass_name == "spread-volatile-semantics") {
329 RegisterPass(CreateSpreadVolatileSemanticsPass());
Ben Claytond0f684e2019-08-30 22:36:08 +0100330 } else if (pass_name == "descriptor-scalar-replacement") {
331 RegisterPass(CreateDescriptorScalarReplacementPass());
Chris Forbescc5697f2019-01-30 11:54:08 -0800332 } else if (pass_name == "eliminate-dead-code-aggressive") {
333 RegisterPass(CreateAggressiveDCEPass());
Chris Forbescc5697f2019-01-30 11:54:08 -0800334 } else if (pass_name == "eliminate-insert-extract") {
335 RegisterPass(CreateInsertExtractElimPass());
336 } else if (pass_name == "eliminate-local-single-block") {
337 RegisterPass(CreateLocalSingleBlockLoadStoreElimPass());
338 } else if (pass_name == "eliminate-local-single-store") {
339 RegisterPass(CreateLocalSingleStoreElimPass());
340 } else if (pass_name == "merge-blocks") {
341 RegisterPass(CreateBlockMergePass());
342 } else if (pass_name == "merge-return") {
343 RegisterPass(CreateMergeReturnPass());
344 } else if (pass_name == "eliminate-dead-branches") {
345 RegisterPass(CreateDeadBranchElimPass());
346 } else if (pass_name == "eliminate-dead-functions") {
347 RegisterPass(CreateEliminateDeadFunctionsPass());
348 } else if (pass_name == "eliminate-local-multi-store") {
349 RegisterPass(CreateLocalMultiStoreElimPass());
Chris Forbescc5697f2019-01-30 11:54:08 -0800350 } else if (pass_name == "eliminate-dead-const") {
351 RegisterPass(CreateEliminateDeadConstantPass());
352 } else if (pass_name == "eliminate-dead-inserts") {
353 RegisterPass(CreateDeadInsertElimPass());
354 } else if (pass_name == "eliminate-dead-variables") {
355 RegisterPass(CreateDeadVariableEliminationPass());
Ben Claytonb73b7602019-07-29 13:56:13 +0100356 } else if (pass_name == "eliminate-dead-members") {
357 RegisterPass(CreateEliminateDeadMembersPass());
Chris Forbescc5697f2019-01-30 11:54:08 -0800358 } else if (pass_name == "fold-spec-const-op-composite") {
359 RegisterPass(CreateFoldSpecConstantOpAndCompositePass());
360 } else if (pass_name == "loop-unswitch") {
361 RegisterPass(CreateLoopUnswitchPass());
362 } else if (pass_name == "scalar-replacement") {
363 if (pass_args.size() == 0) {
364 RegisterPass(CreateScalarReplacementPass());
365 } else {
366 int limit = -1;
367 if (pass_args.find_first_not_of("0123456789") == std::string::npos) {
368 limit = atoi(pass_args.c_str());
369 }
370
371 if (limit >= 0) {
372 RegisterPass(CreateScalarReplacementPass(limit));
373 } else {
374 Error(consumer(), nullptr, {},
375 "--scalar-replacement must have no arguments or a non-negative "
376 "integer argument");
377 return false;
378 }
379 }
380 } else if (pass_name == "strength-reduction") {
381 RegisterPass(CreateStrengthReductionPass());
382 } else if (pass_name == "unify-const") {
383 RegisterPass(CreateUnifyConstantPass());
384 } else if (pass_name == "flatten-decorations") {
385 RegisterPass(CreateFlattenDecorationPass());
386 } else if (pass_name == "compact-ids") {
387 RegisterPass(CreateCompactIdsPass());
388 } else if (pass_name == "cfg-cleanup") {
389 RegisterPass(CreateCFGCleanupPass());
390 } else if (pass_name == "local-redundancy-elimination") {
391 RegisterPass(CreateLocalRedundancyEliminationPass());
392 } else if (pass_name == "loop-invariant-code-motion") {
393 RegisterPass(CreateLoopInvariantCodeMotionPass());
394 } else if (pass_name == "reduce-load-size") {
Alexis Hetu00e0af12021-11-08 08:57:46 -0500395 if (pass_args.size() == 0) {
396 RegisterPass(CreateReduceLoadSizePass());
397 } else {
398 double load_replacement_threshold = 0.9;
399 if (pass_args.find_first_not_of(".0123456789") == std::string::npos) {
400 load_replacement_threshold = atof(pass_args.c_str());
401 }
402
403 if (load_replacement_threshold >= 0) {
404 RegisterPass(CreateReduceLoadSizePass(load_replacement_threshold));
405 } else {
406 Error(consumer(), nullptr, {},
407 "--reduce-load-size must have no arguments or a non-negative "
408 "double argument");
409 return false;
410 }
411 }
Chris Forbescc5697f2019-01-30 11:54:08 -0800412 } else if (pass_name == "redundancy-elimination") {
413 RegisterPass(CreateRedundancyEliminationPass());
414 } else if (pass_name == "private-to-local") {
415 RegisterPass(CreatePrivateToLocalPass());
416 } else if (pass_name == "remove-duplicates") {
417 RegisterPass(CreateRemoveDuplicatesPass());
418 } else if (pass_name == "workaround-1209") {
419 RegisterPass(CreateWorkaround1209Pass());
420 } else if (pass_name == "replace-invalid-opcode") {
421 RegisterPass(CreateReplaceInvalidOpcodePass());
422 } else if (pass_name == "inst-bindless-check") {
Ben Clayton38e46912020-05-26 15:56:15 +0100423 RegisterPass(CreateInstBindlessCheckPass(7, 23, false, false));
Chris Forbescc5697f2019-01-30 11:54:08 -0800424 RegisterPass(CreateSimplificationPass());
425 RegisterPass(CreateDeadBranchElimPass());
426 RegisterPass(CreateBlockMergePass());
Alexis Hetu00e0af12021-11-08 08:57:46 -0500427 RegisterPass(CreateAggressiveDCEPass(true));
Ben Claytond0f684e2019-08-30 22:36:08 +0100428 } else if (pass_name == "inst-desc-idx-check") {
Ben Clayton38e46912020-05-26 15:56:15 +0100429 RegisterPass(CreateInstBindlessCheckPass(7, 23, true, true));
Ben Claytond0f684e2019-08-30 22:36:08 +0100430 RegisterPass(CreateSimplificationPass());
431 RegisterPass(CreateDeadBranchElimPass());
432 RegisterPass(CreateBlockMergePass());
Alexis Hetu00e0af12021-11-08 08:57:46 -0500433 RegisterPass(CreateAggressiveDCEPass(true));
Alexis Hetu3eb4dd82020-10-29 21:37:20 -0400434 } else if (pass_name == "inst-buff-oob-check") {
Ben Clayton745997b2021-01-21 22:51:51 +0000435 RegisterPass(CreateInstBindlessCheckPass(7, 23, false, false, true, true));
Alexis Hetu3eb4dd82020-10-29 21:37:20 -0400436 RegisterPass(CreateSimplificationPass());
437 RegisterPass(CreateDeadBranchElimPass());
438 RegisterPass(CreateBlockMergePass());
Alexis Hetu00e0af12021-11-08 08:57:46 -0500439 RegisterPass(CreateAggressiveDCEPass(true));
Ben Claytond0f684e2019-08-30 22:36:08 +0100440 } else if (pass_name == "inst-buff-addr-check") {
Ben Clayton38e46912020-05-26 15:56:15 +0100441 RegisterPass(CreateInstBuffAddrCheckPass(7, 23));
Alexis Hetu00e0af12021-11-08 08:57:46 -0500442 RegisterPass(CreateAggressiveDCEPass(true));
Ben Claytond552f632019-11-18 11:18:41 +0000443 } else if (pass_name == "convert-relaxed-to-half") {
444 RegisterPass(CreateConvertRelaxedToHalfPass());
445 } else if (pass_name == "relax-float-ops") {
446 RegisterPass(CreateRelaxFloatOpsPass());
Alexis Hetub8a77462020-03-27 07:59:09 -0400447 } else if (pass_name == "inst-debug-printf") {
448 RegisterPass(CreateInstDebugPrintfPass(7, 23));
Chris Forbescc5697f2019-01-30 11:54:08 -0800449 } else if (pass_name == "simplify-instructions") {
450 RegisterPass(CreateSimplificationPass());
451 } else if (pass_name == "ssa-rewrite") {
452 RegisterPass(CreateSSARewritePass());
453 } else if (pass_name == "copy-propagate-arrays") {
454 RegisterPass(CreateCopyPropagateArraysPass());
455 } else if (pass_name == "loop-fission") {
456 int register_threshold_to_split =
457 (pass_args.size() > 0) ? atoi(pass_args.c_str()) : -1;
458 if (register_threshold_to_split > 0) {
459 RegisterPass(CreateLoopFissionPass(
460 static_cast<size_t>(register_threshold_to_split)));
461 } else {
462 Error(consumer(), nullptr, {},
463 "--loop-fission must have a positive integer argument");
464 return false;
465 }
466 } else if (pass_name == "loop-fusion") {
467 int max_registers_per_loop =
468 (pass_args.size() > 0) ? atoi(pass_args.c_str()) : -1;
469 if (max_registers_per_loop > 0) {
470 RegisterPass(
471 CreateLoopFusionPass(static_cast<size_t>(max_registers_per_loop)));
472 } else {
473 Error(consumer(), nullptr, {},
474 "--loop-fusion must have a positive integer argument");
475 return false;
476 }
477 } else if (pass_name == "loop-unroll") {
478 RegisterPass(CreateLoopUnrollPass(true));
479 } else if (pass_name == "upgrade-memory-model") {
480 RegisterPass(CreateUpgradeMemoryModelPass());
481 } else if (pass_name == "vector-dce") {
482 RegisterPass(CreateVectorDCEPass());
483 } else if (pass_name == "loop-unroll-partial") {
484 int factor = (pass_args.size() > 0) ? atoi(pass_args.c_str()) : 0;
485 if (factor > 0) {
486 RegisterPass(CreateLoopUnrollPass(false, factor));
487 } else {
488 Error(consumer(), nullptr, {},
489 "--loop-unroll-partial must have a positive integer argument");
490 return false;
491 }
492 } else if (pass_name == "loop-peeling") {
493 RegisterPass(CreateLoopPeelingPass());
494 } else if (pass_name == "loop-peeling-threshold") {
495 int factor = (pass_args.size() > 0) ? atoi(pass_args.c_str()) : 0;
496 if (factor > 0) {
497 opt::LoopPeelingPass::SetLoopPeelingThreshold(factor);
498 } else {
499 Error(consumer(), nullptr, {},
500 "--loop-peeling-threshold must have a positive integer argument");
501 return false;
502 }
503 } else if (pass_name == "ccp") {
504 RegisterPass(CreateCCPPass());
505 } else if (pass_name == "code-sink") {
506 RegisterPass(CreateCodeSinkingPass());
Ben Claytonb73b7602019-07-29 13:56:13 +0100507 } else if (pass_name == "fix-storage-class") {
508 RegisterPass(CreateFixStorageClassPass());
Chris Forbescc5697f2019-01-30 11:54:08 -0800509 } else if (pass_name == "O") {
510 RegisterPerformancePasses();
511 } else if (pass_name == "Os") {
512 RegisterSizePasses();
513 } else if (pass_name == "legalize-hlsl") {
514 RegisterLegalizationPasses();
Alexis Hetu00e0af12021-11-08 08:57:46 -0500515 } else if (pass_name == "remove-unused-interface-variables") {
516 RegisterPass(CreateRemoveUnusedInterfaceVariablesPass());
Ben Claytond0f684e2019-08-30 22:36:08 +0100517 } else if (pass_name == "graphics-robust-access") {
518 RegisterPass(CreateGraphicsRobustAccessPass());
519 } else if (pass_name == "wrap-opkill") {
520 RegisterPass(CreateWrapOpKillPass());
521 } else if (pass_name == "amd-ext-to-khr") {
522 RegisterPass(CreateAmdExtToKhrPass());
Alexis Hetu00e0af12021-11-08 08:57:46 -0500523 } else if (pass_name == "interpolate-fixup") {
524 RegisterPass(CreateInterpolateFixupPass());
Nicolas Capens9cbc5e22022-03-08 13:03:25 -0500525 } else if (pass_name == "remove-dont-inline") {
526 RegisterPass(CreateRemoveDontInlinePass());
Nicolas Capens4111ae92022-03-23 12:23:11 -0400527 } else if (pass_name == "eliminate-dead-input-components") {
Nicolas Capens84c9c452022-11-18 14:11:05 +0000528 RegisterPass(CreateEliminateDeadInputComponentsSafePass());
Nicolas Capens9d252072022-05-26 17:20:50 -0400529 } else if (pass_name == "fix-func-call-param") {
530 RegisterPass(CreateFixFuncCallArgumentsPass());
Alexis Hetu00e0af12021-11-08 08:57:46 -0500531 } else if (pass_name == "convert-to-sampled-image") {
532 if (pass_args.size() > 0) {
533 auto descriptor_set_binding_pairs =
534 opt::ConvertToSampledImagePass::ParseDescriptorSetBindingPairsString(
535 pass_args.c_str());
536 if (!descriptor_set_binding_pairs) {
537 Errorf(consumer(), nullptr, {},
538 "Invalid argument for --convert-to-sampled-image: %s",
539 pass_args.c_str());
540 return false;
541 }
542 RegisterPass(CreateConvertToSampledImagePass(
543 std::move(*descriptor_set_binding_pairs)));
544 } else {
545 Errorf(consumer(), nullptr, {},
546 "Invalid pairs of descriptor set and binding '%s'. Expected a "
547 "string of <descriptor set>:<binding> pairs.",
548 pass_args.c_str());
549 return false;
550 }
Chris Forbescc5697f2019-01-30 11:54:08 -0800551 } else {
552 Errorf(consumer(), nullptr, {},
553 "Unknown flag '--%s'. Use --help for a list of valid flags",
554 pass_name.c_str());
555 return false;
556 }
557
558 return true;
559}
560
561void Optimizer::SetTargetEnv(const spv_target_env env) {
562 impl_->target_env = env;
563}
564
565bool Optimizer::Run(const uint32_t* original_binary,
566 const size_t original_binary_size,
567 std::vector<uint32_t>* optimized_binary) const {
568 return Run(original_binary, original_binary_size, optimized_binary,
569 OptimizerOptions());
570}
571
572bool Optimizer::Run(const uint32_t* original_binary,
573 const size_t original_binary_size,
574 std::vector<uint32_t>* optimized_binary,
575 const ValidatorOptions& validator_options,
576 bool skip_validation) const {
577 OptimizerOptions opt_options;
578 opt_options.set_run_validator(!skip_validation);
579 opt_options.set_validator_options(validator_options);
580 return Run(original_binary, original_binary_size, optimized_binary,
581 opt_options);
582}
583
584bool Optimizer::Run(const uint32_t* original_binary,
585 const size_t original_binary_size,
586 std::vector<uint32_t>* optimized_binary,
587 const spv_optimizer_options opt_options) const {
588 spvtools::SpirvTools tools(impl_->target_env);
589 tools.SetMessageConsumer(impl_->pass_manager.consumer());
590 if (opt_options->run_validator_ &&
591 !tools.Validate(original_binary, original_binary_size,
592 &opt_options->val_options_)) {
593 return false;
594 }
595
596 std::unique_ptr<opt::IRContext> context = BuildModule(
597 impl_->target_env, consumer(), original_binary, original_binary_size);
598 if (context == nullptr) return false;
599
600 context->set_max_id_bound(opt_options->max_id_bound_);
Ben Claytonb73b7602019-07-29 13:56:13 +0100601 context->set_preserve_bindings(opt_options->preserve_bindings_);
602 context->set_preserve_spec_constants(opt_options->preserve_spec_constants_);
Chris Forbescc5697f2019-01-30 11:54:08 -0800603
Ben Claytonb73b7602019-07-29 13:56:13 +0100604 impl_->pass_manager.SetValidatorOptions(&opt_options->val_options_);
605 impl_->pass_manager.SetTargetEnv(impl_->target_env);
Chris Forbescc5697f2019-01-30 11:54:08 -0800606 auto status = impl_->pass_manager.Run(context.get());
Ben Claytonb73b7602019-07-29 13:56:13 +0100607
Ben Claytond0f684e2019-08-30 22:36:08 +0100608 if (status == opt::Pass::Status::Failure) {
609 return false;
Ben Claytonb73b7602019-07-29 13:56:13 +0100610 }
611
Ben Claytond0f684e2019-08-30 22:36:08 +0100612#ifndef NDEBUG
Alexis Hetub8a77462020-03-27 07:59:09 -0400613 // We do not keep the result id of DebugScope in struct DebugScope.
Alexis Hetu3eb4dd82020-10-29 21:37:20 -0400614 // Instead, we assign random ids for them, which results in integrity
Ben Clayton745997b2021-01-21 22:51:51 +0000615 // check failures. In addition, propagating the OpLine/OpNoLine to preserve
616 // the debug information through transformations results in integrity
Alexis Hetu3eb4dd82020-10-29 21:37:20 -0400617 // check failures. We want to skip the integrity check when the module
Ben Clayton745997b2021-01-21 22:51:51 +0000618 // contains DebugScope or OpLine/OpNoLine instructions.
Alexis Hetub8a77462020-03-27 07:59:09 -0400619 if (status == opt::Pass::Status::SuccessWithoutChange &&
Ben Clayton745997b2021-01-21 22:51:51 +0000620 !context->module()->ContainsDebugInfo()) {
Ben Claytond552f632019-11-18 11:18:41 +0000621 std::vector<uint32_t> optimized_binary_with_nop;
622 context->module()->ToBinary(&optimized_binary_with_nop,
623 /* skip_nop = */ false);
624 assert(optimized_binary_with_nop.size() == original_binary_size &&
625 "Binary size unexpectedly changed despite the optimizer saying "
626 "there was no change");
Nicolas Capens00a1bcc2022-07-29 16:49:40 -0400627
628 // Compare the magic number to make sure the binaries were encoded in the
629 // endianness. If not, the contents of the binaries will be different, so
630 // do not check the contents.
631 if (optimized_binary_with_nop[0] == original_binary[0]) {
632 assert(memcmp(optimized_binary_with_nop.data(), original_binary,
633 original_binary_size) == 0 &&
634 "Binary content unexpectedly changed despite the optimizer saying "
635 "there was no change");
636 }
Ben Claytond0f684e2019-08-30 22:36:08 +0100637 }
638#endif // !NDEBUG
639
Ben Claytond552f632019-11-18 11:18:41 +0000640 // Note that |original_binary| and |optimized_binary| may share the same
641 // buffer and the below will invalidate |original_binary|.
642 optimized_binary->clear();
643 context->module()->ToBinary(optimized_binary, /* skip_nop = */ true);
644
Ben Claytond0f684e2019-08-30 22:36:08 +0100645 return true;
Chris Forbescc5697f2019-01-30 11:54:08 -0800646}
647
648Optimizer& Optimizer::SetPrintAll(std::ostream* out) {
649 impl_->pass_manager.SetPrintAll(out);
650 return *this;
651}
652
653Optimizer& Optimizer::SetTimeReport(std::ostream* out) {
654 impl_->pass_manager.SetTimeReport(out);
655 return *this;
656}
657
Ben Claytonb73b7602019-07-29 13:56:13 +0100658Optimizer& Optimizer::SetValidateAfterAll(bool validate) {
659 impl_->pass_manager.SetValidateAfterAll(validate);
660 return *this;
661}
662
Chris Forbescc5697f2019-01-30 11:54:08 -0800663Optimizer::PassToken CreateNullPass() {
664 return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::NullPass>());
665}
666
667Optimizer::PassToken CreateStripDebugInfoPass() {
668 return MakeUnique<Optimizer::PassToken::Impl>(
669 MakeUnique<opt::StripDebugInfoPass>());
670}
671
672Optimizer::PassToken CreateStripReflectInfoPass() {
sugoi1b398bf32022-02-18 10:27:28 -0500673 return CreateStripNonSemanticInfoPass();
674}
675
676Optimizer::PassToken CreateStripNonSemanticInfoPass() {
Chris Forbescc5697f2019-01-30 11:54:08 -0800677 return MakeUnique<Optimizer::PassToken::Impl>(
sugoi1b398bf32022-02-18 10:27:28 -0500678 MakeUnique<opt::StripNonSemanticInfoPass>());
Chris Forbescc5697f2019-01-30 11:54:08 -0800679}
680
681Optimizer::PassToken CreateEliminateDeadFunctionsPass() {
682 return MakeUnique<Optimizer::PassToken::Impl>(
683 MakeUnique<opt::EliminateDeadFunctionsPass>());
684}
685
Ben Claytonb73b7602019-07-29 13:56:13 +0100686Optimizer::PassToken CreateEliminateDeadMembersPass() {
687 return MakeUnique<Optimizer::PassToken::Impl>(
688 MakeUnique<opt::EliminateDeadMembersPass>());
689}
690
Chris Forbescc5697f2019-01-30 11:54:08 -0800691Optimizer::PassToken CreateSetSpecConstantDefaultValuePass(
692 const std::unordered_map<uint32_t, std::string>& id_value_map) {
693 return MakeUnique<Optimizer::PassToken::Impl>(
694 MakeUnique<opt::SetSpecConstantDefaultValuePass>(id_value_map));
695}
696
697Optimizer::PassToken CreateSetSpecConstantDefaultValuePass(
698 const std::unordered_map<uint32_t, std::vector<uint32_t>>& id_value_map) {
699 return MakeUnique<Optimizer::PassToken::Impl>(
700 MakeUnique<opt::SetSpecConstantDefaultValuePass>(id_value_map));
701}
702
703Optimizer::PassToken CreateFlattenDecorationPass() {
704 return MakeUnique<Optimizer::PassToken::Impl>(
705 MakeUnique<opt::FlattenDecorationPass>());
706}
707
708Optimizer::PassToken CreateFreezeSpecConstantValuePass() {
709 return MakeUnique<Optimizer::PassToken::Impl>(
710 MakeUnique<opt::FreezeSpecConstantValuePass>());
711}
712
713Optimizer::PassToken CreateFoldSpecConstantOpAndCompositePass() {
714 return MakeUnique<Optimizer::PassToken::Impl>(
715 MakeUnique<opt::FoldSpecConstantOpAndCompositePass>());
716}
717
718Optimizer::PassToken CreateUnifyConstantPass() {
719 return MakeUnique<Optimizer::PassToken::Impl>(
720 MakeUnique<opt::UnifyConstantPass>());
721}
722
723Optimizer::PassToken CreateEliminateDeadConstantPass() {
724 return MakeUnique<Optimizer::PassToken::Impl>(
725 MakeUnique<opt::EliminateDeadConstantPass>());
726}
727
728Optimizer::PassToken CreateDeadVariableEliminationPass() {
729 return MakeUnique<Optimizer::PassToken::Impl>(
730 MakeUnique<opt::DeadVariableElimination>());
731}
732
733Optimizer::PassToken CreateStrengthReductionPass() {
734 return MakeUnique<Optimizer::PassToken::Impl>(
735 MakeUnique<opt::StrengthReductionPass>());
736}
737
738Optimizer::PassToken CreateBlockMergePass() {
739 return MakeUnique<Optimizer::PassToken::Impl>(
740 MakeUnique<opt::BlockMergePass>());
741}
742
743Optimizer::PassToken CreateInlineExhaustivePass() {
744 return MakeUnique<Optimizer::PassToken::Impl>(
745 MakeUnique<opt::InlineExhaustivePass>());
746}
747
748Optimizer::PassToken CreateInlineOpaquePass() {
749 return MakeUnique<Optimizer::PassToken::Impl>(
750 MakeUnique<opt::InlineOpaquePass>());
751}
752
753Optimizer::PassToken CreateLocalAccessChainConvertPass() {
754 return MakeUnique<Optimizer::PassToken::Impl>(
755 MakeUnique<opt::LocalAccessChainConvertPass>());
756}
757
758Optimizer::PassToken CreateLocalSingleBlockLoadStoreElimPass() {
759 return MakeUnique<Optimizer::PassToken::Impl>(
760 MakeUnique<opt::LocalSingleBlockLoadStoreElimPass>());
761}
762
763Optimizer::PassToken CreateLocalSingleStoreElimPass() {
764 return MakeUnique<Optimizer::PassToken::Impl>(
765 MakeUnique<opt::LocalSingleStoreElimPass>());
766}
767
768Optimizer::PassToken CreateInsertExtractElimPass() {
769 return MakeUnique<Optimizer::PassToken::Impl>(
770 MakeUnique<opt::SimplificationPass>());
771}
772
773Optimizer::PassToken CreateDeadInsertElimPass() {
774 return MakeUnique<Optimizer::PassToken::Impl>(
775 MakeUnique<opt::DeadInsertElimPass>());
776}
777
778Optimizer::PassToken CreateDeadBranchElimPass() {
779 return MakeUnique<Optimizer::PassToken::Impl>(
780 MakeUnique<opt::DeadBranchElimPass>());
781}
782
783Optimizer::PassToken CreateLocalMultiStoreElimPass() {
784 return MakeUnique<Optimizer::PassToken::Impl>(
Ben Claytond552f632019-11-18 11:18:41 +0000785 MakeUnique<opt::SSARewritePass>());
Chris Forbescc5697f2019-01-30 11:54:08 -0800786}
787
Alexis Hetu1ef51fa2022-11-24 09:03:10 -0500788Optimizer::PassToken CreateAggressiveDCEPass(bool preserve_interface,
789 bool remove_outputs) {
sugoi1b398bf32022-02-18 10:27:28 -0500790 return MakeUnique<Optimizer::PassToken::Impl>(
Alexis Hetu1ef51fa2022-11-24 09:03:10 -0500791 MakeUnique<opt::AggressiveDCEPass>(preserve_interface, remove_outputs));
Alexis Hetu00e0af12021-11-08 08:57:46 -0500792}
793
794Optimizer::PassToken CreateRemoveUnusedInterfaceVariablesPass() {
795 return MakeUnique<Optimizer::PassToken::Impl>(
796 MakeUnique<opt::RemoveUnusedInterfaceVariablesPass>());
Chris Forbescc5697f2019-01-30 11:54:08 -0800797}
798
Alexis Hetu7975f152020-11-02 11:08:33 -0500799Optimizer::PassToken CreatePropagateLineInfoPass() {
800 return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::EmptyPass>());
801}
802
803Optimizer::PassToken CreateRedundantLineInfoElimPass() {
804 return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::EmptyPass>());
805}
806
Chris Forbescc5697f2019-01-30 11:54:08 -0800807Optimizer::PassToken CreateCompactIdsPass() {
808 return MakeUnique<Optimizer::PassToken::Impl>(
809 MakeUnique<opt::CompactIdsPass>());
810}
811
812Optimizer::PassToken CreateMergeReturnPass() {
813 return MakeUnique<Optimizer::PassToken::Impl>(
814 MakeUnique<opt::MergeReturnPass>());
815}
816
817std::vector<const char*> Optimizer::GetPassNames() const {
818 std::vector<const char*> v;
819 for (uint32_t i = 0; i < impl_->pass_manager.NumPasses(); i++) {
820 v.push_back(impl_->pass_manager.GetPass(i)->name());
821 }
822 return v;
823}
824
825Optimizer::PassToken CreateCFGCleanupPass() {
826 return MakeUnique<Optimizer::PassToken::Impl>(
827 MakeUnique<opt::CFGCleanupPass>());
828}
829
830Optimizer::PassToken CreateLocalRedundancyEliminationPass() {
831 return MakeUnique<Optimizer::PassToken::Impl>(
832 MakeUnique<opt::LocalRedundancyEliminationPass>());
833}
834
835Optimizer::PassToken CreateLoopFissionPass(size_t threshold) {
836 return MakeUnique<Optimizer::PassToken::Impl>(
837 MakeUnique<opt::LoopFissionPass>(threshold));
838}
839
840Optimizer::PassToken CreateLoopFusionPass(size_t max_registers_per_loop) {
841 return MakeUnique<Optimizer::PassToken::Impl>(
842 MakeUnique<opt::LoopFusionPass>(max_registers_per_loop));
843}
844
845Optimizer::PassToken CreateLoopInvariantCodeMotionPass() {
846 return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::LICMPass>());
847}
848
849Optimizer::PassToken CreateLoopPeelingPass() {
850 return MakeUnique<Optimizer::PassToken::Impl>(
851 MakeUnique<opt::LoopPeelingPass>());
852}
853
854Optimizer::PassToken CreateLoopUnswitchPass() {
855 return MakeUnique<Optimizer::PassToken::Impl>(
856 MakeUnique<opt::LoopUnswitchPass>());
857}
858
859Optimizer::PassToken CreateRedundancyEliminationPass() {
860 return MakeUnique<Optimizer::PassToken::Impl>(
861 MakeUnique<opt::RedundancyEliminationPass>());
862}
863
864Optimizer::PassToken CreateRemoveDuplicatesPass() {
865 return MakeUnique<Optimizer::PassToken::Impl>(
866 MakeUnique<opt::RemoveDuplicatesPass>());
867}
868
869Optimizer::PassToken CreateScalarReplacementPass(uint32_t size_limit) {
870 return MakeUnique<Optimizer::PassToken::Impl>(
871 MakeUnique<opt::ScalarReplacementPass>(size_limit));
872}
873
874Optimizer::PassToken CreatePrivateToLocalPass() {
875 return MakeUnique<Optimizer::PassToken::Impl>(
876 MakeUnique<opt::PrivateToLocalPass>());
877}
878
879Optimizer::PassToken CreateCCPPass() {
880 return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::CCPPass>());
881}
882
883Optimizer::PassToken CreateWorkaround1209Pass() {
884 return MakeUnique<Optimizer::PassToken::Impl>(
885 MakeUnique<opt::Workaround1209>());
886}
887
888Optimizer::PassToken CreateIfConversionPass() {
889 return MakeUnique<Optimizer::PassToken::Impl>(
890 MakeUnique<opt::IfConversion>());
891}
892
893Optimizer::PassToken CreateReplaceInvalidOpcodePass() {
894 return MakeUnique<Optimizer::PassToken::Impl>(
895 MakeUnique<opt::ReplaceInvalidOpcodePass>());
896}
897
898Optimizer::PassToken CreateSimplificationPass() {
899 return MakeUnique<Optimizer::PassToken::Impl>(
900 MakeUnique<opt::SimplificationPass>());
901}
902
903Optimizer::PassToken CreateLoopUnrollPass(bool fully_unroll, int factor) {
904 return MakeUnique<Optimizer::PassToken::Impl>(
905 MakeUnique<opt::LoopUnroller>(fully_unroll, factor));
906}
907
908Optimizer::PassToken CreateSSARewritePass() {
909 return MakeUnique<Optimizer::PassToken::Impl>(
910 MakeUnique<opt::SSARewritePass>());
911}
912
913Optimizer::PassToken CreateCopyPropagateArraysPass() {
914 return MakeUnique<Optimizer::PassToken::Impl>(
915 MakeUnique<opt::CopyPropagateArrays>());
916}
917
918Optimizer::PassToken CreateVectorDCEPass() {
919 return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::VectorDCE>());
920}
921
Alexis Hetu00e0af12021-11-08 08:57:46 -0500922Optimizer::PassToken CreateReduceLoadSizePass(
923 double load_replacement_threshold) {
Chris Forbescc5697f2019-01-30 11:54:08 -0800924 return MakeUnique<Optimizer::PassToken::Impl>(
Alexis Hetu00e0af12021-11-08 08:57:46 -0500925 MakeUnique<opt::ReduceLoadSize>(load_replacement_threshold));
Chris Forbescc5697f2019-01-30 11:54:08 -0800926}
927
928Optimizer::PassToken CreateCombineAccessChainsPass() {
929 return MakeUnique<Optimizer::PassToken::Impl>(
930 MakeUnique<opt::CombineAccessChains>());
931}
932
933Optimizer::PassToken CreateUpgradeMemoryModelPass() {
934 return MakeUnique<Optimizer::PassToken::Impl>(
935 MakeUnique<opt::UpgradeMemoryModel>());
936}
937
Ben Clayton745997b2021-01-21 22:51:51 +0000938Optimizer::PassToken CreateInstBindlessCheckPass(
939 uint32_t desc_set, uint32_t shader_id, bool desc_length_enable,
940 bool desc_init_enable, bool buff_oob_enable, bool texbuff_oob_enable) {
Chris Forbescc5697f2019-01-30 11:54:08 -0800941 return MakeUnique<Optimizer::PassToken::Impl>(
Ben Clayton38e46912020-05-26 15:56:15 +0100942 MakeUnique<opt::InstBindlessCheckPass>(
Ben Clayton745997b2021-01-21 22:51:51 +0000943 desc_set, shader_id, desc_length_enable, desc_init_enable,
944 buff_oob_enable, texbuff_oob_enable,
945 desc_length_enable || desc_init_enable || buff_oob_enable));
Chris Forbescc5697f2019-01-30 11:54:08 -0800946}
947
Alexis Hetub8a77462020-03-27 07:59:09 -0400948Optimizer::PassToken CreateInstDebugPrintfPass(uint32_t desc_set,
949 uint32_t shader_id) {
950 return MakeUnique<Optimizer::PassToken::Impl>(
951 MakeUnique<opt::InstDebugPrintfPass>(desc_set, shader_id));
952}
953
Ben Claytond0f684e2019-08-30 22:36:08 +0100954Optimizer::PassToken CreateInstBuffAddrCheckPass(uint32_t desc_set,
Ben Clayton38e46912020-05-26 15:56:15 +0100955 uint32_t shader_id) {
Ben Claytond0f684e2019-08-30 22:36:08 +0100956 return MakeUnique<Optimizer::PassToken::Impl>(
Ben Clayton38e46912020-05-26 15:56:15 +0100957 MakeUnique<opt::InstBuffAddrCheckPass>(desc_set, shader_id));
Ben Claytond0f684e2019-08-30 22:36:08 +0100958}
959
Ben Claytond552f632019-11-18 11:18:41 +0000960Optimizer::PassToken CreateConvertRelaxedToHalfPass() {
961 return MakeUnique<Optimizer::PassToken::Impl>(
962 MakeUnique<opt::ConvertToHalfPass>());
963}
964
965Optimizer::PassToken CreateRelaxFloatOpsPass() {
966 return MakeUnique<Optimizer::PassToken::Impl>(
967 MakeUnique<opt::RelaxFloatOpsPass>());
968}
969
Chris Forbescc5697f2019-01-30 11:54:08 -0800970Optimizer::PassToken CreateCodeSinkingPass() {
971 return MakeUnique<Optimizer::PassToken::Impl>(
972 MakeUnique<opt::CodeSinkingPass>());
973}
974
Ben Claytonb73b7602019-07-29 13:56:13 +0100975Optimizer::PassToken CreateFixStorageClassPass() {
976 return MakeUnique<Optimizer::PassToken::Impl>(
977 MakeUnique<opt::FixStorageClass>());
978}
979
Ben Claytond0f684e2019-08-30 22:36:08 +0100980Optimizer::PassToken CreateGraphicsRobustAccessPass() {
981 return MakeUnique<Optimizer::PassToken::Impl>(
982 MakeUnique<opt::GraphicsRobustAccessPass>());
983}
984
Alexis Hetu00e0af12021-11-08 08:57:46 -0500985Optimizer::PassToken CreateReplaceDescArrayAccessUsingVarIndexPass() {
986 return MakeUnique<Optimizer::PassToken::Impl>(
987 MakeUnique<opt::ReplaceDescArrayAccessUsingVarIndex>());
988}
989
sugoi1b398bf32022-02-18 10:27:28 -0500990Optimizer::PassToken CreateSpreadVolatileSemanticsPass() {
991 return MakeUnique<Optimizer::PassToken::Impl>(
992 MakeUnique<opt::SpreadVolatileSemantics>());
993}
994
Ben Claytond0f684e2019-08-30 22:36:08 +0100995Optimizer::PassToken CreateDescriptorScalarReplacementPass() {
996 return MakeUnique<Optimizer::PassToken::Impl>(
997 MakeUnique<opt::DescriptorScalarReplacement>());
998}
999
1000Optimizer::PassToken CreateWrapOpKillPass() {
1001 return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::WrapOpKill>());
1002}
1003
1004Optimizer::PassToken CreateAmdExtToKhrPass() {
1005 return MakeUnique<Optimizer::PassToken::Impl>(
1006 MakeUnique<opt::AmdExtensionToKhrPass>());
1007}
1008
Alexis Hetu00e0af12021-11-08 08:57:46 -05001009Optimizer::PassToken CreateInterpolateFixupPass() {
1010 return MakeUnique<Optimizer::PassToken::Impl>(
1011 MakeUnique<opt::InterpFixupPass>());
1012}
1013
Nicolas Capens4111ae92022-03-23 12:23:11 -04001014Optimizer::PassToken CreateEliminateDeadInputComponentsPass() {
1015 return MakeUnique<Optimizer::PassToken::Impl>(
Nicolas Capens84c9c452022-11-18 14:11:05 +00001016 MakeUnique<opt::EliminateDeadInputComponentsPass>(
1017 /* output_instead */ false, /* vertex_shader_only */ false));
1018}
1019
1020Optimizer::PassToken CreateEliminateDeadOutputComponentsPass() {
1021 return MakeUnique<Optimizer::PassToken::Impl>(
1022 MakeUnique<opt::EliminateDeadInputComponentsPass>(
1023 /* output_instead */ true, /* vertex_shader_only */ false));
1024}
1025
1026Optimizer::PassToken CreateEliminateDeadInputComponentsSafePass() {
1027 return MakeUnique<Optimizer::PassToken::Impl>(
Nicolas Capens4111ae92022-03-23 12:23:11 -04001028 MakeUnique<opt::EliminateDeadInputComponentsPass>());
1029}
1030
Nicolas Capens84c9c452022-11-18 14:11:05 +00001031Optimizer::PassToken CreateAnalyzeLiveInputPass(
1032 std::unordered_set<uint32_t>* live_locs,
1033 std::unordered_set<uint32_t>* live_builtins) {
1034 return MakeUnique<Optimizer::PassToken::Impl>(
1035 MakeUnique<opt::AnalyzeLiveInputPass>(live_locs, live_builtins));
1036}
1037
1038Optimizer::PassToken CreateEliminateDeadOutputStoresPass(
1039 std::unordered_set<uint32_t>* live_locs,
1040 std::unordered_set<uint32_t>* live_builtins) {
1041 return MakeUnique<Optimizer::PassToken::Impl>(
1042 MakeUnique<opt::EliminateDeadOutputStoresPass>(live_locs, live_builtins));
1043}
1044
Alexis Hetu00e0af12021-11-08 08:57:46 -05001045Optimizer::PassToken CreateConvertToSampledImagePass(
1046 const std::vector<opt::DescriptorSetAndBinding>&
1047 descriptor_set_binding_pairs) {
1048 return MakeUnique<Optimizer::PassToken::Impl>(
1049 MakeUnique<opt::ConvertToSampledImagePass>(descriptor_set_binding_pairs));
1050}
1051
Nicolas Capens9d252072022-05-26 17:20:50 -04001052Optimizer::PassToken CreateInterfaceVariableScalarReplacementPass() {
1053 return MakeUnique<Optimizer::PassToken::Impl>(
1054 MakeUnique<opt::InterfaceVariableScalarReplacement>());
1055}
1056
Nicolas Capens9cbc5e22022-03-08 13:03:25 -05001057Optimizer::PassToken CreateRemoveDontInlinePass() {
1058 return MakeUnique<Optimizer::PassToken::Impl>(
1059 MakeUnique<opt::RemoveDontInline>());
1060}
Nicolas Capens9d252072022-05-26 17:20:50 -04001061
1062Optimizer::PassToken CreateFixFuncCallArgumentsPass() {
1063 return MakeUnique<Optimizer::PassToken::Impl>(
1064 MakeUnique<opt::FixFuncCallArgumentsPass>());
1065}
Chris Forbescc5697f2019-01-30 11:54:08 -08001066} // namespace spvtools