blob: 2c42c920d7b55ec6549cb4e2be4d5989d68e433b [file] [log] [blame]
Dejan Mircevskib6fe02f2016-01-07 13:44:22 -05001// Copyright (c) 2015-2016 The Khronos Group Inc.
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +01002//
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
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +010027#include "binary.h"
David Netofcc7d582015-10-27 15:31:10 -040028
David Neto7bff3eb2015-11-20 14:21:10 -050029#include <algorithm>
David Netofcc7d582015-10-27 15:31:10 -040030#include <cassert>
31#include <cstring>
Andrew Woloszyn7ffd8ff2016-01-11 16:22:34 -050032#include <iterator>
David Neto0ca6b592015-10-30 16:06:15 -040033#include <limits>
David Netofcc7d582015-10-27 15:31:10 -040034#include <unordered_map>
35
David Netofcc7d582015-10-27 15:31:10 -040036#include "assembly_grammar.h"
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +010037#include "diagnostic.h"
38#include "ext_inst.h"
39#include "opcode.h"
40#include "operand.h"
David Neto5a703352016-02-17 14:44:00 -050041#include "spirv-tools/libspirv.h"
Lei Zhangaa056cd2015-11-11 14:24:04 -050042#include "spirv_constant.h"
David Neto4c215712015-12-22 15:08:41 -050043#include "spirv_endian.h"
Andrew Woloszyn157e41b2015-10-16 15:11:00 -040044
Andrew Woloszyn55ecc2e2015-11-11 11:05:07 -050045spv_result_t spvBinaryHeaderGet(const spv_const_binary binary,
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +010046 const spv_endianness_t endian,
Lei Zhang1a0334e2015-11-02 09:41:20 -050047 spv_header_t* pHeader) {
David Neto0ca6b592015-10-30 16:06:15 -040048 if (!binary->code) return SPV_ERROR_INVALID_BINARY;
49 if (binary->wordCount < SPV_INDEX_INSTRUCTION)
50 return SPV_ERROR_INVALID_BINARY;
Lei Zhang40056702015-09-11 14:31:27 -040051 if (!pHeader) return SPV_ERROR_INVALID_POINTER;
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +010052
53 // TODO: Validation checking?
54 pHeader->magic = spvFixWord(binary->code[SPV_INDEX_MAGIC_NUMBER], endian);
55 pHeader->version = spvFixWord(binary->code[SPV_INDEX_VERSION_NUMBER], endian);
56 pHeader->generator =
57 spvFixWord(binary->code[SPV_INDEX_GENERATOR_NUMBER], endian);
58 pHeader->bound = spvFixWord(binary->code[SPV_INDEX_BOUND], endian);
59 pHeader->schema = spvFixWord(binary->code[SPV_INDEX_SCHEMA], endian);
60 pHeader->instructions = &binary->code[SPV_INDEX_INSTRUCTION];
61
62 return SPV_SUCCESS;
63}
64
David Neto78c3b432015-08-27 13:03:52 -040065// TODO(dneto): This API is not powerful enough in the case that the
66// number and type of operands are not known until partway through parsing
67// the operation. This happens when enum operands might have different number
68// of operands, or with extended instructions.
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +010069spv_operand_type_t spvBinaryOperandInfo(const uint32_t word,
70 const uint16_t operandIndex,
71 const spv_opcode_desc opcodeEntry,
72 const spv_operand_table operandTable,
Lei Zhang1a0334e2015-11-02 09:41:20 -050073 spv_operand_desc* pOperandEntry) {
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +010074 spv_operand_type_t type;
David Neto78c3b432015-08-27 13:03:52 -040075 if (operandIndex < opcodeEntry->numTypes) {
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +010076 // NOTE: Do operand table lookup to set operandEntry if successful
David Netoba73a7c2016-01-06 13:08:39 -050077 const int index = operandIndex - 1;
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +010078 type = opcodeEntry->operandTypes[index];
79 spv_operand_desc entry = nullptr;
80 if (!spvOperandTableValueLookup(operandTable, type, word, &entry)) {
81 if (SPV_OPERAND_TYPE_NONE != entry->operandTypes[0]) {
82 *pOperandEntry = entry;
83 }
84 }
85 } else if (*pOperandEntry) {
86 // NOTE: Use specified operand entry operand type for this word
David Netoba73a7c2016-01-06 13:08:39 -050087 const int index = operandIndex - opcodeEntry->numTypes;
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +010088 type = (*pOperandEntry)->operandTypes[index];
Lei Zhangb36e7042015-10-28 13:40:52 -040089 } else if (SpvOpSwitch == opcodeEntry->opcode) {
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +010090 // NOTE: OpSwitch is a special case which expects a list of paired extra
91 // operands
92 assert(0 &&
93 "This case is previously untested, remove this assert and ensure it "
94 "is behaving correctly!");
David Netoba73a7c2016-01-06 13:08:39 -050095 const int lastIndex = opcodeEntry->numTypes - 1;
96 const int index = lastIndex + ((operandIndex - lastIndex) % 2);
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +010097 type = opcodeEntry->operandTypes[index];
98 } else {
99 // NOTE: Default to last operand type in opcode entry
David Netoba73a7c2016-01-06 13:08:39 -0500100 const int index = opcodeEntry->numTypes - 1;
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100101 type = opcodeEntry->operandTypes[index];
102 }
103 return type;
104}
105
David Neto0ca6b592015-10-30 16:06:15 -0400106namespace {
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100107
David Neto0ca6b592015-10-30 16:06:15 -0400108// A SPIR-V binary parser. A parser instance communicates detailed parse
109// results via callbacks.
110class Parser {
111 public:
112 // The user_data value is provided to the callbacks as context.
Lei Zhang972788b2015-11-12 13:48:30 -0500113 Parser(const spv_const_context context, void* user_data,
114 spv_parsed_header_fn_t parsed_header_fn,
David Neto0ca6b592015-10-30 16:06:15 -0400115 spv_parsed_instruction_fn_t parsed_instruction_fn)
Lei Zhang972788b2015-11-12 13:48:30 -0500116 : grammar_(context),
117 user_data_(user_data),
David Neto0ca6b592015-10-30 16:06:15 -0400118 parsed_header_fn_(parsed_header_fn),
119 parsed_instruction_fn_(parsed_instruction_fn) {}
120
121 // Parses the specified binary SPIR-V module, issuing callbacks on a parsed
122 // header and for each parsed instruction. Returns SPV_SUCCESS on success.
123 // Otherwise returns an error code and issues a diagnostic.
124 spv_result_t parse(const uint32_t* words, size_t num_words,
125 spv_diagnostic* diagnostic);
126
127 private:
128 // All remaining methods work on the current module parse state.
129
130 // Like the parse method, but works on the current module parse state.
131 spv_result_t parseModule();
132
133 // Parses an instruction at the current position of the binary. Assumes
134 // the header has been parsed, the endian has been set, and the word index is
135 // still in range. Advances the parsing position past the instruction, and
136 // updates other parsing state for the current module.
137 // On success, returns SPV_SUCCESS and issues the parsed-instruction callback.
138 // On failure, returns an error code and issues a diagnostic.
139 spv_result_t parseInstruction();
140
David Neto7bff3eb2015-11-20 14:21:10 -0500141 // Parses an instruction operand with the given type, for an instruction
142 // starting at inst_offset words into the SPIR-V binary.
143 // If the SPIR-V binary is the same endianness as the host, then the
144 // endian_converted_inst_words parameter is ignored. Otherwise, this method
145 // appends the words for this operand, converted to host native endianness,
146 // to the end of endian_converted_inst_words. This method also updates the
147 // expected_operands parameter, and the scalar members of the inst parameter.
148 // On success, returns SPV_SUCCESS, advances past the operand, and pushes a
149 // new entry on to the operands vector. Otherwise returns an error code and
150 // issues a diagnostic.
151 spv_result_t parseOperand(size_t inst_offset, spv_parsed_instruction_t* inst,
David Neto0ca6b592015-10-30 16:06:15 -0400152 const spv_operand_type_t type,
David Neto7bff3eb2015-11-20 14:21:10 -0500153 std::vector<uint32_t>* endian_converted_inst_words,
David Neto0ca6b592015-10-30 16:06:15 -0400154 std::vector<spv_parsed_operand_t>* operands,
155 spv_operand_pattern_t* expected_operands);
156
157 // Records the numeric type for an operand according to the type information
158 // associated with the given non-zero type Id. This can fail if the type Id
159 // is not a type Id, or if the type Id does not reference a scalar numeric
160 // type. On success, return SPV_SUCCESS and populates the num_words,
161 // number_kind, and number_bit_width fields of parsed_operand.
162 spv_result_t setNumericTypeInfoForType(spv_parsed_operand_t* parsed_operand,
163 uint32_t type_id);
164
David Neto7bff3eb2015-11-20 14:21:10 -0500165 // Records the number type for an instruction at the given offset, if that
166 // instruction generates a type. For types that aren't scalar numbers,
167 // record something with number kind SPV_NUMBER_NONE.
168 void recordNumberType(size_t inst_offset,
169 const spv_parsed_instruction_t* inst);
David Neto0ca6b592015-10-30 16:06:15 -0400170
171 // Returns a diagnostic stream object initialized with current position in
172 // the input stream, and for the given error code. Any data written to the
173 // returned object will be propagated to the current parse's diagnostic
174 // object.
David Neto01656362015-11-20 10:44:41 -0500175 libspirv::DiagnosticStream diagnostic(spv_result_t error) {
David Neto7bff3eb2015-11-20 14:21:10 -0500176 return libspirv::DiagnosticStream({0, 0, _.word_index}, _.diagnostic,
177 error);
David Neto0ca6b592015-10-30 16:06:15 -0400178 }
179
180 // Returns a diagnostic stream object with the default parse error code.
David Neto01656362015-11-20 10:44:41 -0500181 libspirv::DiagnosticStream diagnostic() {
David Neto0ca6b592015-10-30 16:06:15 -0400182 // The default failure for parsing is invalid binary.
183 return diagnostic(SPV_ERROR_INVALID_BINARY);
184 }
185
David Netod9ad0502015-11-24 18:37:24 -0500186 // Issues a diagnostic describing an exhaustion of input condition when
187 // trying to decode an instruction operand, and returns
188 // SPV_ERROR_INVALID_BINARY.
189 spv_result_t exhaustedInputDiagnostic(size_t inst_offset, SpvOp opcode,
190 spv_operand_type_t type) {
191 return diagnostic() << "End of input reached while decoding Op"
192 << spvOpcodeString(opcode) << " starting at word "
193 << inst_offset
194 << ((_.word_index < _.num_words) ? ": truncated "
195 : ": missing ")
196 << spvOperandTypeStr(type) << " operand at word offset "
197 << _.word_index - inst_offset << ".";
198 }
199
David Neto0ca6b592015-10-30 16:06:15 -0400200 // Returns the endian-corrected word at the current position.
201 uint32_t peek() const { return peekAt(_.word_index); }
202
203 // Returns the endian-corrected word at the given position.
204 uint32_t peekAt(size_t index) const {
205 assert(index < _.num_words);
206 return spvFixWord(_.words[index], _.endian);
207 }
208
209 // Data members
210
211 const libspirv::AssemblyGrammar grammar_; // SPIR-V syntax utility.
212 void* const user_data_; // Context for the callbacks
213 const spv_parsed_header_fn_t parsed_header_fn_; // Parsed header callback
214 const spv_parsed_instruction_fn_t
215 parsed_instruction_fn_; // Parsed instruction callback
216
217 // Describes the format of a typed literal number.
218 struct NumberType {
219 spv_number_kind_t type;
220 uint32_t bit_width;
221 };
222
223 // The state used to parse a single SPIR-V binary module.
224 struct State {
225 State(const uint32_t* words_arg, size_t num_words_arg,
226 spv_diagnostic* diagnostic_arg)
227 : words(words_arg),
228 num_words(num_words_arg),
229 diagnostic(diagnostic_arg),
230 word_index(0),
231 endian() {}
232 State() : State(0, 0, nullptr) {}
233 const uint32_t* words; // Words in the binary SPIR-V module.
234 size_t num_words; // Number of words in the module.
235 spv_diagnostic* diagnostic; // Where diagnostics go.
236 size_t word_index; // The current position in words.
237 spv_endianness_t endian; // The endianness of the binary.
David Neto7bff3eb2015-11-20 14:21:10 -0500238 // Is the SPIR-V binary in a different endiannes from the host native
239 // endianness?
240 bool requires_endian_conversion;
David Neto0ca6b592015-10-30 16:06:15 -0400241
242 // Maps a result ID to its type ID. By convention:
243 // - a result ID that is a type definition maps to itself.
244 // - a result ID without a type maps to 0. (E.g. for OpLabel)
245 std::unordered_map<uint32_t, uint32_t> id_to_type_id;
246 // Maps a type ID to its number type description.
247 std::unordered_map<uint32_t, NumberType> type_id_to_number_type_info;
248 // Maps an ExtInstImport id to the extended instruction type.
249 std::unordered_map<uint32_t, spv_ext_inst_type_t>
250 import_id_to_ext_inst_type;
251 } _;
252};
253
254spv_result_t Parser::parse(const uint32_t* words, size_t num_words,
255 spv_diagnostic* diagnostic_arg) {
256 _ = State(words, num_words, diagnostic_arg);
257
258 const spv_result_t result = parseModule();
259
260 // Clear the module state. The tables might be big.
261 _ = State();
262
263 return result;
264}
265
266spv_result_t Parser::parseModule() {
267 if (!_.words) return diagnostic() << "Missing module.";
268
269 if (_.num_words < SPV_INDEX_INSTRUCTION)
270 return diagnostic() << "Module has incomplete header: only " << _.num_words
271 << " words instead of " << SPV_INDEX_INSTRUCTION;
272
273 // Check the magic number and detect the module's endianness.
Andrew Woloszyn55ecc2e2015-11-11 11:05:07 -0500274 spv_const_binary_t binary{_.words, _.num_words};
David Neto0ca6b592015-10-30 16:06:15 -0400275 if (spvBinaryEndianness(&binary, &_.endian)) {
276 return diagnostic() << "Invalid SPIR-V magic number '" << std::hex
277 << _.words[0] << "'.";
278 }
David Neto7bff3eb2015-11-20 14:21:10 -0500279 _.requires_endian_conversion = !spvIsHostEndian(_.endian);
David Neto0ca6b592015-10-30 16:06:15 -0400280
281 // Process the header.
282 spv_header_t header;
283 if (spvBinaryHeaderGet(&binary, _.endian, &header)) {
284 // It turns out there is no way to trigger this error since the only
285 // failure cases are already handled above, with better messages.
286 return diagnostic(SPV_ERROR_INTERNAL)
287 << "Internal error: unhandled header parse failure";
288 }
289 if (parsed_header_fn_) {
290 if (auto error = parsed_header_fn_(user_data_, _.endian, header.magic,
291 header.version, header.generator,
292 header.bound, header.schema)) {
293 return error;
294 }
295 }
296
297 // Process the instructions.
298 _.word_index = SPV_INDEX_INSTRUCTION;
299 while (_.word_index < _.num_words)
300 if (auto error = parseInstruction()) return error;
301
302 // Running off the end should already have been reported earlier.
303 assert(_.word_index == _.num_words);
304
305 return SPV_SUCCESS;
306}
307
308spv_result_t Parser::parseInstruction() {
309 // The zero values for all members except for opcode are the
310 // correct initial values.
311 spv_parsed_instruction_t inst = {};
David Neto7bff3eb2015-11-20 14:21:10 -0500312
313 const uint32_t first_word = peek();
314
315 // TODO(dneto): If it's too expensive to construct the following "words"
316 // and "operands" vectors for each instruction, each instruction, then make
317 // them class data members instead, and clear them here.
318
319 // If the module's endianness is different from the host native endianness,
320 // then converted_words contains the the endian-translated words in the
321 // instruction.
322 std::vector<uint32_t> endian_converted_words = {first_word};
323 if (_.requires_endian_conversion) {
324 // Most instructions have fewer than 25 words.
325 endian_converted_words.reserve(25);
326 }
David Neto0ca6b592015-10-30 16:06:15 -0400327
328 // After a successful parse of the instruction, the inst.operands member
329 // will point to this vector's storage.
David Neto0ca6b592015-10-30 16:06:15 -0400330 std::vector<spv_parsed_operand_t> operands;
331 // Most instructions have fewer than 25 logical operands.
332 operands.reserve(25);
333
334 assert(_.word_index < _.num_words);
335 // Decompose and check the first word.
336 uint16_t inst_word_count = 0;
David Neto7bff3eb2015-11-20 14:21:10 -0500337 spvOpcodeSplit(first_word, &inst_word_count, &inst.opcode);
David Neto0ca6b592015-10-30 16:06:15 -0400338 if (inst_word_count < 1) {
339 return diagnostic() << "Invalid instruction word count: "
340 << inst_word_count;
341 }
342 spv_opcode_desc opcode_desc;
343 if (grammar_.lookupOpcode(inst.opcode, &opcode_desc))
344 return diagnostic() << "Invalid opcode: " << int(inst.opcode);
345
David Neto7bff3eb2015-11-20 14:21:10 -0500346 // Advance past the opcode word. But remember the of the start
347 // of the instruction.
348 const size_t inst_offset = _.word_index;
David Neto0ca6b592015-10-30 16:06:15 -0400349 _.word_index++;
350
351 // Maintains the ordered list of expected operand types.
352 // For many instructions we only need the {numTypes, operandTypes}
353 // entries in opcode_desc. However, sometimes we need to modify
354 // the list as we parse the operands. This occurs when an operand
355 // has its own logical operands (such as the LocalSize operand for
356 // ExecutionMode), or for extended instructions that may have their
357 // own operands depending on the selected extended instruction.
358 spv_operand_pattern_t expected_operands(
359 opcode_desc->operandTypes,
360 opcode_desc->operandTypes + opcode_desc->numTypes);
361
David Neto7bff3eb2015-11-20 14:21:10 -0500362 while (_.word_index < inst_offset + inst_word_count) {
363 const uint16_t inst_word_index = uint16_t(_.word_index - inst_offset);
David Neto0ca6b592015-10-30 16:06:15 -0400364 if (expected_operands.empty()) {
365 return diagnostic() << "Invalid instruction Op" << opcode_desc->name
David Neto7bff3eb2015-11-20 14:21:10 -0500366 << " starting at word " << inst_offset
David Neto0ca6b592015-10-30 16:06:15 -0400367 << ": expected no more operands after "
368 << inst_word_index
369 << " words, but stated word count is "
370 << inst_word_count << ".";
371 }
372
373 spv_operand_type_t type = spvTakeFirstMatchableOperand(&expected_operands);
374
David Neto7bff3eb2015-11-20 14:21:10 -0500375 if (auto error =
376 parseOperand(inst_offset, &inst, type, &endian_converted_words,
David Netod9ad0502015-11-24 18:37:24 -0500377 &operands, &expected_operands)) {
David Neto0ca6b592015-10-30 16:06:15 -0400378 return error;
David Netod9ad0502015-11-24 18:37:24 -0500379 }
David Neto0ca6b592015-10-30 16:06:15 -0400380 }
381
382 if (!expected_operands.empty() &&
383 !spvOperandIsOptional(expected_operands.front())) {
384 return diagnostic() << "End of input reached while decoding Op"
385 << opcode_desc->name << " starting at word "
David Neto7bff3eb2015-11-20 14:21:10 -0500386 << inst_offset << ": expected more operands after "
David Neto0ca6b592015-10-30 16:06:15 -0400387 << inst_word_count << " words.";
388 }
389
David Neto7bff3eb2015-11-20 14:21:10 -0500390 if ((inst_offset + inst_word_count) != _.word_index) {
David Netod9ad0502015-11-24 18:37:24 -0500391 return diagnostic() << "Invalid word count: Op" << opcode_desc->name
392 << " starting at word " << inst_offset
393 << " says it has " << inst_word_count
David Neto7bff3eb2015-11-20 14:21:10 -0500394 << " words, but found " << _.word_index - inst_offset
David Neto0ca6b592015-10-30 16:06:15 -0400395 << " words instead.";
396 }
David Neto15afbf92015-11-23 14:17:35 -0500397
398 // Check the computed length of the endian-converted words vector against
399 // the declared number of words in the instruction. If endian conversion
400 // is required, then they should match. If no endian conversion was
401 // performed, then the vector only contains the initial opcode/word-count
402 // word.
403 assert(!_.requires_endian_conversion ||
404 (inst_word_count == endian_converted_words.size()));
405 assert(_.requires_endian_conversion || (endian_converted_words.size() == 1));
David Neto0ca6b592015-10-30 16:06:15 -0400406
David Neto7bff3eb2015-11-20 14:21:10 -0500407 recordNumberType(inst_offset, &inst);
David Neto0ca6b592015-10-30 16:06:15 -0400408
David Neto7bff3eb2015-11-20 14:21:10 -0500409 if (_.requires_endian_conversion) {
410 // We must wait until here to set this pointer, because the vector might
411 // have been be resized while we accumulated its elements.
412 inst.words = endian_converted_words.data();
413 } else {
414 // If no conversion is required, then just point to the underlying binary.
415 // This saves time and space.
416 inst.words = _.words + inst_offset;
417 }
418 inst.num_words = inst_word_count;
419
420 // We must wait until here to set this pointer, because the vector might
421 // have been be resized while we accumulated its elements.
David Neto0ca6b592015-10-30 16:06:15 -0400422 inst.operands = operands.data();
Andrew Woloszyn3a4bc7e2015-11-19 09:22:53 -0500423 inst.num_operands = uint16_t(operands.size());
David Neto0ca6b592015-10-30 16:06:15 -0400424
425 // Issue the callback. The callee should know that all the storage in inst
426 // is transient, and will disappear immediately afterward.
427 if (parsed_instruction_fn_) {
428 if (auto error = parsed_instruction_fn_(user_data_, &inst)) return error;
429 }
430
431 return SPV_SUCCESS;
432}
433
David Neto7bff3eb2015-11-20 14:21:10 -0500434spv_result_t Parser::parseOperand(size_t inst_offset,
435 spv_parsed_instruction_t* inst,
David Neto0ca6b592015-10-30 16:06:15 -0400436 const spv_operand_type_t type,
David Neto7bff3eb2015-11-20 14:21:10 -0500437 std::vector<uint32_t>* words,
David Neto0ca6b592015-10-30 16:06:15 -0400438 std::vector<spv_parsed_operand_t>* operands,
439 spv_operand_pattern_t* expected_operands) {
440 // We'll fill in this result as we go along.
441 spv_parsed_operand_t parsed_operand;
David Neto7bff3eb2015-11-20 14:21:10 -0500442 parsed_operand.offset = uint16_t(_.word_index - inst_offset);
David Neto0ca6b592015-10-30 16:06:15 -0400443 // Most operands occupy one word. This might be be adjusted later.
444 parsed_operand.num_words = 1;
445 // The type argument is the one used by the grammar to parse the instruction.
446 // But it can exposes internal parser details such as whether an operand is
447 // optional or actually represents a variable-length sequence of operands.
448 // The resulting type should be adjusted to avoid those internal details.
449 // In most cases, the resulting operand type is the same as the grammar type.
450 parsed_operand.type = type;
451
452 // Assume non-numeric values. This will be updated for literal numbers.
453 parsed_operand.number_kind = SPV_NUMBER_NONE;
454 parsed_operand.number_bit_width = 0;
455
David Netod9ad0502015-11-24 18:37:24 -0500456 if (_.word_index >= _.num_words)
457 return exhaustedInputDiagnostic(inst_offset, inst->opcode, type);
458
David Neto0ca6b592015-10-30 16:06:15 -0400459 const uint32_t word = peek();
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100460
David Neto7bff3eb2015-11-20 14:21:10 -0500461 // Do the words in this operand have to be converted to native endianness?
462 // True for all but literal strings.
463 bool convert_operand_endianness = true;
464
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100465 switch (type) {
Andrew Woloszyn537e7762015-09-29 11:28:34 -0400466 case SPV_OPERAND_TYPE_TYPE_ID:
David Neto677e0c72016-01-05 14:56:02 -0500467 if (!word)
468 return diagnostic(SPV_ERROR_INVALID_ID) << "Error: Type Id is 0";
David Neto0ca6b592015-10-30 16:06:15 -0400469 inst->type_id = word;
470 break;
471
472 case SPV_OPERAND_TYPE_RESULT_ID:
David Neto677e0c72016-01-05 14:56:02 -0500473 if (!word)
474 return diagnostic(SPV_ERROR_INVALID_ID) << "Error: Result Id is 0";
David Neto0ca6b592015-10-30 16:06:15 -0400475 inst->result_id = word;
476 // Save the result ID to type ID mapping.
477 // In the grammar, type ID always appears before result ID.
478 if (_.id_to_type_id.find(inst->result_id) != _.id_to_type_id.end())
Umar Arshadf76e0f52015-11-18 15:43:43 -0500479 return diagnostic(SPV_ERROR_INVALID_ID) << "Id " << inst->result_id
David Neto677e0c72016-01-05 14:56:02 -0500480 << " is defined more than once";
David Neto0ca6b592015-10-30 16:06:15 -0400481 // Record it.
482 // A regular value maps to its type. Some instructions (e.g. OpLabel)
483 // have no type Id, and will map to 0. The result Id for a
484 // type-generating instruction (e.g. OpTypeInt) maps to itself.
485 _.id_to_type_id[inst->result_id] = spvOpcodeGeneratesType(inst->opcode)
486 ? inst->result_id
487 : inst->type_id;
488 break;
489
490 case SPV_OPERAND_TYPE_ID:
David Neto78c3b432015-08-27 13:03:52 -0400491 case SPV_OPERAND_TYPE_OPTIONAL_ID:
Umar Arshadf76e0f52015-11-18 15:43:43 -0500492 if (!word) return diagnostic(SPV_ERROR_INVALID_ID) << "Id is 0";
David Neto0ca6b592015-10-30 16:06:15 -0400493 parsed_operand.type = SPV_OPERAND_TYPE_ID;
494
495 if (inst->opcode == SpvOpExtInst && parsed_operand.offset == 3) {
496 // The current word is the extended instruction set Id.
497 // Set the extended instruction set type for the current instruction.
498 auto ext_inst_type_iter = _.import_id_to_ext_inst_type.find(word);
499 if (ext_inst_type_iter == _.import_id_to_ext_inst_type.end()) {
Umar Arshadf76e0f52015-11-18 15:43:43 -0500500 return diagnostic(SPV_ERROR_INVALID_ID)
David Neto0ca6b592015-10-30 16:06:15 -0400501 << "OpExtInst set Id " << word
502 << " does not reference an OpExtInstImport result Id";
503 }
504 inst->ext_inst_type = ext_inst_type_iter->second;
505 }
506 break;
507
David Neto64a9be92015-11-18 15:48:32 -0500508 case SPV_OPERAND_TYPE_SCOPE_ID:
509 case SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID:
David Netod9ad0502015-11-24 18:37:24 -0500510 // Check for trivially invalid values. The operand descriptions already
511 // have the word "ID" in them.
512 if (!word) return diagnostic() << spvOperandTypeStr(type) << " is 0";
David Neto0ca6b592015-10-30 16:06:15 -0400513 break;
514
David Neto445ce442015-10-15 15:22:06 -0400515 case SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER: {
David Neto0ca6b592015-10-30 16:06:15 -0400516 assert(SpvOpExtInst == inst->opcode);
517 assert(inst->ext_inst_type != SPV_EXT_INST_TYPE_NONE);
518 spv_ext_inst_desc ext_inst;
519 if (grammar_.lookupExtInst(inst->ext_inst_type, word, &ext_inst))
520 return diagnostic() << "Invalid extended instruction number: " << word;
521 spvPrependOperandTypes(ext_inst->operandTypes, expected_operands);
David Neto445ce442015-10-15 15:22:06 -0400522 } break;
David Neto0ca6b592015-10-30 16:06:15 -0400523
David Neto21196942015-11-11 02:45:45 -0500524 case SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER: {
525 assert(SpvOpSpecConstantOp == inst->opcode);
526 if (grammar_.lookupSpecConstantOpcode(SpvOp(word))) {
527 return diagnostic() << "Invalid " << spvOperandTypeStr(type) << ": "
528 << word;
529 }
530 spv_opcode_desc opcode_entry = nullptr;
531 if (grammar_.lookupOpcode(SpvOp(word), &opcode_entry)) {
532 return diagnostic(SPV_ERROR_INTERNAL)
533 << "OpSpecConstant opcode table out of sync";
534 }
535 // OpSpecConstant opcodes must have a type and result. We've already
536 // processed them, so skip them when preparing to parse the other
537 // operants for the opcode.
538 assert(opcode_entry->hasType);
539 assert(opcode_entry->hasResult);
540 assert(opcode_entry->numTypes >= 2);
541 spvPrependOperandTypes(opcode_entry->operandTypes + 2, expected_operands);
542 } break;
543
David Neto445ce442015-10-15 15:22:06 -0400544 case SPV_OPERAND_TYPE_LITERAL_INTEGER:
Lei Zhang6483bd72015-10-14 17:02:39 -0400545 case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_INTEGER:
David Neto201caf72015-11-04 17:38:17 -0500546 // These are regular single-word literal integer operands.
547 // Post-parsing validation should check the range of the parsed value.
David Neto0ca6b592015-10-30 16:06:15 -0400548 parsed_operand.type = SPV_OPERAND_TYPE_LITERAL_INTEGER;
David Neto201caf72015-11-04 17:38:17 -0500549 // It turns out they are always unsigned integers!
550 parsed_operand.number_kind = SPV_NUMBER_UNSIGNED_INT;
551 parsed_operand.number_bit_width = 32;
552 break;
553
554 case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER:
555 case SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER:
Lei Zhangaa3cd5a2015-11-10 14:29:35 -0500556 parsed_operand.type = SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER;
David Neto0ca6b592015-10-30 16:06:15 -0400557 if (inst->opcode == SpvOpSwitch) {
558 // The literal operands have the same type as the value
559 // referenced by the selector Id.
David Neto7bff3eb2015-11-20 14:21:10 -0500560 const uint32_t selector_id = peekAt(inst_offset + 1);
David Neto3664bd52015-12-23 13:21:43 -0500561 const auto type_id_iter = _.id_to_type_id.find(selector_id);
562 if (type_id_iter == _.id_to_type_id.end() ||
563 type_id_iter->second == 0) {
David Neto0ca6b592015-10-30 16:06:15 -0400564 return diagnostic() << "Invalid OpSwitch: selector id " << selector_id
565 << " has no type";
566 }
567 uint32_t type_id = type_id_iter->second;
568
569 if (selector_id == type_id) {
570 // Recall that by convention, a result ID that is a type definition
571 // maps to itself.
572 return diagnostic() << "Invalid OpSwitch: selector id " << selector_id
573 << " is a type, not a value";
574 }
575 if (auto error = setNumericTypeInfoForType(&parsed_operand, type_id))
576 return error;
577 if (parsed_operand.number_kind != SPV_NUMBER_UNSIGNED_INT &&
578 parsed_operand.number_kind != SPV_NUMBER_SIGNED_INT) {
579 return diagnostic() << "Invalid OpSwitch: selector id " << selector_id
580 << " is not a scalar integer";
581 }
Lei Zhangb41d1502015-09-14 15:22:23 -0400582 } else {
David Neto201caf72015-11-04 17:38:17 -0500583 assert(inst->opcode == SpvOpConstant ||
584 inst->opcode == SpvOpSpecConstant);
585 // The literal number type is determined by the type Id for the
586 // constant.
587 assert(inst->type_id);
588 if (auto error =
589 setNumericTypeInfoForType(&parsed_operand, inst->type_id))
590 return error;
Lei Zhangb41d1502015-09-14 15:22:23 -0400591 }
David Neto0ca6b592015-10-30 16:06:15 -0400592 break;
593
David Neto78c3b432015-08-27 13:03:52 -0400594 case SPV_OPERAND_TYPE_LITERAL_STRING:
595 case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_STRING: {
David Neto7bff3eb2015-11-20 14:21:10 -0500596 convert_operand_endianness = false;
David Neto0ca6b592015-10-30 16:06:15 -0400597 const char* string =
598 reinterpret_cast<const char*>(_.words + _.word_index);
David Netod9ad0502015-11-24 18:37:24 -0500599 // Compute the length of the string, but make sure we don't run off the
600 // end of the input.
601 const size_t remaining_input_bytes =
602 sizeof(uint32_t) * (_.num_words - _.word_index);
603 const size_t string_num_content_bytes =
604 strnlen(string, remaining_input_bytes);
605 // If there was no terminating null byte, then that's an end-of-input
606 // error.
607 if (string_num_content_bytes == remaining_input_bytes)
608 return exhaustedInputDiagnostic(inst_offset, inst->opcode, type);
609 // Account for null in the word length, so add 1 for null, then add 3 to
610 // make sure we round up. The following is equivalent to:
611 // (string_num_content_bytes + 1 + 3) / 4
612 const size_t string_num_words = string_num_content_bytes / 4 + 1;
David Neto0ca6b592015-10-30 16:06:15 -0400613 // Make sure we can record the word count without overflow.
David Netod9ad0502015-11-24 18:37:24 -0500614 //
615 // This error can't currently be triggered because of validity
616 // checks elsewhere.
David Neto0ca6b592015-10-30 16:06:15 -0400617 if (string_num_words > std::numeric_limits<uint16_t>::max()) {
618 return diagnostic() << "Literal string is longer than "
619 << std::numeric_limits<uint16_t>::max()
620 << " words: " << string_num_words << " words long";
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100621 }
Andrew Woloszyn3a4bc7e2015-11-19 09:22:53 -0500622 parsed_operand.num_words = uint16_t(string_num_words);
David Neto0ca6b592015-10-30 16:06:15 -0400623 parsed_operand.type = SPV_OPERAND_TYPE_LITERAL_STRING;
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100624
David Neto0ca6b592015-10-30 16:06:15 -0400625 if (SpvOpExtInstImport == inst->opcode) {
626 // Record the extended instruction type for the ID for this import.
627 // There is only one string literal argument to OpExtInstImport,
628 // so it's sufficient to guard this just on the opcode.
629 const spv_ext_inst_type_t ext_inst_type =
630 spvExtInstImportTypeGet(string);
631 if (SPV_EXT_INST_TYPE_NONE == ext_inst_type) {
632 return diagnostic() << "Invalid extended instruction import '"
633 << string << "'";
Andrew Woloszyne59e6b72015-10-14 14:18:43 -0400634 }
David Neto0ca6b592015-10-30 16:06:15 -0400635 // We must have parsed a valid result ID. It's a condition
636 // of the grammar, and we only accept non-zero result Ids.
637 assert(inst->result_id);
638 _.import_id_to_ext_inst_type[inst->result_id] = ext_inst_type;
Andrew Woloszyne59e6b72015-10-14 14:18:43 -0400639 }
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100640 } break;
David Neto0ca6b592015-10-30 16:06:15 -0400641
642 case SPV_OPERAND_TYPE_OPTIONAL_EXECUTION_MODE:
643 parsed_operand.type = SPV_OPERAND_TYPE_EXECUTION_MODE;
644 // Fall through
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100645 case SPV_OPERAND_TYPE_CAPABILITY:
646 case SPV_OPERAND_TYPE_SOURCE_LANGUAGE:
647 case SPV_OPERAND_TYPE_EXECUTION_MODEL:
648 case SPV_OPERAND_TYPE_ADDRESSING_MODEL:
649 case SPV_OPERAND_TYPE_MEMORY_MODEL:
650 case SPV_OPERAND_TYPE_EXECUTION_MODE:
651 case SPV_OPERAND_TYPE_STORAGE_CLASS:
652 case SPV_OPERAND_TYPE_DIMENSIONALITY:
653 case SPV_OPERAND_TYPE_SAMPLER_ADDRESSING_MODE:
654 case SPV_OPERAND_TYPE_SAMPLER_FILTER_MODE:
David Netod9ad0502015-11-24 18:37:24 -0500655 case SPV_OPERAND_TYPE_SAMPLER_IMAGE_FORMAT:
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100656 case SPV_OPERAND_TYPE_FP_ROUNDING_MODE:
657 case SPV_OPERAND_TYPE_LINKAGE_TYPE:
658 case SPV_OPERAND_TYPE_ACCESS_QUALIFIER:
David Neto2889a0c2016-02-15 13:50:00 -0500659 case SPV_OPERAND_TYPE_OPTIONAL_ACCESS_QUALIFIER:
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100660 case SPV_OPERAND_TYPE_FUNCTION_PARAMETER_ATTRIBUTE:
661 case SPV_OPERAND_TYPE_DECORATION:
662 case SPV_OPERAND_TYPE_BUILT_IN:
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100663 case SPV_OPERAND_TYPE_GROUP_OPERATION:
664 case SPV_OPERAND_TYPE_KERNEL_ENQ_FLAGS:
David Neto47994822015-08-27 13:11:01 -0400665 case SPV_OPERAND_TYPE_KERNEL_PROFILING_INFO: {
David Neto0ca6b592015-10-30 16:06:15 -0400666 // A single word that is a plain enum value.
David Neto2889a0c2016-02-15 13:50:00 -0500667
668 // Map an optional operand type to its corresponding concrete type.
669 if (type == SPV_OPERAND_TYPE_OPTIONAL_ACCESS_QUALIFIER)
670 parsed_operand.type = SPV_OPERAND_TYPE_ACCESS_QUALIFIER;
671
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100672 spv_operand_desc entry;
David Neto0ca6b592015-10-30 16:06:15 -0400673 if (grammar_.lookupOperand(type, word, &entry)) {
David Neto201caf72015-11-04 17:38:17 -0500674 return diagnostic() << "Invalid "
675 << spvOperandTypeStr(parsed_operand.type)
David Neto0ca6b592015-10-30 16:06:15 -0400676 << " operand: " << word;
Lei Zhang40056702015-09-11 14:31:27 -0400677 }
David Neto78c3b432015-08-27 13:03:52 -0400678 // Prepare to accept operands to this operand, if needed.
David Neto0ca6b592015-10-30 16:06:15 -0400679 spvPrependOperandTypes(entry->operandTypes, expected_operands);
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100680 } break;
David Neto0ca6b592015-10-30 16:06:15 -0400681
David Neto619db262015-09-25 12:43:37 -0400682 case SPV_OPERAND_TYPE_FP_FAST_MATH_MODE:
683 case SPV_OPERAND_TYPE_FUNCTION_CONTROL:
684 case SPV_OPERAND_TYPE_LOOP_CONTROL:
David Neto2889a0c2016-02-15 13:50:00 -0500685 case SPV_OPERAND_TYPE_IMAGE:
David Neto619db262015-09-25 12:43:37 -0400686 case SPV_OPERAND_TYPE_OPTIONAL_IMAGE:
687 case SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS:
688 case SPV_OPERAND_TYPE_SELECTION_CONTROL: {
689 // This operand is a mask.
David Neto201caf72015-11-04 17:38:17 -0500690
691 // Map an optional operand type to its corresponding concrete type.
692 if (type == SPV_OPERAND_TYPE_OPTIONAL_IMAGE)
693 parsed_operand.type = SPV_OPERAND_TYPE_IMAGE;
694 else if (type == SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS)
695 parsed_operand.type = SPV_OPERAND_TYPE_MEMORY_ACCESS;
696
David Neto0ca6b592015-10-30 16:06:15 -0400697 // Check validity of set mask bits. Also prepare for operands for those
698 // masks if they have any. To get operand order correct, scan from
699 // MSB to LSB since we can only prepend operands to a pattern.
700 // The only case in the grammar where you have more than one mask bit
701 // having an operand is for image operands. See SPIR-V 3.14 Image
702 // Operands.
703 uint32_t remaining_word = word;
704 for (uint32_t mask = (1u << 31); remaining_word; mask >>= 1) {
David Neto619db262015-09-25 12:43:37 -0400705 if (remaining_word & mask) {
David Neto619db262015-09-25 12:43:37 -0400706 spv_operand_desc entry;
David Neto0ca6b592015-10-30 16:06:15 -0400707 if (grammar_.lookupOperand(type, mask, &entry)) {
David Neto201caf72015-11-04 17:38:17 -0500708 return diagnostic()
709 << "Invalid " << spvOperandTypeStr(parsed_operand.type)
710 << " operand: " << word << " has invalid mask component "
711 << mask;
David Neto619db262015-09-25 12:43:37 -0400712 }
David Neto0ca6b592015-10-30 16:06:15 -0400713 remaining_word ^= mask;
714 spvPrependOperandTypes(entry->operandTypes, expected_operands);
David Neto619db262015-09-25 12:43:37 -0400715 }
716 }
David Neto0ca6b592015-10-30 16:06:15 -0400717 if (word == 0) {
718 // An all-zeroes mask *might* also be valid.
David Neto619db262015-09-25 12:43:37 -0400719 spv_operand_desc entry;
David Neto0ca6b592015-10-30 16:06:15 -0400720 if (SPV_SUCCESS == grammar_.lookupOperand(type, 0, &entry)) {
David Neto619db262015-09-25 12:43:37 -0400721 // Prepare for its operands, if any.
David Neto0ca6b592015-10-30 16:06:15 -0400722 spvPrependOperandTypes(entry->operandTypes, expected_operands);
David Neto619db262015-09-25 12:43:37 -0400723 }
724 }
David Neto619db262015-09-25 12:43:37 -0400725 } break;
David Neto0ca6b592015-10-30 16:06:15 -0400726 default:
727 return diagnostic() << "Internal error: Unhandled operand type: " << type;
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100728 }
729
David Neto0ca6b592015-10-30 16:06:15 -0400730 assert(int(SPV_OPERAND_TYPE_FIRST_CONCRETE_TYPE) <= int(parsed_operand.type));
731 assert(int(SPV_OPERAND_TYPE_LAST_CONCRETE_TYPE) >= int(parsed_operand.type));
732
733 operands->push_back(parsed_operand);
734
David Neto7bff3eb2015-11-20 14:21:10 -0500735 const size_t index_after_operand = _.word_index + parsed_operand.num_words;
David Netod9ad0502015-11-24 18:37:24 -0500736
737 // Avoid buffer overrun for the cases where the operand has more than one
738 // word, and where it isn't a string. (Those other cases have already been
739 // handled earlier.) For example, this error can occur for a multi-word
740 // argument to OpConstant, or a multi-word case literal operand for OpSwitch.
741 if (_.num_words < index_after_operand)
742 return exhaustedInputDiagnostic(inst_offset, inst->opcode, type);
743
David Neto7bff3eb2015-11-20 14:21:10 -0500744 if (_.requires_endian_conversion) {
745 // Copy instruction words. Translate to native endianness as needed.
746 if (convert_operand_endianness) {
747 const spv_endianness_t endianness = _.endian;
748 std::transform(_.words + _.word_index, _.words + index_after_operand,
Andrew Woloszyn3b69d052016-01-11 13:54:30 -0500749 std::back_inserter(*words),
750 [endianness](const uint32_t raw_word) {
David Neto677e0c72016-01-05 14:56:02 -0500751 return spvFixWord(raw_word, endianness);
David Neto7bff3eb2015-11-20 14:21:10 -0500752 });
753 } else {
754 words->insert(words->end(), _.words + _.word_index,
755 _.words + index_after_operand);
756 }
757 }
758
759 // Advance past the operand.
760 _.word_index = index_after_operand;
David Neto0ca6b592015-10-30 16:06:15 -0400761
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100762 return SPV_SUCCESS;
763}
764
David Neto0ca6b592015-10-30 16:06:15 -0400765spv_result_t Parser::setNumericTypeInfoForType(
766 spv_parsed_operand_t* parsed_operand, uint32_t type_id) {
David Neto201caf72015-11-04 17:38:17 -0500767 assert(type_id != 0);
David Neto0ca6b592015-10-30 16:06:15 -0400768 auto type_info_iter = _.type_id_to_number_type_info.find(type_id);
769 if (type_info_iter == _.type_id_to_number_type_info.end()) {
770 return diagnostic() << "Type Id " << type_id << " is not a type";
771 }
772 const NumberType& info = type_info_iter->second;
773 if (info.type == SPV_NUMBER_NONE) {
774 // This is a valid type, but for something other than a scalar number.
775 return diagnostic() << "Type Id " << type_id
776 << " is not a scalar numeric type";
Andrew Woloszyn157e41b2015-10-16 15:11:00 -0400777 }
778
David Neto0ca6b592015-10-30 16:06:15 -0400779 parsed_operand->number_kind = info.type;
780 parsed_operand->number_bit_width = info.bit_width;
David Neto066bd522016-01-05 14:57:58 -0500781 // Round up the word count.
782 parsed_operand->num_words = static_cast<uint16_t>((info.bit_width + 31) / 32);
Andrew Woloszyn157e41b2015-10-16 15:11:00 -0400783 return SPV_SUCCESS;
784}
785
David Neto7bff3eb2015-11-20 14:21:10 -0500786void Parser::recordNumberType(size_t inst_offset,
787 const spv_parsed_instruction_t* inst) {
David Neto0ca6b592015-10-30 16:06:15 -0400788 if (spvOpcodeGeneratesType(inst->opcode)) {
789 NumberType info = {SPV_NUMBER_NONE, 0};
790 if (SpvOpTypeInt == inst->opcode) {
David Neto7bff3eb2015-11-20 14:21:10 -0500791 const bool is_signed = peekAt(inst_offset + 3) != 0;
David Neto0ca6b592015-10-30 16:06:15 -0400792 info.type = is_signed ? SPV_NUMBER_SIGNED_INT : SPV_NUMBER_UNSIGNED_INT;
David Neto7bff3eb2015-11-20 14:21:10 -0500793 info.bit_width = peekAt(inst_offset + 2);
David Neto0ca6b592015-10-30 16:06:15 -0400794 } else if (SpvOpTypeFloat == inst->opcode) {
795 info.type = SPV_NUMBER_FLOATING;
David Neto7bff3eb2015-11-20 14:21:10 -0500796 info.bit_width = peekAt(inst_offset + 2);
Lei Zhang40056702015-09-11 14:31:27 -0400797 }
David Neto0ca6b592015-10-30 16:06:15 -0400798 // The *result* Id of a type generating instruction is the type Id.
799 _.type_id_to_number_type_info[inst->result_id] = info;
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100800 }
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100801}
802
David Neto0ca6b592015-10-30 16:06:15 -0400803} // anonymous namespace
Andrew Woloszyncfeac482015-09-09 13:04:32 -0400804
Lei Zhang972788b2015-11-12 13:48:30 -0500805spv_result_t spvBinaryParse(const spv_const_context context, void* user_data,
806 const uint32_t* code, const size_t num_words,
David Neto0ca6b592015-10-30 16:06:15 -0400807 spv_parsed_header_fn_t parsed_header,
808 spv_parsed_instruction_fn_t parsed_instruction,
809 spv_diagnostic* diagnostic) {
Lei Zhang972788b2015-11-12 13:48:30 -0500810 Parser parser(context, user_data, parsed_header, parsed_instruction);
David Neto0ca6b592015-10-30 16:06:15 -0400811 return parser.parse(code, num_words, diagnostic);
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100812}
813
David Neto0ca6b592015-10-30 16:06:15 -0400814// TODO(dneto): This probably belongs in text.cpp since that's the only place
815// that a spv_binary_t value is created.
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100816void spvBinaryDestroy(spv_binary binary) {
Lei Zhang40056702015-09-11 14:31:27 -0400817 if (!binary) return;
Eric Engestromeb6ae972016-02-18 23:41:16 +0000818 delete[] binary->code;
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100819 delete binary;
820}