| // Copyright (c) 2018 Google LLC | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // http://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| #include "source/comp/bit_stream.h" | |
| #include "source/comp/markv.h" | |
| #include "source/comp/markv_codec.h" | |
| #include "source/comp/markv_logger.h" | |
| #include "source/util/make_unique.h" | |
| #ifndef SOURCE_COMP_MARKV_DECODER_H_ | |
| #define SOURCE_COMP_MARKV_DECODER_H_ | |
| namespace spvtools { | |
| namespace comp { | |
| class MarkvLogger; | |
| // Decodes MARK-V buffers written by MarkvEncoder. | |
| class MarkvDecoder : public MarkvCodec { | |
| public: | |
| // |model| is owned by the caller, must be not null and valid during the | |
| // lifetime of MarkvEncoder. | |
| MarkvDecoder(spv_const_context context, const std::vector<uint8_t>& markv, | |
| const MarkvCodecOptions& options, const MarkvModel* model) | |
| : MarkvCodec(context, GetValidatorOptions(options), model), | |
| options_(options), | |
| reader_(markv) { | |
| SetIdBound(1); | |
| parsed_operands_.reserve(25); | |
| inst_words_.reserve(25); | |
| } | |
| ~MarkvDecoder() = default; | |
| // Creates an internal logger which writes comments on the decoding process. | |
| void CreateLogger(MarkvLogConsumer log_consumer, | |
| MarkvDebugConsumer debug_consumer) { | |
| logger_ = MakeUnique<MarkvLogger>(log_consumer, debug_consumer); | |
| } | |
| // Decodes SPIR-V from MARK-V and stores the words in |spirv_binary|. | |
| // Can be called only once. Fails if data of wrong format or ends prematurely, | |
| // of if validation fails. | |
| spv_result_t DecodeModule(std::vector<uint32_t>* spirv_binary); | |
| // Creates and returns validator options. Returned value owned by the caller. | |
| static spv_validator_options GetValidatorOptions( | |
| const MarkvCodecOptions& options) { | |
| return options.validate_spirv_binary ? spvValidatorOptionsCreate() | |
| : nullptr; | |
| } | |
| private: | |
| // Describes the format of a typed literal number. | |
| struct NumberType { | |
| spv_number_kind_t type; | |
| uint32_t bit_width; | |
| }; | |
| // Reads a single bit from reader_. The read bit is stored in |bit|. | |
| // Returns false iff reader_ fails. | |
| bool ReadBit(bool* bit) { | |
| uint64_t bits = 0; | |
| const bool result = reader_.ReadBits(&bits, 1); | |
| if (result) *bit = bits ? true : false; | |
| return result; | |
| }; | |
| // Returns ReadBit bound to the class object. | |
| std::function<bool(bool*)> GetReadBitCallback() { | |
| return std::bind(&MarkvDecoder::ReadBit, this, std::placeholders::_1); | |
| } | |
| // Reads a single non-id word from bit stream. operand_.type determines if | |
| // the word needs to be decoded and how. | |
| spv_result_t DecodeNonIdWord(uint32_t* word); | |
| // Reads and decodes both opcode and num_operands as a single code. | |
| // Returns SPV_UNSUPPORTED iff no suitable codec was found. | |
| spv_result_t DecodeOpcodeAndNumberOfOperands(uint32_t* opcode, | |
| uint32_t* num_operands); | |
| // Reads mtf rank from bit stream. |mtf| is used to determine the codec | |
| // scheme. |fallback_method| is used if no codec defined for |mtf|. | |
| spv_result_t DecodeMtfRankHuffman(uint64_t mtf, uint32_t fallback_method, | |
| uint32_t* rank); | |
| // Reads id using coding based on mtf associated with the id descriptor. | |
| // Returns SPV_UNSUPPORTED iff fallback method needs to be used. | |
| spv_result_t DecodeIdWithDescriptor(uint32_t* id); | |
| // Reads id using coding based on the given |mtf|, which is expected to | |
| // contain the needed |id|. | |
| spv_result_t DecodeExistingId(uint64_t mtf, uint32_t* id); | |
| // Reads type id of the current instruction if can't be inferred. | |
| spv_result_t DecodeTypeId(); | |
| // Reads result id of the current instruction if can't be inferred. | |
| spv_result_t DecodeResultId(); | |
| // Reads id which is neither type nor result id. | |
| spv_result_t DecodeRefId(uint32_t* id); | |
| // Reads and discards bits until the beginning of the next byte if the | |
| // number of bits until the next byte is less than |byte_break_if_less_than|. | |
| bool ReadToByteBreak(size_t byte_break_if_less_than); | |
| // Returns instruction words decoded up to this point. | |
| const uint32_t* GetInstWords() const override { return inst_words_.data(); } | |
| // Reads a literal number as it is described in |operand| from the bit stream, | |
| // decodes and writes it to spirv_. | |
| spv_result_t DecodeLiteralNumber(const spv_parsed_operand_t& operand); | |
| // Reads instruction from bit stream, decodes and validates it. | |
| // Decoded instruction is valid until the next call of DecodeInstruction(). | |
| spv_result_t DecodeInstruction(); | |
| // Read operand from the stream decodes and validates it. | |
| spv_result_t DecodeOperand(size_t operand_offset, | |
| const spv_operand_type_t type, | |
| spv_operand_pattern_t* expected_operands); | |
| // Records the numeric type for an operand according to the type information | |
| // associated with the given non-zero type Id. This can fail if the type Id | |
| // is not a type Id, or if the type Id does not reference a scalar numeric | |
| // type. On success, return SPV_SUCCESS and populates the num_words, | |
| // number_kind, and number_bit_width fields of parsed_operand. | |
| spv_result_t SetNumericTypeInfoForType(spv_parsed_operand_t* parsed_operand, | |
| uint32_t type_id); | |
| // Records the number type for the current instruction, if it generates a | |
| // type. For types that aren't scalar numbers, record something with number | |
| // kind SPV_NUMBER_NONE. | |
| void RecordNumberType(); | |
| MarkvCodecOptions options_; | |
| // Temporary sink where decoded SPIR-V words are written. Once it contains the | |
| // entire module, the container is moved and returned. | |
| std::vector<uint32_t> spirv_; | |
| // Bit stream containing encoded data. | |
| BitReaderWord64 reader_; | |
| // Temporary storage for operands of the currently parsed instruction. | |
| // Valid until next DecodeInstruction call. | |
| std::vector<spv_parsed_operand_t> parsed_operands_; | |
| // Temporary storage for current instruction words. | |
| // Valid until next DecodeInstruction call. | |
| std::vector<uint32_t> inst_words_; | |
| // Maps a type ID to its number type description. | |
| std::unordered_map<uint32_t, NumberType> type_id_to_number_type_info_; | |
| // Maps an ExtInstImport id to the extended instruction type. | |
| std::unordered_map<uint32_t, spv_ext_inst_type_t> import_id_to_ext_inst_type_; | |
| }; | |
| } // namespace comp | |
| } // namespace spvtools | |
| #endif // SOURCE_COMP_MARKV_DECODER_H_ |