// Copyright (c) 2016 Google Inc. | |
// | |
// Licensed under the Apache License, Version 2.0 (the "License"); | |
// you may not use this file except in compliance with the License. | |
// You may obtain a copy of the License at | |
// | |
// http://www.apache.org/licenses/LICENSE-2.0 | |
// | |
// Unless required by applicable law or agreed to in writing, software | |
// distributed under the License is distributed on an "AS IS" BASIS, | |
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
// See the License for the specific language governing permissions and | |
// limitations under the License. | |
namespace spvtools { | |
// Message consumer. The C strings for source and message are only alive for the | |
// specific invocation. | |
using MessageConsumer = std::function<void( | |
spv_message_level_t /* level */, const char* /* source */, | |
const spv_position_t& /* position */, const char* /* message */ | |
)>; | |
using HeaderParser = std::function<spv_result_t( | |
const spv_endianness_t endianess, const spv_parsed_header_t& instruction)>; | |
using InstructionParser = | |
std::function<spv_result_t(const spv_parsed_instruction_t& instruction)>; | |
// C++ RAII wrapper around the C context object spv_context. | |
class SPIRV_TOOLS_EXPORT Context { | |
public: | |
// Constructs a context targeting the given environment |env|. | |
// | |
// See specific API calls for how the target environment is interpreted | |
// (particularly assembly and validation). | |
// | |
// The constructed instance will have an empty message consumer, which just | |
// ignores all messages from the library. Use SetMessageConsumer() to supply | |
// one if messages are of concern. | |
explicit Context(spv_target_env env); | |
// Enables move constructor/assignment operations. | |
Context(Context&& other); | |
Context& operator=(Context&& other); | |
// Disables copy constructor/assignment operations. | |
Context(const Context&) = delete; | |
Context& operator=(const Context&) = delete; | |
// Destructs this instance. | |
~Context(); | |
// Sets the message consumer to the given |consumer|. The |consumer| will be | |
// invoked once for each message communicated from the library. | |
void SetMessageConsumer(MessageConsumer consumer); | |
// Returns the underlying spv_context. | |
spv_context& CContext(); | |
const spv_context& CContext() const; | |
private: | |
spv_context context_; | |
}; | |
// A RAII wrapper around a validator options object. | |
class SPIRV_TOOLS_EXPORT ValidatorOptions { | |
public: | |
ValidatorOptions() : options_(spvValidatorOptionsCreate()) {} | |
~ValidatorOptions() { spvValidatorOptionsDestroy(options_); } | |
// Allow implicit conversion to the underlying object. | |
operator spv_validator_options() const { return options_; } | |
// Sets a limit. | |
void SetUniversalLimit(spv_validator_limit limit_type, uint32_t limit) { | |
spvValidatorOptionsSetUniversalLimit(options_, limit_type, limit); | |
} | |
void SetRelaxStructStore(bool val) { | |
spvValidatorOptionsSetRelaxStoreStruct(options_, val); | |
} | |
// Enables VK_KHR_relaxed_block_layout when validating standard | |
// uniform/storage buffer/push-constant layout. If true, disables | |
// scalar block layout rules. | |
void SetRelaxBlockLayout(bool val) { | |
spvValidatorOptionsSetRelaxBlockLayout(options_, val); | |
} | |
// Enables VK_KHR_uniform_buffer_standard_layout when validating standard | |
// uniform layout. If true, disables scalar block layout rules. | |
void SetUniformBufferStandardLayout(bool val) { | |
spvValidatorOptionsSetUniformBufferStandardLayout(options_, val); | |
} | |
// Enables VK_EXT_scalar_block_layout when validating standard | |
// uniform/storage buffer/push-constant layout. If true, disables | |
// relaxed block layout rules. | |
void SetScalarBlockLayout(bool val) { | |
spvValidatorOptionsSetScalarBlockLayout(options_, val); | |
} | |
// Enables scalar layout when validating Workgroup blocks. See | |
// VK_KHR_workgroup_memory_explicit_layout. | |
void SetWorkgroupScalarBlockLayout(bool val) { | |
spvValidatorOptionsSetWorkgroupScalarBlockLayout(options_, val); | |
} | |
// Skips validating standard uniform/storage buffer/push-constant layout. | |
void SetSkipBlockLayout(bool val) { | |
spvValidatorOptionsSetSkipBlockLayout(options_, val); | |
} | |
// Enables LocalSizeId decorations where the environment would not otherwise | |
// allow them. | |
void SetAllowLocalSizeId(bool val) { | |
spvValidatorOptionsSetAllowLocalSizeId(options_, val); | |
} | |
// Records whether or not the validator should relax the rules on pointer | |
// usage in logical addressing mode. | |
// | |
// When relaxed, it will allow the following usage cases of pointers: | |
// 1) OpVariable allocating an object whose type is a pointer type | |
// 2) OpReturnValue returning a pointer value | |
void SetRelaxLogicalPointer(bool val) { | |
spvValidatorOptionsSetRelaxLogicalPointer(options_, val); | |
} | |
// Records whether or not the validator should relax the rules because it is | |
// expected that the optimizations will make the code legal. | |
// | |
// When relaxed, it will allow the following: | |
// 1) It will allow relaxed logical pointers. Setting this option will also | |
// set that option. | |
// 2) Pointers that are pass as parameters to function calls do not have to | |
// match the storage class of the formal parameter. | |
// 3) Pointers that are actual parameters on function calls do not have to | |
// point to the same type pointed as the formal parameter. The types just | |
// need to logically match. | |
// 4) GLSLstd450 Interpolate* instructions can have a load of an interpolant | |
// for a first argument. | |
void SetBeforeHlslLegalization(bool val) { | |
spvValidatorOptionsSetBeforeHlslLegalization(options_, val); | |
} | |
// Whether friendly names should be used in validation error messages. | |
void SetFriendlyNames(bool val) { | |
spvValidatorOptionsSetFriendlyNames(options_, val); | |
} | |
private: | |
spv_validator_options options_; | |
}; | |
// A C++ wrapper around an optimization options object. | |
class SPIRV_TOOLS_EXPORT OptimizerOptions { | |
public: | |
OptimizerOptions() : options_(spvOptimizerOptionsCreate()) {} | |
~OptimizerOptions() { spvOptimizerOptionsDestroy(options_); } | |
// Allow implicit conversion to the underlying object. | |
operator spv_optimizer_options() const { return options_; } | |
// Records whether or not the optimizer should run the validator before | |
// optimizing. If |run| is true, the validator will be run. | |
void set_run_validator(bool run) { | |
spvOptimizerOptionsSetRunValidator(options_, run); | |
} | |
// Records the validator options that should be passed to the validator if it | |
// is run. | |
void set_validator_options(const ValidatorOptions& val_options) { | |
spvOptimizerOptionsSetValidatorOptions(options_, val_options); | |
} | |
// Records the maximum possible value for the id bound. | |
void set_max_id_bound(uint32_t new_bound) { | |
spvOptimizerOptionsSetMaxIdBound(options_, new_bound); | |
} | |
// Records whether all bindings within the module should be preserved. | |
void set_preserve_bindings(bool preserve_bindings) { | |
spvOptimizerOptionsSetPreserveBindings(options_, preserve_bindings); | |
} | |
// Records whether all specialization constants within the module | |
// should be preserved. | |
void set_preserve_spec_constants(bool preserve_spec_constants) { | |
spvOptimizerOptionsSetPreserveSpecConstants(options_, | |
preserve_spec_constants); | |
} | |
private: | |
spv_optimizer_options options_; | |
}; | |
// A C++ wrapper around a reducer options object. | |
class SPIRV_TOOLS_EXPORT ReducerOptions { | |
public: | |
ReducerOptions() : options_(spvReducerOptionsCreate()) {} | |
~ReducerOptions() { spvReducerOptionsDestroy(options_); } | |
// Allow implicit conversion to the underlying object. | |
operator spv_reducer_options() const { // NOLINT(google-explicit-constructor) | |
return options_; | |
} | |
// See spvReducerOptionsSetStepLimit. | |
void set_step_limit(uint32_t step_limit) { | |
spvReducerOptionsSetStepLimit(options_, step_limit); | |
} | |
// See spvReducerOptionsSetFailOnValidationError. | |
void set_fail_on_validation_error(bool fail_on_validation_error) { | |
spvReducerOptionsSetFailOnValidationError(options_, | |
fail_on_validation_error); | |
} | |
// See spvReducerOptionsSetTargetFunction. | |
void set_target_function(uint32_t target_function) { | |
spvReducerOptionsSetTargetFunction(options_, target_function); | |
} | |
private: | |
spv_reducer_options options_; | |
}; | |
// A C++ wrapper around a fuzzer options object. | |
class SPIRV_TOOLS_EXPORT FuzzerOptions { | |
public: | |
FuzzerOptions() : options_(spvFuzzerOptionsCreate()) {} | |
~FuzzerOptions() { spvFuzzerOptionsDestroy(options_); } | |
// Allow implicit conversion to the underlying object. | |
operator spv_fuzzer_options() const { // NOLINT(google-explicit-constructor) | |
return options_; | |
} | |
// See spvFuzzerOptionsEnableReplayValidation. | |
void enable_replay_validation() { | |
spvFuzzerOptionsEnableReplayValidation(options_); | |
} | |
// See spvFuzzerOptionsSetRandomSeed. | |
void set_random_seed(uint32_t seed) { | |
spvFuzzerOptionsSetRandomSeed(options_, seed); | |
} | |
// See spvFuzzerOptionsSetReplayRange. | |
void set_replay_range(int32_t replay_range) { | |
spvFuzzerOptionsSetReplayRange(options_, replay_range); | |
} | |
// See spvFuzzerOptionsSetShrinkerStepLimit. | |
void set_shrinker_step_limit(uint32_t shrinker_step_limit) { | |
spvFuzzerOptionsSetShrinkerStepLimit(options_, shrinker_step_limit); | |
} | |
// See spvFuzzerOptionsEnableFuzzerPassValidation. | |
void enable_fuzzer_pass_validation() { | |
spvFuzzerOptionsEnableFuzzerPassValidation(options_); | |
} | |
// See spvFuzzerOptionsEnableAllPasses. | |
void enable_all_passes() { spvFuzzerOptionsEnableAllPasses(options_); } | |
private: | |
spv_fuzzer_options options_; | |
}; | |
// C++ interface for SPIRV-Tools functionalities. It wraps the context | |
// (including target environment and the corresponding SPIR-V grammar) and | |
// provides methods for assembling, disassembling, and validating. | |
// | |
// Instances of this class provide basic thread-safety guarantee. | |
class SPIRV_TOOLS_EXPORT SpirvTools { | |
public: | |
enum { | |
// Default assembling option used by assemble(): | |
kDefaultAssembleOption = SPV_TEXT_TO_BINARY_OPTION_NONE, | |
// Default disassembling option used by Disassemble(): | |
// * Avoid prefix comments from decoding the SPIR-V module header, and | |
// * Use friendly names for variables. | |
kDefaultDisassembleOption = SPV_BINARY_TO_TEXT_OPTION_NO_HEADER | | |
SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES | |
}; | |
// Constructs an instance targeting the given environment |env|. | |
// | |
// The constructed instance will have an empty message consumer, which just | |
// ignores all messages from the library. Use SetMessageConsumer() to supply | |
// one if messages are of concern. | |
explicit SpirvTools(spv_target_env env); | |
// Disables copy/move constructor/assignment operations. | |
SpirvTools(const SpirvTools&) = delete; | |
SpirvTools(SpirvTools&&) = delete; | |
SpirvTools& operator=(const SpirvTools&) = delete; | |
SpirvTools& operator=(SpirvTools&&) = delete; | |
// Destructs this instance. | |
~SpirvTools(); | |
// Sets the message consumer to the given |consumer|. The |consumer| will be | |
// invoked once for each message communicated from the library. | |
void SetMessageConsumer(MessageConsumer consumer); | |
// Assembles the given assembly |text| and writes the result to |binary|. | |
// Returns true on successful assembling. |binary| will be kept untouched if | |
// assembling is unsuccessful. | |
// The SPIR-V binary version is set to the highest version of SPIR-V supported | |
// by the target environment with which this SpirvTools object was created. | |
bool Assemble(const std::string& text, std::vector<uint32_t>* binary, | |
uint32_t options = kDefaultAssembleOption) const; | |
// |text_size| specifies the number of bytes in |text|. A terminating null | |
// character is not required to present in |text| as long as |text| is valid. | |
// The SPIR-V binary version is set to the highest version of SPIR-V supported | |
// by the target environment with which this SpirvTools object was created. | |
bool Assemble(const char* text, size_t text_size, | |
std::vector<uint32_t>* binary, | |
uint32_t options = kDefaultAssembleOption) const; | |
// Disassembles the given SPIR-V |binary| with the given |options| and writes | |
// the assembly to |text|. Returns true on successful disassembling. |text| | |
// will be kept untouched if diassembling is unsuccessful. | |
bool Disassemble(const std::vector<uint32_t>& binary, std::string* text, | |
uint32_t options = kDefaultDisassembleOption) const; | |
// |binary_size| specifies the number of words in |binary|. | |
bool Disassemble(const uint32_t* binary, size_t binary_size, | |
std::string* text, | |
uint32_t options = kDefaultDisassembleOption) const; | |
// Parses a SPIR-V binary, specified as counted sequence of 32-bit words. | |
// Parsing feedback is provided via two callbacks provided as std::function. | |
// In a valid parse the parsed-header callback is called once, and | |
// then the parsed-instruction callback is called once for each instruction | |
// in the stream. | |
// Returns true on successful parsing. | |
// If diagnostic is non-null, a diagnostic is emitted on failed parsing. | |
// If diagnostic is null the context's message consumer | |
// will be used to emit any errors. If a callback returns anything other than | |
// SPV_SUCCESS, then that status code is returned, no further callbacks are | |
// issued, and no additional diagnostics are emitted. | |
// This is a wrapper around the C API spvBinaryParse. | |
bool Parse(const std::vector<uint32_t>& binary, | |
const HeaderParser& header_parser, | |
const InstructionParser& instruction_parser, | |
spv_diagnostic* diagnostic = nullptr); | |
// Validates the given SPIR-V |binary|. Returns true if no issues are found. | |
// Otherwise, returns false and communicates issues via the message consumer | |
// registered. | |
// Validates for SPIR-V spec rules for the SPIR-V version named in the | |
// binary's header (at word offset 1). Additionally, if the target | |
// environment is a client API (such as Vulkan 1.1), then validate for that | |
// client API version, to the extent that it is verifiable from data in the | |
// binary itself. | |
bool Validate(const std::vector<uint32_t>& binary) const; | |
// Like the previous overload, but provides the binary as a pointer and size: | |
// |binary_size| specifies the number of words in |binary|. | |
// Validates for SPIR-V spec rules for the SPIR-V version named in the | |
// binary's header (at word offset 1). Additionally, if the target | |
// environment is a client API (such as Vulkan 1.1), then validate for that | |
// client API version, to the extent that it is verifiable from data in the | |
// binary itself. | |
bool Validate(const uint32_t* binary, size_t binary_size) const; | |
// Like the previous overload, but takes an options object. | |
// Validates for SPIR-V spec rules for the SPIR-V version named in the | |
// binary's header (at word offset 1). Additionally, if the target | |
// environment is a client API (such as Vulkan 1.1), then validate for that | |
// client API version, to the extent that it is verifiable from data in the | |
// binary itself, or in the validator options. | |
bool Validate(const uint32_t* binary, size_t binary_size, | |
spv_validator_options options) const; | |
// Was this object successfully constructed. | |
bool IsValid() const; | |
private: | |
struct SPIRV_TOOLS_LOCAL | |
Impl; // Opaque struct for holding the data fields used by this class. | |
std::unique_ptr<Impl> impl_; // Unique pointer to implementation data. | |
}; | |
} // namespace spvtools | |