Skip to content

[SHT_LLVM_BB_ADDR_MAP] Encode and decode callsite offsets in a newly-introduced SHT_LLVM_BB_ADDR_MAP version. #144426

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

Merged
merged 1 commit into from
Jun 23, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 15 additions & 7 deletions llvm/include/llvm/Object/ELFTypes.h
Original file line number Diff line number Diff line change
@@ -831,6 +831,7 @@ struct BBAddrMap {
bool BrProb : 1;
bool MultiBBRange : 1;
bool OmitBBEntries : 1;
bool CallsiteOffsets : 1;

bool hasPGOAnalysis() const { return FuncEntryCount || BBFreq || BrProb; }

@@ -842,7 +843,8 @@ struct BBAddrMap {
(static_cast<uint8_t>(BBFreq) << 1) |
(static_cast<uint8_t>(BrProb) << 2) |
(static_cast<uint8_t>(MultiBBRange) << 3) |
(static_cast<uint8_t>(OmitBBEntries) << 4);
(static_cast<uint8_t>(OmitBBEntries) << 4) |
(static_cast<uint8_t>(CallsiteOffsets) << 5);
}

// Decodes from minimum bit width representation and validates no
@@ -851,7 +853,7 @@ struct BBAddrMap {
Features Feat{
static_cast<bool>(Val & (1 << 0)), static_cast<bool>(Val & (1 << 1)),
static_cast<bool>(Val & (1 << 2)), static_cast<bool>(Val & (1 << 3)),
static_cast<bool>(Val & (1 << 4))};
static_cast<bool>(Val & (1 << 4)), static_cast<bool>(Val & (1 << 5))};
if (Feat.encode() != Val)
return createStringError(
std::error_code(), "invalid encoding for BBAddrMap::Features: 0x%x",
@@ -861,9 +863,10 @@ struct BBAddrMap {

bool operator==(const Features &Other) const {
return std::tie(FuncEntryCount, BBFreq, BrProb, MultiBBRange,
OmitBBEntries) ==
OmitBBEntries, CallsiteOffsets) ==
std::tie(Other.FuncEntryCount, Other.BBFreq, Other.BrProb,
Other.MultiBBRange, Other.OmitBBEntries);
Other.MultiBBRange, Other.OmitBBEntries,
Other.CallsiteOffsets);
}
};

@@ -914,13 +917,18 @@ struct BBAddrMap {
uint32_t Size = 0; // Size of the basic block.
Metadata MD = {false, false, false, false,
false}; // Metdata for this basic block.
// Offsets of callsites (end of call instructions), relative to the basic
// block start.
SmallVector<uint32_t, 1> CallsiteOffsets;

BBEntry(uint32_t ID, uint32_t Offset, uint32_t Size, Metadata MD)
: ID(ID), Offset(Offset), Size(Size), MD(MD){};
BBEntry(uint32_t ID, uint32_t Offset, uint32_t Size, Metadata MD,
SmallVector<uint32_t, 1> CallsiteOffsets)
: ID(ID), Offset(Offset), Size(Size), MD(MD),
CallsiteOffsets(std::move(CallsiteOffsets)) {}

bool operator==(const BBEntry &Other) const {
return ID == Other.ID && Offset == Other.Offset && Size == Other.Size &&
MD == Other.MD;
MD == Other.MD && CallsiteOffsets == Other.CallsiteOffsets;
}

bool hasReturn() const { return MD.HasReturn; }
15 changes: 15 additions & 0 deletions llvm/include/llvm/ObjectYAML/ELFYAML.h
Original file line number Diff line number Diff line change
@@ -162,6 +162,7 @@ struct BBAddrMapEntry {
llvm::yaml::Hex64 AddressOffset;
llvm::yaml::Hex64 Size;
llvm::yaml::Hex64 Metadata;
std::optional<std::vector<llvm::yaml::Hex64>> CallsiteOffsets;
};
uint8_t Version;
llvm::yaml::Hex8 Feature;
@@ -180,6 +181,20 @@ struct BBAddrMapEntry {
return 0;
return BBRanges->front().BaseAddress;
}

// Returns if any BB entries have non-empty callsite offsets.
bool hasAnyCallsiteOffsets() const {
if (!BBRanges)
return false;
for (const ELFYAML::BBAddrMapEntry::BBRangeEntry &BBR : *BBRanges) {
if (!BBR.BBEntries)
continue;
for (const ELFYAML::BBAddrMapEntry::BBEntry &BBE : *BBR.BBEntries)
if (BBE.CallsiteOffsets && !BBE.CallsiteOffsets->empty())
return true;
}
return false;
}
};

