libspirv.hpp 15 KB

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