Coverage Report

Created: 2023-03-01 07:33

/src/spirv-tools/source/binary.cpp
Line
Count
Source (jump to first uncovered line)
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
38
spv_result_t spvBinaryHeaderGet(const spv_const_binary binary,
39
                                const spv_endianness_t endian,
40
1.23M
                                spv_header_t* pHeader) {
41
1.23M
  if (!binary->code) return SPV_ERROR_INVALID_BINARY;
42
1.23M
  if (binary->wordCount < SPV_INDEX_INSTRUCTION)
43
6
    return SPV_ERROR_INVALID_BINARY;
44
1.23M
  if (!pHeader) return SPV_ERROR_INVALID_POINTER;
45
46
  // TODO: Validation checking?
47
1.23M
  pHeader->magic = spvFixWord(binary->code[SPV_INDEX_MAGIC_NUMBER], endian);
48
1.23M
  pHeader->version = spvFixWord(binary->code[SPV_INDEX_VERSION_NUMBER], endian);
49
  // Per 2.3.1 version's high and low bytes are 0
50
1.23M
  if ((pHeader->version & 0x000000ff) || pHeader->version & 0xff000000)
51
4.79k
    return SPV_ERROR_INVALID_BINARY;
52
  // Minimum version was 1.0 and max version is defined by SPV_VERSION.
53
1.22M
  if (pHeader->version < SPV_SPIRV_VERSION_WORD(1, 0) ||
54
1.22M
      pHeader->version > SPV_VERSION)
55
6.71k
    return SPV_ERROR_INVALID_BINARY;
56
57
1.21M
  pHeader->generator =
58
1.21M
      spvFixWord(binary->code[SPV_INDEX_GENERATOR_NUMBER], endian);
59
1.21M
  pHeader->bound = spvFixWord(binary->code[SPV_INDEX_BOUND], endian);
60
1.21M
  pHeader->schema = spvFixWord(binary->code[SPV_INDEX_SCHEMA], endian);
61
1.21M
  pHeader->instructions = &binary->code[SPV_INDEX_INSTRUCTION];
62
63
1.21M
  return SPV_SUCCESS;
64
1.22M
}
65
66
std::string spvDecodeLiteralStringOperand(const spv_parsed_instruction_t& inst,
67
7.68M
                                          const uint16_t operand_index) {
68
7.68M
  assert(operand_index < inst.num_operands);
69
0
  const spv_parsed_operand_t& operand = inst.operands[operand_index];
70
71
7.68M
  return spvtools::utils::MakeString(inst.words + operand.offset,
72
7.68M
                                     operand.num_words);
73
7.68M
}
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.
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
1.21M
        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.
145
556k
  spvtools::DiagnosticStream diagnostic(spv_result_t error) {
146
556k
    return spvtools::DiagnosticStream({0, 0, _.instruction_count}, consumer_,
147
556k
                                      "", error);
148
556k
  }
149
150
  // Returns a diagnostic stream object with the default parse error code.
151
517k
  spvtools::DiagnosticStream diagnostic() {
152
    // The default failure for parsing is invalid binary.
153
517k
    return diagnostic(SPV_ERROR_INVALID_BINARY);
154
517k
  }
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.
159
  spv_result_t exhaustedInputDiagnostic(size_t inst_offset, spv::Op opcode,
160
129k
                                        spv_operand_type_t type) {
161
129k
    return diagnostic() << "End of input reached while decoding Op"
162
129k
                        << spvOpcodeString(opcode) << " starting at word "
163
129k
                        << inst_offset
164
129k
                        << ((_.word_index < _.num_words) ? ": truncated "
165
129k
                                                         : ": missing ")
166
129k
                        << spvOperandTypeStr(type) << " operand at word offset "
167
129k
                        << _.word_index - inst_offset << ".";
168
129k
  }
169
170
  // Returns the endian-corrected word at the current position.
171
246M
  uint32_t peek() const { return peekAt(_.word_index); }
172
173
  // Returns the endian-corrected word at the given position.
174
267M
  uint32_t peekAt(size_t index) const {
175
267M
    assert(index < _.num_words);
176
0
    return spvFixWord(_.words[index], _.endian);
177
267M
  }
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 {
196
    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
3.64M
          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
3.64M
      operands.reserve(25);
208
3.64M
      endian_converted_words.reserve(25);
209
3.64M
      expected_operands.reserve(25);
210
3.64M
    }
