Skip to content

Commit 7e25481

Browse files
author
Fabian Parzefall
committed
[BOLT] Track fragment info for all split fragments
To generate all symbols correctly, it is necessary to record the address of each fragment. This patch moves the address info for the main and cold fragments from BinaryFunction to FunctionFragment, where this data is recorded for all fragments. Reviewed By: rafauler Differential Revision: https://reviews.llvm.org/D132051
1 parent 101344a commit 7e25481

File tree

6 files changed

+181
-159
lines changed

6 files changed

+181
-159
lines changed

bolt/include/bolt/Core/BinaryFunction.h

Lines changed: 12 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -232,9 +232,6 @@ class BinaryFunction {
232232
/// Size of the function in the output file.
233233
uint64_t OutputSize{0};
234234

235-
/// Offset in the file.
236-
uint64_t FileOffset{0};
237-
238235
/// Maximum size this function is allowed to have.
239236
uint64_t MaxSize{std::numeric_limits<uint64_t>::max()};
240237

@@ -345,14 +342,6 @@ class BinaryFunction {
345342
/// This attribute is only valid when hasCFG() == true.
346343
bool HasCanonicalCFG{true};
347344

348-
/// The address for the code for this function in codegen memory.
349-
/// Used for functions that are emitted in a dedicated section with a fixed
350-
/// address. E.g. for functions that are overwritten in-place.
351-
uint64_t ImageAddress{0};
352-
353-
/// The size of the code in memory.
354-
uint64_t ImageSize{0};
355-
356345
/// Name for the section this function code should reside in.
357346
std::string CodeSectionName;
358347

@@ -1060,7 +1049,9 @@ class BinaryFunction {
10601049
}
10611050

10621051
/// Return offset of the function body in the binary file.
1063-
uint64_t getFileOffset() const { return FileOffset; }
1052+
uint64_t getFileOffset() const {
1053+
return getLayout().getMainFragment().getFileOffset();
1054+
}
10641055

10651056
/// Return (original) byte size of the function.
10661057
uint64_t getSize() const { return Size; }
@@ -1698,7 +1689,7 @@ class BinaryFunction {
16981689
int64_t NewOffset);
16991690

17001691
BinaryFunction &setFileOffset(uint64_t Offset) {
1701-
FileOffset = Offset;
1692+
getLayout().getMainFragment().setFileOffset(Offset);
17021693
return *this;
17031694
}
17041695

@@ -1785,20 +1776,24 @@ class BinaryFunction {
17851776
uint16_t getMaxColdAlignmentBytes() const { return MaxColdAlignmentBytes; }
17861777

17871778
BinaryFunction &setImageAddress(uint64_t Address) {
1788-
ImageAddress = Address;
1779+
getLayout().getMainFragment().setImageAddress(Address);
17891780
return *this;
17901781
}
17911782

17921783
/// Return the address of this function' image in memory.
1793-
uint64_t getImageAddress() const { return ImageAddress; }
1784+
uint64_t getImageAddress() const {
1785+
return getLayout().getMainFragment().getImageAddress();
1786+
}
17941787

17951788
BinaryFunction &setImageSize(uint64_t Size) {
1796-
ImageSize = Size;
1789+
getLayout().getMainFragment().setImageSize(Size);
17971790
return *this;
17981791
}
17991792

18001793
/// Return the size of this function' image in memory.
1801-
uint64_t getImageSize() const { return ImageSize; }
1794+
uint64_t getImageSize() const {
1795+
return getLayout().getMainFragment().getImageSize();
1796+
}
18021797

18031798
/// Return true if the function is a secondary fragment of another function.
18041799
bool isFragment() const { return IsFragment; }
@@ -2302,33 +2297,6 @@ class BinaryFunction {
23022297
bool isAArch64Veneer() const;
23032298

23042299
virtual ~BinaryFunction();
2305-
2306-
/// Info for fragmented functions.
2307-
class FragmentInfo {
2308-
private:
2309-
uint64_t Address{0};
2310-
uint64_t ImageAddress{0};
2311-
uint64_t ImageSize{0};
2312-
uint64_t FileOffset{0};
2313-
2314-
public:
2315-
uint64_t getAddress() const { return Address; }
2316-
uint64_t getImageAddress() const { return ImageAddress; }
2317-
uint64_t getImageSize() const { return ImageSize; }
2318-
uint64_t getFileOffset() const { return FileOffset; }
2319-
2320-
void setAddress(uint64_t VAddress) { Address = VAddress; }
2321-
void setImageAddress(uint64_t Address) { ImageAddress = Address; }
2322-
void setImageSize(uint64_t Size) { ImageSize = Size; }
2323-
void setFileOffset(uint64_t Offset) { FileOffset = Offset; }
2324-
};
2325-
2326-
/// Cold fragment of the function.
2327-
FragmentInfo ColdFragment;
2328-
2329-
FragmentInfo &cold() { return ColdFragment; }
2330-
2331-
const FragmentInfo &cold() const { return ColdFragment; }
23322300
};
23332301

23342302
inline raw_ostream &operator<<(raw_ostream &OS,

bolt/include/bolt/Core/FunctionLayout.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,20 @@ class FunctionFragment {
8383
unsigned StartIndex;
8484
unsigned Size = 0;
8585

86+
/// Output address for the fragment.
87+
uint64_t Address = 0;
88+
89+
/// The address for the code for this fragment in codegen memory. Used for
90+
/// functions that are emitted in a dedicated section with a fixed address,
91+
/// e.g. for functions that are overwritten in-place.
92+
uint64_t ImageAddress = 0;
93+
94+
/// The size of the code in memory.
95+
uint64_t ImageSize = 0;
96+
97+
/// Offset in the file.
98+
uint64_t FileOffset = 0;
99+
86100
FunctionFragment(FunctionLayout &Layout, FragmentNum Num);
87101
FunctionFragment(const FunctionFragment &) = default;
88102
FunctionFragment(FunctionFragment &&) = default;
@@ -97,6 +111,15 @@ class FunctionFragment {
97111
}
98112
bool isSplitFragment() const { return !isMainFragment(); }
99113

114+
uint64_t getAddress() const { return Address; }
115+
void setAddress(uint64_t Value) { Address = Value; }
116+
uint64_t getImageAddress() const { return ImageAddress; }
117+
void setImageAddress(uint64_t Address) { ImageAddress = Address; }
118+
uint64_t getImageSize() const { return ImageSize; }
119+
void setImageSize(uint64_t Size) { ImageSize = Size; }
120+
uint64_t getFileOffset() const { return FileOffset; }
121+
void setFileOffset(uint64_t Offset) { FileOffset = Offset; }
122+
100123
unsigned size() const { return Size; };
101124
bool empty() const { return size() == 0; };
102125
iterator begin();

bolt/lib/Core/BinaryFunction.cpp

Lines changed: 36 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -425,19 +425,19 @@ void BinaryFunction::print(raw_ostream &OS, std::string Annotation,
425425
Sep = "\n ";
426426
}
427427
}
428-
OS << "\n Number : " << FunctionNumber
429-
<< "\n State : " << CurrentState
430-
<< "\n Address : 0x" << Twine::utohexstr(Address)
431-
<< "\n Size : 0x" << Twine::utohexstr(Size)
432-
<< "\n MaxSize : 0x" << Twine::utohexstr(MaxSize)
433-
<< "\n Offset : 0x" << Twine::utohexstr(FileOffset)
434-
<< "\n Section : " << SectionName
435-
<< "\n Orc Section : " << getCodeSectionName()
436-
<< "\n LSDA : 0x" << Twine::utohexstr(getLSDAAddress())
437-
<< "\n IsSimple : " << IsSimple
438-
<< "\n IsMultiEntry: " << isMultiEntry()
439-
<< "\n IsSplit : " << isSplit()
440-
<< "\n BB Count : " << size();
428+
OS << "\n Number : " << FunctionNumber;
429+
OS << "\n State : " << CurrentState;
430+
OS << "\n Address : 0x" << Twine::utohexstr(Address);
431+
OS << "\n Size : 0x" << Twine::utohexstr(Size);
432+
OS << "\n MaxSize : 0x" << Twine::utohexstr(MaxSize);
433+
OS << "\n Offset : 0x" << Twine::utohexstr(getFileOffset());
434+
OS << "\n Section : " << SectionName;
435+
OS << "\n Orc Section : " << getCodeSectionName();
436+
OS << "\n LSDA : 0x" << Twine::utohexstr(getLSDAAddress());
437+
OS << "\n IsSimple : " << IsSimple;
438+
OS << "\n IsMultiEntry: " << isMultiEntry();
439+
OS << "\n IsSplit : " << isSplit();
440+
OS << "\n BB Count : " << size();
441441

442442
if (HasFixedIndirectBranch)
443443
OS << "\n HasFixedIndirectBranch : true";
@@ -473,8 +473,8 @@ void BinaryFunction::print(raw_ostream &OS, std::string Annotation,
473473
for (const BinaryBasicBlock *BB : Layout.blocks())
474474
OS << LS << BB->getName();
475475
}
476-
if (ImageAddress)
477-
OS << "\n Image : 0x" << Twine::utohexstr(ImageAddress);
476+
if (getImageAddress())
477+
OS << "\n Image : 0x" << Twine::utohexstr(getImageAddress());
478478
if (ExecutionCount != COUNT_NO_PROFILE) {
479479
OS << "\n Exec Count : " << ExecutionCount;
480480
OS << "\n Profile Acc : " << format("%.1f%%", ProfileMatchRatio * 100.0f);
@@ -4062,7 +4062,7 @@ void BinaryFunction::updateOutputValues(const MCAsmLayout &Layout) {
40624062
setOutputDataAddress(BaseAddress + DataOffset);
40634063
}
40644064
if (isSplit()) {
4065-
for (const FunctionFragment &FF : getLayout().getSplitFragments()) {
4065+
for (FunctionFragment &FF : getLayout().getSplitFragments()) {
40664066
ErrorOr<BinarySection &> ColdSection =
40674067
getCodeSection(FF.getFragmentNum());
40684068
// If fragment is empty, cold section might not exist
@@ -4084,8 +4084,8 @@ void BinaryFunction::updateOutputValues(const MCAsmLayout &Layout) {
40844084
const uint64_t ColdStartOffset =
40854085
Layout.getSymbolOffset(*ColdStartSymbol);
40864086
const uint64_t ColdEndOffset = Layout.getSymbolOffset(*ColdEndSymbol);
4087-
cold().setAddress(ColdBaseAddress + ColdStartOffset);
4088-
cold().setImageSize(ColdEndOffset - ColdStartOffset);
4087+
FF.setAddress(ColdBaseAddress + ColdStartOffset);
4088+
FF.setImageSize(ColdEndOffset - ColdStartOffset);
40894089
if (hasConstantIsland()) {
40904090
const uint64_t DataOffset =
40914091
Layout.getSymbolOffset(*getFunctionColdConstantIslandLabel());
@@ -4112,44 +4112,39 @@ void BinaryFunction::updateOutputValues(const MCAsmLayout &Layout) {
41124112
if (getLayout().block_empty())
41134113
return;
41144114

4115-
assert((getLayout().isHotColdSplit() ||
4116-
(cold().getAddress() == 0 && cold().getImageSize() == 0 &&
4117-
BC.HasRelocations)) &&
4118-
"Function must be split two ways or cold fragment must have no "
4119-
"address (only in relocation mode)");
4120-
4121-
BinaryBasicBlock *PrevBB = nullptr;
41224115
for (FunctionFragment &FF : getLayout().fragments()) {
4116+
if (FF.empty())
4117+
continue;
4118+
41234119
const uint64_t FragmentBaseAddress =
41244120
getCodeSection(isSimple() ? FF.getFragmentNum() : FragmentNum::main())
41254121
->getOutputAddress();
4122+
4123+
BinaryBasicBlock *PrevBB = nullptr;
41264124
for (BinaryBasicBlock *const BB : FF) {
41274125
assert(BB->getLabel()->isDefined() && "symbol should be defined");
41284126
if (!BC.HasRelocations) {
4129-
if (BB->isSplit()) {
4130-
assert(FragmentBaseAddress == cold().getAddress());
4131-
} else {
4127+
if (BB->isSplit())
4128+
assert(FragmentBaseAddress == FF.getAddress());
4129+
else
41324130
assert(FragmentBaseAddress == getOutputAddress());
4133-
}
41344131
}
4132+
41354133
const uint64_t BBOffset = Layout.getSymbolOffset(*BB->getLabel());
41364134
const uint64_t BBAddress = FragmentBaseAddress + BBOffset;
41374135
BB->setOutputStartAddress(BBAddress);
41384136

4139-
if (PrevBB) {
4140-
uint64_t PrevBBEndAddress = BBAddress;
4141-
if (BB->isSplit() != PrevBB->isSplit())
4142-
PrevBBEndAddress = getOutputAddress() + getOutputSize();
4143-
PrevBB->setOutputEndAddress(PrevBBEndAddress);
4144-
}
4137+
if (PrevBB)
4138+
PrevBB->setOutputEndAddress(BBAddress);
41454139
PrevBB = BB;
41464140

41474141
BB->updateOutputValues(Layout);
41484142
}
4143+
4144+
PrevBB->setOutputEndAddress(PrevBB->isSplit()
4145+
? FF.getAddress() + FF.getImageSize()
4146+
: getOutputAddress() + getOutputSize());
41494147
}
4150-
PrevBB->setOutputEndAddress(PrevBB->isSplit()
4151-
? cold().getAddress() + cold().getImageSize()
4152-
: getOutputAddress() + getOutputSize());
41534148
}
41544149

41554150
DebugAddressRangesVector BinaryFunction::getOutputAddressRanges() const {
@@ -4165,8 +4160,9 @@ DebugAddressRangesVector BinaryFunction::getOutputAddressRanges() const {
41654160
getOutputAddress() + getOutputSize());
41664161
if (isSplit()) {
41674162
assert(isEmitted() && "split function should be emitted");
4168-
OutputRanges.emplace_back(cold().getAddress(),
4169-
cold().getAddress() + cold().getImageSize());
4163+
for (const FunctionFragment &FF : getLayout().getSplitFragments())
4164+
OutputRanges.emplace_back(FF.getAddress(),
4165+
FF.getAddress() + FF.getImageSize());
41704166
}
41714167

41724168
if (isSimple())

bolt/lib/Core/FunctionLayout.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -204,10 +204,14 @@ bool FunctionLayout::update(const ArrayRef<BinaryBasicBlock *> NewLayout) {
204204

205205
void FunctionLayout::clear() {
206206
Blocks = BasicBlockListType();
207-
for (FunctionFragment *const FF : Fragments)
208-
delete FF;
209-
Fragments = FragmentListType();
210-
addFragment();
207+
// If the binary does not have relocations and is not split, the function will
208+
// be written to the output stream at its original file offset (see
209+
// `RewriteInstance::rewriteFile`). Hence, when the layout is cleared, retain
210+
// the main fragment, so that this information is not lost.
211+
std::for_each(Fragments.begin() + 1, Fragments.end(),
212+
[](FunctionFragment *const FF) { delete FF; });
213+
Fragments = FragmentListType{Fragments.front()};
214+
getMainFragment().Size = 0;
211215
}
212216

213217
const BinaryBasicBlock *

bolt/lib/Profile/BoltAddressTranslation.cpp

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -73,29 +73,27 @@ void BoltAddressTranslation::write(const BinaryContext &BC, raw_ostream &OS) {
7373
LLVM_DEBUG(dbgs() << "Function name: " << Function.getPrintName() << "\n");
7474
LLVM_DEBUG(dbgs() << " Address reference: 0x"
7575
<< Twine::utohexstr(Function.getOutputAddress()) << "\n");
76+
7677
MapTy Map;
77-
const bool IsSplit = Function.isSplit();
78-
for (const BinaryBasicBlock *const BB : Function.getLayout().blocks()) {
79-
if (IsSplit && BB->isCold())
80-
break;
78+
for (const BinaryBasicBlock *const BB :
79+
Function.getLayout().getMainFragment())
8180
writeEntriesForBB(Map, *BB, Function.getOutputAddress());
82-
}
83-
Maps.insert(std::pair<uint64_t, MapTy>(Function.getOutputAddress(), Map));
81+
Maps.emplace(Function.getOutputAddress(), std::move(Map));
8482

85-
if (!IsSplit)
83+
if (!Function.isSplit())
8684
continue;
8785

88-
// Cold map
89-
Map.clear();
86+
// Split maps
9087
LLVM_DEBUG(dbgs() << " Cold part\n");
91-
for (const BinaryBasicBlock *const BB : Function.getLayout().blocks()) {
92-
if (!BB->isCold())
93-
continue;
94-
writeEntriesForBB(Map, *BB, Function.cold().getAddress());
88+
for (const FunctionFragment &FF :
89+
Function.getLayout().getSplitFragments()) {
90+
Map.clear();
91+
for (const BinaryBasicBlock *const BB : FF)
92+
writeEntriesForBB(Map, *BB, FF.getAddress());
93+
94+
Maps.emplace(FF.getAddress(), std::move(Map));
95+
ColdPartSource.emplace(FF.getAddress(), Function.getOutputAddress());
9596
}
96-
Maps.insert(std::pair<uint64_t, MapTy>(Function.cold().getAddress(), Map));
97-
ColdPartSource.insert(std::pair<uint64_t, uint64_t>(
98-
Function.cold().getAddress(), Function.getOutputAddress()));
9997
}
10098

10199
const uint32_t NumFuncs = Maps.size();

0 commit comments

Comments
 (0)