Skip to content

Commit 69e8ed4

Browse files
committed
[Bolt] Teach bolt about no-return functions
1 parent f8fea5d commit 69e8ed4

File tree

6 files changed

+151
-0
lines changed

6 files changed

+151
-0
lines changed

bolt/include/bolt/Core/BinaryContext.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,10 @@ class BinaryContext {
272272
/// DWARF line info for CUs.
273273
std::map<unsigned, DwarfLineTable> DwarfLineTablesCUMap;
274274

275+
/// Container to cache results about functions that their paths lead to
276+
/// a no-return function.
277+
std::unordered_map<BinaryFunction *, bool> CallsNoReturnFunction;
278+
275279
/// Internal helper for removing section name from a lookup table.
276280
void deregisterSectionName(const BinarySection &Section);
277281

@@ -282,6 +286,16 @@ class BinaryContext {
282286
std::unique_ptr<DWARFContext> DwCtx,
283287
JournalingStreams Logger);
284288

289+
void setHasPathToNoReturn(BinaryFunction *Func, bool value = true) {
290+
CallsNoReturnFunction[Func] = value;
291+
}
292+
293+
bool cachedInNoReturnMap(BinaryFunction *Func) {
294+
return CallsNoReturnFunction.find(Func) != CallsNoReturnFunction.end();
295+
}
296+
297+
bool hasPathToNoReturn(BinaryFunction *Func);
298+
285299
/// Superset of compiler units that will contain overwritten code that needs
286300
/// new debug info. In a few cases, functions may end up not being
287301
/// overwritten, but it is okay to re-generate debug info for them.
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//===- bolt/Passes/Discover.h -----------------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef BOLT_PASSES_DISCOVERNORETURN_H
10+
#define BOLT_PASSES_DISCOVERNORETURN_H
11+
12+
#include "bolt/Core/BinaryContext.h"
13+
#include "bolt/Core/BinaryFunction.h"
14+
#include "bolt/Passes/BinaryPasses.h"
15+
#include <unordered_map>
16+
17+
namespace llvm {
18+
19+
namespace bolt {
20+
21+
class DiscoverNoReturnPass : public BinaryFunctionPass {
22+
public:
23+
explicit DiscoverNoReturnPass() : BinaryFunctionPass(false) {}
24+
25+
const char *getName() const override { return "discover-no-return"; }
26+
27+
Error runOnFunctions(BinaryContext &BC) override;
28+
29+
private:
30+
std::unordered_map<BinaryFunction *, bool> Visited;
31+
bool traverseFromFunction(BinaryFunction *Func, BinaryContext &BC);
32+
};
33+
} // namespace bolt
34+
} // namespace llvm
35+
36+
#endif

bolt/lib/Core/BinaryContext.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,20 @@ Expected<std::unique_ptr<BinaryContext>> BinaryContext::createBinaryContext(
308308
return std::move(BC);
309309
}
310310

311+
bool BinaryContext::hasPathToNoReturn(BinaryFunction *Func) {
312+
// Dummy way to mark no-return functions.
313+
// FIXME: Find a better way.
314+
if (std::string FuncName = Func->getPrintName();
315+
FuncName == "__cxa_throw@PLT" || FuncName != "_Unwind_Resume@PLT" ||
316+
FuncName == "__cxa_rethrow@PLT" || FuncName != "exit@PLT" ||
317+
FuncName == "abort@PLT" || FuncName == "setjmp@PLT" ||
318+
FuncName == "longjmp@PLT")
319+
return true;
320+
321+
auto itr = CallsNoReturnFunction.find(Func);
322+
return itr != CallsNoReturnFunction.end() && itr->second;
323+
}
324+
311325
bool BinaryContext::forceSymbolRelocations(StringRef SymbolName) const {
312326
if (opts::HotText &&
313327
(SymbolName == "__hot_start" || SymbolName == "__hot_end"))

bolt/lib/Passes/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ add_llvm_library(LLVMBOLTPasses
88
CacheMetrics.cpp
99
DataflowAnalysis.cpp
1010
DataflowInfoManager.cpp
11+
DiscoverNoReturnPass.cpp
1112
FrameAnalysis.cpp
1213
FrameOptimizer.cpp
1314
FixRelaxationPass.cpp
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
//===- bolt/Passes/ReorderSection.cpp - Reordering of section data --------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file implements DiscoverNoReturnPass class.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "bolt/Passes/DiscoverNoReturnPass.h"
14+
15+
using namespace llvm;
16+
17+
namespace opts {
18+
extern cl::OptionCategory BoltCategory;
19+
20+
static cl::opt<bool> DiscoverNoReturnAnalysis(
21+
"discover-no-return",
22+
cl::desc("analyze the binary and mark no-return functions"), cl::init(true),
23+
cl::cat(BoltCategory), cl::ReallyHidden);
24+
} // namespace opts
25+
26+
namespace llvm {
27+
namespace bolt {
28+
29+
Error DiscoverNoReturnPass::runOnFunctions(BinaryContext &BC) {
30+
bool Changed;
31+
do {
32+
Changed = false;
33+
for (auto &BFI : BC.getBinaryFunctions()) {
34+
auto &Func = BFI.second;
35+
bool PrevStat = BC.hasPathToNoReturn(&Func);
36+
bool CurStat = traverseFromFunction(&Func, BC);
37+
Changed |= (PrevStat != CurStat);
38+
}
39+
} while (Changed);
40+
41+
return Error::success();
42+
}
43+
44+
bool DiscoverNoReturnPass::traverseFromFunction(BinaryFunction *Func,
45+
BinaryContext &BC) {
46+
// The Function cached before, so return its value
47+
if (BC.cachedInNoReturnMap(Func))
48+
return BC.hasPathToNoReturn(Func);
49+
50+
Visited[Func] = true;
51+
bool Result = true;
52+
bool hasCalls = 0;
53+
bool hasReturns = 0;
54+
for (auto &BB : *Func) {
55+
if (!BB.getNumCalls())
56+
continue;
57+
for (auto &Inst : BB) {
58+
if (BC.MIB->isCall(Inst)) {
59+
hasCalls = true;
60+
const MCSymbol *TargetSymbol = BC.MIB->getTargetSymbol(Inst);
61+
BinaryFunction *TargetFunction = BC.SymbolToFunctionMap[TargetSymbol];
62+
if (!Visited.count(TargetFunction))
63+
Result &= traverseFromFunction(TargetFunction, BC);
64+
}
65+
hasReturns |= BC.MIB->isReturn(Inst);
66+
}
67+
}
68+
69+
// This functions is represented as a leaf in the call graph and doesn't
70+
// have a no-return attribute.
71+
if (!hasCalls && hasReturns)
72+
Result = false;
73+
74+
// If the function doens't have a return instruction then it's a
75+
// no-return function.
76+
if (!hasReturns)
77+
Result = true;
78+
79+
BC.setHasPathToNoReturn(Func, Result);
80+
return Result;
81+
}
82+
83+
} // end namespace bolt
84+
} // end namespace llvm

bolt/lib/Rewrite/BinaryPassManager.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "bolt/Passes/AsmDump.h"
1414
#include "bolt/Passes/CMOVConversion.h"
1515
#include "bolt/Passes/ContinuityStats.h"
16+
#include "bolt/Passes/DiscoverNoReturnPass.h"
1617
#include "bolt/Passes/FixRISCVCallsPass.h"
1718
#include "bolt/Passes/FixRelaxationPass.h"
1819
#include "bolt/Passes/FrameOptimizer.h"
@@ -443,6 +444,7 @@ Error BinaryFunctionPassManager::runAllPasses(BinaryContext &BC) {
443444

444445
Manager.registerPass(std::make_unique<CMOVConversion>(),
445446
opts::CMOVConversionFlag);
447+
Manager.registerPass(std::make_unique<DiscoverNoReturnPass>());
446448

447449
// This pass syncs local branches with CFG. If any of the following
448450
// passes breaks the sync - they either need to re-run the pass or

0 commit comments

Comments
 (0)