1*b5893f02SDimitry Andric //===- StackSafetyAnalysis.cpp - Stack memory safety analysis -------------===//
2*b5893f02SDimitry Andric //
3*b5893f02SDimitry Andric //                     The LLVM Compiler Infrastructure
4*b5893f02SDimitry Andric //
5*b5893f02SDimitry Andric // This file is distributed under the University of Illinois Open Source
6*b5893f02SDimitry Andric // License. See LICENSE.TXT for details.
7*b5893f02SDimitry Andric //
8*b5893f02SDimitry Andric //===----------------------------------------------------------------------===//
9*b5893f02SDimitry Andric //
10*b5893f02SDimitry Andric //===----------------------------------------------------------------------===//
11*b5893f02SDimitry Andric 
12*b5893f02SDimitry Andric #include "llvm/Analysis/StackSafetyAnalysis.h"
13*b5893f02SDimitry Andric #include "llvm/Analysis/ScalarEvolutionExpressions.h"
14*b5893f02SDimitry Andric #include "llvm/IR/CallSite.h"
15*b5893f02SDimitry Andric #include "llvm/IR/InstIterator.h"
16*b5893f02SDimitry Andric #include "llvm/IR/IntrinsicInst.h"
17*b5893f02SDimitry Andric #include "llvm/Support/raw_ostream.h"
18*b5893f02SDimitry Andric 
19*b5893f02SDimitry Andric using namespace llvm;
20*b5893f02SDimitry Andric 
21*b5893f02SDimitry Andric #define DEBUG_TYPE "stack-safety"
22*b5893f02SDimitry Andric 
23*b5893f02SDimitry Andric static cl::opt<int> StackSafetyMaxIterations("stack-safety-max-iterations",
24*b5893f02SDimitry Andric                                              cl::init(20), cl::Hidden);
25*b5893f02SDimitry Andric 
26*b5893f02SDimitry Andric namespace {
27*b5893f02SDimitry Andric 
28*b5893f02SDimitry Andric /// Rewrite an SCEV expression for a memory access address to an expression that
29*b5893f02SDimitry Andric /// represents offset from the given alloca.
30*b5893f02SDimitry Andric class AllocaOffsetRewriter : public SCEVRewriteVisitor<AllocaOffsetRewriter> {
31*b5893f02SDimitry Andric   const Value *AllocaPtr;
32*b5893f02SDimitry Andric 
33*b5893f02SDimitry Andric public:
AllocaOffsetRewriter(ScalarEvolution & SE,const Value * AllocaPtr)34*b5893f02SDimitry Andric   AllocaOffsetRewriter(ScalarEvolution &SE, const Value *AllocaPtr)
35*b5893f02SDimitry Andric       : SCEVRewriteVisitor(SE), AllocaPtr(AllocaPtr) {}
36*b5893f02SDimitry Andric 
visit(const SCEV * Expr)37*b5893f02SDimitry Andric   const SCEV *visit(const SCEV *Expr) {
38*b5893f02SDimitry Andric     // Only re-write the expression if the alloca is used in an addition
39*b5893f02SDimitry Andric     // expression (it can be used in other types of expressions if it's cast to
40*b5893f02SDimitry Andric     // an int and passed as an argument.)
41*b5893f02SDimitry Andric     if (!isa<SCEVAddRecExpr>(Expr) && !isa<SCEVAddExpr>(Expr) &&
42*b5893f02SDimitry Andric         !isa<SCEVUnknown>(Expr))
43*b5893f02SDimitry Andric       return Expr;
44*b5893f02SDimitry Andric     return SCEVRewriteVisitor<AllocaOffsetRewriter>::visit(Expr);
45*b5893f02SDimitry Andric   }
46*b5893f02SDimitry Andric 
visitUnknown(const SCEVUnknown * Expr)47*b5893f02SDimitry Andric   const SCEV *visitUnknown(const SCEVUnknown *Expr) {
48*b5893f02SDimitry Andric     // FIXME: look through one or several levels of definitions?
49*b5893f02SDimitry Andric     // This can be inttoptr(AllocaPtr) and SCEV would not unwrap
50*b5893f02SDimitry Andric     // it for us.
51*b5893f02SDimitry Andric     if (Expr->getValue() == AllocaPtr)
52*b5893f02SDimitry Andric       return SE.getZero(Expr->getType());
53*b5893f02SDimitry Andric     return Expr;
54*b5893f02SDimitry Andric   }
55*b5893f02SDimitry Andric };
56*b5893f02SDimitry Andric 
57*b5893f02SDimitry Andric /// Describes use of address in as a function call argument.
58*b5893f02SDimitry Andric struct PassAsArgInfo {
59*b5893f02SDimitry Andric   /// Function being called.
60*b5893f02SDimitry Andric   const GlobalValue *Callee = nullptr;
61*b5893f02SDimitry Andric   /// Index of argument which pass address.
62*b5893f02SDimitry Andric   size_t ParamNo = 0;
63*b5893f02SDimitry Andric   // Offset range of address from base address (alloca or calling function
64*b5893f02SDimitry Andric   // argument).
65*b5893f02SDimitry Andric   // Range should never set to empty-set, that is an invalid access range
66*b5893f02SDimitry Andric   // that can cause empty-set to be propagated with ConstantRange::add
67*b5893f02SDimitry Andric   ConstantRange Offset;
PassAsArgInfo__anonbb2e384e0111::PassAsArgInfo68*b5893f02SDimitry Andric   PassAsArgInfo(const GlobalValue *Callee, size_t ParamNo, ConstantRange Offset)
69*b5893f02SDimitry Andric       : Callee(Callee), ParamNo(ParamNo), Offset(Offset) {}
70*b5893f02SDimitry Andric 
getName__anonbb2e384e0111::PassAsArgInfo71*b5893f02SDimitry Andric   StringRef getName() const { return Callee->getName(); }
72*b5893f02SDimitry Andric };
73*b5893f02SDimitry Andric 
operator <<(raw_ostream & OS,const PassAsArgInfo & P)74*b5893f02SDimitry Andric raw_ostream &operator<<(raw_ostream &OS, const PassAsArgInfo &P) {
75*b5893f02SDimitry Andric   return OS << "@" << P.getName() << "(arg" << P.ParamNo << ", " << P.Offset
76*b5893f02SDimitry Andric             << ")";
77*b5893f02SDimitry Andric }
78*b5893f02SDimitry Andric 
79*b5893f02SDimitry Andric /// Describe uses of address (alloca or parameter) inside of the function.
80*b5893f02SDimitry Andric struct UseInfo {
81*b5893f02SDimitry Andric   // Access range if the address (alloca or parameters).
82*b5893f02SDimitry Andric   // It is allowed to be empty-set when there are no known accesses.
83*b5893f02SDimitry Andric   ConstantRange Range;
84*b5893f02SDimitry Andric 
85*b5893f02SDimitry Andric   // List of calls which pass address as an argument.
86*b5893f02SDimitry Andric   SmallVector<PassAsArgInfo, 4> Calls;
87*b5893f02SDimitry Andric 
UseInfo__anonbb2e384e0111::UseInfo88*b5893f02SDimitry Andric   explicit UseInfo(unsigned PointerSize) : Range{PointerSize, false} {}
89*b5893f02SDimitry Andric 
updateRange__anonbb2e384e0111::UseInfo90*b5893f02SDimitry Andric   void updateRange(ConstantRange R) { Range = Range.unionWith(R); }
91*b5893f02SDimitry Andric };
92*b5893f02SDimitry Andric 
operator <<(raw_ostream & OS,const UseInfo & U)93*b5893f02SDimitry Andric raw_ostream &operator<<(raw_ostream &OS, const UseInfo &U) {
94*b5893f02SDimitry Andric   OS << U.Range;
95*b5893f02SDimitry Andric   for (auto &Call : U.Calls)
96*b5893f02SDimitry Andric     OS << ", " << Call;
97*b5893f02SDimitry Andric   return OS;
98*b5893f02SDimitry Andric }
99*b5893f02SDimitry Andric 
100*b5893f02SDimitry Andric struct AllocaInfo {
101*b5893f02SDimitry Andric   const AllocaInst *AI = nullptr;
102*b5893f02SDimitry Andric   uint64_t Size = 0;
103*b5893f02SDimitry Andric   UseInfo Use;
104*b5893f02SDimitry Andric 
AllocaInfo__anonbb2e384e0111::AllocaInfo105*b5893f02SDimitry Andric   AllocaInfo(unsigned PointerSize, const AllocaInst *AI, uint64_t Size)
106*b5893f02SDimitry Andric       : AI(AI), Size(Size), Use(PointerSize) {}
107*b5893f02SDimitry Andric 
getName__anonbb2e384e0111::AllocaInfo108*b5893f02SDimitry Andric   StringRef getName() const { return AI->getName(); }
109*b5893f02SDimitry Andric };
110*b5893f02SDimitry Andric 
operator <<(raw_ostream & OS,const AllocaInfo & A)111*b5893f02SDimitry Andric raw_ostream &operator<<(raw_ostream &OS, const AllocaInfo &A) {
112*b5893f02SDimitry Andric   return OS << A.getName() << "[" << A.Size << "]: " << A.Use;
113*b5893f02SDimitry Andric }
114*b5893f02SDimitry Andric 
115*b5893f02SDimitry Andric struct ParamInfo {
116*b5893f02SDimitry Andric   const Argument *Arg = nullptr;
117*b5893f02SDimitry Andric   UseInfo Use;
118*b5893f02SDimitry Andric 
ParamInfo__anonbb2e384e0111::ParamInfo119*b5893f02SDimitry Andric   explicit ParamInfo(unsigned PointerSize, const Argument *Arg)
120*b5893f02SDimitry Andric       : Arg(Arg), Use(PointerSize) {}
121*b5893f02SDimitry Andric 
getName__anonbb2e384e0111::ParamInfo122*b5893f02SDimitry Andric   StringRef getName() const { return Arg ? Arg->getName() : "<N/A>"; }
123*b5893f02SDimitry Andric };
124*b5893f02SDimitry Andric 
operator <<(raw_ostream & OS,const ParamInfo & P)125*b5893f02SDimitry Andric raw_ostream &operator<<(raw_ostream &OS, const ParamInfo &P) {
126*b5893f02SDimitry Andric   return OS << P.getName() << "[]: " << P.Use;
127*b5893f02SDimitry Andric }
128*b5893f02SDimitry Andric 
129*b5893f02SDimitry Andric /// Calculate the allocation size of a given alloca. Returns 0 if the
130*b5893f02SDimitry Andric /// size can not be statically determined.
getStaticAllocaAllocationSize(const AllocaInst * AI)131*b5893f02SDimitry Andric uint64_t getStaticAllocaAllocationSize(const AllocaInst *AI) {
132*b5893f02SDimitry Andric   const DataLayout &DL = AI->getModule()->getDataLayout();
133*b5893f02SDimitry Andric   uint64_t Size = DL.getTypeAllocSize(AI->getAllocatedType());
134*b5893f02SDimitry Andric   if (AI->isArrayAllocation()) {
135*b5893f02SDimitry Andric     auto C = dyn_cast<ConstantInt>(AI->getArraySize());
136*b5893f02SDimitry Andric     if (!C)
137*b5893f02SDimitry Andric       return 0;
138*b5893f02SDimitry Andric     Size *= C->getZExtValue();
139*b5893f02SDimitry Andric   }
140*b5893f02SDimitry Andric   return Size;
141*b5893f02SDimitry Andric }
142*b5893f02SDimitry Andric 
143*b5893f02SDimitry Andric } // end anonymous namespace
144*b5893f02SDimitry Andric 
145*b5893f02SDimitry Andric /// Describes uses of allocas and parameters inside of a single function.
146*b5893f02SDimitry Andric struct StackSafetyInfo::FunctionInfo {
147*b5893f02SDimitry Andric   // May be a Function or a GlobalAlias
148*b5893f02SDimitry Andric   const GlobalValue *GV = nullptr;
149*b5893f02SDimitry Andric   // Informations about allocas uses.
150*b5893f02SDimitry Andric   SmallVector<AllocaInfo, 4> Allocas;
151*b5893f02SDimitry Andric   // Informations about parameters uses.
152*b5893f02SDimitry Andric   SmallVector<ParamInfo, 4> Params;
153*b5893f02SDimitry Andric   // TODO: describe return value as depending on one or more of its arguments.
154*b5893f02SDimitry Andric 
155*b5893f02SDimitry Andric   // StackSafetyDataFlowAnalysis counter stored here for faster access.
156*b5893f02SDimitry Andric   int UpdateCount = 0;
157*b5893f02SDimitry Andric 
FunctionInfoStackSafetyInfo::FunctionInfo158*b5893f02SDimitry Andric   FunctionInfo(const StackSafetyInfo &SSI) : FunctionInfo(*SSI.Info) {}
159*b5893f02SDimitry Andric 
FunctionInfoStackSafetyInfo::FunctionInfo160*b5893f02SDimitry Andric   explicit FunctionInfo(const Function *F) : GV(F){};
161*b5893f02SDimitry Andric   // Creates FunctionInfo that forwards all the parameters to the aliasee.
162*b5893f02SDimitry Andric   explicit FunctionInfo(const GlobalAlias *A);
163*b5893f02SDimitry Andric 
164*b5893f02SDimitry Andric   FunctionInfo(FunctionInfo &&) = default;
165*b5893f02SDimitry Andric 
IsDSOLocalStackSafetyInfo::FunctionInfo166*b5893f02SDimitry Andric   bool IsDSOLocal() const { return GV->isDSOLocal(); };
167*b5893f02SDimitry Andric 
IsInterposableStackSafetyInfo::FunctionInfo168*b5893f02SDimitry Andric   bool IsInterposable() const { return GV->isInterposable(); };
169*b5893f02SDimitry Andric 
getNameStackSafetyInfo::FunctionInfo170*b5893f02SDimitry Andric   StringRef getName() const { return GV->getName(); }
171*b5893f02SDimitry Andric 
printStackSafetyInfo::FunctionInfo172*b5893f02SDimitry Andric   void print(raw_ostream &O) const {
173*b5893f02SDimitry Andric     // TODO: Consider different printout format after
174*b5893f02SDimitry Andric     // StackSafetyDataFlowAnalysis. Calls and parameters are irrelevant then.
175*b5893f02SDimitry Andric     O << "  @" << getName() << (IsDSOLocal() ? "" : " dso_preemptable")
176*b5893f02SDimitry Andric       << (IsInterposable() ? " interposable" : "") << "\n";
177*b5893f02SDimitry Andric     O << "    args uses:\n";
178*b5893f02SDimitry Andric     for (auto &P : Params)
179*b5893f02SDimitry Andric       O << "      " << P << "\n";
180*b5893f02SDimitry Andric     O << "    allocas uses:\n";
181*b5893f02SDimitry Andric     for (auto &AS : Allocas)
182*b5893f02SDimitry Andric       O << "      " << AS << "\n";
183*b5893f02SDimitry Andric   }
184*b5893f02SDimitry Andric 
185*b5893f02SDimitry Andric private:
186*b5893f02SDimitry Andric   FunctionInfo(const FunctionInfo &) = default;
187*b5893f02SDimitry Andric };
188*b5893f02SDimitry Andric 
FunctionInfo(const GlobalAlias * A)189*b5893f02SDimitry Andric StackSafetyInfo::FunctionInfo::FunctionInfo(const GlobalAlias *A) : GV(A) {
190*b5893f02SDimitry Andric   unsigned PointerSize = A->getParent()->getDataLayout().getPointerSizeInBits();
191*b5893f02SDimitry Andric   const GlobalObject *Aliasee = A->getBaseObject();
192*b5893f02SDimitry Andric   const FunctionType *Type = cast<FunctionType>(Aliasee->getValueType());
193*b5893f02SDimitry Andric   // 'Forward' all parameters to this alias to the aliasee
194*b5893f02SDimitry Andric   for (unsigned ArgNo = 0; ArgNo < Type->getNumParams(); ArgNo++) {
195*b5893f02SDimitry Andric     Params.emplace_back(PointerSize, nullptr);
196*b5893f02SDimitry Andric     UseInfo &US = Params.back().Use;
197*b5893f02SDimitry Andric     US.Calls.emplace_back(Aliasee, ArgNo, ConstantRange(APInt(PointerSize, 0)));
198*b5893f02SDimitry Andric   }
199*b5893f02SDimitry Andric }
200*b5893f02SDimitry Andric 
201*b5893f02SDimitry Andric namespace {
202*b5893f02SDimitry Andric 
203*b5893f02SDimitry Andric class StackSafetyLocalAnalysis {
204*b5893f02SDimitry Andric   const Function &F;
205*b5893f02SDimitry Andric   const DataLayout &DL;
206*b5893f02SDimitry Andric   ScalarEvolution &SE;
207*b5893f02SDimitry Andric   unsigned PointerSize = 0;
208*b5893f02SDimitry Andric 
209*b5893f02SDimitry Andric   const ConstantRange UnknownRange;
210*b5893f02SDimitry Andric 
211*b5893f02SDimitry Andric   ConstantRange offsetFromAlloca(Value *Addr, const Value *AllocaPtr);
212*b5893f02SDimitry Andric   ConstantRange getAccessRange(Value *Addr, const Value *AllocaPtr,
213*b5893f02SDimitry Andric                                uint64_t AccessSize);
214*b5893f02SDimitry Andric   ConstantRange getMemIntrinsicAccessRange(const MemIntrinsic *MI, const Use &U,
215*b5893f02SDimitry Andric                                            const Value *AllocaPtr);
216*b5893f02SDimitry Andric 
217*b5893f02SDimitry Andric   bool analyzeAllUses(const Value *Ptr, UseInfo &AS);
218*b5893f02SDimitry Andric 
getRange(uint64_t Lower,uint64_t Upper) const219*b5893f02SDimitry Andric   ConstantRange getRange(uint64_t Lower, uint64_t Upper) const {
220*b5893f02SDimitry Andric     return ConstantRange(APInt(PointerSize, Lower), APInt(PointerSize, Upper));
221*b5893f02SDimitry Andric   }
222*b5893f02SDimitry Andric 
223*b5893f02SDimitry Andric public:
StackSafetyLocalAnalysis(const Function & F,ScalarEvolution & SE)224*b5893f02SDimitry Andric   StackSafetyLocalAnalysis(const Function &F, ScalarEvolution &SE)
225*b5893f02SDimitry Andric       : F(F), DL(F.getParent()->getDataLayout()), SE(SE),
226*b5893f02SDimitry Andric         PointerSize(DL.getPointerSizeInBits()),
227*b5893f02SDimitry Andric         UnknownRange(PointerSize, true) {}
228*b5893f02SDimitry Andric 
229*b5893f02SDimitry Andric   // Run the transformation on the associated function.
230*b5893f02SDimitry Andric   StackSafetyInfo run();
231*b5893f02SDimitry Andric };
232*b5893f02SDimitry Andric 
233*b5893f02SDimitry Andric ConstantRange
offsetFromAlloca(Value * Addr,const Value * AllocaPtr)234*b5893f02SDimitry Andric StackSafetyLocalAnalysis::offsetFromAlloca(Value *Addr,
235*b5893f02SDimitry Andric                                            const Value *AllocaPtr) {
236*b5893f02SDimitry Andric   if (!SE.isSCEVable(Addr->getType()))
237*b5893f02SDimitry Andric     return UnknownRange;
238*b5893f02SDimitry Andric 
239*b5893f02SDimitry Andric   AllocaOffsetRewriter Rewriter(SE, AllocaPtr);
240*b5893f02SDimitry Andric   const SCEV *Expr = Rewriter.visit(SE.getSCEV(Addr));
241*b5893f02SDimitry Andric   ConstantRange Offset = SE.getUnsignedRange(Expr).zextOrTrunc(PointerSize);
242*b5893f02SDimitry Andric   assert(!Offset.isEmptySet());
243*b5893f02SDimitry Andric   return Offset;
244*b5893f02SDimitry Andric }
245*b5893f02SDimitry Andric 
getAccessRange(Value * Addr,const Value * AllocaPtr,uint64_t AccessSize)246*b5893f02SDimitry Andric ConstantRange StackSafetyLocalAnalysis::getAccessRange(Value *Addr,
247*b5893f02SDimitry Andric                                                        const Value *AllocaPtr,
248*b5893f02SDimitry Andric                                                        uint64_t AccessSize) {
249*b5893f02SDimitry Andric   if (!SE.isSCEVable(Addr->getType()))
250*b5893f02SDimitry Andric     return UnknownRange;
251*b5893f02SDimitry Andric 
252*b5893f02SDimitry Andric   AllocaOffsetRewriter Rewriter(SE, AllocaPtr);
253*b5893f02SDimitry Andric   const SCEV *Expr = Rewriter.visit(SE.getSCEV(Addr));
254*b5893f02SDimitry Andric 
255*b5893f02SDimitry Andric   ConstantRange AccessStartRange =
256*b5893f02SDimitry Andric       SE.getUnsignedRange(Expr).zextOrTrunc(PointerSize);
257*b5893f02SDimitry Andric   ConstantRange SizeRange = getRange(0, AccessSize);
258*b5893f02SDimitry Andric   ConstantRange AccessRange = AccessStartRange.add(SizeRange);
259*b5893f02SDimitry Andric   assert(!AccessRange.isEmptySet());
260*b5893f02SDimitry Andric   return AccessRange;
261*b5893f02SDimitry Andric }
262*b5893f02SDimitry Andric 
getMemIntrinsicAccessRange(const MemIntrinsic * MI,const Use & U,const Value * AllocaPtr)263*b5893f02SDimitry Andric ConstantRange StackSafetyLocalAnalysis::getMemIntrinsicAccessRange(
264*b5893f02SDimitry Andric     const MemIntrinsic *MI, const Use &U, const Value *AllocaPtr) {
265*b5893f02SDimitry Andric   if (auto MTI = dyn_cast<MemTransferInst>(MI)) {
266*b5893f02SDimitry Andric     if (MTI->getRawSource() != U && MTI->getRawDest() != U)
267*b5893f02SDimitry Andric       return getRange(0, 1);
268*b5893f02SDimitry Andric   } else {
269*b5893f02SDimitry Andric     if (MI->getRawDest() != U)
270*b5893f02SDimitry Andric       return getRange(0, 1);
271*b5893f02SDimitry Andric   }
272*b5893f02SDimitry Andric   const auto *Len = dyn_cast<ConstantInt>(MI->getLength());
273*b5893f02SDimitry Andric   // Non-constant size => unsafe. FIXME: try SCEV getRange.
274*b5893f02SDimitry Andric   if (!Len)
275*b5893f02SDimitry Andric     return UnknownRange;
276*b5893f02SDimitry Andric   ConstantRange AccessRange = getAccessRange(U, AllocaPtr, Len->getZExtValue());
277*b5893f02SDimitry Andric   return AccessRange;
278*b5893f02SDimitry Andric }
279*b5893f02SDimitry Andric 
280*b5893f02SDimitry Andric /// The function analyzes all local uses of Ptr (alloca or argument) and
281*b5893f02SDimitry Andric /// calculates local access range and all function calls where it was used.
analyzeAllUses(const Value * Ptr,UseInfo & US)282*b5893f02SDimitry Andric bool StackSafetyLocalAnalysis::analyzeAllUses(const Value *Ptr, UseInfo &US) {
283*b5893f02SDimitry Andric   SmallPtrSet<const Value *, 16> Visited;
284*b5893f02SDimitry Andric   SmallVector<const Value *, 8> WorkList;
285*b5893f02SDimitry Andric   WorkList.push_back(Ptr);
286*b5893f02SDimitry Andric 
287*b5893f02SDimitry Andric   // A DFS search through all uses of the alloca in bitcasts/PHI/GEPs/etc.
288*b5893f02SDimitry Andric   while (!WorkList.empty()) {
289*b5893f02SDimitry Andric     const Value *V = WorkList.pop_back_val();
290*b5893f02SDimitry Andric     for (const Use &UI : V->uses()) {
291*b5893f02SDimitry Andric       auto I = cast<const Instruction>(UI.getUser());
292*b5893f02SDimitry Andric       assert(V == UI.get());
293*b5893f02SDimitry Andric 
294*b5893f02SDimitry Andric       switch (I->getOpcode()) {
295*b5893f02SDimitry Andric       case Instruction::Load: {
296*b5893f02SDimitry Andric         US.updateRange(
297*b5893f02SDimitry Andric             getAccessRange(UI, Ptr, DL.getTypeStoreSize(I->getType())));
298*b5893f02SDimitry Andric         break;
299*b5893f02SDimitry Andric       }
300*b5893f02SDimitry Andric 
301*b5893f02SDimitry Andric       case Instruction::VAArg:
302*b5893f02SDimitry Andric         // "va-arg" from a pointer is safe.
303*b5893f02SDimitry Andric         break;
304*b5893f02SDimitry Andric       case Instruction::Store: {
305*b5893f02SDimitry Andric         if (V == I->getOperand(0)) {
306*b5893f02SDimitry Andric           // Stored the pointer - conservatively assume it may be unsafe.
307*b5893f02SDimitry Andric           US.updateRange(UnknownRange);
308*b5893f02SDimitry Andric           return false;
309*b5893f02SDimitry Andric         }
310*b5893f02SDimitry Andric         US.updateRange(getAccessRange(
311*b5893f02SDimitry Andric             UI, Ptr, DL.getTypeStoreSize(I->getOperand(0)->getType())));
312*b5893f02SDimitry Andric         break;
313*b5893f02SDimitry Andric       }
314*b5893f02SDimitry Andric 
315*b5893f02SDimitry Andric       case Instruction::Ret:
316*b5893f02SDimitry Andric         // Information leak.
317*b5893f02SDimitry Andric         // FIXME: Process parameters correctly. This is a leak only if we return
318*b5893f02SDimitry Andric         // alloca.
319*b5893f02SDimitry Andric         US.updateRange(UnknownRange);
320*b5893f02SDimitry Andric         return false;
321*b5893f02SDimitry Andric 
322*b5893f02SDimitry Andric       case Instruction::Call:
323*b5893f02SDimitry Andric       case Instruction::Invoke: {
324*b5893f02SDimitry Andric         ImmutableCallSite CS(I);
325*b5893f02SDimitry Andric 
326*b5893f02SDimitry Andric         if (I->isLifetimeStartOrEnd())
327*b5893f02SDimitry Andric           break;
328*b5893f02SDimitry Andric 
329*b5893f02SDimitry Andric         if (const MemIntrinsic *MI = dyn_cast<MemIntrinsic>(I)) {
330*b5893f02SDimitry Andric           US.updateRange(getMemIntrinsicAccessRange(MI, UI, Ptr));
331*b5893f02SDimitry Andric           break;
332*b5893f02SDimitry Andric         }
333*b5893f02SDimitry Andric 
334*b5893f02SDimitry Andric         // FIXME: consult devirt?
335*b5893f02SDimitry Andric         // Do not follow aliases, otherwise we could inadvertently follow
336*b5893f02SDimitry Andric         // dso_preemptable aliases or aliases with interposable linkage.
337*b5893f02SDimitry Andric         const GlobalValue *Callee = dyn_cast<GlobalValue>(
338*b5893f02SDimitry Andric             CS.getCalledValue()->stripPointerCastsNoFollowAliases());
339*b5893f02SDimitry Andric         if (!Callee) {
340*b5893f02SDimitry Andric           US.updateRange(UnknownRange);
341*b5893f02SDimitry Andric           return false;
342*b5893f02SDimitry Andric         }
343*b5893f02SDimitry Andric 
344*b5893f02SDimitry Andric         assert(isa<Function>(Callee) || isa<GlobalAlias>(Callee));
345*b5893f02SDimitry Andric 
346*b5893f02SDimitry Andric         ImmutableCallSite::arg_iterator B = CS.arg_begin(), E = CS.arg_end();
347*b5893f02SDimitry Andric         for (ImmutableCallSite::arg_iterator A = B; A != E; ++A) {
348*b5893f02SDimitry Andric           if (A->get() == V) {
349*b5893f02SDimitry Andric             ConstantRange Offset = offsetFromAlloca(UI, Ptr);
350*b5893f02SDimitry Andric             US.Calls.emplace_back(Callee, A - B, Offset);
351*b5893f02SDimitry Andric           }
352*b5893f02SDimitry Andric         }
353*b5893f02SDimitry Andric 
354*b5893f02SDimitry Andric         break;
355*b5893f02SDimitry Andric       }
356*b5893f02SDimitry Andric 
357*b5893f02SDimitry Andric       default:
358*b5893f02SDimitry Andric         if (Visited.insert(I).second)
359*b5893f02SDimitry Andric           WorkList.push_back(cast<const Instruction>(I));
360*b5893f02SDimitry Andric       }
361*b5893f02SDimitry Andric     }
362*b5893f02SDimitry Andric   }
363*b5893f02SDimitry Andric 
364*b5893f02SDimitry Andric   return true;
365*b5893f02SDimitry Andric }
366*b5893f02SDimitry Andric 
run()367*b5893f02SDimitry Andric StackSafetyInfo StackSafetyLocalAnalysis::run() {
368*b5893f02SDimitry Andric   StackSafetyInfo::FunctionInfo Info(&F);
369*b5893f02SDimitry Andric   assert(!F.isDeclaration() &&
370*b5893f02SDimitry Andric          "Can't run StackSafety on a function declaration");
371*b5893f02SDimitry Andric 
372*b5893f02SDimitry Andric   LLVM_DEBUG(dbgs() << "[StackSafety] " << F.getName() << "\n");
373*b5893f02SDimitry Andric 
374*b5893f02SDimitry Andric   for (auto &I : instructions(F)) {
375*b5893f02SDimitry Andric     if (auto AI = dyn_cast<AllocaInst>(&I)) {
376*b5893f02SDimitry Andric       Info.Allocas.emplace_back(PointerSize, AI,
377*b5893f02SDimitry Andric                                 getStaticAllocaAllocationSize(AI));
378*b5893f02SDimitry Andric       AllocaInfo &AS = Info.Allocas.back();
379*b5893f02SDimitry Andric       analyzeAllUses(AI, AS.Use);
380*b5893f02SDimitry Andric     }
381*b5893f02SDimitry Andric   }
382*b5893f02SDimitry Andric 
383*b5893f02SDimitry Andric   for (const Argument &A : make_range(F.arg_begin(), F.arg_end())) {
384*b5893f02SDimitry Andric     Info.Params.emplace_back(PointerSize, &A);
385*b5893f02SDimitry Andric     ParamInfo &PS = Info.Params.back();
386*b5893f02SDimitry Andric     analyzeAllUses(&A, PS.Use);
387*b5893f02SDimitry Andric   }
388*b5893f02SDimitry Andric 
389*b5893f02SDimitry Andric   LLVM_DEBUG(dbgs() << "[StackSafety] done\n");
390*b5893f02SDimitry Andric   LLVM_DEBUG(Info.print(dbgs()));
391*b5893f02SDimitry Andric   return StackSafetyInfo(std::move(Info));
392*b5893f02SDimitry Andric }
393*b5893f02SDimitry Andric 
394*b5893f02SDimitry Andric class StackSafetyDataFlowAnalysis {
395*b5893f02SDimitry Andric   using FunctionMap =
396*b5893f02SDimitry Andric       std::map<const GlobalValue *, StackSafetyInfo::FunctionInfo>;
397*b5893f02SDimitry Andric 
398*b5893f02SDimitry Andric   FunctionMap Functions;
399*b5893f02SDimitry Andric   // Callee-to-Caller multimap.
400*b5893f02SDimitry Andric   DenseMap<const GlobalValue *, SmallVector<const GlobalValue *, 4>> Callers;
401*b5893f02SDimitry Andric   SetVector<const GlobalValue *> WorkList;
402*b5893f02SDimitry Andric 
403*b5893f02SDimitry Andric   unsigned PointerSize = 0;
404*b5893f02SDimitry Andric   const ConstantRange UnknownRange;
405*b5893f02SDimitry Andric 
406*b5893f02SDimitry Andric   ConstantRange getArgumentAccessRange(const GlobalValue *Callee,
407*b5893f02SDimitry Andric                                        unsigned ParamNo) const;
408*b5893f02SDimitry Andric   bool updateOneUse(UseInfo &US, bool UpdateToFullSet);
409*b5893f02SDimitry Andric   void updateOneNode(const GlobalValue *Callee,
410*b5893f02SDimitry Andric                      StackSafetyInfo::FunctionInfo &FS);
updateOneNode(const GlobalValue * Callee)411*b5893f02SDimitry Andric   void updateOneNode(const GlobalValue *Callee) {
412*b5893f02SDimitry Andric     updateOneNode(Callee, Functions.find(Callee)->second);
413*b5893f02SDimitry Andric   }
updateAllNodes()414*b5893f02SDimitry Andric   void updateAllNodes() {
415*b5893f02SDimitry Andric     for (auto &F : Functions)
416*b5893f02SDimitry Andric       updateOneNode(F.first, F.second);
417*b5893f02SDimitry Andric   }
418*b5893f02SDimitry Andric   void runDataFlow();
419*b5893f02SDimitry Andric   void verifyFixedPoint();
420*b5893f02SDimitry Andric 
421*b5893f02SDimitry Andric public:
422*b5893f02SDimitry Andric   StackSafetyDataFlowAnalysis(
423*b5893f02SDimitry Andric       Module &M, std::function<const StackSafetyInfo &(Function &)> FI);
424*b5893f02SDimitry Andric   StackSafetyGlobalInfo run();
425*b5893f02SDimitry Andric };
426*b5893f02SDimitry Andric 
StackSafetyDataFlowAnalysis(Module & M,std::function<const StackSafetyInfo & (Function &)> FI)427*b5893f02SDimitry Andric StackSafetyDataFlowAnalysis::StackSafetyDataFlowAnalysis(
428*b5893f02SDimitry Andric     Module &M, std::function<const StackSafetyInfo &(Function &)> FI)
429*b5893f02SDimitry Andric     : PointerSize(M.getDataLayout().getPointerSizeInBits()),
430*b5893f02SDimitry Andric       UnknownRange(PointerSize, true) {
431*b5893f02SDimitry Andric   // Without ThinLTO, run the local analysis for every function in the TU and
432*b5893f02SDimitry Andric   // then run the DFA.
433*b5893f02SDimitry Andric   for (auto &F : M.functions())
434*b5893f02SDimitry Andric     if (!F.isDeclaration())
435*b5893f02SDimitry Andric       Functions.emplace(&F, FI(F));
436*b5893f02SDimitry Andric   for (auto &A : M.aliases())
437*b5893f02SDimitry Andric     if (isa<Function>(A.getBaseObject()))
438*b5893f02SDimitry Andric       Functions.emplace(&A, StackSafetyInfo::FunctionInfo(&A));
439*b5893f02SDimitry Andric }
440*b5893f02SDimitry Andric 
441*b5893f02SDimitry Andric ConstantRange
getArgumentAccessRange(const GlobalValue * Callee,unsigned ParamNo) const442*b5893f02SDimitry Andric StackSafetyDataFlowAnalysis::getArgumentAccessRange(const GlobalValue *Callee,
443*b5893f02SDimitry Andric                                                     unsigned ParamNo) const {
444*b5893f02SDimitry Andric   auto IT = Functions.find(Callee);
445*b5893f02SDimitry Andric   // Unknown callee (outside of LTO domain or an indirect call).
446*b5893f02SDimitry Andric   if (IT == Functions.end())
447*b5893f02SDimitry Andric     return UnknownRange;
448*b5893f02SDimitry Andric   const StackSafetyInfo::FunctionInfo &FS = IT->second;
449*b5893f02SDimitry Andric   // The definition of this symbol may not be the definition in this linkage
450*b5893f02SDimitry Andric   // unit.
451*b5893f02SDimitry Andric   if (!FS.IsDSOLocal() || FS.IsInterposable())
452*b5893f02SDimitry Andric     return UnknownRange;
453*b5893f02SDimitry Andric   if (ParamNo >= FS.Params.size()) // possibly vararg
454*b5893f02SDimitry Andric     return UnknownRange;
455*b5893f02SDimitry Andric   return FS.Params[ParamNo].Use.Range;
456*b5893f02SDimitry Andric }
457*b5893f02SDimitry Andric 
updateOneUse(UseInfo & US,bool UpdateToFullSet)458*b5893f02SDimitry Andric bool StackSafetyDataFlowAnalysis::updateOneUse(UseInfo &US,
459*b5893f02SDimitry Andric                                                bool UpdateToFullSet) {
460*b5893f02SDimitry Andric   bool Changed = false;
461*b5893f02SDimitry Andric   for (auto &CS : US.Calls) {
462*b5893f02SDimitry Andric     assert(!CS.Offset.isEmptySet() &&
463*b5893f02SDimitry Andric            "Param range can't be empty-set, invalid offset range");
464*b5893f02SDimitry Andric 
465*b5893f02SDimitry Andric     ConstantRange CalleeRange = getArgumentAccessRange(CS.Callee, CS.ParamNo);
466*b5893f02SDimitry Andric     CalleeRange = CalleeRange.add(CS.Offset);
467*b5893f02SDimitry Andric     if (!US.Range.contains(CalleeRange)) {
468*b5893f02SDimitry Andric       Changed = true;
469*b5893f02SDimitry Andric       if (UpdateToFullSet)
470*b5893f02SDimitry Andric         US.Range = UnknownRange;
471*b5893f02SDimitry Andric       else
472*b5893f02SDimitry Andric         US.Range = US.Range.unionWith(CalleeRange);
473*b5893f02SDimitry Andric     }
474*b5893f02SDimitry Andric   }
475*b5893f02SDimitry Andric   return Changed;
476*b5893f02SDimitry Andric }
477*b5893f02SDimitry Andric 
updateOneNode(const GlobalValue * Callee,StackSafetyInfo::FunctionInfo & FS)478*b5893f02SDimitry Andric void StackSafetyDataFlowAnalysis::updateOneNode(
479*b5893f02SDimitry Andric     const GlobalValue *Callee, StackSafetyInfo::FunctionInfo &FS) {
480*b5893f02SDimitry Andric   bool UpdateToFullSet = FS.UpdateCount > StackSafetyMaxIterations;
481*b5893f02SDimitry Andric   bool Changed = false;
482*b5893f02SDimitry Andric   for (auto &AS : FS.Allocas)
483*b5893f02SDimitry Andric     Changed |= updateOneUse(AS.Use, UpdateToFullSet);
484*b5893f02SDimitry Andric   for (auto &PS : FS.Params)
485*b5893f02SDimitry Andric     Changed |= updateOneUse(PS.Use, UpdateToFullSet);
486*b5893f02SDimitry Andric 
487*b5893f02SDimitry Andric   if (Changed) {
488*b5893f02SDimitry Andric     LLVM_DEBUG(dbgs() << "=== update [" << FS.UpdateCount
489*b5893f02SDimitry Andric                       << (UpdateToFullSet ? ", full-set" : "") << "] "
490*b5893f02SDimitry Andric                       << FS.getName() << "\n");
491*b5893f02SDimitry Andric     // Callers of this function may need updating.
492*b5893f02SDimitry Andric     for (auto &CallerID : Callers[Callee])
493*b5893f02SDimitry Andric       WorkList.insert(CallerID);
494*b5893f02SDimitry Andric 
495*b5893f02SDimitry Andric     ++FS.UpdateCount;
496*b5893f02SDimitry Andric   }
497*b5893f02SDimitry Andric }
498*b5893f02SDimitry Andric 
runDataFlow()499*b5893f02SDimitry Andric void StackSafetyDataFlowAnalysis::runDataFlow() {
500*b5893f02SDimitry Andric   Callers.clear();
501*b5893f02SDimitry Andric   WorkList.clear();
502*b5893f02SDimitry Andric 
503*b5893f02SDimitry Andric   SmallVector<const GlobalValue *, 16> Callees;
504*b5893f02SDimitry Andric   for (auto &F : Functions) {
505*b5893f02SDimitry Andric     Callees.clear();
506*b5893f02SDimitry Andric     StackSafetyInfo::FunctionInfo &FS = F.second;
507*b5893f02SDimitry Andric     for (auto &AS : FS.Allocas)
508*b5893f02SDimitry Andric       for (auto &CS : AS.Use.Calls)
509*b5893f02SDimitry Andric         Callees.push_back(CS.Callee);
510*b5893f02SDimitry Andric     for (auto &PS : FS.Params)
511*b5893f02SDimitry Andric       for (auto &CS : PS.Use.Calls)
512*b5893f02SDimitry Andric         Callees.push_back(CS.Callee);
513*b5893f02SDimitry Andric 
514*b5893f02SDimitry Andric     llvm::sort(Callees);
515*b5893f02SDimitry Andric     Callees.erase(std::unique(Callees.begin(), Callees.end()), Callees.end());
516*b5893f02SDimitry Andric 
517*b5893f02SDimitry Andric     for (auto &Callee : Callees)
518*b5893f02SDimitry Andric       Callers[Callee].push_back(F.first);
519*b5893f02SDimitry Andric   }
520*b5893f02SDimitry Andric 
521*b5893f02SDimitry Andric   updateAllNodes();
522*b5893f02SDimitry Andric 
523*b5893f02SDimitry Andric   while (!WorkList.empty()) {
524*b5893f02SDimitry Andric     const GlobalValue *Callee = WorkList.back();
525*b5893f02SDimitry Andric     WorkList.pop_back();
526*b5893f02SDimitry Andric     updateOneNode(Callee);
527*b5893f02SDimitry Andric   }
528*b5893f02SDimitry Andric }
529*b5893f02SDimitry Andric 
verifyFixedPoint()530*b5893f02SDimitry Andric void StackSafetyDataFlowAnalysis::verifyFixedPoint() {
531*b5893f02SDimitry Andric   WorkList.clear();
532*b5893f02SDimitry Andric   updateAllNodes();
533*b5893f02SDimitry Andric   assert(WorkList.empty());
534*b5893f02SDimitry Andric }
535*b5893f02SDimitry Andric 
run()536*b5893f02SDimitry Andric StackSafetyGlobalInfo StackSafetyDataFlowAnalysis::run() {
537*b5893f02SDimitry Andric   runDataFlow();
538*b5893f02SDimitry Andric   LLVM_DEBUG(verifyFixedPoint());
539*b5893f02SDimitry Andric 
540*b5893f02SDimitry Andric   StackSafetyGlobalInfo SSI;
541*b5893f02SDimitry Andric   for (auto &F : Functions)
542*b5893f02SDimitry Andric     SSI.emplace(F.first, std::move(F.second));
543*b5893f02SDimitry Andric   return SSI;
544*b5893f02SDimitry Andric }
545*b5893f02SDimitry Andric 
print(const StackSafetyGlobalInfo & SSI,raw_ostream & O,const Module & M)546*b5893f02SDimitry Andric void print(const StackSafetyGlobalInfo &SSI, raw_ostream &O, const Module &M) {
547*b5893f02SDimitry Andric   size_t Count = 0;
548*b5893f02SDimitry Andric   for (auto &F : M.functions())
549*b5893f02SDimitry Andric     if (!F.isDeclaration()) {
550*b5893f02SDimitry Andric       SSI.find(&F)->second.print(O);
551*b5893f02SDimitry Andric       O << "\n";
552*b5893f02SDimitry Andric       ++Count;
553*b5893f02SDimitry Andric     }
554*b5893f02SDimitry Andric   for (auto &A : M.aliases()) {
555*b5893f02SDimitry Andric     SSI.find(&A)->second.print(O);
556*b5893f02SDimitry Andric     O << "\n";
557*b5893f02SDimitry Andric     ++Count;
558*b5893f02SDimitry Andric   }
559*b5893f02SDimitry Andric   assert(Count == SSI.size() && "Unexpected functions in the result");
560*b5893f02SDimitry Andric }
561*b5893f02SDimitry Andric 
562*b5893f02SDimitry Andric } // end anonymous namespace
563*b5893f02SDimitry Andric 
564*b5893f02SDimitry Andric StackSafetyInfo::StackSafetyInfo() = default;
565*b5893f02SDimitry Andric StackSafetyInfo::StackSafetyInfo(StackSafetyInfo &&) = default;
566*b5893f02SDimitry Andric StackSafetyInfo &StackSafetyInfo::operator=(StackSafetyInfo &&) = default;
567*b5893f02SDimitry Andric 
StackSafetyInfo(FunctionInfo && Info)568*b5893f02SDimitry Andric StackSafetyInfo::StackSafetyInfo(FunctionInfo &&Info)
569*b5893f02SDimitry Andric     : Info(new FunctionInfo(std::move(Info))) {}
570*b5893f02SDimitry Andric 
571*b5893f02SDimitry Andric StackSafetyInfo::~StackSafetyInfo() = default;
572*b5893f02SDimitry Andric 
print(raw_ostream & O) const573*b5893f02SDimitry Andric void StackSafetyInfo::print(raw_ostream &O) const { Info->print(O); }
574*b5893f02SDimitry Andric 
575*b5893f02SDimitry Andric AnalysisKey StackSafetyAnalysis::Key;
576*b5893f02SDimitry Andric 
run(Function & F,FunctionAnalysisManager & AM)577*b5893f02SDimitry Andric StackSafetyInfo StackSafetyAnalysis::run(Function &F,
578*b5893f02SDimitry Andric                                          FunctionAnalysisManager &AM) {
579*b5893f02SDimitry Andric   StackSafetyLocalAnalysis SSLA(F, AM.getResult<ScalarEvolutionAnalysis>(F));
580*b5893f02SDimitry Andric   return SSLA.run();
581*b5893f02SDimitry Andric }
582*b5893f02SDimitry Andric 
run(Function & F,FunctionAnalysisManager & AM)583*b5893f02SDimitry Andric PreservedAnalyses StackSafetyPrinterPass::run(Function &F,
584*b5893f02SDimitry Andric                                               FunctionAnalysisManager &AM) {
585*b5893f02SDimitry Andric   OS << "'Stack Safety Local Analysis' for function '" << F.getName() << "'\n";
586*b5893f02SDimitry Andric   AM.getResult<StackSafetyAnalysis>(F).print(OS);
587*b5893f02SDimitry Andric   return PreservedAnalyses::all();
588*b5893f02SDimitry Andric }
589*b5893f02SDimitry Andric 
590*b5893f02SDimitry Andric char StackSafetyInfoWrapperPass::ID = 0;
591*b5893f02SDimitry Andric 
StackSafetyInfoWrapperPass()592*b5893f02SDimitry Andric StackSafetyInfoWrapperPass::StackSafetyInfoWrapperPass() : FunctionPass(ID) {
593*b5893f02SDimitry Andric   initializeStackSafetyInfoWrapperPassPass(*PassRegistry::getPassRegistry());
594*b5893f02SDimitry Andric }
595*b5893f02SDimitry Andric 
getAnalysisUsage(AnalysisUsage & AU) const596*b5893f02SDimitry Andric void StackSafetyInfoWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const {
597*b5893f02SDimitry Andric   AU.addRequired<ScalarEvolutionWrapperPass>();
598*b5893f02SDimitry Andric   AU.setPreservesAll();
599*b5893f02SDimitry Andric }
600*b5893f02SDimitry Andric 
print(raw_ostream & O,const Module * M) const601*b5893f02SDimitry Andric void StackSafetyInfoWrapperPass::print(raw_ostream &O, const Module *M) const {
602*b5893f02SDimitry Andric   SSI.print(O);
603*b5893f02SDimitry Andric }
604*b5893f02SDimitry Andric 
runOnFunction(Function & F)605*b5893f02SDimitry Andric bool StackSafetyInfoWrapperPass::runOnFunction(Function &F) {
606*b5893f02SDimitry Andric   StackSafetyLocalAnalysis SSLA(
607*b5893f02SDimitry Andric       F, getAnalysis<ScalarEvolutionWrapperPass>().getSE());
608*b5893f02SDimitry Andric   SSI = StackSafetyInfo(SSLA.run());
609*b5893f02SDimitry Andric   return false;
610*b5893f02SDimitry Andric }
611*b5893f02SDimitry Andric 
612*b5893f02SDimitry Andric AnalysisKey StackSafetyGlobalAnalysis::Key;
613*b5893f02SDimitry Andric 
614*b5893f02SDimitry Andric StackSafetyGlobalInfo
run(Module & M,ModuleAnalysisManager & AM)615*b5893f02SDimitry Andric StackSafetyGlobalAnalysis::run(Module &M, ModuleAnalysisManager &AM) {
616*b5893f02SDimitry Andric   FunctionAnalysisManager &FAM =
617*b5893f02SDimitry Andric       AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
618*b5893f02SDimitry Andric 
619*b5893f02SDimitry Andric   StackSafetyDataFlowAnalysis SSDFA(
620*b5893f02SDimitry Andric       M, [&FAM](Function &F) -> const StackSafetyInfo & {
621*b5893f02SDimitry Andric         return FAM.getResult<StackSafetyAnalysis>(F);
622*b5893f02SDimitry Andric       });
623*b5893f02SDimitry Andric   return SSDFA.run();
624*b5893f02SDimitry Andric }
625*b5893f02SDimitry Andric 
run(Module & M,ModuleAnalysisManager & AM)626*b5893f02SDimitry Andric PreservedAnalyses StackSafetyGlobalPrinterPass::run(Module &M,
627*b5893f02SDimitry Andric                                                     ModuleAnalysisManager &AM) {
628*b5893f02SDimitry Andric   OS << "'Stack Safety Analysis' for module '" << M.getName() << "'\n";
629*b5893f02SDimitry Andric   print(AM.getResult<StackSafetyGlobalAnalysis>(M), OS, M);
630*b5893f02SDimitry Andric   return PreservedAnalyses::all();
631*b5893f02SDimitry Andric }
632*b5893f02SDimitry Andric 
633*b5893f02SDimitry Andric char StackSafetyGlobalInfoWrapperPass::ID = 0;
634*b5893f02SDimitry Andric 
StackSafetyGlobalInfoWrapperPass()635*b5893f02SDimitry Andric StackSafetyGlobalInfoWrapperPass::StackSafetyGlobalInfoWrapperPass()
636*b5893f02SDimitry Andric     : ModulePass(ID) {
637*b5893f02SDimitry Andric   initializeStackSafetyGlobalInfoWrapperPassPass(
638*b5893f02SDimitry Andric       *PassRegistry::getPassRegistry());
639*b5893f02SDimitry Andric }
640*b5893f02SDimitry Andric 
print(raw_ostream & O,const Module * M) const641*b5893f02SDimitry Andric void StackSafetyGlobalInfoWrapperPass::print(raw_ostream &O,
642*b5893f02SDimitry Andric                                              const Module *M) const {
643*b5893f02SDimitry Andric   ::print(SSI, O, *M);
644*b5893f02SDimitry Andric }
645*b5893f02SDimitry Andric 
getAnalysisUsage(AnalysisUsage & AU) const646*b5893f02SDimitry Andric void StackSafetyGlobalInfoWrapperPass::getAnalysisUsage(
647*b5893f02SDimitry Andric     AnalysisUsage &AU) const {
648*b5893f02SDimitry Andric   AU.addRequired<StackSafetyInfoWrapperPass>();
649*b5893f02SDimitry Andric }
650*b5893f02SDimitry Andric 
runOnModule(Module & M)651*b5893f02SDimitry Andric bool StackSafetyGlobalInfoWrapperPass::runOnModule(Module &M) {
652*b5893f02SDimitry Andric   StackSafetyDataFlowAnalysis SSDFA(
653*b5893f02SDimitry Andric       M, [this](Function &F) -> const StackSafetyInfo & {
654*b5893f02SDimitry Andric         return getAnalysis<StackSafetyInfoWrapperPass>(F).getResult();
655*b5893f02SDimitry Andric       });
656*b5893f02SDimitry Andric   SSI = SSDFA.run();
657*b5893f02SDimitry Andric   return false;
658*b5893f02SDimitry Andric }
659*b5893f02SDimitry Andric 
660*b5893f02SDimitry Andric static const char LocalPassArg[] = "stack-safety-local";
661*b5893f02SDimitry Andric static const char LocalPassName[] = "Stack Safety Local Analysis";
662*b5893f02SDimitry Andric INITIALIZE_PASS_BEGIN(StackSafetyInfoWrapperPass, LocalPassArg, LocalPassName,
663*b5893f02SDimitry Andric                       false, true)
664*b5893f02SDimitry Andric INITIALIZE_PASS_DEPENDENCY(ScalarEvolutionWrapperPass)
665*b5893f02SDimitry Andric INITIALIZE_PASS_END(StackSafetyInfoWrapperPass, LocalPassArg, LocalPassName,
666*b5893f02SDimitry Andric                     false, true)
667*b5893f02SDimitry Andric 
668*b5893f02SDimitry Andric static const char GlobalPassName[] = "Stack Safety Analysis";
669*b5893f02SDimitry Andric INITIALIZE_PASS_BEGIN(StackSafetyGlobalInfoWrapperPass, DEBUG_TYPE,
670*b5893f02SDimitry Andric                       GlobalPassName, false, false)
671*b5893f02SDimitry Andric INITIALIZE_PASS_DEPENDENCY(StackSafetyInfoWrapperPass)
672*b5893f02SDimitry Andric INITIALIZE_PASS_END(StackSafetyGlobalInfoWrapperPass, DEBUG_TYPE,
673*b5893f02SDimitry Andric                     GlobalPassName, false, false)
674