blob: 8657c55a966f9e3867f8929713d42da83fd7a4ac [file] [log] [blame]
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +01001// 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
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +010027#include "binary.h"
David Netofcc7d582015-10-27 15:31:10 -040028
29#include <cassert>
30#include <cstring>
David Neto0ca6b592015-10-30 16:06:15 -040031#include <limits>
David Netofcc7d582015-10-27 15:31:10 -040032#include <unordered_map>
33
David Netofcc7d582015-10-27 15:31:10 -040034#include "assembly_grammar.h"
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +010035#include "diagnostic.h"
David Netodb901b62015-10-27 16:14:40 -040036#include "endian.h"
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +010037#include "ext_inst.h"
Lei Zhang923f6c12015-11-11 12:45:23 -050038#include "libspirv/libspirv.h"
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +010039#include "opcode.h"
40#include "operand.h"
Lei Zhangaa056cd2015-11-11 14:24:04 -050041#include "spirv_constant.h"
Andrew Woloszyn157e41b2015-10-16 15:11:00 -040042
Andrew Woloszyn55ecc2e2015-11-11 11:05:07 -050043spv_result_t spvBinaryHeaderGet(const spv_const_binary binary,
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +010044 const spv_endianness_t endian,
Lei Zhang1a0334e2015-11-02 09:41:20 -050045 spv_header_t* pHeader) {
David Neto0ca6b592015-10-30 16:06:15 -040046 if (!binary->code) return SPV_ERROR_INVALID_BINARY;
47 if (binary->wordCount < SPV_INDEX_INSTRUCTION)
48 return SPV_ERROR_INVALID_BINARY;
Lei Zhang40056702015-09-11 14:31:27 -040049 if (!pHeader) return SPV_ERROR_INVALID_POINTER;
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +010050
51 // TODO: Validation checking?
52 pHeader->magic = spvFixWord(binary->code[SPV_INDEX_MAGIC_NUMBER], endian);
53 pHeader->version = spvFixWord(binary->code[SPV_INDEX_VERSION_NUMBER], endian);
54 pHeader->generator =
55 spvFixWord(binary->code[SPV_INDEX_GENERATOR_NUMBER], endian);
56 pHeader->bound = spvFixWord(binary->code[SPV_INDEX_BOUND], endian);
57 pHeader->schema = spvFixWord(binary->code[SPV_INDEX_SCHEMA], endian);
58 pHeader->instructions = &binary->code[SPV_INDEX_INSTRUCTION];
59
60 return SPV_SUCCESS;
61}
62
David Neto78c3b432015-08-27 13:03:52 -040063// TODO(dneto): This API is not powerful enough in the case that the
64// number and type of operands are not known until partway through parsing
65// the operation. This happens when enum operands might have different number
66// of operands, or with extended instructions.
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +010067spv_operand_type_t spvBinaryOperandInfo(const uint32_t word,
68 const uint16_t operandIndex,
69 const spv_opcode_desc opcodeEntry,
70 const spv_operand_table operandTable,
Lei Zhang1a0334e2015-11-02 09:41:20 -050071 spv_operand_desc* pOperandEntry) {
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +010072 spv_operand_type_t type;
David Neto78c3b432015-08-27 13:03:52 -040073 if (operandIndex < opcodeEntry->numTypes) {
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +010074 // NOTE: Do operand table lookup to set operandEntry if successful
75 uint16_t index = operandIndex - 1;
76 type = opcodeEntry->operandTypes[index];
77 spv_operand_desc entry = nullptr;
78 if (!spvOperandTableValueLookup(operandTable, type, word, &entry)) {
79 if (SPV_OPERAND_TYPE_NONE != entry->operandTypes[0]) {
80 *pOperandEntry = entry;
81 }
82 }
83 } else if (*pOperandEntry) {
84 // NOTE: Use specified operand entry operand type for this word
David Neto78c3b432015-08-27 13:03:52 -040085 uint16_t index = operandIndex - opcodeEntry->numTypes;
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +010086 type = (*pOperandEntry)->operandTypes[index];
Lei Zhangb36e7042015-10-28 13:40:52 -040087 } else if (SpvOpSwitch == opcodeEntry->opcode) {
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +010088 // NOTE: OpSwitch is a special case which expects a list of paired extra
89 // operands
90 assert(0 &&
91 "This case is previously untested, remove this assert and ensure it "
92 "is behaving correctly!");
David Neto78c3b432015-08-27 13:03:52 -040093 uint16_t lastIndex = opcodeEntry->numTypes - 1;
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +010094 uint16_t index = lastIndex + ((operandIndex - lastIndex) % 2);
95 type = opcodeEntry->operandTypes[index];
96 } else {
97 // NOTE: Default to last operand type in opcode entry
David Neto78c3b432015-08-27 13:03:52 -040098 uint16_t index = opcodeEntry->numTypes - 1;
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +010099 type = opcodeEntry->operandTypes[index];
100 }
101 return type;
102}
103
David Neto0ca6b592015-10-30 16:06:15 -0400104namespace {
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100105
David Neto0ca6b592015-10-30 16:06:15 -0400106// A SPIR-V binary parser. A parser instance communicates detailed parse
107// results via callbacks.
108class Parser {
109 public:
110 // The user_data value is provided to the callbacks as context.
Lei Zhang972788b2015-11-12 13:48:30 -0500111 Parser(const spv_const_context context, void* user_data,
112 spv_parsed_header_fn_t parsed_header_fn,
David Neto0ca6b592015-10-30 16:06:15 -0400113 spv_parsed_instruction_fn_t parsed_instruction_fn)
Lei Zhang972788b2015-11-12 13:48:30 -0500114 : grammar_(context),
115 user_data_(user_data),
David Neto0ca6b592015-10-30 16:06:15 -0400116 parsed_header_fn_(parsed_header_fn),
117 parsed_instruction_fn_(parsed_instruction_fn) {}
118
119 // Parses the specified binary SPIR-V module, issuing callbacks on a parsed
120 // header and for each parsed instruction. Returns SPV_SUCCESS on success.
121 // Otherwise returns an error code and issues a diagnostic.
122 spv_result_t parse(const uint32_t* words, size_t num_words,
123 spv_diagnostic* diagnostic);
124
125 private:
126 // All remaining methods work on the current module parse state.
127
128 // Like the parse method, but works on the current module parse state.
129 spv_result_t parseModule();
130
131 // Parses an instruction at the current position of the binary. Assumes
132 // the header has been parsed, the endian has been set, and the word index is
133 // still in range. Advances the parsing position past the instruction, and
134 // updates other parsing state for the current module.
135 // On success, returns SPV_SUCCESS and issues the parsed-instruction callback.
136 // On failure, returns an error code and issues a diagnostic.
137 spv_result_t parseInstruction();
138
139 // Parses an instruction operand with the given type.
140 // May update the expected_operands parameter, and the scalar members of the
141 // inst parameter. On success, returns SPV_SUCCESS, advances past the
142 // operand, and pushes a new entry on to the operands vector. Otherwise
143 // returns an error code and issues a diagnostic.
144 spv_result_t parseOperand(spv_parsed_instruction_t* inst,
145 const spv_operand_type_t type,
146 std::vector<spv_parsed_operand_t>* operands,
147 spv_operand_pattern_t* expected_operands);
148
149 // Records the numeric type for an operand according to the type information
150 // associated with the given non-zero type Id. This can fail if the type Id
151 // is not a type Id, or if the type Id does not reference a scalar numeric
152 // type. On success, return SPV_SUCCESS and populates the num_words,
153 // number_kind, and number_bit_width fields of parsed_operand.
154 spv_result_t setNumericTypeInfoForType(spv_parsed_operand_t* parsed_operand,
155 uint32_t type_id);
156
157 // Records the number type for an instruction if that instruction generates
158 // a type. For types that aren't scalar numbers, record something with
159 // number kind SPV_NUMBER_NONE.
160 void recordNumberType(const spv_parsed_instruction_t* inst);
161
162 // Returns a diagnostic stream object initialized with current position in
163 // the input stream, and for the given error code. Any data written to the
164 // returned object will be propagated to the current parse's diagnostic
165 // object.
166 DiagnosticStream diagnostic(spv_result_t error) {
167 return DiagnosticStream({0, 0, _.word_index}, _.diagnostic, error);
168 }
169
170 // Returns a diagnostic stream object with the default parse error code.
171 DiagnosticStream diagnostic() {
172 // The default failure for parsing is invalid binary.
173 return diagnostic(SPV_ERROR_INVALID_BINARY);
174 }
175
176 // Returns the endian-corrected word at the current position.
177 uint32_t peek() const { return peekAt(_.word_index); }
178
179 // Returns the endian-corrected word at the given position.
180 uint32_t peekAt(size_t index) const {
181 assert(index < _.num_words);
182 return spvFixWord(_.words[index], _.endian);
183 }
184
185 // Data members
186
187 const libspirv::AssemblyGrammar grammar_; // SPIR-V syntax utility.
188 void* const user_data_; // Context for the callbacks
189 const spv_parsed_header_fn_t parsed_header_fn_; // Parsed header callback
190 const spv_parsed_instruction_fn_t
191 parsed_instruction_fn_; // Parsed instruction callback
192
193 // Describes the format of a typed literal number.
194 struct NumberType {
195 spv_number_kind_t type;
196 uint32_t bit_width;
197 };
198
199 // The state used to parse a single SPIR-V binary module.
200 struct State {
201 State(const uint32_t* words_arg, size_t num_words_arg,
202 spv_diagnostic* diagnostic_arg)
203 : words(words_arg),
204 num_words(num_words_arg),
205 diagnostic(diagnostic_arg),
206 word_index(0),
207 endian() {}
208 State() : State(0, 0, nullptr) {}
209 const uint32_t* words; // Words in the binary SPIR-V module.
210 size_t num_words; // Number of words in the module.
211 spv_diagnostic* diagnostic; // Where diagnostics go.
212 size_t word_index; // The current position in words.
213 spv_endianness_t endian; // The endianness of the binary.
214
215 // Maps a result ID to its type ID. By convention:
216 // - a result ID that is a type definition maps to itself.
217 // - a result ID without a type maps to 0. (E.g. for OpLabel)
218 std::unordered_map<uint32_t, uint32_t> id_to_type_id;
219 // Maps a type ID to its number type description.
220 std::unordered_map<uint32_t, NumberType> type_id_to_number_type_info;
221 // Maps an ExtInstImport id to the extended instruction type.
222 std::unordered_map<uint32_t, spv_ext_inst_type_t>
223 import_id_to_ext_inst_type;
224 } _;
225};
226
227spv_result_t Parser::parse(const uint32_t* words, size_t num_words,
228 spv_diagnostic* diagnostic_arg) {
229 _ = State(words, num_words, diagnostic_arg);
230
231 const spv_result_t result = parseModule();
232
233 // Clear the module state. The tables might be big.
234 _ = State();
235
236 return result;
237}
238
239spv_result_t Parser::parseModule() {
240 if (!_.words) return diagnostic() << "Missing module.";
241
242 if (_.num_words < SPV_INDEX_INSTRUCTION)
243 return diagnostic() << "Module has incomplete header: only " << _.num_words
244 << " words instead of " << SPV_INDEX_INSTRUCTION;
245
246 // Check the magic number and detect the module's endianness.
Andrew Woloszyn55ecc2e2015-11-11 11:05:07 -0500247 spv_const_binary_t binary{_.words, _.num_words};
David Neto0ca6b592015-10-30 16:06:15 -0400248 if (spvBinaryEndianness(&binary, &_.endian)) {
249 return diagnostic() << "Invalid SPIR-V magic number '" << std::hex
250 << _.words[0] << "'.";
251 }
252
253 // Process the header.
254 spv_header_t header;
255 if (spvBinaryHeaderGet(&binary, _.endian, &header)) {
256 // It turns out there is no way to trigger this error since the only
257 // failure cases are already handled above, with better messages.
258 return diagnostic(SPV_ERROR_INTERNAL)
259 << "Internal error: unhandled header parse failure";
260 }
261 if (parsed_header_fn_) {
262 if (auto error = parsed_header_fn_(user_data_, _.endian, header.magic,
263 header.version, header.generator,
264 header.bound, header.schema)) {
265 return error;
266 }
267 }
268
269 // Process the instructions.
270 _.word_index = SPV_INDEX_INSTRUCTION;
271 while (_.word_index < _.num_words)
272 if (auto error = parseInstruction()) return error;
273
274 // Running off the end should already have been reported earlier.
275 assert(_.word_index == _.num_words);
276
277 return SPV_SUCCESS;
278}
279
280spv_result_t Parser::parseInstruction() {
281 // The zero values for all members except for opcode are the
282 // correct initial values.
283 spv_parsed_instruction_t inst = {};
284 inst.offset = _.word_index;
285
286 // After a successful parse of the instruction, the inst.operands member
287 // will point to this vector's storage.
288 // TODO(dneto): If it's too expensive to construct the operands vector for
289 // each instruction, then make this a class data member instead, and clear it
290 // here.
291 std::vector<spv_parsed_operand_t> operands;
292 // Most instructions have fewer than 25 logical operands.
293 operands.reserve(25);
294
295 assert(_.word_index < _.num_words);
296 // Decompose and check the first word.
297 uint16_t inst_word_count = 0;
298 spvOpcodeSplit(peek(), &inst_word_count, &inst.opcode);
299 if (inst_word_count < 1) {
300 return diagnostic() << "Invalid instruction word count: "
301 << inst_word_count;
302 }
303 spv_opcode_desc opcode_desc;
304 if (grammar_.lookupOpcode(inst.opcode, &opcode_desc))
305 return diagnostic() << "Invalid opcode: " << int(inst.opcode);
306
307 _.word_index++;
308
309 // Maintains the ordered list of expected operand types.
310 // For many instructions we only need the {numTypes, operandTypes}
311 // entries in opcode_desc. However, sometimes we need to modify
312 // the list as we parse the operands. This occurs when an operand
313 // has its own logical operands (such as the LocalSize operand for
314 // ExecutionMode), or for extended instructions that may have their
315 // own operands depending on the selected extended instruction.
316 spv_operand_pattern_t expected_operands(
317 opcode_desc->operandTypes,
318 opcode_desc->operandTypes + opcode_desc->numTypes);
319
320 while (_.word_index < inst.offset + inst_word_count) {
321 const uint16_t inst_word_index = _.word_index - inst.offset;
322 if (expected_operands.empty()) {
323 return diagnostic() << "Invalid instruction Op" << opcode_desc->name
324 << " starting at word " << inst.offset
325 << ": expected no more operands after "
326 << inst_word_index
327 << " words, but stated word count is "
328 << inst_word_count << ".";
329 }
330
331 spv_operand_type_t type = spvTakeFirstMatchableOperand(&expected_operands);
332
333 if (auto error = parseOperand(&inst, type, &operands, &expected_operands))
334 return error;
335 }
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 "
341 << inst.offset << ": expected more operands after "
342 << inst_word_count << " words.";
343 }
344
345 if ((inst.offset + inst_word_count) != _.word_index) {
346 return diagnostic() << "Invalid word count: Instruction starting at word "
347 << inst.offset << " says it has " << inst_word_count
348 << " words, but found " << _.word_index - inst.offset
349 << " words instead.";
350 }
351
352 recordNumberType(&inst);
353
354 // Must wait until here to set the inst.operands pointer because the vector
355 // might be resized while we accumulate itse elements.
356 inst.operands = operands.data();
357 inst.num_operands = operands.size();
358
359 // Issue the callback. The callee should know that all the storage in inst
360 // is transient, and will disappear immediately afterward.
361 if (parsed_instruction_fn_) {
362 if (auto error = parsed_instruction_fn_(user_data_, &inst)) return error;
363 }
364
365 return SPV_SUCCESS;
366}
367
368spv_result_t Parser::parseOperand(spv_parsed_instruction_t* inst,
369 const spv_operand_type_t type,
370 std::vector<spv_parsed_operand_t>* operands,
371 spv_operand_pattern_t* expected_operands) {
372 // We'll fill in this result as we go along.
373 spv_parsed_operand_t parsed_operand;
374 parsed_operand.offset = _.word_index - inst->offset;
375 // Most operands occupy one word. This might be be adjusted later.
376 parsed_operand.num_words = 1;
377 // The type argument is the one used by the grammar to parse the instruction.
378 // But it can exposes internal parser details such as whether an operand is
379 // optional or actually represents a variable-length sequence of operands.
380 // The resulting type should be adjusted to avoid those internal details.
381 // In most cases, the resulting operand type is the same as the grammar type.
382 parsed_operand.type = type;
383
384 // Assume non-numeric values. This will be updated for literal numbers.
385 parsed_operand.number_kind = SPV_NUMBER_NONE;
386 parsed_operand.number_bit_width = 0;
387
388 const uint32_t word = peek();
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100389
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100390 switch (type) {
Andrew Woloszyn537e7762015-09-29 11:28:34 -0400391 case SPV_OPERAND_TYPE_TYPE_ID:
David Neto0ca6b592015-10-30 16:06:15 -0400392 if (!word) return diagnostic() << "Error: Type Id is 0";
393 inst->type_id = word;
394 break;
395
396 case SPV_OPERAND_TYPE_RESULT_ID:
397 if (!word) return diagnostic() << "Error: Result Id is 0";
398 inst->result_id = word;
399 // Save the result ID to type ID mapping.
400 // In the grammar, type ID always appears before result ID.
401 if (_.id_to_type_id.find(inst->result_id) != _.id_to_type_id.end())
402 return diagnostic() << "Id " << inst->result_id
403 << " is defined more than once";
404 // Record it.
405 // A regular value maps to its type. Some instructions (e.g. OpLabel)
406 // have no type Id, and will map to 0. The result Id for a
407 // type-generating instruction (e.g. OpTypeInt) maps to itself.
408 _.id_to_type_id[inst->result_id] = spvOpcodeGeneratesType(inst->opcode)
409 ? inst->result_id
410 : inst->type_id;
411 break;
412
413 case SPV_OPERAND_TYPE_ID:
David Neto78c3b432015-08-27 13:03:52 -0400414 case SPV_OPERAND_TYPE_OPTIONAL_ID:
David Neto0ca6b592015-10-30 16:06:15 -0400415 if (!word) return diagnostic() << "Id is 0";
416 parsed_operand.type = SPV_OPERAND_TYPE_ID;
417
418 if (inst->opcode == SpvOpExtInst && parsed_operand.offset == 3) {
419 // The current word is the extended instruction set Id.
420 // Set the extended instruction set type for the current instruction.
421 auto ext_inst_type_iter = _.import_id_to_ext_inst_type.find(word);
422 if (ext_inst_type_iter == _.import_id_to_ext_inst_type.end()) {
423 return diagnostic()
424 << "OpExtInst set Id " << word
425 << " does not reference an OpExtInstImport result Id";
426 }
427 inst->ext_inst_type = ext_inst_type_iter->second;
428 }
429 break;
430
David Neto64a9be92015-11-18 15:48:32 -0500431 case SPV_OPERAND_TYPE_SCOPE_ID:
432 case SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID:
David Neto0ca6b592015-10-30 16:06:15 -0400433 if (!word) return diagnostic() << spvOperandTypeStr(type) << " Id is 0";
434 break;
435
David Neto445ce442015-10-15 15:22:06 -0400436 case SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER: {
David Neto0ca6b592015-10-30 16:06:15 -0400437 assert(SpvOpExtInst == inst->opcode);
438 assert(inst->ext_inst_type != SPV_EXT_INST_TYPE_NONE);
439 spv_ext_inst_desc ext_inst;
440 if (grammar_.lookupExtInst(inst->ext_inst_type, word, &ext_inst))
441 return diagnostic() << "Invalid extended instruction number: " << word;
442 spvPrependOperandTypes(ext_inst->operandTypes, expected_operands);
David Neto445ce442015-10-15 15:22:06 -0400443 } break;
David Neto0ca6b592015-10-30 16:06:15 -0400444
David Neto21196942015-11-11 02:45:45 -0500445 case SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER: {
446 assert(SpvOpSpecConstantOp == inst->opcode);
447 if (grammar_.lookupSpecConstantOpcode(SpvOp(word))) {
448 return diagnostic() << "Invalid " << spvOperandTypeStr(type) << ": "
449 << word;
450 }
451 spv_opcode_desc opcode_entry = nullptr;
452 if (grammar_.lookupOpcode(SpvOp(word), &opcode_entry)) {
453 return diagnostic(SPV_ERROR_INTERNAL)
454 << "OpSpecConstant opcode table out of sync";
455 }
456 // OpSpecConstant opcodes must have a type and result. We've already
457 // processed them, so skip them when preparing to parse the other
458 // operants for the opcode.
459 assert(opcode_entry->hasType);
460 assert(opcode_entry->hasResult);
461 assert(opcode_entry->numTypes >= 2);
462 spvPrependOperandTypes(opcode_entry->operandTypes + 2, expected_operands);
463 } break;
464
David Neto445ce442015-10-15 15:22:06 -0400465 case SPV_OPERAND_TYPE_LITERAL_INTEGER:
Lei Zhang6483bd72015-10-14 17:02:39 -0400466 case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_INTEGER:
David Neto201caf72015-11-04 17:38:17 -0500467 // These are regular single-word literal integer operands.
468 // Post-parsing validation should check the range of the parsed value.
David Neto0ca6b592015-10-30 16:06:15 -0400469 parsed_operand.type = SPV_OPERAND_TYPE_LITERAL_INTEGER;
David Neto201caf72015-11-04 17:38:17 -0500470 // It turns out they are always unsigned integers!
471 parsed_operand.number_kind = SPV_NUMBER_UNSIGNED_INT;
472 parsed_operand.number_bit_width = 32;
473 break;
474
475 case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER:
476 case SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER:
Lei Zhangaa3cd5a2015-11-10 14:29:35 -0500477 parsed_operand.type = SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER;
David Neto0ca6b592015-10-30 16:06:15 -0400478 if (inst->opcode == SpvOpSwitch) {
479 // The literal operands have the same type as the value
480 // referenced by the selector Id.
481 const uint32_t selector_id = peekAt(inst->offset + 1);
482 auto type_id_iter = _.id_to_type_id.find(selector_id);
483 if (type_id_iter == _.id_to_type_id.end()) {
484 return diagnostic() << "Invalid OpSwitch: selector id " << selector_id
485 << " has no type";
486 }
487 uint32_t type_id = type_id_iter->second;
488
489 if (selector_id == type_id) {
490 // Recall that by convention, a result ID that is a type definition
491 // maps to itself.
492 return diagnostic() << "Invalid OpSwitch: selector id " << selector_id
493 << " is a type, not a value";
494 }
495 if (auto error = setNumericTypeInfoForType(&parsed_operand, type_id))
496 return error;
497 if (parsed_operand.number_kind != SPV_NUMBER_UNSIGNED_INT &&
498 parsed_operand.number_kind != SPV_NUMBER_SIGNED_INT) {
499 return diagnostic() << "Invalid OpSwitch: selector id " << selector_id
500 << " is not a scalar integer";
501 }
Lei Zhangb41d1502015-09-14 15:22:23 -0400502 } else {
David Neto201caf72015-11-04 17:38:17 -0500503 assert(inst->opcode == SpvOpConstant ||
504 inst->opcode == SpvOpSpecConstant);
505 // The literal number type is determined by the type Id for the
506 // constant.
507 assert(inst->type_id);
508 if (auto error =
509 setNumericTypeInfoForType(&parsed_operand, inst->type_id))
510 return error;
Lei Zhangb41d1502015-09-14 15:22:23 -0400511 }
David Neto0ca6b592015-10-30 16:06:15 -0400512 break;
513
David Neto78c3b432015-08-27 13:03:52 -0400514 case SPV_OPERAND_TYPE_LITERAL_STRING:
515 case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_STRING: {
David Neto0ca6b592015-10-30 16:06:15 -0400516 // TODO(dneto): Make and use spvFixupString();
517 const char* string =
518 reinterpret_cast<const char*>(_.words + _.word_index);
519 size_t string_num_words = (strlen(string) / 4) + 1; // Account for null.
520 // Make sure we can record the word count without overflow.
521 // We still might have a string that's 64K words, but would still
522 // make the instruction too long because of earlier operands.
523 // That will be caught later at the end of the instruciton.
524 if (string_num_words > std::numeric_limits<uint16_t>::max()) {
525 return diagnostic() << "Literal string is longer than "
526 << std::numeric_limits<uint16_t>::max()
527 << " words: " << string_num_words << " words long";
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100528 }
David Neto0ca6b592015-10-30 16:06:15 -0400529 parsed_operand.num_words = string_num_words;
530 parsed_operand.type = SPV_OPERAND_TYPE_LITERAL_STRING;
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100531
David Neto0ca6b592015-10-30 16:06:15 -0400532 if (SpvOpExtInstImport == inst->opcode) {
533 // Record the extended instruction type for the ID for this import.
534 // There is only one string literal argument to OpExtInstImport,
535 // so it's sufficient to guard this just on the opcode.
536 const spv_ext_inst_type_t ext_inst_type =
537 spvExtInstImportTypeGet(string);
538 if (SPV_EXT_INST_TYPE_NONE == ext_inst_type) {
539 return diagnostic() << "Invalid extended instruction import '"
540 << string << "'";
Andrew Woloszyne59e6b72015-10-14 14:18:43 -0400541 }
David Neto0ca6b592015-10-30 16:06:15 -0400542 // We must have parsed a valid result ID. It's a condition
543 // of the grammar, and we only accept non-zero result Ids.
544 assert(inst->result_id);
545 _.import_id_to_ext_inst_type[inst->result_id] = ext_inst_type;
Andrew Woloszyne59e6b72015-10-14 14:18:43 -0400546 }
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100547 } break;
David Neto0ca6b592015-10-30 16:06:15 -0400548
549 case SPV_OPERAND_TYPE_OPTIONAL_EXECUTION_MODE:
550 parsed_operand.type = SPV_OPERAND_TYPE_EXECUTION_MODE;
551 // Fall through
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100552 case SPV_OPERAND_TYPE_CAPABILITY:
553 case SPV_OPERAND_TYPE_SOURCE_LANGUAGE:
554 case SPV_OPERAND_TYPE_EXECUTION_MODEL:
555 case SPV_OPERAND_TYPE_ADDRESSING_MODEL:
556 case SPV_OPERAND_TYPE_MEMORY_MODEL:
557 case SPV_OPERAND_TYPE_EXECUTION_MODE:
558 case SPV_OPERAND_TYPE_STORAGE_CLASS:
559 case SPV_OPERAND_TYPE_DIMENSIONALITY:
560 case SPV_OPERAND_TYPE_SAMPLER_ADDRESSING_MODE:
561 case SPV_OPERAND_TYPE_SAMPLER_FILTER_MODE:
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100562 case SPV_OPERAND_TYPE_FP_ROUNDING_MODE:
563 case SPV_OPERAND_TYPE_LINKAGE_TYPE:
564 case SPV_OPERAND_TYPE_ACCESS_QUALIFIER:
565 case SPV_OPERAND_TYPE_FUNCTION_PARAMETER_ATTRIBUTE:
566 case SPV_OPERAND_TYPE_DECORATION:
567 case SPV_OPERAND_TYPE_BUILT_IN:
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100568 case SPV_OPERAND_TYPE_GROUP_OPERATION:
569 case SPV_OPERAND_TYPE_KERNEL_ENQ_FLAGS:
David Neto47994822015-08-27 13:11:01 -0400570 case SPV_OPERAND_TYPE_KERNEL_PROFILING_INFO: {
David Neto0ca6b592015-10-30 16:06:15 -0400571 // A single word that is a plain enum value.
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100572 spv_operand_desc entry;
David Neto0ca6b592015-10-30 16:06:15 -0400573 if (grammar_.lookupOperand(type, word, &entry)) {
David Neto201caf72015-11-04 17:38:17 -0500574 return diagnostic() << "Invalid "
575 << spvOperandTypeStr(parsed_operand.type)
David Neto0ca6b592015-10-30 16:06:15 -0400576 << " operand: " << word;
Lei Zhang40056702015-09-11 14:31:27 -0400577 }
David Neto78c3b432015-08-27 13:03:52 -0400578 // Prepare to accept operands to this operand, if needed.
David Neto0ca6b592015-10-30 16:06:15 -0400579 spvPrependOperandTypes(entry->operandTypes, expected_operands);
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100580 } break;
David Neto0ca6b592015-10-30 16:06:15 -0400581
David Neto619db262015-09-25 12:43:37 -0400582 case SPV_OPERAND_TYPE_FP_FAST_MATH_MODE:
583 case SPV_OPERAND_TYPE_FUNCTION_CONTROL:
584 case SPV_OPERAND_TYPE_LOOP_CONTROL:
585 case SPV_OPERAND_TYPE_OPTIONAL_IMAGE:
586 case SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS:
587 case SPV_OPERAND_TYPE_SELECTION_CONTROL: {
588 // This operand is a mask.
David Neto201caf72015-11-04 17:38:17 -0500589
590 // Map an optional operand type to its corresponding concrete type.
591 if (type == SPV_OPERAND_TYPE_OPTIONAL_IMAGE)
592 parsed_operand.type = SPV_OPERAND_TYPE_IMAGE;
593 else if (type == SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS)
594 parsed_operand.type = SPV_OPERAND_TYPE_MEMORY_ACCESS;
595
David Neto0ca6b592015-10-30 16:06:15 -0400596 // Check validity of set mask bits. Also prepare for operands for those
597 // masks if they have any. To get operand order correct, scan from
598 // MSB to LSB since we can only prepend operands to a pattern.
599 // The only case in the grammar where you have more than one mask bit
600 // having an operand is for image operands. See SPIR-V 3.14 Image
601 // Operands.
602 uint32_t remaining_word = word;
603 for (uint32_t mask = (1u << 31); remaining_word; mask >>= 1) {
David Neto619db262015-09-25 12:43:37 -0400604 if (remaining_word & mask) {
David Neto619db262015-09-25 12:43:37 -0400605 spv_operand_desc entry;
David Neto0ca6b592015-10-30 16:06:15 -0400606 if (grammar_.lookupOperand(type, mask, &entry)) {
David Neto201caf72015-11-04 17:38:17 -0500607 return diagnostic()
608 << "Invalid " << spvOperandTypeStr(parsed_operand.type)
609 << " operand: " << word << " has invalid mask component "
610 << mask;
David Neto619db262015-09-25 12:43:37 -0400611 }
David Neto0ca6b592015-10-30 16:06:15 -0400612 remaining_word ^= mask;
613 spvPrependOperandTypes(entry->operandTypes, expected_operands);
David Neto619db262015-09-25 12:43:37 -0400614 }
615 }
David Neto0ca6b592015-10-30 16:06:15 -0400616 if (word == 0) {
617 // An all-zeroes mask *might* also be valid.
David Neto619db262015-09-25 12:43:37 -0400618 spv_operand_desc entry;
David Neto0ca6b592015-10-30 16:06:15 -0400619 if (SPV_SUCCESS == grammar_.lookupOperand(type, 0, &entry)) {
David Neto619db262015-09-25 12:43:37 -0400620 // Prepare for its operands, if any.
David Neto0ca6b592015-10-30 16:06:15 -0400621 spvPrependOperandTypes(entry->operandTypes, expected_operands);
David Neto619db262015-09-25 12:43:37 -0400622 }
623 }
David Neto619db262015-09-25 12:43:37 -0400624 } break;
David Neto0ca6b592015-10-30 16:06:15 -0400625 default:
626 return diagnostic() << "Internal error: Unhandled operand type: " << type;
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100627 }
628
David Neto0ca6b592015-10-30 16:06:15 -0400629 assert(int(SPV_OPERAND_TYPE_FIRST_CONCRETE_TYPE) <= int(parsed_operand.type));
630 assert(int(SPV_OPERAND_TYPE_LAST_CONCRETE_TYPE) >= int(parsed_operand.type));
631
632 operands->push_back(parsed_operand);
633
634 _.word_index += parsed_operand.num_words;
635
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100636 return SPV_SUCCESS;
637}
638
David Neto0ca6b592015-10-30 16:06:15 -0400639spv_result_t Parser::setNumericTypeInfoForType(
640 spv_parsed_operand_t* parsed_operand, uint32_t type_id) {
David Neto201caf72015-11-04 17:38:17 -0500641 assert(type_id != 0);
David Neto0ca6b592015-10-30 16:06:15 -0400642 auto type_info_iter = _.type_id_to_number_type_info.find(type_id);
643 if (type_info_iter == _.type_id_to_number_type_info.end()) {
644 return diagnostic() << "Type Id " << type_id << " is not a type";
645 }
646 const NumberType& info = type_info_iter->second;
647 if (info.type == SPV_NUMBER_NONE) {
648 // This is a valid type, but for something other than a scalar number.
649 return diagnostic() << "Type Id " << type_id
650 << " is not a scalar numeric type";
Andrew Woloszyn157e41b2015-10-16 15:11:00 -0400651 }
652
David Neto0ca6b592015-10-30 16:06:15 -0400653 parsed_operand->number_kind = info.type;
654 parsed_operand->number_bit_width = info.bit_width;
David Neto229b90f2015-11-06 11:23:57 -0500655 parsed_operand->num_words = (info.bit_width + 31) / 32; // Round up
Andrew Woloszyn157e41b2015-10-16 15:11:00 -0400656 return SPV_SUCCESS;
657}
658
David Neto0ca6b592015-10-30 16:06:15 -0400659void Parser::recordNumberType(const spv_parsed_instruction_t* inst) {
660 if (spvOpcodeGeneratesType(inst->opcode)) {
661 NumberType info = {SPV_NUMBER_NONE, 0};
662 if (SpvOpTypeInt == inst->opcode) {
663 const bool is_signed = peekAt(inst->offset + 3) != 0;
664 info.type = is_signed ? SPV_NUMBER_SIGNED_INT : SPV_NUMBER_UNSIGNED_INT;
665 info.bit_width = peekAt(inst->offset + 2);
666 } else if (SpvOpTypeFloat == inst->opcode) {
667 info.type = SPV_NUMBER_FLOATING;
668 info.bit_width = peekAt(inst->offset + 2);
Lei Zhang40056702015-09-11 14:31:27 -0400669 }
David Neto0ca6b592015-10-30 16:06:15 -0400670 // The *result* Id of a type generating instruction is the type Id.
671 _.type_id_to_number_type_info[inst->result_id] = info;
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100672 }
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100673}
674
David Neto0ca6b592015-10-30 16:06:15 -0400675} // anonymous namespace
Andrew Woloszyncfeac482015-09-09 13:04:32 -0400676
Lei Zhang972788b2015-11-12 13:48:30 -0500677spv_result_t spvBinaryParse(const spv_const_context context, void* user_data,
678 const uint32_t* code, const size_t num_words,
David Neto0ca6b592015-10-30 16:06:15 -0400679 spv_parsed_header_fn_t parsed_header,
680 spv_parsed_instruction_fn_t parsed_instruction,
681 spv_diagnostic* diagnostic) {
Lei Zhang972788b2015-11-12 13:48:30 -0500682 Parser parser(context, user_data, parsed_header, parsed_instruction);
David Neto0ca6b592015-10-30 16:06:15 -0400683 return parser.parse(code, num_words, diagnostic);
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100684}
685
David Neto0ca6b592015-10-30 16:06:15 -0400686// TODO(dneto): This probably belongs in text.cpp since that's the only place
687// that a spv_binary_t value is created.
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100688void spvBinaryDestroy(spv_binary binary) {
Lei Zhang40056702015-09-11 14:31:27 -0400689 if (!binary) return;
Kenneth Benzie (Benie)83e5a292015-05-22 18:26:19 +0100690 if (binary->code) {
691 delete[] binary->code;
692 }
693 delete binary;
694}