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.