// // This file is distributed under the MIT License. See LICENSE.md for details. // // LLVM includes #include #include #include "llvm/Support/raw_ostream.h" // revng includes #include #include using namespace llvm; static cl::opt EnableDebugOutput("liveness-analysis-debug", cl::desc("Enables debug output for Liveness Analysis")); using LiveSet = UnionMonotoneSet; using LivenessMap = std::map; class LivenessAnalysis : public MonotoneFramework> { private: llvm::Function &F; LivenessMap LiveIn; using PHIPred = std::pair; std::map>> PHIEdges; public: using Base = MonotoneFramework>; void assertLowerThanOrEqual(const LiveSet &A, const LiveSet &B) const { revng_assert(A.lowerThanOrEqual(B)); } LivenessAnalysis(llvm::Function &F) : Base(&F.getEntryBlock()), F(F){ for (BasicBlock &BB : F) { succ_iterator NextSucc = succ_begin(&BB); succ_iterator EndSucc = succ_end(&BB); if (NextSucc == EndSucc) // BB has no successors Base::registerExtremal(&BB); } } void dumpFinalState() const { revng_abort(); } llvm::SmallVector successors(llvm::BasicBlock *BB, InterruptType &) const { llvm::SmallVector Result; for (llvm::BasicBlock *Predecessor : make_range(pred_begin(BB), pred_end(BB))) Result.push_back(Predecessor); return Result; } llvm::Optional handleEdge(const LiveSet &Original, llvm::BasicBlock *Source, llvm::BasicBlock *Destination) const { llvm::Optional Result; auto SrcIt = PHIEdges.find(Source); if (SrcIt == PHIEdges.end()) return Result; const std::set &Pred = SrcIt->second.at(Destination); for (Use *P : Pred) { auto *ThePHI = cast(P->getUser()); auto *LiveI = dyn_cast(P->get()); for (Value *V : ThePHI->incoming_values()) { if (auto *VInstr = dyn_cast(V)) { if (VInstr != LiveI) { // lazily copy the Original only if necessary if (not Result.hasValue()) Result = Original.copy(); Result->erase(VInstr); } } } } return Result; } size_t successor_size(llvm::BasicBlock *BB, InterruptType &) const { return succ_end(BB) - succ_begin(BB); } static LiveSet extremalValue(llvm::BasicBlock *BB) { return LiveSet::bottom(); } const LivenessMap &getLiveIn() { return LiveIn; }; InterruptType transfer(llvm::BasicBlock *BB) { LiveSet LiveInResult = this->State[BB].copy(); if (EnableDebugOutput) { errs() << "\nTransfer on BB:\n"; BB->dump(); errs() << "Initial (Live Out)\n"; for (Instruction *I : LiveInResult) I->dump(); } BasicBlock::reverse_iterator RIt = BB->rbegin(); BasicBlock::reverse_iterator REnd= BB->rend(); for (; RIt != REnd; ++RIt) { Instruction &I = *RIt; if (EnableDebugOutput) { errs() << "Analyzing operands of Instruction:\n"; I.dump(); } if (auto *PHI = dyn_cast(&I)) { if (EnableDebugOutput) { errs() << "Is a PHI\n"; } for (Use &U : PHI->incoming_values()) PHIEdges[BB][PHI->getIncomingBlock(U)].insert(&U); } for (Use &U : I.operands()) { if (EnableDebugOutput) { errs() << "Analyzing operand:\n"; U.get()->dump(); } if (auto *OpInst = dyn_cast(U)) { if (EnableDebugOutput) { errs() << "Add to LiveSet:\n"; OpInst->dump(); } LiveInResult.insert(OpInst); } } if (EnableDebugOutput) { errs() << "Erase Instruction:\n"; I.dump(); } LiveInResult.erase(&I); } if (EnableDebugOutput) { errs() << "\nFinal (Live In)\n"; for (Instruction *I : LiveInResult) I->dump(); } LiveIn[BB] = LiveInResult.copy(); return InterruptType::createInterrupt(std::move(LiveInResult)); } void initialize() { Base::initialize(); LiveIn.clear(); } }; struct LivenessAnalysisPass : public FunctionPass { static char ID; LivenessAnalysisPass() : FunctionPass(ID) {} bool runOnFunction(Function &F) override { std::string FName = F.getName(); errs() << "\nLiveness for Function: " << FName << '\n'; errs() << "/---------------------------\n"; LivenessAnalysis LA(F); LA.initialize(); LA.run(); errs() << "\n Liveness RESULT for Function: " << FName << '\n'; if (EnableDebugOutput) { for (auto &BB2LiveSet : LA.getLiveIn()) { const BasicBlock *BB = BB2LiveSet.first; const LiveSet &LiveIn = BB2LiveSet.second; std::string BBName = BB->getName(); errs() << "BasicBlock:\n"; BB->dump(); errs() << "LiveIn:\n"; for (const Instruction *I : LiveIn) { I->dump(); } } } errs() << "\\---------------------------\n"; return false; } }; char LivenessAnalysisPass::ID = 0; static RegisterPass X("liveness", "Liveness Analysis", false, false);