diff options
author | Patrick Wildt <patrick@cvs.openbsd.org> | 2017-01-14 19:56:09 +0000 |
---|---|---|
committer | Patrick Wildt <patrick@cvs.openbsd.org> | 2017-01-14 19:56:09 +0000 |
commit | e71ad5fbc2d616fafda7b18d6ce16d7b83086bc1 (patch) | |
tree | 472308e37d1ce5780d389325fa6d5756462ffb32 /gnu | |
parent | dd108df16423a7a8bfc250e9cc68d0f273414c03 (diff) |
Import LLVM 3.9.1 including clang and lld.
Diffstat (limited to 'gnu')
65 files changed, 2344 insertions, 4252 deletions
diff --git a/gnu/llvm/include/llvm/DebugInfo/CodeView/ModuleSubstream.h b/gnu/llvm/include/llvm/DebugInfo/CodeView/ModuleSubstream.h index 8860ae42fc0..6affac801d4 100644 --- a/gnu/llvm/include/llvm/DebugInfo/CodeView/ModuleSubstream.h +++ b/gnu/llvm/include/llvm/DebugInfo/CodeView/ModuleSubstream.h @@ -11,8 +11,8 @@ #define LLVM_DEBUGINFO_CODEVIEW_MODULESUBSTREAM_H #include "llvm/DebugInfo/CodeView/CodeView.h" -#include "llvm/DebugInfo/MSF/StreamArray.h" -#include "llvm/DebugInfo/MSF/StreamRef.h" +#include "llvm/DebugInfo/CodeView/StreamArray.h" +#include "llvm/DebugInfo/CodeView/StreamRef.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" @@ -59,31 +59,29 @@ struct ColumnNumberEntry { class ModuleSubstream { public: ModuleSubstream(); - ModuleSubstream(ModuleSubstreamKind Kind, msf::ReadableStreamRef Data); - static Error initialize(msf::ReadableStreamRef Stream, ModuleSubstream &Info); + ModuleSubstream(ModuleSubstreamKind Kind, StreamRef Data); + static Error initialize(StreamRef Stream, ModuleSubstream &Info); uint32_t getRecordLength() const; ModuleSubstreamKind getSubstreamKind() const; - msf::ReadableStreamRef getRecordData() const; + StreamRef getRecordData() const; private: ModuleSubstreamKind Kind; - msf::ReadableStreamRef Data; + StreamRef Data; }; -typedef msf::VarStreamArray<ModuleSubstream> ModuleSubstreamArray; -} // namespace codeview - -namespace msf { -template <> struct VarStreamArrayExtractor<codeview::ModuleSubstream> { - Error operator()(ReadableStreamRef Stream, uint32_t &Length, - codeview::ModuleSubstream &Info) const { - if (auto EC = codeview::ModuleSubstream::initialize(Stream, Info)) +template <> struct VarStreamArrayExtractor<ModuleSubstream> { + Error operator()(StreamRef Stream, uint32_t &Length, + ModuleSubstream &Info) const { + if (auto EC = ModuleSubstream::initialize(Stream, Info)) return EC; Length = Info.getRecordLength(); return Error::success(); } }; -} // namespace msf -} // namespace llvm + +typedef VarStreamArray<ModuleSubstream> ModuleSubstreamArray; +} +} #endif // LLVM_DEBUGINFO_CODEVIEW_MODULESUBSTREAM_H diff --git a/gnu/llvm/include/llvm/DebugInfo/CodeView/ModuleSubstreamVisitor.h b/gnu/llvm/include/llvm/DebugInfo/CodeView/ModuleSubstreamVisitor.h index f9927d66093..6df23090371 100644 --- a/gnu/llvm/include/llvm/DebugInfo/CodeView/ModuleSubstreamVisitor.h +++ b/gnu/llvm/include/llvm/DebugInfo/CodeView/ModuleSubstreamVisitor.h @@ -10,75 +10,28 @@ #ifndef LLVM_DEBUGINFO_CODEVIEW_MODULESUBSTREAMVISITOR_H #define LLVM_DEBUGINFO_CODEVIEW_MODULESUBSTREAMVISITOR_H -#include "llvm/ADT/ArrayRef.h" #include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/CodeView/CodeViewError.h" #include "llvm/DebugInfo/CodeView/Line.h" #include "llvm/DebugInfo/CodeView/ModuleSubstream.h" -#include "llvm/DebugInfo/MSF/StreamArray.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" -#include "llvm/DebugInfo/MSF/StreamRef.h" -#include "llvm/Support/Endian.h" -#include "llvm/Support/Error.h" -#include <cstdint> +#include "llvm/DebugInfo/CodeView/StreamReader.h" +#include "llvm/DebugInfo/CodeView/StreamRef.h" namespace llvm { - namespace codeview { struct LineColumnEntry { support::ulittle32_t NameIndex; - msf::FixedStreamArray<LineNumberEntry> LineNumbers; - msf::FixedStreamArray<ColumnNumberEntry> Columns; + FixedStreamArray<LineNumberEntry> LineNumbers; + FixedStreamArray<ColumnNumberEntry> Columns; }; -struct FileChecksumEntry { - uint32_t FileNameOffset; // Byte offset of filename in global stringtable. - FileChecksumKind Kind; // The type of checksum. - ArrayRef<uint8_t> Checksum; // The bytes of the checksum. -}; - -typedef msf::VarStreamArray<LineColumnEntry> LineInfoArray; -typedef msf::VarStreamArray<FileChecksumEntry> FileChecksumArray; - -class IModuleSubstreamVisitor { +template <> class VarStreamArrayExtractor<LineColumnEntry> { public: - virtual ~IModuleSubstreamVisitor() = default; + VarStreamArrayExtractor(const LineSubstreamHeader *Header) : Header(Header) {} - virtual Error visitUnknown(ModuleSubstreamKind Kind, - msf::ReadableStreamRef Data) = 0; - virtual Error visitSymbols(msf::ReadableStreamRef Data); - virtual Error visitLines(msf::ReadableStreamRef Data, - const LineSubstreamHeader *Header, - const LineInfoArray &Lines); - virtual Error visitStringTable(msf::ReadableStreamRef Data); - virtual Error visitFileChecksums(msf::ReadableStreamRef Data, - const FileChecksumArray &Checksums); - virtual Error visitFrameData(msf::ReadableStreamRef Data); - virtual Error visitInlineeLines(msf::ReadableStreamRef Data); - virtual Error visitCrossScopeImports(msf::ReadableStreamRef Data); - virtual Error visitCrossScopeExports(msf::ReadableStreamRef Data); - virtual Error visitILLines(msf::ReadableStreamRef Data); - virtual Error visitFuncMDTokenMap(msf::ReadableStreamRef Data); - virtual Error visitTypeMDTokenMap(msf::ReadableStreamRef Data); - virtual Error visitMergedAssemblyInput(msf::ReadableStreamRef Data); - virtual Error visitCoffSymbolRVA(msf::ReadableStreamRef Data); -}; - -Error visitModuleSubstream(const ModuleSubstream &R, - IModuleSubstreamVisitor &V); -} // end namespace codeview - -namespace msf { - -template <> class VarStreamArrayExtractor<codeview::LineColumnEntry> { -public: - VarStreamArrayExtractor(const codeview::LineSubstreamHeader *Header) - : Header(Header) {} - - Error operator()(ReadableStreamRef Stream, uint32_t &Len, - codeview::LineColumnEntry &Item) const { - using namespace codeview; + Error operator()(StreamRef Stream, uint32_t &Len, + LineColumnEntry &Item) const { const LineFileBlockHeader *BlockHeader; StreamReader Reader(Stream); if (auto EC = Reader.readObject(BlockHeader)) @@ -108,14 +61,19 @@ public: } private: - const codeview::LineSubstreamHeader *Header; + const LineSubstreamHeader *Header; }; -template <> class VarStreamArrayExtractor<codeview::FileChecksumEntry> { +struct FileChecksumEntry { + uint32_t FileNameOffset; // Byte offset of filename in global stringtable. + FileChecksumKind Kind; // The type of checksum. + ArrayRef<uint8_t> Checksum; // The bytes of the checksum. +}; + +template <> class VarStreamArrayExtractor<FileChecksumEntry> { public: - Error operator()(ReadableStreamRef Stream, uint32_t &Len, - codeview::FileChecksumEntry &Item) const { - using namespace codeview; + Error operator()(StreamRef Stream, uint32_t &Len, + FileChecksumEntry &Item) const { const FileChecksum *Header; StreamReader Reader(Stream); if (auto EC = Reader.readObject(Header)) @@ -129,8 +87,35 @@ public: } }; -} // end namespace msf +typedef VarStreamArray<LineColumnEntry> LineInfoArray; +typedef VarStreamArray<FileChecksumEntry> FileChecksumArray; + +class IModuleSubstreamVisitor { +public: + virtual ~IModuleSubstreamVisitor() {} + + virtual Error visitUnknown(ModuleSubstreamKind Kind, StreamRef Data) = 0; + virtual Error visitSymbols(StreamRef Data); + virtual Error visitLines(StreamRef Data, const LineSubstreamHeader *Header, + const LineInfoArray &Lines); + virtual Error visitStringTable(StreamRef Data); + virtual Error visitFileChecksums(StreamRef Data, + const FileChecksumArray &Checksums); + virtual Error visitFrameData(StreamRef Data); + virtual Error visitInlineeLines(StreamRef Data); + virtual Error visitCrossScopeImports(StreamRef Data); + virtual Error visitCrossScopeExports(StreamRef Data); + virtual Error visitILLines(StreamRef Data); + virtual Error visitFuncMDTokenMap(StreamRef Data); + virtual Error visitTypeMDTokenMap(StreamRef Data); + virtual Error visitMergedAssemblyInput(StreamRef Data); + virtual Error visitCoffSymbolRVA(StreamRef Data); +}; + +Error visitModuleSubstream(const ModuleSubstream &R, + IModuleSubstreamVisitor &V); -} // end namespace llvm +} // namespace codeview +} // namespace llvm #endif // LLVM_DEBUGINFO_CODEVIEW_MODULESUBSTREAMVISITOR_H diff --git a/gnu/llvm/include/llvm/DebugInfo/CodeView/TypeRecords.def b/gnu/llvm/include/llvm/DebugInfo/CodeView/TypeRecords.def index c98dbac21a7..0959f4bf19c 100644 --- a/gnu/llvm/include/llvm/DebugInfo/CodeView/TypeRecords.def +++ b/gnu/llvm/include/llvm/DebugInfo/CodeView/TypeRecords.def @@ -43,8 +43,6 @@ TYPE_RECORD(LF_PROCEDURE, 0x1008, Procedure) TYPE_RECORD(LF_MFUNCTION, 0x1009, MemberFunction) TYPE_RECORD(LF_ARGLIST, 0x1201, ArgList) -TYPE_RECORD(LF_FIELDLIST, 0x1203, FieldList) - TYPE_RECORD(LF_ARRAY, 0x1503, Array) TYPE_RECORD(LF_CLASS, 0x1504, Class) TYPE_RECORD_ALIAS(LF_STRUCTURE, 0x1505, Struct, Class) @@ -161,6 +159,7 @@ CV_TYPE(LF_OEM2, 0x1011) CV_TYPE(LF_SKIP, 0x1200) CV_TYPE(LF_DEFARG_ST, 0x1202) +CV_TYPE(LF_FIELDLIST, 0x1203) CV_TYPE(LF_DERIVED, 0x1204) CV_TYPE(LF_DIMCONU, 0x1207) CV_TYPE(LF_DIMCONLU, 0x1208) diff --git a/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/DbiStream.h b/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/DbiStream.h index c97ca32ab43..6ab3c806755 100644 --- a/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/DbiStream.h +++ b/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/DbiStream.h @@ -11,10 +11,10 @@ #define LLVM_DEBUGINFO_PDB_RAW_PDBDBISTREAM_H #include "llvm/DebugInfo/CodeView/ModuleSubstream.h" -#include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/DebugInfo/MSF/StreamArray.h" -#include "llvm/DebugInfo/MSF/StreamRef.h" +#include "llvm/DebugInfo/CodeView/StreamArray.h" +#include "llvm/DebugInfo/CodeView/StreamRef.h" #include "llvm/DebugInfo/PDB/PDBTypes.h" +#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" #include "llvm/DebugInfo/PDB/Raw/ModInfo.h" #include "llvm/DebugInfo/PDB/Raw/NameHashTable.h" #include "llvm/DebugInfo/PDB/Raw/RawConstants.h" @@ -36,8 +36,32 @@ class ISectionContribVisitor; class DbiStream { friend class DbiStreamBuilder; + struct HeaderInfo { + support::little32_t VersionSignature; + support::ulittle32_t VersionHeader; + support::ulittle32_t Age; // Should match InfoStream. + support::ulittle16_t GlobalSymbolStreamIndex; // Global symbol stream # + support::ulittle16_t BuildNumber; // See DbiBuildNo structure. + support::ulittle16_t PublicSymbolStreamIndex; // Public symbols stream # + support::ulittle16_t PdbDllVersion; // version of mspdbNNN.dll + support::ulittle16_t SymRecordStreamIndex; // Symbol records stream # + support::ulittle16_t PdbDllRbld; // rbld number of mspdbNNN.dll + support::little32_t ModiSubstreamSize; // Size of module info stream + support::little32_t SecContrSubstreamSize; // Size of sec. contrib stream + support::little32_t SectionMapSize; // Size of sec. map substream + support::little32_t FileInfoSize; // Size of file info substream + support::little32_t TypeServerSize; // Size of type server map + support::ulittle32_t MFCTypeServerIndex; // Index of MFC Type Server + support::little32_t OptionalDbgHdrSize; // Size of DbgHeader info + support::little32_t ECSubstreamSize; // Size of EC stream (what is EC?) + support::ulittle16_t Flags; // See DbiFlags enum. + support::ulittle16_t MachineType; // See PDB_MachineType enum. + + support::ulittle32_t Reserved; // Pad to 64 bytes + }; + public: - DbiStream(PDBFile &File, std::unique_ptr<msf::MappedBlockStream> Stream); + DbiStream(PDBFile &File, std::unique_ptr<MappedBlockStream> Stream); ~DbiStream(); Error reload(); @@ -62,6 +86,8 @@ public: PDB_Machine getMachineType() const; + enum { InvalidStreamIndex = 0xffff }; + /// If the given stream type is present, returns its stream index. If it is /// not present, returns InvalidStreamIndex. uint32_t getDebugStreamIndex(DbgHeaderType Type) const; @@ -70,15 +96,16 @@ public: Expected<StringRef> getFileNameForIndex(uint32_t Index) const; - msf::FixedStreamArray<object::coff_section> getSectionHeaders(); + codeview::FixedStreamArray<object::coff_section> getSectionHeaders(); - msf::FixedStreamArray<object::FpoData> getFpoRecords(); + codeview::FixedStreamArray<object::FpoData> getFpoRecords(); - msf::FixedStreamArray<SecMapEntry> getSectionMap() const; + codeview::FixedStreamArray<SecMapEntry> getSectionMap() const; void visitSectionContributions(ISectionContribVisitor &Visitor) const; + Error commit(); + private: - Error initializeModInfoArray(); Error initializeSectionContributionData(); Error initializeSectionHeadersData(); Error initializeSectionMapData(); @@ -86,35 +113,35 @@ private: Error initializeFpoRecords(); PDBFile &Pdb; - std::unique_ptr<msf::MappedBlockStream> Stream; + std::unique_ptr<MappedBlockStream> Stream; std::vector<ModuleInfoEx> ModuleInfos; NameHashTable ECNames; - msf::ReadableStreamRef ModInfoSubstream; - msf::ReadableStreamRef SecContrSubstream; - msf::ReadableStreamRef SecMapSubstream; - msf::ReadableStreamRef FileInfoSubstream; - msf::ReadableStreamRef TypeServerMapSubstream; - msf::ReadableStreamRef ECSubstream; + codeview::StreamRef ModInfoSubstream; + codeview::StreamRef SecContrSubstream; + codeview::StreamRef SecMapSubstream; + codeview::StreamRef FileInfoSubstream; + codeview::StreamRef TypeServerMapSubstream; + codeview::StreamRef ECSubstream; - msf::ReadableStreamRef NamesBuffer; + codeview::StreamRef NamesBuffer; - msf::FixedStreamArray<support::ulittle16_t> DbgStreams; + codeview::FixedStreamArray<support::ulittle16_t> DbgStreams; PdbRaw_DbiSecContribVer SectionContribVersion; - msf::FixedStreamArray<SectionContrib> SectionContribs; - msf::FixedStreamArray<SectionContrib2> SectionContribs2; - msf::FixedStreamArray<SecMapEntry> SectionMap; - msf::FixedStreamArray<support::little32_t> FileNameOffsets; + codeview::FixedStreamArray<SectionContrib> SectionContribs; + codeview::FixedStreamArray<SectionContrib2> SectionContribs2; + codeview::FixedStreamArray<SecMapEntry> SectionMap; + codeview::FixedStreamArray<support::little32_t> FileNameOffsets; - std::unique_ptr<msf::MappedBlockStream> SectionHeaderStream; - msf::FixedStreamArray<object::coff_section> SectionHeaders; + std::unique_ptr<MappedBlockStream> SectionHeaderStream; + codeview::FixedStreamArray<object::coff_section> SectionHeaders; - std::unique_ptr<msf::MappedBlockStream> FpoStream; - msf::FixedStreamArray<object::FpoData> FpoRecords; + std::unique_ptr<MappedBlockStream> FpoStream; + codeview::FixedStreamArray<object::FpoData> FpoRecords; - const DbiStreamHeader *Header; + const HeaderInfo *Header; }; } } diff --git a/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/DbiStreamBuilder.h b/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/DbiStreamBuilder.h index 99a3ac7fb1d..2c7350f3c3e 100644 --- a/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/DbiStreamBuilder.h +++ b/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/DbiStreamBuilder.h @@ -11,31 +11,20 @@ #define LLVM_DEBUGINFO_PDB_RAW_PDBDBISTREAMBUILDER_H #include "llvm/ADT/Optional.h" -#include "llvm/ADT/StringSet.h" #include "llvm/Support/Error.h" -#include "llvm/DebugInfo/MSF/ByteStream.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" #include "llvm/DebugInfo/PDB/PDBTypes.h" #include "llvm/DebugInfo/PDB/Raw/PDBFile.h" #include "llvm/DebugInfo/PDB/Raw/RawConstants.h" -#include "llvm/Support/Endian.h" namespace llvm { -namespace msf { -class MSFBuilder; -} -namespace object { -struct coff_section; -} namespace pdb { class DbiStream; -struct DbiStreamHeader; class PDBFile; class DbiStreamBuilder { public: - DbiStreamBuilder(msf::MSFBuilder &Msf); + DbiStreamBuilder(); DbiStreamBuilder(const DbiStreamBuilder &) = delete; DbiStreamBuilder &operator=(const DbiStreamBuilder &) = delete; @@ -47,57 +36,12 @@ public: void setPdbDllRbld(uint16_t R); void setFlags(uint16_t F); void setMachineType(PDB_Machine M); - void setSectionContribs(ArrayRef<SectionContrib> SecMap); - void setSectionMap(ArrayRef<SecMapEntry> SecMap); - - // Add given bytes as a new stream. - Error addDbgStream(pdb::DbgHeaderType Type, ArrayRef<uint8_t> Data); uint32_t calculateSerializedLength() const; - Error addModuleInfo(StringRef ObjFile, StringRef Module); - Error addModuleSourceFile(StringRef Module, StringRef File); - - Error finalizeMsfLayout(); - - Error commit(const msf::MSFLayout &Layout, - const msf::WritableStream &Buffer); - - // A helper function to create Section Contributions from COFF input - // section headers. - static std::vector<SectionContrib> - createSectionContribs(ArrayRef<llvm::object::coff_section> SecHdrs); - - // A helper function to create a Section Map from a COFF section header. - static std::vector<SecMapEntry> - createSectionMap(ArrayRef<llvm::object::coff_section> SecHdrs); + Expected<std::unique_ptr<DbiStream>> build(PDBFile &File); private: - struct DebugStream { - ArrayRef<uint8_t> Data; - uint16_t StreamNumber = 0; - }; - - Error finalize(); - uint32_t calculateModiSubstreamSize() const; - uint32_t calculateSectionContribsStreamSize() const; - uint32_t calculateSectionMapStreamSize() const; - uint32_t calculateFileInfoSubstreamSize() const; - uint32_t calculateNamesBufferSize() const; - uint32_t calculateDbgStreamsSize() const; - - Error generateModiSubstream(); - Error generateFileInfoSubstream(); - - struct ModuleInfo { - std::vector<StringRef> SourceFiles; - StringRef Obj; - StringRef Mod; - }; - - msf::MSFBuilder &Msf; - BumpPtrAllocator &Allocator; - Optional<PdbRaw_DbiVer> VerHeader; uint32_t Age; uint16_t BuildNumber; @@ -105,20 +49,6 @@ private: uint16_t PdbDllRbld; uint16_t Flags; PDB_Machine MachineType; - - const DbiStreamHeader *Header; - - StringMap<std::unique_ptr<ModuleInfo>> ModuleInfos; - std::vector<ModuleInfo *> ModuleInfoList; - - StringMap<uint32_t> SourceFileNames; - - msf::WritableStreamRef NamesBuffer; - msf::MutableByteStream ModInfoBuffer; - msf::MutableByteStream FileInfoBuffer; - ArrayRef<SectionContrib> SectionContribs; - ArrayRef<SecMapEntry> SectionMap; - llvm::SmallVector<DebugStream, (int)DbgHeaderType::Max> DbgStreams; }; } } diff --git a/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/ISectionContribVisitor.h b/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/ISectionContribVisitor.h index fb00d6ad4bc..355a25a38ef 100644 --- a/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/ISectionContribVisitor.h +++ b/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/ISectionContribVisitor.h @@ -12,19 +12,17 @@ namespace llvm { namespace pdb { - struct SectionContrib; struct SectionContrib2; class ISectionContribVisitor { public: - virtual ~ISectionContribVisitor() = default; + virtual ~ISectionContribVisitor() {} virtual void visit(const SectionContrib &C) = 0; virtual void visit(const SectionContrib2 &C) = 0; }; - -} // end namespace pdb -} // end namespace llvm +} // namespace pdb +} // namespace llvm #endif // LLVM_DEBUGINFO_PDB_RAW_ISECTIONCONTRIBVISITOR_H diff --git a/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/InfoStream.h b/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/InfoStream.h index 6b8b94ff1a3..1980bec7153 100644 --- a/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/InfoStream.h +++ b/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/InfoStream.h @@ -11,8 +11,8 @@ #define LLVM_DEBUGINFO_PDB_RAW_PDBINFOSTREAM_H #include "llvm/ADT/StringMap.h" -#include "llvm/DebugInfo/MSF/MappedBlockStream.h" #include "llvm/DebugInfo/PDB/PDBTypes.h" +#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" #include "llvm/DebugInfo/PDB/Raw/NameMap.h" #include "llvm/DebugInfo/PDB/Raw/RawConstants.h" @@ -27,10 +27,18 @@ class PDBFile; class InfoStream { friend class InfoStreamBuilder; + struct HeaderInfo { + support::ulittle32_t Version; + support::ulittle32_t Signature; + support::ulittle32_t Age; + PDB_UniqueId Guid; + }; + public: - InfoStream(std::unique_ptr<msf::MappedBlockStream> Stream); + InfoStream(std::unique_ptr<MappedBlockStream> Stream); Error reload(); + Error commit(); PdbRaw_ImplVer getVersion() const; uint32_t getSignature() const; @@ -41,7 +49,7 @@ public: iterator_range<StringMapConstIterator<uint32_t>> named_streams() const; private: - std::unique_ptr<msf::MappedBlockStream> Stream; + std::unique_ptr<MappedBlockStream> Stream; // PDB file format version. We only support VC70. See the enumeration // `PdbRaw_ImplVer` for the other possible values. diff --git a/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/InfoStreamBuilder.h b/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/InfoStreamBuilder.h index cb60b1eb69b..e9869bb2786 100644 --- a/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/InfoStreamBuilder.h +++ b/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/InfoStreamBuilder.h @@ -19,16 +19,12 @@ #include "llvm/DebugInfo/PDB/Raw/RawConstants.h" namespace llvm { -namespace msf { -class MSFBuilder; -class StreamWriter; -} namespace pdb { class PDBFile; class InfoStreamBuilder { public: - InfoStreamBuilder(msf::MSFBuilder &Msf); + InfoStreamBuilder(); InfoStreamBuilder(const InfoStreamBuilder &) = delete; InfoStreamBuilder &operator=(const InfoStreamBuilder &) = delete; @@ -41,18 +37,13 @@ public: uint32_t calculateSerializedLength() const; - Error finalizeMsfLayout(); - - Error commit(const msf::MSFLayout &Layout, - const msf::WritableStream &Buffer) const; + Expected<std::unique_ptr<InfoStream>> build(PDBFile &File); private: - msf::MSFBuilder &Msf; - - PdbRaw_ImplVer Ver; - uint32_t Sig; - uint32_t Age; - PDB_UniqueId Guid; + Optional<PdbRaw_ImplVer> Ver; + Optional<uint32_t> Sig; + Optional<uint32_t> Age; + Optional<PDB_UniqueId> Guid; NameMapBuilder NamedStreams; }; diff --git a/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/ModInfo.h b/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/ModInfo.h index bf5cf53b331..b8da0bfabf3 100644 --- a/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/ModInfo.h +++ b/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/ModInfo.h @@ -11,26 +11,24 @@ #define LLVM_DEBUGINFO_PDB_RAW_MODINFO_H #include "llvm/ADT/StringRef.h" -#include "llvm/DebugInfo/MSF/StreamArray.h" -#include "llvm/DebugInfo/MSF/StreamRef.h" -#include "llvm/DebugInfo/PDB/Raw/RawTypes.h" -#include "llvm/Support/Error.h" +#include "llvm/DebugInfo/CodeView/StreamArray.h" +#include "llvm/DebugInfo/CodeView/StreamRef.h" #include <cstdint> #include <vector> namespace llvm { - namespace pdb { class ModInfo { - friend class DbiStreamBuilder; +private: + struct FileLayout; public: ModInfo(); ModInfo(const ModInfo &Info); ~ModInfo(); - static Error initialize(msf::ReadableStreamRef Stream, ModInfo &Info); + static Error initialize(codeview::StreamRef Stream, ModInfo &Info); bool hasECInfo() const; uint16_t getTypeServerIndex() const; @@ -50,12 +48,13 @@ public: private: StringRef ModuleName; StringRef ObjFileName; - const ModuleInfoHeader *Layout = nullptr; + const FileLayout *Layout; }; struct ModuleInfoEx { ModuleInfoEx(const ModInfo &Info) : Info(Info) {} - ModuleInfoEx(const ModuleInfoEx &Ex) = default; + ModuleInfoEx(const ModuleInfoEx &Ex) + : Info(Ex.Info), SourceFiles(Ex.SourceFiles) {} ModInfo Info; std::vector<StringRef> SourceFiles; @@ -63,10 +62,9 @@ struct ModuleInfoEx { } // end namespace pdb -namespace msf { - +namespace codeview { template <> struct VarStreamArrayExtractor<pdb::ModInfo> { - Error operator()(ReadableStreamRef Stream, uint32_t &Length, + Error operator()(StreamRef Stream, uint32_t &Length, pdb::ModInfo &Info) const { if (auto EC = pdb::ModInfo::initialize(Stream, Info)) return EC; @@ -74,8 +72,7 @@ template <> struct VarStreamArrayExtractor<pdb::ModInfo> { return Error::success(); } }; - -} // end namespace msf +} } // end namespace llvm diff --git a/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/ModStream.h b/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/ModStream.h index d5e7a6830d8..d22962cc1e2 100644 --- a/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/ModStream.h +++ b/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/ModStream.h @@ -13,10 +13,10 @@ #include "llvm/ADT/iterator_range.h" #include "llvm/DebugInfo/CodeView/CVRecord.h" #include "llvm/DebugInfo/CodeView/ModuleSubstream.h" +#include "llvm/DebugInfo/CodeView/StreamArray.h" +#include "llvm/DebugInfo/CodeView/StreamRef.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.h" -#include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/DebugInfo/MSF/StreamArray.h" -#include "llvm/DebugInfo/MSF/StreamRef.h" +#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" #include "llvm/Support/Error.h" namespace llvm { @@ -26,14 +26,11 @@ class ModInfo; class ModStream { public: - ModStream(const ModInfo &Module, - std::unique_ptr<msf::MappedBlockStream> Stream); + ModStream(const ModInfo &Module, std::unique_ptr<MappedBlockStream> Stream); ~ModStream(); Error reload(); - uint32_t signature() const { return Signature; } - iterator_range<codeview::CVSymbolArray::Iterator> symbols(bool *HadError) const; @@ -45,14 +42,12 @@ public: private: const ModInfo &Mod; - uint32_t Signature; - - std::unique_ptr<msf::MappedBlockStream> Stream; + std::unique_ptr<MappedBlockStream> Stream; codeview::CVSymbolArray SymbolsSubstream; - msf::ReadableStreamRef LinesSubstream; - msf::ReadableStreamRef C13LinesSubstream; - msf::ReadableStreamRef GlobalRefsSubstream; + codeview::StreamRef LinesSubstream; + codeview::StreamRef C13LinesSubstream; + codeview::StreamRef GlobalRefsSubstream; codeview::ModuleSubstreamArray LineInfo; }; diff --git a/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/NameHashTable.h b/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/NameHashTable.h index 00d022d4d8e..c9e060a3a70 100644 --- a/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/NameHashTable.h +++ b/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/NameHashTable.h @@ -12,15 +12,15 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" -#include "llvm/DebugInfo/MSF/StreamArray.h" -#include "llvm/DebugInfo/MSF/StreamRef.h" +#include "llvm/DebugInfo/CodeView/StreamArray.h" +#include "llvm/DebugInfo/CodeView/StreamRef.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include <cstdint> #include <vector> namespace llvm { -namespace msf { +namespace codeview { class StreamReader; } namespace pdb { @@ -29,7 +29,7 @@ class NameHashTable { public: NameHashTable(); - Error load(msf::StreamReader &Stream); + Error load(codeview::StreamReader &Stream); uint32_t getNameCount() const { return NameCount; } uint32_t getHashVersion() const { return HashVersion; } @@ -38,11 +38,11 @@ public: StringRef getStringForID(uint32_t ID) const; uint32_t getIDForString(StringRef Str) const; - msf::FixedStreamArray<support::ulittle32_t> name_ids() const; + codeview::FixedStreamArray<support::ulittle32_t> name_ids() const; private: - msf::ReadableStreamRef NamesBuffer; - msf::FixedStreamArray<support::ulittle32_t> IDs; + codeview::StreamRef NamesBuffer; + codeview::FixedStreamArray<support::ulittle32_t> IDs; uint32_t Signature; uint32_t HashVersion; uint32_t NameCount; diff --git a/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/NameMap.h b/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/NameMap.h index de1163bc307..8a9b0d187ac 100644 --- a/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/NameMap.h +++ b/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/NameMap.h @@ -16,7 +16,7 @@ #include <cstdint> namespace llvm { -namespace msf { +namespace codeview { class StreamReader; class StreamWriter; } @@ -28,7 +28,8 @@ class NameMap { public: NameMap(); - Error load(msf::StreamReader &Stream); + Error load(codeview::StreamReader &Stream); + Error commit(codeview::StreamWriter &Writer); bool tryGetValue(StringRef Name, uint32_t &Value) const; diff --git a/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/NameMapBuilder.h b/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/NameMapBuilder.h index f5244ac2180..bf49bfd9bf2 100644 --- a/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/NameMapBuilder.h +++ b/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/NameMapBuilder.h @@ -17,9 +17,6 @@ #include <memory> namespace llvm { -namespace msf { -class StreamWriter; -} namespace pdb { class NameMap; @@ -30,7 +27,6 @@ public: void addMapping(StringRef Name, uint32_t Mapping); Expected<std::unique_ptr<NameMap>> build(); - Error commit(msf::StreamWriter &Writer) const; uint32_t calculateSerializedLength() const; diff --git a/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/PDBFile.h b/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/PDBFile.h index 29f5b2163d8..f4d7eb47d3b 100644 --- a/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/PDBFile.h +++ b/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/PDBFile.h @@ -11,10 +11,10 @@ #define LLVM_DEBUGINFO_PDB_RAW_PDBFILE_H #include "llvm/ADT/DenseMap.h" -#include "llvm/DebugInfo/MSF/IMSFFile.h" -#include "llvm/DebugInfo/MSF/MSFCommon.h" -#include "llvm/DebugInfo/MSF/StreamArray.h" -#include "llvm/DebugInfo/MSF/StreamInterface.h" +#include "llvm/DebugInfo/CodeView/StreamArray.h" +#include "llvm/DebugInfo/CodeView/StreamInterface.h" +#include "llvm/DebugInfo/PDB/Raw/IPDBFile.h" +#include "llvm/DebugInfo/PDB/Raw/MsfCommon.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" @@ -24,26 +24,25 @@ namespace llvm { -namespace msf { -class MappedBlockStream; +namespace codeview { +class StreamInterface; } namespace pdb { class DbiStream; -class GlobalsStream; class InfoStream; +class MappedBlockStream; class NameHashTable; class PDBFileBuilder; class PublicsStream; class SymbolStream; class TpiStream; -class PDBFile : public msf::IMSFFile { +class PDBFile : public IPDBFile { friend PDBFileBuilder; public: - PDBFile(std::unique_ptr<msf::ReadableStream> PdbFileBuffer, - BumpPtrAllocator &Allocator); + explicit PDBFile(std::unique_ptr<codeview::StreamInterface> PdbFileBuffer); ~PDBFile() override; uint32_t getFreeBlockMapBlock() const; @@ -67,18 +66,11 @@ public: Error setBlockData(uint32_t BlockIndex, uint32_t Offset, ArrayRef<uint8_t> Data) const override; - ArrayRef<uint32_t> getFpmPages() const { return FpmPages; } - - ArrayRef<support::ulittle32_t> getStreamSizes() const { - return ContainerLayout.StreamSizes; - } + ArrayRef<support::ulittle32_t> getStreamSizes() const { return StreamSizes; } ArrayRef<ArrayRef<support::ulittle32_t>> getStreamMap() const { - return ContainerLayout.StreamMap; + return StreamMap; } - const msf::MSFLayout &getMsfLayout() const { return ContainerLayout; } - const msf::ReadableStream &getMsfBuffer() const { return *Buffer; } - ArrayRef<support::ulittle32_t> getDirectoryBlockArray() const; Error parseFileHeaders(); @@ -86,45 +78,33 @@ public: Expected<InfoStream &> getPDBInfoStream(); Expected<DbiStream &> getPDBDbiStream(); - Expected<GlobalsStream &> getPDBGlobalsStream(); Expected<TpiStream &> getPDBTpiStream(); Expected<TpiStream &> getPDBIpiStream(); Expected<PublicsStream &> getPDBPublicsStream(); Expected<SymbolStream &> getPDBSymbolStream(); Expected<NameHashTable &> getStringTable(); - BumpPtrAllocator &getAllocator() { return Allocator; } - - bool hasPDBDbiStream() const; - bool hasPDBGlobalsStream(); - bool hasPDBInfoStream(); - bool hasPDBIpiStream() const; - bool hasPDBPublicsStream(); - bool hasPDBSymbolStream(); - bool hasPDBTpiStream() const; - bool hasStringTable(); - - private: - Expected<std::unique_ptr<msf::MappedBlockStream>> safelyCreateIndexedStream( - const msf::MSFLayout &Layout, const msf::ReadableStream &MsfData, - uint32_t StreamIndex) const; + Error commit(); - BumpPtrAllocator &Allocator; +private: + Error setSuperBlock(const msf::SuperBlock *Block); - std::unique_ptr<msf::ReadableStream> Buffer; + BumpPtrAllocator Allocator; - std::vector<uint32_t> FpmPages; - msf::MSFLayout ContainerLayout; + std::unique_ptr<codeview::StreamInterface> Buffer; + const msf::SuperBlock *SB; + ArrayRef<support::ulittle32_t> StreamSizes; + ArrayRef<support::ulittle32_t> DirectoryBlocks; + std::vector<ArrayRef<support::ulittle32_t>> StreamMap; - std::unique_ptr<GlobalsStream> Globals; std::unique_ptr<InfoStream> Info; std::unique_ptr<DbiStream> Dbi; std::unique_ptr<TpiStream> Tpi; std::unique_ptr<TpiStream> Ipi; std::unique_ptr<PublicsStream> Publics; std::unique_ptr<SymbolStream> Symbols; - std::unique_ptr<msf::MappedBlockStream> DirectoryStream; - std::unique_ptr<msf::MappedBlockStream> StringTableStream; + std::unique_ptr<MappedBlockStream> DirectoryStream; + std::unique_ptr<MappedBlockStream> StringTableStream; std::unique_ptr<NameHashTable> StringTable; }; } diff --git a/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/PDBFileBuilder.h b/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/PDBFileBuilder.h index 27fc4b53b64..47c755b4326 100644 --- a/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/PDBFileBuilder.h +++ b/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/PDBFileBuilder.h @@ -13,50 +13,45 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/Optional.h" -#include "llvm/DebugInfo/PDB/Raw/PDBFile.h" -#include "llvm/DebugInfo/PDB/Raw/RawConstants.h" -#include "llvm/Support/Allocator.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" +#include "llvm/DebugInfo/PDB/Raw/MsfBuilder.h" +#include "llvm/DebugInfo/PDB/Raw/PDBFile.h" + #include <memory> #include <vector> namespace llvm { -namespace msf { -class MSFBuilder; +namespace codeview { +class StreamInterface; } namespace pdb { class DbiStreamBuilder; class InfoStreamBuilder; -class TpiStreamBuilder; +class PDBFile; class PDBFileBuilder { public: - explicit PDBFileBuilder(BumpPtrAllocator &Allocator); + explicit PDBFileBuilder( + std::unique_ptr<codeview::StreamInterface> FileBuffer); PDBFileBuilder(const PDBFileBuilder &) = delete; PDBFileBuilder &operator=(const PDBFileBuilder &) = delete; - Error initialize(uint32_t BlockSize); + Error initialize(const msf::SuperBlock &Super); - msf::MSFBuilder &getMsfBuilder(); + MsfBuilder &getMsfBuilder(); InfoStreamBuilder &getInfoBuilder(); DbiStreamBuilder &getDbiBuilder(); - TpiStreamBuilder &getTpiBuilder(); - TpiStreamBuilder &getIpiBuilder(); - Error commit(StringRef Filename); + Expected<std::unique_ptr<PDBFile>> build(); private: - Expected<msf::MSFLayout> finalizeMsfLayout() const; - - BumpPtrAllocator &Allocator; - - std::unique_ptr<msf::MSFBuilder> Msf; std::unique_ptr<InfoStreamBuilder> Info; std::unique_ptr<DbiStreamBuilder> Dbi; - std::unique_ptr<TpiStreamBuilder> Tpi; - std::unique_ptr<TpiStreamBuilder> Ipi; + + std::unique_ptr<PDBFile> File; + std::unique_ptr<MsfBuilder> Msf; }; } } diff --git a/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/PublicsStream.h b/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/PublicsStream.h index 577f2986ff2..f5bfb0ed60a 100644 --- a/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/PublicsStream.h +++ b/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/PublicsStream.h @@ -10,10 +10,10 @@ #ifndef LLVM_DEBUGINFO_PDB_RAW_PUBLICSSTREAM_H #define LLVM_DEBUGINFO_PDB_RAW_PUBLICSSTREAM_H +#include "llvm/DebugInfo/CodeView/StreamArray.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.h" -#include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/DebugInfo/MSF/StreamArray.h" #include "llvm/DebugInfo/PDB/PDBTypes.h" +#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" #include "llvm/DebugInfo/PDB/Raw/RawConstants.h" #include "llvm/DebugInfo/PDB/Raw/RawTypes.h" @@ -22,14 +22,14 @@ namespace llvm { namespace pdb { class DbiStream; -struct GSIHashHeader; class PDBFile; class PublicsStream { + struct GSIHashHeader; struct HeaderInfo; public: - PublicsStream(PDBFile &File, std::unique_ptr<msf::MappedBlockStream> Stream); + PublicsStream(PDBFile &File, std::unique_ptr<MappedBlockStream> Stream); ~PublicsStream(); Error reload(); @@ -38,16 +38,16 @@ public: uint32_t getNumBuckets() const { return NumBuckets; } iterator_range<codeview::CVSymbolArray::Iterator> getSymbols(bool *HadError) const; - msf::FixedStreamArray<support::ulittle32_t> getHashBuckets() const { + codeview::FixedStreamArray<support::ulittle32_t> getHashBuckets() const { return HashBuckets; } - msf::FixedStreamArray<support::ulittle32_t> getAddressMap() const { + codeview::FixedStreamArray<support::ulittle32_t> getAddressMap() const { return AddressMap; } - msf::FixedStreamArray<support::ulittle32_t> getThunkMap() const { + codeview::FixedStreamArray<support::ulittle32_t> getThunkMap() const { return ThunkMap; } - msf::FixedStreamArray<SectionOffset> getSectionOffsets() const { + codeview::FixedStreamArray<SectionOffset> getSectionOffsets() const { return SectionOffsets; } @@ -56,14 +56,14 @@ public: private: PDBFile &Pdb; - std::unique_ptr<msf::MappedBlockStream> Stream; + std::unique_ptr<MappedBlockStream> Stream; uint32_t NumBuckets = 0; ArrayRef<uint8_t> Bitmap; - msf::FixedStreamArray<PSHashRecord> HashRecords; - msf::FixedStreamArray<support::ulittle32_t> HashBuckets; - msf::FixedStreamArray<support::ulittle32_t> AddressMap; - msf::FixedStreamArray<support::ulittle32_t> ThunkMap; - msf::FixedStreamArray<SectionOffset> SectionOffsets; + codeview::FixedStreamArray<PSHashRecord> HashRecords; + codeview::FixedStreamArray<support::ulittle32_t> HashBuckets; + codeview::FixedStreamArray<support::ulittle32_t> AddressMap; + codeview::FixedStreamArray<support::ulittle32_t> ThunkMap; + codeview::FixedStreamArray<SectionOffset> SectionOffsets; const HeaderInfo *Header; const GSIHashHeader *HashHdr; diff --git a/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/RawConstants.h b/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/RawConstants.h index af114ff5249..8daaf47882d 100644 --- a/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/RawConstants.h +++ b/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/RawConstants.h @@ -17,8 +17,6 @@ namespace llvm { namespace pdb { -const uint16_t kInvalidStreamIndex = 0xFFFF; - enum PdbRaw_ImplVer : uint32_t { PdbImplVC2 = 19941610, PdbImplVC4 = 19950623, @@ -63,8 +61,6 @@ enum SpecialStream : uint32_t { StreamTPI = 2, StreamDBI = 3, StreamIPI = 4, - - kSpecialStreamCount }; enum class DbgHeaderType : uint16_t { diff --git a/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/RawError.h b/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/RawError.h index f96b8066bbe..b0687cddbf4 100644 --- a/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/RawError.h +++ b/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/RawError.h @@ -19,14 +19,11 @@ namespace pdb { enum class raw_error_code { unspecified = 1, feature_unsupported, - invalid_format, corrupt_file, insufficient_buffer, no_stream, index_out_of_bounds, invalid_block_address, - duplicate_entry, - no_entry, not_writable, invalid_tpi_hash, }; diff --git a/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/RawSession.h b/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/RawSession.h index 5a6c469fcc8..73d281eab1a 100644 --- a/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/RawSession.h +++ b/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/RawSession.h @@ -12,7 +12,6 @@ #include "llvm/ADT/StringRef.h" #include "llvm/DebugInfo/PDB/IPDBSession.h" -#include "llvm/Support/Allocator.h" #include "llvm/Support/Error.h" namespace llvm { @@ -21,8 +20,7 @@ class PDBFile; class RawSession : public IPDBSession { public: - RawSession(std::unique_ptr<PDBFile> PdbFile, - std::unique_ptr<BumpPtrAllocator> Allocator); + explicit RawSession(std::unique_ptr<PDBFile> PdbFile); ~RawSession() override; static Error createFromPdb(StringRef Path, @@ -70,7 +68,6 @@ public: private: std::unique_ptr<PDBFile> Pdb; - std::unique_ptr<BumpPtrAllocator> Allocator; }; } } diff --git a/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/RawTypes.h b/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/RawTypes.h index d404b3994db..afcfe9405c0 100644 --- a/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/RawTypes.h +++ b/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/RawTypes.h @@ -80,228 +80,6 @@ struct TypeIndexOffset { support::ulittle32_t Offset; }; -/// Some of the values are stored in bitfields. Since this needs to be portable -/// across compilers and architectures (big / little endian in particular) we -/// can't use the actual structures below, but must instead do the shifting -/// and masking ourselves. The struct definitions are provided for reference. -struct DbiFlags { - /// uint16_t IncrementalLinking : 1; // True if linked incrementally - /// uint16_t IsStripped : 1; // True if private symbols were - /// stripped. - /// uint16_t HasCTypes : 1; // True if linked with /debug:ctypes. - /// uint16_t Reserved : 13; - static const uint16_t FlagIncrementalMask = 0x0001; - static const uint16_t FlagStrippedMask = 0x0002; - static const uint16_t FlagHasCTypesMask = 0x0004; -}; - -struct DbiBuildNo { - /// uint16_t MinorVersion : 8; - /// uint16_t MajorVersion : 7; - /// uint16_t NewVersionFormat : 1; - static const uint16_t BuildMinorMask = 0x00FF; - static const uint16_t BuildMinorShift = 0; - - static const uint16_t BuildMajorMask = 0x7F00; - static const uint16_t BuildMajorShift = 8; -}; - -/// The fixed size header that appears at the beginning of the DBI Stream. -struct DbiStreamHeader { - support::little32_t VersionSignature; - support::ulittle32_t VersionHeader; - - /// How "old" is this DBI Stream. Should match the age of the PDB InfoStream. - support::ulittle32_t Age; - - /// Global symbol stream # - support::ulittle16_t GlobalSymbolStreamIndex; - - /// See DbiBuildNo structure. - support::ulittle16_t BuildNumber; - - /// Public symbols stream # - support::ulittle16_t PublicSymbolStreamIndex; - - /// version of mspdbNNN.dll - support::ulittle16_t PdbDllVersion; - - /// Symbol records stream # - support::ulittle16_t SymRecordStreamIndex; - - /// rbld number of mspdbNNN.dll - support::ulittle16_t PdbDllRbld; - - /// Size of module info stream - support::little32_t ModiSubstreamSize; - - /// Size of sec. contrib stream - support::little32_t SecContrSubstreamSize; - - /// Size of sec. map substream - support::little32_t SectionMapSize; - - /// Size of file info substream - support::little32_t FileInfoSize; - - /// Size of type server map - support::little32_t TypeServerSize; - - /// Index of MFC Type Server - support::ulittle32_t MFCTypeServerIndex; - - /// Size of DbgHeader info - support::little32_t OptionalDbgHdrSize; - - /// Size of EC stream (what is EC?) - support::little32_t ECSubstreamSize; - - /// See DbiFlags enum. - support::ulittle16_t Flags; - - /// See PDB_MachineType enum. - support::ulittle16_t MachineType; - - /// Pad to 64 bytes - support::ulittle32_t Reserved; -}; -static_assert(sizeof(DbiStreamHeader) == 64, "Invalid DbiStreamHeader size!"); - -struct SectionContribEntry { - support::ulittle16_t Section; - char Padding1[2]; - support::little32_t Offset; - support::little32_t Size; - support::ulittle32_t Characteristics; - support::ulittle16_t ModuleIndex; - char Padding2[2]; - support::ulittle32_t DataCrc; - support::ulittle32_t RelocCrc; -}; - -/// The header preceeding the File Info Substream of the DBI stream. -struct FileInfoSubstreamHeader { - /// Total # of modules, should match number of records in the ModuleInfo - /// substream. - support::ulittle16_t NumModules; - - /// Total # of source files. This value is not accurate because PDB actually - /// supports more than 64k source files, so we ignore it and compute the value - /// from other stream fields. - support::ulittle16_t NumSourceFiles; - - /// Following this header the File Info Substream is laid out as follows: - /// ulittle16_t ModIndices[NumModules]; - /// ulittle16_t ModFileCounts[NumModules]; - /// ulittle32_t FileNameOffsets[NumSourceFiles]; - /// char Names[][NumSourceFiles]; - /// with the caveat that `NumSourceFiles` cannot be trusted, so - /// it is computed by summing the `ModFileCounts` array. -}; - -struct ModInfoFlags { - /// uint16_t fWritten : 1; // True if ModInfo is dirty - /// uint16_t fECEnabled : 1; // Is EC symbolic info present? (What is EC?) - /// uint16_t unused : 6; // Reserved - /// uint16_t iTSM : 8; // Type Server Index for this module - static const uint16_t HasECFlagMask = 0x2; - - static const uint16_t TypeServerIndexMask = 0xFF00; - static const uint16_t TypeServerIndexShift = 8; -}; - -/// The header preceeding each entry in the Module Info substream of the DBI -/// stream. -struct ModuleInfoHeader { - /// Currently opened module. This field is a pointer in the reference - /// implementation, but that won't work on 64-bit systems, and anyway it - /// doesn't make sense to read a pointer from a file. For now it is unused, - /// so just ignore it. - support::ulittle32_t Mod; - - /// First section contribution of this module. - SectionContribEntry SC; - - /// See ModInfoFlags definition. - support::ulittle16_t Flags; - - /// Stream Number of module debug info - support::ulittle16_t ModDiStream; - - /// Size of local symbol debug info in above stream - support::ulittle32_t SymBytes; - - /// Size of line number debug info in above stream - support::ulittle32_t LineBytes; - - /// Size of C13 line number info in above stream - support::ulittle32_t C13Bytes; - - /// Number of files contributing to this module - support::ulittle16_t NumFiles; - - /// Padding so the next field is 4-byte aligned. - char Padding1[2]; - - /// Array of [0..NumFiles) DBI name buffer offsets. This field is a pointer - /// in the reference implementation, but as with `Mod`, we ignore it for now - /// since it is unused. - support::ulittle32_t FileNameOffs; - - /// Name Index for src file name - support::ulittle32_t SrcFileNameNI; - - /// Name Index for path to compiler PDB - support::ulittle32_t PdbFilePathNI; - - /// Following this header are two zero terminated strings. - /// char ModuleName[]; - /// char ObjFileName[]; -}; - -/// Defines a 128-bit unique identifier. This maps to a GUID on Windows, but -/// is abstracted here for the purposes of non-Windows platforms that don't have -/// the GUID structure defined. -struct PDB_UniqueId { - uint8_t Guid[16]; -}; - -// The header preceeding the global TPI stream. -// This corresponds to `HDR` in PDB/dbi/tpi.h. -struct TpiStreamHeader { - struct EmbeddedBuf { - support::little32_t Off; - support::ulittle32_t Length; - }; - - support::ulittle32_t Version; - support::ulittle32_t HeaderSize; - support::ulittle32_t TypeIndexBegin; - support::ulittle32_t TypeIndexEnd; - support::ulittle32_t TypeRecordBytes; - - // The following members correspond to `TpiHash` in PDB/dbi/tpi.h. - support::ulittle16_t HashStreamIndex; - support::ulittle16_t HashAuxStreamIndex; - support::ulittle32_t HashKeySize; - support::ulittle32_t NumHashBuckets; - - EmbeddedBuf HashValueBuffer; - EmbeddedBuf IndexOffsetBuffer; - EmbeddedBuf HashAdjBuffer; -}; - -const uint32_t MinTpiHashBuckets = 0x1000; -const uint32_t MaxTpiHashBuckets = 0x40000; - -/// The header preceeding the global PDB Stream (Stream 1) -struct InfoStreamHeader { - support::ulittle32_t Version; - support::ulittle32_t Signature; - support::ulittle32_t Age; - PDB_UniqueId Guid; -}; - } // namespace pdb } // namespace llvm diff --git a/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/SymbolStream.h b/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/SymbolStream.h index 41d5e6ad64a..685a23411a3 100644 --- a/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/SymbolStream.h +++ b/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/SymbolStream.h @@ -10,20 +10,19 @@ #ifndef LLVM_DEBUGINFO_PDB_RAW_PDBSYMBOLSTREAM_H #define LLVM_DEBUGINFO_PDB_RAW_PDBSYMBOLSTREAM_H +#include "llvm/DebugInfo/CodeView/StreamArray.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" #include "llvm/Support/Error.h" namespace llvm { -namespace msf { -class MappedBlockStream; -} namespace pdb { class PDBFile; class SymbolStream { public: - SymbolStream(std::unique_ptr<msf::MappedBlockStream> Stream); + SymbolStream(std::unique_ptr<MappedBlockStream> Stream); ~SymbolStream(); Error reload(); @@ -34,7 +33,7 @@ public: private: codeview::CVSymbolArray SymbolRecords; - std::unique_ptr<msf::MappedBlockStream> Stream; + std::unique_ptr<MappedBlockStream> Stream; }; } } diff --git a/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/TpiStream.h b/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/TpiStream.h index de21abe4c81..4f36d70aabe 100644 --- a/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/TpiStream.h +++ b/gnu/llvm/include/llvm/DebugInfo/PDB/Raw/TpiStream.h @@ -10,9 +10,11 @@ #ifndef LLVM_DEBUGINFO_PDB_RAW_PDBTPISTREAM_H #define LLVM_DEBUGINFO_PDB_RAW_PDBTPISTREAM_H +#include "llvm/DebugInfo/CodeView/StreamArray.h" +#include "llvm/DebugInfo/CodeView/StreamRef.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/DebugInfo/MSF/StreamArray.h" #include "llvm/DebugInfo/PDB/PDBTypes.h" +#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" #include "llvm/DebugInfo/PDB/Raw/RawConstants.h" #include "llvm/DebugInfo/PDB/Raw/RawTypes.h" #include "llvm/Support/raw_ostream.h" @@ -20,18 +22,14 @@ #include "llvm/Support/Error.h" namespace llvm { -namespace msf { -class MappedBlockStream; -} namespace pdb { class PDBFile; class TpiStream { - friend class TpiStreamBuilder; + struct HeaderInfo; public: - TpiStream(const PDBFile &File, - std::unique_ptr<msf::MappedBlockStream> Stream); + TpiStream(const PDBFile &File, std::unique_ptr<MappedBlockStream> Stream); ~TpiStream(); Error reload(); @@ -45,9 +43,9 @@ public: uint32_t getHashKeySize() const; uint32_t NumHashBuckets() const; - msf::FixedStreamArray<support::ulittle32_t> getHashValues() const; - msf::FixedStreamArray<TypeIndexOffset> getTypeIndexOffsets() const; - msf::FixedStreamArray<TypeIndexOffset> getHashAdjustments() const; + codeview::FixedStreamArray<support::ulittle32_t> getHashValues() const; + codeview::FixedStreamArray<TypeIndexOffset> getTypeIndexOffsets() const; + codeview::FixedStreamArray<TypeIndexOffset> getHashAdjustments() const; iterator_range<codeview::CVTypeArray::Iterator> types(bool *HadError) const; @@ -57,16 +55,16 @@ private: Error verifyHashValues(); const PDBFile &Pdb; - std::unique_ptr<msf::MappedBlockStream> Stream; + std::unique_ptr<MappedBlockStream> Stream; codeview::CVTypeArray TypeRecords; - std::unique_ptr<msf::ReadableStream> HashStream; - msf::FixedStreamArray<support::ulittle32_t> HashValues; - msf::FixedStreamArray<TypeIndexOffset> TypeIndexOffsets; - msf::FixedStreamArray<TypeIndexOffset> HashAdjustments; + std::unique_ptr<MappedBlockStream> HashStream; + codeview::FixedStreamArray<support::ulittle32_t> HashValues; + codeview::FixedStreamArray<TypeIndexOffset> TypeIndexOffsets; + codeview::FixedStreamArray<TypeIndexOffset> HashAdjustments; - const TpiStreamHeader *Header; + const HeaderInfo *Header; }; } } diff --git a/gnu/llvm/include/llvm/Object/ModuleSummaryIndexObjectFile.h b/gnu/llvm/include/llvm/Object/ModuleSummaryIndexObjectFile.h index 6205927039d..d021fb29427 100644 --- a/gnu/llvm/include/llvm/Object/ModuleSummaryIndexObjectFile.h +++ b/gnu/llvm/include/llvm/Object/ModuleSummaryIndexObjectFile.h @@ -50,11 +50,11 @@ public: llvm_unreachable("not implemented"); return 0; } - basic_symbol_iterator symbol_begin() const override { + basic_symbol_iterator symbol_begin_impl() const override { llvm_unreachable("not implemented"); return basic_symbol_iterator(BasicSymbolRef()); } - basic_symbol_iterator symbol_end() const override { + basic_symbol_iterator symbol_end_impl() const override { llvm_unreachable("not implemented"); return basic_symbol_iterator(BasicSymbolRef()); } @@ -79,18 +79,25 @@ public: static ErrorOr<MemoryBufferRef> findBitcodeInMemBuffer(MemoryBufferRef Object); + /// \brief Looks for summary sections in the given memory buffer, + /// returns true if found, else false. + static bool hasGlobalValueSummaryInMemBuffer( + MemoryBufferRef Object, + const DiagnosticHandlerFunction &DiagnosticHandler); + /// \brief Parse module summary index in the given memory buffer. /// Return new ModuleSummaryIndexObjectFile instance containing parsed module /// summary/index. - static Expected<std::unique_ptr<ModuleSummaryIndexObjectFile>> - create(MemoryBufferRef Object); + static ErrorOr<std::unique_ptr<ModuleSummaryIndexObjectFile>> + create(MemoryBufferRef Object, + const DiagnosticHandlerFunction &DiagnosticHandler); }; } /// Parse the module summary index out of an IR file and return the module /// summary index object if found, or nullptr if not. -Expected<std::unique_ptr<ModuleSummaryIndex>> -getModuleSummaryIndexForFile(StringRef Path); +ErrorOr<std::unique_ptr<ModuleSummaryIndex>> getModuleSummaryIndexForFile( + StringRef Path, const DiagnosticHandlerFunction &DiagnosticHandler); } #endif diff --git a/gnu/llvm/include/llvm/Support/ELFRelocs/AMDGPU.def b/gnu/llvm/include/llvm/Support/ELFRelocs/AMDGPU.def index c66f88d14ec..c1e6797fdb0 100644 --- a/gnu/llvm/include/llvm/Support/ELFRelocs/AMDGPU.def +++ b/gnu/llvm/include/llvm/Support/ELFRelocs/AMDGPU.def @@ -2,15 +2,11 @@ #error "ELF_RELOC must be defined" #endif -ELF_RELOC(R_AMDGPU_NONE, 0) -ELF_RELOC(R_AMDGPU_ABS32_LO, 1) -ELF_RELOC(R_AMDGPU_ABS32_HI, 2) -ELF_RELOC(R_AMDGPU_ABS64, 3) -ELF_RELOC(R_AMDGPU_REL32, 4) -ELF_RELOC(R_AMDGPU_REL64, 5) -ELF_RELOC(R_AMDGPU_ABS32, 6) -ELF_RELOC(R_AMDGPU_GOTPCREL, 7) -ELF_RELOC(R_AMDGPU_GOTPCREL32_LO, 8) -ELF_RELOC(R_AMDGPU_GOTPCREL32_HI, 9) -ELF_RELOC(R_AMDGPU_REL32_LO, 10) -ELF_RELOC(R_AMDGPU_REL32_HI, 11) +ELF_RELOC(R_AMDGPU_NONE, 0) +ELF_RELOC(R_AMDGPU_ABS32_LO, 1) +ELF_RELOC(R_AMDGPU_ABS32_HI, 2) +ELF_RELOC(R_AMDGPU_ABS64, 3) +ELF_RELOC(R_AMDGPU_REL32, 4) +ELF_RELOC(R_AMDGPU_REL64, 5) +ELF_RELOC(R_AMDGPU_ABS32, 6) +ELF_RELOC(R_AMDGPU_GOTPCREL, 7) diff --git a/gnu/llvm/include/llvm/Support/ELFRelocs/BPF.def b/gnu/llvm/include/llvm/Support/ELFRelocs/BPF.def index 5dd7f70b696..868974d683c 100644 --- a/gnu/llvm/include/llvm/Support/ELFRelocs/BPF.def +++ b/gnu/llvm/include/llvm/Support/ELFRelocs/BPF.def @@ -4,5 +4,6 @@ // No relocation ELF_RELOC(R_BPF_NONE, 0) -ELF_RELOC(R_BPF_64_64, 1) -ELF_RELOC(R_BPF_64_32, 10) +// Map index in "maps" section to file descriptor +// within ld_64 instruction. +ELF_RELOC(R_BPF_MAP_FD, 1) diff --git a/gnu/llvm/include/llvm/Support/MachO.def b/gnu/llvm/include/llvm/Support/MachO.def index 57522897d0f..9ca6440dd82 100644 --- a/gnu/llvm/include/llvm/Support/MachO.def +++ b/gnu/llvm/include/llvm/Support/MachO.def @@ -15,37 +15,27 @@ HANDLE_LOAD_COMMAND(LC_SEGMENT, 0x00000001u, segment_command) HANDLE_LOAD_COMMAND(LC_SYMTAB, 0x00000002u, symtab_command) -// LC_SYMSEG is obsolete and no longer supported. HANDLE_LOAD_COMMAND(LC_SYMSEG, 0x00000003u, symseg_command) HANDLE_LOAD_COMMAND(LC_THREAD, 0x00000004u, thread_command) HANDLE_LOAD_COMMAND(LC_UNIXTHREAD, 0x00000005u, thread_command) -// LC_LOADFVMLIB is obsolete and no longer supported. HANDLE_LOAD_COMMAND(LC_LOADFVMLIB, 0x00000006u, fvmlib_command) -// LC_IDFVMLIB is obsolete and no longer supported. HANDLE_LOAD_COMMAND(LC_IDFVMLIB, 0x00000007u, fvmlib_command) -// LC_IDENT is obsolete and no longer supported. HANDLE_LOAD_COMMAND(LC_IDENT, 0x00000008u, ident_command) -// LC_FVMFILE is obsolete and no longer supported. HANDLE_LOAD_COMMAND(LC_FVMFILE, 0x00000009u, fvmfile_command) -// LC_PREPAGE is obsolete and no longer supported. HANDLE_LOAD_COMMAND(LC_PREPAGE, 0x0000000Au, load_command) HANDLE_LOAD_COMMAND(LC_DYSYMTAB, 0x0000000Bu, dysymtab_command) HANDLE_LOAD_COMMAND(LC_LOAD_DYLIB, 0x0000000Cu, dylib_command) HANDLE_LOAD_COMMAND(LC_ID_DYLIB, 0x0000000Du, dylib_command) HANDLE_LOAD_COMMAND(LC_LOAD_DYLINKER, 0x0000000Eu, dylinker_command) HANDLE_LOAD_COMMAND(LC_ID_DYLINKER, 0x0000000Fu, dylinker_command) -// LC_PREBOUND_DYLIB is obsolete and no longer supported. HANDLE_LOAD_COMMAND(LC_PREBOUND_DYLIB, 0x00000010u, prebound_dylib_command) HANDLE_LOAD_COMMAND(LC_ROUTINES, 0x00000011u, routines_command) HANDLE_LOAD_COMMAND(LC_SUB_FRAMEWORK, 0x00000012u, sub_framework_command) HANDLE_LOAD_COMMAND(LC_SUB_UMBRELLA, 0x00000013u, sub_umbrella_command) HANDLE_LOAD_COMMAND(LC_SUB_CLIENT, 0x00000014u, sub_client_command) HANDLE_LOAD_COMMAND(LC_SUB_LIBRARY, 0x00000015u, sub_library_command) -// LC_TWOLEVEL_HINTS is obsolete and no longer supported. HANDLE_LOAD_COMMAND(LC_TWOLEVEL_HINTS, 0x00000016u, twolevel_hints_command) -// LC_PREBIND_CKSUM is obsolete and no longer supported. HANDLE_LOAD_COMMAND(LC_PREBIND_CKSUM, 0x00000017u, prebind_cksum_command) -// LC_LOAD_WEAK_DYLIB is obsolete and no longer supported. HANDLE_LOAD_COMMAND(LC_LOAD_WEAK_DYLIB, 0x80000018u, dylib_command) HANDLE_LOAD_COMMAND(LC_SEGMENT_64, 0x00000019u, segment_command_64) HANDLE_LOAD_COMMAND(LC_ROUTINES_64, 0x0000001Au, routines_command_64) diff --git a/gnu/llvm/include/llvm/Transforms/Utils/MemorySSA.h b/gnu/llvm/include/llvm/Transforms/Utils/MemorySSA.h index 408c6a157cd..befc34cb80f 100644 --- a/gnu/llvm/include/llvm/Transforms/Utils/MemorySSA.h +++ b/gnu/llvm/include/llvm/Transforms/Utils/MemorySSA.h @@ -110,11 +110,6 @@ class Instruction; class MemoryAccess; class LLVMContext; class raw_ostream; -enum { - // Used to signify what the default invalid ID is for MemoryAccess's - // getID() - INVALID_MEMORYACCESS_ID = 0 -}; template <class T> class memoryaccess_def_iterator_base; using memoryaccess_def_iterator = memoryaccess_def_iterator_base<MemoryAccess>; @@ -162,8 +157,7 @@ protected: friend class MemoryDef; friend class MemoryPhi; - /// \brief Used for debugging and tracking things about MemoryAccesses. - /// Guaranteed unique among MemoryAccesses, no guarantees otherwise. + /// \brief Used internally to give IDs to MemoryAccesses for printing virtual unsigned getID() const = 0; MemoryAccess(LLVMContext &C, unsigned Vty, BasicBlock *BB, @@ -176,6 +170,25 @@ private: BasicBlock *Block; }; +template <> +struct ilist_traits<MemoryAccess> : public ilist_default_traits<MemoryAccess> { + /// See details of the instruction class for why this trick works + // FIXME: This downcast is UB. See llvm.org/PR26753. + LLVM_NO_SANITIZE("object-size") + MemoryAccess *createSentinel() const { + return static_cast<MemoryAccess *>(&Sentinel); + } + + static void destroySentinel(MemoryAccess *) {} + + MemoryAccess *provideInitialHead() const { return createSentinel(); } + MemoryAccess *ensureHead(MemoryAccess *) const { return createSentinel(); } + static void noteHead(MemoryAccess *, MemoryAccess *) {} + +private: + mutable ilist_half_node<MemoryAccess> Sentinel; +}; + inline raw_ostream &operator<<(raw_ostream &OS, const MemoryAccess &MA) { MA.print(OS); return OS; @@ -241,7 +254,7 @@ public: void *operator new(size_t s) { return User::operator new(s, 1); } MemoryUse(LLVMContext &C, MemoryAccess *DMA, Instruction *MI, BasicBlock *BB) - : MemoryUseOrDef(C, DMA, MemoryUseVal, MI, BB), OptimizedID(0) {} + : MemoryUseOrDef(C, DMA, MemoryUseVal, MI, BB) {} static inline bool classof(const MemoryUse *) { return true; } static inline bool classof(const Value *MA) { @@ -249,18 +262,6 @@ public: } void print(raw_ostream &OS) const override; - void setDefiningAccess(MemoryAccess *DMA, bool Optimized = false) { - if (Optimized) - OptimizedID = DMA->getID(); - MemoryUseOrDef::setDefiningAccess(DMA); - } - bool isOptimized() const { - return getDefiningAccess() && OptimizedID == getDefiningAccess()->getID(); - } - /// \brief Reset the ID of what this MemoryUse was optimized to, causing it to - /// be rewalked by the walker if necessary. - /// This really should only be called by tests. - void resetOptimized() { OptimizedID = INVALID_MEMORYACCESS_ID; } protected: friend class MemorySSA; @@ -268,9 +269,6 @@ protected: unsigned getID() const override { llvm_unreachable("MemoryUses do not have IDs"); } - -private: - unsigned int OptimizedID; }; template <> @@ -309,6 +307,8 @@ public: protected: friend class MemorySSA; + // For debugging only. This gets used to give memory accesses pretty numbers + // when printing them out unsigned getID() const override { return ID; } private: @@ -387,14 +387,6 @@ public: return block_begin() + getNumOperands(); } - iterator_range<block_iterator> blocks() { - return make_range(block_begin(), block_end()); - } - - iterator_range<const_block_iterator> blocks() const { - return make_range(block_begin(), block_end()); - } - op_range incoming_values() { return operands(); } const_op_range incoming_values() const { return operands(); } @@ -473,6 +465,8 @@ protected: User::allocHungoffUses(N, /* IsPhi */ true); } + /// For debugging only. This gets used to give memory accesses pretty numbers + /// when printing them out unsigned getID() const final { return ID; } private: @@ -500,6 +494,7 @@ class MemorySSAWalker; class MemorySSA { public: MemorySSA(Function &, AliasAnalysis *, DominatorTree *); + MemorySSA(MemorySSA &&); ~MemorySSA(); MemorySSAWalker *getWalker(); @@ -508,7 +503,7 @@ public: /// access associated with it. If passed a basic block gets the memory phi /// node that exists for that block, if there is one. Otherwise, this will get /// a MemoryUseOrDef. - MemoryUseOrDef *getMemoryAccess(const Instruction *) const; + MemoryAccess *getMemoryAccess(const Value *) const; MemoryPhi *getMemoryAccess(const BasicBlock *BB) const; void dump() const; @@ -535,12 +530,11 @@ public: /// /// This list is not modifiable by the user. const AccessList *getBlockAccesses(const BasicBlock *BB) const { - return getWritableBlockAccesses(BB); + auto It = PerBlockAccesses.find(BB); + return It == PerBlockAccesses.end() ? nullptr : It->second.get(); } - /// \brief Create an empty MemoryPhi in MemorySSA for a given basic block. - /// Only one MemoryPhi for a block exists at a time, so this function will - /// assert if you try to create one where it already exists. + /// \brief Create an empty MemoryPhi in MemorySSA MemoryPhi *createMemoryPhi(BasicBlock *BB); enum InsertionPlace { Beginning, End }; @@ -556,8 +550,6 @@ public: /// will be placed. The caller is expected to keep ordering the same as /// instructions. /// It will return the new MemoryAccess. - /// Note: If a MemoryAccess already exists for I, this function will make it - /// inaccessible and it *must* have removeMemoryAccess called on it. MemoryAccess *createMemoryAccessInBB(Instruction *I, MemoryAccess *Definition, const BasicBlock *BB, InsertionPlace Point); @@ -569,23 +561,12 @@ public: /// used to replace an existing memory instruction. It will *not* create PHI /// nodes, or verify the clobbering definition. The clobbering definition /// must be non-null. - /// Note: If a MemoryAccess already exists for I, this function will make it - /// inaccessible and it *must* have removeMemoryAccess called on it. - MemoryUseOrDef *createMemoryAccessBefore(Instruction *I, - MemoryAccess *Definition, - MemoryUseOrDef *InsertPt); - MemoryUseOrDef *createMemoryAccessAfter(Instruction *I, - MemoryAccess *Definition, - MemoryAccess *InsertPt); - - // \brief Splice \p What to just before \p Where. - // - // In order to be efficient, the following conditions must be met: - // - \p Where dominates \p What, - // - All memory accesses in [\p Where, \p What) are no-alias with \p What. - // - // TODO: relax the MemoryDef requirement on Where. - void spliceMemoryAccessAbove(MemoryDef *Where, MemoryUseOrDef *What); + MemoryAccess *createMemoryAccessBefore(Instruction *I, + MemoryAccess *Definition, + MemoryAccess *InsertPt); + MemoryAccess *createMemoryAccessAfter(Instruction *I, + MemoryAccess *Definition, + MemoryAccess *InsertPt); /// \brief Remove a MemoryAccess from MemorySSA, including updating all /// definitions and uses. @@ -599,14 +580,6 @@ public: /// whether MemoryAccess \p A dominates MemoryAccess \p B. bool locallyDominates(const MemoryAccess *A, const MemoryAccess *B) const; - /// \brief Given two memory accesses in potentially different blocks, - /// determine whether MemoryAccess \p A dominates MemoryAccess \p B. - bool dominates(const MemoryAccess *A, const MemoryAccess *B) const; - - /// \brief Given a MemoryAccess and a Use, determine whether MemoryAccess \p A - /// dominates Use \p B. - bool dominates(const MemoryAccess *A, const Use &B) const; - /// \brief Verify that MemorySSA is self consistent (IE definitions dominate /// all uses, uses appear in the right places). This is used by unit tests. void verifyMemorySSA() const; @@ -619,20 +592,9 @@ protected: void verifyDomination(Function &F) const; void verifyOrdering(Function &F) const; - // This is used by the use optimizer class - AccessList *getWritableBlockAccesses(const BasicBlock *BB) const { - auto It = PerBlockAccesses.find(BB); - return It == PerBlockAccesses.end() ? nullptr : It->second.get(); - } - private: class CachingWalker; - class OptimizeUses; - - CachingWalker *getWalkerImpl(); void buildMemorySSA(); - void optimizeUses(); - void verifyUseInDefs(MemoryAccess *, MemoryAccess *) const; using AccessMap = DenseMap<const BasicBlock *, std::unique_ptr<AccessList>>; @@ -646,14 +608,10 @@ private: MemoryAccess *findDominatingDef(BasicBlock *, enum InsertionPlace); void removeFromLookups(MemoryAccess *); - void placePHINodes(const SmallPtrSetImpl<BasicBlock *> &, - const DenseMap<const BasicBlock *, unsigned int> &); MemoryAccess *renameBlock(BasicBlock *, MemoryAccess *); void renamePass(DomTreeNode *, MemoryAccess *IncomingVal, SmallPtrSet<BasicBlock *, 16> &Visited); AccessList *getOrCreateAccessList(const BasicBlock *); - void renumberBlock(const BasicBlock *) const; - AliasAnalysis *AA; DominatorTree *DT; Function &F; @@ -663,12 +621,6 @@ private: AccessMap PerBlockAccesses; std::unique_ptr<MemoryAccess> LiveOnEntryDef; - // Domination mappings - // Note that the numbering is local to a block, even though the map is - // global. - mutable SmallPtrSet<const BasicBlock *, 16> BlockNumberingValid; - mutable DenseMap<const MemoryAccess *, unsigned long> BlockNumbering; - // Memory SSA building info std::unique_ptr<CachingWalker> Walker; unsigned NextID; @@ -689,20 +641,12 @@ public: /// class MemorySSAAnalysis : public AnalysisInfoMixin<MemorySSAAnalysis> { friend AnalysisInfoMixin<MemorySSAAnalysis>; - static AnalysisKey Key; + static char PassID; public: - // Wrap MemorySSA result to ensure address stability of internal MemorySSA - // pointers after construction. Use a wrapper class instead of plain - // unique_ptr<MemorySSA> to avoid build breakage on MSVC. - struct Result { - Result(std::unique_ptr<MemorySSA> &&MSSA) : MSSA(std::move(MSSA)) {} - MemorySSA &getMSSA() { return *MSSA.get(); } + typedef MemorySSA Result; - std::unique_ptr<MemorySSA> MSSA; - }; - - Result run(Function &F, FunctionAnalysisManager &AM); + MemorySSA run(Function &F, AnalysisManager<Function> &AM); }; /// \brief Printer pass for \c MemorySSA. @@ -711,12 +655,12 @@ class MemorySSAPrinterPass : public PassInfoMixin<MemorySSAPrinterPass> { public: explicit MemorySSAPrinterPass(raw_ostream &OS) : OS(OS) {} - PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); + PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM); }; /// \brief Verifier pass for \c MemorySSA. struct MemorySSAVerifierPass : PassInfoMixin<MemorySSAVerifierPass> { - PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); + PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM); }; /// \brief Legacy analysis pass which computes \c MemorySSA. @@ -771,7 +715,7 @@ public: /// store %a /// } else { /// 2 = MemoryDef(liveOnEntry) - /// store %b + /// store %b /// } /// 3 = MemoryPhi(2, 1) /// MemoryUse(3) @@ -779,15 +723,7 @@ public: /// /// calling this API on load(%a) will return the MemoryPhi, not the MemoryDef /// in the if (a) branch. - MemoryAccess *getClobberingMemoryAccess(const Instruction *I) { - MemoryAccess *MA = MSSA->getMemoryAccess(I); - assert(MA && "Handed an instruction that MemorySSA doesn't recognize?"); - return getClobberingMemoryAccess(MA); - } - - /// Does the same thing as getClobberingMemoryAccess(const Instruction *I), - /// but takes a MemoryAccess instead of an Instruction. - virtual MemoryAccess *getClobberingMemoryAccess(MemoryAccess *) = 0; + virtual MemoryAccess *getClobberingMemoryAccess(const Instruction *) = 0; /// \brief Given a potentially clobbering memory access and a new location, /// calling this will give you the nearest dominating clobbering MemoryAccess @@ -801,7 +737,7 @@ public: /// will return that MemoryDef, whereas the above would return the clobber /// starting from the use side of the memory def. virtual MemoryAccess *getClobberingMemoryAccess(MemoryAccess *, - const MemoryLocation &) = 0; + MemoryLocation &) = 0; /// \brief Given a memory access, invalidate anything this walker knows about /// that access. @@ -810,8 +746,6 @@ public: /// the walker it uses or returns. virtual void invalidateInfo(MemoryAccess *) {} - virtual void verify(const MemorySSA *MSSA) { assert(MSSA == this->MSSA); } - protected: friend class MemorySSA; // For updating MSSA pointer in MemorySSA move // constructor. @@ -822,12 +756,9 @@ protected: /// simply returns the links as they were constructed by the builder. class DoNothingMemorySSAWalker final : public MemorySSAWalker { public: - // Keep the overrides below from hiding the Instruction overload of - // getClobberingMemoryAccess. - using MemorySSAWalker::getClobberingMemoryAccess; - MemoryAccess *getClobberingMemoryAccess(MemoryAccess *) override; + MemoryAccess *getClobberingMemoryAccess(const Instruction *) override; MemoryAccess *getClobberingMemoryAccess(MemoryAccess *, - const MemoryLocation &) override; + MemoryLocation &) override; }; using MemoryAccessPair = std::pair<MemoryAccess *, MemoryLocation>; @@ -906,21 +837,29 @@ inline const_memoryaccess_def_iterator MemoryAccess::defs_end() const { /// \brief GraphTraits for a MemoryAccess, which walks defs in the normal case, /// and uses in the inverse case. template <> struct GraphTraits<MemoryAccess *> { - using NodeRef = MemoryAccess *; + using NodeType = MemoryAccess; using ChildIteratorType = memoryaccess_def_iterator; - static NodeRef getEntryNode(NodeRef N) { return N; } - static ChildIteratorType child_begin(NodeRef N) { return N->defs_begin(); } - static ChildIteratorType child_end(NodeRef N) { return N->defs_end(); } + static NodeType *getEntryNode(NodeType *N) { return N; } + static inline ChildIteratorType child_begin(NodeType *N) { + return N->defs_begin(); + } + static inline ChildIteratorType child_end(NodeType *N) { + return N->defs_end(); + } }; template <> struct GraphTraits<Inverse<MemoryAccess *>> { - using NodeRef = MemoryAccess *; + using NodeType = MemoryAccess; using ChildIteratorType = MemoryAccess::iterator; - static NodeRef getEntryNode(NodeRef N) { return N; } - static ChildIteratorType child_begin(NodeRef N) { return N->user_begin(); } - static ChildIteratorType child_end(NodeRef N) { return N->user_end(); } + static NodeType *getEntryNode(NodeType *N) { return N; } + static inline ChildIteratorType child_begin(NodeType *N) { + return N->user_begin(); + } + static inline ChildIteratorType child_end(NodeType *N) { + return N->user_end(); + } }; /// \brief Provide an iterator that walks defs, giving both the memory access, @@ -1005,10 +944,6 @@ inline upward_defs_iterator upward_defs_begin(const MemoryAccessPair &Pair) { inline upward_defs_iterator upward_defs_end() { return upward_defs_iterator(); } -// Return true when MD may alias MU, return false otherwise. -bool defClobbersUseOrDef(MemoryDef *MD, const MemoryUseOrDef *MU, - AliasAnalysis &AA); - } // end namespace llvm #endif // LLVM_TRANSFORMS_UTILS_MEMORYSSA_H diff --git a/gnu/llvm/lib/DebugInfo/CodeView/ModuleSubstream.cpp b/gnu/llvm/lib/DebugInfo/CodeView/ModuleSubstream.cpp index 768ebaa1c98..2e31ed6b5b7 100644 --- a/gnu/llvm/lib/DebugInfo/CodeView/ModuleSubstream.cpp +++ b/gnu/llvm/lib/DebugInfo/CodeView/ModuleSubstream.cpp @@ -9,20 +9,17 @@ #include "llvm/DebugInfo/CodeView/ModuleSubstream.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" +#include "llvm/DebugInfo/CodeView/StreamReader.h" using namespace llvm; using namespace llvm::codeview; -using namespace llvm::msf; ModuleSubstream::ModuleSubstream() : Kind(ModuleSubstreamKind::None) {} -ModuleSubstream::ModuleSubstream(ModuleSubstreamKind Kind, - ReadableStreamRef Data) +ModuleSubstream::ModuleSubstream(ModuleSubstreamKind Kind, StreamRef Data) : Kind(Kind), Data(Data) {} -Error ModuleSubstream::initialize(ReadableStreamRef Stream, - ModuleSubstream &Info) { +Error ModuleSubstream::initialize(StreamRef Stream, ModuleSubstream &Info) { const ModuleSubsectionHeader *Header; StreamReader Reader(Stream); if (auto EC = Reader.readObject(Header)) @@ -42,4 +39,4 @@ uint32_t ModuleSubstream::getRecordLength() const { ModuleSubstreamKind ModuleSubstream::getSubstreamKind() const { return Kind; } -ReadableStreamRef ModuleSubstream::getRecordData() const { return Data; } +StreamRef ModuleSubstream::getRecordData() const { return Data; } diff --git a/gnu/llvm/lib/DebugInfo/CodeView/ModuleSubstreamVisitor.cpp b/gnu/llvm/lib/DebugInfo/CodeView/ModuleSubstreamVisitor.cpp index 52479327798..6f237ee67fe 100644 --- a/gnu/llvm/lib/DebugInfo/CodeView/ModuleSubstreamVisitor.cpp +++ b/gnu/llvm/lib/DebugInfo/CodeView/ModuleSubstreamVisitor.cpp @@ -8,54 +8,50 @@ //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/CodeView/ModuleSubstreamVisitor.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" -#include "llvm/DebugInfo/MSF/StreamRef.h" using namespace llvm; using namespace llvm::codeview; -using namespace llvm::msf; -Error IModuleSubstreamVisitor::visitSymbols(ReadableStreamRef Data) { +Error IModuleSubstreamVisitor::visitSymbols(StreamRef Data) { return visitUnknown(ModuleSubstreamKind::Symbols, Data); } -Error IModuleSubstreamVisitor::visitLines(ReadableStreamRef Data, +Error IModuleSubstreamVisitor::visitLines(StreamRef Data, const LineSubstreamHeader *Header, const LineInfoArray &Lines) { return visitUnknown(ModuleSubstreamKind::Lines, Data); } -Error IModuleSubstreamVisitor::visitStringTable(ReadableStreamRef Data) { +Error IModuleSubstreamVisitor::visitStringTable(StreamRef Data) { return visitUnknown(ModuleSubstreamKind::StringTable, Data); } Error IModuleSubstreamVisitor::visitFileChecksums( - ReadableStreamRef Data, const FileChecksumArray &Checksums) { + StreamRef Data, const FileChecksumArray &Checksums) { return visitUnknown(ModuleSubstreamKind::FileChecksums, Data); } -Error IModuleSubstreamVisitor::visitFrameData(ReadableStreamRef Data) { +Error IModuleSubstreamVisitor::visitFrameData(StreamRef Data) { return visitUnknown(ModuleSubstreamKind::FrameData, Data); } -Error IModuleSubstreamVisitor::visitInlineeLines(ReadableStreamRef Data) { +Error IModuleSubstreamVisitor::visitInlineeLines(StreamRef Data) { return visitUnknown(ModuleSubstreamKind::InlineeLines, Data); } -Error IModuleSubstreamVisitor::visitCrossScopeImports(ReadableStreamRef Data) { +Error IModuleSubstreamVisitor::visitCrossScopeImports(StreamRef Data) { return visitUnknown(ModuleSubstreamKind::CrossScopeExports, Data); } -Error IModuleSubstreamVisitor::visitCrossScopeExports(ReadableStreamRef Data) { +Error IModuleSubstreamVisitor::visitCrossScopeExports(StreamRef Data) { return visitUnknown(ModuleSubstreamKind::CrossScopeImports, Data); } -Error IModuleSubstreamVisitor::visitILLines(ReadableStreamRef Data) { +Error IModuleSubstreamVisitor::visitILLines(StreamRef Data) { return visitUnknown(ModuleSubstreamKind::ILLines, Data); } -Error IModuleSubstreamVisitor::visitFuncMDTokenMap(ReadableStreamRef Data) { +Error IModuleSubstreamVisitor::visitFuncMDTokenMap(StreamRef Data) { return visitUnknown(ModuleSubstreamKind::FuncMDTokenMap, Data); } -Error IModuleSubstreamVisitor::visitTypeMDTokenMap(ReadableStreamRef Data) { +Error IModuleSubstreamVisitor::visitTypeMDTokenMap(StreamRef Data) { return visitUnknown(ModuleSubstreamKind::TypeMDTokenMap, Data); } -Error IModuleSubstreamVisitor::visitMergedAssemblyInput( - ReadableStreamRef Data) { +Error IModuleSubstreamVisitor::visitMergedAssemblyInput(StreamRef Data) { return visitUnknown(ModuleSubstreamKind::MergedAssemblyInput, Data); } -Error IModuleSubstreamVisitor::visitCoffSymbolRVA(ReadableStreamRef Data) { +Error IModuleSubstreamVisitor::visitCoffSymbolRVA(StreamRef Data) { return visitUnknown(ModuleSubstreamKind::CoffSymbolRVA, Data); } diff --git a/gnu/llvm/lib/DebugInfo/CodeView/TypeRecord.cpp b/gnu/llvm/lib/DebugInfo/CodeView/TypeRecord.cpp index b951c068ca8..f63371e8c14 100644 --- a/gnu/llvm/lib/DebugInfo/CodeView/TypeRecord.cpp +++ b/gnu/llvm/lib/DebugInfo/CodeView/TypeRecord.cpp @@ -8,15 +8,374 @@ //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/DebugInfo/CodeView/RecordSerialization.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" -#include "llvm/DebugInfo/MSF/ByteStream.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" +#include "llvm/DebugInfo/CodeView/RecordSerialization.h" using namespace llvm; using namespace llvm::codeview; //===----------------------------------------------------------------------===// +// Type record deserialization +//===----------------------------------------------------------------------===// + +ErrorOr<MemberPointerInfo> +MemberPointerInfo::deserialize(ArrayRef<uint8_t> &Data) { + const Layout *L = nullptr; + if (auto EC = consumeObject(Data, L)) + return EC; + + TypeIndex T = L->ClassType; + uint16_t R = L->Representation; + PointerToMemberRepresentation PMR = + static_cast<PointerToMemberRepresentation>(R); + return MemberPointerInfo(T, PMR); +} + +ErrorOr<ModifierRecord> ModifierRecord::deserialize(TypeRecordKind Kind, + ArrayRef<uint8_t> &Data) { + const Layout *L = nullptr; + if (auto EC = consumeObject(Data, L)) + return EC; + + TypeIndex M = L->ModifiedType; + uint16_t O = L->Modifiers; + ModifierOptions MO = static_cast<ModifierOptions>(O); + return ModifierRecord(M, MO); +} + +ErrorOr<ProcedureRecord> ProcedureRecord::deserialize(TypeRecordKind Kind, + ArrayRef<uint8_t> &Data) { + const Layout *L = nullptr; + if (auto EC = consumeObject(Data, L)) + return EC; + return ProcedureRecord(L->ReturnType, L->CallConv, L->Options, + L->NumParameters, L->ArgListType); +} + +ErrorOr<MemberFunctionRecord> +MemberFunctionRecord::deserialize(TypeRecordKind Kind, + ArrayRef<uint8_t> &Data) { + const Layout *L = nullptr; + CV_DESERIALIZE(Data, L); + return MemberFunctionRecord(L->ReturnType, L->ClassType, L->ThisType, + L->CallConv, L->Options, L->NumParameters, + L->ArgListType, L->ThisAdjustment); +} + +ErrorOr<MemberFuncIdRecord> +MemberFuncIdRecord::deserialize(TypeRecordKind Kind, ArrayRef<uint8_t> &Data) { + const Layout *L = nullptr; + StringRef Name; + CV_DESERIALIZE(Data, L, Name); + return MemberFuncIdRecord(L->ClassType, L->FunctionType, Name); +} + +ErrorOr<ArgListRecord> ArgListRecord::deserialize(TypeRecordKind Kind, + ArrayRef<uint8_t> &Data) { + if (Kind != TypeRecordKind::StringList && Kind != TypeRecordKind::ArgList) + return std::make_error_code(std::errc::illegal_byte_sequence); + + const Layout *L = nullptr; + ArrayRef<TypeIndex> Indices; + CV_DESERIALIZE(Data, L, CV_ARRAY_FIELD_N(Indices, L->NumArgs)); + return ArgListRecord(Kind, Indices); +} + +ErrorOr<PointerRecord> PointerRecord::deserialize(TypeRecordKind Kind, + ArrayRef<uint8_t> &Data) { + const Layout *L = nullptr; + if (auto EC = consumeObject(Data, L)) + return EC; + + PointerKind PtrKind = L->getPtrKind(); + PointerMode Mode = L->getPtrMode(); + uint32_t Opts = L->Attrs; + PointerOptions Options = static_cast<PointerOptions>(Opts); + uint8_t Size = L->getPtrSize(); + + if (L->isPointerToMember()) { + auto E = MemberPointerInfo::deserialize(Data); + if (E.getError()) + return std::make_error_code(std::errc::illegal_byte_sequence); + return PointerRecord(L->PointeeType, PtrKind, Mode, Options, Size, *E); + } + + return PointerRecord(L->PointeeType, PtrKind, Mode, Options, Size); +} + +ErrorOr<NestedTypeRecord> +NestedTypeRecord::deserialize(TypeRecordKind Kind, ArrayRef<uint8_t> &Data) { + const Layout *L = nullptr; + StringRef Name; + CV_DESERIALIZE(Data, L, Name); + return NestedTypeRecord(L->Type, Name); +} + +ErrorOr<ArrayRecord> ArrayRecord::deserialize(TypeRecordKind Kind, + ArrayRef<uint8_t> &Data) { + const Layout *L = nullptr; + uint64_t Size; + StringRef Name; + CV_DESERIALIZE(Data, L, CV_NUMERIC_FIELD(Size), Name); + return ArrayRecord(L->ElementType, L->IndexType, Size, Name); +} + +ErrorOr<ClassRecord> ClassRecord::deserialize(TypeRecordKind Kind, + ArrayRef<uint8_t> &Data) { + uint64_t Size = 0; + StringRef Name; + StringRef UniqueName; + uint16_t Props; + const Layout *L = nullptr; + + CV_DESERIALIZE(Data, L, CV_NUMERIC_FIELD(Size), Name, + CV_CONDITIONAL_FIELD(UniqueName, L->hasUniqueName())); + + Props = L->Properties; + uint16_t WrtValue = (Props & WinRTKindMask) >> WinRTKindShift; + WindowsRTClassKind WRT = static_cast<WindowsRTClassKind>(WrtValue); + uint16_t HfaMask = (Props & HfaKindMask) >> HfaKindShift; + HfaKind Hfa = static_cast<HfaKind>(HfaMask); + + ClassOptions Options = static_cast<ClassOptions>(Props); + return ClassRecord(Kind, L->MemberCount, Options, Hfa, WRT, L->FieldList, + L->DerivedFrom, L->VShape, Size, Name, UniqueName); +} + +ErrorOr<UnionRecord> UnionRecord::deserialize(TypeRecordKind Kind, + ArrayRef<uint8_t> &Data) { + uint64_t Size = 0; + StringRef Name; + StringRef UniqueName; + uint16_t Props; + + const Layout *L = nullptr; + CV_DESERIALIZE(Data, L, CV_NUMERIC_FIELD(Size), Name, + CV_CONDITIONAL_FIELD(UniqueName, L->hasUniqueName())); + + Props = L->Properties; + + uint16_t HfaMask = (Props & HfaKindMask) >> HfaKindShift; + HfaKind Hfa = static_cast<HfaKind>(HfaMask); + ClassOptions Options = static_cast<ClassOptions>(Props); + return UnionRecord(L->MemberCount, Options, Hfa, L->FieldList, Size, Name, + UniqueName); +} + +ErrorOr<EnumRecord> EnumRecord::deserialize(TypeRecordKind Kind, + ArrayRef<uint8_t> &Data) { + const Layout *L = nullptr; + StringRef Name; + StringRef UniqueName; + CV_DESERIALIZE(Data, L, Name, + CV_CONDITIONAL_FIELD(UniqueName, L->hasUniqueName())); + + uint16_t P = L->Properties; + ClassOptions Options = static_cast<ClassOptions>(P); + return EnumRecord(L->NumEnumerators, Options, L->FieldListType, Name, + UniqueName, L->UnderlyingType); +} + +ErrorOr<BitFieldRecord> BitFieldRecord::deserialize(TypeRecordKind Kind, + ArrayRef<uint8_t> &Data) { + const Layout *L = nullptr; + CV_DESERIALIZE(Data, L); + return BitFieldRecord(L->Type, L->BitSize, L->BitOffset); +} + +ErrorOr<VFTableShapeRecord> +VFTableShapeRecord::deserialize(TypeRecordKind Kind, ArrayRef<uint8_t> &Data) { + const Layout *L = nullptr; + if (auto EC = consumeObject(Data, L)) + return EC; + + std::vector<VFTableSlotKind> Slots; + uint16_t Count = L->VFEntryCount; + while (Count > 0) { + if (Data.empty()) + return std::make_error_code(std::errc::illegal_byte_sequence); + + // Process up to 2 nibbles at a time (if there are at least 2 remaining) + uint8_t Value = Data[0] & 0x0F; + Slots.push_back(static_cast<VFTableSlotKind>(Value)); + if (--Count > 0) { + Value = (Data[0] & 0xF0) >> 4; + Slots.push_back(static_cast<VFTableSlotKind>(Value)); + --Count; + } + Data = Data.slice(1); + } + + return VFTableShapeRecord(Slots); +} + +ErrorOr<TypeServer2Record> +TypeServer2Record::deserialize(TypeRecordKind Kind, ArrayRef<uint8_t> &Data) { + const Layout *L = nullptr; + StringRef Name; + CV_DESERIALIZE(Data, L, Name); + return TypeServer2Record(StringRef(L->Guid, 16), L->Age, Name); +} + +ErrorOr<StringIdRecord> StringIdRecord::deserialize(TypeRecordKind Kind, + ArrayRef<uint8_t> &Data) { + const Layout *L = nullptr; + StringRef Name; + CV_DESERIALIZE(Data, L, Name); + return StringIdRecord(L->id, Name); +} + +ErrorOr<FuncIdRecord> FuncIdRecord::deserialize(TypeRecordKind Kind, + ArrayRef<uint8_t> &Data) { + const Layout *L = nullptr; + StringRef Name; + CV_DESERIALIZE(Data, L, Name); + return FuncIdRecord(L->ParentScope, L->FunctionType, Name); +} + +ErrorOr<UdtSourceLineRecord> +UdtSourceLineRecord::deserialize(TypeRecordKind Kind, ArrayRef<uint8_t> &Data) { + const Layout *L = nullptr; + CV_DESERIALIZE(Data, L); + return UdtSourceLineRecord(L->UDT, L->SourceFile, L->LineNumber); +} + +ErrorOr<BuildInfoRecord> BuildInfoRecord::deserialize(TypeRecordKind Kind, + ArrayRef<uint8_t> &Data) { + const Layout *L = nullptr; + ArrayRef<TypeIndex> Indices; + CV_DESERIALIZE(Data, L, CV_ARRAY_FIELD_N(Indices, L->NumArgs)); + return BuildInfoRecord(Indices); +} + +ErrorOr<VFTableRecord> VFTableRecord::deserialize(TypeRecordKind Kind, + ArrayRef<uint8_t> &Data) { + const Layout *L = nullptr; + StringRef Name; + std::vector<StringRef> Names; + CV_DESERIALIZE(Data, L, Name, CV_ARRAY_FIELD_TAIL(Names)); + return VFTableRecord(L->CompleteClass, L->OverriddenVFTable, L->VFPtrOffset, + Name, Names); +} + +ErrorOr<OneMethodRecord> OneMethodRecord::deserialize(TypeRecordKind Kind, + ArrayRef<uint8_t> &Data) { + const Layout *L = nullptr; + StringRef Name; + int32_t VFTableOffset = -1; + + CV_DESERIALIZE(Data, L, CV_CONDITIONAL_FIELD(VFTableOffset, + L->Attrs.isIntroducedVirtual()), + Name); + + MethodOptions Options = L->Attrs.getFlags(); + MethodKind MethKind = L->Attrs.getMethodKind(); + MemberAccess Access = L->Attrs.getAccess(); + OneMethodRecord Method(L->Type, MethKind, Options, Access, VFTableOffset, + Name); + // Validate the vftable offset. + if (Method.isIntroducingVirtual() && Method.getVFTableOffset() < 0) + return std::make_error_code(std::errc::illegal_byte_sequence); + return Method; +} + +ErrorOr<MethodOverloadListRecord> +MethodOverloadListRecord::deserialize(TypeRecordKind Kind, + ArrayRef<uint8_t> &Data) { + std::vector<OneMethodRecord> Methods; + while (!Data.empty()) { + const Layout *L = nullptr; + int32_t VFTableOffset = -1; + CV_DESERIALIZE(Data, L, CV_CONDITIONAL_FIELD( + VFTableOffset, L->Attrs.isIntroducedVirtual())); + + MethodOptions Options = L->Attrs.getFlags(); + MethodKind MethKind = L->Attrs.getMethodKind(); + MemberAccess Access = L->Attrs.getAccess(); + + Methods.emplace_back(L->Type, MethKind, Options, Access, VFTableOffset, + StringRef()); + + // Validate the vftable offset. + auto &Method = Methods.back(); + if (Method.isIntroducingVirtual() && Method.getVFTableOffset() < 0) + return std::make_error_code(std::errc::illegal_byte_sequence); + } + return MethodOverloadListRecord(Methods); +} + +ErrorOr<OverloadedMethodRecord> +OverloadedMethodRecord::deserialize(TypeRecordKind Kind, + ArrayRef<uint8_t> &Data) { + const Layout *L = nullptr; + StringRef Name; + CV_DESERIALIZE(Data, L, Name); + return OverloadedMethodRecord(L->MethodCount, L->MethList, Name); +} + +ErrorOr<DataMemberRecord> +DataMemberRecord::deserialize(TypeRecordKind Kind, ArrayRef<uint8_t> &Data) { + const Layout *L = nullptr; + uint64_t Offset; + StringRef Name; + CV_DESERIALIZE(Data, L, CV_NUMERIC_FIELD(Offset), Name); + return DataMemberRecord(L->Attrs.getAccess(), L->Type, Offset, Name); +} + +ErrorOr<StaticDataMemberRecord> +StaticDataMemberRecord::deserialize(TypeRecordKind Kind, + ArrayRef<uint8_t> &Data) { + const Layout *L = nullptr; + StringRef Name; + CV_DESERIALIZE(Data, L, Name); + return StaticDataMemberRecord(L->Attrs.getAccess(), L->Type, Name); +} + +ErrorOr<EnumeratorRecord> +EnumeratorRecord::deserialize(TypeRecordKind Kind, ArrayRef<uint8_t> &Data) { + const Layout *L = nullptr; + APSInt Value; + StringRef Name; + CV_DESERIALIZE(Data, L, Value, Name); + return EnumeratorRecord(L->Attrs.getAccess(), Value, Name); +} + +ErrorOr<VFPtrRecord> VFPtrRecord::deserialize(TypeRecordKind Kind, + ArrayRef<uint8_t> &Data) { + const Layout *L = nullptr; + if (auto EC = consumeObject(Data, L)) + return EC; + return VFPtrRecord(L->Type); +} + +ErrorOr<BaseClassRecord> BaseClassRecord::deserialize(TypeRecordKind Kind, + ArrayRef<uint8_t> &Data) { + const Layout *L = nullptr; + uint64_t Offset; + CV_DESERIALIZE(Data, L, CV_NUMERIC_FIELD(Offset)); + return BaseClassRecord(L->Attrs.getAccess(), L->BaseType, Offset); +} + +ErrorOr<VirtualBaseClassRecord> +VirtualBaseClassRecord::deserialize(TypeRecordKind Kind, + ArrayRef<uint8_t> &Data) { + const Layout *L = nullptr; + uint64_t Offset; + uint64_t Index; + CV_DESERIALIZE(Data, L, CV_NUMERIC_FIELD(Offset), CV_NUMERIC_FIELD(Index)); + return VirtualBaseClassRecord(L->Attrs.getAccess(), L->BaseType, L->VBPtrType, + Offset, Index); +} + +ErrorOr<ListContinuationRecord> +ListContinuationRecord::deserialize(TypeRecordKind Kind, + ArrayRef<uint8_t> &Data) { + const Layout *L = nullptr; + CV_DESERIALIZE(Data, L); + return ListContinuationRecord(L->ContinuationIndex); +} + +//===----------------------------------------------------------------------===// // Type index remapping //===----------------------------------------------------------------------===// @@ -78,7 +437,7 @@ bool PointerRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) { bool Success = true; Success &= remapIndex(IndexMap, ReferentType); if (isPointerToMember()) - Success &= MemberInfo->remapTypeIndices(IndexMap); + Success &= MemberInfo.remapTypeIndices(IndexMap); return Success; } diff --git a/gnu/llvm/lib/DebugInfo/PDB/Raw/DbiStream.cpp b/gnu/llvm/lib/DebugInfo/PDB/Raw/DbiStream.cpp index 4f4a0cf6578..3c0586c728f 100644 --- a/gnu/llvm/lib/DebugInfo/PDB/Raw/DbiStream.cpp +++ b/gnu/llvm/lib/DebugInfo/PDB/Raw/DbiStream.cpp @@ -7,13 +7,13 @@ // //===----------------------------------------------------------------------===// -#include "llvm/ADT/StringRef.h" -#include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/DebugInfo/MSF/StreamArray.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" -#include "llvm/DebugInfo/PDB/PDBTypes.h" #include "llvm/DebugInfo/PDB/Raw/DbiStream.h" + +#include "llvm/DebugInfo/CodeView/StreamArray.h" +#include "llvm/DebugInfo/CodeView/StreamReader.h" +#include "llvm/DebugInfo/CodeView/StreamWriter.h" #include "llvm/DebugInfo/PDB/Raw/ISectionContribVisitor.h" +#include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.h" #include "llvm/DebugInfo/PDB/Raw/InfoStream.h" #include "llvm/DebugInfo/PDB/Raw/ModInfo.h" #include "llvm/DebugInfo/PDB/Raw/NameHashTable.h" @@ -22,17 +22,49 @@ #include "llvm/DebugInfo/PDB/Raw/RawError.h" #include "llvm/DebugInfo/PDB/Raw/RawTypes.h" #include "llvm/Object/COFF.h" -#include "llvm/Support/Error.h" -#include <algorithm> -#include <cstddef> -#include <cstdint> using namespace llvm; using namespace llvm::codeview; -using namespace llvm::msf; using namespace llvm::pdb; using namespace llvm::support; +namespace { +// Some of the values are stored in bitfields. Since this needs to be portable +// across compilers and architectures (big / little endian in particular) we +// can't use the actual structures below, but must instead do the shifting +// and masking ourselves. The struct definitions are provided for reference. + +// struct DbiFlags { +// uint16_t IncrementalLinking : 1; // True if linked incrementally +// uint16_t IsStripped : 1; // True if private symbols were stripped. +// uint16_t HasCTypes : 1; // True if linked with /debug:ctypes. +// uint16_t Reserved : 13; +//}; +const uint16_t FlagIncrementalMask = 0x0001; +const uint16_t FlagStrippedMask = 0x0002; +const uint16_t FlagHasCTypesMask = 0x0004; + +// struct DbiBuildNo { +// uint16_t MinorVersion : 8; +// uint16_t MajorVersion : 7; +// uint16_t NewVersionFormat : 1; +//}; +const uint16_t BuildMinorMask = 0x00FF; +const uint16_t BuildMinorShift = 0; + +const uint16_t BuildMajorMask = 0x7F00; +const uint16_t BuildMajorShift = 8; + +struct FileInfoSubstreamHeader { + ulittle16_t NumModules; // Total # of modules, should match number of + // records in the ModuleInfo substream. + ulittle16_t NumSourceFiles; // Total # of source files. This value is not + // accurate because PDB actually supports more + // than 64k source files, so we ignore it and + // compute the value from other stream fields. +}; +} + template <typename ContribType> static Error loadSectionContribs(FixedStreamArray<ContribType> &Output, StreamReader &Reader) { @@ -49,14 +81,15 @@ static Error loadSectionContribs(FixedStreamArray<ContribType> &Output, DbiStream::DbiStream(PDBFile &File, std::unique_ptr<MappedBlockStream> Stream) : Pdb(File), Stream(std::move(Stream)), Header(nullptr) { + static_assert(sizeof(HeaderInfo) == 64, "Invalid HeaderInfo size!"); } -DbiStream::~DbiStream() = default; +DbiStream::~DbiStream() {} Error DbiStream::reload() { StreamReader Reader(*Stream); - if (Stream->getLength() < sizeof(DbiStreamHeader)) + if (Stream->getLength() < sizeof(HeaderInfo)) return make_error<RawError>(raw_error_code::corrupt_file, "DBI Stream does not contain a header."); if (auto EC = Reader.readObject(Header)) @@ -83,7 +116,7 @@ Error DbiStream::reload() { "DBI Age does not match PDB Age."); if (Stream->getLength() != - sizeof(DbiStreamHeader) + Header->ModiSubstreamSize + + sizeof(HeaderInfo) + Header->ModiSubstreamSize + Header->SecContrSubstreamSize + Header->SectionMapSize + Header->FileInfoSize + Header->TypeServerSize + Header->OptionalDbgHdrSize + Header->ECSubstreamSize) @@ -109,11 +142,14 @@ Error DbiStream::reload() { return make_error<RawError>(raw_error_code::corrupt_file, "DBI type server substream not aligned."); - if (auto EC = - Reader.readStreamRef(ModInfoSubstream, Header->ModiSubstreamSize)) - return EC; - if (auto EC = initializeModInfoArray()) + // Since each ModInfo in the stream is a variable length, we have to iterate + // them to know how many there actually are. + VarStreamArray<ModInfo> ModInfoArray; + if (auto EC = Reader.readArray(ModInfoArray, Header->ModiSubstreamSize)) return EC; + for (auto &Info : ModInfoArray) { + ModuleInfos.emplace_back(Info); + } if (auto EC = Reader.readStreamRef(SecContrSubstream, Header->SecContrSubstreamSize)) @@ -173,27 +209,25 @@ uint16_t DbiStream::getGlobalSymbolStreamIndex() const { uint16_t DbiStream::getFlags() const { return Header->Flags; } bool DbiStream::isIncrementallyLinked() const { - return (Header->Flags & DbiFlags::FlagIncrementalMask) != 0; + return (Header->Flags & FlagIncrementalMask) != 0; } bool DbiStream::hasCTypes() const { - return (Header->Flags & DbiFlags::FlagHasCTypesMask) != 0; + return (Header->Flags & FlagHasCTypesMask) != 0; } bool DbiStream::isStripped() const { - return (Header->Flags & DbiFlags::FlagStrippedMask) != 0; + return (Header->Flags & FlagStrippedMask) != 0; } uint16_t DbiStream::getBuildNumber() const { return Header->BuildNumber; } uint16_t DbiStream::getBuildMajorVersion() const { - return (Header->BuildNumber & DbiBuildNo::BuildMajorMask) >> - DbiBuildNo::BuildMajorShift; + return (Header->BuildNumber & BuildMajorMask) >> BuildMajorShift; } uint16_t DbiStream::getBuildMinorVersion() const { - return (Header->BuildNumber & DbiBuildNo::BuildMinorMask) >> - DbiBuildNo::BuildMinorShift; + return (Header->BuildNumber & BuildMinorMask) >> BuildMinorShift; } uint16_t DbiStream::getPdbDllRbld() const { return Header->PdbDllRbld; } @@ -209,20 +243,21 @@ PDB_Machine DbiStream::getMachineType() const { return static_cast<PDB_Machine>(Machine); } -msf::FixedStreamArray<object::coff_section> DbiStream::getSectionHeaders() { +codeview::FixedStreamArray<object::coff_section> +DbiStream::getSectionHeaders() { return SectionHeaders; } -msf::FixedStreamArray<object::FpoData> DbiStream::getFpoRecords() { +codeview::FixedStreamArray<object::FpoData> DbiStream::getFpoRecords() { return FpoRecords; } ArrayRef<ModuleInfoEx> DbiStream::modules() const { return ModuleInfos; } -msf::FixedStreamArray<SecMapEntry> DbiStream::getSectionMap() const { +codeview::FixedStreamArray<SecMapEntry> DbiStream::getSectionMap() const { return SectionMap; } -void DbiStream::visitSectionContributions( +void llvm::pdb::DbiStream::visitSectionContributions( ISectionContribVisitor &Visitor) const { if (SectionContribVersion == DbiSecContribVer60) { for (auto &SC : SectionContribs) @@ -250,24 +285,6 @@ Error DbiStream::initializeSectionContributionData() { "Unsupported DBI Section Contribution version"); } -Error DbiStream::initializeModInfoArray() { - if (ModInfoSubstream.getLength() == 0) - return Error::success(); - - // Since each ModInfo in the stream is a variable length, we have to iterate - // them to know how many there actually are. - StreamReader Reader(ModInfoSubstream); - - VarStreamArray<ModInfo> ModInfoArray; - if (auto EC = Reader.readArray(ModInfoArray, ModInfoSubstream.getLength())) - return EC; - for (auto &Info : ModInfoArray) { - ModuleInfos.emplace_back(Info); - } - - return Error::success(); -} - // Initializes this->SectionHeaders. Error DbiStream::initializeSectionHeadersData() { if (DbgStreams.size() == 0) @@ -277,21 +294,22 @@ Error DbiStream::initializeSectionHeadersData() { if (StreamNum >= Pdb.getNumStreams()) return make_error<RawError>(raw_error_code::no_stream); - auto SHS = MappedBlockStream::createIndexedStream( - Pdb.getMsfLayout(), Pdb.getMsfBuffer(), StreamNum); + auto SHS = MappedBlockStream::createIndexedStream(StreamNum, Pdb); + if (!SHS) + return SHS.takeError(); - size_t StreamLen = SHS->getLength(); + size_t StreamLen = (*SHS)->getLength(); if (StreamLen % sizeof(object::coff_section)) return make_error<RawError>(raw_error_code::corrupt_file, "Corrupted section header stream."); size_t NumSections = StreamLen / sizeof(object::coff_section); - msf::StreamReader Reader(*SHS); + codeview::StreamReader Reader(**SHS); if (auto EC = Reader.readArray(SectionHeaders, NumSections)) return make_error<RawError>(raw_error_code::corrupt_file, "Could not read a bitmap."); - SectionHeaderStream = std::move(SHS); + SectionHeaderStream = std::move(*SHS); return Error::success(); } @@ -303,26 +321,27 @@ Error DbiStream::initializeFpoRecords() { uint32_t StreamNum = getDebugStreamIndex(DbgHeaderType::NewFPO); // This means there is no FPO data. - if (StreamNum == kInvalidStreamIndex) + if (StreamNum == InvalidStreamIndex) return Error::success(); if (StreamNum >= Pdb.getNumStreams()) return make_error<RawError>(raw_error_code::no_stream); - auto FS = MappedBlockStream::createIndexedStream( - Pdb.getMsfLayout(), Pdb.getMsfBuffer(), StreamNum); + auto FS = MappedBlockStream::createIndexedStream(StreamNum, Pdb); + if (!FS) + return FS.takeError(); - size_t StreamLen = FS->getLength(); + size_t StreamLen = (*FS)->getLength(); if (StreamLen % sizeof(object::FpoData)) return make_error<RawError>(raw_error_code::corrupt_file, "Corrupted New FPO stream."); size_t NumRecords = StreamLen / sizeof(object::FpoData); - msf::StreamReader Reader(*FS); + codeview::StreamReader Reader(**FS); if (auto EC = Reader.readArray(FpoRecords, NumRecords)) return make_error<RawError>(raw_error_code::corrupt_file, "Corrupted New FPO stream."); - FpoStream = std::move(FS); + FpoStream = std::move(*FS); return Error::success(); } @@ -340,6 +359,18 @@ Error DbiStream::initializeSectionMapData() { } Error DbiStream::initializeFileInfo() { + // The layout of the FileInfoSubstream is like this: + // struct { + // ulittle16_t NumModules; + // ulittle16_t NumSourceFiles; + // ulittle16_t ModIndices[NumModules]; + // ulittle16_t ModFileCounts[NumModules]; + // ulittle32_t FileNameOffsets[NumSourceFiles]; + // char Names[][NumSourceFiles]; + // }; + // with the caveat that `NumSourceFiles` cannot be trusted, so + // it is computed by summing `ModFileCounts`. + // if (FileInfoSubstream.getLength() == 0) return Error::success(); @@ -406,10 +437,7 @@ Error DbiStream::initializeFileInfo() { } uint32_t DbiStream::getDebugStreamIndex(DbgHeaderType Type) const { - uint16_t T = static_cast<uint16_t>(Type); - if (T >= DbgStreams.size()) - return kInvalidStreamIndex; - return DbgStreams[T]; + return DbgStreams[static_cast<uint16_t>(Type)]; } Expected<StringRef> DbiStream::getFileNameForIndex(uint32_t Index) const { @@ -424,3 +452,11 @@ Expected<StringRef> DbiStream::getFileNameForIndex(uint32_t Index) const { return std::move(EC); return Name; } + +Error DbiStream::commit() { + StreamWriter Writer(*Stream); + if (auto EC = Writer.writeObject(*Header)) + return EC; + + return Error::success(); +} diff --git a/gnu/llvm/lib/DebugInfo/PDB/Raw/DbiStreamBuilder.cpp b/gnu/llvm/lib/DebugInfo/PDB/Raw/DbiStreamBuilder.cpp index 1d5b8d693b1..34ff8ae3a90 100644 --- a/gnu/llvm/lib/DebugInfo/PDB/Raw/DbiStreamBuilder.cpp +++ b/gnu/llvm/lib/DebugInfo/PDB/Raw/DbiStreamBuilder.cpp @@ -9,28 +9,18 @@ #include "llvm/DebugInfo/PDB/Raw/DbiStreamBuilder.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/DebugInfo/MSF/MSFBuilder.h" -#include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/DebugInfo/MSF/StreamWriter.h" +#include "llvm/DebugInfo/CodeView/StreamWriter.h" #include "llvm/DebugInfo/PDB/Raw/DbiStream.h" +#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" #include "llvm/DebugInfo/PDB/Raw/RawError.h" -#include "llvm/Object/COFF.h" -#include "llvm/Support/COFF.h" using namespace llvm; using namespace llvm::codeview; -using namespace llvm::msf; using namespace llvm::pdb; -namespace { -class ModiSubstreamBuilder {}; -} - -DbiStreamBuilder::DbiStreamBuilder(msf::MSFBuilder &Msf) - : Msf(Msf), Allocator(Msf.getAllocator()), Age(1), BuildNumber(0), - PdbDllVersion(0), PdbDllRbld(0), Flags(0), MachineType(PDB_Machine::x86), - Header(nullptr), DbgStreams((int)DbgHeaderType::Max) {} +DbiStreamBuilder::DbiStreamBuilder() + : Age(1), BuildNumber(0), PdbDllVersion(0), PdbDllRbld(0), Flags(0), + MachineType(PDB_Machine::x86) {} void DbiStreamBuilder::setVersionHeader(PdbRaw_DbiVer V) { VerHeader = V; } @@ -46,207 +36,24 @@ void DbiStreamBuilder::setFlags(uint16_t F) { Flags = F; } void DbiStreamBuilder::setMachineType(PDB_Machine M) { MachineType = M; } -void DbiStreamBuilder::setSectionContribs(ArrayRef<SectionContrib> Arr) { - SectionContribs = Arr; -} - -void DbiStreamBuilder::setSectionMap(ArrayRef<SecMapEntry> SecMap) { - SectionMap = SecMap; -} - -Error DbiStreamBuilder::addDbgStream(pdb::DbgHeaderType Type, - ArrayRef<uint8_t> Data) { - if (DbgStreams[(int)Type].StreamNumber) - return make_error<RawError>(raw_error_code::duplicate_entry, - "The specified stream type already exists"); - auto ExpectedIndex = Msf.addStream(Data.size()); - if (!ExpectedIndex) - return ExpectedIndex.takeError(); - uint32_t Index = std::move(*ExpectedIndex); - DbgStreams[(int)Type].Data = Data; - DbgStreams[(int)Type].StreamNumber = Index; - return Error::success(); -} - uint32_t DbiStreamBuilder::calculateSerializedLength() const { // For now we only support serializing the header. - return sizeof(DbiStreamHeader) + calculateFileInfoSubstreamSize() + - calculateModiSubstreamSize() + calculateSectionContribsStreamSize() + - calculateSectionMapStreamSize() + calculateDbgStreamsSize(); -} - -Error DbiStreamBuilder::addModuleInfo(StringRef ObjFile, StringRef Module) { - auto Entry = llvm::make_unique<ModuleInfo>(); - ModuleInfo *M = Entry.get(); - Entry->Mod = Module; - Entry->Obj = ObjFile; - auto Result = ModuleInfos.insert(std::make_pair(Module, std::move(Entry))); - if (!Result.second) - return make_error<RawError>(raw_error_code::duplicate_entry, - "The specified module already exists"); - ModuleInfoList.push_back(M); - return Error::success(); -} - -Error DbiStreamBuilder::addModuleSourceFile(StringRef Module, StringRef File) { - auto ModIter = ModuleInfos.find(Module); - if (ModIter == ModuleInfos.end()) - return make_error<RawError>(raw_error_code::no_entry, - "The specified module was not found"); - uint32_t Index = SourceFileNames.size(); - SourceFileNames.insert(std::make_pair(File, Index)); - auto &ModEntry = *ModIter; - ModEntry.second->SourceFiles.push_back(File); - return Error::success(); -} - -uint32_t DbiStreamBuilder::calculateModiSubstreamSize() const { - uint32_t Size = 0; - for (const auto &M : ModuleInfoList) { - Size += sizeof(ModuleInfoHeader); - Size += M->Mod.size() + 1; - Size += M->Obj.size() + 1; - } - return alignTo(Size, sizeof(uint32_t)); -} - -uint32_t DbiStreamBuilder::calculateSectionContribsStreamSize() const { - if (SectionContribs.empty()) - return 0; - return sizeof(enum PdbRaw_DbiSecContribVer) + - sizeof(SectionContribs[0]) * SectionContribs.size(); -} - -uint32_t DbiStreamBuilder::calculateSectionMapStreamSize() const { - if (SectionMap.empty()) - return 0; - return sizeof(SecMapHeader) + sizeof(SecMapEntry) * SectionMap.size(); -} - -uint32_t DbiStreamBuilder::calculateFileInfoSubstreamSize() const { - uint32_t Size = 0; - Size += sizeof(ulittle16_t); // NumModules - Size += sizeof(ulittle16_t); // NumSourceFiles - Size += ModuleInfoList.size() * sizeof(ulittle16_t); // ModIndices - Size += ModuleInfoList.size() * sizeof(ulittle16_t); // ModFileCounts - uint32_t NumFileInfos = 0; - for (const auto &M : ModuleInfoList) - NumFileInfos += M->SourceFiles.size(); - Size += NumFileInfos * sizeof(ulittle32_t); // FileNameOffsets - Size += calculateNamesBufferSize(); - return alignTo(Size, sizeof(uint32_t)); -} - -uint32_t DbiStreamBuilder::calculateNamesBufferSize() const { - uint32_t Size = 0; - for (const auto &F : SourceFileNames) { - Size += F.getKeyLength() + 1; // Names[I]; - } - return Size; -} - -uint32_t DbiStreamBuilder::calculateDbgStreamsSize() const { - return DbgStreams.size() * sizeof(uint16_t); -} - -Error DbiStreamBuilder::generateModiSubstream() { - uint32_t Size = calculateModiSubstreamSize(); - auto Data = Allocator.Allocate<uint8_t>(Size); - - ModInfoBuffer = MutableByteStream(MutableArrayRef<uint8_t>(Data, Size)); - - StreamWriter ModiWriter(ModInfoBuffer); - for (const auto &M : ModuleInfoList) { - ModuleInfoHeader Layout = {}; - Layout.ModDiStream = kInvalidStreamIndex; - Layout.NumFiles = M->SourceFiles.size(); - if (auto EC = ModiWriter.writeObject(Layout)) - return EC; - if (auto EC = ModiWriter.writeZeroString(M->Mod)) - return EC; - if (auto EC = ModiWriter.writeZeroString(M->Obj)) - return EC; - } - if (ModiWriter.bytesRemaining() > sizeof(uint32_t)) - return make_error<RawError>(raw_error_code::invalid_format, - "Unexpected bytes in Modi Stream Data"); - return Error::success(); -} - -Error DbiStreamBuilder::generateFileInfoSubstream() { - uint32_t Size = calculateFileInfoSubstreamSize(); - uint32_t NameSize = calculateNamesBufferSize(); - auto Data = Allocator.Allocate<uint8_t>(Size); - uint32_t NamesOffset = Size - NameSize; - - FileInfoBuffer = MutableByteStream(MutableArrayRef<uint8_t>(Data, Size)); - - WritableStreamRef MetadataBuffer = - WritableStreamRef(FileInfoBuffer).keep_front(NamesOffset); - StreamWriter MetadataWriter(MetadataBuffer); - - uint16_t ModiCount = std::min<uint32_t>(UINT16_MAX, ModuleInfos.size()); - uint16_t FileCount = std::min<uint32_t>(UINT16_MAX, SourceFileNames.size()); - if (auto EC = MetadataWriter.writeInteger(ModiCount)) // NumModules - return EC; - if (auto EC = MetadataWriter.writeInteger(FileCount)) // NumSourceFiles - return EC; - for (uint16_t I = 0; I < ModiCount; ++I) { - if (auto EC = MetadataWriter.writeInteger(I)) // Mod Indices - return EC; - } - for (const auto MI : ModuleInfoList) { - FileCount = static_cast<uint16_t>(MI->SourceFiles.size()); - if (auto EC = MetadataWriter.writeInteger(FileCount)) // Mod File Counts - return EC; - } - - // Before writing the FileNameOffsets array, write the NamesBuffer array. - // A side effect of this is that this will actually compute the various - // file name offsets, so we can then go back and write the FileNameOffsets - // array to the other substream. - NamesBuffer = WritableStreamRef(FileInfoBuffer).drop_front(NamesOffset); - StreamWriter NameBufferWriter(NamesBuffer); - for (auto &Name : SourceFileNames) { - Name.second = NameBufferWriter.getOffset(); - if (auto EC = NameBufferWriter.writeZeroString(Name.getKey())) - return EC; - } - - for (const auto MI : ModuleInfoList) { - for (StringRef Name : MI->SourceFiles) { - auto Result = SourceFileNames.find(Name); - if (Result == SourceFileNames.end()) - return make_error<RawError>(raw_error_code::no_entry, - "The source file was not found."); - if (auto EC = MetadataWriter.writeInteger(Result->second)) - return EC; - } - } - - if (NameBufferWriter.bytesRemaining() > 0) - return make_error<RawError>(raw_error_code::invalid_format, - "The names buffer contained unexpected data."); - - if (MetadataWriter.bytesRemaining() > sizeof(uint32_t)) - return make_error<RawError>( - raw_error_code::invalid_format, - "The metadata buffer contained unexpected data."); - - return Error::success(); -} - -Error DbiStreamBuilder::finalize() { - if (Header) - return Error::success(); - - DbiStreamHeader *H = Allocator.Allocate<DbiStreamHeader>(); - - if (auto EC = generateModiSubstream()) - return EC; - if (auto EC = generateFileInfoSubstream()) - return EC; - + return sizeof(DbiStream::HeaderInfo); +} + +Expected<std::unique_ptr<DbiStream>> DbiStreamBuilder::build(PDBFile &File) { + if (!VerHeader.hasValue()) + return make_error<RawError>(raw_error_code::unspecified, + "Missing DBI Stream Version"); + + auto DbiS = MappedBlockStream::createIndexedStream(StreamDBI, File); + if (!DbiS) + return DbiS.takeError(); + auto DS = std::move(*DbiS); + DbiStream::HeaderInfo *H = + static_cast<DbiStream::HeaderInfo *>(DS->getAllocator().Allocate( + sizeof(DbiStream::HeaderInfo), + llvm::AlignOf<DbiStream::HeaderInfo>::Alignment)); H->VersionHeader = *VerHeader; H->VersionSignature = -1; H->Age = Age; @@ -257,156 +64,18 @@ Error DbiStreamBuilder::finalize() { H->MachineType = static_cast<uint16_t>(MachineType); H->ECSubstreamSize = 0; - H->FileInfoSize = FileInfoBuffer.getLength(); - H->ModiSubstreamSize = ModInfoBuffer.getLength(); - H->OptionalDbgHdrSize = DbgStreams.size() * sizeof(uint16_t); - H->SecContrSubstreamSize = calculateSectionContribsStreamSize(); - H->SectionMapSize = calculateSectionMapStreamSize(); + H->FileInfoSize = 0; + H->ModiSubstreamSize = 0; + H->OptionalDbgHdrSize = 0; + H->SecContrSubstreamSize = 0; + H->SectionMapSize = 0; H->TypeServerSize = 0; - H->SymRecordStreamIndex = kInvalidStreamIndex; - H->PublicSymbolStreamIndex = kInvalidStreamIndex; - H->MFCTypeServerIndex = kInvalidStreamIndex; - H->GlobalSymbolStreamIndex = kInvalidStreamIndex; - - Header = H; - return Error::success(); -} - -Error DbiStreamBuilder::finalizeMsfLayout() { - uint32_t Length = calculateSerializedLength(); - if (auto EC = Msf.setStreamSize(StreamDBI, Length)) - return EC; - return Error::success(); -} - -static uint16_t toSecMapFlags(uint32_t Flags) { - uint16_t Ret = 0; - if (Flags & COFF::IMAGE_SCN_MEM_READ) - Ret |= static_cast<uint16_t>(OMFSegDescFlags::Read); - if (Flags & COFF::IMAGE_SCN_MEM_WRITE) - Ret |= static_cast<uint16_t>(OMFSegDescFlags::Write); - if (Flags & COFF::IMAGE_SCN_MEM_EXECUTE) - Ret |= static_cast<uint16_t>(OMFSegDescFlags::Execute); - if (Flags & COFF::IMAGE_SCN_MEM_EXECUTE) - Ret |= static_cast<uint16_t>(OMFSegDescFlags::Execute); - if (!(Flags & COFF::IMAGE_SCN_MEM_16BIT)) - Ret |= static_cast<uint16_t>(OMFSegDescFlags::AddressIs32Bit); - - // This seems always 1. - Ret |= static_cast<uint16_t>(OMFSegDescFlags::IsSelector); - - return Ret; -} - -// A utility function to create Section Contributions -// for a given input sections. -std::vector<SectionContrib> DbiStreamBuilder::createSectionContribs( - ArrayRef<object::coff_section> SecHdrs) { - std::vector<SectionContrib> Ret; - - // Create a SectionContrib for each input section. - for (auto &Sec : SecHdrs) { - Ret.emplace_back(); - auto &Entry = Ret.back(); - memset(&Entry, 0, sizeof(Entry)); - - Entry.Off = Sec.PointerToRawData; - Entry.Size = Sec.SizeOfRawData; - Entry.Characteristics = Sec.Characteristics; - } - return Ret; -} - -// A utility function to create a Section Map for a given list of COFF sections. -// -// A Section Map seem to be a copy of a COFF section list in other format. -// I don't know why a PDB file contains both a COFF section header and -// a Section Map, but it seems it must be present in a PDB. -std::vector<SecMapEntry> DbiStreamBuilder::createSectionMap( - ArrayRef<llvm::object::coff_section> SecHdrs) { - std::vector<SecMapEntry> Ret; - int Idx = 0; - - auto Add = [&]() -> SecMapEntry & { - Ret.emplace_back(); - auto &Entry = Ret.back(); - memset(&Entry, 0, sizeof(Entry)); - - Entry.Frame = Idx + 1; - - // We don't know the meaning of these fields yet. - Entry.SecName = UINT16_MAX; - Entry.ClassName = UINT16_MAX; - - return Entry; - }; - - for (auto &Hdr : SecHdrs) { - auto &Entry = Add(); - Entry.Flags = toSecMapFlags(Hdr.Characteristics); - Entry.SecByteLength = Hdr.VirtualSize; - ++Idx; - } - - // The last entry is for absolute symbols. - auto &Entry = Add(); - Entry.Flags = static_cast<uint16_t>(OMFSegDescFlags::AddressIs32Bit) | - static_cast<uint16_t>(OMFSegDescFlags::IsAbsoluteAddress); - Entry.SecByteLength = UINT32_MAX; - - return Ret; -} - -Error DbiStreamBuilder::commit(const msf::MSFLayout &Layout, - const msf::WritableStream &Buffer) { - if (auto EC = finalize()) - return EC; - - auto InfoS = - WritableMappedBlockStream::createIndexedStream(Layout, Buffer, StreamDBI); - - StreamWriter Writer(*InfoS); - if (auto EC = Writer.writeObject(*Header)) - return EC; - - if (auto EC = Writer.writeStreamRef(ModInfoBuffer)) - return EC; - - if (!SectionContribs.empty()) { - if (auto EC = Writer.writeEnum(DbiSecContribVer60)) - return EC; - if (auto EC = Writer.writeArray(SectionContribs)) - return EC; - } - - if (!SectionMap.empty()) { - ulittle16_t Size = static_cast<ulittle16_t>(SectionMap.size()); - SecMapHeader SMHeader = {Size, Size}; - if (auto EC = Writer.writeObject(SMHeader)) - return EC; - if (auto EC = Writer.writeArray(SectionMap)) - return EC; - } - - if (auto EC = Writer.writeStreamRef(FileInfoBuffer)) - return EC; - - for (auto &Stream : DbgStreams) - if (auto EC = Writer.writeInteger(Stream.StreamNumber)) - return EC; - - for (auto &Stream : DbgStreams) { - if (Stream.StreamNumber == kInvalidStreamIndex) - continue; - auto WritableStream = WritableMappedBlockStream::createIndexedStream( - Layout, Buffer, Stream.StreamNumber); - StreamWriter DbgStreamWriter(*WritableStream); - if (auto EC = DbgStreamWriter.writeArray(Stream.Data)) - return EC; - } - - if (Writer.bytesRemaining() > 0) - return make_error<RawError>(raw_error_code::invalid_format, - "Unexpected bytes found in DBI Stream"); - return Error::success(); + H->SymRecordStreamIndex = DbiStream::InvalidStreamIndex; + H->PublicSymbolStreamIndex = DbiStream::InvalidStreamIndex; + H->MFCTypeServerIndex = DbiStream::InvalidStreamIndex; + H->GlobalSymbolStreamIndex = DbiStream::InvalidStreamIndex; + + auto Dbi = llvm::make_unique<DbiStream>(File, std::move(DS)); + Dbi->Header = H; + return std::move(Dbi); } diff --git a/gnu/llvm/lib/DebugInfo/PDB/Raw/Hash.cpp b/gnu/llvm/lib/DebugInfo/PDB/Raw/Hash.cpp index b9f685ec69d..23cb55786d7 100644 --- a/gnu/llvm/lib/DebugInfo/PDB/Raw/Hash.cpp +++ b/gnu/llvm/lib/DebugInfo/PDB/Raw/Hash.cpp @@ -11,7 +11,6 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/Support/Endian.h" -#include "llvm/Support/JamCRC.h" using namespace llvm; using namespace llvm::support; @@ -74,13 +73,59 @@ uint32_t pdb::hashStringV2(StringRef Str) { Hash ^= (Hash >> 6); } - return Hash * 1664525U + 1013904223U; + return Hash * 1664525L + 1013904223L; } +static const uint32_t V8HashTable[] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, + 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, + 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, + 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, + 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, + 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, + 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, + 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, + 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106, + 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, + 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, + 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, + 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, + 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, + 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, + 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, + 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, + 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, + 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, + 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, + 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, + 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, + 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, + 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, + 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, + 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, + 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, + 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, + 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, + 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, + 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, + 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, + 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, +}; + // Corresponds to `SigForPbCb` in langapi/shared/crc32.h. uint32_t pdb::hashBufferV8(ArrayRef<uint8_t> Buf) { - JamCRC JC(/*Init=*/0U); - JC.update(makeArrayRef<char>(reinterpret_cast<const char *>(Buf.data()), - Buf.size())); - return JC.getCRC(); + uint32_t Hash = 0; + for (uint8_t Byte : Buf) + Hash = (Hash >> 8) ^ V8HashTable[(Hash & 0xff) ^ Byte]; + return Hash; } diff --git a/gnu/llvm/lib/DebugInfo/PDB/Raw/InfoStream.cpp b/gnu/llvm/lib/DebugInfo/PDB/Raw/InfoStream.cpp index f19535d1180..c33a764587c 100644 --- a/gnu/llvm/lib/DebugInfo/PDB/Raw/InfoStream.cpp +++ b/gnu/llvm/lib/DebugInfo/PDB/Raw/InfoStream.cpp @@ -10,25 +10,24 @@ #include "llvm/DebugInfo/PDB/Raw/InfoStream.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" -#include "llvm/DebugInfo/MSF/StreamWriter.h" +#include "llvm/DebugInfo/CodeView/StreamReader.h" +#include "llvm/DebugInfo/CodeView/StreamWriter.h" +#include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.h" #include "llvm/DebugInfo/PDB/Raw/PDBFile.h" #include "llvm/DebugInfo/PDB/Raw/RawConstants.h" #include "llvm/DebugInfo/PDB/Raw/RawError.h" -#include "llvm/DebugInfo/PDB/Raw/RawTypes.h" using namespace llvm; using namespace llvm::codeview; -using namespace llvm::msf; using namespace llvm::pdb; InfoStream::InfoStream(std::unique_ptr<MappedBlockStream> Stream) : Stream(std::move(Stream)) {} Error InfoStream::reload() { - StreamReader Reader(*Stream); + codeview::StreamReader Reader(*Stream); - const InfoStreamHeader *H; + const HeaderInfo *H; if (auto EC = Reader.readObject(H)) return joinErrors( std::move(EC), @@ -75,3 +74,17 @@ uint32_t InfoStream::getSignature() const { return Signature; } uint32_t InfoStream::getAge() const { return Age; } PDB_UniqueId InfoStream::getGuid() const { return Guid; } + +Error InfoStream::commit() { + StreamWriter Writer(*Stream); + + HeaderInfo H; + H.Age = Age; + H.Signature = Signature; + H.Version = Version; + H.Guid = Guid; + if (auto EC = Writer.writeObject(H)) + return EC; + + return NamedStreams.commit(Writer); +} diff --git a/gnu/llvm/lib/DebugInfo/PDB/Raw/InfoStreamBuilder.cpp b/gnu/llvm/lib/DebugInfo/PDB/Raw/InfoStreamBuilder.cpp index 73fbf853b4f..7be9cc32db9 100644 --- a/gnu/llvm/lib/DebugInfo/PDB/Raw/InfoStreamBuilder.cpp +++ b/gnu/llvm/lib/DebugInfo/PDB/Raw/InfoStreamBuilder.cpp @@ -9,20 +9,16 @@ #include "llvm/DebugInfo/PDB/Raw/InfoStreamBuilder.h" -#include "llvm/DebugInfo/MSF/MSFBuilder.h" -#include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/DebugInfo/MSF/StreamWriter.h" +#include "llvm/DebugInfo/CodeView/StreamWriter.h" #include "llvm/DebugInfo/PDB/Raw/InfoStream.h" +#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" #include "llvm/DebugInfo/PDB/Raw/RawError.h" -#include "llvm/DebugInfo/PDB/Raw/RawTypes.h" using namespace llvm; using namespace llvm::codeview; -using namespace llvm::msf; using namespace llvm::pdb; -InfoStreamBuilder::InfoStreamBuilder(msf::MSFBuilder &Msf) - : Msf(Msf), Ver(PdbRaw_ImplVer::PdbImplVC70), Sig(-1), Age(0) {} +InfoStreamBuilder::InfoStreamBuilder() {} void InfoStreamBuilder::setVersion(PdbRaw_ImplVer V) { Ver = V; } @@ -37,29 +33,35 @@ NameMapBuilder &InfoStreamBuilder::getNamedStreamsBuilder() { } uint32_t InfoStreamBuilder::calculateSerializedLength() const { - return sizeof(InfoStreamHeader) + NamedStreams.calculateSerializedLength(); + return sizeof(InfoStream::HeaderInfo) + + NamedStreams.calculateSerializedLength(); } -Error InfoStreamBuilder::finalizeMsfLayout() { - uint32_t Length = calculateSerializedLength(); - if (auto EC = Msf.setStreamSize(StreamPDB, Length)) - return EC; - return Error::success(); -} - -Error InfoStreamBuilder::commit(const msf::MSFLayout &Layout, - const msf::WritableStream &Buffer) const { - auto InfoS = - WritableMappedBlockStream::createIndexedStream(Layout, Buffer, StreamPDB); - StreamWriter Writer(*InfoS); - - InfoStreamHeader H; - H.Age = Age; - H.Signature = Sig; - H.Version = Ver; - H.Guid = Guid; - if (auto EC = Writer.writeObject(H)) - return EC; +Expected<std::unique_ptr<InfoStream>> InfoStreamBuilder::build(PDBFile &File) { + if (!Ver.hasValue()) + return make_error<RawError>(raw_error_code::unspecified, + "Missing PDB Stream Version"); + if (!Sig.hasValue()) + return make_error<RawError>(raw_error_code::unspecified, + "Missing PDB Stream Signature"); + if (!Age.hasValue()) + return make_error<RawError>(raw_error_code::unspecified, + "Missing PDB Stream Age"); + if (!Guid.hasValue()) + return make_error<RawError>(raw_error_code::unspecified, + "Missing PDB Stream Guid"); - return NamedStreams.commit(Writer); + auto InfoS = MappedBlockStream::createIndexedStream(StreamPDB, File); + if (!InfoS) + return InfoS.takeError(); + auto Info = llvm::make_unique<InfoStream>(std::move(*InfoS)); + Info->Version = *Ver; + Info->Signature = *Sig; + Info->Age = *Age; + Info->Guid = *Guid; + auto NS = NamedStreams.build(); + if (!NS) + return NS.takeError(); + Info->NamedStreams = **NS; + return std::move(Info); } diff --git a/gnu/llvm/lib/DebugInfo/PDB/Raw/ModInfo.cpp b/gnu/llvm/lib/DebugInfo/PDB/Raw/ModInfo.cpp index b34d7700d03..bae135f77bc 100644 --- a/gnu/llvm/lib/DebugInfo/PDB/Raw/ModInfo.cpp +++ b/gnu/llvm/lib/DebugInfo/PDB/Raw/ModInfo.cpp @@ -7,27 +7,76 @@ // //===----------------------------------------------------------------------===// -#include "llvm/DebugInfo/MSF/StreamReader.h" #include "llvm/DebugInfo/PDB/Raw/ModInfo.h" -#include "llvm/DebugInfo/PDB/Raw/RawTypes.h" + +#include "llvm/DebugInfo/CodeView/StreamReader.h" +#include "llvm/DebugInfo/PDB/Raw/PDBFile.h" #include "llvm/Support/Endian.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/MathExtras.h" -#include <cstdint> using namespace llvm; -using namespace llvm::msf; using namespace llvm::pdb; using namespace llvm::support; -ModInfo::ModInfo() = default; - -ModInfo::ModInfo(const ModInfo &Info) = default; - -ModInfo::~ModInfo() = default; +namespace { + +struct SCBytes { + ulittle16_t Section; + char Padding1[2]; + little32_t Offset; + little32_t Size; + ulittle32_t Characteristics; + ulittle16_t ModuleIndex; + char Padding2[2]; + ulittle32_t DataCrc; + ulittle32_t RelocCrc; +}; + +// struct Flags { +// uint16_t fWritten : 1; // True if ModInfo is dirty +// uint16_t fECEnabled : 1; // Is EC symbolic info present? (What is EC?) +// uint16_t unused : 6; // Reserved +// uint16_t iTSM : 8; // Type Server Index for this module +//}; +const uint16_t HasECFlagMask = 0x2; + +const uint16_t TypeServerIndexMask = 0xFF00; +const uint16_t TypeServerIndexShift = 8; +} -Error ModInfo::initialize(ReadableStreamRef Stream, ModInfo &Info) { - StreamReader Reader(Stream); +struct ModInfo::FileLayout { + ulittle32_t Mod; // Currently opened module. This field is a + // pointer in the reference implementation, but + // that won't work on 64-bit systems, and anyway + // it doesn't make sense to read a pointer from a + // file. For now it is unused, so just ignore it. + SCBytes SC; // First section contribution of this module. + ulittle16_t Flags; // See Flags definition. + ulittle16_t ModDiStream; // Stream Number of module debug info + ulittle32_t SymBytes; // Size of local symbol debug info in above stream + ulittle32_t LineBytes; // Size of line number debug info in above stream + ulittle32_t C13Bytes; // Size of C13 line number info in above stream + ulittle16_t NumFiles; // Number of files contributing to this module + char Padding1[2]; // Padding so the next field is 4-byte aligned. + ulittle32_t FileNameOffs; // array of [0..NumFiles) DBI name buffer offsets. + // This field is a pointer in the reference + // implementation, but as with `Mod`, we ignore it + // for now since it is unused. + ulittle32_t SrcFileNameNI; // Name Index for src file name + ulittle32_t PdbFilePathNI; // Name Index for path to compiler PDB + // Null terminated Module name + // Null terminated Obj File Name +}; + +ModInfo::ModInfo() : Layout(nullptr) {} + +ModInfo::ModInfo(const ModInfo &Info) + : ModuleName(Info.ModuleName), ObjFileName(Info.ObjFileName), + Layout(Info.Layout) {} + +ModInfo::~ModInfo() {} + +Error ModInfo::initialize(codeview::StreamRef Stream, ModInfo &Info) { + codeview::StreamReader Reader(Stream); if (auto EC = Reader.readObject(Info.Layout)) return EC; @@ -39,13 +88,10 @@ Error ModInfo::initialize(ReadableStreamRef Stream, ModInfo &Info) { return Error::success(); } -bool ModInfo::hasECInfo() const { - return (Layout->Flags & ModInfoFlags::HasECFlagMask) != 0; -} +bool ModInfo::hasECInfo() const { return (Layout->Flags & HasECFlagMask) != 0; } uint16_t ModInfo::getTypeServerIndex() const { - return (Layout->Flags & ModInfoFlags::TypeServerIndexMask) >> - ModInfoFlags::TypeServerIndexShift; + return (Layout->Flags & TypeServerIndexMask) >> TypeServerIndexShift; } uint16_t ModInfo::getModuleStreamIndex() const { return Layout->ModDiStream; } @@ -75,7 +121,7 @@ StringRef ModInfo::getObjFileName() const { return ObjFileName; } uint32_t ModInfo::getRecordLength() const { uint32_t M = ModuleName.str().size() + 1; uint32_t O = ObjFileName.str().size() + 1; - uint32_t Size = sizeof(ModuleInfoHeader) + M + O; - Size = alignTo(Size, 4); + uint32_t Size = sizeof(FileLayout) + M + O; + Size = llvm::alignTo(Size, 4); return Size; } diff --git a/gnu/llvm/lib/DebugInfo/PDB/Raw/ModStream.cpp b/gnu/llvm/lib/DebugInfo/PDB/Raw/ModStream.cpp index 0ffc5b7d44a..3415fcd4779 100644 --- a/gnu/llvm/lib/DebugInfo/PDB/Raw/ModStream.cpp +++ b/gnu/llvm/lib/DebugInfo/PDB/Raw/ModStream.cpp @@ -7,43 +7,39 @@ // //===----------------------------------------------------------------------===// -#include "llvm/ADT/iterator_range.h" -#include "llvm/DebugInfo/CodeView/SymbolRecord.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" -#include "llvm/DebugInfo/MSF/StreamRef.h" -#include "llvm/DebugInfo/PDB/Raw/ModInfo.h" #include "llvm/DebugInfo/PDB/Raw/ModStream.h" + +#include "llvm/DebugInfo/CodeView/StreamReader.h" +#include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.h" +#include "llvm/DebugInfo/PDB/Raw/ModInfo.h" #include "llvm/DebugInfo/PDB/Raw/PDBFile.h" #include "llvm/DebugInfo/PDB/Raw/RawError.h" #include "llvm/DebugInfo/PDB/Raw/RawTypes.h" -#include "llvm/Support/Error.h" -#include <algorithm> -#include <cstdint> using namespace llvm; -using namespace llvm::msf; using namespace llvm::pdb; ModStream::ModStream(const ModInfo &Module, std::unique_ptr<MappedBlockStream> Stream) : Mod(Module), Stream(std::move(Stream)) {} -ModStream::~ModStream() = default; +ModStream::~ModStream() {} Error ModStream::reload() { - StreamReader Reader(*Stream); + codeview::StreamReader Reader(*Stream); uint32_t SymbolSize = Mod.getSymbolDebugInfoByteSize(); uint32_t C11Size = Mod.getLineInfoByteSize(); uint32_t C13Size = Mod.getC13LineInfoByteSize(); if (C11Size > 0 && C13Size > 0) - return make_error<RawError>(raw_error_code::corrupt_file, - "Module has both C11 and C13 line info"); + return llvm::make_error<RawError>(raw_error_code::corrupt_file, + "Module has both C11 and C13 line info"); - ReadableStreamRef S; + codeview::StreamRef S; - if (auto EC = Reader.readInteger(Signature)) + uint32_t SymbolSubstreamSig = 0; + if (auto EC = Reader.readInteger(SymbolSubstreamSig)) return EC; if (auto EC = Reader.readArray(SymbolsSubstream, SymbolSize - 4)) return EC; @@ -53,7 +49,7 @@ Error ModStream::reload() { if (auto EC = Reader.readStreamRef(C13LinesSubstream, C13Size)) return EC; - StreamReader LineReader(C13LinesSubstream); + codeview::StreamReader LineReader(C13LinesSubstream); if (auto EC = LineReader.readArray(LineInfo, LineReader.bytesRemaining())) return EC; @@ -63,8 +59,8 @@ Error ModStream::reload() { if (auto EC = Reader.readStreamRef(GlobalRefsSubstream, GlobalRefsSize)) return EC; if (Reader.bytesRemaining() > 0) - return make_error<RawError>(raw_error_code::corrupt_file, - "Unexpected bytes in module stream."); + return llvm::make_error<RawError>(raw_error_code::corrupt_file, + "Unexpected bytes in module stream."); return Error::success(); } @@ -73,13 +69,14 @@ iterator_range<codeview::CVSymbolArray::Iterator> ModStream::symbols(bool *HadError) const { // It's OK if the stream is empty. if (SymbolsSubstream.getUnderlyingStream().getLength() == 0) - return make_range(SymbolsSubstream.end(), SymbolsSubstream.end()); - return make_range(SymbolsSubstream.begin(HadError), SymbolsSubstream.end()); + return llvm::make_range(SymbolsSubstream.end(), SymbolsSubstream.end()); + return llvm::make_range(SymbolsSubstream.begin(HadError), + SymbolsSubstream.end()); } iterator_range<codeview::ModuleSubstreamArray::Iterator> ModStream::lines(bool *HadError) const { - return make_range(LineInfo.begin(HadError), LineInfo.end()); + return llvm::make_range(LineInfo.begin(HadError), LineInfo.end()); } Error ModStream::commit() { return Error::success(); } diff --git a/gnu/llvm/lib/DebugInfo/PDB/Raw/NameHashTable.cpp b/gnu/llvm/lib/DebugInfo/PDB/Raw/NameHashTable.cpp index 84cccb354bd..ae4ebf27721 100644 --- a/gnu/llvm/lib/DebugInfo/PDB/Raw/NameHashTable.cpp +++ b/gnu/llvm/lib/DebugInfo/PDB/Raw/NameHashTable.cpp @@ -10,19 +10,18 @@ #include "llvm/DebugInfo/PDB/Raw/NameHashTable.h" #include "llvm/ADT/ArrayRef.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" +#include "llvm/DebugInfo/CodeView/StreamReader.h" #include "llvm/DebugInfo/PDB/Raw/Hash.h" #include "llvm/DebugInfo/PDB/Raw/RawError.h" #include "llvm/Support/Endian.h" using namespace llvm; -using namespace llvm::msf; using namespace llvm::support; using namespace llvm::pdb; NameHashTable::NameHashTable() : Signature(0), HashVersion(0), NameCount(0) {} -Error NameHashTable::load(StreamReader &Stream) { +Error NameHashTable::load(codeview::StreamReader &Stream) { struct Header { support::ulittle32_t Signature; support::ulittle32_t HashVersion; @@ -73,7 +72,7 @@ StringRef NameHashTable::getStringForID(uint32_t ID) const { // the starting offset of the string we're looking for. So just seek into // the desired offset and a read a null terminated stream from that offset. StringRef Result; - StreamReader NameReader(NamesBuffer); + codeview::StreamReader NameReader(NamesBuffer); NameReader.setOffset(ID); if (auto EC = NameReader.readZeroString(Result)) consumeError(std::move(EC)); @@ -99,6 +98,7 @@ uint32_t NameHashTable::getIDForString(StringRef Str) const { return IDs[0]; } -FixedStreamArray<support::ulittle32_t> NameHashTable::name_ids() const { +codeview::FixedStreamArray<support::ulittle32_t> +NameHashTable::name_ids() const { return IDs; } diff --git a/gnu/llvm/lib/DebugInfo/PDB/Raw/NameMap.cpp b/gnu/llvm/lib/DebugInfo/PDB/Raw/NameMap.cpp index 0f55f58da38..b8a4eb79a48 100644 --- a/gnu/llvm/lib/DebugInfo/PDB/Raw/NameMap.cpp +++ b/gnu/llvm/lib/DebugInfo/PDB/Raw/NameMap.cpp @@ -7,24 +7,20 @@ // //===----------------------------------------------------------------------===// -#include "llvm/ADT/SparseBitVector.h" -#include "llvm/ADT/StringMap.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/iterator_range.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" #include "llvm/DebugInfo/PDB/Raw/NameMap.h" +#include "llvm/ADT/SparseBitVector.h" +#include "llvm/DebugInfo/CodeView/StreamReader.h" +#include "llvm/DebugInfo/CodeView/StreamWriter.h" #include "llvm/DebugInfo/PDB/Raw/RawError.h" -#include "llvm/Support/Error.h" -#include <algorithm> -#include <cstdint> using namespace llvm; -using namespace llvm::msf; +using namespace llvm::codeview; using namespace llvm::pdb; -NameMap::NameMap() = default; +NameMap::NameMap() {} + +Error NameMap::load(codeview::StreamReader &Stream) { -Error NameMap::load(StreamReader &Stream) { // This is some sort of weird string-set/hash table encoded in the stream. // It starts with the number of bytes in the table. uint32_t NumberOfBytes; @@ -149,9 +145,63 @@ Error NameMap::load(StreamReader &Stream) { return Error::success(); } +Error NameMap::commit(codeview::StreamWriter &Writer) { + // The first field is the number of bytes of string data. So add + // up the length of all strings plus a null terminator for each + // one. + uint32_t NumBytes = 0; + for (auto B = Mapping.begin(), E = Mapping.end(); B != E; ++B) { + NumBytes += B->getKeyLength() + 1; + } + + if (auto EC = Writer.writeInteger(NumBytes)) // Number of bytes of string data + return EC; + // Now all of the string data itself. + for (auto B = Mapping.begin(), E = Mapping.end(); B != E; ++B) { + if (auto EC = Writer.writeZeroString(B->getKey())) + return EC; + } + + if (auto EC = Writer.writeInteger(Mapping.size())) // Hash Size + return EC; + + if (auto EC = Writer.writeInteger(Mapping.size())) // Max Number of Strings + return EC; + + if (auto EC = Writer.writeInteger(Mapping.size())) // Num Present Words + return EC; + + // For each entry in the mapping, write a bit mask which represents a bucket + // to store it in. We don't use this, so the value we write isn't important + // to us, it just has to be there. + for (auto B = Mapping.begin(), E = Mapping.end(); B != E; ++B) { + if (auto EC = Writer.writeInteger(1U)) + return EC; + } + + if (auto EC = Writer.writeInteger(0U)) // Num Deleted Words + return EC; + + // Mappings of each word. + uint32_t OffsetSoFar = 0; + for (auto B = Mapping.begin(), E = Mapping.end(); B != E; ++B) { + // This is a list of key value pairs where the key is the offset into the + // strings buffer, and the value is a stream number. Write each pair. + if (auto EC = Writer.writeInteger(OffsetSoFar)) + return EC; + + if (auto EC = Writer.writeInteger(B->second)) + return EC; + + OffsetSoFar += B->getKeyLength() + 1; + } + + return Error::success(); +} + iterator_range<StringMapConstIterator<uint32_t>> NameMap::entries() const { - return make_range<StringMapConstIterator<uint32_t>>(Mapping.begin(), - Mapping.end()); + return llvm::make_range<StringMapConstIterator<uint32_t>>(Mapping.begin(), + Mapping.end()); } bool NameMap::tryGetValue(StringRef Name, uint32_t &Value) const { diff --git a/gnu/llvm/lib/DebugInfo/PDB/Raw/NameMapBuilder.cpp b/gnu/llvm/lib/DebugInfo/PDB/Raw/NameMapBuilder.cpp index f570d5931b0..41c6c2cd810 100644 --- a/gnu/llvm/lib/DebugInfo/PDB/Raw/NameMapBuilder.cpp +++ b/gnu/llvm/lib/DebugInfo/PDB/Raw/NameMapBuilder.cpp @@ -7,19 +7,15 @@ // //===----------------------------------------------------------------------===// -#include "llvm/ADT/STLExtras.h" -#include "llvm/DebugInfo/MSF/StreamWriter.h" -#include "llvm/DebugInfo/PDB/Raw/NameMap.h" #include "llvm/DebugInfo/PDB/Raw/NameMapBuilder.h" + +#include "llvm/DebugInfo/PDB/Raw/NameMap.h" #include "llvm/Support/Endian.h" -#include "llvm/Support/Error.h" -#include <algorithm> -#include <cstdint> using namespace llvm; using namespace llvm::pdb; -NameMapBuilder::NameMapBuilder() = default; +NameMapBuilder::NameMapBuilder() {} void NameMapBuilder::addMapping(StringRef Name, uint32_t Mapping) { StringDataBytes += Name.size() + 1; @@ -52,57 +48,3 @@ uint32_t NameMapBuilder::calculateSerializedLength() const { return TotalLength; } - -Error NameMapBuilder::commit(msf::StreamWriter &Writer) const { - // The first field is the number of bytes of string data. So add - // up the length of all strings plus a null terminator for each - // one. - uint32_t NumBytes = 0; - for (auto B = Map.begin(), E = Map.end(); B != E; ++B) { - NumBytes += B->getKeyLength() + 1; - } - - if (auto EC = Writer.writeInteger(NumBytes)) // Number of bytes of string data - return EC; - // Now all of the string data itself. - for (auto B = Map.begin(), E = Map.end(); B != E; ++B) { - if (auto EC = Writer.writeZeroString(B->getKey())) - return EC; - } - - if (auto EC = Writer.writeInteger(Map.size())) // Hash Size - return EC; - - if (auto EC = Writer.writeInteger(Map.size())) // Max Number of Strings - return EC; - - if (auto EC = Writer.writeInteger(Map.size())) // Num Present Words - return EC; - - // For each entry in the mapping, write a bit mask which represents a bucket - // to store it in. We don't use this, so the value we write isn't important - // to us, it just has to be there. - for (auto B = Map.begin(), E = Map.end(); B != E; ++B) { - if (auto EC = Writer.writeInteger(1U)) - return EC; - } - - if (auto EC = Writer.writeInteger(0U)) // Num Deleted Words - return EC; - - // Mappings of each word. - uint32_t OffsetSoFar = 0; - for (auto B = Map.begin(), E = Map.end(); B != E; ++B) { - // This is a list of key value pairs where the key is the offset into the - // strings buffer, and the value is a stream number. Write each pair. - if (auto EC = Writer.writeInteger(OffsetSoFar)) - return EC; - - if (auto EC = Writer.writeInteger(B->second)) - return EC; - - OffsetSoFar += B->getKeyLength() + 1; - } - - return Error::success(); -} diff --git a/gnu/llvm/lib/DebugInfo/PDB/Raw/PDBFile.cpp b/gnu/llvm/lib/DebugInfo/PDB/Raw/PDBFile.cpp index 53491518b8c..95016753dc1 100644 --- a/gnu/llvm/lib/DebugInfo/PDB/Raw/PDBFile.cpp +++ b/gnu/llvm/lib/DebugInfo/PDB/Raw/PDBFile.cpp @@ -7,84 +7,68 @@ // //===----------------------------------------------------------------------===// +#include "llvm/DebugInfo/PDB/Raw/PDBFile.h" + #include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/DebugInfo/MSF/MSFCommon.h" -#include "llvm/DebugInfo/MSF/StreamArray.h" -#include "llvm/DebugInfo/MSF/StreamInterface.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" +#include "llvm/DebugInfo/CodeView/StreamArray.h" +#include "llvm/DebugInfo/CodeView/StreamInterface.h" +#include "llvm/DebugInfo/CodeView/StreamReader.h" +#include "llvm/DebugInfo/CodeView/StreamWriter.h" #include "llvm/DebugInfo/PDB/Raw/DbiStream.h" -#include "llvm/DebugInfo/PDB/Raw/GlobalsStream.h" +#include "llvm/DebugInfo/PDB/Raw/DirectoryStreamData.h" +#include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.h" #include "llvm/DebugInfo/PDB/Raw/InfoStream.h" #include "llvm/DebugInfo/PDB/Raw/NameHashTable.h" -#include "llvm/DebugInfo/PDB/Raw/PDBFile.h" #include "llvm/DebugInfo/PDB/Raw/PublicsStream.h" #include "llvm/DebugInfo/PDB/Raw/RawError.h" #include "llvm/DebugInfo/PDB/Raw/SymbolStream.h" #include "llvm/DebugInfo/PDB/Raw/TpiStream.h" #include "llvm/Support/Endian.h" -#include "llvm/Support/Error.h" -#include <algorithm> -#include <cassert> -#include <cstdint> +#include "llvm/Support/FileOutputBuffer.h" +#include "llvm/Support/MemoryBuffer.h" using namespace llvm; using namespace llvm::codeview; -using namespace llvm::msf; using namespace llvm::pdb; namespace { typedef FixedStreamArray<support::ulittle32_t> ulittle_array; -} // end anonymous namespace +} -PDBFile::PDBFile(std::unique_ptr<ReadableStream> PdbFileBuffer, - BumpPtrAllocator &Allocator) - : Allocator(Allocator), Buffer(std::move(PdbFileBuffer)) {} +PDBFile::PDBFile(std::unique_ptr<StreamInterface> PdbFileBuffer) + : Buffer(std::move(PdbFileBuffer)), SB(nullptr) {} -PDBFile::~PDBFile() = default; +PDBFile::~PDBFile() {} -uint32_t PDBFile::getBlockSize() const { return ContainerLayout.SB->BlockSize; } +uint32_t PDBFile::getBlockSize() const { return SB->BlockSize; } -uint32_t PDBFile::getFreeBlockMapBlock() const { - return ContainerLayout.SB->FreeBlockMapBlock; -} +uint32_t PDBFile::getFreeBlockMapBlock() const { return SB->FreeBlockMapBlock; } -uint32_t PDBFile::getBlockCount() const { - return ContainerLayout.SB->NumBlocks; -} +uint32_t PDBFile::getBlockCount() const { return SB->NumBlocks; } -uint32_t PDBFile::getNumDirectoryBytes() const { - return ContainerLayout.SB->NumDirectoryBytes; -} +uint32_t PDBFile::getNumDirectoryBytes() const { return SB->NumDirectoryBytes; } -uint32_t PDBFile::getBlockMapIndex() const { - return ContainerLayout.SB->BlockMapAddr; -} +uint32_t PDBFile::getBlockMapIndex() const { return SB->BlockMapAddr; } -uint32_t PDBFile::getUnknown1() const { return ContainerLayout.SB->Unknown1; } +uint32_t PDBFile::getUnknown1() const { return SB->Unknown1; } uint32_t PDBFile::getNumDirectoryBlocks() const { - return msf::bytesToBlocks(ContainerLayout.SB->NumDirectoryBytes, - ContainerLayout.SB->BlockSize); + return msf::bytesToBlocks(SB->NumDirectoryBytes, SB->BlockSize); } uint64_t PDBFile::getBlockMapOffset() const { - return (uint64_t)ContainerLayout.SB->BlockMapAddr * - ContainerLayout.SB->BlockSize; + return (uint64_t)SB->BlockMapAddr * SB->BlockSize; } -uint32_t PDBFile::getNumStreams() const { - return ContainerLayout.StreamSizes.size(); -} +uint32_t PDBFile::getNumStreams() const { return StreamSizes.size(); } uint32_t PDBFile::getStreamByteSize(uint32_t StreamIndex) const { - return ContainerLayout.StreamSizes[StreamIndex]; + return StreamSizes[StreamIndex]; } ArrayRef<support::ulittle32_t> PDBFile::getStreamBlockList(uint32_t StreamIndex) const { - return ContainerLayout.StreamMap[StreamIndex]; + return StreamMap[StreamIndex]; } uint32_t PDBFile::getFileSize() const { return Buffer->getLength(); } @@ -101,72 +85,41 @@ Expected<ArrayRef<uint8_t>> PDBFile::getBlockData(uint32_t BlockIndex, Error PDBFile::setBlockData(uint32_t BlockIndex, uint32_t Offset, ArrayRef<uint8_t> Data) const { - return make_error<RawError>(raw_error_code::not_writable, - "PDBFile is immutable"); + if (Offset >= getBlockSize()) + return make_error<RawError>( + raw_error_code::invalid_block_address, + "setBlockData attempted to write out of block bounds."); + if (Data.size() > getBlockSize() - Offset) + return make_error<RawError>( + raw_error_code::invalid_block_address, + "setBlockData attempted to write out of block bounds."); + + uint64_t StreamBlockOffset = msf::blockToOffset(BlockIndex, getBlockSize()); + StreamBlockOffset += Offset; + return Buffer->writeBytes(StreamBlockOffset, Data); } Error PDBFile::parseFileHeaders() { StreamReader Reader(*Buffer); - // Initialize SB. - const msf::SuperBlock *SB = nullptr; if (auto EC = Reader.readObject(SB)) { consumeError(std::move(EC)); return make_error<RawError>(raw_error_code::corrupt_file, "Does not contain superblock"); } - if (auto EC = msf::validateSuperBlock(*SB)) - return EC; - - if (Buffer->getLength() % SB->BlockSize != 0) - return make_error<RawError>(raw_error_code::corrupt_file, - "File size is not a multiple of block size"); - ContainerLayout.SB = SB; - - // Initialize Free Page Map. - ContainerLayout.FreePageMap.resize(SB->NumBlocks); - // The Fpm exists either at block 1 or block 2 of the MSF. However, this - // allows for a maximum of getBlockSize() * 8 blocks bits in the Fpm, and - // thusly an equal number of total blocks in the file. For a block size - // of 4KiB (very common), this would yield 32KiB total blocks in file, for a - // maximum file size of 32KiB * 4KiB = 128MiB. Obviously this won't do, so - // the Fpm is split across the file at `getBlockSize()` intervals. As a - // result, every block whose index is of the form |{1,2} + getBlockSize() * k| - // for any non-negative integer k is an Fpm block. In theory, we only really - // need to reserve blocks of the form |{1,2} + getBlockSize() * 8 * k|, but - // current versions of the MSF format already expect the Fpm to be arranged - // at getBlockSize() intervals, so we have to be compatible. - // See the function fpmPn() for more information: - // https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/msf/msf.cpp#L489 - auto FpmStream = MappedBlockStream::createFpmStream(ContainerLayout, *Buffer); - StreamReader FpmReader(*FpmStream); - ArrayRef<uint8_t> FpmBytes; - if (auto EC = FpmReader.readBytes(FpmBytes, - msf::getFullFpmByteSize(ContainerLayout))) + if (auto EC = setSuperBlock(SB)) return EC; - uint32_t BlocksRemaining = getBlockCount(); - uint32_t BI = 0; - for (auto Byte : FpmBytes) { - uint32_t BlocksThisByte = std::min(BlocksRemaining, 8U); - for (uint32_t I = 0; I < BlocksThisByte; ++I) { - if (Byte & (1 << I)) - ContainerLayout.FreePageMap[BI] = true; - --BlocksRemaining; - ++BI; - } - } Reader.setOffset(getBlockMapOffset()); - if (auto EC = Reader.readArray(ContainerLayout.DirectoryBlocks, - getNumDirectoryBlocks())) + if (auto EC = Reader.readArray(DirectoryBlocks, getNumDirectoryBlocks())) return EC; return Error::success(); } Error PDBFile::parseStreamData() { - assert(ContainerLayout.SB); + assert(SB); if (DirectoryStream) return Error::success(); @@ -177,20 +130,21 @@ Error PDBFile::parseStreamData() { // is exactly what we are attempting to parse. By specifying a custom // subclass of IPDBStreamData which only accesses the fields that have already // been parsed, we can avoid this and reuse MappedBlockStream. - auto DS = MappedBlockStream::createDirectoryStream(ContainerLayout, *Buffer); - StreamReader Reader(*DS); + auto DS = MappedBlockStream::createDirectoryStream(*this); + if (!DS) + return DS.takeError(); + StreamReader Reader(**DS); if (auto EC = Reader.readInteger(NumStreams)) return EC; - if (auto EC = Reader.readArray(ContainerLayout.StreamSizes, NumStreams)) + if (auto EC = Reader.readArray(StreamSizes, NumStreams)) return EC; for (uint32_t I = 0; I < NumStreams; ++I) { uint32_t StreamSize = getStreamByteSize(I); // FIXME: What does StreamSize ~0U mean? uint64_t NumExpectedStreamBlocks = - StreamSize == UINT32_MAX - ? 0 - : msf::bytesToBlocks(StreamSize, ContainerLayout.SB->BlockSize); + StreamSize == UINT32_MAX ? 0 : msf::bytesToBlocks(StreamSize, + SB->BlockSize); // For convenience, we store the block array contiguously. This is because // if someone calls setStreamMap(), it is more convenient to be able to call @@ -202,46 +156,29 @@ Error PDBFile::parseStreamData() { if (auto EC = Reader.readArray(Blocks, NumExpectedStreamBlocks)) return EC; for (uint32_t Block : Blocks) { - uint64_t BlockEndOffset = - (uint64_t)(Block + 1) * ContainerLayout.SB->BlockSize; + uint64_t BlockEndOffset = (uint64_t)(Block + 1) * SB->BlockSize; if (BlockEndOffset > getFileSize()) return make_error<RawError>(raw_error_code::corrupt_file, "Stream block map is corrupt."); } - ContainerLayout.StreamMap.push_back(Blocks); + StreamMap.push_back(Blocks); } // We should have read exactly SB->NumDirectoryBytes bytes. assert(Reader.bytesRemaining() == 0); - DirectoryStream = std::move(DS); + DirectoryStream = std::move(*DS); return Error::success(); } -ArrayRef<support::ulittle32_t> PDBFile::getDirectoryBlockArray() const { - return ContainerLayout.DirectoryBlocks; -} - -Expected<GlobalsStream &> PDBFile::getPDBGlobalsStream() { - if (!Globals) { - auto DbiS = getPDBDbiStream(); - if (!DbiS) - return DbiS.takeError(); - - auto GlobalS = safelyCreateIndexedStream( - ContainerLayout, *Buffer, DbiS->getGlobalSymbolStreamIndex()); - if (!GlobalS) return GlobalS.takeError(); - auto TempGlobals = llvm::make_unique<GlobalsStream>(std::move(*GlobalS)); - if (auto EC = TempGlobals->reload()) - return std::move(EC); - Globals = std::move(TempGlobals); - } - return *Globals; +llvm::ArrayRef<support::ulittle32_t> PDBFile::getDirectoryBlockArray() const { + return DirectoryBlocks; } Expected<InfoStream &> PDBFile::getPDBInfoStream() { if (!Info) { - auto InfoS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamPDB); - if (!InfoS) return InfoS.takeError(); + auto InfoS = MappedBlockStream::createIndexedStream(StreamPDB, *this); + if (!InfoS) + return InfoS.takeError(); auto TempInfo = llvm::make_unique<InfoStream>(std::move(*InfoS)); if (auto EC = TempInfo->reload()) return std::move(EC); @@ -252,8 +189,9 @@ Expected<InfoStream &> PDBFile::getPDBInfoStream() { Expected<DbiStream &> PDBFile::getPDBDbiStream() { if (!Dbi) { - auto DbiS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamDBI); - if (!DbiS) return DbiS.takeError(); + auto DbiS = MappedBlockStream::createIndexedStream(StreamDBI, *this); + if (!DbiS) + return DbiS.takeError(); auto TempDbi = llvm::make_unique<DbiStream>(*this, std::move(*DbiS)); if (auto EC = TempDbi->reload()) return std::move(EC); @@ -264,8 +202,9 @@ Expected<DbiStream &> PDBFile::getPDBDbiStream() { Expected<TpiStream &> PDBFile::getPDBTpiStream() { if (!Tpi) { - auto TpiS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamTPI); - if (!TpiS) return TpiS.takeError(); + auto TpiS = MappedBlockStream::createIndexedStream(StreamTPI, *this); + if (!TpiS) + return TpiS.takeError(); auto TempTpi = llvm::make_unique<TpiStream>(*this, std::move(*TpiS)); if (auto EC = TempTpi->reload()) return std::move(EC); @@ -276,8 +215,9 @@ Expected<TpiStream &> PDBFile::getPDBTpiStream() { Expected<TpiStream &> PDBFile::getPDBIpiStream() { if (!Ipi) { - auto IpiS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamIPI); - if (!IpiS) return IpiS.takeError(); + auto IpiS = MappedBlockStream::createIndexedStream(StreamIPI, *this); + if (!IpiS) + return IpiS.takeError(); auto TempIpi = llvm::make_unique<TpiStream>(*this, std::move(*IpiS)); if (auto EC = TempIpi->reload()) return std::move(EC); @@ -292,9 +232,12 @@ Expected<PublicsStream &> PDBFile::getPDBPublicsStream() { if (!DbiS) return DbiS.takeError(); - auto PublicS = safelyCreateIndexedStream( - ContainerLayout, *Buffer, DbiS->getPublicSymbolStreamIndex()); - if (!PublicS) return PublicS.takeError(); + uint32_t PublicsStreamNum = DbiS->getPublicSymbolStreamIndex(); + + auto PublicS = + MappedBlockStream::createIndexedStream(PublicsStreamNum, *this); + if (!PublicS) + return PublicS.takeError(); auto TempPublics = llvm::make_unique<PublicsStream>(*this, std::move(*PublicS)); if (auto EC = TempPublics->reload()) @@ -311,10 +254,11 @@ Expected<SymbolStream &> PDBFile::getPDBSymbolStream() { return DbiS.takeError(); uint32_t SymbolStreamNum = DbiS->getSymRecordStreamIndex(); - auto SymbolS = - safelyCreateIndexedStream(ContainerLayout, *Buffer, SymbolStreamNum); - if (!SymbolS) return SymbolS.takeError(); + auto SymbolS = + MappedBlockStream::createIndexedStream(SymbolStreamNum, *this); + if (!SymbolS) + return SymbolS.takeError(); auto TempSymbols = llvm::make_unique<SymbolStream>(std::move(*SymbolS)); if (auto EC = TempSymbols->reload()) return std::move(EC); @@ -331,9 +275,14 @@ Expected<NameHashTable &> PDBFile::getStringTable() { uint32_t NameStreamIndex = IS->getNamedStreamIndex("/names"); - auto NS = - safelyCreateIndexedStream(ContainerLayout, *Buffer, NameStreamIndex); - if (!NS) return NS.takeError(); + if (NameStreamIndex == 0) + return make_error<RawError>(raw_error_code::no_stream); + if (NameStreamIndex >= getNumStreams()) + return make_error<RawError>(raw_error_code::no_stream); + + auto NS = MappedBlockStream::createIndexedStream(NameStreamIndex, *this); + if (!NS) + return NS.takeError(); StreamReader Reader(**NS); auto N = llvm::make_unique<NameHashTable>(); @@ -345,47 +294,72 @@ Expected<NameHashTable &> PDBFile::getStringTable() { return *StringTable; } -bool PDBFile::hasPDBDbiStream() const { return StreamDBI < getNumStreams(); } +Error PDBFile::setSuperBlock(const msf::SuperBlock *Block) { + if (auto EC = msf::validateSuperBlock(*Block)) + return EC; + + if (Buffer->getLength() % SB->BlockSize != 0) + return make_error<RawError>(raw_error_code::corrupt_file, + "File size is not a multiple of block size"); -bool PDBFile::hasPDBGlobalsStream() { - auto DbiS = getPDBDbiStream(); - if (!DbiS) return false; - return DbiS->getGlobalSymbolStreamIndex() < getNumStreams(); + SB = Block; + return Error::success(); } -bool PDBFile::hasPDBInfoStream() { return StreamPDB < getNumStreams(); } +Error PDBFile::commit() { + StreamWriter Writer(*Buffer); -bool PDBFile::hasPDBIpiStream() const { return StreamIPI < getNumStreams(); } + if (auto EC = Writer.writeObject(*SB)) + return EC; + Writer.setOffset(getBlockMapOffset()); + if (auto EC = Writer.writeArray(DirectoryBlocks)) + return EC; -bool PDBFile::hasPDBPublicsStream() { - auto DbiS = getPDBDbiStream(); - if (!DbiS) return false; - return DbiS->getPublicSymbolStreamIndex() < getNumStreams(); -} + auto DS = MappedBlockStream::createDirectoryStream(*this); + if (!DS) + return DS.takeError(); + auto DirStream = std::move(*DS); + StreamWriter DW(*DirStream); + if (auto EC = DW.writeInteger(this->getNumStreams())) + return EC; -bool PDBFile::hasPDBSymbolStream() { - auto DbiS = getPDBDbiStream(); - if (!DbiS) return false; - return DbiS->getSymRecordStreamIndex() < getNumStreams(); -} + if (auto EC = DW.writeArray(StreamSizes)) + return EC; -bool PDBFile::hasPDBTpiStream() const { return StreamTPI < getNumStreams(); } + for (const auto &Blocks : StreamMap) { + if (auto EC = DW.writeArray(Blocks)) + return EC; + } -bool PDBFile::hasStringTable() { - auto IS = getPDBInfoStream(); - if (!IS) return false; - return IS->getNamedStreamIndex("/names") < getNumStreams(); -} + if (Info) { + if (auto EC = Info->commit()) + return EC; + } + + if (Dbi) { + if (auto EC = Dbi->commit()) + return EC; + } + + if (Symbols) { + if (auto EC = Symbols->commit()) + return EC; + } + + if (Publics) { + if (auto EC = Publics->commit()) + return EC; + } + + if (Tpi) { + if (auto EC = Tpi->commit()) + return EC; + } + + if (Ipi) { + if (auto EC = Ipi->commit()) + return EC; + } -/// Wrapper around MappedBlockStream::createIndexedStream() -/// that checks if a stream with that index actually exists. -/// If it does not, the return value will have an MSFError with -/// code msf_error_code::no_stream. Else, the return value will -/// contain the stream returned by createIndexedStream(). -Expected<std::unique_ptr<MappedBlockStream>> PDBFile::safelyCreateIndexedStream( - const MSFLayout &Layout, const ReadableStream &MsfData, - uint32_t StreamIndex) const { - if (StreamIndex >= getNumStreams()) - return make_error<RawError>(raw_error_code::no_stream); - return MappedBlockStream::createIndexedStream(Layout, MsfData, StreamIndex); + return Buffer->commit(); } diff --git a/gnu/llvm/lib/DebugInfo/PDB/Raw/PDBFileBuilder.cpp b/gnu/llvm/lib/DebugInfo/PDB/Raw/PDBFileBuilder.cpp index 6fec0e32a8a..9063fd62d29 100644 --- a/gnu/llvm/lib/DebugInfo/PDB/Raw/PDBFileBuilder.cpp +++ b/gnu/llvm/lib/DebugInfo/PDB/Raw/PDBFileBuilder.cpp @@ -11,138 +11,92 @@ #include "llvm/ADT/BitVector.h" -#include "llvm/DebugInfo/MSF/MSFBuilder.h" -#include "llvm/DebugInfo/MSF/StreamInterface.h" -#include "llvm/DebugInfo/MSF/StreamWriter.h" -#include "llvm/DebugInfo/PDB/GenericError.h" +#include "llvm/DebugInfo/CodeView/StreamInterface.h" +#include "llvm/DebugInfo/CodeView/StreamWriter.h" #include "llvm/DebugInfo/PDB/Raw/DbiStream.h" #include "llvm/DebugInfo/PDB/Raw/DbiStreamBuilder.h" #include "llvm/DebugInfo/PDB/Raw/InfoStream.h" #include "llvm/DebugInfo/PDB/Raw/InfoStreamBuilder.h" #include "llvm/DebugInfo/PDB/Raw/RawError.h" -#include "llvm/DebugInfo/PDB/Raw/TpiStream.h" -#include "llvm/DebugInfo/PDB/Raw/TpiStreamBuilder.h" using namespace llvm; using namespace llvm::codeview; -using namespace llvm::msf; using namespace llvm::pdb; using namespace llvm::support; -PDBFileBuilder::PDBFileBuilder(BumpPtrAllocator &Allocator) - : Allocator(Allocator) {} +PDBFileBuilder::PDBFileBuilder( + std::unique_ptr<codeview::StreamInterface> FileBuffer) + : File(llvm::make_unique<PDBFile>(std::move(FileBuffer))) {} -Error PDBFileBuilder::initialize(uint32_t BlockSize) { - auto ExpectedMsf = MSFBuilder::create(Allocator, BlockSize); +Error PDBFileBuilder::initialize(const msf::SuperBlock &Super) { + auto ExpectedMsf = + MsfBuilder::create(File->Allocator, Super.BlockSize, Super.NumBlocks); if (!ExpectedMsf) return ExpectedMsf.takeError(); - Msf = llvm::make_unique<MSFBuilder>(std::move(*ExpectedMsf)); + + auto &MsfResult = *ExpectedMsf; + if (auto EC = MsfResult.setBlockMapAddr(Super.BlockMapAddr)) + return EC; + Msf = llvm::make_unique<MsfBuilder>(std::move(MsfResult)); + Msf->setFreePageMap(Super.FreeBlockMapBlock); + Msf->setUnknown1(Super.Unknown1); return Error::success(); } -MSFBuilder &PDBFileBuilder::getMsfBuilder() { return *Msf; } +MsfBuilder &PDBFileBuilder::getMsfBuilder() { return *Msf; } InfoStreamBuilder &PDBFileBuilder::getInfoBuilder() { if (!Info) - Info = llvm::make_unique<InfoStreamBuilder>(*Msf); + Info = llvm::make_unique<InfoStreamBuilder>(); return *Info; } DbiStreamBuilder &PDBFileBuilder::getDbiBuilder() { if (!Dbi) - Dbi = llvm::make_unique<DbiStreamBuilder>(*Msf); + Dbi = llvm::make_unique<DbiStreamBuilder>(); return *Dbi; } -TpiStreamBuilder &PDBFileBuilder::getTpiBuilder() { - if (!Tpi) - Tpi = llvm::make_unique<TpiStreamBuilder>(*Msf, StreamTPI); - return *Tpi; -} - -TpiStreamBuilder &PDBFileBuilder::getIpiBuilder() { - if (!Ipi) - Ipi = llvm::make_unique<TpiStreamBuilder>(*Msf, StreamIPI); - return *Ipi; -} - -Expected<msf::MSFLayout> PDBFileBuilder::finalizeMsfLayout() const { +Expected<std::unique_ptr<PDBFile>> PDBFileBuilder::build() { if (Info) { - if (auto EC = Info->finalizeMsfLayout()) + uint32_t Length = Info->calculateSerializedLength(); + if (auto EC = Msf->setStreamSize(StreamPDB, Length)) return std::move(EC); } if (Dbi) { - if (auto EC = Dbi->finalizeMsfLayout()) + uint32_t Length = Dbi->calculateSerializedLength(); + if (auto EC = Msf->setStreamSize(StreamDBI, Length)) return std::move(EC); } - if (Tpi) { - if (auto EC = Tpi->finalizeMsfLayout()) - return std::move(EC); - } - if (Ipi) { - if (auto EC = Ipi->finalizeMsfLayout()) - return std::move(EC); - } - - return Msf->build(); -} -Error PDBFileBuilder::commit(StringRef Filename) { - auto ExpectedLayout = finalizeMsfLayout(); + auto ExpectedLayout = Msf->build(); if (!ExpectedLayout) return ExpectedLayout.takeError(); - auto &Layout = *ExpectedLayout; - uint64_t Filesize = Layout.SB->BlockSize * Layout.SB->NumBlocks; - auto OutFileOrError = FileOutputBuffer::create(Filename, Filesize); - if (OutFileOrError.getError()) - return llvm::make_error<pdb::GenericError>(generic_error_code::invalid_path, - Filename); - FileBufferByteStream Buffer(std::move(*OutFileOrError)); - StreamWriter Writer(Buffer); - - if (auto EC = Writer.writeObject(*Layout.SB)) - return EC; - uint32_t BlockMapOffset = - msf::blockToOffset(Layout.SB->BlockMapAddr, Layout.SB->BlockSize); - Writer.setOffset(BlockMapOffset); - if (auto EC = Writer.writeArray(Layout.DirectoryBlocks)) - return EC; - - auto DirStream = - WritableMappedBlockStream::createDirectoryStream(Layout, Buffer); - StreamWriter DW(*DirStream); - if (auto EC = - DW.writeInteger(static_cast<uint32_t>(Layout.StreamSizes.size()))) - return EC; - - if (auto EC = DW.writeArray(Layout.StreamSizes)) - return EC; - - for (const auto &Blocks : Layout.StreamMap) { - if (auto EC = DW.writeArray(Blocks)) - return EC; - } + const msf::Layout &L = *ExpectedLayout; + File->StreamMap = L.StreamMap; + File->StreamSizes = L.StreamSizes; + File->DirectoryBlocks = L.DirectoryBlocks; + File->SB = L.SB; if (Info) { - if (auto EC = Info->commit(Layout, Buffer)) - return EC; + auto ExpectedInfo = Info->build(*File); + if (!ExpectedInfo) + return ExpectedInfo.takeError(); + File->Info = std::move(*ExpectedInfo); } if (Dbi) { - if (auto EC = Dbi->commit(Layout, Buffer)) - return EC; + auto ExpectedDbi = Dbi->build(*File); + if (!ExpectedDbi) + return ExpectedDbi.takeError(); + File->Dbi = std::move(*ExpectedDbi); } - if (Tpi) { - if (auto EC = Tpi->commit(Layout, Buffer)) - return EC; - } - - if (Ipi) { - if (auto EC = Ipi->commit(Layout, Buffer)) - return EC; - } + if (File->Info && File->Dbi && File->Info->getAge() != File->Dbi->getAge()) + return llvm::make_error<RawError>( + raw_error_code::corrupt_file, + "PDB Stream Age doesn't match Dbi Stream Age!"); - return Buffer.commit(); + return std::move(File); } diff --git a/gnu/llvm/lib/DebugInfo/PDB/Raw/PublicsStream.cpp b/gnu/llvm/lib/DebugInfo/PDB/Raw/PublicsStream.cpp index b31f605a078..af3d2d026b4 100644 --- a/gnu/llvm/lib/DebugInfo/PDB/Raw/PublicsStream.cpp +++ b/gnu/llvm/lib/DebugInfo/PDB/Raw/PublicsStream.cpp @@ -22,25 +22,30 @@ // //===----------------------------------------------------------------------===// -#include "GSI.h" -#include "llvm/ADT/iterator_range.h" -#include "llvm/DebugInfo/CodeView/SymbolRecord.h" -#include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" -#include "llvm/DebugInfo/PDB/Raw/PDBFile.h" #include "llvm/DebugInfo/PDB/Raw/PublicsStream.h" + +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/StreamReader.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.h" +#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Raw/PDBFile.h" +#include "llvm/DebugInfo/PDB/Raw/RawConstants.h" #include "llvm/DebugInfo/PDB/Raw/RawError.h" #include "llvm/DebugInfo/PDB/Raw/SymbolStream.h" + +#include "llvm/ADT/BitVector.h" #include "llvm/Support/Endian.h" -#include "llvm/Support/Error.h" -#include <algorithm> -#include <cstdint> +#include "llvm/Support/Format.h" +#include "llvm/Support/MathExtras.h" using namespace llvm; -using namespace llvm::msf; using namespace llvm::support; using namespace llvm::pdb; + +static const unsigned IPHR_HASH = 4096; + // This is PSGSIHDR struct defined in // https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/dbi/gsi.h struct PublicsStream::HeaderInfo { @@ -54,11 +59,23 @@ struct PublicsStream::HeaderInfo { ulittle32_t NumSections; }; +// This is GSIHashHdr. +struct PublicsStream::GSIHashHeader { + enum : unsigned { + HdrSignature = ~0U, + HdrVersion = 0xeffe0000 + 19990810, + }; + ulittle32_t VerSignature; + ulittle32_t VerHdr; + ulittle32_t HrSize; + ulittle32_t NumBuckets; +}; + PublicsStream::PublicsStream(PDBFile &File, std::unique_ptr<MappedBlockStream> Stream) : Pdb(File), Stream(std::move(Stream)) {} -PublicsStream::~PublicsStream() = default; +PublicsStream::~PublicsStream() {} uint32_t PublicsStream::getSymHash() const { return Header->SymHash; } uint32_t PublicsStream::getAddrMap() const { return Header->AddrMap; } @@ -69,7 +86,7 @@ uint32_t PublicsStream::getAddrMap() const { return Header->AddrMap; } // we skip over the hash table which we believe contains information about // public symbols. Error PublicsStream::reload() { - StreamReader Reader(*Stream); + codeview::StreamReader Reader(*Stream); // Check stream size. if (Reader.bytesRemaining() < sizeof(HeaderInfo) + sizeof(GSIHashHeader)) @@ -81,15 +98,40 @@ Error PublicsStream::reload() { return make_error<RawError>(raw_error_code::corrupt_file, "Publics Stream does not contain a header."); - if (auto EC = readGSIHashHeader(HashHdr, Reader)) - return EC; + if (Reader.readObject(HashHdr)) + return make_error<RawError>(raw_error_code::corrupt_file, + "Publics Stream does not contain a header."); - if (auto EC = readGSIHashRecords(HashRecords, HashHdr, Reader)) - return EC; + // An array of HashRecord follows. Read them. + if (HashHdr->HrSize % sizeof(PSHashRecord)) + return make_error<RawError>(raw_error_code::corrupt_file, + "Invalid HR array size."); + uint32_t NumHashRecords = HashHdr->HrSize / sizeof(PSHashRecord); + if (auto EC = Reader.readArray(HashRecords, NumHashRecords)) + return joinErrors(std::move(EC), + make_error<RawError>(raw_error_code::corrupt_file, + "Could not read an HR array")); - if (auto EC = readGSIHashBuckets(HashBuckets, HashHdr, Reader)) - return EC; - NumBuckets = HashBuckets.size(); + // A bitmap of a fixed length follows. + size_t BitmapSizeInBits = alignTo(IPHR_HASH + 1, 32); + uint32_t NumBitmapEntries = BitmapSizeInBits / 8; + if (auto EC = Reader.readBytes(Bitmap, NumBitmapEntries)) + return joinErrors(std::move(EC), + make_error<RawError>(raw_error_code::corrupt_file, + "Could not read a bitmap.")); + for (uint8_t B : Bitmap) + NumBuckets += countPopulation(B); + + // We don't yet understand the following data structures completely, + // but we at least know the types and sizes. Here we are trying + // to read the stream till end so that we at least can detect + // corrupted streams. + + // Hash buckets follow. + if (auto EC = Reader.readArray(HashBuckets, NumBuckets)) + return joinErrors(std::move(EC), + make_error<RawError>(raw_error_code::corrupt_file, + "Hash buckets corrupted.")); // Something called "address map" follows. uint32_t NumAddressMapEntries = Header->AddrMap / sizeof(uint32_t); @@ -121,7 +163,7 @@ PublicsStream::getSymbols(bool *HadError) const { auto SymbolS = Pdb.getPDBSymbolStream(); if (SymbolS.takeError()) { codeview::CVSymbolArray::Iterator Iter; - return make_range(Iter, Iter); + return llvm::make_range(Iter, Iter); } SymbolStream &SS = SymbolS.get(); diff --git a/gnu/llvm/lib/DebugInfo/PDB/Raw/RawError.cpp b/gnu/llvm/lib/DebugInfo/PDB/Raw/RawError.cpp index f4a5057509e..eb169f70e11 100644 --- a/gnu/llvm/lib/DebugInfo/PDB/Raw/RawError.cpp +++ b/gnu/llvm/lib/DebugInfo/PDB/Raw/RawError.cpp @@ -11,7 +11,7 @@ namespace { // deal with the Error value directly, rather than converting to error_code. class RawErrorCategory : public std::error_category { public: - const char *name() const noexcept override { return "llvm.pdb.raw"; } + const char *name() const LLVM_NOEXCEPT override { return "llvm.pdb.raw"; } std::string message(int Condition) const override { switch (static_cast<raw_error_code>(Condition)) { @@ -19,8 +19,6 @@ public: return "An unknown error has occurred."; case raw_error_code::feature_unsupported: return "The feature is unsupported by the implementation."; - case raw_error_code::invalid_format: - return "The record is in an unexpected format."; case raw_error_code::corrupt_file: return "The PDB file is corrupt."; case raw_error_code::insufficient_buffer: @@ -32,10 +30,6 @@ public: return "The specified item does not exist in the array."; case raw_error_code::invalid_block_address: return "The specified block address is not valid."; - case raw_error_code::duplicate_entry: - return "The entry already exists."; - case raw_error_code::no_entry: - return "The entry does not exist."; case raw_error_code::not_writable: return "The PDB does not support writing."; case raw_error_code::invalid_tpi_hash: diff --git a/gnu/llvm/lib/DebugInfo/PDB/Raw/RawSession.cpp b/gnu/llvm/lib/DebugInfo/PDB/Raw/RawSession.cpp index cd3a2064c71..455d33140dd 100644 --- a/gnu/llvm/lib/DebugInfo/PDB/Raw/RawSession.cpp +++ b/gnu/llvm/lib/DebugInfo/PDB/Raw/RawSession.cpp @@ -7,8 +7,10 @@ // //===----------------------------------------------------------------------===// -#include "llvm/ADT/STLExtras.h" -#include "llvm/DebugInfo/MSF/ByteStream.h" +#include "llvm/DebugInfo/PDB/Raw/RawSession.h" + +#include "llvm/DebugInfo/CodeView/ByteStream.h" +#include "llvm/DebugInfo/CodeView/StreamInterface.h" #include "llvm/DebugInfo/PDB/GenericError.h" #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" #include "llvm/DebugInfo/PDB/IPDBSourceFile.h" @@ -16,51 +18,59 @@ #include "llvm/DebugInfo/PDB/PDBSymbolExe.h" #include "llvm/DebugInfo/PDB/Raw/PDBFile.h" #include "llvm/DebugInfo/PDB/Raw/RawError.h" -#include "llvm/DebugInfo/PDB/Raw/RawSession.h" -#include "llvm/Support/Allocator.h" -#include "llvm/Support/Error.h" + #include "llvm/Support/ErrorOr.h" #include "llvm/Support/MemoryBuffer.h" -#include <algorithm> -#include <memory> using namespace llvm; -using namespace llvm::msf; using namespace llvm::pdb; -RawSession::RawSession(std::unique_ptr<PDBFile> PdbFile, - std::unique_ptr<BumpPtrAllocator> Allocator) - : Pdb(std::move(PdbFile)), Allocator(std::move(Allocator)) {} +namespace { +// We need a class which behaves like an immutable ByteStream, but whose data +// is backed by an llvm::MemoryBuffer. It also needs to own the underlying +// MemoryBuffer, so this simple adapter is a good way to achieve that. +class InputByteStream : public codeview::ByteStream<false> { +public: + explicit InputByteStream(std::unique_ptr<MemoryBuffer> Buffer) + : ByteStream(ArrayRef<uint8_t>(Buffer->getBuffer().bytes_begin(), + Buffer->getBuffer().bytes_end())), + MemBuffer(std::move(Buffer)) {} + + std::unique_ptr<MemoryBuffer> MemBuffer; +}; +} + +RawSession::RawSession(std::unique_ptr<PDBFile> PdbFile) + : Pdb(std::move(PdbFile)) {} -RawSession::~RawSession() = default; +RawSession::~RawSession() {} Error RawSession::createFromPdb(StringRef Path, std::unique_ptr<IPDBSession> &Session) { + ErrorOr<std::unique_ptr<MemoryBuffer>> ErrorOrBuffer = MemoryBuffer::getFileOrSTDIN(Path, /*FileSize=*/-1, /*RequiresNullTerminator=*/false); if (!ErrorOrBuffer) - return make_error<GenericError>(generic_error_code::invalid_path); + return llvm::make_error<GenericError>(generic_error_code::invalid_path); std::unique_ptr<MemoryBuffer> Buffer = std::move(*ErrorOrBuffer); - auto Stream = llvm::make_unique<MemoryBufferByteStream>(std::move(Buffer)); + auto Stream = llvm::make_unique<InputByteStream>(std::move(Buffer)); - auto Allocator = llvm::make_unique<BumpPtrAllocator>(); - auto File = llvm::make_unique<PDBFile>(std::move(Stream), *Allocator); + std::unique_ptr<PDBFile> File(new PDBFile(std::move(Stream))); if (auto EC = File->parseFileHeaders()) return EC; if (auto EC = File->parseStreamData()) return EC; - Session = - llvm::make_unique<RawSession>(std::move(File), std::move(Allocator)); + Session.reset(new RawSession(std::move(File))); return Error::success(); } Error RawSession::createFromExe(StringRef Path, std::unique_ptr<IPDBSession> &Session) { - return make_error<RawError>(raw_error_code::feature_unsupported); + return llvm::make_error<RawError>(raw_error_code::feature_unsupported); } uint64_t RawSession::getLoadAddress() const { return 0; } @@ -93,26 +103,26 @@ RawSession::findLineNumbersByAddress(uint64_t Address, uint32_t Length) const { std::unique_ptr<IPDBEnumSourceFiles> RawSession::findSourceFiles(const PDBSymbolCompiland *Compiland, - StringRef Pattern, + llvm::StringRef Pattern, PDB_NameSearchFlags Flags) const { return nullptr; } std::unique_ptr<IPDBSourceFile> RawSession::findOneSourceFile(const PDBSymbolCompiland *Compiland, - StringRef Pattern, + llvm::StringRef Pattern, PDB_NameSearchFlags Flags) const { return nullptr; } std::unique_ptr<IPDBEnumChildren<PDBSymbolCompiland>> -RawSession::findCompilandsForSourceFile(StringRef Pattern, +RawSession::findCompilandsForSourceFile(llvm::StringRef Pattern, PDB_NameSearchFlags Flags) const { return nullptr; } std::unique_ptr<PDBSymbolCompiland> -RawSession::findOneCompilandForSourceFile(StringRef Pattern, +RawSession::findOneCompilandForSourceFile(llvm::StringRef Pattern, PDB_NameSearchFlags Flags) const { return nullptr; } diff --git a/gnu/llvm/lib/DebugInfo/PDB/Raw/SymbolStream.cpp b/gnu/llvm/lib/DebugInfo/PDB/Raw/SymbolStream.cpp index 2f3ac3497f3..41b2a64bfb1 100644 --- a/gnu/llvm/lib/DebugInfo/PDB/Raw/SymbolStream.cpp +++ b/gnu/llvm/lib/DebugInfo/PDB/Raw/SymbolStream.cpp @@ -10,9 +10,10 @@ #include "llvm/DebugInfo/PDB/Raw/SymbolStream.h" #include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/StreamReader.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" +#include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.h" +#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" #include "llvm/DebugInfo/PDB/Raw/PDBFile.h" #include "llvm/DebugInfo/PDB/Raw/RawConstants.h" #include "llvm/DebugInfo/PDB/Raw/RawError.h" @@ -20,7 +21,6 @@ #include "llvm/Support/Endian.h" using namespace llvm; -using namespace llvm::msf; using namespace llvm::support; using namespace llvm::pdb; @@ -30,7 +30,7 @@ SymbolStream::SymbolStream(std::unique_ptr<MappedBlockStream> Stream) SymbolStream::~SymbolStream() {} Error SymbolStream::reload() { - StreamReader Reader(*Stream); + codeview::StreamReader Reader(*Stream); if (auto EC = Reader.readArray(SymbolRecords, Stream->getLength())) return EC; diff --git a/gnu/llvm/lib/DebugInfo/PDB/Raw/TpiStream.cpp b/gnu/llvm/lib/DebugInfo/PDB/Raw/TpiStream.cpp index a1167cd9845..5617e57ccf6 100644 --- a/gnu/llvm/lib/DebugInfo/PDB/Raw/TpiStream.cpp +++ b/gnu/llvm/lib/DebugInfo/PDB/Raw/TpiStream.cpp @@ -7,55 +7,155 @@ // //===----------------------------------------------------------------------===// -#include "llvm/ADT/iterator_range.h" +#include "llvm/DebugInfo/PDB/Raw/TpiStream.h" + #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" -#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/StreamReader.h" +#include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h" -#include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" +#include "llvm/DebugInfo/PDB/Raw/Hash.h" +#include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.h" +#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" #include "llvm/DebugInfo/PDB/Raw/PDBFile.h" #include "llvm/DebugInfo/PDB/Raw/RawConstants.h" #include "llvm/DebugInfo/PDB/Raw/RawError.h" #include "llvm/DebugInfo/PDB/Raw/RawTypes.h" -#include "llvm/DebugInfo/PDB/Raw/TpiHashing.h" -#include "llvm/DebugInfo/PDB/Raw/TpiStream.h" + #include "llvm/Support/Endian.h" -#include "llvm/Support/Error.h" -#include <algorithm> -#include <cstdint> -#include <vector> using namespace llvm; using namespace llvm::codeview; using namespace llvm::support; -using namespace llvm::msf; using namespace llvm::pdb; +namespace { +const uint32_t MinHashBuckets = 0x1000; +const uint32_t MaxHashBuckets = 0x40000; +} + +// This corresponds to `HDR` in PDB/dbi/tpi.h. +struct TpiStream::HeaderInfo { + struct EmbeddedBuf { + little32_t Off; + ulittle32_t Length; + }; + + ulittle32_t Version; + ulittle32_t HeaderSize; + ulittle32_t TypeIndexBegin; + ulittle32_t TypeIndexEnd; + ulittle32_t TypeRecordBytes; + + // The following members correspond to `TpiHash` in PDB/dbi/tpi.h. + ulittle16_t HashStreamIndex; + ulittle16_t HashAuxStreamIndex; + ulittle32_t HashKeySize; + ulittle32_t NumHashBuckets; + + EmbeddedBuf HashValueBuffer; + EmbeddedBuf IndexOffsetBuffer; + EmbeddedBuf HashAdjBuffer; +}; + TpiStream::TpiStream(const PDBFile &File, std::unique_ptr<MappedBlockStream> Stream) : Pdb(File), Stream(std::move(Stream)) {} -TpiStream::~TpiStream() = default; +TpiStream::~TpiStream() {} + +// Corresponds to `fUDTAnon`. +template <typename T> static bool isAnonymous(T &Rec) { + StringRef Name = Rec.getName(); + return Name == "<unnamed-tag>" || Name == "__unnamed" || + Name.endswith("::<unnamed-tag>") || Name.endswith("::__unnamed"); +} + +// Computes a hash for a given TPI record. +template <typename T> +static uint32_t getTpiHash(T &Rec, const CVRecord<TypeLeafKind> &RawRec) { + auto Opts = static_cast<uint16_t>(Rec.getOptions()); + + bool ForwardRef = + Opts & static_cast<uint16_t>(ClassOptions::ForwardReference); + bool Scoped = Opts & static_cast<uint16_t>(ClassOptions::Scoped); + bool UniqueName = Opts & static_cast<uint16_t>(ClassOptions::HasUniqueName); + bool IsAnon = UniqueName && isAnonymous(Rec); + + if (!ForwardRef && !Scoped && !IsAnon) + return hashStringV1(Rec.getName()); + if (!ForwardRef && UniqueName && !IsAnon) + return hashStringV1(Rec.getUniqueName()); + return hashBufferV8(RawRec.RawData); +} + +namespace { +class TpiHashVerifier : public TypeVisitorCallbacks { +public: + TpiHashVerifier(FixedStreamArray<support::ulittle32_t> &HashValues, + uint32_t NumHashBuckets) + : HashValues(HashValues), NumHashBuckets(NumHashBuckets) {} + + Error visitUdtSourceLine(UdtSourceLineRecord &Rec) override { + return verifySourceLine(Rec); + } + + Error visitUdtModSourceLine(UdtModSourceLineRecord &Rec) override { + return verifySourceLine(Rec); + } + + Error visitClass(ClassRecord &Rec) override { return verify(Rec); } + Error visitEnum(EnumRecord &Rec) override { return verify(Rec); } + Error visitUnion(UnionRecord &Rec) override { return verify(Rec); } + + Error visitTypeBegin(const CVRecord<TypeLeafKind> &Rec) override { + ++Index; + RawRecord = &Rec; + return Error::success(); + } + +private: + template <typename T> Error verify(T &Rec) { + uint32_t Hash = getTpiHash(Rec, *RawRecord); + if (Hash % NumHashBuckets != HashValues[Index]) + return errorInvalidHash(); + return Error::success(); + } + + template <typename T> Error verifySourceLine(T &Rec) { + char Buf[4]; + support::endian::write32le(Buf, Rec.getUDT().getIndex()); + uint32_t Hash = hashStringV1(StringRef(Buf, 4)); + if (Hash % NumHashBuckets != HashValues[Index]) + return errorInvalidHash(); + return Error::success(); + } + + Error errorInvalidHash() { + return make_error<RawError>( + raw_error_code::invalid_tpi_hash, + "Type index is 0x" + utohexstr(TypeIndex::FirstNonSimpleIndex + Index)); + } + + FixedStreamArray<support::ulittle32_t> HashValues; + const CVRecord<TypeLeafKind> *RawRecord; + uint32_t NumHashBuckets; + uint32_t Index = -1; +}; +} // Verifies that a given type record matches with a given hash value. // Currently we only verify SRC_LINE records. Error TpiStream::verifyHashValues() { TpiHashVerifier Verifier(HashValues, Header->NumHashBuckets); - TypeDeserializer Deserializer; - - TypeVisitorCallbackPipeline Pipeline; - Pipeline.addCallbackToPipeline(Deserializer); - Pipeline.addCallbackToPipeline(Verifier); - - CVTypeVisitor Visitor(Pipeline); + CVTypeVisitor Visitor(Verifier); return Visitor.visitTypeStream(TypeRecords); } Error TpiStream::reload() { StreamReader Reader(*Stream); - if (Reader.bytesRemaining() < sizeof(TpiStreamHeader)) + if (Reader.bytesRemaining() < sizeof(HeaderInfo)) return make_error<RawError>(raw_error_code::corrupt_file, "TPI Stream does not contain a header."); @@ -67,7 +167,7 @@ Error TpiStream::reload() { return make_error<RawError>(raw_error_code::corrupt_file, "Unsupported TPI Version."); - if (Header->HeaderSize != sizeof(TpiStreamHeader)) + if (Header->HeaderSize != sizeof(HeaderInfo)) return make_error<RawError>(raw_error_code::corrupt_file, "Corrupt TPI Header size."); @@ -75,8 +175,8 @@ Error TpiStream::reload() { return make_error<RawError>(raw_error_code::corrupt_file, "TPI Stream expected 4 byte hash key size."); - if (Header->NumHashBuckets < MinTpiHashBuckets || - Header->NumHashBuckets > MaxTpiHashBuckets) + if (Header->NumHashBuckets < MinHashBuckets || + Header->NumHashBuckets > MaxHashBuckets) return make_error<RawError>(raw_error_code::corrupt_file, "TPI Stream Invalid number of hash buckets."); @@ -85,47 +185,43 @@ Error TpiStream::reload() { return EC; // Hash indices, hash values, etc come from the hash stream. - if (Header->HashStreamIndex != kInvalidStreamIndex) { - if (Header->HashStreamIndex >= Pdb.getNumStreams()) - return make_error<RawError>(raw_error_code::corrupt_file, - "Invalid TPI hash stream index."); - - auto HS = MappedBlockStream::createIndexedStream( - Pdb.getMsfLayout(), Pdb.getMsfBuffer(), Header->HashStreamIndex); - StreamReader HSR(*HS); - - uint32_t NumHashValues = - Header->HashValueBuffer.Length / sizeof(ulittle32_t); - if (NumHashValues != NumTypeRecords()) - return make_error<RawError>( - raw_error_code::corrupt_file, - "TPI hash count does not match with the number of type records."); - HSR.setOffset(Header->HashValueBuffer.Off); - if (auto EC = HSR.readArray(HashValues, NumHashValues)) - return EC; - std::vector<ulittle32_t> HashValueList; - for (auto I : HashValues) - HashValueList.push_back(I); - - HSR.setOffset(Header->IndexOffsetBuffer.Off); - uint32_t NumTypeIndexOffsets = - Header->IndexOffsetBuffer.Length / sizeof(TypeIndexOffset); - if (auto EC = HSR.readArray(TypeIndexOffsets, NumTypeIndexOffsets)) - return EC; - - HSR.setOffset(Header->HashAdjBuffer.Off); - uint32_t NumHashAdjustments = - Header->HashAdjBuffer.Length / sizeof(TypeIndexOffset); - if (auto EC = HSR.readArray(HashAdjustments, NumHashAdjustments)) - return EC; - - HashStream = std::move(HS); - - // TPI hash table is a parallel array for the type records. - // Verify that the hash values match with type records. - if (auto EC = verifyHashValues()) - return EC; - } + if (Header->HashStreamIndex >= Pdb.getNumStreams()) + return make_error<RawError>(raw_error_code::corrupt_file, + "Invalid TPI hash stream index."); + + auto HS = + MappedBlockStream::createIndexedStream(Header->HashStreamIndex, Pdb); + if (!HS) + return HS.takeError(); + StreamReader HSR(**HS); + + uint32_t NumHashValues = Header->HashValueBuffer.Length / sizeof(ulittle32_t); + if (NumHashValues != NumTypeRecords()) + return make_error<RawError>( + raw_error_code::corrupt_file, + "TPI hash count does not match with the number of type records."); + HSR.setOffset(Header->HashValueBuffer.Off); + if (auto EC = HSR.readArray(HashValues, NumHashValues)) + return EC; + + HSR.setOffset(Header->IndexOffsetBuffer.Off); + uint32_t NumTypeIndexOffsets = + Header->IndexOffsetBuffer.Length / sizeof(TypeIndexOffset); + if (auto EC = HSR.readArray(TypeIndexOffsets, NumTypeIndexOffsets)) + return EC; + + HSR.setOffset(Header->HashAdjBuffer.Off); + uint32_t NumHashAdjustments = + Header->HashAdjBuffer.Length / sizeof(TypeIndexOffset); + if (auto EC = HSR.readArray(HashAdjustments, NumHashAdjustments)) + return EC; + + HashStream = std::move(*HS); + + // TPI hash table is a parallel array for the type records. + // Verify that the hash values match with type records. + if (auto EC = verifyHashValues()) + return EC; return Error::success(); } @@ -171,7 +267,7 @@ TpiStream::getHashAdjustments() const { iterator_range<CVTypeArray::Iterator> TpiStream::types(bool *HadError) const { - return make_range(TypeRecords.begin(HadError), TypeRecords.end()); + return llvm::make_range(TypeRecords.begin(HadError), TypeRecords.end()); } Error TpiStream::commit() { return Error::success(); } diff --git a/gnu/llvm/lib/IR/AttributeSetNode.h b/gnu/llvm/lib/IR/AttributeSetNode.h index 23ce3713c20..fab1ed51e4d 100644 --- a/gnu/llvm/lib/IR/AttributeSetNode.h +++ b/gnu/llvm/lib/IR/AttributeSetNode.h @@ -15,17 +15,10 @@ #ifndef LLVM_IR_ATTRIBUTESETNODE_H #define LLVM_IR_ATTRIBUTESETNODE_H -#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/FoldingSet.h" -#include "llvm/ADT/Optional.h" -#include "llvm/ADT/StringRef.h" #include "llvm/IR/Attributes.h" #include "llvm/Support/TrailingObjects.h" -#include <algorithm> #include <climits> -#include <cstdint> -#include <string> -#include <utility> namespace llvm { @@ -56,11 +49,10 @@ class AttributeSetNode final } } -public: - // AttributesSetNode is uniqued, these should not be available. + // AttributesSetNode is uniqued, these should not be publicly available. + void operator=(const AttributeSetNode &) = delete; AttributeSetNode(const AttributeSetNode &) = delete; - AttributeSetNode &operator=(const AttributeSetNode &) = delete; - +public: void operator delete(void *p) { ::operator delete(p); } static AttributeSetNode *get(LLVMContext &C, ArrayRef<Attribute> Attrs); @@ -96,11 +88,11 @@ public: Profile(ID, makeArrayRef(begin(), end())); } static void Profile(FoldingSetNodeID &ID, ArrayRef<Attribute> AttrList) { - for (const auto &Attr : AttrList) - Attr.Profile(ID); + for (unsigned I = 0, E = AttrList.size(); I != E; ++I) + AttrList[I].Profile(ID); } }; -} // end namespace llvm +} // end llvm namespace -#endif // LLVM_IR_ATTRIBUTESETNODE_H +#endif diff --git a/gnu/llvm/lib/Object/ModuleSummaryIndexObjectFile.cpp b/gnu/llvm/lib/Object/ModuleSummaryIndexObjectFile.cpp index 11ace84b9ce..e6b1040d8f5 100644 --- a/gnu/llvm/lib/Object/ModuleSummaryIndexObjectFile.cpp +++ b/gnu/llvm/lib/Object/ModuleSummaryIndexObjectFile.cpp @@ -13,7 +13,7 @@ #include "llvm/Object/ModuleSummaryIndexObjectFile.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/Bitcode/BitcodeReader.h" +#include "llvm/Bitcode/ReaderWriter.h" #include "llvm/IR/ModuleSummaryIndex.h" #include "llvm/MC/MCStreamer.h" #include "llvm/Object/ObjectFile.h" @@ -22,12 +22,6 @@ using namespace llvm; using namespace object; -static llvm::cl::opt<bool> IgnoreEmptyThinLTOIndexFile( - "ignore-empty-index-file", llvm::cl::ZeroOrMore, - llvm::cl::desc( - "Ignore an empty index file and perform non-ThinLTO compilation"), - llvm::cl::init(false)); - ModuleSummaryIndexObjectFile::ModuleSummaryIndexObjectFile( MemoryBufferRef Object, std::unique_ptr<ModuleSummaryIndex> I) : SymbolicFile(Binary::ID_ModuleSummaryIndex, Object), Index(std::move(I)) { @@ -73,42 +67,59 @@ ModuleSummaryIndexObjectFile::findBitcodeInMemBuffer(MemoryBufferRef Object) { } } +// Looks for module summary index in the given memory buffer. +// returns true if found, else false. +bool ModuleSummaryIndexObjectFile::hasGlobalValueSummaryInMemBuffer( + MemoryBufferRef Object, + const DiagnosticHandlerFunction &DiagnosticHandler) { + ErrorOr<MemoryBufferRef> BCOrErr = findBitcodeInMemBuffer(Object); + if (!BCOrErr) + return false; + + return hasGlobalValueSummary(BCOrErr.get(), DiagnosticHandler); +} + // Parse module summary index in the given memory buffer. // Return new ModuleSummaryIndexObjectFile instance containing parsed // module summary/index. -Expected<std::unique_ptr<ModuleSummaryIndexObjectFile>> -ModuleSummaryIndexObjectFile::create(MemoryBufferRef Object) { +ErrorOr<std::unique_ptr<ModuleSummaryIndexObjectFile>> +ModuleSummaryIndexObjectFile::create( + MemoryBufferRef Object, + const DiagnosticHandlerFunction &DiagnosticHandler) { + std::unique_ptr<ModuleSummaryIndex> Index; + ErrorOr<MemoryBufferRef> BCOrErr = findBitcodeInMemBuffer(Object); if (!BCOrErr) - return errorCodeToError(BCOrErr.getError()); + return BCOrErr.getError(); - Expected<std::unique_ptr<ModuleSummaryIndex>> IOrErr = - getModuleSummaryIndex(BCOrErr.get()); + ErrorOr<std::unique_ptr<ModuleSummaryIndex>> IOrErr = + getModuleSummaryIndex(BCOrErr.get(), DiagnosticHandler); - if (!IOrErr) - return IOrErr.takeError(); + if (std::error_code EC = IOrErr.getError()) + return EC; + + Index = std::move(IOrErr.get()); - std::unique_ptr<ModuleSummaryIndex> Index = std::move(IOrErr.get()); return llvm::make_unique<ModuleSummaryIndexObjectFile>(Object, std::move(Index)); } // Parse the module summary index out of an IR file and return the summary // index object if found, or nullptr if not. -Expected<std::unique_ptr<ModuleSummaryIndex>> -llvm::getModuleSummaryIndexForFile(StringRef Path) { +ErrorOr<std::unique_ptr<ModuleSummaryIndex>> llvm::getModuleSummaryIndexForFile( + StringRef Path, const DiagnosticHandlerFunction &DiagnosticHandler) { ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr = MemoryBuffer::getFileOrSTDIN(Path); std::error_code EC = FileOrErr.getError(); if (EC) - return errorCodeToError(EC); + return EC; MemoryBufferRef BufferRef = (FileOrErr.get())->getMemBufferRef(); - if (IgnoreEmptyThinLTOIndexFile && !BufferRef.getBufferSize()) - return nullptr; - Expected<std::unique_ptr<object::ModuleSummaryIndexObjectFile>> ObjOrErr = - object::ModuleSummaryIndexObjectFile::create(BufferRef); - if (!ObjOrErr) - return ObjOrErr.takeError(); + ErrorOr<std::unique_ptr<object::ModuleSummaryIndexObjectFile>> ObjOrErr = + object::ModuleSummaryIndexObjectFile::create(BufferRef, + DiagnosticHandler); + EC = ObjOrErr.getError(); + if (EC) + return EC; object::ModuleSummaryIndexObjectFile &Obj = **ObjOrErr; return Obj.takeIndex(); diff --git a/gnu/llvm/lib/Target/AArch64/AArch64SchedVulcan.td b/gnu/llvm/lib/Target/AArch64/AArch64SchedVulcan.td index 35a40c314bf..0aa2462eba8 100644 --- a/gnu/llvm/lib/Target/AArch64/AArch64SchedVulcan.td +++ b/gnu/llvm/lib/Target/AArch64/AArch64SchedVulcan.td @@ -49,12 +49,15 @@ def VulcanP5 : ProcResource<1>; let SchedModel = VulcanModel in { -// Define groups for the functional units on each issue port. Each group -// created will be used by a WriteRes later on. +// Define groups for the functional units on each +// issue port. Each group created will be used +// by a WriteRes later on. // -// NOTE: Some groups only contain one member. This is a way to create names for -// the various functional units that share a single issue port. For example, -// "VulcanI1" for ALU ops on port 1 and "VulcanF1" for FP ops on port 1. +// NOTE: Some groups only contain one member. This +// is a way to create names for the various functional +// units that share a single issue port. For example, +// "VulcanI1" for ALU ops on port 1 and "VulcanF1" for +// FP ops on port 1. // Integer divide and multiply micro-ops only on port 1. def VulcanI1 : ProcResGroup<[VulcanP1]>; diff --git a/gnu/llvm/lib/Target/AMDGPU/AMDGPURuntimeMetadata.h b/gnu/llvm/lib/Target/AMDGPU/AMDGPURuntimeMetadata.h index ecd2ac72bf1..40f63943450 100644 --- a/gnu/llvm/lib/Target/AMDGPU/AMDGPURuntimeMetadata.h +++ b/gnu/llvm/lib/Target/AMDGPU/AMDGPURuntimeMetadata.h @@ -13,13 +13,18 @@ /// /// Runtime requests certain information (metadata) about kernels to be able /// to execute the kernels and answer the queries about the kernels. -/// The metadata is represented as a note element in the .note ELF section of a -/// binary (code object). The desc field of the note element is a YAML string -/// consisting of key-value pairs. Each key is a string. Each value can be -/// an integer, a string, or an YAML sequence. There are 3 levels of YAML maps. -/// At the beginning of the YAML string is the module level YAML map. A -/// kernel-level YAML map is in the amd.Kernels sequence. A -/// kernel-argument-level map is in the amd.Args sequence. +/// The metadata is represented as a byte stream in an ELF section of a +/// binary (code object). The byte stream consists of key-value pairs. +/// Each key is an 8 bit unsigned integer. Each value can be an integer, +/// a string, or a stream of key-value pairs. There are 3 levels of key-value +/// pair streams. At the beginning of the ELF section is the top level +/// key-value pair stream. A kernel-level key-value pair stream starts after +/// encountering KeyKernelBegin and ends immediately before encountering +/// KeyKernelEnd. A kernel-argument-level key-value pair stream starts +/// after encountering KeyArgBegin and ends immediately before encountering +/// KeyArgEnd. A kernel-level key-value pair stream can only appear in a top +/// level key-value pair stream. A kernel-argument-level key-value pair stream +/// can only appear in a kernel-level key-value pair stream. /// /// The format should be kept backward compatible. New enum values and bit /// fields should be appended at the end. It is suggested to bump up the @@ -32,64 +37,77 @@ #ifndef LLVM_LIB_TARGET_AMDGPU_AMDGPURUNTIMEMETADATA_H #define LLVM_LIB_TARGET_AMDGPU_AMDGPURUNTIMEMETADATA_H -#include <cstdint> -#include <vector> -#include <string> +#include <stdint.h> namespace AMDGPU { namespace RuntimeMD { // Version and revision of runtime metadata - const unsigned char MDVersion = 2; + const unsigned char MDVersion = 1; const unsigned char MDRevision = 0; - // Name of keys for runtime metadata. - namespace KeyName { - const char MDVersion[] = "amd.MDVersion"; // Runtime metadata version - const char Language[] = "amd.Language"; // Language - const char LanguageVersion[] = "amd.LanguageVersion"; // Language version - const char Kernels[] = "amd.Kernels"; // Kernels - const char KernelName[] = "amd.KernelName"; // Kernel name - const char Args[] = "amd.Args"; // Kernel arguments - const char ArgSize[] = "amd.ArgSize"; // Kernel arg size - const char ArgAlign[] = "amd.ArgAlign"; // Kernel arg alignment - const char ArgTypeName[] = "amd.ArgTypeName"; // Kernel type name - const char ArgName[] = "amd.ArgName"; // Kernel name - const char ArgKind[] = "amd.ArgKind"; // Kernel argument kind - const char ArgValueType[] = "amd.ArgValueType"; // Kernel argument value type - const char ArgAddrQual[] = "amd.ArgAddrQual"; // Kernel argument address qualifier - const char ArgAccQual[] = "amd.ArgAccQual"; // Kernel argument access qualifier - const char ArgIsConst[] = "amd.ArgIsConst"; // Kernel argument is const qualified - const char ArgIsRestrict[] = "amd.ArgIsRestrict"; // Kernel argument is restrict qualified - const char ArgIsVolatile[] = "amd.ArgIsVolatile"; // Kernel argument is volatile qualified - const char ArgIsPipe[] = "amd.ArgIsPipe"; // Kernel argument is pipe qualified - const char ReqdWorkGroupSize[] = "amd.ReqdWorkGroupSize"; // Required work group size - const char WorkGroupSizeHint[] = "amd.WorkGroupSizeHint"; // Work group size hint - const char VecTypeHint[] = "amd.VecTypeHint"; // Vector type hint - const char KernelIndex[] = "amd.KernelIndex"; // Kernel index for device enqueue - const char NoPartialWorkGroups[] = "amd.NoPartialWorkGroups"; // No partial work groups - const char PrintfInfo[] = "amd.PrintfInfo"; // Prinf function call information - const char ArgActualAcc[] = "amd.ArgActualAcc"; // The actual kernel argument access qualifier - const char ArgPointeeAlign[] = "amd.ArgPointeeAlign"; // Alignment of pointee type - } + // ELF section name containing runtime metadata + const char SectionName[] = ".AMDGPU.runtime_metadata"; + + // Enumeration values of keys in runtime metadata. + enum Key { + KeyNull = 0, // Place holder. Ignored when encountered + KeyMDVersion = 1, // Runtime metadata version + KeyLanguage = 2, // Language + KeyLanguageVersion = 3, // Language version + KeyKernelBegin = 4, // Beginning of kernel-level stream + KeyKernelEnd = 5, // End of kernel-level stream + KeyKernelName = 6, // Kernel name + KeyArgBegin = 7, // Beginning of kernel-arg-level stream + KeyArgEnd = 8, // End of kernel-arg-level stream + KeyArgSize = 9, // Kernel arg size + KeyArgAlign = 10, // Kernel arg alignment + KeyArgTypeName = 11, // Kernel type name + KeyArgName = 12, // Kernel name + KeyArgTypeKind = 13, // Kernel argument type kind + KeyArgValueType = 14, // Kernel argument value type + KeyArgAddrQual = 15, // Kernel argument address qualifier + KeyArgAccQual = 16, // Kernel argument access qualifier + KeyArgIsConst = 17, // Kernel argument is const qualified + KeyArgIsRestrict = 18, // Kernel argument is restrict qualified + KeyArgIsVolatile = 19, // Kernel argument is volatile qualified + KeyArgIsPipe = 20, // Kernel argument is pipe qualified + KeyReqdWorkGroupSize = 21, // Required work group size + KeyWorkGroupSizeHint = 22, // Work group size hint + KeyVecTypeHint = 23, // Vector type hint + KeyKernelIndex = 24, // Kernel index for device enqueue + KeySGPRs = 25, // Number of SGPRs + KeyVGPRs = 26, // Number of VGPRs + KeyMinWavesPerSIMD = 27, // Minimum number of waves per SIMD + KeyMaxWavesPerSIMD = 28, // Maximum number of waves per SIMD + KeyFlatWorkGroupSizeLimits = 29, // Flat work group size limits + KeyMaxWorkGroupSize = 30, // Maximum work group size + KeyNoPartialWorkGroups = 31, // No partial work groups + }; + + enum Language : uint8_t { + OpenCL_C = 0, + HCC = 1, + OpenMP = 2, + OpenCL_CPP = 3, +}; + + enum LanguageVersion : uint16_t { + V100 = 100, + V110 = 110, + V120 = 120, + V200 = 200, + V210 = 210, + }; namespace KernelArg { - enum Kind : uint8_t { - ByValue = 0, - GlobalBuffer = 1, - DynamicSharedPointer = 2, - Sampler = 3, - Image = 4, - Pipe = 5, - Queue = 6, - HiddenGlobalOffsetX = 7, - HiddenGlobalOffsetY = 8, - HiddenGlobalOffsetZ = 9, - HiddenNone = 10, - HiddenPrintfBuffer = 11, - HiddenDefaultQueue = 12, - HiddenCompletionAction = 13, + enum TypeKind : uint8_t { + Value = 0, + Pointer = 1, + Image = 2, + Sampler = 3, + Queue = 4, }; enum ValueType : uint16_t { @@ -107,86 +125,13 @@ namespace RuntimeMD { F64 = 11, }; - // Avoid using 'None' since it conflicts with a macro in X11 header file. enum AccessQualifer : uint8_t { - AccNone = 0, + None = 0, ReadOnly = 1, WriteOnly = 2, ReadWrite = 3, }; - - enum AddressSpaceQualifer : uint8_t { - Private = 0, - Global = 1, - Constant = 2, - Local = 3, - Generic = 4, - Region = 5, - }; } // namespace KernelArg - - // Invalid values are used to indicate an optional key should not be emitted. - const uint8_t INVALID_ADDR_QUAL = 0xff; - const uint8_t INVALID_ACC_QUAL = 0xff; - const uint32_t INVALID_KERNEL_INDEX = ~0U; - - namespace KernelArg { - // In-memory representation of kernel argument information. - struct Metadata { - uint32_t Size; - uint32_t Align; - uint32_t PointeeAlign; - uint8_t Kind; - uint16_t ValueType; - std::string TypeName; - std::string Name; - uint8_t AddrQual; - uint8_t AccQual; - uint8_t IsVolatile; - uint8_t IsConst; - uint8_t IsRestrict; - uint8_t IsPipe; - Metadata() : Size(0), Align(0), PointeeAlign(0), Kind(0), ValueType(0), - AddrQual(INVALID_ADDR_QUAL), AccQual(INVALID_ACC_QUAL), IsVolatile(0), - IsConst(0), IsRestrict(0), IsPipe(0) {} - }; - } - - namespace Kernel { - // In-memory representation of kernel information. - struct Metadata { - std::string Name; - std::string Language; - std::vector<uint8_t> LanguageVersion; - std::vector<uint32_t> ReqdWorkGroupSize; - std::vector<uint32_t> WorkGroupSizeHint; - std::string VecTypeHint; - uint32_t KernelIndex; - uint8_t NoPartialWorkGroups; - std::vector<KernelArg::Metadata> Args; - Metadata() : KernelIndex(INVALID_KERNEL_INDEX), NoPartialWorkGroups(0) {} - }; - } - - namespace Program { - // In-memory representation of program information. - struct Metadata { - std::vector<uint8_t> MDVersionSeq; - std::vector<std::string> PrintfInfo; - std::vector<Kernel::Metadata> Kernels; - - explicit Metadata(){} - - // Construct from an YAML string. - explicit Metadata(const std::string &YAML); - - // Convert to YAML string. - std::string toYAML(); - - // Convert from YAML string. - static Metadata fromYAML(const std::string &S); - }; - } } // namespace RuntimeMD } // namespace AMDGPU diff --git a/gnu/llvm/lib/Target/NVPTX/NVPTXInferAddressSpaces.cpp b/gnu/llvm/lib/Target/NVPTX/NVPTXInferAddressSpaces.cpp index f4940c937a2..e451d273cf4 100644 --- a/gnu/llvm/lib/Target/NVPTX/NVPTXInferAddressSpaces.cpp +++ b/gnu/llvm/lib/Target/NVPTX/NVPTXInferAddressSpaces.cpp @@ -87,6 +87,9 @@ // Finally, it fixes the undef in %y' so that // %y' = phi float addrspace(3)* [ %input, %y2' ] // +// TODO: This pass is experimental and not enabled by default. Users can turn it +// on by setting the -nvptx-use-infer-addrspace flag of llc. We plan to replace +// NVPTXNonFavorGenericAddrSpaces with this pass shortly. //===----------------------------------------------------------------------===// #define DEBUG_TYPE "nvptx-infer-addrspace" diff --git a/gnu/llvm/lib/Transforms/Utils/MemorySSA.cpp b/gnu/llvm/lib/Transforms/Utils/MemorySSA.cpp index 1ce4225f09c..8ba3cae43b1 100644 --- a/gnu/llvm/lib/Transforms/Utils/MemorySSA.cpp +++ b/gnu/llvm/lib/Transforms/Utils/MemorySSA.cpp @@ -17,7 +17,6 @@ #include "llvm/ADT/GraphTraits.h" #include "llvm/ADT/PostOrderIterator.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/Statistic.h" @@ -61,11 +60,6 @@ INITIALIZE_PASS_DEPENDENCY(MemorySSAWrapperPass) INITIALIZE_PASS_END(MemorySSAPrinterLegacyPass, "print-memoryssa", "Memory SSA Printer", false, false) -static cl::opt<unsigned> MaxCheckLimit( - "memssa-check-limit", cl::Hidden, cl::init(100), - cl::desc("The maximum number of stores/phis MemorySSA" - "will consider trying to walk past (default = 100)")); - static cl::opt<bool> VerifyMemorySSA("verify-memoryssa", cl::init(false), cl::Hidden, cl::desc("Verify MemorySSA in legacy printer pass.")); @@ -92,963 +86,7 @@ public: OS << "; " << *MA << "\n"; } }; -} - -namespace { -/// Our current alias analysis API differentiates heavily between calls and -/// non-calls, and functions called on one usually assert on the other. -/// This class encapsulates the distinction to simplify other code that wants -/// "Memory affecting instructions and related data" to use as a key. -/// For example, this class is used as a densemap key in the use optimizer. -class MemoryLocOrCall { -public: - MemoryLocOrCall() : IsCall(false) {} - MemoryLocOrCall(MemoryUseOrDef *MUD) - : MemoryLocOrCall(MUD->getMemoryInst()) {} - MemoryLocOrCall(const MemoryUseOrDef *MUD) - : MemoryLocOrCall(MUD->getMemoryInst()) {} - - MemoryLocOrCall(Instruction *Inst) { - if (ImmutableCallSite(Inst)) { - IsCall = true; - CS = ImmutableCallSite(Inst); - } else { - IsCall = false; - // There is no such thing as a memorylocation for a fence inst, and it is - // unique in that regard. - if (!isa<FenceInst>(Inst)) - Loc = MemoryLocation::get(Inst); - } - } - - explicit MemoryLocOrCall(const MemoryLocation &Loc) - : IsCall(false), Loc(Loc) {} - - bool IsCall; - ImmutableCallSite getCS() const { - assert(IsCall); - return CS; - } - MemoryLocation getLoc() const { - assert(!IsCall); - return Loc; - } - - bool operator==(const MemoryLocOrCall &Other) const { - if (IsCall != Other.IsCall) - return false; - - if (IsCall) - return CS.getCalledValue() == Other.CS.getCalledValue(); - return Loc == Other.Loc; - } - -private: - union { - ImmutableCallSite CS; - MemoryLocation Loc; - }; -}; -} - -namespace llvm { -template <> struct DenseMapInfo<MemoryLocOrCall> { - static inline MemoryLocOrCall getEmptyKey() { - return MemoryLocOrCall(DenseMapInfo<MemoryLocation>::getEmptyKey()); - } - static inline MemoryLocOrCall getTombstoneKey() { - return MemoryLocOrCall(DenseMapInfo<MemoryLocation>::getTombstoneKey()); - } - static unsigned getHashValue(const MemoryLocOrCall &MLOC) { - if (MLOC.IsCall) - return hash_combine(MLOC.IsCall, - DenseMapInfo<const Value *>::getHashValue( - MLOC.getCS().getCalledValue())); - return hash_combine( - MLOC.IsCall, DenseMapInfo<MemoryLocation>::getHashValue(MLOC.getLoc())); - } - static bool isEqual(const MemoryLocOrCall &LHS, const MemoryLocOrCall &RHS) { - return LHS == RHS; - } -}; - -enum class Reorderability { Always, IfNoAlias, Never }; - -/// This does one-way checks to see if Use could theoretically be hoisted above -/// MayClobber. This will not check the other way around. -/// -/// This assumes that, for the purposes of MemorySSA, Use comes directly after -/// MayClobber, with no potentially clobbering operations in between them. -/// (Where potentially clobbering ops are memory barriers, aliased stores, etc.) -static Reorderability getLoadReorderability(const LoadInst *Use, - const LoadInst *MayClobber) { - bool VolatileUse = Use->isVolatile(); - bool VolatileClobber = MayClobber->isVolatile(); - // Volatile operations may never be reordered with other volatile operations. - if (VolatileUse && VolatileClobber) - return Reorderability::Never; - - // The lang ref allows reordering of volatile and non-volatile operations. - // Whether an aliasing nonvolatile load and volatile load can be reordered, - // though, is ambiguous. Because it may not be best to exploit this ambiguity, - // we only allow volatile/non-volatile reordering if the volatile and - // non-volatile operations don't alias. - Reorderability Result = VolatileUse || VolatileClobber - ? Reorderability::IfNoAlias - : Reorderability::Always; - - // If a load is seq_cst, it cannot be moved above other loads. If its ordering - // is weaker, it can be moved above other loads. We just need to be sure that - // MayClobber isn't an acquire load, because loads can't be moved above - // acquire loads. - // - // Note that this explicitly *does* allow the free reordering of monotonic (or - // weaker) loads of the same address. - bool SeqCstUse = Use->getOrdering() == AtomicOrdering::SequentiallyConsistent; - bool MayClobberIsAcquire = isAtLeastOrStrongerThan(MayClobber->getOrdering(), - AtomicOrdering::Acquire); - if (SeqCstUse || MayClobberIsAcquire) - return Reorderability::Never; - return Result; -} - -static bool instructionClobbersQuery(MemoryDef *MD, - const MemoryLocation &UseLoc, - const Instruction *UseInst, - AliasAnalysis &AA) { - Instruction *DefInst = MD->getMemoryInst(); - assert(DefInst && "Defining instruction not actually an instruction"); - - if (const IntrinsicInst *II = dyn_cast<IntrinsicInst>(DefInst)) { - // These intrinsics will show up as affecting memory, but they are just - // markers. - switch (II->getIntrinsicID()) { - case Intrinsic::lifetime_start: - case Intrinsic::lifetime_end: - case Intrinsic::invariant_start: - case Intrinsic::invariant_end: - case Intrinsic::assume: - return false; - default: - break; - } - } - - ImmutableCallSite UseCS(UseInst); - if (UseCS) { - ModRefInfo I = AA.getModRefInfo(DefInst, UseCS); - return I != MRI_NoModRef; - } - - if (auto *DefLoad = dyn_cast<LoadInst>(DefInst)) { - if (auto *UseLoad = dyn_cast<LoadInst>(UseInst)) { - switch (getLoadReorderability(UseLoad, DefLoad)) { - case Reorderability::Always: - return false; - case Reorderability::Never: - return true; - case Reorderability::IfNoAlias: - return !AA.isNoAlias(UseLoc, MemoryLocation::get(DefLoad)); - } - } - } - - return AA.getModRefInfo(DefInst, UseLoc) & MRI_Mod; -} - -static bool instructionClobbersQuery(MemoryDef *MD, const MemoryUseOrDef *MU, - const MemoryLocOrCall &UseMLOC, - AliasAnalysis &AA) { - // FIXME: This is a temporary hack to allow a single instructionClobbersQuery - // to exist while MemoryLocOrCall is pushed through places. - if (UseMLOC.IsCall) - return instructionClobbersQuery(MD, MemoryLocation(), MU->getMemoryInst(), - AA); - return instructionClobbersQuery(MD, UseMLOC.getLoc(), MU->getMemoryInst(), - AA); -} - -// Return true when MD may alias MU, return false otherwise. -bool defClobbersUseOrDef(MemoryDef *MD, const MemoryUseOrDef *MU, - AliasAnalysis &AA) { - return instructionClobbersQuery(MD, MU, MemoryLocOrCall(MU), AA); -} -} - -namespace { -struct UpwardsMemoryQuery { - // True if our original query started off as a call - bool IsCall; - // The pointer location we started the query with. This will be empty if - // IsCall is true. - MemoryLocation StartingLoc; - // This is the instruction we were querying about. - const Instruction *Inst; - // The MemoryAccess we actually got called with, used to test local domination - const MemoryAccess *OriginalAccess; - - UpwardsMemoryQuery() - : IsCall(false), Inst(nullptr), OriginalAccess(nullptr) {} - - UpwardsMemoryQuery(const Instruction *Inst, const MemoryAccess *Access) - : IsCall(ImmutableCallSite(Inst)), Inst(Inst), OriginalAccess(Access) { - if (!IsCall) - StartingLoc = MemoryLocation::get(Inst); - } -}; - -static bool lifetimeEndsAt(MemoryDef *MD, const MemoryLocation &Loc, - AliasAnalysis &AA) { - Instruction *Inst = MD->getMemoryInst(); - if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(Inst)) { - switch (II->getIntrinsicID()) { - case Intrinsic::lifetime_start: - case Intrinsic::lifetime_end: - return AA.isMustAlias(MemoryLocation(II->getArgOperand(1)), Loc); - default: - return false; - } - } - return false; -} - -static bool isUseTriviallyOptimizableToLiveOnEntry(AliasAnalysis &AA, - const Instruction *I) { - // If the memory can't be changed, then loads of the memory can't be - // clobbered. - // - // FIXME: We should handle invariant groups, as well. It's a bit harder, - // because we need to pay close attention to invariant group barriers. - return isa<LoadInst>(I) && (I->getMetadata(LLVMContext::MD_invariant_load) || - AA.pointsToConstantMemory(I)); -} - -/// Cache for our caching MemorySSA walker. -class WalkerCache { - DenseMap<ConstMemoryAccessPair, MemoryAccess *> Accesses; - DenseMap<const MemoryAccess *, MemoryAccess *> Calls; - -public: - MemoryAccess *lookup(const MemoryAccess *MA, const MemoryLocation &Loc, - bool IsCall) const { - ++NumClobberCacheLookups; - MemoryAccess *R = IsCall ? Calls.lookup(MA) : Accesses.lookup({MA, Loc}); - if (R) - ++NumClobberCacheHits; - return R; - } - - bool insert(const MemoryAccess *MA, MemoryAccess *To, - const MemoryLocation &Loc, bool IsCall) { - // This is fine for Phis, since there are times where we can't optimize - // them. Making a def its own clobber is never correct, though. - assert((MA != To || isa<MemoryPhi>(MA)) && - "Something can't clobber itself!"); - - ++NumClobberCacheInserts; - bool Inserted; - if (IsCall) - Inserted = Calls.insert({MA, To}).second; - else - Inserted = Accesses.insert({{MA, Loc}, To}).second; - - return Inserted; - } - - bool remove(const MemoryAccess *MA, const MemoryLocation &Loc, bool IsCall) { - return IsCall ? Calls.erase(MA) : Accesses.erase({MA, Loc}); - } - - void clear() { - Accesses.clear(); - Calls.clear(); - } - - bool contains(const MemoryAccess *MA) const { - for (auto &P : Accesses) - if (P.first.first == MA || P.second == MA) - return true; - for (auto &P : Calls) - if (P.first == MA || P.second == MA) - return true; - return false; - } -}; - -/// Walks the defining uses of MemoryDefs. Stops after we hit something that has -/// no defining use (e.g. a MemoryPhi or liveOnEntry). Note that, when comparing -/// against a null def_chain_iterator, this will compare equal only after -/// walking said Phi/liveOnEntry. -struct def_chain_iterator - : public iterator_facade_base<def_chain_iterator, std::forward_iterator_tag, - MemoryAccess *> { - def_chain_iterator() : MA(nullptr) {} - def_chain_iterator(MemoryAccess *MA) : MA(MA) {} - - MemoryAccess *operator*() const { return MA; } - - def_chain_iterator &operator++() { - // N.B. liveOnEntry has a null defining access. - if (auto *MUD = dyn_cast<MemoryUseOrDef>(MA)) - MA = MUD->getDefiningAccess(); - else - MA = nullptr; - return *this; - } - - bool operator==(const def_chain_iterator &O) const { return MA == O.MA; } - -private: - MemoryAccess *MA; -}; - -static iterator_range<def_chain_iterator> -def_chain(MemoryAccess *MA, MemoryAccess *UpTo = nullptr) { -#ifdef EXPENSIVE_CHECKS - assert((!UpTo || find(def_chain(MA), UpTo) != def_chain_iterator()) && - "UpTo isn't in the def chain!"); -#endif - return make_range(def_chain_iterator(MA), def_chain_iterator(UpTo)); -} - -/// Verifies that `Start` is clobbered by `ClobberAt`, and that nothing -/// inbetween `Start` and `ClobberAt` can clobbers `Start`. -/// -/// This is meant to be as simple and self-contained as possible. Because it -/// uses no cache, etc., it can be relatively expensive. -/// -/// \param Start The MemoryAccess that we want to walk from. -/// \param ClobberAt A clobber for Start. -/// \param StartLoc The MemoryLocation for Start. -/// \param MSSA The MemorySSA isntance that Start and ClobberAt belong to. -/// \param Query The UpwardsMemoryQuery we used for our search. -/// \param AA The AliasAnalysis we used for our search. -static void LLVM_ATTRIBUTE_UNUSED -checkClobberSanity(MemoryAccess *Start, MemoryAccess *ClobberAt, - const MemoryLocation &StartLoc, const MemorySSA &MSSA, - const UpwardsMemoryQuery &Query, AliasAnalysis &AA) { - assert(MSSA.dominates(ClobberAt, Start) && "Clobber doesn't dominate start?"); - - if (MSSA.isLiveOnEntryDef(Start)) { - assert(MSSA.isLiveOnEntryDef(ClobberAt) && - "liveOnEntry must clobber itself"); - return; - } - - bool FoundClobber = false; - DenseSet<MemoryAccessPair> VisitedPhis; - SmallVector<MemoryAccessPair, 8> Worklist; - Worklist.emplace_back(Start, StartLoc); - // Walk all paths from Start to ClobberAt, while looking for clobbers. If one - // is found, complain. - while (!Worklist.empty()) { - MemoryAccessPair MAP = Worklist.pop_back_val(); - // All we care about is that nothing from Start to ClobberAt clobbers Start. - // We learn nothing from revisiting nodes. - if (!VisitedPhis.insert(MAP).second) - continue; - - for (MemoryAccess *MA : def_chain(MAP.first)) { - if (MA == ClobberAt) { - if (auto *MD = dyn_cast<MemoryDef>(MA)) { - // instructionClobbersQuery isn't essentially free, so don't use `|=`, - // since it won't let us short-circuit. - // - // Also, note that this can't be hoisted out of the `Worklist` loop, - // since MD may only act as a clobber for 1 of N MemoryLocations. - FoundClobber = - FoundClobber || MSSA.isLiveOnEntryDef(MD) || - instructionClobbersQuery(MD, MAP.second, Query.Inst, AA); - } - break; - } - - // We should never hit liveOnEntry, unless it's the clobber. - assert(!MSSA.isLiveOnEntryDef(MA) && "Hit liveOnEntry before clobber?"); - - if (auto *MD = dyn_cast<MemoryDef>(MA)) { - (void)MD; - assert(!instructionClobbersQuery(MD, MAP.second, Query.Inst, AA) && - "Found clobber before reaching ClobberAt!"); - continue; - } - - assert(isa<MemoryPhi>(MA)); - Worklist.append(upward_defs_begin({MA, MAP.second}), upward_defs_end()); - } - } - - // If ClobberAt is a MemoryPhi, we can assume something above it acted as a - // clobber. Otherwise, `ClobberAt` should've acted as a clobber at some point. - assert((isa<MemoryPhi>(ClobberAt) || FoundClobber) && - "ClobberAt never acted as a clobber"); -} - -/// Our algorithm for walking (and trying to optimize) clobbers, all wrapped up -/// in one class. -class ClobberWalker { - /// Save a few bytes by using unsigned instead of size_t. - using ListIndex = unsigned; - - /// Represents a span of contiguous MemoryDefs, potentially ending in a - /// MemoryPhi. - struct DefPath { - MemoryLocation Loc; - // Note that, because we always walk in reverse, Last will always dominate - // First. Also note that First and Last are inclusive. - MemoryAccess *First; - MemoryAccess *Last; - Optional<ListIndex> Previous; - - DefPath(const MemoryLocation &Loc, MemoryAccess *First, MemoryAccess *Last, - Optional<ListIndex> Previous) - : Loc(Loc), First(First), Last(Last), Previous(Previous) {} - - DefPath(const MemoryLocation &Loc, MemoryAccess *Init, - Optional<ListIndex> Previous) - : DefPath(Loc, Init, Init, Previous) {} - }; - - const MemorySSA &MSSA; - AliasAnalysis &AA; - DominatorTree &DT; - WalkerCache &WC; - UpwardsMemoryQuery *Query; - bool UseCache; - - // Phi optimization bookkeeping - SmallVector<DefPath, 32> Paths; - DenseSet<ConstMemoryAccessPair> VisitedPhis; - DenseMap<const BasicBlock *, MemoryAccess *> WalkTargetCache; - - void setUseCache(bool Use) { UseCache = Use; } - bool shouldIgnoreCache() const { - // UseCache will only be false when we're debugging, or when expensive - // checks are enabled. In either case, we don't care deeply about speed. - return LLVM_UNLIKELY(!UseCache); - } - - void addCacheEntry(const MemoryAccess *What, MemoryAccess *To, - const MemoryLocation &Loc) const { -// EXPENSIVE_CHECKS because most of these queries are redundant. -#ifdef EXPENSIVE_CHECKS - assert(MSSA.dominates(To, What)); -#endif - if (shouldIgnoreCache()) - return; - WC.insert(What, To, Loc, Query->IsCall); - } - - MemoryAccess *lookupCache(const MemoryAccess *MA, const MemoryLocation &Loc) { - return shouldIgnoreCache() ? nullptr : WC.lookup(MA, Loc, Query->IsCall); - } - - void cacheDefPath(const DefPath &DN, MemoryAccess *Target) const { - if (shouldIgnoreCache()) - return; - - for (MemoryAccess *MA : def_chain(DN.First, DN.Last)) - addCacheEntry(MA, Target, DN.Loc); - - // DefPaths only express the path we walked. So, DN.Last could either be a - // thing we want to cache, or not. - if (DN.Last != Target) - addCacheEntry(DN.Last, Target, DN.Loc); - } - - /// Find the nearest def or phi that `From` can legally be optimized to. - /// - /// FIXME: Deduplicate this with MSSA::findDominatingDef. Ideally, MSSA should - /// keep track of this information for us, and allow us O(1) lookups of this - /// info. - MemoryAccess *getWalkTarget(const MemoryPhi *From) { - assert(From->getNumOperands() && "Phi with no operands?"); - - BasicBlock *BB = From->getBlock(); - auto At = WalkTargetCache.find(BB); - if (At != WalkTargetCache.end()) - return At->second; - - SmallVector<const BasicBlock *, 8> ToCache; - ToCache.push_back(BB); - - MemoryAccess *Result = MSSA.getLiveOnEntryDef(); - DomTreeNode *Node = DT.getNode(BB); - while ((Node = Node->getIDom())) { - auto At = WalkTargetCache.find(BB); - if (At != WalkTargetCache.end()) { - Result = At->second; - break; - } - - auto *Accesses = MSSA.getBlockAccesses(Node->getBlock()); - if (Accesses) { - auto Iter = find_if(reverse(*Accesses), [](const MemoryAccess &MA) { - return !isa<MemoryUse>(MA); - }); - if (Iter != Accesses->rend()) { - Result = const_cast<MemoryAccess *>(&*Iter); - break; - } - } - - ToCache.push_back(Node->getBlock()); - } - - for (const BasicBlock *BB : ToCache) - WalkTargetCache.insert({BB, Result}); - return Result; - } - - /// Result of calling walkToPhiOrClobber. - struct UpwardsWalkResult { - /// The "Result" of the walk. Either a clobber, the last thing we walked, or - /// both. - MemoryAccess *Result; - bool IsKnownClobber; - bool FromCache; - }; - - /// Walk to the next Phi or Clobber in the def chain starting at Desc.Last. - /// This will update Desc.Last as it walks. It will (optionally) also stop at - /// StopAt. - /// - /// This does not test for whether StopAt is a clobber - UpwardsWalkResult walkToPhiOrClobber(DefPath &Desc, - MemoryAccess *StopAt = nullptr) { - assert(!isa<MemoryUse>(Desc.Last) && "Uses don't exist in my world"); - - for (MemoryAccess *Current : def_chain(Desc.Last)) { - Desc.Last = Current; - if (Current == StopAt) - return {Current, false, false}; - - if (auto *MD = dyn_cast<MemoryDef>(Current)) - if (MSSA.isLiveOnEntryDef(MD) || - instructionClobbersQuery(MD, Desc.Loc, Query->Inst, AA)) - return {MD, true, false}; - - // Cache checks must be done last, because if Current is a clobber, the - // cache will contain the clobber for Current. - if (MemoryAccess *MA = lookupCache(Current, Desc.Loc)) - return {MA, true, true}; - } - - assert(isa<MemoryPhi>(Desc.Last) && - "Ended at a non-clobber that's not a phi?"); - return {Desc.Last, false, false}; - } - - void addSearches(MemoryPhi *Phi, SmallVectorImpl<ListIndex> &PausedSearches, - ListIndex PriorNode) { - auto UpwardDefs = make_range(upward_defs_begin({Phi, Paths[PriorNode].Loc}), - upward_defs_end()); - for (const MemoryAccessPair &P : UpwardDefs) { - PausedSearches.push_back(Paths.size()); - Paths.emplace_back(P.second, P.first, PriorNode); - } - } - - /// Represents a search that terminated after finding a clobber. This clobber - /// may or may not be present in the path of defs from LastNode..SearchStart, - /// since it may have been retrieved from cache. - struct TerminatedPath { - MemoryAccess *Clobber; - ListIndex LastNode; - }; - - /// Get an access that keeps us from optimizing to the given phi. - /// - /// PausedSearches is an array of indices into the Paths array. Its incoming - /// value is the indices of searches that stopped at the last phi optimization - /// target. It's left in an unspecified state. - /// - /// If this returns None, NewPaused is a vector of searches that terminated - /// at StopWhere. Otherwise, NewPaused is left in an unspecified state. - Optional<TerminatedPath> - getBlockingAccess(MemoryAccess *StopWhere, - SmallVectorImpl<ListIndex> &PausedSearches, - SmallVectorImpl<ListIndex> &NewPaused, - SmallVectorImpl<TerminatedPath> &Terminated) { - assert(!PausedSearches.empty() && "No searches to continue?"); - - // BFS vs DFS really doesn't make a difference here, so just do a DFS with - // PausedSearches as our stack. - while (!PausedSearches.empty()) { - ListIndex PathIndex = PausedSearches.pop_back_val(); - DefPath &Node = Paths[PathIndex]; - - // If we've already visited this path with this MemoryLocation, we don't - // need to do so again. - // - // NOTE: That we just drop these paths on the ground makes caching - // behavior sporadic. e.g. given a diamond: - // A - // B C - // D - // - // ...If we walk D, B, A, C, we'll only cache the result of phi - // optimization for A, B, and D; C will be skipped because it dies here. - // This arguably isn't the worst thing ever, since: - // - We generally query things in a top-down order, so if we got below D - // without needing cache entries for {C, MemLoc}, then chances are - // that those cache entries would end up ultimately unused. - // - We still cache things for A, so C only needs to walk up a bit. - // If this behavior becomes problematic, we can fix without a ton of extra - // work. - if (!VisitedPhis.insert({Node.Last, Node.Loc}).second) - continue; - - UpwardsWalkResult Res = walkToPhiOrClobber(Node, /*StopAt=*/StopWhere); - if (Res.IsKnownClobber) { - assert(Res.Result != StopWhere || Res.FromCache); - // If this wasn't a cache hit, we hit a clobber when walking. That's a - // failure. - TerminatedPath Term{Res.Result, PathIndex}; - if (!Res.FromCache || !MSSA.dominates(Res.Result, StopWhere)) - return Term; - - // Otherwise, it's a valid thing to potentially optimize to. - Terminated.push_back(Term); - continue; - } - - if (Res.Result == StopWhere) { - // We've hit our target. Save this path off for if we want to continue - // walking. - NewPaused.push_back(PathIndex); - continue; - } - - assert(!MSSA.isLiveOnEntryDef(Res.Result) && "liveOnEntry is a clobber"); - addSearches(cast<MemoryPhi>(Res.Result), PausedSearches, PathIndex); - } - - return None; - } - - template <typename T, typename Walker> - struct generic_def_path_iterator - : public iterator_facade_base<generic_def_path_iterator<T, Walker>, - std::forward_iterator_tag, T *> { - generic_def_path_iterator() : W(nullptr), N(None) {} - generic_def_path_iterator(Walker *W, ListIndex N) : W(W), N(N) {} - - T &operator*() const { return curNode(); } - - generic_def_path_iterator &operator++() { - N = curNode().Previous; - return *this; - } - - bool operator==(const generic_def_path_iterator &O) const { - if (N.hasValue() != O.N.hasValue()) - return false; - return !N.hasValue() || *N == *O.N; - } - - private: - T &curNode() const { return W->Paths[*N]; } - - Walker *W; - Optional<ListIndex> N; - }; - - using def_path_iterator = generic_def_path_iterator<DefPath, ClobberWalker>; - using const_def_path_iterator = - generic_def_path_iterator<const DefPath, const ClobberWalker>; - - iterator_range<def_path_iterator> def_path(ListIndex From) { - return make_range(def_path_iterator(this, From), def_path_iterator()); - } - - iterator_range<const_def_path_iterator> const_def_path(ListIndex From) const { - return make_range(const_def_path_iterator(this, From), - const_def_path_iterator()); - } - - struct OptznResult { - /// The path that contains our result. - TerminatedPath PrimaryClobber; - /// The paths that we can legally cache back from, but that aren't - /// necessarily the result of the Phi optimization. - SmallVector<TerminatedPath, 4> OtherClobbers; - }; - - ListIndex defPathIndex(const DefPath &N) const { - // The assert looks nicer if we don't need to do &N - const DefPath *NP = &N; - assert(!Paths.empty() && NP >= &Paths.front() && NP <= &Paths.back() && - "Out of bounds DefPath!"); - return NP - &Paths.front(); - } - - /// Try to optimize a phi as best as we can. Returns a SmallVector of Paths - /// that act as legal clobbers. Note that this won't return *all* clobbers. - /// - /// Phi optimization algorithm tl;dr: - /// - Find the earliest def/phi, A, we can optimize to - /// - Find if all paths from the starting memory access ultimately reach A - /// - If not, optimization isn't possible. - /// - Otherwise, walk from A to another clobber or phi, A'. - /// - If A' is a def, we're done. - /// - If A' is a phi, try to optimize it. - /// - /// A path is a series of {MemoryAccess, MemoryLocation} pairs. A path - /// terminates when a MemoryAccess that clobbers said MemoryLocation is found. - OptznResult tryOptimizePhi(MemoryPhi *Phi, MemoryAccess *Start, - const MemoryLocation &Loc) { - assert(Paths.empty() && VisitedPhis.empty() && - "Reset the optimization state."); - - Paths.emplace_back(Loc, Start, Phi, None); - // Stores how many "valid" optimization nodes we had prior to calling - // addSearches/getBlockingAccess. Necessary for caching if we had a blocker. - auto PriorPathsSize = Paths.size(); - - SmallVector<ListIndex, 16> PausedSearches; - SmallVector<ListIndex, 8> NewPaused; - SmallVector<TerminatedPath, 4> TerminatedPaths; - - addSearches(Phi, PausedSearches, 0); - - // Moves the TerminatedPath with the "most dominated" Clobber to the end of - // Paths. - auto MoveDominatedPathToEnd = [&](SmallVectorImpl<TerminatedPath> &Paths) { - assert(!Paths.empty() && "Need a path to move"); - auto Dom = Paths.begin(); - for (auto I = std::next(Dom), E = Paths.end(); I != E; ++I) - if (!MSSA.dominates(I->Clobber, Dom->Clobber)) - Dom = I; - auto Last = Paths.end() - 1; - if (Last != Dom) - std::iter_swap(Last, Dom); - }; - - MemoryPhi *Current = Phi; - while (1) { - assert(!MSSA.isLiveOnEntryDef(Current) && - "liveOnEntry wasn't treated as a clobber?"); - - MemoryAccess *Target = getWalkTarget(Current); - // If a TerminatedPath doesn't dominate Target, then it wasn't a legal - // optimization for the prior phi. - assert(all_of(TerminatedPaths, [&](const TerminatedPath &P) { - return MSSA.dominates(P.Clobber, Target); - })); - - // FIXME: This is broken, because the Blocker may be reported to be - // liveOnEntry, and we'll happily wait for that to disappear (read: never) - // For the moment, this is fine, since we do nothing with blocker info. - if (Optional<TerminatedPath> Blocker = getBlockingAccess( - Target, PausedSearches, NewPaused, TerminatedPaths)) { - // Cache our work on the blocking node, since we know that's correct. - cacheDefPath(Paths[Blocker->LastNode], Blocker->Clobber); - - // Find the node we started at. We can't search based on N->Last, since - // we may have gone around a loop with a different MemoryLocation. - auto Iter = find_if(def_path(Blocker->LastNode), [&](const DefPath &N) { - return defPathIndex(N) < PriorPathsSize; - }); - assert(Iter != def_path_iterator()); - - DefPath &CurNode = *Iter; - assert(CurNode.Last == Current); - - // Two things: - // A. We can't reliably cache all of NewPaused back. Consider a case - // where we have two paths in NewPaused; one of which can't optimize - // above this phi, whereas the other can. If we cache the second path - // back, we'll end up with suboptimal cache entries. We can handle - // cases like this a bit better when we either try to find all - // clobbers that block phi optimization, or when our cache starts - // supporting unfinished searches. - // B. We can't reliably cache TerminatedPaths back here without doing - // extra checks; consider a case like: - // T - // / \ - // D C - // \ / - // S - // Where T is our target, C is a node with a clobber on it, D is a - // diamond (with a clobber *only* on the left or right node, N), and - // S is our start. Say we walk to D, through the node opposite N - // (read: ignoring the clobber), and see a cache entry in the top - // node of D. That cache entry gets put into TerminatedPaths. We then - // walk up to C (N is later in our worklist), find the clobber, and - // quit. If we append TerminatedPaths to OtherClobbers, we'll cache - // the bottom part of D to the cached clobber, ignoring the clobber - // in N. Again, this problem goes away if we start tracking all - // blockers for a given phi optimization. - TerminatedPath Result{CurNode.Last, defPathIndex(CurNode)}; - return {Result, {}}; - } - - // If there's nothing left to search, then all paths led to valid clobbers - // that we got from our cache; pick the nearest to the start, and allow - // the rest to be cached back. - if (NewPaused.empty()) { - MoveDominatedPathToEnd(TerminatedPaths); - TerminatedPath Result = TerminatedPaths.pop_back_val(); - return {Result, std::move(TerminatedPaths)}; - } - - MemoryAccess *DefChainEnd = nullptr; - SmallVector<TerminatedPath, 4> Clobbers; - for (ListIndex Paused : NewPaused) { - UpwardsWalkResult WR = walkToPhiOrClobber(Paths[Paused]); - if (WR.IsKnownClobber) - Clobbers.push_back({WR.Result, Paused}); - else - // Micro-opt: If we hit the end of the chain, save it. - DefChainEnd = WR.Result; - } - - if (!TerminatedPaths.empty()) { - // If we couldn't find the dominating phi/liveOnEntry in the above loop, - // do it now. - if (!DefChainEnd) - for (MemoryAccess *MA : def_chain(Target)) - DefChainEnd = MA; - - // If any of the terminated paths don't dominate the phi we'll try to - // optimize, we need to figure out what they are and quit. - const BasicBlock *ChainBB = DefChainEnd->getBlock(); - for (const TerminatedPath &TP : TerminatedPaths) { - // Because we know that DefChainEnd is as "high" as we can go, we - // don't need local dominance checks; BB dominance is sufficient. - if (DT.dominates(ChainBB, TP.Clobber->getBlock())) - Clobbers.push_back(TP); - } - } - - // If we have clobbers in the def chain, find the one closest to Current - // and quit. - if (!Clobbers.empty()) { - MoveDominatedPathToEnd(Clobbers); - TerminatedPath Result = Clobbers.pop_back_val(); - return {Result, std::move(Clobbers)}; - } - - assert(all_of(NewPaused, - [&](ListIndex I) { return Paths[I].Last == DefChainEnd; })); - - // Because liveOnEntry is a clobber, this must be a phi. - auto *DefChainPhi = cast<MemoryPhi>(DefChainEnd); - - PriorPathsSize = Paths.size(); - PausedSearches.clear(); - for (ListIndex I : NewPaused) - addSearches(DefChainPhi, PausedSearches, I); - NewPaused.clear(); - - Current = DefChainPhi; - } - } - - /// Caches everything in an OptznResult. - void cacheOptResult(const OptznResult &R) { - if (R.OtherClobbers.empty()) { - // If we're not going to be caching OtherClobbers, don't bother with - // marking visited/etc. - for (const DefPath &N : const_def_path(R.PrimaryClobber.LastNode)) - cacheDefPath(N, R.PrimaryClobber.Clobber); - return; - } - - // PrimaryClobber is our answer. If we can cache anything back, we need to - // stop caching when we visit PrimaryClobber. - SmallBitVector Visited(Paths.size()); - for (const DefPath &N : const_def_path(R.PrimaryClobber.LastNode)) { - Visited[defPathIndex(N)] = true; - cacheDefPath(N, R.PrimaryClobber.Clobber); - } - - for (const TerminatedPath &P : R.OtherClobbers) { - for (const DefPath &N : const_def_path(P.LastNode)) { - ListIndex NIndex = defPathIndex(N); - if (Visited[NIndex]) - break; - Visited[NIndex] = true; - cacheDefPath(N, P.Clobber); - } - } - } - - void verifyOptResult(const OptznResult &R) const { - assert(all_of(R.OtherClobbers, [&](const TerminatedPath &P) { - return MSSA.dominates(P.Clobber, R.PrimaryClobber.Clobber); - })); - } - - void resetPhiOptznState() { - Paths.clear(); - VisitedPhis.clear(); - } - -public: - ClobberWalker(const MemorySSA &MSSA, AliasAnalysis &AA, DominatorTree &DT, - WalkerCache &WC) - : MSSA(MSSA), AA(AA), DT(DT), WC(WC), UseCache(true) {} - - void reset() { WalkTargetCache.clear(); } - - /// Finds the nearest clobber for the given query, optimizing phis if - /// possible. - MemoryAccess *findClobber(MemoryAccess *Start, UpwardsMemoryQuery &Q, - bool UseWalkerCache = true) { - setUseCache(UseWalkerCache); - Query = &Q; - - MemoryAccess *Current = Start; - // This walker pretends uses don't exist. If we're handed one, silently grab - // its def. (This has the nice side-effect of ensuring we never cache uses) - if (auto *MU = dyn_cast<MemoryUse>(Start)) - Current = MU->getDefiningAccess(); - - DefPath FirstDesc(Q.StartingLoc, Current, Current, None); - // Fast path for the overly-common case (no crazy phi optimization - // necessary) - UpwardsWalkResult WalkResult = walkToPhiOrClobber(FirstDesc); - MemoryAccess *Result; - if (WalkResult.IsKnownClobber) { - cacheDefPath(FirstDesc, WalkResult.Result); - Result = WalkResult.Result; - } else { - OptznResult OptRes = tryOptimizePhi(cast<MemoryPhi>(FirstDesc.Last), - Current, Q.StartingLoc); - verifyOptResult(OptRes); - cacheOptResult(OptRes); - resetPhiOptznState(); - Result = OptRes.PrimaryClobber.Clobber; - } - -#ifdef EXPENSIVE_CHECKS - checkClobberSanity(Current, Result, Q.StartingLoc, MSSA, Q, AA); -#endif - return Result; - } - - void verify(const MemorySSA *MSSA) { assert(MSSA == &this->MSSA); } -}; - -struct RenamePassData { - DomTreeNode *DTN; - DomTreeNode::const_iterator ChildIt; - MemoryAccess *IncomingVal; - - RenamePassData(DomTreeNode *D, DomTreeNode::const_iterator It, - MemoryAccess *M) - : DTN(D), ChildIt(It), IncomingVal(M) {} - void swap(RenamePassData &RHS) { - std::swap(DTN, RHS.DTN); - std::swap(ChildIt, RHS.ChildIt); - std::swap(IncomingVal, RHS.IncomingVal); - } -}; -} // anonymous namespace -namespace llvm { /// \brief A MemorySSAWalker that does AA walks and caching of lookups to /// disambiguate accesses. /// @@ -1083,39 +121,59 @@ namespace llvm { /// ret i32 %r /// } class MemorySSA::CachingWalker final : public MemorySSAWalker { - WalkerCache Cache; - ClobberWalker Walker; - bool AutoResetWalker; - - MemoryAccess *getClobberingMemoryAccess(MemoryAccess *, UpwardsMemoryQuery &); - void verifyRemoved(MemoryAccess *); - public: CachingWalker(MemorySSA *, AliasAnalysis *, DominatorTree *); ~CachingWalker() override; - using MemorySSAWalker::getClobberingMemoryAccess; - MemoryAccess *getClobberingMemoryAccess(MemoryAccess *) override; + MemoryAccess *getClobberingMemoryAccess(const Instruction *) override; MemoryAccess *getClobberingMemoryAccess(MemoryAccess *, - const MemoryLocation &) override; + MemoryLocation &) override; void invalidateInfo(MemoryAccess *) override; - /// Whether we call resetClobberWalker() after each time we *actually* walk to - /// answer a clobber query. - void setAutoResetWalker(bool AutoReset) { AutoResetWalker = AutoReset; } +protected: + struct UpwardsMemoryQuery; + MemoryAccess *doCacheLookup(const MemoryAccess *, const UpwardsMemoryQuery &, + const MemoryLocation &); + + void doCacheInsert(const MemoryAccess *, MemoryAccess *, + const UpwardsMemoryQuery &, const MemoryLocation &); - /// Drop the walker's persistent data structures. At the moment, this means - /// "drop the walker's cache of BasicBlocks -> - /// earliest-MemoryAccess-we-can-optimize-to". This is necessary if we're - /// going to have DT updates, if we remove MemoryAccesses, etc. - void resetClobberWalker() { Walker.reset(); } + void doCacheRemove(const MemoryAccess *, const UpwardsMemoryQuery &, + const MemoryLocation &); - void verify(const MemorySSA *MSSA) override { - MemorySSAWalker::verify(MSSA); - Walker.verify(MSSA); +private: + MemoryAccessPair UpwardsDFSWalk(MemoryAccess *, const MemoryLocation &, + UpwardsMemoryQuery &, bool); + MemoryAccess *getClobberingMemoryAccess(MemoryAccess *, UpwardsMemoryQuery &); + bool instructionClobbersQuery(const MemoryDef *, UpwardsMemoryQuery &, + const MemoryLocation &Loc) const; + void verifyRemoved(MemoryAccess *); + SmallDenseMap<ConstMemoryAccessPair, MemoryAccess *> + CachedUpwardsClobberingAccess; + DenseMap<const MemoryAccess *, MemoryAccess *> CachedUpwardsClobberingCall; + AliasAnalysis *AA; + DominatorTree *DT; +}; +} + +namespace { +struct RenamePassData { + DomTreeNode *DTN; + DomTreeNode::const_iterator ChildIt; + MemoryAccess *IncomingVal; + + RenamePassData(DomTreeNode *D, DomTreeNode::const_iterator It, + MemoryAccess *M) + : DTN(D), ChildIt(It), IncomingVal(M) {} + void swap(RenamePassData &RHS) { + std::swap(DTN, RHS.DTN); + std::swap(ChildIt, RHS.ChildIt); + std::swap(IncomingVal, RHS.IncomingVal); } }; +} +namespace llvm { /// \brief Rename a single basic block into MemorySSA form. /// Uses the standard SSA renaming algorithm. /// \returns The new incoming value. @@ -1126,13 +184,21 @@ MemoryAccess *MemorySSA::renameBlock(BasicBlock *BB, if (It != PerBlockAccesses.end()) { AccessList *Accesses = It->second.get(); for (MemoryAccess &L : *Accesses) { - if (MemoryUseOrDef *MUD = dyn_cast<MemoryUseOrDef>(&L)) { - if (MUD->getDefiningAccess() == nullptr) - MUD->setDefiningAccess(IncomingVal); - if (isa<MemoryDef>(&L)) - IncomingVal = &L; - } else { + switch (L.getValueID()) { + case Value::MemoryUseVal: + cast<MemoryUse>(&L)->setDefiningAccess(IncomingVal); + break; + case Value::MemoryDefVal: + // We can't legally optimize defs, because we only allow single + // memory phis/uses on operations, and if we optimize these, we can + // end up with multiple reaching defs. Uses do not have this + // problem, since they do not produce a value + cast<MemoryDef>(&L)->setDefiningAccess(IncomingVal); IncomingVal = &L; + break; + case Value::MemoryPhiVal: + IncomingVal = &L; + break; } } } @@ -1229,10 +295,21 @@ void MemorySSA::markUnreachableAsLiveOnEntry(BasicBlock *BB) { MemorySSA::MemorySSA(Function &Func, AliasAnalysis *AA, DominatorTree *DT) : AA(AA), DT(DT), F(Func), LiveOnEntryDef(nullptr), Walker(nullptr), - NextID(INVALID_MEMORYACCESS_ID) { + NextID(0) { buildMemorySSA(); } +MemorySSA::MemorySSA(MemorySSA &&MSSA) + : AA(MSSA.AA), DT(MSSA.DT), F(MSSA.F), + ValueToMemoryAccess(std::move(MSSA.ValueToMemoryAccess)), + PerBlockAccesses(std::move(MSSA.PerBlockAccesses)), + LiveOnEntryDef(std::move(MSSA.LiveOnEntryDef)), + Walker(std::move(MSSA.Walker)), NextID(MSSA.NextID) { + // Update the Walker MSSA pointer so it doesn't point to the moved-from MSSA + // object any more. + Walker->MSSA = this; +} + MemorySSA::~MemorySSA() { // Drop all our references for (const auto &Pair : PerBlockAccesses) @@ -1248,245 +325,6 @@ MemorySSA::AccessList *MemorySSA::getOrCreateAccessList(const BasicBlock *BB) { return Res.first->second.get(); } -/// This class is a batch walker of all MemoryUse's in the program, and points -/// their defining access at the thing that actually clobbers them. Because it -/// is a batch walker that touches everything, it does not operate like the -/// other walkers. This walker is basically performing a top-down SSA renaming -/// pass, where the version stack is used as the cache. This enables it to be -/// significantly more time and memory efficient than using the regular walker, -/// which is walking bottom-up. -class MemorySSA::OptimizeUses { -public: - OptimizeUses(MemorySSA *MSSA, MemorySSAWalker *Walker, AliasAnalysis *AA, - DominatorTree *DT) - : MSSA(MSSA), Walker(Walker), AA(AA), DT(DT) { - Walker = MSSA->getWalker(); - } - - void optimizeUses(); - -private: - /// This represents where a given memorylocation is in the stack. - struct MemlocStackInfo { - // This essentially is keeping track of versions of the stack. Whenever - // the stack changes due to pushes or pops, these versions increase. - unsigned long StackEpoch; - unsigned long PopEpoch; - // This is the lower bound of places on the stack to check. It is equal to - // the place the last stack walk ended. - // Note: Correctness depends on this being initialized to 0, which densemap - // does - unsigned long LowerBound; - const BasicBlock *LowerBoundBlock; - // This is where the last walk for this memory location ended. - unsigned long LastKill; - bool LastKillValid; - }; - void optimizeUsesInBlock(const BasicBlock *, unsigned long &, unsigned long &, - SmallVectorImpl<MemoryAccess *> &, - DenseMap<MemoryLocOrCall, MemlocStackInfo> &); - MemorySSA *MSSA; - MemorySSAWalker *Walker; - AliasAnalysis *AA; - DominatorTree *DT; -}; - -/// Optimize the uses in a given block This is basically the SSA renaming -/// algorithm, with one caveat: We are able to use a single stack for all -/// MemoryUses. This is because the set of *possible* reaching MemoryDefs is -/// the same for every MemoryUse. The *actual* clobbering MemoryDef is just -/// going to be some position in that stack of possible ones. -/// -/// We track the stack positions that each MemoryLocation needs -/// to check, and last ended at. This is because we only want to check the -/// things that changed since last time. The same MemoryLocation should -/// get clobbered by the same store (getModRefInfo does not use invariantness or -/// things like this, and if they start, we can modify MemoryLocOrCall to -/// include relevant data) -void MemorySSA::OptimizeUses::optimizeUsesInBlock( - const BasicBlock *BB, unsigned long &StackEpoch, unsigned long &PopEpoch, - SmallVectorImpl<MemoryAccess *> &VersionStack, - DenseMap<MemoryLocOrCall, MemlocStackInfo> &LocStackInfo) { - - /// If no accesses, nothing to do. - MemorySSA::AccessList *Accesses = MSSA->getWritableBlockAccesses(BB); - if (Accesses == nullptr) - return; - - // Pop everything that doesn't dominate the current block off the stack, - // increment the PopEpoch to account for this. - while (!VersionStack.empty()) { - BasicBlock *BackBlock = VersionStack.back()->getBlock(); - if (DT->dominates(BackBlock, BB)) - break; - while (VersionStack.back()->getBlock() == BackBlock) - VersionStack.pop_back(); - ++PopEpoch; - } - for (MemoryAccess &MA : *Accesses) { - auto *MU = dyn_cast<MemoryUse>(&MA); - if (!MU) { - VersionStack.push_back(&MA); - ++StackEpoch; - continue; - } - - if (isUseTriviallyOptimizableToLiveOnEntry(*AA, MU->getMemoryInst())) { - MU->setDefiningAccess(MSSA->getLiveOnEntryDef(), true); - continue; - } - - MemoryLocOrCall UseMLOC(MU); - auto &LocInfo = LocStackInfo[UseMLOC]; - // If the pop epoch changed, it means we've removed stuff from top of - // stack due to changing blocks. We may have to reset the lower bound or - // last kill info. - if (LocInfo.PopEpoch != PopEpoch) { - LocInfo.PopEpoch = PopEpoch; - LocInfo.StackEpoch = StackEpoch; - // If the lower bound was in something that no longer dominates us, we - // have to reset it. - // We can't simply track stack size, because the stack may have had - // pushes/pops in the meantime. - // XXX: This is non-optimal, but only is slower cases with heavily - // branching dominator trees. To get the optimal number of queries would - // be to make lowerbound and lastkill a per-loc stack, and pop it until - // the top of that stack dominates us. This does not seem worth it ATM. - // A much cheaper optimization would be to always explore the deepest - // branch of the dominator tree first. This will guarantee this resets on - // the smallest set of blocks. - if (LocInfo.LowerBoundBlock && LocInfo.LowerBoundBlock != BB && - !DT->dominates(LocInfo.LowerBoundBlock, BB)) { - // Reset the lower bound of things to check. - // TODO: Some day we should be able to reset to last kill, rather than - // 0. - LocInfo.LowerBound = 0; - LocInfo.LowerBoundBlock = VersionStack[0]->getBlock(); - LocInfo.LastKillValid = false; - } - } else if (LocInfo.StackEpoch != StackEpoch) { - // If all that has changed is the StackEpoch, we only have to check the - // new things on the stack, because we've checked everything before. In - // this case, the lower bound of things to check remains the same. - LocInfo.PopEpoch = PopEpoch; - LocInfo.StackEpoch = StackEpoch; - } - if (!LocInfo.LastKillValid) { - LocInfo.LastKill = VersionStack.size() - 1; - LocInfo.LastKillValid = true; - } - - // At this point, we should have corrected last kill and LowerBound to be - // in bounds. - assert(LocInfo.LowerBound < VersionStack.size() && - "Lower bound out of range"); - assert(LocInfo.LastKill < VersionStack.size() && - "Last kill info out of range"); - // In any case, the new upper bound is the top of the stack. - unsigned long UpperBound = VersionStack.size() - 1; - - if (UpperBound - LocInfo.LowerBound > MaxCheckLimit) { - DEBUG(dbgs() << "MemorySSA skipping optimization of " << *MU << " (" - << *(MU->getMemoryInst()) << ")" - << " because there are " << UpperBound - LocInfo.LowerBound - << " stores to disambiguate\n"); - // Because we did not walk, LastKill is no longer valid, as this may - // have been a kill. - LocInfo.LastKillValid = false; - continue; - } - bool FoundClobberResult = false; - while (UpperBound > LocInfo.LowerBound) { - if (isa<MemoryPhi>(VersionStack[UpperBound])) { - // For phis, use the walker, see where we ended up, go there - Instruction *UseInst = MU->getMemoryInst(); - MemoryAccess *Result = Walker->getClobberingMemoryAccess(UseInst); - // We are guaranteed to find it or something is wrong - while (VersionStack[UpperBound] != Result) { - assert(UpperBound != 0); - --UpperBound; - } - FoundClobberResult = true; - break; - } - - MemoryDef *MD = cast<MemoryDef>(VersionStack[UpperBound]); - // If the lifetime of the pointer ends at this instruction, it's live on - // entry. - if (!UseMLOC.IsCall && lifetimeEndsAt(MD, UseMLOC.getLoc(), *AA)) { - // Reset UpperBound to liveOnEntryDef's place in the stack - UpperBound = 0; - FoundClobberResult = true; - break; - } - if (instructionClobbersQuery(MD, MU, UseMLOC, *AA)) { - FoundClobberResult = true; - break; - } - --UpperBound; - } - // At the end of this loop, UpperBound is either a clobber, or lower bound - // PHI walking may cause it to be < LowerBound, and in fact, < LastKill. - if (FoundClobberResult || UpperBound < LocInfo.LastKill) { - MU->setDefiningAccess(VersionStack[UpperBound], true); - // We were last killed now by where we got to - LocInfo.LastKill = UpperBound; - } else { - // Otherwise, we checked all the new ones, and now we know we can get to - // LastKill. - MU->setDefiningAccess(VersionStack[LocInfo.LastKill], true); - } - LocInfo.LowerBound = VersionStack.size() - 1; - LocInfo.LowerBoundBlock = BB; - } -} - -/// Optimize uses to point to their actual clobbering definitions. -void MemorySSA::OptimizeUses::optimizeUses() { - - // We perform a non-recursive top-down dominator tree walk - struct StackInfo { - const DomTreeNode *Node; - DomTreeNode::const_iterator Iter; - }; - - SmallVector<MemoryAccess *, 16> VersionStack; - SmallVector<StackInfo, 16> DomTreeWorklist; - DenseMap<MemoryLocOrCall, MemlocStackInfo> LocStackInfo; - VersionStack.push_back(MSSA->getLiveOnEntryDef()); - - unsigned long StackEpoch = 1; - unsigned long PopEpoch = 1; - for (const auto *DomNode : depth_first(DT->getRootNode())) - optimizeUsesInBlock(DomNode->getBlock(), StackEpoch, PopEpoch, VersionStack, - LocStackInfo); -} - -void MemorySSA::placePHINodes( - const SmallPtrSetImpl<BasicBlock *> &DefiningBlocks, - const DenseMap<const BasicBlock *, unsigned int> &BBNumbers) { - // Determine where our MemoryPhi's should go - ForwardIDFCalculator IDFs(*DT); - IDFs.setDefiningBlocks(DefiningBlocks); - SmallVector<BasicBlock *, 32> IDFBlocks; - IDFs.calculate(IDFBlocks); - - std::sort(IDFBlocks.begin(), IDFBlocks.end(), - [&BBNumbers](const BasicBlock *A, const BasicBlock *B) { - return BBNumbers.lookup(A) < BBNumbers.lookup(B); - }); - - // Now place MemoryPhi nodes. - for (auto &BB : IDFBlocks) { - // Insert phi node - AccessList *Accesses = getOrCreateAccessList(BB); - MemoryPhi *Phi = new MemoryPhi(BB->getContext(), BB, NextID++); - ValueToMemoryAccess[BB] = Phi; - // Phi's always are placed at the front of the block. - Accesses->push_front(Phi); - } -} - void MemorySSA::buildMemorySSA() { // We create an access to represent "live on entry", for things like // arguments or users of globals, where the memory they use is defined before @@ -1497,8 +335,6 @@ void MemorySSA::buildMemorySSA() { BasicBlock &StartingPoint = F.getEntryBlock(); LiveOnEntryDef = make_unique<MemoryDef>(F.getContext(), nullptr, nullptr, &StartingPoint, NextID++); - DenseMap<const BasicBlock *, unsigned int> BBNumbers; - unsigned NextBBNum = 0; // We maintain lists of memory accesses per-block, trading memory for time. We // could just look up the memory access for every possible instruction in the @@ -1508,7 +344,6 @@ void MemorySSA::buildMemorySSA() { // Go through each block, figure out where defs occur, and chain together all // the accesses. for (BasicBlock &B : F) { - BBNumbers[&B] = NextBBNum++; bool InsertIntoDef = false; AccessList *Accesses = nullptr; for (Instruction &I : B) { @@ -1526,20 +361,81 @@ void MemorySSA::buildMemorySSA() { if (Accesses) DefUseBlocks.insert(&B); } - placePHINodes(DefiningBlocks, BBNumbers); + + // Compute live-in. + // Live in is normally defined as "all the blocks on the path from each def to + // each of it's uses". + // MemoryDef's are implicit uses of previous state, so they are also uses. + // This means we don't really have def-only instructions. The only + // MemoryDef's that are not really uses are those that are of the LiveOnEntry + // variable (because LiveOnEntry can reach anywhere, and every def is a + // must-kill of LiveOnEntry). + // In theory, you could precisely compute live-in by using alias-analysis to + // disambiguate defs and uses to see which really pair up with which. + // In practice, this would be really expensive and difficult. So we simply + // assume all defs are also uses that need to be kept live. + // Because of this, the end result of this live-in computation will be "the + // entire set of basic blocks that reach any use". + + SmallPtrSet<BasicBlock *, 32> LiveInBlocks; + SmallVector<BasicBlock *, 64> LiveInBlockWorklist(DefUseBlocks.begin(), + DefUseBlocks.end()); + // Now that we have a set of blocks where a value is live-in, recursively add + // predecessors until we find the full region the value is live. + while (!LiveInBlockWorklist.empty()) { + BasicBlock *BB = LiveInBlockWorklist.pop_back_val(); + + // The block really is live in here, insert it into the set. If already in + // the set, then it has already been processed. + if (!LiveInBlocks.insert(BB).second) + continue; + + // Since the value is live into BB, it is either defined in a predecessor or + // live into it to. + LiveInBlockWorklist.append(pred_begin(BB), pred_end(BB)); + } + + // Determine where our MemoryPhi's should go + ForwardIDFCalculator IDFs(*DT); + IDFs.setDefiningBlocks(DefiningBlocks); + IDFs.setLiveInBlocks(LiveInBlocks); + SmallVector<BasicBlock *, 32> IDFBlocks; + IDFs.calculate(IDFBlocks); + + // Now place MemoryPhi nodes. + for (auto &BB : IDFBlocks) { + // Insert phi node + AccessList *Accesses = getOrCreateAccessList(BB); + MemoryPhi *Phi = new MemoryPhi(BB->getContext(), BB, NextID++); + ValueToMemoryAccess.insert(std::make_pair(BB, Phi)); + // Phi's always are placed at the front of the block. + Accesses->push_front(Phi); + } // Now do regular SSA renaming on the MemoryDef/MemoryUse. Visited will get // filled in with all blocks. SmallPtrSet<BasicBlock *, 16> Visited; renamePass(DT->getRootNode(), LiveOnEntryDef.get(), Visited); - CachingWalker *Walker = getWalkerImpl(); + MemorySSAWalker *Walker = getWalker(); - // We're doing a batch of updates; don't drop useful caches between them. - Walker->setAutoResetWalker(false); - OptimizeUses(this, Walker, AA, DT).optimizeUses(); - Walker->setAutoResetWalker(true); - Walker->resetClobberWalker(); + // Now optimize the MemoryUse's defining access to point to the nearest + // dominating clobbering def. + // This ensures that MemoryUse's that are killed by the same store are + // immediate users of that store, one of the invariants we guarantee. + for (auto DomNode : depth_first(DT)) { + BasicBlock *BB = DomNode->getBlock(); + auto AI = PerBlockAccesses.find(BB); + if (AI == PerBlockAccesses.end()) + continue; + AccessList *Accesses = AI->second.get(); + for (auto &MA : *Accesses) { + if (auto *MU = dyn_cast<MemoryUse>(&MA)) { + Instruction *Inst = MU->getMemoryInst(); + MU->setDefiningAccess(Walker->getClobberingMemoryAccess(Inst)); + } + } + } // Mark the uses in unreachable blocks as live on entry, so that they go // somewhere. @@ -1548,9 +444,7 @@ void MemorySSA::buildMemorySSA() { markUnreachableAsLiveOnEntry(&BB); } -MemorySSAWalker *MemorySSA::getWalker() { return getWalkerImpl(); } - -MemorySSA::CachingWalker *MemorySSA::getWalkerImpl() { +MemorySSAWalker *MemorySSA::getWalker() { if (Walker) return Walker.get(); @@ -1562,10 +456,9 @@ MemoryPhi *MemorySSA::createMemoryPhi(BasicBlock *BB) { assert(!getMemoryAccess(BB) && "MemoryPhi already exists for this BB"); AccessList *Accesses = getOrCreateAccessList(BB); MemoryPhi *Phi = new MemoryPhi(BB->getContext(), BB, NextID++); - ValueToMemoryAccess[BB] = Phi; + ValueToMemoryAccess.insert(std::make_pair(BB, Phi)); // Phi's always are placed at the front of the block. Accesses->push_front(Phi); - BlockNumberingValid.erase(BB); return Phi; } @@ -1588,64 +481,39 @@ MemoryAccess *MemorySSA::createMemoryAccessInBB(Instruction *I, auto *Accesses = getOrCreateAccessList(BB); if (Point == Beginning) { // It goes after any phi nodes - auto AI = find_if( - *Accesses, [](const MemoryAccess &MA) { return !isa<MemoryPhi>(MA); }); + auto AI = std::find_if( + Accesses->begin(), Accesses->end(), + [](const MemoryAccess &MA) { return !isa<MemoryPhi>(MA); }); Accesses->insert(AI, NewAccess); } else { Accesses->push_back(NewAccess); } - BlockNumberingValid.erase(BB); + return NewAccess; } - -MemoryUseOrDef *MemorySSA::createMemoryAccessBefore(Instruction *I, - MemoryAccess *Definition, - MemoryUseOrDef *InsertPt) { +MemoryAccess *MemorySSA::createMemoryAccessBefore(Instruction *I, + MemoryAccess *Definition, + MemoryAccess *InsertPt) { assert(I->getParent() == InsertPt->getBlock() && "New and old access must be in the same block"); MemoryUseOrDef *NewAccess = createDefinedAccess(I, Definition); auto *Accesses = getOrCreateAccessList(InsertPt->getBlock()); Accesses->insert(AccessList::iterator(InsertPt), NewAccess); - BlockNumberingValid.erase(InsertPt->getBlock()); return NewAccess; } -MemoryUseOrDef *MemorySSA::createMemoryAccessAfter(Instruction *I, - MemoryAccess *Definition, - MemoryAccess *InsertPt) { +MemoryAccess *MemorySSA::createMemoryAccessAfter(Instruction *I, + MemoryAccess *Definition, + MemoryAccess *InsertPt) { assert(I->getParent() == InsertPt->getBlock() && "New and old access must be in the same block"); MemoryUseOrDef *NewAccess = createDefinedAccess(I, Definition); auto *Accesses = getOrCreateAccessList(InsertPt->getBlock()); Accesses->insertAfter(AccessList::iterator(InsertPt), NewAccess); - BlockNumberingValid.erase(InsertPt->getBlock()); return NewAccess; } -void MemorySSA::spliceMemoryAccessAbove(MemoryDef *Where, - MemoryUseOrDef *What) { - assert(What != getLiveOnEntryDef() && - Where != getLiveOnEntryDef() && "Can't splice (above) LOE."); - assert(dominates(Where, What) && "Only upwards splices are permitted."); - - if (Where == What) - return; - if (isa<MemoryDef>(What)) { - // TODO: possibly use removeMemoryAccess' more efficient RAUW - What->replaceAllUsesWith(What->getDefiningAccess()); - What->setDefiningAccess(Where->getDefiningAccess()); - Where->setDefiningAccess(What); - } - AccessList *Src = getWritableBlockAccesses(What->getBlock()); - AccessList *Dest = getWritableBlockAccesses(Where->getBlock()); - Dest->splice(AccessList::iterator(Where), *Src, What); - - BlockNumberingValid.erase(What->getBlock()); - if (What->getBlock() != Where->getBlock()) - BlockNumberingValid.erase(Where->getBlock()); -} - /// \brief Helper function to create new memory accesses MemoryUseOrDef *MemorySSA::createNewAccess(Instruction *I) { // The assume intrinsic has a control dependency which we model by claiming @@ -1674,7 +542,7 @@ MemoryUseOrDef *MemorySSA::createNewAccess(Instruction *I) { MUD = new MemoryDef(I->getContext(), nullptr, I, I->getParent(), NextID++); else MUD = new MemoryUse(I->getContext(), nullptr, I, I->getParent()); - ValueToMemoryAccess[I] = MUD; + ValueToMemoryAccess.insert(std::make_pair(I, MUD)); return MUD; } @@ -1743,7 +611,6 @@ static MemoryAccess *onlySingleValue(MemoryPhi *MP) { void MemorySSA::removeFromLookups(MemoryAccess *MA) { assert(MA->use_empty() && "Trying to remove memory access that still has uses"); - BlockNumbering.erase(MA); if (MemoryUseOrDef *MUD = dyn_cast<MemoryUseOrDef>(MA)) MUD->setDefiningAccess(nullptr); // Invalidate our walker's cache if necessary @@ -1757,9 +624,7 @@ void MemorySSA::removeFromLookups(MemoryAccess *MA) { } else { MemoryInst = MA->getBlock(); } - auto VMA = ValueToMemoryAccess.find(MemoryInst); - if (VMA->second == MA) - ValueToMemoryAccess.erase(VMA); + ValueToMemoryAccess.erase(MemoryInst); auto AccessIt = PerBlockAccesses.find(MA->getBlock()); std::unique_ptr<AccessList> &Accesses = AccessIt->second; @@ -1787,27 +652,8 @@ void MemorySSA::removeMemoryAccess(MemoryAccess *MA) { } // Re-point the uses at our defining access - if (!MA->use_empty()) { - // Reset optimized on users of this store, and reset the uses. - // A few notes: - // 1. This is a slightly modified version of RAUW to avoid walking the - // uses twice here. - // 2. If we wanted to be complete, we would have to reset the optimized - // flags on users of phi nodes if doing the below makes a phi node have all - // the same arguments. Instead, we prefer users to removeMemoryAccess those - // phi nodes, because doing it here would be N^3. - if (MA->hasValueHandle()) - ValueHandleBase::ValueIsRAUWd(MA, NewDefTarget); - // Note: We assume MemorySSA is not used in metadata since it's not really - // part of the IR. - - while (!MA->use_empty()) { - Use &U = *MA->use_begin(); - if (MemoryUse *MU = dyn_cast<MemoryUse>(U.getUser())) - MU->resetOptimized(); - U.set(NewDefTarget); - } - } + if (!MA->use_empty()) + MA->replaceAllUsesWith(NewDefTarget); // The call below to erase will destroy MA, so we can't change the order we // are doing things here @@ -1828,7 +674,6 @@ void MemorySSA::verifyMemorySSA() const { verifyDefUses(F); verifyDomination(F); verifyOrdering(F); - Walker->verify(this); } /// \brief Verify that the order and existence of MemoryAccesses matches the @@ -1872,38 +717,70 @@ void MemorySSA::verifyOrdering(Function &F) const { /// \brief Verify the domination properties of MemorySSA by checking that each /// definition dominates all of its uses. void MemorySSA::verifyDomination(Function &F) const { -#ifndef NDEBUG for (BasicBlock &B : F) { // Phi nodes are attached to basic blocks - if (MemoryPhi *MP = getMemoryAccess(&B)) - for (const Use &U : MP->uses()) - assert(dominates(MP, U) && "Memory PHI does not dominate it's uses"); + if (MemoryPhi *MP = getMemoryAccess(&B)) { + for (User *U : MP->users()) { + BasicBlock *UseBlock; + // Phi operands are used on edges, we simulate the right domination by + // acting as if the use occurred at the end of the predecessor block. + if (MemoryPhi *P = dyn_cast<MemoryPhi>(U)) { + for (const auto &Arg : P->operands()) { + if (Arg == MP) { + UseBlock = P->getIncomingBlock(Arg); + break; + } + } + } else { + UseBlock = cast<MemoryAccess>(U)->getBlock(); + } + (void)UseBlock; + assert(DT->dominates(MP->getBlock(), UseBlock) && + "Memory PHI does not dominate it's uses"); + } + } for (Instruction &I : B) { MemoryAccess *MD = dyn_cast_or_null<MemoryDef>(getMemoryAccess(&I)); if (!MD) continue; - for (const Use &U : MD->uses()) - assert(dominates(MD, U) && "Memory Def does not dominate it's uses"); + for (User *U : MD->users()) { + BasicBlock *UseBlock; + (void)UseBlock; + // Things are allowed to flow to phi nodes over their predecessor edge. + if (auto *P = dyn_cast<MemoryPhi>(U)) { + for (const auto &Arg : P->operands()) { + if (Arg == MD) { + UseBlock = P->getIncomingBlock(Arg); + break; + } + } + } else { + UseBlock = cast<MemoryAccess>(U)->getBlock(); + } + assert(DT->dominates(MD->getBlock(), UseBlock) && + "Memory Def does not dominate it's uses"); + } } } -#endif } /// \brief Verify the def-use lists in MemorySSA, by verifying that \p Use /// appears in the use list of \p Def. - +/// +/// llvm_unreachable is used instead of asserts because this may be called in +/// a build without asserts. In that case, we don't want this to turn into a +/// nop. void MemorySSA::verifyUseInDefs(MemoryAccess *Def, MemoryAccess *Use) const { -#ifndef NDEBUG // The live on entry use may cause us to get a NULL def here - if (!Def) - assert(isLiveOnEntryDef(Use) && - "Null def but use not point to live on entry def"); - else - assert(is_contained(Def->users(), Use) && - "Did not find use in def's use list"); -#endif + if (!Def) { + if (!isLiveOnEntryDef(Use)) + llvm_unreachable("Null def but use not point to live on entry def"); + } else if (std::find(Def->user_begin(), Def->user_end(), Use) == + Def->user_end()) { + llvm_unreachable("Did not find use in def's use list"); + } } /// \brief Verify the immediate use information, by walking all the memory @@ -1921,35 +798,21 @@ void MemorySSA::verifyDefUses(Function &F) const { } for (Instruction &I : B) { - if (MemoryUseOrDef *MA = getMemoryAccess(&I)) { - verifyUseInDefs(MA->getDefiningAccess(), MA); + if (MemoryAccess *MA = getMemoryAccess(&I)) { + assert(isa<MemoryUseOrDef>(MA) && + "Found a phi node not attached to a bb"); + verifyUseInDefs(cast<MemoryUseOrDef>(MA)->getDefiningAccess(), MA); } } } } -MemoryUseOrDef *MemorySSA::getMemoryAccess(const Instruction *I) const { - return cast_or_null<MemoryUseOrDef>(ValueToMemoryAccess.lookup(I)); +MemoryAccess *MemorySSA::getMemoryAccess(const Value *I) const { + return ValueToMemoryAccess.lookup(I); } MemoryPhi *MemorySSA::getMemoryAccess(const BasicBlock *BB) const { - return cast_or_null<MemoryPhi>(ValueToMemoryAccess.lookup(cast<Value>(BB))); -} - -/// Perform a local numbering on blocks so that instruction ordering can be -/// determined in constant time. -/// TODO: We currently just number in order. If we numbered by N, we could -/// allow at least N-1 sequences of insertBefore or insertAfter (and at least -/// log2(N) sequences of mixed before and after) without needing to invalidate -/// the numbering. -void MemorySSA::renumberBlock(const BasicBlock *B) const { - // The pre-increment ensures the numbers really start at 1. - unsigned long CurrentNumber = 0; - const AccessList *AL = getBlockAccesses(B); - assert(AL != nullptr && "Asking to renumber an empty block"); - for (const auto &I : *AL) - BlockNumbering[&I] = ++CurrentNumber; - BlockNumberingValid.insert(B); + return cast_or_null<MemoryPhi>(getMemoryAccess((const Value *)BB)); } /// \brief Determine, for two memory accesses in the same block, @@ -1958,10 +821,9 @@ void MemorySSA::renumberBlock(const BasicBlock *B) const { bool MemorySSA::locallyDominates(const MemoryAccess *Dominator, const MemoryAccess *Dominatee) const { - const BasicBlock *DominatorBlock = Dominator->getBlock(); - - assert((DominatorBlock == Dominatee->getBlock()) && + assert((Dominator->getBlock() == Dominatee->getBlock()) && "Asking for local domination when accesses are in different blocks!"); + // A node dominates itself. if (Dominatee == Dominator) return true; @@ -1976,42 +838,14 @@ bool MemorySSA::locallyDominates(const MemoryAccess *Dominator, if (isLiveOnEntryDef(Dominator)) return true; - if (!BlockNumberingValid.count(DominatorBlock)) - renumberBlock(DominatorBlock); - - unsigned long DominatorNum = BlockNumbering.lookup(Dominator); - // All numbers start with 1 - assert(DominatorNum != 0 && "Block was not numbered properly"); - unsigned long DominateeNum = BlockNumbering.lookup(Dominatee); - assert(DominateeNum != 0 && "Block was not numbered properly"); - return DominatorNum < DominateeNum; -} - -bool MemorySSA::dominates(const MemoryAccess *Dominator, - const MemoryAccess *Dominatee) const { - if (Dominator == Dominatee) - return true; - - if (isLiveOnEntryDef(Dominatee)) - return false; - - if (Dominator->getBlock() != Dominatee->getBlock()) - return DT->dominates(Dominator->getBlock(), Dominatee->getBlock()); - return locallyDominates(Dominator, Dominatee); -} + // Get the access list for the block + const AccessList *AccessList = getBlockAccesses(Dominator->getBlock()); + AccessList::const_reverse_iterator It(Dominator->getIterator()); -bool MemorySSA::dominates(const MemoryAccess *Dominator, - const Use &Dominatee) const { - if (MemoryPhi *MP = dyn_cast<MemoryPhi>(Dominatee.getUser())) { - BasicBlock *UseBB = MP->getIncomingBlock(Dominatee); - // The def must dominate the incoming block of the phi. - if (UseBB != Dominator->getBlock()) - return DT->dominates(Dominator->getBlock(), UseBB); - // If the UseBB and the DefBB are the same, compare locally. - return locallyDominates(Dominator, cast<MemoryAccess>(Dominatee)); - } - // If it's not a PHI node use, the normal dominates can already handle it. - return dominates(Dominator, cast<MemoryAccess>(Dominatee.getUser())); + // If we hit the beginning of the access list before we hit dominatee, we must + // dominate it + return std::none_of(It, AccessList->rend(), + [&](const MemoryAccess &MA) { return &MA == Dominatee; }); } const static char LiveOnEntryStr[] = "liveOnEntry"; @@ -2090,26 +924,25 @@ bool MemorySSAPrinterLegacyPass::runOnFunction(Function &F) { return false; } -AnalysisKey MemorySSAAnalysis::Key; +char MemorySSAAnalysis::PassID; -MemorySSAAnalysis::Result MemorySSAAnalysis::run(Function &F, - FunctionAnalysisManager &AM) { +MemorySSA MemorySSAAnalysis::run(Function &F, AnalysisManager<Function> &AM) { auto &DT = AM.getResult<DominatorTreeAnalysis>(F); auto &AA = AM.getResult<AAManager>(F); - return MemorySSAAnalysis::Result(make_unique<MemorySSA>(F, &AA, &DT)); + return MemorySSA(F, &AA, &DT); } PreservedAnalyses MemorySSAPrinterPass::run(Function &F, FunctionAnalysisManager &AM) { OS << "MemorySSA for function: " << F.getName() << "\n"; - AM.getResult<MemorySSAAnalysis>(F).getMSSA().print(OS); + AM.getResult<MemorySSAAnalysis>(F).print(OS); return PreservedAnalyses::all(); } PreservedAnalyses MemorySSAVerifierPass::run(Function &F, FunctionAnalysisManager &AM) { - AM.getResult<MemorySSAAnalysis>(F).getMSSA().verifyMemorySSA(); + AM.getResult<MemorySSAAnalysis>(F).verifyMemorySSA(); return PreservedAnalyses::all(); } @@ -2145,11 +978,41 @@ MemorySSAWalker::MemorySSAWalker(MemorySSA *M) : MSSA(M) {} MemorySSA::CachingWalker::CachingWalker(MemorySSA *M, AliasAnalysis *A, DominatorTree *D) - : MemorySSAWalker(M), Walker(*M, *A, *D, Cache), AutoResetWalker(true) {} + : MemorySSAWalker(M), AA(A), DT(D) {} MemorySSA::CachingWalker::~CachingWalker() {} +struct MemorySSA::CachingWalker::UpwardsMemoryQuery { + // True if we saw a phi whose predecessor was a backedge + bool SawBackedgePhi; + // True if our original query started off as a call + bool IsCall; + // The pointer location we started the query with. This will be empty if + // IsCall is true. + MemoryLocation StartingLoc; + // This is the instruction we were querying about. + const Instruction *Inst; + // Set of visited Instructions for this query. + DenseSet<MemoryAccessPair> Visited; + // Vector of visited call accesses for this query. This is separated out + // because you can always cache and lookup the result of call queries (IE when + // IsCall == true) for every call in the chain. The calls have no AA location + // associated with them with them, and thus, no context dependence. + SmallVector<const MemoryAccess *, 32> VisitedCalls; + // The MemoryAccess we actually got called with, used to test local domination + const MemoryAccess *OriginalAccess; + + UpwardsMemoryQuery() + : SawBackedgePhi(false), IsCall(false), Inst(nullptr), + OriginalAccess(nullptr) {} + + UpwardsMemoryQuery(const Instruction *Inst, const MemoryAccess *Access) + : SawBackedgePhi(false), IsCall(ImmutableCallSite(Inst)), Inst(Inst), + OriginalAccess(Access) {} +}; + void MemorySSA::CachingWalker::invalidateInfo(MemoryAccess *MA) { + // TODO: We can do much better cache invalidation with differently stored // caches. For now, for MemoryUses, we simply remove them // from the cache, and kill the entire call/non-call cache for everything @@ -2163,38 +1026,220 @@ void MemorySSA::CachingWalker::invalidateInfo(MemoryAccess *MA) { // itself. if (MemoryUse *MU = dyn_cast<MemoryUse>(MA)) { - UpwardsMemoryQuery Q(MU->getMemoryInst(), MU); - Cache.remove(MU, Q.StartingLoc, Q.IsCall); - MU->resetOptimized(); + UpwardsMemoryQuery Q; + Instruction *I = MU->getMemoryInst(); + Q.IsCall = bool(ImmutableCallSite(I)); + Q.Inst = I; + if (!Q.IsCall) + Q.StartingLoc = MemoryLocation::get(I); + doCacheRemove(MA, Q, Q.StartingLoc); } else { // If it is not a use, the best we can do right now is destroy the cache. - Cache.clear(); + CachedUpwardsClobberingCall.clear(); + CachedUpwardsClobberingAccess.clear(); } #ifdef EXPENSIVE_CHECKS + // Run this only when expensive checks are enabled. verifyRemoved(MA); #endif } +void MemorySSA::CachingWalker::doCacheRemove(const MemoryAccess *M, + const UpwardsMemoryQuery &Q, + const MemoryLocation &Loc) { + if (Q.IsCall) + CachedUpwardsClobberingCall.erase(M); + else + CachedUpwardsClobberingAccess.erase({M, Loc}); +} + +void MemorySSA::CachingWalker::doCacheInsert(const MemoryAccess *M, + MemoryAccess *Result, + const UpwardsMemoryQuery &Q, + const MemoryLocation &Loc) { + // This is fine for Phis, since there are times where we can't optimize them. + // Making a def its own clobber is never correct, though. + assert((Result != M || isa<MemoryPhi>(M)) && + "Something can't clobber itself!"); + ++NumClobberCacheInserts; + if (Q.IsCall) + CachedUpwardsClobberingCall[M] = Result; + else + CachedUpwardsClobberingAccess[{M, Loc}] = Result; +} + +MemoryAccess * +MemorySSA::CachingWalker::doCacheLookup(const MemoryAccess *M, + const UpwardsMemoryQuery &Q, + const MemoryLocation &Loc) { + ++NumClobberCacheLookups; + MemoryAccess *Result; + + if (Q.IsCall) + Result = CachedUpwardsClobberingCall.lookup(M); + else + Result = CachedUpwardsClobberingAccess.lookup({M, Loc}); + + if (Result) + ++NumClobberCacheHits; + return Result; +} + +bool MemorySSA::CachingWalker::instructionClobbersQuery( + const MemoryDef *MD, UpwardsMemoryQuery &Q, + const MemoryLocation &Loc) const { + Instruction *DefMemoryInst = MD->getMemoryInst(); + assert(DefMemoryInst && "Defining instruction not actually an instruction"); + + if (!Q.IsCall) + return AA->getModRefInfo(DefMemoryInst, Loc) & MRI_Mod; + + // If this is a call, mark it for caching + if (ImmutableCallSite(DefMemoryInst)) + Q.VisitedCalls.push_back(MD); + ModRefInfo I = AA->getModRefInfo(DefMemoryInst, ImmutableCallSite(Q.Inst)); + return I != MRI_NoModRef; +} + +MemoryAccessPair MemorySSA::CachingWalker::UpwardsDFSWalk( + MemoryAccess *StartingAccess, const MemoryLocation &Loc, + UpwardsMemoryQuery &Q, bool FollowingBackedge) { + MemoryAccess *ModifyingAccess = nullptr; + + auto DFI = df_begin(StartingAccess); + for (auto DFE = df_end(StartingAccess); DFI != DFE;) { + MemoryAccess *CurrAccess = *DFI; + if (MSSA->isLiveOnEntryDef(CurrAccess)) + return {CurrAccess, Loc}; + // If this is a MemoryDef, check whether it clobbers our current query. This + // needs to be done before consulting the cache, because the cache reports + // the clobber for CurrAccess. If CurrAccess is a clobber for this query, + // and we ask the cache for information first, then we might skip this + // clobber, which is bad. + if (auto *MD = dyn_cast<MemoryDef>(CurrAccess)) { + // If we hit the top, stop following this path. + // While we can do lookups, we can't sanely do inserts here unless we were + // to track everything we saw along the way, since we don't know where we + // will stop. + if (instructionClobbersQuery(MD, Q, Loc)) { + ModifyingAccess = CurrAccess; + break; + } + } + if (auto CacheResult = doCacheLookup(CurrAccess, Q, Loc)) + return {CacheResult, Loc}; + + // We need to know whether it is a phi so we can track backedges. + // Otherwise, walk all upward defs. + if (!isa<MemoryPhi>(CurrAccess)) { + ++DFI; + continue; + } + +#ifndef NDEBUG + // The loop below visits the phi's children for us. Because phis are the + // only things with multiple edges, skipping the children should always lead + // us to the end of the loop. + // + // Use a copy of DFI because skipChildren would kill our search stack, which + // would make caching anything on the way back impossible. + auto DFICopy = DFI; + assert(DFICopy.skipChildren() == DFE && + "Skipping phi's children doesn't end the DFS?"); +#endif + + const MemoryAccessPair PHIPair(CurrAccess, Loc); + + // Don't try to optimize this phi again if we've already tried to do so. + if (!Q.Visited.insert(PHIPair).second) { + ModifyingAccess = CurrAccess; + break; + } + + std::size_t InitialVisitedCallSize = Q.VisitedCalls.size(); + + // Recurse on PHI nodes, since we need to change locations. + // TODO: Allow graphtraits on pairs, which would turn this whole function + // into a normal single depth first walk. + MemoryAccess *FirstDef = nullptr; + for (auto MPI = upward_defs_begin(PHIPair), MPE = upward_defs_end(); + MPI != MPE; ++MPI) { + bool Backedge = + !FollowingBackedge && + DT->dominates(CurrAccess->getBlock(), MPI.getPhiArgBlock()); + + MemoryAccessPair CurrentPair = + UpwardsDFSWalk(MPI->first, MPI->second, Q, Backedge); + // All the phi arguments should reach the same point if we can bypass + // this phi. The alternative is that they hit this phi node, which + // means we can skip this argument. + if (FirstDef && CurrentPair.first != PHIPair.first && + CurrentPair.first != FirstDef) { + ModifyingAccess = CurrAccess; + break; + } + + if (!FirstDef) + FirstDef = CurrentPair.first; + } + + // If we exited the loop early, go with the result it gave us. + if (!ModifyingAccess) { + assert(FirstDef && "Found a Phi with no upward defs?"); + ModifyingAccess = FirstDef; + } else { + // If we can't optimize this Phi, then we can't safely cache any of the + // calls we visited when trying to optimize it. Wipe them out now. + Q.VisitedCalls.resize(InitialVisitedCallSize); + } + break; + } + + if (!ModifyingAccess) + return {MSSA->getLiveOnEntryDef(), Q.StartingLoc}; + + const BasicBlock *OriginalBlock = StartingAccess->getBlock(); + assert(DFI.getPathLength() > 0 && "We dropped our path?"); + unsigned N = DFI.getPathLength(); + // If we found a clobbering def, the last element in the path will be our + // clobber, so we don't want to cache that to itself. OTOH, if we optimized a + // phi, we can add the last thing in the path to the cache, since that won't + // be the result. + if (DFI.getPath(N - 1) == ModifyingAccess) + --N; + for (; N > 1; --N) { + MemoryAccess *CacheAccess = DFI.getPath(N - 1); + BasicBlock *CurrBlock = CacheAccess->getBlock(); + if (!FollowingBackedge) + doCacheInsert(CacheAccess, ModifyingAccess, Q, Loc); + if (DT->dominates(CurrBlock, OriginalBlock) && + (CurrBlock != OriginalBlock || !FollowingBackedge || + MSSA->locallyDominates(CacheAccess, StartingAccess))) + break; + } + + // Cache everything else on the way back. The caller should cache + // StartingAccess for us. + for (; N > 1; --N) { + MemoryAccess *CacheAccess = DFI.getPath(N - 1); + doCacheInsert(CacheAccess, ModifyingAccess, Q, Loc); + } + + return {ModifyingAccess, Loc}; +} + /// \brief Walk the use-def chains starting at \p MA and find /// the MemoryAccess that actually clobbers Loc. /// /// \returns our clobbering memory access MemoryAccess *MemorySSA::CachingWalker::getClobberingMemoryAccess( MemoryAccess *StartingAccess, UpwardsMemoryQuery &Q) { - MemoryAccess *New = Walker.findClobber(StartingAccess, Q); -#ifdef EXPENSIVE_CHECKS - MemoryAccess *NewNoCache = - Walker.findClobber(StartingAccess, Q, /*UseWalkerCache=*/false); - assert(NewNoCache == New && "Cache made us hand back a different result?"); -#endif - if (AutoResetWalker) - resetClobberWalker(); - return New; + return UpwardsDFSWalk(StartingAccess, Q.StartingLoc, Q, false).first; } MemoryAccess *MemorySSA::CachingWalker::getClobberingMemoryAccess( - MemoryAccess *StartingAccess, const MemoryLocation &Loc) { + MemoryAccess *StartingAccess, MemoryLocation &Loc) { if (isa<MemoryPhi>(StartingAccess)) return StartingAccess; @@ -2212,10 +1257,10 @@ MemoryAccess *MemorySSA::CachingWalker::getClobberingMemoryAccess( UpwardsMemoryQuery Q; Q.OriginalAccess = StartingUseOrDef; Q.StartingLoc = Loc; - Q.Inst = I; + Q.Inst = StartingUseOrDef->getMemoryInst(); Q.IsCall = false; - if (auto *CacheResult = Cache.lookup(StartingUseOrDef, Loc, Q.IsCall)) + if (auto CacheResult = doCacheLookup(StartingUseOrDef, Q, Q.StartingLoc)) return CacheResult; // Unlike the other function, do not walk to the def of a def, because we are @@ -2225,6 +1270,9 @@ MemoryAccess *MemorySSA::CachingWalker::getClobberingMemoryAccess( : StartingUseOrDef; MemoryAccess *Clobber = getClobberingMemoryAccess(DefiningAccess, Q); + // Only cache this if it wouldn't make Clobber point to itself. + if (Clobber != StartingAccess) + doCacheInsert(Q.OriginalAccess, Clobber, Q, Q.StartingLoc); DEBUG(dbgs() << "Starting Memory SSA clobber for " << *I << " is "); DEBUG(dbgs() << *StartingUseOrDef << "\n"); DEBUG(dbgs() << "Final Memory SSA clobber for " << *I << " is "); @@ -2233,38 +1281,28 @@ MemoryAccess *MemorySSA::CachingWalker::getClobberingMemoryAccess( } MemoryAccess * -MemorySSA::CachingWalker::getClobberingMemoryAccess(MemoryAccess *MA) { - auto *StartingAccess = dyn_cast<MemoryUseOrDef>(MA); - // If this is a MemoryPhi, we can't do anything. - if (!StartingAccess) - return MA; - - // If this is an already optimized use or def, return the optimized result. - // Note: Currently, we do not store the optimized def result because we'd need - // a separate field, since we can't use it as the defining access. - if (MemoryUse *MU = dyn_cast<MemoryUse>(StartingAccess)) - if (MU->isOptimized()) - return MU->getDefiningAccess(); - - const Instruction *I = StartingAccess->getMemoryInst(); - UpwardsMemoryQuery Q(I, StartingAccess); +MemorySSA::CachingWalker::getClobberingMemoryAccess(const Instruction *I) { + // There should be no way to lookup an instruction and get a phi as the + // access, since we only map BB's to PHI's. So, this must be a use or def. + auto *StartingAccess = cast<MemoryUseOrDef>(MSSA->getMemoryAccess(I)); + + bool IsCall = bool(ImmutableCallSite(I)); + // We can't sanely do anything with a fences, they conservatively // clobber all memory, and have no locations to get pointers from to // try to disambiguate. - if (!Q.IsCall && I->isFenceLike()) + if (!IsCall && I->isFenceLike()) return StartingAccess; - if (auto *CacheResult = Cache.lookup(StartingAccess, Q.StartingLoc, Q.IsCall)) + UpwardsMemoryQuery Q; + Q.OriginalAccess = StartingAccess; + Q.IsCall = IsCall; + if (!Q.IsCall) + Q.StartingLoc = MemoryLocation::get(I); + Q.Inst = I; + if (auto CacheResult = doCacheLookup(StartingAccess, Q, Q.StartingLoc)) return CacheResult; - if (isUseTriviallyOptimizableToLiveOnEntry(*MSSA->AA, I)) { - MemoryAccess *LiveOnEntry = MSSA->getLiveOnEntryDef(); - Cache.insert(StartingAccess, LiveOnEntry, Q.StartingLoc, Q.IsCall); - if (MemoryUse *MU = dyn_cast<MemoryUse>(StartingAccess)) - MU->setDefiningAccess(LiveOnEntry, true); - return LiveOnEntry; - } - // Start with the thing we already think clobbers this location MemoryAccess *DefiningAccess = StartingAccess->getDefiningAccess(); @@ -2274,32 +1312,50 @@ MemorySSA::CachingWalker::getClobberingMemoryAccess(MemoryAccess *MA) { return DefiningAccess; MemoryAccess *Result = getClobberingMemoryAccess(DefiningAccess, Q); + // DFS won't cache a result for DefiningAccess. So, if DefiningAccess isn't + // our clobber, be sure that it gets a cache entry, too. + if (Result != DefiningAccess) + doCacheInsert(DefiningAccess, Result, Q, Q.StartingLoc); + doCacheInsert(Q.OriginalAccess, Result, Q, Q.StartingLoc); + // TODO: When this implementation is more mature, we may want to figure out + // what this additional caching buys us. It's most likely A Good Thing. + if (Q.IsCall) + for (const MemoryAccess *MA : Q.VisitedCalls) + if (MA != Result) + doCacheInsert(MA, Result, Q, Q.StartingLoc); + DEBUG(dbgs() << "Starting Memory SSA clobber for " << *I << " is "); DEBUG(dbgs() << *DefiningAccess << "\n"); DEBUG(dbgs() << "Final Memory SSA clobber for " << *I << " is "); DEBUG(dbgs() << *Result << "\n"); - if (MemoryUse *MU = dyn_cast<MemoryUse>(StartingAccess)) - MU->setDefiningAccess(Result, true); return Result; } // Verify that MA doesn't exist in any of the caches. void MemorySSA::CachingWalker::verifyRemoved(MemoryAccess *MA) { - assert(!Cache.contains(MA) && "Found removed MemoryAccess in cache."); +#ifndef NDEBUG + for (auto &P : CachedUpwardsClobberingAccess) + assert(P.first.first != MA && P.second != MA && + "Found removed MemoryAccess in cache."); + for (auto &P : CachedUpwardsClobberingCall) + assert(P.first != MA && P.second != MA && + "Found removed MemoryAccess in cache."); +#endif // !NDEBUG } MemoryAccess * -DoNothingMemorySSAWalker::getClobberingMemoryAccess(MemoryAccess *MA) { +DoNothingMemorySSAWalker::getClobberingMemoryAccess(const Instruction *I) { + MemoryAccess *MA = MSSA->getMemoryAccess(I); if (auto *Use = dyn_cast<MemoryUseOrDef>(MA)) return Use->getDefiningAccess(); return MA; } MemoryAccess *DoNothingMemorySSAWalker::getClobberingMemoryAccess( - MemoryAccess *StartingAccess, const MemoryLocation &) { + MemoryAccess *StartingAccess, MemoryLocation &) { if (auto *Use = dyn_cast<MemoryUseOrDef>(StartingAccess)) return Use->getDefiningAccess(); return StartingAccess; } -} // namespace llvm +} diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGCUDABuiltin.cpp b/gnu/llvm/tools/clang/lib/CodeGen/CGCUDABuiltin.cpp index 44dd003757a..ea3b888635c 100644 --- a/gnu/llvm/tools/clang/lib/CodeGen/CGCUDABuiltin.cpp +++ b/gnu/llvm/tools/clang/lib/CodeGen/CGCUDABuiltin.cpp @@ -99,12 +99,6 @@ CodeGenFunction::EmitCUDADevicePrintfCallExpr(const CallExpr *E, llvm::SmallVector<llvm::Type *, 8> ArgTypes; for (unsigned I = 1, NumArgs = Args.size(); I < NumArgs; ++I) ArgTypes.push_back(Args[I].RV.getScalarVal()->getType()); - - // Using llvm::StructType is correct only because printf doesn't accept - // aggregates. If we had to handle aggregates here, we'd have to manually - // compute the offsets within the alloca -- we wouldn't be able to assume - // that the alignment of the llvm type was the same as the alignment of the - // clang type. llvm::Type *AllocaTy = llvm::StructType::create(ArgTypes, "printf_args"); llvm::Value *Alloca = CreateTempAlloca(AllocaTy); diff --git a/gnu/llvm/tools/lld/COFF/Librarian.cpp b/gnu/llvm/tools/lld/COFF/Librarian.cpp index 4c597fad734..25fb4a87b3e 100644 --- a/gnu/llvm/tools/lld/COFF/Librarian.cpp +++ b/gnu/llvm/tools/lld/COFF/Librarian.cpp @@ -54,7 +54,7 @@ static uint16_t getImgRelRelocation() { } } -template <class T> static void append(std::vector<uint8_t> &B, const T &Data) { +template <class T> void append(std::vector<uint8_t> &B, const T &Data) { size_t S = B.size(); B.resize(S + sizeof(T)); memcpy(&B[S], &Data, sizeof(T)); @@ -352,16 +352,15 @@ ObjectFactory::createNullImportDescriptor(std::vector<uint8_t> &Buffer) { NewArchiveMember ObjectFactory::createNullThunk(std::vector<uint8_t> &Buffer) { static const uint32_t NumberOfSections = 2; static const uint32_t NumberOfSymbols = 1; - uint32_t VASize = is32bit() ? 4 : 8; // COFF Header coff_file_header Header{ u16(Config->Machine), u16(NumberOfSections), u32(0), u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) + // .idata$5 - VASize + + sizeof(export_address_table_entry) + // .idata$4 - VASize), + sizeof(export_address_table_entry)), u32(NumberOfSymbols), u16(0), u16(is32bit() ? IMAGE_FILE_32BIT_MACHINE : 0), }; @@ -372,40 +371,36 @@ NewArchiveMember ObjectFactory::createNullThunk(std::vector<uint8_t> &Buffer) { {{'.', 'i', 'd', 'a', 't', 'a', '$', '5'}, u32(0), u32(0), - u32(VASize), + u32(sizeof(export_address_table_entry)), u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)), u32(0), u32(0), u16(0), u16(0), - u32((is32bit() ? IMAGE_SCN_ALIGN_4BYTES : IMAGE_SCN_ALIGN_8BYTES) | - IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | - IMAGE_SCN_MEM_WRITE)}, + u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA | + IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)}, {{'.', 'i', 'd', 'a', 't', 'a', '$', '4'}, u32(0), u32(0), - u32(VASize), + u32(sizeof(export_address_table_entry)), u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) + - VASize), + sizeof(export_address_table_entry)), u32(0), u32(0), u16(0), u16(0), - u32((is32bit() ? IMAGE_SCN_ALIGN_4BYTES : IMAGE_SCN_ALIGN_8BYTES) | - IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | - IMAGE_SCN_MEM_WRITE)}, + u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA | + IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)}, }; append(Buffer, SectionTable); - // .idata$5, ILT - append(Buffer, u32(0)); - if (!is32bit()) - append(Buffer, u32(0)); + // .idata$5 + static const export_address_table_entry ILT{u32(0)}; + append(Buffer, ILT); - // .idata$4, IAT - append(Buffer, u32(0)); - if (!is32bit()) - append(Buffer, u32(0)); + // .idata$4 + static const export_address_table_entry IAT{u32(0)}; + append(Buffer, IAT); // Symbol Table coff_symbol16 SymbolTable[NumberOfSymbols] = { @@ -463,7 +458,7 @@ void lld::coff::writeImportLibrary() { std::vector<NewArchiveMember> Members; std::string Path = getImplibPath(); - std::string DLLName = sys::path::filename(Config->OutputFile); + std::string DLLName = llvm::sys::path::filename(Config->OutputFile); ObjectFactory OF(DLLName); std::vector<uint8_t> ImportDescriptor; diff --git a/gnu/llvm/tools/lld/COFF/ModuleDef.cpp b/gnu/llvm/tools/lld/COFF/ModuleDef.cpp index a273b6f535d..5e393f45d18 100644 --- a/gnu/llvm/tools/lld/COFF/ModuleDef.cpp +++ b/gnu/llvm/tools/lld/COFF/ModuleDef.cpp @@ -18,7 +18,6 @@ #include "Config.h" #include "Error.h" -#include "Memory.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/StringSaver.h" @@ -114,7 +113,7 @@ private: class Parser { public: - explicit Parser(StringRef S) : Lex(S) {} + explicit Parser(StringRef S, StringSaver *A) : Lex(S), Alloc(A) {} void parse() { do { @@ -198,9 +197,9 @@ private: if (Config->Machine == I386) { if (!isDecorated(E.Name)) - E.Name = Saver.save("_" + E.Name); + E.Name = Alloc->save("_" + E.Name); if (!E.ExtName.empty() && !isDecorated(E.ExtName)) - E.ExtName = Saver.save("_" + E.ExtName); + E.ExtName = Alloc->save("_" + E.ExtName); } for (;;) { @@ -279,11 +278,14 @@ private: Lexer Lex; Token Tok; std::vector<Token> Stack; + StringSaver *Alloc; }; } // anonymous namespace -void parseModuleDefs(MemoryBufferRef MB) { Parser(MB.getBuffer()).parse(); } +void parseModuleDefs(MemoryBufferRef MB, StringSaver *Alloc) { + Parser(MB.getBuffer(), Alloc).parse(); +} } // namespace coff } // namespace lld diff --git a/gnu/llvm/tools/lld/include/lld/Core/Parallel.h b/gnu/llvm/tools/lld/include/lld/Core/Parallel.h index f241453a4d3..2dde97d9e3f 100644 --- a/gnu/llvm/tools/lld/include/lld/Core/Parallel.h +++ b/gnu/llvm/tools/lld/include/lld/Core/Parallel.h @@ -121,7 +121,7 @@ public: // Spawn all but one of the threads in another thread as spawning threads // can take a while. std::thread([&, threadCount] { - for (size_t i = 1; i < threadCount; ++i) { + for (std::size_t i = 1; i < threadCount; ++i) { std::thread([=] { work(); }).detach(); @@ -270,65 +270,26 @@ template <class T> void parallel_sort(T *start, T *end) { } #if !defined(LLVM_ENABLE_THREADS) || LLVM_ENABLE_THREADS == 0 -template <class IterTy, class FuncTy> -void parallel_for_each(IterTy Begin, IterTy End, FuncTy Fn) { - std::for_each(Begin, End, Fn); -} - -template <class IndexTy, class FuncTy> -void parallel_for(IndexTy Begin, IndexTy End, FuncTy Fn) { - for (IndexTy I = Begin; I != End; ++I) - Fn(I); +template <class Iterator, class Func> +void parallel_for_each(Iterator begin, Iterator end, Func func) { + std::for_each(begin, end, func); } #elif defined(_MSC_VER) // Use ppl parallel_for_each on Windows. -template <class IterTy, class FuncTy> -void parallel_for_each(IterTy Begin, IterTy End, FuncTy Fn) { - concurrency::parallel_for_each(Begin, End, Fn); -} - -template <class IndexTy, class FuncTy> -void parallel_for(IndexTy Begin, IndexTy End, FuncTy Fn) { - concurrency::parallel_for(Begin, End, Fn); +template <class Iterator, class Func> +void parallel_for_each(Iterator begin, Iterator end, Func func) { + concurrency::parallel_for_each(begin, end, func); } #else -template <class IterTy, class FuncTy> -void parallel_for_each(IterTy Begin, IterTy End, FuncTy Fn) { - // TaskGroup has a relatively high overhead, so we want to reduce - // the number of spawn() calls. We'll create up to 1024 tasks here. - // (Note that 1024 is an arbitrary number. This code probably needs - // improving to take the number of available cores into account.) - ptrdiff_t TaskSize = std::distance(Begin, End) / 1024; - if (TaskSize == 0) - TaskSize = 1; - - TaskGroup Tg; - while (TaskSize <= std::distance(Begin, End)) { - Tg.spawn([=, &Fn] { std::for_each(Begin, Begin + TaskSize, Fn); }); - Begin += TaskSize; - } - Tg.spawn([=, &Fn] { std::for_each(Begin, End, Fn); }); -} - -template <class IndexTy, class FuncTy> -void parallel_for(IndexTy Begin, IndexTy End, FuncTy Fn) { - ptrdiff_t TaskSize = (End - Begin) / 1024; - if (TaskSize == 0) - TaskSize = 1; - - TaskGroup Tg; - IndexTy I = Begin; - for (; I < End; I += TaskSize) { - Tg.spawn([=, &Fn] { - for (IndexTy J = I, E = I + TaskSize; J != E; ++J) - Fn(J); - }); - Begin += TaskSize; +template <class Iterator, class Func> +void parallel_for_each(Iterator begin, Iterator end, Func func) { + TaskGroup tg; + ptrdiff_t taskSize = 1024; + while (taskSize <= std::distance(begin, end)) { + tg.spawn([=, &func] { std::for_each(begin, begin + taskSize, func); }); + begin += taskSize; } - Tg.spawn([=, &Fn] { - for (IndexTy J = I; J < End; ++J) - Fn(J); - }); + std::for_each(begin, end, func); } #endif } // end namespace lld diff --git a/gnu/llvm/tools/llvm-pdbdump/LLVMOutputStyle.cpp b/gnu/llvm/tools/llvm-pdbdump/LLVMOutputStyle.cpp index 629ba40b113..6d94295d126 100644 --- a/gnu/llvm/tools/llvm-pdbdump/LLVMOutputStyle.cpp +++ b/gnu/llvm/tools/llvm-pdbdump/LLVMOutputStyle.cpp @@ -10,22 +10,14 @@ #include "LLVMOutputStyle.h" #include "llvm-pdbdump.h" -#include "llvm/DebugInfo/CodeView/CVTypeDumper.h" -#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" #include "llvm/DebugInfo/CodeView/EnumTables.h" #include "llvm/DebugInfo/CodeView/ModuleSubstreamVisitor.h" #include "llvm/DebugInfo/CodeView/SymbolDumper.h" -#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h" -#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" -#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h" -#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h" -#include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" #include "llvm/DebugInfo/PDB/PDBExtras.h" #include "llvm/DebugInfo/PDB/Raw/DbiStream.h" #include "llvm/DebugInfo/PDB/Raw/EnumTables.h" -#include "llvm/DebugInfo/PDB/Raw/GlobalsStream.h" #include "llvm/DebugInfo/PDB/Raw/ISectionContribVisitor.h" +#include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.h" #include "llvm/DebugInfo/PDB/Raw/InfoStream.h" #include "llvm/DebugInfo/PDB/Raw/ModInfo.h" #include "llvm/DebugInfo/PDB/Raw/ModStream.h" @@ -39,57 +31,15 @@ using namespace llvm; using namespace llvm::codeview; -using namespace llvm::msf; using namespace llvm::pdb; -namespace { -struct PageStats { - explicit PageStats(const BitVector &FreePages) - : Upm(FreePages), ActualUsedPages(FreePages.size()), - MultiUsePages(FreePages.size()), UseAfterFreePages(FreePages.size()) { - const_cast<BitVector &>(Upm).flip(); - // To calculate orphaned pages, we start with the set of pages that the - // MSF thinks are used. Each time we find one that actually *is* used, - // we unset it. Whichever bits remain set at the end are orphaned. - OrphanedPages = Upm; - } - - // The inverse of the MSF File's copy of the Fpm. The basis for which we - // determine the allocation status of each page. - const BitVector Upm; - - // Pages which are marked as used in the FPM and are used at least once. - BitVector ActualUsedPages; - - // Pages which are marked as used in the FPM but are used more than once. - BitVector MultiUsePages; - - // Pages which are marked as used in the FPM but are not used at all. - BitVector OrphanedPages; - - // Pages which are marked free in the FPM but are used. - BitVector UseAfterFreePages; -}; -} - -static void recordKnownUsedPage(PageStats &Stats, uint32_t UsedIndex) { - if (Stats.Upm.test(UsedIndex)) { - if (Stats.ActualUsedPages.test(UsedIndex)) - Stats.MultiUsePages.set(UsedIndex); - Stats.ActualUsedPages.set(UsedIndex); - Stats.OrphanedPages.reset(UsedIndex); - } else { - // The MSF doesn't think this page is used, but it is. - Stats.UseAfterFreePages.set(UsedIndex); - } -} - static void printSectionOffset(llvm::raw_ostream &OS, const SectionOffset &Off) { OS << Off.Off << ", " << Off.Isect; } -LLVMOutputStyle::LLVMOutputStyle(PDBFile &File) : File(File), P(outs()) {} +LLVMOutputStyle::LLVMOutputStyle(PDBFile &File) + : File(File), P(outs()), TD(&P, false) {} Error LLVMOutputStyle::dump() { if (auto EC = dumpFileHeaders()) @@ -98,19 +48,16 @@ Error LLVMOutputStyle::dump() { if (auto EC = dumpStreamSummary()) return EC; - if (auto EC = dumpFreePageMap()) - return EC; - if (auto EC = dumpStreamBlocks()) return EC; - if (auto EC = dumpBlockRanges()) + if (auto EC = dumpStreamData()) return EC; - if (auto EC = dumpStreamBytes()) + if (auto EC = dumpInfoStream()) return EC; - if (auto EC = dumpInfoStream()) + if (auto EC = dumpNamedStream()) return EC; if (auto EC = dumpTpiStream(StreamTPI)) @@ -128,9 +75,6 @@ Error LLVMOutputStyle::dump() { if (auto EC = dumpSectionMap()) return EC; - if (auto EC = dumpGlobalsStream()) - return EC; - if (auto EC = dumpPublicsStream()) return EC; @@ -166,9 +110,9 @@ Error LLVMOutputStyle::dumpFileHeaders() { return Error::success(); } -void LLVMOutputStyle::discoverStreamPurposes() { - if (!StreamPurposes.empty()) - return; +Error LLVMOutputStyle::dumpStreamSummary() { + if (!opts::raw::DumpStreamSummary) + return Error::success(); // It's OK if we fail to load some of these streams, we still attempt to print // what we can. @@ -177,6 +121,7 @@ void LLVMOutputStyle::discoverStreamPurposes() { auto Ipi = File.getPDBIpiStream(); auto Info = File.getPDBInfoStream(); + ListScope L(P, "Streams"); uint32_t StreamCount = File.getNumStreams(); std::unordered_map<uint16_t, const ModuleInfoEx *> ModStreams; std::unordered_map<uint16_t, std::string> NamedStreams; @@ -193,8 +138,9 @@ void LLVMOutputStyle::discoverStreamPurposes() { } } - StreamPurposes.resize(StreamCount); for (uint16_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) { + std::string Label("Stream "); + Label += to_string(StreamIdx); std::string Value; if (StreamIdx == OldMSFDirectory) Value = "Old MSF Directory"; @@ -265,7 +211,11 @@ void LLVMOutputStyle::discoverStreamPurposes() { Value = "???"; } } - StreamPurposes[StreamIdx] = Value; + Value = "[" + Value + "]"; + Value = + Value + " (" + to_string(File.getStreamByteSize(StreamIdx)) + " bytes)"; + + P.printString(Label, Value); } // Consume errors from missing streams. @@ -277,105 +227,11 @@ void LLVMOutputStyle::discoverStreamPurposes() { consumeError(Ipi.takeError()); if (!Info) consumeError(Info.takeError()); -} - -Error LLVMOutputStyle::dumpStreamSummary() { - if (!opts::raw::DumpStreamSummary) - return Error::success(); - - discoverStreamPurposes(); - - uint32_t StreamCount = File.getNumStreams(); - - ListScope L(P, "Streams"); - for (uint16_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) { - std::string Label("Stream "); - Label += to_string(StreamIdx); - - std::string Value = "[" + StreamPurposes[StreamIdx] + "] ("; - Value += to_string(File.getStreamByteSize(StreamIdx)); - Value += " bytes)"; - - P.printString(Label, Value); - } P.flush(); return Error::success(); } -Error LLVMOutputStyle::dumpFreePageMap() { - if (!opts::raw::DumpPageStats) - return Error::success(); - - // Start with used pages instead of free pages because - // the number of free pages is far larger than used pages. - BitVector FPM = File.getMsfLayout().FreePageMap; - - PageStats PS(FPM); - - recordKnownUsedPage(PS, 0); // MSF Super Block - - uint32_t BlocksPerSection = msf::getFpmIntervalLength(File.getMsfLayout()); - uint32_t NumSections = msf::getNumFpmIntervals(File.getMsfLayout()); - for (uint32_t I = 0; I < NumSections; ++I) { - uint32_t Fpm0 = 1 + BlocksPerSection * I; - // 2 Fpm blocks spaced at `getBlockSize()` block intervals - recordKnownUsedPage(PS, Fpm0); - recordKnownUsedPage(PS, Fpm0 + 1); - } - - recordKnownUsedPage(PS, File.getBlockMapIndex()); // Stream Table - - for (auto DB : File.getDirectoryBlockArray()) - recordKnownUsedPage(PS, DB); - - // Record pages used by streams. Note that pages for stream 0 - // are considered being unused because that's what MSVC tools do. - // Stream 0 doesn't contain actual data, so it makes some sense, - // though it's a bit confusing to us. - for (auto &SE : File.getStreamMap().drop_front(1)) - for (auto &S : SE) - recordKnownUsedPage(PS, S); - - dumpBitVector("Msf Free Pages", FPM); - dumpBitVector("Orphaned Pages", PS.OrphanedPages); - dumpBitVector("Multiply Used Pages", PS.MultiUsePages); - dumpBitVector("Use After Free Pages", PS.UseAfterFreePages); - return Error::success(); -} - -void LLVMOutputStyle::dumpBitVector(StringRef Name, const BitVector &V) { - std::vector<uint32_t> Vec; - for (uint32_t I = 0, E = V.size(); I != E; ++I) - if (V[I]) - Vec.push_back(I); - P.printList(Name, Vec); -} - -Error LLVMOutputStyle::dumpGlobalsStream() { - if (!opts::raw::DumpGlobals) - return Error::success(); - if (!File.hasPDBGlobalsStream()) { - P.printString("Globals Stream not present"); - return Error::success(); - } - - auto Globals = File.getPDBGlobalsStream(); - if (!Globals) - return Globals.takeError(); - DictScope D(P, "Globals Stream"); - - auto Dbi = File.getPDBDbiStream(); - if (!Dbi) - return Dbi.takeError(); - - P.printNumber("Stream number", Dbi->getGlobalSymbolStreamIndex()); - P.printNumber("Number of buckets", Globals->getNumBuckets()); - P.printList("Hash Buckets", Globals->getHashBuckets()); - - return Error::success(); -} - Error LLVMOutputStyle::dumpStreamBlocks() { if (!opts::raw::DumpStreamBlocks) return Error::success(); @@ -391,64 +247,29 @@ Error LLVMOutputStyle::dumpStreamBlocks() { return Error::success(); } -Error LLVMOutputStyle::dumpBlockRanges() { - if (!opts::raw::DumpBlockRange.hasValue()) - return Error::success(); - auto &R = *opts::raw::DumpBlockRange; - uint32_t Max = R.Max.getValueOr(R.Min); - - if (Max < R.Min) - return make_error<StringError>( - "Invalid block range specified. Max < Min", - std::make_error_code(std::errc::bad_address)); - if (Max >= File.getBlockCount()) - return make_error<StringError>( - "Invalid block range specified. Requested block out of bounds", - std::make_error_code(std::errc::bad_address)); - - DictScope D(P, "Block Data"); - for (uint32_t I = R.Min; I <= Max; ++I) { - auto ExpectedData = File.getBlockData(I, File.getBlockSize()); - if (!ExpectedData) - return ExpectedData.takeError(); - std::string Label; - llvm::raw_string_ostream S(Label); - S << "Block " << I; - S.flush(); - P.printBinaryBlock(Label, *ExpectedData); - } - - return Error::success(); -} - -Error LLVMOutputStyle::dumpStreamBytes() { - if (opts::raw::DumpStreamData.empty()) +Error LLVMOutputStyle::dumpStreamData() { + uint32_t StreamCount = File.getNumStreams(); + StringRef DumpStreamStr = opts::raw::DumpStreamDataIdx; + uint32_t DumpStreamNum; + if (DumpStreamStr.getAsInteger(/*Radix=*/0U, DumpStreamNum)) return Error::success(); - discoverStreamPurposes(); - - DictScope D(P, "Stream Data"); - for (uint32_t SI : opts::raw::DumpStreamData) { - if (SI >= File.getNumStreams()) - return make_error<RawError>(raw_error_code::no_stream); - - auto S = MappedBlockStream::createIndexedStream(File.getMsfLayout(), - File.getMsfBuffer(), SI); - if (!S) - continue; - DictScope DD(P, "Stream"); - - P.printNumber("Index", SI); - P.printString("Type", StreamPurposes[SI]); - P.printNumber("Size", S->getLength()); - auto Blocks = File.getMsfLayout().StreamMap[SI]; - P.printList("Blocks", Blocks); - - StreamReader R(*S); - ArrayRef<uint8_t> StreamData; - if (auto EC = R.readBytes(StreamData, S->getLength())) + if (DumpStreamNum >= StreamCount) + return make_error<RawError>(raw_error_code::no_stream); + + auto S = MappedBlockStream::createIndexedStream(DumpStreamNum, File); + if (!S) + return S.takeError(); + codeview::StreamReader R(**S); + while (R.bytesRemaining() > 0) { + ArrayRef<uint8_t> Data; + uint32_t BytesToReadInBlock = std::min( + R.bytesRemaining(), static_cast<uint32_t>(File.getBlockSize())); + if (auto EC = R.readBytes(Data, BytesToReadInBlock)) return EC; - P.printBinaryBlock("Data", StreamData); + P.printBinaryBlock( + "Data", + StringRef(reinterpret_cast<const char *>(Data.begin()), Data.size())); } return Error::success(); } @@ -456,10 +277,6 @@ Error LLVMOutputStyle::dumpStreamBytes() { Error LLVMOutputStyle::dumpInfoStream() { if (!opts::raw::DumpHeaders) return Error::success(); - if (!File.hasPDBInfoStream()) { - P.printString("PDB Stream not present"); - return Error::success(); - } auto IS = File.getPDBInfoStream(); if (!IS) return IS.takeError(); @@ -472,6 +289,49 @@ Error LLVMOutputStyle::dumpInfoStream() { return Error::success(); } +Error LLVMOutputStyle::dumpNamedStream() { + if (opts::raw::DumpStreamDataName.empty()) + return Error::success(); + + auto IS = File.getPDBInfoStream(); + if (!IS) + return IS.takeError(); + + uint32_t NameStreamIndex = + IS->getNamedStreamIndex(opts::raw::DumpStreamDataName); + if (NameStreamIndex == 0 || NameStreamIndex >= File.getNumStreams()) + return make_error<RawError>(raw_error_code::no_stream); + + if (NameStreamIndex != 0) { + std::string Name("Stream '"); + Name += opts::raw::DumpStreamDataName; + Name += "'"; + DictScope D(P, Name); + P.printNumber("Index", NameStreamIndex); + + auto NameStream = + MappedBlockStream::createIndexedStream(NameStreamIndex, File); + if (!NameStream) + return NameStream.takeError(); + codeview::StreamReader Reader(**NameStream); + + NameHashTable NameTable; + if (auto EC = NameTable.load(Reader)) + return EC; + + P.printHex("Signature", NameTable.getSignature()); + P.printNumber("Version", NameTable.getHashVersion()); + P.printNumber("Name Count", NameTable.getNameCount()); + ListScope L(P, "Names"); + for (uint32_t ID : NameTable.name_ids()) { + StringRef Str = NameTable.getStringForID(ID); + if (!Str.empty()) + P.printString(to_string(ID), Str); + } + } + return Error::success(); +} + static void printTypeIndexOffset(raw_ostream &OS, const TypeIndexOffset &TIOff) { OS << "{" << TIOff.Type.getIndex() << ", " << TIOff.Offset << "}"; @@ -498,19 +358,11 @@ Error LLVMOutputStyle::dumpTpiStream(uint32_t StreamIdx) { StringRef Label; StringRef VerLabel; if (StreamIdx == StreamTPI) { - if (!File.hasPDBTpiStream()) { - P.printString("Type Info Stream (TPI) not present"); - return Error::success(); - } DumpRecordBytes = opts::raw::DumpTpiRecordBytes; DumpRecords = opts::raw::DumpTpiRecords; Label = "Type Info Stream (TPI)"; VerLabel = "TPI Version"; } else if (StreamIdx == StreamIPI) { - if (!File.hasPDBIpiStream()) { - P.printString("Type Info Stream (IPI) not present"); - return Error::success(); - } DumpRecordBytes = opts::raw::DumpIpiRecordBytes; DumpRecords = opts::raw::DumpIpiRecords; Label = "Type Info Stream (IPI)"; @@ -524,7 +376,6 @@ Error LLVMOutputStyle::dumpTpiStream(uint32_t StreamIdx) { if (!Tpi) return Tpi.takeError(); - CVTypeDumper Dumper(TypeDB); if (DumpRecords || DumpRecordBytes) { DictScope D(P, Label); @@ -538,13 +389,12 @@ Error LLVMOutputStyle::dumpTpiStream(uint32_t StreamIdx) { DictScope DD(P, ""); if (DumpRecords) { - TypeDumpVisitor TDV(TypeDB, &P, false); - if (auto EC = Dumper.dump(Type, TDV)) + if (auto EC = TD.dump(Type)) return EC; } if (DumpRecordBytes) - P.printBinaryBlock("Bytes", Type.content()); + P.printBinaryBlock("Bytes", Type.Data); } dumpTpiHash(P, *Tpi); if (HadError) @@ -552,23 +402,19 @@ Error LLVMOutputStyle::dumpTpiStream(uint32_t StreamIdx) { "TPI stream contained corrupt record"); } else if (opts::raw::DumpModuleSyms) { // Even if the user doesn't want to dump type records, we still need to - // iterate them in order to build the type database. So when they want to - // dump symbols but not types, don't stick a dumper on the end, just build - // the type database. - TypeDatabaseVisitor DBV(TypeDB); - TypeDeserializer Deserializer; - TypeVisitorCallbackPipeline Pipeline; - Pipeline.addCallbackToPipeline(Deserializer); - Pipeline.addCallbackToPipeline(DBV); - - CVTypeVisitor Visitor(Pipeline); + // iterate them in order to build the list of types so that we can print + // them when dumping module symbols. So when they want to dump symbols + // but not types, use a null output stream. + ScopedPrinter *OldP = TD.getPrinter(); + TD.setPrinter(nullptr); bool HadError = false; - for (auto Type : Tpi->types(&HadError)) { - if (auto EC = Visitor.visitTypeRecord(Type)) + for (auto &Type : Tpi->types(&HadError)) { + if (auto EC = TD.dump(Type)) return EC; } + TD.setPrinter(OldP); dumpTpiHash(P, *Tpi); if (HadError) return make_error<RawError>(raw_error_code::corrupt_file, @@ -583,10 +429,6 @@ Error LLVMOutputStyle::dumpDbiStream() { opts::raw::DumpModuleFiles || opts::raw::DumpLineInfo; if (!opts::raw::DumpHeaders && !DumpModules) return Error::success(); - if (!File.hasPDBDbiStream()) { - P.printString("DBI Stream not present"); - return Error::success(); - } auto DS = File.getPDBDbiStream(); if (!DS) @@ -642,28 +484,24 @@ Error LLVMOutputStyle::dumpDbiStream() { (opts::raw::DumpModuleSyms || opts::raw::DumpSymRecordBytes); if (HasModuleDI && (ShouldDumpSymbols || opts::raw::DumpLineInfo)) { auto ModStreamData = MappedBlockStream::createIndexedStream( - File.getMsfLayout(), File.getMsfBuffer(), - Modi.Info.getModuleStreamIndex()); - - ModStream ModS(Modi.Info, std::move(ModStreamData)); + Modi.Info.getModuleStreamIndex(), File); + if (!ModStreamData) + return ModStreamData.takeError(); + ModStream ModS(Modi.Info, std::move(*ModStreamData)); if (auto EC = ModS.reload()) return EC; if (ShouldDumpSymbols) { ListScope SS(P, "Symbols"); - codeview::CVSymbolDumper SD(P, TypeDB, nullptr, false); + codeview::CVSymbolDumper SD(P, TD, nullptr, false); bool HadError = false; - for (auto S : ModS.symbols(&HadError)) { - DictScope LL(P, ""); - if (opts::raw::DumpModuleSyms) { - if (auto EC = SD.dump(S)) { - llvm::consumeError(std::move(EC)); - HadError = true; - break; - } - } + for (const auto &S : ModS.symbols(&HadError)) { + DictScope DD(P, ""); + + if (opts::raw::DumpModuleSyms) + SD.dump(S); if (opts::raw::DumpSymRecordBytes) - P.printBinaryBlock("Bytes", S.content()); + P.printBinaryBlock("Bytes", S.Data); } if (HadError) return make_error<RawError>( @@ -679,7 +517,7 @@ Error LLVMOutputStyle::dumpDbiStream() { public: RecordVisitor(ScopedPrinter &P, PDBFile &F) : P(P), F(F) {} Error visitUnknown(ModuleSubstreamKind Kind, - ReadableStreamRef Stream) override { + StreamRef Stream) override { DictScope DD(P, "Unknown"); ArrayRef<uint8_t> Data; StreamReader R(Stream); @@ -692,7 +530,7 @@ Error LLVMOutputStyle::dumpDbiStream() { return Error::success(); } Error - visitFileChecksums(ReadableStreamRef Data, + visitFileChecksums(StreamRef Data, const FileChecksumArray &Checksums) override { DictScope DD(P, "FileChecksums"); for (const auto &C : Checksums) { @@ -708,8 +546,7 @@ Error LLVMOutputStyle::dumpDbiStream() { return Error::success(); } - Error visitLines(ReadableStreamRef Data, - const LineSubstreamHeader *Header, + Error visitLines(StreamRef Data, const LineSubstreamHeader *Header, const LineInfoArray &Lines) override { DictScope DD(P, "Lines"); for (const auto &L : Lines) { @@ -773,10 +610,6 @@ Error LLVMOutputStyle::dumpDbiStream() { Error LLVMOutputStyle::dumpSectionContribs() { if (!opts::raw::DumpSectionContribs) return Error::success(); - if (!File.hasPDBDbiStream()) { - P.printString("DBI Stream not present"); - return Error::success(); - } auto Dbi = File.getPDBDbiStream(); if (!Dbi) @@ -824,10 +657,6 @@ Error LLVMOutputStyle::dumpSectionContribs() { Error LLVMOutputStyle::dumpSectionMap() { if (!opts::raw::DumpSectionMap) return Error::success(); - if (!File.hasPDBDbiStream()) { - P.printString("DBI Stream not present"); - return Error::success(); - } auto Dbi = File.getPDBDbiStream(); if (!Dbi) @@ -837,6 +666,7 @@ Error LLVMOutputStyle::dumpSectionMap() { for (auto &M : Dbi->getSectionMap()) { DictScope D(P, "Entry"); P.printFlags("Flags", M.Flags, getOMFSegMapDescFlagNames()); + P.printNumber("Flags", M.Flags); P.printNumber("Ovl", M.Ovl); P.printNumber("Group", M.Group); P.printNumber("Frame", M.Frame); @@ -852,15 +682,11 @@ Error LLVMOutputStyle::dumpSectionMap() { Error LLVMOutputStyle::dumpPublicsStream() { if (!opts::raw::DumpPublics) return Error::success(); - if (!File.hasPDBPublicsStream()) { - P.printString("Publics Stream not present"); - return Error::success(); - } + DictScope D(P, "Publics Stream"); auto Publics = File.getPDBPublicsStream(); if (!Publics) return Publics.takeError(); - DictScope D(P, "Publics Stream"); auto Dbi = File.getPDBDbiStream(); if (!Dbi) @@ -876,17 +702,14 @@ Error LLVMOutputStyle::dumpPublicsStream() { P.printList("Section Offsets", Publics->getSectionOffsets(), printSectionOffset); ListScope L(P, "Symbols"); - codeview::CVSymbolDumper SD(P, TypeDB, nullptr, false); + codeview::CVSymbolDumper SD(P, TD, nullptr, false); bool HadError = false; for (auto S : Publics->getSymbols(&HadError)) { DictScope DD(P, ""); - if (auto EC = SD.dump(S)) { - HadError = true; - break; - } + SD.dump(S); if (opts::raw::DumpSymRecordBytes) - P.printBinaryBlock("Bytes", S.content()); + P.printBinaryBlock("Bytes", S.Data); } if (HadError) return make_error<RawError>( @@ -899,10 +722,6 @@ Error LLVMOutputStyle::dumpPublicsStream() { Error LLVMOutputStyle::dumpSectionHeaders() { if (!opts::raw::DumpSectionHeaders) return Error::success(); - if (!File.hasPDBDbiStream()) { - P.printString("DBI Stream not present"); - return Error::success(); - } auto Dbi = File.getPDBDbiStream(); if (!Dbi) @@ -932,10 +751,6 @@ Error LLVMOutputStyle::dumpSectionHeaders() { Error LLVMOutputStyle::dumpFpoStream() { if (!opts::raw::DumpFpo) return Error::success(); - if (!File.hasPDBDbiStream()) { - P.printString("DBI Stream not present"); - return Error::success(); - } auto Dbi = File.getPDBDbiStream(); if (!Dbi) diff --git a/gnu/llvm/tools/llvm-pdbdump/LLVMOutputStyle.h b/gnu/llvm/tools/llvm-pdbdump/LLVMOutputStyle.h index 816d591f08f..77935d10220 100644 --- a/gnu/llvm/tools/llvm-pdbdump/LLVMOutputStyle.h +++ b/gnu/llvm/tools/llvm-pdbdump/LLVMOutputStyle.h @@ -12,11 +12,10 @@ #include "OutputStyle.h" -#include "llvm/DebugInfo/CodeView/TypeDatabase.h" +#include "llvm/DebugInfo/CodeView/TypeDumper.h" #include "llvm/Support/ScopedPrinter.h" namespace llvm { -class BitVector; namespace pdb { class LLVMOutputStyle : public OutputStyle { public: @@ -25,16 +24,12 @@ public: Error dump() override; private: - void discoverStreamPurposes(); - Error dumpFileHeaders(); Error dumpStreamSummary(); - Error dumpFreePageMap(); - Error dumpBlockRanges(); - Error dumpGlobalsStream(); - Error dumpStreamBytes(); Error dumpStreamBlocks(); + Error dumpStreamData(); Error dumpInfoStream(); + Error dumpNamedStream(); Error dumpTpiStream(uint32_t StreamIdx); Error dumpDbiStream(); Error dumpSectionContribs(); @@ -43,14 +38,11 @@ private: Error dumpSectionHeaders(); Error dumpFpoStream(); - void dumpBitVector(StringRef Name, const BitVector &V); - void flush(); PDBFile &File; ScopedPrinter P; - codeview::TypeDatabase TypeDB; - std::vector<std::string> StreamPurposes; + codeview::CVTypeDumper TD; }; } } diff --git a/gnu/llvm/tools/llvm-pdbdump/PdbYaml.cpp b/gnu/llvm/tools/llvm-pdbdump/PdbYaml.cpp index 34e0611e146..e83f24e8774 100644 --- a/gnu/llvm/tools/llvm-pdbdump/PdbYaml.cpp +++ b/gnu/llvm/tools/llvm-pdbdump/PdbYaml.cpp @@ -9,38 +9,16 @@ #include "PdbYaml.h" -#include "YamlSerializationContext.h" -#include "YamlSymbolDumper.h" -#include "YamlTypeDumper.h" - -#include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h" -#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" -#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" -#include "llvm/DebugInfo/CodeView/SymbolVisitorCallbackPipeline.h" -#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" -#include "llvm/DebugInfo/CodeView/TypeSerializer.h" -#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h" #include "llvm/DebugInfo/PDB/PDBExtras.h" -#include "llvm/DebugInfo/PDB/PDBTypes.h" #include "llvm/DebugInfo/PDB/Raw/PDBFile.h" -#include "llvm/DebugInfo/PDB/Raw/TpiHashing.h" using namespace llvm; +using namespace llvm::yaml; using namespace llvm::pdb; using namespace llvm::pdb::yaml; -using namespace llvm::yaml; - -LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(uint32_t) -LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::StringRef) -LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::NamedStreamMapping) -LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::PdbDbiModuleInfo) -LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::PdbSymbolRecord) -LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::PdbTpiRecord) -LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::StreamBlockList) namespace llvm { namespace yaml { - template <> struct ScalarTraits<llvm::pdb::PDB_UniqueId> { static void output(const llvm::pdb::PDB_UniqueId &S, void *, llvm::raw_ostream &OS) { @@ -57,7 +35,7 @@ template <> struct ScalarTraits<llvm::pdb::PDB_UniqueId> { Scalar[24] != '-') return "GUID sections are not properly delineated with dashes"; - uint8_t *OutBuffer = S.Guid; + char *OutBuffer = S.Guid; for (auto Iter = Scalar.begin(); Iter != Scalar.end();) { if (*Iter == '-' || *Iter == '{' || *Iter == '}') { ++Iter; @@ -123,16 +101,6 @@ template <> struct ScalarEnumerationTraits<llvm::pdb::PdbRaw_ImplVer> { io.enumCase(Value, "VC140", llvm::pdb::PdbRaw_ImplVer::PdbImplVC140); } }; - -template <> struct ScalarEnumerationTraits<llvm::pdb::PdbRaw_TpiVer> { - static void enumeration(IO &io, llvm::pdb::PdbRaw_TpiVer &Value) { - io.enumCase(Value, "VC40", llvm::pdb::PdbRaw_TpiVer::PdbTpiV40); - io.enumCase(Value, "VC41", llvm::pdb::PdbRaw_TpiVer::PdbTpiV41); - io.enumCase(Value, "VC50", llvm::pdb::PdbRaw_TpiVer::PdbTpiV50); - io.enumCase(Value, "VC70", llvm::pdb::PdbRaw_TpiVer::PdbTpiV70); - io.enumCase(Value, "VC80", llvm::pdb::PdbRaw_TpiVer::PdbTpiV80); - } -}; } } @@ -142,11 +110,9 @@ void MappingTraits<PdbObject>::mapping(IO &IO, PdbObject &Obj) { IO.mapOptional("StreamMap", Obj.StreamMap); IO.mapOptional("PdbStream", Obj.PdbStream); IO.mapOptional("DbiStream", Obj.DbiStream); - IO.mapOptionalWithContext("TpiStream", Obj.TpiStream, Obj.Allocator); - IO.mapOptionalWithContext("IpiStream", Obj.IpiStream, Obj.Allocator); } -void MappingTraits<MSFHeaders>::mapping(IO &IO, MSFHeaders &Obj) { +void MappingTraits<MsfHeaders>::mapping(IO &IO, MsfHeaders &Obj) { IO.mapRequired("SuperBlock", Obj.SuperBlock); IO.mapRequired("NumDirectoryBlocks", Obj.NumDirectoryBlocks); IO.mapRequired("DirectoryBlocks", Obj.DirectoryBlocks); @@ -187,21 +153,6 @@ void MappingTraits<PdbDbiStream>::mapping(IO &IO, PdbDbiStream &Obj) { IO.mapRequired("PdbDllRbld", Obj.PdbDllRbld); IO.mapRequired("Flags", Obj.Flags); IO.mapRequired("MachineType", Obj.MachineType); - IO.mapOptional("Modules", Obj.ModInfos); -} - -void MappingContextTraits<PdbTpiStream, BumpPtrAllocator>::mapping( - IO &IO, pdb::yaml::PdbTpiStream &Obj, BumpPtrAllocator &Allocator) { - // Create a single serialization context that will be passed through the - // entire process of serializing / deserializing a Tpi Stream. This is - // especially important when we are going from Pdb -> Yaml because we need - // to maintain state in a TypeTableBuilder across mappings, and at the end of - // the entire process, we need to have one TypeTableBuilder that has every - // record. - pdb::yaml::SerializationContext Context(IO, Allocator); - - IO.mapRequired("Version", Obj.Version); - IO.mapRequired("Records", Obj.Records, Context); } void MappingTraits<NamedStreamMapping>::mapping(IO &IO, @@ -209,62 +160,3 @@ void MappingTraits<NamedStreamMapping>::mapping(IO &IO, IO.mapRequired("Name", Obj.StreamName); IO.mapRequired("StreamNum", Obj.StreamNumber); } - -void MappingTraits<PdbSymbolRecord>::mapping(IO &IO, PdbSymbolRecord &Obj) { - codeview::SymbolVisitorCallbackPipeline Pipeline; - codeview::SymbolDeserializer Deserializer(nullptr); - codeview::yaml::YamlSymbolDumper Dumper(IO); - - if (IO.outputting()) { - // For PDB to Yaml, deserialize into a high level record type, then dump it. - Pipeline.addCallbackToPipeline(Deserializer); - Pipeline.addCallbackToPipeline(Dumper); - } else { - return; - } - - codeview::CVSymbolVisitor Visitor(Pipeline); - consumeError(Visitor.visitSymbolRecord(Obj.Record)); -} - -void MappingTraits<PdbModiStream>::mapping(IO &IO, PdbModiStream &Obj) { - IO.mapRequired("Signature", Obj.Signature); - IO.mapRequired("Records", Obj.Symbols); -} - -void MappingTraits<PdbDbiModuleInfo>::mapping(IO &IO, PdbDbiModuleInfo &Obj) { - IO.mapRequired("Module", Obj.Mod); - IO.mapRequired("ObjFile", Obj.Obj); - IO.mapOptional("SourceFiles", Obj.SourceFiles); - IO.mapOptional("Modi", Obj.Modi); -} - -void MappingContextTraits<PdbTpiRecord, pdb::yaml::SerializationContext>:: - mapping(IO &IO, pdb::yaml::PdbTpiRecord &Obj, - pdb::yaml::SerializationContext &Context) { - codeview::TypeVisitorCallbackPipeline Pipeline; - codeview::TypeDeserializer Deserializer; - codeview::TypeSerializer Serializer(Context.Allocator); - pdb::TpiHashUpdater Hasher; - - if (IO.outputting()) { - // For PDB to Yaml, deserialize into a high level record type, then dump it. - Pipeline.addCallbackToPipeline(Deserializer); - Pipeline.addCallbackToPipeline(Context.Dumper); - } else { - // For Yaml to PDB, extract from the high level record type, then write it - // to bytes. - - // This might be interpreted as a hack, but serializing FieldList - // sub-records requires having access to the same serializer being used by - // the FieldList itself. - Context.ActiveSerializer = &Serializer; - Pipeline.addCallbackToPipeline(Context.Dumper); - Pipeline.addCallbackToPipeline(Serializer); - Pipeline.addCallbackToPipeline(Hasher); - } - - codeview::CVTypeVisitor Visitor(Pipeline); - consumeError(Visitor.visitTypeRecord(Obj.Record)); - Context.ActiveSerializer = nullptr; -} diff --git a/gnu/llvm/tools/llvm-pdbdump/PdbYaml.h b/gnu/llvm/tools/llvm-pdbdump/PdbYaml.h index 398186f16d7..a7389af2205 100644 --- a/gnu/llvm/tools/llvm-pdbdump/PdbYaml.h +++ b/gnu/llvm/tools/llvm-pdbdump/PdbYaml.h @@ -13,10 +13,8 @@ #include "OutputStyle.h" #include "llvm/ADT/Optional.h" -#include "llvm/DebugInfo/CodeView/SymbolRecord.h" -#include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/DebugInfo/MSF/MSFCommon.h" #include "llvm/DebugInfo/PDB/PDBTypes.h" +#include "llvm/DebugInfo/PDB/Raw/MsfCommon.h" #include "llvm/DebugInfo/PDB/Raw/PDBFile.h" #include "llvm/DebugInfo/PDB/Raw/RawConstants.h" #include "llvm/Support/Endian.h" @@ -28,9 +26,7 @@ namespace llvm { namespace pdb { namespace yaml { -struct SerializationContext; - -struct MSFHeaders { +struct MsfHeaders { msf::SuperBlock SuperBlock; uint32_t NumDirectoryBlocks; std::vector<uint32_t> DirectoryBlocks; @@ -55,22 +51,6 @@ struct PdbInfoStream { std::vector<NamedStreamMapping> NamedStreams; }; -struct PdbSymbolRecord { - codeview::CVSymbol Record; -}; - -struct PdbModiStream { - uint32_t Signature; - std::vector<PdbSymbolRecord> Symbols; -}; - -struct PdbDbiModuleInfo { - StringRef Obj; - StringRef Mod; - std::vector<StringRef> SourceFiles; - Optional<PdbModiStream> Modi; -}; - struct PdbDbiStream { PdbRaw_DbiVer VerHeader; uint32_t Age; @@ -79,35 +59,14 @@ struct PdbDbiStream { uint16_t PdbDllRbld; uint16_t Flags; PDB_Machine MachineType; - - std::vector<PdbDbiModuleInfo> ModInfos; -}; - -struct PdbTpiRecord { - codeview::CVType Record; -}; - -struct PdbTpiFieldListRecord { - codeview::CVMemberRecord Record; -}; - -struct PdbTpiStream { - PdbRaw_TpiVer Version; - std::vector<PdbTpiRecord> Records; }; struct PdbObject { - explicit PdbObject(BumpPtrAllocator &Allocator) : Allocator(Allocator) {} - - Optional<MSFHeaders> Headers; + Optional<MsfHeaders> Headers; Optional<std::vector<uint32_t>> StreamSizes; Optional<std::vector<StreamBlockList>> StreamMap; Optional<PdbInfoStream> PdbStream; Optional<PdbDbiStream> DbiStream; - Optional<PdbTpiStream> TpiStream; - Optional<PdbTpiStream> IpiStream; - - BumpPtrAllocator &Allocator; }; } } @@ -120,12 +79,12 @@ template <> struct MappingTraits<pdb::yaml::PdbObject> { static void mapping(IO &IO, pdb::yaml::PdbObject &Obj); }; -template <> struct MappingTraits<pdb::yaml::MSFHeaders> { - static void mapping(IO &IO, pdb::yaml::MSFHeaders &Obj); +template <> struct MappingTraits<pdb::yaml::MsfHeaders> { + static void mapping(IO &IO, pdb::yaml::MsfHeaders &Obj); }; -template <> struct MappingTraits<msf::SuperBlock> { - static void mapping(IO &IO, msf::SuperBlock &SB); +template <> struct MappingTraits<pdb::msf::SuperBlock> { + static void mapping(IO &IO, pdb::msf::SuperBlock &SB); }; template <> struct MappingTraits<pdb::yaml::StreamBlockList> { @@ -140,35 +99,14 @@ template <> struct MappingTraits<pdb::yaml::PdbDbiStream> { static void mapping(IO &IO, pdb::yaml::PdbDbiStream &Obj); }; -template <> -struct MappingContextTraits<pdb::yaml::PdbTpiStream, llvm::BumpPtrAllocator> { - static void mapping(IO &IO, pdb::yaml::PdbTpiStream &Obj, - llvm::BumpPtrAllocator &Allocator); -}; - template <> struct MappingTraits<pdb::yaml::NamedStreamMapping> { static void mapping(IO &IO, pdb::yaml::NamedStreamMapping &Obj); }; - -template <> struct MappingTraits<pdb::yaml::PdbSymbolRecord> { - static void mapping(IO &IO, pdb::yaml::PdbSymbolRecord &Obj); -}; - -template <> struct MappingTraits<pdb::yaml::PdbModiStream> { - static void mapping(IO &IO, pdb::yaml::PdbModiStream &Obj); -}; - -template <> struct MappingTraits<pdb::yaml::PdbDbiModuleInfo> { - static void mapping(IO &IO, pdb::yaml::PdbDbiModuleInfo &Obj); -}; - -template <> -struct MappingContextTraits<pdb::yaml::PdbTpiRecord, - pdb::yaml::SerializationContext> { - static void mapping(IO &IO, pdb::yaml::PdbTpiRecord &Obj, - pdb::yaml::SerializationContext &Context); -}; } } +LLVM_YAML_IS_SEQUENCE_VECTOR(uint32_t) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::NamedStreamMapping) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::StreamBlockList) + #endif // LLVM_TOOLS_LLVMPDBDUMP_PDBYAML_H diff --git a/gnu/llvm/tools/llvm-pdbdump/YAMLOutputStyle.cpp b/gnu/llvm/tools/llvm-pdbdump/YAMLOutputStyle.cpp index 3f2733d701a..a8b6202d5d1 100644 --- a/gnu/llvm/tools/llvm-pdbdump/YAMLOutputStyle.cpp +++ b/gnu/llvm/tools/llvm-pdbdump/YAMLOutputStyle.cpp @@ -12,29 +12,19 @@ #include "PdbYaml.h" #include "llvm-pdbdump.h" -#include "llvm/DebugInfo/MSF/MappedBlockStream.h" #include "llvm/DebugInfo/PDB/Raw/DbiStream.h" #include "llvm/DebugInfo/PDB/Raw/InfoStream.h" -#include "llvm/DebugInfo/PDB/Raw/ModStream.h" #include "llvm/DebugInfo/PDB/Raw/PDBFile.h" #include "llvm/DebugInfo/PDB/Raw/RawConstants.h" -#include "llvm/DebugInfo/PDB/Raw/TpiStream.h" using namespace llvm; using namespace llvm::pdb; -YAMLOutputStyle::YAMLOutputStyle(PDBFile &File) - : File(File), Out(outs()), Obj(File.getAllocator()) {} +YAMLOutputStyle::YAMLOutputStyle(PDBFile &File) : File(File), Out(outs()) {} Error YAMLOutputStyle::dump() { if (opts::pdb2yaml::StreamDirectory) opts::pdb2yaml::StreamMetadata = true; - if (opts::pdb2yaml::DbiModuleSyms) - opts::pdb2yaml::DbiModuleInfo = true; - if (opts::pdb2yaml::DbiModuleSourceFileInfo) - opts::pdb2yaml::DbiModuleInfo = true; - if (opts::pdb2yaml::DbiModuleInfo) - opts::pdb2yaml::DbiStream = true; if (auto EC = dumpFileHeaders()) return EC; @@ -51,12 +41,6 @@ Error YAMLOutputStyle::dump() { if (auto EC = dumpDbiStream()) return EC; - if (auto EC = dumpTpiStream()) - return EC; - - if (auto EC = dumpIpiStream()) - return EC; - flush(); return Error::success(); } @@ -65,7 +49,7 @@ Error YAMLOutputStyle::dumpFileHeaders() { if (opts::pdb2yaml::NoFileHeaders) return Error::success(); - yaml::MSFHeaders Headers; + yaml::MsfHeaders Headers; Obj.Headers.emplace(); Obj.Headers->SuperBlock.NumBlocks = File.getBlockCount(); Obj.Headers->SuperBlock.BlockMapAddr = File.getBlockMapIndex(); @@ -149,79 +133,6 @@ Error YAMLOutputStyle::dumpDbiStream() { Obj.DbiStream->PdbDllRbld = DS.getPdbDllRbld(); Obj.DbiStream->PdbDllVersion = DS.getPdbDllVersion(); Obj.DbiStream->VerHeader = DS.getDbiVersion(); - if (opts::pdb2yaml::DbiModuleInfo) { - for (const auto &MI : DS.modules()) { - yaml::PdbDbiModuleInfo DMI; - DMI.Mod = MI.Info.getModuleName(); - DMI.Obj = MI.Info.getObjFileName(); - if (opts::pdb2yaml::DbiModuleSourceFileInfo) - DMI.SourceFiles = MI.SourceFiles; - - if (opts::pdb2yaml::DbiModuleSyms && - MI.Info.getModuleStreamIndex() != kInvalidStreamIndex) { - DMI.Modi.emplace(); - auto ModStreamData = msf::MappedBlockStream::createIndexedStream( - File.getMsfLayout(), File.getMsfBuffer(), - MI.Info.getModuleStreamIndex()); - - pdb::ModStream ModS(MI.Info, std::move(ModStreamData)); - if (auto EC = ModS.reload()) - return EC; - - DMI.Modi->Signature = ModS.signature(); - bool HadError = false; - for (auto &Sym : ModS.symbols(&HadError)) { - pdb::yaml::PdbSymbolRecord Record{Sym}; - DMI.Modi->Symbols.push_back(Record); - } - } - Obj.DbiStream->ModInfos.push_back(DMI); - } - } - return Error::success(); -} - -Error YAMLOutputStyle::dumpTpiStream() { - if (!opts::pdb2yaml::TpiStream) - return Error::success(); - - auto TpiS = File.getPDBTpiStream(); - if (!TpiS) - return TpiS.takeError(); - - auto &TS = TpiS.get(); - Obj.TpiStream.emplace(); - Obj.TpiStream->Version = TS.getTpiVersion(); - for (auto &Record : TS.types(nullptr)) { - yaml::PdbTpiRecord R; - // It's not necessary to set R.RecordData here. That only exists as a - // way to have the `PdbTpiRecord` structure own the memory that `R.Record` - // references. In the case of reading an existing PDB though, that memory - // is owned by the backing stream. - R.Record = Record; - Obj.TpiStream->Records.push_back(R); - } - - return Error::success(); -} - -Error YAMLOutputStyle::dumpIpiStream() { - if (!opts::pdb2yaml::IpiStream) - return Error::success(); - - auto IpiS = File.getPDBIpiStream(); - if (!IpiS) - return IpiS.takeError(); - - auto &IS = IpiS.get(); - Obj.IpiStream.emplace(); - Obj.IpiStream->Version = IS.getTpiVersion(); - for (auto &Record : IS.types(nullptr)) { - yaml::PdbTpiRecord R; - R.Record = Record; - Obj.IpiStream->Records.push_back(R); - } - return Error::success(); } diff --git a/gnu/llvm/tools/llvm-pdbdump/YAMLOutputStyle.h b/gnu/llvm/tools/llvm-pdbdump/YAMLOutputStyle.h index 3cd603a95b6..d36dfec5f25 100644 --- a/gnu/llvm/tools/llvm-pdbdump/YAMLOutputStyle.h +++ b/gnu/llvm/tools/llvm-pdbdump/YAMLOutputStyle.h @@ -13,7 +13,7 @@ #include "OutputStyle.h" #include "PdbYaml.h" -#include "llvm/DebugInfo/CodeView/CVTypeDumper.h" +#include "llvm/DebugInfo/CodeView/TypeDumper.h" #include "llvm/Support/ScopedPrinter.h" #include "llvm/Support/YAMLTraits.h" @@ -31,8 +31,6 @@ private: Error dumpStreamDirectory(); Error dumpPDBStream(); Error dumpDbiStream(); - Error dumpTpiStream(); - Error dumpIpiStream(); void flush(); diff --git a/gnu/llvm/unittests/DebugInfo/PDB/ErrorChecking.h b/gnu/llvm/unittests/DebugInfo/PDB/ErrorChecking.h index 6d4a7de7834..da734a9b1b5 100644 --- a/gnu/llvm/unittests/DebugInfo/PDB/ErrorChecking.h +++ b/gnu/llvm/unittests/DebugInfo/PDB/ErrorChecking.h @@ -36,14 +36,6 @@ } \ } -#define EXPECT_UNEXPECTED(Exp) \ - { \ - auto E = Exp.takeError(); \ - EXPECT_TRUE(static_cast<bool>(E)); \ - if (E) { \ - consumeError(std::move(E)); \ - return; \ - } \ - } +#define EXPECT_UNEXPECTED(Exp) EXPECT_ERROR(Err) #endif diff --git a/gnu/llvm/unittests/Transforms/Utils/MemorySSA.cpp b/gnu/llvm/unittests/Transforms/Utils/MemorySSA.cpp index 945fe32c316..c21121f7870 100644 --- a/gnu/llvm/unittests/Transforms/Utils/MemorySSA.cpp +++ b/gnu/llvm/unittests/Transforms/Utils/MemorySSA.cpp @@ -42,17 +42,14 @@ protected: AssumptionCache AC; AAResults AA; BasicAAResult BAA; - // We need to defer MSSA construction until AA is *entirely* set up, which - // requires calling addAAResult. Hence, we just use a pointer here. - std::unique_ptr<MemorySSA> MSSA; + MemorySSA MSSA; MemorySSAWalker *Walker; TestAnalyses(MemorySSATest &Test) : DT(*Test.F), AC(*Test.F), AA(Test.TLI), - BAA(Test.DL, Test.TLI, AC, &DT) { + BAA(Test.DL, Test.TLI, AC, &DT), MSSA(*Test.F, &AA, &DT) { AA.addAAResult(BAA); - MSSA = make_unique<MemorySSA>(*Test.F, &AA, &DT); - Walker = MSSA->getWalker(); + Walker = MSSA.getWalker(); } }; @@ -68,10 +65,10 @@ public: : M("MemorySSATest", C), B(C), DL(DLString), TLI(TLII), F(nullptr) {} }; -TEST_F(MemorySSATest, CreateALoad) { +TEST_F(MemorySSATest, CreateALoadAndPhi) { // We create a diamond where there is a store on one side, and then after - // building MemorySSA, create a load after the merge point, and use it to test - // updating by creating an access for the load. + // running memory ssa, create a load after the merge point, and use it to test + // updating by creating an access for the load and a memoryphi. F = Function::Create( FunctionType::get(B.getVoidTy(), {B.getInt8PtrTy()}, false), GlobalValue::ExternalLinkage, "F", &M); @@ -83,19 +80,23 @@ TEST_F(MemorySSATest, CreateALoad) { B.CreateCondBr(B.getTrue(), Left, Right); B.SetInsertPoint(Left); Argument *PointerArg = &*F->arg_begin(); - B.CreateStore(B.getInt8(16), PointerArg); + StoreInst *StoreInst = B.CreateStore(B.getInt8(16), PointerArg); BranchInst::Create(Merge, Left); BranchInst::Create(Merge, Right); setupAnalyses(); - MemorySSA &MSSA = *Analyses->MSSA; + MemorySSA &MSSA = Analyses->MSSA; // Add the load B.SetInsertPoint(Merge); LoadInst *LoadInst = B.CreateLoad(PointerArg); + // Should be no phi to start + EXPECT_EQ(MSSA.getMemoryAccess(Merge), nullptr); - // MemoryPHI should already exist. - MemoryPhi *MP = MSSA.getMemoryAccess(Merge); - EXPECT_NE(MP, nullptr); + // Create the phi + MemoryPhi *MP = MSSA.createMemoryPhi(Merge); + MemoryDef *StoreAccess = cast<MemoryDef>(MSSA.getMemoryAccess(StoreInst)); + MP->addIncoming(StoreAccess, Left); + MP->addIncoming(MSSA.getLiveOnEntryDef(), Right); // Create the load memory acccess MemoryUse *LoadAccess = cast<MemoryUse>( @@ -105,41 +106,6 @@ TEST_F(MemorySSATest, CreateALoad) { MSSA.verifyMemorySSA(); } -TEST_F(MemorySSATest, MoveAStore) { - // We create a diamond where there is a in the entry, a store on one side, and - // a load at the end. After building MemorySSA, we test updating by moving - // the store from the side block to the entry block. - F = Function::Create( - FunctionType::get(B.getVoidTy(), {B.getInt8PtrTy()}, false), - GlobalValue::ExternalLinkage, "F", &M); - BasicBlock *Entry(BasicBlock::Create(C, "", F)); - BasicBlock *Left(BasicBlock::Create(C, "", F)); - BasicBlock *Right(BasicBlock::Create(C, "", F)); - BasicBlock *Merge(BasicBlock::Create(C, "", F)); - B.SetInsertPoint(Entry); - Argument *PointerArg = &*F->arg_begin(); - StoreInst *EntryStore = B.CreateStore(B.getInt8(16), PointerArg); - B.CreateCondBr(B.getTrue(), Left, Right); - B.SetInsertPoint(Left); - StoreInst *SideStore = B.CreateStore(B.getInt8(16), PointerArg); - BranchInst::Create(Merge, Left); - BranchInst::Create(Merge, Right); - B.SetInsertPoint(Merge); - B.CreateLoad(PointerArg); - setupAnalyses(); - MemorySSA &MSSA = *Analyses->MSSA; - - // Move the store - SideStore->moveBefore(Entry->getTerminator()); - MemoryAccess *EntryStoreAccess = MSSA.getMemoryAccess(EntryStore); - MemoryAccess *SideStoreAccess = MSSA.getMemoryAccess(SideStore); - MemoryAccess *NewStoreAccess = MSSA.createMemoryAccessAfter( - SideStore, EntryStoreAccess, EntryStoreAccess); - EntryStoreAccess->replaceAllUsesWith(NewStoreAccess); - MSSA.removeMemoryAccess(SideStoreAccess); - MSSA.verifyMemorySSA(); -} - TEST_F(MemorySSATest, RemoveAPhi) { // We create a diamond where there is a store on one side, and then a load // after the merge point. This enables us to test a bunch of different @@ -162,7 +128,7 @@ TEST_F(MemorySSATest, RemoveAPhi) { LoadInst *LoadInst = B.CreateLoad(PointerArg); setupAnalyses(); - MemorySSA &MSSA = *Analyses->MSSA; + MemorySSA &MSSA = Analyses->MSSA; // Before, the load will be a use of a phi<store, liveonentry>. MemoryUse *LoadAccess = cast<MemoryUse>(MSSA.getMemoryAccess(LoadInst)); MemoryDef *StoreAccess = cast<MemoryDef>(MSSA.getMemoryAccess(StoreInst)); @@ -205,7 +171,7 @@ TEST_F(MemorySSATest, RemoveMemoryAccess) { LoadInst *LoadInst = B.CreateLoad(PointerArg); setupAnalyses(); - MemorySSA &MSSA = *Analyses->MSSA; + MemorySSA &MSSA = Analyses->MSSA; MemorySSAWalker *Walker = Analyses->Walker; // Before, the load will be a use of a phi<store, liveonentry>. It should be @@ -225,15 +191,9 @@ TEST_F(MemorySSATest, RemoveMemoryAccess) { // but we should now get live on entry for the clobbering definition of the // load, since it will walk past the phi node since every argument is the // same. - // XXX: This currently requires either removing the phi or resetting optimized - // on the load - - EXPECT_FALSE( - MSSA.isLiveOnEntryDef(Walker->getClobberingMemoryAccess(LoadInst))); - // If we reset optimized, we get live on entry. - LoadAccess->resetOptimized(); EXPECT_TRUE( MSSA.isLiveOnEntryDef(Walker->getClobberingMemoryAccess(LoadInst))); + // The phi should now be a two entry phi with two live on entry defs. for (const auto &Op : DefiningAccess->operands()) { MemoryAccess *Operand = cast<MemoryAccess>(&*Op); @@ -270,13 +230,14 @@ TEST_F(MemorySSATest, TestTripleStore) { StoreInst *S3 = B.CreateStore(ConstantInt::get(Int8, 2), Alloca); setupAnalyses(); - MemorySSA &MSSA = *Analyses->MSSA; + MemorySSA &MSSA = Analyses->MSSA; MemorySSAWalker *Walker = Analyses->Walker; unsigned I = 0; for (StoreInst *V : {S1, S2, S3}) { // Everything should be clobbered by its defining access - MemoryAccess *DefiningAccess = MSSA.getMemoryAccess(V)->getDefiningAccess(); + MemoryAccess *DefiningAccess = + cast<MemoryUseOrDef>(MSSA.getMemoryAccess(V))->getDefiningAccess(); MemoryAccess *WalkerClobber = Walker->getClobberingMemoryAccess(V); EXPECT_EQ(DefiningAccess, WalkerClobber) << "Store " << I << " doesn't have the correct clobbering access"; @@ -300,7 +261,7 @@ TEST_F(MemorySSATest, TestStoreAndLoad) { Instruction *LI = B.CreateLoad(Alloca); setupAnalyses(); - MemorySSA &MSSA = *Analyses->MSSA; + MemorySSA &MSSA = Analyses->MSSA; MemorySSAWalker *Walker = Analyses->Walker; MemoryAccess *LoadClobber = Walker->getClobberingMemoryAccess(LI); @@ -329,7 +290,7 @@ TEST_F(MemorySSATest, TestStoreDoubleQuery) { StoreInst *SI = B.CreateStore(ConstantInt::get(Int8, 0), Alloca); setupAnalyses(); - MemorySSA &MSSA = *Analyses->MSSA; + MemorySSA &MSSA = Analyses->MSSA; MemorySSAWalker *Walker = Analyses->Walker; MemoryAccess *StoreAccess = MSSA.getMemoryAccess(SI); @@ -347,188 +308,3 @@ TEST_F(MemorySSATest, TestStoreDoubleQuery) { EXPECT_EQ(Clobber, StoreAccess); EXPECT_TRUE(MSSA.isLiveOnEntryDef(LiveOnEntry)); } - -// Bug: During phi optimization, the walker wouldn't cache to the proper result -// in the farthest-walked BB. -// -// Specifically, it would assume that whatever we walked to was a clobber. -// "Whatever we walked to" isn't a clobber if we hit a cache entry. -// -// ...So, we need a test case that looks like: -// A -// / \ -// B | -// \ / -// C -// -// Where, when we try to optimize a thing in 'C', a blocker is found in 'B'. -// The walk must determine that the blocker exists by using cache entries *while -// walking* 'B'. -TEST_F(MemorySSATest, PartialWalkerCacheWithPhis) { - F = Function::Create(FunctionType::get(B.getVoidTy(), {}, false), - GlobalValue::ExternalLinkage, "F", &M); - B.SetInsertPoint(BasicBlock::Create(C, "A", F)); - Type *Int8 = Type::getInt8Ty(C); - Constant *One = ConstantInt::get(Int8, 1); - Constant *Zero = ConstantInt::get(Int8, 0); - Value *AllocA = B.CreateAlloca(Int8, One, "a"); - Value *AllocB = B.CreateAlloca(Int8, One, "b"); - BasicBlock *IfThen = BasicBlock::Create(C, "B", F); - BasicBlock *IfEnd = BasicBlock::Create(C, "C", F); - - B.CreateCondBr(UndefValue::get(Type::getInt1Ty(C)), IfThen, IfEnd); - - B.SetInsertPoint(IfThen); - Instruction *FirstStore = B.CreateStore(Zero, AllocA); - B.CreateStore(Zero, AllocB); - Instruction *ALoad0 = B.CreateLoad(AllocA, ""); - Instruction *BStore = B.CreateStore(Zero, AllocB); - // Due to use optimization/etc. we make a store to A, which is removed after - // we build MSSA. This helps keep the test case simple-ish. - Instruction *KillStore = B.CreateStore(Zero, AllocA); - Instruction *ALoad = B.CreateLoad(AllocA, ""); - B.CreateBr(IfEnd); - - B.SetInsertPoint(IfEnd); - Instruction *BelowPhi = B.CreateStore(Zero, AllocA); - - setupAnalyses(); - MemorySSA &MSSA = *Analyses->MSSA; - MemorySSAWalker *Walker = Analyses->Walker; - - // Kill `KillStore`; it exists solely so that the load after it won't be - // optimized to FirstStore. - MSSA.removeMemoryAccess(MSSA.getMemoryAccess(KillStore)); - KillStore->eraseFromParent(); - auto *ALoadMA = cast<MemoryUse>(MSSA.getMemoryAccess(ALoad)); - EXPECT_EQ(ALoadMA->getDefiningAccess(), MSSA.getMemoryAccess(BStore)); - - // Populate the cache for the store to AllocB directly after FirstStore. It - // should point to something in block B (so something in D can't be optimized - // to it). - MemoryAccess *Load0Clobber = Walker->getClobberingMemoryAccess(ALoad0); - EXPECT_EQ(MSSA.getMemoryAccess(FirstStore), Load0Clobber); - - // If the bug exists, this will introduce a bad cache entry for %a on BStore. - // It will point to the store to %b after FirstStore. This only happens during - // phi optimization. - MemoryAccess *BottomClobber = Walker->getClobberingMemoryAccess(BelowPhi); - MemoryAccess *Phi = MSSA.getMemoryAccess(IfEnd); - EXPECT_EQ(BottomClobber, Phi); - - // This query will first check the cache for {%a, BStore}. It should point to - // FirstStore, not to the store after FirstStore. - MemoryAccess *UseClobber = Walker->getClobberingMemoryAccess(ALoad); - EXPECT_EQ(UseClobber, MSSA.getMemoryAccess(FirstStore)); -} - -// Test that our walker properly handles loads with the invariant group -// attribute. It's a bit hacky, since we add the invariant attribute *after* -// building MSSA. Otherwise, the use optimizer will optimize it for us, which -// isn't what we want. -// FIXME: It may be easier/cleaner to just add an 'optimize uses?' flag to MSSA. -TEST_F(MemorySSATest, WalkerInvariantLoadOpt) { - F = Function::Create(FunctionType::get(B.getVoidTy(), {}, false), - GlobalValue::ExternalLinkage, "F", &M); - B.SetInsertPoint(BasicBlock::Create(C, "", F)); - Type *Int8 = Type::getInt8Ty(C); - Constant *One = ConstantInt::get(Int8, 1); - Value *AllocA = B.CreateAlloca(Int8, One, ""); - - Instruction *Store = B.CreateStore(One, AllocA); - Instruction *Load = B.CreateLoad(AllocA); - - setupAnalyses(); - MemorySSA &MSSA = *Analyses->MSSA; - MemorySSAWalker *Walker = Analyses->Walker; - - auto *LoadMA = cast<MemoryUse>(MSSA.getMemoryAccess(Load)); - auto *StoreMA = cast<MemoryDef>(MSSA.getMemoryAccess(Store)); - EXPECT_EQ(LoadMA->getDefiningAccess(), StoreMA); - - // ...At the time of writing, no cache should exist for LoadMA. Be a bit - // flexible to future changes. - Walker->invalidateInfo(LoadMA); - Load->setMetadata(LLVMContext::MD_invariant_load, MDNode::get(C, {})); - - MemoryAccess *LoadClobber = Walker->getClobberingMemoryAccess(LoadMA); - EXPECT_EQ(LoadClobber, MSSA.getLiveOnEntryDef()); -} - -// Test loads get reoptimized properly by the walker. -TEST_F(MemorySSATest, WalkerReopt) { - F = Function::Create(FunctionType::get(B.getVoidTy(), {}, false), - GlobalValue::ExternalLinkage, "F", &M); - B.SetInsertPoint(BasicBlock::Create(C, "", F)); - Type *Int8 = Type::getInt8Ty(C); - Value *AllocaA = B.CreateAlloca(Int8, ConstantInt::get(Int8, 1), "A"); - Instruction *SIA = B.CreateStore(ConstantInt::get(Int8, 0), AllocaA); - Value *AllocaB = B.CreateAlloca(Int8, ConstantInt::get(Int8, 1), "B"); - Instruction *SIB = B.CreateStore(ConstantInt::get(Int8, 0), AllocaB); - Instruction *LIA = B.CreateLoad(AllocaA); - - setupAnalyses(); - MemorySSA &MSSA = *Analyses->MSSA; - MemorySSAWalker *Walker = Analyses->Walker; - - MemoryAccess *LoadClobber = Walker->getClobberingMemoryAccess(LIA); - MemoryUse *LoadAccess = cast<MemoryUse>(MSSA.getMemoryAccess(LIA)); - EXPECT_EQ(LoadClobber, MSSA.getMemoryAccess(SIA)); - EXPECT_TRUE(MSSA.isLiveOnEntryDef(Walker->getClobberingMemoryAccess(SIA))); - MSSA.removeMemoryAccess(LoadAccess); - - // Create the load memory access pointing to an unoptimized place. - MemoryUse *NewLoadAccess = cast<MemoryUse>(MSSA.createMemoryAccessInBB( - LIA, MSSA.getMemoryAccess(SIB), LIA->getParent(), MemorySSA::End)); - // This should it cause it to be optimized - EXPECT_EQ(Walker->getClobberingMemoryAccess(NewLoadAccess), LoadClobber); - EXPECT_EQ(NewLoadAccess->getDefiningAccess(), LoadClobber); -} - -// Test out MemorySSA::spliceMemoryAccessAbove. -TEST_F(MemorySSATest, SpliceAboveMemoryDef) { - F = Function::Create(FunctionType::get(B.getVoidTy(), {}, false), - GlobalValue::ExternalLinkage, "F", &M); - B.SetInsertPoint(BasicBlock::Create(C, "", F)); - - Type *Int8 = Type::getInt8Ty(C); - Value *A = B.CreateAlloca(Int8, ConstantInt::get(Int8, 1), "A"); - Value *B_ = B.CreateAlloca(Int8, ConstantInt::get(Int8, 1), "B"); - Value *C = B.CreateAlloca(Int8, ConstantInt::get(Int8, 1), "C"); - - StoreInst *StoreA0 = B.CreateStore(ConstantInt::get(Int8, 0), A); - StoreInst *StoreB = B.CreateStore(ConstantInt::get(Int8, 0), B_); - LoadInst *LoadB = B.CreateLoad(B_); - StoreInst *StoreA1 = B.CreateStore(ConstantInt::get(Int8, 4), A); - // splice this above StoreB - StoreInst *StoreC = B.CreateStore(ConstantInt::get(Int8, 4), C); - StoreInst *StoreA2 = B.CreateStore(ConstantInt::get(Int8, 4), A); - LoadInst *LoadC = B.CreateLoad(C); - - setupAnalyses(); - MemorySSA &MSSA = *Analyses->MSSA; - MemorySSAWalker &Walker = *Analyses->Walker; - - StoreC->moveBefore(StoreB); - MSSA.spliceMemoryAccessAbove(cast<MemoryDef>(MSSA.getMemoryAccess(StoreB)), - MSSA.getMemoryAccess(StoreC)); - - MSSA.verifyMemorySSA(); - - EXPECT_EQ(MSSA.getMemoryAccess(StoreB)->getDefiningAccess(), - MSSA.getMemoryAccess(StoreC)); - EXPECT_EQ(MSSA.getMemoryAccess(StoreC)->getDefiningAccess(), - MSSA.getMemoryAccess(StoreA0)); - EXPECT_EQ(MSSA.getMemoryAccess(StoreA2)->getDefiningAccess(), - MSSA.getMemoryAccess(StoreA1)); - EXPECT_EQ(Walker.getClobberingMemoryAccess(LoadB), - MSSA.getMemoryAccess(StoreB)); - EXPECT_EQ(Walker.getClobberingMemoryAccess(LoadC), - MSSA.getMemoryAccess(StoreC)); - - // exercise block numbering - EXPECT_TRUE(MSSA.locallyDominates(MSSA.getMemoryAccess(StoreC), - MSSA.getMemoryAccess(StoreB))); - EXPECT_TRUE(MSSA.locallyDominates(MSSA.getMemoryAccess(StoreA1), - MSSA.getMemoryAccess(StoreA2))); -} |