Update MARK-V to version 1.01
authorAndrey Tuganov <andreyt@google.com>
Wed, 9 Aug 2017 18:01:12 +0000 (14:01 -0400)
committerDavid Neto <dneto@google.com>
Wed, 6 Sep 2017 20:03:16 +0000 (16:03 -0400)
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

12 files changed:
source/comp/CMakeLists.txt
source/comp/markv_autogen.cpp [new file with mode: 0644]
source/comp/markv_autogen.h [new file with mode: 0644]
source/comp/markv_autogen.inc [new file with mode: 0644]
source/comp/markv_codec.cpp
source/operand.cpp
source/operand.h
source/util/huffman_codec.h
source/util/move_to_front.h
source/validate_id.cpp
test/comp/markv_codec_test.cpp
tools/stats/stats_analyzer.cpp

index 11def56aaf6dae831b22e9550ed781a6f50cdbf9..86f8c4ebfc3a74d897336eea037ee302f712b418 100644 (file)
@@ -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 (file)
index 0000000..7db3c52
--- /dev/null
@@ -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 <algorithm>
+#include <map>
+#include <memory>
+#include <vector>
+#include <unordered_map>
+
+#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 <SHADER_CORPUS_DIR> -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 (file)
index 0000000..a7a21f7
--- /dev/null
@@ -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 <map>
+#include <memory>
+#include <numeric>
+
+#include "util/huffman_codec.h"
+
+inline uint64_t GetMarkvNonOfTheAbove() {
+  // Magic number.
+  return 1111111111111111111;
+}
+
+std::map<uint64_t, uint32_t> GetOpcodeAndNumOperandsHist();
+
+std::map<uint32_t, std::unique_ptr<spvutils::HuffmanCodec<uint64_t>>>
+GetOpcodeAndNumOperandsMarkovHuffmanCodecs();
+
+std::map<uint32_t, std::unique_ptr<spvutils::HuffmanCodec<std::string>>>
+GetLiteralStringHuffmanCodecs();
+
+std::map<std::pair<uint32_t, uint32_t>,
+    std::unique_ptr<spvutils::HuffmanCodec<uint64_t>>>
+    GetNonIdWordHuffmanCodecs();
+
+    std::map<std::pair<uint32_t, uint32_t>,
+    std::unique_ptr<spvutils::HuffmanCodec<uint64_t>>>
+    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 (file)
index 0000000..83a7fbd
--- /dev/null
@@ -0,0 +1,3920 @@
+
+std::map<uint64_t, uint32_t> GetOpcodeAndNumOperandsHist() {
+  return std::map<uint64_t, uint32_t>({
+    { 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<uint32_t, std::unique_ptr<HuffmanCodec<uint64_t>>>
+GetOpcodeAndNumOperandsMarkovHuffmanCodecs() {
+  std::map<uint32_t, std::unique_ptr<HuffmanCodec<uint64_t>>> codecs;
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, std::unique_ptr<HuffmanCodec<std::string>>>
+GetLiteralStringHuffmanCodecs() {
+  std::map<uint32_t, std::unique_ptr<HuffmanCodec<std::string>>> codecs;
+  {
+    std::unique_ptr<HuffmanCodec<std::string>> codec(new HuffmanCodec<std::string>(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<HuffmanCodec<std::string>> codec(new HuffmanCodec<std::string>(3, {
+      {"", 0, 0},
+      {"GLSL.std.450", 0, 0},
+      {"kMarkvNoneOfTheAbove", 0, 0},
+      {"", 1, 2},
+    }));
+
+    codecs.emplace(SpvOpExtInstImport, std::move(codec));
+  }
+
+  return codecs;
+}
+
+std::map<std::pair<uint32_t, uint32_t>, std::unique_ptr<HuffmanCodec<uint64_t>>>
+GetNonIdWordHuffmanCodecs() {
+  std::map<std::pair<uint32_t, uint32_t>, std::unique_ptr<HuffmanCodec<uint64_t>>> codecs;
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpExtInst, 3), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(3, {
+      {0, 0, 0},
+      {0, 0, 0},
+      {1111111111111111111, 0, 0},
+      {0, 1, 2},
+    }));
+
+    codecs.emplace(std::pair<uint32_t, uint32_t>(SpvOpMemoryModel, 0), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(3, {
+      {0, 0, 0},
+      {1, 0, 0},
+      {1111111111111111111, 0, 0},
+      {0, 1, 2},
+    }));
+
+    codecs.emplace(std::pair<uint32_t, uint32_t>(SpvOpMemoryModel, 1), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(5, {
+      {0, 0, 0},
+      {0, 0, 0},
+      {4, 0, 0},
+      {1111111111111111111, 0, 0},
+      {0, 1, 3},
+      {0, 2, 4},
+    }));
+
+    codecs.emplace(std::pair<uint32_t, uint32_t>(SpvOpEntryPoint, 0), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(3, {
+      {0, 0, 0},
+      {7, 0, 0},
+      {1111111111111111111, 0, 0},
+      {0, 1, 2},
+    }));
+
+    codecs.emplace(std::pair<uint32_t, uint32_t>(SpvOpExecutionMode, 1), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpExecutionMode, 2), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(5, {
+      {0, 0, 0},
+      {1, 0, 0},
+      {32, 0, 0},
+      {1111111111111111111, 0, 0},
+      {0, 2, 3},
+      {0, 1, 4},
+    }));
+
+    codecs.emplace(std::pair<uint32_t, uint32_t>(SpvOpCapability, 0), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(3, {
+      {0, 0, 0},
+      {32, 0, 0},
+      {1111111111111111111, 0, 0},
+      {0, 1, 2},
+    }));
+
+    codecs.emplace(std::pair<uint32_t, uint32_t>(SpvOpTypeInt, 1), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(5, {
+      {0, 0, 0},
+      {0, 0, 0},
+      {1, 0, 0},
+      {1111111111111111111, 0, 0},
+      {0, 2, 3},
+      {0, 1, 4},
+    }));
+
+    codecs.emplace(std::pair<uint32_t, uint32_t>(SpvOpTypeInt, 2), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(3, {
+      {0, 0, 0},
+      {32, 0, 0},
+      {1111111111111111111, 0, 0},
+      {0, 1, 2},
+    }));
+
+    codecs.emplace(std::pair<uint32_t, uint32_t>(SpvOpTypeFloat, 1), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpTypeVector, 2), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpTypeMatrix, 2), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpTypeImage, 2), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(5, {
+      {0, 0, 0},
+      {0, 0, 0},
+      {1, 0, 0},
+      {1111111111111111111, 0, 0},
+      {0, 2, 3},
+      {0, 1, 4},
+    }));
+
+    codecs.emplace(std::pair<uint32_t, uint32_t>(SpvOpTypeImage, 3), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(3, {
+      {0, 0, 0},
+      {0, 0, 0},
+      {1111111111111111111, 0, 0},
+      {0, 1, 2},
+    }));
+
+    codecs.emplace(std::pair<uint32_t, uint32_t>(SpvOpTypeImage, 4), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(3, {
+      {0, 0, 0},
+      {0, 0, 0},
+      {1111111111111111111, 0, 0},
+      {0, 1, 2},
+    }));
+
+    codecs.emplace(std::pair<uint32_t, uint32_t>(SpvOpTypeImage, 5), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(3, {
+      {0, 0, 0},
+      {1, 0, 0},
+      {1111111111111111111, 0, 0},
+      {0, 1, 2},
+    }));
+
+    codecs.emplace(std::pair<uint32_t, uint32_t>(SpvOpTypeImage, 6), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(3, {
+      {0, 0, 0},
+      {0, 0, 0},
+      {1111111111111111111, 0, 0},
+      {0, 1, 2},
+    }));
+
+    codecs.emplace(std::pair<uint32_t, uint32_t>(SpvOpTypeImage, 7), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpTypePointer, 1), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpConstant, 2), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(3, {
+      {0, 0, 0},
+      {0, 0, 0},
+      {1111111111111111111, 0, 0},
+      {0, 1, 2},
+    }));
+
+    codecs.emplace(std::pair<uint32_t, uint32_t>(SpvOpFunction, 2), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpVariable, 2), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpDecorate, 1), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpDecorate, 2), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpMemberDecorate, 1), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpMemberDecorate, 2), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpMemberDecorate, 3), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpVectorShuffle, 4), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpVectorShuffle, 5), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpVectorShuffle, 6), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpVectorShuffle, 7), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpCompositeExtract, 3), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpCompositeExtract, 4), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpCompositeExtract, 5), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpCompositeInsert, 4), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpCompositeInsert, 5), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(3, {
+      {0, 0, 0},
+      {1, 0, 0},
+      {1111111111111111111, 0, 0},
+      {0, 1, 2},
+    }));
+
+    codecs.emplace(std::pair<uint32_t, uint32_t>(SpvOpImageSampleImplicitLod, 4), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(5, {
+      {0, 0, 0},
+      {2, 0, 0},
+      {10, 0, 0},
+      {1111111111111111111, 0, 0},
+      {0, 2, 3},
+      {0, 1, 4},
+    }));
+
+    codecs.emplace(std::pair<uint32_t, uint32_t>(SpvOpImageSampleExplicitLod, 4), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(3, {
+      {0, 0, 0},
+      {2, 0, 0},
+      {1111111111111111111, 0, 0},
+      {0, 1, 2},
+    }));
+
+    codecs.emplace(std::pair<uint32_t, uint32_t>(SpvOpImageSampleDrefExplicitLod, 5), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(3, {
+      {0, 0, 0},
+      {0, 0, 0},
+      {1111111111111111111, 0, 0},
+      {0, 1, 2},
+    }));
+
+    codecs.emplace(std::pair<uint32_t, uint32_t>(SpvOpSelectionMerge, 1), std::move(codec));
+  }
+
+  return codecs;
+}
+
+std::map<std::pair<uint32_t, uint32_t>, std::unique_ptr<HuffmanCodec<uint64_t>>>
+GetIdDescriptorHuffmanCodecs() {
+  std::map<std::pair<uint32_t, uint32_t>, std::unique_ptr<HuffmanCodec<uint64_t>>> codecs;
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpExtInst, 0), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(3, {
+      {0, 0, 0},
+      {2161102232, 0, 0},
+      {1111111111111111111, 0, 0},
+      {0, 2, 1},
+    }));
+
+    codecs.emplace(std::pair<uint32_t, uint32_t>(SpvOpExtInst, 1), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(3, {
+      {0, 0, 0},
+      {4228502127, 0, 0},
+      {1111111111111111111, 0, 0},
+      {0, 1, 2},
+    }));
+
+    codecs.emplace(std::pair<uint32_t, uint32_t>(SpvOpExtInst, 2), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpExtInst, 4), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpExtInst, 5), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpExtInst, 6), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpTypePointer, 0), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpTypePointer, 2), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpConstant, 0), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpConstant, 1), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpConstantComposite, 0), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpConstantComposite, 1), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpConstantComposite, 2), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpConstantComposite, 3), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpConstantComposite, 4), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpConstantComposite, 5), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpVariable, 0), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpVariable, 1), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpLoad, 0), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpLoad, 1), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpLoad, 2), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpStore, 0), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpStore, 1), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpAccessChain, 0), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpAccessChain, 1), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpAccessChain, 2), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpAccessChain, 3), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpAccessChain, 4), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpAccessChain, 5), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(5, {
+      {0, 0, 0},
+      {142465290, 0, 0},
+      {1782996825, 0, 0},
+      {1111111111111111111, 0, 0},
+      {0, 2, 1},
+      {0, 4, 3},
+    }));
+
+    codecs.emplace(std::pair<uint32_t, uint32_t>(SpvOpAccessChain, 6), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpVectorShuffle, 0), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpVectorShuffle, 1), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpVectorShuffle, 2), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpVectorShuffle, 3), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpCompositeConstruct, 0), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(5, {
+      {0, 0, 0},
+      {1319785741, 0, 0},
+      {3753486980, 0, 0},
+      {1111111111111111111, 0, 0},
+      {0, 2, 1},
+      {0, 3, 4},
+    }));
+
+    codecs.emplace(std::pair<uint32_t, uint32_t>(SpvOpCompositeConstruct, 1), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpCompositeConstruct, 2), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpCompositeConstruct, 3), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpCompositeConstruct, 4), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpCompositeConstruct, 5), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpCompositeExtract, 0), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(1, {
+      {0, 0, 0},
+      {1111111111111111111, 0, 0},
+    }));
+
+    codecs.emplace(std::pair<uint32_t, uint32_t>(SpvOpCompositeExtract, 1), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpCompositeExtract, 2), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpCompositeInsert, 0), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(1, {
+      {0, 0, 0},
+      {1111111111111111111, 0, 0},
+    }));
+
+    codecs.emplace(std::pair<uint32_t, uint32_t>(SpvOpCompositeInsert, 1), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpCompositeInsert, 2), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpCompositeInsert, 3), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(3, {
+      {0, 0, 0},
+      {3334207724, 0, 0},
+      {1111111111111111111, 0, 0},
+      {0, 1, 2},
+    }));
+
+    codecs.emplace(std::pair<uint32_t, uint32_t>(SpvOpImageSampleImplicitLod, 0), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpImageSampleImplicitLod, 1), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpImageSampleImplicitLod, 2), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpImageSampleImplicitLod, 3), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpImageSampleImplicitLod, 5), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpFAdd, 0), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(1, {
+      {0, 0, 0},
+      {1111111111111111111, 0, 0},
+    }));
+
+    codecs.emplace(std::pair<uint32_t, uint32_t>(SpvOpFAdd, 1), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpFAdd, 2), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpFAdd, 3), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpFSub, 0), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpFSub, 1), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpFSub, 2), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpFSub, 3), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpFMul, 0), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(1, {
+      {0, 0, 0},
+      {1111111111111111111, 0, 0},
+    }));
+
+    codecs.emplace(std::pair<uint32_t, uint32_t>(SpvOpFMul, 1), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpFMul, 2), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpFMul, 3), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpVectorTimesScalar, 0), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpVectorTimesScalar, 1), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpVectorTimesScalar, 2), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpVectorTimesScalar, 3), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(3, {
+      {0, 0, 0},
+      {1951208733, 0, 0},
+      {1111111111111111111, 0, 0},
+      {0, 1, 2},
+    }));
+
+    codecs.emplace(std::pair<uint32_t, uint32_t>(SpvOpDot, 0), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpDot, 1), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpDot, 2), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(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<uint32_t, uint32_t>(SpvOpDot, 3), std::move(codec));
+  }
+
+  {
+    std::unique_ptr<HuffmanCodec<uint64_t>> codec(new HuffmanCodec<uint64_t>(3, {
+      {0, 0, 0},
+      {1036475267, 0, 0},
+      {1111111111111111111, 0, 0},
+      {0, 1, 2},
+    }));
+
+    codecs.emplace(std::pair<uint32_t, uint32_t>(SpvOpLabel, 0), std::move(codec));
+  }
+
+  return codecs;
+}
index 2288dc3d3f62bf5fa1beb1fae8d97d2e6dfa449d..c99fdd9945c9033cdd40957fe173724c1901b0bf 100644 (file)
 #include <cstring>
 #include <functional>
 #include <iostream>