struct PGOAnalysisMapEntry {
7 changes: 5 additions & 2 deletions llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
Original file line number Diff line number Diff line change
@@ -1426,9 +1426,12 @@ getBBAddrMapFeature(const MachineFunction &MF, int NumMBBSectionRanges) {
"BB entries info is required for BBFreq and BrProb "
"features");
}
return {FuncEntryCountEnabled, BBFreqEnabled, BrProbEnabled,
return {FuncEntryCountEnabled,
BBFreqEnabled,
BrProbEnabled,
MF.hasBBSections() && NumMBBSectionRanges > 1,
static_cast<bool>(BBAddrMapSkipEmitBBEntries)};
static_cast<bool>(BBAddrMapSkipEmitBBEntries),
false};
}

void AsmPrinter::emitBBAddrMapSection(const MachineFunction &MF) {
31 changes: 27 additions & 4 deletions llvm/lib/Object/ELF.cpp
Original file line number Diff line number Diff line change
@@ -837,7 +837,7 @@ decodeBBAddrMapImpl(const ELFFile<ELFT> &EF,
Version = Data.getU8(Cur);
if (!Cur)
break;
if (Version > 2)
if (Version > 3)
return createError("unsupported SHT_LLVM_BB_ADDR_MAP version: " +
Twine(static_cast<int>(Version)));
Feature = Data.getU8(Cur); // Feature byte
@@ -847,12 +847,18 @@ decodeBBAddrMapImpl(const ELFFile<ELFT> &EF,
if (!FeatEnableOrErr)
return FeatEnableOrErr.takeError();
FeatEnable = *FeatEnableOrErr;
if (Feature != 0 && Version < 2 && Cur)
if (FeatEnable.hasPGOAnalysis() && Version < 2)
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)));
if (FeatEnable.CallsiteOffsets && Version < 3)
return createError(
"version should be >= 3 for SHT_LLVM_BB_ADDR_MAP when "
"callsite offsets feature is enabled: version = " +
Twine(static_cast<int>(Version)) +
" feature = " + Twine(static_cast<int>(Feature)));
}
uint32_t NumBlocksInBBRange = 0;
uint32_t NumBBRanges = 1;
@@ -893,7 +899,23 @@ decodeBBAddrMapImpl(const ELFFile<ELFT> &EF,
? 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);
// Read the callsite offsets.
uint32_t LastCallsiteOffset = 0;
SmallVector<uint32_t, 1> CallsiteOffsets;
if (FeatEnable.CallsiteOffsets) {
uint32_t NumCallsites =
readULEB128As<uint32_t>(Data, Cur, ULEBSizeErr);
CallsiteOffsets.reserve(NumCallsites);
for (uint32_t CallsiteIndex = 0;
!ULEBSizeErr && Cur && (CallsiteIndex < NumCallsites);
++CallsiteIndex) {
LastCallsiteOffset +=
readULEB128As<uint32_t>(Data, Cur, ULEBSizeErr);
CallsiteOffsets.push_back(LastCallsiteOffset);
}
}
uint32_t Size = readULEB128As<uint32_t>(Data, Cur, ULEBSizeErr) +
LastCallsiteOffset;
uint32_t MD = readULEB128As<uint32_t>(Data, Cur, ULEBSizeErr);
if (Version >= 1) {
// Offset is calculated relative to the end of the previous BB.
@@ -906,7 +928,8 @@ decodeBBAddrMapImpl(const ELFFile<ELFT> &EF,
MetadataDecodeErr = MetadataOrErr.takeError();
break;
}
BBEntries.push_back({ID, Offset, Size, *MetadataOrErr});
BBEntries.push_back(
{ID, Offset, Size, *MetadataOrErr, CallsiteOffsets});
}
TotalNumBlocks += BBEntries.size();
}
13 changes: 12 additions & 1 deletion llvm/lib/ObjectYAML/ELFEmitter.cpp
Original file line number Diff line number Diff line change
@@ -1452,7 +1452,7 @@ void ELFState<ELFT>::writeSectionContent(
for (const auto &[Idx, E] : llvm::enumerate(*Section.Entries)) {
// Write version and feature values.
if (Section.Type == llvm::ELF::SHT_LLVM_BB_ADDR_MAP) {
if (E.Version > 2)
if (E.Version > 3)
WithColor::warning() << "unsupported SHT_LLVM_BB_ADDR_MAP version: "
<< static_cast<int>(E.Version)
<< "; encoding using the most recent version";
@@ -1483,6 +1483,8 @@ void ELFState<ELFT>::writeSectionContent(
if (!E.BBRanges)
continue;
uint64_t TotalNumBlocks = 0;
bool EmitCallsiteOffsets =
FeatureOrErr->CallsiteOffsets || E.hasAnyCallsiteOffsets();
for (const ELFYAML::BBAddrMapEntry::BBRangeEntry &BBR : *E.BBRanges) {
// Write the base address of the range.
CBA.write<uintX_t>(BBR.BaseAddress, ELFT::Endianness);
@@ -1500,6 +1502,15 @@ void ELFState<ELFT>::writeSectionContent(
if (Section.Type == llvm::ELF::SHT_LLVM_BB_ADDR_MAP && E.Version > 1)
SHeader.sh_size += CBA.writeULEB128(BBE.ID);
SHeader.sh_size += CBA.writeULEB128(BBE.AddressOffset);
if (EmitCallsiteOffsets) {
size_t NumCallsiteOffsets =
BBE.CallsiteOffsets ? BBE.CallsiteOffsets->size() : 0;
SHeader.sh_size += CBA.writeULEB128(NumCallsiteOffsets);
if (BBE.CallsiteOffsets) {
for (uint32_t Offset : *BBE.CallsiteOffsets)
SHeader.sh_size += CBA.writeULEB128(Offset);
}
}
SHeader.sh_size += CBA.writeULEB128(BBE.Size);
SHeader.sh_size += CBA.writeULEB128(BBE.Metadata);
}
1 change: 1 addition & 0 deletions llvm/lib/ObjectYAML/ELFYAML.cpp
Original file line number Diff line number Diff line change
@@ -1882,6 +1882,7 @@ void MappingTraits<ELFYAML::BBAddrMapEntry::BBEntry>::mapping(
IO.mapRequired("AddressOffset", E.AddressOffset);
IO.mapRequired("Size", E.Size);
IO.mapRequired("Metadata", E.Metadata);
IO.mapOptional("CallsiteOffsets", E.CallsiteOffsets);
}

void MappingTraits<ELFYAML::PGOAnalysisMapEntry>::mapping(
10 changes: 6 additions & 4 deletions llvm/test/tools/llvm-readobj/ELF/bb-addr-map.test
Original file line number Diff line number Diff line change
@@ -49,7 +49,8 @@
# CHECK-NEXT: {
# CHECK-NEXT: ID: 2
# CHECK-NEXT: Offset: 0x3
# CHECK-NEXT: Size: 0x4
# CHECK-NEXT: Callsite Offsets: [1, 3]
# CHECK-NEXT: Size: 0x7
# CHECK-NEXT: HasReturn: Yes
# CHECK-NEXT: HasTailCall: No
# CHECK-NEXT: IsEHPad: Yes
@@ -75,7 +76,7 @@
# CHECK-NEXT: HasTailCall: No
# CHECK-NEXT: IsEHPad: No
# CHECK-NEXT: CanFallThrough: Yes
# CHECK-NEXT: HasIndirectBranch: No
# CHECK-NEXT: HasIndirectBranch: No
# CHECK-NEXT: }
# CHECK-NEXT: ]
# CHECK-NEXT: }
@@ -143,8 +144,8 @@ Sections:
ShSize: [[SIZE=<none>]]
Link: .text
Entries:
- Version: 2
Feature: 0x8
- Version: 3
Feature: 0x28
BBRanges:
- BaseAddress: [[ADDR=0x11111]]
BBEntries:
@@ -158,6 +159,7 @@ Sections:
AddressOffset: 0x3
Size: 0x4
Metadata: 0x15
CallsiteOffsets: [ 0x1 , 0x2 ]
- Version: 2
BBRanges:
- BaseAddress: 0x22222
30 changes: 16 additions & 14 deletions llvm/test/tools/obj2yaml/ELF/bb-addr-map.yaml
Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@
# VALID-NEXT: - Name: .llvm_bb_addr_map
# VALID-NEXT: Type: SHT_LLVM_BB_ADDR_MAP
# VALID-NEXT: Entries:
# VALID-NEXT: - Version: 2
# VALID-NEXT: - Version: 3
# VALID-NEXT: BBRanges:
## The 'BaseAddress' field is omitted when it's zero.
# VALID-NEXT: - BBEntries:
@@ -30,15 +30,16 @@
# VALID-NEXT: AddressOffset: 0xFFFFFFFFFFFFFFF7
# VALID-NEXT: Size: 0xFFFFFFFFFFFFFFF8
# VALID-NEXT: Metadata: 0xFFFFFFFFFFFFFFF9
# VALID-NEXT: - Version: 2
# VALID-NEXT: Feature: 0x8
# VALID-NEXT: - Version: 3
# VALID-NEXT: Feature: 0x28
# VALID-NEXT: BBRanges:
# VALID-NEXT: - BaseAddress: 0xFFFFFFFFFFFFFF20
# VALID-NEXT: BBEntries:
# VALID-NEXT: - ID: 6
# VALID-NEXT: AddressOffset: 0xA
# VALID-NEXT: Size: 0xB
# VALID-NEXT: Metadata: 0xC
# VALID-NEXT: - ID: 6
# VALID-NEXT: AddressOffset: 0xA
# VALID-NEXT: Size: 0xB
# VALID-NEXT: Metadata: 0xC
# VALID-NEXT: CallsiteOffsets: [ 0x1, 0x2 ]

--- !ELF
FileHeader:
@@ -50,7 +51,7 @@ Sections:
Type: SHT_LLVM_BB_ADDR_MAP
ShSize: [[SIZE=<none>]]
Entries:
- Version: 2
- Version: 3
Feature: 0x0
BBRanges:
- BaseAddress: 0x0
@@ -67,17 +68,18 @@ Sections:
AddressOffset: 0xFFFFFFFFFFFFFFF7
Size: 0xFFFFFFFFFFFFFFF8
Metadata: 0xFFFFFFFFFFFFFFF9
- Version: 2
Feature: 0x8
- Version: 3
Feature: 0x28
NumBBRanges: [[NUMBBRANGES=<none>]]
BBRanges:
- BaseAddress: 0xFFFFFFFFFFFFFF20
NumBlocks: [[NUMBLOCKS=<none>]]
BBEntries:
- ID: 6
AddressOffset: 0xA
Size: 0xB
Metadata: 0xC
- ID: 6
AddressOffset: 0xA
Size: 0xB
Metadata: 0xC
CallsiteOffsets: [ 0x1, 0x2 ]

## Check obj2yaml can dump empty .llvm_bb_addr_map sections.

48 changes: 35 additions & 13 deletions llvm/test/tools/yaml2obj/ELF/bb-addr-map.yaml
Original file line number Diff line number Diff line change
@@ -36,36 +36,41 @@
# Case 4: Specify Entries.
# CHECK: Name: .llvm_bb_addr_map (1)
# CHECK: SectionData (
# CHECK-NEXT: 0000: 02002000 00000000 0000010B 010203
# CHECK-NEXT: 0000: 03002000 00000000 0000010B 01020102
# CHECK-NEXT: 0010: 0203
# CHECK-NEXT: )

# Case 5: Specify Entries and omit the Address field.
# CHECK: Name: .llvm_bb_addr_map (1)
# CHECK: Address:
# CHECK-SAME: {{^ 0x0$}}
# CHECK: SectionData (
# CHECK-NEXT: 0000: 02000000 00000000 0000010C 010203
# CHECK-NEXT: 0000: 03000000 00000000 0000010C 010203
# CHECK-NEXT: )

# Case 6: Override the NumBlocks field.
# CHECK: Name: .llvm_bb_addr_map (1)
# CHECK: SectionData (
# CHECK-NEXT: 0000: 02002000 00000000 0000020D 010203
# CHECK-NEXT: 0000: 03002000 00000000 0000020D 010203
# CHECK-NEXT: )

# Case 7: Specify empty BBRanges.
# CHECK: Name: .llvm_bb_addr_map (1)
# CHECK: SectionData (
# CHECK-NEXT: 0000: 020000
# CHECK-NEXT: 0000: 030000
# CHECK-NEXT: )

# Case 8: Specify empty BBRanges with multi-bb-range.
# CHECK: Name: .llvm_bb_addr_map (1)
# CHECK: SectionData (
# CHECK-NEXT: 0000: 020800
# CHECK-NEXT: 0000: 030800
# CHECK-NEXT: )


# Case 9: Specify empty CallsiteOffsets.
# CHECK: Name: .llvm_bb_addr_map (1)
# CHECK: SectionData (
# CHECK-NEXT: 0000: 03202000 00000000 0000010E 01000203
# CHECK-NEXT: )


--- !ELF
@@ -100,21 +105,22 @@ Sections:
- Name: '.llvm_bb_addr_map (4)'
Type: SHT_LLVM_BB_ADDR_MAP
Entries:
- Version: 2
- Version: 3
BBRanges:
- BaseAddress: 0x0000000000000020
BBEntries:
- ID: 11
AddressOffset: 0x00000001
Size: 0x00000002
Metadata: 0x00000003
CallsiteOffsets: [0x1, 0x2]

## 5) When specifying the description with Entries, the 'Address' field will be
## zero when omitted.
- Name: '.llvm_bb_addr_map (5)'
Type: SHT_LLVM_BB_ADDR_MAP
Entries:
- Version: 2
- Version: 3
BBRanges:
- BBEntries:
- ID: 12
@@ -127,7 +133,7 @@ Sections:
- Name: '.llvm_bb_addr_map (6)'
Type: SHT_LLVM_BB_ADDR_MAP
Entries:
- Version: 2
- Version: 3
BBRanges:
- BaseAddress: 0x0000000000000020
NumBlocks: 2
@@ -142,18 +148,34 @@ Sections:
- Name: '.llvm_bb_addr_map (7)'
Type: SHT_LLVM_BB_ADDR_MAP
Entries:
- Version: 2
- Version: 3
BBRanges: []

## 8) We can produce a SHT_LLVM_BB_ADDR_MAP section from a multi-bb-range
## description with one entry with empty BBRanges.
- Name: '.llvm_bb_addr_map (8)'
Type: SHT_LLVM_BB_ADDR_MAP
Entries:
- Version: 2
- Version: 3
Feature: 0x8
BBRanges: []

## 9) We can produce a SHT_LLVM_BB_ADDR_MAP section from a description
## with empty callsite offsets.
- Name: '.llvm_bb_addr_map (9)'
Type: SHT_LLVM_BB_ADDR_MAP
Entries:
- Version: 3
Feature: 0x20
BBRanges:
- BaseAddress: 0x0000000000000020
BBEntries:
- ID: 14
AddressOffset: 0x00000001
Size: 0x00000002
Metadata: 0x00000003
CallsiteOffsets: []

## Check we can't use Entries at the same time as either Content or Size.
# RUN: not yaml2obj --docnum=2 -DCONTENT="00" %s 2>&1 | FileCheck %s --check-prefix=INVALID
# RUN: not yaml2obj --docnum=2 -DSIZE="0" %s 2>&1 | FileCheck %s --check-prefix=INVALID
@@ -175,7 +197,7 @@ Sections:

## Check that yaml2obj generates a warning when we use unsupported versions.
# RUN: yaml2obj --docnum=3 %s 2>&1 | FileCheck %s --check-prefix=INVALID-VERSION
# INVALID-VERSION: warning: unsupported SHT_LLVM_BB_ADDR_MAP version: 3; encoding using the most recent version
# INVALID-VERSION: warning: unsupported SHT_LLVM_BB_ADDR_MAP version: 4; encoding using the most recent version

--- !ELF
FileHeader:
@@ -187,4 +209,4 @@ Sections:
Type: SHT_LLVM_BB_ADDR_MAP
Entries:
## Specify unsupported version
- Version: 3
- Version: 4
2 changes: 2 additions & 0 deletions llvm/tools/llvm-readobj/ELFDumper.cpp
Original file line number Diff line number Diff line change
@@ -7878,6 +7878,8 @@ void LLVMELFDumper<ELFT>::printBBAddrMaps(bool PrettyPGOAnalysis) {
DictScope BBED(W);
W.printNumber("ID", BBE.ID);
W.printHex("Offset", BBE.Offset);
if (!BBE.CallsiteOffsets.empty())
W.printList("Callsite Offsets", BBE.CallsiteOffsets);
W.printHex("Size", BBE.Size);
W.printBoolean("HasReturn", BBE.hasReturn());
W.printBoolean("HasTailCall", BBE.hasTailCall());
14 changes: 12 additions & 2 deletions llvm/tools/obj2yaml/elf2yaml.cpp
Original file line number Diff line number Diff line change
@@ -899,7 +899,7 @@ ELFDumper<ELFT>::dumpBBAddrMapSection(const Elf_Shdr *Shdr) {
while (Cur && Cur.tell() < Content.size()) {
if (Shdr->sh_type == ELF::SHT_LLVM_BB_ADDR_MAP) {
Version = Data.getU8(Cur);
if (Cur && Version > 2)
if (Cur && Version > 3)
return createStringError(
errc::invalid_argument,
"invalid SHT_LLVM_BB_ADDR_MAP section version: " +
@@ -934,9 +934,19 @@ ELFDumper<ELFT>::dumpBBAddrMapSection(const Elf_Shdr *Shdr) {
++BlockIndex) {
uint32_t ID = Version >= 2 ? Data.getULEB128(Cur) : BlockIndex;
uint64_t Offset = Data.getULEB128(Cur);
std::optional<std::vector<llvm::yaml::Hex64>> CallsiteOffsets;
if (FeatureOrErr->CallsiteOffsets) {
uint32_t NumCallsites = Data.getULEB128(Cur);
CallsiteOffsets = std::vector<llvm::yaml::Hex64>(NumCallsites, 0);
for (uint32_t CallsiteIndex = 0; Cur && CallsiteIndex < NumCallsites;
++CallsiteIndex) {
(*CallsiteOffsets)[CallsiteIndex] = Data.getULEB128(Cur);
}
}
uint64_t Size = Data.getULEB128(Cur);
uint64_t Metadata = Data.getULEB128(Cur);
BBEntries.push_back({ID, Offset, Size, Metadata});
BBEntries.push_back(
{ID, Offset, Size, Metadata, std::move(CallsiteOffsets)});
}
TotalNumBlocks += BBEntries.size();
BBRanges.push_back({BaseAddress, /*NumBlocks=*/{}, BBEntries});
94 changes: 59 additions & 35 deletions llvm/unittests/Object/ELFObjectFileTest.cpp
Original file line number Diff line number Diff line change
@@ -531,7 +531,7 @@ TEST(ELFObjectFileTest, InvalidDecodeBBAddrMap) {
// Check that we can detect unsupported versions.
SmallString<128> UnsupportedVersionYamlString(CommonYamlString);
UnsupportedVersionYamlString += R"(
- Version: 3
- Version: 4
BBRanges:
- BaseAddress: 0x11111
BBEntries:
@@ -543,12 +543,12 @@ TEST(ELFObjectFileTest, InvalidDecodeBBAddrMap) {
{
SCOPED_TRACE("unsupported version");
DoCheck(UnsupportedVersionYamlString,
"unsupported SHT_LLVM_BB_ADDR_MAP version: 3");
"unsupported SHT_LLVM_BB_ADDR_MAP version: 4");
}

SmallString<128> ZeroBBRangesYamlString(CommonYamlString);
ZeroBBRangesYamlString += R"(
- Version: 2
- Version: 3
Feature: 0x8
BBRanges: []
)";
@@ -561,7 +561,7 @@ TEST(ELFObjectFileTest, InvalidDecodeBBAddrMap) {

SmallString<128> CommonVersionedYamlString(CommonYamlString);
CommonVersionedYamlString += R"(
- Version: 2
- Version: 3
BBRanges:
- BaseAddress: 0x11111
BBEntries:
@@ -669,6 +669,26 @@ TEST(ELFObjectFileTest, InvalidDecodeBBAddrMap) {
)";
DoCheck(OverLimitNumBBRanges,
"ULEB128 value at offset 0x2 exceeds UINT32_MAX (0x100000000)");

// Check that we can detect unsupported version for callsite offsets.
SmallString<128> UnsupportedLowVersionYamlString(CommonYamlString);
UnsupportedLowVersionYamlString += R"(
- Version: 2
Feature: 0x20
BBRanges:
- BBEntries:
- AddressOffset: 0x0
Size: 0x1
Metadata: 0x2
CallsiteOffsets: [ 0x1 ]
)";

{
SCOPED_TRACE("unsupported version");
DoCheck(UnsupportedLowVersionYamlString,
"version should be >= 3 for SHT_LLVM_BB_ADDR_MAP when callsite"
" offsets feature is enabled: version = 2 feature = 32");
}
}

// Test for the ELFObjectFile::readBBAddrMap API.
@@ -684,19 +704,21 @@ TEST(ELFObjectFileTest, ReadBBAddrMap) {
Type: SHT_LLVM_BB_ADDR_MAP
Link: 1
Entries:
- Version: 2
- Version: 3
Feature: 0x20
BBRanges:
- BaseAddress: 0x11111
BBEntries:
- ID: 1
AddressOffset: 0x0
Size: 0x1
Metadata: 0x2
- ID: 1
AddressOffset: 0x0
Size: 0x1
Metadata: 0x2
CallsiteOffsets: [ 0x1 , 0x1 ]
- Name: .llvm_bb_addr_map_2
Type: SHT_LLVM_BB_ADDR_MAP
Link: 1
Entries:
- Version: 2
- Version: 3
Feature: 0x8
BBRanges:
- BaseAddress: 0x22222
@@ -738,14 +760,15 @@ TEST(ELFObjectFileTest, ReadBBAddrMap) {
)");

BBAddrMap E1 = {
{{0x11111, {{1, 0x0, 0x1, {false, true, false, false, false}}}}}};
{{0x11111,
{{1, 0x0, 0x3, {false, true, false, false, false}, {0x1, 0x2}}}}}};
BBAddrMap E2 = {
{{0x22222, {{2, 0x0, 0x2, {false, false, true, false, false}}}},
{0xFFFFF, {{15, 0xF0, 0xF1, {true, true, true, true, true}}}}}};
{{0x22222, {{2, 0x0, 0x2, {false, false, true, false, false}, {}}}},
{0xFFFFF, {{15, 0xF0, 0xF1, {true, true, true, true, true}, {}}}}}};
BBAddrMap E3 = {
{{0x33333, {{0, 0x0, 0x3, {false, true, true, false, false}}}}}};
{{0x33333, {{0, 0x0, 0x3, {false, true, true, false, false}, {}}}}}};
BBAddrMap E4 = {
{{0x44444, {{0, 0x0, 0x4, {false, false, false, true, true}}}}}};
{{0x44444, {{0, 0x0, 0x4, {false, false, false, true, true}, {}}}}}};

std::vector<BBAddrMap> Section0BBAddrMaps = {E4};
std::vector<BBAddrMap> Section1BBAddrMaps = {E3};
@@ -1137,28 +1160,29 @@ TEST(ELFObjectFileTest, ReadPGOAnalysisMap) {
)");

BBAddrMap E1 = {
{{0x11111, {{1, 0x0, 0x1, {false, true, false, false, false}}}}}};
PGOAnalysisMap P1 = {892, {}, {true, false, false, false, false}};
{{0x11111, {{1, 0x0, 0x1, {false, true, false, false, false}, {}}}}}};
PGOAnalysisMap P1 = {892, {}, {true, false, false, false, false, false}};
BBAddrMap E2 = {
{{0x22222, {{2, 0x0, 0x2, {false, false, true, false, false}}}}}};
PGOAnalysisMap P2 = {
{}, {{BlockFrequency(343), {}}}, {false, true, false, false, false}};
{{0x22222, {{2, 0x0, 0x2, {false, false, true, false, false}, {}}}}}};
PGOAnalysisMap P2 = {{},
{{BlockFrequency(343), {}}},
{false, true, false, false, false, false}};
BBAddrMap E3 = {{{0x33333,
{{0, 0x0, 0x3, {false, true, true, false, false}},
{1, 0x3, 0x3, {false, false, true, false, false}},
{2, 0x6, 0x3, {false, false, false, false, false}}}}}};
{{0, 0x0, 0x3, {false, true, true, false, false}, {}},
{1, 0x3, 0x3, {false, false, true, false, false}, {}},
{2, 0x6, 0x3, {false, false, false, false, false}, {}}}}}};
PGOAnalysisMap P3 = {{},
{{{},
{{1, BranchProbability::getRaw(0x1111'1111)},
{2, BranchProbability::getRaw(0xeeee'eeee)}}},
{{}, {{2, BranchProbability::getRaw(0xffff'ffff)}}},
{{}, {}}},
{false, false, true, false, false}};
{false, false, true, false, false, false}};
BBAddrMap E4 = {{{0x44444,
{{0, 0x0, 0x4, {false, false, false, true, true}},
{1, 0x4, 0x4, {false, false, false, false, false}},
{2, 0x8, 0x4, {false, false, false, false, false}},
{3, 0xc, 0x4, {false, false, false, false, false}}}}}};
{{0, 0x0, 0x4, {false, false, false, true, true}, {}},
{1, 0x4, 0x4, {false, false, false, false, false}, {}},
{2, 0x8, 0x4, {false, false, false, false, false}, {}},
{3, 0xc, 0x4, {false, false, false, false, false}, {}}}}}};
PGOAnalysisMap P4 = {
1000,
{{BlockFrequency(1000),
@@ -1170,22 +1194,22 @@ TEST(ELFObjectFileTest, ReadPGOAnalysisMap) {
{3, BranchProbability::getRaw(0xeeee'eeee)}}},
{BlockFrequency(18), {{3, BranchProbability::getRaw(0xffff'ffff)}}},
{BlockFrequency(1000), {}}},
{true, true, true, false, false}};
{true, true, true, false, false, false}};
BBAddrMap E5 = {
{{0x55555, {{2, 0x0, 0x2, {false, false, true, false, false}}}}}};
PGOAnalysisMap P5 = {{}, {}, {false, false, false, false, false}};
{{0x55555, {{2, 0x0, 0x2, {false, false, true, false, false}, {}}}}}};
PGOAnalysisMap P5 = {{}, {}, {false, false, false, false, false, false}};
BBAddrMap E6 = {
{{0x66666,
{{0, 0x0, 0x6, {false, true, true, false, false}},
{1, 0x6, 0x6, {false, false, true, false, false}}}},
{0x666661, {{2, 0x0, 0x6, {false, false, false, false, false}}}}}};
{{0, 0x0, 0x6, {false, true, true, false, false}, {}},
{1, 0x6, 0x6, {false, false, true, false, false}, {}}}},
{0x666661, {{2, 0x0, 0x6, {false, false, false, false, false}, {}}}}}};
PGOAnalysisMap P6 = {{},
{{{},
{{1, BranchProbability::getRaw(0x2222'2222)},
{2, BranchProbability::getRaw(0xcccc'cccc)}}},
{{}, {{2, BranchProbability::getRaw(0x8888'8888)}}},
{{}, {}}},
{false, false, true, true, false}};
{false, false, true, true, false, false}};

std::vector<BBAddrMap> Section0BBAddrMaps = {E4, E5, E6};
std::vector<BBAddrMap> Section1BBAddrMaps = {E3};
31 changes: 17 additions & 14 deletions llvm/unittests/Object/ELFTypesTest.cpp
Original file line number Diff line number Diff line change
@@ -101,18 +101,21 @@ static_assert(
"PGOAnalysisMap should use the same type for basic block ID as BBAddrMap");

TEST(ELFTypesTest, BBAddrMapFeaturesEncodingTest) {
const std::array<BBAddrMap::Features, 9> Decoded = {
{{false, false, false, false, false},
{true, false, false, false, false},
{false, true, false, false, false},
{false, false, true, false, false},
{false, false, false, true, false},
{true, true, false, false, false},
{false, true, true, false, false},
{false, true, true, true, false},
{true, true, true, true, false}}};
const std::array<uint8_t, 9> Encoded = {
{0b0000, 0b0001, 0b0010, 0b0100, 0b1000, 0b0011, 0b0110, 0b1110, 0b1111}};
const std::array<BBAddrMap::Features, 11> Decoded = {
{{false, false, false, false, false, false},
{true, false, false, false, false, false},
{false, true, false, false, false, false},
{false, false, true, false, false, false},
{false, false, false, true, false, false},
{true, true, false, false, false, false},
{false, true, true, false, false, false},
{false, true, true, true, false, false},
{true, true, true, true, false, false},
{false, false, false, false, true, false},
{false, false, false, false, false, true}}};
const std::array<uint8_t, 11> Encoded = {{0b0000, 0b0001, 0b0010, 0b0100,
0b1000, 0b0011, 0b0110, 0b1110,
0b1111, 0b1'0000, 0b10'0000}};
for (const auto &[Feat, EncodedVal] : llvm::zip(Decoded, Encoded))
EXPECT_EQ(Feat.encode(), EncodedVal);
for (const auto &[Feat, EncodedVal] : llvm::zip(Decoded, Encoded)) {
@@ -125,9 +128,9 @@ TEST(ELFTypesTest, BBAddrMapFeaturesEncodingTest) {

TEST(ELFTypesTest, BBAddrMapFeaturesInvalidEncodingTest) {
const std::array<std::string, 2> Errors = {
"invalid encoding for BBAddrMap::Features: 0x20",
"invalid encoding for BBAddrMap::Features: 0x40",
"invalid encoding for BBAddrMap::Features: 0xf0"};
const std::array<uint8_t, 2> Values = {{0b10'0000, 0b1111'0000}};
const std::array<uint8_t, 2> Values = {{0b100'0000, 0b1111'0000}};
for (const auto &[Val, Error] : llvm::zip(Values, Errors)) {
EXPECT_THAT_ERROR(BBAddrMap::Features::decode(Val).takeError(),
FailedWithMessage(Error));