clang 24.0.0git
SourceLocationEncoding.h
Go to the documentation of this file.
1//===--- SourceLocationEncoding.h - Small serialized locations --*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// We wish to encode the SourceLocation from other module file not dependent
10// on the other module file. So that the source location changes from other
11// module file may not affect the contents of the current module file. Then the
12// users don't need to recompile the whole project due to a new line in a module
13// unit in the root of the dependency graph.
14//
15// To achieve this, we need to encode the index of the module file into the
16// encoding of the source location. The encoding of the source location may be:
17//
18// |-----------------------|-----------------------|
19// | A | B | C |
20//
21// * A: 32 bit. The index of the module file in the module manager + 1. The +1
22// here is necessary since we wish 0 stands for the current module file.
23// * B: 31 bit. The offset of the source location to the module file containing
24// it.
25// * C: The macro bit. We rotate it to the lowest bit so that we can save some
26// space in case the index of the module file is 0.
27//
28//
29//===----------------------------------------------------------------------===//
30
31#ifndef LLVM_CLANG_SERIALIZATION_SOURCELOCATIONENCODING_H
32#define LLVM_CLANG_SERIALIZATION_SOURCELOCATIONENCODING_H
33
35#include "llvm/Support/MathExtras.h"
36#include <climits>
37
38namespace clang {
39
40/// Serialized encoding of SourceLocations without context.
41/// Optimized to have small unsigned values (=> small after VBR encoding).
42///
43// Macro locations have the top bit set, we rotate by one so it is the low bit.
45 using UIntTy = SourceLocation::UIntTy;
46 constexpr static unsigned UIntBits = CHAR_BIT * sizeof(UIntTy);
47
48 static UIntTy encodeRaw(UIntTy Raw) {
49 return (Raw << 1) | (Raw >> (UIntBits - 1));
50 }
51 static UIntTy decodeRaw(UIntTy Raw) {
52 return (Raw >> 1) | (Raw << (UIntBits - 1));
53 }
54
55public:
56 using RawLocEncoding = uint64_t;
57
58 static RawLocEncoding encode(SourceLocation Loc, UIntTy BaseOffset,
59 unsigned BaseModuleFileIndex);
60 static std::pair<SourceLocation, unsigned> decode(RawLocEncoding);
61
62 /// A delta encoder for a run of source locations.
63 /// The high level strategy of the chain to encode the run is the following.
64 /// Locations: SL0 SL1 SL2
65 /// map to : (SL0 - anchor) (SL1 - SL0) (SL2 - SL1)
66 ///
67 /// Two wrinkles complicate this strategy's implementation.
68 /// First, since the delta-encoded values are meant for VBR compression, they
69 /// are mapped from int to unsigned int with the zigZag method.
70 ///
71 /// Second, two cases are given their own codes instead of being stored as
72 /// distances.
73 ///
74 /// An invalid SourceLocation encodes to 0 -- encodeRaw is a bijection and
75 /// encodeRaw(0) == 0 -- and 0 is kept for it here. This case is common
76 /// because a macro argument expansion has no end location, so the writer
77 /// stores an invalid one in that field. Expressing it as a distance would be
78 /// wasteful: the distance from Prev back to the origin is a number as large
79 /// as Prev itself, while a dedicated code costs a single VBR chunk.
80 ///
81 /// A distance of zero -- the location repeats the Previous one in the run --
82 /// is stored as 1. That is also common, since an expansion's start and end
83 /// coincide whenever the invocation spans a single token.
84 ///
85 /// Reserving 0 has a consequence. For a given Prev, zigZag(0 - Prev) is the
86 /// distance that would arrive back at 0, and it can never occur, because an
87 /// invalid location took the branch above. So that code is dead, and
88 /// compacting it out is what makes everything fit:
89 ///
90 /// delta = V - Prev
91 /// hole = zigZag(0 - Prev)
92 /// encoded = zigZag(delta) + 1 if zigZag(delta) < hole
93 /// = zigZag(delta) if zigZag(delta) > hole
94 ///
95 /// Or pictorially:
96 /// zigZag(delta): 0, 1, ... hole - 1, hole + 1, hole + 2, ...
97 /// encoded: 1, 2, ... hole, hole + 1, hole + 2, ...
98 ///
99 // In other words, if zigZag(delta) < hole, we increment
100 /// the encoded value by 1 to leave 0 to represent V == 0. If zigZag(delta)
101 /// is larger than hole, we do not need to add 1. Therefore, we will
102 /// not accidentally add 1 to values that may overflow beyond 2^32 - 1,
103 /// which may lead to accidental change of the ModuleFileIndex bits.
104 /// This mapping avoids the issue llvm/llvm-project#145529 attempted to fix by
105 /// design.
106 class Chain {
107 UIntTy Prev;
108
109 /// Maps an int to an unsigned int.
110 /// Explicitly, zigZag does the following mapping:
111 /// From: 0, -1, +1, -2, +2, ...
112 /// To: 0, 1, 2, 3, 4, ...
113 /// In other words, the mapping is the following:
114 /// zigZag(V) = 2 * V if V >= 0
115 /// = 2 * |V| - 1 if V < 0
116 static UIntTy zigZag(UIntTy V) {
117 return (V << 1) ^ (UIntTy(0) - (V >> (UIntBits - 1)));
118 }
119
120 /// Reverse mapping of zigZag.
121 static UIntTy zagZig(UIntTy V) { return (V >> 1) ^ (UIntTy(0) - (V & 1)); }
122
123 /// Computes the hole left by 0 - Prev.
124 UIntTy hole() const { return zigZag(UIntTy(0) - Prev); }
125
126 public:
127 explicit Chain(UIntTy AnchorOffset) : Prev(encodeRaw(AnchorOffset)) {
128 // Using zero as anchor could make the chain very expensive since
129 // the deltas may be big.
130 // Choose an offset that is closer to the source location being
131 // encoded.
132 assert(AnchorOffset != 0 && "Chain anchor should be non-zero");
133 }
134
136 // If the source location is external, do not encode.
137 if (V >> 32)
138 return V;
139
140 // Use 0 to encode an input of 0.
141 if (V == 0)
142 return 0;
143
144 // Delta encode the rest of the possible input values.
145 UIntTy SL = static_cast<UIntTy>(V);
146 UIntTy E = zigZag(SL - Prev);
147 UIntTy H = hole();
148 assert(E != H && "Non-zero location cannot be mapped to the hole");
149 Prev = SL;
150 return E < H ? static_cast<RawLocEncoding>(E) + 1 : E;
151 }
152
154 // If the source location is external, it is not delta encoded.
155 if (V >> 32)
156 return V;
157
158 // If V is 0, it is not delta encoded.
159 if (V == 0)
160 return 0;
161
162 // Delta-decode the value.
163 UIntTy H = hole();
164 UIntTy D = static_cast<UIntTy>(V);
165 Prev += zagZig(D <= H ? D - 1 : D);
166 return Prev;
167 }
168 };
169};
170
173 unsigned BaseModuleFileIndex) {
174 // If the source location is a local source location, we can try to optimize
175 // the similar sequences to only record the differences.
176 if (!BaseOffset)
177 return encodeRaw(Loc.getRawEncoding());
178 if (Loc.isInvalid())
179 return 0;
180
181 // Otherwise, the higher bits are used to store the module file index,
182 // so it is meaningless to optimize the source locations into small
183 // integers. Let's try to always use the raw encodings.
184 assert(Loc.getOffset() >= BaseOffset);
185 Loc = Loc.getLocWithOffset(-BaseOffset);
186 RawLocEncoding Encoded = encodeRaw(Loc.getRawEncoding());
187
188 // 16 bits should be sufficient to store the module file index.
189 assert(BaseModuleFileIndex < (1 << 16));
190 Encoded |= (RawLocEncoding)BaseModuleFileIndex << 32;
191 return Encoded;
192}
193inline std::pair<SourceLocation, unsigned>
195 unsigned ModuleFileIndex = Encoded >> 32;
196
197 if (!ModuleFileIndex)
198 return {SourceLocation::getFromRawEncoding(decodeRaw(Encoded)),
199 ModuleFileIndex};
200
201 Encoded &= llvm::maskTrailingOnes<RawLocEncoding>(32);
202 SourceLocation Loc = SourceLocation::getFromRawEncoding(decodeRaw(Encoded));
203
204 return {Loc, ModuleFileIndex};
205}
206
207} // namespace clang
208#endif
#define V(N, I)
Defines the clang::SourceLocation class and associated facilities.
RawLocEncoding deltaDecode(RawLocEncoding V)
RawLocEncoding deltaEncode(RawLocEncoding V)
Serialized encoding of SourceLocations without context.
static RawLocEncoding encode(SourceLocation Loc, UIntTy BaseOffset, unsigned BaseModuleFileIndex)
static std::pair< SourceLocation, unsigned > decode(RawLocEncoding)
Encodes a location in the source.
static SourceLocation getFromRawEncoding(UIntTy Encoding)
Turn a raw encoding of a SourceLocation object into a real SourceLocation.
SourceLocation getLocWithOffset(IntTy Offset) const
Return a source location with the specified offset from this SourceLocation.
UIntTy getRawEncoding() const
When a SourceLocation itself cannot be used, this returns an (opaque) 32-bit integer encoding for it.
#define CHAR_BIT
Definition limits.h:71
Top level wrappers for InstallAPI frontend operations.