+#include <iterator>
 #include <list>
 #include <memory>
 #include <numeric>
 #include <string>
 #include <vector>
 
+#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"
 #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<uint32_t>;
+using MultiMoveToFront = spvutils::MultiMoveToFront<uint32_t>;
 
 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<uint32_t>::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<uint64_t, std::unique_ptr<HuffmanCodec<uint32_t>>>
+GetMtfHuffmanCodecs() {
+  std::map<uint64_t, std::unique_ptr<HuffmanCodec<uint32_t>>> codecs;
+
+  std::unique_ptr<HuffmanCodec<uint32_t>> codec;
+
+  codec.reset(new HuffmanCodec<uint32_t>(std::map<uint32_t, uint32_t>({
+    { 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<uint32_t>(std::map<uint32_t, uint32_t>({
+    { 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<uint32_t>* 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<uint64_t>* 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<uint64_t>* GetNonIdWordHuffmanCodec(
+      uint32_t opcode, uint32_t operand_index) const {
+    const auto it = non_id_word_huffman_codecs_.find(
+        std::pair<uint32_t, uint32_t>(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<uint64_t>* GetIdDescriptorHuffmanCodec(
+      uint32_t opcode, uint32_t operand_index) const {
+    const auto it = id_descriptor_huffman_codecs_.find(
+        std::pair<uint32_t, uint32_t>(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<std::string>* 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<uint64_t, std::unique_ptr<HuffmanCodec<uint32_t>>>
+      mtf_huffman_codecs_;
+
+  // Huffman codec for base-rate of opcode_and_num_operands.
+  HuffmanCodec<uint64_t> opcode_and_num_operands_huffman_codec_;
+
+  // Huffman codecs for opcode_and_num_operands. The map key is previous opcode.
+  std::map<uint32_t, std::unique_ptr<HuffmanCodec<uint64_t>>>
+      opcode_and_num_operands_markov_huffman_codecs_;
+
+  // Huffman codecs for non-id single-word operand values.
+  // The map key is pair <opcode, operand_index>.
+  std::map<std::pair<uint32_t, uint32_t>,
+      std::unique_ptr<HuffmanCodec<uint64_t>>>
+      non_id_word_huffman_codecs_;
+
+  // Huffman codecs for id descriptors. The map key is pair
+  // <opcode, operand_index>.
+  std::map<std::pair<uint32_t, uint32_t>,
+      std::unique_ptr<HuffmanCodec<uint64_t>>>
+      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<uint32_t, std::unique_ptr<HuffmanCodec<std::string>>>
+      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;
+  }
+
+  // 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;
   }
 
-  spv_validator_options validator_options_;
+  // 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;
+
+  // 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<uint32_t, uint32_t> 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<uint32_t> remaining_function_parameter_types_;
+
+  // List of ids local to the current function.
+  std::vector<uint32_t> ids_local_to_cur_function_;
 
-  // Move-to-front list of all ids.
-  // TODO(atgoo@github.com) Consider a better move-to-front implementation.
-  std::list<uint32_t> move_to_front_ids_;
+  // List of instructions in the order they are given in the module.
+  std::vector<const Instruction*> instructions_;
+
+  // Maps used for the 'presumed id' techniques. Maps small constant integer
+  // value to its id and back.
+  std::map<uint32_t, uint32_t> presumed_index_to_id_;
+  std::map<uint32_t, uint32_t> 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<uint16_t>(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<std::stringstream> disassembly_;
-
-  // All ids which were previosly encountered in the module.
-  std::unordered_set<uint32_t> 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);
-    }
-  }
+  // Reads a single bit from reader_. The read bit is stored in |bit|.
+  // Returns false iff reader_ fails.
+  bool ReadBit(bool* bit) {
+    uint64_t bits = 0;
+    const bool result = reader_.ReadBits(&bits, 1);
+    if (result)
+      *bit = bits ? true : false;
+    return result;
+  };
 
-  // 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;
-    }
+  // Returns ReadBit bound to the class object.
+  std::function<bool(bool*)> GetReadBitCallback() {
+    return std::bind(&MarkvDecoder::ReadBit, this, std::placeholders::_1);
   }
 
-  // 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;
+  // 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);
 
-    *id = GetIdAndMoveToFront(index);
-    return true;
-  }
+  // 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);
 
-  bool ReadToByteBreakIfAgreed() {
-    if (!ShouldByteBreak(reader_.GetNumReadBits()))
-      return true;
+  // 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);
 
-    uint64_t bits = 0;
-    if (!reader_.ReadBits(&bits,
-                          GetNumBitsToNextByte(reader_.GetNumReadBits())))
-      return false;
+  // 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);
 
-    if (bits != 0)
-      return false;
+  // 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);
 
-    return true;
+  // 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,263 +992,1482 @@ class MarkvDecoder : public MarkvCodecBase {
   // Valid until next DecodeInstruction call.
   std::vector<spv_parsed_operand_t> 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<uint32_t, uint32_t> id_to_type_id_;
+  // Temporary storage for current instruction words.
+  // Valid until next DecodeInstruction call.
+  std::vector<uint32_t> inst_words_;
+
   // Maps a type ID to its number type description.
   std::unordered_map<uint32_t, NumberType> type_id_to_number_type_info_;
+
   // Maps an ExtInstImport id to the extended instruction type.
   std::unordered_map<uint32_t, spv_ext_inst_type_t> import_id_to_ext_inst_type_;
 };
 
-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);
-    }
-  } else if (operand.number_bit_width == 16) {
-    const uint16_t word =
-        static_cast<uint16_t>(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);
+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 {
-    assert(operand.number_bit_width == 64);
-    const uint64_t word =
-        uint64_t(instruction.word(operand.offset)) |
-        (uint64_t(instruction.word(operand.offset + 1)) << 32);
-    if (operand.number_kind == SPV_NUMBER_UNSIGNED_INT) {
-      writer_.WriteVariableWidthU64(word, model_->u64_chunk_length());
-    } else if (operand.number_kind == SPV_NUMBER_SIGNED_INT) {
-      int64_t val = 0;
-      std::memcpy(&val, &word, 8);
-      writer_.WriteVariableWidthS64(val, model_->s64_chunk_length(),
-                                    model_->s64_block_exponent());
-    } else if (operand.number_kind == SPV_NUMBER_FLOATING) {
-      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));
+      }
     }
   }
-}
-
-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;
+  // 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());
   }
 
-  const Instruction& instruction = GetCurrentInstruction();
-  const auto& operands = instruction.operands();
+  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);
+  }
 
-  LogDisassemblyInstruction();
+  // Add result_id to MTFs.
 
-  // Write opcode.
-  writer_.WriteVariableWidthU32(inst.opcode, model_->opcode_chunk_length());
+  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 (!OpcodeHasFixedNumberOfOperands(SpvOp(inst.opcode))) {
-    // If the opcode has a variable number of operands, encode the number of
-    // operands with the instruction.
+  if (spvOpcodeIsComposite(opcode)) {
+    multi_mtf_.Insert(kMtfTypeComposite, inst_.result_id);
+  }
 
-    if (logger_)
-      logger_->AppendWhitespaces(kCommentNumWhitespaces);
+  if (opcode == SpvOpLabel) {
+    multi_mtf_.InsertOrPromote(kMtfLabel, inst_.result_id);
+  }
 
-    writer_.WriteVariableWidthU16(inst.num_operands,
-                                  model_->num_operands_chunk_length());
+  if (opcode == SpvOpTypeInt) {
+    multi_mtf_.Insert(kMtfTypeScalar, inst_.result_id);
+    multi_mtf_.Insert(kMtfTypeIntScalarOrVector, inst_.result_id);
   }
 
-  // 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 (opcode == SpvOpTypeFloat) {
+    multi_mtf_.Insert(kMtfTypeScalar, inst_.result_id);
+    multi_mtf_.Insert(kMtfTypeFloatScalarOrVector, inst_.result_id);
+  }
 
-    if (logger_)
-      logger_->AppendWhitespaces(kCommentNumWhitespaces);
+  if (opcode == SpvOpTypeBool) {
+    multi_mtf_.Insert(kMtfTypeScalar, inst_.result_id);
+    multi_mtf_.Insert(kMtfTypeBoolScalarOrVector, inst_.result_id);
+  }
 
-    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<const char*>(&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);
-      }
+  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);
   }
 
