blob: 5ff9f46ec7949519d55f4b63020b793f3db07f68 [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
27#ifndef _LIBSPIRV_UTIL_TEXT_HANDLER_H_
28#define _LIBSPIRV_UTIL_TEXT_HANDLER_H_
29
30#include <libspirv/libspirv.h>
31#include <unordered_map>
32
33#include "diagnostic.h"
David Netob5dc8fc2015-10-06 16:22:00 -040034#include "instruction.h"
Andrew Woloszyn71fc0552015-09-24 10:26:51 -040035#include "operand.h"
36
37namespace libspirv {
38// Structures
39
Andrew Woloszyn71fc0552015-09-24 10:26:51 -040040// This is a lattice for tracking types.
41enum class IdTypeClass {
42 kBottom, // We have no information yet.
43 kScalarIntegerType,
44 kScalarFloatType,
45 kOtherType
46};
47
48
49// Contains ID type information that needs to be tracked across all Ids.
50// Bitwidth is only valid when type_class is kScalarIntegerType or
51// kScalarFloatType.
52struct IdType {
53 uint32_t bitwidth; // Safe to assume that we will not have > 2^32 bits.
54 IdTypeClass type_class;
55};
56
Andrew Woloszyn537e7762015-09-29 11:28:34 -040057// Returns true if the type is a scalar integer type.
58inline bool isScalarIntegral(const IdType& type) {
59 return type.type_class == IdTypeClass::kScalarIntegerType;
60}
61
62// Returns true if the type is a scalar floating point type.
63inline bool isScalarFloating(const IdType& type) {
64 return type.type_class == IdTypeClass::kScalarFloatType;
65}
66
Andrew Woloszyn71fc0552015-09-24 10:26:51 -040067// Encapsulates the grammar to use for SPIR-V assembly.
68// Contains methods to query for valid instructions and operands.
69class AssemblyGrammar {
70 public:
71 AssemblyGrammar(const spv_operand_table operand_table,
72 const spv_opcode_table opcode_table,
73 const spv_ext_inst_table ext_inst_table)
74 : operandTable_(operand_table),
75 opcodeTable_(opcode_table),
76 extInstTable_(ext_inst_table) {}
77
78 // Returns true if the compilation_data has been initialized with valid data.
79 bool isValid() const;
80
81 // Fills in the desc parameter with the information about the opcode
82 // of the given name. Returns SPV_SUCCESS if the opcode was found, and
83 // SPV_ERROR_INVALID_LOOKUP if the opcode does not exist.
84 spv_result_t lookupOpcode(const char *name, spv_opcode_desc *desc) const;
85
Andrew Woloszyn537e7762015-09-29 11:28:34 -040086 // Fills in the desc parameter with the information about the opcode
87 // of the valid. Returns SPV_SUCCESS if the opcode was found, and
88 // SPV_ERROR_INVALID_LOOKUP if the opcode does not exist.
89 spv_result_t lookupOpcode(Op opcode, spv_opcode_desc *desc) const;
90
Andrew Woloszyn71fc0552015-09-24 10:26:51 -040091 // Fills in the desc parameter with the information about the given
92 // operand. Returns SPV_SUCCESS if the operand was found, and
93 // SPV_ERROR_INVALID_LOOKUP otherwise.
94 spv_result_t lookupOperand(spv_operand_type_t type, const char *name,
95 size_t name_len, spv_operand_desc *desc) const;
96
97 // Parses a mask expression string for the given operand type.
98 //
99 // A mask expression is a sequence of one or more terms separated by '|',
100 // where each term is a named enum value for a given type. No whitespace
101 // is permitted.
102 //
103 // On success, the value is written to pValue, and SPV_SUCCESS is returend.
104 // The operand type is defined by the type parameter, and the text to be
105 // parsed is defined by the textValue parameter.
106 spv_result_t parseMaskOperand(const spv_operand_type_t type,
107 const char *textValue, uint32_t *pValue) const;
108
109
110 // Writes the extended operand with the given type and text to the *extInst
111 // parameter.
112 // Returns SPV_SUCCESS if the value could be found.
113 spv_result_t lookupExtInst(spv_ext_inst_type_t type, const char *textValue,
114 spv_ext_inst_desc *extInst) const;
115
116 // Inserts the operands expected after the given typed mask onto the front
117 // of the given pattern.
118 //
119 // Each set bit in the mask represents zero or more operand types that should
120 // be prepended onto the pattern. Opearnds for a less significant bit always
121 // appear before operands for a more significatn bit.
122 //
123 // If a set bit is unknown, then we assume it has no operands.
124 void prependOperandTypesForMask(const spv_operand_type_t type,
125 const uint32_t mask,
126 spv_operand_pattern_t *pattern) const;
127
128 private:
129 const spv_operand_table operandTable_;
130 const spv_opcode_table opcodeTable_;
131 const spv_ext_inst_table extInstTable_;
132};
133
134// Encapsulates the data used during the assembly of a SPIR-V module.
135class AssemblyContext {
136 public:
137 AssemblyContext(spv_text text, spv_diagnostic *diagnostic)
138 : current_position_({}),
139 pDiagnostic_(diagnostic),
140 text_(text),
141 bound_(1) {}
142
143 // Assigns a new integer value to the given text ID, or returns the previously
144 // assigned integer value if the ID has been seen before.
145 uint32_t spvNamedIdAssignOrGet(const char *textValue);
146
147 // Returns the largest largest numeric ID that has been assigned.
148 uint32_t getBound() const;
149
150 // Advances position to point to the next word in the input stream.
151 // Returns SPV_SUCCESS on success.
152 spv_result_t advance();
153
154 // Sets word to the next word in the input text. Fills endPosition with
155 // the next location past the end of the word.
156 spv_result_t getWord(std::string &word, spv_position endPosition);
157
158 // Returns the next word in the input stream. It is invalid to call this
159 // method if position has been set to a location in the stream that does not
160 // exist. If there are no subsequent words, the empty string will be returend.
161 std::string getWord() const;
162
163 // Returns true if the next word in the input is the start of a new Opcode.
164 bool startsWithOp();
165
166 // Returns true if the next word in the input is the start of a new
167 // instruction.
168 bool isStartOfNewInst();
169
170 // Returns a diagnostic object initialized with current position in the input
David Netoac508b02015-10-09 15:48:09 -0400171 // stream, and for the given error code. Any data written to this object will
172 // show up in pDiagnsotic on destruction.
173 DiagnosticStream diagnostic(spv_result_t error) {
174 return DiagnosticStream(&current_position_, pDiagnostic_, error);
175 }
176
177 // Returns a diagnostic object with the default assembly error code.
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400178 DiagnosticStream diagnostic() {
David Netoac508b02015-10-09 15:48:09 -0400179 // The default failure for assembly is invalid text.
180 return diagnostic(SPV_ERROR_INVALID_TEXT);
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400181 }
182
183 // Returns then next characted in the input stream.
184 char peek() const;
185
186 // Returns true if there is more text in the input stream.
187 bool hasText() const;
188
189 // Seeks the input stream forward by 'size' characters.
190 void seekForward(uint32_t size);
191
192 // Sets the current position in the input stream to the given position.
193 void setPosition(const spv_position_t &newPosition) {
194 current_position_ = newPosition;
195 }
196
197 // Returns the current position in the input stream.
198 const spv_position_t &position() const { return current_position_; }
199
200 // Appends the given 32-bit value to the given instruction.
201 // Returns SPV_SUCCESS if the value could be correctly inserted in the the
202 // instruction.
203 spv_result_t binaryEncodeU32(const uint32_t value, spv_instruction_t *pInst);
204 // Appends the given 64-bit value to the given instruction.
205 // Returns SPV_SUCCESS if the value could be correctly inserted in the the
206 // instruction.
207 spv_result_t binaryEncodeU64(const uint64_t value, spv_instruction_t *pInst);
208 // Appends the given string to the given instruction.
209 // Returns SPV_SUCCESS if the value could be correctly inserted in the the
210 // instruction.
211 spv_result_t binaryEncodeString(const char *value, spv_instruction_t *pInst);
212
Andrew Woloszyn537e7762015-09-29 11:28:34 -0400213 // Returns the IdType associated with this type-generating value.
214 // If the type has not been previously recorded with recordTypeDefinition,
215 // { 0, IdTypeClass::kBottom } will be returned.
216 IdType getTypeOfTypeGeneratingValue(uint32_t value) const;
217
218 // Returns the IdType that represents the return value of this Value
219 // generating instruction.
220 // If the value has not been recorded with recordTypeIdForValue, or the type
221 // could not be determined { 0, IdTypeClass::kBottom } will be returned.
222 IdType getTypeOfValueInstruction(uint32_t value) const;
223
224 // Tracks the type-defining instruction. The result of the tracking can
225 // later be queried using getValueType.
226 // pInst is expected to be completely filled in by the time this instruction
227 // is called.
228 // Returns SPV_SUCCESS on success, or SPV_ERROR_INVALID_VALUE on error.
229 spv_result_t recordTypeDefinition(const spv_instruction_t* pInst);
230
231 // Tracks the relationship between the value and its type.
232 spv_result_t recordTypeIdForValue(uint32_t value, uint32_t type);
233
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400234 private:
235 // Maps ID names to their corresponding numerical ids.
236 using spv_named_id_table = std::unordered_map<std::string, uint32_t>;
237 // Maps type-defining IDs to their IdType.
238 using spv_id_to_type_map = std::unordered_map<uint32_t, IdType>;
239 // Maps Ids to the id of their type.
240 using spv_id_to_type_id = std::unordered_map<uint32_t, uint32_t>;
241
242 spv_named_id_table named_ids_;
243 spv_id_to_type_map types_;
244 spv_id_to_type_id value_types_;
245 spv_position_t current_position_;
246 spv_diagnostic *pDiagnostic_;
247 spv_text text_;
248 uint32_t bound_;
249};
250}
251#endif // _LIBSPIRV_UTIL_TEXT_HANDLER_H_
252