| 308 | } |
| 309 | |
| 310 | spv_result_t Parser::parseInstruction() { |
| 311 | _.instruction_count++; |
| 312 | |
| 313 | // The zero values for all members except for opcode are the |
| 314 | // correct initial values. |
| 315 | spv_parsed_instruction_t inst = {}; |
| 316 | |
| 317 | const uint32_t first_word = peek(); |
| 318 | |
| 319 | // If the module's endianness is different from the host native endianness, |
| 320 | // then converted_words contains the endian-translated words in the |
| 321 | // instruction. |
| 322 | _.endian_converted_words.clear(); |
| 323 | _.endian_converted_words.push_back(first_word); |
| 324 | |
| 325 | // After a successful parse of the instruction, the inst.operands member |
| 326 | // will point to this vector's storage. |
| 327 | _.operands.clear(); |
| 328 | |
| 329 | assert(_.word_index < _.num_words); |
| 330 | // Decompose and check the first word. |
| 331 | uint16_t inst_word_count = 0; |
| 332 | spvOpcodeSplit(first_word, &inst_word_count, &inst.opcode); |
| 333 | if (inst_word_count < 1) { |
| 334 | return diagnostic() << "Invalid instruction word count: " |
| 335 | << inst_word_count; |
| 336 | } |
| 337 | const spvtools::InstructionDesc* opcode_desc = nullptr; |
| 338 | const bool opcode_known = |
| 339 | spvtools::LookupOpcode(static_cast<spv::Op>(inst.opcode), &opcode_desc) == |
| 340 | SPV_SUCCESS; |
| 341 | if (!opcode_known && !handle_unknown_opcodes_) |
| 342 | return diagnostic() << "Invalid opcode: " << inst.opcode; |
| 343 | |
| 344 | // Advance past the opcode word. But remember the start of the instruction. |
| 345 | const size_t inst_offset = _.word_index; |
| 346 | _.word_index++; |
| 347 | |
| 348 | // Emits the instruction at inst_offset as raw data with no decoded operands. |
| 349 | auto emitAsUnknown = [&]() -> spv_result_t { |
| 350 | if (inst_offset + inst_word_count > _.num_words) { |
| 351 | return diagnostic() << "Truncated binary: instruction at word " |
| 352 | << inst_offset << " claims " << inst_word_count |
| 353 | << " words but binary ends at " << _.num_words; |
| 354 | } |
| 355 | // Repopulate endian_converted_words from scratch. The operand loop may |
| 356 | // have partially filled it before the unknown enum was detected. |
| 357 | _.endian_converted_words.clear(); |
| 358 | _.endian_converted_words.push_back(first_word); |
| 359 | if (_.requires_endian_conversion) { |
| 360 | for (uint16_t i = 1; i < inst_word_count; i++) { |
| 361 | _.endian_converted_words.push_back(peekAt(inst_offset + i)); |
| 362 | } |
| 363 | } |
| 364 | _.word_index = inst_offset + inst_word_count; |
| 365 | inst.words = _.requires_endian_conversion ? _.endian_converted_words.data() |
| 366 | : _.words + inst_offset; |
| 367 | inst.num_words = inst_word_count; |
nothing calls this directly
no test coverage detected