diff --git a/llvm/include/llvm/Analysis/StackSafetyAnalysis.h b/llvm/include/llvm/Analysis/StackSafetyAnalysis.h --- a/llvm/include/llvm/Analysis/StackSafetyAnalysis.h +++ b/llvm/include/llvm/Analysis/StackSafetyAnalysis.h @@ -15,15 +15,77 @@ #define LLVM_ANALYSIS_STACKSAFETYANALYSIS_H #include "llvm/IR/PassManager.h" +#include "llvm/IR/ConstantRange.h" #include "llvm/Pass.h" namespace llvm { +// Forward declaring +class AllocaInst; +class Argument; /// Interface to access stack safety analysis results for single function. class StackSafetyInfo { public: struct FunctionInfo; + /// Describes use of address in as a function call argument. + struct PassAsArgInfo { + /// Function being called. + const GlobalValue *Callee = nullptr; + /// Index of argument which pass address. + size_t ParamNo = 0; + // Offset range of address from base address (alloca or calling function + // argument). + // Range should never set to empty-set, that is an invalid access range + // that can cause empty-set to be propagated with ConstantRange::add + ConstantRange Offset; + PassAsArgInfo(const GlobalValue *Callee, size_t ParamNo, + ConstantRange Offset) + : Callee(Callee), ParamNo(ParamNo), Offset(Offset) {} + + StringRef getName() const { return Callee->getName(); } + }; + + /// Describe uses of address (alloca or parameter) inside of the function. + struct UseInfo { + // Access range if the address (alloca or parameters). + // It is allowed to be empty-set when there are no known accesses. + ConstantRange Range; + + // List of calls which pass address as an argument. + SmallVector Calls; + + explicit UseInfo(unsigned PointerSize) : Range{PointerSize, false} {} + + void updateRange(ConstantRange R) { Range = Range.unionWith(R); } + }; + + struct AllocaInfo { + const AllocaInst *AI = nullptr; + uint64_t Size = 0; + UseInfo Use; + + AllocaInfo(unsigned PointerSize, const AllocaInst *AI, uint64_t Size) + : AI(AI), Size(Size), Use(PointerSize) {} + + StringRef getName() const; + }; + + struct ParamInfo { + const Argument *Arg = nullptr; + UseInfo Use; + + explicit ParamInfo(unsigned PointerSize, const Argument *Arg) + : Arg(Arg), Use(PointerSize) {} + + StringRef getName() const; + }; + + using AllocaIterator = + SmallVector::const_iterator; + using ParamsIterator = + SmallVector::const_iterator; + private: std::unique_ptr Info; @@ -36,6 +98,9 @@ // TODO: Add useful for client methods. void print(raw_ostream &O) const; + + iterator_range allocas() const; + iterator_range params() const; }; /// StackSafetyInfo wrapper for the new pass manager. diff --git a/llvm/lib/Analysis/StackSafetyAnalysis.cpp b/llvm/lib/Analysis/StackSafetyAnalysis.cpp --- a/llvm/lib/Analysis/StackSafetyAnalysis.cpp +++ b/llvm/lib/Analysis/StackSafetyAnalysis.cpp @@ -54,75 +54,24 @@ } }; -/// Describes use of address in as a function call argument. -struct PassAsArgInfo { - /// Function being called. - const GlobalValue *Callee = nullptr; - /// Index of argument which pass address. - size_t ParamNo = 0; - // Offset range of address from base address (alloca or calling function - // argument). - // Range should never set to empty-set, that is an invalid access range - // that can cause empty-set to be propagated with ConstantRange::add - ConstantRange Offset; - PassAsArgInfo(const GlobalValue *Callee, size_t ParamNo, ConstantRange Offset) - : Callee(Callee), ParamNo(ParamNo), Offset(Offset) {} - - StringRef getName() const { return Callee->getName(); } -}; - -raw_ostream &operator<<(raw_ostream &OS, const PassAsArgInfo &P) { +raw_ostream &operator<<(raw_ostream &OS, + const StackSafetyInfo::PassAsArgInfo &P) { return OS << "@" << P.getName() << "(arg" << P.ParamNo << ", " << P.Offset << ")"; } -/// Describe uses of address (alloca or parameter) inside of the function. -struct UseInfo { - // Access range if the address (alloca or parameters). - // It is allowed to be empty-set when there are no known accesses. - ConstantRange Range; - - // List of calls which pass address as an argument. - SmallVector Calls; - - explicit UseInfo(unsigned PointerSize) : Range{PointerSize, false} {} - - void updateRange(ConstantRange R) { Range = Range.unionWith(R); } -}; - -raw_ostream &operator<<(raw_ostream &OS, const UseInfo &U) { +raw_ostream &operator<<(raw_ostream &OS, const StackSafetyInfo::UseInfo &U) { OS << U.Range; for (auto &Call : U.Calls) OS << ", " << Call; return OS; } -struct AllocaInfo { - const AllocaInst *AI = nullptr; - uint64_t Size = 0; - UseInfo Use; - - AllocaInfo(unsigned PointerSize, const AllocaInst *AI, uint64_t Size) - : AI(AI), Size(Size), Use(PointerSize) {} - - StringRef getName() const { return AI->getName(); } -}; - -raw_ostream &operator<<(raw_ostream &OS, const AllocaInfo &A) { +raw_ostream &operator<<(raw_ostream &OS, const StackSafetyInfo::AllocaInfo &A) { return OS << A.getName() << "[" << A.Size << "]: " << A.Use; } -struct ParamInfo { - const Argument *Arg = nullptr; - UseInfo Use; - - explicit ParamInfo(unsigned PointerSize, const Argument *Arg) - : Arg(Arg), Use(PointerSize) {} - - StringRef getName() const { return Arg ? Arg->getName() : ""; } -}; - -raw_ostream &operator<<(raw_ostream &OS, const ParamInfo &P) { +raw_ostream &operator<<(raw_ostream &OS, const StackSafetyInfo::ParamInfo &P) { return OS << P.getName() << "[]: " << P.Use; } @@ -147,9 +96,9 @@ // May be a Function or a GlobalAlias const GlobalValue *GV = nullptr; // Informations about allocas uses. - SmallVector Allocas; + SmallVector Allocas; // Informations about parameters uses. - SmallVector Params; + SmallVector Params; // TODO: describe return value as depending on one or more of its arguments. // StackSafetyDataFlowAnalysis counter stored here for faster access. @@ -172,6 +121,12 @@ void print(raw_ostream &O) const { // TODO: Consider different printout format after // StackSafetyDataFlowAnalysis. Calls and parameters are irrelevant then. + + // After refactoring, the operator overload that is inside the anonymous + // namespace is no longer accessible directly when being passed with the + // refactored ParamInfo and AllocaInfo objects + using ::operator<<; + O << " @" << getName() << (IsDSOLocal() ? "" : " dso_preemptable") << (IsInterposable() ? " interposable" : "") << "\n"; O << " args uses:\n"; @@ -198,6 +153,21 @@ } } +iterator_range StackSafetyInfo::allocas() const { + assert(Info != nullptr && "FunctionInfo is null"); + return make_range(Info->Allocas.begin(), Info->Allocas.end()); +} +iterator_range StackSafetyInfo::params() const { + assert(Info != nullptr && "FunctionInfo is null"); + return make_range(Info->Params.begin(), Info->Params.end()); +} + +StringRef StackSafetyInfo::AllocaInfo::getName() const { return AI->getName(); } + +StringRef StackSafetyInfo::ParamInfo::getName() const { + return Arg ? Arg->getName() : ""; +} + namespace { class StackSafetyLocalAnalysis { @@ -214,7 +184,7 @@ ConstantRange getMemIntrinsicAccessRange(const MemIntrinsic *MI, const Use &U, const Value *AllocaPtr); - bool analyzeAllUses(const Value *Ptr, UseInfo &AS); + bool analyzeAllUses(const Value *Ptr, StackSafetyInfo::UseInfo &AS); ConstantRange getRange(uint64_t Lower, uint64_t Upper) const { return ConstantRange(APInt(PointerSize, Lower), APInt(PointerSize, Upper)); @@ -279,7 +249,8 @@ /// The function analyzes all local uses of Ptr (alloca or argument) and /// calculates local access range and all function calls where it was used. -bool StackSafetyLocalAnalysis::analyzeAllUses(const Value *Ptr, UseInfo &US) { +bool StackSafetyLocalAnalysis::analyzeAllUses(const Value *Ptr, + StackSafetyInfo::UseInfo &US) { SmallPtrSet Visited; SmallVector WorkList; WorkList.push_back(Ptr); @@ -375,14 +346,14 @@ if (auto AI = dyn_cast(&I)) { Info.Allocas.emplace_back(PointerSize, AI, getStaticAllocaAllocationSize(AI)); - AllocaInfo &AS = Info.Allocas.back(); + StackSafetyInfo::AllocaInfo &AS = Info.Allocas.back(); analyzeAllUses(AI, AS.Use); } } for (const Argument &A : make_range(F.arg_begin(), F.arg_end())) { Info.Params.emplace_back(PointerSize, &A); - ParamInfo &PS = Info.Params.back(); + StackSafetyInfo::ParamInfo &PS = Info.Params.back(); analyzeAllUses(&A, PS.Use); } @@ -405,7 +376,7 @@ ConstantRange getArgumentAccessRange(const GlobalValue *Callee, unsigned ParamNo) const; - bool updateOneUse(UseInfo &US, bool UpdateToFullSet); + bool updateOneUse(StackSafetyInfo::UseInfo &US, bool UpdateToFullSet); void updateOneNode(const GlobalValue *Callee, StackSafetyInfo::FunctionInfo &FS); void updateOneNode(const GlobalValue *Callee) { @@ -455,7 +426,7 @@ return FS.Params[ParamNo].Use.Range; } -bool StackSafetyDataFlowAnalysis::updateOneUse(UseInfo &US, +bool StackSafetyDataFlowAnalysis::updateOneUse(StackSafetyInfo::UseInfo &US, bool UpdateToFullSet) { bool Changed = false; for (auto &CS : US.Calls) {