211
2.43M
    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
239
spv_result_t Parser::parse(const uint32_t* words, size_t num_words,
240
1.21M
                           spv_diagnostic* diagnostic_arg) {
241
1.21M
  _ = State(words, num_words, diagnostic_arg);
242
243
1.21M
  const spv_result_t result = parseModule();
244
245
  // Clear the module state.  The tables might be big.
246
1.21M
  _ = State();
247
248
1.21M
  return result;
249
1.21M
}
250
251
1.21M
spv_result_t Parser::parseModule() {
252
1.21M
  if (!_.words) return diagnostic() << "Missing module.";
253
254
1.21M
  if (_.num_words < SPV_INDEX_INSTRUCTION)
255
2.76k
    return diagnostic() << "Module has incomplete header: only " << _.num_words
256
2.76k
                        << " words instead of " << SPV_INDEX_INSTRUCTION;
257
258
  // Check the magic number and detect the module's endianness.
259
1.21M
  spv_const_binary_t binary{_.words, _.num_words};
260
1.21M
  if (spvBinaryEndianness(&binary, &_.endian)) {
261
13.4k
    return diagnostic() << "Invalid SPIR-V magic number '" << std::hex
262
13.4k
                        << _.words[0] << "'.";
263
13.4k
  }
264
1.20M
  _.requires_endian_conversion = !spvIsHostEndian(_.endian);
265
266
  // Process the header.
267
1.20M
  spv_header_t header;
268
1.20M
  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
11.4k
    return diagnostic(SPV_ERROR_INTERNAL)
272
11.4k
           << "Internal error: unhandled header parse failure";
273
11.4k
  }
274
1.18M
  if (parsed_header_fn_) {
275
750k
    if (auto error = parsed_header_fn_(user_data_, _.endian, header.magic,
276
750k
                                       header.version, header.generator,
277
750k
                                       header.bound, header.schema)) {
278
0
      return error;
279
0
    }
280
750k
  }
281
282
  // Process the instructions.
283
1.18M
  _.word_index = SPV_INDEX_INSTRUCTION;
284
45.3M
  while (_.word_index < _.num_words)
285
44.7M
    if (auto error = parseInstruction()) return error;
286
287
  // Running off the end should already have been reported earlier.
288
619k
  assert(_.word_index == _.num_words);
289
290
0
  return SPV_SUCCESS;
