diff --git a/include/revng/EarlyFunctionAnalysis/CollectFunctionsFromCalleesPass.h b/include/revng/EarlyFunctionAnalysis/CollectFunctionsFromCalleesPass.h index 79b7cffe7..5b16053b3 100644 --- a/include/revng/EarlyFunctionAnalysis/CollectFunctionsFromCalleesPass.h +++ b/include/revng/EarlyFunctionAnalysis/CollectFunctionsFromCalleesPass.h @@ -18,11 +18,7 @@ public: public: CollectFunctionsFromCalleesWrapperPass() : llvm::ModulePass(ID) {} - void getAnalysisUsage(llvm::AnalysisUsage &AU) const override final { - AU.setPreservesAll(); - AU.addRequired(); - AU.addRequired(); - } + void getAnalysisUsage(llvm::AnalysisUsage &AU) const override final; public: bool runOnModule(llvm::Module &M) override final; diff --git a/include/revng/EarlyFunctionAnalysis/CollectFunctionsFromUnusedAddressesPass.h b/include/revng/EarlyFunctionAnalysis/CollectFunctionsFromUnusedAddressesPass.h index faa9b67d1..38bcb76b0 100644 --- a/include/revng/EarlyFunctionAnalysis/CollectFunctionsFromUnusedAddressesPass.h +++ b/include/revng/EarlyFunctionAnalysis/CollectFunctionsFromUnusedAddressesPass.h @@ -18,11 +18,7 @@ public: public: CollectFunctionsFromUnusedAddressesWrapperPass() : llvm::ModulePass(ID) {} - void getAnalysisUsage(llvm::AnalysisUsage &AU) const override final { - AU.setPreservesAll(); - AU.addRequired(); - AU.addRequired(); - } + void getAnalysisUsage(llvm::AnalysisUsage &AU) const override final; public: bool runOnModule(llvm::Module &M) override final; diff --git a/include/revng/EarlyFunctionAnalysis/FunctionMetadataCache.h b/include/revng/EarlyFunctionAnalysis/FunctionMetadataCache.h new file mode 100644 index 000000000..9d514b4fc --- /dev/null +++ b/include/revng/EarlyFunctionAnalysis/FunctionMetadataCache.h @@ -0,0 +1,156 @@ +#pragma once + +// +// This file is distributed under the MIT License. See LICENSE.md for details. +// + +#include "llvm/IR/Instructions.h" +#include "llvm/IR/PassManager.h" + +#include "revng/EarlyFunctionAnalysis/FunctionMetadata.h" +#include "revng/Model/Binary.h" +#include "revng/Model/IRHelpers.h" +#include "revng/Support/Assert.h" +#include "revng/Support/IRHelpers.h" +#include "revng/Support/MetaAddress.h" +#include "revng/TupleTree/TupleTree.h" + +namespace detail { + +inline TupleTree +extractFunctionMetadata(llvm::MDNode *MD) { + using namespace llvm; + + efa::FunctionMetadata FM; + const MDOperand &Op = MD->getOperand(0); + revng_assert(MD != nullptr && isa(Op)); + + StringRef YAMLString = cast(Op)->getString(); + auto MaybeParsed = TupleTree::deserialize(YAMLString); + revng_assert(MaybeParsed); + MaybeParsed->verify(); + return std::move(MaybeParsed.get()); +} + +inline TupleTree +extractFunctionMetadata(const llvm::Function *F) { + auto *MDNode = F->getMetadata(FunctionMetadataMDName); + return detail::extractFunctionMetadata(MDNode); +} + +inline TupleTree +extractFunctionMetadata(const llvm::BasicBlock *BB) { + auto *MDNode = BB->getTerminator()->getMetadata(FunctionMetadataMDName); + return detail::extractFunctionMetadata(MDNode); +} + +} // namespace detail + +class FunctionMetadataCache { +private: + std::map FunctionCache; + +public: + const efa::FunctionMetadata & + getFunctionMetadata(const llvm::Function *Function) { + if (auto Iter = FunctionCache.find(Function); Iter == FunctionCache.end()) { + efa::FunctionMetadata FM = *detail::extractFunctionMetadata(Function) + .get(); + FunctionCache.try_emplace(Function, FM); + } + + return FunctionCache.find(Function)->second; + } + + const efa::FunctionMetadata &getFunctionMetadata(const llvm::BasicBlock *BB) { + if (auto Iter = FunctionCache.find(BB); Iter == FunctionCache.end()) { + efa::FunctionMetadata FM = *detail::extractFunctionMetadata(BB).get(); + FunctionCache.try_emplace(BB, FM); + } + + return FunctionCache.find(BB)->second; + } + + /// \brief Given a Call instruction and the model type of its parent function, + /// return the edge on the model that represents that call + /// (std::nullopt if this doesn't exist) and the MetaAddress associated + /// to the call-site. + inline std::pair, MetaAddress> + getCallEdge(const model::Binary &Binary, const llvm::CallInst *Call) { + using namespace llvm; + + MetaAddress BlockAddress = getMetaAddressMetadata(Call, + CallerBlockStartMDName); + if (BlockAddress.isInvalid()) + return { std::nullopt, BlockAddress }; + + auto *ParentFunction = Call->getParent()->getParent(); + const efa::FunctionMetadata &FM = getFunctionMetadata(ParentFunction); + const efa::BasicBlock &Block = FM.ControlFlowGraph.at(BlockAddress); + + // Find the call edge + efa::CallEdge *ModelCall = nullptr; + for (auto &Edge : Block.Successors) { + if (auto *CE = dyn_cast(Edge.get())) { + revng_assert(ModelCall == nullptr); + ModelCall = CE; + } + } + revng_assert(ModelCall != nullptr); + + return { *ModelCall, Block.Start }; + } + + /// \return the prototype associated to a CallInst. + /// + /// \note If the model type of the parent function is not provided, this will + /// be + /// deduced using the Call instruction's parent function. + /// + /// \note If the callsite has no associated prototype, e.g. the called + /// functions + /// is not an isolated function, a null pointer is returned. + inline model::TypePath + getCallSitePrototype(const model::Binary &Binary, + const llvm::CallInst *Call, + const model::Function *ParentFunction = nullptr) { + if (not ParentFunction) + ParentFunction = llvmToModelFunction(Binary, *Call->getFunction()); + + if (not ParentFunction) + return {}; + + const auto &[Edge, BlockAddress] = getCallEdge(Binary, Call); + if (not Edge) + return {}; + + return getPrototype(Binary, ParentFunction->Entry, BlockAddress, *Edge); + } +}; + +class FunctionMetadataCachePass : public llvm::ImmutablePass { +public: + static char ID; + +private: + FunctionMetadataCache Cache; + +public: + FunctionMetadataCachePass() : llvm::ImmutablePass(ID) {} + FunctionMetadataCache &get() { return Cache; } +}; + +class FunctionMetadataCacheAnalysis + : public llvm::AnalysisInfoMixin { + friend llvm::AnalysisInfoMixin; + +private: + FunctionMetadataCache Cache; + static llvm::AnalysisKey Key; + +public: + using Result = FunctionMetadataCache; + +public: + FunctionMetadataCache *runOnModule(llvm::Module &M) { return &Cache; } +}; diff --git a/include/revng/EarlyFunctionAnalysis/IRHelpers.h b/include/revng/EarlyFunctionAnalysis/IRHelpers.h deleted file mode 100644 index 175d2a1f7..000000000 --- a/include/revng/EarlyFunctionAnalysis/IRHelpers.h +++ /dev/null @@ -1,100 +0,0 @@ -#pragma once - -// -// This file is distributed under the MIT License. See LICENSE.md for details. -// - -#include "llvm/IR/Instructions.h" - -#include "revng/EarlyFunctionAnalysis/FunctionMetadata.h" -#include "revng/Model/Binary.h" -#include "revng/Model/IRHelpers.h" -#include "revng/Support/Assert.h" -#include "revng/Support/IRHelpers.h" -#include "revng/Support/MetaAddress.h" -#include "revng/TupleTree/TupleTree.h" - -namespace detail { - -inline TupleTree -extractFunctionMetadata(llvm::MDNode *MD) { - using namespace llvm; - - efa::FunctionMetadata FM; - const MDOperand &Op = MD->getOperand(0); - revng_assert(MD != nullptr && isa(Op)); - - StringRef YAMLString = cast(Op)->getString(); - auto MaybeParsed = TupleTree::deserialize(YAMLString); - revng_assert(MaybeParsed); - MaybeParsed->verify(); - return std::move(MaybeParsed.get()); -} - -} // namespace detail - -inline TupleTree -extractFunctionMetadata(const llvm::Function *F) { - auto *MDNode = F->getMetadata(FunctionMetadataMDName); - return detail::extractFunctionMetadata(MDNode); -} - -inline TupleTree -extractFunctionMetadata(llvm::BasicBlock *BB) { - auto *MDNode = BB->getTerminator()->getMetadata(FunctionMetadataMDName); - return detail::extractFunctionMetadata(MDNode); -} - -/// \brief Given a Call instruction and the model type of its parent function, -/// return the edge on the model that represents that call (std::nullopt -/// if this doesn't exist) and the MetaAddress associated to the -/// call-site. -inline std::pair, MetaAddress> -getCallEdge(const model::Binary &Binary, const llvm::CallInst *Call) { - using namespace llvm; - - MetaAddress BlockAddress = getMetaAddressMetadata(Call, - CallerBlockStartMDName); - if (BlockAddress.isInvalid()) - return { std::nullopt, BlockAddress }; - - auto *ParentFunction = Call->getParent()->getParent(); - efa::FunctionMetadata FM = *extractFunctionMetadata(ParentFunction).get(); - efa::BasicBlock Block = FM.ControlFlowGraph.at(BlockAddress); - - // Find the call edge - efa::CallEdge *ModelCall = nullptr; - for (auto &Edge : Block.Successors) { - if (auto *CE = dyn_cast(Edge.get())) { - revng_assert(ModelCall == nullptr); - ModelCall = CE; - } - } - revng_assert(ModelCall != nullptr); - - return { *ModelCall, Block.Start }; -} - -/// \return the prototype associated to a CallInst. -/// -/// \note If the model type of the parent function is not provided, this will be -/// deduced using the Call instruction's parent function. -/// -/// \note If the callsite has no associated prototype, e.g. the called functions -/// is not an isolated function, a null pointer is returned. -inline model::TypePath -getCallSitePrototype(const model::Binary &Binary, - const llvm::CallInst *Call, - const model::Function *ParentFunction = nullptr) { - if (not ParentFunction) - ParentFunction = llvmToModelFunction(Binary, *Call->getFunction()); - - if (not ParentFunction) - return {}; - - const auto &[Edge, BlockAddress] = getCallEdge(Binary, Call); - if (not Edge) - return {}; - - return getPrototype(Binary, ParentFunction->Entry, BlockAddress, *Edge); -} diff --git a/include/revng/EarlyFunctionAnalysis/LoadFunctionMetadataPass.h b/include/revng/EarlyFunctionAnalysis/LoadFunctionMetadataPass.h deleted file mode 100644 index 65bad75aa..000000000 --- a/include/revng/EarlyFunctionAnalysis/LoadFunctionMetadataPass.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -// -// This file is distributed under the MIT License. See LICENSE.md for details. -// - -#include "llvm/Pass.h" - -class LoadFunctionMetadataPass : public llvm::ModulePass { -public: - const efa::FunctionMetadata &get(llvm::Function *F); - -private: - std::map EntryToMetadata; - -public: - static char ID; - -public: - LoadFunctionMetadataPass() : llvm::ModulePass(ID) {} - - void getAnalysisUsage(llvm::AnalysisUsage &AU) const override { - AU.setPreservesAll(); - } - - bool runOnModule(llvm::Module &M) override; -}; diff --git a/include/revng/FunctionIsolation/EnforceABI.h b/include/revng/FunctionIsolation/EnforceABI.h index 3a0273b6a..3f586e619 100644 --- a/include/revng/FunctionIsolation/EnforceABI.h +++ b/include/revng/FunctionIsolation/EnforceABI.h @@ -19,9 +19,5 @@ public: bool runOnModule(llvm::Module &M) override; - void getAnalysisUsage(llvm::AnalysisUsage &AU) const override { - AU.addRequired(); - AU.addRequired(); - AU.setPreservesAll(); - } + void getAnalysisUsage(llvm::AnalysisUsage &AU) const override; }; diff --git a/include/revng/FunctionIsolation/IsolateFunctions.h b/include/revng/FunctionIsolation/IsolateFunctions.h index 68d77fb3e..a13391b59 100644 --- a/include/revng/FunctionIsolation/IsolateFunctions.h +++ b/include/revng/FunctionIsolation/IsolateFunctions.h @@ -20,9 +20,5 @@ public: bool runOnModule(llvm::Module &M) override; - void getAnalysisUsage(llvm::AnalysisUsage &AU) const override { - AU.setPreservesAll(); - AU.addRequired(); - AU.addRequired(); - } + void getAnalysisUsage(llvm::AnalysisUsage &AU) const override; }; diff --git a/include/revng/Pipes/LLVMAnalysisImplementation.h b/include/revng/Pipes/LLVMAnalysisImplementation.h index a6fdde454..6e9c2f865 100644 --- a/include/revng/Pipes/LLVMAnalysisImplementation.h +++ b/include/revng/Pipes/LLVMAnalysisImplementation.h @@ -6,6 +6,7 @@ #include "llvm/IR/LegacyPassManager.h" +#include "revng/EarlyFunctionAnalysis/FunctionMetadataCache.h" #include "revng/Model/LoadModelPass.h" #include "revng/Pipeline/Context.h" #include "revng/Pipeline/LLVMContainer.h" @@ -44,6 +45,7 @@ public: llvm::legacy::PassManager &Manager) const { auto Global = llvm::cantFail(Ctx.getGlobal(ModelGlobalName)); Manager.add(new LoadModelWrapperPass(ModelWrapper(Global->get()))); + Manager.add(new FunctionMetadataCachePass()); (Manager.add(new Passes()), ...); }; }; diff --git a/lib/EarlyFunctionAnalysis/CMakeLists.txt b/lib/EarlyFunctionAnalysis/CMakeLists.txt index b1fd6ec6d..8312f8443 100644 --- a/lib/EarlyFunctionAnalysis/CMakeLists.txt +++ b/lib/EarlyFunctionAnalysis/CMakeLists.txt @@ -16,7 +16,7 @@ revng_add_analyses_library_internal( FunctionMetadata.cpp FunctionSummaryOracle.cpp IndirectBranchInfoPrinterPass.cpp - LoadFunctionMetadataPass.cpp + FunctionMetadataCache.cpp Outliner.cpp PromoteGlobalToLocalVars.cpp SegregateDirectStackAccesses.cpp diff --git a/lib/EarlyFunctionAnalysis/CollectFunctionsFromCalleesPass.cpp b/lib/EarlyFunctionAnalysis/CollectFunctionsFromCalleesPass.cpp index 848fa96b2..713b2a983 100644 --- a/lib/EarlyFunctionAnalysis/CollectFunctionsFromCalleesPass.cpp +++ b/lib/EarlyFunctionAnalysis/CollectFunctionsFromCalleesPass.cpp @@ -8,6 +8,7 @@ #include "llvm/IR/Module.h" #include "revng/EarlyFunctionAnalysis/CollectFunctionsFromCalleesPass.h" +#include "revng/EarlyFunctionAnalysis/FunctionMetadataCache.h" using namespace llvm; @@ -21,6 +22,14 @@ static Register Y("collect-functions-from-callees", static Logger<> Log("functions-from-callees-collection"); +using CFFCWP = CollectFunctionsFromCalleesWrapperPass; +void CFFCWP::getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesAll(); + AU.addRequired(); + AU.addRequired(); + AU.addRequired(); +} + static void collectFunctionsFromCallees(Module &M, GeneratedCodeBasicInfo &GCBI, model::Binary &Binary) { diff --git a/lib/EarlyFunctionAnalysis/CollectFunctionsFromUnusedAddressesPass.cpp b/lib/EarlyFunctionAnalysis/CollectFunctionsFromUnusedAddressesPass.cpp index 1bd177b43..b9a27c029 100644 --- a/lib/EarlyFunctionAnalysis/CollectFunctionsFromUnusedAddressesPass.cpp +++ b/lib/EarlyFunctionAnalysis/CollectFunctionsFromUnusedAddressesPass.cpp @@ -8,7 +8,7 @@ #include "llvm/IR/Module.h" #include "revng/EarlyFunctionAnalysis/CollectFunctionsFromUnusedAddressesPass.h" -#include "revng/EarlyFunctionAnalysis/IRHelpers.h" +#include "revng/EarlyFunctionAnalysis/FunctionMetadataCache.h" using CFFUAWrapperPass = CollectFunctionsFromUnusedAddressesWrapperPass; char CFFUAWrapperPass::ID = 0; @@ -28,11 +28,64 @@ public: model::Binary &Binary) : M(M), GCBI(GCBI), Binary(Binary) {} - void run(); + void run(FunctionMetadataCache &MDCache) { + loadAllCFGs(MDCache); + collectFunctionsFromUnusedAddresses(); + } private: - void loadAllCFGs(); - void collectFunctionsFromUnusedAddresses(); + void loadAllCFGs(FunctionMetadataCache &MDCache) { + for (auto &Function : Binary.Functions) { + llvm::BasicBlock *Entry = GCBI.getBlockAt(Function.Entry); + llvm::Instruction *Term = Entry->getTerminator(); + auto *FMMDNode = Term->getMetadata(FunctionMetadataMDName); + // CFG not serialized for this function? Skip it + if (not FMMDNode) + continue; + + const efa::FunctionMetadata &FM = MDCache.getFunctionMetadata(Entry); + for (const efa::BasicBlock &Block : FM.ControlFlowGraph) + VisitedBlocks.insert(Block.Start); + } + } + + void collectFunctionsFromUnusedAddresses() { + using namespace llvm; + Function &Root = *M.getFunction("root"); + + for (BasicBlock &BB : Root) { + if (getType(&BB) != BlockType::JumpTargetBlock) + continue; + + MetaAddress Entry = GCBI.getJumpTarget(&BB); + if (Binary.Functions.find(Entry) != Binary.Functions.end()) + continue; + + uint32_t Reasons = GCBI.getJTReasons(&BB); + bool IsUnusedGlobalData = hasReason(Reasons, JTReason::UnusedGlobalData); + bool IsMemoryStore = hasReason(Reasons, JTReason::MemoryStore); + bool IsPCStore = hasReason(Reasons, JTReason::PCStore); + bool IsReturnAddress = hasReason(Reasons, JTReason::ReturnAddress); + bool IsLoadAddress = hasReason(Reasons, JTReason::LoadAddress); + bool IsNotPartOfOtherCFG = VisitedBlocks.count(Entry) == 0; + + // Do not consider addresses found in .rodata that are part of jump + // tables of a function. + if (not IsLoadAddress + and (IsUnusedGlobalData + or (IsMemoryStore and not IsPCStore and not IsReturnAddress)) + and IsNotPartOfOtherCFG) { + // TODO: keep IsReturnAddress? + // Consider addresses found in global data that have not been used or + // addresses that are not return addresses and do not end up in the PC + // directly. + Binary.Functions[Entry]; + revng_log(Log, + "Found function from unused addresses: " + << BB.getName().str()); + } + } + } private: llvm::Module &M; @@ -41,69 +94,12 @@ private: SortedVector VisitedBlocks; }; -void CFFUAImpl::loadAllCFGs() { - for (auto &Function : Binary.Functions) { - llvm::BasicBlock *Entry = GCBI.getBlockAt(Function.Entry); - llvm::Instruction *Term = Entry->getTerminator(); - auto *FMMDNode = Term->getMetadata(FunctionMetadataMDName); - // CFG not serialized for this function? Skip it - if (not FMMDNode) - continue; - - efa::FunctionMetadata FM = *extractFunctionMetadata(Entry).get(); - for (const efa::BasicBlock &Block : FM.ControlFlowGraph) - VisitedBlocks.insert(Block.Start); - } -} - -void CFFUAImpl::collectFunctionsFromUnusedAddresses() { - using namespace llvm; - Function &Root = *M.getFunction("root"); - - for (BasicBlock &BB : Root) { - if (getType(&BB) != BlockType::JumpTargetBlock) - continue; - - MetaAddress Entry = GCBI.getJumpTarget(&BB); - if (Binary.Functions.find(Entry) != Binary.Functions.end()) - continue; - - uint32_t Reasons = GCBI.getJTReasons(&BB); - bool IsUnusedGlobalData = hasReason(Reasons, JTReason::UnusedGlobalData); - bool IsMemoryStore = hasReason(Reasons, JTReason::MemoryStore); - bool IsPCStore = hasReason(Reasons, JTReason::PCStore); - bool IsReturnAddress = hasReason(Reasons, JTReason::ReturnAddress); - bool IsLoadAddress = hasReason(Reasons, JTReason::LoadAddress); - bool IsNotPartOfOtherCFG = VisitedBlocks.count(Entry) == 0; - - // Do not consider addresses found in .rodata that are part of jump - // tables of a function. - if (not IsLoadAddress - and (IsUnusedGlobalData - or (IsMemoryStore and not IsPCStore and not IsReturnAddress)) - and IsNotPartOfOtherCFG) { - // TODO: keep IsReturnAddress? - // Consider addresses found in global data that have not been used or - // addresses that are not return addresses and do not end up in the PC - // directly. - Binary.Functions[Entry]; - revng_log(Log, - "Found function from unused addresses: " << BB.getName().str()); - } - } -} - -void CFFUAImpl::run() { - loadAllCFGs(); - collectFunctionsFromUnusedAddresses(); -} - bool CFFUAWrapperPass::runOnModule(llvm::Module &M) { auto &LMWP = getAnalysis().get(); auto &GCBI = getAnalysis().getGCBI(); CFFUAImpl Impl(M, GCBI, *LMWP.getWriteableModel()); - Impl.run(); + Impl.run(getAnalysis().get()); return false; } @@ -117,6 +113,13 @@ CollectFunctionsFromUnusedAddressesPass::run(llvm::Module &M, auto &GCBI = MAM.getResult(M); CFFUAImpl Impl(M, GCBI, *LM->getWriteableModel()); - Impl.run(); + Impl.run(*MAM.getCachedResult(M)); return llvm::PreservedAnalyses::all(); } + +void CFFUAWrapperPass::getAnalysisUsage(llvm::AnalysisUsage &AU) const { + AU.setPreservesAll(); + AU.addRequired(); + AU.addRequired(); + AU.addRequired(); +} diff --git a/lib/EarlyFunctionAnalysis/FunctionMetadataCache.cpp b/lib/EarlyFunctionAnalysis/FunctionMetadataCache.cpp new file mode 100644 index 000000000..03ab4e019 --- /dev/null +++ b/lib/EarlyFunctionAnalysis/FunctionMetadataCache.cpp @@ -0,0 +1,16 @@ +// +// This file is distributed under the MIT License. See LICENSE.md for details. +// + +#include "revng/EarlyFunctionAnalysis/FunctionMetadataCache.h" + +char FunctionMetadataCachePass::ID = '_'; + +llvm::AnalysisKey FunctionMetadataCacheAnalysis::Key; + +static llvm::RegisterPass _("metadata-cache", + "Create metadata cache " + "to be " + "used by later passes", + true, + true); diff --git a/lib/EarlyFunctionAnalysis/LoadFunctionMetadataPass.cpp b/lib/EarlyFunctionAnalysis/LoadFunctionMetadataPass.cpp deleted file mode 100644 index 4faca21fd..000000000 --- a/lib/EarlyFunctionAnalysis/LoadFunctionMetadataPass.cpp +++ /dev/null @@ -1,25 +0,0 @@ -/// \file LoadFunctionMetadataPass.cpp - -// -// This file is distributed under the MIT License. See LICENSE.md for details. -// - -#include "revng/EarlyFunctionAnalysis/IRHelpers.h" -#include "revng/EarlyFunctionAnalysis/LoadFunctionMetadataPass.h" -#include "revng/Model/IRHelpers.h" - -const efa::FunctionMetadata &LoadFunctionMetadataPass::get(llvm::Function *F) { - auto Address = getMetaAddressOfIsolatedFunction(*F); - auto It = EntryToMetadata.find(Address); - if (It == EntryToMetadata.end()) { - efa::FunctionMetadata FM = *extractFunctionMetadata(F).get(); - It = EntryToMetadata.insert(It, { Address, std::move(FM) }); - } - - return It->second; -} - -bool LoadFunctionMetadataPass::runOnModule(llvm::Module &M) { - // Do nothing - return false; -} diff --git a/lib/FunctionIsolation/EnforceABI.cpp b/lib/FunctionIsolation/EnforceABI.cpp index 1435d4127..3feb59e7b 100644 --- a/lib/FunctionIsolation/EnforceABI.cpp +++ b/lib/FunctionIsolation/EnforceABI.cpp @@ -23,7 +23,7 @@ #include "revng/ADT/LazySmallBitVector.h" #include "revng/ADT/SmallMap.h" #include "revng/EarlyFunctionAnalysis/CallEdge.h" -#include "revng/EarlyFunctionAnalysis/IRHelpers.h" +#include "revng/EarlyFunctionAnalysis/FunctionMetadataCache.h" #include "revng/FunctionIsolation/EnforceABI.h" #include "revng/FunctionIsolation/StructInitializers.h" #include "revng/Model/Register.h" @@ -70,14 +70,16 @@ class EnforceABIImpl { public: EnforceABIImpl(Module &M, GeneratedCodeBasicInfo &GCBI, - const model::Binary &Binary) : + const model::Binary &Binary, + FunctionMetadataCache &Cache) : M(M), GCBI(GCBI), FunctionDispatcher(M.getFunction("function_dispatcher")), Context(M.getContext()), Initializers(&M), Binary(Binary), - MetaAddressStruct(MetaAddress::getStruct(&M)) {} + MetaAddressStruct(MetaAddress::getStruct(&M)), + Cache(&Cache) {} void run(); @@ -105,6 +107,7 @@ private: StructInitializers Initializers; const model::Binary &Binary; StructType *MetaAddressStruct; + FunctionMetadataCache *Cache; }; bool EnforceABI::runOnModule(Module &M) { @@ -114,7 +117,10 @@ bool EnforceABI::runOnModule(Module &M) { // const const model::Binary &Binary = *ModelWrapper.getReadOnlyModel().get(); - EnforceABIImpl Impl(M, GCBI, Binary); + EnforceABIImpl Impl(M, + GCBI, + Binary, + getAnalysis().get()); Impl.run(); return false; } @@ -327,7 +333,7 @@ void EnforceABIImpl::handleRegularFunctionCall(CallInst *Call) { Callee = OldToNew.at(Callee); // Identify the corresponding call site in the model - efa::FunctionMetadata FM = *extractFunctionMetadata(CallerFunction).get(); + const efa::FunctionMetadata &FM = Cache->getFunctionMetadata(CallerFunction); const efa::BasicBlock *CallerBlock = FM.findBlock(GCBI, Call->getParent()); revng_assert(CallerBlock != nullptr); @@ -452,3 +458,10 @@ CallInst *EnforceABIImpl::generateCall(IRBuilder<> &Builder, return Result; } + +void EnforceABI::getAnalysisUsage(llvm::AnalysisUsage &AU) const { + AU.addRequired(); + AU.addRequired(); + AU.addRequired(); + AU.setPreservesAll(); +} diff --git a/lib/FunctionIsolation/IsolateFunctions.cpp b/lib/FunctionIsolation/IsolateFunctions.cpp index 8ae297fd6..7201ff606 100644 --- a/lib/FunctionIsolation/IsolateFunctions.cpp +++ b/lib/FunctionIsolation/IsolateFunctions.cpp @@ -35,7 +35,7 @@ #include "revng/EarlyFunctionAnalysis/FunctionEdgeBase.h" #include "revng/EarlyFunctionAnalysis/FunctionSummaryOracle.h" #include "revng/EarlyFunctionAnalysis/Generated/ForwardDecls.h" -#include "revng/EarlyFunctionAnalysis/IRHelpers.h" +#include "revng/EarlyFunctionAnalysis/FunctionMetadataCache.h" #include "revng/EarlyFunctionAnalysis/Outliner.h" #include "revng/FunctionIsolation/IsolateFunctions.h" #include "revng/Model/Binary.h" @@ -180,16 +180,20 @@ private: GlobalVariable *ExceptionSourcePC; GlobalVariable *ExceptionDestinationPC; + FunctionMetadataCache *Cache; + public: IsolateFunctionsImpl(Function *RootFunction, GeneratedCodeBasicInfo &GCBI, - const model::Binary &Binary) : + const model::Binary &Binary, + FunctionMetadataCache &Cache) : RootFunction(RootFunction), TheModule(RootFunction->getParent()), Context(TheModule->getContext()), GCBI(GCBI), Binary(Binary), - Strings(TheModule) {} + Strings(TheModule), + Cache(&Cache) {} public: Function *getLocalFunction(MetaAddress Entry) const { @@ -587,8 +591,7 @@ void IsolateFunctionsImpl::run() { FunctionOutliner Outliner(*TheModule, Binary, GCBI); for (auto &[Entry, F] : IsolatedFunctionsMap) { BasicBlock *OriginalEntryBlock = GCBI.getBlockAt(Entry); - efa::FunctionMetadata FM = *extractFunctionMetadata(OriginalEntryBlock) - .get(); + const auto &FM = Cache->getFunctionMetadata(OriginalEntryBlock); CallIsolatedFunction CallHandler(*this, FM); OutlinedFunction Outlined = Outliner.outline(Entry, &CallHandler); @@ -712,8 +715,18 @@ bool IF::runOnModule(Module &TheModule) { const model::Binary &Binary = *ModelWrapper.getReadOnlyModel(); // Create an object of type IsolateFunctionsImpl and run the pass - IFI Impl(TheModule.getFunction("root"), GCBI, Binary); + IFI Impl(TheModule.getFunction("root"), + GCBI, + Binary, + getAnalysis().get()); Impl.run(); return false; } + +void IsolateFunctions::getAnalysisUsage(llvm::AnalysisUsage &AU) const { + AU.setPreservesAll(); + AU.addRequired(); + AU.addRequired(); + AU.addRequired(); +} diff --git a/lib/Yield/Pipes/AssemblyPipes.cpp b/lib/Yield/Pipes/AssemblyPipes.cpp index 951c0e7c6..90a89620a 100644 --- a/lib/Yield/Pipes/AssemblyPipes.cpp +++ b/lib/Yield/Pipes/AssemblyPipes.cpp @@ -3,7 +3,7 @@ // #include "revng/EarlyFunctionAnalysis/FunctionMetadata.h" -#include "revng/EarlyFunctionAnalysis/IRHelpers.h" +#include "revng/EarlyFunctionAnalysis/FunctionMetadataCache.h" #include "revng/Lift/LoadBinaryPass.h" #include "revng/Model/Binary.h" #include "revng/Pipeline/AllRegistries.h" @@ -42,13 +42,14 @@ void ProcessAssembly::run(pipeline::Context &Context, // This allows it to only be created once. DissassemblyHelper Helper; + FunctionMetadataCache Cache; for (const auto &LLVMFunction : FunctionTags::Isolated.functions(&Module)) { - auto Metadata = extractFunctionMetadata(&LLVMFunction); - auto ModelFunctionIterator = Model->Functions.find(Metadata->Entry); + const auto &Metadata = Cache.getFunctionMetadata(&LLVMFunction); + auto ModelFunctionIterator = Model->Functions.find(Metadata.Entry); revng_assert(ModelFunctionIterator != Model->Functions.end()); const auto &Func = *ModelFunctionIterator; - auto Disassembled = Helper.disassemble(Func, *Metadata, BinaryView, *Model); + auto Disassembled = Helper.disassemble(Func, Metadata, BinaryView, *Model); Output.insert_or_assign(Func.Entry, serializeToString(Disassembled)); } } diff --git a/lib/Yield/Pipes/CallGraphPipes.cpp b/lib/Yield/Pipes/CallGraphPipes.cpp index b5f88a91f..44f29a211 100644 --- a/lib/Yield/Pipes/CallGraphPipes.cpp +++ b/lib/Yield/Pipes/CallGraphPipes.cpp @@ -3,7 +3,7 @@ // #include "revng/EarlyFunctionAnalysis/FunctionMetadata.h" -#include "revng/EarlyFunctionAnalysis/IRHelpers.h" +#include "revng/EarlyFunctionAnalysis/FunctionMetadataCache.h" #include "revng/Model/Binary.h" #include "revng/Pipeline/Location.h" #include "revng/Pipeline/Pipe.h" @@ -32,7 +32,7 @@ void ProcessCallGraph::run(pipeline::Context &Context, // Gather function metadata SortedVector Metadata; for (const auto &LLVMFunction : FunctionTags::Isolated.functions(&Module)) - Metadata.insert(*extractFunctionMetadata(&LLVMFunction)); + Metadata.insert(*::detail::extractFunctionMetadata(&LLVMFunction)); revng_assert(Metadata.size() == Model->Functions.size()); // Gather the relations @@ -117,14 +117,15 @@ void YieldCallGraphSlice::run(pipeline::Context &Context, // Access the llvm module const llvm::Module &Module = TargetList.getModule(); + FunctionMetadataCache Cache; for (const auto &LLVMFunction : FunctionTags::Isolated.functions(&Module)) { - auto Metadata = extractFunctionMetadata(&LLVMFunction); - auto ModelFunctionIterator = Model->Functions.find(Metadata->Entry); + auto &Metadata = Cache.getFunctionMetadata(&LLVMFunction); + auto ModelFunctionIterator = Model->Functions.find(Metadata.Entry); revng_assert(ModelFunctionIterator != Model->Functions.end()); // Slice the graph for the current function and convert it to SVG - Output.insert_or_assign(Metadata->Entry, - yield::svg::callGraphSlice(Metadata->Entry, + Output.insert_or_assign(Metadata.Entry, + yield::svg::callGraphSlice(Metadata.Entry, Relations, *Model)); } diff --git a/tools/efa/extractcfg/DecoratedFunction.h b/tools/efa/extractcfg/DecoratedFunction.h index ae64db4ec..6119a1679 100644 --- a/tools/efa/extractcfg/DecoratedFunction.h +++ b/tools/efa/extractcfg/DecoratedFunction.h @@ -4,7 +4,7 @@ // This file is distributed under the MIT License. See LICENSE.md for details. // -#include "revng/EarlyFunctionAnalysis/IRHelpers.h" +#include "revng/EarlyFunctionAnalysis/FunctionMetadataCache.h" #include "revng/Support/MetaAddress.h" #include "revng/Support/MetaAddress/YAMLTraits.h" #include "revng/Support/YAMLTraits.h" diff --git a/tools/efa/extractcfg/Main.cpp b/tools/efa/extractcfg/Main.cpp index 9b0e0d3d7..dc90952af 100644 --- a/tools/efa/extractcfg/Main.cpp +++ b/tools/efa/extractcfg/Main.cpp @@ -9,7 +9,7 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/MemoryBuffer.h" -#include "revng/EarlyFunctionAnalysis/IRHelpers.h" +#include "revng/EarlyFunctionAnalysis/FunctionMetadataCache.h" #include "revng/Model/ToolHelpers.h" #include "revng/Support/IRHelpers.h" #include "revng/Support/InitRevng.h" @@ -54,6 +54,7 @@ int main(int argc, const char **argv) { auto *RootFunction = Module->getFunction("root"); revng_assert(RootFunction != nullptr); + FunctionMetadataCache Cache; if (not RootFunction->isDeclaration()) { for (BasicBlock &BB : *Module->getFunction("root")) { llvm::Instruction *Term = BB.getTerminator(); @@ -61,7 +62,7 @@ int main(int argc, const char **argv) { if (not FMMDNode) continue; - efa::FunctionMetadata FM = *extractFunctionMetadata(&BB).get(); + const efa::FunctionMetadata &FM = Cache.getFunctionMetadata(&BB); auto &Function = Model->Functions.at(FM.Entry); revng::DecoratedFunction NewFunction(FM.Entry, Function.OriginalName, @@ -73,7 +74,7 @@ int main(int argc, const char **argv) { for (Function &F : FunctionTags::Isolated.functions(Module.get())) { auto *FMMDNode = F.getMetadata(FunctionMetadataMDName); - efa::FunctionMetadata FM = *extractFunctionMetadata(&F).get(); + const efa::FunctionMetadata &FM = Cache.getFunctionMetadata(&F); if (not FMMDNode or DecoratedFunctions.count(FM.Entry) != 0) continue;