blob: 909442cc1dcdb480da93e543eb175600a39b89c2 [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.
Chris Forbescc5697f2019-01-30 11:54:08 -080063};
64
Ben Clayton745997b2021-01-21 22:51:51 +000065Optimizer::Optimizer(spv_target_env env) : impl_(new Impl(env)) {
66 assert(env != SPV_ENV_WEBGPU_0);
67}
Chris Forbescc5697f2019-01-30 11:54:08 -080068
69Optimizer::~Optimizer() {}
70
71void 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
79const MessageConsumer& Optimizer::consumer() const {
80 return impl_->pass_manager.consumer();
81}
82
83Optimizer& 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.
111Optimizer& Optimizer::RegisterLegalizationPasses() {
112 return
Ben Claytond0f684e2019-08-30 22:36:08 +0100113 // 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())
Chris Forbescc5697f2019-01-30 11:54:08 -0800117 // 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())
Ben Claytonb73b7602019-07-29 13:56:13 +0100124 // 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())
Chris Forbescc5697f2019-01-30 11:54:08 -0800128 // 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}
160
161Optimizer& Optimizer::RegisterPerformancePasses() {
Ben Claytond0f684e2019-08-30 22:36:08 +0100162 return RegisterPass(CreateWrapOpKillPass())
163 .RegisterPass(CreateDeadBranchElimPass())
Chris Forbescc5697f2019-01-30 11:54:08 -0800164 .RegisterPass(CreateMergeReturnPass())
165 .RegisterPass(CreateInlineExhaustivePass())
Sean Risserd2283f82020-11-05 14:17:31 -0500166 .RegisterPass(CreateEliminateDeadFunctionsPass())
Chris Forbescc5697f2019-01-30 11:54:08 -0800167 .RegisterPass(CreateAggressiveDCEPass())
168 .RegisterPass(CreatePrivateToLocalPass())
169 .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass())
170 .RegisterPass(CreateLocalSingleStoreElimPass())
171 .RegisterPass(CreateAggressiveDCEPass())
172 .RegisterPass(CreateScalarReplacementPass())
173 .RegisterPass(CreateLocalAccessChainConvertPass())
174 .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass())
175 .RegisterPass(CreateLocalSingleStoreElimPass())
176 .RegisterPass(CreateAggressiveDCEPass())
177 .RegisterPass(CreateLocalMultiStoreElimPass())
178 .RegisterPass(CreateAggressiveDCEPass())
179 .RegisterPass(CreateCCPPass())
180 .RegisterPass(CreateAggressiveDCEPass())
Ben Clayton38e46912020-05-26 15:56:15 +0100181 .RegisterPass(CreateLoopUnrollPass(true))
182 .RegisterPass(CreateDeadBranchElimPass())
Chris Forbescc5697f2019-01-30 11:54:08 -0800183 .RegisterPass(CreateRedundancyEliminationPass())
184 .RegisterPass(CreateCombineAccessChainsPass())
185 .RegisterPass(CreateSimplificationPass())
Ben Clayton38e46912020-05-26 15:56:15 +0100186 .RegisterPass(CreateScalarReplacementPass())
187 .RegisterPass(CreateLocalAccessChainConvertPass())
188 .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass())
189 .RegisterPass(CreateLocalSingleStoreElimPass())
190 .RegisterPass(CreateAggressiveDCEPass())
191 .RegisterPass(CreateSSARewritePass())
192 .RegisterPass(CreateAggressiveDCEPass())
Chris Forbescc5697f2019-01-30 11:54:08 -0800193 .RegisterPass(CreateVectorDCEPass())
194 .RegisterPass(CreateDeadInsertElimPass())
195 .RegisterPass(CreateDeadBranchElimPass())
196 .RegisterPass(CreateSimplificationPass())
197 .RegisterPass(CreateIfConversionPass())
198 .RegisterPass(CreateCopyPropagateArraysPass())
199 .RegisterPass(CreateReduceLoadSizePass())
200 .RegisterPass(CreateAggressiveDCEPass())
201 .RegisterPass(CreateBlockMergePass())
202 .RegisterPass(CreateRedundancyEliminationPass())
203 .RegisterPass(CreateDeadBranchElimPass())
204 .RegisterPass(CreateBlockMergePass())
Ben Claytonb73b7602019-07-29 13:56:13 +0100205 .RegisterPass(CreateSimplificationPass());
Chris Forbescc5697f2019-01-30 11:54:08 -0800206}
207
208Optimizer& Optimizer::RegisterSizePasses() {
Ben Claytond0f684e2019-08-30 22:36:08 +0100209 return RegisterPass(CreateWrapOpKillPass())
210 .RegisterPass(CreateDeadBranchElimPass())
Chris Forbescc5697f2019-01-30 11:54:08 -0800211 .RegisterPass(CreateMergeReturnPass())
212 .RegisterPass(CreateInlineExhaustivePass())
Ben Clayton0b54f132020-01-06 13:38:54 +0000213 .RegisterPass(CreateEliminateDeadFunctionsPass())
Chris Forbescc5697f2019-01-30 11:54:08 -0800214 .RegisterPass(CreatePrivateToLocalPass())
Ben Clayton0b54f132020-01-06 13:38:54 +0000215 .RegisterPass(CreateScalarReplacementPass(0))
Chris Forbescc5697f2019-01-30 11:54:08 -0800216 .RegisterPass(CreateLocalMultiStoreElimPass())
Chris Forbescc5697f2019-01-30 11:54:08 -0800217 .RegisterPass(CreateCCPPass())
Ben Clayton0b54f132020-01-06 13:38:54 +0000218 .RegisterPass(CreateLoopUnrollPass(true))
219 .RegisterPass(CreateDeadBranchElimPass())
220 .RegisterPass(CreateSimplificationPass())
221 .RegisterPass(CreateScalarReplacementPass(0))
222 .RegisterPass(CreateLocalSingleStoreElimPass())
223 .RegisterPass(CreateIfConversionPass())
224 .RegisterPass(CreateSimplificationPass())
Chris Forbescc5697f2019-01-30 11:54:08 -0800225 .RegisterPass(CreateAggressiveDCEPass())
226 .RegisterPass(CreateDeadBranchElimPass())
Chris Forbescc5697f2019-01-30 11:54:08 -0800227 .RegisterPass(CreateBlockMergePass())
Ben Clayton0b54f132020-01-06 13:38:54 +0000228 .RegisterPass(CreateLocalAccessChainConvertPass())
229 .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass())
230 .RegisterPass(CreateAggressiveDCEPass())
231 .RegisterPass(CreateCopyPropagateArraysPass())
232 .RegisterPass(CreateVectorDCEPass())
Chris Forbescc5697f2019-01-30 11:54:08 -0800233 .RegisterPass(CreateDeadInsertElimPass())
Ben Clayton0b54f132020-01-06 13:38:54 +0000234 .RegisterPass(CreateEliminateDeadMembersPass())
235 .RegisterPass(CreateLocalSingleStoreElimPass())
236 .RegisterPass(CreateBlockMergePass())
237 .RegisterPass(CreateLocalMultiStoreElimPass())
Chris Forbescc5697f2019-01-30 11:54:08 -0800238 .RegisterPass(CreateRedundancyEliminationPass())
Ben Clayton0b54f132020-01-06 13:38:54 +0000239 .RegisterPass(CreateSimplificationPass())
240 .RegisterPass(CreateAggressiveDCEPass())
241 .RegisterPass(CreateCFGCleanupPass());
Chris Forbescc5697f2019-01-30 11:54:08 -0800242}
243
Chris Forbescc5697f2019-01-30 11:54:08 -0800244bool Optimizer::RegisterPassesFromFlags(const std::vector<std::string>& flags) {
245 for (const auto& flag : flags) {
246 if (!RegisterPassFromFlag(flag)) {
247 return false;
248 }
249 }
250
251 return true;
252}
253
254bool Optimizer::FlagHasValidForm(const std::string& flag) const {
255 if (flag == "-O" || flag == "-Os") {
256 return true;
257 } else if (flag.size() > 2 && flag.substr(0, 2) == "--") {
258 return true;
259 }
260
261 Errorf(consumer(), nullptr, {},
262 "%s is not a valid flag. Flag passes should have the form "
263 "'--pass_name[=pass_args]'. Special flag names also accepted: -O "
264 "and -Os.",
265 flag.c_str());
266 return false;
267}
268
269bool Optimizer::RegisterPassFromFlag(const std::string& flag) {
270 if (!FlagHasValidForm(flag)) {
271 return false;
272 }
273
274 // Split flags of the form --pass_name=pass_args.
275 auto p = utils::SplitFlagArgs(flag);
276 std::string pass_name = p.first;
277 std::string pass_args = p.second;
278
279 // FIXME(dnovillo): This should be re-factored so that pass names can be
280 // automatically checked against Pass::name() and PassToken instances created
281 // via a template function. Additionally, class Pass should have a desc()
282 // method that describes the pass (so it can be used in --help).
283 //
284 // Both Pass::name() and Pass::desc() should be static class members so they
285 // can be invoked without creating a pass instance.
Ben Clayton745997b2021-01-21 22:51:51 +0000286 if (pass_name == "strip-debug") {
Chris Forbescc5697f2019-01-30 11:54:08 -0800287 RegisterPass(CreateStripDebugInfoPass());
288 } else if (pass_name == "strip-reflect") {
289 RegisterPass(CreateStripReflectInfoPass());
290 } else if (pass_name == "set-spec-const-default-value") {
291 if (pass_args.size() > 0) {
292 auto spec_ids_vals =
293 opt::SetSpecConstantDefaultValuePass::ParseDefaultValuesString(
294 pass_args.c_str());
295 if (!spec_ids_vals) {
296 Errorf(consumer(), nullptr, {},
297 "Invalid argument for --set-spec-const-default-value: %s",
298 pass_args.c_str());
299 return false;
300 }
301 RegisterPass(
302 CreateSetSpecConstantDefaultValuePass(std::move(*spec_ids_vals)));
303 } else {
304 Errorf(consumer(), nullptr, {},
305 "Invalid spec constant value string '%s'. Expected a string of "
306 "<spec id>:<default value> pairs.",
307 pass_args.c_str());
308 return false;
309 }
310 } else if (pass_name == "if-conversion") {
311 RegisterPass(CreateIfConversionPass());
312 } else if (pass_name == "freeze-spec-const") {
313 RegisterPass(CreateFreezeSpecConstantValuePass());
314 } else if (pass_name == "inline-entry-points-exhaustive") {
315 RegisterPass(CreateInlineExhaustivePass());
316 } else if (pass_name == "inline-entry-points-opaque") {
317 RegisterPass(CreateInlineOpaquePass());
318 } else if (pass_name == "combine-access-chains") {
319 RegisterPass(CreateCombineAccessChainsPass());
320 } else if (pass_name == "convert-local-access-chains") {
321 RegisterPass(CreateLocalAccessChainConvertPass());
Ben Claytond0f684e2019-08-30 22:36:08 +0100322 } else if (pass_name == "descriptor-scalar-replacement") {
323 RegisterPass(CreateDescriptorScalarReplacementPass());
Chris Forbescc5697f2019-01-30 11:54:08 -0800324 } else if (pass_name == "eliminate-dead-code-aggressive") {
325 RegisterPass(CreateAggressiveDCEPass());
Chris Forbescc5697f2019-01-30 11:54:08 -0800326 } else if (pass_name == "eliminate-insert-extract") {
327 RegisterPass(CreateInsertExtractElimPass());
328 } else if (pass_name == "eliminate-local-single-block") {
329 RegisterPass(CreateLocalSingleBlockLoadStoreElimPass());
330 } else if (pass_name == "eliminate-local-single-store") {
331 RegisterPass(CreateLocalSingleStoreElimPass());
332 } else if (pass_name == "merge-blocks") {
333 RegisterPass(CreateBlockMergePass());
334 } else if (pass_name == "merge-return") {
335 RegisterPass(CreateMergeReturnPass());
336 } else if (pass_name == "eliminate-dead-branches") {
337 RegisterPass(CreateDeadBranchElimPass());
338 } else if (pass_name == "eliminate-dead-functions") {
339 RegisterPass(CreateEliminateDeadFunctionsPass());
340 } else if (pass_name == "eliminate-local-multi-store") {
341 RegisterPass(CreateLocalMultiStoreElimPass());
Chris Forbescc5697f2019-01-30 11:54:08 -0800342 } else if (pass_name == "eliminate-dead-const") {
343 RegisterPass(CreateEliminateDeadConstantPass());
344 } else if (pass_name == "eliminate-dead-inserts") {
345 RegisterPass(CreateDeadInsertElimPass());
346 } else if (pass_name == "eliminate-dead-variables") {
347 RegisterPass(CreateDeadVariableEliminationPass());
Ben Claytonb73b7602019-07-29 13:56:13 +0100348 } else if (pass_name == "eliminate-dead-members") {
349 RegisterPass(CreateEliminateDeadMembersPass());
Chris Forbescc5697f2019-01-30 11:54:08 -0800350 } else if (pass_name == "fold-spec-const-op-composite") {
351 RegisterPass(CreateFoldSpecConstantOpAndCompositePass());
352 } else if (pass_name == "loop-unswitch") {
353 RegisterPass(CreateLoopUnswitchPass());
354 } else if (pass_name == "scalar-replacement") {
355 if (pass_args.size() == 0) {
356 RegisterPass(CreateScalarReplacementPass());
357 } else {
358 int limit = -1;
359 if (pass_args.find_first_not_of("0123456789") == std::string::npos) {
360 limit = atoi(pass_args.c_str());
361 }
362
363 if (limit >= 0) {
364 RegisterPass(CreateScalarReplacementPass(limit));
365 } else {
366 Error(consumer(), nullptr, {},
367 "--scalar-replacement must have no arguments or a non-negative "
368 "integer argument");
369 return false;
370 }
371 }
372 } else if (pass_name == "strength-reduction") {
373 RegisterPass(CreateStrengthReductionPass());
374 } else if (pass_name == "unify-const") {
375 RegisterPass(CreateUnifyConstantPass());
376 } else if (pass_name == "flatten-decorations") {
377 RegisterPass(CreateFlattenDecorationPass());
378 } else if (pass_name == "compact-ids") {
379 RegisterPass(CreateCompactIdsPass());
380 } else if (pass_name == "cfg-cleanup") {
381 RegisterPass(CreateCFGCleanupPass());
382 } else if (pass_name == "local-redundancy-elimination") {
383 RegisterPass(CreateLocalRedundancyEliminationPass());
384 } else if (pass_name == "loop-invariant-code-motion") {
385 RegisterPass(CreateLoopInvariantCodeMotionPass());
386 } else if (pass_name == "reduce-load-size") {
387 RegisterPass(CreateReduceLoadSizePass());
388 } else if (pass_name == "redundancy-elimination") {
389 RegisterPass(CreateRedundancyEliminationPass());
390 } else if (pass_name == "private-to-local") {
391 RegisterPass(CreatePrivateToLocalPass());
392 } else if (pass_name == "remove-duplicates") {
393 RegisterPass(CreateRemoveDuplicatesPass());
394 } else if (pass_name == "workaround-1209") {
395 RegisterPass(CreateWorkaround1209Pass());
396 } else if (pass_name == "replace-invalid-opcode") {
397 RegisterPass(CreateReplaceInvalidOpcodePass());
398 } else if (pass_name == "inst-bindless-check") {
Ben Clayton38e46912020-05-26 15:56:15 +0100399 RegisterPass(CreateInstBindlessCheckPass(7, 23, false, false));
Chris Forbescc5697f2019-01-30 11:54:08 -0800400 RegisterPass(CreateSimplificationPass());
401 RegisterPass(CreateDeadBranchElimPass());
402 RegisterPass(CreateBlockMergePass());
403 RegisterPass(CreateAggressiveDCEPass());
Ben Claytond0f684e2019-08-30 22:36:08 +0100404 } else if (pass_name == "inst-desc-idx-check") {
Ben Clayton38e46912020-05-26 15:56:15 +0100405 RegisterPass(CreateInstBindlessCheckPass(7, 23, true, true));
Ben Claytond0f684e2019-08-30 22:36:08 +0100406 RegisterPass(CreateSimplificationPass());
407 RegisterPass(CreateDeadBranchElimPass());
408 RegisterPass(CreateBlockMergePass());
409 RegisterPass(CreateAggressiveDCEPass());
Alexis Hetu3eb4dd82020-10-29 21:37:20 -0400410 } else if (pass_name == "inst-buff-oob-check") {
Ben Clayton745997b2021-01-21 22:51:51 +0000411 RegisterPass(CreateInstBindlessCheckPass(7, 23, false, false, true, true));
Alexis Hetu3eb4dd82020-10-29 21:37:20 -0400412 RegisterPass(CreateSimplificationPass());
413 RegisterPass(CreateDeadBranchElimPass());
414 RegisterPass(CreateBlockMergePass());
415 RegisterPass(CreateAggressiveDCEPass());
Ben Claytond0f684e2019-08-30 22:36:08 +0100416 } else if (pass_name == "inst-buff-addr-check") {
Ben Clayton38e46912020-05-26 15:56:15 +0100417 RegisterPass(CreateInstBuffAddrCheckPass(7, 23));
Ben Claytond0f684e2019-08-30 22:36:08 +0100418 RegisterPass(CreateAggressiveDCEPass());
Ben Claytond552f632019-11-18 11:18:41 +0000419 } else if (pass_name == "convert-relaxed-to-half") {
420 RegisterPass(CreateConvertRelaxedToHalfPass());
421 } else if (pass_name == "relax-float-ops") {
422 RegisterPass(CreateRelaxFloatOpsPass());
Alexis Hetub8a77462020-03-27 07:59:09 -0400423 } else if (pass_name == "inst-debug-printf") {
424 RegisterPass(CreateInstDebugPrintfPass(7, 23));
Chris Forbescc5697f2019-01-30 11:54:08 -0800425 } else if (pass_name == "simplify-instructions") {
426 RegisterPass(CreateSimplificationPass());
427 } else if (pass_name == "ssa-rewrite") {
428 RegisterPass(CreateSSARewritePass());
429 } else if (pass_name == "copy-propagate-arrays") {
430 RegisterPass(CreateCopyPropagateArraysPass());
431 } else if (pass_name == "loop-fission") {
432 int register_threshold_to_split =
433 (pass_args.size() > 0) ? atoi(pass_args.c_str()) : -1;
434 if (register_threshold_to_split > 0) {
435 RegisterPass(CreateLoopFissionPass(
436 static_cast<size_t>(register_threshold_to_split)));
437 } else {
438 Error(consumer(), nullptr, {},
439 "--loop-fission must have a positive integer argument");
440 return false;
441 }
442 } else if (pass_name == "loop-fusion") {
443 int max_registers_per_loop =
444 (pass_args.size() > 0) ? atoi(pass_args.c_str()) : -1;
445 if (max_registers_per_loop > 0) {
446 RegisterPass(
447 CreateLoopFusionPass(static_cast<size_t>(max_registers_per_loop)));
448 } else {
449 Error(consumer(), nullptr, {},
450 "--loop-fusion must have a positive integer argument");
451 return false;
452 }
453 } else if (pass_name == "loop-unroll") {
454 RegisterPass(CreateLoopUnrollPass(true));
455 } else if (pass_name == "upgrade-memory-model") {
456 RegisterPass(CreateUpgradeMemoryModelPass());
457 } else if (pass_name == "vector-dce") {
458 RegisterPass(CreateVectorDCEPass());
459 } else if (pass_name == "loop-unroll-partial") {
460 int factor = (pass_args.size() > 0) ? atoi(pass_args.c_str()) : 0;
461 if (factor > 0) {
462 RegisterPass(CreateLoopUnrollPass(false, factor));
463 } else {
464 Error(consumer(), nullptr, {},
465 "--loop-unroll-partial must have a positive integer argument");
466 return false;
467 }
468 } else if (pass_name == "loop-peeling") {
469 RegisterPass(CreateLoopPeelingPass());
470 } else if (pass_name == "loop-peeling-threshold") {
471 int factor = (pass_args.size() > 0) ? atoi(pass_args.c_str()) : 0;
472 if (factor > 0) {
473 opt::LoopPeelingPass::SetLoopPeelingThreshold(factor);
474 } else {
475 Error(consumer(), nullptr, {},
476 "--loop-peeling-threshold must have a positive integer argument");
477 return false;
478 }
479 } else if (pass_name == "ccp") {
480 RegisterPass(CreateCCPPass());
481 } else if (pass_name == "code-sink") {
482 RegisterPass(CreateCodeSinkingPass());
Ben Claytonb73b7602019-07-29 13:56:13 +0100483 } else if (pass_name == "fix-storage-class") {
484 RegisterPass(CreateFixStorageClassPass());
Chris Forbescc5697f2019-01-30 11:54:08 -0800485 } else if (pass_name == "O") {
486 RegisterPerformancePasses();
487 } else if (pass_name == "Os") {
488 RegisterSizePasses();
489 } else if (pass_name == "legalize-hlsl") {
490 RegisterLegalizationPasses();
Ben Claytond0f684e2019-08-30 22:36:08 +0100491 } else if (pass_name == "graphics-robust-access") {
492 RegisterPass(CreateGraphicsRobustAccessPass());
493 } else if (pass_name == "wrap-opkill") {
494 RegisterPass(CreateWrapOpKillPass());
495 } else if (pass_name == "amd-ext-to-khr") {
496 RegisterPass(CreateAmdExtToKhrPass());
Chris Forbescc5697f2019-01-30 11:54:08 -0800497 } else {
498 Errorf(consumer(), nullptr, {},
499 "Unknown flag '--%s'. Use --help for a list of valid flags",
500 pass_name.c_str());
501 return false;
502 }
503
504 return true;
505}
506
507void Optimizer::SetTargetEnv(const spv_target_env env) {
508 impl_->target_env = env;
509}
510
511bool Optimizer::Run(const uint32_t* original_binary,
512 const size_t original_binary_size,
513 std::vector<uint32_t>* optimized_binary) const {
514 return Run(original_binary, original_binary_size, optimized_binary,
515 OptimizerOptions());
516}
517
518bool Optimizer::Run(const uint32_t* original_binary,
519 const size_t original_binary_size,
520 std::vector<uint32_t>* optimized_binary,
521 const ValidatorOptions& validator_options,
522 bool skip_validation) const {
523 OptimizerOptions opt_options;
524 opt_options.set_run_validator(!skip_validation);
525 opt_options.set_validator_options(validator_options);
526 return Run(original_binary, original_binary_size, optimized_binary,
527 opt_options);
528}
529
530bool Optimizer::Run(const uint32_t* original_binary,
531 const size_t original_binary_size,
532 std::vector<uint32_t>* optimized_binary,
533 const spv_optimizer_options opt_options) const {
534 spvtools::SpirvTools tools(impl_->target_env);
535 tools.SetMessageConsumer(impl_->pass_manager.consumer());
536 if (opt_options->run_validator_ &&
537 !tools.Validate(original_binary, original_binary_size,
538 &opt_options->val_options_)) {
539 return false;
540 }
541
542 std::unique_ptr<opt::IRContext> context = BuildModule(
543 impl_->target_env, consumer(), original_binary, original_binary_size);
544 if (context == nullptr) return false;
545
546 context->set_max_id_bound(opt_options->max_id_bound_);
Ben Claytonb73b7602019-07-29 13:56:13 +0100547 context->set_preserve_bindings(opt_options->preserve_bindings_);
548 context->set_preserve_spec_constants(opt_options->preserve_spec_constants_);
Chris Forbescc5697f2019-01-30 11:54:08 -0800549
Ben Claytonb73b7602019-07-29 13:56:13 +0100550 impl_->pass_manager.SetValidatorOptions(&opt_options->val_options_);
551 impl_->pass_manager.SetTargetEnv(impl_->target_env);
Chris Forbescc5697f2019-01-30 11:54:08 -0800552 auto status = impl_->pass_manager.Run(context.get());
Ben Claytonb73b7602019-07-29 13:56:13 +0100553
Ben Claytond0f684e2019-08-30 22:36:08 +0100554 if (status == opt::Pass::Status::Failure) {
555 return false;
Ben Claytonb73b7602019-07-29 13:56:13 +0100556 }
557
Ben Claytond0f684e2019-08-30 22:36:08 +0100558#ifndef NDEBUG
Alexis Hetub8a77462020-03-27 07:59:09 -0400559 // We do not keep the result id of DebugScope in struct DebugScope.
Alexis Hetu3eb4dd82020-10-29 21:37:20 -0400560 // Instead, we assign random ids for them, which results in integrity
Ben Clayton745997b2021-01-21 22:51:51 +0000561 // check failures. In addition, propagating the OpLine/OpNoLine to preserve
562 // the debug information through transformations results in integrity
Alexis Hetu3eb4dd82020-10-29 21:37:20 -0400563 // check failures. We want to skip the integrity check when the module
Ben Clayton745997b2021-01-21 22:51:51 +0000564 // contains DebugScope or OpLine/OpNoLine instructions.
Alexis Hetub8a77462020-03-27 07:59:09 -0400565 if (status == opt::Pass::Status::SuccessWithoutChange &&
Ben Clayton745997b2021-01-21 22:51:51 +0000566 !context->module()->ContainsDebugInfo()) {
Ben Claytond552f632019-11-18 11:18:41 +0000567 std::vector<uint32_t> optimized_binary_with_nop;
568 context->module()->ToBinary(&optimized_binary_with_nop,
569 /* skip_nop = */ false);
570 assert(optimized_binary_with_nop.size() == original_binary_size &&
571 "Binary size unexpectedly changed despite the optimizer saying "
572 "there was no change");
573 assert(memcmp(optimized_binary_with_nop.data(), original_binary,
574 original_binary_size) == 0 &&
575 "Binary content unexpectedly changed despite the optimizer saying "
576 "there was no change");
Ben Claytond0f684e2019-08-30 22:36:08 +0100577 }
578#endif // !NDEBUG
579
Ben Claytond552f632019-11-18 11:18:41 +0000580 // Note that |original_binary| and |optimized_binary| may share the same
581 // buffer and the below will invalidate |original_binary|.
582 optimized_binary->clear();
583 context->module()->ToBinary(optimized_binary, /* skip_nop = */ true);
584
Ben Claytond0f684e2019-08-30 22:36:08 +0100585 return true;
Chris Forbescc5697f2019-01-30 11:54:08 -0800586}
587
588Optimizer& Optimizer::SetPrintAll(std::ostream* out) {
589 impl_->pass_manager.SetPrintAll(out);
590 return *this;
591}
592
593Optimizer& Optimizer::SetTimeReport(std::ostream* out) {
594 impl_->pass_manager.SetTimeReport(out);
595 return *this;
596}
597
Ben Claytonb73b7602019-07-29 13:56:13 +0100598Optimizer& Optimizer::SetValidateAfterAll(bool validate) {
599 impl_->pass_manager.SetValidateAfterAll(validate);
600 return *this;
601}
602
Chris Forbescc5697f2019-01-30 11:54:08 -0800603Optimizer::PassToken CreateNullPass() {
604 return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::NullPass>());
605}
606
607Optimizer::PassToken CreateStripDebugInfoPass() {
608 return MakeUnique<Optimizer::PassToken::Impl>(
609 MakeUnique<opt::StripDebugInfoPass>());
610}
611
612Optimizer::PassToken CreateStripReflectInfoPass() {
613 return MakeUnique<Optimizer::PassToken::Impl>(
614 MakeUnique<opt::StripReflectInfoPass>());
615}
616
617Optimizer::PassToken CreateEliminateDeadFunctionsPass() {
618 return MakeUnique<Optimizer::PassToken::Impl>(
619 MakeUnique<opt::EliminateDeadFunctionsPass>());
620}
621
Ben Claytonb73b7602019-07-29 13:56:13 +0100622Optimizer::PassToken CreateEliminateDeadMembersPass() {
623 return MakeUnique<Optimizer::PassToken::Impl>(
624 MakeUnique<opt::EliminateDeadMembersPass>());
625}
626
Chris Forbescc5697f2019-01-30 11:54:08 -0800627Optimizer::PassToken CreateSetSpecConstantDefaultValuePass(
628 const std::unordered_map<uint32_t, std::string>& id_value_map) {
629 return MakeUnique<Optimizer::PassToken::Impl>(
630 MakeUnique<opt::SetSpecConstantDefaultValuePass>(id_value_map));
631}
632
633Optimizer::PassToken CreateSetSpecConstantDefaultValuePass(
634 const std::unordered_map<uint32_t, std::vector<uint32_t>>& id_value_map) {
635 return MakeUnique<Optimizer::PassToken::Impl>(
636 MakeUnique<opt::SetSpecConstantDefaultValuePass>(id_value_map));
637}
638
639Optimizer::PassToken CreateFlattenDecorationPass() {
640 return MakeUnique<Optimizer::PassToken::Impl>(
641 MakeUnique<opt::FlattenDecorationPass>());
642}
643
644Optimizer::PassToken CreateFreezeSpecConstantValuePass() {
645 return MakeUnique<Optimizer::PassToken::Impl>(
646 MakeUnique<opt::FreezeSpecConstantValuePass>());
647}
648
649Optimizer::PassToken CreateFoldSpecConstantOpAndCompositePass() {
650 return MakeUnique<Optimizer::PassToken::Impl>(
651 MakeUnique<opt::FoldSpecConstantOpAndCompositePass>());
652}
653
654Optimizer::PassToken CreateUnifyConstantPass() {
655 return MakeUnique<Optimizer::PassToken::Impl>(
656 MakeUnique<opt::UnifyConstantPass>());
657}
658
659Optimizer::PassToken CreateEliminateDeadConstantPass() {
660 return MakeUnique<Optimizer::PassToken::Impl>(
661 MakeUnique<opt::EliminateDeadConstantPass>());
662}
663
664Optimizer::PassToken CreateDeadVariableEliminationPass() {
665 return MakeUnique<Optimizer::PassToken::Impl>(
666 MakeUnique<opt::DeadVariableElimination>());
667}
668
669Optimizer::PassToken CreateStrengthReductionPass() {
670 return MakeUnique<Optimizer::PassToken::Impl>(
671 MakeUnique<opt::StrengthReductionPass>());
672}
673
674Optimizer::PassToken CreateBlockMergePass() {
675 return MakeUnique<Optimizer::PassToken::Impl>(
676 MakeUnique<opt::BlockMergePass>());
677}
678
679Optimizer::PassToken CreateInlineExhaustivePass() {
680 return MakeUnique<Optimizer::PassToken::Impl>(
681 MakeUnique<opt::InlineExhaustivePass>());
682}
683
684Optimizer::PassToken CreateInlineOpaquePass() {
685 return MakeUnique<Optimizer::PassToken::Impl>(
686 MakeUnique<opt::InlineOpaquePass>());
687}
688
689Optimizer::PassToken CreateLocalAccessChainConvertPass() {
690 return MakeUnique<Optimizer::PassToken::Impl>(
691 MakeUnique<opt::LocalAccessChainConvertPass>());
692}
693
694Optimizer::PassToken CreateLocalSingleBlockLoadStoreElimPass() {
695 return MakeUnique<Optimizer::PassToken::Impl>(
696 MakeUnique<opt::LocalSingleBlockLoadStoreElimPass>());
697}
698
699Optimizer::PassToken CreateLocalSingleStoreElimPass() {
700 return MakeUnique<Optimizer::PassToken::Impl>(
701 MakeUnique<opt::LocalSingleStoreElimPass>());
702}
703
704Optimizer::PassToken CreateInsertExtractElimPass() {
705 return MakeUnique<Optimizer::PassToken::Impl>(
706 MakeUnique<opt::SimplificationPass>());
707}
708
709Optimizer::PassToken CreateDeadInsertElimPass() {
710 return MakeUnique<Optimizer::PassToken::Impl>(
711 MakeUnique<opt::DeadInsertElimPass>());
712}
713
714Optimizer::PassToken CreateDeadBranchElimPass() {
715 return MakeUnique<Optimizer::PassToken::Impl>(
716 MakeUnique<opt::DeadBranchElimPass>());
717}
718
719Optimizer::PassToken CreateLocalMultiStoreElimPass() {
720 return MakeUnique<Optimizer::PassToken::Impl>(
Ben Claytond552f632019-11-18 11:18:41 +0000721 MakeUnique<opt::SSARewritePass>());
Chris Forbescc5697f2019-01-30 11:54:08 -0800722}
723
724Optimizer::PassToken CreateAggressiveDCEPass() {
725 return MakeUnique<Optimizer::PassToken::Impl>(
726 MakeUnique<opt::AggressiveDCEPass>());
727}
728
Alexis Hetu7975f152020-11-02 11:08:33 -0500729Optimizer::PassToken CreatePropagateLineInfoPass() {
730 return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::EmptyPass>());
731}
732
733Optimizer::PassToken CreateRedundantLineInfoElimPass() {
734 return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::EmptyPass>());
735}
736
Chris Forbescc5697f2019-01-30 11:54:08 -0800737Optimizer::PassToken CreateCompactIdsPass() {
738 return MakeUnique<Optimizer::PassToken::Impl>(
739 MakeUnique<opt::CompactIdsPass>());
740}
741
742Optimizer::PassToken CreateMergeReturnPass() {
743 return MakeUnique<Optimizer::PassToken::Impl>(
744 MakeUnique<opt::MergeReturnPass>());
745}
746
747std::vector<const char*> Optimizer::GetPassNames() const {
748 std::vector<const char*> v;
749 for (uint32_t i = 0; i < impl_->pass_manager.NumPasses(); i++) {
750 v.push_back(impl_->pass_manager.GetPass(i)->name());
751 }
752 return v;
753}
754
755Optimizer::PassToken CreateCFGCleanupPass() {
756 return MakeUnique<Optimizer::PassToken::Impl>(
757 MakeUnique<opt::CFGCleanupPass>());
758}
759
760Optimizer::PassToken CreateLocalRedundancyEliminationPass() {
761 return MakeUnique<Optimizer::PassToken::Impl>(
762 MakeUnique<opt::LocalRedundancyEliminationPass>());
763}
764
765Optimizer::PassToken CreateLoopFissionPass(size_t threshold) {
766 return MakeUnique<Optimizer::PassToken::Impl>(
767 MakeUnique<opt::LoopFissionPass>(threshold));
768}
769
770Optimizer::PassToken CreateLoopFusionPass(size_t max_registers_per_loop) {
771 return MakeUnique<Optimizer::PassToken::Impl>(
772 MakeUnique<opt::LoopFusionPass>(max_registers_per_loop));
773}
774
775Optimizer::PassToken CreateLoopInvariantCodeMotionPass() {
776 return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::LICMPass>());
777}
778
779Optimizer::PassToken CreateLoopPeelingPass() {
780 return MakeUnique<Optimizer::PassToken::Impl>(
781 MakeUnique<opt::LoopPeelingPass>());
782}
783
784Optimizer::PassToken CreateLoopUnswitchPass() {
785 return MakeUnique<Optimizer::PassToken::Impl>(
786 MakeUnique<opt::LoopUnswitchPass>());
787}
788
789Optimizer::PassToken CreateRedundancyEliminationPass() {
790 return MakeUnique<Optimizer::PassToken::Impl>(
791 MakeUnique<opt::RedundancyEliminationPass>());
792}
793
794Optimizer::PassToken CreateRemoveDuplicatesPass() {
795 return MakeUnique<Optimizer::PassToken::Impl>(
796 MakeUnique<opt::RemoveDuplicatesPass>());
797}
798
799Optimizer::PassToken CreateScalarReplacementPass(uint32_t size_limit) {
800 return MakeUnique<Optimizer::PassToken::Impl>(
801 MakeUnique<opt::ScalarReplacementPass>(size_limit));
802}
803
804Optimizer::PassToken CreatePrivateToLocalPass() {
805 return MakeUnique<Optimizer::PassToken::Impl>(
806 MakeUnique<opt::PrivateToLocalPass>());
807}
808
809Optimizer::PassToken CreateCCPPass() {
810 return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::CCPPass>());
811}
812
813Optimizer::PassToken CreateWorkaround1209Pass() {
814 return MakeUnique<Optimizer::PassToken::Impl>(
815 MakeUnique<opt::Workaround1209>());
816}
817
818Optimizer::PassToken CreateIfConversionPass() {
819 return MakeUnique<Optimizer::PassToken::Impl>(
820 MakeUnique<opt::IfConversion>());
821}
822
823Optimizer::PassToken CreateReplaceInvalidOpcodePass() {
824 return MakeUnique<Optimizer::PassToken::Impl>(
825 MakeUnique<opt::ReplaceInvalidOpcodePass>());
826}
827
828Optimizer::PassToken CreateSimplificationPass() {
829 return MakeUnique<Optimizer::PassToken::Impl>(
830 MakeUnique<opt::SimplificationPass>());
831}
832
833Optimizer::PassToken CreateLoopUnrollPass(bool fully_unroll, int factor) {
834 return MakeUnique<Optimizer::PassToken::Impl>(
835 MakeUnique<opt::LoopUnroller>(fully_unroll, factor));
836}
837
838Optimizer::PassToken CreateSSARewritePass() {
839 return MakeUnique<Optimizer::PassToken::Impl>(
840 MakeUnique<opt::SSARewritePass>());
841}
842
843Optimizer::PassToken CreateCopyPropagateArraysPass() {
844 return MakeUnique<Optimizer::PassToken::Impl>(
845 MakeUnique<opt::CopyPropagateArrays>());
846}
847
848Optimizer::PassToken CreateVectorDCEPass() {
849 return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::VectorDCE>());
850}
851
852Optimizer::PassToken CreateReduceLoadSizePass() {
853 return MakeUnique<Optimizer::PassToken::Impl>(
854 MakeUnique<opt::ReduceLoadSize>());
855}
856
857Optimizer::PassToken CreateCombineAccessChainsPass() {
858 return MakeUnique<Optimizer::PassToken::Impl>(
859 MakeUnique<opt::CombineAccessChains>());
860}
861
862Optimizer::PassToken CreateUpgradeMemoryModelPass() {
863 return MakeUnique<Optimizer::PassToken::Impl>(
864 MakeUnique<opt::UpgradeMemoryModel>());
865}
866
Ben Clayton745997b2021-01-21 22:51:51 +0000867Optimizer::PassToken CreateInstBindlessCheckPass(
868 uint32_t desc_set, uint32_t shader_id, bool desc_length_enable,
869 bool desc_init_enable, bool buff_oob_enable, bool texbuff_oob_enable) {
Chris Forbescc5697f2019-01-30 11:54:08 -0800870 return MakeUnique<Optimizer::PassToken::Impl>(
Ben Clayton38e46912020-05-26 15:56:15 +0100871 MakeUnique<opt::InstBindlessCheckPass>(
Ben Clayton745997b2021-01-21 22:51:51 +0000872 desc_set, shader_id, desc_length_enable, desc_init_enable,
873 buff_oob_enable, texbuff_oob_enable,
874 desc_length_enable || desc_init_enable || buff_oob_enable));
Chris Forbescc5697f2019-01-30 11:54:08 -0800875}
876
Alexis Hetub8a77462020-03-27 07:59:09 -0400877Optimizer::PassToken CreateInstDebugPrintfPass(uint32_t desc_set,
878 uint32_t shader_id) {
879 return MakeUnique<Optimizer::PassToken::Impl>(
880 MakeUnique<opt::InstDebugPrintfPass>(desc_set, shader_id));
881}
882
Ben Claytond0f684e2019-08-30 22:36:08 +0100883Optimizer::PassToken CreateInstBuffAddrCheckPass(uint32_t desc_set,
Ben Clayton38e46912020-05-26 15:56:15 +0100884 uint32_t shader_id) {
Ben Claytond0f684e2019-08-30 22:36:08 +0100885 return MakeUnique<Optimizer::PassToken::Impl>(
Ben Clayton38e46912020-05-26 15:56:15 +0100886 MakeUnique<opt::InstBuffAddrCheckPass>(desc_set, shader_id));
Ben Claytond0f684e2019-08-30 22:36:08 +0100887}
888
Ben Claytond552f632019-11-18 11:18:41 +0000889Optimizer::PassToken CreateConvertRelaxedToHalfPass() {
890 return MakeUnique<Optimizer::PassToken::Impl>(
891 MakeUnique<opt::ConvertToHalfPass>());
892}
893
894Optimizer::PassToken CreateRelaxFloatOpsPass() {
895 return MakeUnique<Optimizer::PassToken::Impl>(
896 MakeUnique<opt::RelaxFloatOpsPass>());
897}
898
Chris Forbescc5697f2019-01-30 11:54:08 -0800899Optimizer::PassToken CreateCodeSinkingPass() {
900 return MakeUnique<Optimizer::PassToken::Impl>(
901 MakeUnique<opt::CodeSinkingPass>());
902}
903
Ben Claytonb73b7602019-07-29 13:56:13 +0100904Optimizer::PassToken CreateFixStorageClassPass() {
905 return MakeUnique<Optimizer::PassToken::Impl>(
906 MakeUnique<opt::FixStorageClass>());
907}
908
Ben Claytond0f684e2019-08-30 22:36:08 +0100909Optimizer::PassToken CreateGraphicsRobustAccessPass() {
910 return MakeUnique<Optimizer::PassToken::Impl>(
911 MakeUnique<opt::GraphicsRobustAccessPass>());
912}
913
914Optimizer::PassToken CreateDescriptorScalarReplacementPass() {
915 return MakeUnique<Optimizer::PassToken::Impl>(
916 MakeUnique<opt::DescriptorScalarReplacement>());
917}
918
919Optimizer::PassToken CreateWrapOpKillPass() {
920 return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::WrapOpKill>());
921}
922
923Optimizer::PassToken CreateAmdExtToKhrPass() {
924 return MakeUnique<Optimizer::PassToken::Impl>(
925 MakeUnique<opt::AmdExtensionToKhrPass>());
926}
927
Chris Forbescc5697f2019-01-30 11:54:08 -0800928} // namespace spvtools