291
1.18M
}
292
293
44.7M
spv_result_t Parser::parseInstruction() {
294
44.7M
  _.instruction_count++;
295
296
  // The zero values for all members except for opcode are the
297
  // correct initial values.
298
44.7M
  spv_parsed_instruction_t inst = {};
299
300
44.7M
  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
44.7M
  _.endian_converted_words.clear();
306
44.7M
  _.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
44.7M
  _.operands.clear();
311
312
44.7M
  assert(_.word_index < _.num_words);
313
  // Decompose and check the first word.
314
0
  uint16_t inst_word_count = 0;
315
44.7M
  spvOpcodeSplit(first_word, &inst_word_count, &inst.opcode);
316
44.7M
  if (inst_word_count < 1) {
317
13.6k
    return diagnostic() << "Invalid instruction word count: "
318
13.6k
                        << inst_word_count;
319
13.6k
  }
320
44.7M
  spv_opcode_desc opcode_desc;
321
44.7M
  if (grammar_.lookupOpcode(static_cast<spv::Op>(inst.opcode), &opcode_desc))
322
31.5k
    return diagnostic() << "Invalid opcode: " << inst.opcode;
323
324
  // Advance past the opcode word.  But remember the of the start
325
  // of the instruction.
326
44.6M
  const size_t inst_offset = _.word_index;
327
44.6M
  _.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
44.6M
  _.expected_operands.clear();
337
157M
  for (auto i = 0; i < opcode_desc->numTypes; i++)
338
113M
    _.expected_operands.push_back(
339
113M
        opcode_desc->operandTypes[opcode_desc->numTypes - i - 1]);
340
341
245M
  while (_.word_index < inst_offset + inst_word_count) {
342
201M
    const uint16_t inst_word_index = uint16_t(_.word_index - inst_offset);
343
201M
    if (_.expected_operands.empty()) {
344
54.7k
      return diagnostic() << "Invalid instruction Op" << opcode_desc->name
345
54.7k
                          << " starting at word " << inst_offset
346
54.7k
                          << ": expected no more operands after "
347
54.7k
                          << inst_word_index
348
54.7k
                          << " words, but stated word count is "
349
54.7k
                          << inst_word_count << ".";
350
54.7k
    }
351
352
201M
    spv_operand_type_t type =
353
201M
        spvTakeFirstMatchableOperand(&_.expected_operands);
354
355
201M
    if (auto error =
356
201M
            parseOperand(inst_offset, &inst, type, &_.endian_converted_words,
357
201M
                         &_.operands, &_.expected_operands)) {
358
400k
      return error;
359
400k
    }
360
201M
  }
361
362
44.2M
  if (!_.expected_operands.empty() &&
363
44.2M
      !spvOperandIsOptional(_.expected_operands.back())) {
364
7.80k
    return diagnostic() << "End of input reached while decoding Op"
365
7.80k
                        << opcode_desc->name << " starting at word "
366
7.80k
                        << inst_offset << ": expected more operands after "
367
7.80k
                        << inst_word_count << " words.";
368
7.80k
  }
369
370
44.2M
  if ((inst_offset + inst_word_count) != _.word_index) {
371
20.0k
    return diagnostic() << "Invalid word count: Op" << opcode_desc->name
372
20.0k
                        << " starting at word " << inst_offset
373
20.0k
                        << " says it has " << inst_word_count
374
20.0k
                        << " words, but found " << _.word_index - inst_offset
375
20.0k
                        << " words instead.";
376
20.0k
  }
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
44.2M
  assert(!_.requires_endian_conversion ||
384
44.2M
         (inst_word_count == _.endian_converted_words.size()));
385
0
  assert(_.requires_endian_conversion ||
386
44.2M
         (_.endian_converted_words.size() == 1));
387
388
0
  recordNumberType(inst_offset, &inst);
389
390
44.2M
  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
6.81M
    inst.words = _.endian_converted_words.data();
394
37.3M
  } else {
395
    // If no conversion is required, then just point to the underlying binary.
396
    // This saves time and space.
397
37.3M
    inst.words = _.words + inst_offset;
398
37.3M
  }
399
44.2M
  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
44.2M
  inst.operands = _.operands.data();
404
44.2M
  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
44.2M
  if (parsed_instruction_fn_) {
409
44.1M
    if (auto error = parsed_instruction_fn_(user_data_, &inst)) return error;
410
44.1M
  }
411
412
44.1M
  return SPV_SUCCESS;