-  AddByteBreakIfAgreed();
-
-  if (logger_) {
-    logger_->NewLine();
-    logger_->NewLine();
+  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);
   }
 
-  return SPV_SUCCESS;
-}
+  if (inst_.type_id) {
+    const Instruction* type_inst = GetDefInst(inst_.type_id);
+    assert(type_inst);
 
-spv_result_t MarkvDecoder::DecodeLiteralNumber(
-    const spv_parsed_operand_t& operand) {
-  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);
+    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);
     }
-    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);
+
+    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);
+          }
+        }
+      }
     }
-    spirv_.push_back(word);
-  } else {
-    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()))
-        return vstate_.diag(SPV_ERROR_INVALID_BINARY)
-            << "Failed to read literal U64";
-    } else if (operand.number_kind == SPV_NUMBER_SIGNED_INT) {
-      int64_t val = 0;
-      if (!reader_.ReadVariableWidthS64(&val, model_->s64_chunk_length(),
-                                        model_->s64_block_exponent()))
-        return vstate_.diag(SPV_ERROR_INVALID_BINARY)
-            << "Failed to read literal S64";
-      std::memcpy(&word, &val, 8);
-    } else if (operand.number_kind == SPV_NUMBER_FLOATING) {
-      if (!reader_.ReadUnencoded(&word))
-        return vstate_.diag(SPV_ERROR_INVALID_BINARY)
-            << "Failed to read literal F64";
-    } else {
-      assert(0);
+
+    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;
     }
