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