413
44.2M
}
414
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
201M
                                  spv_operand_pattern_t* expected_operands) {
421
201M
  const spv::Op opcode = static_cast<spv::Op>(inst->opcode);
422
  // We'll fill in this result as we go along.
423
201M
  spv_parsed_operand_t parsed_operand;
424
201M
  parsed_operand.offset = uint16_t(_.word_index - inst_offset);
425
  // Most operands occupy one word.  This might be be adjusted later.
426
201M
  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
201M
  parsed_operand.type = type;
433
434
  // Assume non-numeric values.  This will be updated for literal numbers.
435
201M
  parsed_operand.number_kind = SPV_NUMBER_NONE;
436
201M
  parsed_operand.number_bit_width = 0;
437
438
201M
  if (_.word_index >= _.num_words)
439
121k
    return exhaustedInputDiagnostic(inst_offset, opcode, type);
440
441
201M
  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
201M
  bool convert_operand_endianness = true;
446
447
201M
  switch (type) {
448
13.8M
    case SPV_OPERAND_TYPE_TYPE_ID:
449
13.8M
      if (!word)
450
198
        return diagnostic(SPV_ERROR_INVALID_ID) << "Error: Type Id is 0";
451
13.8M
      inst->type_id = word;
452
13.8M
      break;
453
454
21.3M
    case SPV_OPERAND_TYPE_RESULT_ID:
455
21.3M
      if (!word)
456
393
        return diagnostic(SPV_ERROR_INVALID_ID) << "Error: Result Id is 0";
457
21.3M
      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
21.3M
      if (_.id_to_type_id.find(inst->result_id) != _.id_to_type_id.end())
461
1.13k
        return diagnostic(SPV_ERROR_INVALID_ID)
462
1.13k
               << "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
21.3M
      _.id_to_type_id[inst->result_id] =
468
21.3M
          spvOpcodeGeneratesType(opcode) ? inst->result_id : inst->type_id;
469
21.3M
      break;
470
471
58.0M
    case SPV_OPERAND_TYPE_ID:
472
106M
    case SPV_OPERAND_TYPE_OPTIONAL_ID:
473
106M
      if (!word) return diagnostic(SPV_ERROR_INVALID_ID) << "Id is 0";
474
106M
      parsed_operand.type = SPV_OPERAND_TYPE_ID;
475
476
106M
      if (opcode == spv::Op::OpExtInst && 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
578k
        auto ext_inst_type_iter = _.import_id_to_ext_inst_type.find(word);
480
578k
        if (ext_inst_type_iter == _.import_id_to_ext_inst_type.end()) {
481
21.3k
          return diagnostic(SPV_ERROR_INVALID_ID)
482
21.3k
                 << "OpExtInst set Id " << word
483
21.3k
                 << " does not reference an OpExtInstImport result Id";
484
21.3k
        }
485
557k
        inst->ext_inst_type = ext_inst_type_iter->second;
486
557k
      }
487
106M
      break;
488
489
106M
    case SPV_OPERAND_TYPE_SCOPE_ID:
490
810k
    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
810k
      if (!word) return diagnostic() << spvOperandTypeStr(type) << " is 0";
494
810k
      break;
495
496
810k
    case SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER: {
497
556k
      assert(spv::Op::OpExtInst == opcode);
498
0
      assert(inst->ext_inst_type != SPV_EXT_INST_TYPE_NONE);
499
0
      spv_ext_inst_desc ext_inst;
500
556k
      if (grammar_.lookupExtInst(inst->ext_inst_type, word, &ext_inst) ==
501
556k
          SPV_SUCCESS) {
502
        // if we know about this ext inst, push the expected operands
503
447k
        spvPushOperandTypes(ext_inst->operandTypes, expected_operands);
504
447k
      } else {
505
        // if we don't know this extended instruction and the set isn't
506
        // non-semantic, we cannot process further
507
109k
        if (!spvExtInstIsNonSemantic(inst->ext_inst_type)) {
508
1.74k
          return diagnostic()
509
1.74k
                 << "Invalid extended instruction number: " << word;
510
107k
        } 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
107k
          expected_operands->push_back(SPV_OPERAND_TYPE_VARIABLE_ID);
514
107k
        }
515
109k
      }
516
556k
    } break;
517
518
554k
    case SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER: {
519
12.8k
      assert(spv::Op::OpSpecConstantOp == opcode);
520
12.8k
      if (word > static_cast<uint32_t>(spv::Op::Max) ||
521
12.8k
          grammar_.lookupSpecConstantOpcode(spv::Op(word))) {
522
10.3k
        return diagnostic()
523
10.3k
               << "Invalid " << spvOperandTypeStr(type) << ": " << word;
524
10.3k
      }
525
2.53k
      spv_opcode_desc opcode_entry = nullptr;
526
2.53k
      if (grammar_.lookupOpcode(spv::Op(word), &opcode_entry)) {
527
0
        return diagnostic(SPV_ERROR_INTERNAL)
528
0
               << "OpSpecConstant opcode table out of sync";
529
0
      }
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
2.53k
      assert(opcode_entry->hasType);
534
0
      assert(opcode_entry->hasResult);
535
0
      assert(opcode_entry->numTypes >= 2);
536
0
      spvPushOperandTypes(opcode_entry->operandTypes + 2, expected_operands);
537
2.53k
    } break;
538
539
5.37M
    case SPV_OPERAND_TYPE_LITERAL_INTEGER:
540
12.2M
    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
12.2M
      parsed_operand.type = SPV_OPERAND_TYPE_LITERAL_INTEGER;
544
      // It turns out they are always unsigned integers!
545
12.2M
      parsed_operand.number_kind = SPV_NUMBER_UNSIGNED_INT;
546
12.2M
      parsed_operand.number_bit_width = 32;
547
12.2M
      break;
548
549
2.09M
    case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER:
550
22.5M
    case SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER:
551
22.5M
      parsed_operand.type = SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER;
552
22.5M
      if (opcode == spv::Op::OpSwitch) {
553
        // The literal operands have the same type as the value
554
        // referenced by the selector Id.
555
20.4M
        const uint32_t selector_id = peekAt(inst_offset + 1);
556
20.4M
        const auto type_id_iter = _.id_to_type_id.find(selector_id);
557
20.4M
        if (type_id_iter == _.id_to_type_id.end() ||
558
20.4M
            type_id_iter->second == 0) {
559
20.5k
          return diagnostic() << "Invalid OpSwitch: selector id " << selector_id
560
20.5k
                              << " has no type";
561
20.5k
        }
562
20.4M
        uint32_t type_id = type_id_iter->second;
563
564
20.4M
        if (selector_id == type_id) {
565
          // Recall that by convention, a result ID that is a type definition
566
          // maps to itself.
567
2.67k
          return diagnostic() << "Invalid OpSwitch: selector id " << selector_id
568
2.67k
                              << " is a type, not a value";
569
2.67k
        }
570
20.4M
        if (auto error = setNumericTypeInfoForType(&parsed_operand, type_id))
571
9.13k
          return error;
572
20.3M
        if (parsed_operand.number_kind != SPV_NUMBER_UNSIGNED_INT &&
573
20.3M
            parsed_operand.number_kind != SPV_NUMBER_SIGNED_INT) {
574
194
          return diagnostic() << "Invalid OpSwitch: selector id " << selector_id
575
194
                              << " is not a scalar integer";
576
194
        }
577
20.3M
      } else {
578
2.09M
        assert(opcode == spv::Op::OpConstant ||
579
2.09M
               opcode == spv::Op::OpSpecConstant);
580
        // The literal number type is determined by the type Id for the
581
        // constant.
582
0
        assert(inst->type_id);
583
2.09M
        if (auto error =
584
2.09M
                setNumericTypeInfoForType(&parsed_operand, inst->type_id))
585
34.5k
          return error;
586
2.09M
      }
587
22.4M
      break;
588
589
22.4M
    case SPV_OPERAND_TYPE_LITERAL_STRING:
590
8.94M
    case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_STRING: {
591
8.94M
      const size_t max_words = _.num_words - _.word_index;
592
8.94M
      std::string string =
593
8.94M
          spvtools::utils::MakeString(_.words + _.word_index, max_words, false);
594
595
8.94M
      if (string.length() == max_words * 4)
596
3.05k
        return exhaustedInputDiagnostic(inst_offset, opcode, type);
597
598
      // Make sure we can record the word count without overflow.
599
      //
600
      // This error can't currently be triggered because of validity
601
      // checks elsewhere.
602
8.94M
      const size_t string_num_words = string.length() / 4 + 1;
603
8.94M
      if (string_num_words > std::numeric_limits<uint16_t>::max()) {
604
572
        return diagnostic() << "Literal string is longer than "
605
572
                            << std::numeric_limits<uint16_t>::max()
606
572
                            << " words: " << string_num_words << " words long";
607
572
      }
608
8.94M
      parsed_operand.num_words = uint16_t(string_num_words);
609
8.94M
      parsed_operand.type = SPV_OPERAND_TYPE_LITERAL_STRING;
610
611
8.94M
      if (spv::Op::OpExtInstImport == opcode) {
612
        // Record the extended instruction type for the ID for this import.
613
        // There is only one string literal argument to OpExtInstImport,
614
        // so it's sufficient to guard this just on the opcode.
615
535k
        const spv_ext_inst_type_t ext_inst_type =
616
535k
            spvExtInstImportTypeGet(string.c_str());
617
535k
        if (SPV_EXT_INST_TYPE_NONE == ext_inst_type) {
618
123k
          return diagnostic()
619
123k
                 << "Invalid extended instruction import '" << string << "'";
620
123k
        }
621
        // We must have parsed a valid result ID.  It's a condition
622
        // of the grammar, and we only accept non-zero result Ids.
623
412k
        assert(inst->result_id);
624
0
        _.import_id_to_ext_inst_type[inst->result_id] = ext_inst_type;
625
412k
      }
626
8.94M
    } break;
627
628
8.81M
    case SPV_OPERAND_TYPE_CAPABILITY:
629
1.37M
    case SPV_OPERAND_TYPE_SOURCE_LANGUAGE:
630
2.24M
    case SPV_OPERAND_TYPE_EXECUTION_MODEL:
631
3.09M
    case SPV_OPERAND_TYPE_ADDRESSING_MODEL:
632
3.94M
    case SPV_OPERAND_TYPE_MEMORY_MODEL:
633
4.68M
    case SPV_OPERAND_TYPE_EXECUTION_MODE:
634
6.44M
    case SPV_OPERAND_TYPE_STORAGE_CLASS:
635
6.54M
    case SPV_OPERAND_TYPE_DIMENSIONALITY:
636
6.54M
    case SPV_OPERAND_TYPE_SAMPLER_ADDRESSING_MODE:
637
6.54M
    case SPV_OPERAND_TYPE_SAMPLER_FILTER_MODE:
638
6.65M
    case SPV_OPERAND_TYPE_SAMPLER_IMAGE_FORMAT:
639
6.65M
    case SPV_OPERAND_TYPE_FP_ROUNDING_MODE:
640
6.65M
    case SPV_OPERAND_TYPE_LINKAGE_TYPE:
641
6.66M
    case SPV_OPERAND_TYPE_ACCESS_QUALIFIER:
642
6.66M
    case SPV_OPERAND_TYPE_OPTIONAL_ACCESS_QUALIFIER:
643
6.87M
    case SPV_OPERAND_TYPE_FUNCTION_PARAMETER_ATTRIBUTE:
644
10.4M
    case SPV_OPERAND_TYPE_DECORATION:
645
11.9M
    case SPV_OPERAND_TYPE_BUILT_IN:
646
11.9M
    case SPV_OPERAND_TYPE_GROUP_OPERATION:
647
11.9M
    case SPV_OPERAND_TYPE_KERNEL_ENQ_FLAGS:
648
11.9M
    case SPV_OPERAND_TYPE_KERNEL_PROFILING_INFO:
649
11.9M
    case SPV_OPERAND_TYPE_RAY_FLAGS:
650
11.9M
    case SPV_OPERAND_TYPE_RAY_QUERY_INTERSECTION:
651
11.9M
    case SPV_OPERAND_TYPE_RAY_QUERY_COMMITTED_INTERSECTION_TYPE:
652
11.9M
    case SPV_OPERAND_TYPE_RAY_QUERY_CANDIDATE_INTERSECTION_TYPE:
653
11.9M
    case SPV_OPERAND_TYPE_DEBUG_BASE_TYPE_ATTRIBUTE_ENCODING:
654
11.9M
    case SPV_OPERAND_TYPE_DEBUG_COMPOSITE_TYPE:
655
11.9M
    case SPV_OPERAND_TYPE_DEBUG_TYPE_QUALIFIER:
656
11.9M
    case SPV_OPERAND_TYPE_DEBUG_OPERATION:
657
11.9M
    case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_BASE_TYPE_ATTRIBUTE_ENCODING:
658
11.9M
    case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_COMPOSITE_TYPE:
659
11.9M
    case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_TYPE_QUALIFIER:
660
11.9M
    case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_OPERATION:
661
11.9M
    case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_IMPORTED_ENTITY:
662
11.9M
    case SPV_OPERAND_TYPE_FPDENORM_MODE:
663
12.1M
    case SPV_OPERAND_TYPE_FPOPERATION_MODE:
664
12.1M
    case SPV_OPERAND_TYPE_QUANTIZATION_MODES:
665
12.1M
    case SPV_OPERAND_TYPE_OVERFLOW_MODES:
666
12.1M
    case SPV_OPERAND_TYPE_PACKED_VECTOR_FORMAT:
667
12.1M
    case SPV_OPERAND_TYPE_OPTIONAL_PACKED_VECTOR_FORMAT: {
668
      // A single word that is a plain enum value.
669
670
      // Map an optional operand type to its corresponding concrete type.
671
12.1M
      if (type == SPV_OPERAND_TYPE_OPTIONAL_ACCESS_QUALIFIER)
672
247
        parsed_operand.type = SPV_OPERAND_TYPE_ACCESS_QUALIFIER;
673
12.1M
      if (type == SPV_OPERAND_TYPE_OPTIONAL_PACKED_VECTOR_FORMAT)
674
1.36k
        parsed_operand.type = SPV_OPERAND_TYPE_PACKED_VECTOR_FORMAT;
675
676
12.1M
      spv_operand_desc entry;
677
12.1M
      if (grammar_.lookupOperand(type, word, &entry)) {
678
19.0k
        return diagnostic()
679
19.0k
               << "Invalid " << spvOperandTypeStr(parsed_operand.type)
680
19.0k
               << " operand: " << word;
681
19.0k
      }
682
      // Prepare to accept operands to this operand, if needed.
683
12.1M
      spvPushOperandTypes(entry->operandTypes, expected_operands);
684
12.1M
    } break;
685
686
306k
    case SPV_OPERAND_TYPE_FP_FAST_MATH_MODE:
687
839k
    case SPV_OPERAND_TYPE_FUNCTION_CONTROL:
688
1.36M
    case SPV_OPERAND_TYPE_LOOP_CONTROL:
689
1.36M
    case SPV_OPERAND_TYPE_IMAGE:
690
1.57M
    case SPV_OPERAND_TYPE_OPTIONAL_IMAGE:
691
1.94M
    case SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS:
692
2.62M
    case SPV_OPERAND_TYPE_SELECTION_CONTROL:
693
2.63M
    case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_INFO_FLAGS:
694
2.63M
    case SPV_OPERAND_TYPE_DEBUG_INFO_FLAGS: {
695
      // This operand is a mask.
696
697
      // Map an optional operand type to its corresponding concrete type.
698
2.63M
      if (type == SPV_OPERAND_TYPE_OPTIONAL_IMAGE)
699
215k
        parsed_operand.type = SPV_OPERAND_TYPE_IMAGE;
700
2.41M
      else if (type == SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS)
701
365k
        parsed_operand.type = SPV_OPERAND_TYPE_MEMORY_ACCESS;
702
703
      // Check validity of set mask bits. Also prepare for operands for those
704
      // masks if they have any.  To get operand order correct, scan from
705
      // MSB to LSB since we can only prepend operands to a pattern.
706
      // The only case in the grammar where you have more than one mask bit
707
      // having an operand is for image operands.  See SPIR-V 3.14 Image
708
      // Operands.
709
2.63M
      uint32_t remaining_word = word;
710
46.4M
      for (uint32_t mask = (1u << 31); remaining_word; mask >>= 1) {
711
43.8M
        if (remaining_word & mask) {
712
4.94M
          spv_operand_desc entry;
713
4.94M
          if (grammar_.lookupOperand(type, mask, &entry)) {
714
22.1k
            return diagnostic()
715
22.1k
                   << "Invalid " << spvOperandTypeStr(parsed_operand.type)
716
22.1k
                   << " operand: " << word << " has invalid mask component "
717
22.1k
                   << mask;
718
22.1k
          }
719
4.92M
          remaining_word ^= mask;
720
4.92M
          spvPushOperandTypes(entry->operandTypes, expected_operands);
721
4.92M
        }
722
43.8M
      }
723
2.60M
      if (word == 0) {
724
        // An all-zeroes mask *might* also be valid.
725
1.16M
        spv_operand_desc entry;
726
1.16M
        if (SPV_SUCCESS == grammar_.lookupOperand(type, 0, &entry)) {
727
          // Prepare for its operands, if any.
728
1.16M
          spvPushOperandTypes(entry->operandTypes, expected_operands);
729
1.16M
        }
730
1.16M
      }
731
2.60M
    } break;
732
0
    default:
733
0
      return diagnostic() << "Internal error: Unhandled operand type: " << type;
734
201M
  }
