From 28ceefcac34e07be17a9408b266bae558917eadf Mon Sep 17 00:00:00 2001 From: Alessandro Di Federico Date: Wed, 6 Mar 2019 18:35:26 +0100 Subject: [PATCH] SA: unify management of CSV indices --- lib/StackAnalysis/ASSlot.h | 6 ++- lib/StackAnalysis/Cache.cpp | 38 +++++++++++++- lib/StackAnalysis/Cache.h | 21 +++++++- lib/StackAnalysis/InterproceduralAnalysis.cpp | 16 +++--- lib/StackAnalysis/InterproceduralAnalysis.h | 2 +- lib/StackAnalysis/Intraprocedural.cpp | 51 +++++-------------- lib/StackAnalysis/Intraprocedural.h | 11 ++-- lib/StackAnalysis/StackAnalysis.cpp | 4 +- 8 files changed, 89 insertions(+), 60 deletions(-) diff --git a/lib/StackAnalysis/ASSlot.h b/lib/StackAnalysis/ASSlot.h index 5e6e1db52..a73cf9af7 100644 --- a/lib/StackAnalysis/ASSlot.h +++ b/lib/StackAnalysis/ASSlot.h @@ -210,7 +210,11 @@ private: QuickMetadata QMD(M->getContext()); Offset = Offset - 2; - const auto &Operand = QMD.extract(Tuple, 4)->getOperand(Offset); + const auto *ABIRegisters = QMD.extract(Tuple, 4); + if (Offset >= static_cast(ABIRegisters->getNumOperands())) + return llvm::Optional(); + + const auto &Operand = ABIRegisters->getOperand(Offset); return QMD.extract(Operand.get()).str(); } }; diff --git a/lib/StackAnalysis/Cache.cpp b/lib/StackAnalysis/Cache.cpp index c8724f46a..b2c550980 100644 --- a/lib/StackAnalysis/Cache.cpp +++ b/lib/StackAnalysis/Cache.cpp @@ -5,9 +5,13 @@ // This file is distributed under the MIT License. See LICENSE.md for details. // +// Local libraries includes +#include "revng/BasicAnalyses/GeneratedCodeBasicInfo.h" + // Local includes #include "Cache.h" +using llvm::AllocaInst; using llvm::BasicBlock; using llvm::BinaryOperator; using llvm::BlockAddress; @@ -299,7 +303,39 @@ void Cache::identifyLinkRegisters(const Module *M) { } } -Cache::Cache(const Function *F) : DefaultLinkRegister(nullptr) { +void Cache::assignCPUIndices(Function *F, GeneratedCodeBasicInfo *GCBI) { + // Enumerate CPU state and allocas + CSVToIndexMap.clear(); + IndexToCSVMap.clear(); + + // Skip 0, keep it as "invalid value" + int32_t I = 1; + + IndexToCSVMap[I++] = GCBI->pcReg(); + + // Go through global variables first + for (llvm::GlobalVariable *GV : GCBI->abiRegisters()) + IndexToCSVMap[I++] = GV; + + CSVCount = I; + + // Look for AllocaInst at the beginning of the root function + llvm::BasicBlock *Entry = &*F->begin(); + auto It = Entry->begin(); + while (It != Entry->end() and isa(&*It)) { + IndexToCSVMap[I] = &*It; + + I++; + It++; + } + + for (auto &P : IndexToCSVMap) + CSVToIndexMap[P.second] = P.first; +} + +Cache::Cache(Function *F, GeneratedCodeBasicInfo *GCBI) : + DefaultLinkRegister(nullptr) { + assignCPUIndices(F, GCBI); identifyPartialStores(F); identifyIdentityLoads(F); identifyLinkRegisters(F->getParent()); diff --git a/lib/StackAnalysis/Cache.h b/lib/StackAnalysis/Cache.h index fd60283cf..121f94a61 100644 --- a/lib/StackAnalysis/Cache.h +++ b/lib/StackAnalysis/Cache.h @@ -5,6 +5,8 @@ #include "Element.h" #include "IntraproceduralFunctionSummary.h" +class GeneratedCodeBasicInfo; + namespace StackAnalysis { /// \brief Cache for the result of the analysis of a function @@ -33,9 +35,25 @@ private: std::set IdentityLoads; std::set IdentityStores; + std::map CSVToIndexMap; + std::map IndexToCSVMap; + int32_t CSVCount; + public: /// \brief Identify default storage for link register, identity loads - Cache(const llvm::Function *F); + Cache(llvm::Function *F, GeneratedCodeBasicInfo *GCBI); + + int32_t getCPUIndex(const llvm::User *U) const { return CSVToIndexMap.at(U); } + bool isCPU(const llvm::User *U) const { return CSVToIndexMap.count(U) != 0; } + bool isCSV(const llvm::User *U) const { + return CSVToIndexMap.count(U) != 0 and CSVToIndexMap.at(U) < CSVCount; + } + llvm::GlobalVariable *getCSVByIndex(int32_t I) const { + return llvm::cast(IndexToCSVMap.at(I)); + } + bool isCSVIndex(int32_t I) const { + return IndexToCSVMap.count(I) != 0 and I < CSVCount; + } bool isFakeFunction(llvm::BasicBlock *Function) const { return FakeFunctions.count(Function) != 0; @@ -107,6 +125,7 @@ public: } private: + void assignCPUIndices(llvm::Function *F, GeneratedCodeBasicInfo *GCBI); void identifyPartialStores(const llvm::Function *F); void identifyIdentityLoads(const llvm::Function *F); void identifyLinkRegisters(const llvm::Module *M); diff --git a/lib/StackAnalysis/InterproceduralAnalysis.cpp b/lib/StackAnalysis/InterproceduralAnalysis.cpp index 39da0d961..dde64fd9e 100644 --- a/lib/StackAnalysis/InterproceduralAnalysis.cpp +++ b/lib/StackAnalysis/InterproceduralAnalysis.cpp @@ -585,16 +585,9 @@ struct ClobberedRegistersAnalysis { } }; -FunctionsSummary ResultsPool::finalize(Module *M) { +FunctionsSummary ResultsPool::finalize(Module *M, Cache *TheCache) { ASID CPU = ASID::cpuID(); - // Build a map from indices used in the stack analysis to the corresponding - // CSVs - std::vector IndexToCSV; - IndexToCSV.push_back(nullptr); - for (GlobalVariable &CSV : M->globals()) - IndexToCSV.push_back(&CSV); - // Create the result data structure FunctionsSummary Result; @@ -608,7 +601,7 @@ FunctionsSummary ResultsPool::finalize(Module *M) { for (auto &P : Clobbered) { auto &Function = Result.Functions[P.first]; for (int32_t Offset : P.second) - Function.ClobberedRegisters.insert(IndexToCSV.at(Offset)); + Function.ClobberedRegisters.insert(TheCache->getCSVByIndex(Offset)); } // Register block types @@ -696,7 +689,10 @@ FunctionsSummary ResultsPool::finalize(Module *M) { for (ASSlot Slot : FCS.Slots) { revng_assert(Slot.addressSpace() == CPU); int32_t Offset = Slot.offset(); - GlobalVariable *CSV = IndexToCSV.at(Offset); + if (not TheCache->isCSVIndex(Offset)) + continue; + + GlobalVariable *CSV = TheCache->getCSVByIndex(Offset); FunctionSlot TheFunctionSlot{ FunctionEntry, Offset }; bool CalleeHasSlot = FRA.count(TheFunctionSlot) != 0; diff --git a/lib/StackAnalysis/InterproceduralAnalysis.h b/lib/StackAnalysis/InterproceduralAnalysis.h index 3b5257138..c1631d02a 100644 --- a/lib/StackAnalysis/InterproceduralAnalysis.h +++ b/lib/StackAnalysis/InterproceduralAnalysis.h @@ -120,7 +120,7 @@ public: /// \brief Finalized the data stored in this object and produce a /// FunctionsSummary - FunctionsSummary finalize(llvm::Module *M); + FunctionsSummary finalize(llvm::Module *M, Cache *TheCache); void dump(const llvm::Module *M) const debug_function { dump(M, dbg); } diff --git a/lib/StackAnalysis/Intraprocedural.cpp b/lib/StackAnalysis/Intraprocedural.cpp index b8c233885..fdc23cc14 100644 --- a/lib/StackAnalysis/Intraprocedural.cpp +++ b/lib/StackAnalysis/Intraprocedural.cpp @@ -68,32 +68,6 @@ void Analysis::initialize() { revng_log(SaLog, "Creating Analysis for " << getName(Entry)); - // Enumerate CPU state and allocas - { - CPUIndices.clear(); - - // Skip 0, keep it as "invalid value" - int32_t I = 1; - - CPUIndices[GCBI->pcReg()] = I++; - - // Go through global variables first - for (const llvm::GlobalVariable *GV : GCBI->abiRegisters()) - CPUIndices[GV] = I++; - - CSVCount = I; - - // Look for AllocaInst at the beginning of the root function - const llvm::BasicBlock *Entry = &*M->getFunction("root")->begin(); - auto It = Entry->begin(); - while (It != Entry->end() and isa(&*It)) { - CPUIndices[&*It] = I; - - I++; - It++; - } - } - TerminatorInst *T = Entry->getTerminator(); revng_assert(T != nullptr); @@ -104,9 +78,9 @@ void Analysis::initialize() { // and the link register int32_t LinkRegisterIndex = 0; if (LinkRegister != nullptr) - LinkRegisterIndex = CPUIndices.at(LinkRegister); - PCIndex = CPUIndices.at(GCBI->pcReg()); - SPIndex = CPUIndices.at(GCBI->spReg()); + LinkRegisterIndex = TheCache->getCPUIndex(LinkRegister); + PCIndex = TheCache->getCPUIndex(GCBI->pcReg()); + SPIndex = TheCache->getCPUIndex(GCBI->spReg()); // Set the stack pointer to SP0+0 ASSlot StackPointer = ASSlot::create(ASID::cpuID(), SPIndex); @@ -147,18 +121,18 @@ private: ContentMap InstructionContent; ///< Map for the instructions in this BB ContentMap &VariableContent; ///< Reference to map for allocas const DataLayout &DL; - const std::map &CPUIndices; + const Cache *TheCache; public: BasicBlockState(BasicBlock *BB, ContentMap &VariableContent, const DataLayout &DL, - const std::map &CPUIndices) : + const Cache *TheCache) : BB(BB), M(getModule(BB)), VariableContent(VariableContent), DL(DL), - CPUIndices(CPUIndices) {} + TheCache(TheCache) {} /// \brief Gets the Value associated to \p V /// @@ -174,13 +148,12 @@ public: Value get(llvm::Value *V) const { if (auto *CSV = dyn_cast(V)) { - return Value::fromSlot(ASID::cpuID(), CPUIndices.at(CSV)); + return Value::fromSlot(ASID::cpuID(), TheCache->getCPUIndex(CSV)); } else if (auto *CSV = dyn_cast(V)) { - auto It = CPUIndices.find(CSV); - if (It != CPUIndices.end()) - return Value::fromSlot(ASID::cpuID(), It->second); + if (TheCache->isCPU(CSV)) + return Value::fromSlot(ASID::cpuID(), TheCache->getCPUIndex(CSV)); else return Value(); @@ -336,7 +309,7 @@ Interrupt Analysis::transfer(BasicBlock *BB) { // Initialize an object to keep track of the values associated to each // instruction in the current basic block - BasicBlockState BBState(BB, VariableContent, M->getDataLayout(), CPUIndices); + BasicBlockState BBState(BB, VariableContent, M->getDataLayout(), TheCache); for (Instruction &I : *BB) { @@ -964,6 +937,10 @@ Interrupt Analysis::handleCall(Instruction *Caller, } } +ASSlot Analysis::slotFromCSV(llvm::User *U) const { + return ASSlot::create(ASID::cpuID(), TheCache->getCPUIndex(U)); +} + IFS Analysis::createSummary() { // Finalize the ABI IR (e.g., fill-in reverse links) TheABIIR.finalize(); diff --git a/lib/StackAnalysis/Intraprocedural.h b/lib/StackAnalysis/Intraprocedural.h index 4d7133f27..403b30f5c 100644 --- a/lib/StackAnalysis/Intraprocedural.h +++ b/lib/StackAnalysis/Intraprocedural.h @@ -23,6 +23,7 @@ // Local includes #include "ABIIR.h" +#include "Cache.h" #include "Element.h" #include "FunctionABI.h" #include "IntraproceduralFunctionSummary.h" @@ -357,7 +358,6 @@ private: int32_t SPIndex; ///< Offset of the stack pointer CSV int32_t PCIndex; ///< Offset of the PC CSV ABIFunction TheABIIR; ///< The ABI IR - int32_t CSVCount; ///< Number of CSVs, used to distinguish from alloca /// \brief Set of return addresses from fake function calls std::set FakeReturnAddresses; @@ -383,8 +383,6 @@ private: bool AnalyzeABI; - std::map CPUIndices; - public: Analysis(llvm::BasicBlock *Entry, const Cache &TheCache, @@ -407,7 +405,8 @@ public: } bool isCSV(ASSlot Slot) const { - return Slot.addressSpace() == ASID::cpuID() && Slot.offset() < CSVCount; + return (Slot.addressSpace() == ASID::cpuID() + and TheCache->isCSVIndex(Slot.offset())); } void assertLowerThanOrEqual(const Element &A, const Element &B) const { @@ -562,9 +561,7 @@ private: return false; } - ASSlot slotFromCSV(llvm::User *U) const { - return ASSlot::create(ASID::cpuID(), CPUIndices.at(U)); - } + ASSlot slotFromCSV(llvm::User *U) const; }; } // namespace Intraprocedural diff --git a/lib/StackAnalysis/StackAnalysis.cpp b/lib/StackAnalysis/StackAnalysis.cpp index 4dff8ebfd..dc56c41c0 100644 --- a/lib/StackAnalysis/StackAnalysis.cpp +++ b/lib/StackAnalysis/StackAnalysis.cpp @@ -119,7 +119,7 @@ bool StackAnalysis::runOnModule(Module &M) { } // Initialize the cache where all the results will be accumulated - Cache TheCache(&F); + Cache TheCache(&F, &GCBI); // Pool where the final results will be collected ResultsPool Results; @@ -176,7 +176,7 @@ bool StackAnalysis::runOnModule(Module &M) { } std::stringstream Output; - GrandResult = Results.finalize(&M); + GrandResult = Results.finalize(&M, &TheCache); GrandResult.dump(&M, Output); TextRepresentation = Output.str();