Skip to content

Commit 9469ea2

Browse files
[BOLT] Avoid n^2 complexity in fixBranches(). NFCI (#160407)
Iterator implementation of PR #156243: This improves BOLT runtime when optimizing rustc_driver.so from 15 minutes to 7 minutes (or 49 minutes to 37 minutes of userspace time). Co-authored-by: Mark-Simulacrum <mark.simulacrum@gmail.com>
1 parent 06fb26c commit 9469ea2

File tree

3 files changed

+33
-14
lines changed

3 files changed

+33
-14
lines changed

bolt/include/bolt/Core/FunctionLayout.h

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -232,20 +232,31 @@ class FunctionLayout {
232232
return Blocks[Index];
233233
}
234234

235+
/// Return the basic block after the given basic block iterator in the layout
236+
/// or nullptr if the last basic block iterator is given.
237+
const BinaryBasicBlock *getBasicBlockAfter(block_const_iterator BlockIt,
238+
bool IgnoreSplits = true) const;
239+
240+
/// Returns the basic block after the given basic block in the layout or
241+
/// nullptr if the last basic block is given.
242+
///
243+
/// Note: prefer the version that takes the iterator as this function uses
244+
/// linear basic block lookup.
245+
const BinaryBasicBlock *getBasicBlockAfter(const BinaryBasicBlock *BB,
246+
bool IgnoreSplits = true) const;
247+
235248
/// Returns the basic block after the given basic block in the layout or
236249
/// nullptr if the last basic block is given.
250+
///
251+
/// Note: prefer the version that takes the iterator as this function uses
252+
/// linear basic block lookup.
237253
BinaryBasicBlock *getBasicBlockAfter(const BinaryBasicBlock *const BB,
238254
const bool IgnoreSplits = true) {
239255
return const_cast<BinaryBasicBlock *>(
240256
static_cast<const FunctionLayout &>(*this).getBasicBlockAfter(
241257
BB, IgnoreSplits));
242258
}
243259

244-
/// Returns the basic block after the given basic block in the layout or
245-
/// nullptr if the last basic block is given.
246-
const BinaryBasicBlock *getBasicBlockAfter(const BinaryBasicBlock *BB,
247-
bool IgnoreSplits = true) const;
248-
249260
/// True if the layout contains at least two non-empty fragments.
250261
bool isSplit() const;
251262

bolt/lib/Core/BinaryFunction.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3598,7 +3598,9 @@ void BinaryFunction::fixBranches() {
35983598
auto &MIB = BC.MIB;
35993599
MCContext *Ctx = BC.Ctx.get();
36003600

3601-
for (BinaryBasicBlock *BB : BasicBlocks) {
3601+
for (auto BBI = Layout.block_begin(), BBE = Layout.block_end(); BBI != BBE;
3602+
++BBI) {
3603+
BinaryBasicBlock *BB = *BBI;
36023604
const MCSymbol *TBB = nullptr;
36033605
const MCSymbol *FBB = nullptr;
36043606
MCInst *CondBranch = nullptr;
@@ -3612,7 +3614,7 @@ void BinaryFunction::fixBranches() {
36123614

36133615
// Basic block that follows the current one in the final layout.
36143616
const BinaryBasicBlock *const NextBB =
3615-
Layout.getBasicBlockAfter(BB, /*IgnoreSplits=*/false);
3617+
Layout.getBasicBlockAfter(BBI, /*IgnoreSplits*/ false);
36163618

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

bolt/lib/Core/FunctionLayout.cpp

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -224,23 +224,29 @@ void FunctionLayout::clear() {
224224
}
225225

226226
const BinaryBasicBlock *
227-
FunctionLayout::getBasicBlockAfter(const BinaryBasicBlock *BB,
227+
FunctionLayout::getBasicBlockAfter(block_const_iterator BBIter,
228228
bool IgnoreSplits) const {
229-
const block_const_iterator BBPos = find(blocks(), BB);
230-
if (BBPos == block_end())
231-
return nullptr;
232-
233-
const block_const_iterator BlockAfter = std::next(BBPos);
229+
const block_const_iterator BlockAfter = std::next(BBIter);
234230
if (BlockAfter == block_end())
235231
return nullptr;
236232

237233
if (!IgnoreSplits)
238-
if (BlockAfter == getFragment(BB->getFragmentNum()).end())
234+
if (BlockAfter == getFragment((*BBIter)->getFragmentNum()).end())
239235
return nullptr;
240236

241237
return *BlockAfter;
242238
}
243239

240+
const BinaryBasicBlock *
241+
FunctionLayout::getBasicBlockAfter(const BinaryBasicBlock *BB,
242+
bool IgnoreSplits) const {
243+
const block_const_iterator BBPos = find(blocks(), BB);
244+
if (BBPos == block_end())
245+
return nullptr;
246+
247+
return getBasicBlockAfter(BBPos, IgnoreSplits);
248+
}
249+
244250
bool FunctionLayout::isSplit() const {
245251
const unsigned NonEmptyFragCount = llvm::count_if(
246252
fragments(), [](const FunctionFragment &FF) { return !FF.empty(); });

0 commit comments

Comments
 (0)