Skip to content

Commit f5aa80a

Browse files
maksfbmemfrob
authored andcommitted
[BOLT][Refactoring] Make CTC first class operand, etc.
Summary: This diff is a preparation for decoupling function disassembly, profile association, and CFG construction phases. We used to have multiple ways to mark conditional tail calls with annotations or TailCallOffsets map. Since CTC information is affecting the correctness, it is justifiable to have it as a operand class for instruction with a destination (0 is a valid one). "Offset" annotation now replaces "EdgeCountData" and "IndirectBranchData" annotations to extract profile data for any given instruction. Inlining for small functions was broken in a presence of profiled (annotated) instructions and hence I had to remove "-inline-small-functions" from the test case. Also fix an issue with UNDEF section for created __hot_start/__hot_end symbols. Now the symbols use ABS section. (cherry picked from FBD6087284)
1 parent 92b81ae commit f5aa80a

File tree

7 files changed

+45
-97
lines changed

7 files changed

+45
-97
lines changed

bolt/BinaryFunction.cpp

Lines changed: 29 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -740,7 +740,7 @@ BinaryFunction::analyzeIndirectBranch(MCInst &Instruction,
740740
//
741741
// We handle PIC-style jump tables separately.
742742
//
743-
if (Instruction.getNumOperands() == 1) {
743+
if (Instruction.getNumPrimeOperands() == 1) {
744744
// If the indirect jump is on register - try to detect if the
745745
// register value is loaded from a memory location.
746746
assert(Instruction.getOperand(0).isReg() && "register operand expected");
@@ -1064,7 +1064,7 @@ void BinaryFunction::disassemble(ArrayRef<uint8_t> FunctionData) {
10641064

10651065
if (!IsZeroPadding) {
10661066
// Ignore this function. Skip to the next one in non-relocs mode.
1067-
errs() << "BOLT-ERROR: unable to disassemble instruction at offset 0x"
1067+
errs() << "BOLT-WARNING: unable to disassemble instruction at offset 0x"
10681068
<< Twine::utohexstr(Offset) << " (address 0x"
10691069
<< Twine::utohexstr(AbsoluteInstrAddr) << ") in function "
10701070
<< *this << '\n';
@@ -1098,7 +1098,7 @@ void BinaryFunction::disassemble(ArrayRef<uint8_t> FunctionData) {
10981098
int64_t Value;
10991099
const auto Result =
11001100
BC.MIA->replaceImmWithSymbol(Instruction, Relocation.Symbol,
1101-
Relocation.Addend, BC.Ctx.get(), Value);
1101+
Relocation.Addend, Ctx.get(), Value);
11021102
(void)Result;
11031103
assert(Result && "cannot replace immediate with relocation");
11041104

@@ -1125,7 +1125,7 @@ void BinaryFunction::disassemble(ArrayRef<uint8_t> FunctionData) {
11251125
// or a recursive call.
11261126
bool IsCall = MIA->isCall(Instruction);
11271127
const bool IsCondBranch = MIA->isConditionalBranch(Instruction);
1128-
MCSymbol *TargetSymbol{nullptr};
1128+
MCSymbol *TargetSymbol = nullptr;
11291129

11301130
if (IsCall && containsAddress(TargetAddress)) {
11311131
if (TargetAddress == getAddress()) {
@@ -1154,7 +1154,7 @@ void BinaryFunction::disassemble(ArrayRef<uint8_t> FunctionData) {
11541154
<< " : replacing with nop.\n");
11551155
BC.MIA->createNoop(Instruction);
11561156
if (IsCondBranch) {
1157-
// Register branch function profile validation.
1157+
// Register branch offset for profile validation.
11581158
IgnoredBranches.emplace_back(Offset, Offset + Size);
11591159
}
11601160
goto add_instruction;
@@ -1182,10 +1182,6 @@ void BinaryFunction::disassemble(ArrayRef<uint8_t> FunctionData) {
11821182
<< Twine::utohexstr(AbsoluteInstrAddr) << ".\n";
11831183
}
11841184
}
1185-
// TODO: A better way to do this would be using annotations for
1186-
// MCInst objects.
1187-
TailCallOffsets.emplace(std::make_pair(Offset,
1188-
TargetAddress));
11891185
IsCall = true;
11901186
}
11911187

@@ -1231,34 +1227,28 @@ void BinaryFunction::disassemble(ArrayRef<uint8_t> FunctionData) {
12311227
// Add taken branch info.
12321228
TakenBranches.emplace_back(Offset, TargetAddress - getAddress());
12331229
}
1234-
if (IsCondBranch) {
1235-
// Add fallthrough branch info.
1236-
FTBranches.emplace_back(Offset, Offset + Size);
1237-
}
1238-
1239-
const bool isIndirect =
1240-
((IsCall || !IsCondBranch) && MIA->isIndirectBranch(Instruction));
1241-
12421230
Instruction.clear();
12431231
Instruction.addOperand(
12441232
MCOperand::createExpr(
12451233
MCSymbolRefExpr::create(TargetSymbol,
12461234
MCSymbolRefExpr::VK_None,
12471235
*Ctx)));
12481236

1249-
if (BranchData) {
1237+
// Record call offset for profile matching.
1238+
if (IsCall) {
1239+
MIA->addAnnotation(Ctx.get(), Instruction, "Offset", Offset);
1240+
}
1241+
if (IsCondBranch) {
1242+
// Add fallthrough branch info.
1243+
FTBranches.emplace_back(Offset, Offset + Size);
12501244
if (IsCall) {
1251-
MIA->addAnnotation(Ctx.get(), Instruction, "EdgeCountData", Offset);
1252-
}
1253-
if (isIndirect) {
1254-
MIA->addAnnotation(Ctx.get(), Instruction, "IndirectBranchData",
1255-
Offset);
1245+
MIA->setConditionalTailCall(Instruction, TargetAddress);
12561246
}
12571247
}
12581248
} else {
12591249
// Could not evaluate branch. Should be an indirect call or an
12601250
// indirect branch. Bail out on the latter case.
1261-
bool MaybeEdgeCountData = false;
1251+
MIA->addAnnotation(Ctx.get(), Instruction, "Offset", Offset);
12621252
if (MIA->isIndirectBranch(Instruction)) {
12631253
auto Result = analyzeIndirectBranch(Instruction, Size, Offset);
12641254
switch (Result) {
@@ -1269,47 +1259,27 @@ void BinaryFunction::disassemble(ArrayRef<uint8_t> FunctionData) {
12691259
auto Result = MIA->convertJmpToTailCall(Instruction);
12701260
(void)Result;
12711261
assert(Result);
1272-
if (BranchData) {
1273-
MIA->addAnnotation(Ctx.get(), Instruction, "IndirectBranchData",
1274-
Offset);
1275-
}
12761262
}
12771263
break;
12781264
case IndirectBranchType::POSSIBLE_JUMP_TABLE:
12791265
case IndirectBranchType::POSSIBLE_PIC_JUMP_TABLE:
12801266
if (opts::JumpTables == JTS_NONE)
12811267
IsSimple = false;
1282-
MaybeEdgeCountData = true;
12831268
break;
12841269
case IndirectBranchType::UNKNOWN:
12851270
// Keep processing. We'll do more checks and fixes in
12861271
// postProcessIndirectBranches().
1287-
MaybeEdgeCountData = true;
1288-
if (BranchData) {
1289-
MIA->addAnnotation(Ctx.get(),
1290-
Instruction,
1291-
"MaybeIndirectBranchData",
1292-
Offset);
1293-
}
12941272
break;
12951273
};
1296-
} else if (MIA->isCall(Instruction)) {
1297-
if (BranchData) {
1298-
MIA->addAnnotation(Ctx.get(), Instruction, "IndirectBranchData",
1299-
Offset);
1300-
}
1301-
}
1302-
if (BranchData) {
1303-
const char* AttrName =
1304-
MaybeEdgeCountData ? "MaybeEdgeCountData" : "EdgeCountData";
1305-
MIA->addAnnotation(Ctx.get(), Instruction, AttrName, Offset);
13061274
}
13071275
// Indirect call. We only need to fix it if the operand is RIP-relative
13081276
if (IsSimple && MIA->hasRIPOperand(Instruction)) {
13091277
if (!handleRIPOperand(Instruction, AbsoluteInstrAddr, Size)) {
13101278
errs() << "BOLT-ERROR: cannot handle RIP operand at 0x"
13111279
<< Twine::utohexstr(AbsoluteInstrAddr)
13121280
<< ". Skipping function " << *this << ".\n";
1281+
if (opts::Relocs)
1282+
exit(1);
13131283
IsSimple = false;
13141284
}
13151285
}
@@ -1320,6 +1290,8 @@ void BinaryFunction::disassemble(ArrayRef<uint8_t> FunctionData) {
13201290
errs() << "BOLT-ERROR: cannot handle RIP operand at 0x"
13211291
<< Twine::utohexstr(AbsoluteInstrAddr)
13221292
<< ". Skipping function " << *this << ".\n";
1293+
if (opts::Relocs)
1294+
exit(1);
13231295
IsSimple = false;
13241296
}
13251297
}
@@ -1336,7 +1308,6 @@ void BinaryFunction::disassemble(ArrayRef<uint8_t> FunctionData) {
13361308

13371309
postProcessJumpTables();
13381310

1339-
// Update state.
13401311
updateState(State::Disassembled);
13411312
}
13421313

@@ -1402,12 +1373,6 @@ bool BinaryFunction::postProcessIndirectBranches() {
14021373
// it must be a tail call.
14031374
if (layout_size() == 1) {
14041375
BC.MIA->convertJmpToTailCall(Instr);
1405-
BC.MIA->renameAnnotation(Instr,
1406-
"MaybeEdgeCountData",
1407-
"EdgeCountData");
1408-
BC.MIA->renameAnnotation(Instr,
1409-
"MaybeIndirectBranchData",
1410-
"IndirectBranchData");
14111376
return true;
14121377
}
14131378

@@ -1487,12 +1452,6 @@ bool BinaryFunction::postProcessIndirectBranches() {
14871452
return false;
14881453
}
14891454
BC.MIA->convertJmpToTailCall(Instr);
1490-
BC.MIA->renameAnnotation(Instr,
1491-
"MaybeEdgeCountData",
1492-
"EdgeCountData");
1493-
BC.MIA->renameAnnotation(Instr,
1494-
"MaybeIndirectBranchData",
1495-
"IndirectBranchData");
14961455
}
14971456
}
14981457
return true;
@@ -1573,15 +1532,14 @@ bool BinaryFunction::buildCFG() {
15731532
// unconditional branch, and the unconditional branch is not
15741533
// a destination of another branch. In the latter case, the
15751534
// basic block will consist of a single unconditional branch
1576-
// (missed optimization opportunity?).
1535+
// (missed "double-jump" optimization).
15771536
//
15781537
// Created basic blocks are sorted in layout order since they are
15791538
// created in the same order as instructions, and instructions are
15801539
// sorted by offsets.
15811540
BinaryBasicBlock *InsertBB{nullptr};
15821541
BinaryBasicBlock *PrevBB{nullptr};
15831542
bool IsLastInstrNop{false};
1584-
bool IsPreviousInstrTailCall{false};
15851543
const MCInst *PrevInstr{nullptr};
15861544

15871545
auto addCFIPlaceholders =
@@ -1615,11 +1573,13 @@ bool BinaryFunction::buildCFG() {
16151573
}
16161574
if (!InsertBB) {
16171575
// It must be a fallthrough or unreachable code. Create a new block unless
1618-
// we see an unconditional branch following a conditional one.
1576+
// we see an unconditional branch following a conditional one. The latter
1577+
// should not be a conditional tail call.
16191578
assert(PrevBB && "no previous basic block for a fall through");
16201579
assert(PrevInstr && "no previous instruction for a fall through");
16211580
if (MIA->isUnconditionalBranch(Instr) &&
1622-
!MIA->isUnconditionalBranch(*PrevInstr) && !IsPreviousInstrTailCall) {
1581+
!MIA->isUnconditionalBranch(*PrevInstr) &&
1582+
!MIA->getConditionalTailCall(*PrevInstr)) {
16231583
// Temporarily restore inserter basic block.
16241584
InsertBB = PrevBB;
16251585
} else {
@@ -1637,16 +1597,10 @@ bool BinaryFunction::buildCFG() {
16371597
uint32_t InsertIndex = InsertBB->addInstruction(Instr);
16381598
PrevInstr = &Instr;
16391599

1640-
// Record whether this basic block is terminated with a tail call.
1641-
auto TCI = TailCallOffsets.find(Offset);
1642-
if (TCI != TailCallOffsets.end()) {
1643-
uint64_t TargetAddr = TCI->second;
1600+
// Record conditional tail call info.
1601+
if (const auto CTCDest = MIA->getConditionalTailCall(Instr)) {
16441602
TailCallTerminatedBlocks.emplace(
1645-
std::make_pair(InsertBB,
1646-
TailCallInfo(Offset, InsertIndex, TargetAddr)));
1647-
IsPreviousInstrTailCall = true;
1648-
} else {
1649-
IsPreviousInstrTailCall = false;
1603+
std::make_pair(InsertBB, TailCallInfo(Offset, InsertIndex, *CTCDest)));
16501604
}
16511605

16521606
// Add associated CFI instrs. We always add the CFI instruction that is
@@ -1821,9 +1775,7 @@ bool BinaryFunction::buildCFG() {
18211775

18221776
// Check if the last instruction is a conditional jump that serves as a tail
18231777
// call.
1824-
bool IsCondTailCall = MIA->isConditionalBranch(*LastInstIter) &&
1825-
TailCallTerminatedBlocks.count(BB);
1826-
1778+
const auto IsCondTailCall = MIA->getConditionalTailCall(*LastInstIter);
18271779
if (BB->succ_size() == 0) {
18281780
if (IsCondTailCall) {
18291781
// Conditional tail call without profile data for non-taken branch.
@@ -1915,7 +1867,6 @@ bool BinaryFunction::buildCFG() {
19151867
// NB: don't clear Labels list as we may need them if we mark the function
19161868
// as non-simple later in the process of discovering extra entry points.
19171869
clearList(Instructions);
1918-
clearList(TailCallOffsets);
19191870
clearList(TailCallTerminatedBlocks);
19201871
clearList(OffsetToCFI);
19211872
clearList(TakenBranches);
@@ -4384,7 +4335,7 @@ DynoStats BinaryFunction::getDynoStats() const {
43844335
if (!BC.MIA->isCall(Instr))
43854336
continue;
43864337
uint64_t CallFreq = BBExecutionCount;
4387-
if (BC.MIA->isCTC(Instr)) {
4338+
if (BC.MIA->getConditionalTailCall(Instr)) {
43884339
CallFreq = 0;
43894340
if (auto FreqOrErr =
43904341
BC.MIA->tryGetAnnotationAs<uint64_t>(Instr, "CTCTakenFreq")) {
@@ -4444,7 +4395,7 @@ DynoStats BinaryFunction::getDynoStats() const {
44444395
}
44454396

44464397
// CTCs
4447-
if (BC.MIA->isCTC(*CondBranch)) {
4398+
if (BC.MIA->getConditionalTailCall(*CondBranch)) {
44484399
if (BB->branch_info_begin() != BB->branch_info_end())
44494400
Stats[DynoStats::UNCOND_BRANCHES] += BB->branch_info_begin()->Count;
44504401
continue;

bolt/BinaryFunction.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -482,12 +482,6 @@ class BinaryFunction {
482482
using InstrMapType = std::map<uint32_t, MCInst>;
483483
InstrMapType Instructions;
484484

485-
/// Temporary holder of offsets of tail call instructions before CFG is
486-
/// constructed. Map from offset to the corresponding target address of the
487-
/// tail call.
488-
using TailCallOffsetMapType = std::map<uint32_t, uint64_t>;
489-
TailCallOffsetMapType TailCallOffsets;
490-
491485
/// Temporary holder of tail call terminated basic blocks used during CFG
492486
/// construction. Map from tail call terminated basic block to a struct with
493487
/// information about the tail call.

bolt/Passes/BinaryFunctionCallGraph.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -188,10 +188,10 @@ BinaryFunctionCallGraph buildCallGraph(BinaryContext &BC,
188188

189189
// If this is an indirect call use perf data directly.
190190
if (!DstSym && BranchData &&
191-
BC.MIA->hasAnnotation(Inst, "EdgeCountData")) {
192-
const auto DataOffset =
193-
BC.MIA->getAnnotationAs<uint64_t>(Inst, "EdgeCountData");
194-
for (const auto &BI : BranchData->getBranchRange(DataOffset)) {
191+
BC.MIA->hasAnnotation(Inst, "Offset")) {
192+
const auto InstrOffset =
193+
BC.MIA->getAnnotationAs<uint64_t>(Inst, "Offset");
194+
for (const auto &BI : BranchData->getBranchRange(InstrOffset)) {
195195
Counts.push_back(getCallInfoFromBranchData(BI, false));
196196
}
197197
} else {

bolt/Passes/BinaryPasses.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -655,7 +655,7 @@ uint64_t SimplifyConditionalTailCalls::fixTailCalls(BinaryContext &BC,
655655
? 0
656656
: PredBB->getBranchInfo(true).Count;
657657
// Annotate it, so "isCall" returns true for this jcc
658-
MIA->addAnnotation(BC.Ctx.get(), *CondBranch, "IsCTC", true);
658+
MIA->setConditionalTailCall(*CondBranch);
659659
// Add info abount the conditional tail call frequency, otherwise this
660660
// info will be lost when we delete the associated BranchInfo entry
661661
BC.MIA->addAnnotation(BC.Ctx.get(), *CondBranch, "CTCTakenFreq",

bolt/Passes/IndirectCallPromotion.cpp

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ IndirectCallPromotion::getCallTargets(
196196
} else {
197197
const auto *BranchData = BF.getBranchData();
198198
assert(BranchData && "expected initialized branch data");
199-
auto Offset = BC.MIA->getAnnotationAs<uint64_t>(Inst, "IndirectBranchData");
199+
auto Offset = BC.MIA->getAnnotationAs<uint64_t>(Inst, "Offset");
200200
for (const auto &BI : BranchData->getBranchRange(Offset)) {
201201
Callsite Site(BF, BI);
202202
if (Site.isValid()) {
@@ -309,7 +309,7 @@ IndirectCallPromotion::rewriteCall(BinaryContext &BC,
309309
auto TBB = Function.createBasicBlock(0, Sym);
310310
for (auto &Inst : Insts) { // sanitize new instructions.
311311
if (BC.MIA->isCall(Inst))
312-
BC.MIA->removeAnnotation(Inst, "IndirectBranchData");
312+
BC.MIA->removeAnnotation(Inst, "Offset");
313313
}
314314
TBB->addInstructions(Insts.begin(), Insts.end());
315315
NewBBs.emplace_back(std::move(TBB));
@@ -725,20 +725,24 @@ void IndirectCallPromotion::runOnFunctions(
725725
auto &Inst = BB->getInstructionAtIndex(Idx);
726726
const auto InstIdx = &Inst - &(*BB->begin());
727727
const bool IsTailCall = BC.MIA->isTailCall(Inst);
728+
const bool HasBranchData = Function.getBranchData() &&
729+
BC.MIA->hasAnnotation(Inst, "Offset");
728730
const bool IsJumpTable = Function.getJumpTable(Inst);
729-
const bool HasBranchData =
730-
BC.MIA->hasAnnotation(Inst, "IndirectBranchData");
731731
const bool OptimizeCalls =
732732
(opts::IndirectCallPromotion == ICP_CALLS ||
733733
opts::IndirectCallPromotion == ICP_ALL);
734734
const bool OptimizeJumpTables =
735735
(opts::IndirectCallPromotion == ICP_JUMP_TABLES ||
736736
opts::IndirectCallPromotion == ICP_ALL);
737737

738-
if (!((HasBranchData && OptimizeCalls) ||
738+
if (!((HasBranchData && !IsJumpTable && OptimizeCalls) ||
739739
(IsJumpTable && OptimizeJumpTables)))
740740
continue;
741741

742+
// Ignore direct calls.
743+
if (BC.MIA->isCall(Inst) && BC.MIA->getTargetSymbol(Inst, 0))
744+
continue;
745+
742746
assert(BC.MIA->isCall(Inst) || BC.MIA->isIndirectBranch(Inst));
743747

744748
if (IsJumpTable)

bolt/Passes/Inliner.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,7 @@ bool InlineSmallFunctions::inlineCallsInFunction(
447447
auto &Inst = *InstIt;
448448
if (BC.MIA->isCall(Inst) &&
449449
!BC.MIA->isTailCall(Inst) &&
450-
Inst.size() == 1 &&
450+
Inst.getNumPrimeOperands() == 1 &&
451451
Inst.getOperand(0).isExpr()) {
452452
const auto *TargetSymbol = BC.MIA->getTargetSymbol(Inst);
453453
assert(TargetSymbol && "target symbol expected for direct call");
@@ -513,7 +513,7 @@ bool InlineSmallFunctions::inlineCallsInFunctionAggressive(
513513
for (auto InstIt = BB->begin(); InstIt != BB->end(); ) {
514514
auto &Inst = *InstIt;
515515
if (BC.MIA->isCall(Inst) &&
516-
Inst.size() == 1 &&
516+
Inst.getNumPrimeOperands() == 1 &&
517517
Inst.getOperand(0).isExpr()) {
518518
assert(!BC.MIA->isInvoke(Inst));
519519
const auto *TargetSymbol = BC.MIA->getTargetSymbol(Inst);

bolt/RewriteInstance.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3429,7 +3429,6 @@ void RewriteInstance::patchELFSymTabs(ELFObjectFile<ELFT> *File) {
34293429
Symbol.st_shndx = ELF::SHN_ABS;
34303430
Symbol.st_name = AddToStrTab(Name);
34313431
Symbol.st_size = 0;
3432-
Symbol.st_shndx = 0;
34333432
Symbol.st_other = 0;
34343433
Symbol.setBindingAndType(ELF::STB_WEAK, ELF::STT_NOTYPE);
34353434

0 commit comments

Comments
 (0)