libspirv.hpp 16 KB

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