-    spirv_.push_back(static_cast<uint32_t>(word));
-    spirv_.push_back(static_cast<uint32_t>(word >> 32));
-  }
-  return SPV_SUCCESS;
-}
 
-spv_result_t MarkvDecoder::DecodeModule(std::vector<uint32_t>* spirv_binary) {
-  const bool header_read_success =
-      reader_.ReadUnencoded(&header_.magic_number) &&
-      reader_.ReadUnencoded(&header_.markv_version) &&
-      reader_.ReadUnencoded(&header_.markv_model) &&
-      reader_.ReadUnencoded(&header_.markv_length_in_bits) &&
-      reader_.ReadUnencoded(&header_.spirv_version) &&
-      reader_.ReadUnencoded(&header_.spirv_generator);
+    if (type_inst->opcode() == SpvOpTypeVector) {
+      const uint32_t component_type = type_inst->word(2);
+      multi_mtf_.Insert(GetMtfVectorOfComponentType(component_type),
+                        inst_.result_id);
+    }
 
-  if (!header_read_success)
-    return vstate_.diag(SPV_ERROR_INVALID_BINARY)
-        << "Unable to read MARK-V header";
+    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);
 
-  assert(header_.magic_number == kMarkvMagicNumber);
-  assert(header_.markv_length_in_bits > 0);
+      if (multi_mtf_.HasValue(kMtfTypeComposite, data_type))
+        multi_mtf_.Insert(kMtfTypePointerToComposite, inst_.result_id);
+    }
+  }
 
