2525// * C: The macro bit. We rotate it to the lowest bit so that we can save some
2626// space in case the index of the module file is 0.
2727//
28+ // Specially, if the index of the module file is 0, we allow to encode a
29+ // sequence of locations we store only differences between successive elements.
2830//
2931// ===----------------------------------------------------------------------===//
3032
3638#include < climits>
3739
3840namespace clang {
41+ class SourceLocationSequence ;
3942
4043// / Serialized encoding of SourceLocations without context.
4144// / Optimized to have small unsigned values (=> small after VBR encoding).
@@ -51,22 +54,119 @@ class SourceLocationEncoding {
5154 static UIntTy decodeRaw (UIntTy Raw) {
5255 return (Raw >> 1 ) | (Raw << (UIntBits - 1 ));
5356 }
57+ friend SourceLocationSequence;
5458
5559public:
5660 using RawLocEncoding = uint64_t ;
5761
5862 static RawLocEncoding encode (SourceLocation Loc, UIntTy BaseOffset,
59- unsigned BaseModuleFileIndex);
60- static std::pair<SourceLocation, unsigned > decode (RawLocEncoding);
63+ unsigned BaseModuleFileIndex,
64+ SourceLocationSequence * = nullptr );
65+ static std::pair<SourceLocation, unsigned >
66+ decode (RawLocEncoding, SourceLocationSequence * = nullptr );
67+ };
68+
69+ // / Serialized encoding of a sequence of SourceLocations.
70+ // /
71+ // / Optimized to produce small values when locations with the sequence are
72+ // / similar. Each element can be delta-encoded against the last nonzero element.
73+ // /
74+ // / Sequences should be started by creating a SourceLocationSequence::State,
75+ // / and then passed around as SourceLocationSequence*. Example:
76+ // /
77+ // / // establishes a sequence
78+ // / void EmitTopLevelThing() {
79+ // / SourceLocationSequence::State Seq;
80+ // / EmitContainedThing(Seq);
81+ // / EmitRecursiveThing(Seq);
82+ // / }
83+ // /
84+ // / // optionally part of a sequence
85+ // / void EmitContainedThing(SourceLocationSequence *Seq = nullptr) {
86+ // / Record.push_back(SourceLocationEncoding::encode(SomeLoc, Seq));
87+ // / }
88+ // /
89+ // / // establishes a sequence if there isn't one already
90+ // / void EmitRecursiveThing(SourceLocationSequence *ParentSeq = nullptr) {
91+ // / SourceLocationSequence::State Seq(ParentSeq);
92+ // / Record.push_back(SourceLocationEncoding::encode(SomeLoc, Seq));
93+ // / EmitRecursiveThing(Seq);
94+ // / }
95+ // /
96+ class SourceLocationSequence {
97+ using UIntTy = SourceLocation::UIntTy;
98+ using EncodedTy = uint64_t ;
99+ constexpr static auto UIntBits = SourceLocationEncoding::UIntBits;
100+ static_assert (sizeof (EncodedTy) > sizeof (UIntTy), " Need one extra bit!" );
101+
102+ // Prev stores the rotated last nonzero location.
103+ UIntTy &Prev;
104+
105+ // Zig-zag encoding turns small signed integers into small unsigned integers.
106+ // 0 => 0, -1 => 1, 1 => 2, -2 => 3, ...
107+ static UIntTy zigZag (UIntTy V) {
108+ UIntTy Sign = (V & (1 << (UIntBits - 1 ))) ? UIntTy (-1 ) : UIntTy (0 );
109+ return Sign ^ (V << 1 );
110+ }
111+ static UIntTy zagZig (UIntTy V) { return (V >> 1 ) ^ -(V & 1 ); }
112+
113+ SourceLocationSequence (UIntTy &Prev) : Prev(Prev) {}
114+
115+ EncodedTy encodeRaw (UIntTy Raw) {
116+ if (Raw == 0 )
117+ return 0 ;
118+ UIntTy Rotated = SourceLocationEncoding::encodeRaw (Raw);
119+ if (Prev == 0 )
120+ return Prev = Rotated;
121+ UIntTy Delta = Rotated - Prev;
122+ Prev = Rotated;
123+ // Exactly one 33 bit value is possible! (1 << 32).
124+ // This is because we have two representations of zero: trivial & relative.
125+ return 1 + EncodedTy{zigZag (Delta)};
126+ }
127+ UIntTy decodeRaw (EncodedTy Encoded) {
128+ if (Encoded == 0 )
129+ return 0 ;
130+ if (Prev == 0 )
131+ return SourceLocationEncoding::decodeRaw (Prev = Encoded);
132+ return SourceLocationEncoding::decodeRaw (Prev += zagZig (Encoded - 1 ));
133+ }
134+
135+ public:
136+ SourceLocation decode (EncodedTy Encoded) {
137+ return SourceLocation::getFromRawEncoding (decodeRaw (Encoded));
138+ }
139+ EncodedTy encode (SourceLocation Loc) {
140+ return encodeRaw (Loc.getRawEncoding ());
141+ }
142+
143+ class State ;
144+ };
145+
146+ // / This object establishes a SourceLocationSequence.
147+ class SourceLocationSequence ::State {
148+ UIntTy Prev = 0 ;
149+ SourceLocationSequence Seq;
150+
151+ public:
152+ // If Parent is provided and non-null, then this root becomes part of that
153+ // enclosing sequence instead of establishing a new one.
154+ State (SourceLocationSequence *Parent = nullptr )
155+ : Seq(Parent ? Parent->Prev : Prev) {}
156+
157+ // Implicit conversion for uniform use of roots vs propagated sequences.
158+ operator SourceLocationSequence *() { return &Seq; }
61159};
62160
63161inline SourceLocationEncoding::RawLocEncoding
64162SourceLocationEncoding::encode (SourceLocation Loc, UIntTy BaseOffset,
65- unsigned BaseModuleFileIndex) {
163+ unsigned BaseModuleFileIndex,
164+ SourceLocationSequence *Seq) {
66165 // If the source location is a local source location, we can try to optimize
67166 // the similar sequences to only record the differences.
68167 if (!BaseOffset)
69- return encodeRaw (Loc.getRawEncoding ());
168+ return Seq ? Seq->encode (Loc) : encodeRaw (Loc.getRawEncoding ());
169+
70170 if (Loc.isInvalid ())
71171 return 0 ;
72172
@@ -83,11 +183,13 @@ SourceLocationEncoding::encode(SourceLocation Loc, UIntTy BaseOffset,
83183 return Encoded;
84184}
85185inline std::pair<SourceLocation, unsigned >
86- SourceLocationEncoding::decode (RawLocEncoding Encoded) {
186+ SourceLocationEncoding::decode (RawLocEncoding Encoded,
187+ SourceLocationSequence *Seq) {
87188 unsigned ModuleFileIndex = Encoded >> 32 ;
88189
89190 if (!ModuleFileIndex)
90- return {SourceLocation::getFromRawEncoding (decodeRaw (Encoded)),
191+ return {Seq ? Seq->decode (Encoded)
192+ : SourceLocation::getFromRawEncoding (decodeRaw (Encoded)),
91193 ModuleFileIndex};
92194
93195 Encoded &= llvm::maskTrailingOnes<RawLocEncoding>(32 );
0 commit comments