spirv_cross_parsed_ir.hpp 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. /*
  2. * Copyright 2018-2021 Arm Limited
  3. * SPDX-License-Identifier: Apache-2.0 OR MIT
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. /*
  18. * At your option, you may choose to accept this material under either:
  19. * 1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
  20. * 2. The MIT License, found at <http://opensource.org/licenses/MIT>.
  21. */
  22. #ifndef SPIRV_CROSS_PARSED_IR_HPP
  23. #define SPIRV_CROSS_PARSED_IR_HPP
  24. #include "spirv_common.hpp"
  25. #include <stdint.h>
  26. #include <unordered_map>
  27. namespace SPIRV_CROSS_NAMESPACE
  28. {
  29. // This data structure holds all information needed to perform cross-compilation and reflection.
  30. // It is the output of the Parser, but any implementation could create this structure.
  31. // It is intentionally very "open" and struct-like with some helper functions to deal with decorations.
  32. // Parser is the reference implementation of how this data structure should be filled in.
  33. class ParsedIR
  34. {
  35. private:
  36. // This must be destroyed after the "ids" vector.
  37. std::unique_ptr<ObjectPoolGroup> pool_group;
  38. public:
  39. ParsedIR();
  40. // Due to custom allocations from object pools, we cannot use a default copy constructor.
  41. ParsedIR(const ParsedIR &other);
  42. ParsedIR &operator=(const ParsedIR &other);
  43. // Moves are unproblematic, but we need to implement it anyways, since MSVC 2013 does not understand
  44. // how to default-implement these.
  45. ParsedIR(ParsedIR &&other) SPIRV_CROSS_NOEXCEPT;
  46. ParsedIR &operator=(ParsedIR &&other) SPIRV_CROSS_NOEXCEPT;
  47. // Resizes ids, meta and block_meta.
  48. void set_id_bounds(uint32_t bounds);
  49. // The raw SPIR-V, instructions and opcodes refer to this by offset + count.
  50. std::vector<uint32_t> spirv;
  51. // Holds various data structures which inherit from IVariant.
  52. SmallVector<Variant> ids;
  53. // Various meta data for IDs, decorations, names, etc.
  54. std::unordered_map<ID, Meta> meta;
  55. // Holds all IDs which have a certain type.
  56. // This is needed so we can iterate through a specific kind of resource quickly,
  57. // and in-order of module declaration.
  58. SmallVector<ID> ids_for_type[TypeCount];
  59. // Special purpose lists which contain a union of types.
  60. // This is needed so we can declare specialization constants and structs in an interleaved fashion,
  61. // among other things.
  62. // Constants can be undef or of struct type, and struct array sizes can use specialization constants.
  63. SmallVector<ID> ids_for_constant_undef_or_type;
  64. SmallVector<ID> ids_for_constant_or_variable;
  65. // We need to keep track of the width the Ops that contains a type for the
  66. // OpSwitch instruction, since this one doesn't contains the type in the
  67. // instruction itself. And in some case we need to cast the condition to
  68. // wider types. We only need the width to do the branch fixup since the
  69. // type check itself can be done at runtime
  70. std::unordered_map<ID, uint32_t> load_type_width;
  71. // Declared capabilities and extensions in the SPIR-V module.
  72. // Not really used except for reflection at the moment.
  73. SmallVector<spv::Capability> declared_capabilities;
  74. SmallVector<std::string> declared_extensions;
  75. // Meta data about blocks. The cross-compiler needs to query if a block is either of these types.
  76. // It is a bitset as there can be more than one tag per block.
  77. enum BlockMetaFlagBits
  78. {
  79. BLOCK_META_LOOP_HEADER_BIT = 1 << 0,
  80. BLOCK_META_CONTINUE_BIT = 1 << 1,
  81. BLOCK_META_LOOP_MERGE_BIT = 1 << 2,
  82. BLOCK_META_SELECTION_MERGE_BIT = 1 << 3,
  83. BLOCK_META_MULTISELECT_MERGE_BIT = 1 << 4
  84. };
  85. using BlockMetaFlags = uint8_t;
  86. SmallVector<BlockMetaFlags> block_meta;
  87. std::unordered_map<BlockID, BlockID> continue_block_to_loop_header;
  88. // Normally, we'd stick SPIREntryPoint in ids array, but it conflicts with SPIRFunction.
  89. // Entry points can therefore be seen as some sort of meta structure.
  90. std::unordered_map<FunctionID, SPIREntryPoint> entry_points;
  91. FunctionID default_entry_point = 0;
  92. struct Source
  93. {
  94. uint32_t version = 0;
  95. bool es = false;
  96. bool known = false;
  97. bool hlsl = false;
  98. Source() = default;
  99. };
  100. Source source;
  101. spv::AddressingModel addressing_model = spv::AddressingModelMax;
  102. spv::MemoryModel memory_model = spv::MemoryModelMax;
  103. // Decoration handling methods.
  104. // Can be useful for simple "raw" reflection.
  105. // However, most members are here because the Parser needs most of these,
  106. // and might as well just have the whole suite of decoration/name handling in one place.
  107. void set_name(ID id, const std::string &name);
  108. const std::string &get_name(ID id) const;
  109. void set_decoration(ID id, spv::Decoration decoration, uint32_t argument = 0);
  110. void set_decoration_string(ID id, spv::Decoration decoration, const std::string &argument);
  111. bool has_decoration(ID id, spv::Decoration decoration) const;
  112. uint32_t get_decoration(ID id, spv::Decoration decoration) const;
  113. const std::string &get_decoration_string(ID id, spv::Decoration decoration) const;
  114. const Bitset &get_decoration_bitset(ID id) const;
  115. void unset_decoration(ID id, spv::Decoration decoration);
  116. // Decoration handling methods (for members of a struct).
  117. void set_member_name(TypeID id, uint32_t index, const std::string &name);
  118. const std::string &get_member_name(TypeID id, uint32_t index) const;
  119. void set_member_decoration(TypeID id, uint32_t index, spv::Decoration decoration, uint32_t argument = 0);
  120. void set_member_decoration_string(TypeID id, uint32_t index, spv::Decoration decoration,
  121. const std::string &argument);
  122. uint32_t get_member_decoration(TypeID id, uint32_t index, spv::Decoration decoration) const;
  123. const std::string &get_member_decoration_string(TypeID id, uint32_t index, spv::Decoration decoration) const;
  124. bool has_member_decoration(TypeID id, uint32_t index, spv::Decoration decoration) const;
  125. const Bitset &get_member_decoration_bitset(TypeID id, uint32_t index) const;
  126. void unset_member_decoration(TypeID id, uint32_t index, spv::Decoration decoration);
  127. void mark_used_as_array_length(ID id);
  128. uint32_t increase_bound_by(uint32_t count);
  129. Bitset get_buffer_block_flags(const SPIRVariable &var) const;
  130. Bitset get_buffer_block_type_flags(const SPIRType &type) const;
  131. void add_typed_id(Types type, ID id);
  132. void remove_typed_id(Types type, ID id);
  133. class LoopLock
  134. {
  135. public:
  136. explicit LoopLock(uint32_t *counter);
  137. LoopLock(const LoopLock &) = delete;
  138. void operator=(const LoopLock &) = delete;
  139. LoopLock(LoopLock &&other) SPIRV_CROSS_NOEXCEPT;
  140. LoopLock &operator=(LoopLock &&other) SPIRV_CROSS_NOEXCEPT;
  141. ~LoopLock();
  142. private:
  143. uint32_t *lock;
  144. };
  145. // This must be held while iterating over a type ID array.
  146. // It is undefined if someone calls set<>() while we're iterating over a data structure, so we must
  147. // make sure that this case is avoided.
  148. // If we have a hard lock, it is an error to call set<>(), and an exception is thrown.
  149. // If we have a soft lock, we silently ignore any additions to the typed arrays.
  150. // This should only be used for physical ID remapping where we need to create an ID, but we will never
  151. // care about iterating over them.
  152. LoopLock create_loop_hard_lock() const;
  153. LoopLock create_loop_soft_lock() const;
  154. template <typename T, typename Op>
  155. void for_each_typed_id(const Op &op)
  156. {
  157. auto loop_lock = create_loop_hard_lock();
  158. for (auto &id : ids_for_type[T::type])
  159. {
  160. if (ids[id].get_type() == static_cast<Types>(T::type))
  161. op(id, get<T>(id));
  162. }
  163. }
  164. template <typename T, typename Op>
  165. void for_each_typed_id(const Op &op) const
  166. {
  167. auto loop_lock = create_loop_hard_lock();
  168. for (auto &id : ids_for_type[T::type])
  169. {
  170. if (ids[id].get_type() == static_cast<Types>(T::type))
  171. op(id, get<T>(id));
  172. }
  173. }
  174. template <typename T>
  175. void reset_all_of_type()
  176. {
  177. reset_all_of_type(static_cast<Types>(T::type));
  178. }
  179. void reset_all_of_type(Types type);
  180. Meta *find_meta(ID id);
  181. const Meta *find_meta(ID id) const;
  182. const std::string &get_empty_string() const
  183. {
  184. return empty_string;
  185. }
  186. void make_constant_null(uint32_t id, uint32_t type, bool add_to_typed_id_set);
  187. void fixup_reserved_names();
  188. static void sanitize_underscores(std::string &str);
  189. static void sanitize_identifier(std::string &str, bool member, bool allow_reserved_prefixes);
  190. static bool is_globally_reserved_identifier(std::string &str, bool allow_reserved_prefixes);
  191. uint32_t get_spirv_version() const;
  192. private:
  193. template <typename T>
  194. T &get(uint32_t id)
  195. {
  196. return variant_get<T>(ids[id]);
  197. }
  198. template <typename T>
  199. const T &get(uint32_t id) const
  200. {
  201. return variant_get<T>(ids[id]);
  202. }
  203. mutable uint32_t loop_iteration_depth_hard = 0;
  204. mutable uint32_t loop_iteration_depth_soft = 0;
  205. std::string empty_string;
  206. Bitset cleared_bitset;
  207. std::unordered_set<uint32_t> meta_needing_name_fixup;
  208. };
  209. } // namespace SPIRV_CROSS_NAMESPACE
  210. #endif