-  if (header_.magic_number != kMarkvMagicNumber)
-    return vstate_.diag(SPV_ERROR_INVALID_BINARY)
-        << "MARK-V binary has incorrect magic number";
+  if (spvOpcodeGeneratesType(opcode)) {
+    if (opcode != SpvOpTypeFunction) {
+      multi_mtf_.Insert(kMtfTypeNonFunction, inst_.result_id);
+    }
+  }
 
-  // TODO(atgoo@github.com): Print version strings.
-  if (header_.markv_version != GetMarkvVersion())
-    return vstate_.diag(SPV_ERROR_INVALID_BINARY)
-        << "MARK-V binary and the codec have different versions";
+  const uint32_t descriptor = id_descriptors_.ProcessInstruction(inst_);
 
-  spirv_.reserve(header_.markv_length_in_bits / 2); // Heuristic.
-  spirv_.resize(5, 0);
-  spirv_[0] = kSpirvMagicNumber;
-  spirv_[1] = header_.spirv_version;
-  spirv_[2] = header_.spirv_generator;
+  multi_mtf_.Insert(GetMtfIdDescriptor(descriptor), inst_.result_id);
+}
 
-  while (reader_.GetNumReadBits() < header_.markv_length_in_bits) {
-    spv_parsed_instruction_t inst = {};
-    const spv_result_t decode_result = DecodeInstruction(&inst);
+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<SpvOp>(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 {
+    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<uint32_t>(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);
+    if (operand.number_kind == SPV_NUMBER_UNSIGNED_INT) {
+      writer_.WriteVariableWidthU64(word, model_->u64_chunk_length());
+    } else if (operand.number_kind == SPV_NUMBER_SIGNED_INT) {
+      int64_t val = 0;
+      std::memcpy(&val, &word, 8);
+      writer_.WriteVariableWidthS64(val, model_->s64_chunk_length(),
+                                    model_->s64_block_exponent());
+    } else if (operand.number_kind == SPV_NUMBER_FLOATING) {
+      writer_.WriteUnencoded(word);
+    } else {
+      return vstate_.diag(SPV_ERROR_INTERNAL) << "Unsupported bit length";
+    }
+  }
+  return SPV_SUCCESS;
+}
+
+spv_result_t MarkvDecoder::DecodeLiteralNumber(
+    const spv_parsed_operand_t& operand) {
+  if (operand.number_bit_width <= 32) {
+    uint32_t word = 0;
+    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);
+    uint64_t word = 0;
+    if (operand.number_kind == SPV_NUMBER_UNSIGNED_INT) {
+      if (!reader_.ReadVariableWidthU64(&word, model_->u64_chunk_length()))
+        return vstate_.diag(SPV_ERROR_INVALID_BINARY)
+            << "Failed to read literal U64";
+    } else if (operand.number_kind == SPV_NUMBER_SIGNED_INT) {
+      int64_t val = 0;
+      if (!reader_.ReadVariableWidthS64(&val, model_->s64_chunk_length(),
+                                        model_->s64_block_exponent()))
+        return vstate_.diag(SPV_ERROR_INVALID_BINARY)
+            << "Failed to read literal S64";
+      std::memcpy(&word, &val, 8);
+    } else if (operand.number_kind == SPV_NUMBER_FLOATING) {
+      if (!reader_.ReadUnencoded(&word))
+        return vstate_.diag(SPV_ERROR_INVALID_BINARY)
+            << "Failed to read literal F64";
+    } else {
+      return vstate_.diag(SPV_ERROR_INTERNAL) << "Unsupported bit length";
+    }
+    inst_words_.push_back(static_cast<uint32_t>(word));
+    inst_words_.push_back(static_cast<uint32_t>(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("<byte break>");
+  }
+
+  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<const char*>(
+            &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<const char*>(
+              &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<uint32_t>* spirv_binary) {
+  const bool header_read_success =
+      reader_.ReadUnencoded(&header_.magic_number) &&
+      reader_.ReadUnencoded(&header_.markv_version) &&
+      reader_.ReadUnencoded(&header_.markv_model) &&
+      reader_.ReadUnencoded(&header_.markv_length_in_bits) &&
+      reader_.ReadUnencoded(&header_.spirv_version) &&
+      reader_.ReadUnencoded(&header_.spirv_generator);
+
+  if (!header_read_success)
+    return vstate_.diag(SPV_ERROR_INVALID_BINARY)
+        << "Unable to read MARK-V header";
+
+  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)
+        << "MARK-V binary has incorrect magic number";
+
+  // TODO(atgoo@github.com): Print version strings.
+  if (header_.markv_version != GetMarkvVersion())
+    return vstate_.diag(SPV_ERROR_INVALID_BINARY)
+        << "MARK-V binary and the codec have different versions";
+
+  spirv_.reserve(header_.markv_length_in_bits / 2); // Heuristic.
+  spirv_.resize(5, 0);
+  spirv_[0] = kSpirvMagicNumber;
+  spirv_[1] = header_.spirv_version;
+  spirv_[2] = header_.spirv_generator;
+
+  while (reader_.GetNumReadBits() < header_.markv_length_in_bits) {
+    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<uint32_t>* 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<SpvOp>(inst->opcode);
+    size_t operand_offset,
+    const spv_operand_type_t type,
+    spv_operand_pattern_t* expected_operands) {
+  const SpvOp opcode = static_cast<SpvOp>(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<uint16_t>(operand_offset);
-  parsed_operand.type = type;
+  operand_.offset = static_cast<uint16_t>(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";
-      }
-
-      if (inst->type_id == 0)
-        return vstate_.diag(SPV_ERROR_INVALID_BINARY) << "Decoded type_id is 0";
+    case SPV_OPERAND_TYPE_RESULT_ID: {
+      const spv_result_t result = DecodeResultId();
+      if (result != SPV_SUCCESS)
+        return result;
 
-      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<char> 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');
+        }
+      }
+
+      // 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;
+          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();
+  inst_words_.clear();
 
-  bool read_result_id = false;
+  // Opcode/num_words placeholder, the word will be filled in later.
+  inst_words_.push_back(0);
 
-  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";
-    }
+  bool num_operands_still_unknown = true;
+  {
+    uint32_t opcode = 0;
+    uint32_t num_operands = 0;
 
-    if (word >= kMarkvFirstOpcode) {
-      if (word == kMarkvOpNextInstructionEncodesResultId) {
-        read_result_id = true;
-      } else {
+    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<uint16_t>(num_operands);
+      num_operands_still_unknown = false;
+    } else {
+      if (!reader_.ReadVariableWidthU32(
+          &opcode, model_->opcode_chunk_length())) {
         return vstate_.diag(SPV_ERROR_INVALID_BINARY)
-            << "Encountered unknown MARK-V opcode";
+            << "Failed to read opcode of instruction";
       }
-    } else {
-      inst->opcode = static_cast<uint16_t>(word);
-      break;
     }
-  }
 
-  const SpvOp opcode = static_cast<SpvOp>(inst->opcode);
+    inst_.opcode = static_cast<uint16_t>(opcode);
+  }
 
-  // Opcode/num_words placeholder, the word will be filled in later.
-  spirv_.push_back(0);
+  const SpvOp opcode = static_cast<SpvOp>(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]);
+  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<uint16_t>(expected_operands.size());
+  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<uint16_t>(expected_operands.size());
+    }
   }
 
-  for (size_t operand_index = 0;
-       operand_index < static_cast<size_t>(inst->num_operands);
-       ++operand_index) {
+  for (operand_index_ = 0;
+       operand_index_ < static_cast<size_t>(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<uint16_t>(spirv_.size() - instruction_offset);
-  spirv_[instruction_offset] =
-      spvOpcodeMake(inst->num_words, SpvOp(inst->opcode));
+  assert(inst_.num_operands == parsed_operands_.size());
+
+  // 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<uint16_t>(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(
+  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<SpvOp>(inst.opcode);
+void MarkvDecoder::RecordNumberType() {
+  const SpvOp opcode = static_cast<SpvOp>(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) {
index 29da94d13904bf1747df8754861afb7a80ac7cde..8feb6567a696c6e4056f7fbc209f10662592948e 100644 (file)
@@ -328,3 +328,61 @@ bool spvIsIdType(spv_operand_type_t type) {
       return false;
   }
 }
+
+std::function<bool(unsigned)> spvOperandCanBeForwardDeclaredFunction(
+    SpvOp opcode) {
+  std::function<bool(unsigned index)> 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;
+}
index fa7c6f2e9f78b9699ff0aee949c759a0d24c7f38..42099930bc0a3a3632c31d53531274d58a086f1d 100644 (file)
@@ -16,6 +16,7 @@
 #define LIBSPIRV_OPERAND_H_
 
 #include <deque>
+#include <functional>
 
 #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<bool(unsigned)> spvOperandCanBeForwardDeclaredFunction(
+    SpvOp opcode);
+
 #endif  // LIBSPIRV_OPERAND_H_
index 35880203be231c44fa87783d515de2ae1fa786b2..2ccc3c98a41d707d35f3479f8f0c7f258ab7fc8c 100644 (file)
@@ -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<bool(bool*)>& read_bit, Val* val) {
+  bool DecodeFromStream(
+      const std::function<bool(bool*)>& read_bit, Val* val) const {
     uint32_t node = root_;
     while (true) {
       assert(node);
index f02529efe74b627fa09cc1e73429a71b7b56a0ab..efa79a75e47a7025ead8ed67fe5f62ae8b131aa9 100644 (file)
@@ -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<Val>& GetMtf(uint32_t handle) {
+  MoveToFront<Val>& 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<uint32_t, MoveToFront<Val>> mtfs_;
+  std::map<uint64_t, MoveToFront<Val>> mtfs_;
 
   // Container mapping value to sequences which contain that value.
-  std::unordered_map<Val, std::set<uint32_t>> val_to_mtfs_;
+  std::unordered_map<Val, std::set<uint64_t>> val_to_mtfs_;
 
   // Cache for the last accessed sequence.
-  uint32_t cached_handle_ = 0;
+  uint64_t cached_handle_ = 0;
   MoveToFront<Val>* cached_mtf_ = nullptr;
 };
 
@@ -471,7 +471,15 @@ bool MoveToFront<Val>::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<Val>::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<Val>::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_;
index ae3b59fbd4ee5112e40a973d31bd48c1788621ab..64b9d586069cfff5767c7ee2a8fc2150e7b2360e 100644 (file)
@@ -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<bool(unsigned)> getCanBeForwardDeclaredFunction(SpvOp opcode) {
-  function<bool(unsigned index)> 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<SpvOp>(inst->opcode));
+      spvOperandCanBeForwardDeclaredFunction(static_cast<SpvOp>(inst->opcode));
 
   // Keep track of a result id defined by this instruction.  0 means it
   // does not define an id.
index c43cc77ad91274e0b31e3cf11224249afa9067a4..246e6cb970a356b44bade4cd7978741121520955 100644 (file)
@@ -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
index 3f2e7ec0e98e6fd4212bbe2dfcafbcdeb80becef..23c71b596652dea7a3916202434babf1208e6768 100644 (file)
 
 #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<uint32_t> GetAllOpcodes() {
   return std::vector<uint32_t>({
@@ -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<uint32_t, uint32_t>& hist = kv.second;
@@ -638,10 +657,9 @@ void StatsAnalyzer::WriteCodegenOpcodeAndNumOperandsMarkovHuffmanCodecs(
       total += pair.second;
     }
 
-    out << "  {\n";
-    out << "    std::unique_ptr<HuffmanCodec<uint64_t>> "
-        << "codec(new HuffmanCodec<uint64_t>({\n";
+    uint32_t left_out = 0;
 
+    std::map<uint64_t, uint32_t> 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)));
+
+    HuffmanCodec<uint64_t> codec(processed_hist);
 
-    out << "    }));\n" << std::endl;
+    out << "  {\n";
+    out << "    std::unique_ptr<HuffmanCodec<uint64_t>> "
+        << "codec(new HuffmanCodec<uint64_t>";
+    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<HuffmanCodec<std::string>> "
-        << "codec(new HuffmanCodec<std::string>({\n";
+    uint32_t left_out = 0;
+
+    std::map<std::string, uint32_t> 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)));
+
+    HuffmanCodec<std::string> codec(processed_hist);
 
-    out << "    }));\n" << std::endl;
+    out << "  {\n";
+    out << "    std::unique_ptr<HuffmanCodec<std::string>> "
+        << "codec(new HuffmanCodec<std::string>";
+    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<HuffmanCodec<uint64_t>> "
-        << "codec(new HuffmanCodec<uint64_t>({\n";
+    uint32_t left_out = 0;
+
+    std::map<uint64_t, uint32_t> 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)));
+
+    HuffmanCodec<uint64_t> codec(processed_hist);
 
