• 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 interpreted
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   // Enables LocalSizeId decorations where the environment would not otherwise
119   // allow them.
SetAllowLocalSizeId(bool val)120   void SetAllowLocalSizeId(bool val) {
121     spvValidatorOptionsSetAllowLocalSizeId(options_, val);
122   }
123 
124   // Records whether or not the validator should relax the rules on pointer
125   // usage in logical addressing mode.
126   //
127   // When relaxed, it will allow the following usage cases of pointers:
128   // 1) OpVariable allocating an object whose type is a pointer type
129   // 2) OpReturnValue returning a pointer value
SetRelaxLogicalPointer(bool val)130   void SetRelaxLogicalPointer(bool val) {
131     spvValidatorOptionsSetRelaxLogicalPointer(options_, val);
132   }
133 
134   // Records whether or not the validator should relax the rules because it is
135   // expected that the optimizations will make the code legal.
136   //
137   // When relaxed, it will allow the following:
138   // 1) It will allow relaxed logical pointers.  Setting this option will also
139   //    set that option.
140   // 2) Pointers that are pass as parameters to function calls do not have to
141   //    match the storage class of the formal parameter.
142   // 3) Pointers that are actual parameters on function calls do not have to
143   //    point to the same type pointed as the formal parameter.  The types just
144   //    need to logically match.
145   // 4) GLSLstd450 Interpolate* instructions can have a load of an interpolant
146   //    for a first argument.
SetBeforeHlslLegalization(bool val)147   void SetBeforeHlslLegalization(bool val) {
148     spvValidatorOptionsSetBeforeHlslLegalization(options_, val);
149   }
150 
151  private:
152   spv_validator_options options_;
153 };
154 
155 // A C++ wrapper around an optimization options object.
156 class OptimizerOptions {
157  public:
OptimizerOptions()158   OptimizerOptions() : options_(spvOptimizerOptionsCreate()) {}
~OptimizerOptions()159   ~OptimizerOptions() { spvOptimizerOptionsDestroy(options_); }
160 
161   // Allow implicit conversion to the underlying object.
operator spv_optimizer_options() const162   operator spv_optimizer_options() const { return options_; }
163 
164   // Records whether or not the optimizer should run the validator before
165   // optimizing.  If |run| is true, the validator will be run.
set_run_validator(bool run)166   void set_run_validator(bool run) {
167     spvOptimizerOptionsSetRunValidator(options_, run);
168   }
169 
170   // Records the validator options that should be passed to the validator if it
171   // is run.
set_validator_options(const ValidatorOptions & val_options)172   void set_validator_options(const ValidatorOptions& val_options) {
173     spvOptimizerOptionsSetValidatorOptions(options_, val_options);
174   }
175 
176   // Records the maximum possible value for the id bound.
set_max_id_bound(uint32_t new_bound)177   void set_max_id_bound(uint32_t new_bound) {
178     spvOptimizerOptionsSetMaxIdBound(options_, new_bound);
179   }
180 
181   // Records whether all bindings within the module should be preserved.
set_preserve_bindings(bool preserve_bindings)182   void set_preserve_bindings(bool preserve_bindings) {
183     spvOptimizerOptionsSetPreserveBindings(options_, preserve_bindings);
184   }
185 
186   // Records whether all specialization constants within the module
187   // should be preserved.
set_preserve_spec_constants(bool preserve_spec_constants)188   void set_preserve_spec_constants(bool preserve_spec_constants) {
189     spvOptimizerOptionsSetPreserveSpecConstants(options_,
190                                                 preserve_spec_constants);
191   }
192 
193  private:
194   spv_optimizer_options options_;
195 };
196 
197 // A C++ wrapper around a reducer options object.
198 class ReducerOptions {
199  public:
ReducerOptions()200   ReducerOptions() : options_(spvReducerOptionsCreate()) {}
~ReducerOptions()201   ~ReducerOptions() { spvReducerOptionsDestroy(options_); }
202 
203   // Allow implicit conversion to the underlying object.
operator spv_reducer_options() const204   operator spv_reducer_options() const {  // NOLINT(google-explicit-constructor)
205     return options_;
206   }
207 
208   // See spvReducerOptionsSetStepLimit.
set_step_limit(uint32_t step_limit)209   void set_step_limit(uint32_t step_limit) {
210     spvReducerOptionsSetStepLimit(options_, step_limit);
211   }
212 
213   // See spvReducerOptionsSetFailOnValidationError.
set_fail_on_validation_error(bool fail_on_validation_error)214   void set_fail_on_validation_error(bool fail_on_validation_error) {
215     spvReducerOptionsSetFailOnValidationError(options_,
216                                               fail_on_validation_error);
217   }
218 
219   // See spvReducerOptionsSetTargetFunction.
set_target_function(uint32_t target_function)220   void set_target_function(uint32_t target_function) {
221     spvReducerOptionsSetTargetFunction(options_, target_function);
222   }
223 
224  private:
225   spv_reducer_options options_;
226 };
227 
228 // A C++ wrapper around a fuzzer options object.
229 class FuzzerOptions {
230  public:
FuzzerOptions()231   FuzzerOptions() : options_(spvFuzzerOptionsCreate()) {}
~FuzzerOptions()232   ~FuzzerOptions() { spvFuzzerOptionsDestroy(options_); }
233 
234   // Allow implicit conversion to the underlying object.
operator spv_fuzzer_options() const235   operator spv_fuzzer_options() const {  // NOLINT(google-explicit-constructor)
236     return options_;
237   }
238 
239   // See spvFuzzerOptionsEnableReplayValidation.
enable_replay_validation()240   void enable_replay_validation() {
241     spvFuzzerOptionsEnableReplayValidation(options_);
242   }
243 
244   // See spvFuzzerOptionsSetRandomSeed.
set_random_seed(uint32_t seed)245   void set_random_seed(uint32_t seed) {
246     spvFuzzerOptionsSetRandomSeed(options_, seed);
247   }
248 
249   // See spvFuzzerOptionsSetReplayRange.
set_replay_range(int32_t replay_range)250   void set_replay_range(int32_t replay_range) {
251     spvFuzzerOptionsSetReplayRange(options_, replay_range);
252   }
253 
254   // See spvFuzzerOptionsSetShrinkerStepLimit.
set_shrinker_step_limit(uint32_t shrinker_step_limit)255   void set_shrinker_step_limit(uint32_t shrinker_step_limit) {
256     spvFuzzerOptionsSetShrinkerStepLimit(options_, shrinker_step_limit);
257   }
258 
259   // See spvFuzzerOptionsEnableFuzzerPassValidation.
enable_fuzzer_pass_validation()260   void enable_fuzzer_pass_validation() {
261     spvFuzzerOptionsEnableFuzzerPassValidation(options_);
262   }
263 
264   // See spvFuzzerOptionsEnableAllPasses.
enable_all_passes()265   void enable_all_passes() { spvFuzzerOptionsEnableAllPasses(options_); }
266 
267  private:
268   spv_fuzzer_options options_;
269 };
270 
271 // C++ interface for SPIRV-Tools functionalities. It wraps the context
272 // (including target environment and the corresponding SPIR-V grammar) and
273 // provides methods for assembling, disassembling, and validating.
274 //
275 // Instances of this class provide basic thread-safety guarantee.
276 class SpirvTools {
277  public:
278   enum {
279     // Default assembling option used by assemble():
280     kDefaultAssembleOption = SPV_TEXT_TO_BINARY_OPTION_NONE,
281 
282     // Default disassembling option used by Disassemble():
283     // * Avoid prefix comments from decoding the SPIR-V module header, and
284     // * Use friendly names for variables.
285     kDefaultDisassembleOption = SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
286                                 SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES
287   };
288 
289   // Constructs an instance targeting the given environment |env|.
290   //
291   // The constructed instance will have an empty message consumer, which just
292   // ignores all messages from the library. Use SetMessageConsumer() to supply
293   // one if messages are of concern.
294   explicit SpirvTools(spv_target_env env);
295 
296   // Disables copy/move constructor/assignment operations.
297   SpirvTools(const SpirvTools&) = delete;
298   SpirvTools(SpirvTools&&) = delete;
299   SpirvTools& operator=(const SpirvTools&) = delete;
300   SpirvTools& operator=(SpirvTools&&) = delete;
301 
302   // Destructs this instance.
303   ~SpirvTools();
304 
305   // Sets the message consumer to the given |consumer|. The |consumer| will be
306   // invoked once for each message communicated from the library.
307   void SetMessageConsumer(MessageConsumer consumer);
308 
309   // Assembles the given assembly |text| and writes the result to |binary|.
310   // Returns true on successful assembling. |binary| will be kept untouched if
311   // assembling is unsuccessful.
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 std::string& text, std::vector<uint32_t>* binary,
315                 uint32_t options = kDefaultAssembleOption) const;
316   // |text_size| specifies the number of bytes in |text|. A terminating null
317   // character is not required to present in |text| as long as |text| is valid.
318   // The SPIR-V binary version is set to the highest version of SPIR-V supported
319   // by the target environment with which this SpirvTools object was created.
320   bool Assemble(const char* text, size_t text_size,
321                 std::vector<uint32_t>* binary,
322                 uint32_t options = kDefaultAssembleOption) const;
323 
324   // Disassembles the given SPIR-V |binary| with the given |options| and writes
325   // the assembly to |text|. Returns true on successful disassembling. |text|
326   // will be kept untouched if diassembling is unsuccessful.
327   bool Disassemble(const std::vector<uint32_t>& binary, std::string* text,
328                    uint32_t options = kDefaultDisassembleOption) const;
329   // |binary_size| specifies the number of words in |binary|.
330   bool Disassemble(const uint32_t* binary, size_t binary_size,
331                    std::string* text,
332                    uint32_t options = kDefaultDisassembleOption) const;
333 
334   // Validates the given SPIR-V |binary|. Returns true if no issues are found.
335   // Otherwise, returns false and communicates issues via the message consumer
336   // registered.
337   // Validates for SPIR-V spec rules for the SPIR-V version named in the
338   // binary's header (at word offset 1).  Additionally, if the target
339   // environment is a client API (such as Vulkan 1.1), then validate for that
340   // client API version, to the extent that it is verifiable from data in the
341   // binary itself.
342   bool Validate(const std::vector<uint32_t>& binary) const;
343   // Like the previous overload, but provides the binary as a pointer and size:
344   // |binary_size| specifies the number of words in |binary|.
345   // Validates for SPIR-V spec rules for the SPIR-V version named in the
346   // binary's header (at word offset 1).  Additionally, if the target
347   // environment is a client API (such as Vulkan 1.1), then validate for that
348   // client API version, to the extent that it is verifiable from data in the
349   // binary itself.
350   bool Validate(const uint32_t* binary, size_t binary_size) const;
351   // Like the previous overload, but takes an options object.
352   // Validates for SPIR-V spec rules for the SPIR-V version named in the
353   // binary's header (at word offset 1).  Additionally, if the target
354   // environment is a client API (such as Vulkan 1.1), then validate for that
355   // client API version, to the extent that it is verifiable from data in the
356   // binary itself, or in the validator options.
357   bool Validate(const uint32_t* binary, size_t binary_size,
358                 spv_validator_options options) const;
359 
360   // Was this object successfully constructed.
361   bool IsValid() const;
362 
363  private:
364   struct Impl;  // Opaque struct for holding the data fields used by this class.
365   std::unique_ptr<Impl> impl_;  // Unique pointer to implementation data.
366 };
367 
368 }  // namespace spvtools
369 
370 #endif  // INCLUDE_SPIRV_TOOLS_LIBSPIRV_HPP_
371