[llvm] Introduction of typified section in ExtBinary format (PR #166553)
Sergey Shcherbinin via llvm-commits
llvm-commits at lists.llvm.org
Mon Jun 29 22:15:46 PDT 2026
https://github.com/SergeyShch01 updated https://github.com/llvm/llvm-project/pull/166553
>From ecf9cc31e50af12d460ddc2ea44812c2aab87ab4 Mon Sep 17 00:00:00 2001
From: Sergey Shcherbinin <sscherbinin at nvidia.com>
Date: Wed, 5 Nov 2025 17:12:18 +0400
Subject: [PATCH 1/7] Introduction of typified section in ExtBinary format
---
llvm/include/llvm/ProfileData/SampleProf.h | 28 ++++++-
.../llvm/ProfileData/SampleProfReader.h | 5 ++
.../llvm/ProfileData/SampleProfWriter.h | 13 +++
llvm/lib/ProfileData/SampleProfReader.cpp | 51 +++++++++++-
llvm/lib/ProfileData/SampleProfWriter.cpp | 82 ++++++++++++++++---
.../llvm-profdata/sample-flatten-profile.test | 2 +
6 files changed, 166 insertions(+), 15 deletions(-)
diff --git a/llvm/include/llvm/ProfileData/SampleProf.h b/llvm/include/llvm/ProfileData/SampleProf.h
index 3dd34aba2d716..a9417dae93f81 100644
--- a/llvm/include/llvm/ProfileData/SampleProf.h
+++ b/llvm/include/llvm/ProfileData/SampleProf.h
@@ -128,9 +128,13 @@ enum SecType {
SecFuncOffsetTable = 4,
SecFuncMetadata = 5,
SecCSNameTable = 6,
+ // Substitution to SecFuncOffsetTable when we have non-LBR profile types
+ SecTypifiedFuncOffsetTable = 7,
// marker for the first type of profile.
SecFuncProfileFirst = 32,
- SecLBRProfile = SecFuncProfileFirst
+ SecLBRProfile = SecFuncProfileFirst,
+ // Substitution to SecLBRProfile when we have non-LBR profile types
+ SecTypifiedProfile = 33
};
static inline std::string getSecName(SecType Type) {
@@ -149,13 +153,20 @@ static inline std::string getSecName(SecType Type) {
return "FunctionMetadata";
case SecCSNameTable:
return "CSNameTableSection";
+ case SecTypifiedFuncOffsetTable:
+ return "TypifiedFuncOffsetTableSection";
case SecLBRProfile:
return "LBRProfileSection";
+ case SecTypifiedProfile:
+ return "TypifiedProfileSection";
default:
return "UnknownSection";
}
}
+// Types of sample profile which can be in placed in SecTypifiedProfile
+enum ProfTypes { ProfTypeLBR = 0, ProfTypeNum };
+
// Entry type of section header table used by SampleProfileExtBinaryBaseReader
// and SampleProfileExtBinaryBaseWriter.
struct SecHdrTableEntry {
@@ -1341,6 +1352,12 @@ class FunctionSamples {
return !(*this == Other);
}
+ bool hasNonLBRSamples() const {
+ // currently just a stub - should be implemented when
+ // first non-LBR profile is encountered
+ return false;
+ }
+
private:
/// CFG hash value for the function.
uint64_t FunctionHash = 0;
@@ -1466,6 +1483,15 @@ class SampleProfileMap
size_t erase(const key_type &Key) { return base_type::erase(Key); }
iterator erase(iterator It) { return base_type::erase(It); }
+
+ bool hasNonLBRProfile() const {
+ for (const auto &[Context, FuncSamples] : *this) {
+ if (FuncSamples.hasNonLBRSamples()) {
+ return true;
+ }
+ }
+ return false;
+ }
};
using NameFunctionSamples = std::pair<hash_code, const FunctionSamples *>;
diff --git a/llvm/include/llvm/ProfileData/SampleProfReader.h b/llvm/include/llvm/ProfileData/SampleProfReader.h
index 799938ab901c1..74e3f1773656d 100644
--- a/llvm/include/llvm/ProfileData/SampleProfReader.h
+++ b/llvm/include/llvm/ProfileData/SampleProfReader.h
@@ -570,6 +570,7 @@ class SampleProfileReader {
FuncMetadataIndex;
std::pair<const uint8_t *, const uint8_t *> ProfileSecRange;
+ bool IsProfileTypified = false;
/// Whether the profile has attribute metadata.
bool ProfileHasAttribute = false;
@@ -687,6 +688,10 @@ class LLVM_ABI SampleProfileReaderBinary : public SampleProfileReader {
/// Read the contents of the given profile instance.
std::error_code readProfile(FunctionSamples &FProfile);
+ /// Read specific profile types.
+ std::error_code readLBRProfile(FunctionSamples &FProfile);
+ std::error_code readTypifiedProfile(FunctionSamples &FProfile);
+
/// Read the contents of Magic number and Version number.
std::error_code readMagicIdent();
diff --git a/llvm/include/llvm/ProfileData/SampleProfWriter.h b/llvm/include/llvm/ProfileData/SampleProfWriter.h
index 9dbeaf56509b0..052843f9f55ac 100644
--- a/llvm/include/llvm/ProfileData/SampleProfWriter.h
+++ b/llvm/include/llvm/ProfileData/SampleProfWriter.h
@@ -215,6 +215,10 @@ class LLVM_ABI SampleProfileWriterBinary : public SampleProfileWriter {
virtual std::error_code writeContextIdx(const SampleContext &Context);
std::error_code writeNameIdx(FunctionId FName);
std::error_code writeBody(const FunctionSamples &S);
+ void writeLBRProfile(const FunctionSamples &S);
+ /// Writes typified profile for function
+ void writeTypifiedProfile(const FunctionSamples &S);
+
inline void stablizeNameTable(MapVector<FunctionId, uint32_t> &NameTable,
std::set<FunctionId> &V);
@@ -230,6 +234,7 @@ class LLVM_ABI SampleProfileWriterBinary : public SampleProfileWriter {
raw_ostream &OS);
bool WriteVTableProf = false;
+ bool WriteTypifiedProf = false;
private:
LLVM_ABI friend ErrorOr<std::unique_ptr<SampleProfileWriter>>
@@ -427,6 +432,9 @@ class LLVM_ABI SampleProfileWriterExtBinary
std::error_code writeSections(const SampleProfileMap &ProfileMap) override;
+ // Configure whether to use typified profile sections
+ void configureTypifiedProfile(const SampleProfileMap &ProfileMap);
+
std::error_code writeCustomSection(SecType Type) override {
return sampleprof_error::success;
};
@@ -435,6 +443,11 @@ class LLVM_ABI SampleProfileWriterExtBinary
assert((SL == DefaultLayout || SL == CtxSplitLayout) &&
"Unsupported layout");
}
+
+ /// Section types for profile storage and bookkeeping (used to switch between
+ /// typified and non-typified profiles).
+ SecType ProfSection = SecLBRProfile;
+ SecType FuncOffsetSection = SecFuncOffsetTable;
};
} // end namespace sampleprof
diff --git a/llvm/lib/ProfileData/SampleProfReader.cpp b/llvm/lib/ProfileData/SampleProfReader.cpp
index 766c0814ca067..d97cc8a6f6b88 100644
--- a/llvm/lib/ProfileData/SampleProfReader.cpp
+++ b/llvm/lib/ProfileData/SampleProfReader.cpp
@@ -710,7 +710,7 @@ SampleProfileReaderBinary::readCallsiteVTableProf(FunctionSamples &FProfile) {
}
std::error_code
-SampleProfileReaderBinary::readProfile(FunctionSamples &FProfile) {
+SampleProfileReaderBinary::readLBRProfile(FunctionSamples &FProfile) {
auto NumSamples = readNumber<uint64_t>();
if (std::error_code EC = NumSamples.getError())
return EC;
@@ -761,6 +761,52 @@ SampleProfileReaderBinary::readProfile(FunctionSamples &FProfile) {
FProfile.addBodySamples(*LineOffset, DiscriminatorVal, *NumSamples);
}
+ return sampleprof_error::success;
+}
+
+std::error_code
+SampleProfileReaderBinary::readTypifiedProfile(FunctionSamples &FProfile) {
+ // read the number of profile types
+ auto ProfNum = readNumber<uint64_t>();
+ if (std::error_code EC = ProfNum.getError())
+ return EC;
+
+ // read specified number of typified profiles
+ for (uint64_t i = 0; i < *ProfNum; i++) {
+ auto Type = readNumber<uint64_t>();
+ if (std::error_code EC = Type.getError())
+ return EC;
+ auto Size = readUnencodedNumber<uint64_t>();
+ if (std::error_code EC = Size.getError())
+ return EC;
+
+ switch (*Type) {
+ case ProfTypeLBR:
+ if (std::error_code EC = readLBRProfile(FProfile))
+ return EC;
+ break;
+ default:
+ // skip unknown profile type for forward compatibility
+ Data += *Size;
+ if (Data > End)
+ return sampleprof_error::truncated;
+ break;
+ }
+ }
+
+ return sampleprof_error::success;
+}
+
+std::error_code
+SampleProfileReaderBinary::readProfile(FunctionSamples &FProfile) {
+ if (IsProfileTypified) {
+ if (std::error_code EC = readTypifiedProfile(FProfile))
+ return EC;
+ } else {
+ if (std::error_code EC = readLBRProfile(FProfile))
+ return EC;
+ }
+
// Read all the samples for inlined function calls.
auto NumCallsites = readNumber<uint32_t>();
if (std::error_code EC = NumCallsites.getError())
@@ -876,11 +922,14 @@ std::error_code SampleProfileReaderExtBinaryBase::readOneSection(
break;
}
case SecLBRProfile:
+ case SecTypifiedProfile:
ProfileSecRange = std::make_pair(Data, End);
+ IsProfileTypified = Entry.Type == SecTypifiedProfile;
if (std::error_code EC = readFuncProfiles())
return EC;
break;
case SecFuncOffsetTable:
+ case SecTypifiedFuncOffsetTable:
// If module is absent, we are using LLVM tools, and need to read all
// profiles, so skip reading the function offset table.
if (!M) {
diff --git a/llvm/lib/ProfileData/SampleProfWriter.cpp b/llvm/lib/ProfileData/SampleProfWriter.cpp
index e5f31348578b8..c9787f367156c 100644
--- a/llvm/lib/ProfileData/SampleProfWriter.cpp
+++ b/llvm/lib/ProfileData/SampleProfWriter.cpp
@@ -46,6 +46,10 @@ static cl::opt<bool> ExtBinaryWriteVTableTypeProf(
"extbinary-write-vtable-type-prof", cl::init(false), cl::Hidden,
cl::desc("Write vtable type profile in ext-binary sample profile writer"));
+static cl::opt<bool> ExtBinaryForceTypifiedProf(
+ "extbinary-force-typified-prof", cl::init(false), cl::Hidden,
+ cl::desc("Force utilization of typified profile format"));
+
namespace llvm {
namespace support {
namespace endian {
@@ -460,11 +464,13 @@ std::error_code SampleProfileWriterExtBinaryBase::writeOneSection(
return EC;
break;
case SecLBRProfile:
+ case SecTypifiedProfile:
SecLBRProfileStart = OutputStream->tell();
if (std::error_code EC = writeFuncProfiles(ProfileMap))
return EC;
break;
case SecFuncOffsetTable:
+ case SecTypifiedFuncOffsetTable:
if (auto EC = writeFuncOffsetTable())
return EC;
break;
@@ -504,11 +510,11 @@ std::error_code SampleProfileWriterExtBinary::writeDefaultLayout(
return EC;
if (auto EC = writeOneSection(SecCSNameTable, 2, ProfileMap))
return EC;
- if (auto EC = writeOneSection(SecLBRProfile, 4, ProfileMap))
+ if (auto EC = writeOneSection(ProfSection, 4, ProfileMap))
return EC;
if (auto EC = writeOneSection(SecProfileSymbolList, 5, ProfileMap))
return EC;
- if (auto EC = writeOneSection(SecFuncOffsetTable, 3, ProfileMap))
+ if (auto EC = writeOneSection(FuncOffsetSection, 3, ProfileMap))
return EC;
if (auto EC = writeOneSection(SecFuncMetadata, 6, ProfileMap))
return EC;
@@ -530,24 +536,23 @@ std::error_code SampleProfileWriterExtBinary::writeCtxSplitLayout(
const SampleProfileMap &ProfileMap) {
SampleProfileMap ContextProfileMap, NoContextProfileMap;
splitProfileMapToTwo(ProfileMap, ContextProfileMap, NoContextProfileMap);
-
if (auto EC = writeOneSection(SecProfSummary, 0, ProfileMap))
return EC;
if (auto EC = writeOneSection(SecNameTable, 1, ProfileMap))
return EC;
- if (auto EC = writeOneSection(SecLBRProfile, 3, ContextProfileMap))
+ if (auto EC = writeOneSection(ProfSection, 3, ContextProfileMap))
return EC;
- if (auto EC = writeOneSection(SecFuncOffsetTable, 2, ContextProfileMap))
+ if (auto EC = writeOneSection(FuncOffsetSection, 2, ContextProfileMap))
return EC;
// Mark the section to have no context. Note section flag needs to be set
// before writing the section.
addSectionFlag(5, SecCommonFlags::SecFlagFlat);
- if (auto EC = writeOneSection(SecLBRProfile, 5, NoContextProfileMap))
+ if (auto EC = writeOneSection(ProfSection, 5, NoContextProfileMap))
return EC;
// Mark the section to have no context. Note section flag needs to be set
// before writing the section.
addSectionFlag(4, SecCommonFlags::SecFlagFlat);
- if (auto EC = writeOneSection(SecFuncOffsetTable, 4, NoContextProfileMap))
+ if (auto EC = writeOneSection(FuncOffsetSection, 4, NoContextProfileMap))
return EC;
if (auto EC = writeOneSection(SecProfileSymbolList, 6, ProfileMap))
return EC;
@@ -557,8 +562,30 @@ std::error_code SampleProfileWriterExtBinary::writeCtxSplitLayout(
return sampleprof_error::success;
}
+void SampleProfileWriterExtBinary::configureTypifiedProfile(
+ const SampleProfileMap &ProfileMap) {
+ if (!ExtBinaryForceTypifiedProf && !ProfileMap.hasNonLBRProfile()) {
+ WriteTypifiedProf = false;
+ ProfSection = SecLBRProfile;
+ FuncOffsetSection = SecFuncOffsetTable;
+ return;
+ }
+ // Use typified profile sections: directly change the section types
+ // to avoid duplicating the whole layout and its handling.
+ WriteTypifiedProf = true;
+ FuncOffsetSection = SecTypifiedFuncOffsetTable;
+ ProfSection = SecTypifiedProfile;
+ for (auto &Entry : SectionHdrLayout) {
+ if (Entry.Type == SecFuncOffsetTable)
+ Entry.Type = SecTypifiedFuncOffsetTable;
+ else if (Entry.Type == SecLBRProfile)
+ Entry.Type = SecTypifiedProfile;
+ }
+}
+
std::error_code SampleProfileWriterExtBinary::writeSections(
const SampleProfileMap &ProfileMap) {
+ configureTypifiedProfile(ProfileMap);
std::error_code EC;
if (SecLayout == DefaultLayout)
EC = writeDefaultLayout(ProfileMap);
@@ -885,14 +912,10 @@ std::error_code SampleProfileWriterBinary::writeSummary() {
}
return sampleprof_error::success;
}
-std::error_code SampleProfileWriterBinary::writeBody(const FunctionSamples &S) {
- auto &OS = *OutputStream;
- if (std::error_code EC = writeContextIdx(S.getContext()))
- return EC;
+void SampleProfileWriterBinary::writeLBRProfile(const FunctionSamples &S) {
+ auto &OS = *OutputStream;
encodeULEB128(S.getTotalSamples(), OS);
-
- // Emit all the body samples.
encodeULEB128(S.getBodySamples().size(), OS);
for (const auto &I : S.getBodySamples()) {
LineLocation Loc = I.first;
@@ -900,6 +923,39 @@ std::error_code SampleProfileWriterBinary::writeBody(const FunctionSamples &S) {
Loc.serialize(OS);
Sample.serialize(OS, getNameTable());
}
+}
+
+void SampleProfileWriterBinary::writeTypifiedProfile(const FunctionSamples &S) {
+ // Currently only LBR profile is supported as typified profile.
+ auto &OS = *OutputStream;
+ // write the number of profile types for function
+ encodeULEB128(1, OS);
+ // Start first profile writing: write profile type
+ encodeULEB128(ProfTypeLBR, OS);
+ // create placeholder for profile size
+ uint64_t SizeOffset = OS.tell();
+ support::endian::Writer PlaceWriter(OS, llvm::endianness::little);
+ PlaceWriter.write(static_cast<uint64_t>(-1));
+ // write the profile itself
+ uint64_t BodyStart = OS.tell();
+ writeLBRProfile(S);
+ uint64_t BodySize = OS.tell() - BodyStart;
+ // write profile size
+ support::endian::SeekableWriter PWriter(static_cast<raw_pwrite_stream &>(OS),
+ llvm::endianness::little);
+ PWriter.pwrite(BodySize, SizeOffset);
+}
+
+std::error_code SampleProfileWriterBinary::writeBody(const FunctionSamples &S) {
+ auto &OS = *OutputStream;
+ if (std::error_code EC = writeContextIdx(S.getContext()))
+ return EC;
+
+ // Emit all the body samples.
+ if (WriteTypifiedProf)
+ writeTypifiedProfile(S);
+ else
+ writeLBRProfile(S);
// Recursively emit all the callsite samples.
uint64_t NumCallsites = 0;
diff --git a/llvm/test/tools/llvm-profdata/sample-flatten-profile.test b/llvm/test/tools/llvm-profdata/sample-flatten-profile.test
index f99021bc6b723..34dab716a067f 100644
--- a/llvm/test/tools/llvm-profdata/sample-flatten-profile.test
+++ b/llvm/test/tools/llvm-profdata/sample-flatten-profile.test
@@ -1,8 +1,10 @@
; RUN: llvm-profdata merge --sample --convert-sample-profile-layout=flat --text %S/Inputs/sample-flatten-profile.proftext -o - | FileCheck %s --match-full-lines --strict-whitespace
; RUN: llvm-profdata merge --sample --extbinary %S/Inputs/sample-flatten-profile.proftext -o %t2 && llvm-profdata merge --sample --convert-sample-profile-layout=flat --text %t2 -o - | FileCheck %s --match-full-lines --strict-whitespace
+; RUN: llvm-profdata merge --sample --extbinary-force-typified-prof --extbinary %S/Inputs/sample-flatten-profile.proftext -o %t2 && llvm-profdata merge --sample --convert-sample-profile-layout=flat --text %t2 -o - | FileCheck %s --match-full-lines --strict-whitespace
; RUN: llvm-profdata merge --sample --convert-sample-profile-layout=flat --text %S/Inputs/sample-flatten-profile-cs.proftext -o - | FileCheck %s --match-full-lines --strict-whitespace --check-prefix=CHECK-CS
; RUN: llvm-profdata merge --sample --extbinary %S/Inputs/sample-flatten-profile-cs.proftext -o %t2 && llvm-profdata merge --sample --convert-sample-profile-layout=flat --text %t2 -o - | FileCheck %s --match-full-lines --strict-whitespace --check-prefix=CHECK-CS
+; RUN: llvm-profdata merge --sample --extbinary-force-typified-prof --extbinary %S/Inputs/sample-flatten-profile-cs.proftext -o %t2 && llvm-profdata merge --sample --convert-sample-profile-layout=flat --text %t2 -o - | FileCheck %s --match-full-lines --strict-whitespace --check-prefix=CHECK-CS
; CHECK:baz:169:10
; CHECK-NEXT: 1: 10
>From 8f82e75bfd20f8bb4d7e6100e8795db49012364e Mon Sep 17 00:00:00 2001
From: Sergey Shcherbinin <sscherbinin at nvidia.com>
Date: Tue, 11 Nov 2025 13:25:02 +0400
Subject: [PATCH 2/7] Typo fixed
Co-authored-by: Mingming Liu <minglotus6 at gmail.com>
---
llvm/include/llvm/ProfileData/SampleProf.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/include/llvm/ProfileData/SampleProf.h b/llvm/include/llvm/ProfileData/SampleProf.h
index a9417dae93f81..26972ca443481 100644
--- a/llvm/include/llvm/ProfileData/SampleProf.h
+++ b/llvm/include/llvm/ProfileData/SampleProf.h
@@ -164,7 +164,7 @@ static inline std::string getSecName(SecType Type) {
}
}
-// Types of sample profile which can be in placed in SecTypifiedProfile
+// Types of sample profile which can be placed in SecTypifiedProfile
enum ProfTypes { ProfTypeLBR = 0, ProfTypeNum };
// Entry type of section header table used by SampleProfileExtBinaryBaseReader
>From 9cddd78414aedc12dc0b06649a53d0fdb5b0fcd6 Mon Sep 17 00:00:00 2001
From: Sergey Shcherbinin <sscherbinin at nvidia.com>
Date: Tue, 11 Nov 2025 14:39:46 +0400
Subject: [PATCH 3/7] Small additional changes
+ Comments LLVM-fication
+ Typified profile writing is split into several interfaces to support future introduction of new profile types
---
llvm/include/llvm/ProfileData/SampleProf.h | 4 +-
.../llvm/ProfileData/SampleProfWriter.h | 8 +++-
llvm/lib/ProfileData/SampleProfReader.cpp | 2 +-
llvm/lib/ProfileData/SampleProfWriter.cpp | 46 ++++++++++++++-----
4 files changed, 43 insertions(+), 17 deletions(-)
diff --git a/llvm/include/llvm/ProfileData/SampleProf.h b/llvm/include/llvm/ProfileData/SampleProf.h
index 26972ca443481..1bb8bdc9bfcfd 100644
--- a/llvm/include/llvm/ProfileData/SampleProf.h
+++ b/llvm/include/llvm/ProfileData/SampleProf.h
@@ -1353,8 +1353,8 @@ class FunctionSamples {
}
bool hasNonLBRSamples() const {
- // currently just a stub - should be implemented when
- // first non-LBR profile is encountered
+ // Currently just a stub - should be implemented when
+ // first non-LBR profile is encountered.
return false;
}
diff --git a/llvm/include/llvm/ProfileData/SampleProfWriter.h b/llvm/include/llvm/ProfileData/SampleProfWriter.h
index 052843f9f55ac..770fcbe5afb92 100644
--- a/llvm/include/llvm/ProfileData/SampleProfWriter.h
+++ b/llvm/include/llvm/ProfileData/SampleProfWriter.h
@@ -216,8 +216,12 @@ class LLVM_ABI SampleProfileWriterBinary : public SampleProfileWriter {
std::error_code writeNameIdx(FunctionId FName);
std::error_code writeBody(const FunctionSamples &S);
void writeLBRProfile(const FunctionSamples &S);
- /// Writes typified profile for function
+
+ /// Interfaces for typified profile writing.
void writeTypifiedProfile(const FunctionSamples &S);
+ std::pair<uint64_t, uint64_t> startProfileType(ProfTypes Type);
+ void finishProfileType(uint64_t SizeOffset, uint64_t BodyOffset);
+ void writeTypifiedLBRProfile(const FunctionSamples &S);
inline void stablizeNameTable(MapVector<FunctionId, uint32_t> &NameTable,
std::set<FunctionId> &V);
@@ -432,7 +436,7 @@ class LLVM_ABI SampleProfileWriterExtBinary
std::error_code writeSections(const SampleProfileMap &ProfileMap) override;
- // Configure whether to use typified profile sections
+ // Configure whether to use typified profile sections.
void configureTypifiedProfile(const SampleProfileMap &ProfileMap);
std::error_code writeCustomSection(SecType Type) override {
diff --git a/llvm/lib/ProfileData/SampleProfReader.cpp b/llvm/lib/ProfileData/SampleProfReader.cpp
index d97cc8a6f6b88..843e38782b440 100644
--- a/llvm/lib/ProfileData/SampleProfReader.cpp
+++ b/llvm/lib/ProfileData/SampleProfReader.cpp
@@ -766,7 +766,7 @@ SampleProfileReaderBinary::readLBRProfile(FunctionSamples &FProfile) {
std::error_code
SampleProfileReaderBinary::readTypifiedProfile(FunctionSamples &FProfile) {
- // read the number of profile types
+ // Read the number of profile types.
auto ProfNum = readNumber<uint64_t>();
if (std::error_code EC = ProfNum.getError())
return EC;
diff --git a/llvm/lib/ProfileData/SampleProfWriter.cpp b/llvm/lib/ProfileData/SampleProfWriter.cpp
index c9787f367156c..941e3e9eab2ac 100644
--- a/llvm/lib/ProfileData/SampleProfWriter.cpp
+++ b/llvm/lib/ProfileData/SampleProfWriter.cpp
@@ -925,27 +925,49 @@ void SampleProfileWriterBinary::writeLBRProfile(const FunctionSamples &S) {
}
}
-void SampleProfileWriterBinary::writeTypifiedProfile(const FunctionSamples &S) {
- // Currently only LBR profile is supported as typified profile.
+std::pair<uint64_t, uint64_t>
+SampleProfileWriterBinary::startProfileType(ProfTypes Type) {
auto &OS = *OutputStream;
- // write the number of profile types for function
- encodeULEB128(1, OS);
- // Start first profile writing: write profile type
- encodeULEB128(ProfTypeLBR, OS);
- // create placeholder for profile size
+ encodeULEB128(Type, OS);
+ // Create placeholder for profile size.
uint64_t SizeOffset = OS.tell();
support::endian::Writer PlaceWriter(OS, llvm::endianness::little);
PlaceWriter.write(static_cast<uint64_t>(-1));
- // write the profile itself
- uint64_t BodyStart = OS.tell();
- writeLBRProfile(S);
- uint64_t BodySize = OS.tell() - BodyStart;
- // write profile size
+ uint64_t BodyOffset = OS.tell();
+ return {SizeOffset, BodyOffset};
+}
+
+void SampleProfileWriterBinary::finishProfileType(uint64_t SizeOffset,
+ uint64_t BodyOffset) {
+ auto &OS = *OutputStream;
+ uint64_t BodySize = OS.tell() - BodyOffset;
+ // Write profile size.
support::endian::SeekableWriter PWriter(static_cast<raw_pwrite_stream &>(OS),
llvm::endianness::little);
PWriter.pwrite(BodySize, SizeOffset);
}
+void SampleProfileWriterBinary::writeTypifiedLBRProfile(
+ const FunctionSamples &S) {
+ auto [SizeOffset, BodyOffset] = startProfileType(ProfTypeLBR);
+ writeLBRProfile(S);
+ finishProfileType(SizeOffset, BodyOffset);
+}
+
+void SampleProfileWriterBinary::writeTypifiedProfile(const FunctionSamples &S) {
+ auto &OS = *OutputStream;
+ bool WriteLBRProf = !S.getBodySamples().empty();
+ // Other profile types should be added here.
+ uint32_t TypesNum = WriteLBRProf;
+ assert(TypesNum && "Empty function samples");
+
+ // Write the number of profile types for function.
+ encodeULEB128(TypesNum, OS);
+
+ if (WriteLBRProf)
+ writeTypifiedLBRProfile(S);
+}
+
std::error_code SampleProfileWriterBinary::writeBody(const FunctionSamples &S) {
auto &OS = *OutputStream;
if (std::error_code EC = writeContextIdx(S.getContext()))
>From 7e5f66a1f944e43b0f239ee16a83ae4b34974169 Mon Sep 17 00:00:00 2001
From: Sergey Shcherbinin <sscherbinin at nvidia.com>
Date: Tue, 11 Nov 2025 18:34:29 +0400
Subject: [PATCH 4/7] Wrong assertion removed
---
llvm/lib/ProfileData/SampleProfWriter.cpp | 1 -
1 file changed, 1 deletion(-)
diff --git a/llvm/lib/ProfileData/SampleProfWriter.cpp b/llvm/lib/ProfileData/SampleProfWriter.cpp
index 941e3e9eab2ac..a3295b5231e14 100644
--- a/llvm/lib/ProfileData/SampleProfWriter.cpp
+++ b/llvm/lib/ProfileData/SampleProfWriter.cpp
@@ -959,7 +959,6 @@ void SampleProfileWriterBinary::writeTypifiedProfile(const FunctionSamples &S) {
bool WriteLBRProf = !S.getBodySamples().empty();
// Other profile types should be added here.
uint32_t TypesNum = WriteLBRProf;
- assert(TypesNum && "Empty function samples");
// Write the number of profile types for function.
encodeULEB128(TypesNum, OS);
>From bbf0f4d4f28f390e12f2f512a61d07c66ae3351b Mon Sep 17 00:00:00 2001
From: Sergey Shcherbinin <sscherbinin at nvidia.com>
Date: Wed, 12 Nov 2025 18:58:09 +0400
Subject: [PATCH 5/7] HeadSamples value is moved to typified LBR profile
sub-section
---
.../llvm/ProfileData/SampleProfReader.h | 6 +--
.../llvm/ProfileData/SampleProfWriter.h | 8 ++--
llvm/lib/ProfileData/SampleProfReader.cpp | 38 ++++++++++++-------
llvm/lib/ProfileData/SampleProfWriter.cpp | 30 +++++++++------
4 files changed, 50 insertions(+), 32 deletions(-)
diff --git a/llvm/include/llvm/ProfileData/SampleProfReader.h b/llvm/include/llvm/ProfileData/SampleProfReader.h
index 74e3f1773656d..6d05989db1c98 100644
--- a/llvm/include/llvm/ProfileData/SampleProfReader.h
+++ b/llvm/include/llvm/ProfileData/SampleProfReader.h
@@ -686,11 +686,11 @@ class LLVM_ABI SampleProfileReaderBinary : public SampleProfileReader {
SampleProfileMap &Profiles);
/// Read the contents of the given profile instance.
- std::error_code readProfile(FunctionSamples &FProfile);
+ std::error_code readProfile(FunctionSamples &FProfile, bool IsNested);
/// Read specific profile types.
- std::error_code readLBRProfile(FunctionSamples &FProfile);
- std::error_code readTypifiedProfile(FunctionSamples &FProfile);
+ std::error_code readLBRProfile(FunctionSamples &FProfile, bool IsNested);
+ std::error_code readTypifiedProfile(FunctionSamples &FProfile, bool IsNested);
/// Read the contents of Magic number and Version number.
std::error_code readMagicIdent();
diff --git a/llvm/include/llvm/ProfileData/SampleProfWriter.h b/llvm/include/llvm/ProfileData/SampleProfWriter.h
index 770fcbe5afb92..42ab29011c4f2 100644
--- a/llvm/include/llvm/ProfileData/SampleProfWriter.h
+++ b/llvm/include/llvm/ProfileData/SampleProfWriter.h
@@ -214,14 +214,14 @@ class LLVM_ABI SampleProfileWriterBinary : public SampleProfileWriter {
std::error_code writeSummary();
virtual std::error_code writeContextIdx(const SampleContext &Context);
std::error_code writeNameIdx(FunctionId FName);
- std::error_code writeBody(const FunctionSamples &S);
- void writeLBRProfile(const FunctionSamples &S);
+ std::error_code writeBody(const FunctionSamples &S, bool IsNested);
+ void writeLBRProfile(const FunctionSamples &S, bool IsNested);
/// Interfaces for typified profile writing.
- void writeTypifiedProfile(const FunctionSamples &S);
+ void writeTypifiedProfile(const FunctionSamples &S, bool IsNested);
std::pair<uint64_t, uint64_t> startProfileType(ProfTypes Type);
void finishProfileType(uint64_t SizeOffset, uint64_t BodyOffset);
- void writeTypifiedLBRProfile(const FunctionSamples &S);
+ void writeTypifiedLBRProfile(const FunctionSamples &S, bool IsNested);
inline void stablizeNameTable(MapVector<FunctionId, uint32_t> &NameTable,
std::set<FunctionId> &V);
diff --git a/llvm/lib/ProfileData/SampleProfReader.cpp b/llvm/lib/ProfileData/SampleProfReader.cpp
index 843e38782b440..10777bc34d606 100644
--- a/llvm/lib/ProfileData/SampleProfReader.cpp
+++ b/llvm/lib/ProfileData/SampleProfReader.cpp
@@ -710,7 +710,14 @@ SampleProfileReaderBinary::readCallsiteVTableProf(FunctionSamples &FProfile) {
}
std::error_code
-SampleProfileReaderBinary::readLBRProfile(FunctionSamples &FProfile) {
+SampleProfileReaderBinary::readLBRProfile(FunctionSamples &FProfile,
+ bool IsNested) {
+ if (IsProfileTypified && !IsNested) {
+ auto NumHeadSamples = readNumber<uint64_t>();
+ if (std::error_code EC = NumHeadSamples.getError())
+ return EC;
+ FProfile.addHeadSamples(*NumHeadSamples);
+ }
auto NumSamples = readNumber<uint64_t>();
if (std::error_code EC = NumSamples.getError())
return EC;
@@ -765,7 +772,8 @@ SampleProfileReaderBinary::readLBRProfile(FunctionSamples &FProfile) {
}
std::error_code
-SampleProfileReaderBinary::readTypifiedProfile(FunctionSamples &FProfile) {
+SampleProfileReaderBinary::readTypifiedProfile(FunctionSamples &FProfile,
+ bool IsNested) {
// Read the number of profile types.
auto ProfNum = readNumber<uint64_t>();
if (std::error_code EC = ProfNum.getError())
@@ -782,7 +790,7 @@ SampleProfileReaderBinary::readTypifiedProfile(FunctionSamples &FProfile) {
switch (*Type) {
case ProfTypeLBR:
- if (std::error_code EC = readLBRProfile(FProfile))
+ if (std::error_code EC = readLBRProfile(FProfile, IsNested))
return EC;
break;
default:
@@ -798,12 +806,13 @@ SampleProfileReaderBinary::readTypifiedProfile(FunctionSamples &FProfile) {
}
std::error_code
-SampleProfileReaderBinary::readProfile(FunctionSamples &FProfile) {
+SampleProfileReaderBinary::readProfile(FunctionSamples &FProfile,
+ bool IsNested) {
if (IsProfileTypified) {
- if (std::error_code EC = readTypifiedProfile(FProfile))
+ if (std::error_code EC = readTypifiedProfile(FProfile, IsNested))
return EC;
} else {
- if (std::error_code EC = readLBRProfile(FProfile))
+ if (std::error_code EC = readLBRProfile(FProfile, IsNested))
return EC;
}
@@ -831,7 +840,7 @@ SampleProfileReaderBinary::readProfile(FunctionSamples &FProfile) {
FunctionSamples &CalleeProfile = FProfile.functionSamplesAt(
LineLocation(*LineOffset, DiscriminatorVal))[*FName];
CalleeProfile.setFunction(*FName);
- if (std::error_code EC = readProfile(CalleeProfile))
+ if (std::error_code EC = readProfile(CalleeProfile, true))
return EC;
}
@@ -845,10 +854,12 @@ std::error_code
SampleProfileReaderBinary::readFuncProfile(const uint8_t *Start,
SampleProfileMap &Profiles) {
Data = Start;
- auto NumHeadSamples = readNumber<uint64_t>();
- if (std::error_code EC = NumHeadSamples.getError())
- return EC;
-
+ ErrorOr<uint64_t> NumHeadSamples = 0;
+ if (!IsProfileTypified) {
+ NumHeadSamples = readNumber<uint64_t>();
+ if (std::error_code EC = NumHeadSamples.getError())
+ return EC;
+ }
auto FContextHash(readSampleContextFromTable());
if (std::error_code EC = FContextHash.getError())
return EC;
@@ -858,12 +869,13 @@ SampleProfileReaderBinary::readFuncProfile(const uint8_t *Start,
auto Res = Profiles.try_emplace(Hash, FContext, FunctionSamples());
FunctionSamples &FProfile = Res.first->second;
FProfile.setContext(FContext);
- FProfile.addHeadSamples(*NumHeadSamples);
+ if (!IsProfileTypified)
+ FProfile.addHeadSamples(*NumHeadSamples);
if (FContext.hasContext())
CSProfileCount++;
- if (std::error_code EC = readProfile(FProfile))
+ if (std::error_code EC = readProfile(FProfile, false))
return EC;
return sampleprof_error::success;
}
diff --git a/llvm/lib/ProfileData/SampleProfWriter.cpp b/llvm/lib/ProfileData/SampleProfWriter.cpp
index a3295b5231e14..0eaf9e13d7a0b 100644
--- a/llvm/lib/ProfileData/SampleProfWriter.cpp
+++ b/llvm/lib/ProfileData/SampleProfWriter.cpp
@@ -264,8 +264,9 @@ SampleProfileWriterExtBinaryBase::writeSample(const FunctionSamples &S) {
uint64_t Offset = OutputStream->tell();
auto &Context = S.getContext();
FuncOffsetTable[Context] = Offset - SecLBRProfileStart;
- encodeULEB128(S.getHeadSamples(), *OutputStream);
- return writeBody(S);
+ if (!WriteTypifiedProf)
+ encodeULEB128(S.getHeadSamples(), *OutputStream);
+ return writeBody(S, false);
}
std::error_code SampleProfileWriterExtBinaryBase::writeFuncOffsetTable() {
@@ -913,8 +914,11 @@ std::error_code SampleProfileWriterBinary::writeSummary() {
return sampleprof_error::success;
}
-void SampleProfileWriterBinary::writeLBRProfile(const FunctionSamples &S) {
+void SampleProfileWriterBinary::writeLBRProfile(const FunctionSamples &S,
+ bool IsNested) {
auto &OS = *OutputStream;
+ if (WriteTypifiedProf && !IsNested)
+ encodeULEB128(S.getHeadSamples(), OS);
encodeULEB128(S.getTotalSamples(), OS);
encodeULEB128(S.getBodySamples().size(), OS);
for (const auto &I : S.getBodySamples()) {
@@ -948,13 +952,14 @@ void SampleProfileWriterBinary::finishProfileType(uint64_t SizeOffset,
}
void SampleProfileWriterBinary::writeTypifiedLBRProfile(
- const FunctionSamples &S) {
+ const FunctionSamples &S, bool IsNested) {
auto [SizeOffset, BodyOffset] = startProfileType(ProfTypeLBR);
- writeLBRProfile(S);
+ writeLBRProfile(S, IsNested);
finishProfileType(SizeOffset, BodyOffset);
}
-void SampleProfileWriterBinary::writeTypifiedProfile(const FunctionSamples &S) {
+void SampleProfileWriterBinary::writeTypifiedProfile(const FunctionSamples &S,
+ bool IsNested) {
auto &OS = *OutputStream;
bool WriteLBRProf = !S.getBodySamples().empty();
// Other profile types should be added here.
@@ -964,19 +969,20 @@ void SampleProfileWriterBinary::writeTypifiedProfile(const FunctionSamples &S) {
encodeULEB128(TypesNum, OS);
if (WriteLBRProf)
- writeTypifiedLBRProfile(S);
+ writeTypifiedLBRProfile(S, IsNested);
}
-std::error_code SampleProfileWriterBinary::writeBody(const FunctionSamples &S) {
+std::error_code SampleProfileWriterBinary::writeBody(const FunctionSamples &S,
+ bool IsNested) {
auto &OS = *OutputStream;
if (std::error_code EC = writeContextIdx(S.getContext()))
return EC;
// Emit all the body samples.
if (WriteTypifiedProf)
- writeTypifiedProfile(S);
+ writeTypifiedProfile(S, IsNested);
else
- writeLBRProfile(S);
+ writeLBRProfile(S, IsNested);
// Recursively emit all the callsite samples.
uint64_t NumCallsites = 0;
@@ -986,7 +992,7 @@ std::error_code SampleProfileWriterBinary::writeBody(const FunctionSamples &S) {
for (const auto &J : S.getCallsiteSamples())
for (const auto &FS : J.second) {
J.first.serialize(OS);
- if (std::error_code EC = writeBody(FS.second))
+ if (std::error_code EC = writeBody(FS.second, true))
return EC;
}
@@ -1002,7 +1008,7 @@ std::error_code SampleProfileWriterBinary::writeBody(const FunctionSamples &S) {
std::error_code
SampleProfileWriterBinary::writeSample(const FunctionSamples &S) {
encodeULEB128(S.getHeadSamples(), *OutputStream);
- return writeBody(S);
+ return writeBody(S, false);
}
/// Create a sample profile file writer based on the specified format.
>From 7393639b4ba09d0c76081070455401bb69196b53 Mon Sep 17 00:00:00 2001
From: Sergey Shcherbinin <sscherbinin at nvidia.com>
Date: Tue, 30 Jun 2026 00:01:23 +0400
Subject: [PATCH 6/7] Apply suggestion from @kazutakahirata
Co-authored-by: Kazu Hirata <kazu at google.com>
---
llvm/include/llvm/ProfileData/SampleProf.h | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/llvm/include/llvm/ProfileData/SampleProf.h b/llvm/include/llvm/ProfileData/SampleProf.h
index 1bb8bdc9bfcfd..1cdf3ea387b0e 100644
--- a/llvm/include/llvm/ProfileData/SampleProf.h
+++ b/llvm/include/llvm/ProfileData/SampleProf.h
@@ -1488,7 +1488,8 @@ class SampleProfileMap
for (const auto &[Context, FuncSamples] : *this) {
if (FuncSamples.hasNonLBRSamples()) {
return true;
- }
+ if (FuncSamples.hasNonLBRSamples())
+ return true;
}
return false;
}
>From 0ed9c41610de6d6eecf42c05043777da43657c47 Mon Sep 17 00:00:00 2001
From: Sergey Shcherbinin <sscherbinin at nvidia.com>
Date: Tue, 30 Jun 2026 09:14:56 +0400
Subject: [PATCH 7/7] Apply suggestion from @kazutakahirata (round 2)
---
llvm/include/llvm/ProfileData/SampleProf.h | 2 --
1 file changed, 2 deletions(-)
diff --git a/llvm/include/llvm/ProfileData/SampleProf.h b/llvm/include/llvm/ProfileData/SampleProf.h
index 1cdf3ea387b0e..3990eafeb357f 100644
--- a/llvm/include/llvm/ProfileData/SampleProf.h
+++ b/llvm/include/llvm/ProfileData/SampleProf.h
@@ -1486,8 +1486,6 @@ class SampleProfileMap
bool hasNonLBRProfile() const {
for (const auto &[Context, FuncSamples] : *this) {
- if (FuncSamples.hasNonLBRSamples()) {
- return true;
if (FuncSamples.hasNonLBRSamples())
return true;
}
More information about the llvm-commits
mailing list