Skip to content

Commit db72cc2

Browse files
[BOLT] Split getBasicBlocksAfter cache into a distinct function
This enables future re-use in other code that calls getBasicBlockAfter in loops, though for now those uses aren't introduced.
1 parent 480d48e commit db72cc2

File tree

3 files changed

+27
-12
lines changed

3 files changed

+27
-12
lines changed

bolt/include/bolt/Core/FunctionLayout.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,9 +243,18 @@ class FunctionLayout {
243243

244244
/// Returns the basic block after the given basic block in the layout or
245245
/// nullptr if the last basic block is given.
246+
///
247+
/// Note that this performs a linear search for BB.
246248
const BinaryBasicBlock *getBasicBlockAfter(const BinaryBasicBlock *BB,
247249
bool IgnoreSplits = true) const;
248250

251+
/// Returns a mapping from BB -> getBasicBlockAfter(BB).
252+
///
253+
/// This should be preferred in loops that call getBasicBlockAfter without
254+
/// changes to the function layout. Caching the results avoid n^2 lookup cost.
255+
DenseMap<BinaryBasicBlock *, BinaryBasicBlock *>
256+
getBasicBlocksAfter(bool IgnoreSplits = true) const;
257+
249258
/// True if the layout contains at least two non-empty fragments.
250259
bool isSplit() const;
251260

bolt/lib/Core/BinaryFunction.cpp

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3591,17 +3591,7 @@ void BinaryFunction::fixBranches() {
35913591
auto &MIB = BC.MIB;
35923592
MCContext *Ctx = BC.Ctx.get();
35933593

3594-
// Caches `FunctionLayout::nextBasicBlock(IgnoreSplits = false)`.
3595-
// nextBasicBlock uses linear search to find the next block, so the loop
3596-
// below becomes O(n^2). This avoids that.
3597-
DenseMap<BinaryBasicBlock *, BinaryBasicBlock *> nextBasicBlock(
3598-
Layout.block_size());
3599-
for (size_t i = 0; i + 1 < Layout.block_size(); i++) {
3600-
auto current = Layout.block_begin() + i;
3601-
auto next = Layout.block_begin() + i + 1;
3602-
if (next != Layout.getFragment((*current)->getFragmentNum()).end())
3603-
nextBasicBlock.insert(std::pair(*current, *next));
3604-
}
3594+
auto NextBasicBlock = Layout.getBasicBlocksAfter(/* IgnoreSplits */ false);
36053595

36063596
for (BinaryBasicBlock *BB : BasicBlocks) {
36073597
const MCSymbol *TBB = nullptr;
@@ -3617,7 +3607,7 @@ void BinaryFunction::fixBranches() {
36173607

36183608
// Basic block that follows the current one in the final layout.
36193609
const BinaryBasicBlock *const NextBB =
3620-
nextBasicBlock.lookup_or(BB, nullptr);
3610+
NextBasicBlock.lookup_or(BB, nullptr);
36213611

36223612
if (BB->succ_size() == 1) {
36233613
// __builtin_unreachable() could create a conditional branch that

bolt/lib/Core/FunctionLayout.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,22 @@ FunctionLayout::getBasicBlockAfter(const BinaryBasicBlock *BB,
241241
return *BlockAfter;
242242
}
243243

244+
DenseMap<BinaryBasicBlock *, BinaryBasicBlock *>
245+
FunctionLayout::getBasicBlocksAfter(bool IgnoreSplits) const {
246+
DenseMap<BinaryBasicBlock *, BinaryBasicBlock *> NextBasicBlock(block_size());
247+
for (size_t i = 0; i + 1 < block_size(); i++) {
248+
auto Current = block_begin() + i;
249+
auto Next = block_begin() + i + 1;
250+
251+
if (IgnoreSplits) {
252+
NextBasicBlock.insert(std::pair(*Current, *Next));
253+
} else if (Next != getFragment((*Current)->getFragmentNum()).end()) {
254+
NextBasicBlock.insert(std::pair(*Current, *Next));
255+
}
256+
}
257+
return NextBasicBlock;
258+
}
259+
244260
bool FunctionLayout::isSplit() const {
245261
const unsigned NonEmptyFragCount = llvm::count_if(
246262
fragments(), [](const FunctionFragment &FF) { return !FF.empty(); });

0 commit comments

Comments
 (0)