-    out << "    }));\n" << std::endl;
+    out << "  {\n";
+    out << "    std::unique_ptr<HuffmanCodec<uint64_t>> "
+        << "codec(new HuffmanCodec<uint64_t>";
+    out << codec.SerializeToText(4);
+    out << ");\n" << std::endl;
     out << "    codecs.emplace(std::pair<uint32_t, uint32_t>(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<uint32_t, uint32_t>& hist = kv.second;
 
+
     uint32_t total = 0;
     for (const auto& pair : hist) {
       total += pair.second;
     }
 
-    out << "  {\n";
-    out << "    std::unique_ptr<HuffmanCodec<uint64_t>> "
-        << "codec(new HuffmanCodec<uint64_t>({\n";
+    uint32_t left_out = 0;
+
+    std::map<uint64_t, uint32_t> 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)));
+
+    HuffmanCodec<uint64_t> codec(processed_hist);
 
-    out << "    }));\n" << std::endl;
+    out << "  {\n";
+    out << "    std::unique_ptr<HuffmanCodec<uint64_t>> "
+        << "codec(new HuffmanCodec<uint64_t>";
+    out << codec.SerializeToText(4);
+    out << ");\n" << std::endl;
     out << "    codecs.emplace(std::pair<uint32_t, uint32_t>(SpvOp"
         << spvOpcodeString(SpvOp(opcode))
         << ", " << index << "), std::move(codec));\n";