text_handler.h 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. // Copyright (c) 2015-2016 The Khronos Group 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 SOURCE_TEXT_HANDLER_H_
  15. #define SOURCE_TEXT_HANDLER_H_
  16. #include <iomanip>
  17. #include <set>
  18. #include <sstream>
  19. #include <string>
  20. #include <type_traits>
  21. #include <unordered_map>
  22. #include <utility>
  23. #include "source/diagnostic.h"
  24. #include "source/instruction.h"
  25. #include "source/text.h"
  26. #include "spirv-tools/libspirv.h"
  27. namespace spvtools {
  28. // Structures
  29. // This is a lattice for tracking types.
  30. enum class IdTypeClass {
  31. kBottom = 0, // We have no information yet.
  32. kScalarIntegerType,
  33. kScalarFloatType,
  34. kOtherType
  35. };
  36. // Contains ID type information that needs to be tracked across all Ids.
  37. // Bitwidth is only valid when type_class is kScalarIntegerType or
  38. // kScalarFloatType.
  39. struct IdType {
  40. uint32_t bitwidth; // Safe to assume that we will not have > 2^32 bits.
  41. bool isSigned; // This is only significant if type_class is integral.
  42. IdTypeClass type_class;
  43. };
  44. // Default equality operator for IdType. Tests if all members are the same.
  45. inline bool operator==(const IdType& first, const IdType& second) {
  46. return (first.bitwidth == second.bitwidth) &&
  47. (first.isSigned == second.isSigned) &&
  48. (first.type_class == second.type_class);
  49. }
  50. // Tests whether any member of the IdTypes do not match.
  51. inline bool operator!=(const IdType& first, const IdType& second) {
  52. return !(first == second);
  53. }
  54. // A value representing an unknown type.
  55. extern const IdType kUnknownType;
  56. // Returns true if the type is a scalar integer type.
  57. inline bool isScalarIntegral(const IdType& type) {
  58. return type.type_class == IdTypeClass::kScalarIntegerType;
  59. }
  60. // Returns true if the type is a scalar floating point type.
  61. inline bool isScalarFloating(const IdType& type) {
  62. return type.type_class == IdTypeClass::kScalarFloatType;
  63. }
  64. // Returns the number of bits in the type.
  65. // This is only valid for bottom, scalar integer, and scalar floating
  66. // classes. For bottom, assume 32 bits.
  67. inline int assumedBitWidth(const IdType& type) {
  68. switch (type.type_class) {
  69. case IdTypeClass::kBottom:
  70. return 32;
  71. case IdTypeClass::kScalarIntegerType:
  72. case IdTypeClass::kScalarFloatType:
  73. return type.bitwidth;
  74. default:
  75. break;
  76. }
  77. // We don't care about this case.
  78. return 0;
  79. }
  80. // A templated class with a static member function Clamp, where Clamp
  81. // sets a referenced value of type T to 0 if T is an unsigned
  82. // integer type, and returns true if it modified the referenced
  83. // value.
  84. template <typename T, typename = void>
  85. class ClampToZeroIfUnsignedType {
  86. public:
  87. // The default specialization does not clamp the value.
  88. static bool Clamp(T*) { return false; }
  89. };
  90. // The specialization of ClampToZeroIfUnsignedType for unsigned integer
  91. // types.
  92. template <typename T>
  93. class ClampToZeroIfUnsignedType<
  94. T, typename std::enable_if<std::is_unsigned<T>::value>::type> {
  95. public:
  96. static bool Clamp(T* value_pointer) {
  97. if (*value_pointer) {
  98. *value_pointer = 0;
  99. return true;
  100. }
  101. return false;
  102. }
  103. };
  104. // Encapsulates the data used during the assembly of a SPIR-V module.
  105. class AssemblyContext {
  106. public:
  107. AssemblyContext(spv_text text, const MessageConsumer& consumer,
  108. std::set<uint32_t>&& ids_to_preserve = std::set<uint32_t>())
  109. : current_position_({}),
  110. consumer_(consumer),
  111. text_(text),
  112. bound_(1),
  113. next_id_(1),
  114. ids_to_preserve_(std::move(ids_to_preserve)) {}
  115. // Assigns a new integer value to the given text ID, or returns the previously
  116. // assigned integer value if the ID has been seen before.
  117. uint32_t spvNamedIdAssignOrGet(const char* textValue);
  118. // Returns the largest largest numeric ID that has been assigned.
  119. uint32_t getBound() const;
  120. // Advances position to point to the next word in the input stream.
  121. // Returns SPV_SUCCESS on success.
  122. spv_result_t advance();
  123. // Sets word to the next word in the input text. Fills next_position with
  124. // the next location past the end of the word.
  125. spv_result_t getWord(std::string* word, spv_position next_position);
  126. // Returns true if the next word in the input is the start of a new Opcode.
  127. bool startsWithOp();
  128. // Returns true if the next word in the input is the start of a new
  129. // instruction.
  130. bool isStartOfNewInst();
  131. // Returns a diagnostic object initialized with current position in the input
  132. // stream, and for the given error code. Any data written to this object will
  133. // show up in pDiagnsotic on destruction.
  134. DiagnosticStream diagnostic(spv_result_t error) {
  135. return DiagnosticStream(current_position_, consumer_, "", error);
  136. }
  137. // Returns a diagnostic object with the default assembly error code.
  138. DiagnosticStream diagnostic() {
  139. // The default failure for assembly is invalid text.
  140. return diagnostic(SPV_ERROR_INVALID_TEXT);
  141. }
  142. // Returns then next character in the input stream.
  143. char peek() const;
  144. // Returns true if there is more text in the input stream.
  145. bool hasText() const;
  146. // Seeks the input stream forward by 'size' characters.
  147. void seekForward(uint32_t size);
  148. // Sets the current position in the input stream to the given position.
  149. void setPosition(const spv_position_t& newPosition) {
  150. current_position_ = newPosition;
  151. }
  152. // Returns the current position in the input stream.
  153. const spv_position_t& position() const { return current_position_; }
  154. // Appends the given 32-bit value to the given instruction.
  155. // Returns SPV_SUCCESS if the value could be correctly inserted in the
  156. // instruction.
  157. spv_result_t binaryEncodeU32(const uint32_t value, spv_instruction_t* pInst);
  158. // Appends the given string to the given instruction.
  159. // Returns SPV_SUCCESS if the value could be correctly inserted in the
  160. // instruction.
  161. spv_result_t binaryEncodeString(const char* value, spv_instruction_t* pInst);
  162. // Appends the given numeric literal to the given instruction.
  163. // Validates and respects the bitwidth supplied in the IdType argument.
  164. // If the type is of class kBottom the value will be encoded as a
  165. // 32-bit integer.
  166. // Returns SPV_SUCCESS if the value could be correctly added to the
  167. // instruction. Returns the given error code on failure, and emits
  168. // a diagnostic if that error code is not SPV_FAILED_MATCH.
  169. spv_result_t binaryEncodeNumericLiteral(const char* numeric_literal,
  170. spv_result_t error_code,
  171. const IdType& type,
  172. spv_instruction_t* pInst);
  173. // Returns the IdType associated with this type-generating value.
  174. // If the type has not been previously recorded with recordTypeDefinition,
  175. // kUnknownType will be returned.
  176. IdType getTypeOfTypeGeneratingValue(uint32_t value) const;
  177. // Returns the IdType that represents the return value of this Value
  178. // generating instruction.
  179. // If the value has not been recorded with recordTypeIdForValue, or the type
  180. // could not be determined kUnknownType will be returned.
  181. IdType getTypeOfValueInstruction(uint32_t value) const;
  182. // Tracks the type-defining instruction. The result of the tracking can
  183. // later be queried using getValueType.
  184. // pInst is expected to be completely filled in by the time this instruction
  185. // is called.
  186. // Returns SPV_SUCCESS on success, or SPV_ERROR_INVALID_VALUE on error.
  187. spv_result_t recordTypeDefinition(const spv_instruction_t* pInst);
  188. // Tracks the relationship between the value and its type.
  189. spv_result_t recordTypeIdForValue(uint32_t value, uint32_t type);
  190. // Records the given Id as being the import of the given extended instruction
  191. // type.
  192. spv_result_t recordIdAsExtInstImport(uint32_t id, spv_ext_inst_type_t type);
  193. // Returns the extended instruction type corresponding to the import with
  194. // the given Id, if it exists. Returns SPV_EXT_INST_TYPE_NONE if the
  195. // id is not the id for an extended instruction type.
  196. spv_ext_inst_type_t getExtInstTypeForId(uint32_t id) const;
  197. // Returns a set consisting of each ID generated by spvNamedIdAssignOrGet from
  198. // a numeric ID text representation. For example, generated from "%12" but not
  199. // from "%foo".
  200. std::set<uint32_t> GetNumericIds() const;
  201. private:
  202. // Maps ID names to their corresponding numerical ids.
  203. using spv_named_id_table = std::unordered_map<std::string, uint32_t>;
  204. // Maps type-defining IDs to their IdType.
  205. using spv_id_to_type_map = std::unordered_map<uint32_t, IdType>;
  206. // Maps Ids to the id of their type.
  207. using spv_id_to_type_id = std::unordered_map<uint32_t, uint32_t>;
  208. spv_named_id_table named_ids_;
  209. spv_id_to_type_map types_;
  210. spv_id_to_type_id value_types_;
  211. // Maps an extended instruction import Id to the extended instruction type.
  212. std::unordered_map<uint32_t, spv_ext_inst_type_t> import_id_to_ext_inst_type_;
  213. spv_position_t current_position_;
  214. MessageConsumer consumer_;
  215. spv_text text_;
  216. uint32_t bound_;
  217. uint32_t next_id_;
  218. std::set<uint32_t> ids_to_preserve_;
  219. };
  220. } // namespace spvtools
  221. #endif // SOURCE_TEXT_HANDLER_H_