Skip to content

Commit 9e4dd66

Browse files
committed
Handle external origin LBR (non-BAT mode)
Created using spr 1.3.4
1 parent 9c4effa commit 9e4dd66

File tree

5 files changed

+132
-969
lines changed

5 files changed

+132
-969
lines changed

bolt/lib/Profile/DataAggregator.cpp

Lines changed: 72 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -775,46 +775,86 @@ bool DataAggregator::doInterBranch(BinaryFunction *FromFunc,
775775

776776
bool DataAggregator::doBranch(uint64_t From, uint64_t To, uint64_t Count,
777777
uint64_t Mispreds) {
778-
bool IsReturn = false;
779-
auto handleAddress = [&](uint64_t &Addr, bool IsFrom) -> BinaryFunction * {
780-
if (BinaryFunction *Func = getBinaryFunctionContainingAddress(Addr)) {
781-
Addr -= Func->getAddress();
782-
if (IsFrom) {
783-
auto checkReturn = [&](auto MaybeInst) {
784-
IsReturn = MaybeInst && BC->MIB->isReturn(*MaybeInst);
785-
};
786-
if (Func->hasInstructions())
787-
checkReturn(Func->getInstructionAtOffset(Addr));
788-
else
789-
checkReturn(Func->disassembleInstructionAtOffset(Addr));
790-
}
778+
// Returns whether \p Offset in \p Func contains a return instruction.
779+
auto checkReturn = [&](const BinaryFunction &Func, const uint64_t Offset) {
780+
auto isReturn = [&](auto MI) { return MI && BC->MIB->isReturn(*MI); };
781+
return Func.hasInstructions()
782+
? isReturn(Func.getInstructionAtOffset(Offset))
783+
: isReturn(Func.disassembleInstructionAtOffset(Offset));
784+
};
791785

792-
if (BAT)
793-
Addr = BAT->translate(Func->getAddress(), Addr, IsFrom);
786+
// Returns whether \p Offset in \p Func corresponds to a call continuation
787+
// fallthrough block.
788+
auto checkCallCont = [&](BinaryFunction &Func, const uint64_t Offset) {
789+
// Note the use of MCInstrAnalysis: no call continuation for a tail call.
790+
auto isCall = [&](auto MI) { return MI && BC->MIA->isCall(*MI); };
791+
792+
// No call continuation at a function start.
793+
if (!Offset)
794+
return false;
795+
796+
// FIXME: support BAT case where the function might be in empty state
797+
// (split fragments declared non-simple).
798+
if (!Func.hasCFG())
799+
return false;
800+
801+
// The offset should not be an entry point or a landing pad.
802+
const BinaryBasicBlock *ContBB = Func.getBasicBlockAtOffset(Offset);
803+
if (!ContBB || ContBB->isEntryPoint() || ContBB->isLandingPad())
804+
return false;
805+
806+
// Check that preceding instruction is a call.
807+
const BinaryBasicBlock *CallBB =
808+
Func.getBasicBlockContainingOffset(Offset - 1);
809+
if (!CallBB || CallBB == ContBB)
810+
return false;
811+
return isCall(CallBB->getLastNonPseudoInstr());
812+
};
794813

795-
if (BinaryFunction *ParentFunc = getBATParentFunction(*Func)) {
796-
Func = ParentFunc;
797-
if (IsFrom)
798-
NumColdSamples += Count;
799-
}
814+
// Mutates \p Addr to an offset into the containing function, performing BAT
815+
// offset translation and parent lookup.
816+
//
817+
// Returns the containing function (or BAT parent) and whether the address
818+
// corresponds to a return (if \p IsFrom) or a call continuation (otherwise).
819+
auto handleAddress = [&](uint64_t &Addr, bool IsFrom) {
820+
BinaryFunction *Func = getBinaryFunctionContainingAddress(Addr);
821+
if (!Func)
822+
return std::pair{Func, false};
800823

801-
return Func;
802-
}
803-
return nullptr;
804-
};
824+
Addr -= Func->getAddress();
805825

806-
BinaryFunction *FromFunc = handleAddress(From, /*IsFrom=*/true);
807-
// Record returns as call->call continuation fall-through.
808-
if (IsReturn) {
809-
LBREntry First{To - 1, To - 1, false};
810-
LBREntry Second{To, To, false};
811-
return doTrace(First, Second, Count);
812-
}
826+
bool IsRetOrCallCont =
827+
IsFrom ? checkReturn(*Func, Addr) : checkCallCont(*Func, Addr);
828+
829+
if (BAT)
830+
Addr = BAT->translate(Func->getAddress(), Addr, IsFrom);
831+
832+
BinaryFunction *ParentFunc = getBATParentFunction(*Func);
833+
if (!ParentFunc)
834+
return std::pair{Func, IsRetOrCallCont};
813835

814-
BinaryFunction *ToFunc = handleAddress(To, /*IsFrom=*/false);
836+
if (IsFrom)
837+
NumColdSamples += Count;
838+
839+
return std::pair{ParentFunc, IsRetOrCallCont};
840+
};
841+
842+
uint64_t ToOrig = To;
843+
auto [FromFunc, IsReturn] = handleAddress(From, /*IsFrom=*/true);
844+
auto [ToFunc, IsCallCont] = handleAddress(To, /*IsFrom=*/false);
815845
if (!FromFunc && !ToFunc)
816846
return false;
817847

848+
// Record call to continuation trace.
849+
if (IsCallCont && FromFunc != ToFunc) {
850+
LBREntry First{ToOrig - 1, ToOrig - 1, false};
851+
LBREntry Second{ToOrig, ToOrig, false};
852+
return doTrace(First, Second, Count);
853+
}
854+
// Ignore returns.
855+
if (IsReturn)
856+
return true;
857+
818858
// Treat recursive control transfers as inter-branches.
819859
if (FromFunc == ToFunc && To != 0) {
820860
recordBranch(*FromFunc, From, To, Count, Mispreds);
@@ -916,24 +956,6 @@ DataAggregator::getFallthroughsInTrace(BinaryFunction &BF,
916956
if (!FromBB || !ToBB)
917957
return std::nullopt;
918958

919-
// Adjust FromBB if the first LBR is a return from the last instruction in
920-
// the previous block (that instruction should be a call).
921-
if (From == FromBB->getOffset() && !BF.containsAddress(FirstLBR.From) &&
922-
!FromBB->isEntryPoint() && !FromBB->isLandingPad()) {
923-
const BinaryBasicBlock *PrevBB =
924-
BF.getLayout().getBlock(FromBB->getIndex() - 1);
925-
if (PrevBB->getSuccessor(FromBB->getLabel())) {
926-
const MCInst *Instr = PrevBB->getLastNonPseudoInstr();
927-
if (Instr && BC.MIB->isCall(*Instr))
928-
FromBB = PrevBB;
929-
else
930-
LLVM_DEBUG(dbgs() << "invalid incoming LBR (no call): " << FirstLBR
931-
<< '\n');
932-
} else {
933-
LLVM_DEBUG(dbgs() << "invalid incoming LBR: " << FirstLBR << '\n');
934-
}
935-
}
936-
937959
// Fill out information for fall-through edges. The From and To could be
938960
// within the same basic block, e.g. when two call instructions are in the
939961
// same block. In this case we skip the processing.

bolt/test/X86/Inputs/callcont-fallthru.preagg

Lines changed: 0 additions & 21 deletions
This file was deleted.

0 commit comments

Comments
 (0)