llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-lld-macho @llvm/pr-subscribers-llvm-binary-utilities Author: Kyungwoo Lee (kyulee-com) <details> <summary>Changes</summary> This introduces a new cgdata format for stable function maps. The raw data is embedded in the __llvm_merge section during compile time. This data can be read and merged using the llvm-cgdata tool, into an indexed cgdata file. Consequently, the tool is now capable of handling either outlined hash trees, stable function maps, or both, as they are orthogonal. Depends on #<!-- -->112662. This is a patch for https://discourse.llvm.org/t/rfc-global-function-merging/82608. --- Patch is 53.06 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/112664.diff 21 Files Affected: - (modified) lld/test/MachO/cgdata-generate.s (+3-3) - (modified) llvm/docs/CommandGuide/llvm-cgdata.rst (+7-9) - (modified) llvm/include/llvm/CGData/CodeGenData.h (+23-1) - (modified) llvm/include/llvm/CGData/CodeGenData.inc (+9-3) - (modified) llvm/include/llvm/CGData/CodeGenDataReader.h (+26-3) - (modified) llvm/include/llvm/CGData/CodeGenDataWriter.h (+16-1) - (modified) llvm/lib/CGData/CodeGenData.cpp (+18-12) - (modified) llvm/lib/CGData/CodeGenDataReader.cpp (+43-20) - (modified) llvm/lib/CGData/CodeGenDataWriter.cpp (+28-2) - (modified) llvm/test/tools/llvm-cgdata/empty.test (+5-3) - (modified) llvm/test/tools/llvm-cgdata/error.test (+8-5) - (added) llvm/test/tools/llvm-cgdata/merge-combined-funcmap-hashtree.test (+66) - (added) llvm/test/tools/llvm-cgdata/merge-funcmap-archive.test (+83) - (added) llvm/test/tools/llvm-cgdata/merge-funcmap-concat.test (+78) - (added) llvm/test/tools/llvm-cgdata/merge-funcmap-double.test (+79) - (added) llvm/test/tools/llvm-cgdata/merge-funcmap-single.test (+36) - (renamed) llvm/test/tools/llvm-cgdata/merge-hashtree-archive.test (+4-4) - (renamed) llvm/test/tools/llvm-cgdata/merge-hashtree-concat.test (+3-3) - (renamed) llvm/test/tools/llvm-cgdata/merge-hashtree-double.test (+4-4) - (renamed) llvm/test/tools/llvm-cgdata/merge-hashtree-single.test (+2-2) - (modified) llvm/tools/llvm-cgdata/llvm-cgdata.cpp (+36-12) ``````````diff diff --git a/lld/test/MachO/cgdata-generate.s b/lld/test/MachO/cgdata-generate.s index 174df39d666c5d..f942ae07f64e0e 100644 --- a/lld/test/MachO/cgdata-generate.s +++ b/lld/test/MachO/cgdata-generate.s @@ -3,12 +3,12 @@ # RUN: rm -rf %t; split-file %s %t -# Synthesize raw cgdata without the header (24 byte) from the indexed cgdata. +# Synthesize raw cgdata without the header (32 byte) from the indexed cgdata. # RUN: llvm-cgdata --convert --format binary %t/raw-1.cgtext -o %t/raw-1.cgdata -# RUN: od -t x1 -j 24 -An %t/raw-1.cgdata | tr -d '\n\r\t' | sed 's/[ ][ ]*/ /g; s/^[ ]*//; s/[ ]*$//; s/[ ]/,0x/g; s/^/0x/' > %t/raw-1-bytes.txt +# RUN: od -t x1 -j 32 -An %t/raw-1.cgdata | tr -d '\n\r\t' | sed 's/[ ][ ]*/ /g; s/^[ ]*//; s/[ ]*$//; s/[ ]/,0x/g; s/^/0x/' > %t/raw-1-bytes.txt # RUN: sed "s/<RAW_BYTES>/$(cat %t/raw-1-bytes.txt)/g" %t/merge-template.s > %t/merge-1.s # RUN: llvm-cgdata --convert --format binary %t/raw-2.cgtext -o %t/raw-2.cgdata -# RUN: od -t x1 -j 24 -An %t/raw-2.cgdata | tr -d '\n\r\t' | sed 's/[ ][ ]*/ /g; s/^[ ]*//; s/[ ]*$//; s/[ ]/,0x/g; s/^/0x/' > %t/raw-2-bytes.txt +# RUN: od -t x1 -j 32 -An %t/raw-2.cgdata | tr -d '\n\r\t' | sed 's/[ ][ ]*/ /g; s/^[ ]*//; s/[ ]*$//; s/[ ]/,0x/g; s/^/0x/' > %t/raw-2-bytes.txt # RUN: sed "s/<RAW_BYTES>/$(cat %t/raw-2-bytes.txt)/g" %t/merge-template.s > %t/merge-2.s # RUN: llvm-mc -filetype obj -triple arm64-apple-darwin %t/merge-1.s -o %t/merge-1.o diff --git a/llvm/docs/CommandGuide/llvm-cgdata.rst b/llvm/docs/CommandGuide/llvm-cgdata.rst index f592e1508844ee..0670decd087e39 100644 --- a/llvm/docs/CommandGuide/llvm-cgdata.rst +++ b/llvm/docs/CommandGuide/llvm-cgdata.rst @@ -11,15 +11,13 @@ SYNOPSIS DESCRIPTION ----------- -The :program:llvm-cgdata utility parses raw codegen data embedded -in compiled binary files and merges them into a single .cgdata file. -It can also inspect and manipulate .cgdata files. -Currently, the tool supports saving and restoring outlined hash trees, -enabling global function outlining across modules, allowing for more -efficient function outlining in subsequent compilations. -The design is extensible, allowing for the incorporation of additional -codegen summaries and optimization techniques, such as global function -merging, in the future. +The :program:llvm-cgdata utility parses raw codegen data embedded in compiled +binary files and merges them into a single .cgdata file. It can also inspect +and manipulate .cgdata files. Currently, the tool supports saving and restoring +outlined hash trees and stable function maps, allowing for more efficient +function outlining and function merging across modules in subsequent +compilations. The design is extensible, allowing for the incorporation of +additional codegen summaries and optimization techniques. COMMANDS -------- diff --git a/llvm/include/llvm/CGData/CodeGenData.h b/llvm/include/llvm/CGData/CodeGenData.h index 53550beeae1f83..5d7c74725ccef1 100644 --- a/llvm/include/llvm/CGData/CodeGenData.h +++ b/llvm/include/llvm/CGData/CodeGenData.h @@ -19,6 +19,7 @@ #include "llvm/Bitcode/BitcodeReader.h" #include "llvm/CGData/OutlinedHashTree.h" #include "llvm/CGData/OutlinedHashTreeRecord.h" +#include "llvm/CGData/StableFunctionMapRecord.h" #include "llvm/IR/Module.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/Caching.h" @@ -41,7 +42,9 @@ enum class CGDataKind { Unknown = 0x0, // A function outlining info. FunctionOutlinedHashTree = 0x1, - LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/FunctionOutlinedHashTree) + // A function merging info. + StableFunctionMergingMap = 0x2, + LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/StableFunctionMergingMap) }; const std::error_category &cgdata_category(); @@ -108,6 +111,8 @@ enum CGDataMode { class CodeGenData { /// Global outlined hash tree that has oulined hash sequences across modules. std::unique_ptr<OutlinedHashTree> PublishedHashTree; + /// Global stable function map that has stable function info across modules. + std::unique_ptr<StableFunctionMap> PublishedStableFunctionMap; /// This flag is set when -fcodegen-data-generate is passed. /// Or, it can be mutated with -fcodegen-data-thinlto-two-rounds. @@ -131,6 +136,9 @@ class CodeGenData { bool hasOutlinedHashTree() { return PublishedHashTree && !PublishedHashTree->empty(); } + bool hasStableFunctionMap() { + return PublishedStableFunctionMap && !PublishedStableFunctionMap->empty(); + } /// Returns the outlined hash tree. This can be globally used in a read-only /// manner. @@ -147,6 +155,12 @@ class CodeGenData { // Ensure we disable emitCGData as we do not want to read and write both. EmitCGData = false; } + void + publishStableFunctionMap(std::unique_ptr<StableFunctionMap> FunctionMap) { + PublishedStableFunctionMap = std::move(FunctionMap); + // Ensure we disable emitCGData as we do not want to read and write both. + EmitCGData = false; + } }; namespace cgdata { @@ -166,6 +180,11 @@ publishOutlinedHashTree(std::unique_ptr<OutlinedHashTree> HashTree) { CodeGenData::getInstance().publishOutlinedHashTree(std::move(HashTree)); } +inline void +publishStableFunctionMap(std::unique_ptr<StableFunctionMap> FunctionMap) { + CodeGenData::getInstance().publishStableFunctionMap(std::move(FunctionMap)); +} + struct StreamCacheData { /// Backing buffer for serialized data stream. SmallVector<SmallString<0>> Outputs; @@ -249,6 +268,8 @@ enum CGDataVersion { // Version 1 is the first version. This version supports the outlined // hash tree. Version1 = 1, + // Version 2 supports the stable function merging map. + Version2 = 2, CurrentVersion = CG_DATA_INDEX_VERSION }; const uint64_t Version = CGDataVersion::CurrentVersion; @@ -258,6 +279,7 @@ struct Header { uint32_t Version; uint32_t DataKind; uint64_t OutlinedHashTreeOffset; + uint64_t StableFunctionMapOffset; // New fields should only be added at the end to ensure that the size // computation is correct. The methods below need to be updated to ensure that diff --git a/llvm/include/llvm/CGData/CodeGenData.inc b/llvm/include/llvm/CGData/CodeGenData.inc index 08ec14ea051a0c..e0ae7a51024d87 100644 --- a/llvm/include/llvm/CGData/CodeGenData.inc +++ b/llvm/include/llvm/CGData/CodeGenData.inc @@ -20,6 +20,8 @@ #define CG_DATA_DEFINED CG_DATA_SECT_ENTRY(CG_outline, CG_DATA_QUOTE(CG_DATA_OUTLINE_COMMON), CG_DATA_OUTLINE_COFF, "__DATA,") +CG_DATA_SECT_ENTRY(CG_merge, CG_DATA_QUOTE(CG_DATA_MERGE_COMMON), + CG_DATA_MERGE_COFF, "__DATA,") #undef CG_DATA_SECT_ENTRY #endif @@ -27,20 +29,24 @@ CG_DATA_SECT_ENTRY(CG_outline, CG_DATA_QUOTE(CG_DATA_OUTLINE_COMMON), /* section name strings common to all targets other than WIN32 */ #define CG_DATA_OUTLINE_COMMON __llvm_outline +#define CG_DATA_MERGE_COMMON __llvm_merge /* Since cg data sections are not allocated, we don't need to * access them at runtime. */ #define CG_DATA_OUTLINE_COFF ".loutline" +#define CG_DATA_MERGE_COFF ".lmerge" #ifdef _WIN32 /* Runtime section names and name strings. */ -#define CG_DATA_SECT_NAME CG_DATA_OUTLINE_COFF +#define CG_DATA_OUTLINE_SECT_NAME CG_DATA_OUTLINE_COFF +#define CG_DATA_MERGE_SECT_NAME CG_DATA_MERGE_COFF #else /* Runtime section names and name strings. */ -#define CG_DATA_SECT_NAME CG_DATA_QUOTE(CG_DATA_OUTLINE_COMMON) +#define CG_DATA_OUTLINE_SECT_NAME CG_DATA_QUOTE(CG_DATA_OUTLINE_COMMON) +#define CG_DATA_MERGE_SECT_NAME CG_DATA_QUOTE(CG_DATA_MERGE_COMMON) #endif /* Indexed codegen data format version (start from 1). */ -#define CG_DATA_INDEX_VERSION 1 +#define CG_DATA_INDEX_VERSION 2 diff --git a/llvm/include/llvm/CGData/CodeGenDataReader.h b/llvm/include/llvm/CGData/CodeGenDataReader.h index 7e4882df2116e2..085dd6dd747c90 100644 --- a/llvm/include/llvm/CGData/CodeGenDataReader.h +++ b/llvm/include/llvm/CGData/CodeGenDataReader.h @@ -15,6 +15,7 @@ #include "llvm/CGData/CodeGenData.h" #include "llvm/CGData/OutlinedHashTreeRecord.h" +#include "llvm/CGData/StableFunctionMapRecord.h" #include "llvm/Support/LineIterator.h" #include "llvm/Support/VirtualFileSystem.h" @@ -36,10 +37,15 @@ class CodeGenDataReader { virtual CGDataKind getDataKind() const = 0; /// Return true if the data has an outlined hash tree. virtual bool hasOutlinedHashTree() const = 0; + /// Return true if the data has a stable function map. + virtual bool hasStableFunctionMap() const = 0; /// Return the outlined hash tree that is released from the reader. std::unique_ptr<OutlinedHashTree> releaseOutlinedHashTree() { return std::move(HashTreeRecord.HashTree); } + std::unique_ptr<StableFunctionMap> releaseStableFunctionMap() { + return std::move(FunctionMapRecord.FunctionMap); + } /// Factory method to create an appropriately typed reader for the given /// codegen data file path and file system. @@ -56,15 +62,21 @@ class CodeGenDataReader { /// is used by `llvm-cgdata --merge` or ThinLTO's two-codegen rounds. /// Optionally, \p CombinedHash can be used to compuate the combined hash of /// the merged data. - static Error mergeFromObjectFile(const object::ObjectFile *Obj, - OutlinedHashTreeRecord &GlobalOutlineRecord, - stable_hash *CombinedHash = nullptr); + static Error + mergeFromObjectFile(const object::ObjectFile *Obj, + OutlinedHashTreeRecord &GlobalOutlineRecord, + StableFunctionMapRecord &GlobalFunctionMapRecord, + stable_hash *CombinedHash = nullptr); protected: /// The outlined hash tree that has been read. When it's released by /// releaseOutlinedHashTree(), it's no longer valid. OutlinedHashTreeRecord HashTreeRecord; + /// The stable function map that has been read. When it's released by + // releaseStableFunctionMap(), it's no longer valid. + StableFunctionMapRecord FunctionMapRecord; + /// Set the current error and return same. Error error(cgdata_error Err, const std::string &ErrMsg = "") { LastError = Err; @@ -115,6 +127,11 @@ class IndexedCodeGenDataReader : public CodeGenDataReader { return Header.DataKind & static_cast<uint32_t>(CGDataKind::FunctionOutlinedHashTree); } + /// Return true if the header indicates the data has a stable function map. + bool hasStableFunctionMap() const override { + return Header.DataKind & + static_cast<uint32_t>(CGDataKind::StableFunctionMergingMap); + } }; /// This format is a simple text format that's suitable for test data. @@ -150,6 +167,12 @@ class TextCodeGenDataReader : public CodeGenDataReader { return static_cast<uint32_t>(DataKind) & static_cast<uint32_t>(CGDataKind::FunctionOutlinedHashTree); } + /// Return true if the header indicates the data has a stable function map. + /// This does not mean that the data is still available. + bool hasStableFunctionMap() const override { + return static_cast<uint32_t>(DataKind) & + static_cast<uint32_t>(CGDataKind::StableFunctionMergingMap); + } }; } // end namespace llvm diff --git a/llvm/include/llvm/CGData/CodeGenDataWriter.h b/llvm/include/llvm/CGData/CodeGenDataWriter.h index 5cb8377b1d07e5..1c4247608999a7 100644 --- a/llvm/include/llvm/CGData/CodeGenDataWriter.h +++ b/llvm/include/llvm/CGData/CodeGenDataWriter.h @@ -15,6 +15,7 @@ #include "llvm/CGData/CodeGenData.h" #include "llvm/CGData/OutlinedHashTreeRecord.h" +#include "llvm/CGData/StableFunctionMapRecord.h" #include "llvm/Support/EndianStream.h" #include "llvm/Support/Error.h" @@ -57,6 +58,9 @@ class CodeGenDataWriter { /// The outlined hash tree to be written. OutlinedHashTreeRecord HashTreeRecord; + /// The stable function map to be written. + StableFunctionMapRecord FunctionMapRecord; + /// A bit mask describing the kind of the codegen data. CGDataKind DataKind = CGDataKind::Unknown; @@ -64,9 +68,12 @@ class CodeGenDataWriter { CodeGenDataWriter() = default; ~CodeGenDataWriter() = default; - /// Add the outlined hash tree record. The input Record is released. + /// Add the outlined hash tree record. The input hash tree is released. void addRecord(OutlinedHashTreeRecord &Record); + /// Add the stable function map record. The input function map is released. + void addRecord(StableFunctionMapRecord &Record); + /// Write the codegen data to \c OS Error write(raw_fd_ostream &OS); @@ -81,11 +88,19 @@ class CodeGenDataWriter { return static_cast<uint32_t>(DataKind) & static_cast<uint32_t>(CGDataKind::FunctionOutlinedHashTree); } + /// Return true if the header indicates the data has a stable function map. + bool hasStableFunctionMap() const { + return static_cast<uint32_t>(DataKind) & + static_cast<uint32_t>(CGDataKind::StableFunctionMergingMap); + } private: /// The offset of the outlined hash tree in the file. uint64_t OutlinedHashTreeOffset; + /// The offset of the stable function map in the file. + uint64_t StableFunctionMapOffset; + /// Write the codegen data header to \c COS Error writeHeader(CGDataOStream &COS); diff --git a/llvm/lib/CGData/CodeGenData.cpp b/llvm/lib/CGData/CodeGenData.cpp index 2a3a74c8bc37af..88dcdfd1f931a2 100644 --- a/llvm/lib/CGData/CodeGenData.cpp +++ b/llvm/lib/CGData/CodeGenData.cpp @@ -14,6 +14,7 @@ #include "llvm/Bitcode/BitcodeWriter.h" #include "llvm/CGData/CodeGenDataReader.h" #include "llvm/CGData/OutlinedHashTreeRecord.h" +#include "llvm/CGData/StableFunctionMapRecord.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/Caching.h" #include "llvm/Support/CommandLine.h" @@ -163,6 +164,8 @@ CodeGenData &CodeGenData::getInstance() { auto Reader = ReaderOrErr->get(); if (Reader->hasOutlinedHashTree()) Instance->publishOutlinedHashTree(Reader->releaseOutlinedHashTree()); + if (Reader->hasStableFunctionMap()) + Instance->publishStableFunctionMap(Reader->releaseStableFunctionMap()); } }); return *Instance; @@ -185,18 +188,14 @@ Expected<Header> Header::readFromBuffer(const unsigned char *Curr) { return make_error<CGDataError>(cgdata_error::unsupported_version); H.DataKind = endian::readNext<uint32_t, endianness::little, unaligned>(Curr); - switch (H.Version) { - // When a new field is added to the header add a case statement here to - // compute the size as offset of the new field + size of the new field. This - // relies on the field being added to the end of the list. - static_assert(IndexedCGData::CGDataVersion::CurrentVersion == Version1, - "Please update the size computation below if a new field has " - "been added to the header, if not add a case statement to " - "fall through to the latest version."); - case 1ull: - H.OutlinedHashTreeOffset = + static_assert(IndexedCGData::CGDataVersion::CurrentVersion == Version2, + "Please update the offset computation below if a new field has " + "been added to the header."); + H.OutlinedHashTreeOffset = + endian::readNext<uint64_t, endianness::little, unaligned>(Curr); + if (H.Version >= 2) + H.StableFunctionMapOffset = endian::readNext<uint64_t, endianness::little, unaligned>(Curr); - } return H; } @@ -257,6 +256,7 @@ std::unique_ptr<Module> loadModuleForTwoRounds(BitcodeModule &OrigModule, Expected<stable_hash> mergeCodeGenData(ArrayRef<StringRef> ObjFiles) { OutlinedHashTreeRecord GlobalOutlineRecord; + StableFunctionMapRecord GlobalStableFunctionMapRecord; stable_hash CombinedHash = 0; for (auto File : ObjFiles) { if (File.empty()) @@ -270,12 +270,18 @@ Expected<stable_hash> mergeCodeGenData(ArrayRef<StringRef> ObjFiles) { std::unique_ptr<object::ObjectFile> &Obj = BinOrErr.get(); if (auto E = CodeGenDataReader::mergeFromObjectFile( - Obj.get(), GlobalOutlineRecord, &CombinedHash)) + Obj.get(), GlobalOutlineRecord, GlobalStableFunctionMapRecord, + &CombinedHash)) return E; } + GlobalStableFunctionMapRecord.finalize(); + if (!GlobalOutlineRecord.empty()) cgdata::publishOutlinedHashTree(std::move(GlobalOutlineRecord.HashTree)); + if (!GlobalStableFunctionMapRecord.empty()) + cgdata::publishStableFunctionMap( + std::move(GlobalStableFunctionMapRecord.FunctionMap)); return CombinedHash; } diff --git a/llvm/lib/CGData/CodeGenDataReader.cpp b/llvm/lib/CGData/CodeGenDataReader.cpp index 2f2481ea60f822..ebeb4ae36f99f3 100644 --- a/llvm/lib/CGData/CodeGenDataReader.cpp +++ b/llvm/lib/CGData/CodeGenDataReader.cpp @@ -32,10 +32,40 @@ setupMemoryBuffer(const Twine &Filename, vfs::FileSystem &FS) { Error CodeGenDataReader::mergeFromObjectFile( const object::ObjectFile *Obj, OutlinedHashTreeRecord &GlobalOutlineRecord, + StableFunctionMapRecord &GlobalFunctionMapRecord, stable_hash *CombinedHash) { Triple TT = Obj->makeTriple(); auto CGOutLineName = getCodeGenDataSectionName(CG_outline, TT.getObjectFormat(), false); + auto CGMergeName = + getCodeGenDataSectionName(CG_merge, TT.getObjectFormat(), false); + + auto processSectionContents = [&](const StringRef &Name, + const StringRef &Contents) { + if (Name != CGOutLineName && Name != CGMergeName) + return; + if (CombinedHash) + *CombinedHash = stable_hash_combine(*CombinedHash, xxh3_64bits(Contents)); + auto *Data = reinterpret_cast<const unsigned char *>(Contents.data()); + auto *EndData = Data + Contents.size(); + // In case dealing with an executable that has concatenated cgdata, + // we want to merge them into a single cgdata. + // Although it's not a typical workflow, we support this scenario + // by looping over all data in the sections. + if (Name == CGOutLineName) { + while (Data != EndData) { + OutlinedHashTreeRecord LocalOutlineRecord; + LocalOutlineRecord.deserialize(Data); + GlobalOutlineRecord.merge(LocalOutlineRecord); + } + } else if (Name == CGMergeName) { + while (Data != EndData) { + StableFunctionMapRecord LocalFunctionMapRecord; + LocalFunctionMapRecord.deserialize(Data); + GlobalFunctionMapRecord.merge(LocalFunctionMapRecord); + } + } + }; for (auto &Section : Obj->sections()) { Expected<StringRef> NameOrErr = Section.getName(); @@ -44,23 +74,7 @@ Error CodeGenDataReader::mergeFromObjectFile( Expected<StringRef> ContentsOrErr = Section.getContents(); if (!ContentsOrErr) return ContentsOrErr.takeError(); - auto *Data = reinterpret_cast<const unsigned char *>(ContentsOrErr->data()); - auto *EndData = Data + ContentsOrErr->size(); - - if (*NameOrErr == CGOutLineName) { - if (CombinedHash) - *CombinedHash = - stable_hash_combine(*CombinedHash, xxh3_64bits(*ContentsOrErr)); - // In case dealing with an executable that has concatenated cgdata, - // we want to merge them into a single cgdata. - // Although it's not a typical workflow, we support this scenario. - while (Data != EndData) { - OutlinedHashTreeRecord LocalOutlineRecord; - LocalOutlineRecord.deserialize(Data); - GlobalOutlineRecord.merge(LocalOutlineRecord); - } - } - // TODO: Add support for other cgdata sections. + processSectionContents(*NameOrErr, *ContentsOrErr); } return Error::success(); @@ -69,7 +83,8 @@ Error CodeGenDataReader::mergeFromObjectFile( Error IndexedCodeGenDataReader::read() { using namespace support; - // The smallest header with the version 1 is 24 bytes + // The smallest header with the version 1 is 24 bytes. + // Do not update this value even with the new version of the header. const unsigned MinHeaderSize = 24; if (DataBuffer->getBufferSize() < MinHeaderSize) return error(cgdata_error::bad_header); @@ -87,6 +102,12 @@ Error IndexedCodeGenDataReader::read() { return error(cgdata_error::eof); HashTreeRecord.deserialize(Ptr); } + if (hasStableFunctionMap()) { + const unsigned char *Ptr = Start + Header.StableFunctionMapOffset; + if (Ptr >= End) + return error(cgdata_error::eof); + FunctionMapRecord.deserialize(Ptr); + } return success(); } @@ -152,6 +1... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/112664 _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits