LLVM: lib/DebugInfo/CodeView/TypeStreamMerger.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
19#include
20
21using namespace llvm;
23
25 assert(!Idx.isSimple() && "simple type indices have no slots");
27}
28
29namespace {
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63class TypeStreamMerger {
64public:
65 explicit TypeStreamMerger(SmallVectorImpl &SourceToDest)
66 : IndexMap(SourceToDest) {
67
68
69
70
71
72 CurIndex += SourceToDest.size();
73 }
74
75 static const TypeIndex Untranslated;
76
77
78 Error mergeTypesAndIds(MergingTypeTableBuilder &DestIds,
79 MergingTypeTableBuilder &DestTypes,
81 std::optional &PCHInfo);
87
88
89 Error mergeTypesAndIds(GlobalTypeTableBuilder &DestIds,
90 GlobalTypeTableBuilder &DestTypes,
93 std::optional &PCHInfo);
100 std::optional &PCHInfo);
101
102private:
104
106
108
109 void addMapping(TypeIndex Idx);
110
111 inline bool remapTypeIndex(TypeIndex &Idx) {
112
113
114
115
116
117 if (!hasTypeStream())
118 return remapIndex(Idx, TypeLookup);
119
120 assert(TypeLookup.empty());
121 return remapIndex(Idx, IndexMap);
122 }
123 inline bool remapItemIndex(TypeIndex &Idx) {
124 assert(hasIdStream());
125 return remapIndex(Idx, IndexMap);
126 }
127
128 bool hasTypeStream() const {
129 return (UseGlobalHashes) ? (!!DestGlobalTypeStream) : (!!DestTypeStream);
130 }
131
132 bool hasIdStream() const {
133 return (UseGlobalHashes) ? (!!DestGlobalIdStream) : (!!DestIdStream);
134 }
135
137 MutableArrayRef<uint8_t> Storage);
138
140 if (LLVM_LIKELY(remapIndexSimple(Idx, Map)))
141 return true;
142
143 return remapIndexFallback(Idx, Map);
144 }
145
146 inline bool remapIndexSimple(TypeIndex &Idx, ArrayRef Map) const {
147
149 return true;
150
151
152
153
155 if (LLVM_UNLIKELY(MapPos >= Map.size() || Map[MapPos] == Untranslated))
156 return false;
157
158 Idx = Map[MapPos];
159 return true;
160 }
161
163
164 Error errorCorruptRecord() const {
166 }
167
168 Expected shouldRemapType(const CVType &Type);
169
170 std::optional LastError;
171
172 bool UseGlobalHashes = false;
173
174 bool IsSecondPass = false;
175
176 unsigned NumBadIndices = 0;
177
179
180 MergingTypeTableBuilder *DestIdStream = nullptr;
181 MergingTypeTableBuilder *DestTypeStream = nullptr;
182
183 GlobalTypeTableBuilder *DestGlobalIdStream = nullptr;
184 GlobalTypeTableBuilder *DestGlobalTypeStream = nullptr;
185
187
188
189
191
192
193
194 SmallVectorImpl &IndexMap;
195
196
197
199
200 std::optional PCHInfo;
201};
202
203}
204
206
207void TypeStreamMerger::addMapping(TypeIndex Idx) {
208 if (!IsSecondPass) {
210 "visitKnownRecord should add one index map entry");
211 IndexMap.push_back(Idx);
212 } else {
215 }
216}
217
218bool TypeStreamMerger::remapIndexFallback(TypeIndex &Idx,
221
222
223
224 if (IsSecondPass && MapPos >= Map.size()) {
225
226
227 if (LastError)
228 LastError = joinErrors(std::move(*LastError), errorCorruptRecord());
229 else
230 LastError = errorCorruptRecord();
231 }
232
233 ++NumBadIndices;
234
235
236
237 Idx = Untranslated;
238 return false;
239}
240
241
242Error TypeStreamMerger::mergeTypeRecords(MergingTypeTableBuilder &Dest,
244 DestTypeStream = &Dest;
245 UseGlobalHashes = false;
246
247 return doit(Types);
248}
249
250Error TypeStreamMerger::mergeIdRecords(MergingTypeTableBuilder &Dest,
253 DestIdStream = &Dest;
254 TypeLookup = TypeSourceToDest;
255 UseGlobalHashes = false;
256
257 return doit(Ids);
258}
259
260Error TypeStreamMerger::mergeTypesAndIds(
261 MergingTypeTableBuilder &DestIds, MergingTypeTableBuilder &DestTypes,
262 const CVTypeArray &IdsAndTypes, std::optional &PCHInfo) {
263 DestIdStream = &DestIds;
264 DestTypeStream = &DestTypes;
265 UseGlobalHashes = false;
266 auto Err = doit(IdsAndTypes);
267 PCHInfo = this->PCHInfo;
268 return Err;
269}
270
271
272Error TypeStreamMerger::mergeTypeRecords(
273 GlobalTypeTableBuilder &Dest, const CVTypeArray &Types,
275 std::optional &PCHInfo) {
276 DestGlobalTypeStream = &Dest;
277 UseGlobalHashes = true;
278 GlobalHashes = Hashes;
279 auto Err = doit(Types);
280 PCHInfo = this->PCHInfo;
281 return Err;
282}
283
284Error TypeStreamMerger::mergeIdRecords(GlobalTypeTableBuilder &Dest,
288 DestGlobalIdStream = &Dest;
289 TypeLookup = TypeSourceToDest;
290 UseGlobalHashes = true;
291 GlobalHashes = Hashes;
292
293 return doit(Ids);
294}
295
296Error TypeStreamMerger::mergeTypesAndIds(
297 GlobalTypeTableBuilder &DestIds, GlobalTypeTableBuilder &DestTypes,
299 std::optional &PCHInfo) {
300 DestGlobalIdStream = &DestIds;
301 DestGlobalTypeStream = &DestTypes;
302 UseGlobalHashes = true;
303 GlobalHashes = Hashes;
304 auto Err = doit(IdsAndTypes);
305 PCHInfo = this->PCHInfo;
306 return Err;
307}
308
310 if (auto EC = remapAllTypes(Types))
311 return EC;
312
313
314
315
316
317
318
319
320 while (!LastError && NumBadIndices > 0) {
321 unsigned BadIndicesRemaining = NumBadIndices;
322 IsSecondPass = true;
323 NumBadIndices = 0;
325
326 if (auto EC = remapAllTypes(Types))
327 return EC;
328
329 assert(NumBadIndices <= BadIndicesRemaining &&
330 "second pass found more bad indices");
331 if (!LastError && NumBadIndices == BadIndicesRemaining) {
333 cv_error_code::corrupt_record, "Input type graph contains cycles");
334 }
335 }
336
337 if (LastError)
338 return std::move(*LastError);
340}
341
342Error TypeStreamMerger::remapAllTypes(const CVTypeArray &Types) {
343 BinaryStreamRef Stream = Types.getUnderlyingStream();
344 ArrayRef<uint8_t> Buffer;
346
348 Buffer, [this](const CVType &T) { return remapType(T); });
349}
350
352 auto R = shouldRemapType(Type);
353 if (!R)
354 return R.takeError();
355
356 TypeIndex DestIdx = Untranslated;
357 if (*R) {
358 auto DoSerialize =
359 [this, Type](MutableArrayRef<uint8_t> Storage) -> ArrayRef<uint8_t> {
361 };
362 unsigned AlignedSize = alignTo(Type.RecordData.size(), 4);
363
365 GlobalTypeTableBuilder &Dest =
366 isIdRecord(Type.kind()) ? *DestGlobalIdStream : *DestGlobalTypeStream;
367 GloballyHashedType H = GlobalHashes[CurIndex.toArrayIndex()];
368 DestIdx = Dest.insertRecordAs(H, AlignedSize, DoSerialize);
369 } else {
370 MergingTypeTableBuilder &Dest =
371 isIdRecord(Type.kind()) ? *DestIdStream : *DestTypeStream;
372
373 RemapStorage.resize(AlignedSize);
374 ArrayRef<uint8_t> Result = DoSerialize(RemapStorage);
377 }
378 }
379 addMapping(DestIdx);
380
381 ++CurIndex;
382 assert((IsSecondPass || IndexMap.size() == slotForIndex(CurIndex)) &&
383 "visitKnownRecord should add one index map entry");
385}
386
387ArrayRef<uint8_t>
388TypeStreamMerger::remapIndices(const CVType &OriginalType,
389 MutableArrayRef<uint8_t> Storage) {
392 "The storage buffer size is not a multiple of 4 bytes which will "
393 "cause misalignment in the output TPI stream!");
394
397 if (Refs.empty() && Align == 0)
399
402
403 uint8_t *DestContent = Storage.data() + sizeof(RecordPrefix);
404
405 for (auto &Ref : Refs) {
406 TypeIndex *DestTIs =
407 reinterpret_cast<TypeIndex *>(DestContent + Ref.Offset);
408
409 for (size_t I = 0; I < Ref.Count; ++I) {
410 TypeIndex &TI = DestTIs[I];
411 bool Success = (Ref.Kind == TiRefKind::IndexRef) ? remapItemIndex(TI)
412 : remapTypeIndex(TI);
414 return {};
415 }
416 }
417
418 if (Align > 0) {
419 RecordPrefix *StorageHeader =
420 reinterpret_cast<RecordPrefix *>(Storage.data());
422
425 *DestContent++ = LF_PAD4 - Align;
426 }
427 return Storage;
428}
429
433 TypeStreamMerger M(SourceToDest);
434 return M.mergeTypeRecords(Dest, Types);
435}
436
441 TypeStreamMerger M(SourceToDest);
442 return M.mergeIdRecords(Dest, TypeSourceToDest, Ids);
443}
444
448 std::optional &PCHInfo) {
449 TypeStreamMerger M(SourceToDest);
450 return M.mergeTypesAndIds(DestIds, DestTypes, IdsAndTypes, PCHInfo);
451}
452
457 std::optional &PCHInfo) {
458 TypeStreamMerger M(SourceToDest);
459 return M.mergeTypesAndIds(DestIds, DestTypes, IdsAndTypes, Hashes, PCHInfo);
460}
461
466 std::optional &PCHInfo) {
467 TypeStreamMerger M(SourceToDest);
468 return M.mergeTypeRecords(Dest, Types, Hashes, PCHInfo);
469}
470
476 TypeStreamMerger M(SourceToDest);
477 return M.mergeIdRecords(Dest, Types, Ids, Hashes);
478}
479
481
482
483
484 if (Type.kind() == LF_ENDPRECOMP) {
487 EP))
488 return joinErrors(std::move(EC), errorCorruptRecord());
489
490 if (PCHInfo)
491 return errorCorruptRecord();
493 return false;
494 }
495 return true;
496}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
#define LLVM_UNLIKELY(EXPR)
#define LLVM_LIKELY(EXPR)
static std::pair< std::vector< int64_t >, std::vector< int64_t > > remapIndices(Function &Caller, BasicBlock *StartBB, PGOContextualProfile &CtxProf, uint32_t CalleeCounters, uint32_t CalleeCallsites)
This file defines the SmallVector class.
static size_t slotForIndex(TypeIndex Idx)
Definition TypeStreamMerger.cpp:24
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
size - Get the array size.
uint64_t getLength() const
LLVM_ABI Error readBytes(uint64_t Offset, uint64_t Size, ArrayRef< uint8_t > &Buffer) const
Given an Offset into this StreamRef and a Size, return a reference to a buffer owned by the stream.
Lightweight error class with error context and mandatory checking.
static ErrorSuccess success()
Create a success value.
Tagged union holding either a T or a Error.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
The instances of the Type class are immutable: once they are created, they are never changed.
ArrayRef< uint8_t > RecordData
uint32_t getSignature() const
TypeIndex insertRecordAs(GloballyHashedType Hash, size_t RecordSize, CreateFunc Create)
TypeIndex insertRecordBytes(ArrayRef< uint8_t > &Record)
static Error deserializeAs(CVType &CVT, T &Record)
uint32_t toArrayIndex() const
static const uint32_t FirstNonSimpleIndex
uint32_t getIndex() const
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
CVRecord< TypeLeafKind > CVType
Error forEachCodeViewRecord(ArrayRef< uint8_t > StreamBuffer, Func F)
VarStreamArray< CVType > CVTypeArray
LLVM_ABI void discoverTypeIndices(ArrayRef< uint8_t > RecordData, SmallVectorImpl< TiReference > &Refs)
LLVM_ABI Error mergeIdRecords(MergingTypeTableBuilder &Dest, ArrayRef< TypeIndex > Types, SmallVectorImpl< TypeIndex > &SourceToDest, const CVTypeArray &Ids)
Merge one set of id records into another.
Definition TypeStreamMerger.cpp:437
LLVM_ABI Error mergeTypeAndIdRecords(MergingTypeTableBuilder &DestIds, MergingTypeTableBuilder &DestTypes, SmallVectorImpl< TypeIndex > &SourceToDest, const CVTypeArray &IdsAndTypes, std::optional< PCHMergerInfo > &PCHInfo)
Merge a unified set of type and id records, splitting them into separate output streams.
Definition TypeStreamMerger.cpp:445
bool isIdRecord(TypeLeafKind K)
Return true if this record should be in the IPI stream of a PDB.
LLVM_ABI Error mergeTypeRecords(MergingTypeTableBuilder &Dest, SmallVectorImpl< TypeIndex > &SourceToDest, const CVTypeArray &Types)
Merge one set of type records into another.
Definition TypeStreamMerger.cpp:430
This is an optimization pass for GlobalISel generic memory operations.
Error joinErrors(Error E1, Error E2)
Concatenate errors.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
Error make_error(ArgTs &&... Args)
Make a Error instance representing failure using the given error info type.
@ Ref
The access may reference the value stored in memory.
void cantFail(Error Err, const char *Msg=nullptr)
Report a fatal error if Err is a failure value.
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
ArrayRef(const T &OneElt) -> ArrayRef< T >
Used to forward information about PCH.OBJ (precompiled) files, when applicable.