blob: df7563235e157acb3dbb5e6affb40d27f8d39fa8 [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//
David Neto9fc86582016-09-01 15:33:59 -04003// 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
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +01006//
David Neto9fc86582016-09-01 15:33:59 -04007// http://www.apache.org/licenses/LICENSE-2.0
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +01008//
David Neto9fc86582016-09-01 15:33:59 -04009// 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.
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +010014
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +010015#include "binary.h"
David Netofcc7d582015-10-27 15:31:10 -040016
David Neto7bff3eb2015-11-20 14:21:10 -050017#include <algorithm>
David Netofcc7d582015-10-27 15:31:10 -040018#include <cassert>
19#include <cstring>
Andrew Woloszyn7ffd8ff2016-01-11 16:22:34 -050020#include <iterator>
David Neto0ca6b592015-10-30 16:06:15 -040021#include <limits>
David Netofcc7d582015-10-27 15:31:10 -040022#include <unordered_map>
Lei Zhangdc6e4832016-09-21 17:16:31 -040023#include <vector>
David Netofcc7d582015-10-27 15:31:10 -040024
David Netofcc7d582015-10-27 15:31:10 -040025#include "assembly_grammar.h"
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +010026#include "diagnostic.h"
27#include "ext_inst.h"
28#include "opcode.h"
29#include "operand.h"
David Netodbc20492017-03-14 12:43:41 -040030#include "spirv/1.2/spirv.h"
Lei Zhangaa056cd2015-11-11 14:24:04 -050031#include "spirv_constant.h"
David Neto4c215712015-12-22 15:08:41 -050032#include "spirv_endian.h"
Andrew Woloszyn157e41b2015-10-16 15:11:00 -040033
Andrew Woloszyn55ecc2e2015-11-11 11:05:07 -050034spv_result_t spvBinaryHeaderGet(const spv_const_binary binary,
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +010035 const spv_endianness_t endian,
Lei Zhang1a0334e2015-11-02 09:41:20 -050036 spv_header_t* pHeader) {
David Neto0ca6b592015-10-30 16:06:15 -040037 if (!binary->code) return SPV_ERROR_INVALID_BINARY;
38 if (binary->wordCount < SPV_INDEX_INSTRUCTION)
39 return SPV_ERROR_INVALID_BINARY;
Lei Zhang40056702015-09-11 14:31:27 -040040 if (!pHeader) return SPV_ERROR_INVALID_POINTER;
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +010041
42 // TODO: Validation checking?
43 pHeader->magic = spvFixWord(binary->code[SPV_INDEX_MAGIC_NUMBER], endian);
44 pHeader->version = spvFixWord(binary->code[SPV_INDEX_VERSION_NUMBER], endian);
45 pHeader->generator =
46 spvFixWord(binary->code[SPV_INDEX_GENERATOR_NUMBER], endian);
47 pHeader->bound = spvFixWord(binary->code[SPV_INDEX_BOUND], endian);
48 pHeader->schema = spvFixWord(binary->code[SPV_INDEX_SCHEMA], endian);
49 pHeader->instructions = &binary->code[SPV_INDEX_INSTRUCTION];
50
51 return SPV_SUCCESS;
52}
53
David Neto0ca6b592015-10-30 16:06:15 -040054namespace {
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +010055
David Neto0ca6b592015-10-30 16:06:15 -040056// A SPIR-V binary parser. A parser instance communicates detailed parse
57// results via callbacks.
58class Parser {
59 public:
60 // The user_data value is provided to the callbacks as context.
Lei Zhang972788b2015-11-12 13:48:30 -050061 Parser(const spv_const_context context, void* user_data,
62 spv_parsed_header_fn_t parsed_header_fn,
David Neto0ca6b592015-10-30 16:06:15 -040063 spv_parsed_instruction_fn_t parsed_instruction_fn)
Lei Zhang972788b2015-11-12 13:48:30 -050064 : grammar_(context),
Lei Zhang755f97f2016-09-02 18:06:18 -040065 consumer_(context->consumer),
Lei Zhang972788b2015-11-12 13:48:30 -050066 user_data_(user_data),
David Neto0ca6b592015-10-30 16:06:15 -040067 parsed_header_fn_(parsed_header_fn),
68 parsed_instruction_fn_(parsed_instruction_fn) {}
69
70 // Parses the specified binary SPIR-V module, issuing callbacks on a parsed
71 // header and for each parsed instruction. Returns SPV_SUCCESS on success.
72 // Otherwise returns an error code and issues a diagnostic.
73 spv_result_t parse(const uint32_t* words, size_t num_words,
74 spv_diagnostic* diagnostic);
75
76 private:
77 // All remaining methods work on the current module parse state.
78
79 // Like the parse method, but works on the current module parse state.
80 spv_result_t parseModule();
81
82 // Parses an instruction at the current position of the binary. Assumes
83 // the header has been parsed, the endian has been set, and the word index is
84 // still in range. Advances the parsing position past the instruction, and
85 // updates other parsing state for the current module.
86 // On success, returns SPV_SUCCESS and issues the parsed-instruction callback.
87 // On failure, returns an error code and issues a diagnostic.
88 spv_result_t parseInstruction();
89
David Neto7bff3eb2015-11-20 14:21:10 -050090 // Parses an instruction operand with the given type, for an instruction
91 // starting at inst_offset words into the SPIR-V binary.
92 // If the SPIR-V binary is the same endianness as the host, then the
93 // endian_converted_inst_words parameter is ignored. Otherwise, this method
94 // appends the words for this operand, converted to host native endianness,
95 // to the end of endian_converted_inst_words. This method also updates the
96 // expected_operands parameter, and the scalar members of the inst parameter.
97 // On success, returns SPV_SUCCESS, advances past the operand, and pushes a
98 // new entry on to the operands vector. Otherwise returns an error code and
99 // issues a diagnostic.
100 spv_result_t parseOperand(size_t inst_offset, spv_parsed_instruction_t* inst,
David Neto0ca6b592015-10-30 16:06:15 -0400101 const spv_operand_type_t type,
David Neto7bff3eb2015-11-20 14:21:10 -0500102 std::vector<uint32_t>* endian_converted_inst_words,
David Neto0ca6b592015-10-30 16:06:15 -0400103 std::vector<spv_parsed_operand_t>* operands,
104 spv_operand_pattern_t* expected_operands);
105
106 // Records the numeric type for an operand according to the type information
107 // associated with the given non-zero type Id. This can fail if the type Id
108 // is not a type Id, or if the type Id does not reference a scalar numeric
109 // type. On success, return SPV_SUCCESS and populates the num_words,
110 // number_kind, and number_bit_width fields of parsed_operand.
111 spv_result_t setNumericTypeInfoForType(spv_parsed_operand_t* parsed_operand,
112 uint32_t type_id);
113
David Neto7bff3eb2015-11-20 14:21:10 -0500114 // Records the number type for an instruction at the given offset, if that
115 // instruction generates a type. For types that aren't scalar numbers,
116 // record something with number kind SPV_NUMBER_NONE.
117 void recordNumberType(size_t inst_offset,
118 const spv_parsed_instruction_t* inst);
David Neto0ca6b592015-10-30 16:06:15 -0400119
120 // Returns a diagnostic stream object initialized with current position in
121 // the input stream, and for the given error code. Any data written to the
122 // returned object will be propagated to the current parse's diagnostic
123 // object.
David Neto01656362015-11-20 10:44:41 -0500124 libspirv::DiagnosticStream diagnostic(spv_result_t error) {
Lei Zhang755f97f2016-09-02 18:06:18 -0400125 return libspirv::DiagnosticStream({0, 0, _.word_index}, consumer_, error);
David Neto0ca6b592015-10-30 16:06:15 -0400126 }
127
128 // Returns a diagnostic stream object with the default parse error code.
David Neto01656362015-11-20 10:44:41 -0500129 libspirv::DiagnosticStream diagnostic() {
David Neto0ca6b592015-10-30 16:06:15 -0400130 // The default failure for parsing is invalid binary.
131 return diagnostic(SPV_ERROR_INVALID_BINARY);
132 }
133
David Netod9ad0502015-11-24 18:37:24 -0500134 // Issues a diagnostic describing an exhaustion of input condition when
135 // trying to decode an instruction operand, and returns
136 // SPV_ERROR_INVALID_BINARY.
137 spv_result_t exhaustedInputDiagnostic(size_t inst_offset, SpvOp opcode,
138 spv_operand_type_t type) {
139 return diagnostic() << "End of input reached while decoding Op"
140 << spvOpcodeString(opcode) << " starting at word "
141 << inst_offset
142 << ((_.word_index < _.num_words) ? ": truncated "
143 : ": missing ")
144 << spvOperandTypeStr(type) << " operand at word offset "
145 << _.word_index - inst_offset << ".";
146 }
147
David Neto0ca6b592015-10-30 16:06:15 -0400148 // Returns the endian-corrected word at the current position.
149 uint32_t peek() const { return peekAt(_.word_index); }
150
151 // Returns the endian-corrected word at the given position.
152 uint32_t peekAt(size_t index) const {
153 assert(index < _.num_words);
154 return spvFixWord(_.words[index], _.endian);
155 }
156
157 // Data members
158
159 const libspirv::AssemblyGrammar grammar_; // SPIR-V syntax utility.
Lei Zhang755f97f2016-09-02 18:06:18 -0400160 const spvtools::MessageConsumer& consumer_; // Message consumer callback.
David Neto0ca6b592015-10-30 16:06:15 -0400161 void* const user_data_; // Context for the callbacks
162 const spv_parsed_header_fn_t parsed_header_fn_; // Parsed header callback
163 const spv_parsed_instruction_fn_t
164 parsed_instruction_fn_; // Parsed instruction callback
165
166 // Describes the format of a typed literal number.
167 struct NumberType {
168 spv_number_kind_t type;
169 uint32_t bit_width;
170 };
171
172 // The state used to parse a single SPIR-V binary module.
173 struct State {
174 State(const uint32_t* words_arg, size_t num_words_arg,
175 spv_diagnostic* diagnostic_arg)
176 : words(words_arg),
177 num_words(num_words_arg),
178 diagnostic(diagnostic_arg),
179 word_index(0),
Lei Zhang712bed02016-02-25 16:11:16 -0500180 endian(),
181 requires_endian_conversion(false) {}
David Neto0ca6b592015-10-30 16:06:15 -0400182 State() : State(0, 0, nullptr) {}
183 const uint32_t* words; // Words in the binary SPIR-V module.
184 size_t num_words; // Number of words in the module.
185 spv_diagnostic* diagnostic; // Where diagnostics go.
186 size_t word_index; // The current position in words.
187 spv_endianness_t endian; // The endianness of the binary.
David Neto7bff3eb2015-11-20 14:21:10 -0500188 // Is the SPIR-V binary in a different endiannes from the host native
189 // endianness?
190 bool requires_endian_conversion;
David Neto0ca6b592015-10-30 16:06:15 -0400191
192 // Maps a result ID to its type ID. By convention:
193 // - a result ID that is a type definition maps to itself.
194 // - a result ID without a type maps to 0. (E.g. for OpLabel)
195 std::unordered_map<uint32_t, uint32_t> id_to_type_id;
196 // Maps a type ID to its number type description.
197 std::unordered_map<uint32_t, NumberType> type_id_to_number_type_info;
198 // Maps an ExtInstImport id to the extended instruction type.
199 std::unordered_map<uint32_t, spv_ext_inst_type_t>
200 import_id_to_ext_inst_type;
Chris Forbesfcd991f2017-06-27 11:00:06 -0700201
202 // Used by parseOperand
203 std::vector<spv_parsed_operand_t> operands;
204 std::vector<uint32_t> endian_converted_words;
David Neto0ca6b592015-10-30 16:06:15 -0400205 } _;
206};
207
208spv_result_t Parser::parse(const uint32_t* words, size_t num_words,
209 spv_diagnostic* diagnostic_arg) {
210 _ = State(words, num_words, diagnostic_arg);
211
212 const spv_result_t result = parseModule();
213
214 // Clear the module state. The tables might be big.
215 _ = State();
216
217 return result;
218}
219
220spv_result_t Parser::parseModule() {
221 if (!_.words) return diagnostic() << "Missing module.";
222
223 if (_.num_words < SPV_INDEX_INSTRUCTION)
224 return diagnostic() << "Module has incomplete header: only " << _.num_words
225 << " words instead of " << SPV_INDEX_INSTRUCTION;
226
227 // Check the magic number and detect the module's endianness.
Andrew Woloszyn55ecc2e2015-11-11 11:05:07 -0500228 spv_const_binary_t binary{_.words, _.num_words};
David Neto0ca6b592015-10-30 16:06:15 -0400229 if (spvBinaryEndianness(&binary, &_.endian)) {
230 return diagnostic() << "Invalid SPIR-V magic number '" << std::hex
231 << _.words[0] << "'.";
232 }
David Neto7bff3eb2015-11-20 14:21:10 -0500233 _.requires_endian_conversion = !spvIsHostEndian(_.endian);
David Neto0ca6b592015-10-30 16:06:15 -0400234
235 // Process the header.
236 spv_header_t header;
237 if (spvBinaryHeaderGet(&binary, _.endian, &header)) {
238 // It turns out there is no way to trigger this error since the only
239 // failure cases are already handled above, with better messages.
240 return diagnostic(SPV_ERROR_INTERNAL)
241 << "Internal error: unhandled header parse failure";
242 }
243 if (parsed_header_fn_) {
244 if (auto error = parsed_header_fn_(user_data_, _.endian, header.magic,
245 header.version, header.generator,
246 header.bound, header.schema)) {
247 return error;
248 }
249 }
250
251 // Process the instructions.
252 _.word_index = SPV_INDEX_INSTRUCTION;
253 while (_.word_index < _.num_words)
254 if (auto error = parseInstruction()) return error;
255
256 // Running off the end should already have been reported earlier.
257 assert(_.word_index == _.num_words);
258
259 return SPV_SUCCESS;
260}
261
262spv_result_t Parser::parseInstruction() {
263 // The zero values for all members except for opcode are the
264 // correct initial values.
265 spv_parsed_instruction_t inst = {};
David Neto7bff3eb2015-11-20 14:21:10 -0500266
267 const uint32_t first_word = peek();
268
269 // TODO(dneto): If it's too expensive to construct the following "words"
270 // and "operands" vectors for each instruction, each instruction, then make
271 // them class data members instead, and clear them here.
272
273 // If the module's endianness is different from the host native endianness,
274 // then converted_words contains the the endian-translated words in the
275 // instruction.
Chris Forbesfcd991f2017-06-27 11:00:06 -0700276 _.endian_converted_words.clear();
277 _.endian_converted_words.push_back(first_word);
David Neto7bff3eb2015-11-20 14:21:10 -0500278 if (_.requires_endian_conversion) {
279 // Most instructions have fewer than 25 words.
Chris Forbesfcd991f2017-06-27 11:00:06 -0700280 _.endian_converted_words.reserve(25);
David Neto7bff3eb2015-11-20 14:21:10 -0500281 }
David Neto0ca6b592015-10-30 16:06:15 -0400282
283 // After a successful parse of the instruction, the inst.operands member
284 // will point to this vector's storage.
David Neto0ca6b592015-10-30 16:06:15 -0400285 // Most instructions have fewer than 25 logical operands.
Chris Forbesfcd991f2017-06-27 11:00:06 -0700286 _.operands.clear();
287 _.operands.reserve(25);
David Neto0ca6b592015-10-30 16:06:15 -0400288
289 assert(_.word_index < _.num_words);
290 // Decompose and check the first word.
291 uint16_t inst_word_count = 0;
David Neto7bff3eb2015-11-20 14:21:10 -0500292 spvOpcodeSplit(first_word, &inst_word_count, &inst.opcode);
David Neto0ca6b592015-10-30 16:06:15 -0400293 if (inst_word_count < 1) {
294 return diagnostic() << "Invalid instruction word count: "
295 << inst_word_count;
296 }
297 spv_opcode_desc opcode_desc;
Lei Zhang6fa3f8a2016-03-31 17:26:31 -0400298 if (grammar_.lookupOpcode(static_cast<SpvOp>(inst.opcode), &opcode_desc))
299 return diagnostic() << "Invalid opcode: " << inst.opcode;
David Neto0ca6b592015-10-30 16:06:15 -0400300
David Neto7bff3eb2015-11-20 14:21:10 -0500301 // Advance past the opcode word. But remember the of the start
302 // of the instruction.
303 const size_t inst_offset = _.word_index;
David Neto0ca6b592015-10-30 16:06:15 -0400304 _.word_index++;
305
306 // Maintains the ordered list of expected operand types.
307 // For many instructions we only need the {numTypes, operandTypes}
308 // entries in opcode_desc. However, sometimes we need to modify
309 // the list as we parse the operands. This occurs when an operand
310 // has its own logical operands (such as the LocalSize operand for
311 // ExecutionMode), or for extended instructions that may have their
312 // own operands depending on the selected extended instruction.
313 spv_operand_pattern_t expected_operands(
314 opcode_desc->operandTypes,
315 opcode_desc->operandTypes + opcode_desc->numTypes);
316
David Neto7bff3eb2015-11-20 14:21:10 -0500317 while (_.word_index < inst_offset + inst_word_count) {
318 const uint16_t inst_word_index = uint16_t(_.word_index - inst_offset);
David Neto0ca6b592015-10-30 16:06:15 -0400319 if (expected_operands.empty()) {
320 return diagnostic() << "Invalid instruction Op" << opcode_desc->name
David Neto7bff3eb2015-11-20 14:21:10 -0500321 << " starting at word " << inst_offset
David Neto0ca6b592015-10-30 16:06:15 -0400322 << ": expected no more operands after "
323 << inst_word_index
324 << " words, but stated word count is "
325 << inst_word_count << ".";
326 }
327
328 spv_operand_type_t type = spvTakeFirstMatchableOperand(&expected_operands);
329
David Neto7bff3eb2015-11-20 14:21:10 -0500330 if (auto error =
Chris Forbesfcd991f2017-06-27 11:00:06 -0700331 parseOperand(inst_offset, &inst, type, &_.endian_converted_words,
332 &_.operands, &expected_operands)) {
David Neto0ca6b592015-10-30 16:06:15 -0400333 return error;
David Netod9ad0502015-11-24 18:37:24 -0500334 }
David Neto0ca6b592015-10-30 16:06:15 -0400335 }
336
337 if (!expected_operands.empty() &&
338 !spvOperandIsOptional(expected_operands.front())) {
339 return diagnostic() << "End of input reached while decoding Op"
340 << opcode_desc->name << " starting at word "
David Neto7bff3eb2015-11-20 14:21:10 -0500341 << inst_offset << ": expected more operands after "
David Neto0ca6b592015-10-30 16:06:15 -0400342 << inst_word_count << " words.";
343 }
344
David Neto7bff3eb2015-11-20 14:21:10 -0500345 if ((inst_offset + inst_word_count) != _.word_index) {
David Netod9ad0502015-11-24 18:37:24 -0500346 return diagnostic() << "Invalid word count: Op" << opcode_desc->name
347 << " starting at word " << inst_offset
348 << " says it has " << inst_word_count
David Neto7bff3eb2015-11-20 14:21:10 -0500349 << " words, but found " << _.word_index - inst_offset
David Neto0ca6b592015-10-30 16:06:15 -0400350 << " words instead.";
351 }
David Neto15afbf92015-11-23 14:17:35 -0500352
353 // Check the computed length of the endian-converted words vector against
354 // the declared number of words in the instruction. If endian conversion
355 // is required, then they should match. If no endian conversion was
356 // performed, then the vector only contains the initial opcode/word-count
357 // word.
358 assert(!_.requires_endian_conversion ||
Chris Forbesfcd991f2017-06-27 11:00:06 -0700359 (inst_word_count == _.endian_converted_words.size()));
360 assert(_.requires_endian_conversion || (_.endian_converted_words.size() == 1));
David Neto0ca6b592015-10-30 16:06:15 -0400361
David Neto7bff3eb2015-11-20 14:21:10 -0500362 recordNumberType(inst_offset, &inst);
David Neto0ca6b592015-10-30 16:06:15 -0400363
David Neto7bff3eb2015-11-20 14:21:10 -0500364 if (_.requires_endian_conversion) {
365 // We must wait until here to set this pointer, because the vector might
366 // have been be resized while we accumulated its elements.
Chris Forbesfcd991f2017-06-27 11:00:06 -0700367 inst.words = _.endian_converted_words.data();
David Neto7bff3eb2015-11-20 14:21:10 -0500368 } else {
369 // If no conversion is required, then just point to the underlying binary.
370 // This saves time and space.
371 inst.words = _.words + inst_offset;
372 }
373 inst.num_words = inst_word_count;
374
375 // We must wait until here to set this pointer, because the vector might
376 // have been be resized while we accumulated its elements.
Chris Forbesfcd991f2017-06-27 11:00:06 -0700377 inst.operands = _.operands.data();
378 inst.num_operands = uint16_t(_.operands.size());
David Neto0ca6b592015-10-30 16:06:15 -0400379
380 // Issue the callback. The callee should know that all the storage in inst
381 // is transient, and will disappear immediately afterward.
382 if (parsed_instruction_fn_) {
383 if (auto error = parsed_instruction_fn_(user_data_, &inst)) return error;
384 }
385
386 return SPV_SUCCESS;
387}
388
David Neto7bff3eb2015-11-20 14:21:10 -0500389spv_result_t Parser::parseOperand(size_t inst_offset,
390 spv_parsed_instruction_t* inst,
David Neto0ca6b592015-10-30 16:06:15 -0400391 const spv_operand_type_t type,
David Neto7bff3eb2015-11-20 14:21:10 -0500392 std::vector<uint32_t>* words,
David Neto0ca6b592015-10-30 16:06:15 -0400393 std::vector<spv_parsed_operand_t>* operands,
394 spv_operand_pattern_t* expected_operands) {
Lei Zhang6fa3f8a2016-03-31 17:26:31 -0400395 const SpvOp opcode = static_cast<SpvOp>(inst->opcode);
David Neto0ca6b592015-10-30 16:06:15 -0400396 // We'll fill in this result as we go along.
397 spv_parsed_operand_t parsed_operand;
David Neto7bff3eb2015-11-20 14:21:10 -0500398 parsed_operand.offset = uint16_t(_.word_index - inst_offset);
David Neto0ca6b592015-10-30 16:06:15 -0400399 // Most operands occupy one word. This might be be adjusted later.
400 parsed_operand.num_words = 1;
401 // The type argument is the one used by the grammar to parse the instruction.
402 // But it can exposes internal parser details such as whether an operand is
403 // optional or actually represents a variable-length sequence of operands.
404 // The resulting type should be adjusted to avoid those internal details.
405 // In most cases, the resulting operand type is the same as the grammar type.
406 parsed_operand.type = type;
407
408 // Assume non-numeric values. This will be updated for literal numbers.
409 parsed_operand.number_kind = SPV_NUMBER_NONE;
410 parsed_operand.number_bit_width = 0;
411
David Netod9ad0502015-11-24 18:37:24 -0500412 if (_.word_index >= _.num_words)
Lei Zhang6fa3f8a2016-03-31 17:26:31 -0400413 return exhaustedInputDiagnostic(inst_offset, opcode, type);
David Netod9ad0502015-11-24 18:37:24 -0500414
David Neto0ca6b592015-10-30 16:06:15 -0400415 const uint32_t word = peek();
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100416
David Neto7bff3eb2015-11-20 14:21:10 -0500417 // Do the words in this operand have to be converted to native endianness?
418 // True for all but literal strings.
419 bool convert_operand_endianness = true;
420
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100421 switch (type) {
Andrew Woloszyn537e7762015-09-29 11:28:34 -0400422 case SPV_OPERAND_TYPE_TYPE_ID:
David Neto677e0c72016-01-05 14:56:02 -0500423 if (!word)
424 return diagnostic(SPV_ERROR_INVALID_ID) << "Error: Type Id is 0";
David Neto0ca6b592015-10-30 16:06:15 -0400425 inst->type_id = word;
426 break;
427
428 case SPV_OPERAND_TYPE_RESULT_ID:
David Neto677e0c72016-01-05 14:56:02 -0500429 if (!word)
430 return diagnostic(SPV_ERROR_INVALID_ID) << "Error: Result Id is 0";
David Neto0ca6b592015-10-30 16:06:15 -0400431 inst->result_id = word;
432 // Save the result ID to type ID mapping.
433 // In the grammar, type ID always appears before result ID.
434 if (_.id_to_type_id.find(inst->result_id) != _.id_to_type_id.end())
Umar Arshadf76e0f52015-11-18 15:43:43 -0500435 return diagnostic(SPV_ERROR_INVALID_ID) << "Id " << inst->result_id
David Neto677e0c72016-01-05 14:56:02 -0500436 << " is defined more than once";
David Neto0ca6b592015-10-30 16:06:15 -0400437 // Record it.
438 // A regular value maps to its type. Some instructions (e.g. OpLabel)
439 // have no type Id, and will map to 0. The result Id for a
440 // type-generating instruction (e.g. OpTypeInt) maps to itself.
Lei Zhang6fa3f8a2016-03-31 17:26:31 -0400441 _.id_to_type_id[inst->result_id] =
442 spvOpcodeGeneratesType(opcode) ? inst->result_id : inst->type_id;
David Neto0ca6b592015-10-30 16:06:15 -0400443 break;
444
445 case SPV_OPERAND_TYPE_ID:
David Neto78c3b432015-08-27 13:03:52 -0400446 case SPV_OPERAND_TYPE_OPTIONAL_ID:
Umar Arshadf76e0f52015-11-18 15:43:43 -0500447 if (!word) return diagnostic(SPV_ERROR_INVALID_ID) << "Id is 0";
David Neto0ca6b592015-10-30 16:06:15 -0400448 parsed_operand.type = SPV_OPERAND_TYPE_ID;
449
Lei Zhang6fa3f8a2016-03-31 17:26:31 -0400450 if (opcode == SpvOpExtInst && parsed_operand.offset == 3) {
David Neto0ca6b592015-10-30 16:06:15 -0400451 // The current word is the extended instruction set Id.
452 // Set the extended instruction set type for the current instruction.
453 auto ext_inst_type_iter = _.import_id_to_ext_inst_type.find(word);
454 if (ext_inst_type_iter == _.import_id_to_ext_inst_type.end()) {
Umar Arshadf76e0f52015-11-18 15:43:43 -0500455 return diagnostic(SPV_ERROR_INVALID_ID)
David Neto0ca6b592015-10-30 16:06:15 -0400456 << "OpExtInst set Id " << word
457 << " does not reference an OpExtInstImport result Id";
458 }
459 inst->ext_inst_type = ext_inst_type_iter->second;
460 }
461 break;
462
David Neto64a9be92015-11-18 15:48:32 -0500463 case SPV_OPERAND_TYPE_SCOPE_ID:
464 case SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID:
David Netod9ad0502015-11-24 18:37:24 -0500465 // Check for trivially invalid values. The operand descriptions already
466 // have the word "ID" in them.
467 if (!word) return diagnostic() << spvOperandTypeStr(type) << " is 0";
David Neto0ca6b592015-10-30 16:06:15 -0400468 break;
469
David Neto445ce442015-10-15 15:22:06 -0400470 case SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER: {
Lei Zhang6fa3f8a2016-03-31 17:26:31 -0400471 assert(SpvOpExtInst == opcode);
David Neto0ca6b592015-10-30 16:06:15 -0400472 assert(inst->ext_inst_type != SPV_EXT_INST_TYPE_NONE);
473 spv_ext_inst_desc ext_inst;
474 if (grammar_.lookupExtInst(inst->ext_inst_type, word, &ext_inst))
475 return diagnostic() << "Invalid extended instruction number: " << word;
476 spvPrependOperandTypes(ext_inst->operandTypes, expected_operands);
David Neto445ce442015-10-15 15:22:06 -0400477 } break;
David Neto0ca6b592015-10-30 16:06:15 -0400478
David Neto21196942015-11-11 02:45:45 -0500479 case SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER: {
Lei Zhang6fa3f8a2016-03-31 17:26:31 -0400480 assert(SpvOpSpecConstantOp == opcode);
David Neto21196942015-11-11 02:45:45 -0500481 if (grammar_.lookupSpecConstantOpcode(SpvOp(word))) {
482 return diagnostic() << "Invalid " << spvOperandTypeStr(type) << ": "
483 << word;
484 }
485 spv_opcode_desc opcode_entry = nullptr;
486 if (grammar_.lookupOpcode(SpvOp(word), &opcode_entry)) {
487 return diagnostic(SPV_ERROR_INTERNAL)
488 << "OpSpecConstant opcode table out of sync";
489 }
490 // OpSpecConstant opcodes must have a type and result. We've already
491 // processed them, so skip them when preparing to parse the other
492 // operants for the opcode.
493 assert(opcode_entry->hasType);
494 assert(opcode_entry->hasResult);
495 assert(opcode_entry->numTypes >= 2);
496 spvPrependOperandTypes(opcode_entry->operandTypes + 2, expected_operands);
497 } break;
498
David Neto445ce442015-10-15 15:22:06 -0400499 case SPV_OPERAND_TYPE_LITERAL_INTEGER:
Lei Zhang6483bd72015-10-14 17:02:39 -0400500 case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_INTEGER:
David Neto201caf72015-11-04 17:38:17 -0500501 // These are regular single-word literal integer operands.
502 // Post-parsing validation should check the range of the parsed value.
David Neto0ca6b592015-10-30 16:06:15 -0400503 parsed_operand.type = SPV_OPERAND_TYPE_LITERAL_INTEGER;
David Neto201caf72015-11-04 17:38:17 -0500504 // It turns out they are always unsigned integers!
505 parsed_operand.number_kind = SPV_NUMBER_UNSIGNED_INT;
506 parsed_operand.number_bit_width = 32;
507 break;
508
509 case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER:
510 case SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER:
Lei Zhangaa3cd5a2015-11-10 14:29:35 -0500511 parsed_operand.type = SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER;
Lei Zhang6fa3f8a2016-03-31 17:26:31 -0400512 if (opcode == SpvOpSwitch) {
David Neto0ca6b592015-10-30 16:06:15 -0400513 // The literal operands have the same type as the value
514 // referenced by the selector Id.
David Neto7bff3eb2015-11-20 14:21:10 -0500515 const uint32_t selector_id = peekAt(inst_offset + 1);
David Neto3664bd52015-12-23 13:21:43 -0500516 const auto type_id_iter = _.id_to_type_id.find(selector_id);
517 if (type_id_iter == _.id_to_type_id.end() ||
518 type_id_iter->second == 0) {
David Neto0ca6b592015-10-30 16:06:15 -0400519 return diagnostic() << "Invalid OpSwitch: selector id " << selector_id
520 << " has no type";
521 }
522 uint32_t type_id = type_id_iter->second;
523
524 if (selector_id == type_id) {
525 // Recall that by convention, a result ID that is a type definition
526 // maps to itself.
527 return diagnostic() << "Invalid OpSwitch: selector id " << selector_id
528 << " is a type, not a value";
529 }
530 if (auto error = setNumericTypeInfoForType(&parsed_operand, type_id))
531 return error;
532 if (parsed_operand.number_kind != SPV_NUMBER_UNSIGNED_INT &&
533 parsed_operand.number_kind != SPV_NUMBER_SIGNED_INT) {
534 return diagnostic() << "Invalid OpSwitch: selector id " << selector_id
535 << " is not a scalar integer";
536 }
Lei Zhangb41d1502015-09-14 15:22:23 -0400537 } else {
Lei Zhang6fa3f8a2016-03-31 17:26:31 -0400538 assert(opcode == SpvOpConstant || opcode == SpvOpSpecConstant);
David Neto201caf72015-11-04 17:38:17 -0500539 // The literal number type is determined by the type Id for the
540 // constant.
541 assert(inst->type_id);
542 if (auto error =
543 setNumericTypeInfoForType(&parsed_operand, inst->type_id))
544 return error;
Lei Zhangb41d1502015-09-14 15:22:23 -0400545 }
David Neto0ca6b592015-10-30 16:06:15 -0400546 break;
547
David Neto78c3b432015-08-27 13:03:52 -0400548 case SPV_OPERAND_TYPE_LITERAL_STRING:
549 case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_STRING: {
David Neto7bff3eb2015-11-20 14:21:10 -0500550 convert_operand_endianness = false;
David Neto0ca6b592015-10-30 16:06:15 -0400551 const char* string =
552 reinterpret_cast<const char*>(_.words + _.word_index);
David Netod9ad0502015-11-24 18:37:24 -0500553 // Compute the length of the string, but make sure we don't run off the
554 // end of the input.
555 const size_t remaining_input_bytes =
556 sizeof(uint32_t) * (_.num_words - _.word_index);
557 const size_t string_num_content_bytes =
David Neto37422e92016-12-19 13:26:42 -0500558 spv_strnlen_s(string, remaining_input_bytes);
David Netod9ad0502015-11-24 18:37:24 -0500559 // If there was no terminating null byte, then that's an end-of-input
560 // error.
561 if (string_num_content_bytes == remaining_input_bytes)
Lei Zhang6fa3f8a2016-03-31 17:26:31 -0400562 return exhaustedInputDiagnostic(inst_offset, opcode, type);
David Netod9ad0502015-11-24 18:37:24 -0500563 // Account for null in the word length, so add 1 for null, then add 3 to
564 // make sure we round up. The following is equivalent to:
565 // (string_num_content_bytes + 1 + 3) / 4
566 const size_t string_num_words = string_num_content_bytes / 4 + 1;
David Neto0ca6b592015-10-30 16:06:15 -0400567 // Make sure we can record the word count without overflow.
David Netod9ad0502015-11-24 18:37:24 -0500568 //
569 // This error can't currently be triggered because of validity
570 // checks elsewhere.
David Neto0ca6b592015-10-30 16:06:15 -0400571 if (string_num_words > std::numeric_limits<uint16_t>::max()) {
572 return diagnostic() << "Literal string is longer than "
573 << std::numeric_limits<uint16_t>::max()
574 << " words: " << string_num_words << " words long";
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100575 }
Andrew Woloszyn3a4bc7e2015-11-19 09:22:53 -0500576 parsed_operand.num_words = uint16_t(string_num_words);
David Neto0ca6b592015-10-30 16:06:15 -0400577 parsed_operand.type = SPV_OPERAND_TYPE_LITERAL_STRING;
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100578
Lei Zhang6fa3f8a2016-03-31 17:26:31 -0400579 if (SpvOpExtInstImport == opcode) {
David Neto0ca6b592015-10-30 16:06:15 -0400580 // Record the extended instruction type for the ID for this import.
581 // There is only one string literal argument to OpExtInstImport,
582 // so it's sufficient to guard this just on the opcode.
583 const spv_ext_inst_type_t ext_inst_type =
584 spvExtInstImportTypeGet(string);
585 if (SPV_EXT_INST_TYPE_NONE == ext_inst_type) {
586 return diagnostic() << "Invalid extended instruction import '"
587 << string << "'";
Andrew Woloszyne59e6b72015-10-14 14:18:43 -0400588 }
David Neto0ca6b592015-10-30 16:06:15 -0400589 // We must have parsed a valid result ID. It's a condition
590 // of the grammar, and we only accept non-zero result Ids.
591 assert(inst->result_id);
592 _.import_id_to_ext_inst_type[inst->result_id] = ext_inst_type;
Andrew Woloszyne59e6b72015-10-14 14:18:43 -0400593 }
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100594 } break;
David Neto0ca6b592015-10-30 16:06:15 -0400595
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100596 case SPV_OPERAND_TYPE_CAPABILITY:
597 case SPV_OPERAND_TYPE_SOURCE_LANGUAGE:
598 case SPV_OPERAND_TYPE_EXECUTION_MODEL:
599 case SPV_OPERAND_TYPE_ADDRESSING_MODEL:
600 case SPV_OPERAND_TYPE_MEMORY_MODEL:
601 case SPV_OPERAND_TYPE_EXECUTION_MODE:
602 case SPV_OPERAND_TYPE_STORAGE_CLASS:
603 case SPV_OPERAND_TYPE_DIMENSIONALITY:
604 case SPV_OPERAND_TYPE_SAMPLER_ADDRESSING_MODE:
605 case SPV_OPERAND_TYPE_SAMPLER_FILTER_MODE:
David Netod9ad0502015-11-24 18:37:24 -0500606 case SPV_OPERAND_TYPE_SAMPLER_IMAGE_FORMAT:
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100607 case SPV_OPERAND_TYPE_FP_ROUNDING_MODE:
608 case SPV_OPERAND_TYPE_LINKAGE_TYPE:
609 case SPV_OPERAND_TYPE_ACCESS_QUALIFIER:
David Neto2889a0c2016-02-15 13:50:00 -0500610 case SPV_OPERAND_TYPE_OPTIONAL_ACCESS_QUALIFIER:
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100611 case SPV_OPERAND_TYPE_FUNCTION_PARAMETER_ATTRIBUTE:
612 case SPV_OPERAND_TYPE_DECORATION:
613 case SPV_OPERAND_TYPE_BUILT_IN:
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100614 case SPV_OPERAND_TYPE_GROUP_OPERATION:
615 case SPV_OPERAND_TYPE_KERNEL_ENQ_FLAGS:
David Neto47994822015-08-27 13:11:01 -0400616 case SPV_OPERAND_TYPE_KERNEL_PROFILING_INFO: {
David Neto0ca6b592015-10-30 16:06:15 -0400617 // A single word that is a plain enum value.
David Neto2889a0c2016-02-15 13:50:00 -0500618
619 // Map an optional operand type to its corresponding concrete type.
620 if (type == SPV_OPERAND_TYPE_OPTIONAL_ACCESS_QUALIFIER)
621 parsed_operand.type = SPV_OPERAND_TYPE_ACCESS_QUALIFIER;
622
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100623 spv_operand_desc entry;
David Neto0ca6b592015-10-30 16:06:15 -0400624 if (grammar_.lookupOperand(type, word, &entry)) {
David Neto201caf72015-11-04 17:38:17 -0500625 return diagnostic() << "Invalid "
626 << spvOperandTypeStr(parsed_operand.type)
David Neto0ca6b592015-10-30 16:06:15 -0400627 << " operand: " << word;
Lei Zhang40056702015-09-11 14:31:27 -0400628 }
David Neto78c3b432015-08-27 13:03:52 -0400629 // Prepare to accept operands to this operand, if needed.
David Neto0ca6b592015-10-30 16:06:15 -0400630 spvPrependOperandTypes(entry->operandTypes, expected_operands);
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100631 } break;
David Neto0ca6b592015-10-30 16:06:15 -0400632
David Neto619db262015-09-25 12:43:37 -0400633 case SPV_OPERAND_TYPE_FP_FAST_MATH_MODE:
634 case SPV_OPERAND_TYPE_FUNCTION_CONTROL:
635 case SPV_OPERAND_TYPE_LOOP_CONTROL:
David Neto2889a0c2016-02-15 13:50:00 -0500636 case SPV_OPERAND_TYPE_IMAGE:
David Neto619db262015-09-25 12:43:37 -0400637 case SPV_OPERAND_TYPE_OPTIONAL_IMAGE:
638 case SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS:
639 case SPV_OPERAND_TYPE_SELECTION_CONTROL: {
640 // This operand is a mask.
David Neto201caf72015-11-04 17:38:17 -0500641
642 // Map an optional operand type to its corresponding concrete type.
643 if (type == SPV_OPERAND_TYPE_OPTIONAL_IMAGE)
644 parsed_operand.type = SPV_OPERAND_TYPE_IMAGE;
645 else if (type == SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS)
646 parsed_operand.type = SPV_OPERAND_TYPE_MEMORY_ACCESS;
647
David Neto0ca6b592015-10-30 16:06:15 -0400648 // Check validity of set mask bits. Also prepare for operands for those
649 // masks if they have any. To get operand order correct, scan from
650 // MSB to LSB since we can only prepend operands to a pattern.
651 // The only case in the grammar where you have more than one mask bit
652 // having an operand is for image operands. See SPIR-V 3.14 Image
653 // Operands.
654 uint32_t remaining_word = word;
655 for (uint32_t mask = (1u << 31); remaining_word; mask >>= 1) {
David Neto619db262015-09-25 12:43:37 -0400656 if (remaining_word & mask) {
David Neto619db262015-09-25 12:43:37 -0400657 spv_operand_desc entry;
David Neto0ca6b592015-10-30 16:06:15 -0400658 if (grammar_.lookupOperand(type, mask, &entry)) {
David Neto201caf72015-11-04 17:38:17 -0500659 return diagnostic()
660 << "Invalid " << spvOperandTypeStr(parsed_operand.type)
661 << " operand: " << word << " has invalid mask component "
662 << mask;
David Neto619db262015-09-25 12:43:37 -0400663 }
David Neto0ca6b592015-10-30 16:06:15 -0400664 remaining_word ^= mask;
665 spvPrependOperandTypes(entry->operandTypes, expected_operands);
David Neto619db262015-09-25 12:43:37 -0400666 }
667 }
David Neto0ca6b592015-10-30 16:06:15 -0400668 if (word == 0) {
669 // An all-zeroes mask *might* also be valid.
David Neto619db262015-09-25 12:43:37 -0400670 spv_operand_desc entry;
David Neto0ca6b592015-10-30 16:06:15 -0400671 if (SPV_SUCCESS == grammar_.lookupOperand(type, 0, &entry)) {
David Neto619db262015-09-25 12:43:37 -0400672 // Prepare for its operands, if any.
David Neto0ca6b592015-10-30 16:06:15 -0400673 spvPrependOperandTypes(entry->operandTypes, expected_operands);
David Neto619db262015-09-25 12:43:37 -0400674 }
675 }
David Neto619db262015-09-25 12:43:37 -0400676 } break;
David Neto0ca6b592015-10-30 16:06:15 -0400677 default:
678 return diagnostic() << "Internal error: Unhandled operand type: " << type;
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100679 }
680
David Neto0ca6b592015-10-30 16:06:15 -0400681 assert(int(SPV_OPERAND_TYPE_FIRST_CONCRETE_TYPE) <= int(parsed_operand.type));
682 assert(int(SPV_OPERAND_TYPE_LAST_CONCRETE_TYPE) >= int(parsed_operand.type));
683
684 operands->push_back(parsed_operand);
685
David Neto7bff3eb2015-11-20 14:21:10 -0500686 const size_t index_after_operand = _.word_index + parsed_operand.num_words;
David Netod9ad0502015-11-24 18:37:24 -0500687
688 // Avoid buffer overrun for the cases where the operand has more than one
689 // word, and where it isn't a string. (Those other cases have already been
690 // handled earlier.) For example, this error can occur for a multi-word
691 // argument to OpConstant, or a multi-word case literal operand for OpSwitch.
692 if (_.num_words < index_after_operand)
Lei Zhang6fa3f8a2016-03-31 17:26:31 -0400693 return exhaustedInputDiagnostic(inst_offset, opcode, type);
David Netod9ad0502015-11-24 18:37:24 -0500694
David Neto7bff3eb2015-11-20 14:21:10 -0500695 if (_.requires_endian_conversion) {
696 // Copy instruction words. Translate to native endianness as needed.
697 if (convert_operand_endianness) {
698 const spv_endianness_t endianness = _.endian;
699 std::transform(_.words + _.word_index, _.words + index_after_operand,
Andrew Woloszyn3b69d052016-01-11 13:54:30 -0500700 std::back_inserter(*words),
701 [endianness](const uint32_t raw_word) {
David Neto677e0c72016-01-05 14:56:02 -0500702 return spvFixWord(raw_word, endianness);
David Neto7bff3eb2015-11-20 14:21:10 -0500703 });
704 } else {
705 words->insert(words->end(), _.words + _.word_index,
706 _.words + index_after_operand);
707 }
708 }
709
710 // Advance past the operand.
711 _.word_index = index_after_operand;
David Neto0ca6b592015-10-30 16:06:15 -0400712
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100713 return SPV_SUCCESS;
714}
715
David Neto0ca6b592015-10-30 16:06:15 -0400716spv_result_t Parser::setNumericTypeInfoForType(
717 spv_parsed_operand_t* parsed_operand, uint32_t type_id) {
David Neto201caf72015-11-04 17:38:17 -0500718 assert(type_id != 0);
David Neto0ca6b592015-10-30 16:06:15 -0400719 auto type_info_iter = _.type_id_to_number_type_info.find(type_id);
720 if (type_info_iter == _.type_id_to_number_type_info.end()) {
721 return diagnostic() << "Type Id " << type_id << " is not a type";
722 }
723 const NumberType& info = type_info_iter->second;
724 if (info.type == SPV_NUMBER_NONE) {
725 // This is a valid type, but for something other than a scalar number.
726 return diagnostic() << "Type Id " << type_id
727 << " is not a scalar numeric type";
Andrew Woloszyn157e41b2015-10-16 15:11:00 -0400728 }
729
David Neto0ca6b592015-10-30 16:06:15 -0400730 parsed_operand->number_kind = info.type;
731 parsed_operand->number_bit_width = info.bit_width;
David Neto066bd522016-01-05 14:57:58 -0500732 // Round up the word count.
733 parsed_operand->num_words = static_cast<uint16_t>((info.bit_width + 31) / 32);
Andrew Woloszyn157e41b2015-10-16 15:11:00 -0400734 return SPV_SUCCESS;
735}
736
David Neto7bff3eb2015-11-20 14:21:10 -0500737void Parser::recordNumberType(size_t inst_offset,
738 const spv_parsed_instruction_t* inst) {
Lei Zhang6fa3f8a2016-03-31 17:26:31 -0400739 const SpvOp opcode = static_cast<SpvOp>(inst->opcode);
740 if (spvOpcodeGeneratesType(opcode)) {
David Neto0ca6b592015-10-30 16:06:15 -0400741 NumberType info = {SPV_NUMBER_NONE, 0};
Lei Zhang6fa3f8a2016-03-31 17:26:31 -0400742 if (SpvOpTypeInt == opcode) {
David Neto7bff3eb2015-11-20 14:21:10 -0500743 const bool is_signed = peekAt(inst_offset + 3) != 0;
David Neto0ca6b592015-10-30 16:06:15 -0400744 info.type = is_signed ? SPV_NUMBER_SIGNED_INT : SPV_NUMBER_UNSIGNED_INT;
David Neto7bff3eb2015-11-20 14:21:10 -0500745 info.bit_width = peekAt(inst_offset + 2);
Lei Zhang6fa3f8a2016-03-31 17:26:31 -0400746 } else if (SpvOpTypeFloat == opcode) {
David Neto0ca6b592015-10-30 16:06:15 -0400747 info.type = SPV_NUMBER_FLOATING;
David Neto7bff3eb2015-11-20 14:21:10 -0500748 info.bit_width = peekAt(inst_offset + 2);
Lei Zhang40056702015-09-11 14:31:27 -0400749 }
David Neto0ca6b592015-10-30 16:06:15 -0400750 // The *result* Id of a type generating instruction is the type Id.
751 _.type_id_to_number_type_info[inst->result_id] = info;
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100752 }
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100753}
754
David Neto0ca6b592015-10-30 16:06:15 -0400755} // anonymous namespace
Andrew Woloszyncfeac482015-09-09 13:04:32 -0400756
Lei Zhang972788b2015-11-12 13:48:30 -0500757spv_result_t spvBinaryParse(const spv_const_context context, void* user_data,
758 const uint32_t* code, const size_t num_words,
David Neto0ca6b592015-10-30 16:06:15 -0400759 spv_parsed_header_fn_t parsed_header,
760 spv_parsed_instruction_fn_t parsed_instruction,
761 spv_diagnostic* diagnostic) {
Lei Zhang755f97f2016-09-02 18:06:18 -0400762 spv_context_t hijack_context = *context;
763 if (diagnostic) {
764 *diagnostic = nullptr;
765 libspirv::UseDiagnosticAsMessageConsumer(&hijack_context, diagnostic);
766 }
767 Parser parser(&hijack_context, user_data, parsed_header, parsed_instruction);
David Neto0ca6b592015-10-30 16:06:15 -0400768 return parser.parse(code, num_words, diagnostic);
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100769}
770
David Neto0ca6b592015-10-30 16:06:15 -0400771// TODO(dneto): This probably belongs in text.cpp since that's the only place
772// that a spv_binary_t value is created.
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100773void spvBinaryDestroy(spv_binary binary) {
Lei Zhang40056702015-09-11 14:31:27 -0400774 if (!binary) return;
Eric Engestromeb6ae972016-02-18 23:41:16 +0000775 delete[] binary->code;
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100776 delete binary;
777}
David Neto37422e92016-12-19 13:26:42 -0500778
779size_t spv_strnlen_s(const char* str, size_t strsz) {
780 if (!str) return 0;
781 for (size_t i = 0; i < strsz; i++) {
782 if (!str[i]) return i;
783 }
784 return strsz;
785}