[llvm] [Bolt] Teach bolt about no-return functions (PR #115616)
via llvm-commits
llvm-commits at lists.llvm.org
Sat Nov 9 10:46:33 PST 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-bolt
Author: None (elhewaty)
<details>
<summary>Changes</summary>
---
Full diff: https://github.com/llvm/llvm-project/pull/115616.diff
6 Files Affected:
- (modified) bolt/include/bolt/Core/BinaryContext.h (+14)
- (added) bolt/include/bolt/Passes/DiscoverNoReturnPass.h (+36)
- (modified) bolt/lib/Core/BinaryContext.cpp (+14)
- (modified) bolt/lib/Passes/CMakeLists.txt (+1)
- (added) bolt/lib/Passes/DiscoverNoReturnPass.cpp (+84)
- (modified) bolt/lib/Rewrite/BinaryPassManager.cpp (+2)
``````````diff
diff --git a/bolt/include/bolt/Core/BinaryContext.h b/bolt/include/bolt/Core/BinaryContext.h
index 08ce892054874c..749a82f0f453b0 100644
--- a/bolt/include/bolt/Core/BinaryContext.h
+++ b/bolt/include/bolt/Core/BinaryContext.h
@@ -272,6 +272,10 @@ class BinaryContext {
/// DWARF line info for CUs.
std::map<unsigned, DwarfLineTable> DwarfLineTablesCUMap;
+ /// Container to cache results about functions that their paths lead to
+ /// a no-return function.
+ std::unordered_map<BinaryFunction *, bool> CallsNoReturnFunction;
+
/// Internal helper for removing section name from a lookup table.
void deregisterSectionName(const BinarySection &Section);
@@ -282,6 +286,16 @@ class BinaryContext {
std::unique_ptr<DWARFContext> DwCtx,
JournalingStreams Logger);
+ void setHasPathToNoReturn(BinaryFunction *Func, bool value = true) {
+ CallsNoReturnFunction[Func] = value;
+ }
+
+ bool cachedInNoReturnMap(BinaryFunction *Func) {
+ return CallsNoReturnFunction.find(Func) != CallsNoReturnFunction.end();
+ }
+
+ bool hasPathToNoReturn(BinaryFunction *Func);
+
/// Superset of compiler units that will contain overwritten code that needs
/// new debug info. In a few cases, functions may end up not being
/// overwritten, but it is okay to re-generate debug info for them.
diff --git a/bolt/include/bolt/Passes/DiscoverNoReturnPass.h b/bolt/include/bolt/Passes/DiscoverNoReturnPass.h
new file mode 100644
index 00000000000000..3a34e1344f3bb4
--- /dev/null
+++ b/bolt/include/bolt/Passes/DiscoverNoReturnPass.h
@@ -0,0 +1,36 @@
+//===- bolt/Passes/Discover.h -----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef BOLT_PASSES_DISCOVERNORETURN_H
+#define BOLT_PASSES_DISCOVERNORETURN_H
+
+#include "bolt/Core/BinaryContext.h"
+#include "bolt/Core/BinaryFunction.h"
+#include "bolt/Passes/BinaryPasses.h"
+#include <unordered_map>
+
+namespace llvm {
+
+namespace bolt {
+
+class DiscoverNoReturnPass : public BinaryFunctionPass {
+public:
+ explicit DiscoverNoReturnPass() : BinaryFunctionPass(false) {}
+
+ const char *getName() const override { return "discover-no-return"; }
+
+ Error runOnFunctions(BinaryContext &BC) override;
+
+private:
+ std::unordered_map<BinaryFunction *, bool> Visited;
+ bool traverseFromFunction(BinaryFunction *Func, BinaryContext &BC);
+};
+} // namespace bolt
+} // namespace llvm
+
+#endif
\ No newline at end of file
diff --git a/bolt/lib/Core/BinaryContext.cpp b/bolt/lib/Core/BinaryContext.cpp
index f246750209d6c4..c8eee1786b794a 100644
--- a/bolt/lib/Core/BinaryContext.cpp
+++ b/bolt/lib/Core/BinaryContext.cpp
@@ -308,6 +308,20 @@ Expected<std::unique_ptr<BinaryContext>> BinaryContext::createBinaryContext(
return std::move(BC);
}
+bool BinaryContext::hasPathToNoReturn(BinaryFunction *Func) {
+ // Dummy way to mark no-return functions.
+ // FIXME: Find a better way.
+ if (std::string FuncName = Func->getPrintName();
+ FuncName == "__cxa_throw at PLT" || FuncName != "_Unwind_Resume at PLT" ||
+ FuncName == "__cxa_rethrow at PLT" || FuncName != "exit at PLT" ||
+ FuncName == "abort at PLT" || FuncName == "setjmp at PLT" ||
+ FuncName == "longjmp at PLT")
+ return true;
+
+ auto itr = CallsNoReturnFunction.find(Func);
+ return itr != CallsNoReturnFunction.end() && itr->second;
+}
+
bool BinaryContext::forceSymbolRelocations(StringRef SymbolName) const {
if (opts::HotText &&
(SymbolName == "__hot_start" || SymbolName == "__hot_end"))
diff --git a/bolt/lib/Passes/CMakeLists.txt b/bolt/lib/Passes/CMakeLists.txt
index 1c1273b3d2420d..7c950ec1decf59 100644
--- a/bolt/lib/Passes/CMakeLists.txt
+++ b/bolt/lib/Passes/CMakeLists.txt
@@ -8,6 +8,7 @@ add_llvm_library(LLVMBOLTPasses
CacheMetrics.cpp
DataflowAnalysis.cpp
DataflowInfoManager.cpp
+ DiscoverNoReturnPass.cpp
FrameAnalysis.cpp
FrameOptimizer.cpp
FixRelaxationPass.cpp
diff --git a/bolt/lib/Passes/DiscoverNoReturnPass.cpp b/bolt/lib/Passes/DiscoverNoReturnPass.cpp
new file mode 100644
index 00000000000000..5b64dc1da2f01f
--- /dev/null
+++ b/bolt/lib/Passes/DiscoverNoReturnPass.cpp
@@ -0,0 +1,84 @@
+//===- bolt/Passes/ReorderSection.cpp - Reordering of section data --------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements DiscoverNoReturnPass class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "bolt/Passes/DiscoverNoReturnPass.h"
+
+using namespace llvm;
+
+namespace opts {
+extern cl::OptionCategory BoltCategory;
+
+static cl::opt<bool> DiscoverNoReturnAnalysis(
+ "discover-no-return",
+ cl::desc("analyze the binary and mark no-return functions"), cl::init(true),
+ cl::cat(BoltCategory), cl::ReallyHidden);
+} // namespace opts
+
+namespace llvm {
+namespace bolt {
+
+Error DiscoverNoReturnPass::runOnFunctions(BinaryContext &BC) {
+ bool Changed;
+ do {
+ Changed = false;
+ for (auto &BFI : BC.getBinaryFunctions()) {
+ auto &Func = BFI.second;
+ bool PrevStat = BC.hasPathToNoReturn(&Func);
+ bool CurStat = traverseFromFunction(&Func, BC);
+ Changed |= (PrevStat != CurStat);
+ }
+ } while (Changed);
+
+ return Error::success();
+}
+
+bool DiscoverNoReturnPass::traverseFromFunction(BinaryFunction *Func,
+ BinaryContext &BC) {
+ // The Function cached before, so return its value
+ if (BC.cachedInNoReturnMap(Func))
+ return BC.hasPathToNoReturn(Func);
+
+ Visited[Func] = true;
+ bool Result = true;
+ bool hasCalls = 0;
+ bool hasReturns = 0;
+ for (auto &BB : *Func) {
+ if (!BB.getNumCalls())
+ continue;
+ for (auto &Inst : BB) {
+ if (BC.MIB->isCall(Inst)) {
+ hasCalls = true;
+ const MCSymbol *TargetSymbol = BC.MIB->getTargetSymbol(Inst);
+ BinaryFunction *TargetFunction = BC.SymbolToFunctionMap[TargetSymbol];
+ if (!Visited.count(TargetFunction))
+ Result &= traverseFromFunction(TargetFunction, BC);
+ }
+ hasReturns |= BC.MIB->isReturn(Inst);
+ }
+ }
+
+ // This functions is represented as a leaf in the call graph and doesn't
+ // have a no-return attribute.
+ if (!hasCalls && hasReturns)
+ Result = false;
+
+ // If the function doens't have a return instruction then it's a
+ // no-return function.
+ if (!hasReturns)
+ Result = true;
+
+ BC.setHasPathToNoReturn(Func, Result);
+ return Result;
+}
+
+} // end namespace bolt
+} // end namespace llvm
diff --git a/bolt/lib/Rewrite/BinaryPassManager.cpp b/bolt/lib/Rewrite/BinaryPassManager.cpp
index b0906041833484..f705e925dd9be9 100644
--- a/bolt/lib/Rewrite/BinaryPassManager.cpp
+++ b/bolt/lib/Rewrite/BinaryPassManager.cpp
@@ -13,6 +13,7 @@
#include "bolt/Passes/AsmDump.h"
#include "bolt/Passes/CMOVConversion.h"
#include "bolt/Passes/ContinuityStats.h"
+#include "bolt/Passes/DiscoverNoReturnPass.h"
#include "bolt/Passes/FixRISCVCallsPass.h"
#include "bolt/Passes/FixRelaxationPass.h"
#include "bolt/Passes/FrameOptimizer.h"
@@ -443,6 +444,7 @@ Error BinaryFunctionPassManager::runAllPasses(BinaryContext &BC) {
Manager.registerPass(std::make_unique<CMOVConversion>(),
opts::CMOVConversionFlag);
+ Manager.registerPass(std::make_unique<DiscoverNoReturnPass>());
// This pass syncs local branches with CFG. If any of the following
// passes breaks the sync - they either need to re-run the pass or
``````````
</details>
https://github.com/llvm/llvm-project/pull/115616
More information about the llvm-commits
mailing list