| // 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_ |