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