Lei Zhang | f18e1f2 | 2016-09-12 14:11:46 -0400 | [diff] [blame] | 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" |
Lei Zhang | f18e1f2 | 2016-09-12 14:11:46 -0400 | [diff] [blame] | 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 | // Optimizes the given SPIR-V module |original_binary| and writes the |
| 81 | // optimized binary into |optimized_binary|. |
| 82 | // Returns true on successful optimization, whether or not the module is |
| 83 | // modified. Returns false if errors occur when processing |original_binary| |
| 84 | // using any of the registered passes. In that case, no further passes are |
| 85 | // excuted and the contents in |optimized_binary| may be invalid. |
| 86 | // |
| 87 | // It's allowed to alias |original_binary| to the start of |optimized_binary|. |
| 88 | bool Run(const uint32_t* original_binary, size_t original_binary_size, |
| 89 | std::vector<uint32_t>* optimized_binary) const; |
| 90 | |
| 91 | private: |
| 92 | struct Impl; // Opaque struct for holding internal data. |
| 93 | std::unique_ptr<Impl> impl_; // Unique pointer to internal data. |
| 94 | }; |
| 95 | |
| 96 | // Creates a null pass. |
| 97 | // A null pass does nothing to the SPIR-V module to be optimized. |
| 98 | Optimizer::PassToken CreateNullPass(); |
| 99 | |
| 100 | // Creates a strip-debug-info pass. |
| 101 | // A strip-debug-info pass removes all debug instructions (as documented in |
| 102 | // Section 3.32.2 of the SPIR-V spec) of the SPIR-V module to be optimized. |
| 103 | Optimizer::PassToken CreateStripDebugInfoPass(); |
| 104 | |
qining | 144f59e | 2017-04-19 18:10:59 -0400 | [diff] [blame^] | 105 | // Creates a set-spec-constant-default-value pass from a mapping from spec-ids |
| 106 | // to the default values in the form of string. |
Lei Zhang | f18e1f2 | 2016-09-12 14:11:46 -0400 | [diff] [blame] | 107 | // A set-spec-constant-default-value pass sets the default values for the |
| 108 | // spec constants that have SpecId decorations (i.e., those defined by |
| 109 | // OpSpecConstant{|True|False} instructions). |
| 110 | Optimizer::PassToken CreateSetSpecConstantDefaultValuePass( |
| 111 | const std::unordered_map<uint32_t, std::string>& id_value_map); |
| 112 | |
qining | 144f59e | 2017-04-19 18:10:59 -0400 | [diff] [blame^] | 113 | // Creates a set-spec-constant-default-value pass from a mapping from spec-ids |
| 114 | // to the default values in the form of bit pattern. |
| 115 | // A set-spec-constant-default-value pass sets the default values for the |
| 116 | // spec constants that have SpecId decorations (i.e., those defined by |
| 117 | // OpSpecConstant{|True|False} instructions). |
| 118 | Optimizer::PassToken CreateSetSpecConstantDefaultValuePass( |
| 119 | const std::unordered_map<uint32_t, std::vector<uint32_t>>& id_value_map); |
| 120 | |
David Neto | 11a867f | 2017-04-01 16:10:16 -0400 | [diff] [blame] | 121 | // Creates a flatten-decoration pass. |
| 122 | // A flatten-decoration pass replaces grouped decorations with equivalent |
| 123 | // ungrouped decorations. That is, it replaces each OpDecorationGroup |
| 124 | // instruction and associated OpGroupDecorate and OpGroupMemberDecorate |
| 125 | // instructions with equivalent OpDecorate and OpMemberDecorate instructions. |
| 126 | // The pass does not attempt to preserve debug information for instructions |
| 127 | // it removes. |
| 128 | Optimizer::PassToken CreateFlattenDecorationPass(); |
| 129 | |
Lei Zhang | f18e1f2 | 2016-09-12 14:11:46 -0400 | [diff] [blame] | 130 | // Creates a freeze-spec-constant-value pass. |
| 131 | // A freeze-spec-constant pass specializes the value of spec constants to |
| 132 | // their default values. This pass only processes the spec constants that have |
| 133 | // SpecId decorations (defined by OpSpecConstant, OpSpecConstantTrue, or |
| 134 | // OpSpecConstantFalse instructions) and replaces them with their normal |
| 135 | // counterparts (OpConstant, OpConstantTrue, or OpConstantFalse). The |
| 136 | // corresponding SpecId annotation instructions will also be removed. This |
| 137 | // pass does not fold the newly added normal constants and does not process |
| 138 | // other spec constants defined by OpSpecConstantComposite or |
| 139 | // OpSpecConstantOp. |
| 140 | Optimizer::PassToken CreateFreezeSpecConstantValuePass(); |
| 141 | |
| 142 | // Creates a fold-spec-constant-op-and-composite pass. |
| 143 | // A fold-spec-constant-op-and-composite pass folds spec constants defined by |
| 144 | // OpSpecConstantOp or OpSpecConstantComposite instruction, to normal Constants |
| 145 | // defined by OpConstantTrue, OpConstantFalse, OpConstant, OpConstantNull, or |
| 146 | // OpConstantComposite instructions. Note that spec constants defined with |
| 147 | // OpSpecConstant, OpSpecConstantTrue, or OpSpecConstantFalse instructions are |
| 148 | // not handled, as these instructions indicate their value are not determined |
| 149 | // and can be changed in future. A spec constant is foldable if all of its |
| 150 | // value(s) can be determined from the module. E.g., an integer spec constant |
| 151 | // defined with OpSpecConstantOp instruction can be folded if its value won't |
| 152 | // change later. This pass will replace the original OpSpecContantOp instruction |
| 153 | // with an OpConstant instruction. When folding composite spec constants, |
| 154 | // new instructions may be inserted to define the components of the composite |
| 155 | // constant first, then the original spec constants will be replaced by |
| 156 | // OpConstantComposite instructions. |
| 157 | // |
| 158 | // There are some operations not supported yet: |
| 159 | // OpSConvert, OpFConvert, OpQuantizeToF16 and |
| 160 | // all the operations under Kernel capability. |
| 161 | // TODO(qining): Add support for the operations listed above. |
| 162 | Optimizer::PassToken CreateFoldSpecConstantOpAndCompositePass(); |
| 163 | |
| 164 | // Creates a unify-constant pass. |
| 165 | // A unify-constant pass de-duplicates the constants. Constants with the exact |
| 166 | // same value and identical form will be unified and only one constant will |
| 167 | // be kept for each unique pair of type and value. |
| 168 | // There are several cases not handled by this pass: |
| 169 | // 1) Constants defined by OpConstantNull instructions (null constants) and |
| 170 | // constants defined by OpConstantFalse, OpConstant or OpConstantComposite |
| 171 | // with value 0 (zero-valued normal constants) are not considered equivalent. |
| 172 | // So null constants won't be used to replace zero-valued normal constants, |
| 173 | // vice versa. |
| 174 | // 2) Whenever there are decorations to the constant's result id id, the |
| 175 | // constant won't be handled, which means, it won't be used to replace any |
| 176 | // other constants, neither can other constants replace it. |
| 177 | // 3) NaN in float point format with different bit patterns are not unified. |
| 178 | Optimizer::PassToken CreateUnifyConstantPass(); |
| 179 | |
| 180 | // Creates a eliminate-dead-constant pass. |
| 181 | // A eliminate-dead-constant pass removes dead constants, including normal |
| 182 | // contants defined by OpConstant, OpConstantComposite, OpConstantTrue, or |
| 183 | // OpConstantFalse and spec constants defined by OpSpecConstant, |
| 184 | // OpSpecConstantComposite, OpSpecConstantTrue, OpSpecConstantFalse or |
| 185 | // OpSpecConstantOp. |
| 186 | Optimizer::PassToken CreateEliminateDeadConstantPass(); |
| 187 | |
Greg Fischer | 04fcc66 | 2016-11-10 10:11:50 -0700 | [diff] [blame] | 188 | // Creates an inline pass. |
| 189 | // An inline pass exhaustively inlines all function calls in all functions |
| 190 | // designated as an entry point. The intent is to enable, albeit through |
| 191 | // brute force, analysis and optimization across function calls by subsequent |
| 192 | // passes. As the inlining is exhaustive, there is no attempt to optimize for |
| 193 | // size or runtime performance. Functions that are not designated as entry |
| 194 | // points are not changed. |
| 195 | Optimizer::PassToken CreateInlinePass(); |
| 196 | |
Andrey Tuganov | 1e309af | 2017-04-11 15:11:04 -0400 | [diff] [blame] | 197 | // Creates a compact ids pass. |
| 198 | // The pass remaps result ids to a compact and gapless range starting from %1. |
| 199 | Optimizer::PassToken CreateCompactIdsPass(); |
| 200 | |
Lei Zhang | f18e1f2 | 2016-09-12 14:11:46 -0400 | [diff] [blame] | 201 | } // namespace spvtools |
| 202 | |
| 203 | #endif // SPIRV_TOOLS_OPTIMIZER_HPP_ |