mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-04-17 15:10:07 +00:00
[COFF] Teach LLD to use the COFF .debug$H section.
This adds the /DEBUG:GHASH option to LLD which will look for the existence of .debug$H sections in linker inputs and use them to accelerate type merging. The clang-cl side has already been added, so this completes the work necessary to begin experimenting with this feature. Differential Revision: https://reviews.llvm.org/D40980 llvm-svn: 320719
This commit is contained in:
parent
e010be38fd
commit
3e534be355
@ -88,18 +88,39 @@ struct GloballyHashedType {
|
||||
ArrayRef<GloballyHashedType> PreviousTypes,
|
||||
ArrayRef<GloballyHashedType> PreviousIds);
|
||||
|
||||
/// Given a sequence of bytes representing a record, compute a global hash for
|
||||
/// this record. Due to the nature of global hashes incorporating the hashes
|
||||
/// of referenced records, this function requires a list of types and ids
|
||||
/// that RecordData might reference, indexable by TypeIndex.
|
||||
static GloballyHashedType hashType(CVType Type,
|
||||
ArrayRef<GloballyHashedType> PreviousTypes,
|
||||
ArrayRef<GloballyHashedType> PreviousIds) {
|
||||
return hashType(Type.RecordData, PreviousTypes, PreviousIds);
|
||||
}
|
||||
|
||||
/// Given a sequence of combined type and ID records, compute global hashes
|
||||
/// for each of them, returning the results in a vector of hashed types.
|
||||
template <typename Range>
|
||||
static std::vector<GloballyHashedType> hashTypes(Range &&Records) {
|
||||
std::vector<GloballyHashedType> Hashes;
|
||||
Hashes.reserve(std::distance(std::begin(Records), std::end(Records)));
|
||||
for (const auto &R : Records)
|
||||
Hashes.push_back(hashType(R, Hashes, Hashes));
|
||||
|
||||
return Hashes;
|
||||
}
|
||||
|
||||
/// Given a sequence of combined type and ID records, compute global hashes
|
||||
/// for each of them, returning the results in a vector of hashed types.
|
||||
template <typename Range>
|
||||
static std::vector<GloballyHashedType>
|
||||
hashIds(Range &&Records, ArrayRef<GloballyHashedType> TypeHashes) {
|
||||
std::vector<GloballyHashedType> IdHashes;
|
||||
for (const auto &R : Records)
|
||||
IdHashes.push_back(hashType(R, TypeHashes, IdHashes));
|
||||
|
||||
return IdHashes;
|
||||
}
|
||||
|
||||
static std::vector<GloballyHashedType>
|
||||
hashTypeCollection(TypeCollection &Types) {
|
||||
std::vector<GloballyHashedType> Hashes;
|
||||
@ -109,6 +130,11 @@ struct GloballyHashedType {
|
||||
return Hashes;
|
||||
}
|
||||
};
|
||||
static_assert(std::is_trivially_copyable<GloballyHashedType>::value,
|
||||
"GloballyHashedType must be trivially copyable so that we can "
|
||||
"reinterpret_cast arrays of hash data to arrays of "
|
||||
"GloballyHashedType");
|
||||
|
||||
} // namespace codeview
|
||||
|
||||
template <> struct DenseMapInfo<codeview::LocallyHashedType> {
|
||||
|
@ -19,6 +19,8 @@ namespace llvm {
|
||||
namespace codeview {
|
||||
|
||||
class TypeIndex;
|
||||
struct GloballyHashedType;
|
||||
class GlobalTypeTableBuilder;
|
||||
class MergingTypeTableBuilder;
|
||||
|
||||
/// \brief Merge one set of type records into another. This method assumes
|
||||
@ -83,6 +85,22 @@ Error mergeTypeAndIdRecords(MergingTypeTableBuilder &DestIds,
|
||||
SmallVectorImpl<TypeIndex> &SourceToDest,
|
||||
const CVTypeArray &IdsAndTypes);
|
||||
|
||||
Error mergeTypeAndIdRecords(GlobalTypeTableBuilder &DestIds,
|
||||
GlobalTypeTableBuilder &DestTypes,
|
||||
SmallVectorImpl<TypeIndex> &SourceToDest,
|
||||
const CVTypeArray &IdsAndTypes,
|
||||
ArrayRef<GloballyHashedType> Hashes);
|
||||
|
||||
Error mergeTypeRecords(GlobalTypeTableBuilder &Dest,
|
||||
SmallVectorImpl<TypeIndex> &SourceToDest,
|
||||
const CVTypeArray &Types,
|
||||
ArrayRef<GloballyHashedType> Hashes);
|
||||
|
||||
Error mergeIdRecords(GlobalTypeTableBuilder &Dest, ArrayRef<TypeIndex> Types,
|
||||
SmallVectorImpl<TypeIndex> &SourceToDest,
|
||||
const CVTypeArray &Ids,
|
||||
ArrayRef<GloballyHashedType> Hashes);
|
||||
|
||||
} // end namespace codeview
|
||||
} // end namespace llvm
|
||||
|
||||
|
@ -743,6 +743,12 @@ struct coff_resource_dir_table {
|
||||
support::ulittle16_t NumberOfIDEntries;
|
||||
};
|
||||
|
||||
struct debug_h_header {
|
||||
support::ulittle32_t Magic;
|
||||
support::ulittle16_t Version;
|
||||
support::ulittle16_t HashAlgorithm;
|
||||
};
|
||||
|
||||
class COFFObjectFile : public ObjectFile {
|
||||
private:
|
||||
friend class ImportDirectoryEntryRef;
|
||||
|
@ -54,7 +54,7 @@ GloballyHashedType::hashType(ArrayRef<uint8_t> RecordData,
|
||||
reinterpret_cast<const TypeIndex *>(RefData.data()), Ref.Count);
|
||||
for (TypeIndex TI : Indices) {
|
||||
ArrayRef<uint8_t> BytesToHash;
|
||||
if (TI.isSimple() || TI.isNoneType()) {
|
||||
if (TI.isSimple() || TI.isNoneType() || TI.toArrayIndex() >= Prev.size()) {
|
||||
const uint8_t *IndexBytes = reinterpret_cast<const uint8_t *>(&TI);
|
||||
BytesToHash = makeArrayRef(IndexBytes, sizeof(TypeIndex));
|
||||
} else {
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "llvm/DebugInfo/CodeView/TypeStreamMerger.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/DebugInfo/CodeView/GlobalTypeTableBuilder.h"
|
||||
#include "llvm/DebugInfo/CodeView/MergingTypeTableBuilder.h"
|
||||
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
|
||||
#include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h"
|
||||
@ -62,6 +63,7 @@ public:
|
||||
|
||||
static const TypeIndex Untranslated;
|
||||
|
||||
// Local hashing entry points
|
||||
Error mergeTypesAndIds(MergingTypeTableBuilder &DestIds,
|
||||
MergingTypeTableBuilder &DestTypes,
|
||||
const CVTypeArray &IdsAndTypes);
|
||||
@ -71,6 +73,18 @@ public:
|
||||
Error mergeTypeRecords(MergingTypeTableBuilder &Dest,
|
||||
const CVTypeArray &Types);
|
||||
|
||||
// Global hashing entry points
|
||||
Error mergeTypesAndIds(GlobalTypeTableBuilder &DestIds,
|
||||
GlobalTypeTableBuilder &DestTypes,
|
||||
const CVTypeArray &IdsAndTypes,
|
||||
ArrayRef<GloballyHashedType> Hashes);
|
||||
Error mergeIdRecords(GlobalTypeTableBuilder &Dest,
|
||||
ArrayRef<TypeIndex> TypeSourceToDest,
|
||||
const CVTypeArray &Ids,
|
||||
ArrayRef<GloballyHashedType> Hashes);
|
||||
Error mergeTypeRecords(GlobalTypeTableBuilder &Dest, const CVTypeArray &Types,
|
||||
ArrayRef<GloballyHashedType> Hashes);
|
||||
|
||||
private:
|
||||
Error doit(const CVTypeArray &Types);
|
||||
|
||||
@ -83,6 +97,14 @@ private:
|
||||
bool remapTypeIndex(TypeIndex &Idx);
|
||||
bool remapItemIndex(TypeIndex &Idx);
|
||||
|
||||
bool hasTypeStream() const {
|
||||
return (UseGlobalHashes) ? (!!DestGlobalTypeStream) : (!!DestTypeStream);
|
||||
}
|
||||
|
||||
bool hasIdStream() const {
|
||||
return (UseGlobalHashes) ? (!!DestGlobalIdStream) : (!!DestIdStream);
|
||||
}
|
||||
|
||||
ArrayRef<uint8_t> serializeRemapped(const RemappedType &Record);
|
||||
|
||||
bool remapIndices(RemappedType &Record, ArrayRef<TiReference> Refs);
|
||||
@ -100,6 +122,8 @@ private:
|
||||
|
||||
Optional<Error> LastError;
|
||||
|
||||
bool UseGlobalHashes = false;
|
||||
|
||||
bool IsSecondPass = false;
|
||||
|
||||
unsigned NumBadIndices = 0;
|
||||
@ -109,6 +133,11 @@ private:
|
||||
MergingTypeTableBuilder *DestIdStream = nullptr;
|
||||
MergingTypeTableBuilder *DestTypeStream = nullptr;
|
||||
|
||||
GlobalTypeTableBuilder *DestGlobalIdStream = nullptr;
|
||||
GlobalTypeTableBuilder *DestGlobalTypeStream = nullptr;
|
||||
|
||||
ArrayRef<GloballyHashedType> GlobalHashes;
|
||||
|
||||
// If we're only mapping id records, this array contains the mapping for
|
||||
// type records.
|
||||
ArrayRef<TypeIndex> TypeLookup;
|
||||
@ -209,7 +238,7 @@ bool TypeStreamMerger::remapTypeIndex(TypeIndex &Idx) {
|
||||
// special mapping from OldTypeStream -> NewTypeStream which was computed
|
||||
// externally. Regardless, we use this special map if and only if we are
|
||||
// doing an id-only mapping.
|
||||
if (DestTypeStream == nullptr)
|
||||
if (!hasTypeStream())
|
||||
return remapIndex(Idx, TypeLookup);
|
||||
|
||||
assert(TypeLookup.empty());
|
||||
@ -217,13 +246,15 @@ bool TypeStreamMerger::remapTypeIndex(TypeIndex &Idx) {
|
||||
}
|
||||
|
||||
bool TypeStreamMerger::remapItemIndex(TypeIndex &Idx) {
|
||||
assert(DestIdStream);
|
||||
assert(hasIdStream());
|
||||
return remapIndex(Idx, IndexMap);
|
||||
}
|
||||
|
||||
// Local hashing entry points
|
||||
Error TypeStreamMerger::mergeTypeRecords(MergingTypeTableBuilder &Dest,
|
||||
const CVTypeArray &Types) {
|
||||
DestTypeStream = &Dest;
|
||||
UseGlobalHashes = false;
|
||||
|
||||
return doit(Types);
|
||||
}
|
||||
@ -233,6 +264,7 @@ Error TypeStreamMerger::mergeIdRecords(MergingTypeTableBuilder &Dest,
|
||||
const CVTypeArray &Ids) {
|
||||
DestIdStream = &Dest;
|
||||
TypeLookup = TypeSourceToDest;
|
||||
UseGlobalHashes = false;
|
||||
|
||||
return doit(Ids);
|
||||
}
|
||||
@ -242,6 +274,41 @@ Error TypeStreamMerger::mergeTypesAndIds(MergingTypeTableBuilder &DestIds,
|
||||
const CVTypeArray &IdsAndTypes) {
|
||||
DestIdStream = &DestIds;
|
||||
DestTypeStream = &DestTypes;
|
||||
UseGlobalHashes = false;
|
||||
return doit(IdsAndTypes);
|
||||
}
|
||||
|
||||
// Global hashing entry points
|
||||
Error TypeStreamMerger::mergeTypeRecords(GlobalTypeTableBuilder &Dest,
|
||||
const CVTypeArray &Types,
|
||||
ArrayRef<GloballyHashedType> Hashes) {
|
||||
DestGlobalTypeStream = &Dest;
|
||||
UseGlobalHashes = true;
|
||||
GlobalHashes = Hashes;
|
||||
|
||||
return doit(Types);
|
||||
}
|
||||
|
||||
Error TypeStreamMerger::mergeIdRecords(GlobalTypeTableBuilder &Dest,
|
||||
ArrayRef<TypeIndex> TypeSourceToDest,
|
||||
const CVTypeArray &Ids,
|
||||
ArrayRef<GloballyHashedType> Hashes) {
|
||||
DestGlobalIdStream = &Dest;
|
||||
TypeLookup = TypeSourceToDest;
|
||||
UseGlobalHashes = true;
|
||||
GlobalHashes = Hashes;
|
||||
|
||||
return doit(Ids);
|
||||
}
|
||||
|
||||
Error TypeStreamMerger::mergeTypesAndIds(GlobalTypeTableBuilder &DestIds,
|
||||
GlobalTypeTableBuilder &DestTypes,
|
||||
const CVTypeArray &IdsAndTypes,
|
||||
ArrayRef<GloballyHashedType> Hashes) {
|
||||
DestGlobalIdStream = &DestIds;
|
||||
DestGlobalTypeStream = &DestTypes;
|
||||
UseGlobalHashes = true;
|
||||
GlobalHashes = Hashes;
|
||||
return doit(IdsAndTypes);
|
||||
}
|
||||
|
||||
@ -286,18 +353,29 @@ Error TypeStreamMerger::remapAllTypes(const CVTypeArray &Types) {
|
||||
}
|
||||
|
||||
Error TypeStreamMerger::remapType(const CVType &Type) {
|
||||
MergingTypeTableBuilder &Dest =
|
||||
isIdRecord(Type.kind()) ? *DestIdStream : *DestTypeStream;
|
||||
|
||||
RemappedType R(Type);
|
||||
SmallVector<TiReference, 32> Refs;
|
||||
discoverTypeIndices(Type.RecordData, Refs);
|
||||
bool MappedAllIndices = remapIndices(R, Refs);
|
||||
ArrayRef<uint8_t> Data = serializeRemapped(R);
|
||||
auto DoSerialize = [this, Type]() -> ArrayRef<uint8_t> {
|
||||
RemappedType R(Type);
|
||||
SmallVector<TiReference, 32> Refs;
|
||||
discoverTypeIndices(Type.RecordData, Refs);
|
||||
if (!remapIndices(R, Refs))
|
||||
return {};
|
||||
return serializeRemapped(R);
|
||||
};
|
||||
|
||||
TypeIndex DestIdx = Untranslated;
|
||||
if (MappedAllIndices)
|
||||
DestIdx = Dest.insertRecordBytes(Data);
|
||||
if (UseGlobalHashes) {
|
||||
GlobalTypeTableBuilder &Dest =
|
||||
isIdRecord(Type.kind()) ? *DestGlobalIdStream : *DestGlobalTypeStream;
|
||||
GloballyHashedType H = GlobalHashes[CurIndex.toArrayIndex()];
|
||||
DestIdx = Dest.insertRecordAs(H, DoSerialize);
|
||||
} else {
|
||||
MergingTypeTableBuilder &Dest =
|
||||
isIdRecord(Type.kind()) ? *DestIdStream : *DestTypeStream;
|
||||
|
||||
auto Data = DoSerialize();
|
||||
if (!Data.empty())
|
||||
DestIdx = Dest.insertRecordBytes(Data);
|
||||
}
|
||||
addMapping(DestIdx);
|
||||
|
||||
++CurIndex;
|
||||
@ -350,3 +428,28 @@ Error llvm::codeview::mergeTypeAndIdRecords(
|
||||
TypeStreamMerger M(SourceToDest);
|
||||
return M.mergeTypesAndIds(DestIds, DestTypes, IdsAndTypes);
|
||||
}
|
||||
|
||||
Error llvm::codeview::mergeTypeAndIdRecords(
|
||||
GlobalTypeTableBuilder &DestIds, GlobalTypeTableBuilder &DestTypes,
|
||||
SmallVectorImpl<TypeIndex> &SourceToDest, const CVTypeArray &IdsAndTypes,
|
||||
ArrayRef<GloballyHashedType> Hashes) {
|
||||
TypeStreamMerger M(SourceToDest);
|
||||
return M.mergeTypesAndIds(DestIds, DestTypes, IdsAndTypes, Hashes);
|
||||
}
|
||||
|
||||
Error llvm::codeview::mergeTypeRecords(GlobalTypeTableBuilder &Dest,
|
||||
SmallVectorImpl<TypeIndex> &SourceToDest,
|
||||
const CVTypeArray &Types,
|
||||
ArrayRef<GloballyHashedType> Hashes) {
|
||||
TypeStreamMerger M(SourceToDest);
|
||||
return M.mergeTypeRecords(Dest, Types, Hashes);
|
||||
}
|
||||
|
||||
Error llvm::codeview::mergeIdRecords(GlobalTypeTableBuilder &Dest,
|
||||
ArrayRef<TypeIndex> Types,
|
||||
SmallVectorImpl<TypeIndex> &SourceToDest,
|
||||
const CVTypeArray &Ids,
|
||||
ArrayRef<GloballyHashedType> Hashes) {
|
||||
TypeStreamMerger M(SourceToDest);
|
||||
return M.mergeIdRecords(Dest, Types, Ids, Hashes);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user