blob: 266284690b9f430083b0bda88f7150a5f47a1df9 [file] [log] [blame]
Andrew Woloszyn71fc0552015-09-24 10:26:51 -04001// Copyright (c) 2015 The Khronos Group Inc.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a
4// copy of this software and/or associated documentation files (the
5// "Materials"), to deal in the Materials without restriction, including
6// without limitation the rights to use, copy, modify, merge, publish,
7// distribute, sublicense, and/or sell copies of the Materials, and to
8// permit persons to whom the Materials are furnished to do so, subject to
9// the following conditions:
10//
11// The above copyright notice and this permission notice shall be included
12// in all copies or substantial portions of the Materials.
13//
14// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
15// KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
16// SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
17// https://www.khronos.org/registry/
18//
19// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
23// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
26
David Neto9f79d782015-10-27 16:27:05 -040027#ifndef LIBSPIRV_TEXT_HANDLER_H_
28#define LIBSPIRV_TEXT_HANDLER_H_
Andrew Woloszyn71fc0552015-09-24 10:26:51 -040029
David Neto62741202015-10-13 15:51:12 -040030#include <iomanip>
31#include <limits>
32#include <sstream>
33#include <type_traits>
Andrew Woloszyn71fc0552015-09-24 10:26:51 -040034#include <unordered_map>
35
David Neto62741202015-10-13 15:51:12 -040036#include <libspirv/libspirv.h>
Andrew Woloszyn71fc0552015-09-24 10:26:51 -040037#include "diagnostic.h"
David Netob5dc8fc2015-10-06 16:22:00 -040038#include "instruction.h"
David Neto78e677b2015-10-05 13:28:46 -040039#include "text.h"
Andrew Woloszyn71fc0552015-09-24 10:26:51 -040040
41namespace libspirv {
42// Structures
43
Andrew Woloszyn71fc0552015-09-24 10:26:51 -040044// This is a lattice for tracking types.
45enum class IdTypeClass {
Lei Zhang1a0334e2015-11-02 09:41:20 -050046 kBottom = 0, // We have no information yet.
Andrew Woloszyn71fc0552015-09-24 10:26:51 -040047 kScalarIntegerType,
48 kScalarFloatType,
49 kOtherType
50};
51
Andrew Woloszyn71fc0552015-09-24 10:26:51 -040052// Contains ID type information that needs to be tracked across all Ids.
53// Bitwidth is only valid when type_class is kScalarIntegerType or
54// kScalarFloatType.
55struct IdType {
56 uint32_t bitwidth; // Safe to assume that we will not have > 2^32 bits.
Lei Zhang1a0334e2015-11-02 09:41:20 -050057 bool isSigned; // This is only significant if type_class is integral.
Andrew Woloszyn71fc0552015-09-24 10:26:51 -040058 IdTypeClass type_class;
59};
60
Andrew Woloszyn157e41b2015-10-16 15:11:00 -040061// Default equality operator for IdType. Tests if all members are the same.
Lei Zhang1a0334e2015-11-02 09:41:20 -050062inline bool operator==(const IdType& first, const IdType& second) {
Andrew Woloszyn157e41b2015-10-16 15:11:00 -040063 return (first.bitwidth == second.bitwidth) &&
64 (first.isSigned == second.isSigned) &&
65 (first.type_class == second.type_class);
66}
67
68// Tests whether any member of the IdTypes do not match.
Lei Zhang1a0334e2015-11-02 09:41:20 -050069inline bool operator!=(const IdType& first, const IdType& second) {
Andrew Woloszyn157e41b2015-10-16 15:11:00 -040070 return !(first == second);
71}
72
David Neto78e677b2015-10-05 13:28:46 -040073// A value representing an unknown type.
74extern const IdType kUnknownType;
75
Andrew Woloszyn537e7762015-09-29 11:28:34 -040076// Returns true if the type is a scalar integer type.
77inline bool isScalarIntegral(const IdType& type) {
78 return type.type_class == IdTypeClass::kScalarIntegerType;
79}
80
81// Returns true if the type is a scalar floating point type.
82inline bool isScalarFloating(const IdType& type) {
83 return type.type_class == IdTypeClass::kScalarFloatType;
84}
85
David Neto78e677b2015-10-05 13:28:46 -040086// Returns the number of bits in the type.
87// This is only valid for bottom, scalar integer, and scalar floating
88// classes. For bottom, assume 32 bits.
89inline int assumedBitWidth(const IdType& type) {
Lei Zhang1a0334e2015-11-02 09:41:20 -050090 switch (type.type_class) {
David Neto78e677b2015-10-05 13:28:46 -040091 case IdTypeClass::kBottom:
92 return 32;
93 case IdTypeClass::kScalarIntegerType:
94 case IdTypeClass::kScalarFloatType:
95 return type.bitwidth;
96 default:
97 break;
98 }
99 // We don't care about this case.
100 return 0;
101}
102
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400103// Encapsulates the data used during the assembly of a SPIR-V module.
104class AssemblyContext {
105 public:
Lei Zhang1a0334e2015-11-02 09:41:20 -0500106 AssemblyContext(spv_text text, spv_diagnostic* diagnostic)
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400107 : current_position_({}),
108 pDiagnostic_(diagnostic),
109 text_(text),
110 bound_(1) {}
111
112 // Assigns a new integer value to the given text ID, or returns the previously
113 // assigned integer value if the ID has been seen before.
Lei Zhang1a0334e2015-11-02 09:41:20 -0500114 uint32_t spvNamedIdAssignOrGet(const char* textValue);
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400115
116 // Returns the largest largest numeric ID that has been assigned.
117 uint32_t getBound() const;
118
119 // Advances position to point to the next word in the input stream.
120 // Returns SPV_SUCCESS on success.
121 spv_result_t advance();
122
123 // Sets word to the next word in the input text. Fills endPosition with
124 // the next location past the end of the word.
Lei Zhang1a0334e2015-11-02 09:41:20 -0500125 spv_result_t getWord(std::string& word, spv_position endPosition);
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400126
127 // Returns the next word in the input stream. It is invalid to call this
128 // method if position has been set to a location in the stream that does not
129 // exist. If there are no subsequent words, the empty string will be returend.
130 std::string getWord() const;
131
132 // Returns true if the next word in the input is the start of a new Opcode.
133 bool startsWithOp();
134
135 // Returns true if the next word in the input is the start of a new
136 // instruction.
137 bool isStartOfNewInst();
138
139 // Returns a diagnostic object initialized with current position in the input
David Netoac508b02015-10-09 15:48:09 -0400140 // stream, and for the given error code. Any data written to this object will
141 // show up in pDiagnsotic on destruction.
142 DiagnosticStream diagnostic(spv_result_t error) {
David Netobae88512015-10-28 13:16:56 -0400143 return DiagnosticStream(current_position_, pDiagnostic_, error);
David Netoac508b02015-10-09 15:48:09 -0400144 }
145
146 // Returns a diagnostic object with the default assembly error code.
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400147 DiagnosticStream diagnostic() {
David Netoac508b02015-10-09 15:48:09 -0400148 // The default failure for assembly is invalid text.
149 return diagnostic(SPV_ERROR_INVALID_TEXT);
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400150 }
151
152 // Returns then next characted in the input stream.
153 char peek() const;
154
155 // Returns true if there is more text in the input stream.
156 bool hasText() const;
157
158 // Seeks the input stream forward by 'size' characters.
159 void seekForward(uint32_t size);
160
161 // Sets the current position in the input stream to the given position.
Lei Zhang1a0334e2015-11-02 09:41:20 -0500162 void setPosition(const spv_position_t& newPosition) {
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400163 current_position_ = newPosition;
164 }
165
166 // Returns the current position in the input stream.
Lei Zhang1a0334e2015-11-02 09:41:20 -0500167 const spv_position_t& position() const { return current_position_; }
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400168
169 // Appends the given 32-bit value to the given instruction.
David Neto78e677b2015-10-05 13:28:46 -0400170 // Returns SPV_SUCCESS if the value could be correctly inserted in the
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400171 // instruction.
Lei Zhang1a0334e2015-11-02 09:41:20 -0500172 spv_result_t binaryEncodeU32(const uint32_t value, spv_instruction_t* pInst);
David Neto78e677b2015-10-05 13:28:46 -0400173
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400174 // Appends the given string to the given instruction.
David Neto78e677b2015-10-05 13:28:46 -0400175 // Returns SPV_SUCCESS if the value could be correctly inserted in the
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400176 // instruction.
Lei Zhang1a0334e2015-11-02 09:41:20 -0500177 spv_result_t binaryEncodeString(const char* value, spv_instruction_t* pInst);
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400178
David Neto78e677b2015-10-05 13:28:46 -0400179 // Appends the given numeric literal to the given instruction.
180 // Validates and respects the bitwidth supplied in the IdType argument.
181 // If the type is of class kBottom the value will be encoded as a
182 // 32-bit integer.
183 // Returns SPV_SUCCESS if the value could be correctly added to the
David Neto51013d12015-10-14 11:31:51 -0400184 // instruction. Returns the given error code on failure, and emits
185 // a diagnotic if that error code is not SPV_FAILED_MATCH.
Lei Zhang1a0334e2015-11-02 09:41:20 -0500186 spv_result_t binaryEncodeNumericLiteral(const char* numeric_literal,
David Neto51013d12015-10-14 11:31:51 -0400187 spv_result_t error_code,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500188 const IdType& type,
189 spv_instruction_t* pInst);
David Neto78e677b2015-10-05 13:28:46 -0400190
Andrew Woloszyn537e7762015-09-29 11:28:34 -0400191 // Returns the IdType associated with this type-generating value.
192 // If the type has not been previously recorded with recordTypeDefinition,
David Neto78e677b2015-10-05 13:28:46 -0400193 // kUnknownType will be returned.
Andrew Woloszyn537e7762015-09-29 11:28:34 -0400194 IdType getTypeOfTypeGeneratingValue(uint32_t value) const;
195
196 // Returns the IdType that represents the return value of this Value
197 // generating instruction.
198 // If the value has not been recorded with recordTypeIdForValue, or the type
David Neto78e677b2015-10-05 13:28:46 -0400199 // could not be determined kUnknownType will be returned.
Andrew Woloszyn537e7762015-09-29 11:28:34 -0400200 IdType getTypeOfValueInstruction(uint32_t value) const;
201
202 // Tracks the type-defining instruction. The result of the tracking can
203 // later be queried using getValueType.
204 // pInst is expected to be completely filled in by the time this instruction
205 // is called.
206 // Returns SPV_SUCCESS on success, or SPV_ERROR_INVALID_VALUE on error.
207 spv_result_t recordTypeDefinition(const spv_instruction_t* pInst);
208
209 // Tracks the relationship between the value and its type.
210 spv_result_t recordTypeIdForValue(uint32_t value, uint32_t type);
211
David Neto62741202015-10-13 15:51:12 -0400212 // Parses a numeric value of a given type from the given text. The number
213 // should take up the entire string, and should be within bounds for the
214 // target type. On success, returns SPV_SUCCESS and populates the object
David Neto51013d12015-10-14 11:31:51 -0400215 // referenced by value_pointer. On failure, returns the given error code,
216 // and emits a diagnostic if that error code is not SPV_FAILED_MATCH.
David Neto62741202015-10-13 15:51:12 -0400217 template <typename T>
Lei Zhang1a0334e2015-11-02 09:41:20 -0500218 spv_result_t parseNumber(const char* text, spv_result_t error_code,
219 T* value_pointer,
220 const char* error_message_fragment) {
David Neto62741202015-10-13 15:51:12 -0400221 // C++11 doesn't define std::istringstream(int8_t&), so calling this method
222 // with a single-byte type leads to implementation-defined behaviour.
223 // Similarly for uint8_t.
Lei Zhang1a0334e2015-11-02 09:41:20 -0500224 static_assert(sizeof(T) > 1,
225 "Don't use a single-byte type this parse method");
David Neto62741202015-10-13 15:51:12 -0400226
227 std::istringstream text_stream(text);
228 // Allow both decimal and hex input for integers.
229 // It also allows octal input, but we don't care about that case.
230 text_stream >> std::setbase(0);
231 text_stream >> *value_pointer;
232 bool ok = true;
233
234 // We should have read something.
235 ok = (text[0] != 0) && !text_stream.bad();
236 // It should have been all the text.
237 ok = ok && text_stream.eof();
238 // It should have been in range.
239 ok = ok && !text_stream.fail();
240 // Work around a bug in the GNU C++11 library. It will happily parse
241 // "-1" for uint16_t as 65535.
242 if (ok && !std::is_signed<T>::value && (text[0] == '-') &&
243 *value_pointer != 0) {
244 ok = false;
245 // Match expected error behaviour of std::istringstream::operator>>
246 // on failure to parse.
247 *value_pointer = 0;
248 }
249
250 if (ok) return SPV_SUCCESS;
David Neto51013d12015-10-14 11:31:51 -0400251 return diagnostic(error_code) << error_message_fragment << text;
David Neto62741202015-10-13 15:51:12 -0400252 }
253
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400254 private:
David Neto78e677b2015-10-05 13:28:46 -0400255 // Appends the given floating point literal to the given instruction.
256 // Returns SPV_SUCCESS if the value was correctly parsed. Otherwise
David Neto51013d12015-10-14 11:31:51 -0400257 // returns the given error code, and emits a diagnostic if that error
258 // code is not SPV_FAILED_MATCH.
259 // Only 32 and 64 bit floating point numbers are supported.
Lei Zhang1a0334e2015-11-02 09:41:20 -0500260 spv_result_t binaryEncodeFloatingPointLiteral(const char* numeric_literal,
David Neto51013d12015-10-14 11:31:51 -0400261 spv_result_t error_code,
David Neto78e677b2015-10-05 13:28:46 -0400262 const IdType& type,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500263 spv_instruction_t* pInst);
David Neto78e677b2015-10-05 13:28:46 -0400264
265 // Appends the given integer literal to the given instruction.
266 // Returns SPV_SUCCESS if the value was correctly parsed. Otherwise
David Neto51013d12015-10-14 11:31:51 -0400267 // returns the given error code, and emits a diagnostic if that error
268 // code is not SPV_FAILED_MATCH.
269 // Integers up to 64 bits are supported.
Lei Zhang1a0334e2015-11-02 09:41:20 -0500270 spv_result_t binaryEncodeIntegerLiteral(const char* numeric_literal,
David Neto51013d12015-10-14 11:31:51 -0400271 spv_result_t error_code,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500272 const IdType& type,
273 spv_instruction_t* pInst);
David Neto78e677b2015-10-05 13:28:46 -0400274
275 // Returns SPV_SUCCESS if the given value fits within the target scalar
276 // integral type. The target type may have an unusual bit width.
277 // If the value was originally specified as a hexadecimal number, then
278 // the overflow bits should be zero. If it was hex and the target type is
279 // signed, then return the sign-extended value through the
280 // updated_value_for_hex pointer argument.
David Neto51013d12015-10-14 11:31:51 -0400281 // On failure, return the given error code and emit a diagnostic if that error
282 // code is not SPV_FAILED_MATCH.
David Neto78e677b2015-10-05 13:28:46 -0400283 template <typename T>
Lei Zhang1a0334e2015-11-02 09:41:20 -0500284 spv_result_t checkRangeAndIfHexThenSignExtend(T value,
285 spv_result_t error_code,
286 const IdType& type, bool is_hex,
287 T* updated_value_for_hex);
David Neto78e677b2015-10-05 13:28:46 -0400288
289 // Writes the given 64-bit literal value into the instruction.
290 // return SPV_SUCCESS if the value could be written in the instruction.
Lei Zhang1a0334e2015-11-02 09:41:20 -0500291 spv_result_t binaryEncodeU64(const uint64_t value, spv_instruction_t* pInst);
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400292 // Maps ID names to their corresponding numerical ids.
293 using spv_named_id_table = std::unordered_map<std::string, uint32_t>;
294 // Maps type-defining IDs to their IdType.
295 using spv_id_to_type_map = std::unordered_map<uint32_t, IdType>;
296 // Maps Ids to the id of their type.
297 using spv_id_to_type_id = std::unordered_map<uint32_t, uint32_t>;
298
299 spv_named_id_table named_ids_;
300 spv_id_to_type_map types_;
301 spv_id_to_type_id value_types_;
302 spv_position_t current_position_;
Lei Zhang1a0334e2015-11-02 09:41:20 -0500303 spv_diagnostic* pDiagnostic_;
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400304 spv_text text_;
305 uint32_t bound_;
306};
307}
David Neto9f79d782015-10-27 16:27:05 -0400308#endif // _LIBSPIRV_TEXT_HANDLER_H_