Coverage Report

Created: 2026-02-14 06:30

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/spirv-tools/source/opt/canonicalize_ids_pass.h
Line
Count
Source
1
// Copyright (c) 2025 LunarG Inc.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
#include <algorithm>
16
#include <map>
17
#include <set>
18
#include <vector>
19
20
#include "source/opt/pass.h"
21
22
namespace spvtools {
23
namespace opt {
24
25
// The canonicalize IDs pass is an optimization to improve compression of SPIR-V
26
// binary files via entropy reduction. It transforms SPIR-V to SPIR-V, remapping
27
// IDs. The resulting modules have an increased ID range (IDs are not as tightly
28
// packed around zero), but will compress better when multiple modules are
29
// compressed together, since the compressor's dictionary can find better cross
30
// module commonality. Remapping is accomplished via canonicalization. Thus,
31
// modules can be compressed one at a time with no loss of quality relative to
32
// operating on many modules at once.
33
34
// This pass should be run after most optimization passes except for
35
// --strip-debug because this pass will use OpName to canonicalize IDs. i.e. Run
36
// --strip-debug after this pass.
37
38
// This is a port of remap utility in glslang. There are great deal of magic
39
// numbers that are present throughout this code. The general goal is to replace
40
// the IDs with a hash value such that the distribution of IDs is deterministic
41
// and minimizes collisions. The magic numbers in the glslang version were
42
// chosen semi-arbitrarily and have been preserved in this port in order to
43
// maintain backward compatibility.
44
45
class CanonicalizeIdsPass : public Pass {
46
 public:
47
0
  CanonicalizeIdsPass() = default;
48
0
  virtual ~CanonicalizeIdsPass() = default;
49
50
  Pass::Status Process() override;
51
52
0
  const char* name() const override { return "canonicalize-ids"; }
53
54
 private:
55
  // Special values for IDs.
56
  static constexpr spv::Id unmapped_{spv::Id(-10000)};
57
  static constexpr spv::Id unused_{spv::Id(-10001)};
58
59
  // Scans the module for IDs and sets them to unmapped_.
60
  void ScanIds();
61
62
  // Functions to compute new IDs.
63
  void CanonicalizeTypeAndConst();
64
  spv::Id HashTypeAndConst(
65
      spv::Id const id) const;  // Helper for CanonicalizeTypeAndConst.
66
  void CanonicalizeNames();
67
  void CanonicalizeFunctions();
68
  spv::Id HashOpCode(Instruction const* const inst)
69
      const;  // Helper for CanonicalizeFunctions.
70
  void CanonicalizeRemainders();
71
72
  // Applies the new IDs.
73
  bool ApplyMap();
74
75
  // Methods to manage the bound field in header.
76
  spv::Id GetBound() const;  // All IDs must satisfy 0 < ID < bound.
77
  void UpdateBound();
78
79
  // Methods to map from old IDs to new IDs.
80
0
  spv::Id GetNewId(spv::Id const old_id) const { return new_id_[old_id]; }
81
  spv::Id SetNewId(spv::Id const old_id, spv::Id new_id);
82
83
  // Methods to manage claimed IDs.
84
  spv::Id ClaimNewId(spv::Id new_id);
85
0
  bool IsNewIdClaimed(spv::Id const new_id) const {
86
0
    return claimed_new_ids_.find(new_id) != claimed_new_ids_.end();
87
0
  }
88
89
  // Queries for old IDs.
90
0
  bool IsOldIdUnmapped(spv::Id const old_id) const {
91
0
    return GetNewId(old_id) == unmapped_;
92
0
  }
93
0
  bool IsOldIdUnused(spv::Id const old_id) const {
94
0
    return GetNewId(old_id) == unused_;
95
0
  }
96
97
  // Container to map old IDs to new IDs. e.g. new_id_[old_id] = new_id
98
  std::vector<spv::Id> new_id_;
99
100
  // IDs from the new ID space that have been claimed (faster than searching
101
  // through new_id_).
102
  std::set<spv::Id> claimed_new_ids_;
103
104
  // Helper functions for printing IDs (useful for debugging).
105
  std::string IdAsString(spv::Id const id) const;
106
  void PrintNewIds() const;
107
108
  // Containers to track IDs we want to canonicalize.
109
  std::vector<spv::Id> type_and_const_ids_;
110
  std::map<std::string, spv::Id> name_ids_;
111
  std::vector<spv::Id> function_ids_;
112
};
113
114
}  // namespace opt
115
}  // namespace spvtools