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 INCLUDE_SPIRV_TOOLS_LIBSPIRV_HPP_ 16 #define INCLUDE_SPIRV_TOOLS_LIBSPIRV_HPP_ 17 18 #include <functional> 19 #include <memory> 20 #include <string> 21 #include <vector> 22 23 #include "spirv-tools/libspirv.h" 24 25 namespace spvtools { 26 27 // Message consumer. The C strings for source and message are only alive for the 28 // specific invocation. 29 using MessageConsumer = std::function<void( 30 spv_message_level_t /* level */, const char* /* source */, 31 const spv_position_t& /* position */, const char* /* message */ 32 )>; 33 34 // C++ RAII wrapper around the C context object spv_context. 35 class Context { 36 public: 37 // Constructs a context targeting the given environment |env|. 38 // 39 // The constructed instance will have an empty message consumer, which just 40 // ignores all messages from the library. Use SetMessageConsumer() to supply 41 // one if messages are of concern. 42 explicit Context(spv_target_env env); 43 44 // Enables move constructor/assignment operations. 45 Context(Context&& other); 46 Context& operator=(Context&& other); 47 48 // Disables copy constructor/assignment operations. 49 Context(const Context&) = delete; 50 Context& operator=(const Context&) = delete; 51 52 // Destructs this instance. 53 ~Context(); 54 55 // Sets the message consumer to the given |consumer|. The |consumer| will be 56 // invoked once for each message communicated from the library. 57 void SetMessageConsumer(MessageConsumer consumer); 58 59 // Returns the underlying spv_context. 60 spv_context& CContext(); 61 const spv_context& CContext() const; 62 63 private: 64 spv_context context_; 65 }; 66 67 // A RAII wrapper around a validator options object. 68 class ValidatorOptions { 69 public: ValidatorOptions()70 ValidatorOptions() : options_(spvValidatorOptionsCreate()) {} ~ValidatorOptions()71 ~ValidatorOptions() { spvValidatorOptionsDestroy(options_); } 72 // Allow implicit conversion to the underlying object. operator spv_validator_options() const73 operator spv_validator_options() const { return options_; } 74 75 // Sets a limit. SetUniversalLimit(spv_validator_limit limit_type,uint32_t limit)76 void SetUniversalLimit(spv_validator_limit limit_type, uint32_t limit) { 77 spvValidatorOptionsSetUniversalLimit(options_, limit_type, limit); 78 } 79 SetRelaxStructStore(bool val)80 void SetRelaxStructStore(bool val) { 81 spvValidatorOptionsSetRelaxStoreStruct(options_, val); 82 } 83 84 // Enables VK_KHR_relaxed_block_layout when validating standard 85 // uniform/storage buffer/push-constant layout. If true, disables 86 // scalar block layout rules. SetRelaxBlockLayout(bool val)87 void SetRelaxBlockLayout(bool val) { 88 spvValidatorOptionsSetRelaxBlockLayout(options_, val); 89 } 90 91 // Enables VK_EXT_scalar_block_layout when validating standard 92 // uniform/storage buffer/push-constant layout. If true, disables 93 // relaxed block layout rules. SetScalarBlockLayout(bool val)94 void SetScalarBlockLayout(bool val) { 95 spvValidatorOptionsSetScalarBlockLayout(options_, val); 96 } 97 98 // Skips validating standard uniform/storage buffer/push-constant layout. SetSkipBlockLayout(bool val)99 void SetSkipBlockLayout(bool val) { 100 spvValidatorOptionsSetSkipBlockLayout(options_, val); 101 } 102 103 // Records whether or not the validator should relax the rules on pointer 104 // usage in logical addressing mode. 105 // 106 // When relaxed, it will allow the following usage cases of pointers: 107 // 1) OpVariable allocating an object whose type is a pointer type 108 // 2) OpReturnValue returning a pointer value SetRelaxLogicalPointer(bool val)109 void SetRelaxLogicalPointer(bool val) { 110 spvValidatorOptionsSetRelaxLogicalPointer(options_, val); 111 } 112 113 private: 114 spv_validator_options options_; 115 }; 116 117 // A C++ wrapper around an optimization options object. 118 class OptimizerOptions { 119 public: OptimizerOptions()120 OptimizerOptions() : options_(spvOptimizerOptionsCreate()) {} ~OptimizerOptions()121 ~OptimizerOptions() { spvOptimizerOptionsDestroy(options_); } 122 123 // Allow implicit conversion to the underlying object. operator spv_optimizer_options() const124 operator spv_optimizer_options() const { return options_; } 125 126 // Records whether or not the optimizer should run the validator before 127 // optimizing. If |run| is true, the validator will be run. set_run_validator(bool run)128 void set_run_validator(bool run) { 129 spvOptimizerOptionsSetRunValidator(options_, run); 130 } 131 132 // Records the validator options that should be passed to the validator if it 133 // is run. set_validator_options(const ValidatorOptions & val_options)134 void set_validator_options(const ValidatorOptions& val_options) { 135 spvOptimizerOptionsSetValidatorOptions(options_, val_options); 136 } 137 138 // Records the maximum possible value for the id bound. set_max_id_bound(uint32_t new_bound)139 void set_max_id_bound(uint32_t new_bound) { 140 spvOptimizerOptionsSetMaxIdBound(options_, new_bound); 141 } 142 143 private: 144 spv_optimizer_options options_; 145 }; 146 147 // A C++ wrapper around a reducer options object. 148 class ReducerOptions { 149 public: ReducerOptions()150 ReducerOptions() : options_(spvReducerOptionsCreate()) {} ~ReducerOptions()151 ~ReducerOptions() { spvReducerOptionsDestroy(options_); } 152 153 // Allow implicit conversion to the underlying object. operator spv_reducer_options() const154 operator spv_reducer_options() const { return options_; } 155 156 // Records the maximum number of reduction steps that should 157 // run before the reducer gives up. set_step_limit(uint32_t step_limit)158 void set_step_limit(uint32_t step_limit) { 159 spvReducerOptionsSetStepLimit(options_, step_limit); 160 } 161 162 // Sets a seed to be used for random number generation. set_seed(uint32_t seed)163 void set_seed(uint32_t seed) { spvReducerOptionsSetSeed(options_, seed); } 164 165 private: 166 spv_reducer_options options_; 167 }; 168 169 // C++ interface for SPIRV-Tools functionalities. It wraps the context 170 // (including target environment and the corresponding SPIR-V grammar) and 171 // provides methods for assembling, disassembling, and validating. 172 // 173 // Instances of this class provide basic thread-safety guarantee. 174 class SpirvTools { 175 public: 176 enum { 177 // Default assembling option used by assemble(): 178 kDefaultAssembleOption = SPV_TEXT_TO_BINARY_OPTION_NONE, 179 180 // Default disassembling option used by Disassemble(): 181 // * Avoid prefix comments from decoding the SPIR-V module header, and 182 // * Use friendly names for variables. 183 kDefaultDisassembleOption = SPV_BINARY_TO_TEXT_OPTION_NO_HEADER | 184 SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES 185 }; 186 187 // Constructs an instance targeting the given environment |env|. 188 // 189 // The constructed instance will have an empty message consumer, which just 190 // ignores all messages from the library. Use SetMessageConsumer() to supply 191 // one if messages are of concern. 192 explicit SpirvTools(spv_target_env env); 193 194 // Disables copy/move constructor/assignment operations. 195 SpirvTools(const SpirvTools&) = delete; 196 SpirvTools(SpirvTools&&) = delete; 197 SpirvTools& operator=(const SpirvTools&) = delete; 198 SpirvTools& operator=(SpirvTools&&) = delete; 199 200 // Destructs this instance. 201 ~SpirvTools(); 202 203 // Sets the message consumer to the given |consumer|. The |consumer| will be 204 // invoked once for each message communicated from the library. 205 void SetMessageConsumer(MessageConsumer consumer); 206 207 // Assembles the given assembly |text| and writes the result to |binary|. 208 // Returns true on successful assembling. |binary| will be kept untouched if 209 // assembling is unsuccessful. 210 bool Assemble(const std::string& text, std::vector<uint32_t>* binary, 211 uint32_t options = kDefaultAssembleOption) const; 212 // |text_size| specifies the number of bytes in |text|. A terminating null 213 // character is not required to present in |text| as long as |text| is valid. 214 bool Assemble(const char* text, size_t text_size, 215 std::vector<uint32_t>* binary, 216 uint32_t options = kDefaultAssembleOption) const; 217 218 // Disassembles the given SPIR-V |binary| with the given |options| and writes 219 // the assembly to |text|. Returns ture on successful disassembling. |text| 220 // will be kept untouched if diassembling is unsuccessful. 221 bool Disassemble(const std::vector<uint32_t>& binary, std::string* text, 222 uint32_t options = kDefaultDisassembleOption) const; 223 // |binary_size| specifies the number of words in |binary|. 224 bool Disassemble(const uint32_t* binary, size_t binary_size, 225 std::string* text, 226 uint32_t options = kDefaultDisassembleOption) const; 227 228 // Validates the given SPIR-V |binary|. Returns true if no issues are found. 229 // Otherwise, returns false and communicates issues via the message consumer 230 // registered. 231 bool Validate(const std::vector<uint32_t>& binary) const; 232 // |binary_size| specifies the number of words in |binary|. 233 bool Validate(const uint32_t* binary, size_t binary_size) const; 234 // Like the previous overload, but takes an options object. 235 bool Validate(const uint32_t* binary, size_t binary_size, 236 spv_validator_options options) const; 237 238 private: 239 struct Impl; // Opaque struct for holding the data fields used by this class. 240 std::unique_ptr<Impl> impl_; // Unique pointer to implementation data. 241 }; 242 243 } // namespace spvtools 244 245 #endif // INCLUDE_SPIRV_TOOLS_LIBSPIRV_HPP_ 246