/src/spirv-tools/source/opt/optimizer.cpp
Line | Count | Source (jump to first uncovered line) |
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 <charconv> |
19 | | #include <memory> |
20 | | #include <string> |
21 | | #include <system_error> |
22 | | #include <unordered_map> |
23 | | #include <utility> |
24 | | #include <vector> |
25 | | |
26 | | #include "source/opt/build_module.h" |
27 | | #include "source/opt/graphics_robust_access_pass.h" |
28 | | #include "source/opt/log.h" |
29 | | #include "source/opt/pass_manager.h" |
30 | | #include "source/opt/passes.h" |
31 | | #include "source/spirv_optimizer_options.h" |
32 | | #include "source/util/make_unique.h" |
33 | | #include "source/util/string_utils.h" |
34 | | |
35 | | namespace spvtools { |
36 | | |
37 | | std::vector<std::string> GetVectorOfStrings(const char** strings, |
38 | 0 | const size_t string_count) { |
39 | 0 | std::vector<std::string> result; |
40 | 0 | for (uint32_t i = 0; i < string_count; i++) { |
41 | 0 | result.emplace_back(strings[i]); |
42 | 0 | } |
43 | 0 | return result; |
44 | 0 | } |
45 | | |
46 | | struct Optimizer::PassToken::Impl { |
47 | 689k | Impl(std::unique_ptr<opt::Pass> p) : pass(std::move(p)) {} |
48 | | |
49 | | std::unique_ptr<opt::Pass> pass; // Internal implementation pass. |
50 | | }; |
51 | | |
52 | | Optimizer::PassToken::PassToken( |
53 | | std::unique_ptr<Optimizer::PassToken::Impl> impl) |
54 | 689k | : impl_(std::move(impl)) {} |
55 | | |
56 | | Optimizer::PassToken::PassToken(std::unique_ptr<opt::Pass>&& pass) |
57 | 0 | : impl_(MakeUnique<Optimizer::PassToken::Impl>(std::move(pass))) {} |
58 | | |
59 | | Optimizer::PassToken::PassToken(PassToken&& that) |
60 | 0 | : impl_(std::move(that.impl_)) {} |
61 | | |
62 | 0 | Optimizer::PassToken& Optimizer::PassToken::operator=(PassToken&& that) { |
63 | 0 | impl_ = std::move(that.impl_); |
64 | 0 | return *this; |
65 | 0 | } |
66 | | |
67 | 689k | Optimizer::PassToken::~PassToken() {} |
68 | | |
69 | | struct Optimizer::Impl { |
70 | 24.2k | explicit Impl(spv_target_env env) : target_env(env), pass_manager() {} |
71 | | |
72 | | spv_target_env target_env; // Target environment. |
73 | | opt::PassManager pass_manager; // Internal implementation pass manager. |
74 | | std::unordered_set<uint32_t> live_locs; // Arg to debug dead output passes |
75 | | }; |
76 | | |
77 | 24.2k | Optimizer::Optimizer(spv_target_env env) : impl_(new Impl(env)) { |
78 | 24.2k | assert(env != SPV_ENV_WEBGPU_0); |
79 | 24.2k | } |
80 | | |
81 | 24.2k | Optimizer::~Optimizer() {} |
82 | | |
83 | 24.2k | void Optimizer::SetMessageConsumer(MessageConsumer c) { |
84 | | // All passes' message consumer needs to be updated. |
85 | 24.2k | for (uint32_t i = 0; i < impl_->pass_manager.NumPasses(); ++i) { |
86 | 0 | impl_->pass_manager.GetPass(i)->SetMessageConsumer(c); |
87 | 0 | } |
88 | 24.2k | impl_->pass_manager.SetMessageConsumer(std::move(c)); |
89 | 24.2k | } |
90 | | |
91 | 700k | const MessageConsumer& Optimizer::consumer() const { |
92 | 700k | return impl_->pass_manager.consumer(); |
93 | 700k | } |
94 | | |
95 | 689k | Optimizer& Optimizer::RegisterPass(PassToken&& p) { |
96 | | // Change to use the pass manager's consumer. |
97 | 689k | p.impl_->pass->SetMessageConsumer(consumer()); |
98 | 689k | impl_->pass_manager.AddPass(std::move(p.impl_->pass)); |
99 | 689k | return *this; |
100 | 689k | } |
101 | | |
102 | | // The legalization passes take a spir-v shader generated by an HLSL front-end |
103 | | // and turn it into a valid vulkan spir-v shader. There are two ways in which |
104 | | // the code will be invalid at the start: |
105 | | // |
106 | | // 1) There will be opaque objects, like images, which will be passed around |
107 | | // in intermediate objects. Valid spir-v will have to replace the use of |
108 | | // the opaque object with an intermediate object that is the result of the |
109 | | // load of the global opaque object. |
110 | | // |
111 | | // 2) There will be variables that contain pointers to structured or uniform |
112 | | // buffers. It be legal, the variables must be eliminated, and the |
113 | | // references to the structured buffers must use the result of OpVariable |
114 | | // in the Uniform storage class. |
115 | | // |
116 | | // Optimization in this list must accept shaders with these relaxation of the |
117 | | // rules. There is not guarantee that this list of optimizations is able to |
118 | | // legalize all inputs, but it is on a best effort basis. |
119 | | // |
120 | | // The legalization problem is essentially a very general copy propagation |
121 | | // problem. The optimization we use are all used to either do copy propagation |
122 | | // or enable more copy propagation. |
123 | 9.22k | Optimizer& Optimizer::RegisterLegalizationPasses(bool preserve_interface) { |
124 | 9.22k | return |
125 | | // Wrap OpKill instructions so all other code can be inlined. |
126 | 9.22k | RegisterPass(CreateWrapOpKillPass()) |
127 | | // Remove unreachable block so that merge return works. |
128 | 9.22k | .RegisterPass(CreateDeadBranchElimPass()) |
129 | | // Merge the returns so we can inline. |
130 | 9.22k | .RegisterPass(CreateMergeReturnPass()) |
131 | | // Make sure uses and definitions are in the same function. |
132 | 9.22k | .RegisterPass(CreateInlineExhaustivePass()) |
133 | | // Make private variable function scope |
134 | 9.22k | .RegisterPass(CreateEliminateDeadFunctionsPass()) |
135 | 9.22k | .RegisterPass(CreatePrivateToLocalPass()) |
136 | | // Fix up the storage classes that DXC may have purposely generated |
137 | | // incorrectly. All functions are inlined, and a lot of dead code has |
138 | | // been removed. |
139 | 9.22k | .RegisterPass(CreateFixStorageClassPass()) |
140 | | // Propagate the value stored to the loads in very simple cases. |
141 | 9.22k | .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass()) |
142 | 9.22k | .RegisterPass(CreateLocalSingleStoreElimPass()) |
143 | 9.22k | .RegisterPass(CreateAggressiveDCEPass(preserve_interface)) |
144 | | // Split up aggregates so they are easier to deal with. |
145 | 9.22k | .RegisterPass(CreateScalarReplacementPass(0)) |
146 | | // Remove loads and stores so everything is in intermediate values. |
147 | | // Takes care of copy propagation of non-members. |
148 | 9.22k | .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass()) |
149 | 9.22k | .RegisterPass(CreateLocalSingleStoreElimPass()) |
150 | 9.22k | .RegisterPass(CreateAggressiveDCEPass(preserve_interface)) |
151 | 9.22k | .RegisterPass(CreateLocalMultiStoreElimPass()) |
152 | 9.22k | .RegisterPass(CreateAggressiveDCEPass(preserve_interface)) |
153 | | // Propagate constants to get as many constant conditions on branches |
154 | | // as possible. |
155 | 9.22k | .RegisterPass(CreateCCPPass()) |
156 | 9.22k | .RegisterPass(CreateLoopUnrollPass(true)) |
157 | 9.22k | .RegisterPass(CreateDeadBranchElimPass()) |
158 | | // Copy propagate members. Cleans up code sequences generated by |
159 | | // scalar replacement. Also important for removing OpPhi nodes. |
160 | 9.22k | .RegisterPass(CreateSimplificationPass()) |
161 | 9.22k | .RegisterPass(CreateAggressiveDCEPass(preserve_interface)) |
162 | 9.22k | .RegisterPass(CreateCopyPropagateArraysPass()) |
163 | | // May need loop unrolling here see |
164 | | // https://github.com/Microsoft/DirectXShaderCompiler/pull/930 |
165 | | // Get rid of unused code that contain traces of illegal code |
166 | | // or unused references to unbound external objects |
167 | 9.22k | .RegisterPass(CreateVectorDCEPass()) |
168 | 9.22k | .RegisterPass(CreateDeadInsertElimPass()) |
169 | 9.22k | .RegisterPass(CreateReduceLoadSizePass()) |
170 | 9.22k | .RegisterPass(CreateAggressiveDCEPass(preserve_interface)) |
171 | 9.22k | .RegisterPass(CreateRemoveUnusedInterfaceVariablesPass()) |
172 | 9.22k | .RegisterPass(CreateInterpolateFixupPass()) |
173 | 9.22k | .RegisterPass(CreateInvocationInterlockPlacementPass()) |
174 | 9.22k | .RegisterPass(CreateOpExtInstWithForwardReferenceFixupPass()); |
175 | 9.22k | } |
176 | | |
177 | 9.22k | Optimizer& Optimizer::RegisterLegalizationPasses() { |
178 | 9.22k | return RegisterLegalizationPasses(false); |
179 | 9.22k | } |
180 | | |
181 | 1.84k | Optimizer& Optimizer::RegisterPerformancePasses(bool preserve_interface) { |
182 | 1.84k | return RegisterPass(CreateWrapOpKillPass()) |
183 | 1.84k | .RegisterPass(CreateDeadBranchElimPass()) |
184 | 1.84k | .RegisterPass(CreateMergeReturnPass()) |
185 | 1.84k | .RegisterPass(CreateInlineExhaustivePass()) |
186 | 1.84k | .RegisterPass(CreateEliminateDeadFunctionsPass()) |
187 | 1.84k | .RegisterPass(CreateAggressiveDCEPass(preserve_interface)) |
188 | 1.84k | .RegisterPass(CreatePrivateToLocalPass()) |
189 | 1.84k | .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass()) |
190 | 1.84k | .RegisterPass(CreateLocalSingleStoreElimPass()) |
191 | 1.84k | .RegisterPass(CreateAggressiveDCEPass(preserve_interface)) |
192 | 1.84k | .RegisterPass(CreateScalarReplacementPass()) |
193 | 1.84k | .RegisterPass(CreateLocalAccessChainConvertPass()) |
194 | 1.84k | .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass()) |
195 | 1.84k | .RegisterPass(CreateLocalSingleStoreElimPass()) |
196 | 1.84k | .RegisterPass(CreateAggressiveDCEPass(preserve_interface)) |
197 | 1.84k | .RegisterPass(CreateLocalMultiStoreElimPass()) |
198 | 1.84k | .RegisterPass(CreateAggressiveDCEPass(preserve_interface)) |
199 | 1.84k | .RegisterPass(CreateCCPPass()) |
200 | 1.84k | .RegisterPass(CreateAggressiveDCEPass(preserve_interface)) |
201 | 1.84k | .RegisterPass(CreateLoopUnrollPass(true)) |
202 | 1.84k | .RegisterPass(CreateDeadBranchElimPass()) |
203 | 1.84k | .RegisterPass(CreateRedundancyEliminationPass()) |
204 | 1.84k | .RegisterPass(CreateCombineAccessChainsPass()) |
205 | 1.84k | .RegisterPass(CreateSimplificationPass()) |
206 | 1.84k | .RegisterPass(CreateScalarReplacementPass()) |
207 | 1.84k | .RegisterPass(CreateLocalAccessChainConvertPass()) |
208 | 1.84k | .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass()) |
209 | 1.84k | .RegisterPass(CreateLocalSingleStoreElimPass()) |
210 | 1.84k | .RegisterPass(CreateAggressiveDCEPass(preserve_interface)) |
211 | 1.84k | .RegisterPass(CreateSSARewritePass()) |
212 | 1.84k | .RegisterPass(CreateAggressiveDCEPass(preserve_interface)) |
213 | 1.84k | .RegisterPass(CreateVectorDCEPass()) |
214 | 1.84k | .RegisterPass(CreateDeadInsertElimPass()) |
215 | 1.84k | .RegisterPass(CreateDeadBranchElimPass()) |
216 | 1.84k | .RegisterPass(CreateSimplificationPass()) |
217 | 1.84k | .RegisterPass(CreateIfConversionPass()) |
218 | 1.84k | .RegisterPass(CreateCopyPropagateArraysPass()) |
219 | 1.84k | .RegisterPass(CreateReduceLoadSizePass()) |
220 | 1.84k | .RegisterPass(CreateAggressiveDCEPass(preserve_interface)) |
221 | 1.84k | .RegisterPass(CreateBlockMergePass()) |
222 | 1.84k | .RegisterPass(CreateRedundancyEliminationPass()) |
223 | 1.84k | .RegisterPass(CreateDeadBranchElimPass()) |
224 | 1.84k | .RegisterPass(CreateBlockMergePass()) |
225 | 1.84k | .RegisterPass(CreateSimplificationPass()); |
226 | 1.84k | } |
227 | | |
228 | 1.84k | Optimizer& Optimizer::RegisterPerformancePasses() { |
229 | 1.84k | return RegisterPerformancePasses(false); |
230 | 1.84k | } |
231 | | |
232 | 10.0k | Optimizer& Optimizer::RegisterSizePasses(bool preserve_interface) { |
233 | 10.0k | return RegisterPass(CreateWrapOpKillPass()) |
234 | 10.0k | .RegisterPass(CreateDeadBranchElimPass()) |
235 | 10.0k | .RegisterPass(CreateMergeReturnPass()) |
236 | 10.0k | .RegisterPass(CreateInlineExhaustivePass()) |
237 | 10.0k | .RegisterPass(CreateEliminateDeadFunctionsPass()) |
238 | 10.0k | .RegisterPass(CreatePrivateToLocalPass()) |
239 | 10.0k | .RegisterPass(CreateScalarReplacementPass(0)) |
240 | 10.0k | .RegisterPass(CreateLocalMultiStoreElimPass()) |
241 | 10.0k | .RegisterPass(CreateCCPPass()) |
242 | 10.0k | .RegisterPass(CreateLoopUnrollPass(true)) |
243 | 10.0k | .RegisterPass(CreateDeadBranchElimPass()) |
244 | 10.0k | .RegisterPass(CreateSimplificationPass()) |
245 | 10.0k | .RegisterPass(CreateScalarReplacementPass(0)) |
246 | 10.0k | .RegisterPass(CreateLocalSingleStoreElimPass()) |
247 | 10.0k | .RegisterPass(CreateIfConversionPass()) |
248 | 10.0k | .RegisterPass(CreateSimplificationPass()) |
249 | 10.0k | .RegisterPass(CreateAggressiveDCEPass(preserve_interface)) |
250 | 10.0k | .RegisterPass(CreateDeadBranchElimPass()) |
251 | 10.0k | .RegisterPass(CreateBlockMergePass()) |
252 | 10.0k | .RegisterPass(CreateLocalAccessChainConvertPass()) |
253 | 10.0k | .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass()) |
254 | 10.0k | .RegisterPass(CreateAggressiveDCEPass(preserve_interface)) |
255 | 10.0k | .RegisterPass(CreateCopyPropagateArraysPass()) |
256 | 10.0k | .RegisterPass(CreateVectorDCEPass()) |
257 | 10.0k | .RegisterPass(CreateDeadInsertElimPass()) |
258 | 10.0k | .RegisterPass(CreateEliminateDeadMembersPass()) |
259 | 10.0k | .RegisterPass(CreateLocalSingleStoreElimPass()) |
260 | 10.0k | .RegisterPass(CreateBlockMergePass()) |
261 | 10.0k | .RegisterPass(CreateLocalMultiStoreElimPass()) |
262 | 10.0k | .RegisterPass(CreateRedundancyEliminationPass()) |
263 | 10.0k | .RegisterPass(CreateSimplificationPass()) |
264 | 10.0k | .RegisterPass(CreateAggressiveDCEPass(preserve_interface)) |
265 | 10.0k | .RegisterPass(CreateCFGCleanupPass()); |
266 | 10.0k | } |
267 | | |
268 | 10.0k | Optimizer& Optimizer::RegisterSizePasses() { return RegisterSizePasses(false); } |
269 | | |
270 | 0 | bool Optimizer::RegisterPassesFromFlags(const std::vector<std::string>& flags) { |
271 | 0 | return RegisterPassesFromFlags(flags, false); |
272 | 0 | } |
273 | | |
274 | | bool Optimizer::RegisterPassesFromFlags(const std::vector<std::string>& flags, |
275 | 0 | bool preserve_interface) { |
276 | 0 | for (const auto& flag : flags) { |
277 | 0 | if (!RegisterPassFromFlag(flag, preserve_interface)) { |
278 | 0 | return false; |
279 | 0 | } |
280 | 0 | } |
281 | | |
282 | 0 | return true; |
283 | 0 | } |
284 | | |
285 | 0 | bool Optimizer::FlagHasValidForm(const std::string& flag) const { |
286 | 0 | if (flag == "-O" || flag == "-Os") { |
287 | 0 | return true; |
288 | 0 | } else if (flag.size() > 2 && flag.substr(0, 2) == "--") { |
289 | 0 | return true; |
290 | 0 | } |
291 | | |
292 | 0 | Errorf(consumer(), nullptr, {}, |
293 | 0 | "%s is not a valid flag. Flag passes should have the form " |
294 | 0 | "'--pass_name[=pass_args]'. Special flag names also accepted: -O " |
295 | 0 | "and -Os.", |
296 | 0 | flag.c_str()); |
297 | 0 | return false; |
298 | 0 | } |
299 | | |
300 | 0 | bool Optimizer::RegisterPassFromFlag(const std::string& flag) { |
301 | 0 | return RegisterPassFromFlag(flag, false); |
302 | 0 | } |
303 | | |
304 | | bool Optimizer::RegisterPassFromFlag(const std::string& flag, |
305 | 0 | bool preserve_interface) { |
306 | 0 | if (!FlagHasValidForm(flag)) { |
307 | 0 | return false; |
308 | 0 | } |
309 | | |
310 | | // Split flags of the form --pass_name=pass_args. |
311 | 0 | auto p = utils::SplitFlagArgs(flag); |
312 | 0 | std::string pass_name = p.first; |
313 | 0 | std::string pass_args = p.second; |
314 | | |
315 | | // FIXME(dnovillo): This should be re-factored so that pass names can be |
316 | | // automatically checked against Pass::name() and PassToken instances created |
317 | | // via a template function. Additionally, class Pass should have a desc() |
318 | | // method that describes the pass (so it can be used in --help). |
319 | | // |
320 | | // Both Pass::name() and Pass::desc() should be static class members so they |
321 | | // can be invoked without creating a pass instance. |
322 | 0 | if (pass_name == "strip-debug") { |
323 | 0 | RegisterPass(CreateStripDebugInfoPass()); |
324 | 0 | } else if (pass_name == "strip-reflect") { |
325 | 0 | RegisterPass(CreateStripReflectInfoPass()); |
326 | 0 | } else if (pass_name == "strip-nonsemantic") { |
327 | 0 | RegisterPass(CreateStripNonSemanticInfoPass()); |
328 | 0 | } else if (pass_name == "fix-opextinst-opcodes") { |
329 | 0 | RegisterPass(CreateOpExtInstWithForwardReferenceFixupPass()); |
330 | 0 | } else if (pass_name == "set-spec-const-default-value") { |
331 | 0 | if (pass_args.size() > 0) { |
332 | 0 | auto spec_ids_vals = |
333 | 0 | opt::SetSpecConstantDefaultValuePass::ParseDefaultValuesString( |
334 | 0 | pass_args.c_str()); |
335 | 0 | if (!spec_ids_vals) { |
336 | 0 | Errorf(consumer(), nullptr, {}, |
337 | 0 | "Invalid argument for --set-spec-const-default-value: %s", |
338 | 0 | pass_args.c_str()); |
339 | 0 | return false; |
340 | 0 | } |
341 | 0 | RegisterPass( |
342 | 0 | CreateSetSpecConstantDefaultValuePass(std::move(*spec_ids_vals))); |
343 | 0 | } else { |
344 | 0 | Errorf(consumer(), nullptr, {}, |
345 | 0 | "Invalid spec constant value string '%s'. Expected a string of " |
346 | 0 | "<spec id>:<default value> pairs.", |
347 | 0 | pass_args.c_str()); |
348 | 0 | return false; |
349 | 0 | } |
350 | 0 | } else if (pass_name == "if-conversion") { |
351 | 0 | RegisterPass(CreateIfConversionPass()); |
352 | 0 | } else if (pass_name == "freeze-spec-const") { |
353 | 0 | RegisterPass(CreateFreezeSpecConstantValuePass()); |
354 | 0 | } else if (pass_name == "inline-entry-points-exhaustive") { |
355 | 0 | RegisterPass(CreateInlineExhaustivePass()); |
356 | 0 | } else if (pass_name == "inline-entry-points-opaque") { |
357 | 0 | RegisterPass(CreateInlineOpaquePass()); |
358 | 0 | } else if (pass_name == "combine-access-chains") { |
359 | 0 | RegisterPass(CreateCombineAccessChainsPass()); |
360 | 0 | } else if (pass_name == "convert-local-access-chains") { |
361 | 0 | RegisterPass(CreateLocalAccessChainConvertPass()); |
362 | 0 | } else if (pass_name == "replace-desc-array-access-using-var-index") { |
363 | 0 | RegisterPass(CreateReplaceDescArrayAccessUsingVarIndexPass()); |
364 | 0 | } else if (pass_name == "spread-volatile-semantics") { |
365 | 0 | RegisterPass(CreateSpreadVolatileSemanticsPass()); |
366 | 0 | } else if (pass_name == "descriptor-scalar-replacement") { |
367 | 0 | RegisterPass(CreateDescriptorScalarReplacementPass()); |
368 | 0 | } else if (pass_name == "descriptor-composite-scalar-replacement") { |
369 | 0 | RegisterPass(CreateDescriptorCompositeScalarReplacementPass()); |
370 | 0 | } else if (pass_name == "descriptor-array-scalar-replacement") { |
371 | 0 | RegisterPass(CreateDescriptorArrayScalarReplacementPass()); |
372 | 0 | } else if (pass_name == "eliminate-dead-code-aggressive") { |
373 | 0 | RegisterPass(CreateAggressiveDCEPass(preserve_interface)); |
374 | 0 | } else if (pass_name == "eliminate-insert-extract") { |
375 | 0 | RegisterPass(CreateInsertExtractElimPass()); |
376 | 0 | } else if (pass_name == "eliminate-local-single-block") { |
377 | 0 | RegisterPass(CreateLocalSingleBlockLoadStoreElimPass()); |
378 | 0 | } else if (pass_name == "eliminate-local-single-store") { |
379 | 0 | RegisterPass(CreateLocalSingleStoreElimPass()); |
380 | 0 | } else if (pass_name == "merge-blocks") { |
381 | 0 | RegisterPass(CreateBlockMergePass()); |
382 | 0 | } else if (pass_name == "merge-return") { |
383 | 0 | RegisterPass(CreateMergeReturnPass()); |
384 | 0 | } else if (pass_name == "eliminate-dead-branches") { |
385 | 0 | RegisterPass(CreateDeadBranchElimPass()); |
386 | 0 | } else if (pass_name == "eliminate-dead-functions") { |
387 | 0 | RegisterPass(CreateEliminateDeadFunctionsPass()); |
388 | 0 | } else if (pass_name == "eliminate-local-multi-store") { |
389 | 0 | RegisterPass(CreateLocalMultiStoreElimPass()); |
390 | 0 | } else if (pass_name == "eliminate-dead-const") { |
391 | 0 | RegisterPass(CreateEliminateDeadConstantPass()); |
392 | 0 | } else if (pass_name == "eliminate-dead-inserts") { |
393 | 0 | RegisterPass(CreateDeadInsertElimPass()); |
394 | 0 | } else if (pass_name == "eliminate-dead-variables") { |
395 | 0 | RegisterPass(CreateDeadVariableEliminationPass()); |
396 | 0 | } else if (pass_name == "eliminate-dead-members") { |
397 | 0 | RegisterPass(CreateEliminateDeadMembersPass()); |
398 | 0 | } else if (pass_name == "fold-spec-const-op-composite") { |
399 | 0 | RegisterPass(CreateFoldSpecConstantOpAndCompositePass()); |
400 | 0 | } else if (pass_name == "loop-unswitch") { |
401 | 0 | RegisterPass(CreateLoopUnswitchPass()); |
402 | 0 | } else if (pass_name == "scalar-replacement") { |
403 | 0 | if (pass_args.size() == 0) { |
404 | 0 | RegisterPass(CreateScalarReplacementPass()); |
405 | 0 | } else { |
406 | 0 | int limit = -1; |
407 | 0 | if (pass_args.find_first_not_of("0123456789") == std::string::npos) { |
408 | 0 | limit = atoi(pass_args.c_str()); |
409 | 0 | } |
410 | |
|
411 | 0 | if (limit >= 0) { |
412 | 0 | RegisterPass(CreateScalarReplacementPass(limit)); |
413 | 0 | } else { |
414 | 0 | Error(consumer(), nullptr, {}, |
415 | 0 | "--scalar-replacement must have no arguments or a non-negative " |
416 | 0 | "integer argument"); |
417 | 0 | return false; |
418 | 0 | } |
419 | 0 | } |
420 | 0 | } else if (pass_name == "strength-reduction") { |
421 | 0 | RegisterPass(CreateStrengthReductionPass()); |
422 | 0 | } else if (pass_name == "unify-const") { |
423 | 0 | RegisterPass(CreateUnifyConstantPass()); |
424 | 0 | } else if (pass_name == "flatten-decorations") { |
425 | 0 | RegisterPass(CreateFlattenDecorationPass()); |
426 | 0 | } else if (pass_name == "compact-ids") { |
427 | 0 | RegisterPass(CreateCompactIdsPass()); |
428 | 0 | } else if (pass_name == "cfg-cleanup") { |
429 | 0 | RegisterPass(CreateCFGCleanupPass()); |
430 | 0 | } else if (pass_name == "local-redundancy-elimination") { |
431 | 0 | RegisterPass(CreateLocalRedundancyEliminationPass()); |
432 | 0 | } else if (pass_name == "loop-invariant-code-motion") { |
433 | 0 | RegisterPass(CreateLoopInvariantCodeMotionPass()); |
434 | 0 | } else if (pass_name == "reduce-load-size") { |
435 | 0 | if (pass_args.size() == 0) { |
436 | 0 | RegisterPass(CreateReduceLoadSizePass()); |
437 | 0 | } else { |
438 | 0 | double load_replacement_threshold = 0.9; |
439 | 0 | if (pass_args.find_first_not_of(".0123456789") == std::string::npos) { |
440 | 0 | load_replacement_threshold = atof(pass_args.c_str()); |
441 | 0 | } |
442 | |
|
443 | 0 | if (load_replacement_threshold >= 0) { |
444 | 0 | RegisterPass(CreateReduceLoadSizePass(load_replacement_threshold)); |
445 | 0 | } else { |
446 | 0 | Error(consumer(), nullptr, {}, |
447 | 0 | "--reduce-load-size must have no arguments or a non-negative " |
448 | 0 | "double argument"); |
449 | 0 | return false; |
450 | 0 | } |
451 | 0 | } |
452 | 0 | } else if (pass_name == "redundancy-elimination") { |
453 | 0 | RegisterPass(CreateRedundancyEliminationPass()); |
454 | 0 | } else if (pass_name == "private-to-local") { |
455 | 0 | RegisterPass(CreatePrivateToLocalPass()); |
456 | 0 | } else if (pass_name == "remove-duplicates") { |
457 | 0 | RegisterPass(CreateRemoveDuplicatesPass()); |
458 | 0 | } else if (pass_name == "workaround-1209") { |
459 | 0 | RegisterPass(CreateWorkaround1209Pass()); |
460 | 0 | } else if (pass_name == "replace-invalid-opcode") { |
461 | 0 | RegisterPass(CreateReplaceInvalidOpcodePass()); |
462 | 0 | } else if (pass_name == "convert-relaxed-to-half") { |
463 | 0 | RegisterPass(CreateConvertRelaxedToHalfPass()); |
464 | 0 | } else if (pass_name == "relax-float-ops") { |
465 | 0 | RegisterPass(CreateRelaxFloatOpsPass()); |
466 | 0 | } else if (pass_name == "simplify-instructions") { |
467 | 0 | RegisterPass(CreateSimplificationPass()); |
468 | 0 | } else if (pass_name == "ssa-rewrite") { |
469 | 0 | RegisterPass(CreateSSARewritePass()); |
470 | 0 | } else if (pass_name == "copy-propagate-arrays") { |
471 | 0 | RegisterPass(CreateCopyPropagateArraysPass()); |
472 | 0 | } else if (pass_name == "loop-fission") { |
473 | 0 | int register_threshold_to_split = |
474 | 0 | (pass_args.size() > 0) ? atoi(pass_args.c_str()) : -1; |
475 | 0 | if (register_threshold_to_split > 0) { |
476 | 0 | RegisterPass(CreateLoopFissionPass( |
477 | 0 | static_cast<size_t>(register_threshold_to_split))); |
478 | 0 | } else { |
479 | 0 | Error(consumer(), nullptr, {}, |
480 | 0 | "--loop-fission must have a positive integer argument"); |
481 | 0 | return false; |
482 | 0 | } |
483 | 0 | } else if (pass_name == "loop-fusion") { |
484 | 0 | int max_registers_per_loop = |
485 | 0 | (pass_args.size() > 0) ? atoi(pass_args.c_str()) : -1; |
486 | 0 | if (max_registers_per_loop > 0) { |
487 | 0 | RegisterPass( |
488 | 0 | CreateLoopFusionPass(static_cast<size_t>(max_registers_per_loop))); |
489 | 0 | } else { |
490 | 0 | Error(consumer(), nullptr, {}, |
491 | 0 | "--loop-fusion must have a positive integer argument"); |
492 | 0 | return false; |
493 | 0 | } |
494 | 0 | } else if (pass_name == "loop-unroll") { |
495 | 0 | RegisterPass(CreateLoopUnrollPass(true)); |
496 | 0 | } else if (pass_name == "upgrade-memory-model") { |
497 | 0 | RegisterPass(CreateUpgradeMemoryModelPass()); |
498 | 0 | } else if (pass_name == "vector-dce") { |
499 | 0 | RegisterPass(CreateVectorDCEPass()); |
500 | 0 | } else if (pass_name == "loop-unroll-partial") { |
501 | 0 | int factor = (pass_args.size() > 0) ? atoi(pass_args.c_str()) : 0; |
502 | 0 | if (factor > 0) { |
503 | 0 | RegisterPass(CreateLoopUnrollPass(false, factor)); |
504 | 0 | } else { |
505 | 0 | Error(consumer(), nullptr, {}, |
506 | 0 | "--loop-unroll-partial must have a positive integer argument"); |
507 | 0 | return false; |
508 | 0 | } |
509 | 0 | } else if (pass_name == "loop-peeling") { |
510 | 0 | RegisterPass(CreateLoopPeelingPass()); |
511 | 0 | } else if (pass_name == "loop-peeling-threshold") { |
512 | 0 | int factor = (pass_args.size() > 0) ? atoi(pass_args.c_str()) : 0; |
513 | 0 | if (factor > 0) { |
514 | 0 | opt::LoopPeelingPass::SetLoopPeelingThreshold(factor); |
515 | 0 | } else { |
516 | 0 | Error(consumer(), nullptr, {}, |
517 | 0 | "--loop-peeling-threshold must have a positive integer argument"); |
518 | 0 | return false; |
519 | 0 | } |
520 | 0 | } else if (pass_name == "ccp") { |
521 | 0 | RegisterPass(CreateCCPPass()); |
522 | 0 | } else if (pass_name == "code-sink") { |
523 | 0 | RegisterPass(CreateCodeSinkingPass()); |
524 | 0 | } else if (pass_name == "fix-storage-class") { |
525 | 0 | RegisterPass(CreateFixStorageClassPass()); |
526 | 0 | } else if (pass_name == "O") { |
527 | 0 | RegisterPerformancePasses(preserve_interface); |
528 | 0 | } else if (pass_name == "Os") { |
529 | 0 | RegisterSizePasses(preserve_interface); |
530 | 0 | } else if (pass_name == "legalize-hlsl") { |
531 | 0 | RegisterLegalizationPasses(preserve_interface); |
532 | 0 | } else if (pass_name == "remove-unused-interface-variables") { |
533 | 0 | RegisterPass(CreateRemoveUnusedInterfaceVariablesPass()); |
534 | 0 | } else if (pass_name == "graphics-robust-access") { |
535 | 0 | RegisterPass(CreateGraphicsRobustAccessPass()); |
536 | 0 | } else if (pass_name == "wrap-opkill") { |
537 | 0 | RegisterPass(CreateWrapOpKillPass()); |
538 | 0 | } else if (pass_name == "amd-ext-to-khr") { |
539 | 0 | RegisterPass(CreateAmdExtToKhrPass()); |
540 | 0 | } else if (pass_name == "interpolate-fixup") { |
541 | 0 | RegisterPass(CreateInterpolateFixupPass()); |
542 | 0 | } else if (pass_name == "remove-dont-inline") { |
543 | 0 | RegisterPass(CreateRemoveDontInlinePass()); |
544 | 0 | } else if (pass_name == "eliminate-dead-input-components") { |
545 | 0 | RegisterPass(CreateEliminateDeadInputComponentsSafePass()); |
546 | 0 | } else if (pass_name == "fix-func-call-param") { |
547 | 0 | RegisterPass(CreateFixFuncCallArgumentsPass()); |
548 | 0 | } else if (pass_name == "convert-to-sampled-image") { |
549 | 0 | if (pass_args.size() > 0) { |
550 | 0 | auto descriptor_set_binding_pairs = |
551 | 0 | opt::ConvertToSampledImagePass::ParseDescriptorSetBindingPairsString( |
552 | 0 | pass_args.c_str()); |
553 | 0 | if (!descriptor_set_binding_pairs) { |
554 | 0 | Errorf(consumer(), nullptr, {}, |
555 | 0 | "Invalid argument for --convert-to-sampled-image: %s", |
556 | 0 | pass_args.c_str()); |
557 | 0 | return false; |
558 | 0 | } |
559 | 0 | RegisterPass(CreateConvertToSampledImagePass( |
560 | 0 | std::move(*descriptor_set_binding_pairs))); |
561 | 0 | } else { |
562 | 0 | Errorf(consumer(), nullptr, {}, |
563 | 0 | "Invalid pairs of descriptor set and binding '%s'. Expected a " |
564 | 0 | "string of <descriptor set>:<binding> pairs.", |
565 | 0 | pass_args.c_str()); |
566 | 0 | return false; |
567 | 0 | } |
568 | 0 | } else if (pass_name == "struct-packing") { |
569 | 0 | if (pass_args.size() == 0) { |
570 | 0 | Error(consumer(), nullptr, {}, |
571 | 0 | "--struct-packing requires a name:rule argument."); |
572 | 0 | return false; |
573 | 0 | } |
574 | | |
575 | 0 | auto separator_pos = pass_args.find(':'); |
576 | 0 | if (separator_pos == std::string::npos || separator_pos == 0 || |
577 | 0 | separator_pos + 1 == pass_args.size()) { |
578 | 0 | Errorf(consumer(), nullptr, {}, |
579 | 0 | "Invalid argument for --struct-packing: %s", pass_args.c_str()); |
580 | 0 | return false; |
581 | 0 | } |
582 | | |
583 | 0 | const std::string struct_name = pass_args.substr(0, separator_pos); |
584 | 0 | const std::string rule_name = pass_args.substr(separator_pos + 1); |
585 | |
|
586 | 0 | RegisterPass( |
587 | 0 | CreateStructPackingPass(struct_name.c_str(), rule_name.c_str())); |
588 | 0 | } else if (pass_name == "switch-descriptorset") { |
589 | 0 | if (pass_args.size() == 0) { |
590 | 0 | Error(consumer(), nullptr, {}, |
591 | 0 | "--switch-descriptorset requires a from:to argument."); |
592 | 0 | return false; |
593 | 0 | } |
594 | 0 | uint32_t from_set = 0, to_set = 0; |
595 | 0 | const char* start = pass_args.data(); |
596 | 0 | const char* end = pass_args.data() + pass_args.size(); |
597 | |
|
598 | 0 | auto result = std::from_chars(start, end, from_set); |
599 | 0 | if (result.ec != std::errc()) { |
600 | 0 | Errorf(consumer(), nullptr, {}, |
601 | 0 | "Invalid argument for --switch-descriptorset: %s", |
602 | 0 | pass_args.c_str()); |
603 | 0 | return false; |
604 | 0 | } |
605 | 0 | start = result.ptr; |
606 | 0 | if (start[0] != ':') { |
607 | 0 | Errorf(consumer(), nullptr, {}, |
608 | 0 | "Invalid argument for --switch-descriptorset: %s", |
609 | 0 | pass_args.c_str()); |
610 | 0 | return false; |
611 | 0 | } |
612 | 0 | start++; |
613 | 0 | result = std::from_chars(start, end, to_set); |
614 | 0 | if (result.ec != std::errc() || result.ptr != end) { |
615 | 0 | Errorf(consumer(), nullptr, {}, |
616 | 0 | "Invalid argument for --switch-descriptorset: %s", |
617 | 0 | pass_args.c_str()); |
618 | 0 | return false; |
619 | 0 | } |
620 | 0 | RegisterPass(CreateSwitchDescriptorSetPass(from_set, to_set)); |
621 | 0 | } else if (pass_name == "modify-maximal-reconvergence") { |
622 | 0 | if (pass_args.size() == 0) { |
623 | 0 | Error(consumer(), nullptr, {}, |
624 | 0 | "--modify-maximal-reconvergence requires an argument"); |
625 | 0 | return false; |
626 | 0 | } |
627 | 0 | if (pass_args == "add") { |
628 | 0 | RegisterPass(CreateModifyMaximalReconvergencePass(true)); |
629 | 0 | } else if (pass_args == "remove") { |
630 | 0 | RegisterPass(CreateModifyMaximalReconvergencePass(false)); |
631 | 0 | } else { |
632 | 0 | Errorf(consumer(), nullptr, {}, |
633 | 0 | "Invalid argument for --modify-maximal-reconvergence: %s (must be " |
634 | 0 | "'add' or 'remove')", |
635 | 0 | pass_args.c_str()); |
636 | 0 | return false; |
637 | 0 | } |
638 | 0 | } else if (pass_name == "trim-capabilities") { |
639 | 0 | RegisterPass(CreateTrimCapabilitiesPass()); |
640 | 0 | } else { |
641 | 0 | Errorf(consumer(), nullptr, {}, |
642 | 0 | "Unknown flag '--%s'. Use --help for a list of valid flags", |
643 | 0 | pass_name.c_str()); |
644 | 0 | return false; |
645 | 0 | } |
646 | | |
647 | 0 | return true; |
648 | 0 | } |
649 | | |
650 | 0 | void Optimizer::SetTargetEnv(const spv_target_env env) { |
651 | 0 | impl_->target_env = env; |
652 | 0 | } |
653 | | |
654 | | bool Optimizer::Run(const uint32_t* original_binary, |
655 | | const size_t original_binary_size, |
656 | 0 | std::vector<uint32_t>* optimized_binary) const { |
657 | 0 | return Run(original_binary, original_binary_size, optimized_binary, |
658 | 0 | OptimizerOptions()); |
659 | 0 | } |
660 | | |
661 | | bool Optimizer::Run(const uint32_t* original_binary, |
662 | | const size_t original_binary_size, |
663 | | std::vector<uint32_t>* optimized_binary, |
664 | | const ValidatorOptions& validator_options, |
665 | 0 | bool skip_validation) const { |
666 | 0 | OptimizerOptions opt_options; |
667 | 0 | opt_options.set_run_validator(!skip_validation); |
668 | 0 | opt_options.set_validator_options(validator_options); |
669 | 0 | return Run(original_binary, original_binary_size, optimized_binary, |
670 | 0 | opt_options); |
671 | 0 | } |
672 | | |
673 | | bool Optimizer::Run(const uint32_t* original_binary, |
674 | | const size_t original_binary_size, |
675 | | std::vector<uint32_t>* optimized_binary, |
676 | 21.1k | const spv_optimizer_options opt_options) const { |
677 | 21.1k | spvtools::SpirvTools tools(impl_->target_env); |
678 | 21.1k | tools.SetMessageConsumer(impl_->pass_manager.consumer()); |
679 | 21.1k | if (opt_options->run_validator_ && |
680 | 21.1k | !tools.Validate(original_binary, original_binary_size, |
681 | 21.1k | &opt_options->val_options_)) { |
682 | 10.3k | return false; |
683 | 10.3k | } |
684 | | |
685 | 10.7k | std::unique_ptr<opt::IRContext> context = BuildModule( |
686 | 10.7k | impl_->target_env, consumer(), original_binary, original_binary_size); |
687 | 10.7k | if (context == nullptr) return false; |
688 | | |
689 | 10.7k | context->set_max_id_bound(opt_options->max_id_bound_); |
690 | 10.7k | context->set_preserve_bindings(opt_options->preserve_bindings_); |
691 | 10.7k | context->set_preserve_spec_constants(opt_options->preserve_spec_constants_); |
692 | | |
693 | 10.7k | impl_->pass_manager.SetValidatorOptions(&opt_options->val_options_); |
694 | 10.7k | impl_->pass_manager.SetTargetEnv(impl_->target_env); |
695 | 10.7k | auto status = impl_->pass_manager.Run(context.get()); |
696 | | |
697 | 10.7k | if (status == opt::Pass::Status::Failure) { |
698 | 5 | return false; |
699 | 5 | } |
700 | | |
701 | 10.7k | #ifndef NDEBUG |
702 | | // We do not keep the result id of DebugScope in struct DebugScope. |
703 | | // Instead, we assign random ids for them, which results in integrity |
704 | | // check failures. In addition, propagating the OpLine/OpNoLine to preserve |
705 | | // the debug information through transformations results in integrity |
706 | | // check failures. We want to skip the integrity check when the module |
707 | | // contains DebugScope or OpLine/OpNoLine instructions. |
708 | 10.7k | if (status == opt::Pass::Status::SuccessWithoutChange && |
709 | 10.7k | !context->module()->ContainsDebugInfo()) { |
710 | 750 | std::vector<uint32_t> optimized_binary_with_nop; |
711 | 750 | context->module()->ToBinary(&optimized_binary_with_nop, |
712 | 750 | /* skip_nop = */ false); |
713 | 750 | assert(optimized_binary_with_nop.size() == original_binary_size && |
714 | 750 | "Binary size unexpectedly changed despite the optimizer saying " |
715 | 750 | "there was no change"); |
716 | | |
717 | | // Compare the magic number to make sure the binaries were encoded in the |
718 | | // endianness. If not, the contents of the binaries will be different, so |
719 | | // do not check the contents. |
720 | 750 | if (optimized_binary_with_nop[0] == original_binary[0]) { |
721 | 683 | assert(memcmp(optimized_binary_with_nop.data(), original_binary, |
722 | 683 | original_binary_size) == 0 && |
723 | 683 | "Binary content unexpectedly changed despite the optimizer saying " |
724 | 683 | "there was no change"); |
725 | 683 | } |
726 | 750 | } |
727 | 10.7k | #endif // !NDEBUG |
728 | | |
729 | | // Note that |original_binary| and |optimized_binary| may share the same |
730 | | // buffer and the below will invalidate |original_binary|. |
731 | 10.7k | optimized_binary->clear(); |
732 | 10.7k | context->module()->ToBinary(optimized_binary, /* skip_nop = */ true); |
733 | | |
734 | 10.7k | return true; |
735 | 10.7k | } |
736 | | |
737 | 0 | Optimizer& Optimizer::SetPrintAll(std::ostream* out) { |
738 | 0 | impl_->pass_manager.SetPrintAll(out); |
739 | 0 | return *this; |
740 | 0 | } |
741 | | |
742 | 0 | Optimizer& Optimizer::SetTimeReport(std::ostream* out) { |
743 | 0 | impl_->pass_manager.SetTimeReport(out); |
744 | 0 | return *this; |
745 | 0 | } |
746 | | |
747 | 0 | Optimizer& Optimizer::SetValidateAfterAll(bool validate) { |
748 | 0 | impl_->pass_manager.SetValidateAfterAll(validate); |
749 | 0 | return *this; |
750 | 0 | } |
751 | | |
752 | 0 | Optimizer::PassToken CreateNullPass() { |
753 | 0 | return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::NullPass>()); |
754 | 0 | } |
755 | | |
756 | 0 | Optimizer::PassToken CreateStripDebugInfoPass() { |
757 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
758 | 0 | MakeUnique<opt::StripDebugInfoPass>()); |
759 | 0 | } |
760 | | |
761 | 0 | Optimizer::PassToken CreateStripReflectInfoPass() { |
762 | 0 | return CreateStripNonSemanticInfoPass(); |
763 | 0 | } |
764 | | |
765 | 0 | Optimizer::PassToken CreateStripNonSemanticInfoPass() { |
766 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
767 | 0 | MakeUnique<opt::StripNonSemanticInfoPass>()); |
768 | 0 | } |
769 | | |
770 | 21.1k | Optimizer::PassToken CreateEliminateDeadFunctionsPass() { |
771 | 21.1k | return MakeUnique<Optimizer::PassToken::Impl>( |
772 | 21.1k | MakeUnique<opt::EliminateDeadFunctionsPass>()); |
773 | 21.1k | } |
774 | | |
775 | 10.0k | Optimizer::PassToken CreateEliminateDeadMembersPass() { |
776 | 10.0k | return MakeUnique<Optimizer::PassToken::Impl>( |
777 | 10.0k | MakeUnique<opt::EliminateDeadMembersPass>()); |
778 | 10.0k | } |
779 | | |
780 | | Optimizer::PassToken CreateSetSpecConstantDefaultValuePass( |
781 | 0 | const std::unordered_map<uint32_t, std::string>& id_value_map) { |
782 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
783 | 0 | MakeUnique<opt::SetSpecConstantDefaultValuePass>(id_value_map)); |
784 | 0 | } |
785 | | |
786 | | Optimizer::PassToken CreateSetSpecConstantDefaultValuePass( |
787 | 0 | const std::unordered_map<uint32_t, std::vector<uint32_t>>& id_value_map) { |
788 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
789 | 0 | MakeUnique<opt::SetSpecConstantDefaultValuePass>(id_value_map)); |
790 | 0 | } |
791 | | |
792 | 0 | Optimizer::PassToken CreateFlattenDecorationPass() { |
793 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
794 | 0 | MakeUnique<opt::FlattenDecorationPass>()); |
795 | 0 | } |
796 | | |
797 | 0 | Optimizer::PassToken CreateFreezeSpecConstantValuePass() { |
798 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
799 | 0 | MakeUnique<opt::FreezeSpecConstantValuePass>()); |
800 | 0 | } |
801 | | |
802 | 0 | Optimizer::PassToken CreateFoldSpecConstantOpAndCompositePass() { |
803 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
804 | 0 | MakeUnique<opt::FoldSpecConstantOpAndCompositePass>()); |
805 | 0 | } |
806 | | |
807 | 0 | Optimizer::PassToken CreateUnifyConstantPass() { |
808 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
809 | 0 | MakeUnique<opt::UnifyConstantPass>()); |
810 | 0 | } |
811 | | |
812 | 0 | Optimizer::PassToken CreateEliminateDeadConstantPass() { |
813 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
814 | 0 | MakeUnique<opt::EliminateDeadConstantPass>()); |
815 | 0 | } |
816 | | |
817 | 0 | Optimizer::PassToken CreateDeadVariableEliminationPass() { |
818 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
819 | 0 | MakeUnique<opt::DeadVariableElimination>()); |
820 | 0 | } |
821 | | |
822 | 0 | Optimizer::PassToken CreateStrengthReductionPass() { |
823 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
824 | 0 | MakeUnique<opt::StrengthReductionPass>()); |
825 | 0 | } |
826 | | |
827 | 23.8k | Optimizer::PassToken CreateBlockMergePass() { |
828 | 23.8k | return MakeUnique<Optimizer::PassToken::Impl>( |
829 | 23.8k | MakeUnique<opt::BlockMergePass>()); |
830 | 23.8k | } |
831 | | |
832 | 21.1k | Optimizer::PassToken CreateInlineExhaustivePass() { |
833 | 21.1k | return MakeUnique<Optimizer::PassToken::Impl>( |
834 | 21.1k | MakeUnique<opt::InlineExhaustivePass>()); |
835 | 21.1k | } |
836 | | |
837 | 0 | Optimizer::PassToken CreateInlineOpaquePass() { |
838 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
839 | 0 | MakeUnique<opt::InlineOpaquePass>()); |
840 | 0 | } |
841 | | |
842 | 13.7k | Optimizer::PassToken CreateLocalAccessChainConvertPass() { |
843 | 13.7k | return MakeUnique<Optimizer::PassToken::Impl>( |
844 | 13.7k | MakeUnique<opt::LocalAccessChainConvertPass>()); |
845 | 13.7k | } |
846 | | |
847 | 34.0k | Optimizer::PassToken CreateLocalSingleBlockLoadStoreElimPass() { |
848 | 34.0k | return MakeUnique<Optimizer::PassToken::Impl>( |
849 | 34.0k | MakeUnique<opt::LocalSingleBlockLoadStoreElimPass>()); |
850 | 34.0k | } |
851 | | |
852 | 44.1k | Optimizer::PassToken CreateLocalSingleStoreElimPass() { |
853 | 44.1k | return MakeUnique<Optimizer::PassToken::Impl>( |
854 | 44.1k | MakeUnique<opt::LocalSingleStoreElimPass>()); |
855 | 44.1k | } |
856 | | |
857 | 0 | Optimizer::PassToken CreateInsertExtractElimPass() { |
858 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
859 | 0 | MakeUnique<opt::SimplificationPass>()); |
860 | 0 | } |
861 | | |
862 | 21.1k | Optimizer::PassToken CreateDeadInsertElimPass() { |
863 | 21.1k | return MakeUnique<Optimizer::PassToken::Impl>( |
864 | 21.1k | MakeUnique<opt::DeadInsertElimPass>()); |
865 | 21.1k | } |
866 | | |
867 | 56.0k | Optimizer::PassToken CreateDeadBranchElimPass() { |
868 | 56.0k | return MakeUnique<Optimizer::PassToken::Impl>( |
869 | 56.0k | MakeUnique<opt::DeadBranchElimPass>()); |
870 | 56.0k | } |
871 | | |
872 | 31.1k | Optimizer::PassToken CreateLocalMultiStoreElimPass() { |
873 | 31.1k | return MakeUnique<Optimizer::PassToken::Impl>( |
874 | 31.1k | MakeUnique<opt::SSARewritePass>()); |
875 | 31.1k | } |
876 | | |
877 | 0 | Optimizer::PassToken CreateAggressiveDCEPass() { |
878 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
879 | 0 | MakeUnique<opt::AggressiveDCEPass>(false, false)); |
880 | 0 | } |
881 | | |
882 | 91.0k | Optimizer::PassToken CreateAggressiveDCEPass(bool preserve_interface) { |
883 | 91.0k | return MakeUnique<Optimizer::PassToken::Impl>( |
884 | 91.0k | MakeUnique<opt::AggressiveDCEPass>(preserve_interface, false)); |
885 | 91.0k | } |
886 | | |
887 | | Optimizer::PassToken CreateAggressiveDCEPass(bool preserve_interface, |
888 | 0 | bool remove_outputs) { |
889 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
890 | 0 | MakeUnique<opt::AggressiveDCEPass>(preserve_interface, remove_outputs)); |
891 | 0 | } |
892 | | |
893 | 9.22k | Optimizer::PassToken CreateRemoveUnusedInterfaceVariablesPass() { |
894 | 9.22k | return MakeUnique<Optimizer::PassToken::Impl>( |
895 | 9.22k | MakeUnique<opt::RemoveUnusedInterfaceVariablesPass>()); |
896 | 9.22k | } |
897 | | |
898 | 0 | Optimizer::PassToken CreatePropagateLineInfoPass() { |
899 | 0 | return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::EmptyPass>()); |
900 | 0 | } |
901 | | |
902 | 0 | Optimizer::PassToken CreateRedundantLineInfoElimPass() { |
903 | 0 | return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::EmptyPass>()); |
904 | 0 | } |
905 | | |
906 | 0 | Optimizer::PassToken CreateCompactIdsPass() { |
907 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
908 | 0 | MakeUnique<opt::CompactIdsPass>()); |
909 | 0 | } |
910 | | |
911 | 21.1k | Optimizer::PassToken CreateMergeReturnPass() { |
912 | 21.1k | return MakeUnique<Optimizer::PassToken::Impl>( |
913 | 21.1k | MakeUnique<opt::MergeReturnPass>()); |
914 | 21.1k | } |
915 | | |
916 | 0 | std::vector<const char*> Optimizer::GetPassNames() const { |
917 | 0 | std::vector<const char*> v; |
918 | 0 | for (uint32_t i = 0; i < impl_->pass_manager.NumPasses(); i++) { |
919 | 0 | v.push_back(impl_->pass_manager.GetPass(i)->name()); |
920 | 0 | } |
921 | 0 | return v; |
922 | 0 | } |
923 | | |
924 | 10.0k | Optimizer::PassToken CreateCFGCleanupPass() { |
925 | 10.0k | return MakeUnique<Optimizer::PassToken::Impl>( |
926 | 10.0k | MakeUnique<opt::CFGCleanupPass>()); |
927 | 10.0k | } |
928 | | |
929 | 0 | Optimizer::PassToken CreateLocalRedundancyEliminationPass() { |
930 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
931 | 0 | MakeUnique<opt::LocalRedundancyEliminationPass>()); |
932 | 0 | } |
933 | | |
934 | 0 | Optimizer::PassToken CreateLoopFissionPass(size_t threshold) { |
935 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
936 | 0 | MakeUnique<opt::LoopFissionPass>(threshold)); |
937 | 0 | } |
938 | | |
939 | 0 | Optimizer::PassToken CreateLoopFusionPass(size_t max_registers_per_loop) { |
940 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
941 | 0 | MakeUnique<opt::LoopFusionPass>(max_registers_per_loop)); |
942 | 0 | } |
943 | | |
944 | 0 | Optimizer::PassToken CreateLoopInvariantCodeMotionPass() { |
945 | 0 | return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::LICMPass>()); |
946 | 0 | } |
947 | | |
948 | 0 | Optimizer::PassToken CreateLoopPeelingPass() { |
949 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
950 | 0 | MakeUnique<opt::LoopPeelingPass>()); |
951 | 0 | } |
952 | | |
953 | 0 | Optimizer::PassToken CreateLoopUnswitchPass() { |
954 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
955 | 0 | MakeUnique<opt::LoopUnswitchPass>()); |
956 | 0 | } |
957 | | |
958 | 13.7k | Optimizer::PassToken CreateRedundancyEliminationPass() { |
959 | 13.7k | return MakeUnique<Optimizer::PassToken::Impl>( |
960 | 13.7k | MakeUnique<opt::RedundancyEliminationPass>()); |
961 | 13.7k | } |
962 | | |
963 | 0 | Optimizer::PassToken CreateRemoveDuplicatesPass() { |
964 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
965 | 0 | MakeUnique<opt::RemoveDuplicatesPass>()); |
966 | 0 | } |
967 | | |
968 | 33.0k | Optimizer::PassToken CreateScalarReplacementPass(uint32_t size_limit) { |
969 | 33.0k | return MakeUnique<Optimizer::PassToken::Impl>( |
970 | 33.0k | MakeUnique<opt::ScalarReplacementPass>(size_limit)); |
971 | 33.0k | } |
972 | | |
973 | 21.1k | Optimizer::PassToken CreatePrivateToLocalPass() { |
974 | 21.1k | return MakeUnique<Optimizer::PassToken::Impl>( |
975 | 21.1k | MakeUnique<opt::PrivateToLocalPass>()); |
976 | 21.1k | } |
977 | | |
978 | 21.1k | Optimizer::PassToken CreateCCPPass() { |
979 | 21.1k | return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::CCPPass>()); |
980 | 21.1k | } |
981 | | |
982 | 0 | Optimizer::PassToken CreateWorkaround1209Pass() { |
983 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
984 | 0 | MakeUnique<opt::Workaround1209>()); |
985 | 0 | } |
986 | | |
987 | 11.9k | Optimizer::PassToken CreateIfConversionPass() { |
988 | 11.9k | return MakeUnique<Optimizer::PassToken::Impl>( |
989 | 11.9k | MakeUnique<opt::IfConversion>()); |
990 | 11.9k | } |
991 | | |
992 | 0 | Optimizer::PassToken CreateReplaceInvalidOpcodePass() { |
993 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
994 | 0 | MakeUnique<opt::ReplaceInvalidOpcodePass>()); |
995 | 0 | } |
996 | | |
997 | 44.9k | Optimizer::PassToken CreateSimplificationPass() { |
998 | 44.9k | return MakeUnique<Optimizer::PassToken::Impl>( |
999 | 44.9k | MakeUnique<opt::SimplificationPass>()); |
1000 | 44.9k | } |
1001 | | |
1002 | 21.1k | Optimizer::PassToken CreateLoopUnrollPass(bool fully_unroll, int factor) { |
1003 | 21.1k | return MakeUnique<Optimizer::PassToken::Impl>( |
1004 | 21.1k | MakeUnique<opt::LoopUnroller>(fully_unroll, factor)); |
1005 | 21.1k | } |
1006 | | |
1007 | 1.84k | Optimizer::PassToken CreateSSARewritePass() { |
1008 | 1.84k | return MakeUnique<Optimizer::PassToken::Impl>( |
1009 | 1.84k | MakeUnique<opt::SSARewritePass>()); |
1010 | 1.84k | } |
1011 | | |
1012 | 21.1k | Optimizer::PassToken CreateCopyPropagateArraysPass() { |
1013 | 21.1k | return MakeUnique<Optimizer::PassToken::Impl>( |
1014 | 21.1k | MakeUnique<opt::CopyPropagateArrays>()); |
1015 | 21.1k | } |
1016 | | |
1017 | 21.1k | Optimizer::PassToken CreateVectorDCEPass() { |
1018 | 21.1k | return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::VectorDCE>()); |
1019 | 21.1k | } |
1020 | | |
1021 | | Optimizer::PassToken CreateReduceLoadSizePass( |
1022 | 11.0k | double load_replacement_threshold) { |
1023 | 11.0k | return MakeUnique<Optimizer::PassToken::Impl>( |
1024 | 11.0k | MakeUnique<opt::ReduceLoadSize>(load_replacement_threshold)); |
1025 | 11.0k | } |
1026 | | |
1027 | 1.84k | Optimizer::PassToken CreateCombineAccessChainsPass() { |
1028 | 1.84k | return MakeUnique<Optimizer::PassToken::Impl>( |
1029 | 1.84k | MakeUnique<opt::CombineAccessChains>()); |
1030 | 1.84k | } |
1031 | | |
1032 | 0 | Optimizer::PassToken CreateUpgradeMemoryModelPass() { |
1033 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
1034 | 0 | MakeUnique<opt::UpgradeMemoryModel>()); |
1035 | 0 | } |
1036 | | |
1037 | 0 | Optimizer::PassToken CreateConvertRelaxedToHalfPass() { |
1038 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
1039 | 0 | MakeUnique<opt::ConvertToHalfPass>()); |
1040 | 0 | } |
1041 | | |
1042 | 0 | Optimizer::PassToken CreateRelaxFloatOpsPass() { |
1043 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
1044 | 0 | MakeUnique<opt::RelaxFloatOpsPass>()); |
1045 | 0 | } |
1046 | | |
1047 | 0 | Optimizer::PassToken CreateCodeSinkingPass() { |
1048 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
1049 | 0 | MakeUnique<opt::CodeSinkingPass>()); |
1050 | 0 | } |
1051 | | |
1052 | 9.22k | Optimizer::PassToken CreateFixStorageClassPass() { |
1053 | 9.22k | return MakeUnique<Optimizer::PassToken::Impl>( |
1054 | 9.22k | MakeUnique<opt::FixStorageClass>()); |
1055 | 9.22k | } |
1056 | | |
1057 | 0 | Optimizer::PassToken CreateGraphicsRobustAccessPass() { |
1058 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
1059 | 0 | MakeUnique<opt::GraphicsRobustAccessPass>()); |
1060 | 0 | } |
1061 | | |
1062 | 0 | Optimizer::PassToken CreateReplaceDescArrayAccessUsingVarIndexPass() { |
1063 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
1064 | 0 | MakeUnique<opt::ReplaceDescArrayAccessUsingVarIndex>()); |
1065 | 0 | } |
1066 | | |
1067 | 0 | Optimizer::PassToken CreateSpreadVolatileSemanticsPass() { |
1068 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
1069 | 0 | MakeUnique<opt::SpreadVolatileSemantics>()); |
1070 | 0 | } |
1071 | | |
1072 | 0 | Optimizer::PassToken CreateDescriptorScalarReplacementPass() { |
1073 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
1074 | 0 | MakeUnique<opt::DescriptorScalarReplacement>( |
1075 | 0 | /* flatten_composites= */ true, /* flatten_arrays= */ true)); |
1076 | 0 | } |
1077 | | |
1078 | 0 | Optimizer::PassToken CreateDescriptorCompositeScalarReplacementPass() { |
1079 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
1080 | 0 | MakeUnique<opt::DescriptorScalarReplacement>( |
1081 | 0 | /* flatten_composites= */ true, /* flatten_arrays= */ false)); |
1082 | 0 | } |
1083 | | |
1084 | 0 | Optimizer::PassToken CreateDescriptorArrayScalarReplacementPass() { |
1085 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
1086 | 0 | MakeUnique<opt::DescriptorScalarReplacement>( |
1087 | 0 | /* flatten_composites= */ false, /* flatten_arrays= */ true)); |
1088 | 0 | } |
1089 | | |
1090 | 21.1k | Optimizer::PassToken CreateWrapOpKillPass() { |
1091 | 21.1k | return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::WrapOpKill>()); |
1092 | 21.1k | } |
1093 | | |
1094 | 0 | Optimizer::PassToken CreateAmdExtToKhrPass() { |
1095 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
1096 | 0 | MakeUnique<opt::AmdExtensionToKhrPass>()); |
1097 | 0 | } |
1098 | | |
1099 | 9.22k | Optimizer::PassToken CreateInterpolateFixupPass() { |
1100 | 9.22k | return MakeUnique<Optimizer::PassToken::Impl>( |
1101 | 9.22k | MakeUnique<opt::InterpFixupPass>()); |
1102 | 9.22k | } |
1103 | | |
1104 | 0 | Optimizer::PassToken CreateEliminateDeadInputComponentsPass() { |
1105 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
1106 | 0 | MakeUnique<opt::EliminateDeadIOComponentsPass>(spv::StorageClass::Input, |
1107 | 0 | /* safe_mode */ false)); |
1108 | 0 | } |
1109 | | |
1110 | 0 | Optimizer::PassToken CreateEliminateDeadOutputComponentsPass() { |
1111 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
1112 | 0 | MakeUnique<opt::EliminateDeadIOComponentsPass>(spv::StorageClass::Output, |
1113 | 0 | /* safe_mode */ false)); |
1114 | 0 | } |
1115 | | |
1116 | 0 | Optimizer::PassToken CreateEliminateDeadInputComponentsSafePass() { |
1117 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
1118 | 0 | MakeUnique<opt::EliminateDeadIOComponentsPass>(spv::StorageClass::Input, |
1119 | 0 | /* safe_mode */ true)); |
1120 | 0 | } |
1121 | | |
1122 | | Optimizer::PassToken CreateAnalyzeLiveInputPass( |
1123 | | std::unordered_set<uint32_t>* live_locs, |
1124 | 0 | std::unordered_set<uint32_t>* live_builtins) { |
1125 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
1126 | 0 | MakeUnique<opt::AnalyzeLiveInputPass>(live_locs, live_builtins)); |
1127 | 0 | } |
1128 | | |
1129 | | Optimizer::PassToken CreateEliminateDeadOutputStoresPass( |
1130 | | std::unordered_set<uint32_t>* live_locs, |
1131 | 0 | std::unordered_set<uint32_t>* live_builtins) { |
1132 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
1133 | 0 | MakeUnique<opt::EliminateDeadOutputStoresPass>(live_locs, live_builtins)); |
1134 | 0 | } |
1135 | | |
1136 | | Optimizer::PassToken CreateConvertToSampledImagePass( |
1137 | | const std::vector<opt::DescriptorSetAndBinding>& |
1138 | 0 | descriptor_set_binding_pairs) { |
1139 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
1140 | 0 | MakeUnique<opt::ConvertToSampledImagePass>(descriptor_set_binding_pairs)); |
1141 | 0 | } |
1142 | | |
1143 | 0 | Optimizer::PassToken CreateInterfaceVariableScalarReplacementPass() { |
1144 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
1145 | 0 | MakeUnique<opt::InterfaceVariableScalarReplacement>()); |
1146 | 0 | } |
1147 | | |
1148 | 0 | Optimizer::PassToken CreateRemoveDontInlinePass() { |
1149 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
1150 | 0 | MakeUnique<opt::RemoveDontInline>()); |
1151 | 0 | } |
1152 | | |
1153 | 0 | Optimizer::PassToken CreateFixFuncCallArgumentsPass() { |
1154 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
1155 | 0 | MakeUnique<opt::FixFuncCallArgumentsPass>()); |
1156 | 0 | } |
1157 | | |
1158 | 0 | Optimizer::PassToken CreateTrimCapabilitiesPass() { |
1159 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
1160 | 0 | MakeUnique<opt::TrimCapabilitiesPass>()); |
1161 | 0 | } |
1162 | | |
1163 | | Optimizer::PassToken CreateStructPackingPass(const char* structToPack, |
1164 | 0 | const char* packingRule) { |
1165 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
1166 | 0 | MakeUnique<opt::StructPackingPass>( |
1167 | 0 | structToPack, |
1168 | 0 | opt::StructPackingPass::ParsePackingRuleFromString(packingRule))); |
1169 | 0 | } |
1170 | | |
1171 | 0 | Optimizer::PassToken CreateSwitchDescriptorSetPass(uint32_t from, uint32_t to) { |
1172 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
1173 | 0 | MakeUnique<opt::SwitchDescriptorSetPass>(from, to)); |
1174 | 0 | } |
1175 | | |
1176 | 9.22k | Optimizer::PassToken CreateInvocationInterlockPlacementPass() { |
1177 | 9.22k | return MakeUnique<Optimizer::PassToken::Impl>( |
1178 | 9.22k | MakeUnique<opt::InvocationInterlockPlacementPass>()); |
1179 | 9.22k | } |
1180 | | |
1181 | 0 | Optimizer::PassToken CreateModifyMaximalReconvergencePass(bool add) { |
1182 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
1183 | 0 | MakeUnique<opt::ModifyMaximalReconvergence>(add)); |
1184 | 0 | } |
1185 | | |
1186 | 9.22k | Optimizer::PassToken CreateOpExtInstWithForwardReferenceFixupPass() { |
1187 | 9.22k | return MakeUnique<Optimizer::PassToken::Impl>( |
1188 | 9.22k | MakeUnique<opt::OpExtInstWithForwardReferenceFixupPass>()); |
1189 | 9.22k | } |
1190 | | |
1191 | | } // namespace spvtools |
1192 | | |
1193 | | extern "C" { |
1194 | | |
1195 | 0 | SPIRV_TOOLS_EXPORT spv_optimizer_t* spvOptimizerCreate(spv_target_env env) { |
1196 | 0 | return reinterpret_cast<spv_optimizer_t*>(new spvtools::Optimizer(env)); |
1197 | 0 | } |
1198 | | |
1199 | 0 | SPIRV_TOOLS_EXPORT void spvOptimizerDestroy(spv_optimizer_t* optimizer) { |
1200 | 0 | delete reinterpret_cast<spvtools::Optimizer*>(optimizer); |
1201 | 0 | } |
1202 | | |
1203 | | SPIRV_TOOLS_EXPORT void spvOptimizerSetMessageConsumer( |
1204 | 0 | spv_optimizer_t* optimizer, spv_message_consumer consumer) { |
1205 | 0 | reinterpret_cast<spvtools::Optimizer*>(optimizer)-> |
1206 | 0 | SetMessageConsumer( |
1207 | 0 | [consumer](spv_message_level_t level, const char* source, |
1208 | 0 | const spv_position_t& position, const char* message) { |
1209 | 0 | return consumer(level, source, &position, message); |
1210 | 0 | }); |
1211 | 0 | } |
1212 | | |
1213 | | SPIRV_TOOLS_EXPORT void spvOptimizerRegisterLegalizationPasses( |
1214 | 0 | spv_optimizer_t* optimizer) { |
1215 | 0 | reinterpret_cast<spvtools::Optimizer*>(optimizer)-> |
1216 | 0 | RegisterLegalizationPasses(); |
1217 | 0 | } |
1218 | | |
1219 | | SPIRV_TOOLS_EXPORT void spvOptimizerRegisterPerformancePasses( |
1220 | 0 | spv_optimizer_t* optimizer) { |
1221 | 0 | reinterpret_cast<spvtools::Optimizer*>(optimizer)-> |
1222 | 0 | RegisterPerformancePasses(); |
1223 | 0 | } |
1224 | | |
1225 | | SPIRV_TOOLS_EXPORT void spvOptimizerRegisterSizePasses( |
1226 | 0 | spv_optimizer_t* optimizer) { |
1227 | 0 | reinterpret_cast<spvtools::Optimizer*>(optimizer)->RegisterSizePasses(); |
1228 | 0 | } |
1229 | | |
1230 | | SPIRV_TOOLS_EXPORT bool spvOptimizerRegisterPassFromFlag( |
1231 | | spv_optimizer_t* optimizer, const char* flag) |
1232 | 0 | { |
1233 | 0 | return reinterpret_cast<spvtools::Optimizer*>(optimizer)-> |
1234 | 0 | RegisterPassFromFlag(flag); |
1235 | 0 | } |
1236 | | |
1237 | | SPIRV_TOOLS_EXPORT bool spvOptimizerRegisterPassesFromFlags( |
1238 | 0 | spv_optimizer_t* optimizer, const char** flags, const size_t flag_count) { |
1239 | 0 | std::vector<std::string> opt_flags = |
1240 | 0 | spvtools::GetVectorOfStrings(flags, flag_count); |
1241 | 0 | return reinterpret_cast<spvtools::Optimizer*>(optimizer) |
1242 | 0 | ->RegisterPassesFromFlags(opt_flags, false); |
1243 | 0 | } |
1244 | | |
1245 | | SPIRV_TOOLS_EXPORT bool |
1246 | | spvOptimizerRegisterPassesFromFlagsWhilePreservingTheInterface( |
1247 | 0 | spv_optimizer_t* optimizer, const char** flags, const size_t flag_count) { |
1248 | 0 | std::vector<std::string> opt_flags = |
1249 | 0 | spvtools::GetVectorOfStrings(flags, flag_count); |
1250 | 0 | return reinterpret_cast<spvtools::Optimizer*>(optimizer) |
1251 | 0 | ->RegisterPassesFromFlags(opt_flags, true); |
1252 | 0 | } |
1253 | | |
1254 | | SPIRV_TOOLS_EXPORT |
1255 | | spv_result_t spvOptimizerRun(spv_optimizer_t* optimizer, |
1256 | | const uint32_t* binary, |
1257 | | const size_t word_count, |
1258 | | spv_binary* optimized_binary, |
1259 | 0 | const spv_optimizer_options options) { |
1260 | 0 | std::vector<uint32_t> optimized; |
1261 | |
|
1262 | 0 | if (!reinterpret_cast<spvtools::Optimizer*>(optimizer)-> |
1263 | 0 | Run(binary, word_count, &optimized, options)) { |
1264 | 0 | return SPV_ERROR_INTERNAL; |
1265 | 0 | } |
1266 | | |
1267 | 0 | auto result_binary = new spv_binary_t(); |
1268 | 0 | if (!result_binary) { |
1269 | 0 | *optimized_binary = nullptr; |
1270 | 0 | return SPV_ERROR_OUT_OF_MEMORY; |
1271 | 0 | } |
1272 | | |
1273 | 0 | result_binary->code = new uint32_t[optimized.size()]; |
1274 | 0 | if (!result_binary->code) { |
1275 | 0 | delete result_binary; |
1276 | 0 | *optimized_binary = nullptr; |
1277 | 0 | return SPV_ERROR_OUT_OF_MEMORY; |
1278 | 0 | } |
1279 | 0 | result_binary->wordCount = optimized.size(); |
1280 | |
|
1281 | 0 | memcpy(result_binary->code, optimized.data(), |
1282 | 0 | optimized.size() * sizeof(uint32_t)); |
1283 | |
|
1284 | 0 | *optimized_binary = result_binary; |
1285 | |
|
1286 | 0 | return SPV_SUCCESS; |
1287 | 0 | } |
1288 | | |
1289 | | } // extern "C" |