735
736
201M
  assert(spvOperandIsConcrete(parsed_operand.type));
737
738
0
  operands->push_back(parsed_operand);
739
740
201M
  const size_t index_after_operand = _.word_index + parsed_operand.num_words;
741
742
  // Avoid buffer overrun for the cases where the operand has more than one
743
  // word, and where it isn't a string.  (Those other cases have already been
744
  // handled earlier.)  For example, this error can occur for a multi-word
745
  // argument to OpConstant, or a multi-word case literal operand for OpSwitch.
746
201M
  if (_.num_words < index_after_operand)
747
4.52k
    return exhaustedInputDiagnostic(inst_offset, opcode, type);
748
749
201M
  if (_.requires_endian_conversion) {
750
    // Copy instruction words.  Translate to native endianness as needed.
751
84.9M
    if (convert_operand_endianness) {
752
84.9M
      const spv_endianness_t endianness = _.endian;
753
84.9M
      std::transform(_.words + _.word_index, _.words + index_after_operand,
754
84.9M
                     std::back_inserter(*words),
755
428M
                     [endianness](const uint32_t raw_word) {
756
428M
                       return spvFixWord(raw_word, endianness);
757
428M
                     });
758
84.9M
    } else {
759
0
      words->insert(words->end(), _.words + _.word_index,
760
0
                    _.words + index_after_operand);
761
0
    }
762
84.9M
  }
