[llvm] [Bolt] Teach bolt about no-return functions (PR #115616)

via llvm-commits llvm-commits at lists.llvm.org
Sat Nov 9 10:46:01 PST 2024


https://github.com/elhewaty created https://github.com/llvm/llvm-project/pull/115616

None

>From 69e8ed4cd6c8a518aa42c55a6368d6820ae3ca1b Mon Sep 17 00:00:00 2001
From: Mohamed Atef <mohamedatef1698 at gmail.com>
Date: Sat, 9 Nov 2024 20:00:34 +0200
Subject: [PATCH] [Bolt] Teach bolt about no-return functions

---
 bolt/include/bolt/Core/BinaryContext.h        | 14 ++++
 .../bolt/Passes/DiscoverNoReturnPass.h        | 36 ++++++++
 bolt/lib/Core/BinaryContext.cpp               | 14 ++++
 bolt/lib/Passes/CMakeLists.txt                |  1 +
 bolt/lib/Passes/DiscoverNoReturnPass.cpp      | 84 +++++++++++++++++++
 bolt/lib/Rewrite/BinaryPassManager.cpp        |  2 +
 6 files changed, 151 insertions(+)
 create mode 100644 bolt/include/bolt/Passes/DiscoverNoReturnPass.h
 create mode 100644 bolt/lib/Passes/DiscoverNoReturnPass.cpp

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



More information about the llvm-commits mailing list