xref: /aosp_15_r20/external/angle/third_party/spirv-tools/src/source/binary.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 // Copyright (c) 2015-2020 The Khronos Group Inc.
2 // Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights
3 // reserved.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 
17 #include "source/binary.h"
18 
19 #include <algorithm>
20 #include <cassert>
21 #include <cstring>
22 #include <iterator>
23 #include <limits>
24 #include <string>
25 #include <unordered_map>
26 #include <vector>
27 
28 #include "source/assembly_grammar.h"
29 #include "source/diagnostic.h"
30 #include "source/ext_inst.h"
31 #include "source/latest_version_spirv_header.h"
32 #include "source/opcode.h"
33 #include "source/operand.h"
34 #include "source/spirv_constant.h"
35 #include "source/spirv_endian.h"
36 #include "source/util/string_utils.h"
37 
spvBinaryHeaderGet(const spv_const_binary binary,const spv_endianness_t endian,spv_header_t * pHeader)38 spv_result_t spvBinaryHeaderGet(const spv_const_binary binary,
39                                 const spv_endianness_t endian,
40                                 spv_header_t* pHeader) {
41   if (!binary->code) return SPV_ERROR_INVALID_BINARY;
42   if (binary->wordCount < SPV_INDEX_INSTRUCTION)
43     return SPV_ERROR_INVALID_BINARY;
44   if (!pHeader) return SPV_ERROR_INVALID_POINTER;
45 
46   // TODO: Validation checking?
47   pHeader->magic = spvFixWord(binary->code[SPV_INDEX_MAGIC_NUMBER], endian);
48   pHeader->version = spvFixWord(binary->code[SPV_INDEX_VERSION_NUMBER], endian);
49   // Per 2.3.1 version's high and low bytes are 0
50   if ((pHeader->version & 0x000000ff) || pHeader->version & 0xff000000)
51     return SPV_ERROR_INVALID_BINARY;
52   // Minimum version was 1.0 and max version is defined by SPV_VERSION.
53   if (pHeader->version < SPV_SPIRV_VERSION_WORD(1, 0) ||
54       pHeader->version > SPV_VERSION)
55     return SPV_ERROR_INVALID_BINARY;
56 
57   pHeader->generator =
58       spvFixWord(binary->code[SPV_INDEX_GENERATOR_NUMBER], endian);
59   pHeader->bound = spvFixWord(binary->code[SPV_INDEX_BOUND], endian);
60   pHeader->schema = spvFixWord(binary->code[SPV_INDEX_SCHEMA], endian);
61   pHeader->instructions = &binary->code[SPV_INDEX_INSTRUCTION];
62 
63   return SPV_SUCCESS;
64 }
65 
spvDecodeLiteralStringOperand(const spv_parsed_instruction_t & inst,const uint16_t operand_index)66 std::string spvDecodeLiteralStringOperand(const spv_parsed_instruction_t& inst,
67                                           const uint16_t operand_index) {
68   assert(operand_index < inst.num_operands);
69   const spv_parsed_operand_t& operand = inst.operands[operand_index];
70 
71   return spvtools::utils::MakeString(inst.words + operand.offset,
72                                      operand.num_words);
73 }
74 
75 namespace {
76 
77 // A SPIR-V binary parser.  A parser instance communicates detailed parse
78 // results via callbacks.
79 class Parser {
80  public:
81   // The user_data value is provided to the callbacks as context.
Parser(const spv_const_context context,void * user_data,spv_parsed_header_fn_t parsed_header_fn,spv_parsed_instruction_fn_t parsed_instruction_fn)82   Parser(const spv_const_context context, void* user_data,
83          spv_parsed_header_fn_t parsed_header_fn,
84          spv_parsed_instruction_fn_t parsed_instruction_fn)
85       : grammar_(context),
86         consumer_(context->consumer),
87         user_data_(user_data),
88         parsed_header_fn_(parsed_header_fn),
89         parsed_instruction_fn_(parsed_instruction_fn) {}
90 
91   // Parses the specified binary SPIR-V module, issuing callbacks on a parsed
92   // header and for each parsed instruction.  Returns SPV_SUCCESS on success.
93   // Otherwise returns an error code and issues a diagnostic.
94   spv_result_t parse(const uint32_t* words, size_t num_words,
95                      spv_diagnostic* diagnostic);
96 
97  private:
98   // All remaining methods work on the current module parse state.
99 
100   // Like the parse method, but works on the current module parse state.
101   spv_result_t parseModule();
102 
103   // Parses an instruction at the current position of the binary.  Assumes
104   // the header has been parsed, the endian has been set, and the word index is
105   // still in range.  Advances the parsing position past the instruction, and
106   // updates other parsing state for the current module.
107   // On success, returns SPV_SUCCESS and issues the parsed-instruction callback.
108   // On failure, returns an error code and issues a diagnostic.
109   spv_result_t parseInstruction();
110 
111   // Parses an instruction operand with the given type, for an instruction
112   // starting at inst_offset words into the SPIR-V binary.
113   // If the SPIR-V binary is the same endianness as the host, then the
114   // endian_converted_inst_words parameter is ignored.  Otherwise, this method
115   // appends the words for this operand, converted to host native endianness,
116   // to the end of endian_converted_inst_words.  This method also updates the
117   // expected_operands parameter, and the scalar members of the inst parameter.
118   // On success, returns SPV_SUCCESS, advances past the operand, and pushes a
119   // new entry on to the operands vector.  Otherwise returns an error code and
120   // issues a diagnostic.
121   spv_result_t parseOperand(size_t inst_offset, spv_parsed_instruction_t* inst,
122                             const spv_operand_type_t type,
123                             std::vector<uint32_t>* endian_converted_inst_words,
124                             std::vector<spv_parsed_operand_t>* operands,
125                             spv_operand_pattern_t* expected_operands);
126 
127   // Records the numeric type for an operand according to the type information
128   // associated with the given non-zero type Id.  This can fail if the type Id
129   // is not a type Id, or if the type Id does not reference a scalar numeric
130   // type.  On success, return SPV_SUCCESS and populates the num_words,
131   // number_kind, and number_bit_width fields of parsed_operand.
132   spv_result_t setNumericTypeInfoForType(spv_parsed_operand_t* parsed_operand,
133                                          uint32_t type_id);
134 
135   // Records the number type for an instruction at the given offset, if that
136   // instruction generates a type.  For types that aren't scalar numbers,
137   // record something with number kind SPV_NUMBER_NONE.
138   void recordNumberType(size_t inst_offset,
139                         const spv_parsed_instruction_t* inst);
140 
141   // Returns a diagnostic stream object initialized with current position in
142   // the input stream, and for the given error code. Any data written to the
143   // returned object will be propagated to the current parse's diagnostic
144   // object.
diagnostic(spv_result_t error)145   spvtools::DiagnosticStream diagnostic(spv_result_t error) {
146     return spvtools::DiagnosticStream({0, 0, _.instruction_count}, consumer_,
147                                       "", error);
148   }
149 
150   // Returns a diagnostic stream object with the default parse error code.
diagnostic()151   spvtools::DiagnosticStream diagnostic() {
152     // The default failure for parsing is invalid binary.
153     return diagnostic(SPV_ERROR_INVALID_BINARY);
154   }
155 
156   // Issues a diagnostic describing an exhaustion of input condition when
157   // trying to decode an instruction operand, and returns
158   // SPV_ERROR_INVALID_BINARY.
exhaustedInputDiagnostic(size_t inst_offset,spv::Op opcode,spv_operand_type_t type)159   spv_result_t exhaustedInputDiagnostic(size_t inst_offset, spv::Op opcode,
160                                         spv_operand_type_t type) {
161     return diagnostic() << "End of input reached while decoding Op"
162                         << spvOpcodeString(opcode) << " starting at word "
163                         << inst_offset
164                         << ((_.word_index < _.num_words) ? ": truncated "
165                                                          : ": missing ")
166                         << spvOperandTypeStr(type) << " operand at word offset "
167                         << _.word_index - inst_offset << ".";
168   }
169 
170   // Returns the endian-corrected word at the current position.
peek() const171   uint32_t peek() const { return peekAt(_.word_index); }
172 
173   // Returns the endian-corrected word at the given position.
peekAt(size_t index) const174   uint32_t peekAt(size_t index) const {
175     assert(index < _.num_words);
176     return spvFixWord(_.words[index], _.endian);
177   }
178 
179   // Data members
180 
181   const spvtools::AssemblyGrammar grammar_;        // SPIR-V syntax utility.
182   const spvtools::MessageConsumer& consumer_;      // Message consumer callback.
183   void* const user_data_;                          // Context for the callbacks
184   const spv_parsed_header_fn_t parsed_header_fn_;  // Parsed header callback
185   const spv_parsed_instruction_fn_t
186       parsed_instruction_fn_;  // Parsed instruction callback
187 
188   // Describes the format of a typed literal number.
189   struct NumberType {
190     spv_number_kind_t type;
191     uint32_t bit_width;
192   };
193 
194   // The state used to parse a single SPIR-V binary module.
195   struct State {
State__anon720ffbe40111::Parser::State196     State(const uint32_t* words_arg, size_t num_words_arg,
197           spv_diagnostic* diagnostic_arg)
198         : words(words_arg),
199           num_words(num_words_arg),
200           diagnostic(diagnostic_arg),
201           word_index(0),
202           instruction_count(0),
203           endian(),
204           requires_endian_conversion(false) {
205       // Temporary storage for parser state within a single instruction.
206       // Most instructions require fewer than 25 words or operands.
207       operands.reserve(25);
208       endian_converted_words.reserve(25);
209       expected_operands.reserve(25);
210     }
State__anon720ffbe40111::Parser::State211     State() : State(0, 0, nullptr) {}
212     const uint32_t* words;       // Words in the binary SPIR-V module.
213     size_t num_words;            // Number of words in the module.
214     spv_diagnostic* diagnostic;  // Where diagnostics go.
215     size_t word_index;           // The current position in words.
216     size_t instruction_count;    // The count of processed instructions
217     spv_endianness_t endian;     // The endianness of the binary.
218     // Is the SPIR-V binary in a different endianness from the host native
219     // endianness?
220     bool requires_endian_conversion;
221 
222     // Maps a result ID to its type ID.  By convention:
223     //  - a result ID that is a type definition maps to itself.
224     //  - a result ID without a type maps to 0.  (E.g. for OpLabel)
225     std::unordered_map<uint32_t, uint32_t> id_to_type_id;
226     // Maps a type ID to its number type description.
227     std::unordered_map<uint32_t, NumberType> type_id_to_number_type_info;
228     // Maps an ExtInstImport id to the extended instruction type.
229     std::unordered_map<uint32_t, spv_ext_inst_type_t>
230         import_id_to_ext_inst_type;
231 
232     // Used by parseOperand
233     std::vector<spv_parsed_operand_t> operands;
234     std::vector<uint32_t> endian_converted_words;
235     spv_operand_pattern_t expected_operands;
236   } _;
237 };
238 
parse(const uint32_t * words,size_t num_words,spv_diagnostic * diagnostic_arg)239 spv_result_t Parser::parse(const uint32_t* words, size_t num_words,
240                            spv_diagnostic* diagnostic_arg) {
241   _ = State(words, num_words, diagnostic_arg);
242 
243   const spv_result_t result = parseModule();
244 
245   // Clear the module state.  The tables might be big.
246   _ = State();
247 
248   return result;
249 }
250 
parseModule()251 spv_result_t Parser::parseModule() {
252   if (!_.words) return diagnostic() << "Missing module.";
253 
254   if (_.num_words < SPV_INDEX_INSTRUCTION)
255     return diagnostic() << "Module has incomplete header: only " << _.num_words
256                         << " words instead of " << SPV_INDEX_INSTRUCTION;
257 
258   // Check the magic number and detect the module's endianness.
259   spv_const_binary_t binary{_.words, _.num_words};
260   if (spvBinaryEndianness(&binary, &_.endian)) {
261     return diagnostic() << "Invalid SPIR-V magic number '" << std::hex
262                         << _.words[0] << "'.";
263   }
264   _.requires_endian_conversion = !spvIsHostEndian(_.endian);
265 
266   // Process the header.
267   spv_header_t header;
268   if (spvBinaryHeaderGet(&binary, _.endian, &header)) {
269     // It turns out there is no way to trigger this error since the only
270     // failure cases are already handled above, with better messages.
271     return diagnostic(SPV_ERROR_INTERNAL)
272            << "Internal error: unhandled header parse failure";
273   }
274   if (parsed_header_fn_) {
275     if (auto error = parsed_header_fn_(user_data_, _.endian, header.magic,
276                                        header.version, header.generator,
277                                        header.bound, header.schema)) {
278       return error;
279     }
280   }
281 
282   // Process the instructions.
283   _.word_index = SPV_INDEX_INSTRUCTION;
284   while (_.word_index < _.num_words)
285     if (auto error = parseInstruction()) return error;
286 
287   // Running off the end should already have been reported earlier.
288   assert(_.word_index == _.num_words);
289 
290   return SPV_SUCCESS;
291 }
292 
parseInstruction()293 spv_result_t Parser::parseInstruction() {
294   _.instruction_count++;
295 
296   // The zero values for all members except for opcode are the
297   // correct initial values.
298   spv_parsed_instruction_t inst = {};
299 
300   const uint32_t first_word = peek();
301 
302   // If the module's endianness is different from the host native endianness,
303   // then converted_words contains the endian-translated words in the
304   // instruction.
305   _.endian_converted_words.clear();
306   _.endian_converted_words.push_back(first_word);
307 
308   // After a successful parse of the instruction, the inst.operands member
309   // will point to this vector's storage.
310   _.operands.clear();
311 
312   assert(_.word_index < _.num_words);
313   // Decompose and check the first word.
314   uint16_t inst_word_count = 0;
315   spvOpcodeSplit(first_word, &inst_word_count, &inst.opcode);
316   if (inst_word_count < 1) {
317     return diagnostic() << "Invalid instruction word count: "
318                         << inst_word_count;
319   }
320   spv_opcode_desc opcode_desc;
321   if (grammar_.lookupOpcode(static_cast<spv::Op>(inst.opcode), &opcode_desc))
322     return diagnostic() << "Invalid opcode: " << inst.opcode;
323 
324   // Advance past the opcode word.  But remember the of the start
325   // of the instruction.
326   const size_t inst_offset = _.word_index;
327   _.word_index++;
328 
329   // Maintains the ordered list of expected operand types.
330   // For many instructions we only need the {numTypes, operandTypes}
331   // entries in opcode_desc.  However, sometimes we need to modify
332   // the list as we parse the operands. This occurs when an operand
333   // has its own logical operands (such as the LocalSize operand for
334   // ExecutionMode), or for extended instructions that may have their
335   // own operands depending on the selected extended instruction.
336   _.expected_operands.clear();
337   for (auto i = 0; i < opcode_desc->numTypes; i++)
338     _.expected_operands.push_back(
339         opcode_desc->operandTypes[opcode_desc->numTypes - i - 1]);
340 
341   while (_.word_index < inst_offset + inst_word_count) {
342     const uint16_t inst_word_index = uint16_t(_.word_index - inst_offset);
343     if (_.expected_operands.empty()) {
344       return diagnostic() << "Invalid instruction Op" << opcode_desc->name
345                           << " starting at word " << inst_offset
346                           << ": expected no more operands after "
347                           << inst_word_index
348                           << " words, but stated word count is "
349                           << inst_word_count << ".";
350     }
351 
352     spv_operand_type_t type =
353         spvTakeFirstMatchableOperand(&_.expected_operands);
354 
355     if (auto error =
356             parseOperand(inst_offset, &inst, type, &_.endian_converted_words,
357                          &_.operands, &_.expected_operands)) {
358       return error;
359     }
360   }
361 
362   if (!_.expected_operands.empty() &&
363       !spvOperandIsOptional(_.expected_operands.back())) {
364     return diagnostic() << "End of input reached while decoding Op"
365                         << opcode_desc->name << " starting at word "
366                         << inst_offset << ": expected more operands after "
367                         << inst_word_count << " words.";
368   }
369 
370   if ((inst_offset + inst_word_count) != _.word_index) {
371     return diagnostic() << "Invalid word count: Op" << opcode_desc->name
372                         << " starting at word " << inst_offset
373                         << " says it has " << inst_word_count
374                         << " words, but found " << _.word_index - inst_offset
375                         << " words instead.";
376   }
377 
378   // Check the computed length of the endian-converted words vector against
379   // the declared number of words in the instruction.  If endian conversion
380   // is required, then they should match.  If no endian conversion was
381   // performed, then the vector only contains the initial opcode/word-count
382   // word.
383   assert(!_.requires_endian_conversion ||
384          (inst_word_count == _.endian_converted_words.size()));
385   assert(_.requires_endian_conversion ||
386          (_.endian_converted_words.size() == 1));
387 
388   recordNumberType(inst_offset, &inst);
389 
390   if (_.requires_endian_conversion) {
391     // We must wait until here to set this pointer, because the vector might
392     // have been be resized while we accumulated its elements.
393     inst.words = _.endian_converted_words.data();
394   } else {
395     // If no conversion is required, then just point to the underlying binary.
396     // This saves time and space.
397     inst.words = _.words + inst_offset;
398   }
399   inst.num_words = inst_word_count;
400 
401   // We must wait until here to set this pointer, because the vector might
402   // have been be resized while we accumulated its elements.
403   inst.operands = _.operands.data();
404   inst.num_operands = uint16_t(_.operands.size());
405 
406   // Issue the callback.  The callee should know that all the storage in inst
407   // is transient, and will disappear immediately afterward.
408   if (parsed_instruction_fn_) {
409     if (auto error = parsed_instruction_fn_(user_data_, &inst)) return error;
410   }
411 
412   return SPV_SUCCESS;
413 }
414 
parseOperand(size_t inst_offset,spv_parsed_instruction_t * inst,const spv_operand_type_t type,std::vector<uint32_t> * words,std::vector<spv_parsed_operand_t> * operands,spv_operand_pattern_t * expected_operands)415 spv_result_t Parser::parseOperand(size_t inst_offset,
416                                   spv_parsed_instruction_t* inst,
417                                   const spv_operand_type_t type,
418                                   std::vector<uint32_t>* words,
419                                   std::vector<spv_parsed_operand_t>* operands,
420                                   spv_operand_pattern_t* expected_operands) {
421   const spv::Op opcode = static_cast<spv::Op>(inst->opcode);
422   // We'll fill in this result as we go along.
423   spv_parsed_operand_t parsed_operand;
424   parsed_operand.offset = uint16_t(_.word_index - inst_offset);
425   // Most operands occupy one word.  This might be be adjusted later.
426   parsed_operand.num_words = 1;
427   // The type argument is the one used by the grammar to parse the instruction.
428   // But it can exposes internal parser details such as whether an operand is
429   // optional or actually represents a variable-length sequence of operands.
430   // The resulting type should be adjusted to avoid those internal details.
431   // In most cases, the resulting operand type is the same as the grammar type.
432   parsed_operand.type = type;
433 
434   // Assume non-numeric values.  This will be updated for literal numbers.
435   parsed_operand.number_kind = SPV_NUMBER_NONE;
436   parsed_operand.number_bit_width = 0;
437 
438   if (_.word_index >= _.num_words)
439     return exhaustedInputDiagnostic(inst_offset, opcode, type);
440 
441   const uint32_t word = peek();
442 
443   // Do the words in this operand have to be converted to native endianness?
444   // True for all but literal strings.
445   bool convert_operand_endianness = true;
446 
447   switch (type) {
448     case SPV_OPERAND_TYPE_TYPE_ID:
449       if (!word)
450         return diagnostic(SPV_ERROR_INVALID_ID) << "Error: Type Id is 0";
451       inst->type_id = word;
452       break;
453 
454     case SPV_OPERAND_TYPE_RESULT_ID:
455       if (!word)
456         return diagnostic(SPV_ERROR_INVALID_ID) << "Error: Result Id is 0";
457       inst->result_id = word;
458       // Save the result ID to type ID mapping.
459       // In the grammar, type ID always appears before result ID.
460       if (_.id_to_type_id.find(inst->result_id) != _.id_to_type_id.end())
461         return diagnostic(SPV_ERROR_INVALID_ID)
462                << "Id " << inst->result_id << " is defined more than once";
463       // Record it.
464       // A regular value maps to its type.  Some instructions (e.g. OpLabel)
465       // have no type Id, and will map to 0.  The result Id for a
466       // type-generating instruction (e.g. OpTypeInt) maps to itself.
467       _.id_to_type_id[inst->result_id] =
468           spvOpcodeGeneratesType(opcode) ? inst->result_id : inst->type_id;
469       break;
470 
471     case SPV_OPERAND_TYPE_ID:
472     case SPV_OPERAND_TYPE_OPTIONAL_ID:
473       if (!word) return diagnostic(SPV_ERROR_INVALID_ID) << "Id is 0";
474       parsed_operand.type = SPV_OPERAND_TYPE_ID;
475 
476       if (spvIsExtendedInstruction(opcode) && parsed_operand.offset == 3) {
477         // The current word is the extended instruction set Id.
478         // Set the extended instruction set type for the current instruction.
479         auto ext_inst_type_iter = _.import_id_to_ext_inst_type.find(word);
480         if (ext_inst_type_iter == _.import_id_to_ext_inst_type.end()) {
481           return diagnostic(SPV_ERROR_INVALID_ID)
482                  << "OpExtInst set Id " << word
483                  << " does not reference an OpExtInstImport result Id";
484         }
485         inst->ext_inst_type = ext_inst_type_iter->second;
486       }
487       break;
488 
489     case SPV_OPERAND_TYPE_SCOPE_ID:
490     case SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID:
491       // Check for trivially invalid values.  The operand descriptions already
492       // have the word "ID" in them.
493       if (!word) return diagnostic() << spvOperandTypeStr(type) << " is 0";
494       break;
495 
496     case SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER: {
497       assert(spvIsExtendedInstruction(opcode));
498       assert(inst->ext_inst_type != SPV_EXT_INST_TYPE_NONE);
499       spv_ext_inst_desc ext_inst;
500       if (grammar_.lookupExtInst(inst->ext_inst_type, word, &ext_inst) ==
501           SPV_SUCCESS) {
502         // if we know about this ext inst, push the expected operands
503         spvPushOperandTypes(ext_inst->operandTypes, expected_operands);
504       } else {
505         // if we don't know this extended instruction and the set isn't
506         // non-semantic, we cannot process further
507         if (!spvExtInstIsNonSemantic(inst->ext_inst_type)) {
508           return diagnostic()
509                  << "Invalid extended instruction number: " << word;
510         } else {
511           // for non-semantic instruction sets, we know the form of all such
512           // extended instructions contains a series of IDs as parameters
513           expected_operands->push_back(SPV_OPERAND_TYPE_VARIABLE_ID);
514         }
515       }
516     } break;
517 
518     case SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER: {
519       assert(spv::Op::OpSpecConstantOp == opcode);
520       if (word > static_cast<uint32_t>(spv::Op::Max) ||
521           grammar_.lookupSpecConstantOpcode(spv::Op(word))) {
522         return diagnostic()
523                << "Invalid " << spvOperandTypeStr(type) << ": " << word;
524       }
525       spv_opcode_desc opcode_entry = nullptr;
526       if (grammar_.lookupOpcode(spv::Op(word), &opcode_entry)) {
527         return diagnostic(SPV_ERROR_INTERNAL)
528                << "OpSpecConstant opcode table out of sync";
529       }
530       // OpSpecConstant opcodes must have a type and result. We've already
531       // processed them, so skip them when preparing to parse the other
532       // operants for the opcode.
533       assert(opcode_entry->hasType);
534       assert(opcode_entry->hasResult);
535       assert(opcode_entry->numTypes >= 2);
536       spvPushOperandTypes(opcode_entry->operandTypes + 2, expected_operands);
537     } break;
538 
539     case SPV_OPERAND_TYPE_LITERAL_INTEGER:
540     case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_INTEGER:
541       // These are regular single-word literal integer operands.
542       // Post-parsing validation should check the range of the parsed value.
543       parsed_operand.type = SPV_OPERAND_TYPE_LITERAL_INTEGER;
544       // It turns out they are always unsigned integers!
545       parsed_operand.number_kind = SPV_NUMBER_UNSIGNED_INT;
546       parsed_operand.number_bit_width = 32;
547       break;
548 
549     case SPV_OPERAND_TYPE_LITERAL_FLOAT:
550       // These are regular single-word literal float operands.
551       parsed_operand.type = SPV_OPERAND_TYPE_LITERAL_FLOAT;
552       parsed_operand.number_kind = SPV_NUMBER_FLOATING;
553       parsed_operand.number_bit_width = 32;
554       break;
555 
556     case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER:
557     case SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER:
558       parsed_operand.type = SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER;
559       if (opcode == spv::Op::OpSwitch) {
560         // The literal operands have the same type as the value
561         // referenced by the selector Id.
562         const uint32_t selector_id = peekAt(inst_offset + 1);
563         const auto type_id_iter = _.id_to_type_id.find(selector_id);
564         if (type_id_iter == _.id_to_type_id.end() ||
565             type_id_iter->second == 0) {
566           return diagnostic() << "Invalid OpSwitch: selector id " << selector_id
567                               << " has no type";
568         }
569         uint32_t type_id = type_id_iter->second;
570 
571         if (selector_id == type_id) {
572           // Recall that by convention, a result ID that is a type definition
573           // maps to itself.
574           return diagnostic() << "Invalid OpSwitch: selector id " << selector_id
575                               << " is a type, not a value";
576         }
577         if (auto error = setNumericTypeInfoForType(&parsed_operand, type_id))
578           return error;
579         if (parsed_operand.number_kind != SPV_NUMBER_UNSIGNED_INT &&
580             parsed_operand.number_kind != SPV_NUMBER_SIGNED_INT) {
581           return diagnostic() << "Invalid OpSwitch: selector id " << selector_id
582                               << " is not a scalar integer";
583         }
584       } else {
585         assert(opcode == spv::Op::OpConstant ||
586                opcode == spv::Op::OpSpecConstant);
587         // The literal number type is determined by the type Id for the
588         // constant.
589         assert(inst->type_id);
590         if (auto error =
591                 setNumericTypeInfoForType(&parsed_operand, inst->type_id))
592           return error;
593       }
594       break;
595 
596     case SPV_OPERAND_TYPE_LITERAL_STRING:
597     case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_STRING: {
598       const size_t max_words = _.num_words - _.word_index;
599       std::string string =
600           spvtools::utils::MakeString(_.words + _.word_index, max_words, false);
601 
602       if (string.length() == max_words * 4)
603         return exhaustedInputDiagnostic(inst_offset, opcode, type);
604 
605       // Make sure we can record the word count without overflow.
606       //
607       // This error can't currently be triggered because of validity
608       // checks elsewhere.
609       const size_t string_num_words = string.length() / 4 + 1;
610       if (string_num_words > std::numeric_limits<uint16_t>::max()) {
611         return diagnostic() << "Literal string is longer than "
612                             << std::numeric_limits<uint16_t>::max()
613                             << " words: " << string_num_words << " words long";
614       }
615       parsed_operand.num_words = uint16_t(string_num_words);
616       parsed_operand.type = SPV_OPERAND_TYPE_LITERAL_STRING;
617 
618       if (spv::Op::OpExtInstImport == opcode) {
619         // Record the extended instruction type for the ID for this import.
620         // There is only one string literal argument to OpExtInstImport,
621         // so it's sufficient to guard this just on the opcode.
622         const spv_ext_inst_type_t ext_inst_type =
623             spvExtInstImportTypeGet(string.c_str());
624         if (SPV_EXT_INST_TYPE_NONE == ext_inst_type) {
625           return diagnostic()
626                  << "Invalid extended instruction import '" << string << "'";
627         }
628         // We must have parsed a valid result ID.  It's a condition
629         // of the grammar, and we only accept non-zero result Ids.
630         assert(inst->result_id);
631         _.import_id_to_ext_inst_type[inst->result_id] = ext_inst_type;
632       }
633     } break;
634 
635     case SPV_OPERAND_TYPE_CAPABILITY:
636     case SPV_OPERAND_TYPE_EXECUTION_MODEL:
637     case SPV_OPERAND_TYPE_ADDRESSING_MODEL:
638     case SPV_OPERAND_TYPE_MEMORY_MODEL:
639     case SPV_OPERAND_TYPE_EXECUTION_MODE:
640     case SPV_OPERAND_TYPE_STORAGE_CLASS:
641     case SPV_OPERAND_TYPE_DIMENSIONALITY:
642     case SPV_OPERAND_TYPE_SAMPLER_ADDRESSING_MODE:
643     case SPV_OPERAND_TYPE_SAMPLER_FILTER_MODE:
644     case SPV_OPERAND_TYPE_SAMPLER_IMAGE_FORMAT:
645     case SPV_OPERAND_TYPE_FP_ROUNDING_MODE:
646     case SPV_OPERAND_TYPE_LINKAGE_TYPE:
647     case SPV_OPERAND_TYPE_ACCESS_QUALIFIER:
648     case SPV_OPERAND_TYPE_OPTIONAL_ACCESS_QUALIFIER:
649     case SPV_OPERAND_TYPE_FUNCTION_PARAMETER_ATTRIBUTE:
650     case SPV_OPERAND_TYPE_DECORATION:
651     case SPV_OPERAND_TYPE_BUILT_IN:
652     case SPV_OPERAND_TYPE_GROUP_OPERATION:
653     case SPV_OPERAND_TYPE_KERNEL_ENQ_FLAGS:
654     case SPV_OPERAND_TYPE_KERNEL_PROFILING_INFO:
655     case SPV_OPERAND_TYPE_RAY_FLAGS:
656     case SPV_OPERAND_TYPE_RAY_QUERY_INTERSECTION:
657     case SPV_OPERAND_TYPE_RAY_QUERY_COMMITTED_INTERSECTION_TYPE:
658     case SPV_OPERAND_TYPE_RAY_QUERY_CANDIDATE_INTERSECTION_TYPE:
659     case SPV_OPERAND_TYPE_DEBUG_BASE_TYPE_ATTRIBUTE_ENCODING:
660     case SPV_OPERAND_TYPE_DEBUG_COMPOSITE_TYPE:
661     case SPV_OPERAND_TYPE_DEBUG_TYPE_QUALIFIER:
662     case SPV_OPERAND_TYPE_DEBUG_OPERATION:
663     case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_BASE_TYPE_ATTRIBUTE_ENCODING:
664     case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_COMPOSITE_TYPE:
665     case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_TYPE_QUALIFIER:
666     case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_OPERATION:
667     case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_IMPORTED_ENTITY:
668     case SPV_OPERAND_TYPE_FPDENORM_MODE:
669     case SPV_OPERAND_TYPE_FPOPERATION_MODE:
670     case SPV_OPERAND_TYPE_QUANTIZATION_MODES:
671     case SPV_OPERAND_TYPE_OVERFLOW_MODES:
672     case SPV_OPERAND_TYPE_PACKED_VECTOR_FORMAT:
673     case SPV_OPERAND_TYPE_OPTIONAL_PACKED_VECTOR_FORMAT:
674     case SPV_OPERAND_TYPE_FPENCODING:
675     case SPV_OPERAND_TYPE_OPTIONAL_FPENCODING:
676     case SPV_OPERAND_TYPE_HOST_ACCESS_QUALIFIER:
677     case SPV_OPERAND_TYPE_LOAD_CACHE_CONTROL:
678     case SPV_OPERAND_TYPE_STORE_CACHE_CONTROL:
679     case SPV_OPERAND_TYPE_NAMED_MAXIMUM_NUMBER_OF_REGISTERS: {
680       // A single word that is a plain enum value.
681 
682       // Map an optional operand type to its corresponding concrete type.
683       if (type == SPV_OPERAND_TYPE_OPTIONAL_ACCESS_QUALIFIER)
684         parsed_operand.type = SPV_OPERAND_TYPE_ACCESS_QUALIFIER;
685       if (type == SPV_OPERAND_TYPE_OPTIONAL_PACKED_VECTOR_FORMAT)
686         parsed_operand.type = SPV_OPERAND_TYPE_PACKED_VECTOR_FORMAT;
687       if (type == SPV_OPERAND_TYPE_OPTIONAL_FPENCODING)
688         parsed_operand.type = SPV_OPERAND_TYPE_FPENCODING;
689 
690       spv_operand_desc entry;
691       if (grammar_.lookupOperand(type, word, &entry)) {
692         return diagnostic()
693                << "Invalid " << spvOperandTypeStr(parsed_operand.type)
694                << " operand: " << word;
695       }
696       // Prepare to accept operands to this operand, if needed.
697       spvPushOperandTypes(entry->operandTypes, expected_operands);
698     } break;
699 
700     case SPV_OPERAND_TYPE_SOURCE_LANGUAGE: {
701       spv_operand_desc entry;
702       if (grammar_.lookupOperand(type, word, &entry)) {
703         return diagnostic()
704                << "Invalid " << spvOperandTypeStr(parsed_operand.type)
705                << " operand: " << word
706                << ", if you are creating a new source language please use "
707                   "value 0 "
708                   "(Unknown) and when ready, add your source language to "
709                   "SPIRV-Headers";
710       }
711       // Prepare to accept operands to this operand, if needed.
712       spvPushOperandTypes(entry->operandTypes, expected_operands);
713     } break;
714 
715     case SPV_OPERAND_TYPE_FP_FAST_MATH_MODE:
716     case SPV_OPERAND_TYPE_FUNCTION_CONTROL:
717     case SPV_OPERAND_TYPE_LOOP_CONTROL:
718     case SPV_OPERAND_TYPE_IMAGE:
719     case SPV_OPERAND_TYPE_OPTIONAL_IMAGE:
720     case SPV_OPERAND_TYPE_MEMORY_ACCESS:
721     case SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS:
722     case SPV_OPERAND_TYPE_OPTIONAL_RAW_ACCESS_CHAIN_OPERANDS:
723     case SPV_OPERAND_TYPE_SELECTION_CONTROL:
724     case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_INFO_FLAGS:
725     case SPV_OPERAND_TYPE_DEBUG_INFO_FLAGS:
726     case SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_OPERANDS:
727     case SPV_OPERAND_TYPE_OPTIONAL_COOPERATIVE_MATRIX_OPERANDS:
728     case SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_REDUCE:
729     case SPV_OPERAND_TYPE_TENSOR_ADDRESSING_OPERANDS: {
730       // This operand is a mask.
731 
732       // Map an optional operand type to its corresponding concrete type.
733       if (type == SPV_OPERAND_TYPE_OPTIONAL_IMAGE)
734         parsed_operand.type = SPV_OPERAND_TYPE_IMAGE;
735       if (type == SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS)
736         parsed_operand.type = SPV_OPERAND_TYPE_MEMORY_ACCESS;
737       if (type == SPV_OPERAND_TYPE_OPTIONAL_COOPERATIVE_MATRIX_OPERANDS)
738         parsed_operand.type = SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_OPERANDS;
739       if (type == SPV_OPERAND_TYPE_OPTIONAL_RAW_ACCESS_CHAIN_OPERANDS)
740         parsed_operand.type = SPV_OPERAND_TYPE_RAW_ACCESS_CHAIN_OPERANDS;
741 
742       // Check validity of set mask bits. Also prepare for operands for those
743       // masks if they have any.  To get operand order correct, scan from
744       // MSB to LSB since we can only prepend operands to a pattern.
745       // The only case in the grammar where you have more than one mask bit
746       // having an operand is for image operands.  See SPIR-V 3.14 Image
747       // Operands.
748       uint32_t remaining_word = word;
749       for (uint32_t mask = (1u << 31); remaining_word; mask >>= 1) {
750         if (remaining_word & mask) {
751           spv_operand_desc entry;
752           if (grammar_.lookupOperand(type, mask, &entry)) {
753             return diagnostic()
754                    << "Invalid " << spvOperandTypeStr(parsed_operand.type)
755                    << " operand: " << word << " has invalid mask component "
756                    << mask;
757           }
758           remaining_word ^= mask;
759           spvPushOperandTypes(entry->operandTypes, expected_operands);
760         }
761       }
762       if (word == 0) {
763         // An all-zeroes mask *might* also be valid.
764         spv_operand_desc entry;
765         if (SPV_SUCCESS == grammar_.lookupOperand(type, 0, &entry)) {
766           // Prepare for its operands, if any.
767           spvPushOperandTypes(entry->operandTypes, expected_operands);
768         }
769       }
770     } break;
771     default:
772       return diagnostic() << "Internal error: Unhandled operand type: " << type;
773   }
774 
775   assert(spvOperandIsConcrete(parsed_operand.type));
776 
777   operands->push_back(parsed_operand);
778 
779   const size_t index_after_operand = _.word_index + parsed_operand.num_words;
780 
781   // Avoid buffer overrun for the cases where the operand has more than one
782   // word, and where it isn't a string.  (Those other cases have already been
783   // handled earlier.)  For example, this error can occur for a multi-word
784   // argument to OpConstant, or a multi-word case literal operand for OpSwitch.
785   if (_.num_words < index_after_operand)
786     return exhaustedInputDiagnostic(inst_offset, opcode, type);
787 
788   if (_.requires_endian_conversion) {
789     // Copy instruction words.  Translate to native endianness as needed.
790     if (convert_operand_endianness) {
791       const spv_endianness_t endianness = _.endian;
792       std::transform(_.words + _.word_index, _.words + index_after_operand,
793                      std::back_inserter(*words),
794                      [endianness](const uint32_t raw_word) {
795                        return spvFixWord(raw_word, endianness);
796                      });
797     } else {
798       words->insert(words->end(), _.words + _.word_index,
799                     _.words + index_after_operand);
800     }
801   }
802 
803   // Advance past the operand.
804   _.word_index = index_after_operand;
805 
806   return SPV_SUCCESS;
807 }
808 
setNumericTypeInfoForType(spv_parsed_operand_t * parsed_operand,uint32_t type_id)809 spv_result_t Parser::setNumericTypeInfoForType(
810     spv_parsed_operand_t* parsed_operand, uint32_t type_id) {
811   assert(type_id != 0);
812   auto type_info_iter = _.type_id_to_number_type_info.find(type_id);
813   if (type_info_iter == _.type_id_to_number_type_info.end()) {
814     return diagnostic() << "Type Id " << type_id << " is not a type";
815   }
816   const NumberType& info = type_info_iter->second;
817   if (info.type == SPV_NUMBER_NONE) {
818     // This is a valid type, but for something other than a scalar number.
819     return diagnostic() << "Type Id " << type_id
820                         << " is not a scalar numeric type";
821   }
822 
823   parsed_operand->number_kind = info.type;
824   parsed_operand->number_bit_width = info.bit_width;
825   // Round up the word count.
826   parsed_operand->num_words = static_cast<uint16_t>((info.bit_width + 31) / 32);
827   return SPV_SUCCESS;
828 }
829 
recordNumberType(size_t inst_offset,const spv_parsed_instruction_t * inst)830 void Parser::recordNumberType(size_t inst_offset,
831                               const spv_parsed_instruction_t* inst) {
832   const spv::Op opcode = static_cast<spv::Op>(inst->opcode);
833   if (spvOpcodeGeneratesType(opcode)) {
834     NumberType info = {SPV_NUMBER_NONE, 0};
835     if (spv::Op::OpTypeInt == opcode) {
836       const bool is_signed = peekAt(inst_offset + 3) != 0;
837       info.type = is_signed ? SPV_NUMBER_SIGNED_INT : SPV_NUMBER_UNSIGNED_INT;
838       info.bit_width = peekAt(inst_offset + 2);
839     } else if (spv::Op::OpTypeFloat == opcode) {
840       info.type = SPV_NUMBER_FLOATING;
841       info.bit_width = peekAt(inst_offset + 2);
842     }
843     // The *result* Id of a type generating instruction is the type Id.
844     _.type_id_to_number_type_info[inst->result_id] = info;
845   }
846 }
847 
848 }  // anonymous namespace
849 
spvBinaryParse(const spv_const_context context,void * user_data,const uint32_t * code,const size_t num_words,spv_parsed_header_fn_t parsed_header,spv_parsed_instruction_fn_t parsed_instruction,spv_diagnostic * diagnostic)850 spv_result_t spvBinaryParse(const spv_const_context context, void* user_data,
851                             const uint32_t* code, const size_t num_words,
852                             spv_parsed_header_fn_t parsed_header,
853                             spv_parsed_instruction_fn_t parsed_instruction,
854                             spv_diagnostic* diagnostic) {
855   spv_context_t hijack_context = *context;
856   if (diagnostic) {
857     *diagnostic = nullptr;
858     spvtools::UseDiagnosticAsMessageConsumer(&hijack_context, diagnostic);
859   }
860   Parser parser(&hijack_context, user_data, parsed_header, parsed_instruction);
861   return parser.parse(code, num_words, diagnostic);
862 }
863 
864 // TODO(dneto): This probably belongs in text.cpp since that's the only place
865 // that a spv_binary_t value is created.
spvBinaryDestroy(spv_binary binary)866 void spvBinaryDestroy(spv_binary binary) {
867   if (binary) {
868     if (binary->code) delete[] binary->code;
869     delete binary;
870   }
871 }
872 
spv_strnlen_s(const char * str,size_t strsz)873 size_t spv_strnlen_s(const char* str, size_t strsz) {
874   if (!str) return 0;
875   for (size_t i = 0; i < strsz; i++) {
876     if (!str[i]) return i;
877   }
878   return strsz;
879 }
880