763
764
  // Advance past the operand.
765
201M
  _.word_index = index_after_operand;
766
767
201M
  return SPV_SUCCESS;
768
201M
}
769
770
spv_result_t Parser::setNumericTypeInfoForType(
771
22.5M
    spv_parsed_operand_t* parsed_operand, uint32_t type_id) {
772
22.5M
  assert(type_id != 0);
773
0
  auto type_info_iter = _.type_id_to_number_type_info.find(type_id);
774
22.5M
  if (type_info_iter == _.type_id_to_number_type_info.end()) {
775
43.3k
    return diagnostic() << "Type Id " << type_id << " is not a type";
776
43.3k
  }
777
22.4M
  const NumberType& info = type_info_iter->second;
778
22.4M
  if (info.type == SPV_NUMBER_NONE) {
779
    // This is a valid type, but for something other than a scalar number.
780
389
    return diagnostic() << "Type Id " << type_id
781
389
                        << " is not a scalar numeric type";
782
389
  }
783
784
22.4M
  parsed_operand->number_kind = info.type;
785
22.4M
  parsed_operand->number_bit_width = info.bit_width;
786
  // Round up the word count.
787
22.4M
  parsed_operand->num_words = static_cast<uint16_t>((info.bit_width + 31) / 32);
788
22.4M
  return SPV_SUCCESS;
789
22.4M
}
790
791
void Parser::recordNumberType(size_t inst_offset,
792
44.2M
                              const spv_parsed_instruction_t* inst) {
793
44.2M
  const spv::Op opcode = static_cast<spv::Op>(inst->opcode);
794
44.2M
  if (spvOpcodeGeneratesType(opcode)) {
795
4.45M
    NumberType info = {SPV_NUMBER_NONE, 0};
796
4.45M
    if (spv::Op::OpTypeInt == opcode) {
797
267k
      const bool is_signed = peekAt(inst_offset + 3) != 0;
798
267k
      info.type = is_signed ? SPV_NUMBER_SIGNED_INT : SPV_NUMBER_UNSIGNED_INT;
799
267k
      info.bit_width = peekAt(inst_offset + 2);
800
4.18M
    } else if (spv::Op::OpTypeFloat == opcode) {
801
832k
      info.type = SPV_NUMBER_FLOATING;
802
832k
      info.bit_width = peekAt(inst_offset + 2);
803
832k
    }
804
    // The *result* Id of a type generating instruction is the type Id.
805
4.45M
    _.type_id_to_number_type_info[inst->result_id] = info;
806
4.45M
  }
807
44.2M
}
808
809
}  // anonymous namespace
810
811
spv_result_t spvBinaryParse(const spv_const_context context, void* user_data,
812
                            const uint32_t* code, const size_t num_words,
813
                            spv_parsed_header_fn_t parsed_header,
814
                            spv_parsed_instruction_fn_t parsed_instruction,
815
1.21M
                            spv_diagnostic* diagnostic) {
816
1.21M
  spv_context_t hijack_context = *context;
817
1.21M
  if (diagnostic) {
818
1.09M
    *diagnostic = nullptr;
819
1.09M
    spvtools::UseDiagnosticAsMessageConsumer(&hijack_context, diagnostic);
820
1.09M
  }
821
1.21M
  Parser parser(&hijack_context, user_data, parsed_header, parsed_instruction);
822
1.21M
  return parser.parse(code, num_words, diagnostic);
823
1.21M
}
824
825
// TODO(dneto): This probably belongs in text.cpp since that's the only place
826
// that a spv_binary_t value is created.
827
12.8k
void spvBinaryDestroy(spv_binary binary) {
828
12.8k
  if (binary) {
829
12.8k
    if (binary->code) delete[] binary->code;
830
12.8k
    delete binary;
831
12.8k
  }
832
12.8k
}
833
834
0
size_t spv_strnlen_s(const char* str, size_t strsz) {
835
0
  if (!str) return 0;
836
0
  for (size_t i = 0; i < strsz; i++) {
837
0
    if (!str[i]) return i;
838
0
  }
839
0
  return strsz;
840
0
}