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