8d9f94d5dd6bfdafd57d0aef96c7e59a7aea0de3
[platform/upstream/SPIRV-Tools.git] / include / spirv-tools / optimizer.hpp
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 #ifndef SPIRV_TOOLS_OPTIMIZER_HPP_
16 #define SPIRV_TOOLS_OPTIMIZER_HPP_
17
18 #include <memory>
19 #include <string>
20 #include <unordered_map>
21 #include <vector>
22
23 #include "libspirv.hpp"
24
25 namespace spvtools {
26
27 // C++ interface for SPIR-V optimization functionalities. It wraps the context
28 // (including target environment and the corresponding SPIR-V grammar) and
29 // provides methods for registering optimization passes and optimizing.
30 //
31 // Instances of this class provides basic thread-safety guarantee.
32 class Optimizer {
33  public:
34   // The token for an optimization pass. It is returned via one of the
35   // Create*Pass() standalone functions at the end of this header file and
36   // consumed by the RegisterPass() method. Tokens are one-time objects that
37   // only support move; copying is not allowed.
38   struct PassToken {
39     struct Impl;  // Opaque struct for holding inernal data.
40
41     PassToken(std::unique_ptr<Impl>);
42
43     // Tokens can only be moved. Copying is disabled.
44     PassToken(const PassToken&) = delete;
45     PassToken(PassToken&&);
46     PassToken& operator=(const PassToken&) = delete;
47     PassToken& operator=(PassToken&&);
48
49     ~PassToken();
50
51     std::unique_ptr<Impl> impl_;  // Unique pointer to internal data.
52   };
53
54   // Constructs an instance with the given target |env|, which is used to decode
55   // the binaries to be optimized later.
56   //
57   // The constructed instance will have an empty message consumer, which just
58   // ignores all messages from the library. Use SetMessageConsumer() to supply
59   // one if messages are of concern.
60   explicit Optimizer(spv_target_env env);
61
62   // Disables copy/move constructor/assignment operations.
63   Optimizer(const Optimizer&) = delete;
64   Optimizer(Optimizer&&) = delete;
65   Optimizer& operator=(const Optimizer&) = delete;
66   Optimizer& operator=(Optimizer&&) = delete;
67
68   // Destructs this instance.
69   ~Optimizer();
70
71   // Sets the message consumer to the given |consumer|. The |consumer| will be
72   // invoked once for each message communicated from the library.
73   void SetMessageConsumer(MessageConsumer consumer);
74
75   // Registers the given |pass| to this optimizer. Passes will be run in the
76   // exact order of registration. The token passed in will be consumed by this
77   // method.
78   Optimizer& RegisterPass(PassToken&& pass);
79
80   // Registers passes that attempt to improve performance of generated code.
81   // This sequence of passes is subject to constant review and will change
82   // from time to time.
83   Optimizer& RegisterPerformancePasses();
84
85   // Registers passes that attempt to improve the size of generated code.
86   // This sequence of passes is subject to constant review and will change
87   // from time to time.
88   Optimizer& RegisterSizePasses();
89
90   // Optimizes the given SPIR-V module |original_binary| and writes the
91   // optimized binary into |optimized_binary|.
92   // Returns true on successful optimization, whether or not the module is
93   // modified. Returns false if errors occur when processing |original_binary|
94   // using any of the registered passes. In that case, no further passes are
95   // executed and the contents in |optimized_binary| may be invalid.
96   //
97   // It's allowed to alias |original_binary| to the start of |optimized_binary|.
98   bool Run(const uint32_t* original_binary, size_t original_binary_size,
99            std::vector<uint32_t>* optimized_binary) const;
100
101   // Returns a vector of strings with all the pass names added to this
102   // optimizer's pass manager. These strings are valid until the associated
103   // pass manager is destroyed.
104   std::vector<const char*> GetPassNames() const;
105
106  private:
107   struct Impl;                  // Opaque struct for holding internal data.
108   std::unique_ptr<Impl> impl_;  // Unique pointer to internal data.
109 };
110
111 // Creates a null pass.
112 // A null pass does nothing to the SPIR-V module to be optimized.
113 Optimizer::PassToken CreateNullPass();
114
115 // Creates a strip-debug-info pass.
116 // A strip-debug-info pass removes all debug instructions (as documented in
117 // Section 3.32.2 of the SPIR-V spec) of the SPIR-V module to be optimized.
118 Optimizer::PassToken CreateStripDebugInfoPass();
119
120 // Creates an eliminate-dead-functions pass.
121 // An eliminate-dead-functions pass will remove all functions that are not in
122 // the call trees rooted at entry points and exported functions.  These
123 // functions are not needed because they will never be called.
124 Optimizer::PassToken CreateEliminateDeadFunctionsPass();
125
126 // Creates a set-spec-constant-default-value pass from a mapping from spec-ids
127 // to the default values in the form of string.
128 // A set-spec-constant-default-value pass sets the default values for the
129 // spec constants that have SpecId decorations (i.e., those defined by
130 // OpSpecConstant{|True|False} instructions).
131 Optimizer::PassToken CreateSetSpecConstantDefaultValuePass(
132     const std::unordered_map<uint32_t, std::string>& id_value_map);
133
134 // Creates a set-spec-constant-default-value pass from a mapping from spec-ids
135 // to the default values in the form of bit pattern.
136 // A set-spec-constant-default-value pass sets the default values for the
137 // spec constants that have SpecId decorations (i.e., those defined by
138 // OpSpecConstant{|True|False} instructions).
139 Optimizer::PassToken CreateSetSpecConstantDefaultValuePass(
140     const std::unordered_map<uint32_t, std::vector<uint32_t>>& id_value_map);
141
142 // Creates a flatten-decoration pass.
143 // A flatten-decoration pass replaces grouped decorations with equivalent
144 // ungrouped decorations.  That is, it replaces each OpDecorationGroup
145 // instruction and associated OpGroupDecorate and OpGroupMemberDecorate
146 // instructions with equivalent OpDecorate and OpMemberDecorate instructions.
147 // The pass does not attempt to preserve debug information for instructions
148 // it removes.
149 Optimizer::PassToken CreateFlattenDecorationPass();
150
151 // Creates a freeze-spec-constant-value pass.
152 // A freeze-spec-constant pass specializes the value of spec constants to
153 // their default values. This pass only processes the spec constants that have
154 // SpecId decorations (defined by OpSpecConstant, OpSpecConstantTrue, or
155 // OpSpecConstantFalse instructions) and replaces them with their normal
156 // counterparts (OpConstant, OpConstantTrue, or OpConstantFalse). The
157 // corresponding SpecId annotation instructions will also be removed. This
158 // pass does not fold the newly added normal constants and does not process
159 // other spec constants defined by OpSpecConstantComposite or
160 // OpSpecConstantOp.
161 Optimizer::PassToken CreateFreezeSpecConstantValuePass();
162
163 // Creates a fold-spec-constant-op-and-composite pass.
164 // A fold-spec-constant-op-and-composite pass folds spec constants defined by
165 // OpSpecConstantOp or OpSpecConstantComposite instruction, to normal Constants
166 // defined by OpConstantTrue, OpConstantFalse, OpConstant, OpConstantNull, or
167 // OpConstantComposite instructions. Note that spec constants defined with
168 // OpSpecConstant, OpSpecConstantTrue, or OpSpecConstantFalse instructions are
169 // not handled, as these instructions indicate their value are not determined
170 // and can be changed in future. A spec constant is foldable if all of its
171 // value(s) can be determined from the module. E.g., an integer spec constant
172 // defined with OpSpecConstantOp instruction can be folded if its value won't
173 // change later. This pass will replace the original OpSpecContantOp instruction
174 // with an OpConstant instruction. When folding composite spec constants,
175 // new instructions may be inserted to define the components of the composite
176 // constant first, then the original spec constants will be replaced by
177 // OpConstantComposite instructions.
178 //
179 // There are some operations not supported yet:
180 //   OpSConvert, OpFConvert, OpQuantizeToF16 and
181 //   all the operations under Kernel capability.
182 // TODO(qining): Add support for the operations listed above.
183 Optimizer::PassToken CreateFoldSpecConstantOpAndCompositePass();
184
185 // Creates a unify-constant pass.
186 // A unify-constant pass de-duplicates the constants. Constants with the exact
187 // same value and identical form will be unified and only one constant will
188 // be kept for each unique pair of type and value.
189 // There are several cases not handled by this pass:
190 //  1) Constants defined by OpConstantNull instructions (null constants) and
191 //  constants defined by OpConstantFalse, OpConstant or OpConstantComposite
192 //  with value 0 (zero-valued normal constants) are not considered equivalent.
193 //  So null constants won't be used to replace zero-valued normal constants,
194 //  vice versa.
195 //  2) Whenever there are decorations to the constant's result id id, the
196 //  constant won't be handled, which means, it won't be used to replace any
197 //  other constants, neither can other constants replace it.
198 //  3) NaN in float point format with different bit patterns are not unified.
199 Optimizer::PassToken CreateUnifyConstantPass();
200
201 // Creates a eliminate-dead-constant pass.
202 // A eliminate-dead-constant pass removes dead constants, including normal
203 // contants defined by OpConstant, OpConstantComposite, OpConstantTrue, or
204 // OpConstantFalse and spec constants defined by OpSpecConstant,
205 // OpSpecConstantComposite, OpSpecConstantTrue, OpSpecConstantFalse or
206 // OpSpecConstantOp.
207 Optimizer::PassToken CreateEliminateDeadConstantPass();
208
209 // Creates a strength-reduction pass.
210 // A strength-reduction pass will look for opportunities to replace an
211 // instruction with an equivalent and less expensive one.  For example,
212 // multiplying by a power of 2 can be replaced by a bit shift.
213 Optimizer::PassToken CreateStrengthReductionPass();
214
215 // Creates a block merge pass.
216 // This pass searches for blocks with a single Branch to a block with no
217 // other predecessors and merges the blocks into a single block. Continue
218 // blocks and Merge blocks are not candidates for the second block.
219 //
220 // The pass is most useful after Dead Branch Elimination, which can leave
221 // such sequences of blocks. Merging them makes subsequent passes more
222 // effective, such as single block local store-load elimination.
223 //
224 // While this pass reduces the number of occurrences of this sequence, at
225 // this time it does not guarantee all such sequences are eliminated.
226 //
227 // Presence of phi instructions can inhibit this optimization. Handling
228 // these is left for future improvements.
229 Optimizer::PassToken CreateBlockMergePass();
230
231 // Creates an exhaustive inline pass.
232 // An exhaustive inline pass attempts to exhaustively inline all function
233 // calls in all functions in an entry point call tree. The intent is to enable,
234 // albeit through brute force, analysis and optimization across function
235 // calls by subsequent optimization passes. As the inlining is exhaustive,
236 // there is no attempt to optimize for size or runtime performance. Functions
237 // that are not in the call tree of an entry point are not changed.
238 Optimizer::PassToken CreateInlineExhaustivePass();
239
240 // Creates an opaque inline pass.
241 // An opaque inline pass inlines all function calls in all functions in all
242 // entry point call trees where the called function contains an opaque type
243 // in either its parameter types or return type. An opaque type is currently
244 // defined as Image, Sampler or SampledImage. The intent is to enable, albeit
245 // through brute force, analysis and optimization across these function calls
246 // by subsequent passes in order to remove the storing of opaque types which is
247 // not legal in Vulkan. Functions that are not in the call tree of an entry
248 // point are not changed.
249 Optimizer::PassToken CreateInlineOpaquePass();
250
251 // Creates a single-block local variable load/store elimination pass.
252 // For every entry point function, do single block memory optimization of
253 // function variables referenced only with non-access-chain loads and stores.
254 // For each targeted variable load, if previous store to that variable in the
255 // block, replace the load's result id with the value id of the store.
256 // If previous load within the block, replace the current load's result id
257 // with the previous load's result id. In either case, delete the current
258 // load. Finally, check if any remaining stores are useless, and delete store
259 // and variable if possible.
260 //
261 // The presence of access chain references and function calls can inhibit
262 // the above optimization.
263 //
264 // Only modules with logical addressing are currently processed.
265 //
266 // This pass is most effective if preceeded by Inlining and
267 // LocalAccessChainConvert. This pass will reduce the work needed to be done
268 // by LocalSingleStoreElim and LocalMultiStoreElim.
269 //
270 // Only functions in the call tree of an entry point are processed.
271 Optimizer::PassToken CreateLocalSingleBlockLoadStoreElimPass();
272
273 // Create dead branch elimination pass.
274 // For each entry point function, this pass will look for SelectionMerge
275 // BranchConditionals with constant condition and convert to a Branch to
276 // the indicated label. It will delete resulting dead blocks.
277 //
278 // For all phi functions in merge block, replace all uses with the id
279 // corresponding to the living predecessor.
280 //
281 // This pass only works on shaders (guaranteed to have structured control
282 // flow). Note that some such branches and blocks may be left to avoid
283 // creating invalid control flow. Improving this is left to future work.
284 //
285 // This pass is most effective when preceeded by passes which eliminate
286 // local loads and stores, effectively propagating constant values where
287 // possible.
288 Optimizer::PassToken CreateDeadBranchElimPass();
289
290 // Creates an SSA local variable load/store elimination pass.
291 // For every entry point function, eliminate all loads and stores of function
292 // scope variables only referenced with non-access-chain loads and stores.
293 // Eliminate the variables as well.
294 //
295 // The presence of access chain references and function calls can inhibit
296 // the above optimization.
297 //
298 // Only shader modules with logical addressing are currently processed.
299 // Currently modules with any extensions enabled are not processed. This
300 // is left for future work.
301 //
302 // This pass is most effective if preceeded by Inlining and
303 // LocalAccessChainConvert. LocalSingleStoreElim and LocalSingleBlockElim
304 // will reduce the work that this pass has to do.
305 Optimizer::PassToken CreateLocalMultiStoreElimPass();
306
307 // Creates a local access chain conversion pass.
308 // A local access chain conversion pass identifies all function scope
309 // variables which are accessed only with loads, stores and access chains
310 // with constant indices. It then converts all loads and stores of such
311 // variables into equivalent sequences of loads, stores, extracts and inserts.
312 //
313 // This pass only processes entry point functions. It currently only converts
314 // non-nested, non-ptr access chains. It does not process modules with
315 // non-32-bit integer types present. Optional memory access options on loads
316 // and stores are ignored as we are only processing function scope variables.
317 //
318 // This pass unifies access to these variables to a single mode and simplifies
319 // subsequent analysis and elimination of these variables along with their
320 // loads and stores allowing values to propagate to their points of use where
321 // possible.
322 Optimizer::PassToken CreateLocalAccessChainConvertPass();
323
324 // Creates a local single store elimination pass.
325 // For each entry point function, this pass eliminates loads and stores for
326 // function scope variable that are stored to only once, where possible. Only
327 // whole variable loads and stores are eliminated; access-chain references are
328 // not optimized. Replace all loads of such variables with the value that is
329 // stored and eliminate any resulting dead code.
330 //
331 // Currently, the presence of access chains and function calls can inhibit this
332 // pass, however the Inlining and LocalAccessChainConvert passes can make it
333 // more effective. In additional, many non-load/store memory operations are
334 // not supported and will prohibit optimization of a function. Support of
335 // these operations are future work.
336 //
337 // This pass will reduce the work needed to be done by LocalSingleBlockElim
338 // and LocalMultiStoreElim and can improve the effectiveness of other passes
339 // such as DeadBranchElimination which depend on values for their analysis.
340 Optimizer::PassToken CreateLocalSingleStoreElimPass();
341
342 // Creates an insert/extract elimination pass.
343 // This pass processes each entry point function in the module, searching for
344 // extracts on a sequence of inserts. It further searches the sequence for an
345 // insert with indices identical to the extract. If such an insert can be
346 // found before hitting a conflicting insert, the extract's result id is
347 // replaced with the id of the values from the insert.
348 //
349 // Besides removing extracts this pass enables subsequent dead code elimination
350 // passes to delete the inserts. This pass performs best after access chains are
351 // converted to inserts and extracts and local loads and stores are eliminated.
352 Optimizer::PassToken CreateInsertExtractElimPass();
353
354 // Creates a pass to consolidate uniform references.
355 // For each entry point function in the module, first change all constant index
356 // access chain loads into equivalent composite extracts. Then consolidate
357 // identical uniform loads into one uniform load. Finally, consolidate
358 // identical uniform extracts into one uniform extract. This may require
359 // moving a load or extract to a point which dominates all uses.
360 //
361 // This pass requires a module to have structured control flow ie shader
362 // capability. It also requires logical addressing ie Addresses capability
363 // is not enabled. It also currently does not support any extensions.
364 //
365 // This pass currently only optimizes loads with a single index.
366 Optimizer::PassToken CreateCommonUniformElimPass();
367
368 // Create aggressive dead code elimination pass
369 // This pass eliminates unused code from functions. In addition,
370 // it detects and eliminates code which may have spurious uses but which do
371 // not contribute to the output of the function. The most common cause of
372 // such code sequences is summations in loops whose result is no longer used
373 // due to dead code elimination. This optimization has additional compile
374 // time cost over standard dead code elimination.
375 //
376 // This pass only processes entry point functions. It also only processes
377 // shaders with logical addressing. It currently will not process functions
378 // with function calls.
379 //
380 // This pass will be made more effective by first running passes that remove
381 // dead control flow and inlines function calls.
382 //
383 // This pass can be especially useful after running Local Access Chain
384 // Conversion, which tends to cause cycles of dead code to be left after
385 // Store/Load elimination passes are completed. These cycles cannot be
386 // eliminated with standard dead code elimination.
387 Optimizer::PassToken CreateAggressiveDCEPass();
388
389 // Creates a compact ids pass.
390 // The pass remaps result ids to a compact and gapless range starting from %1.
391 Optimizer::PassToken CreateCompactIdsPass();
392
393 // Creates a remove duplicate capabilities pass.
394 Optimizer::PassToken CreateRemoveDuplicatesPass();
395
396 // Creates a CFG cleanup pass.
397 // This pass removes cruft from the control flow graph of functions that are
398 // reachable from entry points and exported functions. It currently includes the
399 // following functionality:
400 //
401 // - Removal of unreachable basic blocks.
402 Optimizer::PassToken CreateCFGCleanupPass();
403
404 // Create dead variable elimination pass.
405 // This pass will delete module scope variables, along with their decorations,
406 // that are not referenced.
407 Optimizer::PassToken CreateDeadVariableEliminationPass();
408
409 }  // namespace spvtools
410
411 #endif  // SPIRV_TOOLS_OPTIMIZER_HPP_