• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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   // See specific API calls for how the target environment is interpeted
40   // (particularly assembly and validation).
41   //
42   // The constructed instance will have an empty message consumer, which just
43   // ignores all messages from the library. Use SetMessageConsumer() to supply
44   // one if messages are of concern.
45   explicit Context(spv_target_env env);
46 
47   // Enables move constructor/assignment operations.
48   Context(Context&& other);
49   Context& operator=(Context&& other);
50 
51   // Disables copy constructor/assignment operations.
52   Context(const Context&) = delete;
53   Context& operator=(const Context&) = delete;
54 
55   // Destructs this instance.
56   ~Context();
57 
58   // Sets the message consumer to the given |consumer|. The |consumer| will be
59   // invoked once for each message communicated from the library.
60   void SetMessageConsumer(MessageConsumer consumer);
61 
62   // Returns the underlying spv_context.
63   spv_context& CContext();
64   const spv_context& CContext() const;
65 
66  private:
67   spv_context context_;
68 };
69 
70 // A RAII wrapper around a validator options object.
71 class ValidatorOptions {
72  public:
ValidatorOptions()73   ValidatorOptions() : options_(spvValidatorOptionsCreate()) {}
~ValidatorOptions()74   ~ValidatorOptions() { spvValidatorOptionsDestroy(options_); }
75   // Allow implicit conversion to the underlying object.
operator spv_validator_options() const76   operator spv_validator_options() const { return options_; }
77 
78   // Sets a limit.
SetUniversalLimit(spv_validator_limit limit_type,uint32_t limit)79   void SetUniversalLimit(spv_validator_limit limit_type, uint32_t limit) {
80     spvValidatorOptionsSetUniversalLimit(options_, limit_type, limit);
81   }
82 
SetRelaxStructStore(bool val)83   void SetRelaxStructStore(bool val) {
84     spvValidatorOptionsSetRelaxStoreStruct(options_, val);
85   }
86 
87   // Enables VK_KHR_relaxed_block_layout when validating standard
88   // uniform/storage buffer/push-constant layout.  If true, disables
89   // scalar block layout rules.
SetRelaxBlockLayout(bool val)90   void SetRelaxBlockLayout(bool val) {
91     spvValidatorOptionsSetRelaxBlockLayout(options_, val);
92   }
93 
94   // Enables VK_KHR_uniform_buffer_standard_layout when validating standard
95   // uniform layout.  If true, disables scalar block layout rules.
SetUniformBufferStandardLayout(bool val)96   void SetUniformBufferStandardLayout(bool val) {
97     spvValidatorOptionsSetUniformBufferStandardLayout(options_, val);
98   }
99 
100   // Enables VK_EXT_scalar_block_layout when validating standard
101   // uniform/storage buffer/push-constant layout.  If true, disables
102   // relaxed block layout rules.
SetScalarBlockLayout(bool val)103   void SetScalarBlockLayout(bool val) {
104     spvValidatorOptionsSetScalarBlockLayout(options_, val);
105   }
106 
107   // Enables scalar layout when validating Workgroup blocks.  See
108   // VK_KHR_workgroup_memory_explicit_layout.
SetWorkgroupScalarBlockLayout(bool val)109   void SetWorkgroupScalarBlockLayout(bool val) {
110     spvValidatorOptionsSetWorkgroupScalarBlockLayout(options_, val);
111   }
112 
113   // Skips validating standard uniform/storage buffer/push-constant layout.
SetSkipBlockLayout(bool val)114   void SetSkipBlockLayout(bool val) {
115     spvValidatorOptionsSetSkipBlockLayout(options_, val);
116   }
117 
118   // Records whether or not the validator should relax the rules on pointer
119   // usage in logical addressing mode.
120   //
121   // When relaxed, it will allow the following usage cases of pointers:
122   // 1) OpVariable allocating an object whose type is a pointer type
123   // 2) OpReturnValue returning a pointer value
SetRelaxLogicalPointer(bool val)124   void SetRelaxLogicalPointer(bool val) {
125     spvValidatorOptionsSetRelaxLogicalPointer(options_, val);
126   }
127 
128   // Records whether or not the validator should relax the rules because it is
129   // expected that the optimizations will make the code legal.
130   //
131   // When relaxed, it will allow the following:
132   // 1) It will allow relaxed logical pointers.  Setting this option will also
133   //    set that option.
134   // 2) Pointers that are pass as parameters to function calls do not have to
135   //    match the storage class of the formal parameter.
136   // 3) Pointers that are actaul parameters on function calls do not have to
137   //    point to the same type pointed as the formal parameter.  The types just
138   //    need to logically match.
139   // 4) GLSLstd450 Interpolate* instructions can have a load of an interpolant
140   //    for a first argument.
SetBeforeHlslLegalization(bool val)141   void SetBeforeHlslLegalization(bool val) {
142     spvValidatorOptionsSetBeforeHlslLegalization(options_, val);
143   }
144 
145  private:
146   spv_validator_options options_;
147 };
148 
149 // A C++ wrapper around an optimization options object.
150 class OptimizerOptions {
151  public:
OptimizerOptions()152   OptimizerOptions() : options_(spvOptimizerOptionsCreate()) {}
~OptimizerOptions()153   ~OptimizerOptions() { spvOptimizerOptionsDestroy(options_); }
154 
155   // Allow implicit conversion to the underlying object.
operator spv_optimizer_options() const156   operator spv_optimizer_options() const { return options_; }
157 
158   // Records whether or not the optimizer should run the validator before
159   // optimizing.  If |run| is true, the validator will be run.
set_run_validator(bool run)160   void set_run_validator(bool run) {
161     spvOptimizerOptionsSetRunValidator(options_, run);
162   }
163 
164   // Records the validator options that should be passed to the validator if it
165   // is run.
set_validator_options(const ValidatorOptions & val_options)166   void set_validator_options(const ValidatorOptions& val_options) {
167     spvOptimizerOptionsSetValidatorOptions(options_, val_options);
168   }
169 
170   // Records the maximum possible value for the id bound.
set_max_id_bound(uint32_t new_bound)171   void set_max_id_bound(uint32_t new_bound) {
172     spvOptimizerOptionsSetMaxIdBound(options_, new_bound);
173   }
174 
175   // Records whether all bindings within the module should be preserved.
set_preserve_bindings(bool preserve_bindings)176   void set_preserve_bindings(bool preserve_bindings) {
177     spvOptimizerOptionsSetPreserveBindings(options_, preserve_bindings);
178   }
179 
180   // Records whether all specialization constants within the module
181   // should be preserved.
set_preserve_spec_constants(bool preserve_spec_constants)182   void set_preserve_spec_constants(bool preserve_spec_constants) {
183     spvOptimizerOptionsSetPreserveSpecConstants(options_,
184                                                 preserve_spec_constants);
185   }
186 
187  private:
188   spv_optimizer_options options_;
189 };
190 
191 // A C++ wrapper around a reducer options object.
192 class ReducerOptions {
193  public:
ReducerOptions()194   ReducerOptions() : options_(spvReducerOptionsCreate()) {}
~ReducerOptions()195   ~ReducerOptions() { spvReducerOptionsDestroy(options_); }
196 
197   // Allow implicit conversion to the underlying object.
operator spv_reducer_options() const198   operator spv_reducer_options() const {  // NOLINT(google-explicit-constructor)
199     return options_;
200   }
201 
202   // See spvReducerOptionsSetStepLimit.
set_step_limit(uint32_t step_limit)203   void set_step_limit(uint32_t step_limit) {
204     spvReducerOptionsSetStepLimit(options_, step_limit);
205   }
206 
207   // See spvReducerOptionsSetFailOnValidationError.
set_fail_on_validation_error(bool fail_on_validation_error)208   void set_fail_on_validation_error(bool fail_on_validation_error) {
209     spvReducerOptionsSetFailOnValidationError(options_,
210                                               fail_on_validation_error);
211   }
212 
213   // See spvReducerOptionsSetTargetFunction.
set_target_function(uint32_t target_function)214   void set_target_function(uint32_t target_function) {
215     spvReducerOptionsSetTargetFunction(options_, target_function);
216   }
217 
218  private:
219   spv_reducer_options options_;
220 };
221 
222 // A C++ wrapper around a fuzzer options object.
223 class FuzzerOptions {
224  public:
FuzzerOptions()225   FuzzerOptions() : options_(spvFuzzerOptionsCreate()) {}
~FuzzerOptions()226   ~FuzzerOptions() { spvFuzzerOptionsDestroy(options_); }
227 
228   // Allow implicit conversion to the underlying object.
operator spv_fuzzer_options() const229   operator spv_fuzzer_options() const {  // NOLINT(google-explicit-constructor)
230     return options_;
231   }
232 
233   // See spvFuzzerOptionsEnableReplayValidation.
enable_replay_validation()234   void enable_replay_validation() {
235     spvFuzzerOptionsEnableReplayValidation(options_);
236   }
237 
238   // See spvFuzzerOptionsSetRandomSeed.
set_random_seed(uint32_t seed)239   void set_random_seed(uint32_t seed) {
240     spvFuzzerOptionsSetRandomSeed(options_, seed);
241   }
242 
243   // See spvFuzzerOptionsSetReplayRange.
set_replay_range(int32_t replay_range)244   void set_replay_range(int32_t replay_range) {
245     spvFuzzerOptionsSetReplayRange(options_, replay_range);
246   }
247 
248   // See spvFuzzerOptionsSetShrinkerStepLimit.
set_shrinker_step_limit(uint32_t shrinker_step_limit)249   void set_shrinker_step_limit(uint32_t shrinker_step_limit) {
250     spvFuzzerOptionsSetShrinkerStepLimit(options_, shrinker_step_limit);
251   }
252 
253   // See spvFuzzerOptionsEnableFuzzerPassValidation.
enable_fuzzer_pass_validation()254   void enable_fuzzer_pass_validation() {
255     spvFuzzerOptionsEnableFuzzerPassValidation(options_);
256   }
257 
258   // See spvFuzzerOptionsEnableAllPasses.
enable_all_passes()259   void enable_all_passes() { spvFuzzerOptionsEnableAllPasses(options_); }
260 
261  private:
262   spv_fuzzer_options options_;
263 };
264 
265 // C++ interface for SPIRV-Tools functionalities. It wraps the context
266 // (including target environment and the corresponding SPIR-V grammar) and
267 // provides methods for assembling, disassembling, and validating.
268 //
269 // Instances of this class provide basic thread-safety guarantee.
270 class SpirvTools {
271  public:
272   enum {
273     // Default assembling option used by assemble():
274     kDefaultAssembleOption = SPV_TEXT_TO_BINARY_OPTION_NONE,
275 
276     // Default disassembling option used by Disassemble():
277     // * Avoid prefix comments from decoding the SPIR-V module header, and
278     // * Use friendly names for variables.
279     kDefaultDisassembleOption = SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
280                                 SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES
281   };
282 
283   // Constructs an instance targeting the given environment |env|.
284   //
285   // The constructed instance will have an empty message consumer, which just
286   // ignores all messages from the library. Use SetMessageConsumer() to supply
287   // one if messages are of concern.
288   explicit SpirvTools(spv_target_env env);
289 
290   // Disables copy/move constructor/assignment operations.
291   SpirvTools(const SpirvTools&) = delete;
292   SpirvTools(SpirvTools&&) = delete;
293   SpirvTools& operator=(const SpirvTools&) = delete;
294   SpirvTools& operator=(SpirvTools&&) = delete;
295 
296   // Destructs this instance.
297   ~SpirvTools();
298 
299   // Sets the message consumer to the given |consumer|. The |consumer| will be
300   // invoked once for each message communicated from the library.
301   void SetMessageConsumer(MessageConsumer consumer);
302 
303   // Assembles the given assembly |text| and writes the result to |binary|.
304   // Returns true on successful assembling. |binary| will be kept untouched if
305   // assembling is unsuccessful.
306   // The SPIR-V binary version is set to the highest version of SPIR-V supported
307   // by the target environment with which this SpirvTools object was created.
308   bool Assemble(const std::string& text, std::vector<uint32_t>* binary,
309                 uint32_t options = kDefaultAssembleOption) const;
310   // |text_size| specifies the number of bytes in |text|. A terminating null
311   // character is not required to present in |text| as long as |text| is valid.
312   // The SPIR-V binary version is set to the highest version of SPIR-V supported
313   // by the target environment with which this SpirvTools object was created.
314   bool Assemble(const char* text, size_t text_size,
315                 std::vector<uint32_t>* binary,
316                 uint32_t options = kDefaultAssembleOption) const;
317 
318   // Disassembles the given SPIR-V |binary| with the given |options| and writes
319   // the assembly to |text|. Returns true on successful disassembling. |text|
320   // will be kept untouched if diassembling is unsuccessful.
321   bool Disassemble(const std::vector<uint32_t>& binary, std::string* text,
322                    uint32_t options = kDefaultDisassembleOption) const;
323   // |binary_size| specifies the number of words in |binary|.
324   bool Disassemble(const uint32_t* binary, size_t binary_size,
325                    std::string* text,
326                    uint32_t options = kDefaultDisassembleOption) const;
327 
328   // Validates the given SPIR-V |binary|. Returns true if no issues are found.
329   // Otherwise, returns false and communicates issues via the message consumer
330   // registered.
331   // Validates for SPIR-V spec rules for the SPIR-V version named in the
332   // binary's header (at word offset 1).  Additionally, if the target
333   // environment is a client API (such as Vulkan 1.1), then validate for that
334   // client API version, to the extent that it is verifiable from data in the
335   // binary itself.
336   bool Validate(const std::vector<uint32_t>& binary) const;
337   // Like the previous overload, but provides the binary as a pointer and size:
338   // |binary_size| specifies the number of words in |binary|.
339   // Validates for SPIR-V spec rules for the SPIR-V version named in the
340   // binary's header (at word offset 1).  Additionally, if the target
341   // environment is a client API (such as Vulkan 1.1), then validate for that
342   // client API version, to the extent that it is verifiable from data in the
343   // binary itself.
344   bool Validate(const uint32_t* binary, size_t binary_size) const;
345   // Like the previous overload, but takes an options object.
346   // Validates for SPIR-V spec rules for the SPIR-V version named in the
347   // binary's header (at word offset 1).  Additionally, if the target
348   // environment is a client API (such as Vulkan 1.1), then validate for that
349   // client API version, to the extent that it is verifiable from data in the
350   // binary itself, or in the validator options.
351   bool Validate(const uint32_t* binary, size_t binary_size,
352                 spv_validator_options options) const;
353 
354   // Was this object successfully constructed.
355   bool IsValid() const;
356 
357  private:
358   struct Impl;  // Opaque struct for holding the data fields used by this class.
359   std::unique_ptr<Impl> impl_;  // Unique pointer to implementation data.
360 };
361 
362 }  // namespace spvtools
363 
364 #endif  // INCLUDE_SPIRV_TOOLS_LIBSPIRV_HPP_
365