-
Notifications
You must be signed in to change notification settings - Fork 15.3k
[Bolt] Teach bolt about no-return functions #115616
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [nit] |
||
| 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. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| //===- bolt/Passes/Discover.h -----------------------------------*- C++ -*-===// | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [nit] Invalid file name in the comment. |
||
| // | ||
| // 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 | ||
|
Comment on lines
+9
to
+10
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [nit] Defined name is out of sync with the file name. |
||
|
|
||
| #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 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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(); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder if |
||
| FuncName == "__cxa_throw@PLT" || FuncName != "_Unwind_Resume@PLT" || | ||
| FuncName == "__cxa_rethrow@PLT" || FuncName != "exit@PLT" || | ||
| FuncName == "abort@PLT" || FuncName == "setjmp@PLT" || | ||
| FuncName == "longjmp@PLT") | ||
| return true; | ||
|
Comment on lines
+314
to
+319
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
|
||
| auto itr = CallsNoReturnFunction.find(Func); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [nit] |
||
| return itr != CallsNoReturnFunction.end() && itr->second; | ||
| } | ||
|
|
||
| bool BinaryContext::forceSymbolRelocations(StringRef SymbolName) const { | ||
| if (opts::HotText && | ||
| (SymbolName == "__hot_start" || SymbolName == "__hot_end")) | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,84 @@ | ||||||||||
| //===- bolt/Passes/ReorderSection.cpp - Reordering of section data --------===// | ||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [nit] Wrong file name in the comment. |
||||||||||
| // | ||||||||||
| // 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); | ||||||||||
|
Comment on lines
+35
to
+36
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [nit] Was "State" intended here instead of "Stat"? |
||||||||||
| 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; | ||||||||||
|
Comment on lines
+52
to
+53
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [nit]
Suggested change
|
||||||||||
| 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)) | ||||||||||
|
Comment on lines
+60
to
+62
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. TargetFuntion needs to be checked for nullptr |
||||||||||
| 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; | ||||||||||
|
Comment on lines
+71
to
+77
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Tailcalls should also be taken into account ( |
||||||||||
|
|
||||||||||
| BC.setHasPathToNoReturn(Func, Result); | ||||||||||
| return Result; | ||||||||||
| } | ||||||||||
|
|
||||||||||
| } // end namespace bolt | ||||||||||
| } // end namespace llvm | ||||||||||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, it looks like LLVM Programmer's Manual advises against the usage of
std::unordered_map, though there are several tens of occurrences even in the existing code underllvm/lib. The same inDiscoverNoReturnPass.hbelow.