diff --git a/llvm/include/llvm/Analysis/StackSafetyAnalysis.h b/llvm/include/llvm/Analysis/StackSafetyAnalysis.h index b5589611c8e28..246f44f19f47f 100644 --- a/llvm/include/llvm/Analysis/StackSafetyAnalysis.h +++ b/llvm/include/llvm/Analysis/StackSafetyAnalysis.h @@ -19,6 +19,7 @@ namespace llvm { class AllocaInst; +class ScalarEvolution; /// Interface to access stack safety analysis results for single function. class StackSafetyInfo { @@ -26,30 +27,40 @@ class StackSafetyInfo { struct InfoTy; private: - std::unique_ptr Info; + Function *F = nullptr; + std::function GetSE; + mutable std::unique_ptr Info; public: - StackSafetyInfo(InfoTy Info); + StackSafetyInfo(); + StackSafetyInfo(Function *F, std::function GetSE); StackSafetyInfo(StackSafetyInfo &&); StackSafetyInfo &operator=(StackSafetyInfo &&); ~StackSafetyInfo(); - const InfoTy &getInfo() const { return *Info; } + const InfoTy &getInfo() const; // TODO: Add useful for client methods. - void print(raw_ostream &O, const GlobalValue &F) const; + void print(raw_ostream &O) const; }; class StackSafetyGlobalInfo { public: - using GVToSSI = std::map; + struct InfoTy; private: - GVToSSI SSGI; + Module *M = nullptr; + std::function GetSSI; + mutable std::unique_ptr Info; + const InfoTy &getInfo() const; public: - StackSafetyGlobalInfo() = default; - StackSafetyGlobalInfo(GVToSSI SSGI) : SSGI(std::move(SSGI)) {} + StackSafetyGlobalInfo(); + StackSafetyGlobalInfo( + Module *M, std::function GetSSI); + StackSafetyGlobalInfo(StackSafetyGlobalInfo &&); + StackSafetyGlobalInfo &operator=(StackSafetyGlobalInfo &&); + ~StackSafetyGlobalInfo(); bool setMetadata(Module &M) const; void print(raw_ostream &O) const; @@ -77,14 +88,13 @@ class StackSafetyPrinterPass : public PassInfoMixin { /// StackSafetyInfo wrapper for the legacy pass manager class StackSafetyInfoWrapperPass : public FunctionPass { - Optional SSI; - const Function *F = nullptr; + StackSafetyInfo SSI; public: static char ID; StackSafetyInfoWrapperPass(); - const StackSafetyInfo &getResult() const { return *SSI; } + const StackSafetyInfo &getResult() const { return SSI; } void print(raw_ostream &O, const Module *M) const override; void getAnalysisUsage(AnalysisUsage &AU) const override; @@ -131,6 +141,7 @@ class StackSafetyGlobalInfoWrapperPass : public ModulePass { static char ID; StackSafetyGlobalInfoWrapperPass(); + ~StackSafetyGlobalInfoWrapperPass(); const StackSafetyGlobalInfo &getResult() const { return SSGI; } diff --git a/llvm/lib/Analysis/StackSafetyAnalysis.cpp b/llvm/lib/Analysis/StackSafetyAnalysis.cpp index 15ddea6a957c2..2c8a5e33c847f 100644 --- a/llvm/lib/Analysis/StackSafetyAnalysis.cpp +++ b/llvm/lib/Analysis/StackSafetyAnalysis.cpp @@ -33,8 +33,6 @@ static cl::opt StackSafetyMaxIterations("stack-safety-max-iterations", namespace { -using GVToSSI = StackSafetyGlobalInfo::GVToSSI; - /// Rewrite an SCEV expression for a memory access address to an expression that /// represents offset from the given alloca. class AllocaOffsetRewriter : public SCEVRewriteVisitor { @@ -178,15 +176,17 @@ struct FunctionInfo { } }; +using GVToSSI = std::map; + } // namespace struct StackSafetyInfo::InfoTy { FunctionInfo Info; }; -StackSafetyInfo makeSSI(FunctionInfo Info) { - return StackSafetyInfo(StackSafetyInfo::InfoTy{std::move(Info)}); -} +struct StackSafetyGlobalInfo::InfoTy { + GVToSSI Info; +}; namespace { @@ -430,17 +430,10 @@ class StackSafetyDataFlowAnalysis { void verifyFixedPoint(); #endif - uint32_t findPointerWidth() const { - for (auto &F : Functions) - for (auto &P : F.second.Params) - return P.Range.getBitWidth(); - return 1; - } - public: - explicit StackSafetyDataFlowAnalysis(FunctionMap Functions) + StackSafetyDataFlowAnalysis(uint32_t PointerBitWidth, FunctionMap Functions) : Functions(std::move(Functions)), - UnknownRange(ConstantRange::getFull(findPointerWidth())) {} + UnknownRange(ConstantRange::getFull(PointerBitWidth)) {} const FunctionMap &run(); @@ -560,7 +553,7 @@ bool setStackSafetyMetadata(Module &M, const GVToSSI &SSGI) { auto Iter = SSGI.find(&F); if (Iter == SSGI.end()) continue; - const FunctionInfo &Summary = Iter->second.getInfo().Info; + const FunctionInfo &Summary = Iter->second; size_t Pos = 0; for (auto &I : instructions(F)) { if (auto AI = dyn_cast(&I)) { @@ -623,11 +616,16 @@ GVToSSI createGlobalStackSafetyInfo( for (auto &FI : Copy) ResolveAllCalls(FI.second.Params); - StackSafetyDataFlowAnalysis SSDFA(std::move(Copy)); + uint32_t PointerSize = Copy.begin() + ->first->getParent() + ->getDataLayout() + .getMaxPointerSizeInBits(); + StackSafetyDataFlowAnalysis SSDFA(PointerSize, std::move(Copy)); for (auto &F : SSDFA.run()) { auto FI = F.second; size_t Pos = 0; + auto &SrcF = Functions[F.first]; for (auto &A : FI.Allocas) { ResolveAllCalls(A); for (auto &C : A.Calls) { @@ -635,15 +633,15 @@ GVToSSI createGlobalStackSafetyInfo( SSDFA.getArgumentAccessRange(C.Callee, C.ParamNo, C.Offset)); } // FIXME: This is needed only to preserve calls in print() results. - A.Calls = Functions[F.first].Allocas[Pos].Calls; + A.Calls = SrcF.Allocas[Pos].Calls; ++Pos; } Pos = 0; for (auto &P : FI.Params) { - P.Calls = Functions[F.first].Params[Pos].Calls; + P.Calls = SrcF.Params[Pos].Calls; ++Pos; } - SSI.emplace(F.first, makeSSI(std::move(FI))); + SSI[F.first] = std::move(FI); } return SSI; @@ -651,29 +649,70 @@ GVToSSI createGlobalStackSafetyInfo( } // end anonymous namespace +StackSafetyInfo::StackSafetyInfo() = default; + +StackSafetyInfo::StackSafetyInfo(Function *F, + std::function GetSE) + : F(F), GetSE(GetSE) {} + StackSafetyInfo::StackSafetyInfo(StackSafetyInfo &&) = default; -StackSafetyInfo &StackSafetyInfo::operator=(StackSafetyInfo &&) = default; -StackSafetyInfo::StackSafetyInfo(InfoTy Info) - : Info(new InfoTy(std::move(Info))) {} +StackSafetyInfo &StackSafetyInfo::operator=(StackSafetyInfo &&) = default; StackSafetyInfo::~StackSafetyInfo() = default; -void StackSafetyInfo::print(raw_ostream &O, const GlobalValue &F) const { - Info->Info.print(O, F.getName(), dyn_cast(&F)); +const StackSafetyInfo::InfoTy &StackSafetyInfo::getInfo() const { + if (!Info) { + StackSafetyLocalAnalysis SSLA(*F, GetSE()); + Info.reset(new InfoTy{SSLA.run()}); + } + return *Info; +} + +void StackSafetyInfo::print(raw_ostream &O) const { + getInfo().Info.print(O, F->getName(), dyn_cast(F)); +} + +const StackSafetyGlobalInfo::InfoTy &StackSafetyGlobalInfo::getInfo() const { + if (!Info) { + std::map Functions; + for (auto &F : M->functions()) { + if (!F.isDeclaration()) { + auto FI = GetSSI(F).getInfo().Info; + Functions.emplace(&F, std::move(FI)); + } + } + Info.reset(new InfoTy{createGlobalStackSafetyInfo(std::move(Functions))}); + } + return *Info; } +StackSafetyGlobalInfo::StackSafetyGlobalInfo() = default; + +StackSafetyGlobalInfo::StackSafetyGlobalInfo( + Module *M, std::function GetSSI) + : M(M), GetSSI(GetSSI) {} + +StackSafetyGlobalInfo::StackSafetyGlobalInfo(StackSafetyGlobalInfo &&) = + default; + +StackSafetyGlobalInfo & +StackSafetyGlobalInfo::operator=(StackSafetyGlobalInfo &&) = default; + +StackSafetyGlobalInfo::~StackSafetyGlobalInfo() = default; + bool StackSafetyGlobalInfo::setMetadata(Module &M) const { - return setStackSafetyMetadata(M, SSGI); + return setStackSafetyMetadata(M, getInfo().Info); } void StackSafetyGlobalInfo::print(raw_ostream &O) const { - if (SSGI.empty()) + auto &SSI = getInfo().Info; + if (SSI.empty()) return; - const Module &M = *SSGI.begin()->first->getParent(); + const Module &M = *SSI.begin()->first->getParent(); for (auto &F : M.functions()) { if (!F.isDeclaration()) { - SSGI.find(&F)->second.print(O, F); + SSI.find(&F)->second.print(O, F.getName(), &F); O << "\n"; } } @@ -685,14 +724,15 @@ AnalysisKey StackSafetyAnalysis::Key; StackSafetyInfo StackSafetyAnalysis::run(Function &F, FunctionAnalysisManager &AM) { - StackSafetyLocalAnalysis SSLA(F, AM.getResult(F)); - return makeSSI(SSLA.run()); + return StackSafetyInfo(&F, [&AM, &F]() -> ScalarEvolution & { + return AM.getResult(F); + }); } PreservedAnalyses StackSafetyPrinterPass::run(Function &F, FunctionAnalysisManager &AM) { OS << "'Stack Safety Local Analysis' for function '" << F.getName() << "'\n"; - AM.getResult(F).print(OS, F); + AM.getResult(F).print(OS); return PreservedAnalyses::all(); } @@ -703,19 +743,17 @@ StackSafetyInfoWrapperPass::StackSafetyInfoWrapperPass() : FunctionPass(ID) { } void StackSafetyInfoWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const { - AU.addRequired(); + AU.addRequiredTransitive(); AU.setPreservesAll(); } void StackSafetyInfoWrapperPass::print(raw_ostream &O, const Module *M) const { - SSI->print(O, *F); + SSI.print(O); } bool StackSafetyInfoWrapperPass::runOnFunction(Function &F) { - StackSafetyLocalAnalysis SSLA( - F, getAnalysis().getSE()); - SSI = makeSSI(SSLA.run()); - this->F = &F; + auto *SE = &getAnalysis().getSE(); + SSI = {&F, [SE]() -> ScalarEvolution & { return *SE; }}; return false; } @@ -725,18 +763,9 @@ StackSafetyGlobalInfo StackSafetyGlobalAnalysis::run(Module &M, ModuleAnalysisManager &AM) { FunctionAnalysisManager &FAM = AM.getResult(M).getManager(); - - // FIXME: Lookup Module Summary. - std::map Functions; - - for (auto &F : M.functions()) { - if (!F.isDeclaration()) { - auto FI = FAM.getResult(F).getInfo().Info; - Functions.emplace(&F, std::move(FI)); - } - } - - return createGlobalStackSafetyInfo(std::move(Functions)); + return {&M, [&FAM](Function &F) -> const StackSafetyInfo & { + return FAM.getResult(F); + }}; } PreservedAnalyses StackSafetyGlobalPrinterPass::run(Module &M, @@ -761,6 +790,8 @@ StackSafetyGlobalInfoWrapperPass::StackSafetyGlobalInfoWrapperPass() *PassRegistry::getPassRegistry()); } +StackSafetyGlobalInfoWrapperPass::~StackSafetyGlobalInfoWrapperPass() = default; + void StackSafetyGlobalInfoWrapperPass::print(raw_ostream &O, const Module *M) const { SSGI.print(O); @@ -772,16 +803,9 @@ void StackSafetyGlobalInfoWrapperPass::getAnalysisUsage( } bool StackSafetyGlobalInfoWrapperPass::runOnModule(Module &M) { - std::map Functions; - for (auto &F : M.functions()) { - if (!F.isDeclaration()) { - auto FI = - getAnalysis(F).getResult().getInfo().Info; - Functions.emplace(&F, std::move(FI)); - } - } - - SSGI = createGlobalStackSafetyInfo(std::move(Functions)); + SSGI = {&M, [this](Function &F) -> const StackSafetyInfo & { + return getAnalysis(F).getResult(); + }}; return SSGI.setMetadata(M); }