/src/shaderc/third_party/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 | 88.1k | 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 | 88.1k | : 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 | 88.1k | Optimizer::PassToken::~PassToken() {} |
68 | | |
69 | | struct Optimizer::Impl { |
70 | 1.83k | 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 | 1.83k | Optimizer::Optimizer(spv_target_env env) : impl_(new Impl(env)) { |
78 | 1.83k | assert(env != SPV_ENV_WEBGPU_0); |
79 | 1.83k | } |
80 | | |
81 | 1.83k | Optimizer::~Optimizer() {} |
82 | | |
83 | 1.83k | void Optimizer::SetMessageConsumer(MessageConsumer c) { |
84 | | // All passes' message consumer needs to be updated. |
85 | 1.83k | for (uint32_t i = 0; i < impl_->pass_manager.NumPasses(); ++i) { |
86 | 0 | impl_->pass_manager.GetPass(i)->SetMessageConsumer(c); |
87 | 0 | } |
88 | 1.83k | impl_->pass_manager.SetMessageConsumer(std::move(c)); |
89 | 1.83k | } |
90 | | |
91 | 89.9k | const MessageConsumer& Optimizer::consumer() const { |
92 | 89.9k | return impl_->pass_manager.consumer(); |
93 | 89.9k | } |
94 | | |
95 | 88.1k | Optimizer& Optimizer::RegisterPass(PassToken&& p) { |
96 | | // Change to use the pass manager's consumer. |
97 | 88.1k | p.impl_->pass->SetMessageConsumer(consumer()); |
98 | 88.1k | impl_->pass_manager.AddPass(std::move(p.impl_->pass)); |
99 | 88.1k | return *this; |
100 | 88.1k | } |
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 | 576 | Optimizer& Optimizer::RegisterLegalizationPasses(bool preserve_interface) { |
124 | 576 | return |
125 | | // Wrap OpKill instructions so all other code can be inlined. |
126 | 576 | RegisterPass(CreateWrapOpKillPass()) |
127 | | // Remove unreachable block so that merge return works. |
128 | 576 | .RegisterPass(CreateDeadBranchElimPass()) |
129 | | // Merge the returns so we can inline. |
130 | 576 | .RegisterPass(CreateMergeReturnPass()) |
131 | | // Make sure uses and definitions are in the same function. |
132 | 576 | .RegisterPass(CreateInlineExhaustivePass()) |
133 | | // Make private variable function scope |
134 | 576 | .RegisterPass(CreateEliminateDeadFunctionsPass()) |
135 | 576 | .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 | 576 | .RegisterPass(CreateFixStorageClassPass()) |
140 | | // Propagate the value stored to the loads in very simple cases. |
141 | 576 | .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass()) |
142 | 576 | .RegisterPass(CreateLocalSingleStoreElimPass()) |
143 | 576 | .RegisterPass(CreateAggressiveDCEPass(preserve_interface)) |
144 | | // Split up aggregates so they are easier to deal with. |
145 | 576 | .RegisterPass(CreateScalarReplacementPass(0)) |
146 | | // Remove loads and stores so everything is in intermediate values. |
147 | | // Takes care of copy propagation of non-members. |
148 | 576 | .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass()) |
149 | 576 | .RegisterPass(CreateLocalSingleStoreElimPass()) |
150 | 576 | .RegisterPass(CreateAggressiveDCEPass(preserve_interface)) |
151 | 576 | .RegisterPass(CreateLocalMultiStoreElimPass()) |
152 | 576 | .RegisterPass(CreateAggressiveDCEPass(preserve_interface)) |
153 | | // Propagate constants to get as many constant conditions on branches |
154 | | // as possible. |
155 | 576 | .RegisterPass(CreateCCPPass()) |
156 | 576 | .RegisterPass(CreateLoopUnrollPass(true)) |
157 | 576 | .RegisterPass(CreateDeadBranchElimPass()) |
158 | | // Copy propagate members. Cleans up code sequences generated by |
159 | | // scalar replacement. Also important for removing OpPhi nodes. |
160 | 576 | .RegisterPass(CreateSimplificationPass()) |
161 | 576 | .RegisterPass(CreateAggressiveDCEPass(preserve_interface)) |
162 | 576 | .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 | 576 | .RegisterPass(CreateVectorDCEPass()) |
168 | 576 | .RegisterPass(CreateDeadInsertElimPass()) |
169 | 576 | .RegisterPass(CreateReduceLoadSizePass()) |
170 | 576 | .RegisterPass(CreateAggressiveDCEPass(preserve_interface)) |
171 | 576 | .RegisterPass(CreateRemoveUnusedInterfaceVariablesPass()) |
172 | 576 | .RegisterPass(CreateInterpolateFixupPass()) |
173 | 576 | .RegisterPass(CreateInvocationInterlockPlacementPass()) |
174 | 576 | .RegisterPass(CreateOpExtInstWithForwardReferenceFixupPass()); |
175 | 576 | } |
176 | | |
177 | 576 | Optimizer& Optimizer::RegisterLegalizationPasses() { |
178 | 576 | return RegisterLegalizationPasses(false); |
179 | 576 | } |
180 | | |
181 | 1.30k | Optimizer& Optimizer::RegisterPerformancePasses(bool preserve_interface) { |
182 | 1.30k | return RegisterPass(CreateWrapOpKillPass()) |
183 | 1.30k | .RegisterPass(CreateDeadBranchElimPass()) |
184 | 1.30k | .RegisterPass(CreateMergeReturnPass()) |
185 | 1.30k | .RegisterPass(CreateInlineExhaustivePass()) |
186 | 1.30k | .RegisterPass(CreateEliminateDeadFunctionsPass()) |
187 | 1.30k | .RegisterPass(CreateAggressiveDCEPass(preserve_interface)) |
188 | 1.30k | .RegisterPass(CreatePrivateToLocalPass()) |
189 | 1.30k | .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass()) |
190 | 1.30k | .RegisterPass(CreateLocalSingleStoreElimPass()) |
191 | 1.30k | .RegisterPass(CreateAggressiveDCEPass(preserve_interface)) |
192 | 1.30k | .RegisterPass(CreateScalarReplacementPass(0)) |
193 | 1.30k | .RegisterPass(CreateLocalAccessChainConvertPass()) |
194 | 1.30k | .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass()) |
195 | 1.30k | .RegisterPass(CreateLocalSingleStoreElimPass()) |
196 | 1.30k | .RegisterPass(CreateAggressiveDCEPass(preserve_interface)) |
197 | 1.30k | .RegisterPass(CreateLocalMultiStoreElimPass()) |
198 | 1.30k | .RegisterPass(CreateAggressiveDCEPass(preserve_interface)) |
199 | 1.30k | .RegisterPass(CreateCCPPass()) |
200 | 1.30k | .RegisterPass(CreateAggressiveDCEPass(preserve_interface)) |
201 | 1.30k | .RegisterPass(CreateLoopUnrollPass(true)) |
202 | 1.30k | .RegisterPass(CreateDeadBranchElimPass()) |
203 | 1.30k | .RegisterPass(CreateRedundancyEliminationPass()) |
204 | 1.30k | .RegisterPass(CreateCombineAccessChainsPass()) |
205 | 1.30k | .RegisterPass(CreateSimplificationPass()) |
206 | 1.30k | .RegisterPass(CreateScalarReplacementPass(0)) |
207 | 1.30k | .RegisterPass(CreateLocalAccessChainConvertPass()) |
208 | 1.30k | .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass()) |
209 | 1.30k | .RegisterPass(CreateLocalSingleStoreElimPass()) |
210 | 1.30k | .RegisterPass(CreateAggressiveDCEPass(preserve_interface)) |
211 | 1.30k | .RegisterPass(CreateSSARewritePass()) |
212 | 1.30k | .RegisterPass(CreateAggressiveDCEPass(preserve_interface)) |
213 | 1.30k | .RegisterPass(CreateVectorDCEPass()) |
214 | 1.30k | .RegisterPass(CreateDeadInsertElimPass()) |
215 | 1.30k | .RegisterPass(CreateDeadBranchElimPass()) |
216 | 1.30k | .RegisterPass(CreateSimplificationPass()) |
217 | 1.30k | .RegisterPass(CreateIfConversionPass()) |
218 | 1.30k | .RegisterPass(CreateCopyPropagateArraysPass()) |
219 | 1.30k | .RegisterPass(CreateReduceLoadSizePass()) |
220 | 1.30k | .RegisterPass(CreateAggressiveDCEPass(preserve_interface)) |
221 | 1.30k | .RegisterPass(CreateBlockMergePass()) |
222 | 1.30k | .RegisterPass(CreateRedundancyEliminationPass()) |
223 | 1.30k | .RegisterPass(CreateDeadBranchElimPass()) |
224 | 1.30k | .RegisterPass(CreateBlockMergePass()) |
225 | 1.30k | .RegisterPass(CreateSimplificationPass()); |
226 | 1.30k | } |
227 | | |
228 | 1.30k | Optimizer& Optimizer::RegisterPerformancePasses() { |
229 | 1.30k | return RegisterPerformancePasses(false); |
230 | 1.30k | } |
231 | | |
232 | 362 | Optimizer& Optimizer::RegisterSizePasses(bool preserve_interface) { |
233 | 362 | return RegisterPass(CreateWrapOpKillPass()) |
234 | 362 | .RegisterPass(CreateDeadBranchElimPass()) |
235 | 362 | .RegisterPass(CreateMergeReturnPass()) |
236 | 362 | .RegisterPass(CreateInlineExhaustivePass()) |
237 | 362 | .RegisterPass(CreateEliminateDeadFunctionsPass()) |
238 | 362 | .RegisterPass(CreatePrivateToLocalPass()) |
239 | 362 | .RegisterPass(CreateScalarReplacementPass(0)) |
240 | 362 | .RegisterPass(CreateLocalMultiStoreElimPass()) |
241 | 362 | .RegisterPass(CreateCCPPass()) |
242 | 362 | .RegisterPass(CreateLoopUnrollPass(true)) |
243 | 362 | .RegisterPass(CreateDeadBranchElimPass()) |
244 | 362 | .RegisterPass(CreateSimplificationPass()) |
245 | 362 | .RegisterPass(CreateScalarReplacementPass(0)) |
246 | 362 | .RegisterPass(CreateLocalSingleStoreElimPass()) |
247 | 362 | .RegisterPass(CreateIfConversionPass()) |
248 | 362 | .RegisterPass(CreateSimplificationPass()) |
249 | 362 | .RegisterPass(CreateAggressiveDCEPass(preserve_interface)) |
250 | 362 | .RegisterPass(CreateDeadBranchElimPass()) |
251 | 362 | .RegisterPass(CreateBlockMergePass()) |
252 | 362 | .RegisterPass(CreateLocalAccessChainConvertPass()) |
253 | 362 | .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass()) |
254 | 362 | .RegisterPass(CreateAggressiveDCEPass(preserve_interface)) |
255 | 362 | .RegisterPass(CreateCopyPropagateArraysPass()) |
256 | 362 | .RegisterPass(CreateVectorDCEPass()) |
257 | 362 | .RegisterPass(CreateDeadInsertElimPass()) |
258 | 362 | .RegisterPass(CreateEliminateDeadMembersPass()) |
259 | 362 | .RegisterPass(CreateLocalSingleStoreElimPass()) |
260 | 362 | .RegisterPass(CreateBlockMergePass()) |
261 | 362 | .RegisterPass(CreateLocalMultiStoreElimPass()) |
262 | 362 | .RegisterPass(CreateRedundancyEliminationPass()) |
263 | 362 | .RegisterPass(CreateSimplificationPass()) |
264 | 362 | .RegisterPass(CreateAggressiveDCEPass(preserve_interface)) |
265 | 362 | .RegisterPass(CreateCFGCleanupPass()); |
266 | 362 | } |
267 | | |
268 | 362 | 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(0)); |
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 if (pass_name == "split-combined-image-sampler") { |
641 | 0 | RegisterPass(CreateSplitCombinedImageSamplerPass()); |
642 | 0 | } else if (pass_name == "resolve-binding-conflicts") { |
643 | 0 | RegisterPass(CreateResolveBindingConflictsPass()); |
644 | 0 | } else { |
645 | 0 | Errorf(consumer(), nullptr, {}, |
646 | 0 | "Unknown flag '--%s'. Use --help for a list of valid flags", |
647 | 0 | pass_name.c_str()); |
648 | 0 | return false; |
649 | 0 | } |
650 | | |
651 | 0 | return true; |
652 | 0 | } |
653 | | |
654 | 0 | void Optimizer::SetTargetEnv(const spv_target_env env) { |
655 | 0 | impl_->target_env = env; |
656 | 0 | } |
657 | | |
658 | | bool Optimizer::Run(const uint32_t* original_binary, |
659 | | const size_t original_binary_size, |
660 | 0 | std::vector<uint32_t>* optimized_binary) const { |
661 | 0 | return Run(original_binary, original_binary_size, optimized_binary, |
662 | 0 | OptimizerOptions()); |
663 | 0 | } |
664 | | |
665 | | bool Optimizer::Run(const uint32_t* original_binary, |
666 | | const size_t original_binary_size, |
667 | | std::vector<uint32_t>* optimized_binary, |
668 | | const ValidatorOptions& validator_options, |
669 | 0 | bool skip_validation) const { |
670 | 0 | OptimizerOptions opt_options; |
671 | 0 | opt_options.set_run_validator(!skip_validation); |
672 | 0 | opt_options.set_validator_options(validator_options); |
673 | 0 | return Run(original_binary, original_binary_size, optimized_binary, |
674 | 0 | opt_options); |
675 | 0 | } |
676 | | |
677 | | bool Optimizer::Run(const uint32_t* original_binary, |
678 | | const size_t original_binary_size, |
679 | | std::vector<uint32_t>* optimized_binary, |
680 | 1.83k | const spv_optimizer_options opt_options) const { |
681 | 1.83k | spvtools::SpirvTools tools(impl_->target_env); |
682 | 1.83k | tools.SetMessageConsumer(impl_->pass_manager.consumer()); |
683 | 1.83k | if (opt_options->run_validator_ && |
684 | 1.83k | !tools.Validate(original_binary, original_binary_size, |
685 | 1.83k | &opt_options->val_options_)) { |
686 | 114 | return false; |
687 | 114 | } |
688 | | |
689 | 1.72k | std::unique_ptr<opt::IRContext> context = BuildModule( |
690 | 1.72k | impl_->target_env, consumer(), original_binary, original_binary_size); |
691 | 1.72k | if (context == nullptr) return false; |
692 | | |
693 | 1.72k | context->set_max_id_bound(opt_options->max_id_bound_); |
694 | 1.72k | context->set_preserve_bindings(opt_options->preserve_bindings_); |
695 | 1.72k | context->set_preserve_spec_constants(opt_options->preserve_spec_constants_); |
696 | | |
697 | 1.72k | impl_->pass_manager.SetValidatorOptions(&opt_options->val_options_); |
698 | 1.72k | impl_->pass_manager.SetTargetEnv(impl_->target_env); |
699 | 1.72k | auto status = impl_->pass_manager.Run(context.get()); |
700 | | |
701 | 1.72k | if (status == opt::Pass::Status::Failure) { |
702 | 0 | return false; |
703 | 0 | } |
704 | | |
705 | | #ifndef NDEBUG |
706 | | // We do not keep the result id of DebugScope in struct DebugScope. |
707 | | // Instead, we assign random ids for them, which results in integrity |
708 | | // check failures. In addition, propagating the OpLine/OpNoLine to preserve |
709 | | // the debug information through transformations results in integrity |
710 | | // check failures. We want to skip the integrity check when the module |
711 | | // contains DebugScope or OpLine/OpNoLine instructions. |
712 | | if (status == opt::Pass::Status::SuccessWithoutChange && |
713 | | !context->module()->ContainsDebugInfo()) { |
714 | | std::vector<uint32_t> optimized_binary_with_nop; |
715 | | context->module()->ToBinary(&optimized_binary_with_nop, |
716 | | /* skip_nop = */ false); |
717 | | assert(optimized_binary_with_nop.size() == original_binary_size && |
718 | | "Binary size unexpectedly changed despite the optimizer saying " |
719 | | "there was no change"); |
720 | | |
721 | | // Compare the magic number to make sure the binaries were encoded in the |
722 | | // endianness. If not, the contents of the binaries will be different, so |
723 | | // do not check the contents. |
724 | | if (optimized_binary_with_nop[0] == original_binary[0]) { |
725 | | assert(memcmp(optimized_binary_with_nop.data(), original_binary, |
726 | | original_binary_size) == 0 && |
727 | | "Binary content unexpectedly changed despite the optimizer saying " |
728 | | "there was no change"); |
729 | | } |
730 | | } |
731 | | #endif // !NDEBUG |
732 | | |
733 | | // Note that |original_binary| and |optimized_binary| may share the same |
734 | | // buffer and the below will invalidate |original_binary|. |
735 | 1.72k | optimized_binary->clear(); |
736 | 1.72k | context->module()->ToBinary(optimized_binary, /* skip_nop = */ true); |
737 | | |
738 | 1.72k | return true; |
739 | 1.72k | } |
740 | | |
741 | 0 | Optimizer& Optimizer::SetPrintAll(std::ostream* out) { |
742 | 0 | impl_->pass_manager.SetPrintAll(out); |
743 | 0 | return *this; |
744 | 0 | } |
745 | | |
746 | 0 | Optimizer& Optimizer::SetTimeReport(std::ostream* out) { |
747 | 0 | impl_->pass_manager.SetTimeReport(out); |
748 | 0 | return *this; |
749 | 0 | } |
750 | | |
751 | 0 | Optimizer& Optimizer::SetValidateAfterAll(bool validate) { |
752 | 0 | impl_->pass_manager.SetValidateAfterAll(validate); |
753 | 0 | return *this; |
754 | 0 | } |
755 | | |
756 | 0 | Optimizer::PassToken CreateNullPass() { |
757 | 0 | return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::NullPass>()); |
758 | 0 | } |
759 | | |
760 | 1.66k | Optimizer::PassToken CreateStripDebugInfoPass() { |
761 | 1.66k | return MakeUnique<Optimizer::PassToken::Impl>( |
762 | 1.66k | MakeUnique<opt::StripDebugInfoPass>()); |
763 | 1.66k | } |
764 | | |
765 | 0 | Optimizer::PassToken CreateStripReflectInfoPass() { |
766 | 0 | return CreateStripNonSemanticInfoPass(); |
767 | 0 | } |
768 | | |
769 | 0 | Optimizer::PassToken CreateStripNonSemanticInfoPass() { |
770 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
771 | 0 | MakeUnique<opt::StripNonSemanticInfoPass>()); |
772 | 0 | } |
773 | | |
774 | 2.24k | Optimizer::PassToken CreateEliminateDeadFunctionsPass() { |
775 | 2.24k | return MakeUnique<Optimizer::PassToken::Impl>( |
776 | 2.24k | MakeUnique<opt::EliminateDeadFunctionsPass>()); |
777 | 2.24k | } |
778 | | |
779 | 362 | Optimizer::PassToken CreateEliminateDeadMembersPass() { |
780 | 362 | return MakeUnique<Optimizer::PassToken::Impl>( |
781 | 362 | MakeUnique<opt::EliminateDeadMembersPass>()); |
782 | 362 | } |
783 | | |
784 | | Optimizer::PassToken CreateSetSpecConstantDefaultValuePass( |
785 | 0 | const std::unordered_map<uint32_t, std::string>& id_value_map) { |
786 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
787 | 0 | MakeUnique<opt::SetSpecConstantDefaultValuePass>(id_value_map)); |
788 | 0 | } |
789 | | |
790 | | Optimizer::PassToken CreateSetSpecConstantDefaultValuePass( |
791 | 0 | const std::unordered_map<uint32_t, std::vector<uint32_t>>& id_value_map) { |
792 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
793 | 0 | MakeUnique<opt::SetSpecConstantDefaultValuePass>(id_value_map)); |
794 | 0 | } |
795 | | |
796 | 0 | Optimizer::PassToken CreateFlattenDecorationPass() { |
797 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
798 | 0 | MakeUnique<opt::FlattenDecorationPass>()); |
799 | 0 | } |
800 | | |
801 | 0 | Optimizer::PassToken CreateFreezeSpecConstantValuePass() { |
802 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
803 | 0 | MakeUnique<opt::FreezeSpecConstantValuePass>()); |
804 | 0 | } |
805 | | |
806 | 0 | Optimizer::PassToken CreateFoldSpecConstantOpAndCompositePass() { |
807 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
808 | 0 | MakeUnique<opt::FoldSpecConstantOpAndCompositePass>()); |
809 | 0 | } |
810 | | |
811 | 0 | Optimizer::PassToken CreateUnifyConstantPass() { |
812 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
813 | 0 | MakeUnique<opt::UnifyConstantPass>()); |
814 | 0 | } |
815 | | |
816 | 0 | Optimizer::PassToken CreateEliminateDeadConstantPass() { |
817 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
818 | 0 | MakeUnique<opt::EliminateDeadConstantPass>()); |
819 | 0 | } |
820 | | |
821 | 0 | Optimizer::PassToken CreateDeadVariableEliminationPass() { |
822 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
823 | 0 | MakeUnique<opt::DeadVariableElimination>()); |
824 | 0 | } |
825 | | |
826 | 0 | Optimizer::PassToken CreateStrengthReductionPass() { |
827 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
828 | 0 | MakeUnique<opt::StrengthReductionPass>()); |
829 | 0 | } |
830 | | |
831 | 3.32k | Optimizer::PassToken CreateBlockMergePass() { |
832 | 3.32k | return MakeUnique<Optimizer::PassToken::Impl>( |
833 | 3.32k | MakeUnique<opt::BlockMergePass>()); |
834 | 3.32k | } |
835 | | |
836 | 2.24k | Optimizer::PassToken CreateInlineExhaustivePass() { |
837 | 2.24k | return MakeUnique<Optimizer::PassToken::Impl>( |
838 | 2.24k | MakeUnique<opt::InlineExhaustivePass>()); |
839 | 2.24k | } |
840 | | |
841 | 0 | Optimizer::PassToken CreateInlineOpaquePass() { |
842 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
843 | 0 | MakeUnique<opt::InlineOpaquePass>()); |
844 | 0 | } |
845 | | |
846 | 2.96k | Optimizer::PassToken CreateLocalAccessChainConvertPass() { |
847 | 2.96k | return MakeUnique<Optimizer::PassToken::Impl>( |
848 | 2.96k | MakeUnique<opt::LocalAccessChainConvertPass>()); |
849 | 2.96k | } |
850 | | |
851 | 5.42k | Optimizer::PassToken CreateLocalSingleBlockLoadStoreElimPass() { |
852 | 5.42k | return MakeUnique<Optimizer::PassToken::Impl>( |
853 | 5.42k | MakeUnique<opt::LocalSingleBlockLoadStoreElimPass>()); |
854 | 5.42k | } |
855 | | |
856 | 5.78k | Optimizer::PassToken CreateLocalSingleStoreElimPass() { |
857 | 5.78k | return MakeUnique<Optimizer::PassToken::Impl>( |
858 | 5.78k | MakeUnique<opt::LocalSingleStoreElimPass>()); |
859 | 5.78k | } |
860 | | |
861 | 0 | Optimizer::PassToken CreateInsertExtractElimPass() { |
862 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
863 | 0 | MakeUnique<opt::SimplificationPass>()); |
864 | 0 | } |
865 | | |
866 | 2.24k | Optimizer::PassToken CreateDeadInsertElimPass() { |
867 | 2.24k | return MakeUnique<Optimizer::PassToken::Impl>( |
868 | 2.24k | MakeUnique<opt::DeadInsertElimPass>()); |
869 | 2.24k | } |
870 | | |
871 | 7.44k | Optimizer::PassToken CreateDeadBranchElimPass() { |
872 | 7.44k | return MakeUnique<Optimizer::PassToken::Impl>( |
873 | 7.44k | MakeUnique<opt::DeadBranchElimPass>()); |
874 | 7.44k | } |
875 | | |
876 | 2.60k | Optimizer::PassToken CreateLocalMultiStoreElimPass() { |
877 | 2.60k | return MakeUnique<Optimizer::PassToken::Impl>( |
878 | 2.60k | MakeUnique<opt::SSARewritePass>()); |
879 | 2.60k | } |
880 | | |
881 | 0 | Optimizer::PassToken CreateAggressiveDCEPass() { |
882 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
883 | 0 | MakeUnique<opt::AggressiveDCEPass>(false, false)); |
884 | 0 | } |
885 | | |
886 | 14.3k | Optimizer::PassToken CreateAggressiveDCEPass(bool preserve_interface) { |
887 | 14.3k | return MakeUnique<Optimizer::PassToken::Impl>( |
888 | 14.3k | MakeUnique<opt::AggressiveDCEPass>(preserve_interface, false)); |
889 | 14.3k | } |
890 | | |
891 | | Optimizer::PassToken CreateAggressiveDCEPass(bool preserve_interface, |
892 | 0 | bool remove_outputs) { |
893 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
894 | 0 | MakeUnique<opt::AggressiveDCEPass>(preserve_interface, remove_outputs)); |
895 | 0 | } |
896 | | |
897 | 576 | Optimizer::PassToken CreateRemoveUnusedInterfaceVariablesPass() { |
898 | 576 | return MakeUnique<Optimizer::PassToken::Impl>( |
899 | 576 | MakeUnique<opt::RemoveUnusedInterfaceVariablesPass>()); |
900 | 576 | } |
901 | | |
902 | 0 | Optimizer::PassToken CreatePropagateLineInfoPass() { |
903 | 0 | return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::EmptyPass>()); |
904 | 0 | } |
905 | | |
906 | 0 | Optimizer::PassToken CreateRedundantLineInfoElimPass() { |
907 | 0 | return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::EmptyPass>()); |
908 | 0 | } |
909 | | |
910 | 0 | Optimizer::PassToken CreateCompactIdsPass() { |
911 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
912 | 0 | MakeUnique<opt::CompactIdsPass>()); |
913 | 0 | } |
914 | | |
915 | 2.24k | Optimizer::PassToken CreateMergeReturnPass() { |
916 | 2.24k | return MakeUnique<Optimizer::PassToken::Impl>( |
917 | 2.24k | MakeUnique<opt::MergeReturnPass>()); |
918 | 2.24k | } |
919 | | |
920 | 0 | std::vector<const char*> Optimizer::GetPassNames() const { |
921 | 0 | std::vector<const char*> v; |
922 | 0 | for (uint32_t i = 0; i < impl_->pass_manager.NumPasses(); i++) { |
923 | 0 | v.push_back(impl_->pass_manager.GetPass(i)->name()); |
924 | 0 | } |
925 | 0 | return v; |
926 | 0 | } |
927 | | |
928 | 362 | Optimizer::PassToken CreateCFGCleanupPass() { |
929 | 362 | return MakeUnique<Optimizer::PassToken::Impl>( |
930 | 362 | MakeUnique<opt::CFGCleanupPass>()); |
931 | 362 | } |
932 | | |
933 | 0 | Optimizer::PassToken CreateLocalRedundancyEliminationPass() { |
934 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
935 | 0 | MakeUnique<opt::LocalRedundancyEliminationPass>()); |
936 | 0 | } |
937 | | |
938 | 0 | Optimizer::PassToken CreateLoopFissionPass(size_t threshold) { |
939 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
940 | 0 | MakeUnique<opt::LoopFissionPass>(threshold)); |
941 | 0 | } |
942 | | |
943 | 0 | Optimizer::PassToken CreateLoopFusionPass(size_t max_registers_per_loop) { |
944 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
945 | 0 | MakeUnique<opt::LoopFusionPass>(max_registers_per_loop)); |
946 | 0 | } |
947 | | |
948 | 0 | Optimizer::PassToken CreateLoopInvariantCodeMotionPass() { |
949 | 0 | return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::LICMPass>()); |
950 | 0 | } |
951 | | |
952 | 0 | Optimizer::PassToken CreateLoopPeelingPass() { |
953 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
954 | 0 | MakeUnique<opt::LoopPeelingPass>()); |
955 | 0 | } |
956 | | |
957 | 0 | Optimizer::PassToken CreateLoopUnswitchPass() { |
958 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
959 | 0 | MakeUnique<opt::LoopUnswitchPass>()); |
960 | 0 | } |
961 | | |
962 | 2.96k | Optimizer::PassToken CreateRedundancyEliminationPass() { |
963 | 2.96k | return MakeUnique<Optimizer::PassToken::Impl>( |
964 | 2.96k | MakeUnique<opt::RedundancyEliminationPass>()); |
965 | 2.96k | } |
966 | | |
967 | 0 | Optimizer::PassToken CreateRemoveDuplicatesPass() { |
968 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
969 | 0 | MakeUnique<opt::RemoveDuplicatesPass>()); |
970 | 0 | } |
971 | | |
972 | 3.90k | Optimizer::PassToken CreateScalarReplacementPass(uint32_t size_limit) { |
973 | 3.90k | return MakeUnique<Optimizer::PassToken::Impl>( |
974 | 3.90k | MakeUnique<opt::ScalarReplacementPass>(size_limit)); |
975 | 3.90k | } |
976 | | |
977 | 2.24k | Optimizer::PassToken CreatePrivateToLocalPass() { |
978 | 2.24k | return MakeUnique<Optimizer::PassToken::Impl>( |
979 | 2.24k | MakeUnique<opt::PrivateToLocalPass>()); |
980 | 2.24k | } |
981 | | |
982 | 2.24k | Optimizer::PassToken CreateCCPPass() { |
983 | 2.24k | return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::CCPPass>()); |
984 | 2.24k | } |
985 | | |
986 | 0 | Optimizer::PassToken CreateWorkaround1209Pass() { |
987 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
988 | 0 | MakeUnique<opt::Workaround1209>()); |
989 | 0 | } |
990 | | |
991 | 1.66k | Optimizer::PassToken CreateIfConversionPass() { |
992 | 1.66k | return MakeUnique<Optimizer::PassToken::Impl>( |
993 | 1.66k | MakeUnique<opt::IfConversion>()); |
994 | 1.66k | } |
995 | | |
996 | 0 | Optimizer::PassToken CreateReplaceInvalidOpcodePass() { |
997 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
998 | 0 | MakeUnique<opt::ReplaceInvalidOpcodePass>()); |
999 | 0 | } |
1000 | | |
1001 | 5.56k | Optimizer::PassToken CreateSimplificationPass() { |
1002 | 5.56k | return MakeUnique<Optimizer::PassToken::Impl>( |
1003 | 5.56k | MakeUnique<opt::SimplificationPass>()); |
1004 | 5.56k | } |
1005 | | |
1006 | 2.24k | Optimizer::PassToken CreateLoopUnrollPass(bool fully_unroll, int factor) { |
1007 | 2.24k | return MakeUnique<Optimizer::PassToken::Impl>( |
1008 | 2.24k | MakeUnique<opt::LoopUnroller>(fully_unroll, factor)); |
1009 | 2.24k | } |
1010 | | |
1011 | 1.30k | Optimizer::PassToken CreateSSARewritePass() { |
1012 | 1.30k | return MakeUnique<Optimizer::PassToken::Impl>( |
1013 | 1.30k | MakeUnique<opt::SSARewritePass>()); |
1014 | 1.30k | } |
1015 | | |
1016 | 2.24k | Optimizer::PassToken CreateCopyPropagateArraysPass() { |
1017 | 2.24k | return MakeUnique<Optimizer::PassToken::Impl>( |
1018 | 2.24k | MakeUnique<opt::CopyPropagateArrays>()); |
1019 | 2.24k | } |
1020 | | |
1021 | 2.24k | Optimizer::PassToken CreateVectorDCEPass() { |
1022 | 2.24k | return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::VectorDCE>()); |
1023 | 2.24k | } |
1024 | | |
1025 | | Optimizer::PassToken CreateReduceLoadSizePass( |
1026 | 1.87k | double load_replacement_threshold) { |
1027 | 1.87k | return MakeUnique<Optimizer::PassToken::Impl>( |
1028 | 1.87k | MakeUnique<opt::ReduceLoadSize>(load_replacement_threshold)); |
1029 | 1.87k | } |
1030 | | |
1031 | 1.30k | Optimizer::PassToken CreateCombineAccessChainsPass() { |
1032 | 1.30k | return MakeUnique<Optimizer::PassToken::Impl>( |
1033 | 1.30k | MakeUnique<opt::CombineAccessChains>()); |
1034 | 1.30k | } |
1035 | | |
1036 | 0 | Optimizer::PassToken CreateUpgradeMemoryModelPass() { |
1037 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
1038 | 0 | MakeUnique<opt::UpgradeMemoryModel>()); |
1039 | 0 | } |
1040 | | |
1041 | 0 | Optimizer::PassToken CreateConvertRelaxedToHalfPass() { |
1042 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
1043 | 0 | MakeUnique<opt::ConvertToHalfPass>()); |
1044 | 0 | } |
1045 | | |
1046 | 0 | Optimizer::PassToken CreateRelaxFloatOpsPass() { |
1047 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
1048 | 0 | MakeUnique<opt::RelaxFloatOpsPass>()); |
1049 | 0 | } |
1050 | | |
1051 | 0 | Optimizer::PassToken CreateCodeSinkingPass() { |
1052 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
1053 | 0 | MakeUnique<opt::CodeSinkingPass>()); |
1054 | 0 | } |
1055 | | |
1056 | 576 | Optimizer::PassToken CreateFixStorageClassPass() { |
1057 | 576 | return MakeUnique<Optimizer::PassToken::Impl>( |
1058 | 576 | MakeUnique<opt::FixStorageClass>()); |
1059 | 576 | } |
1060 | | |
1061 | 0 | Optimizer::PassToken CreateGraphicsRobustAccessPass() { |
1062 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
1063 | 0 | MakeUnique<opt::GraphicsRobustAccessPass>()); |
1064 | 0 | } |
1065 | | |
1066 | 0 | Optimizer::PassToken CreateReplaceDescArrayAccessUsingVarIndexPass() { |
1067 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
1068 | 0 | MakeUnique<opt::ReplaceDescArrayAccessUsingVarIndex>()); |
1069 | 0 | } |
1070 | | |
1071 | 0 | Optimizer::PassToken CreateSpreadVolatileSemanticsPass() { |
1072 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
1073 | 0 | MakeUnique<opt::SpreadVolatileSemantics>()); |
1074 | 0 | } |
1075 | | |
1076 | 0 | Optimizer::PassToken CreateDescriptorScalarReplacementPass() { |
1077 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
1078 | 0 | MakeUnique<opt::DescriptorScalarReplacement>( |
1079 | 0 | /* flatten_composites= */ true, /* flatten_arrays= */ true)); |
1080 | 0 | } |
1081 | | |
1082 | 0 | Optimizer::PassToken CreateDescriptorCompositeScalarReplacementPass() { |
1083 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
1084 | 0 | MakeUnique<opt::DescriptorScalarReplacement>( |
1085 | 0 | /* flatten_composites= */ true, /* flatten_arrays= */ false)); |
1086 | 0 | } |
1087 | | |
1088 | 0 | Optimizer::PassToken CreateDescriptorArrayScalarReplacementPass() { |
1089 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
1090 | 0 | MakeUnique<opt::DescriptorScalarReplacement>( |
1091 | 0 | /* flatten_composites= */ false, /* flatten_arrays= */ true)); |
1092 | 0 | } |
1093 | | |
1094 | 2.24k | Optimizer::PassToken CreateWrapOpKillPass() { |
1095 | 2.24k | return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::WrapOpKill>()); |
1096 | 2.24k | } |
1097 | | |
1098 | 0 | Optimizer::PassToken CreateAmdExtToKhrPass() { |
1099 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
1100 | 0 | MakeUnique<opt::AmdExtensionToKhrPass>()); |
1101 | 0 | } |
1102 | | |
1103 | 576 | Optimizer::PassToken CreateInterpolateFixupPass() { |
1104 | 576 | return MakeUnique<Optimizer::PassToken::Impl>( |
1105 | 576 | MakeUnique<opt::InterpFixupPass>()); |
1106 | 576 | } |
1107 | | |
1108 | 0 | Optimizer::PassToken CreateEliminateDeadInputComponentsPass() { |
1109 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
1110 | 0 | MakeUnique<opt::EliminateDeadIOComponentsPass>(spv::StorageClass::Input, |
1111 | 0 | /* safe_mode */ false)); |
1112 | 0 | } |
1113 | | |
1114 | 0 | Optimizer::PassToken CreateEliminateDeadOutputComponentsPass() { |
1115 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
1116 | 0 | MakeUnique<opt::EliminateDeadIOComponentsPass>(spv::StorageClass::Output, |
1117 | 0 | /* safe_mode */ false)); |
1118 | 0 | } |
1119 | | |
1120 | 0 | Optimizer::PassToken CreateEliminateDeadInputComponentsSafePass() { |
1121 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
1122 | 0 | MakeUnique<opt::EliminateDeadIOComponentsPass>(spv::StorageClass::Input, |
1123 | 0 | /* safe_mode */ true)); |
1124 | 0 | } |
1125 | | |
1126 | | Optimizer::PassToken CreateAnalyzeLiveInputPass( |
1127 | | std::unordered_set<uint32_t>* live_locs, |
1128 | 0 | std::unordered_set<uint32_t>* live_builtins) { |
1129 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
1130 | 0 | MakeUnique<opt::AnalyzeLiveInputPass>(live_locs, live_builtins)); |
1131 | 0 | } |
1132 | | |
1133 | | Optimizer::PassToken CreateEliminateDeadOutputStoresPass( |
1134 | | std::unordered_set<uint32_t>* live_locs, |
1135 | 0 | std::unordered_set<uint32_t>* live_builtins) { |
1136 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
1137 | 0 | MakeUnique<opt::EliminateDeadOutputStoresPass>(live_locs, live_builtins)); |
1138 | 0 | } |
1139 | | |
1140 | | Optimizer::PassToken CreateConvertToSampledImagePass( |
1141 | | const std::vector<opt::DescriptorSetAndBinding>& |
1142 | 0 | descriptor_set_binding_pairs) { |
1143 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
1144 | 0 | MakeUnique<opt::ConvertToSampledImagePass>(descriptor_set_binding_pairs)); |
1145 | 0 | } |
1146 | | |
1147 | 0 | Optimizer::PassToken CreateInterfaceVariableScalarReplacementPass() { |
1148 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
1149 | 0 | MakeUnique<opt::InterfaceVariableScalarReplacement>()); |
1150 | 0 | } |
1151 | | |
1152 | 0 | Optimizer::PassToken CreateRemoveDontInlinePass() { |
1153 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
1154 | 0 | MakeUnique<opt::RemoveDontInline>()); |
1155 | 0 | } |
1156 | | |
1157 | 0 | Optimizer::PassToken CreateFixFuncCallArgumentsPass() { |
1158 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
1159 | 0 | MakeUnique<opt::FixFuncCallArgumentsPass>()); |
1160 | 0 | } |
1161 | | |
1162 | 0 | Optimizer::PassToken CreateTrimCapabilitiesPass() { |
1163 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
1164 | 0 | MakeUnique<opt::TrimCapabilitiesPass>()); |
1165 | 0 | } |
1166 | | |
1167 | | Optimizer::PassToken CreateStructPackingPass(const char* structToPack, |
1168 | 0 | const char* packingRule) { |
1169 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
1170 | 0 | MakeUnique<opt::StructPackingPass>( |
1171 | 0 | structToPack, |
1172 | 0 | opt::StructPackingPass::ParsePackingRuleFromString(packingRule))); |
1173 | 0 | } |
1174 | | |
1175 | 0 | Optimizer::PassToken CreateSwitchDescriptorSetPass(uint32_t from, uint32_t to) { |
1176 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
1177 | 0 | MakeUnique<opt::SwitchDescriptorSetPass>(from, to)); |
1178 | 0 | } |
1179 | | |
1180 | 576 | Optimizer::PassToken CreateInvocationInterlockPlacementPass() { |
1181 | 576 | return MakeUnique<Optimizer::PassToken::Impl>( |
1182 | 576 | MakeUnique<opt::InvocationInterlockPlacementPass>()); |
1183 | 576 | } |
1184 | | |
1185 | 0 | Optimizer::PassToken CreateModifyMaximalReconvergencePass(bool add) { |
1186 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
1187 | 0 | MakeUnique<opt::ModifyMaximalReconvergence>(add)); |
1188 | 0 | } |
1189 | | |
1190 | 576 | Optimizer::PassToken CreateOpExtInstWithForwardReferenceFixupPass() { |
1191 | 576 | return MakeUnique<Optimizer::PassToken::Impl>( |
1192 | 576 | MakeUnique<opt::OpExtInstWithForwardReferenceFixupPass>()); |
1193 | 576 | } |
1194 | | |
1195 | 0 | Optimizer::PassToken CreateSplitCombinedImageSamplerPass() { |
1196 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
1197 | 0 | MakeUnique<opt::SplitCombinedImageSamplerPass>()); |
1198 | 0 | } |
1199 | | |
1200 | 0 | Optimizer::PassToken CreateResolveBindingConflictsPass() { |
1201 | 0 | return MakeUnique<Optimizer::PassToken::Impl>( |
1202 | 0 | MakeUnique<opt::ResolveBindingConflictsPass>()); |
1203 | 0 | } |
1204 | | |
1205 | | } // namespace spvtools |
1206 | | |
1207 | | extern "C" { |
1208 | | |
1209 | 0 | SPIRV_TOOLS_EXPORT spv_optimizer_t* spvOptimizerCreate(spv_target_env env) { |
1210 | 0 | return reinterpret_cast<spv_optimizer_t*>(new spvtools::Optimizer(env)); |
1211 | 0 | } |
1212 | | |
1213 | 0 | SPIRV_TOOLS_EXPORT void spvOptimizerDestroy(spv_optimizer_t* optimizer) { |
1214 | 0 | delete reinterpret_cast<spvtools::Optimizer*>(optimizer); |
1215 | 0 | } |
1216 | | |
1217 | | SPIRV_TOOLS_EXPORT void spvOptimizerSetMessageConsumer( |
1218 | 0 | spv_optimizer_t* optimizer, spv_message_consumer consumer) { |
1219 | 0 | reinterpret_cast<spvtools::Optimizer*>(optimizer)-> |
1220 | 0 | SetMessageConsumer( |
1221 | 0 | [consumer](spv_message_level_t level, const char* source, |
1222 | 0 | const spv_position_t& position, const char* message) { |
1223 | 0 | return consumer(level, source, &position, message); |
1224 | 0 | }); |
1225 | 0 | } |
1226 | | |
1227 | | SPIRV_TOOLS_EXPORT void spvOptimizerRegisterLegalizationPasses( |
1228 | 0 | spv_optimizer_t* optimizer) { |
1229 | 0 | reinterpret_cast<spvtools::Optimizer*>(optimizer)-> |
1230 | 0 | RegisterLegalizationPasses(); |
1231 | 0 | } |
1232 | | |
1233 | | SPIRV_TOOLS_EXPORT void spvOptimizerRegisterPerformancePasses( |
1234 | 0 | spv_optimizer_t* optimizer) { |
1235 | 0 | reinterpret_cast<spvtools::Optimizer*>(optimizer)-> |
1236 | 0 | RegisterPerformancePasses(); |
1237 | 0 | } |
1238 | | |
1239 | | SPIRV_TOOLS_EXPORT void spvOptimizerRegisterSizePasses( |
1240 | 0 | spv_optimizer_t* optimizer) { |
1241 | 0 | reinterpret_cast<spvtools::Optimizer*>(optimizer)->RegisterSizePasses(); |
1242 | 0 | } |
1243 | | |
1244 | | SPIRV_TOOLS_EXPORT bool spvOptimizerRegisterPassFromFlag( |
1245 | | spv_optimizer_t* optimizer, const char* flag) |
1246 | 0 | { |
1247 | 0 | return reinterpret_cast<spvtools::Optimizer*>(optimizer)-> |
1248 | 0 | RegisterPassFromFlag(flag); |
1249 | 0 | } |
1250 | | |
1251 | | SPIRV_TOOLS_EXPORT bool spvOptimizerRegisterPassesFromFlags( |
1252 | 0 | spv_optimizer_t* optimizer, const char** flags, const size_t flag_count) { |
1253 | 0 | std::vector<std::string> opt_flags = |
1254 | 0 | spvtools::GetVectorOfStrings(flags, flag_count); |
1255 | 0 | return reinterpret_cast<spvtools::Optimizer*>(optimizer) |
1256 | 0 | ->RegisterPassesFromFlags(opt_flags, false); |
1257 | 0 | } |
1258 | | |
1259 | | SPIRV_TOOLS_EXPORT bool |
1260 | | spvOptimizerRegisterPassesFromFlagsWhilePreservingTheInterface( |
1261 | 0 | spv_optimizer_t* optimizer, const char** flags, const size_t flag_count) { |
1262 | 0 | std::vector<std::string> opt_flags = |
1263 | 0 | spvtools::GetVectorOfStrings(flags, flag_count); |
1264 | 0 | return reinterpret_cast<spvtools::Optimizer*>(optimizer) |
1265 | 0 | ->RegisterPassesFromFlags(opt_flags, true); |
1266 | 0 | } |
1267 | | |
1268 | | SPIRV_TOOLS_EXPORT |
1269 | | spv_result_t spvOptimizerRun(spv_optimizer_t* optimizer, |
1270 | | const uint32_t* binary, |
1271 | | const size_t word_count, |
1272 | | spv_binary* optimized_binary, |
1273 | 0 | const spv_optimizer_options options) { |
1274 | 0 | std::vector<uint32_t> optimized; |
1275 | |
|
1276 | 0 | if (!reinterpret_cast<spvtools::Optimizer*>(optimizer)-> |
1277 | 0 | Run(binary, word_count, &optimized, options)) { |
1278 | 0 | return SPV_ERROR_INTERNAL; |
1279 | 0 | } |
1280 | | |
1281 | 0 | auto result_binary = new spv_binary_t(); |
1282 | 0 | if (!result_binary) { |
1283 | 0 | *optimized_binary = nullptr; |
1284 | 0 | return SPV_ERROR_OUT_OF_MEMORY; |
1285 | 0 | } |
1286 | | |
1287 | 0 | result_binary->code = new uint32_t[optimized.size()]; |
1288 | 0 | if (!result_binary->code) { |
1289 | 0 | delete result_binary; |
1290 | 0 | *optimized_binary = nullptr; |
1291 | 0 | return SPV_ERROR_OUT_OF_MEMORY; |
1292 | 0 | } |
1293 | 0 | result_binary->wordCount = optimized.size(); |
1294 | |
|
1295 | 0 | memcpy(result_binary->code, optimized.data(), |
1296 | 0 | optimized.size() * sizeof(uint32_t)); |
1297 | |
|
1298 | 0 | *optimized_binary = result_binary; |
1299 | |
|
1300 | 0 | return SPV_SUCCESS; |
1301 | 0 | } |
1302 | | |
1303 | | } // extern "C" |