From b36acbec0eda3c58070d4e24210c86f4c5b26479 Mon Sep 17 00:00:00 2001 From: Andrey Tuganov Date: Wed, 9 Aug 2017 14:01:12 -0400 Subject: [PATCH] Update MARK-V to version 1.01 Includes: - Multi-sequence move-to-front - Coding by id descriptor - Statistical coding of non-id words - Joint coding of opcode and num_operands Removed explicit form Huffman codec constructor - The standard use case for it is to be constructed from initializer list. Using serialization for Huffman codecs --- source/comp/CMakeLists.txt | 2 +- source/comp/markv_autogen.cpp | 57 + source/comp/markv_autogen.h | 45 + source/comp/markv_autogen.inc | 3920 ++++++++++++++++++++++++++++++++ source/comp/markv_codec.cpp | 2501 ++++++++++++++++---- source/operand.cpp | 58 + source/operand.h | 8 + source/util/huffman_codec.h | 5 +- source/util/move_to_front.h | 45 +- source/validate_id.cpp | 63 +- test/comp/markv_codec_test.cpp | 419 ++++ tools/stats/stats_analyzer.cpp | 140 +- 12 files changed, 6667 insertions(+), 596 deletions(-) create mode 100644 source/comp/markv_autogen.cpp create mode 100644 source/comp/markv_autogen.h create mode 100644 source/comp/markv_autogen.inc diff --git a/source/comp/CMakeLists.txt b/source/comp/CMakeLists.txt index 11def56aa..86f8c4ebf 100644 --- a/source/comp/CMakeLists.txt +++ b/source/comp/CMakeLists.txt @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -add_library(SPIRV-Tools-comp markv_codec.cpp) +add_library(SPIRV-Tools-comp markv_codec.cpp markv_autogen.cpp) spvtools_default_compile_options(SPIRV-Tools-comp) target_include_directories(SPIRV-Tools-comp diff --git a/source/comp/markv_autogen.cpp b/source/comp/markv_autogen.cpp new file mode 100644 index 000000000..7db3c5232 --- /dev/null +++ b/source/comp/markv_autogen.cpp @@ -0,0 +1,57 @@ +// Copyright (c) 2017 Google Inc. +// +// 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 "markv_autogen.h" + +#include +#include +#include +#include +#include + +#include "spirv/1.2/spirv.h" + +using spvutils::HuffmanCodec; + +namespace { + +// Signals that the value is not in the coding scheme and a fallback method +// needs to be used. +const uint64_t kMarkvNoneOfTheAbove = GetMarkvNonOfTheAbove(); + +inline uint32_t CombineOpcodeAndNumOperands(uint32_t opcode, + uint32_t num_operands) { + return opcode | (num_operands << 16); +} + +} // namespace + +// The following file contains autogenerated statistical coding rules. +// Generated by running spirv-stats on representative corpus of shaders with +// flags: +// --codegen_opcode_and_num_operands_hist +// --codegen_opcode_and_num_operands_markov_huffman_codecs +// --codegen_literal_string_huffman_codecs +// --codegen_non_id_word_huffman_codecs +// --codegen_id_descriptor_huffman_codecs +// +// Example: +// find -type f -print0 | xargs -0 -s 2000000 +// ~/SPIRV-Tools/build/tools/spirv-stats -v +// --codegen_opcode_and_num_operands_hist +// --codegen_opcode_and_num_operands_markov_huffman_codecs +// --codegen_literal_string_huffman_codecs --codegen_non_id_word_huffman_codecs +// --codegen_id_descriptor_huffman_codecs -o +// ~/SPIRV-Tools/source/comp/markv_autogen.inc +#include "markv_autogen.inc" diff --git a/source/comp/markv_autogen.h b/source/comp/markv_autogen.h new file mode 100644 index 000000000..a7a21f7c8 --- /dev/null +++ b/source/comp/markv_autogen.h @@ -0,0 +1,45 @@ +// Copyright (c) 2017 Google Inc. +// +// 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. + +#ifndef LIBSPIRV_COMP_MARKV_AUTOGEN_H_ +#define LIBSPIRV_COMP_MARKV_AUTOGEN_H_ + +#include +#include +#include + +#include "util/huffman_codec.h" + +inline uint64_t GetMarkvNonOfTheAbove() { + // Magic number. + return 1111111111111111111; +} + +std::map GetOpcodeAndNumOperandsHist(); + +std::map>> +GetOpcodeAndNumOperandsMarkovHuffmanCodecs(); + +std::map>> +GetLiteralStringHuffmanCodecs(); + +std::map, + std::unique_ptr>> + GetNonIdWordHuffmanCodecs(); + + std::map, + std::unique_ptr>> + GetIdDescriptorHuffmanCodecs(); + +#endif // LIBSPIRV_COMP_MARKV_AUTOGEN_H_ diff --git a/source/comp/markv_autogen.inc b/source/comp/markv_autogen.inc new file mode 100644 index 000000000..83a7fbd0a --- /dev/null +++ b/source/comp/markv_autogen.inc @@ -0,0 +1,3920 @@ + +std::map GetOpcodeAndNumOperandsHist() { + return std::map({ + { CombineOpcodeAndNumOperands(SpvOpExtInst, 7), 158282 }, + { CombineOpcodeAndNumOperands(SpvOpDot, 4), 151035 }, + { CombineOpcodeAndNumOperands(SpvOpVectorShuffle, 6), 183292 }, + { CombineOpcodeAndNumOperands(SpvOpImageSampleImplicitLod, 4), 126492 }, + { CombineOpcodeAndNumOperands(SpvOpExecutionMode, 2), 13311 }, + { CombineOpcodeAndNumOperands(SpvOpFNegate, 3), 29952 }, + { CombineOpcodeAndNumOperands(SpvOpExtInst, 5), 106847 }, + { CombineOpcodeAndNumOperands(SpvOpImageSampleExplicitLod, 7), 26350 }, + { CombineOpcodeAndNumOperands(SpvOpImageSampleExplicitLod, 6), 28186 }, + { CombineOpcodeAndNumOperands(SpvOpFDiv, 4), 41635 }, + { CombineOpcodeAndNumOperands(SpvOpFMul, 4), 412786 }, + { CombineOpcodeAndNumOperands(SpvOpFunction, 4), 62905 }, + { CombineOpcodeAndNumOperands(SpvOpVectorShuffle, 8), 118614 }, + { CombineOpcodeAndNumOperands(SpvOpDecorate, 2), 100735 }, + { CombineOpcodeAndNumOperands(SpvOpReturnValue, 1), 40852 }, + { CombineOpcodeAndNumOperands(SpvOpVectorTimesScalar, 4), 157091 }, + { CombineOpcodeAndNumOperands(SpvOpExtInst, 6), 122100 }, + { CombineOpcodeAndNumOperands(SpvOpAccessChain, 5), 82930 }, + { CombineOpcodeAndNumOperands(SpvOpFSub, 4), 161019 }, + { CombineOpcodeAndNumOperands(SpvOpConstant, 3), 466014 }, + { CombineOpcodeAndNumOperands(SpvOpCompositeExtract, 5), 107126 }, + { CombineOpcodeAndNumOperands(SpvOpTypeImage, 8), 34775 }, + { CombineOpcodeAndNumOperands(SpvOpImageSampleDrefExplicitLod, 7), 26146 }, + { CombineOpcodeAndNumOperands(SpvOpMemoryModel, 2), 18879 }, + { CombineOpcodeAndNumOperands(SpvOpDecorate, 3), 485251 }, + { CombineOpcodeAndNumOperands(SpvOpCompositeConstruct, 4), 78011 }, + { CombineOpcodeAndNumOperands(SpvOpTypeFloat, 2), 18879 }, + { CombineOpcodeAndNumOperands(SpvOpVectorTimesMatrix, 4), 15848 }, + { CombineOpcodeAndNumOperands(SpvOpTypeVector, 3), 69404 }, + { CombineOpcodeAndNumOperands(SpvOpTypeFunction, 3), 19998 }, + { CombineOpcodeAndNumOperands(SpvOpConstantComposite, 6), 40228 }, + { CombineOpcodeAndNumOperands(SpvOpCapability, 1), 22510 }, + { CombineOpcodeAndNumOperands(SpvOpTypeArray, 3), 37585 }, + { CombineOpcodeAndNumOperands(SpvOpTypeInt, 3), 30454 }, + { CombineOpcodeAndNumOperands(SpvOpFunctionCall, 4), 29021 }, + { CombineOpcodeAndNumOperands(SpvOpFAdd, 4), 342237 }, + { CombineOpcodeAndNumOperands(SpvOpTypeMatrix, 3), 24449 }, + { CombineOpcodeAndNumOperands(SpvOpLabel, 1), 129408 }, + { CombineOpcodeAndNumOperands(SpvOpTypePointer, 3), 246535 }, + { CombineOpcodeAndNumOperands(SpvOpAccessChain, 4), 503456 }, + { CombineOpcodeAndNumOperands(SpvOpTypeFunction, 2), 19779 }, + { CombineOpcodeAndNumOperands(SpvOpBranchConditional, 3), 24139 }, + { CombineOpcodeAndNumOperands(SpvOpVariable, 3), 697946 }, + { CombineOpcodeAndNumOperands(SpvOpConstantComposite, 5), 55769 }, + { CombineOpcodeAndNumOperands(SpvOpTypeVoid, 1), 18879 }, + { CombineOpcodeAndNumOperands(SpvOpCompositeConstruct, 6), 145508 }, + { CombineOpcodeAndNumOperands(SpvOpFunctionParameter, 2), 85583 }, + { CombineOpcodeAndNumOperands(SpvOpTypeSampledImage, 2), 34775 }, + { CombineOpcodeAndNumOperands(SpvOpConstantComposite, 4), 66362 }, + { CombineOpcodeAndNumOperands(SpvOpLoad, 3), 1272902 }, + { CombineOpcodeAndNumOperands(SpvOpReturn, 0), 22122 }, + { CombineOpcodeAndNumOperands(SpvOpCompositeExtract, 4), 861008 }, + { CombineOpcodeAndNumOperands(SpvOpFunctionEnd, 0), 62905 }, + { CombineOpcodeAndNumOperands(SpvOpExtInstImport, 2), 18879 }, + { CombineOpcodeAndNumOperands(SpvOpSelectionMerge, 2), 22009 }, + { CombineOpcodeAndNumOperands(SpvOpBranch, 1), 38275 }, + { CombineOpcodeAndNumOperands(SpvOpTypeBool, 1), 12208 }, + { CombineOpcodeAndNumOperands(SpvOpSampledImage, 4), 95518 }, + { CombineOpcodeAndNumOperands(SpvOpMemberDecorate, 3), 94887 }, + { CombineOpcodeAndNumOperands(SpvOpMemberDecorate, 4), 1942215 }, + { CombineOpcodeAndNumOperands(SpvOpCompositeConstruct, 5), 205266 }, + { CombineOpcodeAndNumOperands(SpvOpUndef, 2), 22157 }, + { CombineOpcodeAndNumOperands(SpvOpCompositeInsert, 5), 142749 }, + { CombineOpcodeAndNumOperands(SpvOpCompositeInsert, 6), 24420 }, + { CombineOpcodeAndNumOperands(SpvOpCompositeExtract, 6), 16896 }, + { CombineOpcodeAndNumOperands(SpvOpStore, 2), 604982 }, + { CombineOpcodeAndNumOperands(SpvOpIAdd, 4), 14471 }, + { CombineOpcodeAndNumOperands(SpvOpVectorShuffle, 7), 269658 }, + { kMarkvNoneOfTheAbove, 399895 }, + }); +} + +std::map>> +GetOpcodeAndNumOperandsMarkovHuffmanCodecs() { + std::map>> codecs; + { + std::unique_ptr> codec(new HuffmanCodec(51, { + {0, 0, 0}, + {131134, 0, 0}, + {196669, 0, 0}, + {262209, 0, 0}, + {262224, 0, 0}, + {262225, 0, 0}, + {262231, 0, 0}, + {262273, 0, 0}, + {262275, 0, 0}, + {262277, 0, 0}, + {262286, 0, 0}, + {262292, 0, 0}, + {327692, 0, 0}, + {327745, 0, 0}, + {327760, 0, 0}, + {327761, 0, 0}, + {327762, 0, 0}, + {393228, 0, 0}, + {393281, 0, 0}, + {393295, 0, 0}, + {393296, 0, 0}, + {393297, 0, 0}, + {393298, 0, 0}, + {458764, 0, 0}, + {458831, 0, 0}, + {524367, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 18, 6}, + {0, 13, 27}, + {0, 19, 12}, + {0, 15, 22}, + {0, 28, 21}, + {0, 29, 16}, + {0, 30, 10}, + {0, 17, 20}, + {0, 11, 25}, + {0, 26, 31}, + {0, 4, 32}, + {0, 34, 33}, + {0, 24, 35}, + {0, 23, 36}, + {0, 37, 14}, + {0, 38, 8}, + {0, 1, 39}, + {0, 3, 9}, + {0, 41, 40}, + {0, 42, 2}, + {0, 43, 5}, + {0, 45, 44}, + {0, 47, 46}, + {0, 48, 7}, + {0, 50, 49}, + })); + + codecs.emplace(SpvOpFMul, std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(53, { + {0, 0, 0}, + {131134, 0, 0}, + {196669, 0, 0}, + {262209, 0, 0}, + {262224, 0, 0}, + {262225, 0, 0}, + {262230, 0, 0}, + {262231, 0, 0}, + {262273, 0, 0}, + {262275, 0, 0}, + {262277, 0, 0}, + {262286, 0, 0}, + {262292, 0, 0}, + {327692, 0, 0}, + {327745, 0, 0}, + {327760, 0, 0}, + {327761, 0, 0}, + {327762, 0, 0}, + {393228, 0, 0}, + {393281, 0, 0}, + {393295, 0, 0}, + {393296, 0, 0}, + {393297, 0, 0}, + {393303, 0, 0}, + {458764, 0, 0}, + {458831, 0, 0}, + {524367, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 9, 23}, + {0, 21, 28}, + {0, 20, 29}, + {0, 14, 30}, + {0, 19, 8}, + {0, 31, 16}, + {0, 25, 11}, + {0, 32, 18}, + {0, 33, 15}, + {0, 4, 12}, + {0, 22, 26}, + {0, 17, 34}, + {0, 13, 6}, + {0, 24, 35}, + {0, 27, 36}, + {0, 3, 37}, + {0, 39, 38}, + {0, 2, 40}, + {0, 42, 41}, + {0, 7, 1}, + {0, 10, 43}, + {0, 5, 44}, + {0, 46, 45}, + {0, 48, 47}, + {0, 50, 49}, + {0, 52, 51}, + })); + + codecs.emplace(SpvOpFAdd, std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(19, { + {0, 0, 0}, + {196631, 0, 0}, + {196640, 0, 0}, + {196641, 0, 0}, + {196651, 0, 0}, + {196667, 0, 0}, + {262188, 0, 0}, + {327724, 0, 0}, + {393260, 0, 0}, + {524313, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 6, 8}, + {0, 7, 11}, + {0, 1, 12}, + {0, 13, 9}, + {0, 14, 3}, + {0, 15, 10}, + {0, 4, 2}, + {0, 17, 16}, + {0, 5, 18}, + })); + + codecs.emplace(SpvOpTypePointer, std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(49, { + {0, 0, 0}, + {65790, 0, 0}, + {131134, 0, 0}, + {196669, 0, 0}, + {262209, 0, 0}, + {262224, 0, 0}, + {262225, 0, 0}, + {262273, 0, 0}, + {262275, 0, 0}, + {262277, 0, 0}, + {262280, 0, 0}, + {262286, 0, 0}, + {262292, 0, 0}, + {262328, 0, 0}, + {327692, 0, 0}, + {327745, 0, 0}, + {327760, 0, 0}, + {327761, 0, 0}, + {327762, 0, 0}, + {393228, 0, 0}, + {393295, 0, 0}, + {393296, 0, 0}, + {458764, 0, 0}, + {458831, 0, 0}, + {524367, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 21, 24}, + {0, 25, 26}, + {0, 15, 20}, + {0, 23, 13}, + {0, 5, 10}, + {0, 11, 27}, + {0, 17, 7}, + {0, 28, 18}, + {0, 1, 29}, + {0, 30, 2}, + {0, 31, 19}, + {0, 32, 16}, + {0, 33, 8}, + {0, 4, 3}, + {0, 9, 34}, + {0, 35, 6}, + {0, 12, 22}, + {0, 37, 36}, + {0, 39, 38}, + {0, 40, 14}, + {0, 42, 41}, + {0, 44, 43}, + {0, 46, 45}, + {0, 48, 47}, + })); + + codecs.emplace(SpvOpFSub, std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(51, { + {0, 0, 0}, + {131134, 0, 0}, + {196669, 0, 0}, + {262209, 0, 0}, + {262224, 0, 0}, + {262225, 0, 0}, + {262231, 0, 0}, + {262273, 0, 0}, + {262275, 0, 0}, + {262277, 0, 0}, + {262286, 0, 0}, + {262292, 0, 0}, + {327692, 0, 0}, + {327745, 0, 0}, + {327760, 0, 0}, + {327761, 0, 0}, + {327762, 0, 0}, + {393228, 0, 0}, + {393295, 0, 0}, + {393296, 0, 0}, + {393297, 0, 0}, + {393298, 0, 0}, + {458764, 0, 0}, + {458831, 0, 0}, + {458842, 0, 0}, + {524367, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 20, 13}, + {0, 21, 27}, + {0, 6, 16}, + {0, 22, 28}, + {0, 29, 1}, + {0, 30, 12}, + {0, 31, 18}, + {0, 3, 4}, + {0, 2, 25}, + {0, 11, 32}, + {0, 33, 23}, + {0, 24, 34}, + {0, 35, 10}, + {0, 8, 15}, + {0, 7, 36}, + {0, 37, 17}, + {0, 38, 26}, + {0, 40, 39}, + {0, 41, 14}, + {0, 9, 42}, + {0, 43, 19}, + {0, 45, 44}, + {0, 47, 46}, + {0, 49, 48}, + {0, 50, 5}, + })); + + codecs.emplace(SpvOpCompositeExtract, std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(49, { + {0, 0, 0}, + {65562, 0, 0}, + {131099, 0, 0}, + {131134, 0, 0}, + {196629, 0, 0}, + {196631, 0, 0}, + {196640, 0, 0}, + {196651, 0, 0}, + {196667, 0, 0}, + {196669, 0, 0}, + {262188, 0, 0}, + {262209, 0, 0}, + {262225, 0, 0}, + {262275, 0, 0}, + {262292, 0, 0}, + {327692, 0, 0}, + {327724, 0, 0}, + {327745, 0, 0}, + {393228, 0, 0}, + {393260, 0, 0}, + {393295, 0, 0}, + {393296, 0, 0}, + {458831, 0, 0}, + {524313, 0, 0}, + {524367, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 21, 14}, + {0, 13, 26}, + {0, 27, 20}, + {0, 18, 28}, + {0, 24, 29}, + {0, 30, 12}, + {0, 31, 22}, + {0, 3, 15}, + {0, 33, 32}, + {0, 34, 10}, + {0, 35, 17}, + {0, 1, 19}, + {0, 5, 11}, + {0, 36, 23}, + {0, 4, 16}, + {0, 2, 37}, + {0, 39, 38}, + {0, 25, 9}, + {0, 41, 40}, + {0, 43, 42}, + {0, 6, 44}, + {0, 7, 45}, + {0, 47, 46}, + {0, 8, 48}, + })); + + codecs.emplace(SpvOpVariable, std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(5, { + {0, 0, 0}, + {131134, 0, 0}, + {196669, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 1, 3}, + {0, 2, 4}, + })); + + codecs.emplace(SpvOpAccessChain, std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(49, { + {0, 0, 0}, + {252, 0, 0}, + {65785, 0, 0}, + {131134, 0, 0}, + {131319, 0, 0}, + {196667, 0, 0}, + {196669, 0, 0}, + {262209, 0, 0}, + {262225, 0, 0}, + {262273, 0, 0}, + {262275, 0, 0}, + {262277, 0, 0}, + {262286, 0, 0}, + {262292, 0, 0}, + {327692, 0, 0}, + {327745, 0, 0}, + {327761, 0, 0}, + {327762, 0, 0}, + {393228, 0, 0}, + {393295, 0, 0}, + {393296, 0, 0}, + {393298, 0, 0}, + {393461, 0, 0}, + {458831, 0, 0}, + {524367, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 18, 16}, + {0, 14, 26}, + {0, 10, 27}, + {0, 28, 17}, + {0, 12, 29}, + {0, 24, 20}, + {0, 31, 30}, + {0, 32, 11}, + {0, 33, 21}, + {0, 34, 13}, + {0, 35, 9}, + {0, 15, 23}, + {0, 36, 4}, + {0, 37, 19}, + {0, 38, 3}, + {0, 7, 1}, + {0, 8, 39}, + {0, 2, 25}, + {0, 22, 40}, + {0, 42, 41}, + {0, 44, 43}, + {0, 46, 45}, + {0, 6, 5}, + {0, 48, 47}, + })); + + codecs.emplace(SpvOpLabel, std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(51, { + {0, 0, 0}, + {253, 0, 0}, + {65785, 0, 0}, + {131134, 0, 0}, + {196669, 0, 0}, + {262201, 0, 0}, + {262209, 0, 0}, + {262224, 0, 0}, + {262225, 0, 0}, + {262273, 0, 0}, + {262275, 0, 0}, + {262277, 0, 0}, + {262286, 0, 0}, + {262292, 0, 0}, + {327692, 0, 0}, + {327745, 0, 0}, + {327760, 0, 0}, + {327761, 0, 0}, + {327762, 0, 0}, + {393228, 0, 0}, + {393281, 0, 0}, + {393295, 0, 0}, + {393296, 0, 0}, + {458764, 0, 0}, + {458831, 0, 0}, + {524367, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 20, 23}, + {0, 19, 27}, + {0, 28, 13}, + {0, 9, 29}, + {0, 18, 30}, + {0, 10, 31}, + {0, 12, 22}, + {0, 32, 14}, + {0, 33, 16}, + {0, 34, 24}, + {0, 35, 25}, + {0, 36, 21}, + {0, 11, 7}, + {0, 38, 37}, + {0, 40, 39}, + {0, 8, 41}, + {0, 1, 2}, + {0, 42, 5}, + {0, 17, 26}, + {0, 15, 43}, + {0, 45, 44}, + {0, 46, 3}, + {0, 48, 47}, + {0, 4, 6}, + {0, 50, 49}, + })); + + codecs.emplace(SpvOpStore, std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(57, { + {0, 0, 0}, + {65790, 0, 0}, + {131134, 0, 0}, + {196669, 0, 0}, + {262209, 0, 0}, + {262224, 0, 0}, + {262225, 0, 0}, + {262230, 0, 0}, + {262231, 0, 0}, + {262273, 0, 0}, + {262275, 0, 0}, + {262277, 0, 0}, + {262286, 0, 0}, + {262292, 0, 0}, + {327692, 0, 0}, + {327745, 0, 0}, + {327760, 0, 0}, + {327761, 0, 0}, + {327762, 0, 0}, + {393228, 0, 0}, + {393281, 0, 0}, + {393295, 0, 0}, + {393296, 0, 0}, + {393297, 0, 0}, + {393304, 0, 0}, + {458764, 0, 0}, + {458817, 0, 0}, + {458831, 0, 0}, + {524367, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 20, 26}, + {0, 23, 30}, + {0, 17, 31}, + {0, 25, 5}, + {0, 14, 32}, + {0, 24, 15}, + {0, 1, 33}, + {0, 34, 22}, + {0, 35, 16}, + {0, 36, 10}, + {0, 8, 19}, + {0, 18, 13}, + {0, 12, 37}, + {0, 38, 9}, + {0, 28, 39}, + {0, 7, 40}, + {0, 29, 6}, + {0, 11, 41}, + {0, 42, 21}, + {0, 43, 27}, + {0, 4, 44}, + {0, 45, 2}, + {0, 3, 46}, + {0, 48, 47}, + {0, 50, 49}, + {0, 52, 51}, + {0, 54, 53}, + {0, 56, 55}, + })); + + codecs.emplace(SpvOpLoad, std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(53, { + {0, 0, 0}, + {131134, 0, 0}, + {196669, 0, 0}, + {262209, 0, 0}, + {262224, 0, 0}, + {262225, 0, 0}, + {262231, 0, 0}, + {262273, 0, 0}, + {262275, 0, 0}, + {262277, 0, 0}, + {262280, 0, 0}, + {262286, 0, 0}, + {262288, 0, 0}, + {262292, 0, 0}, + {327692, 0, 0}, + {327745, 0, 0}, + {327760, 0, 0}, + {327761, 0, 0}, + {327762, 0, 0}, + {393228, 0, 0}, + {393281, 0, 0}, + {393295, 0, 0}, + {393296, 0, 0}, + {393304, 0, 0}, + {458764, 0, 0}, + {458831, 0, 0}, + {524367, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 15, 20}, + {0, 17, 28}, + {0, 29, 19}, + {0, 6, 11}, + {0, 31, 30}, + {0, 14, 26}, + {0, 23, 32}, + {0, 12, 4}, + {0, 21, 25}, + {0, 10, 33}, + {0, 22, 7}, + {0, 34, 27}, + {0, 18, 13}, + {0, 35, 8}, + {0, 36, 16}, + {0, 37, 3}, + {0, 39, 38}, + {0, 41, 40}, + {0, 42, 2}, + {0, 9, 43}, + {0, 44, 5}, + {0, 24, 45}, + {0, 46, 1}, + {0, 48, 47}, + {0, 50, 49}, + {0, 52, 51}, + })); + + codecs.emplace(SpvOpCompositeConstruct, std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(9, { + {0, 0, 0}, + {131143, 0, 0}, + {196679, 0, 0}, + {196680, 0, 0}, + {262216, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 5, 2}, + {0, 3, 6}, + {0, 7, 1}, + {0, 4, 8}, + })); + + codecs.emplace(SpvOpMemberDecorate, std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(19, { + {0, 0, 0}, + {65556, 0, 0}, + {196631, 0, 0}, + {196640, 0, 0}, + {196651, 0, 0}, + {196667, 0, 0}, + {262188, 0, 0}, + {327724, 0, 0}, + {393260, 0, 0}, + {524313, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 8, 10}, + {0, 1, 2}, + {0, 7, 11}, + {0, 3, 12}, + {0, 9, 13}, + {0, 14, 6}, + {0, 15, 5}, + {0, 17, 16}, + {0, 4, 18}, + })); + + codecs.emplace(SpvOpConstantComposite, std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(11, { + {0, 0, 0}, + {65555, 0, 0}, + {131143, 0, 0}, + {196679, 0, 0}, + {196680, 0, 0}, + {262216, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 4, 6}, + {0, 1, 2}, + {0, 8, 7}, + {0, 5, 9}, + {0, 3, 10}, + })); + + codecs.emplace(SpvOpDecorate, std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(19, { + {0, 0, 0}, + {196632, 0, 0}, + {196636, 0, 0}, + {196640, 0, 0}, + {196651, 0, 0}, + {196667, 0, 0}, + {262188, 0, 0}, + {327724, 0, 0}, + {393260, 0, 0}, + {524313, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 1, 9}, + {0, 2, 10}, + {0, 12, 11}, + {0, 7, 8}, + {0, 13, 3}, + {0, 14, 6}, + {0, 15, 5}, + {0, 17, 16}, + {0, 18, 4}, + })); + + codecs.emplace(SpvOpConstant, std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(51, { + {0, 0, 0}, + {65790, 0, 0}, + {131134, 0, 0}, + {196669, 0, 0}, + {196735, 0, 0}, + {262209, 0, 0}, + {262224, 0, 0}, + {262225, 0, 0}, + {262231, 0, 0}, + {262273, 0, 0}, + {262275, 0, 0}, + {262277, 0, 0}, + {262286, 0, 0}, + {262292, 0, 0}, + {327692, 0, 0}, + {327745, 0, 0}, + {327760, 0, 0}, + {327761, 0, 0}, + {327762, 0, 0}, + {393228, 0, 0}, + {393281, 0, 0}, + {393295, 0, 0}, + {393296, 0, 0}, + {458764, 0, 0}, + {458831, 0, 0}, + {524367, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 8, 20}, + {0, 22, 27}, + {0, 9, 28}, + {0, 15, 29}, + {0, 13, 30}, + {0, 21, 17}, + {0, 1, 18}, + {0, 4, 26}, + {0, 23, 31}, + {0, 12, 6}, + {0, 33, 32}, + {0, 34, 25}, + {0, 35, 19}, + {0, 14, 36}, + {0, 24, 37}, + {0, 2, 38}, + {0, 11, 10}, + {0, 40, 39}, + {0, 5, 16}, + {0, 42, 41}, + {0, 7, 43}, + {0, 3, 44}, + {0, 46, 45}, + {0, 48, 47}, + {0, 50, 49}, + })); + + codecs.emplace(SpvOpExtInst, std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(45, { + {0, 0, 0}, + {131134, 0, 0}, + {196669, 0, 0}, + {262209, 0, 0}, + {262224, 0, 0}, + {262225, 0, 0}, + {262231, 0, 0}, + {262273, 0, 0}, + {262275, 0, 0}, + {262277, 0, 0}, + {262286, 0, 0}, + {262292, 0, 0}, + {327692, 0, 0}, + {327745, 0, 0}, + {327760, 0, 0}, + {327762, 0, 0}, + {393228, 0, 0}, + {393295, 0, 0}, + {393296, 0, 0}, + {393303, 0, 0}, + {458764, 0, 0}, + {458831, 0, 0}, + {524367, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 19, 13}, + {0, 6, 24}, + {0, 16, 25}, + {0, 17, 26}, + {0, 27, 12}, + {0, 28, 20}, + {0, 9, 29}, + {0, 23, 14}, + {0, 22, 15}, + {0, 11, 30}, + {0, 31, 21}, + {0, 4, 18}, + {0, 3, 32}, + {0, 5, 33}, + {0, 10, 34}, + {0, 8, 35}, + {0, 36, 1}, + {0, 2, 37}, + {0, 39, 38}, + {0, 7, 40}, + {0, 42, 41}, + {0, 44, 43}, + })); + + codecs.emplace(SpvOpVectorTimesScalar, std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(47, { + {0, 0, 0}, + {131134, 0, 0}, + {196669, 0, 0}, + {262209, 0, 0}, + {262224, 0, 0}, + {262225, 0, 0}, + {262231, 0, 0}, + {262273, 0, 0}, + {262275, 0, 0}, + {262277, 0, 0}, + {262286, 0, 0}, + {262292, 0, 0}, + {327692, 0, 0}, + {327745, 0, 0}, + {327760, 0, 0}, + {327761, 0, 0}, + {327762, 0, 0}, + {393228, 0, 0}, + {393295, 0, 0}, + {393296, 0, 0}, + {393303, 0, 0}, + {458764, 0, 0}, + {458831, 0, 0}, + {524367, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 19, 20}, + {0, 4, 25}, + {0, 13, 26}, + {0, 15, 27}, + {0, 21, 23}, + {0, 28, 8}, + {0, 29, 12}, + {0, 14, 17}, + {0, 18, 30}, + {0, 24, 3}, + {0, 10, 22}, + {0, 11, 31}, + {0, 32, 16}, + {0, 34, 33}, + {0, 35, 5}, + {0, 36, 6}, + {0, 37, 2}, + {0, 9, 38}, + {0, 39, 7}, + {0, 40, 1}, + {0, 42, 41}, + {0, 44, 43}, + {0, 46, 45}, + })); + + codecs.emplace(SpvOpVectorShuffle, std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(29, { + {0, 0, 0}, + {131134, 0, 0}, + {196669, 0, 0}, + {262209, 0, 0}, + {262225, 0, 0}, + {262231, 0, 0}, + {262273, 0, 0}, + {262277, 0, 0}, + {262286, 0, 0}, + {262292, 0, 0}, + {327745, 0, 0}, + {393281, 0, 0}, + {393295, 0, 0}, + {393296, 0, 0}, + {458831, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 11, 10}, + {0, 9, 16}, + {0, 7, 17}, + {0, 8, 18}, + {0, 19, 13}, + {0, 20, 6}, + {0, 5, 21}, + {0, 15, 22}, + {0, 3, 23}, + {0, 12, 2}, + {0, 25, 24}, + {0, 26, 1}, + {0, 4, 27}, + {0, 28, 14}, + })); + + codecs.emplace(SpvOpImageSampleImplicitLod, std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(47, { + {0, 0, 0}, + {131134, 0, 0}, + {196669, 0, 0}, + {262209, 0, 0}, + {262224, 0, 0}, + {262225, 0, 0}, + {262273, 0, 0}, + {262275, 0, 0}, + {262277, 0, 0}, + {262280, 0, 0}, + {262286, 0, 0}, + {262292, 0, 0}, + {327692, 0, 0}, + {327745, 0, 0}, + {327760, 0, 0}, + {327761, 0, 0}, + {327762, 0, 0}, + {393228, 0, 0}, + {393281, 0, 0}, + {393295, 0, 0}, + {393296, 0, 0}, + {393298, 0, 0}, + {458764, 0, 0}, + {458831, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 5, 18}, + {0, 1, 25}, + {0, 24, 23}, + {0, 16, 12}, + {0, 4, 26}, + {0, 6, 27}, + {0, 2, 28}, + {0, 20, 19}, + {0, 9, 29}, + {0, 3, 17}, + {0, 30, 10}, + {0, 21, 31}, + {0, 13, 7}, + {0, 8, 15}, + {0, 33, 32}, + {0, 34, 14}, + {0, 11, 35}, + {0, 37, 36}, + {0, 39, 38}, + {0, 22, 40}, + {0, 42, 41}, + {0, 44, 43}, + {0, 46, 45}, + })); + + codecs.emplace(SpvOpDot, std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(49, { + {0, 0, 0}, + {65785, 0, 0}, + {131134, 0, 0}, + {196669, 0, 0}, + {262209, 0, 0}, + {262221, 0, 0}, + {262224, 0, 0}, + {262225, 0, 0}, + {262230, 0, 0}, + {262273, 0, 0}, + {262275, 0, 0}, + {262277, 0, 0}, + {262286, 0, 0}, + {262292, 0, 0}, + {327692, 0, 0}, + {327760, 0, 0}, + {327761, 0, 0}, + {327762, 0, 0}, + {393228, 0, 0}, + {393295, 0, 0}, + {393296, 0, 0}, + {393298, 0, 0}, + {458764, 0, 0}, + {458831, 0, 0}, + {524367, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 9, 13}, + {0, 26, 10}, + {0, 15, 27}, + {0, 18, 22}, + {0, 29, 28}, + {0, 5, 30}, + {0, 6, 20}, + {0, 31, 12}, + {0, 11, 2}, + {0, 1, 24}, + {0, 14, 25}, + {0, 33, 32}, + {0, 23, 34}, + {0, 36, 35}, + {0, 17, 16}, + {0, 37, 19}, + {0, 38, 21}, + {0, 8, 4}, + {0, 40, 39}, + {0, 42, 41}, + {0, 44, 43}, + {0, 3, 7}, + {0, 46, 45}, + {0, 48, 47}, + })); + + codecs.emplace(SpvOpCompositeInsert, std::move(codec)); + } + + return codecs; +} + +std::map>> +GetLiteralStringHuffmanCodecs() { + std::map>> codecs; + { + std::unique_ptr> codec(new HuffmanCodec(7, { + {"", 0, 0}, + {"MainPs", 0, 0}, + {"MainVs", 0, 0}, + {"kMarkvNoneOfTheAbove", 0, 0}, + {"main", 0, 0}, + {"", 2, 3}, + {"", 1, 5}, + {"", 4, 6}, + })); + + codecs.emplace(SpvOpEntryPoint, std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(3, { + {"", 0, 0}, + {"GLSL.std.450", 0, 0}, + {"kMarkvNoneOfTheAbove", 0, 0}, + {"", 1, 2}, + })); + + codecs.emplace(SpvOpExtInstImport, std::move(codec)); + } + + return codecs; +} + +std::map, std::unique_ptr>> +GetNonIdWordHuffmanCodecs() { + std::map, std::unique_ptr>> codecs; + { + std::unique_ptr> codec(new HuffmanCodec(23, { + {0, 0, 0}, + {4, 0, 0}, + {8, 0, 0}, + {26, 0, 0}, + {31, 0, 0}, + {40, 0, 0}, + {43, 0, 0}, + {46, 0, 0}, + {49, 0, 0}, + {68, 0, 0}, + {69, 0, 0}, + {71, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 11, 8}, + {0, 1, 9}, + {0, 13, 4}, + {0, 14, 2}, + {0, 15, 12}, + {0, 16, 3}, + {0, 18, 17}, + {0, 7, 10}, + {0, 5, 6}, + {0, 20, 19}, + {0, 22, 21}, + })); + + codecs.emplace(std::pair(SpvOpExtInst, 3), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(3, { + {0, 0, 0}, + {0, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 1, 2}, + })); + + codecs.emplace(std::pair(SpvOpMemoryModel, 0), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(3, { + {0, 0, 0}, + {1, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 1, 2}, + })); + + codecs.emplace(std::pair(SpvOpMemoryModel, 1), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(5, { + {0, 0, 0}, + {0, 0, 0}, + {4, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 1, 3}, + {0, 2, 4}, + })); + + codecs.emplace(std::pair(SpvOpEntryPoint, 0), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(3, { + {0, 0, 0}, + {7, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 1, 2}, + })); + + codecs.emplace(std::pair(SpvOpExecutionMode, 1), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(11, { + {0, 0, 0}, + {1, 0, 0}, + {2, 0, 0}, + {3, 0, 0}, + {4, 0, 0}, + {18, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 4, 2}, + {0, 6, 5}, + {0, 7, 1}, + {0, 3, 8}, + {0, 10, 9}, + })); + + codecs.emplace(std::pair(SpvOpExecutionMode, 2), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(5, { + {0, 0, 0}, + {1, 0, 0}, + {32, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 2, 3}, + {0, 1, 4}, + })); + + codecs.emplace(std::pair(SpvOpCapability, 0), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(3, { + {0, 0, 0}, + {32, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 1, 2}, + })); + + codecs.emplace(std::pair(SpvOpTypeInt, 1), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(5, { + {0, 0, 0}, + {0, 0, 0}, + {1, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 2, 3}, + {0, 1, 4}, + })); + + codecs.emplace(std::pair(SpvOpTypeInt, 2), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(3, { + {0, 0, 0}, + {32, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 1, 2}, + })); + + codecs.emplace(std::pair(SpvOpTypeFloat, 1), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(7, { + {0, 0, 0}, + {2, 0, 0}, + {3, 0, 0}, + {4, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 2, 4}, + {0, 1, 5}, + {0, 6, 3}, + })); + + codecs.emplace(std::pair(SpvOpTypeVector, 2), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(7, { + {0, 0, 0}, + {2, 0, 0}, + {3, 0, 0}, + {4, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 1, 4}, + {0, 2, 5}, + {0, 3, 6}, + })); + + codecs.emplace(std::pair(SpvOpTypeMatrix, 2), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(7, { + {0, 0, 0}, + {1, 0, 0}, + {2, 0, 0}, + {3, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 3, 4}, + {0, 2, 5}, + {0, 1, 6}, + })); + + codecs.emplace(std::pair(SpvOpTypeImage, 2), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(5, { + {0, 0, 0}, + {0, 0, 0}, + {1, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 2, 3}, + {0, 1, 4}, + })); + + codecs.emplace(std::pair(SpvOpTypeImage, 3), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(3, { + {0, 0, 0}, + {0, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 1, 2}, + })); + + codecs.emplace(std::pair(SpvOpTypeImage, 4), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(3, { + {0, 0, 0}, + {0, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 1, 2}, + })); + + codecs.emplace(std::pair(SpvOpTypeImage, 5), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(3, { + {0, 0, 0}, + {1, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 1, 2}, + })); + + codecs.emplace(std::pair(SpvOpTypeImage, 6), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(3, { + {0, 0, 0}, + {0, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 1, 2}, + })); + + codecs.emplace(std::pair(SpvOpTypeImage, 7), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(13, { + {0, 0, 0}, + {0, 0, 0}, + {1, 0, 0}, + {2, 0, 0}, + {3, 0, 0}, + {6, 0, 0}, + {7, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 5, 7}, + {0, 6, 8}, + {0, 1, 4}, + {0, 2, 9}, + {0, 10, 3}, + {0, 12, 11}, + })); + + codecs.emplace(std::pair(SpvOpTypePointer, 1), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(35, { + {0, 0, 0}, + {0, 0, 0}, + {1, 0, 0}, + {2, 0, 0}, + {3, 0, 0}, + {4, 0, 0}, + {5, 0, 0}, + {6, 0, 0}, + {7, 0, 0}, + {8, 0, 0}, + {10, 0, 0}, + {981668463, 0, 0}, + {1055437881, 0, 0}, + {1056964608, 0, 0}, + {1065353216, 0, 0}, + {1073741824, 0, 0}, + {3212836864, 0, 0}, + {3332128768, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 10, 11}, + {0, 9, 17}, + {0, 7, 8}, + {0, 6, 16}, + {0, 5, 12}, + {0, 20, 19}, + {0, 21, 15}, + {0, 22, 13}, + {0, 4, 14}, + {0, 2, 23}, + {0, 3, 24}, + {0, 26, 25}, + {0, 1, 27}, + {0, 29, 28}, + {0, 31, 30}, + {0, 33, 32}, + {0, 18, 34}, + })); + + codecs.emplace(std::pair(SpvOpConstant, 2), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(3, { + {0, 0, 0}, + {0, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 1, 2}, + })); + + codecs.emplace(std::pair(SpvOpFunction, 2), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(13, { + {0, 0, 0}, + {0, 0, 0}, + {1, 0, 0}, + {2, 0, 0}, + {3, 0, 0}, + {6, 0, 0}, + {7, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 3, 7}, + {0, 4, 8}, + {0, 9, 2}, + {0, 1, 5}, + {0, 10, 6}, + {0, 12, 11}, + })); + + codecs.emplace(std::pair(SpvOpVariable, 2), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(15, { + {0, 0, 0}, + {0, 0, 0}, + {2, 0, 0}, + {6, 0, 0}, + {11, 0, 0}, + {30, 0, 0}, + {33, 0, 0}, + {34, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 4, 8}, + {0, 9, 1}, + {0, 3, 10}, + {0, 6, 11}, + {0, 12, 2}, + {0, 7, 5}, + {0, 14, 13}, + })); + + codecs.emplace(std::pair(SpvOpDecorate, 1), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(25, { + {0, 0, 0}, + {0, 0, 0}, + {1, 0, 0}, + {2, 0, 0}, + {3, 0, 0}, + {4, 0, 0}, + {5, 0, 0}, + {6, 0, 0}, + {7, 0, 0}, + {8, 0, 0}, + {15, 0, 0}, + {16, 0, 0}, + {64, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 10, 9}, + {0, 14, 8}, + {0, 7, 12}, + {0, 5, 6}, + {0, 15, 11}, + {0, 13, 4}, + {0, 16, 3}, + {0, 18, 17}, + {0, 2, 19}, + {0, 21, 20}, + {0, 23, 22}, + {0, 1, 24}, + })); + + codecs.emplace(std::pair(SpvOpDecorate, 2), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(73, { + {0, 0, 0}, + {0, 0, 0}, + {1, 0, 0}, + {2, 0, 0}, + {3, 0, 0}, + {4, 0, 0}, + {5, 0, 0}, + {6, 0, 0}, + {7, 0, 0}, + {8, 0, 0}, + {9, 0, 0}, + {10, 0, 0}, + {11, 0, 0}, + {12, 0, 0}, + {13, 0, 0}, + {14, 0, 0}, + {15, 0, 0}, + {16, 0, 0}, + {17, 0, 0}, + {18, 0, 0}, + {19, 0, 0}, + {20, 0, 0}, + {21, 0, 0}, + {22, 0, 0}, + {23, 0, 0}, + {24, 0, 0}, + {25, 0, 0}, + {26, 0, 0}, + {27, 0, 0}, + {28, 0, 0}, + {29, 0, 0}, + {30, 0, 0}, + {31, 0, 0}, + {32, 0, 0}, + {33, 0, 0}, + {34, 0, 0}, + {37, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 34, 35}, + {0, 32, 33}, + {0, 30, 31}, + {0, 27, 29}, + {0, 26, 28}, + {0, 23, 25}, + {0, 36, 22}, + {0, 39, 38}, + {0, 41, 40}, + {0, 21, 42}, + {0, 19, 20}, + {0, 17, 18}, + {0, 14, 15}, + {0, 12, 10}, + {0, 16, 13}, + {0, 9, 11}, + {0, 7, 8}, + {0, 6, 5}, + {0, 24, 37}, + {0, 44, 43}, + {0, 3, 4}, + {0, 45, 2}, + {0, 1, 46}, + {0, 48, 47}, + {0, 50, 49}, + {0, 52, 51}, + {0, 54, 53}, + {0, 56, 55}, + {0, 58, 57}, + {0, 60, 59}, + {0, 62, 61}, + {0, 64, 63}, + {0, 66, 65}, + {0, 68, 67}, + {0, 70, 69}, + {0, 72, 71}, + })); + + codecs.emplace(std::pair(SpvOpMemberDecorate, 1), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(7, { + {0, 0, 0}, + {4, 0, 0}, + {7, 0, 0}, + {35, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 1, 4}, + {0, 5, 2}, + {0, 3, 6}, + })); + + codecs.emplace(std::pair(SpvOpMemberDecorate, 2), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(59, { + {0, 0, 0}, + {0, 0, 0}, + {16, 0, 0}, + {28, 0, 0}, + {32, 0, 0}, + {40, 0, 0}, + {44, 0, 0}, + {48, 0, 0}, + {60, 0, 0}, + {64, 0, 0}, + {76, 0, 0}, + {80, 0, 0}, + {92, 0, 0}, + {96, 0, 0}, + {108, 0, 0}, + {112, 0, 0}, + {120, 0, 0}, + {128, 0, 0}, + {140, 0, 0}, + {144, 0, 0}, + {148, 0, 0}, + {152, 0, 0}, + {156, 0, 0}, + {160, 0, 0}, + {176, 0, 0}, + {192, 0, 0}, + {204, 0, 0}, + {208, 0, 0}, + {224, 0, 0}, + {256, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 16, 14}, + {0, 12, 20}, + {0, 6, 26}, + {0, 3, 5}, + {0, 27, 21}, + {0, 8, 28}, + {0, 10, 22}, + {0, 29, 18}, + {0, 32, 31}, + {0, 19, 24}, + {0, 15, 23}, + {0, 13, 11}, + {0, 4, 7}, + {0, 34, 33}, + {0, 36, 35}, + {0, 17, 25}, + {0, 37, 9}, + {0, 39, 38}, + {0, 40, 1}, + {0, 42, 41}, + {0, 44, 43}, + {0, 46, 45}, + {0, 2, 47}, + {0, 49, 48}, + {0, 51, 50}, + {0, 53, 52}, + {0, 55, 54}, + {0, 30, 56}, + {0, 58, 57}, + })); + + codecs.emplace(std::pair(SpvOpMemberDecorate, 3), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(11, { + {0, 0, 0}, + {0, 0, 0}, + {1, 0, 0}, + {2, 0, 0}, + {3, 0, 0}, + {4, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 2, 6}, + {0, 4, 7}, + {0, 8, 3}, + {0, 9, 5}, + {0, 1, 10}, + })); + + codecs.emplace(std::pair(SpvOpVectorShuffle, 4), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(13, { + {0, 0, 0}, + {0, 0, 0}, + {1, 0, 0}, + {2, 0, 0}, + {3, 0, 0}, + {4, 0, 0}, + {5, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 3, 7}, + {0, 8, 5}, + {0, 9, 1}, + {0, 4, 10}, + {0, 11, 6}, + {0, 2, 12}, + })); + + codecs.emplace(std::pair(SpvOpVectorShuffle, 5), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(15, { + {0, 0, 0}, + {0, 0, 0}, + {1, 0, 0}, + {2, 0, 0}, + {3, 0, 0}, + {4, 0, 0}, + {5, 0, 0}, + {6, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 6, 8}, + {0, 5, 2}, + {0, 10, 9}, + {0, 1, 4}, + {0, 12, 11}, + {0, 7, 13}, + {0, 3, 14}, + })); + + codecs.emplace(std::pair(SpvOpVectorShuffle, 6), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(13, { + {0, 0, 0}, + {0, 0, 0}, + {1, 0, 0}, + {2, 0, 0}, + {3, 0, 0}, + {5, 0, 0}, + {6, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 7, 6}, + {0, 8, 3}, + {0, 9, 2}, + {0, 5, 1}, + {0, 11, 10}, + {0, 4, 12}, + })); + + codecs.emplace(std::pair(SpvOpVectorShuffle, 7), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(27, { + {0, 0, 0}, + {0, 0, 0}, + {1, 0, 0}, + {2, 0, 0}, + {3, 0, 0}, + {4, 0, 0}, + {5, 0, 0}, + {8, 0, 0}, + {9, 0, 0}, + {10, 0, 0}, + {12, 0, 0}, + {16, 0, 0}, + {23, 0, 0}, + {24, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 11, 9}, + {0, 13, 10}, + {0, 7, 8}, + {0, 15, 5}, + {0, 17, 16}, + {0, 12, 6}, + {0, 19, 18}, + {0, 21, 20}, + {0, 14, 4}, + {0, 3, 22}, + {0, 23, 2}, + {0, 24, 1}, + {0, 26, 25}, + })); + + codecs.emplace(std::pair(SpvOpCompositeExtract, 3), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(9, { + {0, 0, 0}, + {0, 0, 0}, + {1, 0, 0}, + {2, 0, 0}, + {3, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 3, 2}, + {0, 5, 4}, + {0, 6, 1}, + {0, 8, 7}, + })); + + codecs.emplace(std::pair(SpvOpCompositeExtract, 4), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(9, { + {0, 0, 0}, + {0, 0, 0}, + {1, 0, 0}, + {2, 0, 0}, + {3, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 1, 5}, + {0, 3, 2}, + {0, 6, 4}, + {0, 8, 7}, + })); + + codecs.emplace(std::pair(SpvOpCompositeExtract, 5), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(21, { + {0, 0, 0}, + {0, 0, 0}, + {1, 0, 0}, + {2, 0, 0}, + {3, 0, 0}, + {4, 0, 0}, + {5, 0, 0}, + {6, 0, 0}, + {7, 0, 0}, + {8, 0, 0}, + {9, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 10, 11}, + {0, 9, 12}, + {0, 7, 5}, + {0, 8, 6}, + {0, 4, 13}, + {0, 15, 14}, + {0, 16, 3}, + {0, 17, 2}, + {0, 18, 1}, + {0, 20, 19}, + })); + + codecs.emplace(std::pair(SpvOpCompositeInsert, 4), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(9, { + {0, 0, 0}, + {0, 0, 0}, + {1, 0, 0}, + {2, 0, 0}, + {3, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 3, 5}, + {0, 2, 6}, + {0, 7, 1}, + {0, 4, 8}, + })); + + codecs.emplace(std::pair(SpvOpCompositeInsert, 5), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(3, { + {0, 0, 0}, + {1, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 1, 2}, + })); + + codecs.emplace(std::pair(SpvOpImageSampleImplicitLod, 4), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(5, { + {0, 0, 0}, + {2, 0, 0}, + {10, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 2, 3}, + {0, 1, 4}, + })); + + codecs.emplace(std::pair(SpvOpImageSampleExplicitLod, 4), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(3, { + {0, 0, 0}, + {2, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 1, 2}, + })); + + codecs.emplace(std::pair(SpvOpImageSampleDrefExplicitLod, 5), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(3, { + {0, 0, 0}, + {0, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 1, 2}, + })); + + codecs.emplace(std::pair(SpvOpSelectionMerge, 1), std::move(codec)); + } + + return codecs; +} + +std::map, std::unique_ptr>> +GetIdDescriptorHuffmanCodecs() { + std::map, std::unique_ptr>> codecs; + { + std::unique_ptr> codec(new HuffmanCodec(9, { + {0, 0, 0}, + {679771963, 0, 0}, + {1951208733, 0, 0}, + {2320303498, 0, 0}, + {3334207724, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 3, 5}, + {0, 4, 6}, + {0, 1, 7}, + {0, 2, 8}, + })); + + codecs.emplace(std::pair(SpvOpExtInst, 0), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(3, { + {0, 0, 0}, + {2161102232, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 2, 1}, + })); + + codecs.emplace(std::pair(SpvOpExtInst, 1), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(3, { + {0, 0, 0}, + {4228502127, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 1, 2}, + })); + + codecs.emplace(std::pair(SpvOpExtInst, 2), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(19, { + {0, 0, 0}, + {139011596, 0, 0}, + {810488476, 0, 0}, + {870594305, 0, 0}, + {1742737136, 0, 0}, + {2096388952, 0, 0}, + {2855506940, 0, 0}, + {3044188332, 0, 0}, + {3487022798, 0, 0}, + {3701632935, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 3, 9}, + {0, 2, 8}, + {0, 4, 7}, + {0, 11, 5}, + {0, 13, 12}, + {0, 14, 1}, + {0, 6, 15}, + {0, 17, 16}, + {0, 10, 18}, + })); + + codecs.emplace(std::pair(SpvOpExtInst, 4), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(15, { + {0, 0, 0}, + {139011596, 0, 0}, + {296981500, 0, 0}, + {1367301635, 0, 0}, + {2855506940, 0, 0}, + {3233393284, 0, 0}, + {3251128023, 0, 0}, + {3582002820, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 5, 7}, + {0, 1, 3}, + {0, 2, 9}, + {0, 6, 10}, + {0, 12, 11}, + {0, 4, 13}, + {0, 8, 14}, + })); + + codecs.emplace(std::pair(SpvOpExtInst, 5), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(11, { + {0, 0, 0}, + {296981500, 0, 0}, + {508217552, 0, 0}, + {2683080096, 0, 0}, + {3547456240, 0, 0}, + {3753486980, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 3, 4}, + {0, 5, 2}, + {0, 8, 7}, + {0, 1, 9}, + {0, 6, 10}, + })); + + codecs.emplace(std::pair(SpvOpExtInst, 6), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(65, { + {0, 0, 0}, + {135486769, 0, 0}, + {440421571, 0, 0}, + {450406196, 0, 0}, + {503094540, 0, 0}, + {543621065, 0, 0}, + {827698488, 0, 0}, + {907126242, 0, 0}, + {908777857, 0, 0}, + {910429472, 0, 0}, + {1294403159, 0, 0}, + {1296054774, 0, 0}, + {1297706389, 0, 0}, + {1322549027, 0, 0}, + {1784441183, 0, 0}, + {2080953106, 0, 0}, + {2194691858, 0, 0}, + {2448331885, 0, 0}, + {2468230023, 0, 0}, + {2547657777, 0, 0}, + {2549309392, 0, 0}, + {2550961007, 0, 0}, + {2934934694, 0, 0}, + {2936586309, 0, 0}, + {2938237924, 0, 0}, + {3094180193, 0, 0}, + {3094857332, 0, 0}, + {3095831808, 0, 0}, + {3183924418, 0, 0}, + {3561562003, 0, 0}, + {3563213618, 0, 0}, + {3564865233, 0, 0}, + {4028622909, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 23, 3}, + {0, 18, 24}, + {0, 14, 22}, + {0, 17, 9}, + {0, 1, 26}, + {0, 4, 15}, + {0, 31, 25}, + {0, 8, 7}, + {0, 34, 2}, + {0, 12, 30}, + {0, 36, 35}, + {0, 13, 11}, + {0, 6, 10}, + {0, 5, 37}, + {0, 38, 27}, + {0, 40, 39}, + {0, 42, 41}, + {0, 16, 28}, + {0, 44, 43}, + {0, 21, 45}, + {0, 20, 46}, + {0, 47, 32}, + {0, 48, 19}, + {0, 29, 49}, + {0, 51, 50}, + {0, 53, 52}, + {0, 55, 54}, + {0, 57, 56}, + {0, 58, 33}, + {0, 60, 59}, + {0, 62, 61}, + {0, 64, 63}, + })); + + codecs.emplace(std::pair(SpvOpTypePointer, 0), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(35, { + {0, 0, 0}, + {119981689, 0, 0}, + {162255877, 0, 0}, + {679771963, 0, 0}, + {1154919607, 0, 0}, + {1343794461, 0, 0}, + {1674803691, 0, 0}, + {1951208733, 0, 0}, + {2263349224, 0, 0}, + {2320303498, 0, 0}, + {2924146124, 0, 0}, + {2984325996, 0, 0}, + {3334207724, 0, 0}, + {3410158390, 0, 0}, + {3489360962, 0, 0}, + {3866587616, 0, 0}, + {3868239231, 0, 0}, + {3869890846, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 14, 15}, + {0, 6, 1}, + {0, 8, 13}, + {0, 19, 5}, + {0, 20, 16}, + {0, 11, 2}, + {0, 22, 21}, + {0, 17, 10}, + {0, 4, 23}, + {0, 25, 24}, + {0, 7, 26}, + {0, 9, 27}, + {0, 28, 3}, + {0, 29, 18}, + {0, 30, 12}, + {0, 32, 31}, + {0, 34, 33}, + })); + + codecs.emplace(std::pair(SpvOpTypePointer, 2), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(7, { + {0, 0, 0}, + {789872778, 0, 0}, + {1951208733, 0, 0}, + {2430404313, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 3, 4}, + {0, 1, 5}, + {0, 2, 6}, + })); + + codecs.emplace(std::pair(SpvOpConstant, 0), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(45, { + {0, 0, 0}, + {142465290, 0, 0}, + {144116905, 0, 0}, + {210116709, 0, 0}, + {296981500, 0, 0}, + {529742207, 0, 0}, + {959681532, 0, 0}, + {1156369516, 0, 0}, + {1158021131, 0, 0}, + {1543646433, 0, 0}, + {1782996825, 0, 0}, + {1784648440, 0, 0}, + {2170273742, 0, 0}, + {2321729979, 0, 0}, + {2444465148, 0, 0}, + {2524697596, 0, 0}, + {2557550659, 0, 0}, + {2796901051, 0, 0}, + {2798552666, 0, 0}, + {2855506940, 0, 0}, + {3184177968, 0, 0}, + {3810805277, 0, 0}, + {3929248764, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 16, 13}, + {0, 9, 15}, + {0, 5, 20}, + {0, 14, 8}, + {0, 12, 11}, + {0, 2, 3}, + {0, 24, 21}, + {0, 1, 7}, + {0, 17, 10}, + {0, 22, 25}, + {0, 27, 26}, + {0, 18, 6}, + {0, 19, 28}, + {0, 29, 4}, + {0, 31, 30}, + {0, 33, 32}, + {0, 35, 34}, + {0, 37, 36}, + {0, 39, 38}, + {0, 41, 40}, + {0, 43, 42}, + {0, 23, 44}, + })); + + codecs.emplace(std::pair(SpvOpConstant, 1), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(9, { + {0, 0, 0}, + {679771963, 0, 0}, + {1247793383, 0, 0}, + {2320303498, 0, 0}, + {3334207724, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 2, 5}, + {0, 4, 6}, + {0, 1, 3}, + {0, 8, 7}, + })); + + codecs.emplace(std::pair(SpvOpConstantComposite, 0), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(59, { + {0, 0, 0}, + {15502752, 0, 0}, + {139011596, 0, 0}, + {249378857, 0, 0}, + {251209228, 0, 0}, + {503145996, 0, 0}, + {1325348861, 0, 0}, + {1558001705, 0, 0}, + {1646147798, 0, 0}, + {1679946323, 0, 0}, + {1766401548, 0, 0}, + {1992893964, 0, 0}, + {2123388694, 0, 0}, + {2162986400, 0, 0}, + {2580096524, 0, 0}, + {2598189097, 0, 0}, + {2683080096, 0, 0}, + {2698156268, 0, 0}, + {3133016299, 0, 0}, + {3251128023, 0, 0}, + {3504158761, 0, 0}, + {3538592682, 0, 0}, + {3540244297, 0, 0}, + {3541895912, 0, 0}, + {3570219049, 0, 0}, + {3653838348, 0, 0}, + {3764205609, 0, 0}, + {3882634684, 0, 0}, + {3913885196, 0, 0}, + {4243119782, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 7, 4}, + {0, 24, 15}, + {0, 11, 13}, + {0, 5, 14}, + {0, 6, 3}, + {0, 9, 8}, + {0, 17, 12}, + {0, 27, 18}, + {0, 1, 29}, + {0, 21, 31}, + {0, 23, 22}, + {0, 33, 32}, + {0, 10, 34}, + {0, 25, 28}, + {0, 36, 35}, + {0, 38, 37}, + {0, 16, 39}, + {0, 40, 26}, + {0, 41, 19}, + {0, 20, 42}, + {0, 2, 43}, + {0, 45, 44}, + {0, 47, 46}, + {0, 49, 48}, + {0, 50, 30}, + {0, 52, 51}, + {0, 54, 53}, + {0, 56, 55}, + {0, 58, 57}, + })); + + codecs.emplace(std::pair(SpvOpConstantComposite, 1), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(41, { + {0, 0, 0}, + {142465290, 0, 0}, + {158160339, 0, 0}, + {169135842, 0, 0}, + {210116709, 0, 0}, + {296981500, 0, 0}, + {910398460, 0, 0}, + {959681532, 0, 0}, + {1039111164, 0, 0}, + {1087394637, 0, 0}, + {1156369516, 0, 0}, + {2444465148, 0, 0}, + {2732195517, 0, 0}, + {2796901051, 0, 0}, + {2855506940, 0, 0}, + {3202349435, 0, 0}, + {3362723943, 0, 0}, + {3712763835, 0, 0}, + {3929248764, 0, 0}, + {4016096296, 0, 0}, + {4248015868, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 20, 6}, + {0, 7, 8}, + {0, 3, 2}, + {0, 12, 9}, + {0, 16, 15}, + {0, 19, 17}, + {0, 10, 22}, + {0, 1, 13}, + {0, 23, 11}, + {0, 25, 24}, + {0, 27, 26}, + {0, 28, 18}, + {0, 29, 4}, + {0, 31, 30}, + {0, 33, 32}, + {0, 21, 34}, + {0, 35, 5}, + {0, 37, 36}, + {0, 38, 14}, + {0, 40, 39}, + })); + + codecs.emplace(std::pair(SpvOpConstantComposite, 2), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(39, { + {0, 0, 0}, + {52882140, 0, 0}, + {210116709, 0, 0}, + {296981500, 0, 0}, + {385229009, 0, 0}, + {910398460, 0, 0}, + {959681532, 0, 0}, + {1031290113, 0, 0}, + {1039111164, 0, 0}, + {1172110445, 0, 0}, + {1622381564, 0, 0}, + {1782996825, 0, 0}, + {1971252067, 0, 0}, + {2444465148, 0, 0}, + {2490492987, 0, 0}, + {2678954464, 0, 0}, + {2855506940, 0, 0}, + {3912967080, 0, 0}, + {3929248764, 0, 0}, + {4248015868, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 5, 10}, + {0, 8, 19}, + {0, 6, 21}, + {0, 4, 1}, + {0, 9, 7}, + {0, 14, 12}, + {0, 17, 15}, + {0, 13, 22}, + {0, 24, 23}, + {0, 26, 25}, + {0, 18, 27}, + {0, 28, 2}, + {0, 29, 20}, + {0, 31, 30}, + {0, 32, 11}, + {0, 33, 3}, + {0, 35, 34}, + {0, 36, 16}, + {0, 38, 37}, + })); + + codecs.emplace(std::pair(SpvOpConstantComposite, 3), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(35, { + {0, 0, 0}, + {210116709, 0, 0}, + {296981500, 0, 0}, + {615748604, 0, 0}, + {910398460, 0, 0}, + {959681532, 0, 0}, + {1039111164, 0, 0}, + {1543672828, 0, 0}, + {1612361408, 0, 0}, + {2100532220, 0, 0}, + {2326636627, 0, 0}, + {2444465148, 0, 0}, + {2524697596, 0, 0}, + {2763232252, 0, 0}, + {2855506940, 0, 0}, + {3929248764, 0, 0}, + {4172568578, 0, 0}, + {4248015868, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 7, 3}, + {0, 13, 9}, + {0, 10, 8}, + {0, 4, 16}, + {0, 19, 17}, + {0, 20, 6}, + {0, 21, 12}, + {0, 22, 18}, + {0, 23, 5}, + {0, 24, 15}, + {0, 26, 25}, + {0, 27, 11}, + {0, 1, 28}, + {0, 30, 29}, + {0, 14, 31}, + {0, 2, 32}, + {0, 34, 33}, + })); + + codecs.emplace(std::pair(SpvOpConstantComposite, 4), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(33, { + {0, 0, 0}, + {296981500, 0, 0}, + {615748604, 0, 0}, + {959681532, 0, 0}, + {1039111164, 0, 0}, + {1450415100, 0, 0}, + {1543672828, 0, 0}, + {1939359710, 0, 0}, + {2100532220, 0, 0}, + {2113115132, 0, 0}, + {2326636627, 0, 0}, + {2444465148, 0, 0}, + {2763232252, 0, 0}, + {2855506940, 0, 0}, + {3929248764, 0, 0}, + {4172568578, 0, 0}, + {4248015868, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 5, 17}, + {0, 11, 3}, + {0, 16, 2}, + {0, 8, 6}, + {0, 18, 12}, + {0, 10, 7}, + {0, 9, 15}, + {0, 19, 14}, + {0, 4, 20}, + {0, 22, 21}, + {0, 24, 23}, + {0, 26, 25}, + {0, 27, 1}, + {0, 29, 28}, + {0, 31, 30}, + {0, 32, 13}, + })); + + codecs.emplace(std::pair(SpvOpConstantComposite, 5), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(37, { + {0, 0, 0}, + {543621065, 0, 0}, + {827698488, 0, 0}, + {1294403159, 0, 0}, + {1296054774, 0, 0}, + {1297706389, 0, 0}, + {1322549027, 0, 0}, + {2194691858, 0, 0}, + {2468230023, 0, 0}, + {2547657777, 0, 0}, + {2549309392, 0, 0}, + {2550961007, 0, 0}, + {2934934694, 0, 0}, + {2936586309, 0, 0}, + {2938237924, 0, 0}, + {3095831808, 0, 0}, + {3183924418, 0, 0}, + {3561562003, 0, 0}, + {4028622909, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 16, 6}, + {0, 18, 10}, + {0, 13, 14}, + {0, 11, 20}, + {0, 21, 5}, + {0, 22, 2}, + {0, 3, 23}, + {0, 7, 15}, + {0, 1, 24}, + {0, 8, 17}, + {0, 9, 12}, + {0, 4, 25}, + {0, 19, 26}, + {0, 28, 27}, + {0, 30, 29}, + {0, 32, 31}, + {0, 34, 33}, + {0, 36, 35}, + })); + + codecs.emplace(std::pair(SpvOpVariable, 0), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(37, { + {0, 0, 0}, + {37459569, 0, 0}, + {137840602, 0, 0}, + {565334834, 0, 0}, + {625975427, 0, 0}, + {630964591, 0, 0}, + {680016782, 0, 0}, + {1009983433, 0, 0}, + {1572088444, 0, 0}, + {1584774136, 0, 0}, + {1918481917, 0, 0}, + {2790624748, 0, 0}, + {3181646225, 0, 0}, + {3560665067, 0, 0}, + {3662767579, 0, 0}, + {4053789056, 0, 0}, + {4064212479, 0, 0}, + {4192247221, 0, 0}, + {4224872590, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 4, 3}, + {0, 6, 15}, + {0, 2, 7}, + {0, 5, 20}, + {0, 21, 14}, + {0, 22, 18}, + {0, 10, 23}, + {0, 1, 16}, + {0, 9, 24}, + {0, 8, 17}, + {0, 12, 13}, + {0, 11, 25}, + {0, 19, 26}, + {0, 28, 27}, + {0, 30, 29}, + {0, 32, 31}, + {0, 34, 33}, + {0, 36, 35}, + })); + + codecs.emplace(std::pair(SpvOpVariable, 1), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(15, { + {0, 0, 0}, + {162255877, 0, 0}, + {679771963, 0, 0}, + {1951208733, 0, 0}, + {2320303498, 0, 0}, + {2984325996, 0, 0}, + {3334207724, 0, 0}, + {3869890846, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 7, 5}, + {0, 8, 1}, + {0, 9, 4}, + {0, 2, 10}, + {0, 6, 11}, + {0, 3, 12}, + {0, 14, 13}, + })); + + codecs.emplace(std::pair(SpvOpLoad, 0), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(37, { + {0, 0, 0}, + {543558236, 0, 0}, + {810488476, 0, 0}, + {870594305, 0, 0}, + {883854656, 0, 0}, + {1570165302, 0, 0}, + {1684282922, 0, 0}, + {1901166356, 0, 0}, + {1949759310, 0, 0}, + {2087004702, 0, 0}, + {2096388952, 0, 0}, + {2517964682, 0, 0}, + {2622612602, 0, 0}, + {2970183398, 0, 0}, + {3091876332, 0, 0}, + {3187066832, 0, 0}, + {3496407048, 0, 0}, + {3570411982, 0, 0}, + {3692647551, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 14, 18}, + {0, 3, 7}, + {0, 5, 9}, + {0, 6, 13}, + {0, 21, 20}, + {0, 2, 11}, + {0, 15, 22}, + {0, 16, 23}, + {0, 4, 1}, + {0, 12, 24}, + {0, 17, 8}, + {0, 26, 25}, + {0, 27, 10}, + {0, 29, 28}, + {0, 31, 30}, + {0, 33, 32}, + {0, 35, 34}, + {0, 36, 19}, + })); + + codecs.emplace(std::pair(SpvOpLoad, 1), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(37, { + {0, 0, 0}, + {37459569, 0, 0}, + {137840602, 0, 0}, + {522971108, 0, 0}, + {630964591, 0, 0}, + {1572088444, 0, 0}, + {1584774136, 0, 0}, + {1918481917, 0, 0}, + {1957218950, 0, 0}, + {2313593054, 0, 0}, + {2790624748, 0, 0}, + {2838165089, 0, 0}, + {3181646225, 0, 0}, + {3364388739, 0, 0}, + {3560665067, 0, 0}, + {3662767579, 0, 0}, + {4064212479, 0, 0}, + {4224872590, 0, 0}, + {4239834800, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 9, 11}, + {0, 13, 8}, + {0, 15, 18}, + {0, 5, 2}, + {0, 21, 20}, + {0, 17, 4}, + {0, 3, 22}, + {0, 14, 23}, + {0, 1, 16}, + {0, 7, 24}, + {0, 12, 6}, + {0, 26, 25}, + {0, 27, 10}, + {0, 29, 28}, + {0, 31, 30}, + {0, 33, 32}, + {0, 35, 34}, + {0, 36, 19}, + })); + + codecs.emplace(std::pair(SpvOpLoad, 2), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(19, { + {0, 0, 0}, + {137840602, 0, 0}, + {1009983433, 0, 0}, + {1572088444, 0, 0}, + {1918481917, 0, 0}, + {2790624748, 0, 0}, + {3560665067, 0, 0}, + {3662767579, 0, 0}, + {4192247221, 0, 0}, + {4224872590, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 1, 2}, + {0, 11, 7}, + {0, 8, 9}, + {0, 4, 3}, + {0, 12, 6}, + {0, 5, 13}, + {0, 15, 14}, + {0, 16, 10}, + {0, 18, 17}, + })); + + codecs.emplace(std::pair(SpvOpStore, 0), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(25, { + {0, 0, 0}, + {177111659, 0, 0}, + {296981500, 0, 0}, + {408465899, 0, 0}, + {2055836767, 0, 0}, + {2087004702, 0, 0}, + {2096388952, 0, 0}, + {2622612602, 0, 0}, + {2855506940, 0, 0}, + {2959147533, 0, 0}, + {3187066832, 0, 0}, + {3570411982, 0, 0}, + {3831290364, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 2, 1}, + {0, 12, 11}, + {0, 9, 3}, + {0, 7, 4}, + {0, 14, 8}, + {0, 10, 6}, + {0, 5, 15}, + {0, 17, 16}, + {0, 19, 18}, + {0, 21, 20}, + {0, 23, 22}, + {0, 13, 24}, + })); + + codecs.emplace(std::pair(SpvOpStore, 1), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(25, { + {0, 0, 0}, + {440421571, 0, 0}, + {827698488, 0, 0}, + {907126242, 0, 0}, + {908777857, 0, 0}, + {910429472, 0, 0}, + {1294403159, 0, 0}, + {1296054774, 0, 0}, + {1297706389, 0, 0}, + {2080953106, 0, 0}, + {2468230023, 0, 0}, + {2547657777, 0, 0}, + {3561562003, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 7, 5}, + {0, 12, 11}, + {0, 9, 8}, + {0, 13, 14}, + {0, 15, 4}, + {0, 17, 16}, + {0, 18, 3}, + {0, 19, 10}, + {0, 6, 1}, + {0, 21, 20}, + {0, 22, 2}, + {0, 24, 23}, + })); + + codecs.emplace(std::pair(SpvOpAccessChain, 0), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(29, { + {0, 0, 0}, + {1079999262, 0, 0}, + {2311941439, 0, 0}, + {2313593054, 0, 0}, + {2838165089, 0, 0}, + {2839816704, 0, 0}, + {2841468319, 0, 0}, + {3364388739, 0, 0}, + {3366040354, 0, 0}, + {3367691969, 0, 0}, + {3369343584, 0, 0}, + {4239834800, 0, 0}, + {4241486415, 0, 0}, + {4243138030, 0, 0}, + {4244789645, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 9, 10}, + {0, 14, 12}, + {0, 6, 13}, + {0, 8, 1}, + {0, 2, 5}, + {0, 3, 4}, + {0, 17, 16}, + {0, 11, 18}, + {0, 7, 19}, + {0, 21, 20}, + {0, 23, 22}, + {0, 25, 24}, + {0, 27, 26}, + {0, 15, 28}, + })); + + codecs.emplace(std::pair(SpvOpAccessChain, 1), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(49, { + {0, 0, 0}, + {112745085, 0, 0}, + {116376005, 0, 0}, + {400248103, 0, 0}, + {406044930, 0, 0}, + {522971108, 0, 0}, + {625975427, 0, 0}, + {680016782, 0, 0}, + {1009983433, 0, 0}, + {1062250709, 0, 0}, + {1410849099, 0, 0}, + {1918481917, 0, 0}, + {2190437442, 0, 0}, + {2790624748, 0, 0}, + {2879917723, 0, 0}, + {2882994691, 0, 0}, + {3181646225, 0, 0}, + {3263901372, 0, 0}, + {3390051757, 0, 0}, + {3560665067, 0, 0}, + {3662767579, 0, 0}, + {3717523241, 0, 0}, + {3945795573, 0, 0}, + {4101009465, 0, 0}, + {4290024976, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 1, 23}, + {0, 8, 22}, + {0, 3, 21}, + {0, 9, 5}, + {0, 2, 10}, + {0, 26, 17}, + {0, 27, 14}, + {0, 16, 4}, + {0, 29, 28}, + {0, 12, 30}, + {0, 15, 31}, + {0, 32, 18}, + {0, 6, 7}, + {0, 20, 33}, + {0, 24, 34}, + {0, 35, 13}, + {0, 19, 36}, + {0, 11, 37}, + {0, 39, 38}, + {0, 41, 40}, + {0, 43, 42}, + {0, 44, 25}, + {0, 46, 45}, + {0, 48, 47}, + })); + + codecs.emplace(std::pair(SpvOpAccessChain, 2), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(35, { + {0, 0, 0}, + {142465290, 0, 0}, + {144116905, 0, 0}, + {529742207, 0, 0}, + {1156369516, 0, 0}, + {1158021131, 0, 0}, + {1543646433, 0, 0}, + {1782996825, 0, 0}, + {1784648440, 0, 0}, + {1930923350, 0, 0}, + {2170273742, 0, 0}, + {2557550659, 0, 0}, + {2705477184, 0, 0}, + {2796901051, 0, 0}, + {2798552666, 0, 0}, + {3184177968, 0, 0}, + {3810805277, 0, 0}, + {4198082194, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 11, 9}, + {0, 6, 17}, + {0, 3, 19}, + {0, 15, 12}, + {0, 20, 16}, + {0, 10, 13}, + {0, 21, 4}, + {0, 1, 22}, + {0, 14, 23}, + {0, 5, 24}, + {0, 26, 25}, + {0, 2, 8}, + {0, 27, 18}, + {0, 7, 28}, + {0, 30, 29}, + {0, 32, 31}, + {0, 34, 33}, + })); + + codecs.emplace(std::pair(SpvOpAccessChain, 3), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(41, { + {0, 0, 0}, + {142465290, 0, 0}, + {144116905, 0, 0}, + {198967948, 0, 0}, + {529742207, 0, 0}, + {825595257, 0, 0}, + {1156369516, 0, 0}, + {1158021131, 0, 0}, + {1452222566, 0, 0}, + {1782996825, 0, 0}, + {1784648440, 0, 0}, + {1839499483, 0, 0}, + {2170273742, 0, 0}, + {2466126792, 0, 0}, + {2796901051, 0, 0}, + {2798552666, 0, 0}, + {3184177968, 0, 0}, + {3480031018, 0, 0}, + {3810805277, 0, 0}, + {4106658327, 0, 0}, + {4198082194, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 3, 20}, + {0, 16, 13}, + {0, 11, 5}, + {0, 4, 17}, + {0, 19, 8}, + {0, 18, 12}, + {0, 23, 22}, + {0, 25, 24}, + {0, 27, 26}, + {0, 6, 28}, + {0, 14, 29}, + {0, 1, 30}, + {0, 15, 2}, + {0, 10, 31}, + {0, 9, 32}, + {0, 34, 33}, + {0, 35, 7}, + {0, 21, 36}, + {0, 38, 37}, + {0, 40, 39}, + })); + + codecs.emplace(std::pair(SpvOpAccessChain, 4), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(9, { + {0, 0, 0}, + {144116905, 0, 0}, + {1158021131, 0, 0}, + {1784648440, 0, 0}, + {2798552666, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 1, 5}, + {0, 4, 2}, + {0, 6, 3}, + {0, 8, 7}, + })); + + codecs.emplace(std::pair(SpvOpAccessChain, 5), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(5, { + {0, 0, 0}, + {142465290, 0, 0}, + {1782996825, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 2, 1}, + {0, 4, 3}, + })); + + codecs.emplace(std::pair(SpvOpAccessChain, 6), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(7, { + {0, 0, 0}, + {679771963, 0, 0}, + {2320303498, 0, 0}, + {3334207724, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 3, 4}, + {0, 2, 5}, + {0, 6, 1}, + })); + + codecs.emplace(std::pair(SpvOpVectorShuffle, 0), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(19, { + {0, 0, 0}, + {177111659, 0, 0}, + {837715723, 0, 0}, + {1203545131, 0, 0}, + {1352628475, 0, 0}, + {1367301635, 0, 0}, + {2055836767, 0, 0}, + {2204920111, 0, 0}, + {3619787319, 0, 0}, + {3701632935, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 1, 4}, + {0, 2, 7}, + {0, 11, 9}, + {0, 6, 12}, + {0, 8, 5}, + {0, 3, 13}, + {0, 15, 14}, + {0, 17, 16}, + {0, 10, 18}, + })); + + codecs.emplace(std::pair(SpvOpVectorShuffle, 1), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(17, { + {0, 0, 0}, + {488500848, 0, 0}, + {495107308, 0, 0}, + {2096388952, 0, 0}, + {2157103435, 0, 0}, + {2622612602, 0, 0}, + {3496407048, 0, 0}, + {3570411982, 0, 0}, + {3713290482, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 1, 8}, + {0, 3, 4}, + {0, 10, 2}, + {0, 12, 11}, + {0, 6, 13}, + {0, 7, 5}, + {0, 15, 14}, + {0, 9, 16}, + })); + + codecs.emplace(std::pair(SpvOpVectorShuffle, 2), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(11, { + {0, 0, 0}, + {495107308, 0, 0}, + {2096388952, 0, 0}, + {2622612602, 0, 0}, + {3496407048, 0, 0}, + {3570411982, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 1, 2}, + {0, 3, 7}, + {0, 8, 4}, + {0, 9, 5}, + {0, 6, 10}, + })); + + codecs.emplace(std::pair(SpvOpVectorShuffle, 3), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(7, { + {0, 0, 0}, + {679771963, 0, 0}, + {2320303498, 0, 0}, + {3334207724, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 2, 4}, + {0, 3, 5}, + {0, 6, 1}, + })); + + codecs.emplace(std::pair(SpvOpCompositeConstruct, 0), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(5, { + {0, 0, 0}, + {1319785741, 0, 0}, + {3753486980, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 2, 1}, + {0, 3, 4}, + })); + + codecs.emplace(std::pair(SpvOpCompositeConstruct, 1), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(11, { + {0, 0, 0}, + {296981500, 0, 0}, + {959681532, 0, 0}, + {1141965917, 0, 0}, + {2855506940, 0, 0}, + {3091876332, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 5, 2}, + {0, 4, 3}, + {0, 1, 7}, + {0, 9, 8}, + {0, 6, 10}, + })); + + codecs.emplace(std::pair(SpvOpCompositeConstruct, 2), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(11, { + {0, 0, 0}, + {269823086, 0, 0}, + {296981500, 0, 0}, + {959681532, 0, 0}, + {2219733501, 0, 0}, + {2855506940, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 1, 4}, + {0, 7, 3}, + {0, 5, 2}, + {0, 9, 8}, + {0, 6, 10}, + })); + + codecs.emplace(std::pair(SpvOpCompositeConstruct, 3), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(11, { + {0, 0, 0}, + {296981500, 0, 0}, + {959681532, 0, 0}, + {1227221002, 0, 0}, + {2855506940, 0, 0}, + {3692647551, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 2, 3}, + {0, 1, 5}, + {0, 4, 7}, + {0, 9, 8}, + {0, 6, 10}, + })); + + codecs.emplace(std::pair(SpvOpCompositeConstruct, 4), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(11, { + {0, 0, 0}, + {18776483, 0, 0}, + {296981500, 0, 0}, + {959681532, 0, 0}, + {2855506940, 0, 0}, + {3874089391, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 5, 1}, + {0, 7, 3}, + {0, 4, 8}, + {0, 9, 2}, + {0, 6, 10}, + })); + + codecs.emplace(std::pair(SpvOpCompositeConstruct, 5), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(9, { + {0, 0, 0}, + {679771963, 0, 0}, + {1951208733, 0, 0}, + {2320303498, 0, 0}, + {3334207724, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 3, 5}, + {0, 1, 6}, + {0, 7, 4}, + {0, 2, 8}, + })); + + codecs.emplace(std::pair(SpvOpCompositeExtract, 0), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(1, { + {0, 0, 0}, + {1111111111111111111, 0, 0}, + })); + + codecs.emplace(std::pair(SpvOpCompositeExtract, 1), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(17, { + {0, 0, 0}, + {495107308, 0, 0}, + {850497536, 0, 0}, + {1584369690, 0, 0}, + {1890300748, 0, 0}, + {2043873558, 0, 0}, + {2338272340, 0, 0}, + {3312467582, 0, 0}, + {3504158761, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 1, 8}, + {0, 10, 4}, + {0, 7, 3}, + {0, 6, 11}, + {0, 12, 5}, + {0, 13, 2}, + {0, 15, 14}, + {0, 9, 16}, + })); + + codecs.emplace(std::pair(SpvOpCompositeExtract, 2), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(35, { + {0, 0, 0}, + {545678922, 0, 0}, + {630592085, 0, 0}, + {679771963, 0, 0}, + {899570100, 0, 0}, + {929101967, 0, 0}, + {1100599986, 0, 0}, + {1103903216, 0, 0}, + {1369578001, 0, 0}, + {2320303498, 0, 0}, + {2926633629, 0, 0}, + {3334207724, 0, 0}, + {3486057732, 0, 0}, + {3705139860, 0, 0}, + {3800912395, 0, 0}, + {3822983876, 0, 0}, + {4141567741, 0, 0}, + {4292991777, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 10, 2}, + {0, 12, 17}, + {0, 13, 7}, + {0, 20, 19}, + {0, 5, 16}, + {0, 15, 21}, + {0, 3, 22}, + {0, 23, 18}, + {0, 1, 9}, + {0, 8, 24}, + {0, 11, 14}, + {0, 4, 25}, + {0, 27, 26}, + {0, 6, 28}, + {0, 30, 29}, + {0, 32, 31}, + {0, 34, 33}, + })); + + codecs.emplace(std::pair(SpvOpCompositeInsert, 0), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(1, { + {0, 0, 0}, + {1111111111111111111, 0, 0}, + })); + + codecs.emplace(std::pair(SpvOpCompositeInsert, 1), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(13, { + {0, 0, 0}, + {296981500, 0, 0}, + {2517964682, 0, 0}, + {2855506940, 0, 0}, + {3044188332, 0, 0}, + {3570411982, 0, 0}, + {3764205609, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 4, 1}, + {0, 8, 6}, + {0, 9, 2}, + {0, 10, 3}, + {0, 11, 5}, + {0, 7, 12}, + })); + + codecs.emplace(std::pair(SpvOpCompositeInsert, 2), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(9, { + {0, 0, 0}, + {371428004, 0, 0}, + {1543280290, 0, 0}, + {2162986400, 0, 0}, + {3808408202, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 2, 3}, + {0, 4, 1}, + {0, 7, 6}, + {0, 5, 8}, + })); + + codecs.emplace(std::pair(SpvOpCompositeInsert, 3), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(3, { + {0, 0, 0}, + {3334207724, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 1, 2}, + })); + + codecs.emplace(std::pair(SpvOpImageSampleImplicitLod, 0), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(15, { + {0, 0, 0}, + {236660303, 0, 0}, + {488500848, 0, 0}, + {495107308, 0, 0}, + {1858116930, 0, 0}, + {2231688008, 0, 0}, + {2693892518, 0, 0}, + {3566035349, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 6, 5}, + {0, 4, 7}, + {0, 10, 9}, + {0, 1, 2}, + {0, 12, 11}, + {0, 13, 3}, + {0, 8, 14}, + })); + + codecs.emplace(std::pair(SpvOpImageSampleImplicitLod, 1), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(13, { + {0, 0, 0}, + {883854656, 0, 0}, + {2036361232, 0, 0}, + {2356768706, 0, 0}, + {2637132451, 0, 0}, + {3237903670, 0, 0}, + {3829682756, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 5, 7}, + {0, 8, 6}, + {0, 3, 4}, + {0, 10, 9}, + {0, 2, 11}, + {0, 12, 1}, + })); + + codecs.emplace(std::pair(SpvOpImageSampleImplicitLod, 2), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(15, { + {0, 0, 0}, + {646282397, 0, 0}, + {1352628475, 0, 0}, + {1543798545, 0, 0}, + {1545450160, 0, 0}, + {2517964682, 0, 0}, + {2532518896, 0, 0}, + {3619787319, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 3, 6}, + {0, 1, 4}, + {0, 10, 9}, + {0, 5, 2}, + {0, 12, 11}, + {0, 13, 7}, + {0, 8, 14}, + })); + + codecs.emplace(std::pair(SpvOpImageSampleImplicitLod, 3), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(7, { + {0, 0, 0}, + {2855506940, 0, 0}, + {3266548732, 0, 0}, + {3732640764, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 2, 1}, + {0, 5, 4}, + {0, 3, 6}, + })); + + codecs.emplace(std::pair(SpvOpImageSampleImplicitLod, 5), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(9, { + {0, 0, 0}, + {679771963, 0, 0}, + {1951208733, 0, 0}, + {2320303498, 0, 0}, + {3334207724, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 4, 5}, + {0, 2, 6}, + {0, 1, 3}, + {0, 8, 7}, + })); + + codecs.emplace(std::pair(SpvOpFAdd, 0), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(1, { + {0, 0, 0}, + {1111111111111111111, 0, 0}, + })); + + codecs.emplace(std::pair(SpvOpFAdd, 1), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(11, { + {0, 0, 0}, + {296981500, 0, 0}, + {959681532, 0, 0}, + {1570165302, 0, 0}, + {2096388952, 0, 0}, + {3653838348, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 1, 5}, + {0, 3, 2}, + {0, 8, 7}, + {0, 9, 4}, + {0, 6, 10}, + })); + + codecs.emplace(std::pair(SpvOpFAdd, 2), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(11, { + {0, 0, 0}, + {643418617, 0, 0}, + {959681532, 0, 0}, + {1092948665, 0, 0}, + {2517964682, 0, 0}, + {2683080096, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 5, 3}, + {0, 4, 1}, + {0, 8, 7}, + {0, 9, 2}, + {0, 6, 10}, + })); + + codecs.emplace(std::pair(SpvOpFAdd, 3), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(9, { + {0, 0, 0}, + {679771963, 0, 0}, + {1951208733, 0, 0}, + {2320303498, 0, 0}, + {3334207724, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 3, 5}, + {0, 4, 6}, + {0, 1, 7}, + {0, 2, 8}, + })); + + codecs.emplace(std::pair(SpvOpFSub, 0), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(17, { + {0, 0, 0}, + {615982737, 0, 0}, + {1139547465, 0, 0}, + {1178317551, 0, 0}, + {2330636993, 0, 0}, + {2589449658, 0, 0}, + {3579593979, 0, 0}, + {3730093054, 0, 0}, + {3944781937, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 3, 6}, + {0, 5, 7}, + {0, 8, 1}, + {0, 10, 4}, + {0, 11, 2}, + {0, 13, 12}, + {0, 15, 14}, + {0, 9, 16}, + })); + + codecs.emplace(std::pair(SpvOpFSub, 1), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(23, { + {0, 0, 0}, + {249378857, 0, 0}, + {296981500, 0, 0}, + {1203545131, 0, 0}, + {1265796414, 0, 0}, + {1319785741, 0, 0}, + {2855506940, 0, 0}, + {3091876332, 0, 0}, + {3187066832, 0, 0}, + {3508792859, 0, 0}, + {3619787319, 0, 0}, + {3653838348, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 5, 9}, + {0, 4, 1}, + {0, 7, 10}, + {0, 13, 8}, + {0, 3, 14}, + {0, 6, 15}, + {0, 11, 16}, + {0, 18, 17}, + {0, 20, 19}, + {0, 21, 2}, + {0, 22, 12}, + })); + + codecs.emplace(std::pair(SpvOpFSub, 2), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(33, { + {0, 0, 0}, + {296981500, 0, 0}, + {443558693, 0, 0}, + {1203545131, 0, 0}, + {1265796414, 0, 0}, + {1319785741, 0, 0}, + {1558001705, 0, 0}, + {1955104493, 0, 0}, + {2234361374, 0, 0}, + {2598189097, 0, 0}, + {2775815164, 0, 0}, + {3244209297, 0, 0}, + {3753486980, 0, 0}, + {3886529747, 0, 0}, + {4069810315, 0, 0}, + {4164704452, 0, 0}, + {4273793488, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 10, 7}, + {0, 15, 13}, + {0, 8, 16}, + {0, 6, 2}, + {0, 3, 9}, + {0, 14, 5}, + {0, 11, 18}, + {0, 20, 19}, + {0, 22, 21}, + {0, 23, 12}, + {0, 24, 1}, + {0, 25, 4}, + {0, 27, 26}, + {0, 29, 28}, + {0, 31, 30}, + {0, 17, 32}, + })); + + codecs.emplace(std::pair(SpvOpFSub, 3), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(9, { + {0, 0, 0}, + {679771963, 0, 0}, + {1951208733, 0, 0}, + {2320303498, 0, 0}, + {3334207724, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 4, 5}, + {0, 3, 6}, + {0, 1, 7}, + {0, 8, 2}, + })); + + codecs.emplace(std::pair(SpvOpFMul, 0), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(1, { + {0, 0, 0}, + {1111111111111111111, 0, 0}, + })); + + codecs.emplace(std::pair(SpvOpFMul, 1), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(15, { + {0, 0, 0}, + {810488476, 0, 0}, + {1054461787, 0, 0}, + {1158929937, 0, 0}, + {1203545131, 0, 0}, + {2096388952, 0, 0}, + {3929248764, 0, 0}, + {4008405264, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 3, 2}, + {0, 7, 6}, + {0, 1, 4}, + {0, 5, 9}, + {0, 11, 10}, + {0, 13, 12}, + {0, 8, 14}, + })); + + codecs.emplace(std::pair(SpvOpFMul, 2), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(13, { + {0, 0, 0}, + {171307615, 0, 0}, + {593829839, 0, 0}, + {959681532, 0, 0}, + {1684282922, 0, 0}, + {1811839150, 0, 0}, + {3929248764, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 5, 1}, + {0, 6, 3}, + {0, 4, 2}, + {0, 9, 8}, + {0, 11, 10}, + {0, 7, 12}, + })); + + codecs.emplace(std::pair(SpvOpFMul, 3), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(7, { + {0, 0, 0}, + {679771963, 0, 0}, + {2320303498, 0, 0}, + {3334207724, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 3, 4}, + {0, 2, 5}, + {0, 1, 6}, + })); + + codecs.emplace(std::pair(SpvOpVectorTimesScalar, 0), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(11, { + {0, 0, 0}, + {2504802016, 0, 0}, + {3032677281, 0, 0}, + {3560552546, 0, 0}, + {3797961332, 0, 0}, + {3886529747, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 2, 1}, + {0, 4, 3}, + {0, 7, 5}, + {0, 9, 8}, + {0, 6, 10}, + })); + + codecs.emplace(std::pair(SpvOpVectorTimesScalar, 1), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(35, { + {0, 0, 0}, + {354479447, 0, 0}, + {1325348861, 0, 0}, + {1367301635, 0, 0}, + {1368383673, 0, 0}, + {1646147798, 0, 0}, + {1679946323, 0, 0}, + {1766401548, 0, 0}, + {2096388952, 0, 0}, + {2123388694, 0, 0}, + {2362972044, 0, 0}, + {2660843182, 0, 0}, + {2698156268, 0, 0}, + {2970183398, 0, 0}, + {3133016299, 0, 0}, + {3187066832, 0, 0}, + {3882634684, 0, 0}, + {4243119782, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 2, 11}, + {0, 6, 5}, + {0, 12, 9}, + {0, 16, 14}, + {0, 4, 17}, + {0, 10, 7}, + {0, 3, 1}, + {0, 19, 13}, + {0, 21, 20}, + {0, 23, 22}, + {0, 25, 24}, + {0, 27, 26}, + {0, 29, 28}, + {0, 8, 15}, + {0, 31, 30}, + {0, 33, 32}, + {0, 18, 34}, + })); + + codecs.emplace(std::pair(SpvOpVectorTimesScalar, 2), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(37, { + {0, 0, 0}, + {810488476, 0, 0}, + {959681532, 0, 0}, + {1232501371, 0, 0}, + {1372785527, 0, 0}, + {1526654696, 0, 0}, + {1684282922, 0, 0}, + {1901166356, 0, 0}, + {2244928358, 0, 0}, + {2314864456, 0, 0}, + {2524697596, 0, 0}, + {2568098594, 0, 0}, + {3117071189, 0, 0}, + {3188115516, 0, 0}, + {3554463148, 0, 0}, + {3691770462, 0, 0}, + {3929248764, 0, 0}, + {4060703604, 0, 0}, + {4092487128, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 4, 7}, + {0, 12, 8}, + {0, 17, 13}, + {0, 15, 18}, + {0, 14, 10}, + {0, 9, 5}, + {0, 2, 1}, + {0, 20, 6}, + {0, 22, 21}, + {0, 3, 23}, + {0, 11, 24}, + {0, 26, 25}, + {0, 28, 27}, + {0, 30, 29}, + {0, 32, 31}, + {0, 33, 16}, + {0, 35, 34}, + {0, 19, 36}, + })); + + codecs.emplace(std::pair(SpvOpVectorTimesScalar, 3), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(3, { + {0, 0, 0}, + {1951208733, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 1, 2}, + })); + + codecs.emplace(std::pair(SpvOpDot, 0), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(15, { + {0, 0, 0}, + {170690025, 0, 0}, + {669982125, 0, 0}, + {1625742020, 0, 0}, + {2071351379, 0, 0}, + {2291766425, 0, 0}, + {3104643263, 0, 0}, + {3602108619, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 5, 1}, + {0, 6, 7}, + {0, 2, 3}, + {0, 9, 4}, + {0, 11, 10}, + {0, 13, 12}, + {0, 8, 14}, + })); + + codecs.emplace(std::pair(SpvOpDot, 1), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(45, { + {0, 0, 0}, + {50385656, 0, 0}, + {615982737, 0, 0}, + {837715723, 0, 0}, + {1237148906, 0, 0}, + {1364157225, 0, 0}, + {1499923635, 0, 0}, + {1766401548, 0, 0}, + {2012838864, 0, 0}, + {2096388952, 0, 0}, + {2161102232, 0, 0}, + {2197874825, 0, 0}, + {2279700640, 0, 0}, + {2362972044, 0, 0}, + {2589449658, 0, 0}, + {2881302403, 0, 0}, + {2936040203, 0, 0}, + {2970183398, 0, 0}, + {3187066832, 0, 0}, + {3362830643, 0, 0}, + {3538158875, 0, 0}, + {3635542517, 0, 0}, + {3997432565, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 19, 10}, + {0, 3, 1}, + {0, 5, 6}, + {0, 20, 2}, + {0, 4, 22}, + {0, 25, 24}, + {0, 26, 12}, + {0, 16, 15}, + {0, 17, 9}, + {0, 14, 13}, + {0, 27, 21}, + {0, 7, 18}, + {0, 8, 28}, + {0, 11, 29}, + {0, 31, 30}, + {0, 33, 32}, + {0, 35, 34}, + {0, 37, 36}, + {0, 39, 38}, + {0, 41, 40}, + {0, 43, 42}, + {0, 23, 44}, + })); + + codecs.emplace(std::pair(SpvOpDot, 2), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(41, { + {0, 0, 0}, + {139011596, 0, 0}, + {342159236, 0, 0}, + {837715723, 0, 0}, + {876867882, 0, 0}, + {1356063462, 0, 0}, + {1766401548, 0, 0}, + {2096388952, 0, 0}, + {2197874825, 0, 0}, + {2362972044, 0, 0}, + {2517964682, 0, 0}, + {2589449658, 0, 0}, + {2683080096, 0, 0}, + {2919626325, 0, 0}, + {2936040203, 0, 0}, + {2970183398, 0, 0}, + {2996594997, 0, 0}, + {3187066832, 0, 0}, + {3913885196, 0, 0}, + {3997432565, 0, 0}, + {4010499223, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 2, 3}, + {0, 5, 4}, + {0, 20, 16}, + {0, 19, 1}, + {0, 11, 9}, + {0, 14, 13}, + {0, 22, 17}, + {0, 23, 12}, + {0, 15, 24}, + {0, 8, 7}, + {0, 26, 25}, + {0, 6, 27}, + {0, 28, 18}, + {0, 30, 29}, + {0, 32, 31}, + {0, 34, 33}, + {0, 36, 35}, + {0, 37, 10}, + {0, 39, 38}, + {0, 21, 40}, + })); + + codecs.emplace(std::pair(SpvOpDot, 3), std::move(codec)); + } + + { + std::unique_ptr> codec(new HuffmanCodec(3, { + {0, 0, 0}, + {1036475267, 0, 0}, + {1111111111111111111, 0, 0}, + {0, 1, 2}, + })); + + codecs.emplace(std::pair(SpvOpLabel, 0), std::move(codec)); + } + + return codecs; +} diff --git a/source/comp/markv_codec.cpp b/source/comp/markv_codec.cpp index 2288dc3d3..c99fdd994 100644 --- a/source/comp/markv_codec.cpp +++ b/source/comp/markv_codec.cpp @@ -28,18 +28,25 @@ #include #include #include +#include #include #include #include #include #include +#include "spirv/1.2/GLSL.std.450.h" +#include "spirv/1.2/OpenCL.std.h" +#include "spirv/1.2/spirv.h" + #include "binary.h" #include "diagnostic.h" #include "enum_string_mapping.h" #include "extensions.h" #include "ext_inst.h" +#include "id_descriptor.h" #include "instruction.h" +#include "markv_autogen.h" #include "opcode.h" #include "operand.h" #include "spirv-tools/libspirv.h" @@ -47,16 +54,22 @@ #include "spirv_endian.h" #include "spirv_validator_options.h" #include "util/bit_stream.h" +#include "util/huffman_codec.h" +#include "util/move_to_front.h" #include "util/parse_number.h" #include "validate.h" #include "val/instruction.h" #include "val/validation_state.h" +using libspirv::IdDescriptorCollection; using libspirv::Instruction; using libspirv::ValidationState_t; using spvtools::ValidateInstructionAndUpdateValidationState; using spvutils::BitReaderWord64; using spvutils::BitWriterWord64; +using spvutils::HuffmanCodec; +using MoveToFront = spvutils::MoveToFront; +using MultiMoveToFront = spvutils::MultiMoveToFront; struct spv_markv_encoder_options_t { }; @@ -69,20 +82,142 @@ namespace { const uint32_t kSpirvMagicNumber = SpvMagicNumber; const uint32_t kMarkvMagicNumber = 0x07230303; -enum { - kMarkvFirstOpcode = 65536, - kMarkvOpNextInstructionEncodesResultId = 65536, +// Handles for move-to-front sequences. Enums which end with "Begin" define +// handle spaces which start at that value and span 16 or 32 bit wide. +enum : uint64_t { + kMtfNone = 0, + // All ids. + kMtfAll, + // All forward declared ids. + kMtfForwardDeclared, + // All type ids except for generated by OpTypeFunction. + kMtfTypeNonFunction, + // All labels. + kMtfLabel, + // All ids created by instructions which had type_id. + kMtfObject, + // All types generated by OpTypeFloat, OpTypeInt, OpTypeBool. + kMtfTypeScalar, + // All composite types. + kMtfTypeComposite, + // Boolean type or any vector type of it. + kMtfTypeBoolScalarOrVector, + // All float types or any vector floats type. + kMtfTypeFloatScalarOrVector, + // All int types or any vector int type. + kMtfTypeIntScalarOrVector, + // All types declared as return types in OpTypeFunction. + kMtfTypeReturnedByFunction, + // All object ids which are integer constants. + kMtfConstInteger, + // All composite objects. + kMtfComposite, + // All bool objects or vectors of bools. + kMtfBoolScalarOrVector, + // All float objects or vectors of float. + kMtfFloatScalarOrVector, + // All int objects or vectors of int. + kMtfIntScalarOrVector, + // All pointer types which point to composited. + kMtfTypePointerToComposite, + // Used by EncodeMtfRankHuffman. + kMtfGenericNonZeroRank, + // Handle space for ids of specific type. + kMtfIdOfTypeBegin = 0x10000, + // Handle space for ids generated by specific opcode. + kMtfIdGeneratedByOpcode = 0x20000, + // Handle space for ids of objects with type generated by specific opcode. + kMtfIdWithTypeGeneratedByOpcodeBegin = 0x30000, + // All vectors of specific component type. + kMtfVectorOfComponentTypeBegin = 0x40000, + // All vector types of specific size. + kMtfTypeVectorOfSizeBegin = 0x50000, + // All pointer types to specific type. + kMtfPointerToTypeBegin = 0x60000, + // All function types which return specific type. + kMtfFunctionTypeWithReturnTypeBegin = 0x70000, + // All function objects which return specific type. + kMtfFunctionWithReturnTypeBegin = 0x80000, + // All float vectors of specific size. + kMtfFloatVectorOfSizeBegin = 0x90000, + // Id descriptor space (32-bit). + kMtfIdDescriptorSpaceBegin = 0x100000000, }; +// Used by "presumed index" technique which does special treatment of integer +// constants no greater than this value. +const uint32_t kMarkvMaxPresumedAccessIndex = 31; + +// Signals that the value is not in the coding scheme and a fallback method +// needs to be used. +const uint64_t kMarkvNoneOfTheAbove = GetMarkvNonOfTheAbove(); + +// Mtf ranks smaller than this are encoded with Huffman coding. +const uint32_t kMtfSmallestRankEncodedByValue = 10; + +// Signals that the mtf rank is too large to be encoded with Huffman. +const uint32_t kMtfRankEncodedByValueSignal = + std::numeric_limits::max(); + const size_t kCommentNumWhitespaces = 2; -// TODO(atgoo@github.com): This is a placeholder for an autogenerated flatbuffer -// containing MARK-V model for a specific dataset. +const size_t kByteBreakAfterInstIfLessThanUntilNextByte = 8; + +// Returns a set of mtf rank codecs based on a plausible hand-coded +// distribution. +std::map>> +GetMtfHuffmanCodecs() { + std::map>> codecs; + + std::unique_ptr> codec; + + codec.reset(new HuffmanCodec(std::map({ + { 0, 5 }, + { 1, 40 }, + { 2, 10 }, + { 3, 5 }, + { 4, 5 }, + { 5, 5 }, + { 6, 3 }, + { 7, 3 }, + { 8, 3 }, + { 9, 3 }, + { kMtfRankEncodedByValueSignal, 10 }, + }))); + codecs.emplace(kMtfAll, std::move(codec)); + + codec.reset(new HuffmanCodec(std::map({ + { 1, 50 }, + { 2, 20 }, + { 3, 5 }, + { 4, 5 }, + { 5, 2 }, + { 6, 1 }, + { 7, 1 }, + { 8, 1 }, + { 9, 1 }, + { kMtfRankEncodedByValueSignal, 10 }, + }))); + codecs.emplace(kMtfGenericNonZeroRank, std::move(codec)); + + return codecs; +} + +// Encoding/decoding model containing various constants and codecs. class MarkvModel { public: + MarkvModel() + : mtf_huffman_codecs_(GetMtfHuffmanCodecs()), + opcode_and_num_operands_huffman_codec_(GetOpcodeAndNumOperandsHist()), + opcode_and_num_operands_markov_huffman_codecs_( + GetOpcodeAndNumOperandsMarkovHuffmanCodecs()), + non_id_word_huffman_codecs_(GetNonIdWordHuffmanCodecs()), + id_descriptor_huffman_codecs_(GetIdDescriptorHuffmanCodecs()), + literal_string_huffman_codecs_(GetLiteralStringHuffmanCodecs()) {} + size_t opcode_chunk_length() const { return 7; } size_t num_operands_chunk_length() const { return 3; } - size_t id_index_chunk_length() const { return 3; } + size_t mtf_rank_chunk_length() const { return 5; } size_t u16_chunk_length() const { return 4; } size_t s16_chunk_length() const { return 4; } @@ -95,6 +230,98 @@ class MarkvModel { size_t u64_chunk_length() const { return 8; } size_t s64_chunk_length() const { return 8; } size_t s64_block_exponent() const { return 10; } + + // Returns Huffman codec for ranks of the mtf with given |handle|. + // Different mtfs can use different rank distributions. + // May return nullptr if the codec doesn't exist. + const HuffmanCodec* GetMtfHuffmanCodec(uint64_t handle) const { + const auto it = mtf_huffman_codecs_.find(handle); + if (it == mtf_huffman_codecs_.end()) + return nullptr; + return it->second.get(); + } + + // Returns a codec for common opcode_and_num_operands words for the given + // previous opcode. May return nullptr if the codec doesn't exist. + const HuffmanCodec* GetOpcodeAndNumOperandsMarkovHuffmanCodec( + uint32_t prev_opcode) const { + if (prev_opcode == SpvOpNop) + return &opcode_and_num_operands_huffman_codec_; + + const auto it = + opcode_and_num_operands_markov_huffman_codecs_.find(prev_opcode); + if (it == opcode_and_num_operands_markov_huffman_codecs_.end()) + return nullptr; + return it->second.get(); + } + + // Returns a codec for common non-id words used for given operand slot. + // Operand slot is defined by the opcode and the operand index. + // May return nullptr if the codec doesn't exist. + const HuffmanCodec* GetNonIdWordHuffmanCodec( + uint32_t opcode, uint32_t operand_index) const { + const auto it = non_id_word_huffman_codecs_.find( + std::pair(opcode, operand_index)); + if (it == non_id_word_huffman_codecs_.end()) + return nullptr; + return it->second.get(); + } + + // Returns a codec for common id descriptos used for given operand slot. + // Operand slot is defined by the opcode and the operand index. + // May return nullptr if the codec doesn't exist. + const HuffmanCodec* GetIdDescriptorHuffmanCodec( + uint32_t opcode, uint32_t operand_index) const { + const auto it = id_descriptor_huffman_codecs_.find( + std::pair(opcode, operand_index)); + if (it == id_descriptor_huffman_codecs_.end()) + return nullptr; + return it->second.get(); + } + + // Returns a codec for common strings used by the given opcode. + // Operand slot is defined by the opcode and the operand index. + // May return nullptr if the codec doesn't exist. + const HuffmanCodec* GetLiteralStringHuffmanCodec( + uint32_t opcode) const { + const auto it = literal_string_huffman_codecs_.find(opcode); + if (it == literal_string_huffman_codecs_.end()) + return nullptr; + return it->second.get(); + } + + private: + // Huffman codecs for move-to-front ranks. The map key is mtf handle. Doesn't + // need to contain a different codec for every handle as most use one and the + // same. + std::map>> + mtf_huffman_codecs_; + + // Huffman codec for base-rate of opcode_and_num_operands. + HuffmanCodec opcode_and_num_operands_huffman_codec_; + + // Huffman codecs for opcode_and_num_operands. The map key is previous opcode. + std::map>> + opcode_and_num_operands_markov_huffman_codecs_; + + // Huffman codecs for non-id single-word operand values. + // The map key is pair . + std::map, + std::unique_ptr>> + non_id_word_huffman_codecs_; + + // Huffman codecs for id descriptors. The map key is pair + // . + std::map, + std::unique_ptr>> + id_descriptor_huffman_codecs_; + + // Huffman codecs for literal strings. The map key is the opcode of the + // current instruction. This assumes, that there is no more than one literal + // string operand per instruction, but would still work even if this is not + // the case. Names and debug information strings are not collected. + std::map>> + literal_string_huffman_codecs_; }; const MarkvModel* GetDefaultModel() { @@ -163,6 +390,7 @@ size_t GetOperandVariableWidthChunkLength(spv_operand_type_t type) { case SPV_OPERAND_TYPE_SELECTION_CONTROL: return 4; case SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER: + case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER: return 6; default: return 0; @@ -240,15 +468,10 @@ size_t GetNumBitsToNextByte(size_t bit_pos) { return (8 - (bit_pos % 8)) % 8; } -bool ShouldByteBreak(size_t bit_pos) { - const size_t num_bits_to_next_byte = GetNumBitsToNextByte(bit_pos); - return num_bits_to_next_byte > 0; // && num_bits_to_next_byte <= 2; -} - // Defines and returns current MARK-V version. uint32_t GetMarkvVersion() { const uint32_t kVersionMajor = 1; - const uint32_t kVersionMinor = 0; + const uint32_t kVersionMinor = 1; return kVersionMinor | (kVersionMajor << 16); } @@ -361,20 +584,142 @@ class MarkvCodecBase { return ValidateInstructionAndUpdateValidationState(&vstate_, &inst); } - // Returns the current instruction (the one last processed by the validator). - const Instruction& GetCurrentInstruction() const { - return vstate_.ordered_instructions().back(); + // Returns instruction which created |id| or nullptr if such instruction was + // not registered. + const Instruction* GetDefInst(uint32_t id) const { + const auto it = vstate_.all_definitions().find(id); + if (it == vstate_.all_definitions().end()) + return nullptr; + return it->second; } - spv_validator_options validator_options_; + // Returns type id of vector type component. + uint32_t GetVectorComponentType(uint32_t vector_type_id) const { + const auto it = vstate_.all_definitions().find(vector_type_id); + assert(it != vstate_.all_definitions().end()); + const Instruction* type_inst = it->second; + assert(type_inst->opcode() == SpvOpTypeVector); + + const uint32_t component_type = + type_inst->word(type_inst->operands()[1].offset); + return component_type; + } + + // Returns mtf handle for ids of given type. + uint64_t GetMtfIdOfType(uint32_t type_id) const { + return kMtfIdOfTypeBegin + type_id; + } + + // Returns mtf handle for ids generated by given opcode. + uint64_t GetMtfIdGeneratedByOpcode(SpvOp opcode) const { + return kMtfIdGeneratedByOpcode + opcode; + } + + // Returns mtf handle for ids of type generated by given opcode. + uint64_t GetMtfIdWithTypeGeneratedByOpcode(SpvOp opcode) const { + return kMtfIdWithTypeGeneratedByOpcodeBegin + opcode; + } + + // Returns mtf handle for vectors of specific component type. + uint64_t GetMtfVectorOfComponentType(uint32_t type_id) const { + return kMtfVectorOfComponentTypeBegin + type_id; + } + + // Returns mtf handle for float vectors of specific size. + uint64_t GetMtfFloatVectorOfSize(uint32_t size) const { + return kMtfFloatVectorOfSizeBegin + size; + } + + // Returns mtf handle for vector type of specific size. + uint64_t GetMtfTypeVectorOfSize(uint32_t size) const { + return kMtfTypeVectorOfSizeBegin + size; + } + + // Returns mtf handle for pointers to specific size. + uint64_t GetMtfPointerToType(uint32_t type_id) const { + return kMtfPointerToTypeBegin + type_id; + } + + // Returns mtf handle for function types with given return type. + uint64_t GetMtfFunctionTypeWithReturnType(uint32_t type_id) const { + return kMtfFunctionTypeWithReturnTypeBegin + type_id; + } + + // Returns mtf handle for functions with given return type. + uint64_t GetMtfFunctionWithReturnType(uint32_t type_id) const { + return kMtfFunctionWithReturnTypeBegin + type_id; + } + + // Returns mtf handle for the given id descriptor. + uint64_t GetMtfIdDescriptor(uint32_t descriptor) const { + return kMtfIdDescriptorSpaceBegin + descriptor; + } + + // Process data from the current instruction. This would update MTFs and + // other data containers. + void ProcessCurInstruction(); + + // Returns move-to-front handle to be used for the current operand slot. + // Mtf handle is chosen based on a set of rules defined by SPIR-V grammar. + uint64_t GetRuleBasedMtf(); + + // Returns words of the current instruction. Decoder has a different + // implementation and the array is valid only until the previously decoded + // word. + virtual const uint32_t* GetInstWords() const { + return inst_.words; + } + + // Returns the opcode of the previous instruction. + SpvOp GetPrevOpcode() const { + if (instructions_.empty()) + return SpvOpNop; + + return instructions_.back()->opcode(); + } + + spv_validator_options validator_options_ = nullptr; ValidationState_t vstate_; const libspirv::AssemblyGrammar grammar_; MarkvHeader header_; - const MarkvModel* model_; + const MarkvModel* model_ = nullptr; - // Move-to-front list of all ids. - // TODO(atgoo@github.com) Consider a better move-to-front implementation. - std::list move_to_front_ids_; + // Current instruction, current operand and current operand index. + spv_parsed_instruction_t inst_; + spv_parsed_operand_t operand_; + uint32_t operand_index_; + + // Maps a result ID to its type ID. By convention: + // - a result ID that is a type definition maps to itself. + // - a result ID without a type maps to 0. (E.g. for OpLabel) + std::unordered_map id_to_type_id_; + + // Container for all move-to-front sequences. + MultiMoveToFront multi_mtf_; + + // Id of the current function or zero if outside of function. + uint32_t cur_function_id_ = 0; + + // Return type of the current function. + uint32_t cur_function_return_type_ = 0; + + // Remaining function parameter types. This container is filled on OpFunction, + // and drained on OpFunctionParameter. + std::list remaining_function_parameter_types_; + + // List of ids local to the current function. + std::vector ids_local_to_cur_function_; + + // List of instructions in the order they are given in the module. + std::vector instructions_; + + // Maps used for the 'presumed id' techniques. Maps small constant integer + // value to its id and back. + std::map presumed_index_to_id_; + std::map id_to_presumed_index_; + + // Container/computer for id descriptors. + IdDescriptorCollection id_descriptors_; }; // SPIR-V to MARK-V encoder. Exposes functions EncodeHeader and @@ -426,7 +771,7 @@ class MarkvEncoder : public MarkvCodecBase { assert(writer_.GetData()); std::memcpy(markv_binary->data, &header_, sizeof(header_)); std::memcpy(markv_binary->data + sizeof(header_), - writer_.GetData(), writer_.GetDataSizeBytes()); + writer_.GetData(), writer_.GetDataSizeBytes()); return markv_binary; } @@ -469,59 +814,43 @@ class MarkvEncoder : public MarkvCodecBase { return spvValidatorOptionsCreate(); } - // Writes a single word to bit stream. |type| determines if the word is + // Writes a single word to bit stream. operand_.type determines if the word is // encoded and how. - void EncodeOperandWord(spv_operand_type_t type, uint32_t word) { - const size_t chunk_length = - GetOperandVariableWidthChunkLength(type); - if (chunk_length) { - writer_.WriteVariableWidthU32(word, chunk_length); - } else { - writer_.WriteUnencoded(word); - } - } + spv_result_t EncodeNonIdWord(uint32_t word); - // Returns id index and updates move-to-front. - // Index is uint16 as SPIR-V module is guaranteed to have no more than 65535 - // instructions. - uint16_t GetIdIndex(uint32_t id) { - if (all_known_ids_.count(id)) { - uint16_t index = 0; - for (auto it = move_to_front_ids_.begin(); - it != move_to_front_ids_.end(); ++it) { - if (*it == id) { - if (index != 0) { - move_to_front_ids_.erase(it); - move_to_front_ids_.push_front(id); - } - return index; - } - ++index; - } - assert(0 && "Id not found in move_to_front_ids_"); - return 0; - } else { - all_known_ids_.insert(id); - move_to_front_ids_.push_front(id); - return static_cast(move_to_front_ids_.size() - 1); - } - } + // Writes both opcode and num_operands as a single code. + // Returns SPV_UNSUPPORTED iff no suitable codec was found. + spv_result_t EncodeOpcodeAndNumOperands(uint32_t opcode, uint32_t num_operands); - void AddByteBreakIfAgreed() { - if (!ShouldByteBreak(writer_.GetNumBits())) - return; + // Writes mtf rank to bit stream. |mtf| is used to determine the codec + // scheme. |fallback_method| is used if no codec defined for |mtf|. + spv_result_t EncodeMtfRankHuffman(uint32_t rank, uint64_t mtf, + uint64_t fallback_method); - if (logger_) { - logger_->AppendWhitespaces(kCommentNumWhitespaces); - logger_->AppendText("ByteBreak:"); - } + // Writes id using coding based on mtf associated with the id descriptor. + // Returns SPV_UNSUPPORTED iff fallback method needs to be used. + spv_result_t EncodeIdWithDescriptor(uint32_t id); - writer_.WriteBits(0, GetNumBitsToNextByte(writer_.GetNumBits())); - } + // Writes id using coding based on the given |mtf|, which is expected to + // contain the given |id|. + spv_result_t EncodeExistingId(uint64_t mtf, uint32_t id); + + // Writes type id of the current instruction if can't be inferred. + spv_result_t EncodeTypeId(); + + // Writes result id of the current instruction if can't be inferred. + spv_result_t EncodeResultId(); + + // Writes ids which are neither type nor result ids. + spv_result_t EncodeRefId(uint32_t id); + + // Writes bits to the stream until the beginning of the next byte if the + // number of bits until the next byte is less than |byte_break_if_less_than|. + void AddByteBreak(size_t byte_break_if_less_than); // Encodes a literal number operand and writes it to the bit stream. - void EncodeLiteralNumber(const Instruction& instruction, - const spv_parsed_operand_t& operand); + spv_result_t EncodeLiteralNumber(const Instruction& instruction, + const spv_parsed_operand_t& operand); spv_const_markv_encoder_options options_; @@ -534,9 +863,6 @@ class MarkvEncoder : public MarkvCodecBase { // If not nullptr, disassembled instruction lines will be written to comments. // Format: \n separated instruction lines, no header. std::unique_ptr disassembly_; - - // All ids which were previosly encountered in the module. - std::unordered_set all_known_ids_; }; // Decodes MARK-V buffers written by MarkvEncoder. @@ -551,6 +877,7 @@ class MarkvDecoder : public MarkvCodecBase { (void) options_; vstate_.setIdBound(1); parsed_operands_.reserve(25); + inst_words_.reserve(25); } // Decodes SPIR-V from MARK-V and stores the words in |spirv_binary|. @@ -571,63 +898,59 @@ class MarkvDecoder : public MarkvCodecBase { return spvValidatorOptionsCreate(); } - // Reads a single word from bit stream. |type| determines if the word needs - // to be decoded and how. Returns false if read fails. - bool DecodeOperandWord(spv_operand_type_t type, uint32_t* word) { - const size_t chunk_length = GetOperandVariableWidthChunkLength(type); - if (chunk_length) { - return reader_.ReadVariableWidthU32(word, chunk_length); - } else { - return reader_.ReadUnencoded(word); - } - } - - // Fetches the id from the move-to-front list and moves it to front. - uint32_t GetIdAndMoveToFront(uint16_t index) { - if (index >= move_to_front_ids_.size()) { - // Issue new id. - const uint32_t id = vstate_.getIdBound(); - move_to_front_ids_.push_front(id); - vstate_.setIdBound(id + 1); - return id; - } else { - if (index == 0) - return move_to_front_ids_.front(); - - // Iterate to index. - auto it = move_to_front_ids_.begin(); - for (size_t i = 0; i < index; ++i) - ++it; - const uint32_t id = *it; - move_to_front_ids_.erase(it); - move_to_front_ids_.push_front(id); - return id; - } - } - - // Decodes id index and fetches the id from move-to-front list. - bool DecodeId(uint32_t* id) { - uint16_t index = 0; - if (!reader_.ReadVariableWidthU16(&index, model_->id_index_chunk_length())) - return false; - - *id = GetIdAndMoveToFront(index); - return true; - } - - bool ReadToByteBreakIfAgreed() { - if (!ShouldByteBreak(reader_.GetNumReadBits())) - return true; - + // 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; - if (!reader_.ReadBits(&bits, - GetNumBitsToNextByte(reader_.GetNumReadBits()))) - return false; + const bool result = reader_.ReadBits(&bits, 1); + if (result) + *bit = bits ? true : false; + return result; + }; - if (bits != 0) - return false; + // Returns ReadBit bound to the class object. + std::function GetReadBitCallback() { + return std::bind(&MarkvDecoder::ReadBit, this, std::placeholders::_1); + } - return true; + // 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, @@ -636,14 +959,12 @@ class MarkvDecoder : public MarkvCodecBase { // Reads instruction from bit stream, decodes and validates it. // Decoded instruction is valid until the next call of DecodeInstruction(). - spv_result_t DecodeInstruction(spv_parsed_instruction_t* inst); + spv_result_t DecodeInstruction(); // Read operand from the stream decodes and validates it. - spv_result_t DecodeOperand(size_t instruction_offset, size_t operand_offset, - spv_parsed_instruction_t* inst, + spv_result_t DecodeOperand(size_t operand_offset, const spv_operand_type_t type, - spv_operand_pattern_t* expected_operands, - bool read_result_id); + 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 @@ -653,10 +974,10 @@ class MarkvDecoder : public MarkvCodecBase { spv_result_t SetNumericTypeInfoForType(spv_parsed_operand_t* parsed_operand, uint32_t type_id); - // Records the number type for the given instruction, if that - // instruction generates a type. For types that aren't scalar numbers, - // record something with number kind SPV_NUMBER_NONE. - void RecordNumberType(const spv_parsed_instruction_t& inst); + // 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(); spv_const_markv_decoder_options options_; @@ -671,50 +992,1208 @@ class MarkvDecoder : public MarkvCodecBase { // Valid until next DecodeInstruction call. std::vector parsed_operands_; - // Maps a result ID to its type ID. By convention: - // - a result ID that is a type definition maps to itself. - // - a result ID without a type maps to 0. (E.g. for OpLabel) - std::unordered_map id_to_type_id_; + // Temporary storage for current instruction words. + // Valid until next DecodeInstruction call. + std::vector inst_words_; + // Maps a type ID to its number type description. std::unordered_map type_id_to_number_type_info_; + // Maps an ExtInstImport id to the extended instruction type. std::unordered_map import_id_to_ext_inst_type_; }; -void MarkvEncoder::EncodeLiteralNumber(const Instruction& instruction, - const spv_parsed_operand_t& operand) { - if (operand.number_bit_width == 32) { - const uint32_t word = instruction.word(operand.offset); - if (operand.number_kind == SPV_NUMBER_UNSIGNED_INT) { - writer_.WriteVariableWidthU32(word, model_->u32_chunk_length()); - } else if (operand.number_kind == SPV_NUMBER_SIGNED_INT) { - int32_t val = 0; - std::memcpy(&val, &word, 4); - writer_.WriteVariableWidthS32(val, model_->s32_chunk_length(), - model_->s32_block_exponent()); - } else if (operand.number_kind == SPV_NUMBER_FLOATING) { - writer_.WriteUnencoded(word); - } else { - assert(0); +void MarkvCodecBase::ProcessCurInstruction() { + const SpvOp opcode = SpvOp(inst_.opcode); + + if (inst_.result_id) { + // Collect ids local to the current function. + if (cur_function_id_){ + ids_local_to_cur_function_.push_back(inst_.result_id); } - } else if (operand.number_bit_width == 16) { - const uint16_t word = - static_cast(instruction.word(operand.offset)); - if (operand.number_kind == SPV_NUMBER_UNSIGNED_INT) { - writer_.WriteVariableWidthU16(word, model_->u16_chunk_length()); - } else if (operand.number_kind == SPV_NUMBER_SIGNED_INT) { - int16_t val = 0; - std::memcpy(&val, &word, 2); - writer_.WriteVariableWidthS16(val, model_->s16_chunk_length(), - model_->s16_block_exponent()); - } else if (operand.number_kind == SPV_NUMBER_FLOATING) { - // TODO(atgoo@github.com) Write only 16 bits. - writer_.WriteUnencoded(word); - } else { - assert(0); + + // Starting new function. + if (opcode == SpvOpFunction) { + cur_function_id_ = inst_.result_id; + cur_function_return_type_ = inst_.type_id; + multi_mtf_.Insert(GetMtfFunctionWithReturnType(inst_.type_id), + inst_.result_id); + + // Store function parameter types in a queue, so that we know which types + // to expect in the following OpFunctionParameter instructions. + const Instruction* def_inst = GetDefInst(inst_.words[4]); + assert(def_inst); + assert(def_inst->opcode() == SpvOpTypeFunction); + for (uint32_t i = 3; i < def_inst->words().size(); ++i) { + remaining_function_parameter_types_.push_back(def_inst->word(i)); + } } + } + + // Remove local ids from MTFs if function end. + if (opcode == SpvOpFunctionEnd) { + cur_function_id_ = 0; + for (uint32_t id : ids_local_to_cur_function_) + multi_mtf_.RemoveFromAll(id); + ids_local_to_cur_function_.clear(); + assert(remaining_function_parameter_types_.empty()); + } + + if (!inst_.result_id) + return; + + { + // Save the result ID to type ID mapping. + // In the grammar, type ID always appears before result ID. + // A regular value maps to its type. Some instructions (e.g. OpLabel) + // have no type Id, and will map to 0. The result Id for a + // type-generating instruction (e.g. OpTypeInt) maps to itself. + auto insertion_result = id_to_type_id_.emplace( + inst_.result_id, + spvOpcodeGeneratesType(SpvOp(inst_.opcode)) ? + inst_.result_id : inst_.type_id); + (void)insertion_result; + assert(insertion_result.second); + } + + // Add result_id to MTFs. + + switch (opcode) { + case SpvOpTypeFloat: + case SpvOpTypeInt: + case SpvOpTypeBool: + case SpvOpTypeVector: + case SpvOpTypePointer: + case SpvOpExtInstImport: + case SpvOpTypeSampledImage: + case SpvOpTypeImage: + case SpvOpTypeSampler: + multi_mtf_.Insert(GetMtfIdGeneratedByOpcode(opcode), inst_.result_id); + break; + default: + break; + } + + if (spvOpcodeIsComposite(opcode)) { + multi_mtf_.Insert(kMtfTypeComposite, inst_.result_id); + } + + if (opcode == SpvOpLabel) { + multi_mtf_.InsertOrPromote(kMtfLabel, inst_.result_id); + } + + if (opcode == SpvOpTypeInt) { + multi_mtf_.Insert(kMtfTypeScalar, inst_.result_id); + multi_mtf_.Insert(kMtfTypeIntScalarOrVector, inst_.result_id); + } + + if (opcode == SpvOpTypeFloat) { + multi_mtf_.Insert(kMtfTypeScalar, inst_.result_id); + multi_mtf_.Insert(kMtfTypeFloatScalarOrVector, inst_.result_id); + } + + if (opcode == SpvOpTypeBool) { + multi_mtf_.Insert(kMtfTypeScalar, inst_.result_id); + multi_mtf_.Insert(kMtfTypeBoolScalarOrVector, inst_.result_id); + } + + if (opcode == SpvOpTypeVector) { + const uint32_t component_type_id = inst_.words[2]; + const uint32_t size = inst_.words[3]; + if (multi_mtf_.HasValue(GetMtfIdGeneratedByOpcode(SpvOpTypeFloat), + component_type_id)) { + multi_mtf_.Insert(kMtfTypeFloatScalarOrVector, inst_.result_id); + } else if (multi_mtf_.HasValue(GetMtfIdGeneratedByOpcode(SpvOpTypeInt), + component_type_id)) { + multi_mtf_.Insert(kMtfTypeIntScalarOrVector, inst_.result_id); + } else if (multi_mtf_.HasValue(GetMtfIdGeneratedByOpcode(SpvOpTypeBool), + component_type_id)) { + multi_mtf_.Insert(kMtfTypeBoolScalarOrVector, inst_.result_id); + } + multi_mtf_.Insert(GetMtfTypeVectorOfSize(size), inst_.result_id); + } + + if (inst_.opcode == SpvOpTypeFunction) { + const uint32_t return_type = inst_.words[2]; + multi_mtf_.Insert(kMtfTypeReturnedByFunction, return_type); + multi_mtf_.Insert(GetMtfFunctionTypeWithReturnType(return_type), + inst_.result_id); + } + + if (inst_.type_id) { + const Instruction* type_inst = GetDefInst(inst_.type_id); + assert(type_inst); + + multi_mtf_.Insert(kMtfObject, inst_.result_id); + + multi_mtf_.Insert(GetMtfIdOfType(inst_.type_id), inst_.result_id); + + if (multi_mtf_.HasValue(kMtfTypeFloatScalarOrVector, inst_.type_id)) { + multi_mtf_.Insert(kMtfFloatScalarOrVector, inst_.result_id); + } + + if (multi_mtf_.HasValue(kMtfTypeIntScalarOrVector, inst_.type_id)) + multi_mtf_.Insert(kMtfIntScalarOrVector, inst_.result_id); + + if (multi_mtf_.HasValue(kMtfTypeBoolScalarOrVector, inst_.type_id)) + multi_mtf_.Insert(kMtfBoolScalarOrVector, inst_.result_id); + + if (multi_mtf_.HasValue(kMtfTypeComposite, inst_.type_id)) + multi_mtf_.Insert(kMtfComposite, inst_.result_id); + + if (inst_.opcode == SpvOpConstant) { + if (multi_mtf_.HasValue( + GetMtfIdGeneratedByOpcode(SpvOpTypeInt), inst_.type_id)) { + multi_mtf_.Insert(kMtfConstInteger, inst_.result_id); + const uint32_t presumed_index = inst_.words[3]; + if (presumed_index <= kMarkvMaxPresumedAccessIndex) { + const auto result = + presumed_index_to_id_.emplace(presumed_index, inst_.result_id); + if (result.second) { + id_to_presumed_index_.emplace(inst_.result_id, presumed_index); + } + } + } + } + + switch (type_inst->opcode()) { + case SpvOpTypeInt: + case SpvOpTypeBool: + case SpvOpTypePointer: + case SpvOpTypeVector: + case SpvOpTypeImage: + case SpvOpTypeSampledImage: + case SpvOpTypeSampler: + multi_mtf_.Insert(GetMtfIdWithTypeGeneratedByOpcode( + type_inst->opcode()), inst_.result_id); + break; + default: + break; + } + + if (type_inst->opcode() == SpvOpTypeVector) { + const uint32_t component_type = type_inst->word(2); + multi_mtf_.Insert(GetMtfVectorOfComponentType(component_type), + inst_.result_id); + } + + if (type_inst->opcode() == SpvOpTypePointer) { + assert(type_inst->operands().size() > 2); + assert(type_inst->words().size() > type_inst->operands()[2].offset); + const uint32_t data_type = + type_inst->word(type_inst->operands()[2].offset); + multi_mtf_.Insert(GetMtfPointerToType(data_type), inst_.result_id); + + if (multi_mtf_.HasValue(kMtfTypeComposite, data_type)) + multi_mtf_.Insert(kMtfTypePointerToComposite, inst_.result_id); + } + } + + if (spvOpcodeGeneratesType(opcode)) { + if (opcode != SpvOpTypeFunction) { + multi_mtf_.Insert(kMtfTypeNonFunction, inst_.result_id); + } + } + + const uint32_t descriptor = id_descriptors_.ProcessInstruction(inst_); + + multi_mtf_.Insert(GetMtfIdDescriptor(descriptor), inst_.result_id); +} + +uint64_t MarkvCodecBase::GetRuleBasedMtf() { + // This function is only called for id operands (but not result ids). + assert(spvIsIdType(operand_.type) || + operand_.type == SPV_OPERAND_TYPE_OPTIONAL_ID); + assert(operand_.type != SPV_OPERAND_TYPE_RESULT_ID); + + const SpvOp opcode = static_cast(inst_.opcode); + + // All operand slots which expect label id. + if ((inst_.opcode == SpvOpLoopMerge && operand_index_ <= 1) || + (inst_.opcode == SpvOpSelectionMerge && operand_index_ == 0) || + (inst_.opcode == SpvOpBranch && operand_index_ == 0) || + (inst_.opcode == SpvOpBranchConditional && + (operand_index_ == 1 || operand_index_ == 2 )) || + (inst_.opcode == SpvOpPhi && operand_index_ >= 3 && + operand_index_ % 2 == 1) || + (inst_.opcode == SpvOpSwitch && operand_index_ > 0)) { + return kMtfLabel; + } + + switch (opcode) { + case SpvOpFAdd: + case SpvOpFSub: + case SpvOpFMul: + case SpvOpFDiv: + case SpvOpFRem: + case SpvOpFMod: + case SpvOpFNegate: { + if (operand_index_ == 0) + return kMtfTypeFloatScalarOrVector; + + return GetMtfIdOfType(inst_.type_id); + } + + case SpvOpISub: + case SpvOpIAdd: + case SpvOpIMul: + case SpvOpSDiv: + case SpvOpUDiv: + case SpvOpSMod: + case SpvOpUMod: + case SpvOpSRem: + case SpvOpSNegate: { + if (operand_index_ == 0) + return kMtfTypeIntScalarOrVector; + + return kMtfIntScalarOrVector; + } + + // TODO(atgoo@github.com) Add OpConvertFToU and other opcodes. + + case SpvOpFOrdEqual: + case SpvOpFUnordEqual: + case SpvOpFOrdNotEqual: + case SpvOpFUnordNotEqual: + case SpvOpFOrdLessThan: + case SpvOpFUnordLessThan: + case SpvOpFOrdGreaterThan: + case SpvOpFUnordGreaterThan: + case SpvOpFOrdLessThanEqual: + case SpvOpFUnordLessThanEqual: + case SpvOpFOrdGreaterThanEqual: + case SpvOpFUnordGreaterThanEqual: { + if (operand_index_ == 0) + return kMtfTypeBoolScalarOrVector; + if (operand_index_ == 2) + return kMtfFloatScalarOrVector; + if (operand_index_ == 3) { + const uint32_t first_operand_id = GetInstWords()[3]; + const uint32_t first_operand_type = + id_to_type_id_.at(first_operand_id); + return GetMtfIdOfType(first_operand_type); + } + break; + } + + case SpvOpVectorShuffle: { + if (operand_index_ == 0) { + assert(inst_.num_operands > 4); + return GetMtfTypeVectorOfSize(inst_.num_operands - 4); + } + + assert(inst_.type_id); + if (operand_index_ == 2 || operand_index_ == 3) + return GetMtfVectorOfComponentType( + GetVectorComponentType(inst_.type_id)); + break; + } + + case SpvOpVectorTimesScalar: { + if (operand_index_ == 0) + return GetMtfIdGeneratedByOpcode(SpvOpTypeVector); + + assert(inst_.type_id); + if (operand_index_ == 2) + return GetMtfIdOfType(inst_.type_id); + if (operand_index_ == 3) + return GetMtfIdOfType(GetVectorComponentType(inst_.type_id)); + break; + } + + case SpvOpDot: { + if (operand_index_ == 0) + return GetMtfIdGeneratedByOpcode(SpvOpTypeFloat); + + assert(inst_.type_id); + if (operand_index_ == 2) + return GetMtfVectorOfComponentType(inst_.type_id); + if (operand_index_ == 3) { + const uint32_t vector_id = GetInstWords()[3]; + const uint32_t vector_type = id_to_type_id_.at(vector_id); + return GetMtfIdOfType(vector_type); + } + break; + } + + case SpvOpTypeVector: { + if (operand_index_ == 1) { + return kMtfTypeScalar; + } + break; + } + + case SpvOpTypeMatrix: { + if (operand_index_ == 1) { + return GetMtfIdGeneratedByOpcode(SpvOpTypeVector); + } + break; + } + + case SpvOpTypePointer: { + if (operand_index_ == 2) { + return kMtfTypeNonFunction; + } + break; + } + + case SpvOpTypeStruct: { + if (operand_index_ >= 1) { + return kMtfTypeNonFunction; + } + break; + } + + case SpvOpTypeFunction: { + if (operand_index_ == 1) { + return kMtfTypeNonFunction; + } + + if (operand_index_ >= 2) { + return kMtfTypeNonFunction; + } + break; + } + + case SpvOpLoad: { + if (operand_index_ == 0) + return kMtfTypeNonFunction; + + if (operand_index_ == 2) { + assert(inst_.type_id); + return GetMtfPointerToType(inst_.type_id); + } + break; + } + + case SpvOpStore: { + if (operand_index_ == 0) + return GetMtfIdWithTypeGeneratedByOpcode(SpvOpTypePointer); + if (operand_index_ == 1) { + const uint32_t pointer_id = GetInstWords()[1]; + const uint32_t pointer_type = id_to_type_id_.at(pointer_id); + const auto it = vstate_.all_definitions().find(pointer_type); + assert(it != vstate_.all_definitions().end()); + const Instruction* pointer_inst = it->second; + + assert(pointer_inst->opcode() == SpvOpTypePointer); + const uint32_t data_type = + pointer_inst->word(pointer_inst->operands()[2].offset); + return GetMtfIdOfType(data_type); + } + break; + } + + case SpvOpVariable: { + if (operand_index_ == 0) + return GetMtfIdGeneratedByOpcode(SpvOpTypePointer); + break; + } + + case SpvOpAccessChain: { + if (operand_index_ == 0) + return GetMtfIdGeneratedByOpcode(SpvOpTypePointer); + if (operand_index_ == 2) + return kMtfTypePointerToComposite; + if (operand_index_ >= 3) + return GetMtfIdWithTypeGeneratedByOpcode(SpvOpTypeInt); + break; + } + + case SpvOpCompositeConstruct: { + if (operand_index_ == 0) + return kMtfTypeComposite; + if (operand_index_ >= 2) { + const uint32_t composite_type = GetInstWords()[1]; + if (multi_mtf_.HasValue(kMtfTypeFloatScalarOrVector, composite_type)) + return kMtfFloatScalarOrVector; + if (multi_mtf_.HasValue(kMtfTypeIntScalarOrVector, composite_type)) + return kMtfIntScalarOrVector; + if (multi_mtf_.HasValue(kMtfTypeBoolScalarOrVector, composite_type)) + return kMtfBoolScalarOrVector; + } + break; + } + + case SpvOpCompositeExtract: { + if (operand_index_ == 2) + return kMtfComposite; + break; + } + + case SpvOpConstantComposite: { + if (operand_index_ == 0) + return kMtfTypeComposite; + if (operand_index_ >= 2) { + const Instruction* composite_type_inst = GetDefInst(inst_.type_id); + assert(composite_type_inst); + if (composite_type_inst->opcode() == SpvOpTypeVector) { + return GetMtfIdOfType(composite_type_inst->word(2)); + } + } + break; + } + + case SpvOpExtInst: { + if (operand_index_ == 2) + return GetMtfIdGeneratedByOpcode(SpvOpExtInstImport); + if (operand_index_ >= 4) { + const uint32_t return_type = GetInstWords()[1]; + const uint32_t ext_inst_type = inst_.ext_inst_type; + const uint32_t ext_inst_index = GetInstWords()[4]; + // TODO(atgoo@github.com) The list of extended instructions is + // incomplete. Only common instructions and low-hanging fruits listed. + if (ext_inst_type == SPV_EXT_INST_TYPE_GLSL_STD_450) { + switch (ext_inst_index) { + case GLSLstd450FAbs: + case GLSLstd450FClamp: + case GLSLstd450FMax: + case GLSLstd450FMin: + case GLSLstd450FMix: + case GLSLstd450Step: + case GLSLstd450SmoothStep: + case GLSLstd450Fma: + case GLSLstd450Pow: + case GLSLstd450Exp: + case GLSLstd450Exp2: + case GLSLstd450Log: + case GLSLstd450Log2: + case GLSLstd450Sqrt: + case GLSLstd450InverseSqrt: + case GLSLstd450Fract: + case GLSLstd450Floor: + case GLSLstd450Ceil: + case GLSLstd450Radians: + case GLSLstd450Degrees: + case GLSLstd450Sin: + case GLSLstd450Cos: + case GLSLstd450Tan: + case GLSLstd450Sinh: + case GLSLstd450Cosh: + case GLSLstd450Tanh: + case GLSLstd450Asin: + case GLSLstd450Acos: + case GLSLstd450Atan: + case GLSLstd450Atan2: + case GLSLstd450Asinh: + case GLSLstd450Acosh: + case GLSLstd450Atanh: + case GLSLstd450MatrixInverse: + case GLSLstd450Cross: + case GLSLstd450Normalize: + case GLSLstd450Reflect: + case GLSLstd450FaceForward: + return GetMtfIdOfType(return_type); + case GLSLstd450Length: + case GLSLstd450Distance: + case GLSLstd450Refract: + return kMtfFloatScalarOrVector; + default: + break; + } + } else if (ext_inst_type == SPV_EXT_INST_TYPE_OPENCL_STD) { + switch (ext_inst_index) { + case OpenCLLIB::Fabs: + case OpenCLLIB::FClamp: + case OpenCLLIB::Fmax: + case OpenCLLIB::Fmin: + case OpenCLLIB::Step: + case OpenCLLIB::Smoothstep: + case OpenCLLIB::Fma: + case OpenCLLIB::Pow: + case OpenCLLIB::Exp: + case OpenCLLIB::Exp2: + case OpenCLLIB::Log: + case OpenCLLIB::Log2: + case OpenCLLIB::Sqrt: + case OpenCLLIB::Rsqrt: + case OpenCLLIB::Fract: + case OpenCLLIB::Floor: + case OpenCLLIB::Ceil: + case OpenCLLIB::Radians: + case OpenCLLIB::Degrees: + case OpenCLLIB::Sin: + case OpenCLLIB::Cos: + case OpenCLLIB::Tan: + case OpenCLLIB::Sinh: + case OpenCLLIB::Cosh: + case OpenCLLIB::Tanh: + case OpenCLLIB::Asin: + case OpenCLLIB::Acos: + case OpenCLLIB::Atan: + case OpenCLLIB::Atan2: + case OpenCLLIB::Asinh: + case OpenCLLIB::Acosh: + case OpenCLLIB::Atanh: + case OpenCLLIB::Cross: + case OpenCLLIB::Normalize: + return GetMtfIdOfType(return_type); + case OpenCLLIB::Length: + case OpenCLLIB::Distance: + return kMtfFloatScalarOrVector; + default: + break; + } + } + } + break; + } + + case SpvOpFunction: { + if (operand_index_ == 0) + return kMtfTypeReturnedByFunction; + + if (operand_index_ == 3) { + const uint32_t return_type = GetInstWords()[1]; + return GetMtfFunctionTypeWithReturnType(return_type); + } + break; + } + + case SpvOpFunctionCall: { + if (operand_index_ == 0) + return kMtfTypeReturnedByFunction; + + if (operand_index_ == 2) { + const uint32_t return_type = GetInstWords()[1]; + return GetMtfFunctionWithReturnType(return_type); + } + + if (operand_index_ >= 3) { + const uint32_t function_id = GetInstWords()[3]; + const auto function_it = vstate_.all_definitions().find(function_id); + if (function_it == vstate_.all_definitions().end()) + return kMtfObject; + + const Instruction* function_inst = function_it->second; + assert(function_inst->opcode() == SpvOpFunction); + + const uint32_t function_type_id = function_inst->word(4); + const auto function_type_it = + vstate_.all_definitions().find(function_type_id); + assert(function_type_it != vstate_.all_definitions().end()); + const Instruction* function_type_inst = function_type_it->second; + assert(function_type_inst->opcode() == SpvOpTypeFunction); + + const uint32_t argument_type = + function_type_inst->word(operand_index_); + return GetMtfIdOfType(argument_type); + } + break; + } + + case SpvOpReturnValue: { + if (operand_index_ == 0) + return GetMtfIdOfType(cur_function_return_type_); + break; + } + + case SpvOpBranchConditional: { + if (operand_index_ == 0) + return GetMtfIdWithTypeGeneratedByOpcode(SpvOpTypeBool); + break; + } + + case SpvOpSampledImage: { + if (operand_index_ == 0) + return GetMtfIdGeneratedByOpcode(SpvOpTypeSampledImage); + if (operand_index_ == 2) + return GetMtfIdWithTypeGeneratedByOpcode(SpvOpTypeImage); + if (operand_index_ == 3) + return GetMtfIdWithTypeGeneratedByOpcode(SpvOpTypeSampler); + break; + } + + case SpvOpImageSampleImplicitLod: { + if (operand_index_ == 0) + return GetMtfIdGeneratedByOpcode(SpvOpTypeVector); + if (operand_index_ == 2) + return GetMtfIdWithTypeGeneratedByOpcode(SpvOpTypeSampledImage); + if (operand_index_ == 3) + return GetMtfIdWithTypeGeneratedByOpcode(SpvOpTypeVector); + break; + } + + default: + break; + } + + return kMtfNone; +} + +spv_result_t MarkvEncoder::EncodeNonIdWord(uint32_t word) { + auto* codec = model_->GetNonIdWordHuffmanCodec(inst_.opcode, operand_index_); + + if (codec) { + uint64_t bits = 0; + size_t num_bits = 0; + if (codec->Encode(word, &bits, &num_bits)) { + // Encoding successful. + writer_.WriteBits(bits, num_bits); + return SPV_SUCCESS; + } else { + // Encoding failed, write kMarkvNoneOfTheAbove flag. + if (!codec->Encode(kMarkvNoneOfTheAbove, &bits, &num_bits)) + return vstate_.diag(SPV_ERROR_INTERNAL) + << "Non-id word Huffman table for " + << spvOpcodeString(SpvOp(inst_.opcode)) + << " operand index " << operand_index_ + << " is missing kMarkvNoneOfTheAbove"; + writer_.WriteBits(bits, num_bits); + } + } + + // Fallback encoding. + const size_t chunk_length = GetOperandVariableWidthChunkLength(operand_.type); + if (chunk_length) { + writer_.WriteVariableWidthU32(word, chunk_length); } else { - assert(operand.number_bit_width == 64); + writer_.WriteUnencoded(word); + } + return SPV_SUCCESS; +} + +spv_result_t MarkvDecoder::DecodeNonIdWord(uint32_t* word) { + auto* codec = model_->GetNonIdWordHuffmanCodec(inst_.opcode, operand_index_); + + if (codec) { + uint64_t decoded_value = 0; + if (!codec->DecodeFromStream(GetReadBitCallback(), &decoded_value)) + return vstate_.diag(SPV_ERROR_INVALID_BINARY) + << "Failed to decode non-id word with Huffman"; + + if (decoded_value != kMarkvNoneOfTheAbove) { + // The word decoded successfully. + *word = uint32_t(decoded_value); + assert(*word == decoded_value); + return SPV_SUCCESS; + } + + // Received kMarkvNoneOfTheAbove signal, use fallback decoding. + } + + const size_t chunk_length = GetOperandVariableWidthChunkLength(operand_.type); + if (chunk_length) { + if (!reader_.ReadVariableWidthU32(word, chunk_length)) + return vstate_.diag(SPV_ERROR_INVALID_BINARY) + << "Failed to decode non-id word with varint"; + } else { + if (!reader_.ReadUnencoded(word)) + return vstate_.diag(SPV_ERROR_INVALID_BINARY) + << "Failed to read unencoded non-id word"; + } + return SPV_SUCCESS; +} + +spv_result_t MarkvEncoder::EncodeOpcodeAndNumOperands( + uint32_t opcode, uint32_t num_operands) { + uint64_t bits = 0; + size_t num_bits = 0; + + const uint32_t word = opcode | (num_operands << 16); + + // First try to use the Markov chain codec. + auto* codec = model_->GetOpcodeAndNumOperandsMarkovHuffmanCodec(GetPrevOpcode()); + if (codec) { + if (codec->Encode(word, &bits, &num_bits)) { + // The word was successfully encoded into bits/num_bits. + writer_.WriteBits(bits, num_bits); + return SPV_SUCCESS; + } else { + // The word is not in the Huffman table. Write kMarkvNoneOfTheAbove + // and use fallback encoding. + if (!codec->Encode(kMarkvNoneOfTheAbove, &bits, &num_bits)) + return vstate_.diag(SPV_ERROR_INTERNAL) + << "opcode_and_num_operands Huffman table for " + << spvOpcodeString(GetPrevOpcode()) + << "is missing kMarkvNoneOfTheAbove"; + writer_.WriteBits(bits, num_bits); + } + } + + // Fallback to base-rate codec. + codec = model_->GetOpcodeAndNumOperandsMarkovHuffmanCodec(SpvOpNop); + assert(codec); + if (codec->Encode(word, &bits, &num_bits)) { + // The word was successfully encoded into bits/num_bits. + writer_.WriteBits(bits, num_bits); + return SPV_SUCCESS; + } else { + // The word is not in the Huffman table. Write kMarkvNoneOfTheAbove + // and return false. + if (!codec->Encode(kMarkvNoneOfTheAbove, &bits, &num_bits)) + return vstate_.diag(SPV_ERROR_INTERNAL) + << "Global opcode_and_num_operands Huffman table is missing " + << "kMarkvNoneOfTheAbove"; + writer_.WriteBits(bits, num_bits); + return SPV_UNSUPPORTED; + } +} + +spv_result_t MarkvDecoder::DecodeOpcodeAndNumberOfOperands( + uint32_t* opcode, uint32_t* num_operands) { + // First try to use the Markov chain codec. + auto* codec = model_->GetOpcodeAndNumOperandsMarkovHuffmanCodec(GetPrevOpcode()); + if (codec) { + uint64_t decoded_value = 0; + if (!codec->DecodeFromStream(GetReadBitCallback(), &decoded_value)) + return vstate_.diag(SPV_ERROR_INTERNAL) + << "Failed to decode opcode_and_num_operands, previous opcode is " + << spvOpcodeString(GetPrevOpcode()); + + if (decoded_value != kMarkvNoneOfTheAbove) { + // The word was successfully decoded. + *opcode = uint32_t(decoded_value & 0xFFFF); + *num_operands = uint32_t(decoded_value >> 16); + return SPV_SUCCESS; + } + + // Received kMarkvNoneOfTheAbove signal, use fallback decoding. + } + + // Fallback to base-rate codec. + codec = model_->GetOpcodeAndNumOperandsMarkovHuffmanCodec(SpvOpNop); + assert(codec); + uint64_t decoded_value = 0; + if (!codec->DecodeFromStream(GetReadBitCallback(), &decoded_value)) + return vstate_.diag(SPV_ERROR_INTERNAL) + << "Failed to decode opcode_and_num_operands with global codec"; + + if (decoded_value == kMarkvNoneOfTheAbove) { + // Received kMarkvNoneOfTheAbove signal, fallback further. + return SPV_UNSUPPORTED; + } + + *opcode = uint32_t(decoded_value & 0xFFFF); + *num_operands = uint32_t(decoded_value >> 16); + return SPV_SUCCESS; +} + +spv_result_t MarkvEncoder::EncodeMtfRankHuffman(uint32_t rank, uint64_t mtf, + uint64_t fallback_method) { + const auto* codec = model_->GetMtfHuffmanCodec(mtf); + if (!codec) { + assert(fallback_method != kMtfNone); + codec = model_->GetMtfHuffmanCodec(fallback_method); + } + + if (!codec) + return vstate_.diag(SPV_ERROR_INTERNAL) << "No codec to encode MTF rank"; + + uint64_t bits = 0; + size_t num_bits = 0; + if (rank < kMtfSmallestRankEncodedByValue) { + // Encode using Huffman coding. + if (!codec->Encode(rank, &bits, &num_bits)) + return vstate_.diag(SPV_ERROR_INTERNAL) + << "Failed to encode MTF rank with Huffman"; + + writer_.WriteBits(bits, num_bits); + } else { + // Encode by value. + if (!codec->Encode(kMtfRankEncodedByValueSignal, &bits, &num_bits)) + return vstate_.diag(SPV_ERROR_INTERNAL) + << "Failed to encode kMtfRankEncodedByValueSignal"; + + writer_.WriteBits(bits, num_bits); + writer_.WriteVariableWidthU32(rank - kMtfSmallestRankEncodedByValue, + model_->mtf_rank_chunk_length()); + } + return SPV_SUCCESS; +} + +spv_result_t MarkvDecoder::DecodeMtfRankHuffman( + uint64_t mtf, uint32_t fallback_method, uint32_t* rank) { + const auto* codec = model_->GetMtfHuffmanCodec(mtf); + if (!codec) { + assert(fallback_method != kMtfNone); + codec = model_->GetMtfHuffmanCodec(fallback_method); + } + + if (!codec) + return vstate_.diag(SPV_ERROR_INTERNAL) << "No codec to decode MTF rank"; + + uint32_t decoded_value = 0; + if (!codec->DecodeFromStream(GetReadBitCallback(), &decoded_value)) + return vstate_.diag(SPV_ERROR_INTERNAL) + << "Failed to decode MTF rank with Huffman"; + + if (decoded_value == kMtfRankEncodedByValueSignal) { + // Decode by value. + if (!reader_.ReadVariableWidthU32(rank, model_->mtf_rank_chunk_length())) + return vstate_.diag(SPV_ERROR_INTERNAL) + << "Failed to decode MTF rank with varint"; + *rank += kMtfSmallestRankEncodedByValue; + } else { + // Decode using Huffman coding. + assert(decoded_value < kMtfSmallestRankEncodedByValue); + *rank = decoded_value; + } + return SPV_SUCCESS; +} + +spv_result_t MarkvEncoder::EncodeIdWithDescriptor(uint32_t id) { + auto* codec = model_->GetIdDescriptorHuffmanCodec(inst_.opcode, + operand_index_); + if (!codec) + return SPV_UNSUPPORTED; + + uint64_t bits = 0; + size_t num_bits = 0; + + // Get the descriptor for id. + const uint32_t descriptor = id_descriptors_.GetDescriptor(id); + + if (descriptor && codec->Encode(descriptor, &bits, &num_bits)) { + // If the descriptor exists and is in the table, write the descriptor and + // proceed to encoding the rank. + writer_.WriteBits(bits, num_bits); + } else { + // The descriptor doesn't exist or we have no coding for it. Write + // kMarkvNoneOfTheAbove and go to fallback method. + if (!codec->Encode(kMarkvNoneOfTheAbove, &bits, &num_bits)) + return vstate_.diag(SPV_ERROR_INTERNAL) + << "Descriptor Huffman table for " + << spvOpcodeString(SpvOp(inst_.opcode)) + << " operand index " << operand_index_ + << " is missing kMarkvNoneOfTheAbove"; + + writer_.WriteBits(bits, num_bits); + return SPV_UNSUPPORTED; + } + + // Descriptor has been encoded. Now encode the rank of the id in the + // associated mtf sequence. + const uint64_t mtf = GetMtfIdDescriptor(descriptor); + return EncodeExistingId(mtf, id); +} + +spv_result_t MarkvDecoder::DecodeIdWithDescriptor(uint32_t* id) { + auto* codec = model_->GetIdDescriptorHuffmanCodec(inst_.opcode, + operand_index_); + if (!codec) + return SPV_UNSUPPORTED; + + uint64_t decoded_value = 0; + if (!codec->DecodeFromStream(GetReadBitCallback(), &decoded_value)) + return vstate_.diag(SPV_ERROR_INTERNAL) + << "Failed to decode descriptor with Huffman"; + + if (decoded_value == kMarkvNoneOfTheAbove) + return SPV_UNSUPPORTED; + + // If descriptor exists then the id was encoded through descriptor mtf. + const uint32_t descriptor = uint32_t(decoded_value); + assert(descriptor == decoded_value); + assert(descriptor); + + const uint64_t mtf = GetMtfIdDescriptor(descriptor); + return DecodeExistingId(mtf, id); +} + +spv_result_t MarkvEncoder::EncodeExistingId(uint64_t mtf, uint32_t id) { + assert(multi_mtf_.GetSize(mtf) > 0); + if (multi_mtf_.GetSize(mtf) == 1) { + // If the sequence has only one element no need to write rank, the decoder + // would make the same decision. + return SPV_SUCCESS; + } + + uint32_t rank = 0; + if (!multi_mtf_.RankFromValue(mtf, id, &rank)) + return vstate_.diag(SPV_ERROR_INTERNAL) + << "Id is not in the MTF sequence"; + + return EncodeMtfRankHuffman(rank, mtf, kMtfGenericNonZeroRank); +} + +spv_result_t MarkvDecoder::DecodeExistingId(uint64_t mtf, uint32_t* id) { + assert(multi_mtf_.GetSize(mtf) > 0); + *id = 0; + + uint32_t rank = 0; + + if (multi_mtf_.GetSize(mtf) == 1) { + rank = 1; + } else { + const spv_result_t result = + DecodeMtfRankHuffman(mtf, kMtfGenericNonZeroRank, &rank); + if (result != SPV_SUCCESS) + return result; + } + + assert(rank); + if (!multi_mtf_.ValueFromRank(mtf, rank, id)) + return vstate_.diag(SPV_ERROR_INTERNAL) + << "MTF rank is out of bounds"; + + return SPV_SUCCESS; +} + +spv_result_t MarkvEncoder::EncodeRefId(uint32_t id) { + // TODO(atgoo@github.com) This might not be needed as EncodeIdWithDescriptor + // can handle SpvOpAccessChain indices if enough statistics is collected. + if (inst_.opcode == SpvOpAccessChain && operand_index_ >= 3) { + const auto it = id_to_presumed_index_.find(id); + if (it != id_to_presumed_index_.end()) { + writer_.WriteBits(1, 1); + writer_.WriteFixedWidth(it->second, kMarkvMaxPresumedAccessIndex); + return SPV_SUCCESS; + } + + writer_.WriteBits(0, 1); + } + + { + // Try to encode using id descriptor mtfs. + const spv_result_t result = EncodeIdWithDescriptor(id); + if (result != SPV_UNSUPPORTED) + return result; + // If can't be done continue with other methods. + } + + // Encode using rule-based mtf. + uint64_t mtf = GetRuleBasedMtf(); + const bool can_forward_declare = + spvOperandCanBeForwardDeclaredFunction( + SpvOp(inst_.opcode))(operand_index_); + + if (mtf != kMtfNone && !can_forward_declare) { + assert(multi_mtf_.HasValue(kMtfAll, id)); + return EncodeExistingId(mtf, id); + } + + if (mtf == kMtfNone) + mtf = kMtfAll; + + uint32_t rank = 0; + + if (!multi_mtf_.RankFromValue(mtf, id, &rank)) { + // This is the first occurrence of a forward declared id. + multi_mtf_.Insert(kMtfAll, id); + multi_mtf_.Insert(kMtfForwardDeclared, id); + if (mtf != kMtfAll) + multi_mtf_.Insert(mtf, id); + rank = 0; + } + + return EncodeMtfRankHuffman(rank, mtf, kMtfAll); +} + +spv_result_t MarkvDecoder::DecodeRefId(uint32_t* id) { + if (inst_.opcode == SpvOpAccessChain && operand_index_ >= 3) { + uint64_t use_presumed_index_technique = 0; + if (!reader_.ReadBits(&use_presumed_index_technique, 1)) + return vstate_.diag(SPV_ERROR_INVALID_BINARY) + << "Failed to read use_presumed_index_technique flag"; + + if (use_presumed_index_technique) { + uint64_t value = 0; + if (!reader_.ReadFixedWidth(&value, kMarkvMaxPresumedAccessIndex)) + return vstate_.diag(SPV_ERROR_INVALID_BINARY) + << "Failed to read presumed_index"; + + const uint32_t presumed_index = static_cast(value); + + const auto it = presumed_index_to_id_.find(presumed_index); + if (it == presumed_index_to_id_.end()) { + assert(0); + return vstate_.diag(SPV_ERROR_INTERNAL) + << "Presumed index id not found"; + } + + *id = it->second; + return SPV_SUCCESS; + } + } + + { + const spv_result_t result = DecodeIdWithDescriptor(id); + if (result != SPV_UNSUPPORTED) + return result; + } + + uint64_t mtf = GetRuleBasedMtf(); + const bool can_forward_declare = + spvOperandCanBeForwardDeclaredFunction( + SpvOp(inst_.opcode))(operand_index_); + + if (mtf != kMtfNone && !can_forward_declare) { + return DecodeExistingId(mtf, id); + } + + if (mtf == kMtfNone) + mtf = kMtfAll; + + *id = 0; + + uint32_t rank = 0; + + { + const spv_result_t result = DecodeMtfRankHuffman(mtf, kMtfAll, &rank); + if (result != SPV_SUCCESS) + return result; + } + + if (rank == 0) { + // This is the first occurrence of a forward declared id. + *id = vstate_.getIdBound(); + vstate_.setIdBound(*id + 1); + multi_mtf_.Insert(kMtfAll, *id); + multi_mtf_.Insert(kMtfForwardDeclared, *id); + if (mtf != kMtfAll) + multi_mtf_.Insert(mtf, *id); + } else { + if (!multi_mtf_.ValueFromRank(mtf, rank, id)) + return vstate_.diag(SPV_ERROR_INTERNAL) << "MTF rank out of bounds"; + } + + assert(*id); + return SPV_SUCCESS; +} + +spv_result_t MarkvEncoder::EncodeTypeId() { + if (inst_.opcode == SpvOpFunctionParameter) { + assert(!remaining_function_parameter_types_.empty()); + assert(inst_.type_id == remaining_function_parameter_types_.front()); + remaining_function_parameter_types_.pop_front(); + return SPV_SUCCESS; + } + + { + // Try to encode using id descriptor mtfs. + const spv_result_t result = EncodeIdWithDescriptor(inst_.type_id); + if (result != SPV_UNSUPPORTED) + return result; + // If can't be done continue with other methods. + } + + uint64_t mtf = GetRuleBasedMtf(); + assert(!spvOperandCanBeForwardDeclaredFunction( + SpvOp(inst_.opcode))(operand_index_)); + + if (mtf == kMtfNone) { + mtf = kMtfTypeNonFunction; + // Function types should have been handled by GetRuleBasedMtf. + assert(inst_.opcode != SpvOpFunction); + } + + return EncodeExistingId(mtf, inst_.type_id); +} + +spv_result_t MarkvDecoder::DecodeTypeId() { + if (inst_.opcode == SpvOpFunctionParameter) { + assert(!remaining_function_parameter_types_.empty()); + inst_.type_id = remaining_function_parameter_types_.front(); + remaining_function_parameter_types_.pop_front(); + return SPV_SUCCESS; + } + + { + const spv_result_t result = DecodeIdWithDescriptor(&inst_.type_id); + if (result != SPV_UNSUPPORTED) + return result; + } + + uint64_t mtf = GetRuleBasedMtf(); + assert(!spvOperandCanBeForwardDeclaredFunction( + SpvOp(inst_.opcode))(operand_index_)); + + if (mtf == kMtfNone) { + mtf = kMtfTypeNonFunction; + // Function types should have been handled by GetRuleBasedMtf. + assert(inst_.opcode != SpvOpFunction); + } + + return DecodeExistingId(mtf, &inst_.type_id); +} + +spv_result_t MarkvEncoder::EncodeResultId() { + uint32_t rank = 0; + + const uint64_t num_still_forward_declared = + multi_mtf_.GetSize(kMtfForwardDeclared); + + if (num_still_forward_declared) { + // We write the rank only if kMtfForwardDeclared is not empty. If it is + // empty the decoder knows that there are no forward declared ids to expect. + if (multi_mtf_.RankFromValue(kMtfForwardDeclared, + inst_.result_id, &rank)) { + // This is a definition of a forward declared id. We can remove the id + // from kMtfForwardDeclared. + if (!multi_mtf_.Remove(kMtfForwardDeclared, inst_.result_id)) + return vstate_.diag(SPV_ERROR_INTERNAL) + << "Failed to remove id from kMtfForwardDeclared"; + writer_.WriteBits(1, 1); + writer_.WriteVariableWidthU32( + rank, model_->mtf_rank_chunk_length()); + } else { + rank = 0; + writer_.WriteBits(0, 1); + } + } + + if (!rank) { + multi_mtf_.Insert(kMtfAll, inst_.result_id); + } + + return SPV_SUCCESS; +} + +spv_result_t MarkvDecoder::DecodeResultId() { + uint32_t rank = 0; + + const uint64_t num_still_forward_declared = + multi_mtf_.GetSize(kMtfForwardDeclared); + + if (num_still_forward_declared) { + // Some ids were forward declared. Check if this id is one of them. + uint64_t id_was_forward_declared; + if (!reader_.ReadBits(&id_was_forward_declared, 1)) + return vstate_.diag(SPV_ERROR_INVALID_BINARY) + << "Failed to read id_was_forward_declared flag"; + + if (id_was_forward_declared) { + if (!reader_.ReadVariableWidthU32( + &rank, model_->mtf_rank_chunk_length())) + return vstate_.diag(SPV_ERROR_INVALID_BINARY) + << "Failed to read MTF rank of forward declared id"; + + if (rank) { + // The id was forward declared, recover it from kMtfForwardDeclared. + if (!multi_mtf_.ValueFromRank(kMtfForwardDeclared, + rank, &inst_.result_id)) + return vstate_.diag(SPV_ERROR_INTERNAL) + << "Forward declared MTF rank is out of bounds"; + + // We can now remove the id from kMtfForwardDeclared. + if (!multi_mtf_.Remove(kMtfForwardDeclared, inst_.result_id)) + return vstate_.diag(SPV_ERROR_INTERNAL) + << "Failed to remove id from kMtfForwardDeclared"; + } + } + } + + if (inst_.result_id == 0) { + // The id was not forward declared, issue a new id. + inst_.result_id = vstate_.getIdBound(); + vstate_.setIdBound(inst_.result_id + 1); + } + + if (!rank) { + multi_mtf_.Insert(kMtfAll, inst_.result_id); + } + + return SPV_SUCCESS; +} + +spv_result_t MarkvEncoder::EncodeLiteralNumber( + const Instruction& instruction, const spv_parsed_operand_t& operand) { + if (operand.number_bit_width <= 32) { + const uint32_t word = instruction.word(operand.offset); + return EncodeNonIdWord(word); + } else { + assert(operand.number_bit_width <= 64); const uint64_t word = uint64_t(instruction.word(operand.offset)) | (uint64_t(instruction.word(operand.offset + 1)) << 32); @@ -728,141 +2207,22 @@ void MarkvEncoder::EncodeLiteralNumber(const Instruction& instruction, } else if (operand.number_kind == SPV_NUMBER_FLOATING) { writer_.WriteUnencoded(word); } else { - assert(0); + return vstate_.diag(SPV_ERROR_INTERNAL) << "Unsupported bit length"; } } -} - -spv_result_t MarkvEncoder::EncodeInstruction( - const spv_parsed_instruction_t& inst) { - const spv_result_t validation_result = UpdateValidationState(inst); - if (validation_result != SPV_SUCCESS) - return validation_result; - - bool result_id_was_forward_declared = false; - if (all_known_ids_.count(inst.result_id)) { - // Result id of the instruction was forward declared. - // Write a service opcode to signal this to the decoder. - writer_.WriteVariableWidthU32(kMarkvOpNextInstructionEncodesResultId, - model_->opcode_chunk_length()); - result_id_was_forward_declared = true; - } - - const Instruction& instruction = GetCurrentInstruction(); - const auto& operands = instruction.operands(); - - LogDisassemblyInstruction(); - - // Write opcode. - writer_.WriteVariableWidthU32(inst.opcode, model_->opcode_chunk_length()); - - if (!OpcodeHasFixedNumberOfOperands(SpvOp(inst.opcode))) { - // If the opcode has a variable number of operands, encode the number of - // operands with the instruction. - - if (logger_) - logger_->AppendWhitespaces(kCommentNumWhitespaces); - - writer_.WriteVariableWidthU16(inst.num_operands, - model_->num_operands_chunk_length()); - } - - // Write operands. - for (const auto& operand : operands) { - if (operand.type == SPV_OPERAND_TYPE_RESULT_ID && - !result_id_was_forward_declared) { - // Register the id, but don't encode it. - GetIdIndex(instruction.word(operand.offset)); - continue; - } - - if (logger_) - logger_->AppendWhitespaces(kCommentNumWhitespaces); - - if (operand.type == SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER) { - EncodeLiteralNumber(instruction, operand); - } else if (operand.type == SPV_OPERAND_TYPE_LITERAL_STRING) { - const char* src = - reinterpret_cast(&instruction.words()[operand.offset]); - const size_t length = spv_strnlen_s(src, operand.num_words * 4); - if (length == operand.num_words * 4) - return vstate_.diag(SPV_ERROR_INVALID_BINARY) - << "Failed to find terminal character of literal string"; - for (size_t i = 0; i < length + 1; ++i) - writer_.WriteUnencoded(src[i]); - } else if (spvIsIdType(operand.type)) { - const uint16_t id_index = GetIdIndex(instruction.word(operand.offset)); - writer_.WriteVariableWidthU16(id_index, model_->id_index_chunk_length()); - } else { - for (int i = 0; i < operand.num_words; ++i) { - const uint32_t word = instruction.word(operand.offset + i); - EncodeOperandWord(operand.type, word); - } - } - } - - AddByteBreakIfAgreed(); - - if (logger_) { - logger_->NewLine(); - logger_->NewLine(); - } - return SPV_SUCCESS; } spv_result_t MarkvDecoder::DecodeLiteralNumber( const spv_parsed_operand_t& operand) { - if (operand.number_bit_width == 32) { + if (operand.number_bit_width <= 32) { uint32_t word = 0; - if (operand.number_kind == SPV_NUMBER_UNSIGNED_INT) { - if (!reader_.ReadVariableWidthU32(&word, model_->u32_chunk_length())) - return vstate_.diag(SPV_ERROR_INVALID_BINARY) - << "Failed to read literal U32"; - } else if (operand.number_kind == SPV_NUMBER_SIGNED_INT) { - int32_t val = 0; - if (!reader_.ReadVariableWidthS32(&val, model_->s32_chunk_length(), - model_->s32_block_exponent())) - return vstate_.diag(SPV_ERROR_INVALID_BINARY) - << "Failed to read literal S32"; - std::memcpy(&word, &val, 4); - } else if (operand.number_kind == SPV_NUMBER_FLOATING) { - if (!reader_.ReadUnencoded(&word)) - return vstate_.diag(SPV_ERROR_INVALID_BINARY) - << "Failed to read literal F32"; - } else { - assert(0); - } - spirv_.push_back(word); - } else if (operand.number_bit_width == 16) { - uint32_t word = 0; - if (operand.number_kind == SPV_NUMBER_UNSIGNED_INT) { - uint16_t val = 0; - if (!reader_.ReadVariableWidthU16(&val, model_->u16_chunk_length())) - return vstate_.diag(SPV_ERROR_INVALID_BINARY) - << "Failed to read literal U16"; - word = val; - } else if (operand.number_kind == SPV_NUMBER_SIGNED_INT) { - int16_t val = 0; - if (!reader_.ReadVariableWidthS16(&val, model_->s16_chunk_length(), - model_->s16_block_exponent())) - return vstate_.diag(SPV_ERROR_INVALID_BINARY) - << "Failed to read literal S16"; - // Int16 is stored as int32 in SPIR-V, not as bits. - int32_t val32 = val; - std::memcpy(&word, &val32, 4); - } else if (operand.number_kind == SPV_NUMBER_FLOATING) { - uint16_t word16 = 0; - if (!reader_.ReadUnencoded(&word16)) - return vstate_.diag(SPV_ERROR_INVALID_BINARY) - << "Failed to read literal F16"; - word = word16; - } else { - assert(0); - } - spirv_.push_back(word); + const spv_result_t result = DecodeNonIdWord(&word); + if (result != SPV_SUCCESS) + return result; + inst_words_.push_back(word); } else { - assert(operand.number_bit_width == 64); + assert(operand.number_bit_width <= 64); uint64_t word = 0; if (operand.number_kind == SPV_NUMBER_UNSIGNED_INT) { if (!reader_.ReadVariableWidthU64(&word, model_->u64_chunk_length())) @@ -880,14 +2240,191 @@ spv_result_t MarkvDecoder::DecodeLiteralNumber( return vstate_.diag(SPV_ERROR_INVALID_BINARY) << "Failed to read literal F64"; } else { - assert(0); + return vstate_.diag(SPV_ERROR_INTERNAL) << "Unsupported bit length"; } - spirv_.push_back(static_cast(word)); - spirv_.push_back(static_cast(word >> 32)); + inst_words_.push_back(static_cast(word)); + inst_words_.push_back(static_cast(word >> 32)); } return SPV_SUCCESS; } +void MarkvEncoder::AddByteBreak(size_t byte_break_if_less_than) { + const size_t num_bits_to_next_byte = + GetNumBitsToNextByte(writer_.GetNumBits()); + if (num_bits_to_next_byte == 0 || + num_bits_to_next_byte > byte_break_if_less_than) + return; + + if (logger_) { + logger_->AppendWhitespaces(kCommentNumWhitespaces); + logger_->AppendText(""); + } + + writer_.WriteBits(0, num_bits_to_next_byte); +} + +bool MarkvDecoder::ReadToByteBreak(size_t byte_break_if_less_than) { + const size_t num_bits_to_next_byte = + GetNumBitsToNextByte(reader_.GetNumReadBits()); + if (num_bits_to_next_byte == 0 || + num_bits_to_next_byte > byte_break_if_less_than) + return true; + + + uint64_t bits = 0; + if (!reader_.ReadBits(&bits, num_bits_to_next_byte)) + return false; + + assert(bits == 0); + if (bits != 0) + return false; + + return true; +} + +spv_result_t MarkvEncoder::EncodeInstruction( + const spv_parsed_instruction_t& inst) { + SpvOp opcode = SpvOp(inst.opcode); + inst_ = inst; + + const spv_result_t validation_result = UpdateValidationState(inst); + if (validation_result != SPV_SUCCESS) + return validation_result; + + const Instruction& instruction = vstate_.ordered_instructions().back(); + const auto& operands = instruction.operands(); + + LogDisassemblyInstruction(); + + const spv_result_t opcode_encodig_result = + EncodeOpcodeAndNumOperands(opcode, inst.num_operands); + if (opcode_encodig_result < 0) + return opcode_encodig_result; + + if (opcode_encodig_result != SPV_SUCCESS) { + // Fallback encoding for opcode and num_operands. + writer_.WriteVariableWidthU32(opcode, model_->opcode_chunk_length()); + + if (!OpcodeHasFixedNumberOfOperands(opcode)) { + // If the opcode has a variable number of operands, encode the number of + // operands with the instruction. + + if (logger_) + logger_->AppendWhitespaces(kCommentNumWhitespaces); + + writer_.WriteVariableWidthU16(inst.num_operands, + model_->num_operands_chunk_length()); + } + } + + // Write operands. + for (operand_index_ = 0; operand_index_ < operands.size(); ++operand_index_) { + operand_ = operands[operand_index_]; + + if (logger_) { + logger_->AppendWhitespaces(kCommentNumWhitespaces); + logger_->AppendText("<"); + logger_->AppendText(spvOperandTypeStr(operand_.type)); + logger_->AppendText(">"); + } + + switch (operand_.type) { + case SPV_OPERAND_TYPE_RESULT_ID: + case SPV_OPERAND_TYPE_TYPE_ID: + case SPV_OPERAND_TYPE_ID: + case SPV_OPERAND_TYPE_OPTIONAL_ID: + case SPV_OPERAND_TYPE_SCOPE_ID: + case SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID: { + const uint32_t id = instruction.word(operand_.offset); + if (operand_.type == SPV_OPERAND_TYPE_TYPE_ID) { + const spv_result_t result = EncodeTypeId(); + if (result != SPV_SUCCESS) + return result; + } else if (operand_.type == SPV_OPERAND_TYPE_RESULT_ID) { + const spv_result_t result = EncodeResultId(); + if (result != SPV_SUCCESS) + return result; + } else { + const spv_result_t result = EncodeRefId(id); + if (result != SPV_SUCCESS) + return result; + } + + multi_mtf_.Promote(id); + break; + } + + case SPV_OPERAND_TYPE_LITERAL_INTEGER: { + const spv_result_t result = + EncodeNonIdWord(instruction.word(operand_.offset)); + if (result != SPV_SUCCESS) + return result; + break; + } + + case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER: { + const spv_result_t result = EncodeLiteralNumber(instruction, operand_); + if (result != SPV_SUCCESS) + return result; + break; + } + + case SPV_OPERAND_TYPE_LITERAL_STRING: { + const char* src = reinterpret_cast( + &instruction.words()[operand_.offset]); + + auto* codec = model_->GetLiteralStringHuffmanCodec(opcode); + if (codec) { + uint64_t bits = 0; + size_t num_bits = 0; + const std::string str = reinterpret_cast( + &instruction.words()[operand_.offset]); + if (codec->Encode(str, &bits, &num_bits)) { + writer_.WriteBits(bits, num_bits); + break; + } else { + bool result = codec->Encode("kMarkvNoneOfTheAbove", + &bits, &num_bits); + (void)result; + assert(result); + writer_.WriteBits(bits, num_bits); + } + } + + const size_t length = spv_strnlen_s(src, operand_.num_words * 4); + if (length == operand_.num_words * 4) + return vstate_.diag(SPV_ERROR_INVALID_BINARY) + << "Failed to find terminal character of literal string"; + for (size_t i = 0; i < length + 1; ++i) + writer_.WriteUnencoded(src[i]); + break; + } + + default: { + for (int i = 0; i < operand_.num_words; ++i) { + const uint32_t word = instruction.word(operand_.offset + i); + const spv_result_t result = EncodeNonIdWord(word); + if (result != SPV_SUCCESS) + return result; + } + break; + } + } + } + + AddByteBreak(kByteBreakAfterInstIfLessThanUntilNextByte); + + if (logger_) { + logger_->NewLine(); + logger_->NewLine(); + } + + ProcessCurInstruction(); + instructions_.push_back(&instruction); + + return SPV_SUCCESS; +} + spv_result_t MarkvDecoder::DecodeModule(std::vector* spirv_binary) { const bool header_read_success = reader_.ReadUnencoded(&header_.magic_number) && @@ -901,8 +2438,9 @@ spv_result_t MarkvDecoder::DecodeModule(std::vector* spirv_binary) { return vstate_.diag(SPV_ERROR_INVALID_BINARY) << "Unable to read MARK-V header"; - assert(header_.magic_number == kMarkvMagicNumber); - assert(header_.markv_length_in_bits > 0); + if (header_.markv_length_in_bits == 0) + return vstate_.diag(SPV_ERROR_INVALID_BINARY) + << "Header markv_length_in_bits field is zero"; if (header_.magic_number != kMarkvMagicNumber) return vstate_.diag(SPV_ERROR_INVALID_BINARY) @@ -920,14 +2458,16 @@ spv_result_t MarkvDecoder::DecodeModule(std::vector* spirv_binary) { spirv_[2] = header_.spirv_generator; while (reader_.GetNumReadBits() < header_.markv_length_in_bits) { - spv_parsed_instruction_t inst = {}; - const spv_result_t decode_result = DecodeInstruction(&inst); + inst_ = {}; + const spv_result_t decode_result = DecodeInstruction(); if (decode_result != SPV_SUCCESS) return decode_result; - const spv_result_t validation_result = UpdateValidationState(inst); + const spv_result_t validation_result = UpdateValidationState(inst_); if (validation_result != SPV_SUCCESS) return validation_result; + + instructions_.push_back(&vstate_.ordered_instructions().back()); } @@ -952,65 +2492,43 @@ spv_result_t MarkvDecoder::DecodeModule(std::vector* spirv_binary) { // For now it's better to keep the code independent for experimentation // purposes. spv_result_t MarkvDecoder::DecodeOperand( - size_t instruction_offset, size_t operand_offset, - spv_parsed_instruction_t* inst, const spv_operand_type_t type, - spv_operand_pattern_t* expected_operands, - bool read_result_id) { - const SpvOp opcode = static_cast(inst->opcode); + size_t operand_offset, + const spv_operand_type_t type, + spv_operand_pattern_t* expected_operands) { + const SpvOp opcode = static_cast(inst_.opcode); - spv_parsed_operand_t parsed_operand; - memset(&parsed_operand, 0, sizeof(parsed_operand)); + memset(&operand_, 0, sizeof(operand_)); assert((operand_offset >> 16) == 0); - parsed_operand.offset = static_cast(operand_offset); - parsed_operand.type = type; + operand_.offset = static_cast(operand_offset); + operand_.type = type; // Set default values, may be updated later. - parsed_operand.number_kind = SPV_NUMBER_NONE; - parsed_operand.number_bit_width = 0; + operand_.number_kind = SPV_NUMBER_NONE; + operand_.number_bit_width = 0; - const size_t first_word_index = spirv_.size(); + const size_t first_word_index = inst_words_.size(); switch (type) { - case SPV_OPERAND_TYPE_TYPE_ID: { - if (!DecodeId(&inst->type_id)) { - return vstate_.diag(SPV_ERROR_INVALID_BINARY) - << "Failed to read type_id"; - } + case SPV_OPERAND_TYPE_RESULT_ID: { + const spv_result_t result = DecodeResultId(); + if (result != SPV_SUCCESS) + return result; - if (inst->type_id == 0) - return vstate_.diag(SPV_ERROR_INVALID_BINARY) << "Decoded type_id is 0"; - - spirv_.push_back(inst->type_id); - vstate_.setIdBound(std::max(vstate_.getIdBound(), inst->type_id + 1)); + inst_words_.push_back(inst_.result_id); + vstate_.setIdBound(std::max(vstate_.getIdBound(), inst_.result_id + 1)); + multi_mtf_.Promote(inst_.result_id); break; } - case SPV_OPERAND_TYPE_RESULT_ID: { - if (read_result_id) { - if (!DecodeId(&inst->result_id)) - return vstate_.diag(SPV_ERROR_INVALID_BINARY) - << "Failed to read result_id"; - } else { - inst->result_id = vstate_.getIdBound(); - vstate_.setIdBound(inst->result_id + 1); - move_to_front_ids_.push_front(inst->result_id); - } + case SPV_OPERAND_TYPE_TYPE_ID: { + const spv_result_t result = DecodeTypeId(); + if (result != SPV_SUCCESS) + return result; - spirv_.push_back(inst->result_id); - - // Save the result ID to type ID mapping. - // In the grammar, type ID always appears before result ID. - // A regular value maps to its type. Some instructions (e.g. OpLabel) - // have no type Id, and will map to 0. The result Id for a - // type-generating instruction (e.g. OpTypeInt) maps to itself. - auto insertion_result = id_to_type_id_.emplace( - inst->result_id, - spvOpcodeGeneratesType(opcode) ? inst->result_id : inst->type_id); - if(!insertion_result.second) { - return vstate_.diag(SPV_ERROR_INVALID_ID) - << "Unexpected behavior: id->type_id pair was already registered"; - } + inst_words_.push_back(inst_.type_id); + vstate_.setIdBound(std::max(vstate_.getIdBound(), inst_.type_id + 1)); + multi_mtf_.Promote(inst_.type_id); break; } @@ -1019,46 +2537,50 @@ spv_result_t MarkvDecoder::DecodeOperand( case SPV_OPERAND_TYPE_SCOPE_ID: case SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID: { uint32_t id = 0; - if (!DecodeId(&id)) - return vstate_.diag(SPV_ERROR_INVALID_BINARY) << "Failed to read id"; + const spv_result_t result = DecodeRefId(&id); + if (result != SPV_SUCCESS) + return result; if (id == 0) return vstate_.diag(SPV_ERROR_INVALID_BINARY) << "Decoded id is 0"; - spirv_.push_back(id); - vstate_.setIdBound(std::max(vstate_.getIdBound(), id + 1)); + if (type == SPV_OPERAND_TYPE_ID || + type == SPV_OPERAND_TYPE_OPTIONAL_ID) { - if (type == SPV_OPERAND_TYPE_ID || type == SPV_OPERAND_TYPE_OPTIONAL_ID) { + operand_.type = SPV_OPERAND_TYPE_ID; - parsed_operand.type = SPV_OPERAND_TYPE_ID; - - if (opcode == SpvOpExtInst && parsed_operand.offset == 3) { + if (opcode == SpvOpExtInst && operand_.offset == 3) { // The current word is the extended instruction set id. - // Set the extended instruction set type for the current instruction. + // Set the extended instruction set type for the current + // instruction. auto ext_inst_type_iter = import_id_to_ext_inst_type_.find(id); if (ext_inst_type_iter == import_id_to_ext_inst_type_.end()) { return vstate_.diag(SPV_ERROR_INVALID_ID) << "OpExtInst set id " << id << " does not reference an OpExtInstImport result Id"; } - inst->ext_inst_type = ext_inst_type_iter->second; + inst_.ext_inst_type = ext_inst_type_iter->second; } } + + inst_words_.push_back(id); + vstate_.setIdBound(std::max(vstate_.getIdBound(), id + 1)); + multi_mtf_.Promote(id); break; } case SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER: { uint32_t word = 0; - if (!DecodeOperandWord(type, &word)) - return vstate_.diag(SPV_ERROR_INVALID_BINARY) - << "Failed to read enum"; + const spv_result_t result = DecodeNonIdWord(&word); + if (result != SPV_SUCCESS) + return result; - spirv_.push_back(word); + inst_words_.push_back(word); assert(SpvOpExtInst == opcode); - assert(inst->ext_inst_type != SPV_EXT_INST_TYPE_NONE); + assert(inst_.ext_inst_type != SPV_EXT_INST_TYPE_NONE); spv_ext_inst_desc ext_inst; - if (grammar_.lookupExtInst(inst->ext_inst_type, word, &ext_inst)) + if (grammar_.lookupExtInst(inst_.ext_inst_type, word, &ext_inst)) return vstate_.diag(SPV_ERROR_INVALID_BINARY) << "Invalid extended instruction number: " << word; spvPushOperandTypes(ext_inst->operandTypes, expected_operands); @@ -1069,27 +2591,27 @@ spv_result_t MarkvDecoder::DecodeOperand( case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_INTEGER: { // These are regular single-word literal integer operands. // Post-parsing validation should check the range of the parsed value. - parsed_operand.type = SPV_OPERAND_TYPE_LITERAL_INTEGER; + operand_.type = SPV_OPERAND_TYPE_LITERAL_INTEGER; // It turns out they are always unsigned integers! - parsed_operand.number_kind = SPV_NUMBER_UNSIGNED_INT; - parsed_operand.number_bit_width = 32; + operand_.number_kind = SPV_NUMBER_UNSIGNED_INT; + operand_.number_bit_width = 32; uint32_t word = 0; - if (!DecodeOperandWord(type, &word)) - return vstate_.diag(SPV_ERROR_INVALID_BINARY) - << "Failed to read literal integer"; + const spv_result_t result = DecodeNonIdWord(&word); + if (result != SPV_SUCCESS) + return result; - spirv_.push_back(word); + inst_words_.push_back(word); break; } case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER: - case SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER: - parsed_operand.type = SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER; + case SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER: { + operand_.type = SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER; if (opcode == SpvOpSwitch) { // The literal operands have the same type as the value // referenced by the selector Id. - const uint32_t selector_id = spirv_.at(instruction_offset + 1); + const uint32_t selector_id = inst_words_.at(1); const auto type_id_iter = id_to_type_id_.find(selector_id); if (type_id_iter == id_to_type_id_.end() || type_id_iter->second == 0) { @@ -1106,10 +2628,10 @@ spv_result_t MarkvDecoder::DecodeOperand( << "Invalid OpSwitch: selector id " << selector_id << " is a type, not a value"; } - if (auto error = SetNumericTypeInfoForType(&parsed_operand, type_id)) + if (auto error = SetNumericTypeInfoForType(&operand_, type_id)) return error; - if (parsed_operand.number_kind != SPV_NUMBER_UNSIGNED_INT && - parsed_operand.number_kind != SPV_NUMBER_SIGNED_INT) { + if (operand_.number_kind != SPV_NUMBER_UNSIGNED_INT && + operand_.number_kind != SPV_NUMBER_SIGNED_INT) { return vstate_.diag(SPV_ERROR_INVALID_BINARY) << "Invalid OpSwitch: selector id " << selector_id << " is not a scalar integer"; @@ -1118,40 +2640,60 @@ spv_result_t MarkvDecoder::DecodeOperand( assert(opcode == SpvOpConstant || opcode == SpvOpSpecConstant); // The literal number type is determined by the type Id for the // constant. - assert(inst->type_id); - if (auto error = - SetNumericTypeInfoForType(&parsed_operand, inst->type_id)) + assert(inst_.type_id); + if (auto error = SetNumericTypeInfoForType(&operand_, inst_.type_id)) return error; } - if (auto error = DecodeLiteralNumber(parsed_operand)) + if (auto error = DecodeLiteralNumber(operand_)) return error; break; + } case SPV_OPERAND_TYPE_LITERAL_STRING: case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_STRING: { - parsed_operand.type = SPV_OPERAND_TYPE_LITERAL_STRING; + operand_.type = SPV_OPERAND_TYPE_LITERAL_STRING; std::vector str; - // The loop is expected to terminate once we encounter '\0' or exhaust - // the bit stream. - while (true) { - char ch = 0; - if (!reader_.ReadUnencoded(&ch)) + auto* codec = model_->GetLiteralStringHuffmanCodec(inst_.opcode); + + if (codec) { + std::string decoded_string; + const bool huffman_result = + codec->DecodeFromStream(GetReadBitCallback(), &decoded_string); + assert(huffman_result); + if (!huffman_result) return vstate_.diag(SPV_ERROR_INVALID_BINARY) << "Failed to read literal string"; - str.push_back(ch); + if (decoded_string != "kMarkvNoneOfTheAbove") { + std::copy(decoded_string.begin(), decoded_string.end(), + std::back_inserter(str)); + str.push_back('\0'); + } + } - if (ch == '\0') - break; + // The loop is expected to terminate once we encounter '\0' or exhaust + // the bit stream. + if (str.empty()) { + while (true) { + char ch = 0; + if (!reader_.ReadUnencoded(&ch)) + return vstate_.diag(SPV_ERROR_INVALID_BINARY) + << "Failed to read literal string"; + + str.push_back(ch); + + if (ch == '\0') + break; + } } while (str.size() % 4 != 0) str.push_back('\0'); - spirv_.resize(spirv_.size() + str.size() / 4); - std::memcpy(&spirv_[first_word_index], str.data(), str.size()); + inst_words_.resize(inst_words_.size() + str.size() / 4); + std::memcpy(&inst_words_[first_word_index], str.data(), str.size()); if (SpvOpExtInstImport == opcode) { // Record the extended instruction type for the ID for this import. @@ -1165,9 +2707,9 @@ spv_result_t MarkvDecoder::DecodeOperand( } // We must have parsed a valid result ID. It's a condition // of the grammar, and we only accept non-zero result Ids. - assert(inst->result_id); + assert(inst_.result_id); const bool inserted = import_id_to_ext_inst_type_.emplace( - inst->result_id, ext_inst_type).second; + inst_.result_id, ext_inst_type).second; (void)inserted; assert(inserted); } @@ -1197,21 +2739,21 @@ spv_result_t MarkvDecoder::DecodeOperand( case SPV_OPERAND_TYPE_KERNEL_PROFILING_INFO: { // A single word that is a plain enum value. uint32_t word = 0; - if (!DecodeOperandWord(type, &word)) - return vstate_.diag(SPV_ERROR_INVALID_BINARY) - << "Failed to read enum"; + const spv_result_t result = DecodeNonIdWord(&word); + if (result != SPV_SUCCESS) + return result; - spirv_.push_back(word); + inst_words_.push_back(word); // Map an optional operand type to its corresponding concrete type. if (type == SPV_OPERAND_TYPE_OPTIONAL_ACCESS_QUALIFIER) - parsed_operand.type = SPV_OPERAND_TYPE_ACCESS_QUALIFIER; + operand_.type = SPV_OPERAND_TYPE_ACCESS_QUALIFIER; spv_operand_desc entry; if (grammar_.lookupOperand(type, word, &entry)) { return vstate_.diag(SPV_ERROR_INVALID_BINARY) << "Invalid " - << spvOperandTypeStr(parsed_operand.type) + << spvOperandTypeStr(operand_.type) << " operand: " << word; } @@ -1229,18 +2771,17 @@ spv_result_t MarkvDecoder::DecodeOperand( case SPV_OPERAND_TYPE_SELECTION_CONTROL: { // This operand is a mask. uint32_t word = 0; - if (!DecodeOperandWord(type, &word)) - return vstate_.diag(SPV_ERROR_INVALID_BINARY) - << "Failed to read " << spvOperandTypeStr(type) - << " for " << spvOpcodeString(SpvOp(inst->opcode)); + const spv_result_t result = DecodeNonIdWord(&word); + if (result != SPV_SUCCESS) + return result; - spirv_.push_back(word); + inst_words_.push_back(word); // Map an optional operand type to its corresponding concrete type. if (type == SPV_OPERAND_TYPE_OPTIONAL_IMAGE) - parsed_operand.type = SPV_OPERAND_TYPE_IMAGE; + operand_.type = SPV_OPERAND_TYPE_IMAGE; else if (type == SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS) - parsed_operand.type = SPV_OPERAND_TYPE_MEMORY_ACCESS; + operand_.type = SPV_OPERAND_TYPE_MEMORY_ACCESS; // Check validity of set mask bits. Also prepare for operands for those // masks if they have any. To get operand order correct, scan from @@ -1254,7 +2795,7 @@ spv_result_t MarkvDecoder::DecodeOperand( spv_operand_desc entry; if (grammar_.lookupOperand(type, mask, &entry)) { return vstate_.diag(SPV_ERROR_INVALID_BINARY) - << "Invalid " << spvOperandTypeStr(parsed_operand.type) + << "Invalid " << spvOperandTypeStr(operand_.type) << " operand: " << word << " has invalid mask component " << mask; } @@ -1277,104 +2818,111 @@ spv_result_t MarkvDecoder::DecodeOperand( << "Internal error: Unhandled operand type: " << type; } - parsed_operand.num_words = uint16_t(spirv_.size() - first_word_index); + operand_.num_words = uint16_t(inst_words_.size() - first_word_index); - assert(int(SPV_OPERAND_TYPE_FIRST_CONCRETE_TYPE) <= int(parsed_operand.type)); - assert(int(SPV_OPERAND_TYPE_LAST_CONCRETE_TYPE) >= int(parsed_operand.type)); + assert(int(SPV_OPERAND_TYPE_FIRST_CONCRETE_TYPE) <= int(operand_.type)); + assert(int(SPV_OPERAND_TYPE_LAST_CONCRETE_TYPE) >= int(operand_.type)); - parsed_operands_.push_back(parsed_operand); + parsed_operands_.push_back(operand_); return SPV_SUCCESS; } -spv_result_t MarkvDecoder::DecodeInstruction(spv_parsed_instruction_t* inst) { +spv_result_t MarkvDecoder::DecodeInstruction() { parsed_operands_.clear(); - const size_t instruction_offset = spirv_.size(); - - bool read_result_id = false; - - while (true) { - uint32_t word = 0; - if (!reader_.ReadVariableWidthU32(&word, - model_->opcode_chunk_length())) { - return vstate_.diag(SPV_ERROR_INVALID_BINARY) - << "Failed to read opcode of instruction"; - } - - if (word >= kMarkvFirstOpcode) { - if (word == kMarkvOpNextInstructionEncodesResultId) { - read_result_id = true; - } else { - return vstate_.diag(SPV_ERROR_INVALID_BINARY) - << "Encountered unknown MARK-V opcode"; - } - } else { - inst->opcode = static_cast(word); - break; - } - } - - const SpvOp opcode = static_cast(inst->opcode); + inst_words_.clear(); // Opcode/num_words placeholder, the word will be filled in later. - spirv_.push_back(0); + inst_words_.push_back(0); + + bool num_operands_still_unknown = true; + { + uint32_t opcode = 0; + uint32_t num_operands = 0; + + const spv_result_t opcode_decoding_result = + DecodeOpcodeAndNumberOfOperands(&opcode, &num_operands); + if (opcode_decoding_result < 0) + return opcode_decoding_result; + + if (opcode_decoding_result == SPV_SUCCESS) { + inst_.num_operands = static_cast(num_operands); + num_operands_still_unknown = false; + } else { + if (!reader_.ReadVariableWidthU32( + &opcode, model_->opcode_chunk_length())) { + return vstate_.diag(SPV_ERROR_INVALID_BINARY) + << "Failed to read opcode of instruction"; + } + } + + inst_.opcode = static_cast(opcode); + } + + const SpvOp opcode = static_cast(inst_.opcode); spv_opcode_desc opcode_desc; - if (grammar_.lookupOpcode(opcode, &opcode_desc) - != SPV_SUCCESS) { + if (grammar_.lookupOpcode(opcode, &opcode_desc) != SPV_SUCCESS) { return vstate_.diag(SPV_ERROR_INVALID_BINARY) << "Invalid opcode"; } spv_operand_pattern_t expected_operands; expected_operands.reserve(opcode_desc->numTypes); - for (auto i = 0; i < opcode_desc->numTypes; i++) - expected_operands.push_back(opcode_desc->operandTypes[opcode_desc->numTypes - i - 1]); - - if (!OpcodeHasFixedNumberOfOperands(opcode)) { - if (!reader_.ReadVariableWidthU16(&inst->num_operands, - model_->num_operands_chunk_length())) - return vstate_.diag(SPV_ERROR_INVALID_BINARY) - << "Failed to read num_operands of instruction"; - } else { - inst->num_operands = static_cast(expected_operands.size()); + for (auto i = 0; i < opcode_desc->numTypes; i++) { + expected_operands.push_back( + opcode_desc->operandTypes[opcode_desc->numTypes - i - 1]); } - for (size_t operand_index = 0; - operand_index < static_cast(inst->num_operands); - ++operand_index) { + if (num_operands_still_unknown) { + if (!OpcodeHasFixedNumberOfOperands(opcode)) { + if (!reader_.ReadVariableWidthU16(&inst_.num_operands, + model_->num_operands_chunk_length())) + return vstate_.diag(SPV_ERROR_INVALID_BINARY) + << "Failed to read num_operands of instruction"; + } else { + inst_.num_operands = static_cast(expected_operands.size()); + } + } + + for (operand_index_ = 0; + operand_index_ < static_cast(inst_.num_operands); + ++operand_index_) { assert(!expected_operands.empty()); const spv_operand_type_t type = spvTakeFirstMatchableOperand(&expected_operands); - const size_t operand_offset = spirv_.size() - instruction_offset; + const size_t operand_offset = inst_words_.size(); - const spv_result_t decode_result = - DecodeOperand(instruction_offset, operand_offset, inst, type, - &expected_operands, read_result_id); + const spv_result_t decode_result = DecodeOperand( + operand_offset, type, &expected_operands); if (decode_result != SPV_SUCCESS) return decode_result; } - assert(inst->num_operands == parsed_operands_.size()); - // Only valid while spirv_ and parsed_operands_ remain unchanged. - inst->words = &spirv_[instruction_offset]; - inst->operands = parsed_operands_.empty() ? nullptr : parsed_operands_.data(); - inst->num_words = static_cast(spirv_.size() - instruction_offset); - spirv_[instruction_offset] = - spvOpcodeMake(inst->num_words, SpvOp(inst->opcode)); + assert(inst_.num_operands == parsed_operands_.size()); - assert(inst->num_words == std::accumulate( + // Only valid while inst_words_ and parsed_operands_ remain unchanged (until + // next DecodeInstruction call). + inst_.words = inst_words_.data(); + inst_.operands = parsed_operands_.empty() ? nullptr : parsed_operands_.data(); + inst_.num_words = static_cast(inst_words_.size()); + inst_words_[0] = spvOpcodeMake(inst_.num_words, SpvOp(inst_.opcode)); + + std::copy(inst_words_.begin(), inst_words_.end(), std::back_inserter(spirv_)); + + assert(inst_.num_words == std::accumulate( parsed_operands_.begin(), parsed_operands_.end(), 1, [](int num_words, const spv_parsed_operand_t& operand) { return num_words += operand.num_words; }) && "num_words in instruction doesn't correspond to the sum of num_words" "in the operands"); - RecordNumberType(*inst); + RecordNumberType(); + ProcessCurInstruction(); - if (!ReadToByteBreakIfAgreed()) + if (!ReadToByteBreak(kByteBreakAfterInstIfLessThanUntilNextByte)) return vstate_.diag(SPV_ERROR_INVALID_BINARY) << "Failed to read to byte break"; @@ -1404,20 +2952,20 @@ spv_result_t MarkvDecoder::SetNumericTypeInfoForType( return SPV_SUCCESS; } -void MarkvDecoder::RecordNumberType(const spv_parsed_instruction_t& inst) { - const SpvOp opcode = static_cast(inst.opcode); +void MarkvDecoder::RecordNumberType() { + const SpvOp opcode = static_cast(inst_.opcode); if (spvOpcodeGeneratesType(opcode)) { NumberType info = {SPV_NUMBER_NONE, 0}; if (SpvOpTypeInt == opcode) { - info.bit_width = inst.words[inst.operands[1].offset]; - info.type = inst.words[inst.operands[2].offset] ? + info.bit_width = inst_.words[inst_.operands[1].offset]; + info.type = inst_.words[inst_.operands[2].offset] ? SPV_NUMBER_SIGNED_INT : SPV_NUMBER_UNSIGNED_INT; } else if (SpvOpTypeFloat == opcode) { - info.bit_width = inst.words[inst.operands[1].offset]; + info.bit_width = inst_.words[inst_.operands[1].offset]; info.type = SPV_NUMBER_FLOATING; } // The *result* Id of a type generating instruction is the type Id. - type_id_to_number_type_info_[inst.result_id] = info; + type_id_to_number_type_info_[inst_.result_id] = info; } } @@ -1505,7 +3053,8 @@ spv_result_t spvMarkvToSpirv(spv_const_context context, size_t markv_size_bytes, spv_const_markv_decoder_options options, spv_binary* spirv_binary, - spv_text* /* comments */, spv_diagnostic* diagnostic) { + spv_text* /* comments */, + spv_diagnostic* diagnostic) { spv_position_t position = {}; spv_context_t hijack_context = *context; if (diagnostic) { diff --git a/source/operand.cpp b/source/operand.cpp index 29da94d13..8feb6567a 100644 --- a/source/operand.cpp +++ b/source/operand.cpp @@ -328,3 +328,61 @@ bool spvIsIdType(spv_operand_type_t type) { return false; } } + +std::function spvOperandCanBeForwardDeclaredFunction( + SpvOp opcode) { + std::function out; + switch (opcode) { + case SpvOpExecutionMode: + case SpvOpEntryPoint: + case SpvOpName: + case SpvOpMemberName: + case SpvOpSelectionMerge: + case SpvOpDecorate: + case SpvOpMemberDecorate: + case SpvOpTypeStruct: + case SpvOpBranch: + case SpvOpLoopMerge: + out = [](unsigned) { return true; }; + break; + case SpvOpGroupDecorate: + case SpvOpGroupMemberDecorate: + case SpvOpBranchConditional: + case SpvOpSwitch: + out = [](unsigned index) { return index != 0; }; + break; + + case SpvOpFunctionCall: + // The Function parameter. + out = [](unsigned index) { return index == 2; }; + break; + + case SpvOpPhi: + out = [](unsigned index) { return index > 1; }; + break; + + case SpvOpEnqueueKernel: + // The Invoke parameter. + out = [](unsigned index) { return index == 8; }; + break; + + case SpvOpGetKernelNDrangeSubGroupCount: + case SpvOpGetKernelNDrangeMaxSubGroupSize: + // The Invoke parameter. + out = [](unsigned index) { return index == 3; }; + break; + + case SpvOpGetKernelWorkGroupSize: + case SpvOpGetKernelPreferredWorkGroupSizeMultiple: + // The Invoke parameter. + out = [](unsigned index) { return index == 2; }; + break; + case SpvOpTypeForwardPointer: + out = [](unsigned index) { return index == 0; }; + break; + default: + out = [](unsigned) { return false; }; + break; + } + return out; +} diff --git a/source/operand.h b/source/operand.h index fa7c6f2e9..42099930b 100644 --- a/source/operand.h +++ b/source/operand.h @@ -16,6 +16,7 @@ #define LIBSPIRV_OPERAND_H_ #include +#include #include "spirv-tools/libspirv.h" #include "table.h" @@ -124,4 +125,11 @@ spv_operand_pattern_t spvAlternatePatternFollowingImmediate( // Is the operand an ID? bool spvIsIdType(spv_operand_type_t type); +// Takes the opcode of an instruction and returns +// a function object that will return true if the index +// of the operand can be forward declared. This function will +// used in the SSA validation stage of the pipeline +std::function spvOperandCanBeForwardDeclaredFunction( + SpvOp opcode); + #endif // LIBSPIRV_OPERAND_H_ diff --git a/source/util/huffman_codec.h b/source/util/huffman_codec.h index 35880203b..2ccc3c98a 100644 --- a/source/util/huffman_codec.h +++ b/source/util/huffman_codec.h @@ -210,7 +210,7 @@ class HuffmanCodec { // Encodes |val| and stores its Huffman code in the lower |num_bits| of // |bits|. Returns false of |val| is not in the Huffman table. - bool Encode(const Val& val, uint64_t* bits, size_t* num_bits) { + bool Encode(const Val& val, uint64_t* bits, size_t* num_bits) const { auto it = encoding_table_.find(val); if (it == encoding_table_.end()) return false; @@ -225,7 +225,8 @@ class HuffmanCodec { // |read_bit| has type bool func(bool* bit). When called, the next bit is // stored in |bit|. |read_bit| returns false if the stream terminates // prematurely. - bool DecodeFromStream(const std::function& read_bit, Val* val) { + bool DecodeFromStream( + const std::function& read_bit, Val* val) const { uint32_t node = root_; while (true) { assert(node); diff --git a/source/util/move_to_front.h b/source/util/move_to_front.h index f02529efe..efa79a75e 100644 --- a/source/util/move_to_front.h +++ b/source/util/move_to_front.h @@ -325,7 +325,7 @@ class MultiMoveToFront { public: // Inserts |value| to sequence with handle |mtf|. // Returns false if |mtf| already has |value|. - bool Insert(uint32_t mtf, const Val& value) { + bool Insert(uint64_t mtf, const Val& value) { if (GetMtf(mtf).Insert(value)) { val_to_mtfs_[value].insert(mtf); return true; @@ -335,7 +335,7 @@ class MultiMoveToFront { // Removes |value| from sequence with handle |mtf|. // Returns false if |mtf| doesn't have |value|. - bool Remove(uint32_t mtf, const Val& value) { + bool Remove(uint64_t mtf, const Val& value) { if (GetMtf(mtf).Remove(value)) { val_to_mtfs_[value].erase(mtf); return true; @@ -351,7 +351,7 @@ class MultiMoveToFront { return; auto& mtfs_containing_value = it->second; - for (uint32_t mtf : mtfs_containing_value) { + for (uint64_t mtf : mtfs_containing_value) { GetMtf(mtf).Remove(value); } @@ -360,18 +360,18 @@ class MultiMoveToFront { // Computes rank of |value| in sequence |mtf|. // Returns false if |mtf| doesn't have |value|. - bool RankFromValue(uint32_t mtf, const Val& value, uint32_t* rank) { + bool RankFromValue(uint64_t mtf, const Val& value, uint32_t* rank) { return GetMtf(mtf).RankFromValue(value, rank); } // Finds |value| with |rank| in sequence |mtf|. // Returns false if |rank| is out of bounds. - bool ValueFromRank(uint32_t mtf, uint32_t rank, Val* value) { + bool ValueFromRank(uint64_t mtf, uint32_t rank, Val* value) { return GetMtf(mtf).ValueFromRank(rank, value); } // Returns size of |mtf| sequence. - uint32_t GetSize(uint32_t mtf) { + uint32_t GetSize(uint64_t mtf) { return GetMtf(mtf).GetSize(); } @@ -382,20 +382,20 @@ class MultiMoveToFront { return; const auto& mtfs_containing_value = it->second; - for (uint32_t mtf : mtfs_containing_value) { + for (uint64_t mtf : mtfs_containing_value) { GetMtf(mtf).Promote(value); } } // Inserts |value| in sequence |mtf| or promotes if it's already there. - void InsertOrPromote(uint32_t mtf, const Val& value) { + void InsertOrPromote(uint64_t mtf, const Val& value) { if (!Insert(mtf, value)) { GetMtf(mtf).Promote(value); } } // Returns if |mtf| sequence has |value|. - bool HasValue(uint32_t mtf, const Val& value) { + bool HasValue(uint64_t mtf, const Val& value) { return GetMtf(mtf).HasValue(value); } @@ -403,7 +403,7 @@ class MultiMoveToFront { // Returns actual MoveToFront object corresponding to |handle|. // As multiple operations are often performed consecutively for the same // sequence, the last returned value is cached. - MoveToFront& GetMtf(uint32_t handle) { + MoveToFront& GetMtf(uint64_t handle) { if (!cached_mtf_ || cached_handle_ != handle) { cached_handle_ = handle; cached_mtf_ = &mtfs_[handle]; @@ -413,13 +413,13 @@ class MultiMoveToFront { } // Container holding MoveToFront objects. Map key is sequence handle. - std::map> mtfs_; + std::map> mtfs_; // Container mapping value to sequences which contain that value. - std::unordered_map> val_to_mtfs_; + std::unordered_map> val_to_mtfs_; // Cache for the last accessed sequence. - uint32_t cached_handle_ = 0; + uint64_t cached_handle_ = 0; MoveToFront* cached_mtf_ = nullptr; }; @@ -471,7 +471,15 @@ bool MoveToFront::RankFromValue(const Val& value, uint32_t* rank) { } const uint32_t old_size = GetSize(); - (void)old_size; + if (old_size == 1) { + if (ValueOf(root_) == value) { + *rank = 1; + return true; + } else { + return false; + } + } + const auto it = value_to_node_.find(value); if (it == value_to_node_.end()) { return false; @@ -524,7 +532,9 @@ bool MoveToFront::Promote(const Val& value) { } const uint32_t old_size = GetSize(); - (void)old_size; + if (old_size == 1) + return ValueOf(root_) == value; + const auto it = value_to_node_.find(value); if (it == value_to_node_.end()) { return false; @@ -561,6 +571,11 @@ bool MoveToFront::ValueFromRank(uint32_t rank, Val* value) { return false; } + if (old_size == 1) { + *value = ValueOf(root_); + return true; + } + const bool update_timestamp = (rank != 1); uint32_t node = root_; diff --git a/source/validate_id.cpp b/source/validate_id.cpp index ae3b59fbd..64b9d5860 100644 --- a/source/validate_id.cpp +++ b/source/validate_id.cpp @@ -26,6 +26,7 @@ #include "instruction.h" #include "message.h" #include "opcode.h" +#include "operand.h" #include "spirv_validator_options.h" #include "spirv-tools/libspirv.h" #include "val/function.h" @@ -3056,66 +3057,6 @@ bool idUsage::isValid(const spv_instruction_t* inst) { #undef TODO #undef CASE } -// This function takes the opcode of an instruction and returns -// a function object that will return true if the index -// of the operand can be forwarad declared. This function will -// used in the SSA validation stage of the pipeline -function getCanBeForwardDeclaredFunction(SpvOp opcode) { - function out; - switch (opcode) { - case SpvOpExecutionMode: - case SpvOpEntryPoint: - case SpvOpName: - case SpvOpMemberName: - case SpvOpSelectionMerge: - case SpvOpDecorate: - case SpvOpMemberDecorate: - case SpvOpTypeStruct: - case SpvOpBranch: - case SpvOpLoopMerge: - out = [](unsigned) { return true; }; - break; - case SpvOpGroupDecorate: - case SpvOpGroupMemberDecorate: - case SpvOpBranchConditional: - case SpvOpSwitch: - out = [](unsigned index) { return index != 0; }; - break; - - case SpvOpFunctionCall: - // The Function parameter. - out = [](unsigned index) { return index == 2; }; - break; - - case SpvOpPhi: - out = [](unsigned index) { return index > 1; }; - break; - - case SpvOpEnqueueKernel: - // The Invoke parameter. - out = [](unsigned index) { return index == 8; }; - break; - - case SpvOpGetKernelNDrangeSubGroupCount: - case SpvOpGetKernelNDrangeMaxSubGroupSize: - // The Invoke parameter. - out = [](unsigned index) { return index == 3; }; - break; - - case SpvOpGetKernelWorkGroupSize: - case SpvOpGetKernelPreferredWorkGroupSizeMultiple: - // The Invoke parameter. - out = [](unsigned index) { return index == 2; }; - break; - case SpvOpTypeForwardPointer: - out = [](unsigned index) { return index == 0; }; - break; - default: - out = [](unsigned) { return false; }; - break; - } - return out; -} } // anonymous namespace namespace libspirv { @@ -3214,7 +3155,7 @@ spv_result_t CheckIdDefinitionDominateUse(const ValidationState_t& _) { spv_result_t IdPass(ValidationState_t& _, const spv_parsed_instruction_t* inst) { auto can_have_forward_declared_ids = - getCanBeForwardDeclaredFunction(static_cast(inst->opcode)); + spvOperandCanBeForwardDeclaredFunction(static_cast(inst->opcode)); // Keep track of a result id defined by this instruction. 0 means it // does not define an id. diff --git a/test/comp/markv_codec_test.cpp b/test/comp/markv_codec_test.cpp index c43cc77ad..246e6cb97 100644 --- a/test/comp/markv_codec_test.cpp +++ b/test/comp/markv_codec_test.cpp @@ -165,6 +165,92 @@ void TestEncodeDecode(const std::string& original_text) { spvMarkvBinaryDestroy(markv_binary); } +void TestEncodeDecodeShaderMainBody(const std::string& body) { + const std::string prefix = +R"( +OpCapability Shader +OpCapability Int64 +OpCapability Float64 +%ext_inst = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +%void = OpTypeVoid +%func = OpTypeFunction %void +%bool = OpTypeBool +%f32 = OpTypeFloat 32 +%u32 = OpTypeInt 32 0 +%s32 = OpTypeInt 32 1 +%f64 = OpTypeFloat 64 +%u64 = OpTypeInt 64 0 +%s64 = OpTypeInt 64 1 +%boolvec2 = OpTypeVector %bool 2 +%s32vec2 = OpTypeVector %s32 2 +%u32vec2 = OpTypeVector %u32 2 +%f32vec2 = OpTypeVector %f32 2 +%f64vec2 = OpTypeVector %f64 2 +%boolvec3 = OpTypeVector %bool 3 +%u32vec3 = OpTypeVector %u32 3 +%s32vec3 = OpTypeVector %s32 3 +%f32vec3 = OpTypeVector %f32 3 +%f64vec3 = OpTypeVector %f64 3 +%boolvec4 = OpTypeVector %bool 4 +%u32vec4 = OpTypeVector %u32 4 +%s32vec4 = OpTypeVector %s32 4 +%f32vec4 = OpTypeVector %f32 4 +%f64vec4 = OpTypeVector %f64 4 + +%f32_0 = OpConstant %f32 0 +%f32_1 = OpConstant %f32 1 +%f32_2 = OpConstant %f32 2 +%f32_3 = OpConstant %f32 3 +%f32_4 = OpConstant %f32 4 +%f32_pi = OpConstant %f32 3.14159 + +%s32_0 = OpConstant %s32 0 +%s32_1 = OpConstant %s32 1 +%s32_2 = OpConstant %s32 2 +%s32_3 = OpConstant %s32 3 +%s32_4 = OpConstant %s32 4 +%s32_m1 = OpConstant %s32 -1 + +%u32_0 = OpConstant %u32 0 +%u32_1 = OpConstant %u32 1 +%u32_2 = OpConstant %u32 2 +%u32_3 = OpConstant %u32 3 +%u32_4 = OpConstant %u32 4 + +%u32vec2_01 = OpConstantComposite %u32vec2 %u32_0 %u32_1 +%u32vec2_12 = OpConstantComposite %u32vec2 %u32_1 %u32_2 +%u32vec3_012 = OpConstantComposite %u32vec3 %u32_0 %u32_1 %u32_2 +%u32vec3_123 = OpConstantComposite %u32vec3 %u32_1 %u32_2 %u32_3 +%u32vec4_0123 = OpConstantComposite %u32vec4 %u32_0 %u32_1 %u32_2 %u32_3 +%u32vec4_1234 = OpConstantComposite %u32vec4 %u32_1 %u32_2 %u32_3 %u32_4 + +%s32vec2_01 = OpConstantComposite %s32vec2 %s32_0 %s32_1 +%s32vec2_12 = OpConstantComposite %s32vec2 %s32_1 %s32_2 +%s32vec3_012 = OpConstantComposite %s32vec3 %s32_0 %s32_1 %s32_2 +%s32vec3_123 = OpConstantComposite %s32vec3 %s32_1 %s32_2 %s32_3 +%s32vec4_0123 = OpConstantComposite %s32vec4 %s32_0 %s32_1 %s32_2 %s32_3 +%s32vec4_1234 = OpConstantComposite %s32vec4 %s32_1 %s32_2 %s32_3 %s32_4 + +%f32vec2_01 = OpConstantComposite %f32vec2 %f32_0 %f32_1 +%f32vec2_12 = OpConstantComposite %f32vec2 %f32_1 %f32_2 +%f32vec3_012 = OpConstantComposite %f32vec3 %f32_0 %f32_1 %f32_2 +%f32vec3_123 = OpConstantComposite %f32vec3 %f32_1 %f32_2 %f32_3 +%f32vec4_0123 = OpConstantComposite %f32vec4 %f32_0 %f32_1 %f32_2 %f32_3 +%f32vec4_1234 = OpConstantComposite %f32vec4 %f32_1 %f32_2 %f32_3 %f32_4 + +%main = OpFunction %void None %func +%main_entry = OpLabel)"; + + const std::string suffix = +R"( +OpReturn +OpFunctionEnd)"; + + TestEncodeDecode(prefix + body + suffix); +} + TEST(Markv, U32Literal) { TestEncodeDecode(R"( OpCapability Shader @@ -322,6 +408,39 @@ OpFunctionEnd )"); } +TEST(Markv, WithMultipleFunctions) { + TestEncodeDecode(R"( +OpCapability Addresses +OpCapability Kernel +OpCapability GenericPointer +OpCapability Linkage +OpMemoryModel Physical32 OpenCL +%f32 = OpTypeFloat 32 +%one = OpConstant %f32 1 +%void = OpTypeVoid +%void_func = OpTypeFunction %void +%f32_func = OpTypeFunction %f32 %f32 +%sqr_plus_one = OpFunction %f32 None %f32_func +%x = OpFunctionParameter %f32 +%100 = OpLabel +%x2 = OpFMul %f32 %x %x +%x2p1 = OpFunctionCall %f32 %plus_one %x2 +OpReturnValue %x2p1 +OpFunctionEnd +%plus_one = OpFunction %f32 None %f32_func +%y = OpFunctionParameter %f32 +%200 = OpLabel +%yp1 = OpFAdd %f32 %y %one +OpReturnValue %yp1 +OpFunctionEnd +%main = OpFunction %void None %void_func +%entry_main = OpLabel +%1p1 = OpFunctionCall %f32 %sqr_plus_one %one +OpReturn +OpFunctionEnd +)"); +} + TEST(Markv, ForwardDeclaredId) { TestEncodeDecode(R"( OpCapability Addresses @@ -430,4 +549,304 @@ OpFunctionEnd )"); } +TEST(Markv, F32Mul) { + TestEncodeDecodeShaderMainBody(R"( +%val1 = OpFMul %f32 %f32_0 %f32_1 +%val2 = OpFMul %f32 %f32_2 %f32_0 +%val3 = OpFMul %f32 %f32_pi %f32_2 +%val4 = OpFMul %f32 %f32_1 %f32_1 +)"); +} + +TEST(Markv, U32Mul) { + TestEncodeDecodeShaderMainBody(R"( +%val1 = OpIMul %u32 %u32_0 %u32_1 +%val2 = OpIMul %u32 %u32_2 %u32_0 +%val3 = OpIMul %u32 %u32_3 %u32_2 +%val4 = OpIMul %u32 %u32_1 %u32_1 +)"); +} + +TEST(Markv, S32Mul) { + TestEncodeDecodeShaderMainBody(R"( +%val1 = OpIMul %s32 %s32_0 %s32_1 +%val2 = OpIMul %s32 %s32_2 %s32_0 +%val3 = OpIMul %s32 %s32_m1 %s32_2 +%val4 = OpIMul %s32 %s32_1 %s32_1 +)"); +} + +TEST(Markv, F32Add) { + TestEncodeDecodeShaderMainBody(R"( +%val1 = OpFAdd %f32 %f32_0 %f32_1 +%val2 = OpFAdd %f32 %f32_2 %f32_0 +%val3 = OpFAdd %f32 %f32_pi %f32_2 +%val4 = OpFAdd %f32 %f32_1 %f32_1 +)"); +} + +TEST(Markv, U32Add) { + TestEncodeDecodeShaderMainBody(R"( +%val1 = OpIAdd %u32 %u32_0 %u32_1 +%val2 = OpIAdd %u32 %u32_2 %u32_0 +%val3 = OpIAdd %u32 %u32_3 %u32_2 +%val4 = OpIAdd %u32 %u32_1 %u32_1 +)"); +} + +TEST(Markv, S32Add) { + TestEncodeDecodeShaderMainBody(R"( +%val1 = OpIAdd %s32 %s32_0 %s32_1 +%val2 = OpIAdd %s32 %s32_2 %s32_0 +%val3 = OpIAdd %s32 %s32_m1 %s32_2 +%val4 = OpIAdd %s32 %s32_1 %s32_1 +)"); +} + +TEST(Markv, F32Dot) { + TestEncodeDecodeShaderMainBody(R"( +%dot2_1 = OpDot %f32 %f32vec2_01 %f32vec2_12 +%dot2_2 = OpDot %f32 %f32vec2_01 %f32vec2_01 +%dot2_3 = OpDot %f32 %f32vec2_12 %f32vec2_12 +%dot3_1 = OpDot %f32 %f32vec3_012 %f32vec3_123 +%dot3_2 = OpDot %f32 %f32vec3_012 %f32vec3_012 +%dot3_3 = OpDot %f32 %f32vec3_123 %f32vec3_123 +%dot4_1 = OpDot %f32 %f32vec4_0123 %f32vec4_1234 +%dot4_2 = OpDot %f32 %f32vec4_0123 %f32vec4_0123 +%dot4_3 = OpDot %f32 %f32vec4_1234 %f32vec4_1234 +)"); +} + +TEST(Markv, F32VectorCompositeConstruct) { + TestEncodeDecodeShaderMainBody(R"( +%cc1 = OpCompositeConstruct %f32vec4 %f32vec2_01 %f32vec2_12 +%cc2 = OpCompositeConstruct %f32vec3 %f32vec2_01 %f32_2 +%cc3 = OpCompositeConstruct %f32vec2 %f32_1 %f32_2 +%cc4 = OpCompositeConstruct %f32vec4 %f32_1 %f32_2 %cc3 +)"); +} + +TEST(Markv, U32VectorCompositeConstruct) { + TestEncodeDecodeShaderMainBody(R"( +%cc1 = OpCompositeConstruct %u32vec4 %u32vec2_01 %u32vec2_12 +%cc2 = OpCompositeConstruct %u32vec3 %u32vec2_01 %u32_2 +%cc3 = OpCompositeConstruct %u32vec2 %u32_1 %u32_2 +%cc4 = OpCompositeConstruct %u32vec4 %u32_1 %u32_2 %cc3 +)"); +} + +TEST(Markv, S32VectorCompositeConstruct) { + TestEncodeDecodeShaderMainBody(R"( +%cc1 = OpCompositeConstruct %u32vec4 %u32vec2_01 %u32vec2_12 +%cc2 = OpCompositeConstruct %u32vec3 %u32vec2_01 %u32_2 +%cc3 = OpCompositeConstruct %u32vec2 %u32_1 %u32_2 +%cc4 = OpCompositeConstruct %u32vec4 %u32_1 %u32_2 %cc3 +)"); +} + +TEST(Markv, F32VectorCompositeExtract) { + TestEncodeDecodeShaderMainBody(R"( +%f32vec4_3210 = OpCompositeConstruct %f32vec4 %f32_3 %f32_2 %f32_1 %f32_0 +%f32vec3_013 = OpCompositeExtract %f32vec3 %f32vec4_0123 0 1 3 +)"); +} + +TEST(Markv, F32VectorComparison) { + TestEncodeDecodeShaderMainBody(R"( +%f32vec4_3210 = OpCompositeConstruct %f32vec4 %f32_3 %f32_2 %f32_1 %f32_0 +%c1 = OpFOrdEqual %boolvec4 %f32vec4_0123 %f32vec4_3210 +%c2 = OpFUnordEqual %boolvec4 %f32vec4_0123 %f32vec4_3210 +%c3 = OpFOrdNotEqual %boolvec4 %f32vec4_0123 %f32vec4_3210 +%c4 = OpFUnordNotEqual %boolvec4 %f32vec4_0123 %f32vec4_3210 +%c5 = OpFOrdLessThan %boolvec4 %f32vec4_0123 %f32vec4_3210 +%c6 = OpFUnordLessThan %boolvec4 %f32vec4_0123 %f32vec4_3210 +%c7 = OpFOrdGreaterThan %boolvec4 %f32vec4_0123 %f32vec4_3210 +%c8 = OpFUnordGreaterThan %boolvec4 %f32vec4_0123 %f32vec4_3210 +%c9 = OpFOrdLessThanEqual %boolvec4 %f32vec4_0123 %f32vec4_3210 +%c10 = OpFUnordLessThanEqual %boolvec4 %f32vec4_0123 %f32vec4_3210 +%c11 = OpFOrdGreaterThanEqual %boolvec4 %f32vec4_0123 %f32vec4_3210 +%c12 = OpFUnordGreaterThanEqual %boolvec4 %f32vec4_0123 %f32vec4_3210 +)"); +} + +TEST(Markv, VectorShuffle) { + TestEncodeDecodeShaderMainBody(R"( +%f32vec4_3210 = OpCompositeConstruct %f32vec4 %f32_3 %f32_2 %f32_1 %f32_0 +%sh1 = OpVectorShuffle %f32vec2 %f32vec4_0123 %f32vec4_3210 3 6 +%sh2 = OpVectorShuffle %f32vec3 %f32vec2_01 %f32vec4_3210 0 3 4 +)"); +} + +TEST(Markv, VectorTimesScalar) { + TestEncodeDecodeShaderMainBody(R"( +%f32vec4_3210 = OpCompositeConstruct %f32vec4 %f32_3 %f32_2 %f32_1 %f32_0 +%res1 = OpVectorTimesScalar %f32vec4 %f32vec4_0123 %f32_2 +%res2 = OpVectorTimesScalar %f32vec4 %f32vec4_3210 %f32_2 +%res3 = OpVectorTimesScalar %u32vec3 %u32vec3_012 %u32_2 +%res4 = OpVectorTimesScalar %s32vec2 %s32vec2_01 %s32_2 +)"); +} + +TEST(Markv, SpirvSpecSample) { + TestEncodeDecode(R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" %31 %33 %42 %57 + OpExecutionMode %4 OriginLowerLeft + +; Debug information + OpSource GLSL 450 + OpName %4 "main" + OpName %9 "scale" + OpName %17 "S" + OpMemberName %17 0 "b" + OpMemberName %17 1 "v" + OpMemberName %17 2 "i" + OpName %18 "blockName" + OpMemberName %18 0 "s" + OpMemberName %18 1 "cond" + OpName %20 "" + OpName %31 "color" + OpName %33 "color1" + OpName %42 "color2" + OpName %48 "i" + OpName %57 "multiplier" + +; Annotations (non-debug) + OpDecorate %15 ArrayStride 16 + OpMemberDecorate %17 0 Offset 0 + OpMemberDecorate %17 1 Offset 16 + OpMemberDecorate %17 2 Offset 96 + OpMemberDecorate %18 0 Offset 0 + OpMemberDecorate %18 1 Offset 112 + OpDecorate %18 Block + OpDecorate %20 DescriptorSet 0 + OpDecorate %42 NoPerspective + +; All types, variables, and constants + %2 = OpTypeVoid + %3 = OpTypeFunction %2 ; void () + %6 = OpTypeFloat 32 ; 32-bit float + %7 = OpTypeVector %6 4 ; vec4 + %8 = OpTypePointer Function %7 ; function-local vec4* + %10 = OpConstant %6 1 + %11 = OpConstant %6 2 + %12 = OpConstantComposite %7 %10 %10 %11 %10 ; vec4(1.0, 1.0, 2.0, 1.0) + %13 = OpTypeInt 32 0 ; 32-bit int, sign-less + %14 = OpConstant %13 5 + %15 = OpTypeArray %7 %14 + %16 = OpTypeInt 32 1 + %17 = OpTypeStruct %13 %15 %16 + %18 = OpTypeStruct %17 %13 + %19 = OpTypePointer Uniform %18 + %20 = OpVariable %19 Uniform + %21 = OpConstant %16 1 + %22 = OpTypePointer Uniform %13 + %25 = OpTypeBool + %26 = OpConstant %13 0 + %30 = OpTypePointer Output %7 + %31 = OpVariable %30 Output + %32 = OpTypePointer Input %7 + %33 = OpVariable %32 Input + %35 = OpConstant %16 0 + %36 = OpConstant %16 2 + %37 = OpTypePointer Uniform %7 + %42 = OpVariable %32 Input + %47 = OpTypePointer Function %16 + %55 = OpConstant %16 4 + %57 = OpVariable %32 Input + +; All functions + %4 = OpFunction %2 None %3 ; main() + %5 = OpLabel + %9 = OpVariable %8 Function + %48 = OpVariable %47 Function + OpStore %9 %12 + %23 = OpAccessChain %22 %20 %21 ; location of cond + %24 = OpLoad %13 %23 ; load 32-bit int from cond + %27 = OpINotEqual %25 %24 %26 ; convert to bool + OpSelectionMerge %29 None ; structured if + OpBranchConditional %27 %28 %41 ; if cond + %28 = OpLabel ; then + %34 = OpLoad %7 %33 + %38 = OpAccessChain %37 %20 %35 %21 %36 ; s.v[2] + %39 = OpLoad %7 %38 + %40 = OpFAdd %7 %34 %39 + OpStore %31 %40 + OpBranch %29 + %41 = OpLabel ; else + %43 = OpLoad %7 %42 + %44 = OpExtInst %7 %1 Sqrt %43 ; extended instruction sqrt + %45 = OpLoad %7 %9 + %46 = OpFMul %7 %44 %45 + OpStore %31 %46 + OpBranch %29 + %29 = OpLabel ; endif + OpStore %48 %35 + OpBranch %49 + %49 = OpLabel + OpLoopMerge %51 %52 None ; structured loop + OpBranch %53 + %53 = OpLabel + %54 = OpLoad %16 %48 + %56 = OpSLessThan %25 %54 %55 ; i < 4 ? + OpBranchConditional %56 %50 %51 ; body or break + %50 = OpLabel ; body + %58 = OpLoad %7 %57 + %59 = OpLoad %7 %31 + %60 = OpFMul %7 %59 %58 + OpStore %31 %60 + OpBranch %52 + %52 = OpLabel ; continue target + %61 = OpLoad %16 %48 + %62 = OpIAdd %16 %61 %21 ; ++i + OpStore %48 %62 + OpBranch %49 ; loop back + %51 = OpLabel ; loop merge point + OpReturn + OpFunctionEnd +)"); +} + +TEST(Markv, SampleFromDeadBranchEliminationTest) { + TestEncodeDecode(R"( +OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %gl_FragColor +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 140 +OpName %main "main" +OpName %gl_FragColor "gl_FragColor" +%void = OpTypeVoid +%5 = OpTypeFunction %void +%bool = OpTypeBool +%true = OpConstantTrue %bool +%float = OpTypeFloat 32 +%v4float = OpTypeVector %float 4 +%_ptr_Function_v4float = OpTypePointer Function %v4float +%float_0 = OpConstant %float 0 +%12 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 +%float_1 = OpConstant %float 1 +%14 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1 +%_ptr_Output_v4float = OpTypePointer Output %v4float +%gl_FragColor = OpVariable %_ptr_Output_v4float Output +%_ptr_Input_v4float = OpTypePointer Input %v4float +%main = OpFunction %void None %5 +%17 = OpLabel +OpSelectionMerge %18 None +OpBranchConditional %true %19 %20 +%19 = OpLabel +OpBranch %18 +%20 = OpLabel +OpBranch %18 +%18 = OpLabel +%21 = OpPhi %v4float %12 %19 %14 %20 +OpStore %gl_FragColor %21 +OpReturn +OpFunctionEnd +)"); +} + } // namespace diff --git a/tools/stats/stats_analyzer.cpp b/tools/stats/stats_analyzer.cpp index 3f2e7ec0e..23c71b596 100644 --- a/tools/stats/stats_analyzer.cpp +++ b/tools/stats/stats_analyzer.cpp @@ -23,14 +23,26 @@ #include "spirv/1.2/spirv.h" #include "source/enum_string_mapping.h" +#include "source/comp/markv_autogen.h" #include "source/opcode.h" #include "source/operand.h" #include "source/spirv_constant.h" +#include "source/util/huffman_codec.h" using libspirv::SpirvStats; +using spvutils::HuffmanCodec; namespace { +// Signals that the value is not in the coding scheme and a fallback method +// needs to be used. +const uint64_t kMarkvNoneOfTheAbove = GetMarkvNonOfTheAbove(); + +inline uint32_t CombineOpcodeAndNumOperands(uint32_t opcode, + uint32_t num_operands) { + return opcode | (num_operands << 16); +} + // Returns all SPIR-V v1.2 opcodes. std::vector GetAllOpcodes() { return std::vector({ @@ -599,23 +611,30 @@ void StatsAnalyzer::WriteCodegenOpcodeAndNumOperandsHist(std::ostream& out) { total += kv.second; } + uint32_t left_out = 0; + for (const auto& kv : stats_.opcode_and_num_operands_hist) { const uint32_t count = kv.second; const double kFrequentEnoughToAnalyze = 0.001; - if (double(count) / double(total) < kFrequentEnoughToAnalyze) continue; const uint32_t opcode_and_num_operands = kv.first; const uint32_t opcode = opcode_and_num_operands & 0xFFFF; const uint32_t num_operands = opcode_and_num_operands >> 16; - if (opcode == SpvOpTypeStruct) + if (opcode == SpvOpTypeStruct || + double(count) / double(total) < kFrequentEnoughToAnalyze) { + left_out += count; continue; + } out << " { CombineOpcodeAndNumOperands(SpvOp" << spvOpcodeString(SpvOp(opcode)) << ", " << num_operands << "), " << count << " },\n"; } - out << " { kMarkvNoneOfTheAbove, " << 1 + int(total * 0.05) << " },\n"; + // Heuristic. + const uint32_t none_of_the_above = + std::max(1, int(left_out + total * 0.01)); + out << " { kMarkvNoneOfTheAbove, " << none_of_the_above << " },\n"; out << " });\n}\n"; } @@ -628,7 +647,7 @@ void StatsAnalyzer::WriteCodegenOpcodeAndNumOperandsMarkovHuffmanCodecs( for (const auto& kv : stats_.opcode_and_num_operands_markov_hist) { const uint32_t prev_opcode = kv.first; - const double kFrequentEnoughToAnalyze = 0.001; + const double kFrequentEnoughToAnalyze = 0.01; if (opcode_freq_[prev_opcode] < kFrequentEnoughToAnalyze) continue; const std::unordered_map& hist = kv.second; @@ -638,10 +657,9 @@ void StatsAnalyzer::WriteCodegenOpcodeAndNumOperandsMarkovHuffmanCodecs( total += pair.second; } - out << " {\n"; - out << " std::unique_ptr> " - << "codec(new HuffmanCodec({\n"; + uint32_t left_out = 0; + std::map processed_hist; for (const auto& pair : hist) { const uint32_t opcode_and_num_operands = pair.first; const uint32_t opcode = opcode_and_num_operands & 0xFFFF; @@ -654,17 +672,25 @@ void StatsAnalyzer::WriteCodegenOpcodeAndNumOperandsMarkovHuffmanCodecs( const double posterior_freq = double(count) / double(total); if (opcode_freq_[opcode] < kFrequentEnoughToAnalyze && - posterior_freq < kFrequentEnoughToAnalyze) continue; - - total += count; - out << " { CombineOpcodeAndNumOperands(SpvOp" - << spvOpcodeString(SpvOp(opcode)) - << ", " << num_operands << "), " << count << " },\n"; + posterior_freq < kFrequentEnoughToAnalyze) { + left_out += count; + continue; + } + processed_hist.emplace(CombineOpcodeAndNumOperands(opcode, num_operands), + count); } - out << " { kMarkvNoneOfTheAbove, " << 1 + int(total * 0.05) << " },\n"; + // Heuristic. + processed_hist.emplace(kMarkvNoneOfTheAbove, + std::max(1, int(left_out + total * 0.01))); - out << " }));\n" << std::endl; + HuffmanCodec codec(processed_hist); + + out << " {\n"; + out << " std::unique_ptr> " + << "codec(new HuffmanCodec"; + out << codec.SerializeToText(4); + out << ");\n" << std::endl; out << " codecs.emplace(SpvOp" << GetOpcodeString(prev_opcode) << ", std::move(codec));\n"; out << " }\n\n"; @@ -695,22 +721,31 @@ void StatsAnalyzer::WriteCodegenLiteralStringHuffmanCodecs(std::ostream& out) { total += pair.second; } - out << " {\n"; - out << " std::unique_ptr> " - << "codec(new HuffmanCodec({\n"; + uint32_t left_out = 0; + + std::map processed_hist; for (const auto& pair : hist) { const uint32_t count = pair.second; const double freq = double(count) / double(total); const double kStringFrequentEnoughToAnalyze = 0.001; - if (freq < kStringFrequentEnoughToAnalyze) continue; - out << " { std::string(\"" << pair.first << "\"), " << count - << " },\n"; + if (freq < kStringFrequentEnoughToAnalyze) { + left_out += count; + continue; + } + processed_hist.emplace(pair.first, count); } - out << " { std::string(\"kMarkvNoneOfTheAbove\"), " - << 1 + int(total * 0.05) << " },\n"; + // Heuristic. + processed_hist.emplace("kMarkvNoneOfTheAbove", + std::max(1, int(left_out + total * 0.01))); - out << " }));\n" << std::endl; + HuffmanCodec codec(processed_hist); + + out << " {\n"; + out << " std::unique_ptr> " + << "codec(new HuffmanCodec"; + out << codec.SerializeToText(4); + out << ");\n" << std::endl; out << " codecs.emplace(SpvOp" << spvOpcodeString(SpvOp(opcode)) << ", std::move(codec));\n"; out << " }\n\n"; @@ -741,21 +776,32 @@ void StatsAnalyzer::WriteCodegenNonIdWordHuffmanCodecs(std::ostream& out) { total += pair.second; } - out << " {\n"; - out << " std::unique_ptr> " - << "codec(new HuffmanCodec({\n"; + uint32_t left_out = 0; + + std::map processed_hist; for (const auto& pair : hist) { const uint32_t word = pair.first; const uint32_t count = pair.second; const double freq = double(count) / double(total); - const double kWordFrequentEnoughToAnalyze = 0.001; - if (freq < kWordFrequentEnoughToAnalyze) continue; - out << " { " << word << ", " << count << " },\n"; + const double kWordFrequentEnoughToAnalyze = 0.01; + if (freq < kWordFrequentEnoughToAnalyze) { + left_out += count; + continue; + } + processed_hist.emplace(word, count); } - out << " { kMarkvNoneOfTheAbove, " << 1 + int(total * 0.05) << " },\n"; + // Heuristic. + processed_hist.emplace(kMarkvNoneOfTheAbove, + std::max(1, int(left_out + total * 0.01))); - out << " }));\n" << std::endl; + HuffmanCodec codec(processed_hist); + + out << " {\n"; + out << " std::unique_ptr> " + << "codec(new HuffmanCodec"; + out << codec.SerializeToText(4); + out << ");\n" << std::endl; out << " codecs.emplace(std::pair(SpvOp" << spvOpcodeString(SpvOp(opcode)) << ", " << index << "), std::move(codec));\n"; @@ -778,31 +824,43 @@ void StatsAnalyzer::WriteCodegenIdDescriptorHuffmanCodecs( const uint32_t opcode = opcode_and_index.first; const uint32_t index = opcode_and_index.second; - const double kOpcodeFrequentEnoughToAnalyze = 0.001; + const double kOpcodeFrequentEnoughToAnalyze = 0.01; if (opcode_freq_[opcode] < kOpcodeFrequentEnoughToAnalyze) continue; const std::map& hist = kv.second; + uint32_t total = 0; for (const auto& pair : hist) { total += pair.second; } - out << " {\n"; - out << " std::unique_ptr> " - << "codec(new HuffmanCodec({\n"; + uint32_t left_out = 0; + + std::map processed_hist; for (const auto& pair : hist) { const uint32_t descriptor = pair.first; const uint32_t count = pair.second; const double freq = double(count) / double(total); - const double kDescriptorFrequentEnoughToAnalyze = 0.005; - if (freq < kDescriptorFrequentEnoughToAnalyze) continue; - out << " { " << descriptor << ", " << count << " },\n"; + const double kDescriptorFrequentEnoughToAnalyze = 0.01; + if (freq < kDescriptorFrequentEnoughToAnalyze) { + left_out += count; + continue; + } + processed_hist.emplace(descriptor, count); } - out << " { kMarkvNoneOfTheAbove, " << 1 + int(total * 0.05) << " },\n"; + // Heuristic. + processed_hist.emplace(kMarkvNoneOfTheAbove, + std::max(1, int(left_out + total * 0.01))); - out << " }));\n" << std::endl; + HuffmanCodec codec(processed_hist); + + out << " {\n"; + out << " std::unique_ptr> " + << "codec(new HuffmanCodec"; + out << codec.SerializeToText(4); + out << ");\n" << std::endl; out << " codecs.emplace(std::pair(SpvOp" << spvOpcodeString(SpvOp(opcode)) << ", " << index << "), std::move(codec));\n";