From 6a56557177efddc50490133dc0d5acf9ea41ce30 Mon Sep 17 00:00:00 2001 From: Andrea Gussoni Date: Wed, 13 May 2026 14:16:38 +0200 Subject: [PATCH] DetectABI: inline helpers Inline `revng_inline` helper calls into each outlined stub which is consumed by `analyzeABI`, so the analysis can observe the reads and writes the helper performs on the floating point registers. The helper module is linked only once at the beginning of the pass, to avoid double linking issues. --- lib/EarlyFunctionAnalysis/CMakeLists.txt | 1 + lib/EarlyFunctionAnalysis/DetectABI.cpp | 30 +++++++++++++++++++++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/lib/EarlyFunctionAnalysis/CMakeLists.txt b/lib/EarlyFunctionAnalysis/CMakeLists.txt index 1797a0745..603072cfe 100644 --- a/lib/EarlyFunctionAnalysis/CMakeLists.txt +++ b/lib/EarlyFunctionAnalysis/CMakeLists.txt @@ -35,6 +35,7 @@ target_link_libraries( revngEarlyFunctionAnalysis revngBasicAnalyses revngABI + revngInlineHelpers revngSupport revngModel revngPipes diff --git a/lib/EarlyFunctionAnalysis/DetectABI.cpp b/lib/EarlyFunctionAnalysis/DetectABI.cpp index 7fe5a0712..e83eaa1f9 100644 --- a/lib/EarlyFunctionAnalysis/DetectABI.cpp +++ b/lib/EarlyFunctionAnalysis/DetectABI.cpp @@ -30,6 +30,8 @@ #include "revng/EarlyFunctionAnalysis/DetectABI.h" #include "revng/EarlyFunctionAnalysis/FunctionEdgeBase.h" #include "revng/EarlyFunctionAnalysis/FunctionSummaryOracle.h" +#include "revng/InlineHelpers/InlineHelpers.h" +#include "revng/InlineHelpers/LinkHelpersToInline.h" #include "revng/Model/Binary.h" #include "revng/Model/NameBuilder.h" #include "revng/Model/Pass/DeduplicateCollidingNames.h" @@ -107,6 +109,7 @@ public: Manager.add(new LoadModelWrapperPass(ModelWrapper(Global->get()))); Manager.add(new CollectFunctionsFromCalleesWrapperPass()); Manager.add(new ControlFlowGraphCachePass(CFGs)); + Manager.add(new LinkHelpersToInlinePass()); Manager.add(new efa::DetectABIPass()); Manager.add(new CollectFunctionsFromUnusedAddressesWrapperPass()); Manager.add(new efa::DetectABIPass()); @@ -451,7 +454,7 @@ void DetectABI::analyzeABI() { revng_log(Log, "Running ABI analyses"); LoggerIndent Indent(Log); - llvm::Task Task(2, "analyzeABI"); + llvm::Task Task(3, "analyzeABI"); std::map> Functions; // Create all temporary functions @@ -463,6 +466,23 @@ void DetectABI::analyzeABI() { Functions[Function.Entry()] = std::move(NewFunction); } + // Inline `revng_inline`-tagged helper calls so the subsequent ABI dataflow + // analysis can observe the helpers' register reads and writes directly. + // `InlineHelpersPass` only inlines into `Isolated` functions, so we tag the + // outlined stubs as such. These stubs are temporary and are discarded with + // the cloned module once the analysis ends, so the tag never escapes. + // Helpers whose per-call critical arguments are not LLVM constants here + // survive un-inlined and are consumed as opaque calls by the analysis. + for (auto &[Entry, OutlinedFn] : Functions) + FunctionTags::Isolated.addTo(OutlinedFn->Function.get()); + + Task.advance("Inline helpers"); + { + llvm::legacy::PassManager PM; + PM.add(new InlineHelpersPass()); + PM.run(M); + } + // Push this into analyzeFunction OpaqueRegisterUser RegisterUser(&M); @@ -1117,6 +1137,14 @@ llvm::Error DetectABI::run(Model &Model, revng::pipes::CFGMap CFGs(""); ControlFlowGraphCache FMC(CFGs); + // Link helper bodies once at the start of the analysis, to avoid relinking + // for every `inline-helpers` call + { + llvm::legacy::PassManager PM; + PM.add(new LinkHelpersToInlinePass()); + PM.run(Module); + } + collectFunctionsFromCallees(Module, GCBI, Binary); efa::runDetectABI(Module, GCBI, FMC, TupleModel); collectFunctionsFromUnusedAddresses(Module, GCBI, Binary, FMC);