Skip to content

Commit 6046d1d

Browse files
Bill Nellmemfrob
authored andcommitted
[BOLT] Fix N-1'th sctc bug.
Summary: The logic to append an unconditional branch at the end of a block that had the condition flipped on its conditional tail was broken. It should have been looking at the successor to PredBB instead of BB. It also wasn't skipping invalid blocks when finding the fallthrough block. This fixes the SCTC bug uncovered by @spupyrev's work on block reordering. (cherry picked from FBD6269493)
1 parent ec6c241 commit 6046d1d

File tree

2 files changed

+35
-23
lines changed

2 files changed

+35
-23
lines changed

bolt/Passes/BinaryPasses.cpp

Lines changed: 34 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -682,7 +682,11 @@ bool SimplifyConditionalTailCalls::shouldRewriteBranch(
682682
const BinaryBasicBlock *PredBB,
683683
const MCInst &CondBranch,
684684
const BinaryBasicBlock *BB,
685-
const bool DirectionFlag) {
685+
const bool DirectionFlag
686+
) {
687+
if (BeenOptimized.count(PredBB))
688+
return false;
689+
686690
const bool IsForward = BinaryFunction::isForwardBranch(PredBB, BB);
687691

688692
if (IsForward)
@@ -725,9 +729,8 @@ uint64_t SimplifyConditionalTailCalls::fixTailCalls(BinaryContext &BC,
725729
uint64_t NumLocalCTCs = 0;
726730
uint64_t LocalCTCTakenCount = 0;
727731
uint64_t LocalCTCExecCount = 0;
728-
std::vector<std::tuple<BinaryBasicBlock *,
729-
BinaryBasicBlock *,
730-
const BinaryBasicBlock *>> NeedsUncondBranch;
732+
std::vector<std::pair<BinaryBasicBlock *,
733+
const BinaryBasicBlock *>> NeedsUncondBranch;
731734

732735
// Will block be deleted by UCE?
733736
auto isValid = [](const BinaryBasicBlock *BB) {
@@ -792,14 +795,17 @@ uint64_t SimplifyConditionalTailCalls::fixTailCalls(BinaryContext &BC,
792795
if (!shouldRewriteBranch(PredBB, *CondBranch, BB, DirectionFlag))
793796
continue;
794797

798+
// Record this block so that we don't try to optimize it twice.
799+
BeenOptimized.insert(PredBB);
800+
795801
if (CondSucc != BB) {
796802
// Patch the new target address into the conditional branch.
797803
MIA->reverseBranchCondition(*CondBranch, CalleeSymbol, BC.Ctx.get());
798804
// Since we reversed the condition on the branch we need to change
799805
// the target for the unconditional branch or add a unconditional
800806
// branch to the old target. This has to be done manually since
801807
// fixupBranches is not called after SCTC.
802-
NeedsUncondBranch.emplace_back(std::make_tuple(BB, PredBB, CondSucc));
808+
NeedsUncondBranch.emplace_back(std::make_pair(PredBB, CondSucc));
803809
// Swap branch statistics after swapping the branch targets.
804810
auto BI = PredBB->branch_info_begin();
805811
std::swap(*BI, *(BI + 1));
@@ -840,34 +846,39 @@ uint64_t SimplifyConditionalTailCalls::fixTailCalls(BinaryContext &BC,
840846
// Add unconditional branches at the end of BBs to new successors
841847
// as long as the successor is not a fallthrough.
842848
for (auto &Entry : NeedsUncondBranch) {
843-
auto *BB = std::get<0>(Entry);
844-
auto *PredBB = std::get<1>(Entry);
845-
auto *CondSucc = std::get<2>(Entry);
849+
auto *PredBB = Entry.first;
850+
auto *CondSucc = Entry.second;
846851

847852
const MCSymbol *TBB = nullptr;
848853
const MCSymbol *FBB = nullptr;
849854
MCInst *CondBranch = nullptr;
850855
MCInst *UncondBranch = nullptr;
851856
PredBB->analyzeBranch(TBB, FBB, CondBranch, UncondBranch);
852857

853-
// Only add a new branch if the target is not the fall-through.
854-
if (BF.getBasicBlockAfter(BB) != CondSucc || isValid(BB) ||
855-
PredBB->isCold() != CondSucc->isCold()) {
856-
if (UncondBranch) {
858+
// Find the next valid block. Invalid blocks will be deleted
859+
// so they shouldn't be considered fallthrough targets.
860+
const auto *NextBlock = BF.getBasicBlockAfter(PredBB, false);
861+
while (NextBlock && !isValid(NextBlock)) {
862+
NextBlock = BF.getBasicBlockAfter(NextBlock, false);
863+
}
864+
865+
// Get the unconditional successor to this block.
866+
const auto *PredSucc = PredBB->getSuccessor();
867+
assert(PredSucc && "The other branch should be a tail call");
868+
869+
const bool HasFallthrough = (NextBlock && PredSucc == NextBlock);
870+
871+
if (UncondBranch) {
872+
if (HasFallthrough)
873+
PredBB->eraseInstruction(UncondBranch);
874+
else
857875
MIA->replaceBranchTarget(*UncondBranch,
858876
CondSucc->getLabel(),
859877
BC.Ctx.get());
860-
} else {
861-
MCInst Branch;
862-
auto Result = MIA->createUncondBranch(Branch,
863-
CondSucc->getLabel(),
864-
BC.Ctx.get());
865-
(void)Result;
866-
assert(Result);
867-
PredBB->addInstruction(Branch);
868-
}
869-
} else if (UncondBranch) {
870-
PredBB->eraseInstruction(UncondBranch);
878+
} else if (!HasFallthrough) {
879+
MCInst Branch;
880+
MIA->createUncondBranch(Branch, CondSucc->getLabel(), BC.Ctx.get());
881+
PredBB->addInstruction(Branch);
871882
}
872883
}
873884

bolt/Passes/BinaryPasses.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,7 @@ class SimplifyConditionalTailCalls : public BinaryFunctionPass {
276276
uint64_t DeletedBlocks{0};
277277
uint64_t DeletedBytes{0};
278278
std::unordered_set<const BinaryFunction *> Modified;
279+
std::set<const BinaryBasicBlock *> BeenOptimized;
279280

280281
bool shouldRewriteBranch(const BinaryBasicBlock *PredBB,
281282
const MCInst &CondBranch,

0 commit comments

Comments
 (0)