-
Notifications
You must be signed in to change notification settings - Fork 14.3k
Implements PGOBBAddrMap in Object and ObjectYAML with tests [1/5] #71750
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 9 commits
6374da5
989c084
3411bb8
a8943fe
03ed2b2
675b89b
bad3043
2d56621
eeb5827
d574fb3
8e6df9a
5bf9079
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -645,11 +645,36 @@ ELFFile<ELFT>::toMappedAddr(uint64_t VAddr, WarningHandler WarnHandler) const { | |
return base() + Offset; | ||
} | ||
|
||
template <class ELFT> | ||
Expected<std::vector<BBAddrMap>> | ||
ELFFile<ELFT>::decodeBBAddrMap(const Elf_Shdr &Sec, | ||
const Elf_Shdr *RelaSec) const { | ||
bool IsRelocatable = getHeader().e_type == ELF::ET_REL; | ||
// Helper to extract and decode the next ULEB128 value as unsigned int. | ||
// Returns zero and sets ULEBSizeErr if the ULEB128 value exceeds the unsigned | ||
// int limit. | ||
// Also returns zero if ULEBSizeErr is already in an error state. | ||
// ULEBSizeErr is an out variable if an error occurs. | ||
template <typename IntTy, std::enable_if_t<std::is_unsigned_v<IntTy>, int> = 0> | ||
static IntTy readULEB128As(DataExtractor &Data, DataExtractor::Cursor &Cur, | ||
Error &ULEBSizeErr) { | ||
// Bail out and do not extract data if ULEBSizeErr is already set. | ||
if (ULEBSizeErr) | ||
return 0; | ||
uint64_t Offset = Cur.tell(); | ||
uint64_t Value = Data.getULEB128(Cur); | ||
if (Value > std::numeric_limits<IntTy>::max()) { | ||
ULEBSizeErr = createError("ULEB128 value at offset 0x" + | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there any testing of this error? I couldn't immediately find any in this patch, but I suppose it could exist already. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, I this is already tested in the regular BBAddrMap tests. Found at ELFObjectFileTest.cpp:564 |
||
Twine::utohexstr(Offset) + " exceeds UINT" + | ||
Twine(std::numeric_limits<IntTy>::digits) + | ||
"_MAX (0x" + Twine::utohexstr(Value) + ")"); | ||
return 0; | ||
} | ||
return static_cast<IntTy>(Value); | ||
} | ||
|
||
template <typename ELFT> | ||
static Expected<std::vector<BBAddrMap>> | ||
decodeBBAddrMapImpl(const ELFFile<ELFT> &EF, | ||
const typename ELFFile<ELFT>::Elf_Shdr &Sec, | ||
const typename ELFFile<ELFT>::Elf_Shdr *RelaSec, | ||
std::vector<PGOAnalysisMap> *PGOAnalyses) { | ||
bool IsRelocatable = EF.getHeader().e_type == ELF::ET_REL; | ||
|
||
// This DenseMap maps the offset of each function (the location of the | ||
// reference to the function in the SHT_LLVM_BB_ADDR_MAP section) to the | ||
|
@@ -659,44 +684,30 @@ ELFFile<ELFT>::decodeBBAddrMap(const Elf_Shdr &Sec, | |
assert(RelaSec && | ||
"Can't read a SHT_LLVM_BB_ADDR_MAP section in a relocatable " | ||
"object file without providing a relocation section."); | ||
Expected<Elf_Rela_Range> Relas = this->relas(*RelaSec); | ||
Expected<typename ELFFile<ELFT>::Elf_Rela_Range> Relas = EF.relas(*RelaSec); | ||
if (!Relas) | ||
return createError("unable to read relocations for section " + | ||
describe(*this, Sec) + ": " + | ||
describe(EF, Sec) + ": " + | ||
toString(Relas.takeError())); | ||
for (Elf_Rela Rela : *Relas) | ||
for (typename ELFFile<ELFT>::Elf_Rela Rela : *Relas) | ||
FunctionOffsetTranslations[Rela.r_offset] = Rela.r_addend; | ||
} | ||
Expected<ArrayRef<uint8_t>> ContentsOrErr = getSectionContents(Sec); | ||
Expected<ArrayRef<uint8_t>> ContentsOrErr = EF.getSectionContents(Sec); | ||
if (!ContentsOrErr) | ||
return ContentsOrErr.takeError(); | ||
ArrayRef<uint8_t> Content = *ContentsOrErr; | ||
DataExtractor Data(Content, isLE(), ELFT::Is64Bits ? 8 : 4); | ||
DataExtractor Data(Content, EF.isLE(), ELFT::Is64Bits ? 8 : 4); | ||
std::vector<BBAddrMap> FunctionEntries; | ||
|
||
DataExtractor::Cursor Cur(0); | ||
Error ULEBSizeErr = Error::success(); | ||
Error MetadataDecodeErr = Error::success(); | ||
// Helper to extract and decode the next ULEB128 value as uint32_t. | ||
// Returns zero and sets ULEBSizeErr if the ULEB128 value exceeds the uint32_t | ||
// limit. | ||
// Also returns zero if ULEBSizeErr is already in an error state. | ||
auto ReadULEB128AsUInt32 = [&Data, &Cur, &ULEBSizeErr]() -> uint32_t { | ||
// Bail out and do not extract data if ULEBSizeErr is already set. | ||
if (ULEBSizeErr) | ||
return 0; | ||
uint64_t Offset = Cur.tell(); | ||
uint64_t Value = Data.getULEB128(Cur); | ||
if (Value > UINT32_MAX) { | ||
ULEBSizeErr = createError( | ||
"ULEB128 value at offset 0x" + Twine::utohexstr(Offset) + | ||
" exceeds UINT32_MAX (0x" + Twine::utohexstr(Value) + ")"); | ||
return 0; | ||
} | ||
return static_cast<uint32_t>(Value); | ||
}; | ||
|
||
uint8_t Version = 0; | ||
uint8_t Feature = 0; | ||
bool FuncEntryCountEnabled = false; | ||
bool BBFreqEnabled = false; | ||
bool BrProbEnabled = false; | ||
while (!ULEBSizeErr && !MetadataDecodeErr && Cur && | ||
Cur.tell() < Content.size()) { | ||
if (Sec.sh_type == ELF::SHT_LLVM_BB_ADDR_MAP) { | ||
|
@@ -706,10 +717,21 @@ ELFFile<ELFT>::decodeBBAddrMap(const Elf_Shdr &Sec, | |
if (Version > 2) | ||
return createError("unsupported SHT_LLVM_BB_ADDR_MAP version: " + | ||
Twine(static_cast<int>(Version))); | ||
Data.getU8(Cur); // Feature byte | ||
Feature = Data.getU8(Cur); // Feature byte | ||
FuncEntryCountEnabled = | ||
red1bluelost marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Feature & uint8_t(PGOAnalysisMap::Features::FuncEntryCnt); | ||
BBFreqEnabled = Feature & uint8_t(PGOAnalysisMap::Features::BBFreq); | ||
BrProbEnabled = Feature & uint8_t(PGOAnalysisMap::Features::BrProb); | ||
if (Feature != 0 && Version < 2 && Cur) | ||
return createError( | ||
"version should be >= 2 for SHT_LLVM_BB_ADDR_MAP when " | ||
"PGO features are enabled: version = " + | ||
Twine(static_cast<int>(Version)) + | ||
" feature = " + Twine(static_cast<int>(Feature))); | ||
} | ||
uint64_t SectionOffset = Cur.tell(); | ||
uintX_t Address = static_cast<uintX_t>(Data.getAddress(Cur)); | ||
auto Address = | ||
static_cast<typename ELFFile<ELFT>::uintX_t>(Data.getAddress(Cur)); | ||
if (!Cur) | ||
return Cur.takeError(); | ||
if (IsRelocatable) { | ||
|
@@ -718,20 +740,23 @@ ELFFile<ELFT>::decodeBBAddrMap(const Elf_Shdr &Sec, | |
if (FOTIterator == FunctionOffsetTranslations.end()) { | ||
return createError("failed to get relocation data for offset: " + | ||
Twine::utohexstr(SectionOffset) + " in section " + | ||
describe(*this, Sec)); | ||
describe(EF, Sec)); | ||
} | ||
Address = FOTIterator->second; | ||
} | ||
uint32_t NumBlocks = ReadULEB128AsUInt32(); | ||
uint32_t NumBlocks = readULEB128As<uint32_t>(Data, Cur, ULEBSizeErr); | ||
|
||
std::vector<BBAddrMap::BBEntry> BBEntries; | ||
uint32_t PrevBBEndOffset = 0; | ||
for (uint32_t BlockIndex = 0; | ||
!MetadataDecodeErr && !ULEBSizeErr && Cur && (BlockIndex < NumBlocks); | ||
++BlockIndex) { | ||
uint32_t ID = Version >= 2 ? ReadULEB128AsUInt32() : BlockIndex; | ||
uint32_t Offset = ReadULEB128AsUInt32(); | ||
uint32_t Size = ReadULEB128AsUInt32(); | ||
uint32_t MD = ReadULEB128AsUInt32(); | ||
uint32_t ID = Version >= 2 | ||
? readULEB128As<uint32_t>(Data, Cur, ULEBSizeErr) | ||
: BlockIndex; | ||
uint32_t Offset = readULEB128As<uint32_t>(Data, Cur, ULEBSizeErr); | ||
uint32_t Size = readULEB128As<uint32_t>(Data, Cur, ULEBSizeErr); | ||
uint32_t MD = readULEB128As<uint32_t>(Data, Cur, ULEBSizeErr); | ||
if (Version >= 1) { | ||
// Offset is calculated relative to the end of the previous BB. | ||
Offset += PrevBBEndOffset; | ||
|
@@ -746,6 +771,44 @@ ELFFile<ELFT>::decodeBBAddrMap(const Elf_Shdr &Sec, | |
BBEntries.push_back({ID, Offset, Size, *MetadataOrErr}); | ||
} | ||
FunctionEntries.emplace_back(Address, std::move(BBEntries)); | ||
|
||
if (FuncEntryCountEnabled || BBFreqEnabled || BrProbEnabled) { | ||
// Function entry count | ||
uint64_t FuncEntryCount = | ||
FuncEntryCountEnabled | ||
? readULEB128As<uint64_t>(Data, Cur, ULEBSizeErr) | ||
: 0; | ||
|
||
std::vector<PGOAnalysisMap::PGOBBEntry> PGOBBEntries; | ||
for (uint32_t BlockIndex = 0; !MetadataDecodeErr && !ULEBSizeErr && Cur && | ||
(BlockIndex < NumBlocks); | ||
++BlockIndex) { | ||
// Block frequency | ||
uint64_t BBF = | ||
BBFreqEnabled ? readULEB128As<uint64_t>(Data, Cur, ULEBSizeErr) : 0; | ||
|
||
// Branch probability | ||
llvm::SmallVector<PGOAnalysisMap::PGOBBEntry::SuccessorEntry, 2> | ||
Successors; | ||
if (BrProbEnabled) { | ||
auto SuccCount = readULEB128As<uint64_t>(Data, Cur, ULEBSizeErr); | ||
for (uint64_t I = 0; I < SuccCount; ++I) { | ||
uint32_t BBID = readULEB128As<uint32_t>(Data, Cur, ULEBSizeErr); | ||
uint32_t BrProb = readULEB128As<uint32_t>(Data, Cur, ULEBSizeErr); | ||
if (PGOAnalyses) | ||
Successors.push_back({BBID, BranchProbability::getRaw(BrProb)}); | ||
} | ||
} | ||
|
||
if (PGOAnalyses) | ||
PGOBBEntries.push_back({BlockFrequency(BBF), std::move(Successors)}); | ||
} | ||
|
||
if (PGOAnalyses) | ||
PGOAnalyses->push_back({FuncEntryCount, std::move(PGOBBEntries), | ||
FuncEntryCountEnabled, BBFreqEnabled, | ||
BrProbEnabled}); | ||
} | ||
} | ||
// Either Cur is in the error state, or we have an error in ULEBSizeErr or | ||
// MetadataDecodeErr (but not both), but we join all errors here to be safe. | ||
|
@@ -755,6 +818,18 @@ ELFFile<ELFT>::decodeBBAddrMap(const Elf_Shdr &Sec, | |
return FunctionEntries; | ||
} | ||
|
||
template <class ELFT> | ||
Expected<std::vector<BBAddrMap>> | ||
ELFFile<ELFT>::decodeBBAddrMap(const Elf_Shdr &Sec, const Elf_Shdr *RelaSec, | ||
std::vector<PGOAnalysisMap> *PGOAnalyses) const { | ||
size_t OriginalPGOSize = PGOAnalyses ? PGOAnalyses->size() : 0; | ||
auto AddrMapsOrErr = decodeBBAddrMapImpl(*this, Sec, RelaSec, PGOAnalyses); | ||
// remove new analyses when an error occurs | ||
if (!AddrMapsOrErr && PGOAnalyses) | ||
PGOAnalyses->resize(OriginalPGOSize); | ||
return std::move(AddrMapsOrErr); | ||
} | ||
|
||
template <class ELFT> | ||
Expected< | ||
MapVector<const typename ELFT::Shdr *, const typename ELFT::Shdr *>> | ||
|
Uh oh!
There was an error while loading. Please reload this page.